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 // Attempt to use this configuration
1341 Status
= pPort
->pfnConfigure ( pPort
->pProtocol
.v
, pConfigData
);
1342 if ( EFI_ERROR ( Status
)) {
1343 DEBUG (( DEBUG_WARN
| DEBUG_BIND
,
1344 "WARNING - Port 0x%08x failed configuration, Status: %r\r\n",
1347 pPort
->pSocket
->errno
= ErrnoValue
;
1353 Status
= pPort
->pfnConfigure ( pPort
->pProtocol
.v
, NULL
);
1354 if ( EFI_ERROR ( Status
)) {
1355 DEBUG (( DEBUG_ERROR
| DEBUG_BIND
,
1356 "ERROR - Port 0x%08x failed configuration reset, Status: %r\r\n",
1359 ASSERT ( EFI_SUCCESS
== Status
);
1364 // Return the operation status
1366 DBG_EXIT_STATUS ( Status
);
1372 Determine if the socket is closed
1374 This routine checks the state of the socket to determine if
1375 the network specific layer has completed the close operation.
1377 The ::close routine polls this routine to determine when the
1378 close operation is complete. The close operation needs to
1379 reverse the operations of the ::EslSocketAllocate routine.
1381 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
1382 @param [out] pErrno Address to receive the errno value upon completion.
1384 @retval EFI_SUCCESS Socket successfully closed
1385 @retval EFI_NOT_READY Close still in progress
1386 @retval EFI_ALREADY Close operation already in progress
1387 @retval Other Failed to close the socket
1391 EslSocketClosePoll (
1392 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
1398 ESL_SOCKET
* pNextSocket
;
1399 ESL_SOCKET
* pSocket
;
1401 EFI_TPL TplPrevious
;
1409 Status
= EFI_SUCCESS
;
1412 // Synchronize with the socket layer
1414 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
1417 // Locate the socket
1419 pLayer
= &mEslLayer
;
1420 pNextSocket
= pLayer
->pSocketList
;
1421 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
1422 while ( NULL
!= pNextSocket
) {
1423 if ( pNextSocket
== pSocket
) {
1425 // Determine if the socket is in the closing state
1427 if ( SOCKET_STATE_CLOSED
== pSocket
->State
) {
1429 // Walk the list of ports
1431 if ( NULL
== pSocket
->pPortList
) {
1433 // All the ports are closed
1434 // Close the WaitAccept event if necessary
1436 if ( NULL
!= pSocket
->WaitAccept
) {
1437 Status
= gBS
->CloseEvent ( pSocket
->WaitAccept
);
1438 if ( !EFI_ERROR ( Status
)) {
1439 DEBUG (( DEBUG_SOCKET
| DEBUG_CLOSE
| DEBUG_POOL
,
1440 "0x%08x: Closed WaitAccept event\r\n",
1441 pSocket
->WaitAccept
));
1443 // Return the transmit status
1445 Status
= pSocket
->TxError
;
1446 if ( EFI_ERROR ( Status
)) {
1447 pSocket
->errno
= EIO
;
1451 DEBUG (( DEBUG_ERROR
| DEBUG_SOCKET
| DEBUG_CLOSE
| DEBUG_POOL
,
1452 "ERROR - Failed to close the WaitAccept event, Status: %r\r\n",
1454 ASSERT ( EFI_SUCCESS
== Status
);
1460 // At least one port is still open
1462 Status
= EFI_NOT_READY
;
1468 // SocketCloseStart was not called
1470 Status
= EFI_NOT_STARTED
;
1477 // Set the next socket
1479 pNextSocket
= pNextSocket
->pNext
;
1483 // Handle the error case where the socket was already closed
1485 if ( NULL
== pSocket
) {
1489 Status
= EFI_NOT_FOUND
;
1494 // Release the socket layer synchronization
1496 RESTORE_TPL ( TplPrevious
);
1499 // Return the operation status
1501 if ( NULL
!= pErrno
) {
1504 DBG_EXIT_STATUS ( Status
);
1510 Start the close operation on the socket
1512 This routine calls the network specific layer to initiate the
1513 close state machine. This routine then calls the network
1514 specific layer to determine if the close state machine has gone
1515 to completion. The result from this poll is returned to the
1518 The ::close routine calls this routine to start the close
1519 operation which reverses the operations of the
1520 ::EslSocketAllocate routine. The close routine then polls
1521 the ::EslSocketClosePoll routine to determine when the
1524 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
1525 @param [in] bCloseNow Boolean to control close behavior
1526 @param [out] pErrno Address to receive the errno value upon completion.
1528 @retval EFI_SUCCESS Socket successfully closed
1529 @retval EFI_NOT_READY Close still in progress
1530 @retval EFI_ALREADY Close operation already in progress
1531 @retval Other Failed to close the socket
1535 EslSocketCloseStart (
1536 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
1537 IN BOOLEAN bCloseNow
,
1542 ESL_PORT
* pNextPort
;
1544 ESL_SOCKET
* pSocket
;
1546 EFI_TPL TplPrevious
;
1553 Status
= EFI_SUCCESS
;
1557 // Synchronize with the socket layer
1559 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
1562 // Determine if the socket is already closed
1564 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
1565 if ( SOCKET_STATE_CLOSED
> pSocket
->State
) {
1567 // Update the socket state
1569 pSocket
->State
= SOCKET_STATE_CLOSED
;
1572 // Walk the list of ports
1574 pPort
= pSocket
->pPortList
;
1575 while ( NULL
!= pPort
) {
1577 // Start closing the ports
1579 pNextPort
= pPort
->pLinkSocket
;
1580 Status
= EslSocketPortCloseStart ( pPort
,
1582 DEBUG_CLOSE
| DEBUG_LISTEN
| DEBUG_CONNECTION
);
1583 if (( EFI_SUCCESS
!= Status
)
1584 && ( EFI_NOT_READY
!= Status
)) {
1590 // Set the next port
1596 // Attempt to finish closing the socket
1598 if ( NULL
== pPort
) {
1599 Status
= EslSocketClosePoll ( pSocketProtocol
, &errno
);
1603 Status
= EFI_NOT_READY
;
1608 // Release the socket layer synchronization
1610 RESTORE_TPL ( TplPrevious
);
1613 // Return the operation status
1615 if ( NULL
!= pErrno
) {
1618 DBG_EXIT_STATUS ( Status
);
1624 Connect to a remote system via the network.
1626 This routine calls the network specific layer to establish
1627 the remote system address and establish the connection to
1630 The ::connect routine calls this routine to establish a
1631 connection with the specified remote system. This routine
1632 is designed to be polled by the connect routine for completion
1633 of the network connection.
1635 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
1637 @param [in] pSockAddr Network address of the remote system.
1639 @param [in] SockAddrLength Length in bytes of the network address.
1641 @param [out] pErrno Address to receive the errno value upon completion.
1643 @retval EFI_SUCCESS The connection was successfully established.
1644 @retval EFI_NOT_READY The connection is in progress, call this routine again.
1645 @retval Others The connection attempt failed.
1650 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
1651 IN
const struct sockaddr
* pSockAddr
,
1652 IN socklen_t SockAddrLength
,
1656 struct sockaddr_in6 LocalAddress
;
1658 ESL_SOCKET
* pSocket
;
1660 EFI_TPL TplPrevious
;
1662 DEBUG (( DEBUG_CONNECT
, "Entering SocketConnect\r\n" ));
1667 Status
= EFI_SUCCESS
;
1670 // Validate the socket
1673 if ( NULL
!= pSocketProtocol
) {
1674 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
1677 // Validate the name length
1679 if ( SockAddrLength
< ( sizeof ( struct sockaddr
) - sizeof ( pSockAddr
->sa_data
))) {
1680 DEBUG (( DEBUG_CONNECT
,
1681 "ERROR - Invalid bind name length: %d\r\n",
1683 Status
= EFI_INVALID_PARAMETER
;
1684 pSocket
->errno
= EINVAL
;
1693 // Synchronize with the socket layer
1695 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
1698 // Validate the socket state
1700 switch ( pSocket
->State
) {
1703 // Wrong socket state
1705 pSocket
->errno
= EIO
;
1706 Status
= EFI_DEVICE_ERROR
;
1709 case SOCKET_STATE_NOT_CONFIGURED
:
1710 case SOCKET_STATE_BOUND
:
1712 // Validate the address length
1714 if ( SockAddrLength
>= pSocket
->pApi
->MinimumAddressLength
) {
1718 if ( NULL
== pSocket
->pApi
->pfnRemoteAddrSet
) {
1720 // Already connected
1722 pSocket
->errno
= ENOTSUP
;
1723 Status
= EFI_UNSUPPORTED
;
1727 // Determine if BIND was already called
1729 if ( NULL
== pSocket
->pPortList
) {
1731 // Allow any local port
1733 ZeroMem ( &LocalAddress
, sizeof ( LocalAddress
));
1734 LocalAddress
.sin6_len
= (uint8_t)pSocket
->pApi
->MinimumAddressLength
;
1735 LocalAddress
.sin6_family
= pSocket
->pApi
->AddressFamily
;
1736 Status
= EslSocketBind ( &pSocket
->SocketProtocol
,
1737 (struct sockaddr
*)&LocalAddress
,
1738 LocalAddress
.sin6_len
,
1741 if ( NULL
!= pSocket
->pPortList
) {
1743 // Walk the list of ports
1745 pPort
= pSocket
->pPortList
;
1746 while ( NULL
!= pPort
) {
1748 // Set the remote address
1750 Status
= pSocket
->pApi
->pfnRemoteAddrSet ( pPort
,
1753 if ( EFI_ERROR ( Status
)) {
1758 // Set the next port
1760 pPort
= pPort
->pLinkSocket
;
1766 if (( !EFI_ERROR ( Status
))
1767 && ( NULL
!= pSocket
->pApi
->pfnConnectStart
)) {
1769 // Initiate the connection with the remote system
1771 Status
= pSocket
->pApi
->pfnConnectStart ( pSocket
);
1774 // Set the next state if connecting
1776 if ( EFI_NOT_READY
== Status
) {
1777 pSocket
->State
= SOCKET_STATE_CONNECTING
;
1784 DEBUG (( DEBUG_CONNECT
,
1785 "ERROR - Invalid address length: %d\r\n",
1787 Status
= EFI_INVALID_PARAMETER
;
1788 pSocket
->errno
= EINVAL
;
1792 case SOCKET_STATE_CONNECTING
:
1794 // Poll the network adapter
1796 EslSocketRxPoll ( pSocket
);
1799 // Poll for connection completion
1801 if ( NULL
== pSocket
->pApi
->pfnConnectPoll
) {
1803 // Already connected
1805 pSocket
->errno
= EISCONN
;
1806 Status
= EFI_ALREADY_STARTED
;
1809 Status
= pSocket
->pApi
->pfnConnectPoll ( pSocket
);
1812 // Set the next state if connected
1814 if ( EFI_NOT_READY
!= Status
) {
1815 if ( !EFI_ERROR ( Status
)) {
1816 pSocket
->State
= SOCKET_STATE_CONNECTED
;
1819 // Start the receive operations
1821 EslSocketRxStart ( pSocket
->pPortList
);
1824 pSocket
->State
= SOCKET_STATE_BOUND
;
1830 case SOCKET_STATE_CONNECTED
:
1832 // Already connected
1834 pSocket
->errno
= EISCONN
;
1835 Status
= EFI_ALREADY_STARTED
;
1840 // Release the socket layer synchronization
1842 RESTORE_TPL ( TplPrevious
);
1847 // Return the operation status
1849 if ( NULL
!= pErrno
) {
1850 if ( NULL
!= pSocket
) {
1851 *pErrno
= pSocket
->errno
;
1855 // Bad socket protocol
1857 DEBUG (( DEBUG_ERROR
| DEBUG_CONNECT
,
1858 "ERROR - pSocketProtocol invalid!\r\n" ));
1859 Status
= EFI_INVALID_PARAMETER
;
1865 // Return the operation status
1867 DEBUG (( DEBUG_CONNECT
, "Exiting SocketConnect, Status: %r\r\n", Status
));
1873 Copy a fragmented buffer into a destination buffer.
1875 This support routine copies a fragmented buffer to the caller specified buffer.
1877 This routine is called by ::EslIp4Receive and ::EslUdp4Receive.
1879 @param [in] FragmentCount Number of fragments in the table
1881 @param [in] pFragmentTable Address of an EFI_IP4_FRAGMENT_DATA structure
1883 @param [in] BufferLength Length of the the buffer
1885 @param [in] pBuffer Address of a buffer to receive the data.
1887 @param [in] pDataLength Number of received data bytes in the buffer.
1889 @return Returns the address of the next free byte in the buffer.
1893 EslSocketCopyFragmentedBuffer (
1894 IN UINT32 FragmentCount
,
1895 IN EFI_IP4_FRAGMENT_DATA
* pFragmentTable
,
1896 IN
size_t BufferLength
,
1898 OUT
size_t * pDataLength
1909 // Validate the IP and UDP structures are identical
1911 ASSERT ( OFFSET_OF ( EFI_IP4_FRAGMENT_DATA
, FragmentLength
)
1912 == OFFSET_OF ( EFI_UDP4_FRAGMENT_DATA
, FragmentLength
));
1913 ASSERT ( OFFSET_OF ( EFI_IP4_FRAGMENT_DATA
, FragmentBuffer
)
1914 == OFFSET_OF ( EFI_UDP4_FRAGMENT_DATA
, FragmentBuffer
));
1917 // Copy the received data
1920 pBufferEnd
= &pBuffer
[ BufferLength
];
1921 while (( pBufferEnd
> pBuffer
) && ( FragmentCount
> Fragment
)) {
1923 // Determine the amount of received data
1925 pData
= pFragmentTable
[Fragment
].FragmentBuffer
;
1926 BytesToCopy
= pFragmentTable
[Fragment
].FragmentLength
;
1927 if (((size_t)( pBufferEnd
- pBuffer
)) < BytesToCopy
) {
1928 BytesToCopy
= pBufferEnd
- pBuffer
;
1932 // Move the data into the buffer
1935 "0x%08x --> 0x%08x: Copy data 0x%08x bytes\r\n",
1939 CopyMem ( pBuffer
, pData
, BytesToCopy
);
1940 pBuffer
+= BytesToCopy
;
1945 // Return the data length and the buffer address
1947 *pDataLength
= BufferLength
- ( pBufferEnd
- pBuffer
);
1948 DBG_EXIT_HEX ( pBuffer
);
1956 This routine frees the socket structure and handle resources.
1958 The ::close routine calls EslServiceFreeProtocol which then calls
1959 this routine to free the socket context structure and close the
1962 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
1964 @param [out] pErrno Address to receive the errno value upon completion.
1966 @retval EFI_SUCCESS The socket resources were returned successfully.
1971 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
1975 EFI_HANDLE ChildHandle
;
1978 ESL_SOCKET
* pSocket
;
1979 ESL_SOCKET
* pSocketPrevious
;
1981 EFI_TPL TplPrevious
;
1990 Status
= EFI_INVALID_PARAMETER
;
1993 // Validate the socket
1995 pLayer
= &mEslLayer
;
1996 if ( NULL
!= pSocketProtocol
) {
1997 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
2000 // Synchronize with the socket layer
2002 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
2005 // Walk the socket list
2007 pSocketPrevious
= pLayer
->pSocketList
;
2008 if ( NULL
!= pSocketPrevious
) {
2009 if ( pSocket
== pSocketPrevious
) {
2011 // Remove the socket from the head of the list
2013 pLayer
->pSocketList
= pSocket
->pNext
;
2017 // Find the socket in the middle of the list
2019 while (( NULL
!= pSocketPrevious
)
2020 && ( pSocket
!= pSocketPrevious
->pNext
)) {
2022 // Set the next socket
2024 pSocketPrevious
= pSocketPrevious
->pNext
;
2026 if ( NULL
!= pSocketPrevious
) {
2028 // Remove the socket from the middle of the list
2030 pSocketPrevious
= pSocket
->pNext
;
2035 DEBUG (( DEBUG_ERROR
| DEBUG_POOL
,
2036 "ERROR - Socket list is empty!\r\n" ));
2040 // Release the socket layer synchronization
2042 RESTORE_TPL ( TplPrevious
);
2045 // Determine if the socket was found
2047 if ( NULL
!= pSocketPrevious
) {
2048 pSocket
->pNext
= NULL
;
2051 // Remove the socket protocol
2053 ChildHandle
= pSocket
->SocketProtocol
.SocketHandle
;
2054 Status
= gBS
->UninstallMultipleProtocolInterfaces (
2056 &gEfiSocketProtocolGuid
,
2057 &pSocket
->SocketProtocol
,
2059 if ( !EFI_ERROR ( Status
)) {
2060 DEBUG (( DEBUG_POOL
| DEBUG_INFO
,
2061 "Removed: gEfiSocketProtocolGuid from 0x%08x\r\n",
2065 // Free the socket structure
2067 Status
= gBS
->FreePool ( pSocket
);
2068 if ( !EFI_ERROR ( Status
)) {
2069 DEBUG (( DEBUG_POOL
,
2070 "0x%08x: Free pSocket, %d bytes\r\n",
2072 sizeof ( *pSocket
)));
2076 DEBUG (( DEBUG_ERROR
| DEBUG_POOL
,
2077 "ERROR - Failed to free pSocket 0x%08x, Status: %r\r\n",
2083 DEBUG (( DEBUG_ERROR
| DEBUG_POOL
| DEBUG_INFO
,
2084 "ERROR - Failed to remove gEfiSocketProtocolGuid from 0x%08x, Status: %r\r\n",
2090 DEBUG (( DEBUG_ERROR
| DEBUG_INFO
,
2091 "ERROR - The socket was not in the socket list!\r\n" ));
2092 Status
= EFI_NOT_FOUND
;
2096 DEBUG (( DEBUG_ERROR
,
2097 "ERROR - Invalid parameter pSocketProtocol is NULL\r\n" ));
2101 // Return the errno value if possible
2103 if ( NULL
!= pErrno
) {
2108 // Return the operation status
2110 DBG_EXIT_STATUS ( Status
);
2116 Get the local address.
2118 This routine calls the network specific layer to get the network
2119 address of the local host connection point.
2121 The ::getsockname routine calls this routine to obtain the network
2122 address associated with the local host connection point.
2124 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
2126 @param [out] pAddress Network address to receive the local system address
2128 @param [in,out] pAddressLength Length of the local network address structure
2130 @param [out] pErrno Address to receive the errno value upon completion.
2132 @retval EFI_SUCCESS - Local address successfully returned
2136 EslSocketGetLocalAddress (
2137 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
2138 OUT
struct sockaddr
* pAddress
,
2139 IN OUT socklen_t
* pAddressLength
,
2143 socklen_t LengthInBytes
;
2145 ESL_SOCKET
* pSocket
;
2147 EFI_TPL TplPrevious
;
2154 Status
= EFI_SUCCESS
;
2157 // Validate the socket
2160 if ( NULL
!= pSocketProtocol
) {
2161 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
2164 // Verify the socket state
2166 EslSocketIsConfigured ( pSocket
);
2167 if ( pSocket
->bAddressSet
) {
2169 // Verify the address buffer and length address
2171 if (( NULL
!= pAddress
) && ( NULL
!= pAddressLength
)) {
2175 if ( NULL
== pSocket
->pApi
->pfnLocalAddrGet
) {
2176 Status
= EFI_UNSUPPORTED
;
2177 pSocket
->errno
= ENOTSUP
;
2181 // Synchronize with the socket layer
2183 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
2186 // Verify that there is just a single connection
2188 pPort
= pSocket
->pPortList
;
2189 if ( NULL
!= pPort
) {
2191 // Verify the address length
2193 LengthInBytes
= pSocket
->pApi
->AddressLength
;
2194 if (( LengthInBytes
<= *pAddressLength
)
2195 && ( 255 >= LengthInBytes
)) {
2197 // Return the local address and address length
2199 ZeroMem ( pAddress
, LengthInBytes
);
2200 pAddress
->sa_len
= (uint8_t)LengthInBytes
;
2201 *pAddressLength
= pAddress
->sa_len
;
2202 pSocket
->pApi
->pfnLocalAddrGet ( pPort
, pAddress
);
2204 Status
= EFI_SUCCESS
;
2207 pSocket
->errno
= EINVAL
;
2208 Status
= EFI_INVALID_PARAMETER
;
2212 pSocket
->errno
= ENOTCONN
;
2213 Status
= EFI_NOT_STARTED
;
2217 // Release the socket layer synchronization
2219 RESTORE_TPL ( TplPrevious
);
2223 pSocket
->errno
= EINVAL
;
2224 Status
= EFI_INVALID_PARAMETER
;
2231 Status
= EFI_NOT_STARTED
;
2232 pSocket
->errno
= EADDRNOTAVAIL
;
2237 // Return the operation status
2239 if ( NULL
!= pErrno
) {
2240 if ( NULL
!= pSocket
) {
2241 *pErrno
= pSocket
->errno
;
2244 Status
= EFI_INVALID_PARAMETER
;
2248 DBG_EXIT_STATUS ( Status
);
2254 Get the peer address.
2256 This routine calls the network specific layer to get the remote
2257 system connection point.
2259 The ::getpeername routine calls this routine to obtain the network
2260 address of the remote connection point.
2262 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
2264 @param [out] pAddress Network address to receive the remote system address
2266 @param [in,out] pAddressLength Length of the remote network address structure
2268 @param [out] pErrno Address to receive the errno value upon completion.
2270 @retval EFI_SUCCESS - Remote address successfully returned
2274 EslSocketGetPeerAddress (
2275 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
2276 OUT
struct sockaddr
* pAddress
,
2277 IN OUT socklen_t
* pAddressLength
,
2281 socklen_t LengthInBytes
;
2283 ESL_SOCKET
* pSocket
;
2285 EFI_TPL TplPrevious
;
2292 Status
= EFI_SUCCESS
;
2295 // Validate the socket
2298 if ( NULL
!= pSocketProtocol
) {
2299 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
2302 // Verify the socket state
2304 Status
= EslSocketIsConfigured ( pSocket
);
2305 if ( !EFI_ERROR ( Status
)) {
2309 if ( NULL
== pSocket
->pApi
->pfnRemoteAddrGet
) {
2310 Status
= EFI_UNSUPPORTED
;
2311 pSocket
->errno
= ENOTSUP
;
2315 // Verify the address buffer and length address
2317 if (( NULL
!= pAddress
) && ( NULL
!= pAddressLength
)) {
2319 // Verify the socket state
2321 if ( SOCKET_STATE_CONNECTED
== pSocket
->State
) {
2323 // Synchronize with the socket layer
2325 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
2328 // Verify that there is just a single connection
2330 pPort
= pSocket
->pPortList
;
2331 if (( NULL
!= pPort
) && ( NULL
== pPort
->pLinkSocket
)) {
2333 // Verify the address length
2335 LengthInBytes
= pSocket
->pApi
->AddressLength
;
2336 if ( LengthInBytes
<= *pAddressLength
) {
2338 // Return the local address
2340 ZeroMem ( pAddress
, LengthInBytes
);
2341 pAddress
->sa_len
= (uint8_t)LengthInBytes
;
2342 *pAddressLength
= pAddress
->sa_len
;
2343 pSocket
->pApi
->pfnRemoteAddrGet ( pPort
, pAddress
);
2345 Status
= EFI_SUCCESS
;
2348 pSocket
->errno
= EINVAL
;
2349 Status
= EFI_INVALID_PARAMETER
;
2353 pSocket
->errno
= ENOTCONN
;
2354 Status
= EFI_NOT_STARTED
;
2358 // Release the socket layer synchronization
2360 RESTORE_TPL ( TplPrevious
);
2363 pSocket
->errno
= ENOTCONN
;
2364 Status
= EFI_NOT_STARTED
;
2368 pSocket
->errno
= EINVAL
;
2369 Status
= EFI_INVALID_PARAMETER
;
2376 // Return the operation status
2378 if ( NULL
!= pErrno
) {
2379 if ( NULL
!= pSocket
) {
2380 *pErrno
= pSocket
->errno
;
2383 Status
= EFI_INVALID_PARAMETER
;
2387 DBG_EXIT_STATUS ( Status
);
2393 Free the ESL_IO_MGMT event and structure
2395 This support routine walks the free list to close the event in
2396 the ESL_IO_MGMT structure and remove the structure from the free
2399 See the \ref TransmitEngine section.
2401 @param [in] pPort Address of an ::ESL_PORT structure
2402 @param [in] ppFreeQueue Address of the free queue head
2403 @param [in] DebugFlags Flags for debug messages
2404 @param [in] pEventName Zero terminated string containing the event name
2406 @retval EFI_SUCCESS - The structures were properly initialized
2411 IN ESL_PORT
* pPort
,
2412 IN ESL_IO_MGMT
** ppFreeQueue
,
2413 IN UINTN DebugFlags
,
2414 IN CHAR8
* pEventName
2420 ESL_SOCKET
* pSocket
;
2428 Status
= EFI_SUCCESS
;
2431 // Walk the list of IO structures
2433 pSocket
= pPort
->pSocket
;
2434 while ( *ppFreeQueue
) {
2436 // Free the event for this structure
2439 pBuffer
= (UINT8
*)pIo
;
2440 pBuffer
= &pBuffer
[ pSocket
->TxTokenEventOffset
];
2441 pEvent
= (EFI_EVENT
*)pBuffer
;
2442 Status
= gBS
->CloseEvent ( *pEvent
);
2443 if ( EFI_ERROR ( Status
)) {
2444 DEBUG (( DEBUG_ERROR
| DebugFlags
,
2445 "ERROR - Failed to close the %a event, Status: %r\r\n",
2448 pSocket
->errno
= ENOMEM
;
2451 DEBUG (( DebugFlags
,
2452 "0x%08x: Closed %a event 0x%08x\r\n",
2458 // Remove this structure from the queue
2460 *ppFreeQueue
= pIo
->pNext
;
2464 // Return the operation status
2466 DBG_EXIT_STATUS ( Status
);
2472 Initialize the ESL_IO_MGMT structures
2474 This support routine initializes the ESL_IO_MGMT structure and
2475 places them on to a free list.
2477 This routine is called by ::EslSocketPortAllocate routines to prepare
2478 the transmit engines. See the \ref TransmitEngine section.
2480 @param [in] pPort Address of an ::ESL_PORT structure
2481 @param [in, out] ppIo Address containing the first structure address. Upon
2482 return this buffer contains the next structure address.
2483 @param [in] TokenCount Number of structures to initialize
2484 @param [in] ppFreeQueue Address of the free queue head
2485 @param [in] DebugFlags Flags for debug messages
2486 @param [in] pEventName Zero terminated string containing the event name
2487 @param [in] pfnCompletion Completion routine address
2489 @retval EFI_SUCCESS - The structures were properly initialized
2494 IN ESL_PORT
* pPort
,
2495 IN ESL_IO_MGMT
** ppIo
,
2496 IN UINTN TokenCount
,
2497 IN ESL_IO_MGMT
** ppFreeQueue
,
2498 IN UINTN DebugFlags
,
2499 IN CHAR8
* pEventName
,
2500 IN PFN_API_IO_COMPLETE pfnCompletion
2506 ESL_SOCKET
* pSocket
;
2514 Status
= EFI_SUCCESS
;
2517 // Walk the list of IO structures
2519 pSocket
= pPort
->pSocket
;
2521 pEnd
= &pIo
[ TokenCount
];
2522 while ( pEnd
> pIo
) {
2524 // Initialize the IO structure
2527 pIo
->pPacket
= NULL
;
2530 // Allocate the event for this structure
2532 pEvent
= (EFI_EVENT
*)&(((UINT8
*)pIo
)[ pSocket
->TxTokenEventOffset
]);
2533 Status
= gBS
->CreateEvent ( EVT_NOTIFY_SIGNAL
,
2535 (EFI_EVENT_NOTIFY
)pfnCompletion
,
2538 if ( EFI_ERROR ( Status
)) {
2539 DEBUG (( DEBUG_ERROR
| DebugFlags
,
2540 "ERROR - Failed to create the %a event, Status: %r\r\n",
2543 pSocket
->errno
= ENOMEM
;
2546 DEBUG (( DebugFlags
,
2547 "0x%08x: Created %a event 0x%08x\r\n",
2553 // Add this structure to the queue
2555 pIo
->pNext
= *ppFreeQueue
;
2559 // Set the next structure
2565 // Save the next structure
2570 // Return the operation status
2572 DBG_EXIT_STATUS ( Status
);
2578 Determine if the socket is configured
2580 This support routine is called to determine if the socket if the
2581 configuration call was made to the network layer. The following
2582 routines call this routine to verify that they may be successful
2583 in their operations:
2585 <li>::EslSocketGetLocalAddress</li>
2586 <li>::EslSocketGetPeerAddress</li>
2587 <li>::EslSocketPoll</li>
2588 <li>::EslSocketReceive</li>
2589 <li>::EslSocketTransmit</li>
2592 @param [in] pSocket Address of an ::ESL_SOCKET structure
2594 @retval EFI_SUCCESS - The socket is configured
2598 EslSocketIsConfigured (
2599 IN ESL_SOCKET
* pSocket
2603 EFI_TPL TplPrevious
;
2608 Status
= EFI_SUCCESS
;
2611 // Verify the socket state
2613 if ( !pSocket
->bConfigured
) {
2619 if ( NULL
== pSocket
->pApi
->pfnIsConfigured
) {
2620 Status
= EFI_UNSUPPORTED
;
2621 pSocket
->errno
= ENOTSUP
;
2625 // Synchronize with the socket layer
2627 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
2630 // Determine if the socket is configured
2632 Status
= pSocket
->pApi
->pfnIsConfigured ( pSocket
);
2635 // Release the socket layer synchronization
2637 RESTORE_TPL ( TplPrevious
);
2640 // Set errno if a failure occurs
2642 if ( EFI_ERROR ( Status
)) {
2643 pSocket
->errno
= EADDRNOTAVAIL
;
2647 DBG_EXIT_STATUS ( Status
);
2651 // Return the configuration status
2658 Establish the known port to listen for network connections.
2660 This routine calls into the network protocol layer to establish
2661 a handler that is called upon connection completion. The handler
2662 is responsible for inserting the connection into the FIFO.
2664 The ::listen routine indirectly calls this routine to place the
2665 socket into a state that enables connection attempts. Connections
2666 are placed in a FIFO that is serviced by the application. The
2667 application calls the ::accept (::EslSocketAccept) routine to
2668 remove the next connection from the FIFO and get the associated
2671 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
2673 @param [in] Backlog Backlog specifies the maximum FIFO depth for
2674 the connections waiting for the application
2675 to call accept. Connection attempts received
2676 while the queue is full are refused.
2678 @param [out] pErrno Address to receive the errno value upon completion.
2680 @retval EFI_SUCCESS - Socket successfully created
2681 @retval Other - Failed to enable the socket for listen
2686 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
2691 ESL_SOCKET
* pSocket
;
2693 EFI_STATUS TempStatus
;
2694 EFI_TPL TplPrevious
;
2701 Status
= EFI_SUCCESS
;
2704 // Validate the socket
2707 if ( NULL
!= pSocketProtocol
) {
2708 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
2713 if ( NULL
== pSocket
->pApi
->pfnListen
) {
2714 Status
= EFI_UNSUPPORTED
;
2715 pSocket
->errno
= ENOTSUP
;
2721 pSocket
->Status
= EFI_SUCCESS
;
2725 // Verify that the bind operation was successful
2727 if ( SOCKET_STATE_BOUND
== pSocket
->State
) {
2729 // Synchronize with the socket layer
2731 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
2734 // Create the event for SocketAccept completion
2736 Status
= gBS
->CreateEvent ( 0,
2740 &pSocket
->WaitAccept
);
2741 if ( !EFI_ERROR ( Status
)) {
2742 DEBUG (( DEBUG_POOL
,
2743 "0x%08x: Created WaitAccept event\r\n",
2744 pSocket
->WaitAccept
));
2746 // Set the maximum FIFO depth
2748 if ( 0 >= Backlog
) {
2749 Backlog
= MAX_PENDING_CONNECTIONS
;
2752 if ( SOMAXCONN
< Backlog
) {
2753 Backlog
= SOMAXCONN
;
2756 pSocket
->MaxFifoDepth
= Backlog
;
2761 // Initiate the connection attempt listen
2763 Status
= pSocket
->pApi
->pfnListen ( pSocket
);
2766 // Place the socket in the listen state if successful
2768 if ( !EFI_ERROR ( Status
)) {
2769 pSocket
->State
= SOCKET_STATE_LISTENING
;
2770 pSocket
->bListenCalled
= TRUE
;
2774 // Not waiting for SocketAccept to complete
2776 TempStatus
= gBS
->CloseEvent ( pSocket
->WaitAccept
);
2777 if ( !EFI_ERROR ( TempStatus
)) {
2778 DEBUG (( DEBUG_POOL
,
2779 "0x%08x: Closed WaitAccept event\r\n",
2780 pSocket
->WaitAccept
));
2781 pSocket
->WaitAccept
= NULL
;
2784 DEBUG (( DEBUG_ERROR
| DEBUG_POOL
,
2785 "ERROR - Failed to close WaitAccept event, Status: %r\r\n",
2787 ASSERT ( EFI_SUCCESS
== TempStatus
);
2792 DEBUG (( DEBUG_ERROR
| DEBUG_LISTEN
,
2793 "ERROR - Failed to create the WaitAccept event, Status: %r\r\n",
2795 pSocket
->errno
= ENOMEM
;
2799 // Release the socket layer synchronization
2801 RESTORE_TPL ( TplPrevious
);
2804 DEBUG (( DEBUG_ERROR
| DEBUG_LISTEN
,
2805 "ERROR - Bind operation must be performed first!\r\n" ));
2806 pSocket
->errno
= ( SOCKET_STATE_NOT_CONFIGURED
== pSocket
->State
) ? EDESTADDRREQ
2808 Status
= EFI_NO_MAPPING
;
2814 // Return the operation status
2816 if ( NULL
!= pErrno
) {
2817 if ( NULL
!= pSocket
) {
2818 *pErrno
= pSocket
->errno
;
2821 Status
= EFI_INVALID_PARAMETER
;
2825 DBG_EXIT_STATUS ( Status
);
2831 Get the socket options
2833 This routine handles the socket level options and passes the
2834 others to the network specific layer.
2836 The ::getsockopt routine calls this routine to retrieve the
2837 socket options one at a time by name.
2839 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
2840 @param [in] level Option protocol level
2841 @param [in] OptionName Name of the option
2842 @param [out] pOptionValue Buffer to receive the option value
2843 @param [in,out] pOptionLength Length of the buffer in bytes,
2844 upon return length of the option value in bytes
2845 @param [out] pErrno Address to receive the errno value upon completion.
2847 @retval EFI_SUCCESS - Socket data successfully received
2851 EslSocketOptionGet (
2852 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
2855 OUT
void * __restrict pOptionValue
,
2856 IN OUT socklen_t
* __restrict pOptionLength
,
2861 socklen_t LengthInBytes
;
2863 CONST UINT8
* pOptionData
;
2864 ESL_SOCKET
* pSocket
;
2873 Status
= EFI_INVALID_PARAMETER
;
2876 // Validate the socket
2879 if ( NULL
== pSocketProtocol
) {
2880 DEBUG (( DEBUG_OPTION
, "ERROR - pSocketProtocol is NULL!\r\n" ));
2882 else if ( NULL
== pOptionValue
) {
2883 DEBUG (( DEBUG_OPTION
, "ERROR - No option buffer specified\r\n" ));
2885 else if ( NULL
== pOptionLength
) {
2886 DEBUG (( DEBUG_OPTION
, "ERROR - Option length not specified!\r\n" ));
2889 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
2891 MaxBytes
= *pOptionLength
;
2896 // See if the protocol will handle the option
2898 if ( NULL
!= pSocket
->pApi
->pfnOptionGet
) {
2899 if ( pSocket
->pApi
->DefaultProtocol
== level
) {
2900 Status
= pSocket
->pApi
->pfnOptionGet ( pSocket
,
2902 (CONST
void ** __restrict
)&pOptionData
,
2904 errno
= pSocket
->errno
;
2909 // Protocol not supported
2911 DEBUG (( DEBUG_OPTION
,
2912 "ERROR - The socket does not support this protocol!\r\n" ));
2917 // Protocol level not supported
2919 DEBUG (( DEBUG_OPTION
,
2920 "ERROR - %a does not support any options!\r\n",
2921 pSocket
->pApi
->pName
));
2923 errno
= ENOPROTOOPT
;
2924 Status
= EFI_INVALID_PARAMETER
;
2928 switch ( OptionName
) {
2931 // Socket option not supported
2933 DEBUG (( DEBUG_INFO
| DEBUG_OPTION
, "ERROR - Invalid socket option!\r\n" ));
2935 Status
= EFI_INVALID_PARAMETER
;
2940 // Return the listen flag
2942 pOptionData
= (CONST UINT8
*)&pSocket
->bListenCalled
;
2943 LengthInBytes
= sizeof ( pSocket
->bListenCalled
);
2948 // Return the debug flags
2950 pOptionData
= (CONST UINT8
*)&pSocket
->bOobInLine
;
2951 LengthInBytes
= sizeof ( pSocket
->bOobInLine
);
2956 // Return the out-of-band inline flag
2958 pOptionData
= (CONST UINT8
*)&pSocket
->bOobInLine
;
2959 LengthInBytes
= sizeof ( pSocket
->bOobInLine
);
2964 // Return the receive timeout
2966 pOptionData
= (CONST UINT8
*)&pSocket
->RxTimeout
;
2967 LengthInBytes
= sizeof ( pSocket
->RxTimeout
);
2972 // Return the maximum receive buffer size
2974 pOptionData
= (CONST UINT8
*)&pSocket
->MaxRxBuf
;
2975 LengthInBytes
= sizeof ( pSocket
->MaxRxBuf
);
2980 // Return the address reuse flag
2982 pOptionData
= (UINT8
*)&pSocket
->bReUseAddr
;
2983 LengthInBytes
= sizeof ( pSocket
->bReUseAddr
);
2988 // Return the maximum transmit buffer size
2990 pOptionData
= (CONST UINT8
*)&pSocket
->MaxTxBuf
;
2991 LengthInBytes
= sizeof ( pSocket
->MaxTxBuf
);
2996 // Return the socket type
2998 pOptionData
= (CONST UINT8
*)&pSocket
->Type
;
2999 LengthInBytes
= sizeof ( pSocket
->Type
);
3006 // Return the option length
3008 *pOptionLength
= LengthInBytes
;
3011 // Determine if the option is present
3013 if ( 0 != LengthInBytes
) {
3015 // Silently truncate the value length
3017 if ( LengthInBytes
> MaxBytes
) {
3018 DEBUG (( DEBUG_OPTION
,
3019 "INFO - Truncating option from %d to %d bytes\r\n",
3022 LengthInBytes
= MaxBytes
;
3028 CopyMem ( pOptionValue
, pOptionData
, LengthInBytes
);
3031 // Zero fill any remaining space
3033 if ( LengthInBytes
< MaxBytes
) {
3034 ZeroMem ( &((UINT8
*)pOptionValue
)[LengthInBytes
], MaxBytes
- LengthInBytes
);
3037 Status
= EFI_SUCCESS
;
3042 // Return the operation status
3044 if ( NULL
!= pErrno
) {
3047 DBG_EXIT_STATUS ( Status
);
3053 Set the socket options
3055 This routine handles the socket level options and passes the
3056 others to the network specific layer.
3058 The ::setsockopt routine calls this routine to adjust the socket
3059 options one at a time by name.
3061 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
3062 @param [in] level Option protocol level
3063 @param [in] OptionName Name of the option
3064 @param [in] pOptionValue Buffer containing the option value
3065 @param [in] OptionLength Length of the buffer in bytes
3066 @param [out] pErrno Address to receive the errno value upon completion.
3068 @retval EFI_SUCCESS - Option successfully set
3072 EslSocketOptionSet (
3073 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
3076 IN CONST
void * pOptionValue
,
3077 IN socklen_t OptionLength
,
3083 socklen_t LengthInBytes
;
3084 UINT8
* pOptionData
;
3085 ESL_SOCKET
* pSocket
;
3094 Status
= EFI_INVALID_PARAMETER
;
3097 // Validate the socket
3100 if ( NULL
== pSocketProtocol
) {
3101 DEBUG (( DEBUG_OPTION
, "ERROR - pSocketProtocol is NULL!\r\n" ));
3103 else if ( NULL
== pOptionValue
) {
3104 DEBUG (( DEBUG_OPTION
, "ERROR - No option buffer specified\r\n" ));
3108 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
3109 if ( pSocket
->bRxDisable
|| pSocket
->bTxDisable
) {
3110 DEBUG (( DEBUG_OPTION
, "ERROR - Socket has been shutdown!\r\n" ));
3118 // See if the protocol will handle the option
3120 if ( NULL
!= pSocket
->pApi
->pfnOptionSet
) {
3121 if ( pSocket
->pApi
->DefaultProtocol
== level
) {
3122 Status
= pSocket
->pApi
->pfnOptionSet ( pSocket
,
3126 errno
= pSocket
->errno
;
3131 // Protocol not supported
3133 DEBUG (( DEBUG_OPTION
,
3134 "ERROR - The socket does not support this protocol!\r\n" ));
3139 // Protocol level not supported
3141 DEBUG (( DEBUG_OPTION
,
3142 "ERROR - %a does not support any options!\r\n",
3143 pSocket
->pApi
->pName
));
3145 errno
= ENOPROTOOPT
;
3146 Status
= EFI_INVALID_PARAMETER
;
3150 switch ( OptionName
) {
3153 // Option not supported
3155 DEBUG (( DEBUG_OPTION
,
3156 "ERROR - Sockets does not support this option!\r\n" ));
3158 Status
= EFI_INVALID_PARAMETER
;
3163 // Set the debug flags
3165 pOptionData
= (UINT8
*)&pSocket
->bOobInLine
;
3166 LengthInBytes
= sizeof ( pSocket
->bOobInLine
);
3170 pOptionData
= (UINT8
*)&pSocket
->bOobInLine
;
3171 LengthInBytes
= sizeof ( pSocket
->bOobInLine
);
3174 // Validate the option length
3176 if ( sizeof ( UINT32
) == OptionLength
) {
3178 // Restrict the input to TRUE or FALSE
3181 if ( 0 == *(UINT32
*)pOptionValue
) {
3184 pOptionValue
= &bTrueFalse
;
3188 // Force an invalid option length error
3190 OptionLength
= LengthInBytes
- 1;
3196 // Return the receive timeout
3198 pOptionData
= (UINT8
*)&pSocket
->RxTimeout
;
3199 LengthInBytes
= sizeof ( pSocket
->RxTimeout
);
3204 // Return the maximum receive buffer size
3206 pOptionData
= (UINT8
*)&pSocket
->MaxRxBuf
;
3207 LengthInBytes
= sizeof ( pSocket
->MaxRxBuf
);
3212 // Return the address reuse flag
3214 pOptionData
= (UINT8
*)&pSocket
->bReUseAddr
;
3215 LengthInBytes
= sizeof ( pSocket
->bReUseAddr
);
3223 // Return the maximum transmit buffer size
3225 pOptionData
= (UINT8
*)&pSocket
->MaxTxBuf
;
3226 LengthInBytes
= sizeof ( pSocket
->MaxTxBuf
);
3233 // Determine if an option was found
3235 if ( 0 != LengthInBytes
) {
3237 // Validate the option length
3239 if ( LengthInBytes
<= OptionLength
) {
3241 // Set the option value
3243 CopyMem ( pOptionData
, pOptionValue
, LengthInBytes
);
3245 Status
= EFI_SUCCESS
;
3248 DEBUG (( DEBUG_OPTION
,
3249 "ERROR - Buffer to small, %d bytes < %d bytes!\r\n",
3258 // Return the operation status
3260 if ( NULL
!= pErrno
) {
3263 DBG_EXIT_STATUS ( Status
);
3269 Allocate a packet for a receive or transmit operation
3271 This support routine is called by ::EslSocketRxStart and the
3272 network specific TxBuffer routines to get buffer space for the
3275 @param [in] ppPacket Address to receive the ::ESL_PACKET structure
3276 @param [in] LengthInBytes Length of the packet structure
3277 @param [in] ZeroBytes Length of packet to zero
3278 @param [in] DebugFlags Flags for debug messages
3280 @retval EFI_SUCCESS - The packet was allocated successfully
3284 EslSocketPacketAllocate (
3285 IN ESL_PACKET
** ppPacket
,
3286 IN
size_t LengthInBytes
,
3287 IN
size_t ZeroBytes
,
3291 ESL_PACKET
* pPacket
;
3297 // Allocate a packet structure
3299 LengthInBytes
+= sizeof ( *pPacket
)
3300 - sizeof ( pPacket
->Op
);
3301 Status
= gBS
->AllocatePool ( EfiRuntimeServicesData
,
3303 (VOID
**)&pPacket
);
3304 if ( !EFI_ERROR ( Status
)) {
3305 DEBUG (( DebugFlags
| DEBUG_POOL
,
3306 "0x%08x: Allocate pPacket, %d bytes\r\n",
3309 if ( 0 != ZeroBytes
) {
3310 ZeroMem ( &pPacket
->Op
, ZeroBytes
);
3312 pPacket
->PacketSize
= LengthInBytes
;
3315 DEBUG (( DebugFlags
| DEBUG_POOL
| DEBUG_INFO
,
3316 "ERROR - Packet allocation failed for %d bytes, Status: %r\r\n",
3323 // Return the packet
3325 *ppPacket
= pPacket
;
3328 // Return the operation status
3330 DBG_EXIT_STATUS ( Status
);
3336 Free a packet used for receive or transmit operation
3338 This support routine is called by the network specific Close
3339 and TxComplete routines and during error cases in RxComplete
3340 and TxBuffer. Note that the network layers typically place
3341 receive packets on the ESL_SOCKET::pRxFree list for reuse.
3343 @param [in] pPacket Address of an ::ESL_PACKET structure
3344 @param [in] DebugFlags Flags for debug messages
3346 @retval EFI_SUCCESS - The packet was allocated successfully
3350 EslSocketPacketFree (
3351 IN ESL_PACKET
* pPacket
,
3355 UINTN LengthInBytes
;
3361 // Free a packet structure
3363 LengthInBytes
= pPacket
->PacketSize
;
3364 Status
= gBS
->FreePool ( pPacket
);
3365 if ( !EFI_ERROR ( Status
)) {
3366 DEBUG (( DebugFlags
| DEBUG_POOL
,
3367 "0x%08x: Free pPacket, %d bytes\r\n",
3372 DEBUG (( DebugFlags
| DEBUG_POOL
| DEBUG_INFO
,
3373 "ERROR - Failed to free packet 0x%08x, Status: %r\r\n",
3379 // Return the operation status
3381 DBG_EXIT_STATUS ( Status
);
3387 Poll a socket for pending activity.
3389 This routine builds a detected event mask which is returned to
3390 the caller in the buffer provided.
3392 The ::poll routine calls this routine to determine if the socket
3393 needs to be serviced as a result of connection, error, receive or
3396 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
3398 @param [in] Events Events of interest for this socket
3400 @param [in] pEvents Address to receive the detected events
3402 @param [out] pErrno Address to receive the errno value upon completion.
3404 @retval EFI_SUCCESS - Socket successfully polled
3405 @retval EFI_INVALID_PARAMETER - When pEvents is NULL
3410 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
3416 short DetectedEvents
;
3417 ESL_SOCKET
* pSocket
;
3419 EFI_TPL TplPrevious
;
3422 DEBUG (( DEBUG_POLL
, "Entering SocketPoll\r\n" ));
3427 Status
= EFI_SUCCESS
;
3429 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
3433 // Verify the socket state
3435 Status
= EslSocketIsConfigured ( pSocket
);
3436 if ( !EFI_ERROR ( Status
)) {
3438 // Check for invalid events
3440 ValidEvents
= POLLIN
3442 | POLLOUT
| POLLWRNORM
3449 if ( 0 != ( Events
& ( ~ValidEvents
))) {
3450 DetectedEvents
|= POLLNVAL
;
3451 DEBUG (( DEBUG_INFO
| DEBUG_POLL
,
3452 "ERROR - Invalid event mask, Valid Events: 0x%04x, Invalid Events: 0x%04x\r\n",
3453 Events
& ValidEvents
,
3454 Events
& ( ~ValidEvents
)));
3458 // Synchronize with the socket layer
3460 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
3463 // Increase the network performance by extending the
3464 // polling (idle) loop down into the LAN driver
3466 EslSocketRxPoll ( pSocket
);
3469 // Release the socket layer synchronization
3471 RESTORE_TPL ( TplPrevious
);
3474 // Check for pending connections
3476 if ( 0 != pSocket
->FifoDepth
) {
3478 // A connection is waiting for an accept call
3479 // See posix connect documentation at
3480 // http://pubs.opengroup.org/onlinepubs/9699919799/functions/accept.htm
3482 DetectedEvents
|= POLLIN
| POLLRDNORM
;
3484 if ( pSocket
->bConnected
) {
3486 // A connection is present
3487 // See posix connect documentation at
3488 // http://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.htm
3490 DetectedEvents
|= POLLOUT
| POLLWRNORM
;
3494 // The following bits are set based upon the POSIX poll documentation at
3495 // http://pubs.opengroup.org/onlinepubs/9699919799/functions/poll.html
3499 // Check for urgent receive data
3501 if ( 0 < pSocket
->RxOobBytes
) {
3502 DetectedEvents
|= POLLRDBAND
| POLLPRI
| POLLIN
;
3506 // Check for normal receive data
3508 if (( 0 < pSocket
->RxBytes
)
3509 || ( EFI_SUCCESS
!= pSocket
->RxError
)) {
3510 DetectedEvents
|= POLLRDNORM
| POLLIN
;
3514 // Handle the receive errors
3516 if (( EFI_SUCCESS
!= pSocket
->RxError
)
3517 && ( 0 == ( DetectedEvents
& POLLIN
))) {
3518 DetectedEvents
|= POLLERR
| POLLIN
| POLLRDNORM
| POLLRDBAND
;
3522 // Check for urgent transmit data buffer space
3524 if (( MAX_TX_DATA
> pSocket
->TxOobBytes
)
3525 || ( EFI_SUCCESS
!= pSocket
->TxError
)) {
3526 DetectedEvents
|= POLLWRBAND
;
3530 // Check for normal transmit data buffer space
3532 if (( MAX_TX_DATA
> pSocket
->TxBytes
)
3533 || ( EFI_SUCCESS
!= pSocket
->TxError
)) {
3534 DetectedEvents
|= POLLWRNORM
;
3538 // Handle the transmit error
3540 if ( EFI_ERROR ( pSocket
->TxError
)) {
3541 DetectedEvents
|= POLLERR
;
3547 // Return the detected events
3549 *pEvents
= DetectedEvents
& ( Events
3555 // Return the operation status
3557 DEBUG (( DEBUG_POLL
, "Exiting SocketPoll, Status: %r\r\n", Status
));
3563 Allocate and initialize a ESL_PORT structure.
3565 This routine initializes an ::ESL_PORT structure for use by
3566 the socket. This routine calls a routine via
3567 ESL_PROTOCOL_API::pfnPortAllocate to initialize the network
3568 specific resources. The resources are released later by the
3569 \ref PortCloseStateMachine.
3571 This support routine is called by:
3573 <li>::EslSocketBind</li>
3574 <li>::EslTcp4ListenComplete</li>
3576 to connect the socket with the underlying network adapter
3579 @param [in] pSocket Address of an ::ESL_SOCKET structure.
3580 @param [in] pService Address of an ::ESL_SERVICE structure.
3581 @param [in] ChildHandle Network protocol child handle
3582 @param [in] pSockAddr Address of a sockaddr structure that contains the
3583 connection point on the local machine. An IPv4 address
3584 of INADDR_ANY specifies that the connection is made to
3585 all of the network stacks on the platform. Specifying a
3586 specific IPv4 address restricts the connection to the
3587 network stack supporting that address. Specifying zero
3588 for the port causes the network layer to assign a port
3589 number from the dynamic range. Specifying a specific
3590 port number causes the network layer to use that port.
3591 @param [in] bBindTest TRUE if EslSocketBindTest should be called
3592 @param [in] DebugFlags Flags for debug messages
3593 @param [out] ppPort Buffer to receive new ::ESL_PORT structure address
3595 @retval EFI_SUCCESS - Socket successfully created
3599 EslSocketPortAllocate (
3600 IN ESL_SOCKET
* pSocket
,
3601 IN ESL_SERVICE
* pService
,
3602 IN EFI_HANDLE ChildHandle
,
3603 IN CONST
struct sockaddr
* pSockAddr
,
3604 IN BOOLEAN bBindTest
,
3605 IN UINTN DebugFlags
,
3606 OUT ESL_PORT
** ppPort
3609 UINTN LengthInBytes
;
3614 EFI_SERVICE_BINDING_PROTOCOL
* pServiceBinding
;
3615 CONST ESL_SOCKET_BINDING
* pSocketBinding
;
3617 EFI_STATUS TempStatus
;
3622 // Verify the socket layer synchronization
3624 VERIFY_TPL ( TPL_SOCKETS
);
3627 // Use for/break instead of goto
3628 pSocketBinding
= pService
->pSocketBinding
;
3631 // Allocate a port structure
3633 pLayer
= &mEslLayer
;
3634 LengthInBytes
= sizeof ( *pPort
)
3635 + ESL_STRUCTURE_ALIGNMENT_BYTES
3636 + (( pSocketBinding
->RxIo
3637 + pSocketBinding
->TxIoNormal
3638 + pSocketBinding
->TxIoUrgent
)
3639 * sizeof ( ESL_IO_MGMT
));
3640 pPort
= (ESL_PORT
*) AllocateZeroPool ( LengthInBytes
);
3641 if ( NULL
== pPort
) {
3642 Status
= EFI_OUT_OF_RESOURCES
;
3643 pSocket
->errno
= ENOMEM
;
3646 DEBUG (( DebugFlags
| DEBUG_POOL
| DEBUG_INIT
,
3647 "0x%08x: Allocate pPort, %d bytes\r\n",
3652 // Initialize the port
3654 pPort
->DebugFlags
= DebugFlags
;
3655 pPort
->Handle
= ChildHandle
;
3656 pPort
->pService
= pService
;
3657 pPort
->pServiceBinding
= pService
->pServiceBinding
;
3658 pPort
->pSocket
= pSocket
;
3659 pPort
->pSocketBinding
= pService
->pSocketBinding
;
3660 pPort
->Signature
= PORT_SIGNATURE
;
3663 // Open the port protocol
3665 Status
= gBS
->OpenProtocol ( pPort
->Handle
,
3666 pSocketBinding
->pNetworkProtocolGuid
,
3667 &pPort
->pProtocol
.v
,
3668 pLayer
->ImageHandle
,
3670 EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL
);
3671 if ( EFI_ERROR ( Status
)) {
3672 DEBUG (( DEBUG_ERROR
| DebugFlags
,
3673 "ERROR - Failed to open network protocol GUID on controller 0x%08x\r\n",
3675 pSocket
->errno
= EEXIST
;
3678 DEBUG (( DebugFlags
,
3679 "0x%08x: Network protocol GUID opened on controller 0x%08x\r\n",
3684 // Initialize the port specific resources
3686 Status
= pSocket
->pApi
->pfnPortAllocate ( pPort
,
3688 if ( EFI_ERROR ( Status
)) {
3693 // Set the local address
3695 Status
= pSocket
->pApi
->pfnLocalAddrSet ( pPort
, pSockAddr
, bBindTest
);
3696 if ( EFI_ERROR ( Status
)) {
3701 // Test the address/port configuration
3704 Status
= EslSocketBindTest ( pPort
, pSocket
->pApi
->BindTestErrno
);
3705 if ( EFI_ERROR ( Status
)) {
3711 // Initialize the receive structures
3713 pBuffer
= (UINT8
*)&pPort
[ 1 ];
3714 pBuffer
= &pBuffer
[ ESL_STRUCTURE_ALIGNMENT_BYTES
];
3715 pBuffer
= (UINT8
*)( ESL_STRUCTURE_ALIGNMENT_MASK
& (UINTN
)pBuffer
);
3716 pIo
= (ESL_IO_MGMT
*)pBuffer
;
3717 if (( 0 != pSocketBinding
->RxIo
)
3718 && ( NULL
!= pSocket
->pApi
->pfnRxComplete
)) {
3719 Status
= EslSocketIoInit ( pPort
,
3721 pSocketBinding
->RxIo
,
3723 DebugFlags
| DEBUG_POOL
,
3725 pSocket
->pApi
->pfnRxComplete
);
3726 if ( EFI_ERROR ( Status
)) {
3732 // Initialize the urgent transmit structures
3734 if (( 0 != pSocketBinding
->TxIoUrgent
)
3735 && ( NULL
!= pSocket
->pApi
->pfnTxOobComplete
)) {
3736 Status
= EslSocketIoInit ( pPort
,
3738 pSocketBinding
->TxIoUrgent
,
3740 DebugFlags
| DEBUG_POOL
,
3742 pSocket
->pApi
->pfnTxOobComplete
);
3743 if ( EFI_ERROR ( Status
)) {
3749 // Initialize the normal transmit structures
3751 if (( 0 != pSocketBinding
->TxIoNormal
)
3752 && ( NULL
!= pSocket
->pApi
->pfnTxComplete
)) {
3753 Status
= EslSocketIoInit ( pPort
,
3755 pSocketBinding
->TxIoNormal
,
3757 DebugFlags
| DEBUG_POOL
,
3759 pSocket
->pApi
->pfnTxComplete
);
3760 if ( EFI_ERROR ( Status
)) {
3766 // Add this port to the socket
3768 pPort
->pLinkSocket
= pSocket
->pPortList
;
3769 pSocket
->pPortList
= pPort
;
3770 DEBUG (( DebugFlags
,
3771 "0x%08x: Socket adding port: 0x%08x\r\n",
3776 // Add this port to the service
3778 pPort
->pLinkService
= pService
->pPortList
;
3779 pService
->pPortList
= pPort
;
3789 // Clean up after the error if necessary
3791 if ( EFI_ERROR ( Status
)) {
3792 if ( NULL
!= pPort
) {
3796 EslSocketPortClose ( pPort
);
3800 // Close the port if necessary
3802 pServiceBinding
= pService
->pServiceBinding
;
3803 TempStatus
= pServiceBinding
->DestroyChild ( pServiceBinding
,
3805 if ( !EFI_ERROR ( TempStatus
)) {
3806 DEBUG (( DEBUG_BIND
| DEBUG_POOL
,
3807 "0x%08x: %s port handle destroyed\r\n",
3809 pSocketBinding
->pName
));
3812 DEBUG (( DEBUG_ERROR
| DEBUG_BIND
| DEBUG_POOL
,
3813 "ERROR - Failed to destroy the %s port handle 0x%08x, Status: %r\r\n",
3814 pSocketBinding
->pName
,
3817 ASSERT ( EFI_SUCCESS
== TempStatus
);
3822 // Return the operation status
3824 DBG_EXIT_STATUS ( Status
);
3832 This routine releases the resources allocated by ::EslSocketPortAllocate.
3833 This routine calls ESL_PROTOCOL_API::pfnPortClose to release the network
3836 This routine is called by:
3838 <li>::EslSocketPortAllocate - Port initialization failure</li>
3839 <li>::EslSocketPortCloseRxDone - Last step of close processing</li>
3840 <li>::EslTcp4ConnectComplete - Connection failure and reducing the port list to a single port</li>
3842 See the \ref PortCloseStateMachine section.
3844 @param [in] pPort Address of an ::ESL_PORT structure.
3846 @retval EFI_SUCCESS The port is closed
3847 @retval other Port close error
3851 EslSocketPortClose (
3857 ESL_PACKET
* pPacket
;
3858 ESL_PORT
* pPreviousPort
;
3859 ESL_SERVICE
* pService
;
3860 EFI_SERVICE_BINDING_PROTOCOL
* pServiceBinding
;
3861 CONST ESL_SOCKET_BINDING
* pSocketBinding
;
3862 ESL_SOCKET
* pSocket
;
3868 // Verify the socket layer synchronization
3870 VERIFY_TPL ( TPL_SOCKETS
);
3873 // Locate the port in the socket list
3875 Status
= EFI_SUCCESS
;
3876 pLayer
= &mEslLayer
;
3877 DebugFlags
= pPort
->DebugFlags
;
3878 pSocket
= pPort
->pSocket
;
3879 pPreviousPort
= pSocket
->pPortList
;
3880 if ( pPreviousPort
== pPort
) {
3882 // Remove this port from the head of the socket list
3884 pSocket
->pPortList
= pPort
->pLinkSocket
;
3888 // Locate the port in the middle of the socket list
3890 while (( NULL
!= pPreviousPort
)
3891 && ( pPreviousPort
->pLinkSocket
!= pPort
)) {
3892 pPreviousPort
= pPreviousPort
->pLinkSocket
;
3894 if ( NULL
!= pPreviousPort
) {
3896 // Remove the port from the middle of the socket list
3898 pPreviousPort
->pLinkSocket
= pPort
->pLinkSocket
;
3903 // Locate the port in the service list
3904 // Note that the port may not be in the service list
3905 // if the service has been shutdown.
3907 pService
= pPort
->pService
;
3908 if ( NULL
!= pService
) {
3909 pPreviousPort
= pService
->pPortList
;
3910 if ( pPreviousPort
== pPort
) {
3912 // Remove this port from the head of the service list
3914 pService
->pPortList
= pPort
->pLinkService
;
3918 // Locate the port in the middle of the service list
3920 while (( NULL
!= pPreviousPort
)
3921 && ( pPreviousPort
->pLinkService
!= pPort
)) {
3922 pPreviousPort
= pPreviousPort
->pLinkService
;
3924 if ( NULL
!= pPreviousPort
) {
3926 // Remove the port from the middle of the service list
3928 pPreviousPort
->pLinkService
= pPort
->pLinkService
;
3934 // Empty the urgent receive queue
3936 while ( NULL
!= pSocket
->pRxOobPacketListHead
) {
3937 pPacket
= pSocket
->pRxOobPacketListHead
;
3938 pSocket
->pRxOobPacketListHead
= pPacket
->pNext
;
3939 pSocket
->pApi
->pfnPacketFree ( pPacket
, &pSocket
->RxOobBytes
);
3940 EslSocketPacketFree ( pPacket
, DEBUG_RX
);
3942 pSocket
->pRxOobPacketListTail
= NULL
;
3943 ASSERT ( 0 == pSocket
->RxOobBytes
);
3946 // Empty the receive queue
3948 while ( NULL
!= pSocket
->pRxPacketListHead
) {
3949 pPacket
= pSocket
->pRxPacketListHead
;
3950 pSocket
->pRxPacketListHead
= pPacket
->pNext
;
3951 pSocket
->pApi
->pfnPacketFree ( pPacket
, &pSocket
->RxBytes
);
3952 EslSocketPacketFree ( pPacket
, DEBUG_RX
);
3954 pSocket
->pRxPacketListTail
= NULL
;
3955 ASSERT ( 0 == pSocket
->RxBytes
);
3958 // Empty the receive free queue
3960 while ( NULL
!= pSocket
->pRxFree
) {
3961 pPacket
= pSocket
->pRxFree
;
3962 pSocket
->pRxFree
= pPacket
->pNext
;
3963 EslSocketPacketFree ( pPacket
, DEBUG_RX
);
3967 // Release the network specific resources
3969 if ( NULL
!= pSocket
->pApi
->pfnPortClose
) {
3970 Status
= pSocket
->pApi
->pfnPortClose ( pPort
);
3974 // Done with the normal transmit events
3976 Status
= EslSocketIoFree ( pPort
,
3978 DebugFlags
| DEBUG_POOL
,
3979 "normal transmit" );
3982 // Done with the urgent transmit events
3984 Status
= EslSocketIoFree ( pPort
,
3986 DebugFlags
| DEBUG_POOL
,
3987 "urgent transmit" );
3990 // Done with the receive events
3992 Status
= EslSocketIoFree ( pPort
,
3994 DebugFlags
| DEBUG_POOL
,
3998 // Done with the lower layer network protocol
4000 pSocketBinding
= pPort
->pSocketBinding
;
4001 if ( NULL
!= pPort
->pProtocol
.v
) {
4002 Status
= gBS
->CloseProtocol ( pPort
->Handle
,
4003 pSocketBinding
->pNetworkProtocolGuid
,
4004 pLayer
->ImageHandle
,
4006 if ( !EFI_ERROR ( Status
)) {
4007 DEBUG (( DebugFlags
,
4008 "0x%08x: Network protocol GUID closed on controller 0x%08x\r\n",
4013 DEBUG (( DEBUG_ERROR
| DebugFlags
,
4014 "ERROR - Failed to close network protocol GUID on controller 0x%08x, Status: %r\r\n",
4017 ASSERT ( EFI_SUCCESS
== Status
);
4022 // Done with the network port
4024 pServiceBinding
= pPort
->pServiceBinding
;
4025 if ( NULL
!= pPort
->Handle
) {
4026 Status
= pServiceBinding
->DestroyChild ( pServiceBinding
,
4028 if ( !EFI_ERROR ( Status
)) {
4029 DEBUG (( DebugFlags
| DEBUG_POOL
,
4030 "0x%08x: %s port handle destroyed\r\n",
4032 pSocketBinding
->pName
));
4035 DEBUG (( DEBUG_ERROR
| DebugFlags
| DEBUG_POOL
,
4036 "ERROR - Failed to destroy the %s port handle, Status: %r\r\n",
4037 pSocketBinding
->pName
,
4039 ASSERT ( EFI_SUCCESS
== Status
);
4044 // Release the port structure
4046 Status
= gBS
->FreePool ( pPort
);
4047 if ( !EFI_ERROR ( Status
)) {
4048 DEBUG (( DebugFlags
| DEBUG_POOL
,
4049 "0x%08x: Free pPort, %d bytes\r\n",
4051 sizeof ( *pPort
)));
4054 DEBUG (( DEBUG_ERROR
| DebugFlags
| DEBUG_POOL
,
4055 "ERROR - Failed to free pPort: 0x%08x, Status: %r\r\n",
4058 ASSERT ( EFI_SUCCESS
== Status
);
4062 // Mark the socket as closed if necessary
4064 if ( NULL
== pSocket
->pPortList
) {
4065 pSocket
->State
= SOCKET_STATE_CLOSED
;
4066 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4067 "0x%08x: Socket State: SOCKET_STATE_CLOSED\r\n",
4072 // Return the operation status
4074 DBG_EXIT_STATUS ( Status
);
4082 This routine attempts to complete the port close operation.
4084 This routine is called by the TCP layer upon completion of
4085 the close operation and by ::EslSocketPortCloseTxDone.
4086 See the \ref PortCloseStateMachine section.
4088 @param [in] Event The close completion event
4090 @param [in] pPort Address of an ::ESL_PORT structure.
4094 EslSocketPortCloseComplete (
4103 VERIFY_AT_TPL ( TPL_SOCKETS
);
4106 // Update the port state
4108 pPort
->State
= PORT_STATE_CLOSE_DONE
;
4109 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4110 "0x%08x: Port Close State: PORT_STATE_CLOSE_DONE\r\n",
4114 // Shutdown the receive operation on the port
4116 if ( NULL
!= pPort
->pfnRxCancel
) {
4117 pIo
= pPort
->pRxActive
;
4118 while ( NULL
!= pIo
) {
4119 EslSocketRxCancel ( pPort
, pIo
);
4125 // Determine if the receive operation is pending
4127 Status
= EslSocketPortCloseRxDone ( pPort
);
4128 DBG_EXIT_STATUS ( Status
);
4135 This routine determines the state of the receive operations and
4136 continues the close operation after the pending receive operations
4139 This routine is called by
4141 <li>::EslSocketPortCloseComplete</li>
4142 <li>::EslSocketPortCloseTxDone</li>
4143 <li>::EslSocketRxComplete</li>
4145 to determine the state of the receive operations.
4146 See the \ref PortCloseStateMachine section.
4148 @param [in] pPort Address of an ::ESL_PORT structure.
4150 @retval EFI_SUCCESS The port is closed
4151 @retval EFI_NOT_READY The port is still closing
4152 @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
4153 most likely the routine was called already.
4157 EslSocketPortCloseRxDone (
4166 // Verify the socket layer synchronization
4168 VERIFY_TPL ( TPL_SOCKETS
);
4171 // Verify that the port is closing
4173 Status
= EFI_ALREADY_STARTED
;
4174 if ( PORT_STATE_CLOSE_DONE
== pPort
->State
) {
4176 // Determine if the receive operation is pending
4178 Status
= EFI_NOT_READY
;
4179 if ( NULL
== pPort
->pRxActive
) {
4181 // The receive operation is complete
4182 // Update the port state
4184 pPort
->State
= PORT_STATE_CLOSE_RX_DONE
;
4185 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4186 "0x%08x: Port Close State: PORT_STATE_CLOSE_RX_DONE\r\n",
4190 // Complete the port close operation
4192 Status
= EslSocketPortClose ( pPort
);
4195 DEBUG_CODE_BEGIN ();
4199 // Display the outstanding receive operations
4201 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4202 "0x%08x: Port Close: Receive still pending!\r\n",
4204 pIo
= pPort
->pRxActive
;
4205 while ( NULL
!= pIo
) {
4206 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4207 "0x%08x: Packet pending on network adapter\r\n",
4217 // Return the operation status
4219 DBG_EXIT_STATUS ( Status
);
4225 Start the close operation on a port, state 1.
4227 This routine marks the port as closed and initiates the \ref
4228 PortCloseStateMachine. The first step is to allow the \ref
4229 TransmitEngine to run down.
4231 This routine is called by ::EslSocketCloseStart to initiate the socket
4232 network specific close operation on the socket.
4234 @param [in] pPort Address of an ::ESL_PORT structure.
4235 @param [in] bCloseNow Set TRUE to abort active transfers
4236 @param [in] DebugFlags Flags for debug messages
4238 @retval EFI_SUCCESS The port is closed, not normally returned
4239 @retval EFI_NOT_READY The port has started the closing process
4240 @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
4241 most likely the routine was called already.
4245 EslSocketPortCloseStart (
4246 IN ESL_PORT
* pPort
,
4247 IN BOOLEAN bCloseNow
,
4251 ESL_SOCKET
* pSocket
;
4257 // Verify the socket layer synchronization
4259 VERIFY_TPL ( TPL_SOCKETS
);
4262 // Mark the port as closing
4264 Status
= EFI_ALREADY_STARTED
;
4265 pSocket
= pPort
->pSocket
;
4266 pSocket
->errno
= EALREADY
;
4267 if ( PORT_STATE_CLOSE_STARTED
> pPort
->State
) {
4270 // Update the port state
4272 pPort
->State
= PORT_STATE_CLOSE_STARTED
;
4273 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4274 "0x%08x: Port Close State: PORT_STATE_CLOSE_STARTED\r\n",
4276 pPort
->bCloseNow
= bCloseNow
;
4277 pPort
->DebugFlags
= DebugFlags
;
4280 // Determine if transmits are complete
4282 Status
= EslSocketPortCloseTxDone ( pPort
);
4286 // Return the operation status
4288 DBG_EXIT_STATUS ( Status
);
4296 This routine determines the state of the transmit engine and
4297 continue the close operation after the transmission is complete.
4298 The next step is to stop the \ref ReceiveEngine.
4299 See the \ref PortCloseStateMachine section.
4301 This routine is called by ::EslSocketPortCloseStart to determine
4302 if the transmission is complete.
4304 @param [in] pPort Address of an ::ESL_PORT structure.
4306 @retval EFI_SUCCESS The port is closed, not normally returned
4307 @retval EFI_NOT_READY The port is still closing
4308 @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
4309 most likely the routine was called already.
4313 EslSocketPortCloseTxDone (
4318 ESL_SOCKET
* pSocket
;
4324 // Verify the socket layer synchronization
4326 VERIFY_TPL ( TPL_SOCKETS
);
4329 // All transmissions are complete or must be stopped
4330 // Mark the port as TX complete
4332 Status
= EFI_ALREADY_STARTED
;
4333 if ( PORT_STATE_CLOSE_STARTED
== pPort
->State
) {
4335 // Verify that the transmissions are complete
4337 pSocket
= pPort
->pSocket
;
4338 if ( pPort
->bCloseNow
4339 || ( EFI_SUCCESS
!= pSocket
->TxError
)
4340 || (( NULL
== pPort
->pTxActive
)
4341 && ( NULL
== pPort
->pTxOobActive
))) {
4343 // Update the port state
4345 pPort
->State
= PORT_STATE_CLOSE_TX_DONE
;
4346 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4347 "0x%08x: Port Close State: PORT_STATE_CLOSE_TX_DONE\r\n",
4352 // Skip the close operation if the port is not configured
4354 Status
= EFI_SUCCESS
;
4355 pSocket
= pPort
->pSocket
;
4356 if (( pPort
->bConfigured
)
4357 && ( NULL
!= pSocket
->pApi
->pfnPortCloseOp
)) {
4359 // Start the close operation
4361 Status
= pSocket
->pApi
->pfnPortCloseOp ( pPort
);
4362 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4363 "0x%08x: Port Close: Close operation still pending!\r\n",
4365 ASSERT ( EFI_SUCCESS
== Status
);
4369 // The receive operation is complete
4370 // Update the port state
4372 EslSocketPortCloseComplete ( NULL
, pPort
);
4377 // Transmissions are still active, exit
4379 Status
= EFI_NOT_READY
;
4380 pSocket
->errno
= EAGAIN
;
4381 DEBUG_CODE_BEGIN ( );
4383 ESL_PACKET
* pPacket
;
4385 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4386 "0x%08x: Port Close: Transmits are still pending!\r\n",
4390 // Display the pending urgent transmit packets
4392 pPacket
= pSocket
->pTxOobPacketListHead
;
4393 while ( NULL
!= pPacket
) {
4394 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4395 "0x%08x: Packet pending on urgent TX list, %d bytes\r\n",
4397 pPacket
->PacketSize
));
4398 pPacket
= pPacket
->pNext
;
4401 pIo
= pPort
->pTxOobActive
;
4402 while ( NULL
!= pIo
) {
4403 pPacket
= pIo
->pPacket
;
4404 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4405 "0x%08x: Packet active %d bytes, pIo: 0x%08x\r\n",
4407 pPacket
->PacketSize
,
4413 // Display the pending normal transmit packets
4415 pPacket
= pSocket
->pTxPacketListHead
;
4416 while ( NULL
!= pPacket
) {
4417 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4418 "0x%08x: Packet pending on normal TX list, %d bytes\r\n",
4420 pPacket
->PacketSize
));
4421 pPacket
= pPacket
->pNext
;
4424 pIo
= pPort
->pTxActive
;
4425 while ( NULL
!= pIo
) {
4426 pPacket
= pIo
->pPacket
;
4427 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4428 "0x%08x: Packet active %d bytes, pIo: 0x%08x\r\n",
4430 pPacket
->PacketSize
,
4440 // Return the operation status
4442 DBG_EXIT_STATUS ( Status
);
4448 Receive data from a network connection.
4450 This routine calls the network specific routine to remove the
4451 next portion of data from the receive queue and return it to the
4454 The ::recvfrom routine calls this routine to determine if any data
4455 is received from the remote system. Note that the other routines
4456 ::recv and ::read are layered on top of ::recvfrom.
4458 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
4460 @param [in] Flags Message control flags
4462 @param [in] BufferLength Length of the the buffer
4464 @param [in] pBuffer Address of a buffer to receive the data.
4466 @param [in] pDataLength Number of received data bytes in the buffer.
4468 @param [out] pAddress Network address to receive the remote system address
4470 @param [in,out] pAddressLength Length of the remote network address structure
4472 @param [out] pErrno Address to receive the errno value upon completion.
4474 @retval EFI_SUCCESS - Socket data successfully received
4479 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
4481 IN
size_t BufferLength
,
4483 OUT
size_t * pDataLength
,
4484 OUT
struct sockaddr
* pAddress
,
4485 IN OUT socklen_t
* pAddressLength
,
4490 struct sockaddr_in v4
;
4491 struct sockaddr_in6 v6
;
4493 socklen_t AddressLength
;
4494 BOOLEAN bConsumePacket
;
4495 BOOLEAN bUrgentQueue
;
4497 ESL_PACKET
* pNextPacket
;
4498 ESL_PACKET
* pPacket
;
4500 ESL_PACKET
** ppQueueHead
;
4501 ESL_PACKET
** ppQueueTail
;
4502 struct sockaddr
* pRemoteAddress
;
4503 size_t * pRxDataBytes
;
4504 ESL_SOCKET
* pSocket
;
4507 EFI_TPL TplPrevious
;
4514 Status
= EFI_SUCCESS
;
4517 // Validate the socket
4520 if ( NULL
!= pSocketProtocol
) {
4521 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
4524 // Validate the return address parameters
4526 if (( NULL
== pAddress
) || ( NULL
!= pAddressLength
)) {
4528 // Return the transmit error if necessary
4530 if ( EFI_SUCCESS
!= pSocket
->TxError
) {
4531 pSocket
->errno
= EIO
;
4532 Status
= pSocket
->TxError
;
4533 pSocket
->TxError
= EFI_SUCCESS
;
4537 // Verify the socket state
4539 Status
= EslSocketIsConfigured ( pSocket
);
4540 if ( !EFI_ERROR ( Status
)) {
4542 // Validate the buffer length
4544 if (( NULL
== pDataLength
)
4545 || ( NULL
== pBuffer
)) {
4546 if ( NULL
== pDataLength
) {
4548 "ERROR - pDataLength is NULL!\r\n" ));
4552 "ERROR - pBuffer is NULL!\r\n" ));
4554 Status
= EFI_INVALID_PARAMETER
;
4555 pSocket
->errno
= EFAULT
;
4561 if ( NULL
== pSocket
->pApi
->pfnReceive
) {
4562 Status
= EFI_UNSUPPORTED
;
4563 pSocket
->errno
= ENOTSUP
;
4567 // Zero the receive address if being returned
4569 pRemoteAddress
= NULL
;
4570 if ( NULL
!= pAddress
) {
4571 pRemoteAddress
= (struct sockaddr
*)&Addr
;
4572 ZeroMem ( pRemoteAddress
, sizeof ( Addr
));
4573 pRemoteAddress
->sa_family
= pSocket
->pApi
->AddressFamily
;
4574 pRemoteAddress
->sa_len
= (UINT8
)pSocket
->pApi
->AddressLength
;
4578 // Synchronize with the socket layer
4580 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
4585 Status
= EFI_UNSUPPORTED
;
4586 pSocket
->errno
= ENOTCONN
;
4589 // Verify that the socket is connected
4591 if ( SOCKET_STATE_CONNECTED
== pSocket
->State
) {
4593 // Poll the network to increase performance
4595 EslSocketRxPoll ( pSocket
);
4600 pPort
= pSocket
->pPortList
;
4601 if ( NULL
!= pPort
) {
4603 // Determine the queue head
4605 bUrgentQueue
= (BOOLEAN
)( 0 != ( Flags
& MSG_OOB
));
4606 if ( bUrgentQueue
) {
4607 ppQueueHead
= &pSocket
->pRxOobPacketListHead
;
4608 ppQueueTail
= &pSocket
->pRxOobPacketListTail
;
4609 pRxDataBytes
= &pSocket
->RxOobBytes
;
4612 ppQueueHead
= &pSocket
->pRxPacketListHead
;
4613 ppQueueTail
= &pSocket
->pRxPacketListTail
;
4614 pRxDataBytes
= &pSocket
->RxBytes
;
4618 // Determine if there is any data on the queue
4621 pPacket
= *ppQueueHead
;
4622 if ( NULL
!= pPacket
) {
4624 // Copy the received data
4628 // Attempt to receive a packet
4631 bConsumePacket
= (BOOLEAN
)( 0 == ( Flags
& MSG_PEEK
));
4632 pBuffer
= pSocket
->pApi
->pfnReceive ( pPort
,
4638 (struct sockaddr
*)&Addr
,
4640 *pDataLength
+= DataLength
;
4641 BufferLength
-= DataLength
;
4644 // Determine if the data is being read
4646 pNextPacket
= pPacket
->pNext
;
4647 if ( bConsumePacket
) {
4649 // All done with this packet
4650 // Account for any discarded data
4652 pSocket
->pApi
->pfnPacketFree ( pPacket
, pRxDataBytes
);
4653 if ( 0 != SkipBytes
) {
4655 "0x%08x: Port, packet read, skipping over 0x%08x bytes\r\n",
4661 // Remove this packet from the queue
4663 *ppQueueHead
= pPacket
->pNext
;
4664 if ( NULL
== *ppQueueHead
) {
4665 *ppQueueTail
= NULL
;
4669 // Move the packet to the free queue
4671 pPacket
->pNext
= pSocket
->pRxFree
;
4672 pSocket
->pRxFree
= pPacket
;
4674 "0x%08x: Port freeing packet 0x%08x\r\n",
4679 // Restart the receive operation if necessary
4681 if (( NULL
!= pPort
->pRxFree
)
4682 && ( MAX_RX_DATA
> pSocket
->RxBytes
)) {
4683 EslSocketRxStart ( pPort
);
4688 // Get the next packet
4690 pPacket
= pNextPacket
;
4691 } while (( SOCK_STREAM
== pSocket
->Type
)
4692 && ( NULL
!= pPacket
)
4693 && ( 0 < BufferLength
));
4696 // Successful operation
4698 Status
= EFI_SUCCESS
;
4703 // The queue is empty
4704 // Determine if it is time to return the receive error
4706 if ( EFI_ERROR ( pSocket
->RxError
)
4707 && ( NULL
== pSocket
->pRxPacketListHead
)
4708 && ( NULL
== pSocket
->pRxOobPacketListHead
)) {
4709 Status
= pSocket
->RxError
;
4710 pSocket
->RxError
= EFI_SUCCESS
;
4713 pSocket
->errno
= EIO
;
4716 case EFI_CONNECTION_FIN
:
4718 // Continue to return zero bytes received when the
4719 // peer has successfully closed the connection
4721 pSocket
->RxError
= EFI_CONNECTION_FIN
;
4724 Status
= EFI_SUCCESS
;
4727 case EFI_CONNECTION_REFUSED
:
4728 pSocket
->errno
= ECONNREFUSED
;
4731 case EFI_CONNECTION_RESET
:
4732 pSocket
->errno
= ECONNRESET
;
4735 case EFI_HOST_UNREACHABLE
:
4736 pSocket
->errno
= EHOSTUNREACH
;
4739 case EFI_NETWORK_UNREACHABLE
:
4740 pSocket
->errno
= ENETUNREACH
;
4743 case EFI_PORT_UNREACHABLE
:
4744 pSocket
->errno
= EPROTONOSUPPORT
;
4747 case EFI_PROTOCOL_UNREACHABLE
:
4748 pSocket
->errno
= ENOPROTOOPT
;
4753 Status
= EFI_NOT_READY
;
4754 pSocket
->errno
= EAGAIN
;
4761 // Release the socket layer synchronization
4763 RESTORE_TPL ( TplPrevious
);
4765 if (( !EFI_ERROR ( Status
)) && ( NULL
!= pAddress
)) {
4767 // Return the remote address if requested, truncate if necessary
4769 AddressLength
= pRemoteAddress
->sa_len
;
4770 if ( AddressLength
> *pAddressLength
) {
4771 AddressLength
= *pAddressLength
;
4774 "Returning the remote address, 0x%016x bytes --> 0x%16x\r\n", *pAddressLength
, pAddress
));
4775 ZeroMem ( pAddress
, *pAddressLength
);
4776 CopyMem ( pAddress
, &Addr
, AddressLength
);
4779 // Update the address length
4781 *pAddressLength
= pRemoteAddress
->sa_len
;
4792 // Bad return address pointer and length
4794 Status
= EFI_INVALID_PARAMETER
;
4795 pSocket
->errno
= EINVAL
;
4800 // Return the operation status
4802 if ( NULL
!= pErrno
) {
4803 if ( NULL
!= pSocket
) {
4804 *pErrno
= pSocket
->errno
;
4807 Status
= EFI_INVALID_PARAMETER
;
4811 DBG_EXIT_STATUS ( Status
);
4817 Cancel the receive operations
4819 This routine cancels a pending receive operation.
4820 See the \ref ReceiveEngine section.
4822 This routine is called by ::EslSocketShutdown when the socket
4823 layer is being shutdown.
4825 @param [in] pPort Address of an ::ESL_PORT structure
4826 @param [in] pIo Address of an ::ESL_IO_MGMT structure
4831 IN ESL_PORT
* pPort
,
4832 IN ESL_IO_MGMT
* pIo
4840 // Cancel the outstanding receive
4842 Status
= pPort
->pfnRxCancel ( pPort
->pProtocol
.v
,
4844 if ( !EFI_ERROR ( Status
)) {
4845 DEBUG (( pPort
->DebugFlags
| DEBUG_CLOSE
| DEBUG_INFO
,
4846 "0x%08x: Packet receive aborted on port: 0x%08x\r\n",
4851 DEBUG (( pPort
->DebugFlags
| DEBUG_CLOSE
| DEBUG_INFO
,
4852 "0x%08x: Packet receive pending on Port 0x%08x, Status: %r\r\n",
4862 Process the receive completion
4864 This routine queues the data in FIFO order in either the urgent
4865 or normal data queues depending upon the type of data received.
4866 See the \ref ReceiveEngine section.
4868 This routine is called when some data is received by:
4870 <li>::EslIp4RxComplete</li>
4871 <li>::EslTcp4RxComplete</li>
4872 <li>::EslUdp4RxComplete</li>
4875 @param [in] pIo Address of an ::ESL_IO_MGMT structure
4876 @param [in] Status Receive status
4877 @param [in] LengthInBytes Length of the receive data
4878 @param [in] bUrgent TRUE if urgent data is received and FALSE
4883 EslSocketRxComplete (
4884 IN ESL_IO_MGMT
* pIo
,
4885 IN EFI_STATUS Status
,
4886 IN UINTN LengthInBytes
,
4890 BOOLEAN bUrgentQueue
;
4891 ESL_IO_MGMT
* pIoNext
;
4892 ESL_PACKET
* pPacket
;
4894 ESL_PACKET
* pPrevious
;
4895 ESL_PACKET
** ppQueueHead
;
4896 ESL_PACKET
** ppQueueTail
;
4898 ESL_SOCKET
* pSocket
;
4901 VERIFY_AT_TPL ( TPL_SOCKETS
);
4904 // Locate the active receive packet
4906 pPacket
= pIo
->pPacket
;
4908 pSocket
= pPort
->pSocket
;
4914 // +-------------+ +-------------+ +-------------+
4915 // Active | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
4916 // +-------------+ +-------------+ +-------------+
4918 // +-------------+ +-------------+ +-------------+
4919 // Free | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
4920 // +-------------+ +-------------+ +-------------+
4926 // Remove the IO structure from the active list
4927 // The following code searches for the entry in the list and does not
4928 // assume that the receive operations complete in the order they were
4929 // issued to the UEFI network layer.
4931 pIoNext
= pPort
->pRxActive
;
4932 while (( NULL
!= pIoNext
) && ( pIoNext
!= pIo
) && ( pIoNext
->pNext
!= pIo
))
4934 pIoNext
= pIoNext
->pNext
;
4936 ASSERT ( NULL
!= pIoNext
);
4937 if ( pIoNext
== pIo
) {
4938 pPort
->pRxActive
= pIo
->pNext
; // Beginning of list
4941 pIoNext
->pNext
= pIo
->pNext
; // Middle of list
4945 // Free the IO structure
4947 pIo
->pNext
= pPort
->pRxFree
;
4948 pPort
->pRxFree
= pIo
;
4951 // pRxOobPacketListHead pRxOobPacketListTail
4954 // +------------+ +------------+ +------------+
4955 // Urgent Data | ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL
4956 // +------------+ +------------+ +------------+
4958 // +------------+ +------------+ +------------+
4959 // Normal Data | ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL
4960 // +------------+ +------------+ +------------+
4963 // pRxPacketListHead pRxPacketListTail
4966 // Determine the queue to use
4968 bUrgentQueue
= (BOOLEAN
)( bUrgent
4969 && pSocket
->pApi
->bOobSupported
4970 && ( !pSocket
->bOobInLine
));
4971 if ( bUrgentQueue
) {
4972 ppQueueHead
= &pSocket
->pRxOobPacketListHead
;
4973 ppQueueTail
= &pSocket
->pRxOobPacketListTail
;
4974 pRxBytes
= &pSocket
->RxOobBytes
;
4977 ppQueueHead
= &pSocket
->pRxPacketListHead
;
4978 ppQueueTail
= &pSocket
->pRxPacketListTail
;
4979 pRxBytes
= &pSocket
->RxBytes
;
4983 // Determine if this receive was successful
4985 if (( !EFI_ERROR ( Status
))
4986 && ( PORT_STATE_CLOSE_STARTED
> pPort
->State
)
4987 && ( !pSocket
->bRxDisable
)) {
4989 // Account for the received data
4991 *pRxBytes
+= LengthInBytes
;
4994 // Log the received data
4996 DEBUG (( DEBUG_RX
| DEBUG_INFO
,
4997 "0x%08x: Packet queued on %s queue of port 0x%08x with 0x%08x bytes of %s data\r\n",
4999 bUrgentQueue
? L
"urgent" : L
"normal",
5002 bUrgent
? L
"urgent" : L
"normal" ));
5005 // Add the packet to the list tail.
5007 pPacket
->pNext
= NULL
;
5008 pPrevious
= *ppQueueTail
;
5009 if ( NULL
== pPrevious
) {
5010 *ppQueueHead
= pPacket
;
5013 pPrevious
->pNext
= pPacket
;
5015 *ppQueueTail
= pPacket
;
5018 // Attempt to restart this receive operation
5020 if ( pSocket
->MaxRxBuf
> pSocket
->RxBytes
) {
5021 EslSocketRxStart ( pPort
);
5025 "0x%08x: Port RX suspended, 0x%08x bytes queued\r\n",
5027 pSocket
->RxBytes
));
5031 if ( EFI_ERROR ( Status
)) {
5032 DEBUG (( DEBUG_RX
| DEBUG_INFO
,
5033 "ERROR - Receive error on port 0x%08x, packet 0x%08x, Status:%r\r\n",
5040 // Account for the receive bytes and release the driver's buffer
5042 if ( !EFI_ERROR ( Status
)) {
5043 *pRxBytes
+= LengthInBytes
;
5044 pSocket
->pApi
->pfnPacketFree ( pPacket
, pRxBytes
);
5048 // Receive error, free the packet save the error
5050 EslSocketPacketFree ( pPacket
, DEBUG_RX
);
5051 if ( !EFI_ERROR ( pSocket
->RxError
)) {
5052 pSocket
->RxError
= Status
;
5056 // Update the port state
5058 if ( PORT_STATE_CLOSE_STARTED
<= pPort
->State
) {
5059 if ( PORT_STATE_CLOSE_DONE
== pPort
->State
) {
5060 EslSocketPortCloseRxDone ( pPort
);
5064 if ( EFI_ERROR ( Status
)) {
5065 DEBUG (( DEBUG_RX
| DEBUG_INFO
,
5066 "0x%08x: Port state: PORT_STATE_RX_ERROR, Status: %r\r\n",
5069 pPort
->State
= PORT_STATE_RX_ERROR
;
5079 Poll a socket for pending receive activity.
5081 This routine is called at elivated TPL and extends the idle
5082 loop which polls a socket down into the LAN driver layer to
5083 determine if there is any receive activity.
5085 The ::EslSocketPoll, ::EslSocketReceive and ::EslSocketTransmit
5086 routines call this routine when there is nothing to do.
5088 @param [in] pSocket Address of an ::EFI_SOCKET structure.
5093 IN ESL_SOCKET
* pSocket
5098 DEBUG (( DEBUG_POLL
, "Entering EslSocketRxPoll\r\n" ));
5101 // Increase the network performance by extending the
5102 // polling (idle) loop down into the LAN driver
5104 pPort
= pSocket
->pPortList
;
5105 while ( NULL
!= pPort
) {
5107 // Poll the LAN adapter
5109 pPort
->pfnRxPoll ( pPort
->pProtocol
.v
);
5112 // Locate the next LAN adapter
5114 pPort
= pPort
->pLinkSocket
;
5117 DEBUG (( DEBUG_POLL
, "Exiting EslSocketRxPoll\r\n" ));
5122 Start a receive operation
5124 This routine posts a receive buffer to the network adapter.
5125 See the \ref ReceiveEngine section.
5127 This support routine is called by:
5129 <li>::EslIp4Receive to restart the receive engine to release flow control.</li>
5130 <li>::EslIp4RxComplete to continue the operation of the receive engine if flow control is not being applied.</li>
5131 <li>::EslIp4SocketIsConfigured to start the recevie engine for the new socket.</li>
5132 <li>::EslTcp4ListenComplete to start the recevie engine for the new socket.</li>
5133 <li>::EslTcp4Receive to restart the receive engine to release flow control.</li>
5134 <li>::EslTcp4RxComplete to continue the operation of the receive engine if flow control is not being applied.</li>
5135 <li>::EslUdp4Receive to restart the receive engine to release flow control.</li>
5136 <li>::EslUdp4RxComplete to continue the operation of the receive engine if flow control is not being applied.</li>
5137 <li>::EslUdp4SocketIsConfigured to start the recevie engine for the new socket.</li>
5140 @param [in] pPort Address of an ::ESL_PORT structure.
5150 ESL_PACKET
* pPacket
;
5151 ESL_SOCKET
* pSocket
;
5157 // Determine if a receive is already pending
5159 Status
= EFI_SUCCESS
;
5161 pSocket
= pPort
->pSocket
;
5162 if ( !EFI_ERROR ( pPort
->pSocket
->RxError
)) {
5163 if (( NULL
!= pPort
->pRxFree
)
5164 && ( !pSocket
->bRxDisable
)
5165 && ( PORT_STATE_CLOSE_STARTED
> pPort
->State
)) {
5167 // Start all of the pending receive operations
5169 while ( NULL
!= pPort
->pRxFree
) {
5171 // Determine if there are any free packets
5173 pPacket
= pSocket
->pRxFree
;
5174 if ( NULL
!= pPacket
) {
5176 // Remove this packet from the free list
5178 pSocket
->pRxFree
= pPacket
->pNext
;
5180 "0x%08x: Port removed packet 0x%08x from free list\r\n",
5186 // Allocate a packet structure
5188 Status
= EslSocketPacketAllocate ( &pPacket
,
5189 pSocket
->pApi
->RxPacketBytes
,
5190 pSocket
->pApi
->RxZeroBytes
,
5192 if ( EFI_ERROR ( Status
)) {
5194 DEBUG (( DEBUG_ERROR
| DEBUG_RX
,
5195 "0x%08x: Port failed to allocate RX packet, Status: %r\r\n",
5203 // Connect the IO and packet structures
5205 pIo
= pPort
->pRxFree
;
5206 pIo
->pPacket
= pPacket
;
5209 // Eliminate the need for IP4 and UDP4 specific routines by
5210 // clearing the RX data pointer here.
5212 // No driver buffer for this packet
5214 // +--------------------+
5217 // | +---------------+
5219 // | | RxData --> NULL
5220 // +----+---------------+
5222 pBuffer
= (UINT8
*)pIo
;
5223 pBuffer
= &pBuffer
[ pSocket
->pApi
->RxBufferOffset
];
5224 *(VOID
**)pBuffer
= NULL
;
5227 // Network specific receive packet initialization
5229 if ( NULL
!= pSocket
->pApi
->pfnRxStart
) {
5230 pSocket
->pApi
->pfnRxStart ( pPort
, pIo
);
5234 // Start the receive on the packet
5236 Status
= pPort
->pfnRxStart ( pPort
->pProtocol
.v
, &pIo
->Token
);
5237 if ( !EFI_ERROR ( Status
)) {
5238 DEBUG (( DEBUG_RX
| DEBUG_INFO
,
5239 "0x%08x: Packet receive pending on port 0x%08x\r\n",
5243 // Allocate the receive control structure
5245 pPort
->pRxFree
= pIo
->pNext
;
5248 // Mark this receive as pending
5250 pIo
->pNext
= pPort
->pRxActive
;
5251 pPort
->pRxActive
= pIo
;
5255 DEBUG (( DEBUG_RX
| DEBUG_INFO
,
5256 "ERROR - Failed to post a receive on port 0x%08x, Status: %r\r\n",
5259 if ( !EFI_ERROR ( pSocket
->RxError
)) {
5261 // Save the error status
5263 pSocket
->RxError
= Status
;
5269 pIo
->pPacket
= NULL
;
5270 pPacket
->pNext
= pSocket
->pRxFree
;
5271 pSocket
->pRxFree
= pPacket
;
5277 if ( NULL
== pPort
->pRxFree
) {
5278 DEBUG (( DEBUG_RX
| DEBUG_INFO
,
5279 "0x%08x: Port, no available ESL_IO_MGMT structures\r\n",
5282 if ( pSocket
->bRxDisable
) {
5283 DEBUG (( DEBUG_RX
| DEBUG_INFO
,
5284 "0x%08x: Port, receive disabled!\r\n",
5287 if ( PORT_STATE_CLOSE_STARTED
<= pPort
->State
) {
5288 DEBUG (( DEBUG_RX
| DEBUG_INFO
,
5289 "0x%08x: Port, is closing!\r\n",
5295 DEBUG (( DEBUG_ERROR
| DEBUG_RX
,
5296 "ERROR - Previous receive error, Status: %r\r\n",
5297 pPort
->pSocket
->RxError
));
5305 Shutdown the socket receive and transmit operations
5307 This routine sets a flag to stop future transmissions and calls
5308 the network specific layer to cancel the pending receive operation.
5310 The ::shutdown routine calls this routine to stop receive and transmit
5311 operations on the socket.
5313 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
5315 @param [in] How Which operations to stop
5317 @param [out] pErrno Address to receive the errno value upon completion.
5319 @retval EFI_SUCCESS - Socket operations successfully shutdown
5324 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
5331 ESL_SOCKET
* pSocket
;
5333 EFI_TPL TplPrevious
;
5340 Status
= EFI_SUCCESS
;
5343 // Validate the socket
5346 if ( NULL
!= pSocketProtocol
) {
5347 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
5350 // Verify that the socket is connected
5352 if ( pSocket
->bConnected
) {
5354 // Validate the How value
5356 if (( SHUT_RD
<= How
) && ( SHUT_RDWR
>= How
)) {
5358 // Synchronize with the socket layer
5360 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
5363 // Disable the receiver if requested
5365 if (( SHUT_RD
== How
) || ( SHUT_RDWR
== How
)) {
5366 pSocket
->bRxDisable
= TRUE
;
5370 // Disable the transmitter if requested
5372 if (( SHUT_WR
== How
) || ( SHUT_RDWR
== How
)) {
5373 pSocket
->bTxDisable
= TRUE
;
5377 // Cancel the pending receive operations
5379 if ( pSocket
->bRxDisable
) {
5381 // Walk the list of ports
5383 pPort
= pSocket
->pPortList
;
5384 while ( NULL
!= pPort
) {
5386 // Walk the list of active receive operations
5388 pIo
= pPort
->pRxActive
;
5389 while ( NULL
!= pIo
) {
5390 EslSocketRxCancel ( pPort
, pIo
);
5394 // Set the next port
5396 pPort
= pPort
->pLinkSocket
;
5401 // Release the socket layer synchronization
5403 RESTORE_TPL ( TplPrevious
);
5407 // Invalid How value
5409 pSocket
->errno
= EINVAL
;
5410 Status
= EFI_INVALID_PARAMETER
;
5415 // The socket is not connected
5417 pSocket
->errno
= ENOTCONN
;
5418 Status
= EFI_NOT_STARTED
;
5423 // Return the operation status
5425 if ( NULL
!= pErrno
) {
5426 if ( NULL
!= pSocket
) {
5427 *pErrno
= pSocket
->errno
;
5430 Status
= EFI_INVALID_PARAMETER
;
5434 DBG_EXIT_STATUS ( Status
);
5440 Send data using a network connection.
5442 This routine calls the network specific layer to queue the data
5443 for transmission. Eventually the buffer will reach the head of
5444 the queue and will get transmitted over the network by the
5445 \ref TransmitEngine. For datagram
5446 sockets (SOCK_DGRAM and SOCK_RAW) there is no guarantee that
5447 the data reaches the application running on the remote system.
5449 The ::sendto routine calls this routine to send data to the remote
5450 system. Note that ::send and ::write are layered on top of ::sendto.
5452 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
5454 @param [in] Flags Message control flags
5456 @param [in] BufferLength Length of the the buffer
5458 @param [in] pBuffer Address of a buffer containing the data to send
5460 @param [in] pDataLength Address to receive the number of data bytes sent
5462 @param [in] pAddress Network address of the remote system address
5464 @param [in] AddressLength Length of the remote network address structure
5466 @param [out] pErrno Address to receive the errno value upon completion.
5468 @retval EFI_SUCCESS - Socket data successfully queued for transmit
5473 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
5475 IN
size_t BufferLength
,
5476 IN CONST UINT8
* pBuffer
,
5477 OUT
size_t * pDataLength
,
5478 IN
const struct sockaddr
* pAddress
,
5479 IN socklen_t AddressLength
,
5483 ESL_SOCKET
* pSocket
;
5485 EFI_TPL TplPrevious
;
5492 Status
= EFI_SUCCESS
;
5495 // Validate the socket
5498 if ( NULL
!= pSocketProtocol
) {
5499 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
5502 // Return the transmit error if necessary
5504 if ( EFI_SUCCESS
!= pSocket
->TxError
) {
5505 pSocket
->errno
= EIO
;
5506 Status
= pSocket
->TxError
;
5507 pSocket
->TxError
= EFI_SUCCESS
;
5511 // Verify the socket state
5513 Status
= EslSocketIsConfigured ( pSocket
);
5514 if ( !EFI_ERROR ( Status
)) {
5516 // Verify that transmit is still allowed
5518 if ( !pSocket
->bTxDisable
) {
5520 // Validate the buffer length
5522 if (( NULL
== pDataLength
)
5523 && ( 0 > pDataLength
)
5524 && ( NULL
== pBuffer
)) {
5525 if ( NULL
== pDataLength
) {
5527 "ERROR - pDataLength is NULL!\r\n" ));
5529 else if ( NULL
== pBuffer
) {
5531 "ERROR - pBuffer is NULL!\r\n" ));
5535 "ERROR - Data length < 0!\r\n" ));
5537 Status
= EFI_INVALID_PARAMETER
;
5538 pSocket
->errno
= EFAULT
;
5542 // Validate the remote network address
5544 if (( NULL
!= pAddress
)
5545 && ( AddressLength
< pAddress
->sa_len
)) {
5547 "ERROR - Invalid sin_len field in address\r\n" ));
5548 Status
= EFI_INVALID_PARAMETER
;
5549 pSocket
->errno
= EFAULT
;
5555 if ( NULL
== pSocket
->pApi
->pfnTransmit
) {
5556 Status
= EFI_UNSUPPORTED
;
5557 pSocket
->errno
= ENOTSUP
;
5561 // Synchronize with the socket layer
5563 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
5566 // Poll the network to increase performance
5568 EslSocketRxPoll ( pSocket
);
5571 // Attempt to buffer the packet for transmission
5573 Status
= pSocket
->pApi
->pfnTransmit ( pSocket
,
5582 // Release the socket layer synchronization
5584 RESTORE_TPL ( TplPrevious
);
5591 // The transmitter was shutdown
5593 pSocket
->errno
= EPIPE
;
5594 Status
= EFI_NOT_STARTED
;
5601 // Return the operation status
5603 if ( NULL
!= pErrno
) {
5604 if ( NULL
!= pSocket
) {
5605 *pErrno
= pSocket
->errno
;
5608 Status
= EFI_INVALID_PARAMETER
;
5612 DBG_EXIT_STATUS ( Status
);
5618 Complete the transmit operation
5620 This support routine handles the transmit completion processing for
5621 the various network layers. It frees the ::ESL_IO_MGMT structure
5622 and and frees packet resources by calling ::EslSocketPacketFree.
5623 Transmit errors are logged in ESL_SOCKET::TxError.
5624 See the \ref TransmitEngine section.
5626 This routine is called by:
5628 <li>::EslIp4TxComplete</li>
5629 <li>::EslTcp4TxComplete</li>
5630 <li>::EslTcp4TxOobComplete</li>
5631 <li>::EslUdp4TxComplete</li>
5634 @param [in] pIo Address of an ::ESL_IO_MGMT structure
5635 @param [in] LengthInBytes Length of the data in bytes
5636 @param [in] Status Transmit operation status
5637 @param [in] pQueueType Zero terminated string describing queue type
5638 @param [in] ppQueueHead Transmit queue head address
5639 @param [in] ppQueueTail Transmit queue tail address
5640 @param [in] ppActive Active transmit queue address
5641 @param [in] ppFree Free transmit queue address
5645 EslSocketTxComplete (
5646 IN ESL_IO_MGMT
* pIo
,
5647 IN UINT32 LengthInBytes
,
5648 IN EFI_STATUS Status
,
5649 IN CONST CHAR8
* pQueueType
,
5650 IN ESL_PACKET
** ppQueueHead
,
5651 IN ESL_PACKET
** ppQueueTail
,
5652 IN ESL_IO_MGMT
** ppActive
,
5653 IN ESL_IO_MGMT
** ppFree
5656 ESL_PACKET
* pCurrentPacket
;
5657 ESL_IO_MGMT
* pIoNext
;
5658 ESL_PACKET
* pNextPacket
;
5659 ESL_PACKET
* pPacket
;
5661 ESL_SOCKET
* pSocket
;
5664 VERIFY_AT_TPL ( TPL_SOCKETS
);
5667 // Locate the active transmit packet
5669 pPacket
= pIo
->pPacket
;
5671 pSocket
= pPort
->pSocket
;
5676 pIo
->pPacket
= NULL
;
5679 // Remove the IO structure from the active list
5681 pIoNext
= *ppActive
;
5682 while (( NULL
!= pIoNext
) && ( pIoNext
!= pIo
) && ( pIoNext
->pNext
!= pIo
))
5684 pIoNext
= pIoNext
->pNext
;
5686 ASSERT ( NULL
!= pIoNext
);
5687 if ( pIoNext
== pIo
) {
5688 *ppActive
= pIo
->pNext
; // Beginning of list
5691 pIoNext
->pNext
= pIo
->pNext
; // Middle of list
5695 // Free the IO structure
5697 pIo
->pNext
= *ppFree
;
5701 // Display the results
5703 DEBUG (( DEBUG_TX
| DEBUG_INFO
,
5704 "0x%08x: pIo Released\r\n",
5708 // Save any transmit error
5710 if ( EFI_ERROR ( Status
)) {
5711 if ( !EFI_ERROR ( pSocket
->TxError
)) {
5712 pSocket
->TxError
= Status
;
5714 DEBUG (( DEBUG_TX
| DEBUG_INFO
,
5715 "ERROR - Transmit failure for %apacket 0x%08x, Status: %r\r\n",
5721 // Empty the normal transmit list
5723 pCurrentPacket
= pPacket
;
5724 pNextPacket
= *ppQueueHead
;
5725 while ( NULL
!= pNextPacket
) {
5726 pPacket
= pNextPacket
;
5727 pNextPacket
= pPacket
->pNext
;
5728 EslSocketPacketFree ( pPacket
, DEBUG_TX
);
5730 *ppQueueHead
= NULL
;
5731 *ppQueueTail
= NULL
;
5732 pPacket
= pCurrentPacket
;
5735 DEBUG (( DEBUG_TX
| DEBUG_INFO
,
5736 "0x%08x: %apacket transmitted %d bytes successfully\r\n",
5742 // Verify the transmit engine is still running
5744 if ( !pPort
->bCloseNow
) {
5746 // Start the next packet transmission
5748 EslSocketTxStart ( pPort
,
5757 // Release this packet
5759 EslSocketPacketFree ( pPacket
, DEBUG_TX
);
5762 // Finish the close operation if necessary
5764 if ( PORT_STATE_CLOSE_STARTED
<= pPort
->State
) {
5766 // Indicate that the transmit is complete
5768 EslSocketPortCloseTxDone ( pPort
);
5776 Transmit data using a network connection.
5778 This support routine starts a transmit operation on the
5779 underlying network layer.
5781 The network specific code calls this routine to start a
5782 transmit operation. See the \ref TransmitEngine section.
5784 @param [in] pPort Address of an ::ESL_PORT structure
5785 @param [in] ppQueueHead Transmit queue head address
5786 @param [in] ppQueueTail Transmit queue tail address
5787 @param [in] ppActive Active transmit queue address
5788 @param [in] ppFree Free transmit queue address
5793 IN ESL_PORT
* pPort
,
5794 IN ESL_PACKET
** ppQueueHead
,
5795 IN ESL_PACKET
** ppQueueTail
,
5796 IN ESL_IO_MGMT
** ppActive
,
5797 IN ESL_IO_MGMT
** ppFree
5802 ESL_PACKET
* pNextPacket
;
5803 ESL_PACKET
* pPacket
;
5804 VOID
** ppTokenData
;
5805 ESL_SOCKET
* pSocket
;
5813 Status
= EFI_SUCCESS
;
5816 // Get the packet from the queue head
5818 pPacket
= *ppQueueHead
;
5820 if (( NULL
!= pPacket
) && ( NULL
!= pIo
)) {
5821 pSocket
= pPort
->pSocket
;
5823 // *ppQueueHead: pSocket->pRxPacketListHead or pSocket->pRxOobPacketListHead
5826 // +------------+ +------------+ +------------+
5827 // Data | ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL
5828 // +------------+ +------------+ +------------+
5831 // *ppQueueTail: pSocket->pRxPacketListTail or pSocket->pRxOobPacketListTail
5834 // Remove the packet from the queue
5836 pNextPacket
= pPacket
->pNext
;
5837 *ppQueueHead
= pNextPacket
;
5838 if ( NULL
== pNextPacket
) {
5839 *ppQueueTail
= NULL
;
5841 pPacket
->pNext
= NULL
;
5844 // Eliminate the need for IP4 and UDP4 specific routines by
5845 // connecting the token with the TX data control structure here.
5847 // +--------------------+ +--------------------+
5848 // | ESL_IO_MGMT | | ESL_PACKET |
5850 // | +---------------+ +----------------+ |
5851 // | | Token | | Buffer Length | |
5852 // | | TxData --> | Buffer Address | |
5853 // | | | +----------------+---+
5854 // | | Event | | Data Buffer |
5855 // +----+---------------+ | |
5856 // +--------------------+
5858 // Compute the address of the TxData pointer in the token
5860 pBuffer
= (UINT8
*)&pIo
->Token
;
5861 pBuffer
= &pBuffer
[ pSocket
->TxTokenOffset
];
5862 ppTokenData
= (VOID
**)pBuffer
;
5865 // Compute the address of the TX data control structure in the packet
5867 // * EFI_IP4_TRANSMIT_DATA
5868 // * EFI_TCP4_TRANSMIT_DATA
5869 // * EFI_UDP4_TRANSMIT_DATA
5871 pBuffer
= (UINT8
*)pPacket
;
5872 pBuffer
= &pBuffer
[ pSocket
->TxPacketOffset
];
5875 // Connect the token to the transmit data control structure
5877 *ppTokenData
= (VOID
**)pBuffer
;
5880 // Display the results
5882 DEBUG (( DEBUG_TX
| DEBUG_INFO
,
5883 "0x%08x: pIo allocated for pPacket: 0x%08x\r\n",
5888 // Start the transmit operation
5890 Status
= pPort
->pfnTxStart ( pPort
->pProtocol
.v
,
5892 if ( !EFI_ERROR ( Status
)) {
5894 // Connect the structures
5896 pIo
->pPacket
= pPacket
;
5899 // +-------------+ +-------------+ +-------------+
5900 // Free | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
5901 // +-------------+ +-------------+ +-------------+
5904 // *ppFree: pPort->pTxFree or pTxOobFree
5907 // Remove the IO structure from the queue
5909 *ppFree
= pIo
->pNext
;
5912 // *ppActive: pPort->pTxActive or pTxOobActive
5915 // +-------------+ +-------------+ +-------------+
5916 // Active | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
5917 // +-------------+ +-------------+ +-------------+
5920 // Mark this packet as active
5922 pIo
->pPacket
= pPacket
;
5923 pIo
->pNext
= *ppActive
;
5927 if ( EFI_SUCCESS
== pSocket
->TxError
) {
5928 pSocket
->TxError
= Status
;
5932 // Discard the transmit buffer
5934 EslSocketPacketFree ( pPacket
, DEBUG_TX
);