2 Implement the socket support for the socket layer.
5 * Bound - pSocket->PortList is not NULL
6 * Listen - AcceptWait event is not NULL
8 Copyright (c) 2011, Intel Corporation
9 All rights reserved. This program and the accompanying materials
10 are licensed and made available under the terms and conditions of the BSD License
11 which accompanies this distribution. The full text of the license may be found at
12 http://opensource.org/licenses/bsd-license.php
14 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
15 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 \section DataStructures Data Structures
22 +-------------+ +-------------+ +-------------+
23 Service Lists | ::ESL_SERVICE |-->| ESL_SERVICE |-->| ESL_SERVICE |--> NULL (pNext)
24 +-------------+ +-------------+ +-------------+
26 pUdp4List ^ | pTcp4List | |
31 | ::ESL_LAYER | ::mEslLayer | |
35 +-------------+ +-------------+ +-------------+
36 | ::ESL_SOCKET |-->| ::ESL_PORT |-->| ESL_PORT |--> NULL (pLinkSocket)
37 +-------------+ +-------------+ +-------------+
41 +-------------+ +-------------+
42 | ESL_SOCKET |-->| ESL_PORT |--> NULL
43 +-------------+ +-------------+
47 (pNext) | | | | (pLinkService)
48 | | | | pRxPacketListHead
49 | | | `-----------------------------------------------.
50 | | | pRxOobPacketListHead |
51 | | `--------------------------------. |
52 | | pTxPacketListHead | |
53 | `---------------. | |
54 pTxOobPacketListHead | | | |
56 +------------+ +------------+ +------------+ +------------+
57 | ::ESL_PACKET | | ESL_PACKET | | ESL_PACKET | | ESL_PACKET |
58 +------------+ +------------+ +------------+ +------------+
61 +------------+ +------------+ +------------+ +------------+
62 | ESL_PACKET | | ESL_PACKET | | ESL_PACKET | | ESL_PACKET |
63 +------------+ +------------+ +------------+ +------------+
71 ::mEslLayer is the one and only ::ESL_LAYER structure. It connects directly or
72 indirectly to the other data structures. The ESL_LAYER structure has a unique
73 service list for each of the network protocol interfaces.
75 ::ESL_SERVICE manages the network interfaces for a given transport type (IP4, TCP4, UDP4, etc.)
77 ::ESL_SOCKET manages the activity for a single socket instance. As such, it contains
78 the ::EFI_SOCKET_PROTOCOL structure which the BSD socket library uses as the object
79 reference and the API into the EFI socket library.
81 ::ESL_PORT manages the connection with a single instance of the lower layer network.
82 This structure is the socket equivalent of an IP connection or a TCP or UDP port.
84 ::ESL_PACKET buffers data for transmit and receive. There are four queues connected
85 to the ::ESL_SOCKET that manage the data:
87 <li>ESL_SOCKET::pRxPacketListHead - Normal (low) priority receive data</li>
88 <li>ESL_SOCKET::pRxOobPacketListHead - High (out-of-band or urgent) priority receive data</li>
89 <li>ESL_SOCKET::pTxPacketListHead - Normal (low) priority transmit data</li>
90 <li>ESL_SOCKET::pTxOobPacketListHead - High (out-of-band or urgent) priority transmit data</li>
92 The selection of the transmit queue is controlled by the MSG_OOB flag on the transmit
93 request as well as the socket option SO_OOBINLINE. The receive queue is selected by
94 the URGENT data flag for TCP and the setting of the socket option SO_OOBINLINE.
96 Data structure synchronization is done by raising TPL to TPL_SOCKET. Modifying
97 critical elements within the data structures must be done at this TPL. TPL is then
98 restored to the previous level. Note that the code verifies that all callbacks are
99 entering at TPL_SOCKETS for proper data structure synchronization.
101 \section PortCloseStateMachine Port Close State Machine
103 The port close state machine walks the port through the necessary
104 states to stop activity on the port and get it into a state where
105 the resources may be released. The state machine consists of the
106 following arcs and states:
110 +--------------------------+
112 +--------------------------+
114 | ::EslSocketPortCloseStart
116 +--------------------------+
117 | PORT_STATE_CLOSE_STARTED |
118 +--------------------------+
120 | ::EslSocketPortCloseTxDone
122 +--------------------------+
123 | PORT_STATE_CLOSE_TX_DONE |
124 +--------------------------+
126 | ::EslSocketPortCloseComplete
128 +--------------------------+
129 | PORT_STATE_CLOSE_DONE |
130 +--------------------------+
132 | ::EslSocketPortCloseRxDone
134 +--------------------------+
135 | PORT_STATE_CLOSE_RX_DONE |
136 +--------------------------+
138 | ::EslSocketPortClose
140 +--------------------------+
142 +--------------------------+
147 <li>Arc: ::EslSocketPortCloseStart - Marks the port as closing and
148 initiates the port close operation</li>
149 <li>State: PORT_STATE_CLOSE_STARTED</li>
150 <li>Arc: ::EslSocketPortCloseTxDone - Waits until all of the transmit
151 operations to complete. After all of the transmits are complete,
152 this routine initiates the network specific close operation by calling
153 through ESL_PROTOCOL_API::pfnPortCloseOp. One such routine is
154 ::EslTcp4PortCloseOp.
156 <li>State: PORT_STATE_CLOSE_TX_DONE</li>
157 <li>Arc: ::EslSocketPortCloseComplete - Called when the close operation is
158 complete. After the transition to PORT_STATE_CLOSE_DONE,
159 this routine calls ::EslSocketRxCancel to abort the pending receive operations.
161 <li>State: PORT_STATE_CLOSE_DONE</li>
162 <li>Arc: ::EslSocketPortCloseRxDone - Waits until all of the receive
163 operation have been cancelled. After the transition to
164 PORT_STATE_CLOSE_RX_DONE, this routine calls ::EslSocketPortClose.
166 <li>State: PORT_STATE_CLOSE_RX_DONE</li>
167 <li>Arc: ::EslSocketPortClose - This routine discards any receive buffers
168 using a network specific support routine via ESL_PROTOCOL_API::pfnPacketFree.
169 This routine then releases the port resources allocated by ::EslSocketPortAllocate
170 and calls the network specific port close routine (e.g. ::EslTcp4PortClose)
171 via ESL_PROTOCOL_API::pfnPortClose to release any network specific resources.
176 \section ReceiveEngine Receive Engine
178 The receive path accepts data from the network and queues (buffers) it for the
179 application. Flow control is applied once a maximum amount of buffering is reached
180 and is released when the buffer usage drops below that limit. Eventually the
181 application requests data from the socket which removes entries from the queue and
184 The receive engine is the state machine which reads data from the network and
185 fills the queue with received packets. The receive engine uses two data structures
186 to manage the network receive opeations and the buffers.
188 At a high level, the ::ESL_IO_MGMT structures are managing the tokens and
189 events for the interface to the UEFI network stack. The ::ESL_PACKET
190 structures are managing the receive data buffers. The receive engine
191 connects these two structures in the network specific receive completion
211 The ::ESL_IO_MGMT structures are allocated as part of the ::ESL_PORT structure in
212 ::EslSocketPortAllocate. The ESL_IO_MGMT structures are separated and placed on
213 the free list by calling ::EslSocketIoInit. The ESL_IO_MGMT structure contains
214 the network layer specific receive completion token and event. The receive engine
215 is eventually shutdown by ::EslSocketPortCloseTxDone and the resources in these
216 structures are released in ::EslSocketPortClose by a call to ::EslSocketIoFree.
223 +-------------+ +-------------+ +-------------+
224 Active | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
225 +-------------+ +-------------+ +-------------+
227 +-------------+ +-------------+ +-------------+
228 Free | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
229 +-------------+ +-------------+ +-------------+
235 The receive engine is started by calling ::EslSocketRxStart. Flow control pauses
236 the receive engine by stopping the calls to EslSocketRxStart when the amount of
237 receive data waiting for the application meets or exceeds MAX_RX_DATA. After
238 the application reads enough data that the amount of buffering drops below this
239 limit, the calls to EslSockeRxStart continue which releases the flow control.
241 Receive flow control is applied when the port is created, since no receive
242 operation are pending to the low layer network driver. The flow control gets
243 released when the low layer network port is configured or the first receive
244 operation is posted. Flow control remains in the released state until the
245 maximum buffer space is consumed. During this time, ::EslSocketRxComplete
246 calls ::EslSocketRxStart. Flow control is applied in EslSocketRxComplete
247 by skipping the call to EslSocketRxStart. Flow control is eventually
248 released in ::EslSocketReceive when the buffer space drops below the
249 maximum amount causing EslSocketReceive to call EslSocketRxStart.
253 +------------+ +------------+
254 High .----->| ESL_PACKET |-->| ESL_PACKET |--> NULL (pNext)
255 Priority | +------------+ +------------+
257 | pRxOobPacketListHead
263 Priority | +------------+ +------------+ +------------+
264 `----->| ::ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL
265 +------------+ +------------+ +------------+
269 ::EslSocketRxStart connects an ::ESL_PACKET structure to the ::ESL_IO_MGMT structure
270 and then calls the network layer to start the receive operation. Upon
271 receive completion, ::EslSocketRxComplete breaks the connection between these
272 structrues and places the ESL_IO_MGMT structure onto the ESL_PORT::pRxFree list to
273 make token and event available for another receive operation. EslSocketRxComplete
274 then queues the ESL_PACKET structure (data packet) to either the
275 ESL_SOCKET::pRxOobPacketListTail or ESL_SOCKET::pRxPacketListTail depending on
276 whether urgent or normal data was received. Finally ::EslSocketRxComplete attempts
277 to start another receive operation.
281 Setup for IP4 and UDP4
283 +--------------------+
289 +----+---------------+
292 +--------------------+
297 +----+---------------+
299 Completion for IP4 and UDP4
301 +--------------------+ +----------------------+
302 | ESL_IO_MGMT | | Data Buffer |
303 | | | (Driver owned) |
304 | +---------------+ +----------------------+
307 | | | +----------------------+
308 | | RxData --> | EFI_IP4_RECEIVE_DATA |
309 +----+---------------+ | (Driver owned) |
310 | +----------------------+
312 +--------------------+ .
315 | +---------------+ .
316 | | pRxData --> NULL .......
317 +----+---------------+
320 Setup and completion for TCP4
322 +--------------------+ +--------------------------+
323 | ESL_IO_MGMT |-->| ESL_PACKET |
325 | +---------------+ +----------------------+ |
326 | | Token | | EFI_IP4_RECEIVE_DATA | |
328 | | | +----------------------+---+
329 | | Event | | Data Buffer |
330 +----+---------------+ | |
332 +--------------------------+
336 To minimize the number of buffer copies, the data is not copied until the
337 application makes a receive call. At this point socket performs a single copy
338 in the receive path to move the data from the buffer filled by the network layer
339 into the application's buffer.
341 The IP4 and UDP4 drivers go one step further to reduce buffer copies. They
342 allow the socket layer to hold on to the actual receive buffer until the
343 application has performed a receive operation or closes the socket. Both
344 of theses operations return the buffer to the lower layer network driver
345 by calling ESL_PROTOCOL_API::pfnPacketFree.
347 When a socket application wants to receive data it indirectly calls
348 ::EslSocketReceive to remove data from one of the receive data queues. This routine
349 removes the next available packet from ESL_SOCKET::pRxOobPacketListHead or
350 ESL_SOCKET::pRxPacketListHead and copies the data from the packet
351 into the application's buffer. For SOCK_STREAM sockets, if the packet
352 contains more data then the ESL_PACKET structures remains at the head of the
353 receive queue for the next application receive
354 operation. For SOCK_DGRAM, SOCK_RAW and SOCK_SEQ_PACKET sockets, the ::ESL_PACKET
355 structure is removed from the head of the receive queue and any remaining data is
356 discarded as the packet is placed on the free queue.
358 During socket layer shutdown, ::EslSocketShutdown calls ::EslSocketRxCancel to
359 cancel any pending receive operations. EslSocketRxCancel calls the network specific
360 cancel routine using ESL_PORT::pfnRxCancel.
363 \section TransmitEngine Transmit Engine
365 Application calls to ::EslSocketTransmit cause data to be copied into a buffer.
366 The buffer exists as an extension to an ESL_PACKET structure and the structure
367 is placed at the end of the transmit queue.
371 *ppQueueHead: pSocket->pRxPacketListHead or pSocket->pRxOobPacketListHead
374 +------------+ +------------+ +------------+
375 Data | ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL
376 +------------+ +------------+ +------------+
379 *ppQueueTail: pSocket->pRxPacketListTail or pSocket->pRxOobPacketListTail
383 There are actually two transmit queues the normal or low priority queue which is
384 the default and the urgent or high priority queue which is addressed by specifying
385 the MSG_OOB flag during the transmit request. Associated with each queue is a
386 transmit engine which is responsible for sending the data in that queue.
388 The transmit engine is the state machine which removes entries from the head
389 of the transmit queue and causes the data to be sent over the network.
393 +--------------------+ +--------------------+
394 | ESL_IO_MGMT | | ESL_PACKET |
396 | +---------------+ +----------------+ |
397 | | Token | | Buffer Length | |
398 | | TxData --> | Buffer Address | |
399 | | | +----------------+---+
400 | | Event | | Data Buffer |
401 +----+---------------+ | |
402 +--------------------+
405 At a high level, the transmit engine uses a couple of data structures
406 to manage the data flow. The ::ESL_IO_MGMT structures manage the tokens and
407 events for the interface to the UEFI network stack. The ::ESL_PACKET
408 structures manage the data buffers that get sent. The transmit
409 engine connects these two structures prior to transmission and disconnects
410 them upon completion.
414 pPort->pTxActive or pTxOobActive
417 +-------------+ +-------------+ +-------------+
418 Active | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
419 +-------------+ +-------------+ +-------------+
421 +-------------+ +-------------+ +-------------+
422 Free | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
423 +-------------+ +-------------+ +-------------+
426 pPort->pTxFree or pTxOobFree
430 The transmit engine manages multiple transmit operations using the
431 active and free lists shown above. ::EslSocketPortAllocate allocates the
432 ::ESL_IO_MGMT structures as an extension to the ::ESL_PORT structure.
433 This routine places the ESL_IO_MGMT structures on the free list by calling
434 ::EslSocketIoInit. During their lifetime, the ESL_IO_MGMT structures
435 will move from the free list to the active list and back again. The
436 active list contains the packets that are actively being processed by
437 the UEFI network stack. Eventually the ESL_IO_MGMT structures will be
438 removed from the free list and be deallocated by the EslSocketPortClose
441 The network specific code calls the ::EslSocketTxStart routine
442 to hand a packet to the network stack. EslSocketTxStart connects
443 the transmit packet (::ESL_PACKET) to an ::ESL_IO_MGMT structure
444 and then queues the result to one of the active lists:
445 ESL_PORT::pTxActive or ESL_PORT::pTxOobActive. The routine then
446 hands the packet to the network stack.
448 Upon completion, the network specific TxComplete routine calls
449 ::EslSocketTxComplete to disconnect the transmit packet from the
450 ESL_IO_MGMT structure and frees the ::ESL_PACKET structure by calling
451 ::EslSocketPacketFree. The routine places the ::ESL_IO_MGMT structure
452 into the free list either ESL_PORT::pTxFree or ESL_PORT::pTxOobFree.
453 EslSocketTxComplete then starts the next transmit operation while
454 the socket is active or calls the ::EslSocketPortCloseTxDone routine
455 when the socket is shutting down.
463 Socket driver connection points
465 List the network stack connection points for the socket driver.
467 CONST ESL_SOCKET_BINDING cEslSocketBinding
[] = {
469 &gEfiIp4ServiceBindingProtocolGuid
,
470 &gEfiIp4ProtocolGuid
,
472 OFFSET_OF ( ESL_LAYER
, pIp4List
),
475 0 }, // TX Oob buffers
477 &gEfiTcp4ServiceBindingProtocolGuid
,
478 &gEfiTcp4ProtocolGuid
,
479 &mEslTcp4ServiceGuid
,
480 OFFSET_OF ( ESL_LAYER
, pTcp4List
),
483 4 }, // TX Oob buffers
485 &gEfiTcp6ServiceBindingProtocolGuid
,
486 &gEfiTcp6ProtocolGuid
,
487 &mEslTcp6ServiceGuid
,
488 OFFSET_OF ( ESL_LAYER
, pTcp6List
),
491 4 }, // TX Oob buffers
493 &gEfiUdp4ServiceBindingProtocolGuid
,
494 &gEfiUdp4ProtocolGuid
,
495 &mEslUdp4ServiceGuid
,
496 OFFSET_OF ( ESL_LAYER
, pUdp4List
),
499 0 }, // TX Oob buffers
501 &gEfiUdp6ServiceBindingProtocolGuid
,
502 &gEfiUdp6ProtocolGuid
,
503 &mEslUdp6ServiceGuid
,
504 OFFSET_OF ( ESL_LAYER
, pUdp6List
),
507 0 } // TX Oob buffers
510 CONST UINTN cEslSocketBindingEntries
= DIM ( cEslSocketBinding
);
513 APIs to support the various socket types for the v4 network stack.
515 CONST ESL_PROTOCOL_API
* cEslAfInetApi
[] = {
517 &cEslTcp4Api
, // SOCK_STREAM
518 &cEslUdp4Api
, // SOCK_DGRAM
519 &cEslIp4Api
, // SOCK_RAW
521 &cEslTcp4Api
// SOCK_SEQPACKET
525 Number of entries in the v4 API array ::cEslAfInetApi.
527 CONST
int cEslAfInetApiSize
= DIM ( cEslAfInetApi
);
531 APIs to support the various socket types for the v6 network stack.
533 CONST ESL_PROTOCOL_API
* cEslAfInet6Api
[] = {
535 &cEslTcp6Api
, // SOCK_STREAM
536 &cEslUdp6Api
, // SOCK_DGRAM
539 &cEslTcp6Api
// SOCK_SEQPACKET
543 Number of entries in the v6 API array ::cEslAfInet6Api.
545 CONST
int cEslAfInet6ApiSize
= DIM ( cEslAfInet6Api
);
549 Global management structure for the socket layer.
555 Initialize an endpoint for network communication.
557 This routine initializes the communication endpoint.
559 The ::socket routine calls this routine indirectly to create
560 the communication endpoint.
562 @param [in] pSocketProtocol Address of the socket protocol structure.
563 @param [in] domain Select the family of protocols for the client or server
564 application. See the ::socket documentation for values.
565 @param [in] type Specifies how to make the network connection.
566 See the ::socket documentation for values.
567 @param [in] protocol Specifies the lower layer protocol to use.
568 See the ::socket documentation for values.
569 @param [out] pErrno Address to receive the errno value upon completion.
571 @retval EFI_SUCCESS - Socket successfully created
572 @retval EFI_INVALID_PARAMETER - Invalid domain value, errno = EAFNOSUPPORT
573 @retval EFI_INVALID_PARAMETER - Invalid type value, errno = EINVAL
574 @retval EFI_INVALID_PARAMETER - Invalid protocol value, errno = EINVAL
579 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
586 CONST ESL_PROTOCOL_API
* pApi
;
587 CONST ESL_PROTOCOL_API
** ppApiArray
;
588 CONST ESL_PROTOCOL_API
** ppApiArrayEnd
;
590 ESL_SOCKET
* pSocket
;
599 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
602 // Set the default domain if necessary
604 if ( AF_UNSPEC
== domain
) {
612 Status
= EFI_SUCCESS
;
615 // Use break instead of goto
619 // Validate the domain value
621 if (( AF_INET
!= domain
)
622 && ( AF_INET6
!= domain
)
623 && ( AF_LOCAL
!= domain
)) {
624 DEBUG (( DEBUG_ERROR
| DEBUG_SOCKET
,
625 "ERROR - Invalid domain value\r\n" ));
626 Status
= EFI_INVALID_PARAMETER
;
627 errno
= EAFNOSUPPORT
;
632 // Determine the protocol APIs
636 if (( AF_INET
== domain
)
637 || ( AF_LOCAL
== domain
)) {
638 ppApiArray
= &cEslAfInetApi
[0];
639 ApiArraySize
= cEslAfInetApiSize
;
642 ppApiArray
= &cEslAfInet6Api
[0];
643 ApiArraySize
= cEslAfInet6ApiSize
;
647 // Set the default type if necessary
654 // Validate the type value
656 if (( type
>= ApiArraySize
)
657 || ( NULL
== ppApiArray
)
658 || ( NULL
== ppApiArray
[ type
])) {
659 DEBUG (( DEBUG_ERROR
| DEBUG_SOCKET
,
660 "ERROR - Invalid type value\r\n" ));
662 // The socket type is not supported
664 Status
= EFI_INVALID_PARAMETER
;
670 // Set the default protocol if necessary
672 pApi
= ppApiArray
[ type
];
673 if ( 0 == protocol
) {
674 protocol
= pApi
->DefaultProtocol
;
678 // Validate the protocol value
680 if (( pApi
->DefaultProtocol
!= protocol
)
681 && ( SOCK_RAW
!= type
)) {
682 Status
= EFI_INVALID_PARAMETER
;
685 // Assume that the driver supports this protocol
687 ppApiArray
= &cEslAfInetApi
[0];
688 ppApiArrayEnd
= &ppApiArray
[ cEslAfInetApiSize
];
689 while ( ppApiArrayEnd
> ppApiArray
) {
691 if ( protocol
== pApi
->DefaultProtocol
) {
696 if ( ppApiArrayEnd
<= ppApiArray
) {
698 // Verify against the IPv6 table
700 ppApiArray
= &cEslAfInet6Api
[0];
701 ppApiArrayEnd
= &ppApiArray
[ cEslAfInet6ApiSize
];
702 while ( ppApiArrayEnd
> ppApiArray
) {
704 if ( protocol
== pApi
->DefaultProtocol
) {
710 if ( ppApiArrayEnd
<= ppApiArray
) {
711 DEBUG (( DEBUG_ERROR
| DEBUG_SOCKET
,
712 "ERROR - The protocol is not supported!\r\n" ));
713 errno
= EPROTONOSUPPORT
;
718 // The driver does not support this protocol
720 DEBUG (( DEBUG_ERROR
| DEBUG_SOCKET
,
721 "ERROR - The protocol does not support this socket type!\r\n" ));
722 errno
= EPROTONOSUPPORT
;
728 // Save the socket attributes
730 pSocket
->pApi
= pApi
;
731 pSocket
->Domain
= domain
;
732 pSocket
->Type
= type
;
733 pSocket
->Protocol
= protocol
;
742 // Return the operation status
744 if ( NULL
!= pErrno
) {
747 DBG_EXIT_STATUS ( Status
);
753 Accept a network connection.
755 This routine calls the network specific layer to remove the next
756 connection from the FIFO.
758 The ::accept calls this routine to poll for a network
759 connection to the socket. When a connection is available
760 this routine returns the ::EFI_SOCKET_PROTOCOL structure address
761 associated with the new socket and the remote network address
764 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
766 @param [in] pSockAddr Address of a buffer to receive the remote
769 @param [in, out] pSockAddrLength Length in bytes of the address buffer.
770 On output specifies the length of the
771 remote network address.
773 @param [out] ppSocketProtocol Address of a buffer to receive the
774 ::EFI_SOCKET_PROTOCOL instance
775 associated with the new socket.
777 @param [out] pErrno Address to receive the errno value upon completion.
779 @retval EFI_SUCCESS New connection successfully created
780 @retval EFI_NOT_READY No connection is available
785 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
786 IN
struct sockaddr
* pSockAddr
,
787 IN OUT socklen_t
* pSockAddrLength
,
788 IN EFI_SOCKET_PROTOCOL
** ppSocketProtocol
,
792 ESL_SOCKET
* pNewSocket
;
793 ESL_SOCKET
* pSocket
;
802 Status
= EFI_SUCCESS
;
805 // Validate the socket
809 if ( NULL
!= pSocketProtocol
) {
810 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
815 if ( NULL
== pSocket
->pApi
->pfnAccept
) {
816 Status
= EFI_UNSUPPORTED
;
817 pSocket
->errno
= ENOTSUP
;
821 // Validate the sockaddr
823 if (( NULL
!= pSockAddr
)
824 && ( NULL
== pSockAddrLength
)) {
825 DEBUG (( DEBUG_ACCEPT
,
826 "ERROR - pSockAddr is NULL!\r\n" ));
827 Status
= EFI_INVALID_PARAMETER
;
828 pSocket
->errno
= EFAULT
;
832 // Synchronize with the socket layer
834 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
837 // Verify that the socket is in the listen state
839 if ( SOCKET_STATE_LISTENING
!= pSocket
->State
) {
840 DEBUG (( DEBUG_ACCEPT
,
841 "ERROR - Socket is not listening!\r\n" ));
842 if ( NULL
== pSocket
->pApi
->pfnAccept
) {
844 // Socket does not support listen
846 pSocket
->errno
= EOPNOTSUPP
;
847 Status
= EFI_UNSUPPORTED
;
851 // Socket supports listen, but not in listen state
853 pSocket
->errno
= EINVAL
;
854 Status
= EFI_NOT_STARTED
;
859 // Determine if a socket is available
861 if ( 0 == pSocket
->FifoDepth
) {
863 // No connections available
864 // Determine if any ports are available
866 if ( NULL
== pSocket
->pPortList
) {
868 // No ports available
870 Status
= EFI_DEVICE_ERROR
;
871 pSocket
->errno
= EINVAL
;
874 // Update the socket state
876 pSocket
->State
= SOCKET_STATE_NO_PORTS
;
880 // Ports are available
881 // No connection requests at this time
883 Status
= EFI_NOT_READY
;
884 pSocket
->errno
= EAGAIN
;
890 // Attempt to accept the connection and
891 // get the remote network address
893 pNewSocket
= pSocket
->pFifoHead
;
894 ASSERT ( NULL
!= pNewSocket
);
895 Status
= pSocket
->pApi
->pfnAccept ( pNewSocket
,
898 if ( !EFI_ERROR ( Status
)) {
900 // Remove the new socket from the list
902 pSocket
->pFifoHead
= pNewSocket
->pNextConnection
;
903 if ( NULL
== pSocket
->pFifoHead
) {
904 pSocket
->pFifoTail
= NULL
;
908 // Account for this socket
910 pSocket
->FifoDepth
-= 1;
913 // Update the new socket's state
915 pNewSocket
->State
= SOCKET_STATE_CONNECTED
;
916 pNewSocket
->bConfigured
= TRUE
;
917 DEBUG (( DEBUG_ACCEPT
,
918 "0x%08x: Socket connected\r\n",
925 // Release the socket layer synchronization
927 RESTORE_TPL ( TplPrevious
);
933 // Return the new socket
935 if (( NULL
!= ppSocketProtocol
)
936 && ( NULL
!= pNewSocket
)) {
937 *ppSocketProtocol
= &pNewSocket
->SocketProtocol
;
941 // Return the operation status
943 if ( NULL
!= pErrno
) {
944 if ( NULL
!= pSocket
) {
945 *pErrno
= pSocket
->errno
;
948 Status
= EFI_INVALID_PARAMETER
;
952 DBG_EXIT_STATUS ( Status
);
958 Allocate and initialize a ESL_SOCKET structure.
960 This support function allocates an ::ESL_SOCKET structure
961 and installs a protocol on ChildHandle. If pChildHandle is a
962 pointer to NULL, then a new handle is created and returned in
963 pChildHandle. If pChildHandle is not a pointer to NULL, then
964 the protocol installs on the existing pChildHandle.
966 @param [in, out] pChildHandle Pointer to the handle of the child to create.
967 If it is NULL, then a new handle is created.
968 If it is a pointer to an existing UEFI handle,
969 then the protocol is added to the existing UEFI
971 @param [in] DebugFlags Flags for debug messages
972 @param [in, out] ppSocket The buffer to receive an ::ESL_SOCKET structure address.
974 @retval EFI_SUCCESS The protocol was added to ChildHandle.
975 @retval EFI_INVALID_PARAMETER ChildHandle is NULL.
976 @retval EFI_OUT_OF_RESOURCES There are not enough resources available to create
978 @retval other The child handle was not created
984 IN OUT EFI_HANDLE
* pChildHandle
,
986 IN OUT ESL_SOCKET
** ppSocket
991 ESL_SOCKET
* pSocket
;
998 // Create a socket structure
1000 LengthInBytes
= sizeof ( *pSocket
);
1001 pSocket
= (ESL_SOCKET
*) AllocateZeroPool ( LengthInBytes
);
1002 if ( NULL
!= pSocket
) {
1003 DEBUG (( DebugFlags
| DEBUG_POOL
| DEBUG_INIT
,
1004 "0x%08x: Allocate pSocket, %d bytes\r\n",
1009 // Initialize the socket protocol
1011 pSocket
->Signature
= SOCKET_SIGNATURE
;
1012 pSocket
->SocketProtocol
.pfnAccept
= EslSocketAccept
;
1013 pSocket
->SocketProtocol
.pfnBind
= EslSocketBind
;
1014 pSocket
->SocketProtocol
.pfnClosePoll
= EslSocketClosePoll
;
1015 pSocket
->SocketProtocol
.pfnCloseStart
= EslSocketCloseStart
;
1016 pSocket
->SocketProtocol
.pfnConnect
= EslSocketConnect
;
1017 pSocket
->SocketProtocol
.pfnGetLocal
= EslSocketGetLocalAddress
;
1018 pSocket
->SocketProtocol
.pfnGetPeer
= EslSocketGetPeerAddress
;
1019 pSocket
->SocketProtocol
.pfnListen
= EslSocketListen
;
1020 pSocket
->SocketProtocol
.pfnOptionGet
= EslSocketOptionGet
;
1021 pSocket
->SocketProtocol
.pfnOptionSet
= EslSocketOptionSet
;
1022 pSocket
->SocketProtocol
.pfnPoll
= EslSocketPoll
;
1023 pSocket
->SocketProtocol
.pfnReceive
= EslSocketReceive
;
1024 pSocket
->SocketProtocol
.pfnShutdown
= EslSocketShutdown
;
1025 pSocket
->SocketProtocol
.pfnSocket
= EslSocket
;
1026 pSocket
->SocketProtocol
.pfnTransmit
= EslSocketTransmit
;
1028 pSocket
->MaxRxBuf
= MAX_RX_DATA
;
1029 pSocket
->MaxTxBuf
= MAX_TX_DATA
;
1032 // Install the socket protocol on the specified handle
1034 Status
= gBS
->InstallMultipleProtocolInterfaces (
1036 &gEfiSocketProtocolGuid
,
1037 &pSocket
->SocketProtocol
,
1040 if ( !EFI_ERROR ( Status
)) {
1041 DEBUG (( DebugFlags
| DEBUG_POOL
| DEBUG_INIT
| DEBUG_INFO
,
1042 "Installed: gEfiSocketProtocolGuid on 0x%08x\r\n",
1044 pSocket
->SocketProtocol
.SocketHandle
= *pChildHandle
;
1047 // Synchronize with the socket layer
1049 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
1052 // Add this socket to the list
1054 pLayer
= &mEslLayer
;
1055 pSocket
->pNext
= pLayer
->pSocketList
;
1056 pLayer
->pSocketList
= pSocket
;
1059 // Release the socket layer synchronization
1061 RESTORE_TPL ( TplPrevious
);
1064 // Return the socket structure address
1066 *ppSocket
= pSocket
;
1069 DEBUG (( DEBUG_ERROR
| DebugFlags
| DEBUG_POOL
| DEBUG_INIT
,
1070 "ERROR - Failed to install gEfiSocketProtocolGuid on 0x%08x, Status: %r\r\n",
1076 // Release the socket if necessary
1078 if ( EFI_ERROR ( Status
)) {
1079 gBS
->FreePool ( pSocket
);
1080 DEBUG (( DebugFlags
| DEBUG_POOL
| DEBUG_INIT
,
1081 "0x%08x: Free pSocket, %d bytes\r\n",
1083 sizeof ( *pSocket
)));
1088 Status
= EFI_OUT_OF_RESOURCES
;
1092 // Return the operation status
1094 DBG_EXIT_STATUS ( Status
);
1100 Bind a name to a socket.
1102 This routine calls the network specific layer to save the network
1103 address of the local connection point.
1105 The ::bind routine calls this routine to connect a name
1106 (network address and port) to a socket on the local machine.
1108 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
1110 @param [in] pSockAddr Address of a sockaddr structure that contains the
1111 connection point on the local machine. An IPv4 address
1112 of INADDR_ANY specifies that the connection is made to
1113 all of the network stacks on the platform. Specifying a
1114 specific IPv4 address restricts the connection to the
1115 network stack supporting that address. Specifying zero
1116 for the port causes the network layer to assign a port
1117 number from the dynamic range. Specifying a specific
1118 port number causes the network layer to use that port.
1120 @param [in] SockAddrLength Specifies the length in bytes of the sockaddr structure.
1122 @param [out] pErrno Address to receive the errno value upon completion.
1124 @retval EFI_SUCCESS - Socket successfully created
1129 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
1130 IN CONST
struct sockaddr
* pSockAddr
,
1131 IN socklen_t SockAddrLength
,
1135 EFI_HANDLE ChildHandle
;
1138 ESL_SERVICE
** ppServiceListHead
;
1139 ESL_SOCKET
* pSocket
;
1140 ESL_SERVICE
* pService
;
1141 EFI_SERVICE_BINDING_PROTOCOL
* pServiceBinding
;
1143 EFI_TPL TplPrevious
;
1150 Status
= EFI_SUCCESS
;
1153 // Validate the socket
1156 if ( NULL
!= pSocketProtocol
) {
1157 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
1160 // Validate the structure pointer
1163 if ( NULL
== pSockAddr
) {
1164 DEBUG (( DEBUG_BIND
,
1165 "ERROR - pSockAddr is NULL!\r\n" ));
1166 Status
= EFI_INVALID_PARAMETER
;
1167 pSocket
->errno
= EFAULT
;
1171 // Validate the local address length
1173 else if ( SockAddrLength
< pSocket
->pApi
->MinimumAddressLength
) {
1174 DEBUG (( DEBUG_BIND
,
1175 "ERROR - Invalid bind name length: %d\r\n",
1177 Status
= EFI_INVALID_PARAMETER
;
1178 pSocket
->errno
= EINVAL
;
1182 // Validate the shutdown state
1184 else if ( pSocket
->bRxDisable
|| pSocket
->bTxDisable
) {
1185 DEBUG (( DEBUG_BIND
,
1186 "ERROR - Shutdown has been called on socket 0x%08x\r\n",
1188 pSocket
->errno
= EINVAL
;
1189 Status
= EFI_INVALID_PARAMETER
;
1193 // Verify the socket state
1195 else if ( SOCKET_STATE_NOT_CONFIGURED
!= pSocket
->State
) {
1196 DEBUG (( DEBUG_BIND
,
1197 "ERROR - The socket 0x%08x is already configured!\r\n",
1199 pSocket
->errno
= EINVAL
;
1200 Status
= EFI_ALREADY_STARTED
;
1204 // Synchronize with the socket layer
1206 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
1209 // Assume no ports are available
1211 pSocket
->errno
= EADDRNOTAVAIL
;
1212 Status
= EFI_INVALID_PARAMETER
;
1215 // Walk the list of services
1217 pBuffer
= (UINT8
*)&mEslLayer
;
1218 pBuffer
= &pBuffer
[ pSocket
->pApi
->ServiceListOffset
];
1219 ppServiceListHead
= (ESL_SERVICE
**)pBuffer
;
1220 pService
= *ppServiceListHead
;
1221 while ( NULL
!= pService
) {
1225 pServiceBinding
= pService
->pServiceBinding
;
1227 Status
= pServiceBinding
->CreateChild ( pServiceBinding
,
1229 if ( !EFI_ERROR ( Status
)) {
1230 DEBUG (( DEBUG_BIND
| DEBUG_POOL
,
1231 "0x%08x: %s port handle created\r\n",
1233 pService
->pSocketBinding
->pName
));
1238 Status
= EslSocketPortAllocate ( pSocket
,
1247 DEBUG (( DEBUG_BIND
| DEBUG_POOL
,
1248 "ERROR - Failed to open %s port handle, Status: %r\r\n",
1249 pService
->pSocketBinding
->pName
,
1254 // Set the next service
1256 pService
= pService
->pNext
;
1260 // Verify that at least one network connection was found
1262 if ( NULL
!= pSocket
->pPortList
) {
1263 Status
= EFI_SUCCESS
;
1266 if ( EADDRNOTAVAIL
== pSocket
->errno
) {
1267 DEBUG (( DEBUG_BIND
| DEBUG_POOL
| DEBUG_INIT
,
1268 "ERROR - Socket address is not available!\r\n" ));
1270 if ( EADDRINUSE
== pSocket
->errno
) {
1271 DEBUG (( DEBUG_BIND
| DEBUG_POOL
| DEBUG_INIT
,
1272 "ERROR - Socket address is in use!\r\n" ));
1274 Status
= EFI_INVALID_PARAMETER
;
1278 // Mark this socket as bound if successful
1280 if ( !EFI_ERROR ( Status
)) {
1281 pSocket
->State
= SOCKET_STATE_BOUND
;
1286 // Release the socket layer synchronization
1288 RESTORE_TPL ( TplPrevious
);
1293 // Return the operation status
1295 if ( NULL
!= pErrno
) {
1296 if ( NULL
!= pSocket
) {
1297 *pErrno
= pSocket
->errno
;
1300 Status
= EFI_INVALID_PARAMETER
;
1304 DBG_EXIT_STATUS ( Status
);
1310 Test the bind configuration.
1312 @param [in] pPort Address of the ::ESL_PORT structure.
1313 @param [in] ErrnoValue errno value if test fails
1315 @retval EFI_SUCCESS The connection was successfully established.
1316 @retval Others The connection attempt failed.
1321 IN ESL_PORT
* pPort
,
1332 // Locate the configuration data
1334 pBuffer
= (UINT8
*)pPort
;
1335 pBuffer
= &pBuffer
[ pPort
->pSocket
->pApi
->ConfigDataOffset
];
1336 pConfigData
= (VOID
*)pBuffer
;
1339 // Validate that the port is connected
1341 Status
= pPort
->pSocket
->pApi
->pfnVerifyLocalIpAddress ( pPort
, pBuffer
);
1342 if ( EFI_ERROR ( Status
)) {
1343 DEBUG (( DEBUG_WARN
| DEBUG_BIND
,
1344 "WARNING - Port 0x%08x invalid IP address: %r\r\n",
1347 pPort
->pSocket
->errno
= ErrnoValue
;
1351 // Attempt to use this configuration
1353 Status
= pPort
->pfnConfigure ( pPort
->pProtocol
.v
, pConfigData
);
1354 if ( EFI_ERROR ( Status
)) {
1355 DEBUG (( DEBUG_WARN
| DEBUG_BIND
,
1356 "WARNING - Port 0x%08x failed configuration, Status: %r\r\n",
1359 pPort
->pSocket
->errno
= ErrnoValue
;
1365 Status
= pPort
->pfnConfigure ( pPort
->pProtocol
.v
, NULL
);
1366 if ( EFI_ERROR ( Status
)) {
1367 DEBUG (( DEBUG_ERROR
| DEBUG_BIND
,
1368 "ERROR - Port 0x%08x failed configuration reset, Status: %r\r\n",
1371 ASSERT ( EFI_SUCCESS
== Status
);
1377 // Return the operation status
1379 DBG_EXIT_STATUS ( Status
);
1385 Determine if the socket is closed
1387 This routine checks the state of the socket to determine if
1388 the network specific layer has completed the close operation.
1390 The ::close routine polls this routine to determine when the
1391 close operation is complete. The close operation needs to
1392 reverse the operations of the ::EslSocketAllocate routine.
1394 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
1395 @param [out] pErrno Address to receive the errno value upon completion.
1397 @retval EFI_SUCCESS Socket successfully closed
1398 @retval EFI_NOT_READY Close still in progress
1399 @retval EFI_ALREADY Close operation already in progress
1400 @retval Other Failed to close the socket
1404 EslSocketClosePoll (
1405 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
1411 ESL_SOCKET
* pNextSocket
;
1412 ESL_SOCKET
* pSocket
;
1414 EFI_TPL TplPrevious
;
1422 Status
= EFI_SUCCESS
;
1425 // Synchronize with the socket layer
1427 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
1430 // Locate the socket
1432 pLayer
= &mEslLayer
;
1433 pNextSocket
= pLayer
->pSocketList
;
1434 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
1435 while ( NULL
!= pNextSocket
) {
1436 if ( pNextSocket
== pSocket
) {
1438 // Determine if the socket is in the closing state
1440 if ( SOCKET_STATE_CLOSED
== pSocket
->State
) {
1442 // Walk the list of ports
1444 if ( NULL
== pSocket
->pPortList
) {
1446 // All the ports are closed
1447 // Close the WaitAccept event if necessary
1449 if ( NULL
!= pSocket
->WaitAccept
) {
1450 Status
= gBS
->CloseEvent ( pSocket
->WaitAccept
);
1451 if ( !EFI_ERROR ( Status
)) {
1452 DEBUG (( DEBUG_SOCKET
| DEBUG_CLOSE
| DEBUG_POOL
,
1453 "0x%08x: Closed WaitAccept event\r\n",
1454 pSocket
->WaitAccept
));
1456 // Return the transmit status
1458 Status
= pSocket
->TxError
;
1459 if ( EFI_ERROR ( Status
)) {
1460 pSocket
->errno
= EIO
;
1464 DEBUG (( DEBUG_ERROR
| DEBUG_SOCKET
| DEBUG_CLOSE
| DEBUG_POOL
,
1465 "ERROR - Failed to close the WaitAccept event, Status: %r\r\n",
1467 ASSERT ( EFI_SUCCESS
== Status
);
1473 // At least one port is still open
1475 Status
= EFI_NOT_READY
;
1481 // SocketCloseStart was not called
1483 Status
= EFI_NOT_STARTED
;
1490 // Set the next socket
1492 pNextSocket
= pNextSocket
->pNext
;
1496 // Handle the error case where the socket was already closed
1498 if ( NULL
== pSocket
) {
1502 Status
= EFI_NOT_FOUND
;
1507 // Release the socket layer synchronization
1509 RESTORE_TPL ( TplPrevious
);
1512 // Return the operation status
1514 if ( NULL
!= pErrno
) {
1517 DBG_EXIT_STATUS ( Status
);
1523 Start the close operation on the socket
1525 This routine calls the network specific layer to initiate the
1526 close state machine. This routine then calls the network
1527 specific layer to determine if the close state machine has gone
1528 to completion. The result from this poll is returned to the
1531 The ::close routine calls this routine to start the close
1532 operation which reverses the operations of the
1533 ::EslSocketAllocate routine. The close routine then polls
1534 the ::EslSocketClosePoll routine to determine when the
1537 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
1538 @param [in] bCloseNow Boolean to control close behavior
1539 @param [out] pErrno Address to receive the errno value upon completion.
1541 @retval EFI_SUCCESS Socket successfully closed
1542 @retval EFI_NOT_READY Close still in progress
1543 @retval EFI_ALREADY Close operation already in progress
1544 @retval Other Failed to close the socket
1548 EslSocketCloseStart (
1549 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
1550 IN BOOLEAN bCloseNow
,
1555 ESL_PORT
* pNextPort
;
1557 ESL_SOCKET
* pSocket
;
1559 EFI_TPL TplPrevious
;
1566 Status
= EFI_SUCCESS
;
1570 // Synchronize with the socket layer
1572 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
1575 // Determine if the socket is already closed
1577 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
1578 if ( SOCKET_STATE_CLOSED
> pSocket
->State
) {
1580 // Update the socket state
1582 pSocket
->State
= SOCKET_STATE_CLOSED
;
1585 // Walk the list of ports
1587 pPort
= pSocket
->pPortList
;
1588 while ( NULL
!= pPort
) {
1590 // Start closing the ports
1592 pNextPort
= pPort
->pLinkSocket
;
1593 Status
= EslSocketPortCloseStart ( pPort
,
1595 DEBUG_CLOSE
| DEBUG_LISTEN
| DEBUG_CONNECTION
);
1596 if (( EFI_SUCCESS
!= Status
)
1597 && ( EFI_NOT_READY
!= Status
)) {
1603 // Set the next port
1609 // Attempt to finish closing the socket
1611 if ( NULL
== pPort
) {
1612 Status
= EslSocketClosePoll ( pSocketProtocol
, &errno
);
1616 Status
= EFI_NOT_READY
;
1621 // Release the socket layer synchronization
1623 RESTORE_TPL ( TplPrevious
);
1626 // Return the operation status
1628 if ( NULL
!= pErrno
) {
1631 DBG_EXIT_STATUS ( Status
);
1637 Connect to a remote system via the network.
1639 This routine calls the network specific layer to establish
1640 the remote system address and establish the connection to
1643 The ::connect routine calls this routine to establish a
1644 connection with the specified remote system. This routine
1645 is designed to be polled by the connect routine for completion
1646 of the network connection.
1648 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
1650 @param [in] pSockAddr Network address of the remote system.
1652 @param [in] SockAddrLength Length in bytes of the network address.
1654 @param [out] pErrno Address to receive the errno value upon completion.
1656 @retval EFI_SUCCESS The connection was successfully established.
1657 @retval EFI_NOT_READY The connection is in progress, call this routine again.
1658 @retval Others The connection attempt failed.
1663 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
1664 IN
const struct sockaddr
* pSockAddr
,
1665 IN socklen_t SockAddrLength
,
1669 struct sockaddr_in6 LocalAddress
;
1671 ESL_SOCKET
* pSocket
;
1673 EFI_TPL TplPrevious
;
1675 DEBUG (( DEBUG_CONNECT
, "Entering SocketConnect\r\n" ));
1680 Status
= EFI_SUCCESS
;
1683 // Validate the socket
1686 if ( NULL
!= pSocketProtocol
) {
1687 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
1690 // Validate the name length
1692 if ( SockAddrLength
< ( sizeof ( struct sockaddr
) - sizeof ( pSockAddr
->sa_data
))) {
1693 DEBUG (( DEBUG_CONNECT
,
1694 "ERROR - Invalid bind name length: %d\r\n",
1696 Status
= EFI_INVALID_PARAMETER
;
1697 pSocket
->errno
= EINVAL
;
1706 // Synchronize with the socket layer
1708 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
1711 // Validate the socket state
1713 switch ( pSocket
->State
) {
1716 // Wrong socket state
1718 pSocket
->errno
= EIO
;
1719 Status
= EFI_DEVICE_ERROR
;
1722 case SOCKET_STATE_NOT_CONFIGURED
:
1723 case SOCKET_STATE_BOUND
:
1725 // Validate the address length
1727 if ( SockAddrLength
>= pSocket
->pApi
->MinimumAddressLength
) {
1731 if ( NULL
== pSocket
->pApi
->pfnRemoteAddrSet
) {
1733 // Already connected
1735 pSocket
->errno
= ENOTSUP
;
1736 Status
= EFI_UNSUPPORTED
;
1740 // Determine if BIND was already called
1742 if ( NULL
== pSocket
->pPortList
) {
1744 // Allow any local port
1746 ZeroMem ( &LocalAddress
, sizeof ( LocalAddress
));
1747 LocalAddress
.sin6_len
= (uint8_t)pSocket
->pApi
->MinimumAddressLength
;
1748 LocalAddress
.sin6_family
= pSocket
->pApi
->AddressFamily
;
1749 Status
= EslSocketBind ( &pSocket
->SocketProtocol
,
1750 (struct sockaddr
*)&LocalAddress
,
1751 LocalAddress
.sin6_len
,
1754 if ( NULL
!= pSocket
->pPortList
) {
1756 // Walk the list of ports
1758 pPort
= pSocket
->pPortList
;
1759 while ( NULL
!= pPort
) {
1761 // Set the remote address
1763 Status
= pSocket
->pApi
->pfnRemoteAddrSet ( pPort
,
1766 if ( EFI_ERROR ( Status
)) {
1771 // Set the next port
1773 pPort
= pPort
->pLinkSocket
;
1779 if (( !EFI_ERROR ( Status
))
1780 && ( NULL
!= pSocket
->pApi
->pfnConnectStart
)) {
1782 // Initiate the connection with the remote system
1784 Status
= pSocket
->pApi
->pfnConnectStart ( pSocket
);
1787 // Set the next state if connecting
1789 if ( EFI_NOT_READY
== Status
) {
1790 pSocket
->State
= SOCKET_STATE_CONNECTING
;
1797 DEBUG (( DEBUG_CONNECT
,
1798 "ERROR - Invalid address length: %d\r\n",
1800 Status
= EFI_INVALID_PARAMETER
;
1801 pSocket
->errno
= EINVAL
;
1805 case SOCKET_STATE_CONNECTING
:
1807 // Poll the network adapter
1809 EslSocketRxPoll ( pSocket
);
1812 // Poll for connection completion
1814 if ( NULL
== pSocket
->pApi
->pfnConnectPoll
) {
1816 // Already connected
1818 pSocket
->errno
= EISCONN
;
1819 Status
= EFI_ALREADY_STARTED
;
1822 Status
= pSocket
->pApi
->pfnConnectPoll ( pSocket
);
1825 // Set the next state if connected
1827 if ( EFI_NOT_READY
!= Status
) {
1828 if ( EFI_ERROR ( Status
)) {
1829 pSocket
->State
= SOCKET_STATE_BOUND
;
1835 case SOCKET_STATE_CONNECTED
:
1837 // Already connected
1839 pSocket
->errno
= EISCONN
;
1840 Status
= EFI_ALREADY_STARTED
;
1845 // Release the socket layer synchronization
1847 RESTORE_TPL ( TplPrevious
);
1852 // Return the operation status
1854 if ( NULL
!= pErrno
) {
1855 if ( NULL
!= pSocket
) {
1856 *pErrno
= pSocket
->errno
;
1860 // Bad socket protocol
1862 DEBUG (( DEBUG_ERROR
| DEBUG_CONNECT
,
1863 "ERROR - pSocketProtocol invalid!\r\n" ));
1864 Status
= EFI_INVALID_PARAMETER
;
1870 // Return the operation status
1872 DEBUG (( DEBUG_CONNECT
, "Exiting SocketConnect, Status: %r\r\n", Status
));
1878 Copy a fragmented buffer into a destination buffer.
1880 This support routine copies a fragmented buffer to the caller specified buffer.
1882 This routine is called by ::EslIp4Receive and ::EslUdp4Receive.
1884 @param [in] FragmentCount Number of fragments in the table
1886 @param [in] pFragmentTable Address of an EFI_IP4_FRAGMENT_DATA structure
1888 @param [in] BufferLength Length of the the buffer
1890 @param [in] pBuffer Address of a buffer to receive the data.
1892 @param [in] pDataLength Number of received data bytes in the buffer.
1894 @return Returns the address of the next free byte in the buffer.
1898 EslSocketCopyFragmentedBuffer (
1899 IN UINT32 FragmentCount
,
1900 IN EFI_IP4_FRAGMENT_DATA
* pFragmentTable
,
1901 IN
size_t BufferLength
,
1903 OUT
size_t * pDataLength
1914 // Validate the IP and UDP structures are identical
1916 ASSERT ( OFFSET_OF ( EFI_IP4_FRAGMENT_DATA
, FragmentLength
)
1917 == OFFSET_OF ( EFI_UDP4_FRAGMENT_DATA
, FragmentLength
));
1918 ASSERT ( OFFSET_OF ( EFI_IP4_FRAGMENT_DATA
, FragmentBuffer
)
1919 == OFFSET_OF ( EFI_UDP4_FRAGMENT_DATA
, FragmentBuffer
));
1922 // Copy the received data
1925 pBufferEnd
= &pBuffer
[ BufferLength
];
1926 while (( pBufferEnd
> pBuffer
) && ( FragmentCount
> Fragment
)) {
1928 // Determine the amount of received data
1930 pData
= pFragmentTable
[Fragment
].FragmentBuffer
;
1931 BytesToCopy
= pFragmentTable
[Fragment
].FragmentLength
;
1932 if (((size_t)( pBufferEnd
- pBuffer
)) < BytesToCopy
) {
1933 BytesToCopy
= pBufferEnd
- pBuffer
;
1937 // Move the data into the buffer
1940 "0x%08x --> 0x%08x: Copy data 0x%08x bytes\r\n",
1944 CopyMem ( pBuffer
, pData
, BytesToCopy
);
1945 pBuffer
+= BytesToCopy
;
1950 // Return the data length and the buffer address
1952 *pDataLength
= BufferLength
- ( pBufferEnd
- pBuffer
);
1953 DBG_EXIT_HEX ( pBuffer
);
1961 This routine frees the socket structure and handle resources.
1963 The ::close routine calls EslServiceFreeProtocol which then calls
1964 this routine to free the socket context structure and close the
1967 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
1969 @param [out] pErrno Address to receive the errno value upon completion.
1971 @retval EFI_SUCCESS The socket resources were returned successfully.
1976 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
1980 EFI_HANDLE ChildHandle
;
1983 ESL_SOCKET
* pSocket
;
1984 ESL_SOCKET
* pSocketPrevious
;
1986 EFI_TPL TplPrevious
;
1995 Status
= EFI_INVALID_PARAMETER
;
1998 // Validate the socket
2000 pLayer
= &mEslLayer
;
2001 if ( NULL
!= pSocketProtocol
) {
2002 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
2005 // Synchronize with the socket layer
2007 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
2010 // Walk the socket list
2012 pSocketPrevious
= pLayer
->pSocketList
;
2013 if ( NULL
!= pSocketPrevious
) {
2014 if ( pSocket
== pSocketPrevious
) {
2016 // Remove the socket from the head of the list
2018 pLayer
->pSocketList
= pSocket
->pNext
;
2022 // Find the socket in the middle of the list
2024 while (( NULL
!= pSocketPrevious
)
2025 && ( pSocket
!= pSocketPrevious
->pNext
)) {
2027 // Set the next socket
2029 pSocketPrevious
= pSocketPrevious
->pNext
;
2031 if ( NULL
!= pSocketPrevious
) {
2033 // Remove the socket from the middle of the list
2035 pSocketPrevious
= pSocket
->pNext
;
2040 DEBUG (( DEBUG_ERROR
| DEBUG_POOL
,
2041 "ERROR - Socket list is empty!\r\n" ));
2045 // Release the socket layer synchronization
2047 RESTORE_TPL ( TplPrevious
);
2050 // Determine if the socket was found
2052 if ( NULL
!= pSocketPrevious
) {
2053 pSocket
->pNext
= NULL
;
2056 // Remove the socket protocol
2058 ChildHandle
= pSocket
->SocketProtocol
.SocketHandle
;
2059 Status
= gBS
->UninstallMultipleProtocolInterfaces (
2061 &gEfiSocketProtocolGuid
,
2062 &pSocket
->SocketProtocol
,
2064 if ( !EFI_ERROR ( Status
)) {
2065 DEBUG (( DEBUG_POOL
| DEBUG_INFO
,
2066 "Removed: gEfiSocketProtocolGuid from 0x%08x\r\n",
2070 // Free the socket structure
2072 Status
= gBS
->FreePool ( pSocket
);
2073 if ( !EFI_ERROR ( Status
)) {
2074 DEBUG (( DEBUG_POOL
,
2075 "0x%08x: Free pSocket, %d bytes\r\n",
2077 sizeof ( *pSocket
)));
2081 DEBUG (( DEBUG_ERROR
| DEBUG_POOL
,
2082 "ERROR - Failed to free pSocket 0x%08x, Status: %r\r\n",
2088 DEBUG (( DEBUG_ERROR
| DEBUG_POOL
| DEBUG_INFO
,
2089 "ERROR - Failed to remove gEfiSocketProtocolGuid from 0x%08x, Status: %r\r\n",
2095 DEBUG (( DEBUG_ERROR
| DEBUG_INFO
,
2096 "ERROR - The socket was not in the socket list!\r\n" ));
2097 Status
= EFI_NOT_FOUND
;
2101 DEBUG (( DEBUG_ERROR
,
2102 "ERROR - Invalid parameter pSocketProtocol is NULL\r\n" ));
2106 // Return the errno value if possible
2108 if ( NULL
!= pErrno
) {
2113 // Return the operation status
2115 DBG_EXIT_STATUS ( Status
);
2121 Get the local address.
2123 This routine calls the network specific layer to get the network
2124 address of the local host connection point.
2126 The ::getsockname routine calls this routine to obtain the network
2127 address associated with the local host connection point.
2129 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
2131 @param [out] pAddress Network address to receive the local system address
2133 @param [in,out] pAddressLength Length of the local network address structure
2135 @param [out] pErrno Address to receive the errno value upon completion.
2137 @retval EFI_SUCCESS - Local address successfully returned
2141 EslSocketGetLocalAddress (
2142 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
2143 OUT
struct sockaddr
* pAddress
,
2144 IN OUT socklen_t
* pAddressLength
,
2148 socklen_t LengthInBytes
;
2150 ESL_SOCKET
* pSocket
;
2152 EFI_TPL TplPrevious
;
2159 Status
= EFI_SUCCESS
;
2162 // Validate the socket
2165 if ( NULL
!= pSocketProtocol
) {
2166 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
2169 // Verify the socket state
2171 EslSocketIsConfigured ( pSocket
);
2172 if ( pSocket
->bAddressSet
) {
2174 // Verify the address buffer and length address
2176 if (( NULL
!= pAddress
) && ( NULL
!= pAddressLength
)) {
2180 if ( NULL
== pSocket
->pApi
->pfnLocalAddrGet
) {
2181 Status
= EFI_UNSUPPORTED
;
2182 pSocket
->errno
= ENOTSUP
;
2186 // Synchronize with the socket layer
2188 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
2191 // Verify that there is just a single connection
2193 pPort
= pSocket
->pPortList
;
2194 if ( NULL
!= pPort
) {
2196 // Verify the address length
2198 LengthInBytes
= pSocket
->pApi
->AddressLength
;
2199 if (( LengthInBytes
<= *pAddressLength
)
2200 && ( 255 >= LengthInBytes
)) {
2202 // Return the local address and address length
2204 ZeroMem ( pAddress
, LengthInBytes
);
2205 pAddress
->sa_len
= (uint8_t)LengthInBytes
;
2206 *pAddressLength
= pAddress
->sa_len
;
2207 pSocket
->pApi
->pfnLocalAddrGet ( pPort
, pAddress
);
2209 Status
= EFI_SUCCESS
;
2212 pSocket
->errno
= EINVAL
;
2213 Status
= EFI_INVALID_PARAMETER
;
2217 pSocket
->errno
= ENOTCONN
;
2218 Status
= EFI_NOT_STARTED
;
2222 // Release the socket layer synchronization
2224 RESTORE_TPL ( TplPrevious
);
2228 pSocket
->errno
= EINVAL
;
2229 Status
= EFI_INVALID_PARAMETER
;
2236 Status
= EFI_NOT_STARTED
;
2237 pSocket
->errno
= EADDRNOTAVAIL
;
2242 // Return the operation status
2244 if ( NULL
!= pErrno
) {
2245 if ( NULL
!= pSocket
) {
2246 *pErrno
= pSocket
->errno
;
2249 Status
= EFI_INVALID_PARAMETER
;
2253 DBG_EXIT_STATUS ( Status
);
2259 Get the peer address.
2261 This routine calls the network specific layer to get the remote
2262 system connection point.
2264 The ::getpeername routine calls this routine to obtain the network
2265 address of the remote connection point.
2267 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
2269 @param [out] pAddress Network address to receive the remote system address
2271 @param [in,out] pAddressLength Length of the remote network address structure
2273 @param [out] pErrno Address to receive the errno value upon completion.
2275 @retval EFI_SUCCESS - Remote address successfully returned
2279 EslSocketGetPeerAddress (
2280 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
2281 OUT
struct sockaddr
* pAddress
,
2282 IN OUT socklen_t
* pAddressLength
,
2286 socklen_t LengthInBytes
;
2288 ESL_SOCKET
* pSocket
;
2290 EFI_TPL TplPrevious
;
2297 Status
= EFI_SUCCESS
;
2300 // Validate the socket
2303 if ( NULL
!= pSocketProtocol
) {
2304 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
2307 // Verify the socket state
2309 Status
= EslSocketIsConfigured ( pSocket
);
2310 if ( !EFI_ERROR ( Status
)) {
2314 if ( NULL
== pSocket
->pApi
->pfnRemoteAddrGet
) {
2315 Status
= EFI_UNSUPPORTED
;
2316 pSocket
->errno
= ENOTSUP
;
2320 // Verify the address buffer and length address
2322 if (( NULL
!= pAddress
) && ( NULL
!= pAddressLength
)) {
2324 // Verify the socket state
2326 if ( SOCKET_STATE_CONNECTED
== pSocket
->State
) {
2328 // Synchronize with the socket layer
2330 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
2333 // Verify that there is just a single connection
2335 pPort
= pSocket
->pPortList
;
2336 if (( NULL
!= pPort
) && ( NULL
== pPort
->pLinkSocket
)) {
2338 // Verify the address length
2340 LengthInBytes
= pSocket
->pApi
->AddressLength
;
2341 if ( LengthInBytes
<= *pAddressLength
) {
2343 // Return the local address
2345 ZeroMem ( pAddress
, LengthInBytes
);
2346 pAddress
->sa_len
= (uint8_t)LengthInBytes
;
2347 *pAddressLength
= pAddress
->sa_len
;
2348 pSocket
->pApi
->pfnRemoteAddrGet ( pPort
, pAddress
);
2350 Status
= EFI_SUCCESS
;
2353 pSocket
->errno
= EINVAL
;
2354 Status
= EFI_INVALID_PARAMETER
;
2358 pSocket
->errno
= ENOTCONN
;
2359 Status
= EFI_NOT_STARTED
;
2363 // Release the socket layer synchronization
2365 RESTORE_TPL ( TplPrevious
);
2368 pSocket
->errno
= ENOTCONN
;
2369 Status
= EFI_NOT_STARTED
;
2373 pSocket
->errno
= EINVAL
;
2374 Status
= EFI_INVALID_PARAMETER
;
2381 // Return the operation status
2383 if ( NULL
!= pErrno
) {
2384 if ( NULL
!= pSocket
) {
2385 *pErrno
= pSocket
->errno
;
2388 Status
= EFI_INVALID_PARAMETER
;
2392 DBG_EXIT_STATUS ( Status
);
2398 Free the ESL_IO_MGMT event and structure
2400 This support routine walks the free list to close the event in
2401 the ESL_IO_MGMT structure and remove the structure from the free
2404 See the \ref TransmitEngine section.
2406 @param [in] pPort Address of an ::ESL_PORT structure
2407 @param [in] ppFreeQueue Address of the free queue head
2408 @param [in] DebugFlags Flags for debug messages
2409 @param [in] pEventName Zero terminated string containing the event name
2411 @retval EFI_SUCCESS - The structures were properly initialized
2416 IN ESL_PORT
* pPort
,
2417 IN ESL_IO_MGMT
** ppFreeQueue
,
2418 IN UINTN DebugFlags
,
2419 IN CHAR8
* pEventName
2425 ESL_SOCKET
* pSocket
;
2433 Status
= EFI_SUCCESS
;
2436 // Walk the list of IO structures
2438 pSocket
= pPort
->pSocket
;
2439 while ( *ppFreeQueue
) {
2441 // Free the event for this structure
2444 pBuffer
= (UINT8
*)pIo
;
2445 pBuffer
= &pBuffer
[ pSocket
->TxTokenEventOffset
];
2446 pEvent
= (EFI_EVENT
*)pBuffer
;
2447 Status
= gBS
->CloseEvent ( *pEvent
);
2448 if ( EFI_ERROR ( Status
)) {
2449 DEBUG (( DEBUG_ERROR
| DebugFlags
,
2450 "ERROR - Failed to close the %a event, Status: %r\r\n",
2453 pSocket
->errno
= ENOMEM
;
2456 DEBUG (( DebugFlags
,
2457 "0x%08x: Closed %a event 0x%08x\r\n",
2463 // Remove this structure from the queue
2465 *ppFreeQueue
= pIo
->pNext
;
2469 // Return the operation status
2471 DBG_EXIT_STATUS ( Status
);
2477 Initialize the ESL_IO_MGMT structures
2479 This support routine initializes the ESL_IO_MGMT structure and
2480 places them on to a free list.
2482 This routine is called by ::EslSocketPortAllocate routines to prepare
2483 the transmit engines. See the \ref TransmitEngine section.
2485 @param [in] pPort Address of an ::ESL_PORT structure
2486 @param [in, out] ppIo Address containing the first structure address. Upon
2487 return this buffer contains the next structure address.
2488 @param [in] TokenCount Number of structures to initialize
2489 @param [in] ppFreeQueue Address of the free queue head
2490 @param [in] DebugFlags Flags for debug messages
2491 @param [in] pEventName Zero terminated string containing the event name
2492 @param [in] pfnCompletion Completion routine address
2494 @retval EFI_SUCCESS - The structures were properly initialized
2499 IN ESL_PORT
* pPort
,
2500 IN ESL_IO_MGMT
** ppIo
,
2501 IN UINTN TokenCount
,
2502 IN ESL_IO_MGMT
** ppFreeQueue
,
2503 IN UINTN DebugFlags
,
2504 IN CHAR8
* pEventName
,
2505 IN PFN_API_IO_COMPLETE pfnCompletion
2511 ESL_SOCKET
* pSocket
;
2519 Status
= EFI_SUCCESS
;
2522 // Walk the list of IO structures
2524 pSocket
= pPort
->pSocket
;
2526 pEnd
= &pIo
[ TokenCount
];
2527 while ( pEnd
> pIo
) {
2529 // Initialize the IO structure
2532 pIo
->pPacket
= NULL
;
2535 // Allocate the event for this structure
2537 pEvent
= (EFI_EVENT
*)&(((UINT8
*)pIo
)[ pSocket
->TxTokenEventOffset
]);
2538 Status
= gBS
->CreateEvent ( EVT_NOTIFY_SIGNAL
,
2540 (EFI_EVENT_NOTIFY
)pfnCompletion
,
2543 if ( EFI_ERROR ( Status
)) {
2544 DEBUG (( DEBUG_ERROR
| DebugFlags
,
2545 "ERROR - Failed to create the %a event, Status: %r\r\n",
2548 pSocket
->errno
= ENOMEM
;
2551 DEBUG (( DebugFlags
,
2552 "0x%08x: Created %a event 0x%08x\r\n",
2558 // Add this structure to the queue
2560 pIo
->pNext
= *ppFreeQueue
;
2564 // Set the next structure
2570 // Save the next structure
2575 // Return the operation status
2577 DBG_EXIT_STATUS ( Status
);
2583 Determine if the socket is configured
2585 This support routine is called to determine if the socket if the
2586 configuration call was made to the network layer. The following
2587 routines call this routine to verify that they may be successful
2588 in their operations:
2590 <li>::EslSocketGetLocalAddress</li>
2591 <li>::EslSocketGetPeerAddress</li>
2592 <li>::EslSocketPoll</li>
2593 <li>::EslSocketReceive</li>
2594 <li>::EslSocketTransmit</li>
2597 @param [in] pSocket Address of an ::ESL_SOCKET structure
2599 @retval EFI_SUCCESS - The socket is configured
2603 EslSocketIsConfigured (
2604 IN ESL_SOCKET
* pSocket
2608 EFI_TPL TplPrevious
;
2613 Status
= EFI_SUCCESS
;
2616 // Verify the socket state
2618 if ( !pSocket
->bConfigured
) {
2624 if ( NULL
== pSocket
->pApi
->pfnIsConfigured
) {
2625 Status
= EFI_UNSUPPORTED
;
2626 pSocket
->errno
= ENOTSUP
;
2630 // Synchronize with the socket layer
2632 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
2635 // Determine if the socket is configured
2637 Status
= pSocket
->pApi
->pfnIsConfigured ( pSocket
);
2640 // Release the socket layer synchronization
2642 RESTORE_TPL ( TplPrevious
);
2645 // Set errno if a failure occurs
2647 if ( EFI_ERROR ( Status
)) {
2648 pSocket
->errno
= EADDRNOTAVAIL
;
2652 DBG_EXIT_STATUS ( Status
);
2656 // Return the configuration status
2663 Establish the known port to listen for network connections.
2665 This routine calls into the network protocol layer to establish
2666 a handler that is called upon connection completion. The handler
2667 is responsible for inserting the connection into the FIFO.
2669 The ::listen routine indirectly calls this routine to place the
2670 socket into a state that enables connection attempts. Connections
2671 are placed in a FIFO that is serviced by the application. The
2672 application calls the ::accept (::EslSocketAccept) routine to
2673 remove the next connection from the FIFO and get the associated
2676 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
2678 @param [in] Backlog Backlog specifies the maximum FIFO depth for
2679 the connections waiting for the application
2680 to call accept. Connection attempts received
2681 while the queue is full are refused.
2683 @param [out] pErrno Address to receive the errno value upon completion.
2685 @retval EFI_SUCCESS - Socket successfully created
2686 @retval Other - Failed to enable the socket for listen
2691 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
2696 ESL_SOCKET
* pSocket
;
2698 EFI_STATUS TempStatus
;
2699 EFI_TPL TplPrevious
;
2706 Status
= EFI_SUCCESS
;
2709 // Validate the socket
2712 if ( NULL
!= pSocketProtocol
) {
2713 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
2718 if ( NULL
== pSocket
->pApi
->pfnListen
) {
2719 Status
= EFI_UNSUPPORTED
;
2720 pSocket
->errno
= ENOTSUP
;
2726 pSocket
->Status
= EFI_SUCCESS
;
2730 // Verify that the bind operation was successful
2732 if ( SOCKET_STATE_BOUND
== pSocket
->State
) {
2734 // Synchronize with the socket layer
2736 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
2739 // Create the event for SocketAccept completion
2741 Status
= gBS
->CreateEvent ( 0,
2745 &pSocket
->WaitAccept
);
2746 if ( !EFI_ERROR ( Status
)) {
2747 DEBUG (( DEBUG_POOL
,
2748 "0x%08x: Created WaitAccept event\r\n",
2749 pSocket
->WaitAccept
));
2751 // Set the maximum FIFO depth
2753 if ( 0 >= Backlog
) {
2754 Backlog
= MAX_PENDING_CONNECTIONS
;
2757 if ( SOMAXCONN
< Backlog
) {
2758 Backlog
= SOMAXCONN
;
2761 pSocket
->MaxFifoDepth
= Backlog
;
2766 // Initiate the connection attempt listen
2768 Status
= pSocket
->pApi
->pfnListen ( pSocket
);
2771 // Place the socket in the listen state if successful
2773 if ( !EFI_ERROR ( Status
)) {
2774 pSocket
->State
= SOCKET_STATE_LISTENING
;
2775 pSocket
->bListenCalled
= TRUE
;
2779 // Not waiting for SocketAccept to complete
2781 TempStatus
= gBS
->CloseEvent ( pSocket
->WaitAccept
);
2782 if ( !EFI_ERROR ( TempStatus
)) {
2783 DEBUG (( DEBUG_POOL
,
2784 "0x%08x: Closed WaitAccept event\r\n",
2785 pSocket
->WaitAccept
));
2786 pSocket
->WaitAccept
= NULL
;
2789 DEBUG (( DEBUG_ERROR
| DEBUG_POOL
,
2790 "ERROR - Failed to close WaitAccept event, Status: %r\r\n",
2792 ASSERT ( EFI_SUCCESS
== TempStatus
);
2797 DEBUG (( DEBUG_ERROR
| DEBUG_LISTEN
,
2798 "ERROR - Failed to create the WaitAccept event, Status: %r\r\n",
2800 pSocket
->errno
= ENOMEM
;
2804 // Release the socket layer synchronization
2806 RESTORE_TPL ( TplPrevious
);
2809 DEBUG (( DEBUG_ERROR
| DEBUG_LISTEN
,
2810 "ERROR - Bind operation must be performed first!\r\n" ));
2811 pSocket
->errno
= ( SOCKET_STATE_NOT_CONFIGURED
== pSocket
->State
) ? EDESTADDRREQ
2813 Status
= EFI_NO_MAPPING
;
2819 // Return the operation status
2821 if ( NULL
!= pErrno
) {
2822 if ( NULL
!= pSocket
) {
2823 *pErrno
= pSocket
->errno
;
2826 Status
= EFI_INVALID_PARAMETER
;
2830 DBG_EXIT_STATUS ( Status
);
2836 Get the socket options
2838 This routine handles the socket level options and passes the
2839 others to the network specific layer.
2841 The ::getsockopt routine calls this routine to retrieve the
2842 socket options one at a time by name.
2844 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
2845 @param [in] level Option protocol level
2846 @param [in] OptionName Name of the option
2847 @param [out] pOptionValue Buffer to receive the option value
2848 @param [in,out] pOptionLength Length of the buffer in bytes,
2849 upon return length of the option value in bytes
2850 @param [out] pErrno Address to receive the errno value upon completion.
2852 @retval EFI_SUCCESS - Socket data successfully received
2856 EslSocketOptionGet (
2857 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
2860 OUT
void * __restrict pOptionValue
,
2861 IN OUT socklen_t
* __restrict pOptionLength
,
2866 socklen_t LengthInBytes
;
2868 CONST UINT8
* pOptionData
;
2869 ESL_SOCKET
* pSocket
;
2878 Status
= EFI_INVALID_PARAMETER
;
2881 // Validate the socket
2884 if ( NULL
== pSocketProtocol
) {
2885 DEBUG (( DEBUG_OPTION
, "ERROR - pSocketProtocol is NULL!\r\n" ));
2887 else if ( NULL
== pOptionValue
) {
2888 DEBUG (( DEBUG_OPTION
, "ERROR - No option buffer specified\r\n" ));
2890 else if ( NULL
== pOptionLength
) {
2891 DEBUG (( DEBUG_OPTION
, "ERROR - Option length not specified!\r\n" ));
2894 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
2896 MaxBytes
= *pOptionLength
;
2901 // See if the protocol will handle the option
2903 if ( NULL
!= pSocket
->pApi
->pfnOptionGet
) {
2904 if ( pSocket
->pApi
->DefaultProtocol
== level
) {
2905 Status
= pSocket
->pApi
->pfnOptionGet ( pSocket
,
2907 (CONST
void ** __restrict
)&pOptionData
,
2909 errno
= pSocket
->errno
;
2914 // Protocol not supported
2916 DEBUG (( DEBUG_OPTION
,
2917 "ERROR - The socket does not support this protocol!\r\n" ));
2922 // Protocol level not supported
2924 DEBUG (( DEBUG_OPTION
,
2925 "ERROR - %a does not support any options!\r\n",
2926 pSocket
->pApi
->pName
));
2928 errno
= ENOPROTOOPT
;
2929 Status
= EFI_INVALID_PARAMETER
;
2933 switch ( OptionName
) {
2936 // Socket option not supported
2938 DEBUG (( DEBUG_INFO
| DEBUG_OPTION
, "ERROR - Invalid socket option!\r\n" ));
2940 Status
= EFI_INVALID_PARAMETER
;
2945 // Return the listen flag
2947 pOptionData
= (CONST UINT8
*)&pSocket
->bListenCalled
;
2948 LengthInBytes
= sizeof ( pSocket
->bListenCalled
);
2953 // Return the debug flags
2955 pOptionData
= (CONST UINT8
*)&pSocket
->bOobInLine
;
2956 LengthInBytes
= sizeof ( pSocket
->bOobInLine
);
2961 // Return the out-of-band inline flag
2963 pOptionData
= (CONST UINT8
*)&pSocket
->bOobInLine
;
2964 LengthInBytes
= sizeof ( pSocket
->bOobInLine
);
2969 // Return the receive timeout
2971 pOptionData
= (CONST UINT8
*)&pSocket
->RxTimeout
;
2972 LengthInBytes
= sizeof ( pSocket
->RxTimeout
);
2977 // Return the maximum receive buffer size
2979 pOptionData
= (CONST UINT8
*)&pSocket
->MaxRxBuf
;
2980 LengthInBytes
= sizeof ( pSocket
->MaxRxBuf
);
2985 // Return the address reuse flag
2987 pOptionData
= (UINT8
*)&pSocket
->bReUseAddr
;
2988 LengthInBytes
= sizeof ( pSocket
->bReUseAddr
);
2993 // Return the maximum transmit buffer size
2995 pOptionData
= (CONST UINT8
*)&pSocket
->MaxTxBuf
;
2996 LengthInBytes
= sizeof ( pSocket
->MaxTxBuf
);
3001 // Return the socket type
3003 pOptionData
= (CONST UINT8
*)&pSocket
->Type
;
3004 LengthInBytes
= sizeof ( pSocket
->Type
);
3011 // Return the option length
3013 *pOptionLength
= LengthInBytes
;
3016 // Determine if the option is present
3018 if ( 0 != LengthInBytes
) {
3020 // Silently truncate the value length
3022 if ( LengthInBytes
> MaxBytes
) {
3023 DEBUG (( DEBUG_OPTION
,
3024 "INFO - Truncating option from %d to %d bytes\r\n",
3027 LengthInBytes
= MaxBytes
;
3033 CopyMem ( pOptionValue
, pOptionData
, LengthInBytes
);
3036 // Zero fill any remaining space
3038 if ( LengthInBytes
< MaxBytes
) {
3039 ZeroMem ( &((UINT8
*)pOptionValue
)[LengthInBytes
], MaxBytes
- LengthInBytes
);
3042 Status
= EFI_SUCCESS
;
3047 // Return the operation status
3049 if ( NULL
!= pErrno
) {
3052 DBG_EXIT_STATUS ( Status
);
3058 Set the socket options
3060 This routine handles the socket level options and passes the
3061 others to the network specific layer.
3063 The ::setsockopt routine calls this routine to adjust the socket
3064 options one at a time by name.
3066 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
3067 @param [in] level Option protocol level
3068 @param [in] OptionName Name of the option
3069 @param [in] pOptionValue Buffer containing the option value
3070 @param [in] OptionLength Length of the buffer in bytes
3071 @param [out] pErrno Address to receive the errno value upon completion.
3073 @retval EFI_SUCCESS - Option successfully set
3077 EslSocketOptionSet (
3078 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
3081 IN CONST
void * pOptionValue
,
3082 IN socklen_t OptionLength
,
3088 socklen_t LengthInBytes
;
3089 UINT8
* pOptionData
;
3090 ESL_SOCKET
* pSocket
;
3099 Status
= EFI_INVALID_PARAMETER
;
3102 // Validate the socket
3105 if ( NULL
== pSocketProtocol
) {
3106 DEBUG (( DEBUG_OPTION
, "ERROR - pSocketProtocol is NULL!\r\n" ));
3108 else if ( NULL
== pOptionValue
) {
3109 DEBUG (( DEBUG_OPTION
, "ERROR - No option buffer specified\r\n" ));
3113 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
3114 if ( pSocket
->bRxDisable
|| pSocket
->bTxDisable
) {
3115 DEBUG (( DEBUG_OPTION
, "ERROR - Socket has been shutdown!\r\n" ));
3123 // See if the protocol will handle the option
3125 if ( NULL
!= pSocket
->pApi
->pfnOptionSet
) {
3126 if ( pSocket
->pApi
->DefaultProtocol
== level
) {
3127 Status
= pSocket
->pApi
->pfnOptionSet ( pSocket
,
3131 errno
= pSocket
->errno
;
3136 // Protocol not supported
3138 DEBUG (( DEBUG_OPTION
,
3139 "ERROR - The socket does not support this protocol!\r\n" ));
3144 // Protocol level not supported
3146 DEBUG (( DEBUG_OPTION
,
3147 "ERROR - %a does not support any options!\r\n",
3148 pSocket
->pApi
->pName
));
3150 errno
= ENOPROTOOPT
;
3151 Status
= EFI_INVALID_PARAMETER
;
3155 switch ( OptionName
) {
3158 // Option not supported
3160 DEBUG (( DEBUG_OPTION
,
3161 "ERROR - Sockets does not support this option!\r\n" ));
3163 Status
= EFI_INVALID_PARAMETER
;
3168 // Set the debug flags
3170 pOptionData
= (UINT8
*)&pSocket
->bOobInLine
;
3171 LengthInBytes
= sizeof ( pSocket
->bOobInLine
);
3175 pOptionData
= (UINT8
*)&pSocket
->bOobInLine
;
3176 LengthInBytes
= sizeof ( pSocket
->bOobInLine
);
3179 // Validate the option length
3181 if ( sizeof ( UINT32
) == OptionLength
) {
3183 // Restrict the input to TRUE or FALSE
3186 if ( 0 == *(UINT32
*)pOptionValue
) {
3189 pOptionValue
= &bTrueFalse
;
3193 // Force an invalid option length error
3195 OptionLength
= LengthInBytes
- 1;
3201 // Return the receive timeout
3203 pOptionData
= (UINT8
*)&pSocket
->RxTimeout
;
3204 LengthInBytes
= sizeof ( pSocket
->RxTimeout
);
3209 // Return the maximum receive buffer size
3211 pOptionData
= (UINT8
*)&pSocket
->MaxRxBuf
;
3212 LengthInBytes
= sizeof ( pSocket
->MaxRxBuf
);
3217 // Return the address reuse flag
3219 pOptionData
= (UINT8
*)&pSocket
->bReUseAddr
;
3220 LengthInBytes
= sizeof ( pSocket
->bReUseAddr
);
3228 // Return the maximum transmit buffer size
3230 pOptionData
= (UINT8
*)&pSocket
->MaxTxBuf
;
3231 LengthInBytes
= sizeof ( pSocket
->MaxTxBuf
);
3238 // Determine if an option was found
3240 if ( 0 != LengthInBytes
) {
3242 // Validate the option length
3244 if ( LengthInBytes
<= OptionLength
) {
3246 // Set the option value
3248 CopyMem ( pOptionData
, pOptionValue
, LengthInBytes
);
3250 Status
= EFI_SUCCESS
;
3253 DEBUG (( DEBUG_OPTION
,
3254 "ERROR - Buffer to small, %d bytes < %d bytes!\r\n",
3263 // Return the operation status
3265 if ( NULL
!= pErrno
) {
3268 DBG_EXIT_STATUS ( Status
);
3274 Allocate a packet for a receive or transmit operation
3276 This support routine is called by ::EslSocketRxStart and the
3277 network specific TxBuffer routines to get buffer space for the
3280 @param [in] ppPacket Address to receive the ::ESL_PACKET structure
3281 @param [in] LengthInBytes Length of the packet structure
3282 @param [in] ZeroBytes Length of packet to zero
3283 @param [in] DebugFlags Flags for debug messages
3285 @retval EFI_SUCCESS - The packet was allocated successfully
3289 EslSocketPacketAllocate (
3290 IN ESL_PACKET
** ppPacket
,
3291 IN
size_t LengthInBytes
,
3292 IN
size_t ZeroBytes
,
3296 ESL_PACKET
* pPacket
;
3302 // Allocate a packet structure
3304 LengthInBytes
+= sizeof ( *pPacket
)
3305 - sizeof ( pPacket
->Op
);
3306 Status
= gBS
->AllocatePool ( EfiRuntimeServicesData
,
3308 (VOID
**)&pPacket
);
3309 if ( !EFI_ERROR ( Status
)) {
3310 DEBUG (( DebugFlags
| DEBUG_POOL
,
3311 "0x%08x: Allocate pPacket, %d bytes\r\n",
3314 if ( 0 != ZeroBytes
) {
3315 ZeroMem ( &pPacket
->Op
, ZeroBytes
);
3317 pPacket
->PacketSize
= LengthInBytes
;
3320 DEBUG (( DebugFlags
| DEBUG_POOL
| DEBUG_INFO
,
3321 "ERROR - Packet allocation failed for %d bytes, Status: %r\r\n",
3328 // Return the packet
3330 *ppPacket
= pPacket
;
3333 // Return the operation status
3335 DBG_EXIT_STATUS ( Status
);
3341 Free a packet used for receive or transmit operation
3343 This support routine is called by the network specific Close
3344 and TxComplete routines and during error cases in RxComplete
3345 and TxBuffer. Note that the network layers typically place
3346 receive packets on the ESL_SOCKET::pRxFree list for reuse.
3348 @param [in] pPacket Address of an ::ESL_PACKET structure
3349 @param [in] DebugFlags Flags for debug messages
3351 @retval EFI_SUCCESS - The packet was allocated successfully
3355 EslSocketPacketFree (
3356 IN ESL_PACKET
* pPacket
,
3360 UINTN LengthInBytes
;
3366 // Free a packet structure
3368 LengthInBytes
= pPacket
->PacketSize
;
3369 Status
= gBS
->FreePool ( pPacket
);
3370 if ( !EFI_ERROR ( Status
)) {
3371 DEBUG (( DebugFlags
| DEBUG_POOL
,
3372 "0x%08x: Free pPacket, %d bytes\r\n",
3377 DEBUG (( DebugFlags
| DEBUG_POOL
| DEBUG_INFO
,
3378 "ERROR - Failed to free packet 0x%08x, Status: %r\r\n",
3384 // Return the operation status
3386 DBG_EXIT_STATUS ( Status
);
3392 Poll a socket for pending activity.
3394 This routine builds a detected event mask which is returned to
3395 the caller in the buffer provided.
3397 The ::poll routine calls this routine to determine if the socket
3398 needs to be serviced as a result of connection, error, receive or
3401 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
3403 @param [in] Events Events of interest for this socket
3405 @param [in] pEvents Address to receive the detected events
3407 @param [out] pErrno Address to receive the errno value upon completion.
3409 @retval EFI_SUCCESS - Socket successfully polled
3410 @retval EFI_INVALID_PARAMETER - When pEvents is NULL
3415 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
3421 short DetectedEvents
;
3422 ESL_SOCKET
* pSocket
;
3424 EFI_TPL TplPrevious
;
3427 DEBUG (( DEBUG_POLL
, "Entering SocketPoll\r\n" ));
3432 Status
= EFI_SUCCESS
;
3434 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
3438 // Verify the socket state
3440 Status
= EslSocketIsConfigured ( pSocket
);
3441 if ( !EFI_ERROR ( Status
)) {
3443 // Check for invalid events
3445 ValidEvents
= POLLIN
3447 | POLLOUT
| POLLWRNORM
3454 if ( 0 != ( Events
& ( ~ValidEvents
))) {
3455 DetectedEvents
|= POLLNVAL
;
3456 DEBUG (( DEBUG_INFO
| DEBUG_POLL
,
3457 "ERROR - Invalid event mask, Valid Events: 0x%04x, Invalid Events: 0x%04x\r\n",
3458 Events
& ValidEvents
,
3459 Events
& ( ~ValidEvents
)));
3463 // Synchronize with the socket layer
3465 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
3468 // Increase the network performance by extending the
3469 // polling (idle) loop down into the LAN driver
3471 EslSocketRxPoll ( pSocket
);
3474 // Release the socket layer synchronization
3476 RESTORE_TPL ( TplPrevious
);
3479 // Check for pending connections
3481 if ( 0 != pSocket
->FifoDepth
) {
3483 // A connection is waiting for an accept call
3484 // See posix connect documentation at
3485 // http://pubs.opengroup.org/onlinepubs/9699919799/functions/accept.htm
3487 DetectedEvents
|= POLLIN
| POLLRDNORM
;
3489 if ( pSocket
->bConnected
) {
3491 // A connection is present
3492 // See posix connect documentation at
3493 // http://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.htm
3495 DetectedEvents
|= POLLOUT
| POLLWRNORM
;
3499 // The following bits are set based upon the POSIX poll documentation at
3500 // http://pubs.opengroup.org/onlinepubs/9699919799/functions/poll.html
3504 // Check for urgent receive data
3506 if ( 0 < pSocket
->RxOobBytes
) {
3507 DetectedEvents
|= POLLRDBAND
| POLLPRI
| POLLIN
;
3511 // Check for normal receive data
3513 if (( 0 < pSocket
->RxBytes
)
3514 || ( EFI_SUCCESS
!= pSocket
->RxError
)) {
3515 DetectedEvents
|= POLLRDNORM
| POLLIN
;
3519 // Handle the receive errors
3521 if (( EFI_SUCCESS
!= pSocket
->RxError
)
3522 && ( 0 == ( DetectedEvents
& POLLIN
))) {
3523 DetectedEvents
|= POLLERR
| POLLIN
| POLLRDNORM
| POLLRDBAND
;
3527 // Check for urgent transmit data buffer space
3529 if (( MAX_TX_DATA
> pSocket
->TxOobBytes
)
3530 || ( EFI_SUCCESS
!= pSocket
->TxError
)) {
3531 DetectedEvents
|= POLLWRBAND
;
3535 // Check for normal transmit data buffer space
3537 if (( MAX_TX_DATA
> pSocket
->TxBytes
)
3538 || ( EFI_SUCCESS
!= pSocket
->TxError
)) {
3539 DetectedEvents
|= POLLWRNORM
;
3543 // Handle the transmit error
3545 if ( EFI_ERROR ( pSocket
->TxError
)) {
3546 DetectedEvents
|= POLLERR
;
3552 // Return the detected events
3554 *pEvents
= DetectedEvents
& ( Events
3560 // Return the operation status
3562 DEBUG (( DEBUG_POLL
, "Exiting SocketPoll, Status: %r\r\n", Status
));
3568 Allocate and initialize a ESL_PORT structure.
3570 This routine initializes an ::ESL_PORT structure for use by
3571 the socket. This routine calls a routine via
3572 ESL_PROTOCOL_API::pfnPortAllocate to initialize the network
3573 specific resources. The resources are released later by the
3574 \ref PortCloseStateMachine.
3576 This support routine is called by:
3578 <li>::EslSocketBind</li>
3579 <li>::EslTcp4ListenComplete</li>
3581 to connect the socket with the underlying network adapter
3584 @param [in] pSocket Address of an ::ESL_SOCKET structure.
3585 @param [in] pService Address of an ::ESL_SERVICE structure.
3586 @param [in] ChildHandle Network protocol child handle
3587 @param [in] pSockAddr Address of a sockaddr structure that contains the
3588 connection point on the local machine. An IPv4 address
3589 of INADDR_ANY specifies that the connection is made to
3590 all of the network stacks on the platform. Specifying a
3591 specific IPv4 address restricts the connection to the
3592 network stack supporting that address. Specifying zero
3593 for the port causes the network layer to assign a port
3594 number from the dynamic range. Specifying a specific
3595 port number causes the network layer to use that port.
3596 @param [in] bBindTest TRUE if EslSocketBindTest should be called
3597 @param [in] DebugFlags Flags for debug messages
3598 @param [out] ppPort Buffer to receive new ::ESL_PORT structure address
3600 @retval EFI_SUCCESS - Socket successfully created
3604 EslSocketPortAllocate (
3605 IN ESL_SOCKET
* pSocket
,
3606 IN ESL_SERVICE
* pService
,
3607 IN EFI_HANDLE ChildHandle
,
3608 IN CONST
struct sockaddr
* pSockAddr
,
3609 IN BOOLEAN bBindTest
,
3610 IN UINTN DebugFlags
,
3611 OUT ESL_PORT
** ppPort
3614 UINTN LengthInBytes
;
3619 EFI_SERVICE_BINDING_PROTOCOL
* pServiceBinding
;
3620 CONST ESL_SOCKET_BINDING
* pSocketBinding
;
3622 EFI_STATUS TempStatus
;
3627 // Verify the socket layer synchronization
3629 VERIFY_TPL ( TPL_SOCKETS
);
3632 // Use for/break instead of goto
3633 pSocketBinding
= pService
->pSocketBinding
;
3636 // Allocate a port structure
3638 pLayer
= &mEslLayer
;
3639 LengthInBytes
= sizeof ( *pPort
)
3640 + ESL_STRUCTURE_ALIGNMENT_BYTES
3641 + (( pSocketBinding
->RxIo
3642 + pSocketBinding
->TxIoNormal
3643 + pSocketBinding
->TxIoUrgent
)
3644 * sizeof ( ESL_IO_MGMT
));
3645 pPort
= (ESL_PORT
*) AllocateZeroPool ( LengthInBytes
);
3646 if ( NULL
== pPort
) {
3647 Status
= EFI_OUT_OF_RESOURCES
;
3648 pSocket
->errno
= ENOMEM
;
3651 DEBUG (( DebugFlags
| DEBUG_POOL
| DEBUG_INIT
,
3652 "0x%08x: Allocate pPort, %d bytes\r\n",
3657 // Initialize the port
3659 pPort
->DebugFlags
= DebugFlags
;
3660 pPort
->Handle
= ChildHandle
;
3661 pPort
->pService
= pService
;
3662 pPort
->pServiceBinding
= pService
->pServiceBinding
;
3663 pPort
->pSocket
= pSocket
;
3664 pPort
->pSocketBinding
= pService
->pSocketBinding
;
3665 pPort
->Signature
= PORT_SIGNATURE
;
3668 // Open the port protocol
3670 Status
= gBS
->OpenProtocol ( pPort
->Handle
,
3671 pSocketBinding
->pNetworkProtocolGuid
,
3672 &pPort
->pProtocol
.v
,
3673 pLayer
->ImageHandle
,
3675 EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL
);
3676 if ( EFI_ERROR ( Status
)) {
3677 DEBUG (( DEBUG_ERROR
| DebugFlags
,
3678 "ERROR - Failed to open network protocol GUID on controller 0x%08x\r\n",
3680 pSocket
->errno
= EEXIST
;
3683 DEBUG (( DebugFlags
,
3684 "0x%08x: Network protocol GUID opened on controller 0x%08x\r\n",
3689 // Initialize the port specific resources
3691 Status
= pSocket
->pApi
->pfnPortAllocate ( pPort
,
3693 if ( EFI_ERROR ( Status
)) {
3698 // Set the local address
3700 Status
= pSocket
->pApi
->pfnLocalAddrSet ( pPort
, pSockAddr
, bBindTest
);
3701 if ( EFI_ERROR ( Status
)) {
3706 // Test the address/port configuration
3709 Status
= EslSocketBindTest ( pPort
, pSocket
->pApi
->BindTestErrno
);
3710 if ( EFI_ERROR ( Status
)) {
3716 // Initialize the receive structures
3718 pBuffer
= (UINT8
*)&pPort
[ 1 ];
3719 pBuffer
= &pBuffer
[ ESL_STRUCTURE_ALIGNMENT_BYTES
];
3720 pBuffer
= (UINT8
*)( ESL_STRUCTURE_ALIGNMENT_MASK
& (UINTN
)pBuffer
);
3721 pIo
= (ESL_IO_MGMT
*)pBuffer
;
3722 if (( 0 != pSocketBinding
->RxIo
)
3723 && ( NULL
!= pSocket
->pApi
->pfnRxComplete
)) {
3724 Status
= EslSocketIoInit ( pPort
,
3726 pSocketBinding
->RxIo
,
3728 DebugFlags
| DEBUG_POOL
,
3730 pSocket
->pApi
->pfnRxComplete
);
3731 if ( EFI_ERROR ( Status
)) {
3737 // Initialize the urgent transmit structures
3739 if (( 0 != pSocketBinding
->TxIoUrgent
)
3740 && ( NULL
!= pSocket
->pApi
->pfnTxOobComplete
)) {
3741 Status
= EslSocketIoInit ( pPort
,
3743 pSocketBinding
->TxIoUrgent
,
3745 DebugFlags
| DEBUG_POOL
,
3747 pSocket
->pApi
->pfnTxOobComplete
);
3748 if ( EFI_ERROR ( Status
)) {
3754 // Initialize the normal transmit structures
3756 if (( 0 != pSocketBinding
->TxIoNormal
)
3757 && ( NULL
!= pSocket
->pApi
->pfnTxComplete
)) {
3758 Status
= EslSocketIoInit ( pPort
,
3760 pSocketBinding
->TxIoNormal
,
3762 DebugFlags
| DEBUG_POOL
,
3764 pSocket
->pApi
->pfnTxComplete
);
3765 if ( EFI_ERROR ( Status
)) {
3771 // Add this port to the socket
3773 pPort
->pLinkSocket
= pSocket
->pPortList
;
3774 pSocket
->pPortList
= pPort
;
3775 DEBUG (( DebugFlags
,
3776 "0x%08x: Socket adding port: 0x%08x\r\n",
3781 // Add this port to the service
3783 pPort
->pLinkService
= pService
->pPortList
;
3784 pService
->pPortList
= pPort
;
3794 // Clean up after the error if necessary
3796 if ( EFI_ERROR ( Status
)) {
3797 if ( NULL
!= pPort
) {
3801 EslSocketPortClose ( pPort
);
3805 // Close the port if necessary
3807 pServiceBinding
= pService
->pServiceBinding
;
3808 TempStatus
= pServiceBinding
->DestroyChild ( pServiceBinding
,
3810 if ( !EFI_ERROR ( TempStatus
)) {
3811 DEBUG (( DEBUG_BIND
| DEBUG_POOL
,
3812 "0x%08x: %s port handle destroyed\r\n",
3814 pSocketBinding
->pName
));
3817 DEBUG (( DEBUG_ERROR
| DEBUG_BIND
| DEBUG_POOL
,
3818 "ERROR - Failed to destroy the %s port handle 0x%08x, Status: %r\r\n",
3819 pSocketBinding
->pName
,
3822 ASSERT ( EFI_SUCCESS
== TempStatus
);
3827 // Return the operation status
3829 DBG_EXIT_STATUS ( Status
);
3837 This routine releases the resources allocated by ::EslSocketPortAllocate.
3838 This routine calls ESL_PROTOCOL_API::pfnPortClose to release the network
3841 This routine is called by:
3843 <li>::EslSocketPortAllocate - Port initialization failure</li>
3844 <li>::EslSocketPortCloseRxDone - Last step of close processing</li>
3845 <li>::EslTcp4ConnectComplete - Connection failure and reducing the port list to a single port</li>
3847 See the \ref PortCloseStateMachine section.
3849 @param [in] pPort Address of an ::ESL_PORT structure.
3851 @retval EFI_SUCCESS The port is closed
3852 @retval other Port close error
3856 EslSocketPortClose (
3862 ESL_PACKET
* pPacket
;
3863 ESL_PORT
* pPreviousPort
;
3864 ESL_SERVICE
* pService
;
3865 EFI_SERVICE_BINDING_PROTOCOL
* pServiceBinding
;
3866 CONST ESL_SOCKET_BINDING
* pSocketBinding
;
3867 ESL_SOCKET
* pSocket
;
3873 // Verify the socket layer synchronization
3875 VERIFY_TPL ( TPL_SOCKETS
);
3878 // Locate the port in the socket list
3880 Status
= EFI_SUCCESS
;
3881 pLayer
= &mEslLayer
;
3882 DebugFlags
= pPort
->DebugFlags
;
3883 pSocket
= pPort
->pSocket
;
3884 pPreviousPort
= pSocket
->pPortList
;
3885 if ( pPreviousPort
== pPort
) {
3887 // Remove this port from the head of the socket list
3889 pSocket
->pPortList
= pPort
->pLinkSocket
;
3893 // Locate the port in the middle of the socket list
3895 while (( NULL
!= pPreviousPort
)
3896 && ( pPreviousPort
->pLinkSocket
!= pPort
)) {
3897 pPreviousPort
= pPreviousPort
->pLinkSocket
;
3899 if ( NULL
!= pPreviousPort
) {
3901 // Remove the port from the middle of the socket list
3903 pPreviousPort
->pLinkSocket
= pPort
->pLinkSocket
;
3908 // Locate the port in the service list
3909 // Note that the port may not be in the service list
3910 // if the service has been shutdown.
3912 pService
= pPort
->pService
;
3913 if ( NULL
!= pService
) {
3914 pPreviousPort
= pService
->pPortList
;
3915 if ( pPreviousPort
== pPort
) {
3917 // Remove this port from the head of the service list
3919 pService
->pPortList
= pPort
->pLinkService
;
3923 // Locate the port in the middle of the service list
3925 while (( NULL
!= pPreviousPort
)
3926 && ( pPreviousPort
->pLinkService
!= pPort
)) {
3927 pPreviousPort
= pPreviousPort
->pLinkService
;
3929 if ( NULL
!= pPreviousPort
) {
3931 // Remove the port from the middle of the service list
3933 pPreviousPort
->pLinkService
= pPort
->pLinkService
;
3939 // Empty the urgent receive queue
3941 while ( NULL
!= pSocket
->pRxOobPacketListHead
) {
3942 pPacket
= pSocket
->pRxOobPacketListHead
;
3943 pSocket
->pRxOobPacketListHead
= pPacket
->pNext
;
3944 pSocket
->pApi
->pfnPacketFree ( pPacket
, &pSocket
->RxOobBytes
);
3945 EslSocketPacketFree ( pPacket
, DEBUG_RX
);
3947 pSocket
->pRxOobPacketListTail
= NULL
;
3948 ASSERT ( 0 == pSocket
->RxOobBytes
);
3951 // Empty the receive queue
3953 while ( NULL
!= pSocket
->pRxPacketListHead
) {
3954 pPacket
= pSocket
->pRxPacketListHead
;
3955 pSocket
->pRxPacketListHead
= pPacket
->pNext
;
3956 pSocket
->pApi
->pfnPacketFree ( pPacket
, &pSocket
->RxBytes
);
3957 EslSocketPacketFree ( pPacket
, DEBUG_RX
);
3959 pSocket
->pRxPacketListTail
= NULL
;
3960 ASSERT ( 0 == pSocket
->RxBytes
);
3963 // Empty the receive free queue
3965 while ( NULL
!= pSocket
->pRxFree
) {
3966 pPacket
= pSocket
->pRxFree
;
3967 pSocket
->pRxFree
= pPacket
->pNext
;
3968 EslSocketPacketFree ( pPacket
, DEBUG_RX
);
3972 // Release the network specific resources
3974 if ( NULL
!= pSocket
->pApi
->pfnPortClose
) {
3975 Status
= pSocket
->pApi
->pfnPortClose ( pPort
);
3979 // Done with the normal transmit events
3981 Status
= EslSocketIoFree ( pPort
,
3983 DebugFlags
| DEBUG_POOL
,
3984 "normal transmit" );
3987 // Done with the urgent transmit events
3989 Status
= EslSocketIoFree ( pPort
,
3991 DebugFlags
| DEBUG_POOL
,
3992 "urgent transmit" );
3995 // Done with the receive events
3997 Status
= EslSocketIoFree ( pPort
,
3999 DebugFlags
| DEBUG_POOL
,
4003 // Done with the lower layer network protocol
4005 pSocketBinding
= pPort
->pSocketBinding
;
4006 if ( NULL
!= pPort
->pProtocol
.v
) {
4007 Status
= gBS
->CloseProtocol ( pPort
->Handle
,
4008 pSocketBinding
->pNetworkProtocolGuid
,
4009 pLayer
->ImageHandle
,
4011 if ( !EFI_ERROR ( Status
)) {
4012 DEBUG (( DebugFlags
,
4013 "0x%08x: Network protocol GUID closed on controller 0x%08x\r\n",
4018 DEBUG (( DEBUG_ERROR
| DebugFlags
,
4019 "ERROR - Failed to close network protocol GUID on controller 0x%08x, Status: %r\r\n",
4022 ASSERT ( EFI_SUCCESS
== Status
);
4027 // Done with the network port
4029 pServiceBinding
= pPort
->pServiceBinding
;
4030 if ( NULL
!= pPort
->Handle
) {
4031 Status
= pServiceBinding
->DestroyChild ( pServiceBinding
,
4033 if ( !EFI_ERROR ( Status
)) {
4034 DEBUG (( DebugFlags
| DEBUG_POOL
,
4035 "0x%08x: %s port handle destroyed\r\n",
4037 pSocketBinding
->pName
));
4040 DEBUG (( DEBUG_ERROR
| DebugFlags
| DEBUG_POOL
,
4041 "ERROR - Failed to destroy the %s port handle, Status: %r\r\n",
4042 pSocketBinding
->pName
,
4044 ASSERT ( EFI_SUCCESS
== Status
);
4049 // Release the port structure
4051 Status
= gBS
->FreePool ( pPort
);
4052 if ( !EFI_ERROR ( Status
)) {
4053 DEBUG (( DebugFlags
| DEBUG_POOL
,
4054 "0x%08x: Free pPort, %d bytes\r\n",
4056 sizeof ( *pPort
)));
4059 DEBUG (( DEBUG_ERROR
| DebugFlags
| DEBUG_POOL
,
4060 "ERROR - Failed to free pPort: 0x%08x, Status: %r\r\n",
4063 ASSERT ( EFI_SUCCESS
== Status
);
4067 // Mark the socket as closed if necessary
4069 if ( NULL
== pSocket
->pPortList
) {
4070 pSocket
->State
= SOCKET_STATE_CLOSED
;
4071 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4072 "0x%08x: Socket State: SOCKET_STATE_CLOSED\r\n",
4077 // Return the operation status
4079 DBG_EXIT_STATUS ( Status
);
4087 This routine attempts to complete the port close operation.
4089 This routine is called by the TCP layer upon completion of
4090 the close operation and by ::EslSocketPortCloseTxDone.
4091 See the \ref PortCloseStateMachine section.
4093 @param [in] Event The close completion event
4095 @param [in] pPort Address of an ::ESL_PORT structure.
4099 EslSocketPortCloseComplete (
4108 VERIFY_AT_TPL ( TPL_SOCKETS
);
4111 // Update the port state
4113 pPort
->State
= PORT_STATE_CLOSE_DONE
;
4114 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4115 "0x%08x: Port Close State: PORT_STATE_CLOSE_DONE\r\n",
4119 // Shutdown the receive operation on the port
4121 if ( NULL
!= pPort
->pfnRxCancel
) {
4122 pIo
= pPort
->pRxActive
;
4123 while ( NULL
!= pIo
) {
4124 EslSocketRxCancel ( pPort
, pIo
);
4130 // Determine if the receive operation is pending
4132 Status
= EslSocketPortCloseRxDone ( pPort
);
4133 DBG_EXIT_STATUS ( Status
);
4140 This routine determines the state of the receive operations and
4141 continues the close operation after the pending receive operations
4144 This routine is called by
4146 <li>::EslSocketPortCloseComplete</li>
4147 <li>::EslSocketPortCloseTxDone</li>
4148 <li>::EslSocketRxComplete</li>
4150 to determine the state of the receive operations.
4151 See the \ref PortCloseStateMachine section.
4153 @param [in] pPort Address of an ::ESL_PORT structure.
4155 @retval EFI_SUCCESS The port is closed
4156 @retval EFI_NOT_READY The port is still closing
4157 @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
4158 most likely the routine was called already.
4162 EslSocketPortCloseRxDone (
4171 // Verify the socket layer synchronization
4173 VERIFY_TPL ( TPL_SOCKETS
);
4176 // Verify that the port is closing
4178 Status
= EFI_ALREADY_STARTED
;
4179 if ( PORT_STATE_CLOSE_DONE
== pPort
->State
) {
4181 // Determine if the receive operation is pending
4183 Status
= EFI_NOT_READY
;
4184 if ( NULL
== pPort
->pRxActive
) {
4186 // The receive operation is complete
4187 // Update the port state
4189 pPort
->State
= PORT_STATE_CLOSE_RX_DONE
;
4190 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4191 "0x%08x: Port Close State: PORT_STATE_CLOSE_RX_DONE\r\n",
4195 // Complete the port close operation
4197 Status
= EslSocketPortClose ( pPort
);
4200 DEBUG_CODE_BEGIN ();
4204 // Display the outstanding receive operations
4206 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4207 "0x%08x: Port Close: Receive still pending!\r\n",
4209 pIo
= pPort
->pRxActive
;
4210 while ( NULL
!= pIo
) {
4211 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4212 "0x%08x: Packet pending on network adapter\r\n",
4222 // Return the operation status
4224 DBG_EXIT_STATUS ( Status
);
4230 Start the close operation on a port, state 1.
4232 This routine marks the port as closed and initiates the \ref
4233 PortCloseStateMachine. The first step is to allow the \ref
4234 TransmitEngine to run down.
4236 This routine is called by ::EslSocketCloseStart to initiate the socket
4237 network specific close operation on the socket.
4239 @param [in] pPort Address of an ::ESL_PORT structure.
4240 @param [in] bCloseNow Set TRUE to abort active transfers
4241 @param [in] DebugFlags Flags for debug messages
4243 @retval EFI_SUCCESS The port is closed, not normally returned
4244 @retval EFI_NOT_READY The port has started the closing process
4245 @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
4246 most likely the routine was called already.
4250 EslSocketPortCloseStart (
4251 IN ESL_PORT
* pPort
,
4252 IN BOOLEAN bCloseNow
,
4256 ESL_SOCKET
* pSocket
;
4262 // Verify the socket layer synchronization
4264 VERIFY_TPL ( TPL_SOCKETS
);
4267 // Mark the port as closing
4269 Status
= EFI_ALREADY_STARTED
;
4270 pSocket
= pPort
->pSocket
;
4271 pSocket
->errno
= EALREADY
;
4272 if ( PORT_STATE_CLOSE_STARTED
> pPort
->State
) {
4275 // Update the port state
4277 pPort
->State
= PORT_STATE_CLOSE_STARTED
;
4278 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4279 "0x%08x: Port Close State: PORT_STATE_CLOSE_STARTED\r\n",
4281 pPort
->bCloseNow
= bCloseNow
;
4282 pPort
->DebugFlags
= DebugFlags
;
4285 // Determine if transmits are complete
4287 Status
= EslSocketPortCloseTxDone ( pPort
);
4291 // Return the operation status
4293 DBG_EXIT_STATUS ( Status
);
4301 This routine determines the state of the transmit engine and
4302 continue the close operation after the transmission is complete.
4303 The next step is to stop the \ref ReceiveEngine.
4304 See the \ref PortCloseStateMachine section.
4306 This routine is called by ::EslSocketPortCloseStart to determine
4307 if the transmission is complete.
4309 @param [in] pPort Address of an ::ESL_PORT structure.
4311 @retval EFI_SUCCESS The port is closed, not normally returned
4312 @retval EFI_NOT_READY The port is still closing
4313 @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
4314 most likely the routine was called already.
4318 EslSocketPortCloseTxDone (
4323 ESL_SOCKET
* pSocket
;
4329 // Verify the socket layer synchronization
4331 VERIFY_TPL ( TPL_SOCKETS
);
4334 // All transmissions are complete or must be stopped
4335 // Mark the port as TX complete
4337 Status
= EFI_ALREADY_STARTED
;
4338 if ( PORT_STATE_CLOSE_STARTED
== pPort
->State
) {
4340 // Verify that the transmissions are complete
4342 pSocket
= pPort
->pSocket
;
4343 if ( pPort
->bCloseNow
4344 || ( EFI_SUCCESS
!= pSocket
->TxError
)
4345 || (( NULL
== pPort
->pTxActive
)
4346 && ( NULL
== pPort
->pTxOobActive
))) {
4348 // Update the port state
4350 pPort
->State
= PORT_STATE_CLOSE_TX_DONE
;
4351 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4352 "0x%08x: Port Close State: PORT_STATE_CLOSE_TX_DONE\r\n",
4357 // Skip the close operation if the port is not configured
4359 Status
= EFI_SUCCESS
;
4360 pSocket
= pPort
->pSocket
;
4361 if (( pPort
->bConfigured
)
4362 && ( NULL
!= pSocket
->pApi
->pfnPortCloseOp
)) {
4364 // Start the close operation
4366 Status
= pSocket
->pApi
->pfnPortCloseOp ( pPort
);
4367 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4368 "0x%08x: Port Close: Close operation still pending!\r\n",
4370 ASSERT ( EFI_SUCCESS
== Status
);
4374 // The receive operation is complete
4375 // Update the port state
4377 EslSocketPortCloseComplete ( NULL
, pPort
);
4382 // Transmissions are still active, exit
4384 Status
= EFI_NOT_READY
;
4385 pSocket
->errno
= EAGAIN
;
4386 DEBUG_CODE_BEGIN ( );
4388 ESL_PACKET
* pPacket
;
4390 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4391 "0x%08x: Port Close: Transmits are still pending!\r\n",
4395 // Display the pending urgent transmit packets
4397 pPacket
= pSocket
->pTxOobPacketListHead
;
4398 while ( NULL
!= pPacket
) {
4399 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4400 "0x%08x: Packet pending on urgent TX list, %d bytes\r\n",
4402 pPacket
->PacketSize
));
4403 pPacket
= pPacket
->pNext
;
4406 pIo
= pPort
->pTxOobActive
;
4407 while ( NULL
!= pIo
) {
4408 pPacket
= pIo
->pPacket
;
4409 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4410 "0x%08x: Packet active %d bytes, pIo: 0x%08x\r\n",
4412 pPacket
->PacketSize
,
4418 // Display the pending normal transmit packets
4420 pPacket
= pSocket
->pTxPacketListHead
;
4421 while ( NULL
!= pPacket
) {
4422 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4423 "0x%08x: Packet pending on normal TX list, %d bytes\r\n",
4425 pPacket
->PacketSize
));
4426 pPacket
= pPacket
->pNext
;
4429 pIo
= pPort
->pTxActive
;
4430 while ( NULL
!= pIo
) {
4431 pPacket
= pIo
->pPacket
;
4432 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4433 "0x%08x: Packet active %d bytes, pIo: 0x%08x\r\n",
4435 pPacket
->PacketSize
,
4445 // Return the operation status
4447 DBG_EXIT_STATUS ( Status
);
4453 Receive data from a network connection.
4455 This routine calls the network specific routine to remove the
4456 next portion of data from the receive queue and return it to the
4459 The ::recvfrom routine calls this routine to determine if any data
4460 is received from the remote system. Note that the other routines
4461 ::recv and ::read are layered on top of ::recvfrom.
4463 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
4465 @param [in] Flags Message control flags
4467 @param [in] BufferLength Length of the the buffer
4469 @param [in] pBuffer Address of a buffer to receive the data.
4471 @param [in] pDataLength Number of received data bytes in the buffer.
4473 @param [out] pAddress Network address to receive the remote system address
4475 @param [in,out] pAddressLength Length of the remote network address structure
4477 @param [out] pErrno Address to receive the errno value upon completion.
4479 @retval EFI_SUCCESS - Socket data successfully received
4484 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
4486 IN
size_t BufferLength
,
4488 OUT
size_t * pDataLength
,
4489 OUT
struct sockaddr
* pAddress
,
4490 IN OUT socklen_t
* pAddressLength
,
4495 struct sockaddr_in v4
;
4496 struct sockaddr_in6 v6
;
4498 socklen_t AddressLength
;
4499 BOOLEAN bConsumePacket
;
4500 BOOLEAN bUrgentQueue
;
4502 ESL_PACKET
* pNextPacket
;
4503 ESL_PACKET
* pPacket
;
4505 ESL_PACKET
** ppQueueHead
;
4506 ESL_PACKET
** ppQueueTail
;
4507 struct sockaddr
* pRemoteAddress
;
4508 size_t * pRxDataBytes
;
4509 ESL_SOCKET
* pSocket
;
4512 EFI_TPL TplPrevious
;
4519 Status
= EFI_SUCCESS
;
4522 // Validate the socket
4525 if ( NULL
!= pSocketProtocol
) {
4526 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
4529 // Validate the return address parameters
4531 if (( NULL
== pAddress
) || ( NULL
!= pAddressLength
)) {
4533 // Return the transmit error if necessary
4535 if ( EFI_SUCCESS
!= pSocket
->TxError
) {
4536 pSocket
->errno
= EIO
;
4537 Status
= pSocket
->TxError
;
4538 pSocket
->TxError
= EFI_SUCCESS
;
4542 // Verify the socket state
4544 Status
= EslSocketIsConfigured ( pSocket
);
4545 if ( !EFI_ERROR ( Status
)) {
4547 // Validate the buffer length
4549 if (( NULL
== pDataLength
)
4550 || ( NULL
== pBuffer
)) {
4551 if ( NULL
== pDataLength
) {
4553 "ERROR - pDataLength is NULL!\r\n" ));
4557 "ERROR - pBuffer is NULL!\r\n" ));
4559 Status
= EFI_INVALID_PARAMETER
;
4560 pSocket
->errno
= EFAULT
;
4566 if ( NULL
== pSocket
->pApi
->pfnReceive
) {
4567 Status
= EFI_UNSUPPORTED
;
4568 pSocket
->errno
= ENOTSUP
;
4572 // Zero the receive address if being returned
4574 pRemoteAddress
= NULL
;
4575 if ( NULL
!= pAddress
) {
4576 pRemoteAddress
= (struct sockaddr
*)&Addr
;
4577 ZeroMem ( pRemoteAddress
, sizeof ( Addr
));
4578 pRemoteAddress
->sa_family
= pSocket
->pApi
->AddressFamily
;
4579 pRemoteAddress
->sa_len
= (UINT8
)pSocket
->pApi
->AddressLength
;
4583 // Synchronize with the socket layer
4585 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
4590 Status
= EFI_UNSUPPORTED
;
4591 pSocket
->errno
= ENOTCONN
;
4594 // Verify that the socket is connected
4596 if ( SOCKET_STATE_CONNECTED
== pSocket
->State
) {
4598 // Poll the network to increase performance
4600 EslSocketRxPoll ( pSocket
);
4605 pPort
= pSocket
->pPortList
;
4606 if ( NULL
!= pPort
) {
4608 // Determine the queue head
4610 bUrgentQueue
= (BOOLEAN
)( 0 != ( Flags
& MSG_OOB
));
4611 if ( bUrgentQueue
) {
4612 ppQueueHead
= &pSocket
->pRxOobPacketListHead
;
4613 ppQueueTail
= &pSocket
->pRxOobPacketListTail
;
4614 pRxDataBytes
= &pSocket
->RxOobBytes
;
4617 ppQueueHead
= &pSocket
->pRxPacketListHead
;
4618 ppQueueTail
= &pSocket
->pRxPacketListTail
;
4619 pRxDataBytes
= &pSocket
->RxBytes
;
4623 // Determine if there is any data on the queue
4626 pPacket
= *ppQueueHead
;
4627 if ( NULL
!= pPacket
) {
4629 // Copy the received data
4633 // Attempt to receive a packet
4636 bConsumePacket
= (BOOLEAN
)( 0 == ( Flags
& MSG_PEEK
));
4637 pBuffer
= pSocket
->pApi
->pfnReceive ( pPort
,
4643 (struct sockaddr
*)&Addr
,
4645 *pDataLength
+= DataLength
;
4646 BufferLength
-= DataLength
;
4649 // Determine if the data is being read
4651 pNextPacket
= pPacket
->pNext
;
4652 if ( bConsumePacket
) {
4654 // All done with this packet
4655 // Account for any discarded data
4657 pSocket
->pApi
->pfnPacketFree ( pPacket
, pRxDataBytes
);
4658 if ( 0 != SkipBytes
) {
4660 "0x%08x: Port, packet read, skipping over 0x%08x bytes\r\n",
4666 // Remove this packet from the queue
4668 *ppQueueHead
= pPacket
->pNext
;
4669 if ( NULL
== *ppQueueHead
) {
4670 *ppQueueTail
= NULL
;
4674 // Move the packet to the free queue
4676 pPacket
->pNext
= pSocket
->pRxFree
;
4677 pSocket
->pRxFree
= pPacket
;
4679 "0x%08x: Port freeing packet 0x%08x\r\n",
4684 // Restart the receive operation if necessary
4686 if (( NULL
!= pPort
->pRxFree
)
4687 && ( MAX_RX_DATA
> pSocket
->RxBytes
)) {
4688 EslSocketRxStart ( pPort
);
4693 // Get the next packet
4695 pPacket
= pNextPacket
;
4696 } while (( SOCK_STREAM
== pSocket
->Type
)
4697 && ( NULL
!= pPacket
)
4698 && ( 0 < BufferLength
));
4701 // Successful operation
4703 Status
= EFI_SUCCESS
;
4708 // The queue is empty
4709 // Determine if it is time to return the receive error
4711 if ( EFI_ERROR ( pSocket
->RxError
)
4712 && ( NULL
== pSocket
->pRxPacketListHead
)
4713 && ( NULL
== pSocket
->pRxOobPacketListHead
)) {
4714 Status
= pSocket
->RxError
;
4715 pSocket
->RxError
= EFI_SUCCESS
;
4718 pSocket
->errno
= EIO
;
4721 case EFI_CONNECTION_FIN
:
4723 // Continue to return zero bytes received when the
4724 // peer has successfully closed the connection
4726 pSocket
->RxError
= EFI_CONNECTION_FIN
;
4729 Status
= EFI_SUCCESS
;
4732 case EFI_CONNECTION_REFUSED
:
4733 pSocket
->errno
= ECONNREFUSED
;
4736 case EFI_CONNECTION_RESET
:
4737 pSocket
->errno
= ECONNRESET
;
4740 case EFI_HOST_UNREACHABLE
:
4741 pSocket
->errno
= EHOSTUNREACH
;
4744 case EFI_NETWORK_UNREACHABLE
:
4745 pSocket
->errno
= ENETUNREACH
;
4748 case EFI_PORT_UNREACHABLE
:
4749 pSocket
->errno
= EPROTONOSUPPORT
;
4752 case EFI_PROTOCOL_UNREACHABLE
:
4753 pSocket
->errno
= ENOPROTOOPT
;
4758 Status
= EFI_NOT_READY
;
4759 pSocket
->errno
= EAGAIN
;
4766 // Release the socket layer synchronization
4768 RESTORE_TPL ( TplPrevious
);
4770 if (( !EFI_ERROR ( Status
)) && ( NULL
!= pAddress
)) {
4772 // Return the remote address if requested, truncate if necessary
4774 AddressLength
= pRemoteAddress
->sa_len
;
4775 if ( AddressLength
> *pAddressLength
) {
4776 AddressLength
= *pAddressLength
;
4779 "Returning the remote address, 0x%016x bytes --> 0x%16x\r\n", *pAddressLength
, pAddress
));
4780 ZeroMem ( pAddress
, *pAddressLength
);
4781 CopyMem ( pAddress
, &Addr
, AddressLength
);
4784 // Update the address length
4786 *pAddressLength
= pRemoteAddress
->sa_len
;
4797 // Bad return address pointer and length
4799 Status
= EFI_INVALID_PARAMETER
;
4800 pSocket
->errno
= EINVAL
;
4805 // Return the operation status
4807 if ( NULL
!= pErrno
) {
4808 if ( NULL
!= pSocket
) {
4809 *pErrno
= pSocket
->errno
;
4812 Status
= EFI_INVALID_PARAMETER
;
4816 DBG_EXIT_STATUS ( Status
);
4822 Cancel the receive operations
4824 This routine cancels a pending receive operation.
4825 See the \ref ReceiveEngine section.
4827 This routine is called by ::EslSocketShutdown when the socket
4828 layer is being shutdown.
4830 @param [in] pPort Address of an ::ESL_PORT structure
4831 @param [in] pIo Address of an ::ESL_IO_MGMT structure
4836 IN ESL_PORT
* pPort
,
4837 IN ESL_IO_MGMT
* pIo
4845 // Cancel the outstanding receive
4847 Status
= pPort
->pfnRxCancel ( pPort
->pProtocol
.v
,
4849 if ( !EFI_ERROR ( Status
)) {
4850 DEBUG (( pPort
->DebugFlags
| DEBUG_CLOSE
| DEBUG_INFO
,
4851 "0x%08x: Packet receive aborted on port: 0x%08x\r\n",
4856 DEBUG (( pPort
->DebugFlags
| DEBUG_CLOSE
| DEBUG_INFO
,
4857 "0x%08x: Packet receive pending on Port 0x%08x, Status: %r\r\n",
4867 Process the receive completion
4869 This routine queues the data in FIFO order in either the urgent
4870 or normal data queues depending upon the type of data received.
4871 See the \ref ReceiveEngine section.
4873 This routine is called when some data is received by:
4875 <li>::EslIp4RxComplete</li>
4876 <li>::EslTcp4RxComplete</li>
4877 <li>::EslUdp4RxComplete</li>
4880 @param [in] pIo Address of an ::ESL_IO_MGMT structure
4881 @param [in] Status Receive status
4882 @param [in] LengthInBytes Length of the receive data
4883 @param [in] bUrgent TRUE if urgent data is received and FALSE
4888 EslSocketRxComplete (
4889 IN ESL_IO_MGMT
* pIo
,
4890 IN EFI_STATUS Status
,
4891 IN UINTN LengthInBytes
,
4895 BOOLEAN bUrgentQueue
;
4896 ESL_IO_MGMT
* pIoNext
;
4897 ESL_PACKET
* pPacket
;
4899 ESL_PACKET
* pPrevious
;
4900 ESL_PACKET
** ppQueueHead
;
4901 ESL_PACKET
** ppQueueTail
;
4903 ESL_SOCKET
* pSocket
;
4906 VERIFY_AT_TPL ( TPL_SOCKETS
);
4909 // Locate the active receive packet
4911 pPacket
= pIo
->pPacket
;
4913 pSocket
= pPort
->pSocket
;
4919 // +-------------+ +-------------+ +-------------+
4920 // Active | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
4921 // +-------------+ +-------------+ +-------------+
4923 // +-------------+ +-------------+ +-------------+
4924 // Free | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
4925 // +-------------+ +-------------+ +-------------+
4931 // Remove the IO structure from the active list
4932 // The following code searches for the entry in the list and does not
4933 // assume that the receive operations complete in the order they were
4934 // issued to the UEFI network layer.
4936 pIoNext
= pPort
->pRxActive
;
4937 while (( NULL
!= pIoNext
) && ( pIoNext
!= pIo
) && ( pIoNext
->pNext
!= pIo
))
4939 pIoNext
= pIoNext
->pNext
;
4941 ASSERT ( NULL
!= pIoNext
);
4942 if ( pIoNext
== pIo
) {
4943 pPort
->pRxActive
= pIo
->pNext
; // Beginning of list
4946 pIoNext
->pNext
= pIo
->pNext
; // Middle of list
4950 // Free the IO structure
4952 pIo
->pNext
= pPort
->pRxFree
;
4953 pPort
->pRxFree
= pIo
;
4956 // pRxOobPacketListHead pRxOobPacketListTail
4959 // +------------+ +------------+ +------------+
4960 // Urgent Data | ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL
4961 // +------------+ +------------+ +------------+
4963 // +------------+ +------------+ +------------+
4964 // Normal Data | ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL
4965 // +------------+ +------------+ +------------+
4968 // pRxPacketListHead pRxPacketListTail
4971 // Determine the queue to use
4973 bUrgentQueue
= (BOOLEAN
)( bUrgent
4974 && pSocket
->pApi
->bOobSupported
4975 && ( !pSocket
->bOobInLine
));
4976 if ( bUrgentQueue
) {
4977 ppQueueHead
= &pSocket
->pRxOobPacketListHead
;
4978 ppQueueTail
= &pSocket
->pRxOobPacketListTail
;
4979 pRxBytes
= &pSocket
->RxOobBytes
;
4982 ppQueueHead
= &pSocket
->pRxPacketListHead
;
4983 ppQueueTail
= &pSocket
->pRxPacketListTail
;
4984 pRxBytes
= &pSocket
->RxBytes
;
4988 // Determine if this receive was successful
4990 if (( !EFI_ERROR ( Status
))
4991 && ( PORT_STATE_CLOSE_STARTED
> pPort
->State
)
4992 && ( !pSocket
->bRxDisable
)) {
4994 // Account for the received data
4996 *pRxBytes
+= LengthInBytes
;
4999 // Log the received data
5001 DEBUG (( DEBUG_RX
| DEBUG_INFO
,
5002 "0x%08x: Packet queued on %s queue of port 0x%08x with 0x%08x bytes of %s data\r\n",
5004 bUrgentQueue
? L
"urgent" : L
"normal",
5007 bUrgent
? L
"urgent" : L
"normal" ));
5010 // Add the packet to the list tail.
5012 pPacket
->pNext
= NULL
;
5013 pPrevious
= *ppQueueTail
;
5014 if ( NULL
== pPrevious
) {
5015 *ppQueueHead
= pPacket
;
5018 pPrevious
->pNext
= pPacket
;
5020 *ppQueueTail
= pPacket
;
5023 // Attempt to restart this receive operation
5025 if ( pSocket
->MaxRxBuf
> pSocket
->RxBytes
) {
5026 EslSocketRxStart ( pPort
);
5030 "0x%08x: Port RX suspended, 0x%08x bytes queued\r\n",
5032 pSocket
->RxBytes
));
5036 if ( EFI_ERROR ( Status
)) {
5037 DEBUG (( DEBUG_RX
| DEBUG_INFO
,
5038 "ERROR - Receive error on port 0x%08x, packet 0x%08x, Status:%r\r\n",
5045 // Account for the receive bytes and release the driver's buffer
5047 if ( !EFI_ERROR ( Status
)) {
5048 *pRxBytes
+= LengthInBytes
;
5049 pSocket
->pApi
->pfnPacketFree ( pPacket
, pRxBytes
);
5053 // Receive error, free the packet save the error
5055 EslSocketPacketFree ( pPacket
, DEBUG_RX
);
5056 if ( !EFI_ERROR ( pSocket
->RxError
)) {
5057 pSocket
->RxError
= Status
;
5061 // Update the port state
5063 if ( PORT_STATE_CLOSE_STARTED
<= pPort
->State
) {
5064 if ( PORT_STATE_CLOSE_DONE
== pPort
->State
) {
5065 EslSocketPortCloseRxDone ( pPort
);
5069 if ( EFI_ERROR ( Status
)) {
5070 DEBUG (( DEBUG_RX
| DEBUG_INFO
,
5071 "0x%08x: Port state: PORT_STATE_RX_ERROR, Status: %r\r\n",
5074 pPort
->State
= PORT_STATE_RX_ERROR
;
5084 Poll a socket for pending receive activity.
5086 This routine is called at elivated TPL and extends the idle
5087 loop which polls a socket down into the LAN driver layer to
5088 determine if there is any receive activity.
5090 The ::EslSocketPoll, ::EslSocketReceive and ::EslSocketTransmit
5091 routines call this routine when there is nothing to do.
5093 @param [in] pSocket Address of an ::EFI_SOCKET structure.
5098 IN ESL_SOCKET
* pSocket
5103 DEBUG (( DEBUG_POLL
, "Entering EslSocketRxPoll\r\n" ));
5106 // Increase the network performance by extending the
5107 // polling (idle) loop down into the LAN driver
5109 pPort
= pSocket
->pPortList
;
5110 while ( NULL
!= pPort
) {
5112 // Poll the LAN adapter
5114 pPort
->pfnRxPoll ( pPort
->pProtocol
.v
);
5117 // Locate the next LAN adapter
5119 pPort
= pPort
->pLinkSocket
;
5122 DEBUG (( DEBUG_POLL
, "Exiting EslSocketRxPoll\r\n" ));
5127 Start a receive operation
5129 This routine posts a receive buffer to the network adapter.
5130 See the \ref ReceiveEngine section.
5132 This support routine is called by:
5134 <li>::EslIp4Receive to restart the receive engine to release flow control.</li>
5135 <li>::EslIp4RxComplete to continue the operation of the receive engine if flow control is not being applied.</li>
5136 <li>::EslIp4SocketIsConfigured to start the receive engine for the new socket.</li>
5137 <li>::EslTcp4ListenComplete to start the recevie engine for the new socket.</li>
5138 <li>::EslTcp4Receive to restart the receive engine to release flow control.</li>
5139 <li>::EslTcp4RxComplete to continue the operation of the receive engine if flow control is not being applied.</li>
5140 <li>::EslUdp4Receive to restart the receive engine to release flow control.</li>
5141 <li>::EslUdp4RxComplete to continue the operation of the receive engine if flow control is not being applied.</li>
5142 <li>::EslUdp4SocketIsConfigured to start the recevie engine for the new socket.</li>
5145 @param [in] pPort Address of an ::ESL_PORT structure.
5155 ESL_PACKET
* pPacket
;
5156 ESL_SOCKET
* pSocket
;
5162 // Determine if a receive is already pending
5164 Status
= EFI_SUCCESS
;
5166 pSocket
= pPort
->pSocket
;
5167 if ( !EFI_ERROR ( pPort
->pSocket
->RxError
)) {
5168 if (( NULL
!= pPort
->pRxFree
)
5169 && ( !pSocket
->bRxDisable
)
5170 && ( PORT_STATE_CLOSE_STARTED
> pPort
->State
)) {
5172 // Start all of the pending receive operations
5174 while ( NULL
!= pPort
->pRxFree
) {
5176 // Determine if there are any free packets
5178 pPacket
= pSocket
->pRxFree
;
5179 if ( NULL
!= pPacket
) {
5181 // Remove this packet from the free list
5183 pSocket
->pRxFree
= pPacket
->pNext
;
5185 "0x%08x: Port removed packet 0x%08x from free list\r\n",
5191 // Allocate a packet structure
5193 Status
= EslSocketPacketAllocate ( &pPacket
,
5194 pSocket
->pApi
->RxPacketBytes
,
5195 pSocket
->pApi
->RxZeroBytes
,
5197 if ( EFI_ERROR ( Status
)) {
5199 DEBUG (( DEBUG_ERROR
| DEBUG_RX
,
5200 "0x%08x: Port failed to allocate RX packet, Status: %r\r\n",
5208 // Connect the IO and packet structures
5210 pIo
= pPort
->pRxFree
;
5211 pIo
->pPacket
= pPacket
;
5214 // Eliminate the need for IP4 and UDP4 specific routines by
5215 // clearing the RX data pointer here.
5217 // No driver buffer for this packet
5219 // +--------------------+
5222 // | +---------------+
5224 // | | RxData --> NULL
5225 // +----+---------------+
5227 pBuffer
= (UINT8
*)pIo
;
5228 pBuffer
= &pBuffer
[ pSocket
->pApi
->RxBufferOffset
];
5229 *(VOID
**)pBuffer
= NULL
;
5232 // Network specific receive packet initialization
5234 if ( NULL
!= pSocket
->pApi
->pfnRxStart
) {
5235 pSocket
->pApi
->pfnRxStart ( pPort
, pIo
);
5239 // Start the receive on the packet
5241 Status
= pPort
->pfnRxStart ( pPort
->pProtocol
.v
, &pIo
->Token
);
5242 if ( !EFI_ERROR ( Status
)) {
5243 DEBUG (( DEBUG_RX
| DEBUG_INFO
,
5244 "0x%08x: Packet receive pending on port 0x%08x\r\n",
5248 // Allocate the receive control structure
5250 pPort
->pRxFree
= pIo
->pNext
;
5253 // Mark this receive as pending
5255 pIo
->pNext
= pPort
->pRxActive
;
5256 pPort
->pRxActive
= pIo
;
5260 DEBUG (( DEBUG_RX
| DEBUG_INFO
,
5261 "ERROR - Failed to post a receive on port 0x%08x, Status: %r\r\n",
5264 if ( !EFI_ERROR ( pSocket
->RxError
)) {
5266 // Save the error status
5268 pSocket
->RxError
= Status
;
5274 pIo
->pPacket
= NULL
;
5275 pPacket
->pNext
= pSocket
->pRxFree
;
5276 pSocket
->pRxFree
= pPacket
;
5282 if ( NULL
== pPort
->pRxFree
) {
5283 DEBUG (( DEBUG_RX
| DEBUG_INFO
,
5284 "0x%08x: Port, no available ESL_IO_MGMT structures\r\n",
5287 if ( pSocket
->bRxDisable
) {
5288 DEBUG (( DEBUG_RX
| DEBUG_INFO
,
5289 "0x%08x: Port, receive disabled!\r\n",
5292 if ( PORT_STATE_CLOSE_STARTED
<= pPort
->State
) {
5293 DEBUG (( DEBUG_RX
| DEBUG_INFO
,
5294 "0x%08x: Port, is closing!\r\n",
5300 DEBUG (( DEBUG_ERROR
| DEBUG_RX
,
5301 "ERROR - Previous receive error, Status: %r\r\n",
5302 pPort
->pSocket
->RxError
));
5310 Shutdown the socket receive and transmit operations
5312 This routine sets a flag to stop future transmissions and calls
5313 the network specific layer to cancel the pending receive operation.
5315 The ::shutdown routine calls this routine to stop receive and transmit
5316 operations on the socket.
5318 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
5320 @param [in] How Which operations to stop
5322 @param [out] pErrno Address to receive the errno value upon completion.
5324 @retval EFI_SUCCESS - Socket operations successfully shutdown
5329 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
5336 ESL_SOCKET
* pSocket
;
5338 EFI_TPL TplPrevious
;
5345 Status
= EFI_SUCCESS
;
5348 // Validate the socket
5351 if ( NULL
!= pSocketProtocol
) {
5352 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
5355 // Verify that the socket is connected
5357 if ( pSocket
->bConnected
) {
5359 // Validate the How value
5361 if (( SHUT_RD
<= How
) && ( SHUT_RDWR
>= How
)) {
5363 // Synchronize with the socket layer
5365 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
5368 // Disable the receiver if requested
5370 if (( SHUT_RD
== How
) || ( SHUT_RDWR
== How
)) {
5371 pSocket
->bRxDisable
= TRUE
;
5375 // Disable the transmitter if requested
5377 if (( SHUT_WR
== How
) || ( SHUT_RDWR
== How
)) {
5378 pSocket
->bTxDisable
= TRUE
;
5382 // Cancel the pending receive operations
5384 if ( pSocket
->bRxDisable
) {
5386 // Walk the list of ports
5388 pPort
= pSocket
->pPortList
;
5389 while ( NULL
!= pPort
) {
5391 // Walk the list of active receive operations
5393 pIo
= pPort
->pRxActive
;
5394 while ( NULL
!= pIo
) {
5395 EslSocketRxCancel ( pPort
, pIo
);
5399 // Set the next port
5401 pPort
= pPort
->pLinkSocket
;
5406 // Release the socket layer synchronization
5408 RESTORE_TPL ( TplPrevious
);
5412 // Invalid How value
5414 pSocket
->errno
= EINVAL
;
5415 Status
= EFI_INVALID_PARAMETER
;
5420 // The socket is not connected
5422 pSocket
->errno
= ENOTCONN
;
5423 Status
= EFI_NOT_STARTED
;
5428 // Return the operation status
5430 if ( NULL
!= pErrno
) {
5431 if ( NULL
!= pSocket
) {
5432 *pErrno
= pSocket
->errno
;
5435 Status
= EFI_INVALID_PARAMETER
;
5439 DBG_EXIT_STATUS ( Status
);
5445 Send data using a network connection.
5447 This routine calls the network specific layer to queue the data
5448 for transmission. Eventually the buffer will reach the head of
5449 the queue and will get transmitted over the network by the
5450 \ref TransmitEngine. For datagram
5451 sockets (SOCK_DGRAM and SOCK_RAW) there is no guarantee that
5452 the data reaches the application running on the remote system.
5454 The ::sendto routine calls this routine to send data to the remote
5455 system. Note that ::send and ::write are layered on top of ::sendto.
5457 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
5459 @param [in] Flags Message control flags
5461 @param [in] BufferLength Length of the the buffer
5463 @param [in] pBuffer Address of a buffer containing the data to send
5465 @param [in] pDataLength Address to receive the number of data bytes sent
5467 @param [in] pAddress Network address of the remote system address
5469 @param [in] AddressLength Length of the remote network address structure
5471 @param [out] pErrno Address to receive the errno value upon completion.
5473 @retval EFI_SUCCESS - Socket data successfully queued for transmit
5478 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
5480 IN
size_t BufferLength
,
5481 IN CONST UINT8
* pBuffer
,
5482 OUT
size_t * pDataLength
,
5483 IN
const struct sockaddr
* pAddress
,
5484 IN socklen_t AddressLength
,
5488 ESL_SOCKET
* pSocket
;
5490 EFI_TPL TplPrevious
;
5497 Status
= EFI_SUCCESS
;
5500 // Validate the socket
5503 if ( NULL
!= pSocketProtocol
) {
5504 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
5507 // Return the transmit error if necessary
5509 if ( EFI_SUCCESS
!= pSocket
->TxError
) {
5510 pSocket
->errno
= EIO
;
5511 Status
= pSocket
->TxError
;
5512 pSocket
->TxError
= EFI_SUCCESS
;
5516 // Verify the socket state
5518 Status
= EslSocketIsConfigured ( pSocket
);
5519 if ( !EFI_ERROR ( Status
)) {
5521 // Verify that transmit is still allowed
5523 if ( !pSocket
->bTxDisable
) {
5525 // Validate the buffer length
5527 if (( NULL
== pDataLength
)
5528 && ( 0 > pDataLength
)
5529 && ( NULL
== pBuffer
)) {
5530 if ( NULL
== pDataLength
) {
5532 "ERROR - pDataLength is NULL!\r\n" ));
5534 else if ( NULL
== pBuffer
) {
5536 "ERROR - pBuffer is NULL!\r\n" ));
5540 "ERROR - Data length < 0!\r\n" ));
5542 Status
= EFI_INVALID_PARAMETER
;
5543 pSocket
->errno
= EFAULT
;
5547 // Validate the remote network address
5549 if (( NULL
!= pAddress
)
5550 && ( AddressLength
< pAddress
->sa_len
)) {
5552 "ERROR - Invalid sin_len field in address\r\n" ));
5553 Status
= EFI_INVALID_PARAMETER
;
5554 pSocket
->errno
= EFAULT
;
5560 if ( NULL
== pSocket
->pApi
->pfnTransmit
) {
5561 Status
= EFI_UNSUPPORTED
;
5562 pSocket
->errno
= ENOTSUP
;
5566 // Synchronize with the socket layer
5568 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
5571 // Poll the network to increase performance
5573 EslSocketRxPoll ( pSocket
);
5576 // Attempt to buffer the packet for transmission
5578 Status
= pSocket
->pApi
->pfnTransmit ( pSocket
,
5587 // Release the socket layer synchronization
5589 RESTORE_TPL ( TplPrevious
);
5596 // The transmitter was shutdown
5598 pSocket
->errno
= EPIPE
;
5599 Status
= EFI_NOT_STARTED
;
5606 // Return the operation status
5608 if ( NULL
!= pErrno
) {
5609 if ( NULL
!= pSocket
) {
5610 *pErrno
= pSocket
->errno
;
5613 Status
= EFI_INVALID_PARAMETER
;
5617 DBG_EXIT_STATUS ( Status
);
5623 Complete the transmit operation
5625 This support routine handles the transmit completion processing for
5626 the various network layers. It frees the ::ESL_IO_MGMT structure
5627 and and frees packet resources by calling ::EslSocketPacketFree.
5628 Transmit errors are logged in ESL_SOCKET::TxError.
5629 See the \ref TransmitEngine section.
5631 This routine is called by:
5633 <li>::EslIp4TxComplete</li>
5634 <li>::EslTcp4TxComplete</li>
5635 <li>::EslTcp4TxOobComplete</li>
5636 <li>::EslUdp4TxComplete</li>
5639 @param [in] pIo Address of an ::ESL_IO_MGMT structure
5640 @param [in] LengthInBytes Length of the data in bytes
5641 @param [in] Status Transmit operation status
5642 @param [in] pQueueType Zero terminated string describing queue type
5643 @param [in] ppQueueHead Transmit queue head address
5644 @param [in] ppQueueTail Transmit queue tail address
5645 @param [in] ppActive Active transmit queue address
5646 @param [in] ppFree Free transmit queue address
5650 EslSocketTxComplete (
5651 IN ESL_IO_MGMT
* pIo
,
5652 IN UINT32 LengthInBytes
,
5653 IN EFI_STATUS Status
,
5654 IN CONST CHAR8
* pQueueType
,
5655 IN ESL_PACKET
** ppQueueHead
,
5656 IN ESL_PACKET
** ppQueueTail
,
5657 IN ESL_IO_MGMT
** ppActive
,
5658 IN ESL_IO_MGMT
** ppFree
5661 ESL_PACKET
* pCurrentPacket
;
5662 ESL_IO_MGMT
* pIoNext
;
5663 ESL_PACKET
* pNextPacket
;
5664 ESL_PACKET
* pPacket
;
5666 ESL_SOCKET
* pSocket
;
5669 VERIFY_AT_TPL ( TPL_SOCKETS
);
5672 // Locate the active transmit packet
5674 pPacket
= pIo
->pPacket
;
5676 pSocket
= pPort
->pSocket
;
5681 pIo
->pPacket
= NULL
;
5684 // Remove the IO structure from the active list
5686 pIoNext
= *ppActive
;
5687 while (( NULL
!= pIoNext
) && ( pIoNext
!= pIo
) && ( pIoNext
->pNext
!= pIo
))
5689 pIoNext
= pIoNext
->pNext
;
5691 ASSERT ( NULL
!= pIoNext
);
5692 if ( pIoNext
== pIo
) {
5693 *ppActive
= pIo
->pNext
; // Beginning of list
5696 pIoNext
->pNext
= pIo
->pNext
; // Middle of list
5700 // Free the IO structure
5702 pIo
->pNext
= *ppFree
;
5706 // Display the results
5708 DEBUG (( DEBUG_TX
| DEBUG_INFO
,
5709 "0x%08x: pIo Released\r\n",
5713 // Save any transmit error
5715 if ( EFI_ERROR ( Status
)) {
5716 if ( !EFI_ERROR ( pSocket
->TxError
)) {
5717 pSocket
->TxError
= Status
;
5719 DEBUG (( DEBUG_TX
| DEBUG_INFO
,
5720 "ERROR - Transmit failure for %apacket 0x%08x, Status: %r\r\n",
5726 // Empty the normal transmit list
5728 pCurrentPacket
= pPacket
;
5729 pNextPacket
= *ppQueueHead
;
5730 while ( NULL
!= pNextPacket
) {
5731 pPacket
= pNextPacket
;
5732 pNextPacket
= pPacket
->pNext
;
5733 EslSocketPacketFree ( pPacket
, DEBUG_TX
);
5735 *ppQueueHead
= NULL
;
5736 *ppQueueTail
= NULL
;
5737 pPacket
= pCurrentPacket
;
5740 DEBUG (( DEBUG_TX
| DEBUG_INFO
,
5741 "0x%08x: %apacket transmitted %d bytes successfully\r\n",
5747 // Verify the transmit engine is still running
5749 if ( !pPort
->bCloseNow
) {
5751 // Start the next packet transmission
5753 EslSocketTxStart ( pPort
,
5762 // Release this packet
5764 EslSocketPacketFree ( pPacket
, DEBUG_TX
);
5767 // Finish the close operation if necessary
5769 if ( PORT_STATE_CLOSE_STARTED
<= pPort
->State
) {
5771 // Indicate that the transmit is complete
5773 EslSocketPortCloseTxDone ( pPort
);
5781 Transmit data using a network connection.
5783 This support routine starts a transmit operation on the
5784 underlying network layer.
5786 The network specific code calls this routine to start a
5787 transmit operation. See the \ref TransmitEngine section.
5789 @param [in] pPort Address of an ::ESL_PORT structure
5790 @param [in] ppQueueHead Transmit queue head address
5791 @param [in] ppQueueTail Transmit queue tail address
5792 @param [in] ppActive Active transmit queue address
5793 @param [in] ppFree Free transmit queue address
5798 IN ESL_PORT
* pPort
,
5799 IN ESL_PACKET
** ppQueueHead
,
5800 IN ESL_PACKET
** ppQueueTail
,
5801 IN ESL_IO_MGMT
** ppActive
,
5802 IN ESL_IO_MGMT
** ppFree
5807 ESL_PACKET
* pNextPacket
;
5808 ESL_PACKET
* pPacket
;
5809 VOID
** ppTokenData
;
5810 ESL_SOCKET
* pSocket
;
5818 Status
= EFI_SUCCESS
;
5821 // Get the packet from the queue head
5823 pPacket
= *ppQueueHead
;
5825 if (( NULL
!= pPacket
) && ( NULL
!= pIo
)) {
5826 pSocket
= pPort
->pSocket
;
5828 // *ppQueueHead: pSocket->pRxPacketListHead or pSocket->pRxOobPacketListHead
5831 // +------------+ +------------+ +------------+
5832 // Data | ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL
5833 // +------------+ +------------+ +------------+
5836 // *ppQueueTail: pSocket->pRxPacketListTail or pSocket->pRxOobPacketListTail
5839 // Remove the packet from the queue
5841 pNextPacket
= pPacket
->pNext
;
5842 *ppQueueHead
= pNextPacket
;
5843 if ( NULL
== pNextPacket
) {
5844 *ppQueueTail
= NULL
;
5846 pPacket
->pNext
= NULL
;
5849 // Eliminate the need for IP4 and UDP4 specific routines by
5850 // connecting the token with the TX data control structure here.
5852 // +--------------------+ +--------------------+
5853 // | ESL_IO_MGMT | | ESL_PACKET |
5855 // | +---------------+ +----------------+ |
5856 // | | Token | | Buffer Length | |
5857 // | | TxData --> | Buffer Address | |
5858 // | | | +----------------+---+
5859 // | | Event | | Data Buffer |
5860 // +----+---------------+ | |
5861 // +--------------------+
5863 // Compute the address of the TxData pointer in the token
5865 pBuffer
= (UINT8
*)&pIo
->Token
;
5866 pBuffer
= &pBuffer
[ pSocket
->TxTokenOffset
];
5867 ppTokenData
= (VOID
**)pBuffer
;
5870 // Compute the address of the TX data control structure in the packet
5872 // * EFI_IP4_TRANSMIT_DATA
5873 // * EFI_TCP4_TRANSMIT_DATA
5874 // * EFI_UDP4_TRANSMIT_DATA
5876 pBuffer
= (UINT8
*)pPacket
;
5877 pBuffer
= &pBuffer
[ pSocket
->TxPacketOffset
];
5880 // Connect the token to the transmit data control structure
5882 *ppTokenData
= (VOID
**)pBuffer
;
5885 // Display the results
5887 DEBUG (( DEBUG_TX
| DEBUG_INFO
,
5888 "0x%08x: pIo allocated for pPacket: 0x%08x\r\n",
5893 // Start the transmit operation
5895 Status
= pPort
->pfnTxStart ( pPort
->pProtocol
.v
,
5897 if ( !EFI_ERROR ( Status
)) {
5899 // Connect the structures
5901 pIo
->pPacket
= pPacket
;
5904 // +-------------+ +-------------+ +-------------+
5905 // Free | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
5906 // +-------------+ +-------------+ +-------------+
5909 // *ppFree: pPort->pTxFree or pTxOobFree
5912 // Remove the IO structure from the queue
5914 *ppFree
= pIo
->pNext
;
5917 // *ppActive: pPort->pTxActive or pTxOobActive
5920 // +-------------+ +-------------+ +-------------+
5921 // Active | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
5922 // +-------------+ +-------------+ +-------------+
5925 // Mark this packet as active
5927 pIo
->pPacket
= pPacket
;
5928 pIo
->pNext
= *ppActive
;
5933 // Display the transmit error
5935 DEBUG (( DEBUG_TX
| DEBUG_INFO
,
5936 "0x%08x, 0x%08x: pIo, pPacket transmit failure: %r\r\n",
5940 if ( EFI_SUCCESS
== pSocket
->TxError
) {
5941 pSocket
->TxError
= Status
;
5945 // Free the IO structure
5947 pIo
->pNext
= *ppFree
;
5951 // Discard the transmit buffer
5953 EslSocketPacketFree ( pPacket
, DEBUG_TX
);