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) 2011, Intel Corporation
9 All rights reserved. This program and the accompanying materials
10 are licensed and made available under the terms and conditions of the BSD License
11 which accompanies this distribution. The full text of the license may be found at
12 http://opensource.org/licenses/bsd-license.php
14 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
15 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 \section DataStructures Data Structures
22 +-------------+ +-------------+ +-------------+
23 Service Lists | ::ESL_SERVICE |-->| ESL_SERVICE |-->| ESL_SERVICE |--> NULL (pNext)
24 +-------------+ +-------------+ +-------------+
26 pUdp4List ^ | pTcp4List | |
31 | ::ESL_LAYER | ::mEslLayer | |
35 +-------------+ +-------------+ +-------------+
36 | ::ESL_SOCKET |-->| ::ESL_PORT |-->| ESL_PORT |--> NULL (pLinkSocket)
37 +-------------+ +-------------+ +-------------+
41 +-------------+ +-------------+
42 | ESL_SOCKET |-->| ESL_PORT |--> NULL
43 +-------------+ +-------------+
47 (pNext) | | | | (pLinkService)
48 | | | | pRxPacketListHead
49 | | | `-----------------------------------------------.
50 | | | pRxOobPacketListHead |
51 | | `--------------------------------. |
52 | | pTxPacketListHead | |
53 | `---------------. | |
54 pTxOobPacketListHead | | | |
56 +------------+ +------------+ +------------+ +------------+
57 | ::ESL_PACKET | | ESL_PACKET | | ESL_PACKET | | ESL_PACKET |
58 +------------+ +------------+ +------------+ +------------+
61 +------------+ +------------+ +------------+ +------------+
62 | ESL_PACKET | | ESL_PACKET | | ESL_PACKET | | ESL_PACKET |
63 +------------+ +------------+ +------------+ +------------+
71 ::mEslLayer is the one and only ::ESL_LAYER structure. It connects directly or
72 indirectly to the other data structures. The ESL_LAYER structure has a unique
73 service list for each of the network protocol interfaces.
75 ::ESL_SERVICE manages the network interfaces for a given transport type (IP4, TCP4, UDP4, etc.)
77 ::ESL_SOCKET manages the activity for a single socket instance. As such, it contains
78 the ::EFI_SOCKET_PROTOCOL structure which the BSD socket library uses as the object
79 reference and the API into the EFI socket library.
81 ::ESL_PORT manages the connection with a single instance of the lower layer network.
82 This structure is the socket equivalent of an IP connection or a TCP or UDP port.
84 ::ESL_PACKET buffers data for transmit and receive. There are four queues connected
85 to the ::ESL_SOCKET that manage the data:
87 <li>ESL_SOCKET::pRxPacketListHead - Normal (low) priority receive data</li>
88 <li>ESL_SOCKET::pRxOobPacketListHead - High (out-of-band or urgent) priority receive data</li>
89 <li>ESL_SOCKET::pTxPacketListHead - Normal (low) priority transmit data</li>
90 <li>ESL_SOCKET::pTxOobPacketListHead - High (out-of-band or urgent) priority transmit data</li>
92 The selection of the transmit queue is controlled by the MSG_OOB flag on the transmit
93 request as well as the socket option SO_OOBINLINE. The receive queue is selected by
94 the URGENT data flag for TCP and the setting of the socket option SO_OOBINLINE.
96 Data structure synchronization is done by raising TPL to TPL_SOCKET. Modifying
97 critical elements within the data structures must be done at this TPL. TPL is then
98 restored to the previous level. Note that the code verifies that all callbacks are
99 entering at TPL_SOCKETS for proper data structure synchronization.
101 \section PortCloseStateMachine Port Close State Machine
103 The port close state machine walks the port through the necessary
104 states to stop activity on the port and get it into a state where
105 the resources may be released. The state machine consists of the
106 following arcs and states:
110 +--------------------------+
112 +--------------------------+
114 | ::EslSocketPortCloseStart
116 +--------------------------+
117 | PORT_STATE_CLOSE_STARTED |
118 +--------------------------+
120 | ::EslSocketPortCloseTxDone
122 +--------------------------+
123 | PORT_STATE_CLOSE_TX_DONE |
124 +--------------------------+
126 | ::EslSocketPortCloseComplete
128 +--------------------------+
129 | PORT_STATE_CLOSE_DONE |
130 +--------------------------+
132 | ::EslSocketPortCloseRxDone
134 +--------------------------+
135 | PORT_STATE_CLOSE_RX_DONE |
136 +--------------------------+
138 | ::EslSocketPortClose
140 +--------------------------+
142 +--------------------------+
147 <li>Arc: ::EslSocketPortCloseStart - Marks the port as closing and
148 initiates the port close operation</li>
149 <li>State: PORT_STATE_CLOSE_STARTED</li>
150 <li>Arc: ::EslSocketPortCloseTxDone - Waits until all of the transmit
151 operations to complete. After all of the transmits are complete,
152 this routine initiates the network specific close operation by calling
153 through ESL_PROTOCOL_API::pfnPortCloseOp. One such routine is
154 ::EslTcp4PortCloseOp.
156 <li>State: PORT_STATE_CLOSE_TX_DONE</li>
157 <li>Arc: ::EslSocketPortCloseComplete - Called when the close operation is
158 complete. After the transition to PORT_STATE_CLOSE_DONE,
159 this routine calls ::EslSocketRxCancel to abort the pending receive operations.
161 <li>State: PORT_STATE_CLOSE_DONE</li>
162 <li>Arc: ::EslSocketPortCloseRxDone - Waits until all of the receive
163 operation have been cancelled. After the transition to
164 PORT_STATE_CLOSE_RX_DONE, this routine calls ::EslSocketPortClose.
166 <li>State: PORT_STATE_CLOSE_RX_DONE</li>
167 <li>Arc: ::EslSocketPortClose - This routine discards any receive buffers
168 using a network specific support routine via ESL_PROTOCOL_API::pfnPacketFree.
169 This routine then releases the port resources allocated by ::EslSocketPortAllocate
170 and calls the network specific port close routine (e.g. ::EslTcp4PortClose)
171 via ESL_PROTOCOL_API::pfnPortClose to release any network specific resources.
176 \section ReceiveEngine Receive Engine
178 The receive path accepts data from the network and queues (buffers) it for the
179 application. Flow control is applied once a maximum amount of buffering is reached
180 and is released when the buffer usage drops below that limit. Eventually the
181 application requests data from the socket which removes entries from the queue and
184 The receive engine is the state machine which reads data from the network and
185 fills the queue with received packets. The receive engine uses two data structures
186 to manage the network receive opeations and the buffers.
188 At a high level, the ::ESL_IO_MGMT structures are managing the tokens and
189 events for the interface to the UEFI network stack. The ::ESL_PACKET
190 structures are managing the receive data buffers. The receive engine
191 connects these two structures in the network specific receive completion
211 The ::ESL_IO_MGMT structures are allocated as part of the ::ESL_PORT structure in
212 ::EslSocketPortAllocate. The ESL_IO_MGMT structures are separated and placed on
213 the free list by calling ::EslSocketIoInit. The ESL_IO_MGMT structure contains
214 the network layer specific receive completion token and event. The receive engine
215 is eventually shutdown by ::EslSocketPortCloseTxDone and the resources in these
216 structures are released in ::EslSocketPortClose by a call to ::EslSocketIoFree.
223 +-------------+ +-------------+ +-------------+
224 Active | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
225 +-------------+ +-------------+ +-------------+
227 +-------------+ +-------------+ +-------------+
228 Free | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
229 +-------------+ +-------------+ +-------------+
235 The receive engine is started by calling ::EslSocketRxStart. Flow control pauses
236 the receive engine by stopping the calls to EslSocketRxStart when the amount of
237 receive data waiting for the application meets or exceeds MAX_RX_DATA. After
238 the application reads enough data that the amount of buffering drops below this
239 limit, the calls to EslSockeRxStart continue which releases the flow control.
241 Receive flow control is applied when the port is created, since no receive
242 operation are pending to the low layer network driver. The flow control gets
243 released when the low layer network port is configured or the first receive
244 operation is posted. Flow control remains in the released state until the
245 maximum buffer space is consumed. During this time, ::EslSocketRxComplete
246 calls ::EslSocketRxStart. Flow control is applied in EslSocketRxComplete
247 by skipping the call to EslSocketRxStart. Flow control is eventually
248 released in ::EslSocketReceive when the buffer space drops below the
249 maximum amount causing EslSocketReceive to call EslSocketRxStart.
253 +------------+ +------------+
254 High .----->| ESL_PACKET |-->| ESL_PACKET |--> NULL (pNext)
255 Priority | +------------+ +------------+
257 | pRxOobPacketListHead
263 Priority | +------------+ +------------+ +------------+
264 `----->| ::ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL
265 +------------+ +------------+ +------------+
269 ::EslSocketRxStart connects an ::ESL_PACKET structure to the ::ESL_IO_MGMT structure
270 and then calls the network layer to start the receive operation. Upon
271 receive completion, ::EslSocketRxComplete breaks the connection between these
272 structrues and places the ESL_IO_MGMT structure onto the ESL_PORT::pRxFree list to
273 make token and event available for another receive operation. EslSocketRxComplete
274 then queues the ESL_PACKET structure (data packet) to either the
275 ESL_SOCKET::pRxOobPacketListTail or ESL_SOCKET::pRxPacketListTail depending on
276 whether urgent or normal data was received. Finally ::EslSocketRxComplete attempts
277 to start another receive operation.
281 Setup for IP4 and UDP4
283 +--------------------+
289 +----+---------------+
292 +--------------------+
297 +----+---------------+
299 Completion for IP4 and UDP4
301 +--------------------+ +----------------------+
302 | ESL_IO_MGMT | | Data Buffer |
303 | | | (Driver owned) |
304 | +---------------+ +----------------------+
307 | | | +----------------------+
308 | | RxData --> | EFI_IP4_RECEIVE_DATA |
309 +----+---------------+ | (Driver owned) |
310 | +----------------------+
312 +--------------------+ .
315 | +---------------+ .
316 | | pRxData --> NULL .......
317 +----+---------------+
320 Setup and completion for TCP4
322 +--------------------+ +--------------------------+
323 | ESL_IO_MGMT |-->| ESL_PACKET |
325 | +---------------+ +----------------------+ |
326 | | Token | | EFI_IP4_RECEIVE_DATA | |
328 | | | +----------------------+---+
329 | | Event | | Data Buffer |
330 +----+---------------+ | |
332 +--------------------------+
336 To minimize the number of buffer copies, the data is not copied until the
337 application makes a receive call. At this point socket performs a single copy
338 in the receive path to move the data from the buffer filled by the network layer
339 into the application's buffer.
341 The IP4 and UDP4 drivers go one step further to reduce buffer copies. They
342 allow the socket layer to hold on to the actual receive buffer until the
343 application has performed a receive operation or closes the socket. Both
344 of theses operations return the buffer to the lower layer network driver
345 by calling ESL_PROTOCOL_API::pfnPacketFree.
347 When a socket application wants to receive data it indirectly calls
348 ::EslSocketReceive to remove data from one of the receive data queues. This routine
349 removes the next available packet from ESL_SOCKET::pRxOobPacketListHead or
350 ESL_SOCKET::pRxPacketListHead and copies the data from the packet
351 into the application's buffer. For SOCK_STREAM sockets, if the packet
352 contains more data then the ESL_PACKET structures remains at the head of the
353 receive queue for the next application receive
354 operation. For SOCK_DGRAM, SOCK_RAW and SOCK_SEQ_PACKET sockets, the ::ESL_PACKET
355 structure is removed from the head of the receive queue and any remaining data is
356 discarded as the packet is placed on the free queue.
358 During socket layer shutdown, ::EslSocketShutdown calls ::EslSocketRxCancel to
359 cancel any pending receive operations. EslSocketRxCancel calls the network specific
360 cancel routine using ESL_PORT::pfnRxCancel.
363 \section TransmitEngine Transmit Engine
365 Application calls to ::EslSocketTransmit cause data to be copied into a buffer.
366 The buffer exists as an extension to an ESL_PACKET structure and the structure
367 is placed at the end of the transmit queue.
371 *ppQueueHead: pSocket->pRxPacketListHead or pSocket->pRxOobPacketListHead
374 +------------+ +------------+ +------------+
375 Data | ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL
376 +------------+ +------------+ +------------+
379 *ppQueueTail: pSocket->pRxPacketListTail or pSocket->pRxOobPacketListTail
383 There are actually two transmit queues the normal or low priority queue which is
384 the default and the urgent or high priority queue which is addressed by specifying
385 the MSG_OOB flag during the transmit request. Associated with each queue is a
386 transmit engine which is responsible for sending the data in that queue.
388 The transmit engine is the state machine which removes entries from the head
389 of the transmit queue and causes the data to be sent over the network.
393 +--------------------+ +--------------------+
394 | ESL_IO_MGMT | | ESL_PACKET |
396 | +---------------+ +----------------+ |
397 | | Token | | Buffer Length | |
398 | | TxData --> | Buffer Address | |
399 | | | +----------------+---+
400 | | Event | | Data Buffer |
401 +----+---------------+ | |
402 +--------------------+
405 At a high level, the transmit engine uses a couple of data structures
406 to manage the data flow. The ::ESL_IO_MGMT structures manage the tokens and
407 events for the interface to the UEFI network stack. The ::ESL_PACKET
408 structures manage the data buffers that get sent. The transmit
409 engine connects these two structures prior to transmission and disconnects
410 them upon completion.
414 pPort->pTxActive or pTxOobActive
417 +-------------+ +-------------+ +-------------+
418 Active | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
419 +-------------+ +-------------+ +-------------+
421 +-------------+ +-------------+ +-------------+
422 Free | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
423 +-------------+ +-------------+ +-------------+
426 pPort->pTxFree or pTxOobFree
430 The transmit engine manages multiple transmit operations using the
431 active and free lists shown above. ::EslSocketPortAllocate allocates the
432 ::ESL_IO_MGMT structures as an extension to the ::ESL_PORT structure.
433 This routine places the ESL_IO_MGMT structures on the free list by calling
434 ::EslSocketIoInit. During their lifetime, the ESL_IO_MGMT structures
435 will move from the free list to the active list and back again. The
436 active list contains the packets that are actively being processed by
437 the UEFI network stack. Eventually the ESL_IO_MGMT structures will be
438 removed from the free list and be deallocated by the EslSocketPortClose
441 The network specific code calls the ::EslSocketTxStart routine
442 to hand a packet to the network stack. EslSocketTxStart connects
443 the transmit packet (::ESL_PACKET) to an ::ESL_IO_MGMT structure
444 and then queues the result to one of the active lists:
445 ESL_PORT::pTxActive or ESL_PORT::pTxOobActive. The routine then
446 hands the packet to the network stack.
448 Upon completion, the network specific TxComplete routine calls
449 ::EslSocketTxComplete to disconnect the transmit packet from the
450 ESL_IO_MGMT structure and frees the ::ESL_PACKET structure by calling
451 ::EslSocketPacketFree. The routine places the ::ESL_IO_MGMT structure
452 into the free list either ESL_PORT::pTxFree or ESL_PORT::pTxOobFree.
453 EslSocketTxComplete then starts the next transmit operation while
454 the socket is active or calls the ::EslSocketPortCloseTxDone routine
455 when the socket is shutting down.
463 Socket driver connection points
465 List the network stack connection points for the socket driver.
467 CONST ESL_SOCKET_BINDING cEslSocketBinding
[] = {
469 &gEfiIp4ServiceBindingProtocolGuid
,
470 &gEfiIp4ProtocolGuid
,
472 OFFSET_OF ( ESL_LAYER
, pIp4List
),
475 0 }, // TX Oob buffers
477 &gEfiTcp4ServiceBindingProtocolGuid
,
478 &gEfiTcp4ProtocolGuid
,
479 &mEslTcp4ServiceGuid
,
480 OFFSET_OF ( ESL_LAYER
, pTcp4List
),
483 4 }, // TX Oob buffers
485 &gEfiTcp6ServiceBindingProtocolGuid
,
486 &gEfiTcp6ProtocolGuid
,
487 &mEslTcp6ServiceGuid
,
488 OFFSET_OF ( ESL_LAYER
, pTcp6List
),
491 4 }, // TX Oob buffers
493 &gEfiUdp4ServiceBindingProtocolGuid
,
494 &gEfiUdp4ProtocolGuid
,
495 &mEslUdp4ServiceGuid
,
496 OFFSET_OF ( ESL_LAYER
, pUdp4List
),
499 0 }, // TX Oob buffers
501 &gEfiUdp6ServiceBindingProtocolGuid
,
502 &gEfiUdp6ProtocolGuid
,
503 &mEslUdp6ServiceGuid
,
504 OFFSET_OF ( ESL_LAYER
, pUdp6List
),
507 0 } // TX Oob buffers
510 CONST UINTN cEslSocketBindingEntries
= DIM ( cEslSocketBinding
);
513 APIs to support the various socket types for the v4 network stack.
515 CONST ESL_PROTOCOL_API
* cEslAfInetApi
[] = {
517 &cEslTcp4Api
, // SOCK_STREAM
518 &cEslUdp4Api
, // SOCK_DGRAM
519 &cEslIp4Api
, // SOCK_RAW
521 &cEslTcp4Api
// SOCK_SEQPACKET
525 Number of entries in the v4 API array ::cEslAfInetApi.
527 CONST
int cEslAfInetApiSize
= DIM ( cEslAfInetApi
);
531 APIs to support the various socket types for the v6 network stack.
533 CONST ESL_PROTOCOL_API
* cEslAfInet6Api
[] = {
535 &cEslTcp6Api
, // SOCK_STREAM
536 &cEslUdp6Api
, // SOCK_DGRAM
539 &cEslTcp6Api
// SOCK_SEQPACKET
543 Number of entries in the v6 API array ::cEslAfInet6Api.
545 CONST
int cEslAfInet6ApiSize
= DIM ( cEslAfInet6Api
);
549 Global management structure for the socket layer.
555 Initialize an endpoint for network communication.
557 This routine initializes the communication endpoint.
559 The ::socket routine calls this routine indirectly to create
560 the communication endpoint.
562 @param [in] pSocketProtocol Address of the socket protocol structure.
563 @param [in] domain Select the family of protocols for the client or server
564 application. See the ::socket documentation for values.
565 @param [in] type Specifies how to make the network connection.
566 See the ::socket documentation for values.
567 @param [in] protocol Specifies the lower layer protocol to use.
568 See the ::socket documentation for values.
569 @param [out] pErrno Address to receive the errno value upon completion.
571 @retval EFI_SUCCESS - Socket successfully created
572 @retval EFI_INVALID_PARAMETER - Invalid domain value, errno = EAFNOSUPPORT
573 @retval EFI_INVALID_PARAMETER - Invalid type value, errno = EINVAL
574 @retval EFI_INVALID_PARAMETER - Invalid protocol value, errno = EINVAL
579 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
586 CONST ESL_PROTOCOL_API
* pApi
;
587 CONST ESL_PROTOCOL_API
** ppApiArray
;
588 CONST ESL_PROTOCOL_API
** ppApiArrayEnd
;
590 ESL_SOCKET
* pSocket
;
599 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
602 // Set the default domain if necessary
604 if ( AF_UNSPEC
== domain
) {
612 Status
= EFI_SUCCESS
;
615 // Use break instead of goto
619 // Validate the domain value
621 if (( AF_INET
!= domain
)
622 && ( AF_INET6
!= domain
)
623 && ( AF_LOCAL
!= domain
)) {
624 DEBUG (( DEBUG_ERROR
| DEBUG_SOCKET
,
625 "ERROR - Invalid domain value\r\n" ));
626 Status
= EFI_INVALID_PARAMETER
;
627 errno
= EAFNOSUPPORT
;
632 // Determine the protocol APIs
636 if (( AF_INET
== domain
)
637 || ( AF_LOCAL
== domain
)) {
638 ppApiArray
= &cEslAfInetApi
[0];
639 ApiArraySize
= cEslAfInetApiSize
;
642 ppApiArray
= &cEslAfInet6Api
[0];
643 ApiArraySize
= cEslAfInet6ApiSize
;
647 // Set the default type if necessary
654 // Validate the type value
656 if (( type
>= ApiArraySize
)
657 || ( NULL
== ppApiArray
)
658 || ( NULL
== ppApiArray
[ type
])) {
659 DEBUG (( DEBUG_ERROR
| DEBUG_SOCKET
,
660 "ERROR - Invalid type value\r\n" ));
662 // The socket type is not supported
664 Status
= EFI_INVALID_PARAMETER
;
670 // Set the default protocol if necessary
672 pApi
= ppApiArray
[ type
];
673 if ( 0 == protocol
) {
674 protocol
= pApi
->DefaultProtocol
;
678 // Validate the protocol value
680 if (( pApi
->DefaultProtocol
!= protocol
)
681 && ( SOCK_RAW
!= type
)) {
682 Status
= EFI_INVALID_PARAMETER
;
685 // Assume that the driver supports this protocol
687 ppApiArray
= &cEslAfInetApi
[0];
688 ppApiArrayEnd
= &ppApiArray
[ cEslAfInetApiSize
];
689 while ( ppApiArrayEnd
> ppApiArray
) {
691 if ( protocol
== pApi
->DefaultProtocol
) {
696 if ( ppApiArrayEnd
<= ppApiArray
) {
698 // Verify against the IPv6 table
700 ppApiArray
= &cEslAfInet6Api
[0];
701 ppApiArrayEnd
= &ppApiArray
[ cEslAfInet6ApiSize
];
702 while ( ppApiArrayEnd
> ppApiArray
) {
704 if ( protocol
== pApi
->DefaultProtocol
) {
710 if ( ppApiArrayEnd
<= ppApiArray
) {
711 DEBUG (( DEBUG_ERROR
| DEBUG_SOCKET
,
712 "ERROR - The protocol is not supported!\r\n" ));
713 errno
= EPROTONOSUPPORT
;
718 // The driver does not support this protocol
720 DEBUG (( DEBUG_ERROR
| DEBUG_SOCKET
,
721 "ERROR - The protocol does not support this socket type!\r\n" ));
722 errno
= EPROTONOSUPPORT
;
728 // Save the socket attributes
730 pSocket
->pApi
= pApi
;
731 pSocket
->Domain
= domain
;
732 pSocket
->Type
= type
;
733 pSocket
->Protocol
= protocol
;
742 // Return the operation status
744 if ( NULL
!= pErrno
) {
747 DBG_EXIT_STATUS ( Status
);
753 Accept a network connection.
755 This routine calls the network specific layer to remove the next
756 connection from the FIFO.
758 The ::accept calls this routine to poll for a network
759 connection to the socket. When a connection is available
760 this routine returns the ::EFI_SOCKET_PROTOCOL structure address
761 associated with the new socket and the remote network address
764 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
766 @param [in] pSockAddr Address of a buffer to receive the remote
769 @param [in, out] pSockAddrLength Length in bytes of the address buffer.
770 On output specifies the length of the
771 remote network address.
773 @param [out] ppSocketProtocol Address of a buffer to receive the
774 ::EFI_SOCKET_PROTOCOL instance
775 associated with the new socket.
777 @param [out] pErrno Address to receive the errno value upon completion.
779 @retval EFI_SUCCESS New connection successfully created
780 @retval EFI_NOT_READY No connection is available
785 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
786 IN
struct sockaddr
* pSockAddr
,
787 IN OUT socklen_t
* pSockAddrLength
,
788 IN EFI_SOCKET_PROTOCOL
** ppSocketProtocol
,
792 ESL_SOCKET
* pNewSocket
;
793 ESL_SOCKET
* pSocket
;
802 Status
= EFI_SUCCESS
;
805 // Validate the socket
809 if ( NULL
!= pSocketProtocol
) {
810 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
815 if ( NULL
== pSocket
->pApi
->pfnAccept
) {
816 Status
= EFI_UNSUPPORTED
;
817 pSocket
->errno
= ENOTSUP
;
821 // Validate the sockaddr
823 if (( NULL
!= pSockAddr
)
824 && ( NULL
== pSockAddrLength
)) {
825 DEBUG (( DEBUG_ACCEPT
,
826 "ERROR - pSockAddr is NULL!\r\n" ));
827 Status
= EFI_INVALID_PARAMETER
;
828 pSocket
->errno
= EFAULT
;
832 // Synchronize with the socket layer
834 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
837 // Verify that the socket is in the listen state
839 if ( SOCKET_STATE_LISTENING
!= pSocket
->State
) {
840 DEBUG (( DEBUG_ACCEPT
,
841 "ERROR - Socket is not listening!\r\n" ));
842 if ( NULL
== pSocket
->pApi
->pfnAccept
) {
844 // Socket does not support listen
846 pSocket
->errno
= EOPNOTSUPP
;
847 Status
= EFI_UNSUPPORTED
;
851 // Socket supports listen, but not in listen state
853 pSocket
->errno
= EINVAL
;
854 Status
= EFI_NOT_STARTED
;
859 // Determine if a socket is available
861 if ( 0 == pSocket
->FifoDepth
) {
863 // No connections available
864 // Determine if any ports are available
866 if ( NULL
== pSocket
->pPortList
) {
868 // No ports available
870 Status
= EFI_DEVICE_ERROR
;
871 pSocket
->errno
= EINVAL
;
874 // Update the socket state
876 pSocket
->State
= SOCKET_STATE_NO_PORTS
;
880 // Ports are available
881 // No connection requests at this time
883 Status
= EFI_NOT_READY
;
884 pSocket
->errno
= EAGAIN
;
890 // Attempt to accept the connection and
891 // get the remote network address
893 pNewSocket
= pSocket
->pFifoHead
;
894 ASSERT ( NULL
!= pNewSocket
);
895 Status
= pSocket
->pApi
->pfnAccept ( pNewSocket
,
898 if ( !EFI_ERROR ( Status
)) {
900 // Remove the new socket from the list
902 pSocket
->pFifoHead
= pNewSocket
->pNextConnection
;
903 if ( NULL
== pSocket
->pFifoHead
) {
904 pSocket
->pFifoTail
= NULL
;
908 // Account for this socket
910 pSocket
->FifoDepth
-= 1;
913 // Update the new socket's state
915 pNewSocket
->State
= SOCKET_STATE_CONNECTED
;
916 pNewSocket
->bConfigured
= TRUE
;
917 DEBUG (( DEBUG_ACCEPT
,
918 "0x%08x: Socket connected\r\n",
925 // Release the socket layer synchronization
927 RESTORE_TPL ( TplPrevious
);
933 // Return the new socket
935 if (( NULL
!= ppSocketProtocol
)
936 && ( NULL
!= pNewSocket
)) {
937 *ppSocketProtocol
= &pNewSocket
->SocketProtocol
;
941 // Return the operation status
943 if ( NULL
!= pErrno
) {
944 if ( NULL
!= pSocket
) {
945 *pErrno
= pSocket
->errno
;
948 Status
= EFI_INVALID_PARAMETER
;
952 DBG_EXIT_STATUS ( Status
);
958 Allocate and initialize a ESL_SOCKET structure.
960 This support function allocates an ::ESL_SOCKET structure
961 and installs a protocol on ChildHandle. If pChildHandle is a
962 pointer to NULL, then a new handle is created and returned in
963 pChildHandle. If pChildHandle is not a pointer to NULL, then
964 the protocol installs on the existing pChildHandle.
966 @param [in, out] pChildHandle Pointer to the handle of the child to create.
967 If it is NULL, then a new handle is created.
968 If it is a pointer to an existing UEFI handle,
969 then the protocol is added to the existing UEFI
971 @param [in] DebugFlags Flags for debug messages
972 @param [in, out] ppSocket The buffer to receive an ::ESL_SOCKET structure address.
974 @retval EFI_SUCCESS The protocol was added to ChildHandle.
975 @retval EFI_INVALID_PARAMETER ChildHandle is NULL.
976 @retval EFI_OUT_OF_RESOURCES There are not enough resources available to create
978 @retval other The child handle was not created
984 IN OUT EFI_HANDLE
* pChildHandle
,
986 IN OUT ESL_SOCKET
** ppSocket
991 ESL_SOCKET
* pSocket
;
998 // Create a socket structure
1000 LengthInBytes
= sizeof ( *pSocket
);
1001 pSocket
= (ESL_SOCKET
*) AllocateZeroPool ( LengthInBytes
);
1002 if ( NULL
!= pSocket
) {
1003 DEBUG (( DebugFlags
| DEBUG_POOL
| DEBUG_INIT
,
1004 "0x%08x: Allocate pSocket, %d bytes\r\n",
1009 // Initialize the socket protocol
1011 pSocket
->Signature
= SOCKET_SIGNATURE
;
1012 pSocket
->SocketProtocol
.pfnAccept
= EslSocketAccept
;
1013 pSocket
->SocketProtocol
.pfnBind
= EslSocketBind
;
1014 pSocket
->SocketProtocol
.pfnClosePoll
= EslSocketClosePoll
;
1015 pSocket
->SocketProtocol
.pfnCloseStart
= EslSocketCloseStart
;
1016 pSocket
->SocketProtocol
.pfnConnect
= EslSocketConnect
;
1017 pSocket
->SocketProtocol
.pfnGetLocal
= EslSocketGetLocalAddress
;
1018 pSocket
->SocketProtocol
.pfnGetPeer
= EslSocketGetPeerAddress
;
1019 pSocket
->SocketProtocol
.pfnListen
= EslSocketListen
;
1020 pSocket
->SocketProtocol
.pfnOptionGet
= EslSocketOptionGet
;
1021 pSocket
->SocketProtocol
.pfnOptionSet
= EslSocketOptionSet
;
1022 pSocket
->SocketProtocol
.pfnPoll
= EslSocketPoll
;
1023 pSocket
->SocketProtocol
.pfnReceive
= EslSocketReceive
;
1024 pSocket
->SocketProtocol
.pfnShutdown
= EslSocketShutdown
;
1025 pSocket
->SocketProtocol
.pfnSocket
= EslSocket
;
1026 pSocket
->SocketProtocol
.pfnTransmit
= EslSocketTransmit
;
1028 pSocket
->MaxRxBuf
= MAX_RX_DATA
;
1029 pSocket
->MaxTxBuf
= MAX_TX_DATA
;
1032 // Install the socket protocol on the specified handle
1034 Status
= gBS
->InstallMultipleProtocolInterfaces (
1036 &gEfiSocketProtocolGuid
,
1037 &pSocket
->SocketProtocol
,
1040 if ( !EFI_ERROR ( Status
)) {
1041 DEBUG (( DebugFlags
| DEBUG_POOL
| DEBUG_INIT
| DEBUG_INFO
,
1042 "Installed: gEfiSocketProtocolGuid on 0x%08x\r\n",
1044 pSocket
->SocketProtocol
.SocketHandle
= *pChildHandle
;
1047 // Synchronize with the socket layer
1049 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
1052 // Add this socket to the list
1054 pLayer
= &mEslLayer
;
1055 pSocket
->pNext
= pLayer
->pSocketList
;
1056 pLayer
->pSocketList
= pSocket
;
1059 // Release the socket layer synchronization
1061 RESTORE_TPL ( TplPrevious
);
1064 // Return the socket structure address
1066 *ppSocket
= pSocket
;
1069 DEBUG (( DEBUG_ERROR
| DebugFlags
| DEBUG_POOL
| DEBUG_INIT
,
1070 "ERROR - Failed to install gEfiSocketProtocolGuid on 0x%08x, Status: %r\r\n",
1076 // Release the socket if necessary
1078 if ( EFI_ERROR ( Status
)) {
1079 gBS
->FreePool ( pSocket
);
1080 DEBUG (( DebugFlags
| DEBUG_POOL
| DEBUG_INIT
,
1081 "0x%08x: Free pSocket, %d bytes\r\n",
1083 sizeof ( *pSocket
)));
1088 Status
= EFI_OUT_OF_RESOURCES
;
1092 // Return the operation status
1094 DBG_EXIT_STATUS ( Status
);
1100 Bind a name to a socket.
1102 This routine calls the network specific layer to save the network
1103 address of the local connection point.
1105 The ::bind routine calls this routine to connect a name
1106 (network address and port) to a socket on the local machine.
1108 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
1110 @param [in] pSockAddr Address of a sockaddr structure that contains the
1111 connection point on the local machine. An IPv4 address
1112 of INADDR_ANY specifies that the connection is made to
1113 all of the network stacks on the platform. Specifying a
1114 specific IPv4 address restricts the connection to the
1115 network stack supporting that address. Specifying zero
1116 for the port causes the network layer to assign a port
1117 number from the dynamic range. Specifying a specific
1118 port number causes the network layer to use that port.
1120 @param [in] SockAddrLength Specifies the length in bytes of the sockaddr structure.
1122 @param [out] pErrno Address to receive the errno value upon completion.
1124 @retval EFI_SUCCESS - Socket successfully created
1129 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
1130 IN CONST
struct sockaddr
* pSockAddr
,
1131 IN socklen_t SockAddrLength
,
1135 EFI_HANDLE ChildHandle
;
1138 ESL_SERVICE
** ppServiceListHead
;
1139 ESL_SOCKET
* pSocket
;
1140 ESL_SERVICE
* pService
;
1141 EFI_SERVICE_BINDING_PROTOCOL
* pServiceBinding
;
1143 EFI_TPL TplPrevious
;
1150 Status
= EFI_SUCCESS
;
1153 // Validate the socket
1156 if ( NULL
!= pSocketProtocol
) {
1157 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
1160 // Validate the structure pointer
1163 if ( NULL
== pSockAddr
) {
1164 DEBUG (( DEBUG_BIND
,
1165 "ERROR - pSockAddr is NULL!\r\n" ));
1166 Status
= EFI_INVALID_PARAMETER
;
1167 pSocket
->errno
= EFAULT
;
1171 // Validate the local address length
1173 else if ( SockAddrLength
< pSocket
->pApi
->MinimumAddressLength
) {
1174 DEBUG (( DEBUG_BIND
,
1175 "ERROR - Invalid bind name length: %d\r\n",
1177 Status
= EFI_INVALID_PARAMETER
;
1178 pSocket
->errno
= EINVAL
;
1182 // Validate the shutdown state
1184 else if ( pSocket
->bRxDisable
|| pSocket
->bTxDisable
) {
1185 DEBUG (( DEBUG_BIND
,
1186 "ERROR - Shutdown has been called on socket 0x%08x\r\n",
1188 pSocket
->errno
= EINVAL
;
1189 Status
= EFI_INVALID_PARAMETER
;
1193 // Verify the socket state
1195 else if ( SOCKET_STATE_NOT_CONFIGURED
!= pSocket
->State
) {
1196 DEBUG (( DEBUG_BIND
,
1197 "ERROR - The socket 0x%08x is already configured!\r\n",
1199 pSocket
->errno
= EINVAL
;
1200 Status
= EFI_ALREADY_STARTED
;
1204 // Synchronize with the socket layer
1206 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
1209 // Assume no ports are available
1211 pSocket
->errno
= EADDRNOTAVAIL
;
1212 Status
= EFI_INVALID_PARAMETER
;
1215 // Walk the list of services
1217 pBuffer
= (UINT8
*)&mEslLayer
;
1218 pBuffer
= &pBuffer
[ pSocket
->pApi
->ServiceListOffset
];
1219 ppServiceListHead
= (ESL_SERVICE
**)pBuffer
;
1220 pService
= *ppServiceListHead
;
1221 while ( NULL
!= pService
) {
1225 pServiceBinding
= pService
->pServiceBinding
;
1227 Status
= pServiceBinding
->CreateChild ( pServiceBinding
,
1229 if ( !EFI_ERROR ( Status
)) {
1230 DEBUG (( DEBUG_BIND
| DEBUG_POOL
,
1231 "0x%08x: %s port handle created\r\n",
1233 pService
->pSocketBinding
->pName
));
1238 Status
= EslSocketPortAllocate ( pSocket
,
1247 DEBUG (( DEBUG_BIND
| DEBUG_POOL
,
1248 "ERROR - Failed to open %s port handle, Status: %r\r\n",
1249 pService
->pSocketBinding
->pName
,
1254 // Set the next service
1256 pService
= pService
->pNext
;
1260 // Verify that at least one network connection was found
1262 if ( NULL
!= pSocket
->pPortList
) {
1263 Status
= EFI_SUCCESS
;
1266 if ( EADDRNOTAVAIL
== pSocket
->errno
) {
1267 DEBUG (( DEBUG_BIND
| DEBUG_POOL
| DEBUG_INIT
,
1268 "ERROR - Socket address is not available!\r\n" ));
1270 if ( EADDRINUSE
== pSocket
->errno
) {
1271 DEBUG (( DEBUG_BIND
| DEBUG_POOL
| DEBUG_INIT
,
1272 "ERROR - Socket address is in use!\r\n" ));
1274 Status
= EFI_INVALID_PARAMETER
;
1278 // Mark this socket as bound if successful
1280 if ( !EFI_ERROR ( Status
)) {
1281 pSocket
->State
= SOCKET_STATE_BOUND
;
1286 // Release the socket layer synchronization
1288 RESTORE_TPL ( TplPrevious
);
1293 // Return the operation status
1295 if ( NULL
!= pErrno
) {
1296 if ( NULL
!= pSocket
) {
1297 *pErrno
= pSocket
->errno
;
1300 Status
= EFI_INVALID_PARAMETER
;
1304 DBG_EXIT_STATUS ( Status
);
1310 Test the bind configuration.
1312 @param [in] pPort Address of the ::ESL_PORT structure.
1313 @param [in] ErrnoValue errno value if test fails
1315 @retval EFI_SUCCESS The connection was successfully established.
1316 @retval Others The connection attempt failed.
1321 IN ESL_PORT
* pPort
,
1332 // Locate the configuration data
1334 pBuffer
= (UINT8
*)pPort
;
1335 pBuffer
= &pBuffer
[ pPort
->pSocket
->pApi
->ConfigDataOffset
];
1336 pConfigData
= (VOID
*)pBuffer
;
1339 // Validate that the port is connected
1341 Status
= pPort
->pSocket
->pApi
->pfnVerifyLocalIpAddress ( pPort
, pBuffer
);
1342 if ( EFI_ERROR ( Status
)) {
1343 DEBUG (( DEBUG_WARN
| DEBUG_BIND
,
1344 "WARNING - Port 0x%08x invalid IP address: %r\r\n",
1347 pPort
->pSocket
->errno
= ErrnoValue
;
1351 // Attempt to use this configuration
1353 Status
= pPort
->pfnConfigure ( pPort
->pProtocol
.v
, pConfigData
);
1354 if ( EFI_ERROR ( Status
)) {
1355 DEBUG (( DEBUG_WARN
| DEBUG_BIND
,
1356 "WARNING - Port 0x%08x failed configuration, Status: %r\r\n",
1359 pPort
->pSocket
->errno
= ErrnoValue
;
1365 Status
= pPort
->pfnConfigure ( pPort
->pProtocol
.v
, NULL
);
1366 if ( EFI_ERROR ( Status
)) {
1367 DEBUG (( DEBUG_ERROR
| DEBUG_BIND
,
1368 "ERROR - Port 0x%08x failed configuration reset, Status: %r\r\n",
1371 ASSERT ( EFI_SUCCESS
== Status
);
1377 // Return the operation status
1379 DBG_EXIT_STATUS ( Status
);
1385 Determine if the socket is closed
1387 This routine checks the state of the socket to determine if
1388 the network specific layer has completed the close operation.
1390 The ::close routine polls this routine to determine when the
1391 close operation is complete. The close operation needs to
1392 reverse the operations of the ::EslSocketAllocate routine.
1394 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
1395 @param [out] pErrno Address to receive the errno value upon completion.
1397 @retval EFI_SUCCESS Socket successfully closed
1398 @retval EFI_NOT_READY Close still in progress
1399 @retval EFI_ALREADY Close operation already in progress
1400 @retval Other Failed to close the socket
1404 EslSocketClosePoll (
1405 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
1411 ESL_SOCKET
* pNextSocket
;
1412 ESL_SOCKET
* pSocket
;
1414 EFI_TPL TplPrevious
;
1422 Status
= EFI_SUCCESS
;
1425 // Synchronize with the socket layer
1427 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
1430 // Locate the socket
1432 pLayer
= &mEslLayer
;
1433 pNextSocket
= pLayer
->pSocketList
;
1434 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
1435 while ( NULL
!= pNextSocket
) {
1436 if ( pNextSocket
== pSocket
) {
1438 // Determine if the socket is in the closing state
1440 if ( SOCKET_STATE_CLOSED
== pSocket
->State
) {
1442 // Walk the list of ports
1444 if ( NULL
== pSocket
->pPortList
) {
1446 // All the ports are closed
1447 // Close the WaitAccept event if necessary
1449 if ( NULL
!= pSocket
->WaitAccept
) {
1450 Status
= gBS
->CloseEvent ( pSocket
->WaitAccept
);
1451 if ( !EFI_ERROR ( Status
)) {
1452 DEBUG (( DEBUG_SOCKET
| DEBUG_CLOSE
| DEBUG_POOL
,
1453 "0x%08x: Closed WaitAccept event\r\n",
1454 pSocket
->WaitAccept
));
1456 // Return the transmit status
1458 Status
= pSocket
->TxError
;
1459 if ( EFI_ERROR ( Status
)) {
1460 pSocket
->errno
= EIO
;
1464 DEBUG (( DEBUG_ERROR
| DEBUG_SOCKET
| DEBUG_CLOSE
| DEBUG_POOL
,
1465 "ERROR - Failed to close the WaitAccept event, Status: %r\r\n",
1467 ASSERT ( EFI_SUCCESS
== Status
);
1473 // At least one port is still open
1475 Status
= EFI_NOT_READY
;
1481 // SocketCloseStart was not called
1483 Status
= EFI_NOT_STARTED
;
1490 // Set the next socket
1492 pNextSocket
= pNextSocket
->pNext
;
1496 // Handle the error case where the socket was already closed
1498 if ( NULL
== pSocket
) {
1502 Status
= EFI_NOT_FOUND
;
1507 // Release the socket layer synchronization
1509 RESTORE_TPL ( TplPrevious
);
1512 // Return the operation status
1514 if ( NULL
!= pErrno
) {
1517 DBG_EXIT_STATUS ( Status
);
1523 Start the close operation on the socket
1525 This routine calls the network specific layer to initiate the
1526 close state machine. This routine then calls the network
1527 specific layer to determine if the close state machine has gone
1528 to completion. The result from this poll is returned to the
1531 The ::close routine calls this routine to start the close
1532 operation which reverses the operations of the
1533 ::EslSocketAllocate routine. The close routine then polls
1534 the ::EslSocketClosePoll routine to determine when the
1537 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
1538 @param [in] bCloseNow Boolean to control close behavior
1539 @param [out] pErrno Address to receive the errno value upon completion.
1541 @retval EFI_SUCCESS Socket successfully closed
1542 @retval EFI_NOT_READY Close still in progress
1543 @retval EFI_ALREADY Close operation already in progress
1544 @retval Other Failed to close the socket
1548 EslSocketCloseStart (
1549 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
1550 IN BOOLEAN bCloseNow
,
1555 ESL_PORT
* pNextPort
;
1557 ESL_SOCKET
* pSocket
;
1559 EFI_TPL TplPrevious
;
1566 Status
= EFI_SUCCESS
;
1570 // Synchronize with the socket layer
1572 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
1575 // Determine if the socket is already closed
1577 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
1578 if ( SOCKET_STATE_CLOSED
> pSocket
->State
) {
1580 // Update the socket state
1582 pSocket
->State
= SOCKET_STATE_CLOSED
;
1585 // Walk the list of ports
1587 pPort
= pSocket
->pPortList
;
1588 while ( NULL
!= pPort
) {
1590 // Start closing the ports
1592 pNextPort
= pPort
->pLinkSocket
;
1593 Status
= EslSocketPortCloseStart ( pPort
,
1595 DEBUG_CLOSE
| DEBUG_LISTEN
| DEBUG_CONNECTION
);
1596 if (( EFI_SUCCESS
!= Status
)
1597 && ( EFI_NOT_READY
!= Status
)) {
1603 // Set the next port
1609 // Attempt to finish closing the socket
1611 if ( NULL
== pPort
) {
1612 Status
= EslSocketClosePoll ( pSocketProtocol
, &errno
);
1616 Status
= EFI_NOT_READY
;
1621 // Release the socket layer synchronization
1623 RESTORE_TPL ( TplPrevious
);
1626 // Return the operation status
1628 if ( NULL
!= pErrno
) {
1631 DBG_EXIT_STATUS ( Status
);
1637 Connect to a remote system via the network.
1639 This routine calls the network specific layer to establish
1640 the remote system address and establish the connection to
1643 The ::connect routine calls this routine to establish a
1644 connection with the specified remote system. This routine
1645 is designed to be polled by the connect routine for completion
1646 of the network connection.
1648 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
1650 @param [in] pSockAddr Network address of the remote system.
1652 @param [in] SockAddrLength Length in bytes of the network address.
1654 @param [out] pErrno Address to receive the errno value upon completion.
1656 @retval EFI_SUCCESS The connection was successfully established.
1657 @retval EFI_NOT_READY The connection is in progress, call this routine again.
1658 @retval Others The connection attempt failed.
1663 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
1664 IN
const struct sockaddr
* pSockAddr
,
1665 IN socklen_t SockAddrLength
,
1669 struct sockaddr_in6 LocalAddress
;
1671 ESL_SOCKET
* pSocket
;
1673 EFI_TPL TplPrevious
;
1675 DEBUG (( DEBUG_CONNECT
, "Entering SocketConnect\r\n" ));
1680 Status
= EFI_SUCCESS
;
1683 // Validate the socket
1686 if ( NULL
!= pSocketProtocol
) {
1687 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
1690 // Validate the name length
1692 if ( SockAddrLength
< ( sizeof ( struct sockaddr
) - sizeof ( pSockAddr
->sa_data
))) {
1693 DEBUG (( DEBUG_CONNECT
,
1694 "ERROR - Invalid bind name length: %d\r\n",
1696 Status
= EFI_INVALID_PARAMETER
;
1697 pSocket
->errno
= EINVAL
;
1706 // Synchronize with the socket layer
1708 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
1711 // Validate the socket state
1713 switch ( pSocket
->State
) {
1716 // Wrong socket state
1718 pSocket
->errno
= EIO
;
1719 Status
= EFI_DEVICE_ERROR
;
1722 case SOCKET_STATE_NOT_CONFIGURED
:
1723 case SOCKET_STATE_BOUND
:
1725 // Validate the address length
1727 if ( SockAddrLength
>= pSocket
->pApi
->MinimumAddressLength
) {
1731 if ( NULL
== pSocket
->pApi
->pfnRemoteAddrSet
) {
1733 // Already connected
1735 pSocket
->errno
= ENOTSUP
;
1736 Status
= EFI_UNSUPPORTED
;
1740 // Determine if BIND was already called
1742 if ( NULL
== pSocket
->pPortList
) {
1744 // Allow any local port
1746 ZeroMem ( &LocalAddress
, sizeof ( LocalAddress
));
1747 LocalAddress
.sin6_len
= (uint8_t)pSocket
->pApi
->MinimumAddressLength
;
1748 LocalAddress
.sin6_family
= pSocket
->pApi
->AddressFamily
;
1749 Status
= EslSocketBind ( &pSocket
->SocketProtocol
,
1750 (struct sockaddr
*)&LocalAddress
,
1751 LocalAddress
.sin6_len
,
1754 if ( NULL
!= pSocket
->pPortList
) {
1756 // Walk the list of ports
1758 pPort
= pSocket
->pPortList
;
1759 while ( NULL
!= pPort
) {
1761 // Set the remote address
1763 Status
= pSocket
->pApi
->pfnRemoteAddrSet ( pPort
,
1766 if ( EFI_ERROR ( Status
)) {
1771 // Set the next port
1773 pPort
= pPort
->pLinkSocket
;
1779 if (( !EFI_ERROR ( Status
))
1780 && ( NULL
!= pSocket
->pApi
->pfnConnectStart
)) {
1782 // Initiate the connection with the remote system
1784 Status
= pSocket
->pApi
->pfnConnectStart ( pSocket
);
1787 // Set the next state if connecting
1789 if ( EFI_NOT_READY
== Status
) {
1790 pSocket
->State
= SOCKET_STATE_CONNECTING
;
1797 DEBUG (( DEBUG_CONNECT
,
1798 "ERROR - Invalid address length: %d\r\n",
1800 Status
= EFI_INVALID_PARAMETER
;
1801 pSocket
->errno
= EINVAL
;
1805 case SOCKET_STATE_CONNECTING
:
1807 // Poll the network adapter
1809 EslSocketRxPoll ( pSocket
);
1812 // Poll for connection completion
1814 if ( NULL
== pSocket
->pApi
->pfnConnectPoll
) {
1816 // Already connected
1818 pSocket
->errno
= EISCONN
;
1819 Status
= EFI_ALREADY_STARTED
;
1822 Status
= pSocket
->pApi
->pfnConnectPoll ( pSocket
);
1825 // Set the next state if connected
1827 if ( EFI_NOT_READY
!= Status
) {
1828 if ( !EFI_ERROR ( Status
)) {
1829 pSocket
->State
= SOCKET_STATE_CONNECTED
;
1832 // Start the receive operations
1834 EslSocketRxStart ( pSocket
->pPortList
);
1837 pSocket
->State
= SOCKET_STATE_BOUND
;
1843 case SOCKET_STATE_CONNECTED
:
1845 // Already connected
1847 pSocket
->errno
= EISCONN
;
1848 Status
= EFI_ALREADY_STARTED
;
1853 // Release the socket layer synchronization
1855 RESTORE_TPL ( TplPrevious
);
1860 // Return the operation status
1862 if ( NULL
!= pErrno
) {
1863 if ( NULL
!= pSocket
) {
1864 *pErrno
= pSocket
->errno
;
1868 // Bad socket protocol
1870 DEBUG (( DEBUG_ERROR
| DEBUG_CONNECT
,
1871 "ERROR - pSocketProtocol invalid!\r\n" ));
1872 Status
= EFI_INVALID_PARAMETER
;
1878 // Return the operation status
1880 DEBUG (( DEBUG_CONNECT
, "Exiting SocketConnect, Status: %r\r\n", Status
));
1886 Copy a fragmented buffer into a destination buffer.
1888 This support routine copies a fragmented buffer to the caller specified buffer.
1890 This routine is called by ::EslIp4Receive and ::EslUdp4Receive.
1892 @param [in] FragmentCount Number of fragments in the table
1894 @param [in] pFragmentTable Address of an EFI_IP4_FRAGMENT_DATA structure
1896 @param [in] BufferLength Length of the the buffer
1898 @param [in] pBuffer Address of a buffer to receive the data.
1900 @param [in] pDataLength Number of received data bytes in the buffer.
1902 @return Returns the address of the next free byte in the buffer.
1906 EslSocketCopyFragmentedBuffer (
1907 IN UINT32 FragmentCount
,
1908 IN EFI_IP4_FRAGMENT_DATA
* pFragmentTable
,
1909 IN
size_t BufferLength
,
1911 OUT
size_t * pDataLength
1922 // Validate the IP and UDP structures are identical
1924 ASSERT ( OFFSET_OF ( EFI_IP4_FRAGMENT_DATA
, FragmentLength
)
1925 == OFFSET_OF ( EFI_UDP4_FRAGMENT_DATA
, FragmentLength
));
1926 ASSERT ( OFFSET_OF ( EFI_IP4_FRAGMENT_DATA
, FragmentBuffer
)
1927 == OFFSET_OF ( EFI_UDP4_FRAGMENT_DATA
, FragmentBuffer
));
1930 // Copy the received data
1933 pBufferEnd
= &pBuffer
[ BufferLength
];
1934 while (( pBufferEnd
> pBuffer
) && ( FragmentCount
> Fragment
)) {
1936 // Determine the amount of received data
1938 pData
= pFragmentTable
[Fragment
].FragmentBuffer
;
1939 BytesToCopy
= pFragmentTable
[Fragment
].FragmentLength
;
1940 if (((size_t)( pBufferEnd
- pBuffer
)) < BytesToCopy
) {
1941 BytesToCopy
= pBufferEnd
- pBuffer
;
1945 // Move the data into the buffer
1948 "0x%08x --> 0x%08x: Copy data 0x%08x bytes\r\n",
1952 CopyMem ( pBuffer
, pData
, BytesToCopy
);
1953 pBuffer
+= BytesToCopy
;
1958 // Return the data length and the buffer address
1960 *pDataLength
= BufferLength
- ( pBufferEnd
- pBuffer
);
1961 DBG_EXIT_HEX ( pBuffer
);
1969 This routine frees the socket structure and handle resources.
1971 The ::close routine calls EslServiceFreeProtocol which then calls
1972 this routine to free the socket context structure and close the
1975 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
1977 @param [out] pErrno Address to receive the errno value upon completion.
1979 @retval EFI_SUCCESS The socket resources were returned successfully.
1984 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
1988 EFI_HANDLE ChildHandle
;
1991 ESL_SOCKET
* pSocket
;
1992 ESL_SOCKET
* pSocketPrevious
;
1994 EFI_TPL TplPrevious
;
2003 Status
= EFI_INVALID_PARAMETER
;
2006 // Validate the socket
2008 pLayer
= &mEslLayer
;
2009 if ( NULL
!= pSocketProtocol
) {
2010 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
2013 // Synchronize with the socket layer
2015 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
2018 // Walk the socket list
2020 pSocketPrevious
= pLayer
->pSocketList
;
2021 if ( NULL
!= pSocketPrevious
) {
2022 if ( pSocket
== pSocketPrevious
) {
2024 // Remove the socket from the head of the list
2026 pLayer
->pSocketList
= pSocket
->pNext
;
2030 // Find the socket in the middle of the list
2032 while (( NULL
!= pSocketPrevious
)
2033 && ( pSocket
!= pSocketPrevious
->pNext
)) {
2035 // Set the next socket
2037 pSocketPrevious
= pSocketPrevious
->pNext
;
2039 if ( NULL
!= pSocketPrevious
) {
2041 // Remove the socket from the middle of the list
2043 pSocketPrevious
= pSocket
->pNext
;
2048 DEBUG (( DEBUG_ERROR
| DEBUG_POOL
,
2049 "ERROR - Socket list is empty!\r\n" ));
2053 // Release the socket layer synchronization
2055 RESTORE_TPL ( TplPrevious
);
2058 // Determine if the socket was found
2060 if ( NULL
!= pSocketPrevious
) {
2061 pSocket
->pNext
= NULL
;
2064 // Remove the socket protocol
2066 ChildHandle
= pSocket
->SocketProtocol
.SocketHandle
;
2067 Status
= gBS
->UninstallMultipleProtocolInterfaces (
2069 &gEfiSocketProtocolGuid
,
2070 &pSocket
->SocketProtocol
,
2072 if ( !EFI_ERROR ( Status
)) {
2073 DEBUG (( DEBUG_POOL
| DEBUG_INFO
,
2074 "Removed: gEfiSocketProtocolGuid from 0x%08x\r\n",
2078 // Free the socket structure
2080 Status
= gBS
->FreePool ( pSocket
);
2081 if ( !EFI_ERROR ( Status
)) {
2082 DEBUG (( DEBUG_POOL
,
2083 "0x%08x: Free pSocket, %d bytes\r\n",
2085 sizeof ( *pSocket
)));
2089 DEBUG (( DEBUG_ERROR
| DEBUG_POOL
,
2090 "ERROR - Failed to free pSocket 0x%08x, Status: %r\r\n",
2096 DEBUG (( DEBUG_ERROR
| DEBUG_POOL
| DEBUG_INFO
,
2097 "ERROR - Failed to remove gEfiSocketProtocolGuid from 0x%08x, Status: %r\r\n",
2103 DEBUG (( DEBUG_ERROR
| DEBUG_INFO
,
2104 "ERROR - The socket was not in the socket list!\r\n" ));
2105 Status
= EFI_NOT_FOUND
;
2109 DEBUG (( DEBUG_ERROR
,
2110 "ERROR - Invalid parameter pSocketProtocol is NULL\r\n" ));
2114 // Return the errno value if possible
2116 if ( NULL
!= pErrno
) {
2121 // Return the operation status
2123 DBG_EXIT_STATUS ( Status
);
2129 Get the local address.
2131 This routine calls the network specific layer to get the network
2132 address of the local host connection point.
2134 The ::getsockname routine calls this routine to obtain the network
2135 address associated with the local host connection point.
2137 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
2139 @param [out] pAddress Network address to receive the local system address
2141 @param [in,out] pAddressLength Length of the local network address structure
2143 @param [out] pErrno Address to receive the errno value upon completion.
2145 @retval EFI_SUCCESS - Local address successfully returned
2149 EslSocketGetLocalAddress (
2150 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
2151 OUT
struct sockaddr
* pAddress
,
2152 IN OUT socklen_t
* pAddressLength
,
2156 socklen_t LengthInBytes
;
2158 ESL_SOCKET
* pSocket
;
2160 EFI_TPL TplPrevious
;
2167 Status
= EFI_SUCCESS
;
2170 // Validate the socket
2173 if ( NULL
!= pSocketProtocol
) {
2174 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
2177 // Verify the socket state
2179 EslSocketIsConfigured ( pSocket
);
2180 if ( pSocket
->bAddressSet
) {
2182 // Verify the address buffer and length address
2184 if (( NULL
!= pAddress
) && ( NULL
!= pAddressLength
)) {
2188 if ( NULL
== pSocket
->pApi
->pfnLocalAddrGet
) {
2189 Status
= EFI_UNSUPPORTED
;
2190 pSocket
->errno
= ENOTSUP
;
2194 // Synchronize with the socket layer
2196 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
2199 // Verify that there is just a single connection
2201 pPort
= pSocket
->pPortList
;
2202 if ( NULL
!= pPort
) {
2204 // Verify the address length
2206 LengthInBytes
= pSocket
->pApi
->AddressLength
;
2207 if (( LengthInBytes
<= *pAddressLength
)
2208 && ( 255 >= LengthInBytes
)) {
2210 // Return the local address and address length
2212 ZeroMem ( pAddress
, LengthInBytes
);
2213 pAddress
->sa_len
= (uint8_t)LengthInBytes
;
2214 *pAddressLength
= pAddress
->sa_len
;
2215 pSocket
->pApi
->pfnLocalAddrGet ( pPort
, pAddress
);
2217 Status
= EFI_SUCCESS
;
2220 pSocket
->errno
= EINVAL
;
2221 Status
= EFI_INVALID_PARAMETER
;
2225 pSocket
->errno
= ENOTCONN
;
2226 Status
= EFI_NOT_STARTED
;
2230 // Release the socket layer synchronization
2232 RESTORE_TPL ( TplPrevious
);
2236 pSocket
->errno
= EINVAL
;
2237 Status
= EFI_INVALID_PARAMETER
;
2244 Status
= EFI_NOT_STARTED
;
2245 pSocket
->errno
= EADDRNOTAVAIL
;
2250 // Return the operation status
2252 if ( NULL
!= pErrno
) {
2253 if ( NULL
!= pSocket
) {
2254 *pErrno
= pSocket
->errno
;
2257 Status
= EFI_INVALID_PARAMETER
;
2261 DBG_EXIT_STATUS ( Status
);
2267 Get the peer address.
2269 This routine calls the network specific layer to get the remote
2270 system connection point.
2272 The ::getpeername routine calls this routine to obtain the network
2273 address of the remote connection point.
2275 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
2277 @param [out] pAddress Network address to receive the remote system address
2279 @param [in,out] pAddressLength Length of the remote network address structure
2281 @param [out] pErrno Address to receive the errno value upon completion.
2283 @retval EFI_SUCCESS - Remote address successfully returned
2287 EslSocketGetPeerAddress (
2288 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
2289 OUT
struct sockaddr
* pAddress
,
2290 IN OUT socklen_t
* pAddressLength
,
2294 socklen_t LengthInBytes
;
2296 ESL_SOCKET
* pSocket
;
2298 EFI_TPL TplPrevious
;
2305 Status
= EFI_SUCCESS
;
2308 // Validate the socket
2311 if ( NULL
!= pSocketProtocol
) {
2312 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
2315 // Verify the socket state
2317 Status
= EslSocketIsConfigured ( pSocket
);
2318 if ( !EFI_ERROR ( Status
)) {
2322 if ( NULL
== pSocket
->pApi
->pfnRemoteAddrGet
) {
2323 Status
= EFI_UNSUPPORTED
;
2324 pSocket
->errno
= ENOTSUP
;
2328 // Verify the address buffer and length address
2330 if (( NULL
!= pAddress
) && ( NULL
!= pAddressLength
)) {
2332 // Verify the socket state
2334 if ( SOCKET_STATE_CONNECTED
== pSocket
->State
) {
2336 // Synchronize with the socket layer
2338 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
2341 // Verify that there is just a single connection
2343 pPort
= pSocket
->pPortList
;
2344 if (( NULL
!= pPort
) && ( NULL
== pPort
->pLinkSocket
)) {
2346 // Verify the address length
2348 LengthInBytes
= pSocket
->pApi
->AddressLength
;
2349 if ( LengthInBytes
<= *pAddressLength
) {
2351 // Return the local address
2353 ZeroMem ( pAddress
, LengthInBytes
);
2354 pAddress
->sa_len
= (uint8_t)LengthInBytes
;
2355 *pAddressLength
= pAddress
->sa_len
;
2356 pSocket
->pApi
->pfnRemoteAddrGet ( pPort
, pAddress
);
2358 Status
= EFI_SUCCESS
;
2361 pSocket
->errno
= EINVAL
;
2362 Status
= EFI_INVALID_PARAMETER
;
2366 pSocket
->errno
= ENOTCONN
;
2367 Status
= EFI_NOT_STARTED
;
2371 // Release the socket layer synchronization
2373 RESTORE_TPL ( TplPrevious
);
2376 pSocket
->errno
= ENOTCONN
;
2377 Status
= EFI_NOT_STARTED
;
2381 pSocket
->errno
= EINVAL
;
2382 Status
= EFI_INVALID_PARAMETER
;
2389 // Return the operation status
2391 if ( NULL
!= pErrno
) {
2392 if ( NULL
!= pSocket
) {
2393 *pErrno
= pSocket
->errno
;
2396 Status
= EFI_INVALID_PARAMETER
;
2400 DBG_EXIT_STATUS ( Status
);
2406 Free the ESL_IO_MGMT event and structure
2408 This support routine walks the free list to close the event in
2409 the ESL_IO_MGMT structure and remove the structure from the free
2412 See the \ref TransmitEngine section.
2414 @param [in] pPort Address of an ::ESL_PORT structure
2415 @param [in] ppFreeQueue Address of the free queue head
2416 @param [in] DebugFlags Flags for debug messages
2417 @param [in] pEventName Zero terminated string containing the event name
2419 @retval EFI_SUCCESS - The structures were properly initialized
2424 IN ESL_PORT
* pPort
,
2425 IN ESL_IO_MGMT
** ppFreeQueue
,
2426 IN UINTN DebugFlags
,
2427 IN CHAR8
* pEventName
2433 ESL_SOCKET
* pSocket
;
2441 Status
= EFI_SUCCESS
;
2444 // Walk the list of IO structures
2446 pSocket
= pPort
->pSocket
;
2447 while ( *ppFreeQueue
) {
2449 // Free the event for this structure
2452 pBuffer
= (UINT8
*)pIo
;
2453 pBuffer
= &pBuffer
[ pSocket
->TxTokenEventOffset
];
2454 pEvent
= (EFI_EVENT
*)pBuffer
;
2455 Status
= gBS
->CloseEvent ( *pEvent
);
2456 if ( EFI_ERROR ( Status
)) {
2457 DEBUG (( DEBUG_ERROR
| DebugFlags
,
2458 "ERROR - Failed to close the %a event, Status: %r\r\n",
2461 pSocket
->errno
= ENOMEM
;
2464 DEBUG (( DebugFlags
,
2465 "0x%08x: Closed %a event 0x%08x\r\n",
2471 // Remove this structure from the queue
2473 *ppFreeQueue
= pIo
->pNext
;
2477 // Return the operation status
2479 DBG_EXIT_STATUS ( Status
);
2485 Initialize the ESL_IO_MGMT structures
2487 This support routine initializes the ESL_IO_MGMT structure and
2488 places them on to a free list.
2490 This routine is called by ::EslSocketPortAllocate routines to prepare
2491 the transmit engines. See the \ref TransmitEngine section.
2493 @param [in] pPort Address of an ::ESL_PORT structure
2494 @param [in, out] ppIo Address containing the first structure address. Upon
2495 return this buffer contains the next structure address.
2496 @param [in] TokenCount Number of structures to initialize
2497 @param [in] ppFreeQueue Address of the free queue head
2498 @param [in] DebugFlags Flags for debug messages
2499 @param [in] pEventName Zero terminated string containing the event name
2500 @param [in] pfnCompletion Completion routine address
2502 @retval EFI_SUCCESS - The structures were properly initialized
2507 IN ESL_PORT
* pPort
,
2508 IN ESL_IO_MGMT
** ppIo
,
2509 IN UINTN TokenCount
,
2510 IN ESL_IO_MGMT
** ppFreeQueue
,
2511 IN UINTN DebugFlags
,
2512 IN CHAR8
* pEventName
,
2513 IN PFN_API_IO_COMPLETE pfnCompletion
2519 ESL_SOCKET
* pSocket
;
2527 Status
= EFI_SUCCESS
;
2530 // Walk the list of IO structures
2532 pSocket
= pPort
->pSocket
;
2534 pEnd
= &pIo
[ TokenCount
];
2535 while ( pEnd
> pIo
) {
2537 // Initialize the IO structure
2540 pIo
->pPacket
= NULL
;
2543 // Allocate the event for this structure
2545 pEvent
= (EFI_EVENT
*)&(((UINT8
*)pIo
)[ pSocket
->TxTokenEventOffset
]);
2546 Status
= gBS
->CreateEvent ( EVT_NOTIFY_SIGNAL
,
2548 (EFI_EVENT_NOTIFY
)pfnCompletion
,
2551 if ( EFI_ERROR ( Status
)) {
2552 DEBUG (( DEBUG_ERROR
| DebugFlags
,
2553 "ERROR - Failed to create the %a event, Status: %r\r\n",
2556 pSocket
->errno
= ENOMEM
;
2559 DEBUG (( DebugFlags
,
2560 "0x%08x: Created %a event 0x%08x\r\n",
2566 // Add this structure to the queue
2568 pIo
->pNext
= *ppFreeQueue
;
2572 // Set the next structure
2578 // Save the next structure
2583 // Return the operation status
2585 DBG_EXIT_STATUS ( Status
);
2591 Determine if the socket is configured
2593 This support routine is called to determine if the socket if the
2594 configuration call was made to the network layer. The following
2595 routines call this routine to verify that they may be successful
2596 in their operations:
2598 <li>::EslSocketGetLocalAddress</li>
2599 <li>::EslSocketGetPeerAddress</li>
2600 <li>::EslSocketPoll</li>
2601 <li>::EslSocketReceive</li>
2602 <li>::EslSocketTransmit</li>
2605 @param [in] pSocket Address of an ::ESL_SOCKET structure
2607 @retval EFI_SUCCESS - The socket is configured
2611 EslSocketIsConfigured (
2612 IN ESL_SOCKET
* pSocket
2616 EFI_TPL TplPrevious
;
2621 Status
= EFI_SUCCESS
;
2624 // Verify the socket state
2626 if ( !pSocket
->bConfigured
) {
2632 if ( NULL
== pSocket
->pApi
->pfnIsConfigured
) {
2633 Status
= EFI_UNSUPPORTED
;
2634 pSocket
->errno
= ENOTSUP
;
2638 // Synchronize with the socket layer
2640 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
2643 // Determine if the socket is configured
2645 Status
= pSocket
->pApi
->pfnIsConfigured ( pSocket
);
2648 // Release the socket layer synchronization
2650 RESTORE_TPL ( TplPrevious
);
2653 // Set errno if a failure occurs
2655 if ( EFI_ERROR ( Status
)) {
2656 pSocket
->errno
= EADDRNOTAVAIL
;
2660 DBG_EXIT_STATUS ( Status
);
2664 // Return the configuration status
2671 Establish the known port to listen for network connections.
2673 This routine calls into the network protocol layer to establish
2674 a handler that is called upon connection completion. The handler
2675 is responsible for inserting the connection into the FIFO.
2677 The ::listen routine indirectly calls this routine to place the
2678 socket into a state that enables connection attempts. Connections
2679 are placed in a FIFO that is serviced by the application. The
2680 application calls the ::accept (::EslSocketAccept) routine to
2681 remove the next connection from the FIFO and get the associated
2684 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
2686 @param [in] Backlog Backlog specifies the maximum FIFO depth for
2687 the connections waiting for the application
2688 to call accept. Connection attempts received
2689 while the queue is full are refused.
2691 @param [out] pErrno Address to receive the errno value upon completion.
2693 @retval EFI_SUCCESS - Socket successfully created
2694 @retval Other - Failed to enable the socket for listen
2699 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
2704 ESL_SOCKET
* pSocket
;
2706 EFI_STATUS TempStatus
;
2707 EFI_TPL TplPrevious
;
2714 Status
= EFI_SUCCESS
;
2717 // Validate the socket
2720 if ( NULL
!= pSocketProtocol
) {
2721 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
2726 if ( NULL
== pSocket
->pApi
->pfnListen
) {
2727 Status
= EFI_UNSUPPORTED
;
2728 pSocket
->errno
= ENOTSUP
;
2734 pSocket
->Status
= EFI_SUCCESS
;
2738 // Verify that the bind operation was successful
2740 if ( SOCKET_STATE_BOUND
== pSocket
->State
) {
2742 // Synchronize with the socket layer
2744 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
2747 // Create the event for SocketAccept completion
2749 Status
= gBS
->CreateEvent ( 0,
2753 &pSocket
->WaitAccept
);
2754 if ( !EFI_ERROR ( Status
)) {
2755 DEBUG (( DEBUG_POOL
,
2756 "0x%08x: Created WaitAccept event\r\n",
2757 pSocket
->WaitAccept
));
2759 // Set the maximum FIFO depth
2761 if ( 0 >= Backlog
) {
2762 Backlog
= MAX_PENDING_CONNECTIONS
;
2765 if ( SOMAXCONN
< Backlog
) {
2766 Backlog
= SOMAXCONN
;
2769 pSocket
->MaxFifoDepth
= Backlog
;
2774 // Initiate the connection attempt listen
2776 Status
= pSocket
->pApi
->pfnListen ( pSocket
);
2779 // Place the socket in the listen state if successful
2781 if ( !EFI_ERROR ( Status
)) {
2782 pSocket
->State
= SOCKET_STATE_LISTENING
;
2783 pSocket
->bListenCalled
= TRUE
;
2787 // Not waiting for SocketAccept to complete
2789 TempStatus
= gBS
->CloseEvent ( pSocket
->WaitAccept
);
2790 if ( !EFI_ERROR ( TempStatus
)) {
2791 DEBUG (( DEBUG_POOL
,
2792 "0x%08x: Closed WaitAccept event\r\n",
2793 pSocket
->WaitAccept
));
2794 pSocket
->WaitAccept
= NULL
;
2797 DEBUG (( DEBUG_ERROR
| DEBUG_POOL
,
2798 "ERROR - Failed to close WaitAccept event, Status: %r\r\n",
2800 ASSERT ( EFI_SUCCESS
== TempStatus
);
2805 DEBUG (( DEBUG_ERROR
| DEBUG_LISTEN
,
2806 "ERROR - Failed to create the WaitAccept event, Status: %r\r\n",
2808 pSocket
->errno
= ENOMEM
;
2812 // Release the socket layer synchronization
2814 RESTORE_TPL ( TplPrevious
);
2817 DEBUG (( DEBUG_ERROR
| DEBUG_LISTEN
,
2818 "ERROR - Bind operation must be performed first!\r\n" ));
2819 pSocket
->errno
= ( SOCKET_STATE_NOT_CONFIGURED
== pSocket
->State
) ? EDESTADDRREQ
2821 Status
= EFI_NO_MAPPING
;
2827 // Return the operation status
2829 if ( NULL
!= pErrno
) {
2830 if ( NULL
!= pSocket
) {
2831 *pErrno
= pSocket
->errno
;
2834 Status
= EFI_INVALID_PARAMETER
;
2838 DBG_EXIT_STATUS ( Status
);
2844 Get the socket options
2846 This routine handles the socket level options and passes the
2847 others to the network specific layer.
2849 The ::getsockopt routine calls this routine to retrieve the
2850 socket options one at a time by name.
2852 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
2853 @param [in] level Option protocol level
2854 @param [in] OptionName Name of the option
2855 @param [out] pOptionValue Buffer to receive the option value
2856 @param [in,out] pOptionLength Length of the buffer in bytes,
2857 upon return length of the option value in bytes
2858 @param [out] pErrno Address to receive the errno value upon completion.
2860 @retval EFI_SUCCESS - Socket data successfully received
2864 EslSocketOptionGet (
2865 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
2868 OUT
void * __restrict pOptionValue
,
2869 IN OUT socklen_t
* __restrict pOptionLength
,
2874 socklen_t LengthInBytes
;
2876 CONST UINT8
* pOptionData
;
2877 ESL_SOCKET
* pSocket
;
2886 Status
= EFI_INVALID_PARAMETER
;
2889 // Validate the socket
2892 if ( NULL
== pSocketProtocol
) {
2893 DEBUG (( DEBUG_OPTION
, "ERROR - pSocketProtocol is NULL!\r\n" ));
2895 else if ( NULL
== pOptionValue
) {
2896 DEBUG (( DEBUG_OPTION
, "ERROR - No option buffer specified\r\n" ));
2898 else if ( NULL
== pOptionLength
) {
2899 DEBUG (( DEBUG_OPTION
, "ERROR - Option length not specified!\r\n" ));
2902 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
2904 MaxBytes
= *pOptionLength
;
2909 // See if the protocol will handle the option
2911 if ( NULL
!= pSocket
->pApi
->pfnOptionGet
) {
2912 if ( pSocket
->pApi
->DefaultProtocol
== level
) {
2913 Status
= pSocket
->pApi
->pfnOptionGet ( pSocket
,
2915 (CONST
void ** __restrict
)&pOptionData
,
2917 errno
= pSocket
->errno
;
2922 // Protocol not supported
2924 DEBUG (( DEBUG_OPTION
,
2925 "ERROR - The socket does not support this protocol!\r\n" ));
2930 // Protocol level not supported
2932 DEBUG (( DEBUG_OPTION
,
2933 "ERROR - %a does not support any options!\r\n",
2934 pSocket
->pApi
->pName
));
2936 errno
= ENOPROTOOPT
;
2937 Status
= EFI_INVALID_PARAMETER
;
2941 switch ( OptionName
) {
2944 // Socket option not supported
2946 DEBUG (( DEBUG_INFO
| DEBUG_OPTION
, "ERROR - Invalid socket option!\r\n" ));
2948 Status
= EFI_INVALID_PARAMETER
;
2953 // Return the listen flag
2955 pOptionData
= (CONST UINT8
*)&pSocket
->bListenCalled
;
2956 LengthInBytes
= sizeof ( pSocket
->bListenCalled
);
2961 // Return the debug flags
2963 pOptionData
= (CONST UINT8
*)&pSocket
->bOobInLine
;
2964 LengthInBytes
= sizeof ( pSocket
->bOobInLine
);
2969 // Return the out-of-band inline flag
2971 pOptionData
= (CONST UINT8
*)&pSocket
->bOobInLine
;
2972 LengthInBytes
= sizeof ( pSocket
->bOobInLine
);
2977 // Return the receive timeout
2979 pOptionData
= (CONST UINT8
*)&pSocket
->RxTimeout
;
2980 LengthInBytes
= sizeof ( pSocket
->RxTimeout
);
2985 // Return the maximum receive buffer size
2987 pOptionData
= (CONST UINT8
*)&pSocket
->MaxRxBuf
;
2988 LengthInBytes
= sizeof ( pSocket
->MaxRxBuf
);
2993 // Return the address reuse flag
2995 pOptionData
= (UINT8
*)&pSocket
->bReUseAddr
;
2996 LengthInBytes
= sizeof ( pSocket
->bReUseAddr
);
3001 // Return the maximum transmit buffer size
3003 pOptionData
= (CONST UINT8
*)&pSocket
->MaxTxBuf
;
3004 LengthInBytes
= sizeof ( pSocket
->MaxTxBuf
);
3009 // Return the socket type
3011 pOptionData
= (CONST UINT8
*)&pSocket
->Type
;
3012 LengthInBytes
= sizeof ( pSocket
->Type
);
3019 // Return the option length
3021 *pOptionLength
= LengthInBytes
;
3024 // Determine if the option is present
3026 if ( 0 != LengthInBytes
) {
3028 // Silently truncate the value length
3030 if ( LengthInBytes
> MaxBytes
) {
3031 DEBUG (( DEBUG_OPTION
,
3032 "INFO - Truncating option from %d to %d bytes\r\n",
3035 LengthInBytes
= MaxBytes
;
3041 CopyMem ( pOptionValue
, pOptionData
, LengthInBytes
);
3044 // Zero fill any remaining space
3046 if ( LengthInBytes
< MaxBytes
) {
3047 ZeroMem ( &((UINT8
*)pOptionValue
)[LengthInBytes
], MaxBytes
- LengthInBytes
);
3050 Status
= EFI_SUCCESS
;
3055 // Return the operation status
3057 if ( NULL
!= pErrno
) {
3060 DBG_EXIT_STATUS ( Status
);
3066 Set the socket options
3068 This routine handles the socket level options and passes the
3069 others to the network specific layer.
3071 The ::setsockopt routine calls this routine to adjust the socket
3072 options one at a time by name.
3074 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
3075 @param [in] level Option protocol level
3076 @param [in] OptionName Name of the option
3077 @param [in] pOptionValue Buffer containing the option value
3078 @param [in] OptionLength Length of the buffer in bytes
3079 @param [out] pErrno Address to receive the errno value upon completion.
3081 @retval EFI_SUCCESS - Option successfully set
3085 EslSocketOptionSet (
3086 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
3089 IN CONST
void * pOptionValue
,
3090 IN socklen_t OptionLength
,
3096 socklen_t LengthInBytes
;
3097 UINT8
* pOptionData
;
3098 ESL_SOCKET
* pSocket
;
3107 Status
= EFI_INVALID_PARAMETER
;
3110 // Validate the socket
3113 if ( NULL
== pSocketProtocol
) {
3114 DEBUG (( DEBUG_OPTION
, "ERROR - pSocketProtocol is NULL!\r\n" ));
3116 else if ( NULL
== pOptionValue
) {
3117 DEBUG (( DEBUG_OPTION
, "ERROR - No option buffer specified\r\n" ));
3121 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
3122 if ( pSocket
->bRxDisable
|| pSocket
->bTxDisable
) {
3123 DEBUG (( DEBUG_OPTION
, "ERROR - Socket has been shutdown!\r\n" ));
3131 // See if the protocol will handle the option
3133 if ( NULL
!= pSocket
->pApi
->pfnOptionSet
) {
3134 if ( pSocket
->pApi
->DefaultProtocol
== level
) {
3135 Status
= pSocket
->pApi
->pfnOptionSet ( pSocket
,
3139 errno
= pSocket
->errno
;
3144 // Protocol not supported
3146 DEBUG (( DEBUG_OPTION
,
3147 "ERROR - The socket does not support this protocol!\r\n" ));
3152 // Protocol level not supported
3154 DEBUG (( DEBUG_OPTION
,
3155 "ERROR - %a does not support any options!\r\n",
3156 pSocket
->pApi
->pName
));
3158 errno
= ENOPROTOOPT
;
3159 Status
= EFI_INVALID_PARAMETER
;
3163 switch ( OptionName
) {
3166 // Option not supported
3168 DEBUG (( DEBUG_OPTION
,
3169 "ERROR - Sockets does not support this option!\r\n" ));
3171 Status
= EFI_INVALID_PARAMETER
;
3176 // Set the debug flags
3178 pOptionData
= (UINT8
*)&pSocket
->bOobInLine
;
3179 LengthInBytes
= sizeof ( pSocket
->bOobInLine
);
3183 pOptionData
= (UINT8
*)&pSocket
->bOobInLine
;
3184 LengthInBytes
= sizeof ( pSocket
->bOobInLine
);
3187 // Validate the option length
3189 if ( sizeof ( UINT32
) == OptionLength
) {
3191 // Restrict the input to TRUE or FALSE
3194 if ( 0 == *(UINT32
*)pOptionValue
) {
3197 pOptionValue
= &bTrueFalse
;
3201 // Force an invalid option length error
3203 OptionLength
= LengthInBytes
- 1;
3209 // Return the receive timeout
3211 pOptionData
= (UINT8
*)&pSocket
->RxTimeout
;
3212 LengthInBytes
= sizeof ( pSocket
->RxTimeout
);
3217 // Return the maximum receive buffer size
3219 pOptionData
= (UINT8
*)&pSocket
->MaxRxBuf
;
3220 LengthInBytes
= sizeof ( pSocket
->MaxRxBuf
);
3225 // Return the address reuse flag
3227 pOptionData
= (UINT8
*)&pSocket
->bReUseAddr
;
3228 LengthInBytes
= sizeof ( pSocket
->bReUseAddr
);
3236 // Return the maximum transmit buffer size
3238 pOptionData
= (UINT8
*)&pSocket
->MaxTxBuf
;
3239 LengthInBytes
= sizeof ( pSocket
->MaxTxBuf
);
3246 // Determine if an option was found
3248 if ( 0 != LengthInBytes
) {
3250 // Validate the option length
3252 if ( LengthInBytes
<= OptionLength
) {
3254 // Set the option value
3256 CopyMem ( pOptionData
, pOptionValue
, LengthInBytes
);
3258 Status
= EFI_SUCCESS
;
3261 DEBUG (( DEBUG_OPTION
,
3262 "ERROR - Buffer to small, %d bytes < %d bytes!\r\n",
3271 // Return the operation status
3273 if ( NULL
!= pErrno
) {
3276 DBG_EXIT_STATUS ( Status
);
3282 Allocate a packet for a receive or transmit operation
3284 This support routine is called by ::EslSocketRxStart and the
3285 network specific TxBuffer routines to get buffer space for the
3288 @param [in] ppPacket Address to receive the ::ESL_PACKET structure
3289 @param [in] LengthInBytes Length of the packet structure
3290 @param [in] ZeroBytes Length of packet to zero
3291 @param [in] DebugFlags Flags for debug messages
3293 @retval EFI_SUCCESS - The packet was allocated successfully
3297 EslSocketPacketAllocate (
3298 IN ESL_PACKET
** ppPacket
,
3299 IN
size_t LengthInBytes
,
3300 IN
size_t ZeroBytes
,
3304 ESL_PACKET
* pPacket
;
3310 // Allocate a packet structure
3312 LengthInBytes
+= sizeof ( *pPacket
)
3313 - sizeof ( pPacket
->Op
);
3314 Status
= gBS
->AllocatePool ( EfiRuntimeServicesData
,
3316 (VOID
**)&pPacket
);
3317 if ( !EFI_ERROR ( Status
)) {
3318 DEBUG (( DebugFlags
| DEBUG_POOL
,
3319 "0x%08x: Allocate pPacket, %d bytes\r\n",
3322 if ( 0 != ZeroBytes
) {
3323 ZeroMem ( &pPacket
->Op
, ZeroBytes
);
3325 pPacket
->PacketSize
= LengthInBytes
;
3328 DEBUG (( DebugFlags
| DEBUG_POOL
| DEBUG_INFO
,
3329 "ERROR - Packet allocation failed for %d bytes, Status: %r\r\n",
3336 // Return the packet
3338 *ppPacket
= pPacket
;
3341 // Return the operation status
3343 DBG_EXIT_STATUS ( Status
);
3349 Free a packet used for receive or transmit operation
3351 This support routine is called by the network specific Close
3352 and TxComplete routines and during error cases in RxComplete
3353 and TxBuffer. Note that the network layers typically place
3354 receive packets on the ESL_SOCKET::pRxFree list for reuse.
3356 @param [in] pPacket Address of an ::ESL_PACKET structure
3357 @param [in] DebugFlags Flags for debug messages
3359 @retval EFI_SUCCESS - The packet was allocated successfully
3363 EslSocketPacketFree (
3364 IN ESL_PACKET
* pPacket
,
3368 UINTN LengthInBytes
;
3374 // Free a packet structure
3376 LengthInBytes
= pPacket
->PacketSize
;
3377 Status
= gBS
->FreePool ( pPacket
);
3378 if ( !EFI_ERROR ( Status
)) {
3379 DEBUG (( DebugFlags
| DEBUG_POOL
,
3380 "0x%08x: Free pPacket, %d bytes\r\n",
3385 DEBUG (( DebugFlags
| DEBUG_POOL
| DEBUG_INFO
,
3386 "ERROR - Failed to free packet 0x%08x, Status: %r\r\n",
3392 // Return the operation status
3394 DBG_EXIT_STATUS ( Status
);
3400 Poll a socket for pending activity.
3402 This routine builds a detected event mask which is returned to
3403 the caller in the buffer provided.
3405 The ::poll routine calls this routine to determine if the socket
3406 needs to be serviced as a result of connection, error, receive or
3409 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
3411 @param [in] Events Events of interest for this socket
3413 @param [in] pEvents Address to receive the detected events
3415 @param [out] pErrno Address to receive the errno value upon completion.
3417 @retval EFI_SUCCESS - Socket successfully polled
3418 @retval EFI_INVALID_PARAMETER - When pEvents is NULL
3423 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
3429 short DetectedEvents
;
3430 ESL_SOCKET
* pSocket
;
3432 EFI_TPL TplPrevious
;
3435 DEBUG (( DEBUG_POLL
, "Entering SocketPoll\r\n" ));
3440 Status
= EFI_SUCCESS
;
3442 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
3446 // Verify the socket state
3448 Status
= EslSocketIsConfigured ( pSocket
);
3449 if ( !EFI_ERROR ( Status
)) {
3451 // Check for invalid events
3453 ValidEvents
= POLLIN
3455 | POLLOUT
| POLLWRNORM
3462 if ( 0 != ( Events
& ( ~ValidEvents
))) {
3463 DetectedEvents
|= POLLNVAL
;
3464 DEBUG (( DEBUG_INFO
| DEBUG_POLL
,
3465 "ERROR - Invalid event mask, Valid Events: 0x%04x, Invalid Events: 0x%04x\r\n",
3466 Events
& ValidEvents
,
3467 Events
& ( ~ValidEvents
)));
3471 // Synchronize with the socket layer
3473 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
3476 // Increase the network performance by extending the
3477 // polling (idle) loop down into the LAN driver
3479 EslSocketRxPoll ( pSocket
);
3482 // Release the socket layer synchronization
3484 RESTORE_TPL ( TplPrevious
);
3487 // Check for pending connections
3489 if ( 0 != pSocket
->FifoDepth
) {
3491 // A connection is waiting for an accept call
3492 // See posix connect documentation at
3493 // http://pubs.opengroup.org/onlinepubs/9699919799/functions/accept.htm
3495 DetectedEvents
|= POLLIN
| POLLRDNORM
;
3497 if ( pSocket
->bConnected
) {
3499 // A connection is present
3500 // See posix connect documentation at
3501 // http://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.htm
3503 DetectedEvents
|= POLLOUT
| POLLWRNORM
;
3507 // The following bits are set based upon the POSIX poll documentation at
3508 // http://pubs.opengroup.org/onlinepubs/9699919799/functions/poll.html
3512 // Check for urgent receive data
3514 if ( 0 < pSocket
->RxOobBytes
) {
3515 DetectedEvents
|= POLLRDBAND
| POLLPRI
| POLLIN
;
3519 // Check for normal receive data
3521 if (( 0 < pSocket
->RxBytes
)
3522 || ( EFI_SUCCESS
!= pSocket
->RxError
)) {
3523 DetectedEvents
|= POLLRDNORM
| POLLIN
;
3527 // Handle the receive errors
3529 if (( EFI_SUCCESS
!= pSocket
->RxError
)
3530 && ( 0 == ( DetectedEvents
& POLLIN
))) {
3531 DetectedEvents
|= POLLERR
| POLLIN
| POLLRDNORM
| POLLRDBAND
;
3535 // Check for urgent transmit data buffer space
3537 if (( MAX_TX_DATA
> pSocket
->TxOobBytes
)
3538 || ( EFI_SUCCESS
!= pSocket
->TxError
)) {
3539 DetectedEvents
|= POLLWRBAND
;
3543 // Check for normal transmit data buffer space
3545 if (( MAX_TX_DATA
> pSocket
->TxBytes
)
3546 || ( EFI_SUCCESS
!= pSocket
->TxError
)) {
3547 DetectedEvents
|= POLLWRNORM
;
3551 // Handle the transmit error
3553 if ( EFI_ERROR ( pSocket
->TxError
)) {
3554 DetectedEvents
|= POLLERR
;
3560 // Return the detected events
3562 *pEvents
= DetectedEvents
& ( Events
3568 // Return the operation status
3570 DEBUG (( DEBUG_POLL
, "Exiting SocketPoll, Status: %r\r\n", Status
));
3576 Allocate and initialize a ESL_PORT structure.
3578 This routine initializes an ::ESL_PORT structure for use by
3579 the socket. This routine calls a routine via
3580 ESL_PROTOCOL_API::pfnPortAllocate to initialize the network
3581 specific resources. The resources are released later by the
3582 \ref PortCloseStateMachine.
3584 This support routine is called by:
3586 <li>::EslSocketBind</li>
3587 <li>::EslTcp4ListenComplete</li>
3589 to connect the socket with the underlying network adapter
3592 @param [in] pSocket Address of an ::ESL_SOCKET structure.
3593 @param [in] pService Address of an ::ESL_SERVICE structure.
3594 @param [in] ChildHandle Network protocol child handle
3595 @param [in] pSockAddr Address of a sockaddr structure that contains the
3596 connection point on the local machine. An IPv4 address
3597 of INADDR_ANY specifies that the connection is made to
3598 all of the network stacks on the platform. Specifying a
3599 specific IPv4 address restricts the connection to the
3600 network stack supporting that address. Specifying zero
3601 for the port causes the network layer to assign a port
3602 number from the dynamic range. Specifying a specific
3603 port number causes the network layer to use that port.
3604 @param [in] bBindTest TRUE if EslSocketBindTest should be called
3605 @param [in] DebugFlags Flags for debug messages
3606 @param [out] ppPort Buffer to receive new ::ESL_PORT structure address
3608 @retval EFI_SUCCESS - Socket successfully created
3612 EslSocketPortAllocate (
3613 IN ESL_SOCKET
* pSocket
,
3614 IN ESL_SERVICE
* pService
,
3615 IN EFI_HANDLE ChildHandle
,
3616 IN CONST
struct sockaddr
* pSockAddr
,
3617 IN BOOLEAN bBindTest
,
3618 IN UINTN DebugFlags
,
3619 OUT ESL_PORT
** ppPort
3622 UINTN LengthInBytes
;
3627 EFI_SERVICE_BINDING_PROTOCOL
* pServiceBinding
;
3628 CONST ESL_SOCKET_BINDING
* pSocketBinding
;
3630 EFI_STATUS TempStatus
;
3635 // Verify the socket layer synchronization
3637 VERIFY_TPL ( TPL_SOCKETS
);
3640 // Use for/break instead of goto
3641 pSocketBinding
= pService
->pSocketBinding
;
3644 // Allocate a port structure
3646 pLayer
= &mEslLayer
;
3647 LengthInBytes
= sizeof ( *pPort
)
3648 + ESL_STRUCTURE_ALIGNMENT_BYTES
3649 + (( pSocketBinding
->RxIo
3650 + pSocketBinding
->TxIoNormal
3651 + pSocketBinding
->TxIoUrgent
)
3652 * sizeof ( ESL_IO_MGMT
));
3653 pPort
= (ESL_PORT
*) AllocateZeroPool ( LengthInBytes
);
3654 if ( NULL
== pPort
) {
3655 Status
= EFI_OUT_OF_RESOURCES
;
3656 pSocket
->errno
= ENOMEM
;
3659 DEBUG (( DebugFlags
| DEBUG_POOL
| DEBUG_INIT
,
3660 "0x%08x: Allocate pPort, %d bytes\r\n",
3665 // Initialize the port
3667 pPort
->DebugFlags
= DebugFlags
;
3668 pPort
->Handle
= ChildHandle
;
3669 pPort
->pService
= pService
;
3670 pPort
->pServiceBinding
= pService
->pServiceBinding
;
3671 pPort
->pSocket
= pSocket
;
3672 pPort
->pSocketBinding
= pService
->pSocketBinding
;
3673 pPort
->Signature
= PORT_SIGNATURE
;
3676 // Open the port protocol
3678 Status
= gBS
->OpenProtocol ( pPort
->Handle
,
3679 pSocketBinding
->pNetworkProtocolGuid
,
3680 &pPort
->pProtocol
.v
,
3681 pLayer
->ImageHandle
,
3683 EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL
);
3684 if ( EFI_ERROR ( Status
)) {
3685 DEBUG (( DEBUG_ERROR
| DebugFlags
,
3686 "ERROR - Failed to open network protocol GUID on controller 0x%08x\r\n",
3688 pSocket
->errno
= EEXIST
;
3691 DEBUG (( DebugFlags
,
3692 "0x%08x: Network protocol GUID opened on controller 0x%08x\r\n",
3697 // Initialize the port specific resources
3699 Status
= pSocket
->pApi
->pfnPortAllocate ( pPort
,
3701 if ( EFI_ERROR ( Status
)) {
3706 // Set the local address
3708 Status
= pSocket
->pApi
->pfnLocalAddrSet ( pPort
, pSockAddr
, bBindTest
);
3709 if ( EFI_ERROR ( Status
)) {
3714 // Test the address/port configuration
3717 Status
= EslSocketBindTest ( pPort
, pSocket
->pApi
->BindTestErrno
);
3718 if ( EFI_ERROR ( Status
)) {
3724 // Initialize the receive structures
3726 pBuffer
= (UINT8
*)&pPort
[ 1 ];
3727 pBuffer
= &pBuffer
[ ESL_STRUCTURE_ALIGNMENT_BYTES
];
3728 pBuffer
= (UINT8
*)( ESL_STRUCTURE_ALIGNMENT_MASK
& (UINTN
)pBuffer
);
3729 pIo
= (ESL_IO_MGMT
*)pBuffer
;
3730 if (( 0 != pSocketBinding
->RxIo
)
3731 && ( NULL
!= pSocket
->pApi
->pfnRxComplete
)) {
3732 Status
= EslSocketIoInit ( pPort
,
3734 pSocketBinding
->RxIo
,
3736 DebugFlags
| DEBUG_POOL
,
3738 pSocket
->pApi
->pfnRxComplete
);
3739 if ( EFI_ERROR ( Status
)) {
3745 // Initialize the urgent transmit structures
3747 if (( 0 != pSocketBinding
->TxIoUrgent
)
3748 && ( NULL
!= pSocket
->pApi
->pfnTxOobComplete
)) {
3749 Status
= EslSocketIoInit ( pPort
,
3751 pSocketBinding
->TxIoUrgent
,
3753 DebugFlags
| DEBUG_POOL
,
3755 pSocket
->pApi
->pfnTxOobComplete
);
3756 if ( EFI_ERROR ( Status
)) {
3762 // Initialize the normal transmit structures
3764 if (( 0 != pSocketBinding
->TxIoNormal
)
3765 && ( NULL
!= pSocket
->pApi
->pfnTxComplete
)) {
3766 Status
= EslSocketIoInit ( pPort
,
3768 pSocketBinding
->TxIoNormal
,
3770 DebugFlags
| DEBUG_POOL
,
3772 pSocket
->pApi
->pfnTxComplete
);
3773 if ( EFI_ERROR ( Status
)) {
3779 // Add this port to the socket
3781 pPort
->pLinkSocket
= pSocket
->pPortList
;
3782 pSocket
->pPortList
= pPort
;
3783 DEBUG (( DebugFlags
,
3784 "0x%08x: Socket adding port: 0x%08x\r\n",
3789 // Add this port to the service
3791 pPort
->pLinkService
= pService
->pPortList
;
3792 pService
->pPortList
= pPort
;
3802 // Clean up after the error if necessary
3804 if ( EFI_ERROR ( Status
)) {
3805 if ( NULL
!= pPort
) {
3809 EslSocketPortClose ( pPort
);
3813 // Close the port if necessary
3815 pServiceBinding
= pService
->pServiceBinding
;
3816 TempStatus
= pServiceBinding
->DestroyChild ( pServiceBinding
,
3818 if ( !EFI_ERROR ( TempStatus
)) {
3819 DEBUG (( DEBUG_BIND
| DEBUG_POOL
,
3820 "0x%08x: %s port handle destroyed\r\n",
3822 pSocketBinding
->pName
));
3825 DEBUG (( DEBUG_ERROR
| DEBUG_BIND
| DEBUG_POOL
,
3826 "ERROR - Failed to destroy the %s port handle 0x%08x, Status: %r\r\n",
3827 pSocketBinding
->pName
,
3830 ASSERT ( EFI_SUCCESS
== TempStatus
);
3835 // Return the operation status
3837 DBG_EXIT_STATUS ( Status
);
3845 This routine releases the resources allocated by ::EslSocketPortAllocate.
3846 This routine calls ESL_PROTOCOL_API::pfnPortClose to release the network
3849 This routine is called by:
3851 <li>::EslSocketPortAllocate - Port initialization failure</li>
3852 <li>::EslSocketPortCloseRxDone - Last step of close processing</li>
3853 <li>::EslTcp4ConnectComplete - Connection failure and reducing the port list to a single port</li>
3855 See the \ref PortCloseStateMachine section.
3857 @param [in] pPort Address of an ::ESL_PORT structure.
3859 @retval EFI_SUCCESS The port is closed
3860 @retval other Port close error
3864 EslSocketPortClose (
3870 ESL_PACKET
* pPacket
;
3871 ESL_PORT
* pPreviousPort
;
3872 ESL_SERVICE
* pService
;
3873 EFI_SERVICE_BINDING_PROTOCOL
* pServiceBinding
;
3874 CONST ESL_SOCKET_BINDING
* pSocketBinding
;
3875 ESL_SOCKET
* pSocket
;
3881 // Verify the socket layer synchronization
3883 VERIFY_TPL ( TPL_SOCKETS
);
3886 // Locate the port in the socket list
3888 Status
= EFI_SUCCESS
;
3889 pLayer
= &mEslLayer
;
3890 DebugFlags
= pPort
->DebugFlags
;
3891 pSocket
= pPort
->pSocket
;
3892 pPreviousPort
= pSocket
->pPortList
;
3893 if ( pPreviousPort
== pPort
) {
3895 // Remove this port from the head of the socket list
3897 pSocket
->pPortList
= pPort
->pLinkSocket
;
3901 // Locate the port in the middle of the socket list
3903 while (( NULL
!= pPreviousPort
)
3904 && ( pPreviousPort
->pLinkSocket
!= pPort
)) {
3905 pPreviousPort
= pPreviousPort
->pLinkSocket
;
3907 if ( NULL
!= pPreviousPort
) {
3909 // Remove the port from the middle of the socket list
3911 pPreviousPort
->pLinkSocket
= pPort
->pLinkSocket
;
3916 // Locate the port in the service list
3917 // Note that the port may not be in the service list
3918 // if the service has been shutdown.
3920 pService
= pPort
->pService
;
3921 if ( NULL
!= pService
) {
3922 pPreviousPort
= pService
->pPortList
;
3923 if ( pPreviousPort
== pPort
) {
3925 // Remove this port from the head of the service list
3927 pService
->pPortList
= pPort
->pLinkService
;
3931 // Locate the port in the middle of the service list
3933 while (( NULL
!= pPreviousPort
)
3934 && ( pPreviousPort
->pLinkService
!= pPort
)) {
3935 pPreviousPort
= pPreviousPort
->pLinkService
;
3937 if ( NULL
!= pPreviousPort
) {
3939 // Remove the port from the middle of the service list
3941 pPreviousPort
->pLinkService
= pPort
->pLinkService
;
3947 // Empty the urgent receive queue
3949 while ( NULL
!= pSocket
->pRxOobPacketListHead
) {
3950 pPacket
= pSocket
->pRxOobPacketListHead
;
3951 pSocket
->pRxOobPacketListHead
= pPacket
->pNext
;
3952 pSocket
->pApi
->pfnPacketFree ( pPacket
, &pSocket
->RxOobBytes
);
3953 EslSocketPacketFree ( pPacket
, DEBUG_RX
);
3955 pSocket
->pRxOobPacketListTail
= NULL
;
3956 ASSERT ( 0 == pSocket
->RxOobBytes
);
3959 // Empty the receive queue
3961 while ( NULL
!= pSocket
->pRxPacketListHead
) {
3962 pPacket
= pSocket
->pRxPacketListHead
;
3963 pSocket
->pRxPacketListHead
= pPacket
->pNext
;
3964 pSocket
->pApi
->pfnPacketFree ( pPacket
, &pSocket
->RxBytes
);
3965 EslSocketPacketFree ( pPacket
, DEBUG_RX
);
3967 pSocket
->pRxPacketListTail
= NULL
;
3968 ASSERT ( 0 == pSocket
->RxBytes
);
3971 // Empty the receive free queue
3973 while ( NULL
!= pSocket
->pRxFree
) {
3974 pPacket
= pSocket
->pRxFree
;
3975 pSocket
->pRxFree
= pPacket
->pNext
;
3976 EslSocketPacketFree ( pPacket
, DEBUG_RX
);
3980 // Release the network specific resources
3982 if ( NULL
!= pSocket
->pApi
->pfnPortClose
) {
3983 Status
= pSocket
->pApi
->pfnPortClose ( pPort
);
3987 // Done with the normal transmit events
3989 Status
= EslSocketIoFree ( pPort
,
3991 DebugFlags
| DEBUG_POOL
,
3992 "normal transmit" );
3995 // Done with the urgent transmit events
3997 Status
= EslSocketIoFree ( pPort
,
3999 DebugFlags
| DEBUG_POOL
,
4000 "urgent transmit" );
4003 // Done with the receive events
4005 Status
= EslSocketIoFree ( pPort
,
4007 DebugFlags
| DEBUG_POOL
,
4011 // Done with the lower layer network protocol
4013 pSocketBinding
= pPort
->pSocketBinding
;
4014 if ( NULL
!= pPort
->pProtocol
.v
) {
4015 Status
= gBS
->CloseProtocol ( pPort
->Handle
,
4016 pSocketBinding
->pNetworkProtocolGuid
,
4017 pLayer
->ImageHandle
,
4019 if ( !EFI_ERROR ( Status
)) {
4020 DEBUG (( DebugFlags
,
4021 "0x%08x: Network protocol GUID closed on controller 0x%08x\r\n",
4026 DEBUG (( DEBUG_ERROR
| DebugFlags
,
4027 "ERROR - Failed to close network protocol GUID on controller 0x%08x, Status: %r\r\n",
4030 ASSERT ( EFI_SUCCESS
== Status
);
4035 // Done with the network port
4037 pServiceBinding
= pPort
->pServiceBinding
;
4038 if ( NULL
!= pPort
->Handle
) {
4039 Status
= pServiceBinding
->DestroyChild ( pServiceBinding
,
4041 if ( !EFI_ERROR ( Status
)) {
4042 DEBUG (( DebugFlags
| DEBUG_POOL
,
4043 "0x%08x: %s port handle destroyed\r\n",
4045 pSocketBinding
->pName
));
4048 DEBUG (( DEBUG_ERROR
| DebugFlags
| DEBUG_POOL
,
4049 "ERROR - Failed to destroy the %s port handle, Status: %r\r\n",
4050 pSocketBinding
->pName
,
4052 ASSERT ( EFI_SUCCESS
== Status
);
4057 // Release the port structure
4059 Status
= gBS
->FreePool ( pPort
);
4060 if ( !EFI_ERROR ( Status
)) {
4061 DEBUG (( DebugFlags
| DEBUG_POOL
,
4062 "0x%08x: Free pPort, %d bytes\r\n",
4064 sizeof ( *pPort
)));
4067 DEBUG (( DEBUG_ERROR
| DebugFlags
| DEBUG_POOL
,
4068 "ERROR - Failed to free pPort: 0x%08x, Status: %r\r\n",
4071 ASSERT ( EFI_SUCCESS
== Status
);
4075 // Mark the socket as closed if necessary
4077 if ( NULL
== pSocket
->pPortList
) {
4078 pSocket
->State
= SOCKET_STATE_CLOSED
;
4079 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4080 "0x%08x: Socket State: SOCKET_STATE_CLOSED\r\n",
4085 // Return the operation status
4087 DBG_EXIT_STATUS ( Status
);
4095 This routine attempts to complete the port close operation.
4097 This routine is called by the TCP layer upon completion of
4098 the close operation and by ::EslSocketPortCloseTxDone.
4099 See the \ref PortCloseStateMachine section.
4101 @param [in] Event The close completion event
4103 @param [in] pPort Address of an ::ESL_PORT structure.
4107 EslSocketPortCloseComplete (
4116 VERIFY_AT_TPL ( TPL_SOCKETS
);
4119 // Update the port state
4121 pPort
->State
= PORT_STATE_CLOSE_DONE
;
4122 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4123 "0x%08x: Port Close State: PORT_STATE_CLOSE_DONE\r\n",
4127 // Shutdown the receive operation on the port
4129 if ( NULL
!= pPort
->pfnRxCancel
) {
4130 pIo
= pPort
->pRxActive
;
4131 while ( NULL
!= pIo
) {
4132 EslSocketRxCancel ( pPort
, pIo
);
4138 // Determine if the receive operation is pending
4140 Status
= EslSocketPortCloseRxDone ( pPort
);
4141 DBG_EXIT_STATUS ( Status
);
4148 This routine determines the state of the receive operations and
4149 continues the close operation after the pending receive operations
4152 This routine is called by
4154 <li>::EslSocketPortCloseComplete</li>
4155 <li>::EslSocketPortCloseTxDone</li>
4156 <li>::EslSocketRxComplete</li>
4158 to determine the state of the receive operations.
4159 See the \ref PortCloseStateMachine section.
4161 @param [in] pPort Address of an ::ESL_PORT structure.
4163 @retval EFI_SUCCESS The port is closed
4164 @retval EFI_NOT_READY The port is still closing
4165 @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
4166 most likely the routine was called already.
4170 EslSocketPortCloseRxDone (
4179 // Verify the socket layer synchronization
4181 VERIFY_TPL ( TPL_SOCKETS
);
4184 // Verify that the port is closing
4186 Status
= EFI_ALREADY_STARTED
;
4187 if ( PORT_STATE_CLOSE_DONE
== pPort
->State
) {
4189 // Determine if the receive operation is pending
4191 Status
= EFI_NOT_READY
;
4192 if ( NULL
== pPort
->pRxActive
) {
4194 // The receive operation is complete
4195 // Update the port state
4197 pPort
->State
= PORT_STATE_CLOSE_RX_DONE
;
4198 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4199 "0x%08x: Port Close State: PORT_STATE_CLOSE_RX_DONE\r\n",
4203 // Complete the port close operation
4205 Status
= EslSocketPortClose ( pPort
);
4208 DEBUG_CODE_BEGIN ();
4212 // Display the outstanding receive operations
4214 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4215 "0x%08x: Port Close: Receive still pending!\r\n",
4217 pIo
= pPort
->pRxActive
;
4218 while ( NULL
!= pIo
) {
4219 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4220 "0x%08x: Packet pending on network adapter\r\n",
4230 // Return the operation status
4232 DBG_EXIT_STATUS ( Status
);
4238 Start the close operation on a port, state 1.
4240 This routine marks the port as closed and initiates the \ref
4241 PortCloseStateMachine. The first step is to allow the \ref
4242 TransmitEngine to run down.
4244 This routine is called by ::EslSocketCloseStart to initiate the socket
4245 network specific close operation on the socket.
4247 @param [in] pPort Address of an ::ESL_PORT structure.
4248 @param [in] bCloseNow Set TRUE to abort active transfers
4249 @param [in] DebugFlags Flags for debug messages
4251 @retval EFI_SUCCESS The port is closed, not normally returned
4252 @retval EFI_NOT_READY The port has started the closing process
4253 @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
4254 most likely the routine was called already.
4258 EslSocketPortCloseStart (
4259 IN ESL_PORT
* pPort
,
4260 IN BOOLEAN bCloseNow
,
4264 ESL_SOCKET
* pSocket
;
4270 // Verify the socket layer synchronization
4272 VERIFY_TPL ( TPL_SOCKETS
);
4275 // Mark the port as closing
4277 Status
= EFI_ALREADY_STARTED
;
4278 pSocket
= pPort
->pSocket
;
4279 pSocket
->errno
= EALREADY
;
4280 if ( PORT_STATE_CLOSE_STARTED
> pPort
->State
) {
4283 // Update the port state
4285 pPort
->State
= PORT_STATE_CLOSE_STARTED
;
4286 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4287 "0x%08x: Port Close State: PORT_STATE_CLOSE_STARTED\r\n",
4289 pPort
->bCloseNow
= bCloseNow
;
4290 pPort
->DebugFlags
= DebugFlags
;
4293 // Determine if transmits are complete
4295 Status
= EslSocketPortCloseTxDone ( pPort
);
4299 // Return the operation status
4301 DBG_EXIT_STATUS ( Status
);
4309 This routine determines the state of the transmit engine and
4310 continue the close operation after the transmission is complete.
4311 The next step is to stop the \ref ReceiveEngine.
4312 See the \ref PortCloseStateMachine section.
4314 This routine is called by ::EslSocketPortCloseStart to determine
4315 if the transmission is complete.
4317 @param [in] pPort Address of an ::ESL_PORT structure.
4319 @retval EFI_SUCCESS The port is closed, not normally returned
4320 @retval EFI_NOT_READY The port is still closing
4321 @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
4322 most likely the routine was called already.
4326 EslSocketPortCloseTxDone (
4331 ESL_SOCKET
* pSocket
;
4337 // Verify the socket layer synchronization
4339 VERIFY_TPL ( TPL_SOCKETS
);
4342 // All transmissions are complete or must be stopped
4343 // Mark the port as TX complete
4345 Status
= EFI_ALREADY_STARTED
;
4346 if ( PORT_STATE_CLOSE_STARTED
== pPort
->State
) {
4348 // Verify that the transmissions are complete
4350 pSocket
= pPort
->pSocket
;
4351 if ( pPort
->bCloseNow
4352 || ( EFI_SUCCESS
!= pSocket
->TxError
)
4353 || (( NULL
== pPort
->pTxActive
)
4354 && ( NULL
== pPort
->pTxOobActive
))) {
4356 // Update the port state
4358 pPort
->State
= PORT_STATE_CLOSE_TX_DONE
;
4359 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4360 "0x%08x: Port Close State: PORT_STATE_CLOSE_TX_DONE\r\n",
4365 // Skip the close operation if the port is not configured
4367 Status
= EFI_SUCCESS
;
4368 pSocket
= pPort
->pSocket
;
4369 if (( pPort
->bConfigured
)
4370 && ( NULL
!= pSocket
->pApi
->pfnPortCloseOp
)) {
4372 // Start the close operation
4374 Status
= pSocket
->pApi
->pfnPortCloseOp ( pPort
);
4375 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4376 "0x%08x: Port Close: Close operation still pending!\r\n",
4378 ASSERT ( EFI_SUCCESS
== Status
);
4382 // The receive operation is complete
4383 // Update the port state
4385 EslSocketPortCloseComplete ( NULL
, pPort
);
4390 // Transmissions are still active, exit
4392 Status
= EFI_NOT_READY
;
4393 pSocket
->errno
= EAGAIN
;
4394 DEBUG_CODE_BEGIN ( );
4396 ESL_PACKET
* pPacket
;
4398 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4399 "0x%08x: Port Close: Transmits are still pending!\r\n",
4403 // Display the pending urgent transmit packets
4405 pPacket
= pSocket
->pTxOobPacketListHead
;
4406 while ( NULL
!= pPacket
) {
4407 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4408 "0x%08x: Packet pending on urgent TX list, %d bytes\r\n",
4410 pPacket
->PacketSize
));
4411 pPacket
= pPacket
->pNext
;
4414 pIo
= pPort
->pTxOobActive
;
4415 while ( NULL
!= pIo
) {
4416 pPacket
= pIo
->pPacket
;
4417 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4418 "0x%08x: Packet active %d bytes, pIo: 0x%08x\r\n",
4420 pPacket
->PacketSize
,
4426 // Display the pending normal transmit packets
4428 pPacket
= pSocket
->pTxPacketListHead
;
4429 while ( NULL
!= pPacket
) {
4430 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4431 "0x%08x: Packet pending on normal TX list, %d bytes\r\n",
4433 pPacket
->PacketSize
));
4434 pPacket
= pPacket
->pNext
;
4437 pIo
= pPort
->pTxActive
;
4438 while ( NULL
!= pIo
) {
4439 pPacket
= pIo
->pPacket
;
4440 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4441 "0x%08x: Packet active %d bytes, pIo: 0x%08x\r\n",
4443 pPacket
->PacketSize
,
4453 // Return the operation status
4455 DBG_EXIT_STATUS ( Status
);
4461 Receive data from a network connection.
4463 This routine calls the network specific routine to remove the
4464 next portion of data from the receive queue and return it to the
4467 The ::recvfrom routine calls this routine to determine if any data
4468 is received from the remote system. Note that the other routines
4469 ::recv and ::read are layered on top of ::recvfrom.
4471 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
4473 @param [in] Flags Message control flags
4475 @param [in] BufferLength Length of the the buffer
4477 @param [in] pBuffer Address of a buffer to receive the data.
4479 @param [in] pDataLength Number of received data bytes in the buffer.
4481 @param [out] pAddress Network address to receive the remote system address
4483 @param [in,out] pAddressLength Length of the remote network address structure
4485 @param [out] pErrno Address to receive the errno value upon completion.
4487 @retval EFI_SUCCESS - Socket data successfully received
4492 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
4494 IN
size_t BufferLength
,
4496 OUT
size_t * pDataLength
,
4497 OUT
struct sockaddr
* pAddress
,
4498 IN OUT socklen_t
* pAddressLength
,
4503 struct sockaddr_in v4
;
4504 struct sockaddr_in6 v6
;
4506 socklen_t AddressLength
;
4507 BOOLEAN bConsumePacket
;
4508 BOOLEAN bUrgentQueue
;
4510 ESL_PACKET
* pNextPacket
;
4511 ESL_PACKET
* pPacket
;
4513 ESL_PACKET
** ppQueueHead
;
4514 ESL_PACKET
** ppQueueTail
;
4515 struct sockaddr
* pRemoteAddress
;
4516 size_t * pRxDataBytes
;
4517 ESL_SOCKET
* pSocket
;
4520 EFI_TPL TplPrevious
;
4527 Status
= EFI_SUCCESS
;
4530 // Validate the socket
4533 if ( NULL
!= pSocketProtocol
) {
4534 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
4537 // Validate the return address parameters
4539 if (( NULL
== pAddress
) || ( NULL
!= pAddressLength
)) {
4541 // Return the transmit error if necessary
4543 if ( EFI_SUCCESS
!= pSocket
->TxError
) {
4544 pSocket
->errno
= EIO
;
4545 Status
= pSocket
->TxError
;
4546 pSocket
->TxError
= EFI_SUCCESS
;
4550 // Verify the socket state
4552 Status
= EslSocketIsConfigured ( pSocket
);
4553 if ( !EFI_ERROR ( Status
)) {
4555 // Validate the buffer length
4557 if (( NULL
== pDataLength
)
4558 || ( NULL
== pBuffer
)) {
4559 if ( NULL
== pDataLength
) {
4561 "ERROR - pDataLength is NULL!\r\n" ));
4565 "ERROR - pBuffer is NULL!\r\n" ));
4567 Status
= EFI_INVALID_PARAMETER
;
4568 pSocket
->errno
= EFAULT
;
4574 if ( NULL
== pSocket
->pApi
->pfnReceive
) {
4575 Status
= EFI_UNSUPPORTED
;
4576 pSocket
->errno
= ENOTSUP
;
4580 // Zero the receive address if being returned
4582 pRemoteAddress
= NULL
;
4583 if ( NULL
!= pAddress
) {
4584 pRemoteAddress
= (struct sockaddr
*)&Addr
;
4585 ZeroMem ( pRemoteAddress
, sizeof ( Addr
));
4586 pRemoteAddress
->sa_family
= pSocket
->pApi
->AddressFamily
;
4587 pRemoteAddress
->sa_len
= (UINT8
)pSocket
->pApi
->AddressLength
;
4591 // Synchronize with the socket layer
4593 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
4598 Status
= EFI_UNSUPPORTED
;
4599 pSocket
->errno
= ENOTCONN
;
4602 // Verify that the socket is connected
4604 if ( SOCKET_STATE_CONNECTED
== pSocket
->State
) {
4606 // Poll the network to increase performance
4608 EslSocketRxPoll ( pSocket
);
4613 pPort
= pSocket
->pPortList
;
4614 if ( NULL
!= pPort
) {
4616 // Determine the queue head
4618 bUrgentQueue
= (BOOLEAN
)( 0 != ( Flags
& MSG_OOB
));
4619 if ( bUrgentQueue
) {
4620 ppQueueHead
= &pSocket
->pRxOobPacketListHead
;
4621 ppQueueTail
= &pSocket
->pRxOobPacketListTail
;
4622 pRxDataBytes
= &pSocket
->RxOobBytes
;
4625 ppQueueHead
= &pSocket
->pRxPacketListHead
;
4626 ppQueueTail
= &pSocket
->pRxPacketListTail
;
4627 pRxDataBytes
= &pSocket
->RxBytes
;
4631 // Determine if there is any data on the queue
4634 pPacket
= *ppQueueHead
;
4635 if ( NULL
!= pPacket
) {
4637 // Copy the received data
4641 // Attempt to receive a packet
4644 bConsumePacket
= (BOOLEAN
)( 0 == ( Flags
& MSG_PEEK
));
4645 pBuffer
= pSocket
->pApi
->pfnReceive ( pPort
,
4651 (struct sockaddr
*)&Addr
,
4653 *pDataLength
+= DataLength
;
4654 BufferLength
-= DataLength
;
4657 // Determine if the data is being read
4659 pNextPacket
= pPacket
->pNext
;
4660 if ( bConsumePacket
) {
4662 // All done with this packet
4663 // Account for any discarded data
4665 pSocket
->pApi
->pfnPacketFree ( pPacket
, pRxDataBytes
);
4666 if ( 0 != SkipBytes
) {
4668 "0x%08x: Port, packet read, skipping over 0x%08x bytes\r\n",
4674 // Remove this packet from the queue
4676 *ppQueueHead
= pPacket
->pNext
;
4677 if ( NULL
== *ppQueueHead
) {
4678 *ppQueueTail
= NULL
;
4682 // Move the packet to the free queue
4684 pPacket
->pNext
= pSocket
->pRxFree
;
4685 pSocket
->pRxFree
= pPacket
;
4687 "0x%08x: Port freeing packet 0x%08x\r\n",
4692 // Restart the receive operation if necessary
4694 if (( NULL
!= pPort
->pRxFree
)
4695 && ( MAX_RX_DATA
> pSocket
->RxBytes
)) {
4696 EslSocketRxStart ( pPort
);
4701 // Get the next packet
4703 pPacket
= pNextPacket
;
4704 } while (( SOCK_STREAM
== pSocket
->Type
)
4705 && ( NULL
!= pPacket
)
4706 && ( 0 < BufferLength
));
4709 // Successful operation
4711 Status
= EFI_SUCCESS
;
4716 // The queue is empty
4717 // Determine if it is time to return the receive error
4719 if ( EFI_ERROR ( pSocket
->RxError
)
4720 && ( NULL
== pSocket
->pRxPacketListHead
)
4721 && ( NULL
== pSocket
->pRxOobPacketListHead
)) {
4722 Status
= pSocket
->RxError
;
4723 pSocket
->RxError
= EFI_SUCCESS
;
4726 pSocket
->errno
= EIO
;
4729 case EFI_CONNECTION_FIN
:
4731 // Continue to return zero bytes received when the
4732 // peer has successfully closed the connection
4734 pSocket
->RxError
= EFI_CONNECTION_FIN
;
4737 Status
= EFI_SUCCESS
;
4740 case EFI_CONNECTION_REFUSED
:
4741 pSocket
->errno
= ECONNREFUSED
;
4744 case EFI_CONNECTION_RESET
:
4745 pSocket
->errno
= ECONNRESET
;
4748 case EFI_HOST_UNREACHABLE
:
4749 pSocket
->errno
= EHOSTUNREACH
;
4752 case EFI_NETWORK_UNREACHABLE
:
4753 pSocket
->errno
= ENETUNREACH
;
4756 case EFI_PORT_UNREACHABLE
:
4757 pSocket
->errno
= EPROTONOSUPPORT
;
4760 case EFI_PROTOCOL_UNREACHABLE
:
4761 pSocket
->errno
= ENOPROTOOPT
;
4766 Status
= EFI_NOT_READY
;
4767 pSocket
->errno
= EAGAIN
;
4774 // Release the socket layer synchronization
4776 RESTORE_TPL ( TplPrevious
);
4778 if (( !EFI_ERROR ( Status
)) && ( NULL
!= pAddress
)) {
4780 // Return the remote address if requested, truncate if necessary
4782 AddressLength
= pRemoteAddress
->sa_len
;
4783 if ( AddressLength
> *pAddressLength
) {
4784 AddressLength
= *pAddressLength
;
4787 "Returning the remote address, 0x%016x bytes --> 0x%16x\r\n", *pAddressLength
, pAddress
));
4788 ZeroMem ( pAddress
, *pAddressLength
);
4789 CopyMem ( pAddress
, &Addr
, AddressLength
);
4792 // Update the address length
4794 *pAddressLength
= pRemoteAddress
->sa_len
;
4805 // Bad return address pointer and length
4807 Status
= EFI_INVALID_PARAMETER
;
4808 pSocket
->errno
= EINVAL
;
4813 // Return the operation status
4815 if ( NULL
!= pErrno
) {
4816 if ( NULL
!= pSocket
) {
4817 *pErrno
= pSocket
->errno
;
4820 Status
= EFI_INVALID_PARAMETER
;
4824 DBG_EXIT_STATUS ( Status
);
4830 Cancel the receive operations
4832 This routine cancels a pending receive operation.
4833 See the \ref ReceiveEngine section.
4835 This routine is called by ::EslSocketShutdown when the socket
4836 layer is being shutdown.
4838 @param [in] pPort Address of an ::ESL_PORT structure
4839 @param [in] pIo Address of an ::ESL_IO_MGMT structure
4844 IN ESL_PORT
* pPort
,
4845 IN ESL_IO_MGMT
* pIo
4853 // Cancel the outstanding receive
4855 Status
= pPort
->pfnRxCancel ( pPort
->pProtocol
.v
,
4857 if ( !EFI_ERROR ( Status
)) {
4858 DEBUG (( pPort
->DebugFlags
| DEBUG_CLOSE
| DEBUG_INFO
,
4859 "0x%08x: Packet receive aborted on port: 0x%08x\r\n",
4864 DEBUG (( pPort
->DebugFlags
| DEBUG_CLOSE
| DEBUG_INFO
,
4865 "0x%08x: Packet receive pending on Port 0x%08x, Status: %r\r\n",
4875 Process the receive completion
4877 This routine queues the data in FIFO order in either the urgent
4878 or normal data queues depending upon the type of data received.
4879 See the \ref ReceiveEngine section.
4881 This routine is called when some data is received by:
4883 <li>::EslIp4RxComplete</li>
4884 <li>::EslTcp4RxComplete</li>
4885 <li>::EslUdp4RxComplete</li>
4888 @param [in] pIo Address of an ::ESL_IO_MGMT structure
4889 @param [in] Status Receive status
4890 @param [in] LengthInBytes Length of the receive data
4891 @param [in] bUrgent TRUE if urgent data is received and FALSE
4896 EslSocketRxComplete (
4897 IN ESL_IO_MGMT
* pIo
,
4898 IN EFI_STATUS Status
,
4899 IN UINTN LengthInBytes
,
4903 BOOLEAN bUrgentQueue
;
4904 ESL_IO_MGMT
* pIoNext
;
4905 ESL_PACKET
* pPacket
;
4907 ESL_PACKET
* pPrevious
;
4908 ESL_PACKET
** ppQueueHead
;
4909 ESL_PACKET
** ppQueueTail
;
4911 ESL_SOCKET
* pSocket
;
4914 VERIFY_AT_TPL ( TPL_SOCKETS
);
4917 // Locate the active receive packet
4919 pPacket
= pIo
->pPacket
;
4921 pSocket
= pPort
->pSocket
;
4927 // +-------------+ +-------------+ +-------------+
4928 // Active | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
4929 // +-------------+ +-------------+ +-------------+
4931 // +-------------+ +-------------+ +-------------+
4932 // Free | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
4933 // +-------------+ +-------------+ +-------------+
4939 // Remove the IO structure from the active list
4940 // The following code searches for the entry in the list and does not
4941 // assume that the receive operations complete in the order they were
4942 // issued to the UEFI network layer.
4944 pIoNext
= pPort
->pRxActive
;
4945 while (( NULL
!= pIoNext
) && ( pIoNext
!= pIo
) && ( pIoNext
->pNext
!= pIo
))
4947 pIoNext
= pIoNext
->pNext
;
4949 ASSERT ( NULL
!= pIoNext
);
4950 if ( pIoNext
== pIo
) {
4951 pPort
->pRxActive
= pIo
->pNext
; // Beginning of list
4954 pIoNext
->pNext
= pIo
->pNext
; // Middle of list
4958 // Free the IO structure
4960 pIo
->pNext
= pPort
->pRxFree
;
4961 pPort
->pRxFree
= pIo
;
4964 // pRxOobPacketListHead pRxOobPacketListTail
4967 // +------------+ +------------+ +------------+
4968 // Urgent Data | ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL
4969 // +------------+ +------------+ +------------+
4971 // +------------+ +------------+ +------------+
4972 // Normal Data | ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL
4973 // +------------+ +------------+ +------------+
4976 // pRxPacketListHead pRxPacketListTail
4979 // Determine the queue to use
4981 bUrgentQueue
= (BOOLEAN
)( bUrgent
4982 && pSocket
->pApi
->bOobSupported
4983 && ( !pSocket
->bOobInLine
));
4984 if ( bUrgentQueue
) {
4985 ppQueueHead
= &pSocket
->pRxOobPacketListHead
;
4986 ppQueueTail
= &pSocket
->pRxOobPacketListTail
;
4987 pRxBytes
= &pSocket
->RxOobBytes
;
4990 ppQueueHead
= &pSocket
->pRxPacketListHead
;
4991 ppQueueTail
= &pSocket
->pRxPacketListTail
;
4992 pRxBytes
= &pSocket
->RxBytes
;
4996 // Determine if this receive was successful
4998 if (( !EFI_ERROR ( Status
))
4999 && ( PORT_STATE_CLOSE_STARTED
> pPort
->State
)
5000 && ( !pSocket
->bRxDisable
)) {
5002 // Account for the received data
5004 *pRxBytes
+= LengthInBytes
;
5007 // Log the received data
5009 DEBUG (( DEBUG_RX
| DEBUG_INFO
,
5010 "0x%08x: Packet queued on %s queue of port 0x%08x with 0x%08x bytes of %s data\r\n",
5012 bUrgentQueue
? L
"urgent" : L
"normal",
5015 bUrgent
? L
"urgent" : L
"normal" ));
5018 // Add the packet to the list tail.
5020 pPacket
->pNext
= NULL
;
5021 pPrevious
= *ppQueueTail
;
5022 if ( NULL
== pPrevious
) {
5023 *ppQueueHead
= pPacket
;
5026 pPrevious
->pNext
= pPacket
;
5028 *ppQueueTail
= pPacket
;
5031 // Attempt to restart this receive operation
5033 if ( pSocket
->MaxRxBuf
> pSocket
->RxBytes
) {
5034 EslSocketRxStart ( pPort
);
5038 "0x%08x: Port RX suspended, 0x%08x bytes queued\r\n",
5040 pSocket
->RxBytes
));
5044 if ( EFI_ERROR ( Status
)) {
5045 DEBUG (( DEBUG_RX
| DEBUG_INFO
,
5046 "ERROR - Receive error on port 0x%08x, packet 0x%08x, Status:%r\r\n",
5053 // Account for the receive bytes and release the driver's buffer
5055 if ( !EFI_ERROR ( Status
)) {
5056 *pRxBytes
+= LengthInBytes
;
5057 pSocket
->pApi
->pfnPacketFree ( pPacket
, pRxBytes
);
5061 // Receive error, free the packet save the error
5063 EslSocketPacketFree ( pPacket
, DEBUG_RX
);
5064 if ( !EFI_ERROR ( pSocket
->RxError
)) {
5065 pSocket
->RxError
= Status
;
5069 // Update the port state
5071 if ( PORT_STATE_CLOSE_STARTED
<= pPort
->State
) {
5072 if ( PORT_STATE_CLOSE_DONE
== pPort
->State
) {
5073 EslSocketPortCloseRxDone ( pPort
);
5077 if ( EFI_ERROR ( Status
)) {
5078 DEBUG (( DEBUG_RX
| DEBUG_INFO
,
5079 "0x%08x: Port state: PORT_STATE_RX_ERROR, Status: %r\r\n",
5082 pPort
->State
= PORT_STATE_RX_ERROR
;
5092 Poll a socket for pending receive activity.
5094 This routine is called at elivated TPL and extends the idle
5095 loop which polls a socket down into the LAN driver layer to
5096 determine if there is any receive activity.
5098 The ::EslSocketPoll, ::EslSocketReceive and ::EslSocketTransmit
5099 routines call this routine when there is nothing to do.
5101 @param [in] pSocket Address of an ::EFI_SOCKET structure.
5106 IN ESL_SOCKET
* pSocket
5111 DEBUG (( DEBUG_POLL
, "Entering EslSocketRxPoll\r\n" ));
5114 // Increase the network performance by extending the
5115 // polling (idle) loop down into the LAN driver
5117 pPort
= pSocket
->pPortList
;
5118 while ( NULL
!= pPort
) {
5120 // Poll the LAN adapter
5122 pPort
->pfnRxPoll ( pPort
->pProtocol
.v
);
5125 // Locate the next LAN adapter
5127 pPort
= pPort
->pLinkSocket
;
5130 DEBUG (( DEBUG_POLL
, "Exiting EslSocketRxPoll\r\n" ));
5135 Start a receive operation
5137 This routine posts a receive buffer to the network adapter.
5138 See the \ref ReceiveEngine section.
5140 This support routine is called by:
5142 <li>::EslIp4Receive to restart the receive engine to release flow control.</li>
5143 <li>::EslIp4RxComplete to continue the operation of the receive engine if flow control is not being applied.</li>
5144 <li>::EslIp4SocketIsConfigured to start the recevie engine for the new socket.</li>
5145 <li>::EslTcp4ListenComplete to start the recevie engine for the new socket.</li>
5146 <li>::EslTcp4Receive to restart the receive engine to release flow control.</li>
5147 <li>::EslTcp4RxComplete to continue the operation of the receive engine if flow control is not being applied.</li>
5148 <li>::EslUdp4Receive to restart the receive engine to release flow control.</li>
5149 <li>::EslUdp4RxComplete to continue the operation of the receive engine if flow control is not being applied.</li>
5150 <li>::EslUdp4SocketIsConfigured to start the recevie engine for the new socket.</li>
5153 @param [in] pPort Address of an ::ESL_PORT structure.
5163 ESL_PACKET
* pPacket
;
5164 ESL_SOCKET
* pSocket
;
5170 // Determine if a receive is already pending
5172 Status
= EFI_SUCCESS
;
5174 pSocket
= pPort
->pSocket
;
5175 if ( !EFI_ERROR ( pPort
->pSocket
->RxError
)) {
5176 if (( NULL
!= pPort
->pRxFree
)
5177 && ( !pSocket
->bRxDisable
)
5178 && ( PORT_STATE_CLOSE_STARTED
> pPort
->State
)) {
5180 // Start all of the pending receive operations
5182 while ( NULL
!= pPort
->pRxFree
) {
5184 // Determine if there are any free packets
5186 pPacket
= pSocket
->pRxFree
;
5187 if ( NULL
!= pPacket
) {
5189 // Remove this packet from the free list
5191 pSocket
->pRxFree
= pPacket
->pNext
;
5193 "0x%08x: Port removed packet 0x%08x from free list\r\n",
5199 // Allocate a packet structure
5201 Status
= EslSocketPacketAllocate ( &pPacket
,
5202 pSocket
->pApi
->RxPacketBytes
,
5203 pSocket
->pApi
->RxZeroBytes
,
5205 if ( EFI_ERROR ( Status
)) {
5207 DEBUG (( DEBUG_ERROR
| DEBUG_RX
,
5208 "0x%08x: Port failed to allocate RX packet, Status: %r\r\n",
5216 // Connect the IO and packet structures
5218 pIo
= pPort
->pRxFree
;
5219 pIo
->pPacket
= pPacket
;
5222 // Eliminate the need for IP4 and UDP4 specific routines by
5223 // clearing the RX data pointer here.
5225 // No driver buffer for this packet
5227 // +--------------------+
5230 // | +---------------+
5232 // | | RxData --> NULL
5233 // +----+---------------+
5235 pBuffer
= (UINT8
*)pIo
;
5236 pBuffer
= &pBuffer
[ pSocket
->pApi
->RxBufferOffset
];
5237 *(VOID
**)pBuffer
= NULL
;
5240 // Network specific receive packet initialization
5242 if ( NULL
!= pSocket
->pApi
->pfnRxStart
) {
5243 pSocket
->pApi
->pfnRxStart ( pPort
, pIo
);
5247 // Start the receive on the packet
5249 Status
= pPort
->pfnRxStart ( pPort
->pProtocol
.v
, &pIo
->Token
);
5250 if ( !EFI_ERROR ( Status
)) {
5251 DEBUG (( DEBUG_RX
| DEBUG_INFO
,
5252 "0x%08x: Packet receive pending on port 0x%08x\r\n",
5256 // Allocate the receive control structure
5258 pPort
->pRxFree
= pIo
->pNext
;
5261 // Mark this receive as pending
5263 pIo
->pNext
= pPort
->pRxActive
;
5264 pPort
->pRxActive
= pIo
;
5268 DEBUG (( DEBUG_RX
| DEBUG_INFO
,
5269 "ERROR - Failed to post a receive on port 0x%08x, Status: %r\r\n",
5272 if ( !EFI_ERROR ( pSocket
->RxError
)) {
5274 // Save the error status
5276 pSocket
->RxError
= Status
;
5282 pIo
->pPacket
= NULL
;
5283 pPacket
->pNext
= pSocket
->pRxFree
;
5284 pSocket
->pRxFree
= pPacket
;
5290 if ( NULL
== pPort
->pRxFree
) {
5291 DEBUG (( DEBUG_RX
| DEBUG_INFO
,
5292 "0x%08x: Port, no available ESL_IO_MGMT structures\r\n",
5295 if ( pSocket
->bRxDisable
) {
5296 DEBUG (( DEBUG_RX
| DEBUG_INFO
,
5297 "0x%08x: Port, receive disabled!\r\n",
5300 if ( PORT_STATE_CLOSE_STARTED
<= pPort
->State
) {
5301 DEBUG (( DEBUG_RX
| DEBUG_INFO
,
5302 "0x%08x: Port, is closing!\r\n",
5308 DEBUG (( DEBUG_ERROR
| DEBUG_RX
,
5309 "ERROR - Previous receive error, Status: %r\r\n",
5310 pPort
->pSocket
->RxError
));
5318 Shutdown the socket receive and transmit operations
5320 This routine sets a flag to stop future transmissions and calls
5321 the network specific layer to cancel the pending receive operation.
5323 The ::shutdown routine calls this routine to stop receive and transmit
5324 operations on the socket.
5326 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
5328 @param [in] How Which operations to stop
5330 @param [out] pErrno Address to receive the errno value upon completion.
5332 @retval EFI_SUCCESS - Socket operations successfully shutdown
5337 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
5344 ESL_SOCKET
* pSocket
;
5346 EFI_TPL TplPrevious
;
5353 Status
= EFI_SUCCESS
;
5356 // Validate the socket
5359 if ( NULL
!= pSocketProtocol
) {
5360 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
5363 // Verify that the socket is connected
5365 if ( pSocket
->bConnected
) {
5367 // Validate the How value
5369 if (( SHUT_RD
<= How
) && ( SHUT_RDWR
>= How
)) {
5371 // Synchronize with the socket layer
5373 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
5376 // Disable the receiver if requested
5378 if (( SHUT_RD
== How
) || ( SHUT_RDWR
== How
)) {
5379 pSocket
->bRxDisable
= TRUE
;
5383 // Disable the transmitter if requested
5385 if (( SHUT_WR
== How
) || ( SHUT_RDWR
== How
)) {
5386 pSocket
->bTxDisable
= TRUE
;
5390 // Cancel the pending receive operations
5392 if ( pSocket
->bRxDisable
) {
5394 // Walk the list of ports
5396 pPort
= pSocket
->pPortList
;
5397 while ( NULL
!= pPort
) {
5399 // Walk the list of active receive operations
5401 pIo
= pPort
->pRxActive
;
5402 while ( NULL
!= pIo
) {
5403 EslSocketRxCancel ( pPort
, pIo
);
5407 // Set the next port
5409 pPort
= pPort
->pLinkSocket
;
5414 // Release the socket layer synchronization
5416 RESTORE_TPL ( TplPrevious
);
5420 // Invalid How value
5422 pSocket
->errno
= EINVAL
;
5423 Status
= EFI_INVALID_PARAMETER
;
5428 // The socket is not connected
5430 pSocket
->errno
= ENOTCONN
;
5431 Status
= EFI_NOT_STARTED
;
5436 // Return the operation status
5438 if ( NULL
!= pErrno
) {
5439 if ( NULL
!= pSocket
) {
5440 *pErrno
= pSocket
->errno
;
5443 Status
= EFI_INVALID_PARAMETER
;
5447 DBG_EXIT_STATUS ( Status
);
5453 Send data using a network connection.
5455 This routine calls the network specific layer to queue the data
5456 for transmission. Eventually the buffer will reach the head of
5457 the queue and will get transmitted over the network by the
5458 \ref TransmitEngine. For datagram
5459 sockets (SOCK_DGRAM and SOCK_RAW) there is no guarantee that
5460 the data reaches the application running on the remote system.
5462 The ::sendto routine calls this routine to send data to the remote
5463 system. Note that ::send and ::write are layered on top of ::sendto.
5465 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
5467 @param [in] Flags Message control flags
5469 @param [in] BufferLength Length of the the buffer
5471 @param [in] pBuffer Address of a buffer containing the data to send
5473 @param [in] pDataLength Address to receive the number of data bytes sent
5475 @param [in] pAddress Network address of the remote system address
5477 @param [in] AddressLength Length of the remote network address structure
5479 @param [out] pErrno Address to receive the errno value upon completion.
5481 @retval EFI_SUCCESS - Socket data successfully queued for transmit
5486 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
5488 IN
size_t BufferLength
,
5489 IN CONST UINT8
* pBuffer
,
5490 OUT
size_t * pDataLength
,
5491 IN
const struct sockaddr
* pAddress
,
5492 IN socklen_t AddressLength
,
5496 ESL_SOCKET
* pSocket
;
5498 EFI_TPL TplPrevious
;
5505 Status
= EFI_SUCCESS
;
5508 // Validate the socket
5511 if ( NULL
!= pSocketProtocol
) {
5512 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
5515 // Return the transmit error if necessary
5517 if ( EFI_SUCCESS
!= pSocket
->TxError
) {
5518 pSocket
->errno
= EIO
;
5519 Status
= pSocket
->TxError
;
5520 pSocket
->TxError
= EFI_SUCCESS
;
5524 // Verify the socket state
5526 Status
= EslSocketIsConfigured ( pSocket
);
5527 if ( !EFI_ERROR ( Status
)) {
5529 // Verify that transmit is still allowed
5531 if ( !pSocket
->bTxDisable
) {
5533 // Validate the buffer length
5535 if (( NULL
== pDataLength
)
5536 && ( 0 > pDataLength
)
5537 && ( NULL
== pBuffer
)) {
5538 if ( NULL
== pDataLength
) {
5540 "ERROR - pDataLength is NULL!\r\n" ));
5542 else if ( NULL
== pBuffer
) {
5544 "ERROR - pBuffer is NULL!\r\n" ));
5548 "ERROR - Data length < 0!\r\n" ));
5550 Status
= EFI_INVALID_PARAMETER
;
5551 pSocket
->errno
= EFAULT
;
5555 // Validate the remote network address
5557 if (( NULL
!= pAddress
)
5558 && ( AddressLength
< pAddress
->sa_len
)) {
5560 "ERROR - Invalid sin_len field in address\r\n" ));
5561 Status
= EFI_INVALID_PARAMETER
;
5562 pSocket
->errno
= EFAULT
;
5568 if ( NULL
== pSocket
->pApi
->pfnTransmit
) {
5569 Status
= EFI_UNSUPPORTED
;
5570 pSocket
->errno
= ENOTSUP
;
5574 // Synchronize with the socket layer
5576 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
5579 // Poll the network to increase performance
5581 EslSocketRxPoll ( pSocket
);
5584 // Attempt to buffer the packet for transmission
5586 Status
= pSocket
->pApi
->pfnTransmit ( pSocket
,
5595 // Release the socket layer synchronization
5597 RESTORE_TPL ( TplPrevious
);
5604 // The transmitter was shutdown
5606 pSocket
->errno
= EPIPE
;
5607 Status
= EFI_NOT_STARTED
;
5614 // Return the operation status
5616 if ( NULL
!= pErrno
) {
5617 if ( NULL
!= pSocket
) {
5618 *pErrno
= pSocket
->errno
;
5621 Status
= EFI_INVALID_PARAMETER
;
5625 DBG_EXIT_STATUS ( Status
);
5631 Complete the transmit operation
5633 This support routine handles the transmit completion processing for
5634 the various network layers. It frees the ::ESL_IO_MGMT structure
5635 and and frees packet resources by calling ::EslSocketPacketFree.
5636 Transmit errors are logged in ESL_SOCKET::TxError.
5637 See the \ref TransmitEngine section.
5639 This routine is called by:
5641 <li>::EslIp4TxComplete</li>
5642 <li>::EslTcp4TxComplete</li>
5643 <li>::EslTcp4TxOobComplete</li>
5644 <li>::EslUdp4TxComplete</li>
5647 @param [in] pIo Address of an ::ESL_IO_MGMT structure
5648 @param [in] LengthInBytes Length of the data in bytes
5649 @param [in] Status Transmit operation status
5650 @param [in] pQueueType Zero terminated string describing queue type
5651 @param [in] ppQueueHead Transmit queue head address
5652 @param [in] ppQueueTail Transmit queue tail address
5653 @param [in] ppActive Active transmit queue address
5654 @param [in] ppFree Free transmit queue address
5658 EslSocketTxComplete (
5659 IN ESL_IO_MGMT
* pIo
,
5660 IN UINT32 LengthInBytes
,
5661 IN EFI_STATUS Status
,
5662 IN CONST CHAR8
* pQueueType
,
5663 IN ESL_PACKET
** ppQueueHead
,
5664 IN ESL_PACKET
** ppQueueTail
,
5665 IN ESL_IO_MGMT
** ppActive
,
5666 IN ESL_IO_MGMT
** ppFree
5669 ESL_PACKET
* pCurrentPacket
;
5670 ESL_IO_MGMT
* pIoNext
;
5671 ESL_PACKET
* pNextPacket
;
5672 ESL_PACKET
* pPacket
;
5674 ESL_SOCKET
* pSocket
;
5677 VERIFY_AT_TPL ( TPL_SOCKETS
);
5680 // Locate the active transmit packet
5682 pPacket
= pIo
->pPacket
;
5684 pSocket
= pPort
->pSocket
;
5689 pIo
->pPacket
= NULL
;
5692 // Remove the IO structure from the active list
5694 pIoNext
= *ppActive
;
5695 while (( NULL
!= pIoNext
) && ( pIoNext
!= pIo
) && ( pIoNext
->pNext
!= pIo
))
5697 pIoNext
= pIoNext
->pNext
;
5699 ASSERT ( NULL
!= pIoNext
);
5700 if ( pIoNext
== pIo
) {
5701 *ppActive
= pIo
->pNext
; // Beginning of list
5704 pIoNext
->pNext
= pIo
->pNext
; // Middle of list
5708 // Free the IO structure
5710 pIo
->pNext
= *ppFree
;
5714 // Display the results
5716 DEBUG (( DEBUG_TX
| DEBUG_INFO
,
5717 "0x%08x: pIo Released\r\n",
5721 // Save any transmit error
5723 if ( EFI_ERROR ( Status
)) {
5724 if ( !EFI_ERROR ( pSocket
->TxError
)) {
5725 pSocket
->TxError
= Status
;
5727 DEBUG (( DEBUG_TX
| DEBUG_INFO
,
5728 "ERROR - Transmit failure for %apacket 0x%08x, Status: %r\r\n",
5734 // Empty the normal transmit list
5736 pCurrentPacket
= pPacket
;
5737 pNextPacket
= *ppQueueHead
;
5738 while ( NULL
!= pNextPacket
) {
5739 pPacket
= pNextPacket
;
5740 pNextPacket
= pPacket
->pNext
;
5741 EslSocketPacketFree ( pPacket
, DEBUG_TX
);
5743 *ppQueueHead
= NULL
;
5744 *ppQueueTail
= NULL
;
5745 pPacket
= pCurrentPacket
;
5748 DEBUG (( DEBUG_TX
| DEBUG_INFO
,
5749 "0x%08x: %apacket transmitted %d bytes successfully\r\n",
5755 // Verify the transmit engine is still running
5757 if ( !pPort
->bCloseNow
) {
5759 // Start the next packet transmission
5761 EslSocketTxStart ( pPort
,
5770 // Release this packet
5772 EslSocketPacketFree ( pPacket
, DEBUG_TX
);
5775 // Finish the close operation if necessary
5777 if ( PORT_STATE_CLOSE_STARTED
<= pPort
->State
) {
5779 // Indicate that the transmit is complete
5781 EslSocketPortCloseTxDone ( pPort
);
5789 Transmit data using a network connection.
5791 This support routine starts a transmit operation on the
5792 underlying network layer.
5794 The network specific code calls this routine to start a
5795 transmit operation. See the \ref TransmitEngine section.
5797 @param [in] pPort Address of an ::ESL_PORT structure
5798 @param [in] ppQueueHead Transmit queue head address
5799 @param [in] ppQueueTail Transmit queue tail address
5800 @param [in] ppActive Active transmit queue address
5801 @param [in] ppFree Free transmit queue address
5806 IN ESL_PORT
* pPort
,
5807 IN ESL_PACKET
** ppQueueHead
,
5808 IN ESL_PACKET
** ppQueueTail
,
5809 IN ESL_IO_MGMT
** ppActive
,
5810 IN ESL_IO_MGMT
** ppFree
5815 ESL_PACKET
* pNextPacket
;
5816 ESL_PACKET
* pPacket
;
5817 VOID
** ppTokenData
;
5818 ESL_SOCKET
* pSocket
;
5826 Status
= EFI_SUCCESS
;
5829 // Get the packet from the queue head
5831 pPacket
= *ppQueueHead
;
5833 if (( NULL
!= pPacket
) && ( NULL
!= pIo
)) {
5834 pSocket
= pPort
->pSocket
;
5836 // *ppQueueHead: pSocket->pRxPacketListHead or pSocket->pRxOobPacketListHead
5839 // +------------+ +------------+ +------------+
5840 // Data | ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL
5841 // +------------+ +------------+ +------------+
5844 // *ppQueueTail: pSocket->pRxPacketListTail or pSocket->pRxOobPacketListTail
5847 // Remove the packet from the queue
5849 pNextPacket
= pPacket
->pNext
;
5850 *ppQueueHead
= pNextPacket
;
5851 if ( NULL
== pNextPacket
) {
5852 *ppQueueTail
= NULL
;
5854 pPacket
->pNext
= NULL
;
5857 // Eliminate the need for IP4 and UDP4 specific routines by
5858 // connecting the token with the TX data control structure here.
5860 // +--------------------+ +--------------------+
5861 // | ESL_IO_MGMT | | ESL_PACKET |
5863 // | +---------------+ +----------------+ |
5864 // | | Token | | Buffer Length | |
5865 // | | TxData --> | Buffer Address | |
5866 // | | | +----------------+---+
5867 // | | Event | | Data Buffer |
5868 // +----+---------------+ | |
5869 // +--------------------+
5871 // Compute the address of the TxData pointer in the token
5873 pBuffer
= (UINT8
*)&pIo
->Token
;
5874 pBuffer
= &pBuffer
[ pSocket
->TxTokenOffset
];
5875 ppTokenData
= (VOID
**)pBuffer
;
5878 // Compute the address of the TX data control structure in the packet
5880 // * EFI_IP4_TRANSMIT_DATA
5881 // * EFI_TCP4_TRANSMIT_DATA
5882 // * EFI_UDP4_TRANSMIT_DATA
5884 pBuffer
= (UINT8
*)pPacket
;
5885 pBuffer
= &pBuffer
[ pSocket
->TxPacketOffset
];
5888 // Connect the token to the transmit data control structure
5890 *ppTokenData
= (VOID
**)pBuffer
;
5893 // Display the results
5895 DEBUG (( DEBUG_TX
| DEBUG_INFO
,
5896 "0x%08x: pIo allocated for pPacket: 0x%08x\r\n",
5901 // Start the transmit operation
5903 Status
= pPort
->pfnTxStart ( pPort
->pProtocol
.v
,
5905 if ( !EFI_ERROR ( Status
)) {
5907 // Connect the structures
5909 pIo
->pPacket
= pPacket
;
5912 // +-------------+ +-------------+ +-------------+
5913 // Free | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
5914 // +-------------+ +-------------+ +-------------+
5917 // *ppFree: pPort->pTxFree or pTxOobFree
5920 // Remove the IO structure from the queue
5922 *ppFree
= pIo
->pNext
;
5925 // *ppActive: pPort->pTxActive or pTxOobActive
5928 // +-------------+ +-------------+ +-------------+
5929 // Active | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
5930 // +-------------+ +-------------+ +-------------+
5933 // Mark this packet as active
5935 pIo
->pPacket
= pPacket
;
5936 pIo
->pNext
= *ppActive
;
5941 // Display the transmit error
5943 DEBUG (( DEBUG_TX
| DEBUG_INFO
,
5944 "0x%08x, 0x%08x: pIo, pPacket transmit failure: %r\r\n",
5948 if ( EFI_SUCCESS
== pSocket
->TxError
) {
5949 pSocket
->TxError
= Status
;
5953 // Free the IO structure
5955 pIo
->pNext
= *ppFree
;
5959 // Discard the transmit buffer
5961 EslSocketPacketFree ( pPacket
, DEBUG_TX
);