2 Implement the socket support for the socket layer.
5 * Bound - pSocket->PortList is not NULL
6 * Listen - AcceptWait event is not NULL
8 Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>
9 This program and the accompanying materials are licensed and made available under
10 the terms and conditions of the BSD License that accompanies this distribution.
11 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.
462 /** Socket driver connection points
464 List the network stack connection points for the socket driver.
466 CONST ESL_SOCKET_BINDING cEslSocketBinding
[] = {
468 &gEfiIp4ServiceBindingProtocolGuid
,
469 &gEfiIp4ProtocolGuid
,
471 OFFSET_OF ( ESL_LAYER
, pIp4List
),
474 0 }, // TX Oob buffers
476 &gEfiTcp4ServiceBindingProtocolGuid
,
477 &gEfiTcp4ProtocolGuid
,
478 &mEslTcp4ServiceGuid
,
479 OFFSET_OF ( ESL_LAYER
, pTcp4List
),
482 4 }, // TX Oob buffers
484 &gEfiTcp6ServiceBindingProtocolGuid
,
485 &gEfiTcp6ProtocolGuid
,
486 &mEslTcp6ServiceGuid
,
487 OFFSET_OF ( ESL_LAYER
, pTcp6List
),
490 4 }, // TX Oob buffers
492 &gEfiUdp4ServiceBindingProtocolGuid
,
493 &gEfiUdp4ProtocolGuid
,
494 &mEslUdp4ServiceGuid
,
495 OFFSET_OF ( ESL_LAYER
, pUdp4List
),
498 0 }, // TX Oob buffers
500 &gEfiUdp6ServiceBindingProtocolGuid
,
501 &gEfiUdp6ProtocolGuid
,
502 &mEslUdp6ServiceGuid
,
503 OFFSET_OF ( ESL_LAYER
, pUdp6List
),
506 0 } // TX Oob buffers
509 CONST UINTN cEslSocketBindingEntries
= DIM ( cEslSocketBinding
);
511 /// APIs to support the various socket types for the v4 network stack.
512 CONST ESL_PROTOCOL_API
* cEslAfInetApi
[] = {
514 &cEslTcp4Api
, // SOCK_STREAM
515 &cEslUdp4Api
, // SOCK_DGRAM
516 &cEslIp4Api
, // SOCK_RAW
518 &cEslTcp4Api
// SOCK_SEQPACKET
521 /// Number of entries in the v4 API array ::cEslAfInetApi.
522 CONST
int cEslAfInetApiSize
= DIM ( cEslAfInetApi
);
525 /// APIs to support the various socket types for the v6 network stack.
526 CONST ESL_PROTOCOL_API
* cEslAfInet6Api
[] = {
528 &cEslTcp6Api
, // SOCK_STREAM
529 &cEslUdp6Api
, // SOCK_DGRAM
532 &cEslTcp6Api
// SOCK_SEQPACKET
535 /// Number of entries in the v6 API array ::cEslAfInet6Api.
536 CONST
int cEslAfInet6ApiSize
= DIM ( cEslAfInet6Api
);
539 /// Global management structure for the socket layer.
543 /** Initialize an endpoint for network communication.
545 This routine initializes the communication endpoint.
547 The ::socket routine calls this routine indirectly to create
548 the communication endpoint.
550 @param[in] pSocketProtocol Address of the socket protocol structure.
551 @param[in] domain Select the family of protocols for the client or server
552 application. See the ::socket documentation for values.
553 @param[in] type Specifies how to make the network connection.
554 See the ::socket documentation for values.
555 @param[in] protocol Specifies the lower layer protocol to use.
556 See the ::socket documentation for values.
557 @param[out] pErrno Address to receive the errno value upon completion.
559 @retval EFI_SUCCESS - Socket successfully created
560 @retval EFI_INVALID_PARAMETER - Invalid domain value, errno = EAFNOSUPPORT
561 @retval EFI_INVALID_PARAMETER - Invalid type value, errno = EINVAL
562 @retval EFI_INVALID_PARAMETER - Invalid protocol value, errno = EINVAL
566 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
573 CONST ESL_PROTOCOL_API
* pApi
;
574 CONST ESL_PROTOCOL_API
** ppApiArray
;
575 CONST ESL_PROTOCOL_API
** ppApiArrayEnd
;
577 ESL_SOCKET
* pSocket
;
584 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
586 // Set the default domain if necessary
587 if ( AF_UNSPEC
== domain
) {
593 Status
= EFI_SUCCESS
;
595 // Use break instead of goto
597 // Validate the domain value
598 if (( AF_INET
!= domain
)
599 && ( AF_INET6
!= domain
)
600 && ( AF_LOCAL
!= domain
)) {
601 DEBUG (( DEBUG_ERROR
| DEBUG_SOCKET
,
602 "ERROR - Invalid domain value\r\n" ));
603 Status
= EFI_INVALID_PARAMETER
;
604 errno
= EAFNOSUPPORT
;
608 // Determine the protocol APIs
611 if (( AF_INET
== domain
)
612 || ( AF_LOCAL
== domain
)) {
613 ppApiArray
= &cEslAfInetApi
[0];
614 ApiArraySize
= cEslAfInetApiSize
;
617 ppApiArray
= &cEslAfInet6Api
[0];
618 ApiArraySize
= cEslAfInet6ApiSize
;
621 // Set the default type if necessary
626 // Validate the type value
627 if (( type
>= ApiArraySize
)
628 || ( NULL
== ppApiArray
)
629 || ( NULL
== ppApiArray
[ type
])) {
630 DEBUG (( DEBUG_ERROR
| DEBUG_SOCKET
,
631 "ERROR - Invalid type value\r\n" ));
632 // The socket type is not supported
633 Status
= EFI_INVALID_PARAMETER
;
638 // Set the default protocol if necessary
639 pApi
= ppApiArray
[ type
];
640 if ( 0 == protocol
) {
641 protocol
= pApi
->DefaultProtocol
;
644 // Validate the protocol value
645 if (( pApi
->DefaultProtocol
!= protocol
)
646 && ( SOCK_RAW
!= type
)) {
647 Status
= EFI_INVALID_PARAMETER
;
649 // Assume that the driver supports this protocol
650 ppApiArray
= &cEslAfInetApi
[0];
651 ppApiArrayEnd
= &ppApiArray
[ cEslAfInetApiSize
];
652 while ( ppApiArrayEnd
> ppApiArray
) {
654 if ( protocol
== pApi
->DefaultProtocol
) {
659 if ( ppApiArrayEnd
<= ppApiArray
) {
660 // Verify against the IPv6 table
661 ppApiArray
= &cEslAfInet6Api
[0];
662 ppApiArrayEnd
= &ppApiArray
[ cEslAfInet6ApiSize
];
663 while ( ppApiArrayEnd
> ppApiArray
) {
665 if ( protocol
== pApi
->DefaultProtocol
) {
671 if ( ppApiArrayEnd
<= ppApiArray
) {
672 DEBUG (( DEBUG_ERROR
| DEBUG_SOCKET
,
673 "ERROR - The protocol is not supported!\r\n" ));
674 errno
= EPROTONOSUPPORT
;
678 // The driver does not support this protocol
679 DEBUG (( DEBUG_ERROR
| DEBUG_SOCKET
,
680 "ERROR - The protocol does not support this socket type!\r\n" ));
681 errno
= EPROTONOSUPPORT
;
685 // Save the socket attributes
686 pSocket
->pApi
= pApi
;
687 pSocket
->Domain
= domain
;
688 pSocket
->Type
= type
;
689 pSocket
->Protocol
= protocol
;
694 // Return the operation status
695 if ( NULL
!= pErrno
) {
698 DBG_EXIT_STATUS ( Status
);
703 /** Accept a network connection.
705 This routine calls the network specific layer to remove the next
706 connection from the FIFO.
708 The ::accept calls this routine to poll for a network
709 connection to the socket. When a connection is available
710 this routine returns the ::EFI_SOCKET_PROTOCOL structure address
711 associated with the new socket and the remote network address
714 @param[in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
715 @param[in] pSockAddr Address of a buffer to receive the remote
717 @param[in,out] pSockAddrLength Length in bytes of the address buffer.
718 On output specifies the length of the
719 remote network address.
720 @param[out] ppSocketProtocol Address of a buffer to receive the
721 ::EFI_SOCKET_PROTOCOL instance
722 associated with the new socket.
723 @param[out] pErrno Address to receive the errno value upon completion.
725 @retval EFI_SUCCESS New connection successfully created
726 @retval EFI_NOT_READY No connection is available
730 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
731 IN
struct sockaddr
* pSockAddr
,
732 IN OUT socklen_t
* pSockAddrLength
,
733 IN EFI_SOCKET_PROTOCOL
** ppSocketProtocol
,
737 ESL_SOCKET
* pNewSocket
;
738 ESL_SOCKET
* pSocket
;
747 Status
= EFI_SUCCESS
;
750 // Validate the socket
754 if ( NULL
!= pSocketProtocol
) {
755 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
760 if ( NULL
== pSocket
->pApi
->pfnAccept
) {
761 Status
= EFI_UNSUPPORTED
;
762 pSocket
->errno
= ENOTSUP
;
766 // Validate the sockaddr
768 if (( NULL
!= pSockAddr
)
769 && ( NULL
== pSockAddrLength
)) {
770 DEBUG (( DEBUG_ACCEPT
,
771 "ERROR - pSockAddr is NULL!\r\n" ));
772 Status
= EFI_INVALID_PARAMETER
;
773 pSocket
->errno
= EFAULT
;
777 // Synchronize with the socket layer
779 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
782 // Verify that the socket is in the listen state
784 if ( SOCKET_STATE_LISTENING
!= pSocket
->State
) {
785 DEBUG (( DEBUG_ACCEPT
,
786 "ERROR - Socket is not listening!\r\n" ));
787 if ( NULL
== pSocket
->pApi
->pfnAccept
) {
789 // Socket does not support listen
791 pSocket
->errno
= EOPNOTSUPP
;
792 Status
= EFI_UNSUPPORTED
;
796 // Socket supports listen, but not in listen state
798 pSocket
->errno
= EINVAL
;
799 Status
= EFI_NOT_STARTED
;
804 // Determine if a socket is available
806 if ( 0 == pSocket
->FifoDepth
) {
808 // No connections available
809 // Determine if any ports are available
811 if ( NULL
== pSocket
->pPortList
) {
813 // No ports available
815 Status
= EFI_DEVICE_ERROR
;
816 pSocket
->errno
= EINVAL
;
819 // Update the socket state
821 pSocket
->State
= SOCKET_STATE_NO_PORTS
;
825 // Ports are available
826 // No connection requests at this time
828 Status
= EFI_NOT_READY
;
829 pSocket
->errno
= EAGAIN
;
835 // Attempt to accept the connection and
836 // get the remote network address
838 pNewSocket
= pSocket
->pFifoHead
;
839 ASSERT ( NULL
!= pNewSocket
);
840 Status
= pSocket
->pApi
->pfnAccept ( pNewSocket
,
843 if ( !EFI_ERROR ( Status
)) {
845 // Remove the new socket from the list
847 pSocket
->pFifoHead
= pNewSocket
->pNextConnection
;
848 if ( NULL
== pSocket
->pFifoHead
) {
849 pSocket
->pFifoTail
= NULL
;
853 // Account for this socket
855 pSocket
->FifoDepth
-= 1;
858 // Update the new socket's state
860 pNewSocket
->State
= SOCKET_STATE_CONNECTED
;
861 pNewSocket
->bConfigured
= TRUE
;
862 DEBUG (( DEBUG_ACCEPT
,
863 "0x%08x: Socket connected\r\n",
870 // Release the socket layer synchronization
872 RESTORE_TPL ( TplPrevious
);
878 // Return the new socket
880 if (( NULL
!= ppSocketProtocol
)
881 && ( NULL
!= pNewSocket
)) {
882 *ppSocketProtocol
= &pNewSocket
->SocketProtocol
;
886 // Return the operation status
888 if ( NULL
!= pErrno
) {
889 if ( NULL
!= pSocket
) {
890 *pErrno
= pSocket
->errno
;
893 Status
= EFI_INVALID_PARAMETER
;
897 DBG_EXIT_STATUS ( Status
);
902 /** Allocate and initialize a ESL_SOCKET structure.
904 This support function allocates an ::ESL_SOCKET structure
905 and installs a protocol on ChildHandle. If pChildHandle is a
906 pointer to NULL, then a new handle is created and returned in
907 pChildHandle. If pChildHandle is not a pointer to NULL, then
908 the protocol installs on the existing pChildHandle.
910 @param[in,out] pChildHandle Pointer to the handle of the child to create.
911 If it is NULL, then a new handle is created.
912 If it is a pointer to an existing UEFI handle,
913 then the protocol is added to the existing UEFI
915 @param[in] DebugFlags Flags for debug messages
916 @param[in,out] ppSocket The buffer to receive an ::ESL_SOCKET structure address.
918 @retval EFI_SUCCESS The protocol was added to ChildHandle.
919 @retval EFI_INVALID_PARAMETER ChildHandle is NULL.
920 @retval EFI_OUT_OF_RESOURCES There are not enough resources available to create
922 @retval other The child handle was not created
927 IN OUT EFI_HANDLE
* pChildHandle
,
929 IN OUT ESL_SOCKET
** ppSocket
934 ESL_SOCKET
* pSocket
;
941 // Create a socket structure
943 LengthInBytes
= sizeof ( *pSocket
);
944 pSocket
= (ESL_SOCKET
*) AllocateZeroPool ( LengthInBytes
);
945 if ( NULL
!= pSocket
) {
946 DEBUG (( DebugFlags
| DEBUG_POOL
| DEBUG_INIT
,
947 "0x%08x: Allocate pSocket, %d bytes\r\n",
952 // Initialize the socket protocol
954 pSocket
->Signature
= SOCKET_SIGNATURE
;
955 pSocket
->SocketProtocol
.pfnAccept
= EslSocketAccept
;
956 pSocket
->SocketProtocol
.pfnBind
= EslSocketBind
;
957 pSocket
->SocketProtocol
.pfnClosePoll
= EslSocketClosePoll
;
958 pSocket
->SocketProtocol
.pfnCloseStart
= EslSocketCloseStart
;
959 pSocket
->SocketProtocol
.pfnConnect
= EslSocketConnect
;
960 pSocket
->SocketProtocol
.pfnGetLocal
= EslSocketGetLocalAddress
;
961 pSocket
->SocketProtocol
.pfnGetPeer
= EslSocketGetPeerAddress
;
962 pSocket
->SocketProtocol
.pfnListen
= EslSocketListen
;
963 pSocket
->SocketProtocol
.pfnOptionGet
= EslSocketOptionGet
;
964 pSocket
->SocketProtocol
.pfnOptionSet
= EslSocketOptionSet
;
965 pSocket
->SocketProtocol
.pfnPoll
= EslSocketPoll
;
966 pSocket
->SocketProtocol
.pfnReceive
= EslSocketReceive
;
967 pSocket
->SocketProtocol
.pfnShutdown
= EslSocketShutdown
;
968 pSocket
->SocketProtocol
.pfnSocket
= EslSocket
;
969 pSocket
->SocketProtocol
.pfnTransmit
= EslSocketTransmit
;
971 pSocket
->MaxRxBuf
= MAX_RX_DATA
;
972 pSocket
->MaxTxBuf
= MAX_TX_DATA
;
975 // Install the socket protocol on the specified handle
977 Status
= gBS
->InstallMultipleProtocolInterfaces (
979 &gEfiSocketProtocolGuid
,
980 &pSocket
->SocketProtocol
,
983 if ( !EFI_ERROR ( Status
)) {
984 DEBUG (( DebugFlags
| DEBUG_POOL
| DEBUG_INIT
| DEBUG_INFO
,
985 "Installed: gEfiSocketProtocolGuid on 0x%08x\r\n",
987 pSocket
->SocketProtocol
.SocketHandle
= *pChildHandle
;
990 // Synchronize with the socket layer
992 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
995 // Add this socket to the list
998 pSocket
->pNext
= pLayer
->pSocketList
;
999 pLayer
->pSocketList
= pSocket
;
1002 // Release the socket layer synchronization
1004 RESTORE_TPL ( TplPrevious
);
1007 // Return the socket structure address
1009 *ppSocket
= pSocket
;
1012 DEBUG (( DEBUG_ERROR
| DebugFlags
| DEBUG_POOL
| DEBUG_INIT
,
1013 "ERROR - Failed to install gEfiSocketProtocolGuid on 0x%08x, Status: %r\r\n",
1019 // Release the socket if necessary
1021 if ( EFI_ERROR ( Status
)) {
1022 gBS
->FreePool ( pSocket
);
1023 DEBUG (( DebugFlags
| DEBUG_POOL
| DEBUG_INIT
,
1024 "0x%08x: Free pSocket, %d bytes\r\n",
1026 sizeof ( *pSocket
)));
1031 Status
= EFI_OUT_OF_RESOURCES
;
1035 // Return the operation status
1037 DBG_EXIT_STATUS ( Status
);
1042 /** Bind a name to a socket.
1044 This routine calls the network specific layer to save the network
1045 address of the local connection point.
1047 The ::bind routine calls this routine to connect a name
1048 (network address and port) to a socket on the local machine.
1050 @param[in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
1051 @param[in] pSockAddr Address of a sockaddr structure that contains the
1052 connection point on the local machine. An IPv4 address
1053 of INADDR_ANY specifies that the connection is made to
1054 all of the network stacks on the platform. Specifying a
1055 specific IPv4 address restricts the connection to the
1056 network stack supporting that address. Specifying zero
1057 for the port causes the network layer to assign a port
1058 number from the dynamic range. Specifying a specific
1059 port number causes the network layer to use that port.
1060 @param[in] SockAddrLength Specifies the length in bytes of the sockaddr structure.
1061 @param[out] pErrno Address to receive the errno value upon completion.
1063 @retval EFI_SUCCESS - Socket successfully created
1067 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
1068 IN CONST
struct sockaddr
* pSockAddr
,
1069 IN socklen_t SockAddrLength
,
1073 EFI_HANDLE ChildHandle
;
1076 ESL_SERVICE
** ppServiceListHead
;
1077 ESL_SOCKET
* pSocket
;
1078 ESL_SERVICE
* pService
;
1079 EFI_SERVICE_BINDING_PROTOCOL
* pServiceBinding
;
1081 EFI_TPL TplPrevious
;
1088 Status
= EFI_SUCCESS
;
1091 // Validate the socket
1094 if ( NULL
!= pSocketProtocol
) {
1095 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
1098 // Validate the structure pointer
1101 if ( NULL
== pSockAddr
) {
1102 DEBUG (( DEBUG_BIND
,
1103 "ERROR - pSockAddr is NULL!\r\n" ));
1104 Status
= EFI_INVALID_PARAMETER
;
1105 pSocket
->errno
= EFAULT
;
1109 // Validate the local address length
1111 else if ( SockAddrLength
< pSocket
->pApi
->MinimumAddressLength
) {
1112 DEBUG (( DEBUG_BIND
,
1113 "ERROR - Invalid bind name length: %d\r\n",
1115 Status
= EFI_INVALID_PARAMETER
;
1116 pSocket
->errno
= EINVAL
;
1120 // Validate the shutdown state
1122 else if ( pSocket
->bRxDisable
|| pSocket
->bTxDisable
) {
1123 DEBUG (( DEBUG_BIND
,
1124 "ERROR - Shutdown has been called on socket 0x%08x\r\n",
1126 pSocket
->errno
= EINVAL
;
1127 Status
= EFI_INVALID_PARAMETER
;
1131 // Verify the socket state
1133 else if ( SOCKET_STATE_NOT_CONFIGURED
!= pSocket
->State
) {
1134 DEBUG (( DEBUG_BIND
,
1135 "ERROR - The socket 0x%08x is already configured!\r\n",
1137 pSocket
->errno
= EINVAL
;
1138 Status
= EFI_ALREADY_STARTED
;
1142 // Synchronize with the socket layer
1144 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
1147 // Assume no ports are available
1149 pSocket
->errno
= EADDRNOTAVAIL
;
1150 Status
= EFI_INVALID_PARAMETER
;
1153 // Walk the list of services
1155 pBuffer
= (UINT8
*)&mEslLayer
;
1156 pBuffer
= &pBuffer
[ pSocket
->pApi
->ServiceListOffset
];
1157 ppServiceListHead
= (ESL_SERVICE
**)pBuffer
;
1158 pService
= *ppServiceListHead
;
1159 while ( NULL
!= pService
) {
1163 pServiceBinding
= pService
->pServiceBinding
;
1165 Status
= pServiceBinding
->CreateChild ( pServiceBinding
,
1167 if ( !EFI_ERROR ( Status
)) {
1168 DEBUG (( DEBUG_BIND
| DEBUG_POOL
,
1169 "0x%08x: %s port handle created\r\n",
1171 pService
->pSocketBinding
->pName
));
1176 Status
= EslSocketPortAllocate ( pSocket
,
1185 DEBUG (( DEBUG_BIND
| DEBUG_POOL
,
1186 "ERROR - Failed to open %s port handle, Status: %r\r\n",
1187 pService
->pSocketBinding
->pName
,
1192 // Set the next service
1194 pService
= pService
->pNext
;
1198 // Verify that at least one network connection was found
1200 if ( NULL
!= pSocket
->pPortList
) {
1201 Status
= EFI_SUCCESS
;
1204 if ( EADDRNOTAVAIL
== pSocket
->errno
) {
1205 DEBUG (( DEBUG_BIND
| DEBUG_POOL
| DEBUG_INIT
,
1206 "ERROR - Socket address is not available!\r\n" ));
1208 if ( EADDRINUSE
== pSocket
->errno
) {
1209 DEBUG (( DEBUG_BIND
| DEBUG_POOL
| DEBUG_INIT
,
1210 "ERROR - Socket address is in use!\r\n" ));
1212 Status
= EFI_INVALID_PARAMETER
;
1216 // Mark this socket as bound if successful
1218 if ( !EFI_ERROR ( Status
)) {
1219 pSocket
->State
= SOCKET_STATE_BOUND
;
1224 // Release the socket layer synchronization
1226 RESTORE_TPL ( TplPrevious
);
1231 // Return the operation status
1233 if ( NULL
!= pErrno
) {
1234 if ( NULL
!= pSocket
) {
1235 *pErrno
= pSocket
->errno
;
1238 Status
= EFI_INVALID_PARAMETER
;
1242 DBG_EXIT_STATUS ( Status
);
1247 /** Test the bind configuration.
1249 @param[in] pPort Address of the ::ESL_PORT structure.
1250 @param[in] ErrnoValue errno value if test fails
1252 @retval EFI_SUCCESS The connection was successfully established.
1253 @retval Others The connection attempt failed.
1257 IN ESL_PORT
* pPort
,
1268 // Locate the configuration data
1270 pBuffer
= (UINT8
*)pPort
;
1271 pBuffer
= &pBuffer
[ pPort
->pSocket
->pApi
->ConfigDataOffset
];
1272 pConfigData
= (VOID
*)pBuffer
;
1275 // Validate that the port is connected
1277 Status
= pPort
->pSocket
->pApi
->pfnVerifyLocalIpAddress ( pPort
, pBuffer
);
1278 if ( EFI_ERROR ( Status
)) {
1279 DEBUG (( DEBUG_WARN
| DEBUG_BIND
,
1280 "WARNING - Port 0x%08x invalid IP address: %r\r\n",
1283 pPort
->pSocket
->errno
= ErrnoValue
;
1287 // Attempt to use this configuration
1289 Status
= pPort
->pfnConfigure ( pPort
->pProtocol
.v
, pConfigData
);
1290 if ( EFI_ERROR ( Status
)) {
1291 DEBUG (( DEBUG_WARN
| DEBUG_BIND
,
1292 "WARNING - Port 0x%08x failed configuration, Status: %r\r\n",
1295 pPort
->pSocket
->errno
= ErrnoValue
;
1301 Status
= pPort
->pfnConfigure ( pPort
->pProtocol
.v
, NULL
);
1302 if ( EFI_ERROR ( Status
)) {
1303 DEBUG (( DEBUG_ERROR
| DEBUG_BIND
,
1304 "ERROR - Port 0x%08x failed configuration reset, Status: %r\r\n",
1307 ASSERT ( EFI_SUCCESS
== Status
);
1313 // Return the operation status
1315 DBG_EXIT_STATUS ( Status
);
1320 /** Determine if the socket is closed.
1322 This routine checks the state of the socket to determine if
1323 the network specific layer has completed the close operation.
1325 The ::close routine polls this routine to determine when the
1326 close operation is complete. The close operation needs to
1327 reverse the operations of the ::EslSocketAllocate routine.
1329 @param[in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
1330 @param[out] pErrno Address to receive the errno value upon completion.
1332 @retval EFI_SUCCESS Socket successfully closed
1333 @retval EFI_NOT_READY Close still in progress
1334 @retval EFI_ALREADY Close operation already in progress
1335 @retval Other Failed to close the socket
1338 EslSocketClosePoll (
1339 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
1345 ESL_SOCKET
* pNextSocket
;
1346 ESL_SOCKET
* pSocket
;
1348 EFI_TPL TplPrevious
;
1356 Status
= EFI_SUCCESS
;
1359 // Synchronize with the socket layer
1361 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
1364 // Locate the socket
1366 pLayer
= &mEslLayer
;
1367 pNextSocket
= pLayer
->pSocketList
;
1368 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
1369 while ( NULL
!= pNextSocket
) {
1370 if ( pNextSocket
== pSocket
) {
1372 // Determine if the socket is in the closing state
1374 if ( SOCKET_STATE_CLOSED
== pSocket
->State
) {
1376 // Walk the list of ports
1378 if ( NULL
== pSocket
->pPortList
) {
1380 // All the ports are closed
1381 // Close the WaitAccept event if necessary
1383 if ( NULL
!= pSocket
->WaitAccept
) {
1384 Status
= gBS
->CloseEvent ( pSocket
->WaitAccept
);
1385 if ( !EFI_ERROR ( Status
)) {
1386 DEBUG (( DEBUG_SOCKET
| DEBUG_CLOSE
| DEBUG_POOL
,
1387 "0x%08x: Closed WaitAccept event\r\n",
1388 pSocket
->WaitAccept
));
1390 // Return the transmit status
1392 Status
= pSocket
->TxError
;
1393 if ( EFI_ERROR ( Status
)) {
1394 pSocket
->errno
= EIO
;
1398 DEBUG (( DEBUG_ERROR
| DEBUG_SOCKET
| DEBUG_CLOSE
| DEBUG_POOL
,
1399 "ERROR - Failed to close the WaitAccept event, Status: %r\r\n",
1401 ASSERT ( EFI_SUCCESS
== Status
);
1407 // At least one port is still open
1409 Status
= EFI_NOT_READY
;
1415 // SocketCloseStart was not called
1417 Status
= EFI_NOT_STARTED
;
1424 // Set the next socket
1426 pNextSocket
= pNextSocket
->pNext
;
1430 // Handle the error case where the socket was already closed
1432 if ( NULL
== pSocket
) {
1436 Status
= EFI_NOT_FOUND
;
1441 // Release the socket layer synchronization
1443 RESTORE_TPL ( TplPrevious
);
1446 // Return the operation status
1448 if ( NULL
!= pErrno
) {
1451 DBG_EXIT_STATUS ( Status
);
1456 /** Start the close operation on the socket.
1458 This routine calls the network specific layer to initiate the
1459 close state machine. This routine then calls the network
1460 specific layer to determine if the close state machine has gone
1461 to completion. The result from this poll is returned to the
1464 The ::close routine calls this routine to start the close
1465 operation which reverses the operations of the
1466 ::EslSocketAllocate routine. The close routine then polls
1467 the ::EslSocketClosePoll routine to determine when the
1470 @param[in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
1471 @param[in] bCloseNow Boolean to control close behavior
1472 @param[out] pErrno Address to receive the errno value upon completion.
1474 @retval EFI_SUCCESS Socket successfully closed
1475 @retval EFI_NOT_READY Close still in progress
1476 @retval EFI_ALREADY Close operation already in progress
1477 @retval Other Failed to close the socket
1480 EslSocketCloseStart (
1481 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
1482 IN BOOLEAN bCloseNow
,
1487 ESL_PORT
* pNextPort
;
1489 ESL_SOCKET
* pSocket
;
1491 EFI_TPL TplPrevious
;
1498 Status
= EFI_SUCCESS
;
1502 // Synchronize with the socket layer
1504 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
1507 // Determine if the socket is already closed
1509 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
1510 if ( SOCKET_STATE_CLOSED
> pSocket
->State
) {
1512 // Update the socket state
1514 pSocket
->State
= SOCKET_STATE_CLOSED
;
1517 // Walk the list of ports
1519 pPort
= pSocket
->pPortList
;
1520 while ( NULL
!= pPort
) {
1522 // Start closing the ports
1524 pNextPort
= pPort
->pLinkSocket
;
1525 Status
= EslSocketPortCloseStart ( pPort
,
1527 DEBUG_CLOSE
| DEBUG_LISTEN
| DEBUG_CONNECTION
);
1528 if (( EFI_SUCCESS
!= Status
)
1529 && ( EFI_NOT_READY
!= Status
)) {
1535 // Set the next port
1541 // Attempt to finish closing the socket
1543 if ( NULL
== pPort
) {
1544 Status
= EslSocketClosePoll ( pSocketProtocol
, &errno
);
1548 Status
= EFI_NOT_READY
;
1553 // Release the socket layer synchronization
1555 RESTORE_TPL ( TplPrevious
);
1558 // Return the operation status
1560 if ( NULL
!= pErrno
) {
1563 DBG_EXIT_STATUS ( Status
);
1568 /** Connect to a remote system via the network.
1570 This routine calls the network specific layer to establish
1571 the remote system address and establish the connection to
1574 The ::connect routine calls this routine to establish a
1575 connection with the specified remote system. This routine
1576 is designed to be polled by the connect routine for completion
1577 of the network connection.
1579 @param[in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
1580 @param[in] pSockAddr Network address of the remote system.
1581 @param[in] SockAddrLength Length in bytes of the network address.
1582 @param[out] pErrno Address to receive the errno value upon completion.
1584 @retval EFI_SUCCESS The connection was successfully established.
1585 @retval EFI_NOT_READY The connection is in progress, call this routine again.
1586 @retval Others The connection attempt failed.
1590 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
1591 IN
const struct sockaddr
* pSockAddr
,
1592 IN socklen_t SockAddrLength
,
1596 struct sockaddr_in6 LocalAddress
;
1598 ESL_SOCKET
* pSocket
;
1600 EFI_TPL TplPrevious
;
1602 DEBUG (( DEBUG_CONNECT
, "Entering SocketConnect\r\n" ));
1607 Status
= EFI_SUCCESS
;
1610 // Validate the socket
1613 if ( NULL
!= pSocketProtocol
) {
1614 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
1617 // Validate the name length
1619 if ( SockAddrLength
< ( sizeof ( struct sockaddr
) - sizeof ( pSockAddr
->sa_data
))) {
1620 DEBUG (( DEBUG_CONNECT
,
1621 "ERROR - Invalid bind name length: %d\r\n",
1623 Status
= EFI_INVALID_PARAMETER
;
1624 pSocket
->errno
= EINVAL
;
1633 // Synchronize with the socket layer
1635 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
1638 // Validate the socket state
1640 switch ( pSocket
->State
) {
1643 // Wrong socket state
1645 pSocket
->errno
= EIO
;
1646 Status
= EFI_DEVICE_ERROR
;
1649 case SOCKET_STATE_NOT_CONFIGURED
:
1650 case SOCKET_STATE_BOUND
:
1652 // Validate the address length
1654 if ( SockAddrLength
>= pSocket
->pApi
->MinimumAddressLength
) {
1658 if ( NULL
== pSocket
->pApi
->pfnRemoteAddrSet
) {
1660 // Already connected
1662 pSocket
->errno
= ENOTSUP
;
1663 Status
= EFI_UNSUPPORTED
;
1667 // Determine if BIND was already called
1669 if ( NULL
== pSocket
->pPortList
) {
1671 // Allow any local port
1673 ZeroMem ( &LocalAddress
, sizeof ( LocalAddress
));
1674 LocalAddress
.sin6_len
= (uint8_t)pSocket
->pApi
->MinimumAddressLength
;
1675 LocalAddress
.sin6_family
= pSocket
->pApi
->AddressFamily
;
1676 Status
= EslSocketBind ( &pSocket
->SocketProtocol
,
1677 (struct sockaddr
*)&LocalAddress
,
1678 LocalAddress
.sin6_len
,
1681 if ( NULL
!= pSocket
->pPortList
) {
1683 // Walk the list of ports
1685 pPort
= pSocket
->pPortList
;
1686 while ( NULL
!= pPort
) {
1688 // Set the remote address
1690 Status
= pSocket
->pApi
->pfnRemoteAddrSet ( pPort
,
1693 if ( EFI_ERROR ( Status
)) {
1698 // Set the next port
1700 pPort
= pPort
->pLinkSocket
;
1706 if (( !EFI_ERROR ( Status
))
1707 && ( NULL
!= pSocket
->pApi
->pfnConnectStart
)) {
1709 // Initiate the connection with the remote system
1711 Status
= pSocket
->pApi
->pfnConnectStart ( pSocket
);
1714 // Set the next state if connecting
1716 if ( EFI_NOT_READY
== Status
) {
1717 pSocket
->State
= SOCKET_STATE_CONNECTING
;
1724 DEBUG (( DEBUG_CONNECT
,
1725 "ERROR - Invalid address length: %d\r\n",
1727 Status
= EFI_INVALID_PARAMETER
;
1728 pSocket
->errno
= EINVAL
;
1732 case SOCKET_STATE_CONNECTING
:
1734 // Poll the network adapter
1736 EslSocketRxPoll ( pSocket
);
1739 // Poll for connection completion
1741 if ( NULL
== pSocket
->pApi
->pfnConnectPoll
) {
1743 // Already connected
1745 pSocket
->errno
= EISCONN
;
1746 Status
= EFI_ALREADY_STARTED
;
1749 Status
= pSocket
->pApi
->pfnConnectPoll ( pSocket
);
1752 // Set the next state if connected
1754 if ( EFI_NOT_READY
!= Status
) {
1755 if ( EFI_ERROR ( Status
)) {
1756 pSocket
->State
= SOCKET_STATE_BOUND
;
1762 case SOCKET_STATE_CONNECTED
:
1766 Status
= EFI_SUCCESS
;
1771 // Release the socket layer synchronization
1773 RESTORE_TPL ( TplPrevious
);
1778 // Return the operation status
1780 if ( NULL
!= pErrno
) {
1781 if ( NULL
!= pSocket
) {
1782 *pErrno
= pSocket
->errno
;
1786 // Bad socket protocol
1788 DEBUG (( DEBUG_ERROR
| DEBUG_CONNECT
,
1789 "ERROR - pSocketProtocol invalid!\r\n" ));
1790 Status
= EFI_INVALID_PARAMETER
;
1796 // Return the operation status
1798 DEBUG (( DEBUG_CONNECT
, "Exiting SocketConnect, Status: %r\r\n", Status
));
1803 /** Copy a fragmented buffer into a destination buffer.
1805 This support routine copies a fragmented buffer to the caller specified buffer.
1807 This routine is called by ::EslIp4Receive and ::EslUdp4Receive.
1809 @param[in] FragmentCount Number of fragments in the table
1810 @param[in] pFragmentTable Address of an EFI_IP4_FRAGMENT_DATA structure
1811 @param[in] BufferLength Length of the the buffer
1812 @param[in] pBuffer Address of a buffer to receive the data.
1813 @param[in] pDataLength Number of received data bytes in the buffer.
1815 @return Returns the address of the next free byte in the buffer.
1818 EslSocketCopyFragmentedBuffer (
1819 IN UINT32 FragmentCount
,
1820 IN EFI_IP4_FRAGMENT_DATA
* pFragmentTable
,
1821 IN
size_t BufferLength
,
1823 OUT
size_t * pDataLength
1834 // Validate the IP and UDP structures are identical
1836 ASSERT ( OFFSET_OF ( EFI_IP4_FRAGMENT_DATA
, FragmentLength
)
1837 == OFFSET_OF ( EFI_UDP4_FRAGMENT_DATA
, FragmentLength
));
1838 ASSERT ( OFFSET_OF ( EFI_IP4_FRAGMENT_DATA
, FragmentBuffer
)
1839 == OFFSET_OF ( EFI_UDP4_FRAGMENT_DATA
, FragmentBuffer
));
1842 // Copy the received data
1845 pBufferEnd
= &pBuffer
[ BufferLength
];
1846 while (( pBufferEnd
> pBuffer
) && ( FragmentCount
> Fragment
)) {
1848 // Determine the amount of received data
1850 pData
= pFragmentTable
[Fragment
].FragmentBuffer
;
1851 BytesToCopy
= pFragmentTable
[Fragment
].FragmentLength
;
1852 if (((size_t)( pBufferEnd
- pBuffer
)) < BytesToCopy
) {
1853 BytesToCopy
= pBufferEnd
- pBuffer
;
1857 // Move the data into the buffer
1860 "0x%08x --> 0x%08x: Copy data 0x%08x bytes\r\n",
1864 CopyMem ( pBuffer
, pData
, BytesToCopy
);
1865 pBuffer
+= BytesToCopy
;
1870 // Return the data length and the buffer address
1872 *pDataLength
= BufferLength
- ( pBufferEnd
- pBuffer
);
1873 DBG_EXIT_HEX ( pBuffer
);
1878 /** Free the socket.
1880 This routine frees the socket structure and handle resources.
1882 The ::close routine calls EslServiceFreeProtocol which then calls
1883 this routine to free the socket context structure and close the
1886 @param[in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
1887 @param[out] pErrno Address to receive the errno value upon completion.
1889 @retval EFI_SUCCESS The socket resources were returned successfully.
1893 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
1897 EFI_HANDLE ChildHandle
;
1900 ESL_SOCKET
* pSocket
;
1901 ESL_SOCKET
* pSocketPrevious
;
1903 EFI_TPL TplPrevious
;
1912 Status
= EFI_INVALID_PARAMETER
;
1915 // Validate the socket
1917 pLayer
= &mEslLayer
;
1918 if ( NULL
!= pSocketProtocol
) {
1919 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
1922 // Synchronize with the socket layer
1924 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
1927 // Walk the socket list
1929 pSocketPrevious
= pLayer
->pSocketList
;
1930 if ( NULL
!= pSocketPrevious
) {
1931 if ( pSocket
== pSocketPrevious
) {
1933 // Remove the socket from the head of the list
1935 pLayer
->pSocketList
= pSocket
->pNext
;
1939 // Find the socket in the middle of the list
1941 while (( NULL
!= pSocketPrevious
)
1942 && ( pSocket
!= pSocketPrevious
->pNext
)) {
1944 // Set the next socket
1946 pSocketPrevious
= pSocketPrevious
->pNext
;
1948 if ( NULL
!= pSocketPrevious
) {
1950 // Remove the socket from the middle of the list
1952 pSocketPrevious
= pSocket
->pNext
;
1957 DEBUG (( DEBUG_ERROR
| DEBUG_POOL
,
1958 "ERROR - Socket list is empty!\r\n" ));
1962 // Release the socket layer synchronization
1964 RESTORE_TPL ( TplPrevious
);
1967 // Determine if the socket was found
1969 if ( NULL
!= pSocketPrevious
) {
1970 pSocket
->pNext
= NULL
;
1973 // Remove the socket protocol
1975 ChildHandle
= pSocket
->SocketProtocol
.SocketHandle
;
1976 Status
= gBS
->UninstallMultipleProtocolInterfaces (
1978 &gEfiSocketProtocolGuid
,
1979 &pSocket
->SocketProtocol
,
1981 if ( !EFI_ERROR ( Status
)) {
1982 DEBUG (( DEBUG_POOL
| DEBUG_INFO
,
1983 "Removed: gEfiSocketProtocolGuid from 0x%08x\r\n",
1987 // Free the socket structure
1989 Status
= gBS
->FreePool ( pSocket
);
1990 if ( !EFI_ERROR ( Status
)) {
1991 DEBUG (( DEBUG_POOL
,
1992 "0x%08x: Free pSocket, %d bytes\r\n",
1994 sizeof ( *pSocket
)));
1998 DEBUG (( DEBUG_ERROR
| DEBUG_POOL
,
1999 "ERROR - Failed to free pSocket 0x%08x, Status: %r\r\n",
2005 DEBUG (( DEBUG_ERROR
| DEBUG_POOL
| DEBUG_INFO
,
2006 "ERROR - Failed to remove gEfiSocketProtocolGuid from 0x%08x, Status: %r\r\n",
2012 DEBUG (( DEBUG_ERROR
| DEBUG_INFO
,
2013 "ERROR - The socket was not in the socket list!\r\n" ));
2014 Status
= EFI_NOT_FOUND
;
2018 DEBUG (( DEBUG_ERROR
,
2019 "ERROR - Invalid parameter pSocketProtocol is NULL\r\n" ));
2023 // Return the errno value if possible
2025 if ( NULL
!= pErrno
) {
2030 // Return the operation status
2032 DBG_EXIT_STATUS ( Status
);
2037 /** Get the local address.
2039 This routine calls the network specific layer to get the network
2040 address of the local host connection point.
2042 The ::getsockname routine calls this routine to obtain the network
2043 address associated with the local host connection point.
2045 @param[in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
2046 @param[out] pAddress Network address to receive the local system address
2047 @param[in,out] pAddressLength Length of the local network address structure
2048 @param[out] pErrno Address to receive the errno value upon completion.
2050 @retval EFI_SUCCESS - Local address successfully returned
2053 EslSocketGetLocalAddress (
2054 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
2055 OUT
struct sockaddr
* pAddress
,
2056 IN OUT socklen_t
* pAddressLength
,
2060 socklen_t LengthInBytes
;
2062 ESL_SOCKET
* pSocket
;
2064 EFI_TPL TplPrevious
;
2071 Status
= EFI_SUCCESS
;
2074 // Validate the socket
2077 if ( NULL
!= pSocketProtocol
) {
2078 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
2081 // Verify the socket state
2083 EslSocketIsConfigured ( pSocket
);
2084 if ( pSocket
->bAddressSet
) {
2086 // Verify the address buffer and length address
2088 if (( NULL
!= pAddress
) && ( NULL
!= pAddressLength
)) {
2092 if ( NULL
== pSocket
->pApi
->pfnLocalAddrGet
) {
2093 Status
= EFI_UNSUPPORTED
;
2094 pSocket
->errno
= ENOTSUP
;
2098 // Synchronize with the socket layer
2100 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
2103 // Verify that there is just a single connection
2105 pPort
= pSocket
->pPortList
;
2106 if ( NULL
!= pPort
) {
2108 // Verify the address length
2110 LengthInBytes
= pSocket
->pApi
->AddressLength
;
2111 if (( LengthInBytes
<= *pAddressLength
)
2112 && ( 255 >= LengthInBytes
)) {
2114 // Return the local address and address length
2116 ZeroMem ( pAddress
, LengthInBytes
);
2117 pAddress
->sa_len
= (uint8_t)LengthInBytes
;
2118 *pAddressLength
= pAddress
->sa_len
;
2119 pSocket
->pApi
->pfnLocalAddrGet ( pPort
, pAddress
);
2121 Status
= EFI_SUCCESS
;
2124 pSocket
->errno
= EINVAL
;
2125 Status
= EFI_INVALID_PARAMETER
;
2129 pSocket
->errno
= ENOTCONN
;
2130 Status
= EFI_NOT_STARTED
;
2134 // Release the socket layer synchronization
2136 RESTORE_TPL ( TplPrevious
);
2140 pSocket
->errno
= EINVAL
;
2141 Status
= EFI_INVALID_PARAMETER
;
2148 Status
= EFI_NOT_STARTED
;
2149 pSocket
->errno
= EADDRNOTAVAIL
;
2154 // Return the operation status
2156 if ( NULL
!= pErrno
) {
2157 if ( NULL
!= pSocket
) {
2158 *pErrno
= pSocket
->errno
;
2161 Status
= EFI_INVALID_PARAMETER
;
2165 DBG_EXIT_STATUS ( Status
);
2170 /** Get the peer address.
2172 This routine calls the network specific layer to get the remote
2173 system connection point.
2175 The ::getpeername routine calls this routine to obtain the network
2176 address of the remote connection point.
2178 @param[in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
2179 @param[out] pAddress Network address to receive the remote system address
2180 @param[in,out] pAddressLength Length of the remote network address structure
2181 @param[out] pErrno Address to receive the errno value upon completion.
2183 @retval EFI_SUCCESS - Remote address successfully returned
2186 EslSocketGetPeerAddress (
2187 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
2188 OUT
struct sockaddr
* pAddress
,
2189 IN OUT socklen_t
* pAddressLength
,
2193 socklen_t LengthInBytes
;
2195 ESL_SOCKET
* pSocket
;
2197 EFI_TPL TplPrevious
;
2204 Status
= EFI_SUCCESS
;
2207 // Validate the socket
2210 if ( NULL
!= pSocketProtocol
) {
2211 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
2214 // Verify the socket state
2216 Status
= EslSocketIsConfigured ( pSocket
);
2217 if ( !EFI_ERROR ( Status
)) {
2221 if ( NULL
== pSocket
->pApi
->pfnRemoteAddrGet
) {
2222 Status
= EFI_UNSUPPORTED
;
2223 pSocket
->errno
= ENOTSUP
;
2227 // Verify the address buffer and length address
2229 if (( NULL
!= pAddress
) && ( NULL
!= pAddressLength
)) {
2231 // Verify the socket state
2233 if ( SOCKET_STATE_CONNECTED
== pSocket
->State
) {
2235 // Synchronize with the socket layer
2237 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
2240 // Verify that there is just a single connection
2242 pPort
= pSocket
->pPortList
;
2243 if (( NULL
!= pPort
) && ( NULL
== pPort
->pLinkSocket
)) {
2245 // Verify the address length
2247 LengthInBytes
= pSocket
->pApi
->AddressLength
;
2248 if ( LengthInBytes
<= *pAddressLength
) {
2250 // Return the local address
2252 ZeroMem ( pAddress
, LengthInBytes
);
2253 pAddress
->sa_len
= (uint8_t)LengthInBytes
;
2254 *pAddressLength
= pAddress
->sa_len
;
2255 pSocket
->pApi
->pfnRemoteAddrGet ( pPort
, pAddress
);
2257 Status
= EFI_SUCCESS
;
2260 pSocket
->errno
= EINVAL
;
2261 Status
= EFI_INVALID_PARAMETER
;
2265 pSocket
->errno
= ENOTCONN
;
2266 Status
= EFI_NOT_STARTED
;
2270 // Release the socket layer synchronization
2272 RESTORE_TPL ( TplPrevious
);
2275 pSocket
->errno
= ENOTCONN
;
2276 Status
= EFI_NOT_STARTED
;
2280 pSocket
->errno
= EINVAL
;
2281 Status
= EFI_INVALID_PARAMETER
;
2288 // Return the operation status
2290 if ( NULL
!= pErrno
) {
2291 if ( NULL
!= pSocket
) {
2292 *pErrno
= pSocket
->errno
;
2295 Status
= EFI_INVALID_PARAMETER
;
2299 DBG_EXIT_STATUS ( Status
);
2304 /** Free the ESL_IO_MGMT event and structure.
2306 This support routine walks the free list to close the event in
2307 the ESL_IO_MGMT structure and remove the structure from the free
2310 See the \ref TransmitEngine section.
2312 @param[in] pPort Address of an ::ESL_PORT structure
2313 @param[in] ppFreeQueue Address of the free queue head
2314 @param[in] DebugFlags Flags for debug messages
2315 @param[in] pEventName Zero terminated string containing the event name
2317 @retval EFI_SUCCESS - The structures were properly initialized
2321 IN ESL_PORT
* pPort
,
2322 IN ESL_IO_MGMT
** ppFreeQueue
,
2323 IN UINTN DebugFlags
,
2324 IN CHAR8
* pEventName
2330 ESL_SOCKET
* pSocket
;
2338 Status
= EFI_SUCCESS
;
2341 // Walk the list of IO structures
2343 pSocket
= pPort
->pSocket
;
2344 while ( *ppFreeQueue
) {
2346 // Free the event for this structure
2349 pBuffer
= (UINT8
*)pIo
;
2350 pBuffer
= &pBuffer
[ pSocket
->TxTokenEventOffset
];
2351 pEvent
= (EFI_EVENT
*)pBuffer
;
2352 Status
= gBS
->CloseEvent ( *pEvent
);
2353 if ( EFI_ERROR ( Status
)) {
2354 DEBUG (( DEBUG_ERROR
| DebugFlags
,
2355 "ERROR - Failed to close the %a event, Status: %r\r\n",
2358 pSocket
->errno
= ENOMEM
;
2361 DEBUG (( DebugFlags
,
2362 "0x%08x: Closed %a event 0x%08x\r\n",
2368 // Remove this structure from the queue
2370 *ppFreeQueue
= pIo
->pNext
;
2374 // Return the operation status
2376 DBG_EXIT_STATUS ( Status
);
2381 /** Initialize the ESL_IO_MGMT structures.
2383 This support routine initializes the ESL_IO_MGMT structure and
2384 places them on to a free list.
2386 This routine is called by ::EslSocketPortAllocate routines to prepare
2387 the transmit engines. See the \ref TransmitEngine section.
2389 @param[in] pPort Address of an ::ESL_PORT structure
2390 @param[in, out] ppIo Address containing the first structure address. Upon
2391 return this buffer contains the next structure address.
2392 @param[in] TokenCount Number of structures to initialize
2393 @param[in] ppFreeQueue Address of the free queue head
2394 @param[in] DebugFlags Flags for debug messages
2395 @param[in] pEventName Zero terminated string containing the event name
2396 @param[in] pfnCompletion Completion routine address
2398 @retval EFI_SUCCESS - The structures were properly initialized
2402 IN ESL_PORT
* pPort
,
2403 IN ESL_IO_MGMT
** ppIo
,
2404 IN UINTN TokenCount
,
2405 IN ESL_IO_MGMT
** ppFreeQueue
,
2406 IN UINTN DebugFlags
,
2407 IN CHAR8
* pEventName
,
2408 IN PFN_API_IO_COMPLETE pfnCompletion
2414 ESL_SOCKET
* pSocket
;
2422 Status
= EFI_SUCCESS
;
2425 // Walk the list of IO structures
2427 pSocket
= pPort
->pSocket
;
2429 pEnd
= &pIo
[ TokenCount
];
2430 while ( pEnd
> pIo
) {
2432 // Initialize the IO structure
2435 pIo
->pPacket
= NULL
;
2438 // Allocate the event for this structure
2440 pEvent
= (EFI_EVENT
*)&(((UINT8
*)pIo
)[ pSocket
->TxTokenEventOffset
]);
2441 Status
= gBS
->CreateEvent ( EVT_NOTIFY_SIGNAL
,
2443 (EFI_EVENT_NOTIFY
)pfnCompletion
,
2446 if ( EFI_ERROR ( Status
)) {
2447 DEBUG (( DEBUG_ERROR
| DebugFlags
,
2448 "ERROR - Failed to create the %a event, Status: %r\r\n",
2451 pSocket
->errno
= ENOMEM
;
2454 DEBUG (( DebugFlags
,
2455 "0x%08x: Created %a event 0x%08x\r\n",
2461 // Add this structure to the queue
2463 pIo
->pNext
= *ppFreeQueue
;
2467 // Set the next structure
2473 // Save the next structure
2478 // Return the operation status
2480 DBG_EXIT_STATUS ( Status
);
2485 /** Determine if the socket is configured.
2487 This support routine is called to determine if the socket if the
2488 configuration call was made to the network layer. The following
2489 routines call this routine to verify that they may be successful
2490 in their operations:
2492 <li>::EslSocketGetLocalAddress</li>
2493 <li>::EslSocketGetPeerAddress</li>
2494 <li>::EslSocketPoll</li>
2495 <li>::EslSocketReceive</li>
2496 <li>::EslSocketTransmit</li>
2499 @param[in] pSocket Address of an ::ESL_SOCKET structure
2501 @retval EFI_SUCCESS - The socket is configured
2504 EslSocketIsConfigured (
2505 IN ESL_SOCKET
* pSocket
2509 EFI_TPL TplPrevious
;
2514 Status
= EFI_SUCCESS
;
2517 // Verify the socket state
2519 if ( !pSocket
->bConfigured
) {
2525 if ( NULL
== pSocket
->pApi
->pfnIsConfigured
) {
2526 Status
= EFI_UNSUPPORTED
;
2527 pSocket
->errno
= ENOTSUP
;
2531 // Synchronize with the socket layer
2533 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
2536 // Determine if the socket is configured
2538 Status
= pSocket
->pApi
->pfnIsConfigured ( pSocket
);
2541 // Release the socket layer synchronization
2543 RESTORE_TPL ( TplPrevious
);
2546 // Set errno if a failure occurs
2548 if ( EFI_ERROR ( Status
)) {
2549 pSocket
->errno
= EADDRNOTAVAIL
;
2553 DBG_EXIT_STATUS ( Status
);
2557 // Return the configuration status
2563 /** Establish the known port to listen for network connections.
2565 This routine calls into the network protocol layer to establish
2566 a handler that is called upon connection completion. The handler
2567 is responsible for inserting the connection into the FIFO.
2569 The ::listen routine indirectly calls this routine to place the
2570 socket into a state that enables connection attempts. Connections
2571 are placed in a FIFO that is serviced by the application. The
2572 application calls the ::accept (::EslSocketAccept) routine to
2573 remove the next connection from the FIFO and get the associated
2576 @param[in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
2577 @param[in] Backlog Backlog specifies the maximum FIFO depth for
2578 the connections waiting for the application
2579 to call accept. Connection attempts received
2580 while the queue is full are refused.
2581 @param[out] pErrno Address to receive the errno value upon completion.
2583 @retval EFI_SUCCESS - Socket successfully created
2584 @retval Other - Failed to enable the socket for listen
2588 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
2593 ESL_SOCKET
* pSocket
;
2595 EFI_STATUS TempStatus
;
2596 EFI_TPL TplPrevious
;
2603 Status
= EFI_SUCCESS
;
2606 // Validate the socket
2609 if ( NULL
!= pSocketProtocol
) {
2610 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
2615 if ( NULL
== pSocket
->pApi
->pfnListen
) {
2616 Status
= EFI_UNSUPPORTED
;
2617 pSocket
->errno
= ENOTSUP
;
2623 pSocket
->Status
= EFI_SUCCESS
;
2627 // Verify that the bind operation was successful
2629 if ( SOCKET_STATE_BOUND
== pSocket
->State
) {
2631 // Synchronize with the socket layer
2633 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
2636 // Create the event for SocketAccept completion
2638 Status
= gBS
->CreateEvent ( 0,
2642 &pSocket
->WaitAccept
);
2643 if ( !EFI_ERROR ( Status
)) {
2644 DEBUG (( DEBUG_POOL
,
2645 "0x%08x: Created WaitAccept event\r\n",
2646 pSocket
->WaitAccept
));
2648 // Set the maximum FIFO depth
2650 if ( 0 >= Backlog
) {
2651 Backlog
= MAX_PENDING_CONNECTIONS
;
2654 if ( SOMAXCONN
< Backlog
) {
2655 Backlog
= SOMAXCONN
;
2658 pSocket
->MaxFifoDepth
= Backlog
;
2663 // Initiate the connection attempt listen
2665 Status
= pSocket
->pApi
->pfnListen ( pSocket
);
2668 // Place the socket in the listen state if successful
2670 if ( !EFI_ERROR ( Status
)) {
2671 pSocket
->State
= SOCKET_STATE_LISTENING
;
2672 pSocket
->bListenCalled
= TRUE
;
2676 // Not waiting for SocketAccept to complete
2678 TempStatus
= gBS
->CloseEvent ( pSocket
->WaitAccept
);
2679 if ( !EFI_ERROR ( TempStatus
)) {
2680 DEBUG (( DEBUG_POOL
,
2681 "0x%08x: Closed WaitAccept event\r\n",
2682 pSocket
->WaitAccept
));
2683 pSocket
->WaitAccept
= NULL
;
2686 DEBUG (( DEBUG_ERROR
| DEBUG_POOL
,
2687 "ERROR - Failed to close WaitAccept event, Status: %r\r\n",
2689 ASSERT ( EFI_SUCCESS
== TempStatus
);
2694 DEBUG (( DEBUG_ERROR
| DEBUG_LISTEN
,
2695 "ERROR - Failed to create the WaitAccept event, Status: %r\r\n",
2697 pSocket
->errno
= ENOMEM
;
2701 // Release the socket layer synchronization
2703 RESTORE_TPL ( TplPrevious
);
2706 DEBUG (( DEBUG_ERROR
| DEBUG_LISTEN
,
2707 "ERROR - Bind operation must be performed first!\r\n" ));
2708 pSocket
->errno
= ( SOCKET_STATE_NOT_CONFIGURED
== pSocket
->State
) ? EDESTADDRREQ
2710 Status
= EFI_NO_MAPPING
;
2716 // Return the operation status
2718 if ( NULL
!= pErrno
) {
2719 if ( NULL
!= pSocket
) {
2720 *pErrno
= pSocket
->errno
;
2723 Status
= EFI_INVALID_PARAMETER
;
2727 DBG_EXIT_STATUS ( Status
);
2732 /** Get the socket options.
2734 This routine handles the socket level options and passes the
2735 others to the network specific layer.
2737 The ::getsockopt routine calls this routine to retrieve the
2738 socket options one at a time by name.
2740 @param[in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
2741 @param[in] level Option protocol level
2742 @param[in] OptionName Name of the option
2743 @param[out] pOptionValue Buffer to receive the option value
2744 @param[in,out] pOptionLength Length of the buffer in bytes,
2745 upon return length of the option value in bytes
2746 @param[out] pErrno Address to receive the errno value upon completion.
2748 @retval EFI_SUCCESS - Socket data successfully received
2751 EslSocketOptionGet (
2752 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
2755 OUT
void * __restrict pOptionValue
,
2756 IN OUT socklen_t
* __restrict pOptionLength
,
2761 socklen_t LengthInBytes
;
2763 CONST UINT8
* pOptionData
;
2764 ESL_SOCKET
* pSocket
;
2773 Status
= EFI_INVALID_PARAMETER
;
2776 // Validate the socket
2779 if ( NULL
== pSocketProtocol
) {
2780 DEBUG (( DEBUG_OPTION
, "ERROR - pSocketProtocol is NULL!\r\n" ));
2782 else if ( NULL
== pOptionValue
) {
2783 DEBUG (( DEBUG_OPTION
, "ERROR - No option buffer specified\r\n" ));
2785 else if ( NULL
== pOptionLength
) {
2786 DEBUG (( DEBUG_OPTION
, "ERROR - Option length not specified!\r\n" ));
2789 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
2791 MaxBytes
= *pOptionLength
;
2796 // See if the protocol will handle the option
2798 if ( NULL
!= pSocket
->pApi
->pfnOptionGet
) {
2799 if ( pSocket
->pApi
->DefaultProtocol
== level
) {
2800 Status
= pSocket
->pApi
->pfnOptionGet ( pSocket
,
2802 (CONST
void ** __restrict
)&pOptionData
,
2804 errno
= pSocket
->errno
;
2809 // Protocol not supported
2811 DEBUG (( DEBUG_OPTION
,
2812 "ERROR - The socket does not support this protocol!\r\n" ));
2817 // Protocol level not supported
2819 DEBUG (( DEBUG_OPTION
,
2820 "ERROR - %a does not support any options!\r\n",
2821 pSocket
->pApi
->pName
));
2823 errno
= ENOPROTOOPT
;
2824 Status
= EFI_INVALID_PARAMETER
;
2828 switch ( OptionName
) {
2831 // Socket option not supported
2833 DEBUG (( DEBUG_INFO
| DEBUG_OPTION
, "ERROR - Invalid socket option!\r\n" ));
2835 Status
= EFI_INVALID_PARAMETER
;
2840 // Return the listen flag
2842 pOptionData
= (CONST UINT8
*)&pSocket
->bListenCalled
;
2843 LengthInBytes
= sizeof ( pSocket
->bListenCalled
);
2848 // Return the debug flags
2850 pOptionData
= (CONST UINT8
*)&pSocket
->bOobInLine
;
2851 LengthInBytes
= sizeof ( pSocket
->bOobInLine
);
2856 // Return the out-of-band inline flag
2858 pOptionData
= (CONST UINT8
*)&pSocket
->bOobInLine
;
2859 LengthInBytes
= sizeof ( pSocket
->bOobInLine
);
2864 // Return the receive timeout
2866 pOptionData
= (CONST UINT8
*)&pSocket
->RxTimeout
;
2867 LengthInBytes
= sizeof ( pSocket
->RxTimeout
);
2872 // Return the maximum receive buffer size
2874 pOptionData
= (CONST UINT8
*)&pSocket
->MaxRxBuf
;
2875 LengthInBytes
= sizeof ( pSocket
->MaxRxBuf
);
2880 // Return the address reuse flag
2882 pOptionData
= (UINT8
*)&pSocket
->bReUseAddr
;
2883 LengthInBytes
= sizeof ( pSocket
->bReUseAddr
);
2888 // Return the maximum transmit buffer size
2890 pOptionData
= (CONST UINT8
*)&pSocket
->MaxTxBuf
;
2891 LengthInBytes
= sizeof ( pSocket
->MaxTxBuf
);
2896 // Return the socket type
2898 pOptionData
= (CONST UINT8
*)&pSocket
->Type
;
2899 LengthInBytes
= sizeof ( pSocket
->Type
);
2906 // Return the option length
2908 *pOptionLength
= LengthInBytes
;
2911 // Determine if the option is present
2913 if ( 0 != LengthInBytes
) {
2915 // Silently truncate the value length
2917 if ( LengthInBytes
> MaxBytes
) {
2918 DEBUG (( DEBUG_OPTION
,
2919 "INFO - Truncating option from %d to %d bytes\r\n",
2922 LengthInBytes
= MaxBytes
;
2928 CopyMem ( pOptionValue
, pOptionData
, LengthInBytes
);
2931 // Zero fill any remaining space
2933 if ( LengthInBytes
< MaxBytes
) {
2934 ZeroMem ( &((UINT8
*)pOptionValue
)[LengthInBytes
], MaxBytes
- LengthInBytes
);
2937 Status
= EFI_SUCCESS
;
2942 // Return the operation status
2944 if ( NULL
!= pErrno
) {
2947 DBG_EXIT_STATUS ( Status
);
2952 /** Set the socket options.
2954 This routine handles the socket level options and passes the
2955 others to the network specific layer.
2957 The ::setsockopt routine calls this routine to adjust the socket
2958 options one at a time by name.
2960 @param[in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
2961 @param[in] level Option protocol level
2962 @param[in] OptionName Name of the option
2963 @param[in] pOptionValue Buffer containing the option value
2964 @param[in] OptionLength Length of the buffer in bytes
2965 @param[out] pErrno Address to receive the errno value upon completion.
2967 @retval EFI_SUCCESS - Option successfully set
2970 EslSocketOptionSet (
2971 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
2974 IN CONST
void * pOptionValue
,
2975 IN socklen_t OptionLength
,
2981 socklen_t LengthInBytes
;
2982 UINT8
* pOptionData
;
2983 ESL_SOCKET
* pSocket
;
2992 Status
= EFI_INVALID_PARAMETER
;
2995 // Validate the socket
2998 if ( NULL
== pSocketProtocol
) {
2999 DEBUG (( DEBUG_OPTION
, "ERROR - pSocketProtocol is NULL!\r\n" ));
3001 else if ( NULL
== pOptionValue
) {
3002 DEBUG (( DEBUG_OPTION
, "ERROR - No option buffer specified\r\n" ));
3006 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
3007 if ( pSocket
->bRxDisable
|| pSocket
->bTxDisable
) {
3008 DEBUG (( DEBUG_OPTION
, "ERROR - Socket has been shutdown!\r\n" ));
3016 // See if the protocol will handle the option
3018 if ( NULL
!= pSocket
->pApi
->pfnOptionSet
) {
3019 if ( pSocket
->pApi
->DefaultProtocol
== level
) {
3020 Status
= pSocket
->pApi
->pfnOptionSet ( pSocket
,
3024 errno
= pSocket
->errno
;
3029 // Protocol not supported
3031 DEBUG (( DEBUG_OPTION
,
3032 "ERROR - The socket does not support this protocol!\r\n" ));
3037 // Protocol level not supported
3039 DEBUG (( DEBUG_OPTION
,
3040 "ERROR - %a does not support any options!\r\n",
3041 pSocket
->pApi
->pName
));
3043 errno
= ENOPROTOOPT
;
3044 Status
= EFI_INVALID_PARAMETER
;
3048 switch ( OptionName
) {
3051 // Option not supported
3053 DEBUG (( DEBUG_OPTION
,
3054 "ERROR - Sockets does not support this option!\r\n" ));
3056 Status
= EFI_INVALID_PARAMETER
;
3061 // Set the debug flags
3063 pOptionData
= (UINT8
*)&pSocket
->bOobInLine
;
3064 LengthInBytes
= sizeof ( pSocket
->bOobInLine
);
3068 pOptionData
= (UINT8
*)&pSocket
->bOobInLine
;
3069 LengthInBytes
= sizeof ( pSocket
->bOobInLine
);
3072 // Validate the option length
3074 if ( sizeof ( UINT32
) == OptionLength
) {
3076 // Restrict the input to TRUE or FALSE
3079 if ( 0 == *(UINT32
*)pOptionValue
) {
3082 pOptionValue
= &bTrueFalse
;
3086 // Force an invalid option length error
3088 OptionLength
= LengthInBytes
- 1;
3094 // Return the receive timeout
3096 pOptionData
= (UINT8
*)&pSocket
->RxTimeout
;
3097 LengthInBytes
= sizeof ( pSocket
->RxTimeout
);
3102 // Return the maximum receive buffer size
3104 pOptionData
= (UINT8
*)&pSocket
->MaxRxBuf
;
3105 LengthInBytes
= sizeof ( pSocket
->MaxRxBuf
);
3110 // Return the address reuse flag
3112 pOptionData
= (UINT8
*)&pSocket
->bReUseAddr
;
3113 LengthInBytes
= sizeof ( pSocket
->bReUseAddr
);
3121 // Return the maximum transmit buffer size
3123 pOptionData
= (UINT8
*)&pSocket
->MaxTxBuf
;
3124 LengthInBytes
= sizeof ( pSocket
->MaxTxBuf
);
3131 // Determine if an option was found
3133 if ( 0 != LengthInBytes
) {
3135 // Validate the option length
3137 if ( LengthInBytes
<= OptionLength
) {
3139 // Set the option value
3141 CopyMem ( pOptionData
, pOptionValue
, LengthInBytes
);
3143 Status
= EFI_SUCCESS
;
3146 DEBUG (( DEBUG_OPTION
,
3147 "ERROR - Buffer to small, %d bytes < %d bytes!\r\n",
3156 // Return the operation status
3158 if ( NULL
!= pErrno
) {
3161 DBG_EXIT_STATUS ( Status
);
3166 /** Allocate a packet for a receive or transmit operation.
3168 This support routine is called by ::EslSocketRxStart and the
3169 network specific TxBuffer routines to get buffer space for the
3172 @param[in] ppPacket Address to receive the ::ESL_PACKET structure
3173 @param[in] LengthInBytes Length of the packet structure
3174 @param[in] ZeroBytes Length of packet to zero
3175 @param[in] DebugFlags Flags for debug messages
3177 @retval EFI_SUCCESS - The packet was allocated successfully
3180 EslSocketPacketAllocate (
3181 IN ESL_PACKET
** ppPacket
,
3182 IN
size_t LengthInBytes
,
3183 IN
size_t ZeroBytes
,
3187 ESL_PACKET
* pPacket
;
3193 // Allocate a packet structure
3195 LengthInBytes
+= sizeof ( *pPacket
)
3196 - sizeof ( pPacket
->Op
);
3197 Status
= gBS
->AllocatePool ( EfiRuntimeServicesData
,
3199 (VOID
**)&pPacket
);
3200 if ( !EFI_ERROR ( Status
)) {
3201 DEBUG (( DebugFlags
| DEBUG_POOL
,
3202 "0x%08x: Allocate pPacket, %d bytes\r\n",
3205 if ( 0 != ZeroBytes
) {
3206 ZeroMem ( &pPacket
->Op
, ZeroBytes
);
3208 pPacket
->PacketSize
= LengthInBytes
;
3211 DEBUG (( DebugFlags
| DEBUG_POOL
| DEBUG_INFO
,
3212 "ERROR - Packet allocation failed for %d bytes, Status: %r\r\n",
3219 // Return the packet
3221 *ppPacket
= pPacket
;
3224 // Return the operation status
3226 DBG_EXIT_STATUS ( Status
);
3231 /** Free a packet used for receive or transmit operation.
3233 This support routine is called by the network specific Close
3234 and TxComplete routines and during error cases in RxComplete
3235 and TxBuffer. Note that the network layers typically place
3236 receive packets on the ESL_SOCKET::pRxFree list for reuse.
3238 @param[in] pPacket Address of an ::ESL_PACKET structure
3239 @param[in] DebugFlags Flags for debug messages
3241 @retval EFI_SUCCESS - The packet was allocated successfully
3244 EslSocketPacketFree (
3245 IN ESL_PACKET
* pPacket
,
3249 UINTN LengthInBytes
;
3255 // Free a packet structure
3257 LengthInBytes
= pPacket
->PacketSize
;
3258 Status
= gBS
->FreePool ( pPacket
);
3259 if ( !EFI_ERROR ( Status
)) {
3260 DEBUG (( DebugFlags
| DEBUG_POOL
,
3261 "0x%08x: Free pPacket, %d bytes\r\n",
3266 DEBUG (( DebugFlags
| DEBUG_POOL
| DEBUG_INFO
,
3267 "ERROR - Failed to free packet 0x%08x, Status: %r\r\n",
3273 // Return the operation status
3275 DBG_EXIT_STATUS ( Status
);
3280 /** Poll a socket for pending activity.
3282 This routine builds a detected event mask which is returned to
3283 the caller in the buffer provided.
3285 The ::poll routine calls this routine to determine if the socket
3286 needs to be serviced as a result of connection, error, receive or
3289 @param[in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
3290 @param[in] Events Events of interest for this socket
3291 @param[in] pEvents Address to receive the detected events
3292 @param[out] pErrno Address to receive the errno value upon completion.
3294 @retval EFI_SUCCESS - Socket successfully polled
3295 @retval EFI_INVALID_PARAMETER - When pEvents is NULL
3299 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
3305 short DetectedEvents
;
3306 ESL_SOCKET
* pSocket
;
3308 EFI_TPL TplPrevious
;
3310 int _errno
= EINVAL
;
3312 DEBUG (( DEBUG_POLL
, "Entering SocketPoll\r\n" ));
3317 Status
= EFI_SUCCESS
;
3319 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
3323 // Verify the socket state
3325 Status
= EslSocketIsConfigured ( pSocket
);
3326 if ( !EFI_ERROR ( Status
)) {
3328 // Check for invalid events
3330 ValidEvents
= POLLIN
3332 | POLLOUT
| POLLWRNORM
3339 if ( 0 != ( Events
& ( ~ValidEvents
))) {
3340 DetectedEvents
|= POLLNVAL
;
3341 DEBUG (( DEBUG_INFO
| DEBUG_POLL
,
3342 "ERROR - Invalid event mask, Valid Events: 0x%04x, Invalid Events: 0x%04x\r\n",
3343 Events
& ValidEvents
,
3344 Events
& ( ~ValidEvents
)));
3348 // Synchronize with the socket layer
3350 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
3353 // Increase the network performance by extending the
3354 // polling (idle) loop down into the LAN driver
3356 EslSocketRxPoll ( pSocket
);
3359 // Release the socket layer synchronization
3361 RESTORE_TPL ( TplPrevious
);
3364 // Check for pending connections
3366 if ( 0 != pSocket
->FifoDepth
) {
3368 // A connection is waiting for an accept call
3369 // See posix connect documentation at
3370 // http://pubs.opengroup.org/onlinepubs/9699919799/functions/accept.htm
3372 DetectedEvents
|= POLLIN
| POLLRDNORM
;
3374 if ( pSocket
->bConnected
) {
3376 // A connection is present
3377 // See posix connect documentation at
3378 // http://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.htm
3380 DetectedEvents
|= POLLOUT
| POLLWRNORM
;
3384 // The following bits are set based upon the POSIX poll documentation at
3385 // http://pubs.opengroup.org/onlinepubs/9699919799/functions/poll.html
3389 // Check for urgent receive data
3391 if ( 0 < pSocket
->RxOobBytes
) {
3392 DetectedEvents
|= POLLRDBAND
| POLLPRI
| POLLIN
;
3396 // Check for normal receive data
3398 if (( 0 < pSocket
->RxBytes
)
3399 || ( EFI_SUCCESS
!= pSocket
->RxError
)) {
3400 DetectedEvents
|= POLLRDNORM
| POLLIN
;
3404 // Handle the receive errors
3406 if (( EFI_SUCCESS
!= pSocket
->RxError
)
3407 && ( 0 == ( DetectedEvents
& POLLIN
))) {
3408 DetectedEvents
|= POLLERR
| POLLIN
| POLLRDNORM
| POLLRDBAND
;
3412 // Check for urgent transmit data buffer space
3414 if (( MAX_TX_DATA
> pSocket
->TxOobBytes
)
3415 || ( EFI_SUCCESS
!= pSocket
->TxError
)) {
3416 DetectedEvents
|= POLLWRBAND
;
3420 // Check for normal transmit data buffer space
3422 if (( MAX_TX_DATA
> pSocket
->TxBytes
)
3423 || ( EFI_SUCCESS
!= pSocket
->TxError
)) {
3424 DetectedEvents
|= POLLWRNORM
;
3428 // Handle the transmit error
3430 if ( EFI_ERROR ( pSocket
->TxError
)) {
3431 DetectedEvents
|= POLLERR
;
3433 _errno
= pSocket
->errno
;
3438 // Return the detected events
3440 *pEvents
= DetectedEvents
& ( Events
3444 if ( NULL
!= pErrno
) {
3448 // Return the operation status
3450 DEBUG (( DEBUG_POLL
, "Exiting SocketPoll, Status: %r\r\n", Status
));
3455 /** Allocate and initialize a ESL_PORT structure.
3457 This routine initializes an ::ESL_PORT structure for use by
3458 the socket. This routine calls a routine via
3459 ESL_PROTOCOL_API::pfnPortAllocate to initialize the network
3460 specific resources. The resources are released later by the
3461 \ref PortCloseStateMachine.
3463 This support routine is called by:
3465 <li>::EslSocketBind</li>
3466 <li>::EslTcp4ListenComplete</li>
3468 to connect the socket with the underlying network adapter
3471 @param[in] pSocket Address of an ::ESL_SOCKET structure.
3472 @param[in] pService Address of an ::ESL_SERVICE structure.
3473 @param[in] ChildHandle Network protocol child handle
3474 @param[in] pSockAddr Address of a sockaddr structure that contains the
3475 connection point on the local machine. An IPv4 address
3476 of INADDR_ANY specifies that the connection is made to
3477 all of the network stacks on the platform. Specifying a
3478 specific IPv4 address restricts the connection to the
3479 network stack supporting that address. Specifying zero
3480 for the port causes the network layer to assign a port
3481 number from the dynamic range. Specifying a specific
3482 port number causes the network layer to use that port.
3483 @param[in] bBindTest TRUE if EslSocketBindTest should be called
3484 @param[in] DebugFlags Flags for debug messages
3485 @param[out] ppPort Buffer to receive new ::ESL_PORT structure address
3487 @retval EFI_SUCCESS - Socket successfully created
3490 EslSocketPortAllocate (
3491 IN ESL_SOCKET
* pSocket
,
3492 IN ESL_SERVICE
* pService
,
3493 IN EFI_HANDLE ChildHandle
,
3494 IN CONST
struct sockaddr
* pSockAddr
,
3495 IN BOOLEAN bBindTest
,
3496 IN UINTN DebugFlags
,
3497 OUT ESL_PORT
** ppPort
3500 UINTN LengthInBytes
;
3505 EFI_SERVICE_BINDING_PROTOCOL
* pServiceBinding
;
3506 CONST ESL_SOCKET_BINDING
* pSocketBinding
;
3508 EFI_STATUS TempStatus
;
3513 // Verify the socket layer synchronization
3515 VERIFY_TPL ( TPL_SOCKETS
);
3518 // Use for/break instead of goto
3519 pSocketBinding
= pService
->pSocketBinding
;
3522 // Allocate a port structure
3524 pLayer
= &mEslLayer
;
3525 LengthInBytes
= sizeof ( *pPort
)
3526 + ESL_STRUCTURE_ALIGNMENT_BYTES
3527 + (( pSocketBinding
->RxIo
3528 + pSocketBinding
->TxIoNormal
3529 + pSocketBinding
->TxIoUrgent
)
3530 * sizeof ( ESL_IO_MGMT
));
3531 pPort
= (ESL_PORT
*) AllocateZeroPool ( LengthInBytes
);
3532 if ( NULL
== pPort
) {
3533 Status
= EFI_OUT_OF_RESOURCES
;
3534 pSocket
->errno
= ENOMEM
;
3537 DEBUG (( DebugFlags
| DEBUG_POOL
| DEBUG_INIT
,
3538 "0x%08x: Allocate pPort, %d bytes\r\n",
3543 // Initialize the port
3545 pPort
->DebugFlags
= DebugFlags
;
3546 pPort
->Handle
= ChildHandle
;
3547 pPort
->pService
= pService
;
3548 pPort
->pServiceBinding
= pService
->pServiceBinding
;
3549 pPort
->pSocket
= pSocket
;
3550 pPort
->pSocketBinding
= pService
->pSocketBinding
;
3551 pPort
->Signature
= PORT_SIGNATURE
;
3554 // Open the port protocol
3556 Status
= gBS
->OpenProtocol ( pPort
->Handle
,
3557 pSocketBinding
->pNetworkProtocolGuid
,
3558 &pPort
->pProtocol
.v
,
3559 pLayer
->ImageHandle
,
3561 EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL
);
3562 if ( EFI_ERROR ( Status
)) {
3563 DEBUG (( DEBUG_ERROR
| DebugFlags
,
3564 "ERROR - Failed to open network protocol GUID on controller 0x%08x\r\n",
3566 pSocket
->errno
= EEXIST
;
3569 DEBUG (( DebugFlags
,
3570 "0x%08x: Network protocol GUID opened on controller 0x%08x\r\n",
3575 // Initialize the port specific resources
3577 Status
= pSocket
->pApi
->pfnPortAllocate ( pPort
,
3579 if ( EFI_ERROR ( Status
)) {
3584 // Set the local address
3586 Status
= pSocket
->pApi
->pfnLocalAddrSet ( pPort
, pSockAddr
, bBindTest
);
3587 if ( EFI_ERROR ( Status
)) {
3592 // Test the address/port configuration
3595 Status
= EslSocketBindTest ( pPort
, pSocket
->pApi
->BindTestErrno
);
3596 if ( EFI_ERROR ( Status
)) {
3602 // Initialize the receive structures
3604 pBuffer
= (UINT8
*)&pPort
[ 1 ];
3605 pBuffer
= &pBuffer
[ ESL_STRUCTURE_ALIGNMENT_BYTES
];
3606 pBuffer
= (UINT8
*)( ESL_STRUCTURE_ALIGNMENT_MASK
& (UINTN
)pBuffer
);
3607 pIo
= (ESL_IO_MGMT
*)pBuffer
;
3608 if (( 0 != pSocketBinding
->RxIo
)
3609 && ( NULL
!= pSocket
->pApi
->pfnRxComplete
)) {
3610 Status
= EslSocketIoInit ( pPort
,
3612 pSocketBinding
->RxIo
,
3614 DebugFlags
| DEBUG_POOL
,
3616 pSocket
->pApi
->pfnRxComplete
);
3617 if ( EFI_ERROR ( Status
)) {
3623 // Initialize the urgent transmit structures
3625 if (( 0 != pSocketBinding
->TxIoUrgent
)
3626 && ( NULL
!= pSocket
->pApi
->pfnTxOobComplete
)) {
3627 Status
= EslSocketIoInit ( pPort
,
3629 pSocketBinding
->TxIoUrgent
,
3631 DebugFlags
| DEBUG_POOL
,
3633 pSocket
->pApi
->pfnTxOobComplete
);
3634 if ( EFI_ERROR ( Status
)) {
3640 // Initialize the normal transmit structures
3642 if (( 0 != pSocketBinding
->TxIoNormal
)
3643 && ( NULL
!= pSocket
->pApi
->pfnTxComplete
)) {
3644 Status
= EslSocketIoInit ( pPort
,
3646 pSocketBinding
->TxIoNormal
,
3648 DebugFlags
| DEBUG_POOL
,
3650 pSocket
->pApi
->pfnTxComplete
);
3651 if ( EFI_ERROR ( Status
)) {
3657 // Add this port to the socket
3659 pPort
->pLinkSocket
= pSocket
->pPortList
;
3660 pSocket
->pPortList
= pPort
;
3661 DEBUG (( DebugFlags
,
3662 "0x%08x: Socket adding port: 0x%08x\r\n",
3667 // Add this port to the service
3669 pPort
->pLinkService
= pService
->pPortList
;
3670 pService
->pPortList
= pPort
;
3680 // Clean up after the error if necessary
3682 if ( EFI_ERROR ( Status
)) {
3683 if ( NULL
!= pPort
) {
3687 EslSocketPortClose ( pPort
);
3691 // Close the port if necessary
3693 pServiceBinding
= pService
->pServiceBinding
;
3694 TempStatus
= pServiceBinding
->DestroyChild ( pServiceBinding
,
3696 if ( !EFI_ERROR ( TempStatus
)) {
3697 DEBUG (( DEBUG_BIND
| DEBUG_POOL
,
3698 "0x%08x: %s port handle destroyed\r\n",
3700 pSocketBinding
->pName
));
3703 DEBUG (( DEBUG_ERROR
| DEBUG_BIND
| DEBUG_POOL
,
3704 "ERROR - Failed to destroy the %s port handle 0x%08x, Status: %r\r\n",
3705 pSocketBinding
->pName
,
3708 ASSERT ( EFI_SUCCESS
== TempStatus
);
3713 // Return the operation status
3715 DBG_EXIT_STATUS ( Status
);
3722 This routine releases the resources allocated by ::EslSocketPortAllocate.
3723 This routine calls ESL_PROTOCOL_API::pfnPortClose to release the network
3726 This routine is called by:
3728 <li>::EslSocketPortAllocate - Port initialization failure</li>
3729 <li>::EslSocketPortCloseRxDone - Last step of close processing</li>
3730 <li>::EslTcp4ConnectComplete - Connection failure and reducing the port list to a single port</li>
3732 See the \ref PortCloseStateMachine section.
3734 @param[in] pPort Address of an ::ESL_PORT structure.
3736 @retval EFI_SUCCESS The port is closed
3737 @retval other Port close error
3740 EslSocketPortClose (
3746 ESL_PACKET
* pPacket
;
3747 ESL_PORT
* pPreviousPort
;
3748 ESL_SERVICE
* pService
;
3749 EFI_SERVICE_BINDING_PROTOCOL
* pServiceBinding
;
3750 CONST ESL_SOCKET_BINDING
* pSocketBinding
;
3751 ESL_SOCKET
* pSocket
;
3757 // Verify the socket layer synchronization
3759 VERIFY_TPL ( TPL_SOCKETS
);
3762 // Locate the port in the socket list
3764 Status
= EFI_SUCCESS
;
3765 pLayer
= &mEslLayer
;
3766 DebugFlags
= pPort
->DebugFlags
;
3767 pSocket
= pPort
->pSocket
;
3768 pPreviousPort
= pSocket
->pPortList
;
3769 if ( pPreviousPort
== pPort
) {
3771 // Remove this port from the head of the socket list
3773 pSocket
->pPortList
= pPort
->pLinkSocket
;
3777 // Locate the port in the middle of the socket list
3779 while (( NULL
!= pPreviousPort
)
3780 && ( pPreviousPort
->pLinkSocket
!= pPort
)) {
3781 pPreviousPort
= pPreviousPort
->pLinkSocket
;
3783 if ( NULL
!= pPreviousPort
) {
3785 // Remove the port from the middle of the socket list
3787 pPreviousPort
->pLinkSocket
= pPort
->pLinkSocket
;
3792 // Locate the port in the service list
3793 // Note that the port may not be in the service list
3794 // if the service has been shutdown.
3796 pService
= pPort
->pService
;
3797 if ( NULL
!= pService
) {
3798 pPreviousPort
= pService
->pPortList
;
3799 if ( pPreviousPort
== pPort
) {
3801 // Remove this port from the head of the service list
3803 pService
->pPortList
= pPort
->pLinkService
;
3807 // Locate the port in the middle of the service list
3809 while (( NULL
!= pPreviousPort
)
3810 && ( pPreviousPort
->pLinkService
!= pPort
)) {
3811 pPreviousPort
= pPreviousPort
->pLinkService
;
3813 if ( NULL
!= pPreviousPort
) {
3815 // Remove the port from the middle of the service list
3817 pPreviousPort
->pLinkService
= pPort
->pLinkService
;
3823 // Empty the urgent receive queue
3825 while ( NULL
!= pSocket
->pRxOobPacketListHead
) {
3826 pPacket
= pSocket
->pRxOobPacketListHead
;
3827 pSocket
->pRxOobPacketListHead
= pPacket
->pNext
;
3828 pSocket
->pApi
->pfnPacketFree ( pPacket
, &pSocket
->RxOobBytes
);
3829 EslSocketPacketFree ( pPacket
, DEBUG_RX
);
3831 pSocket
->pRxOobPacketListTail
= NULL
;
3832 ASSERT ( 0 == pSocket
->RxOobBytes
);
3835 // Empty the receive queue
3837 while ( NULL
!= pSocket
->pRxPacketListHead
) {
3838 pPacket
= pSocket
->pRxPacketListHead
;
3839 pSocket
->pRxPacketListHead
= pPacket
->pNext
;
3840 pSocket
->pApi
->pfnPacketFree ( pPacket
, &pSocket
->RxBytes
);
3841 EslSocketPacketFree ( pPacket
, DEBUG_RX
);
3843 pSocket
->pRxPacketListTail
= NULL
;
3844 ASSERT ( 0 == pSocket
->RxBytes
);
3847 // Empty the receive free queue
3849 while ( NULL
!= pSocket
->pRxFree
) {
3850 pPacket
= pSocket
->pRxFree
;
3851 pSocket
->pRxFree
= pPacket
->pNext
;
3852 EslSocketPacketFree ( pPacket
, DEBUG_RX
);
3856 // Release the network specific resources
3858 if ( NULL
!= pSocket
->pApi
->pfnPortClose
) {
3859 Status
= pSocket
->pApi
->pfnPortClose ( pPort
);
3863 // Done with the normal transmit events
3865 Status
= EslSocketIoFree ( pPort
,
3867 DebugFlags
| DEBUG_POOL
,
3868 "normal transmit" );
3871 // Done with the urgent transmit events
3873 Status
= EslSocketIoFree ( pPort
,
3875 DebugFlags
| DEBUG_POOL
,
3876 "urgent transmit" );
3879 // Done with the receive events
3881 Status
= EslSocketIoFree ( pPort
,
3883 DebugFlags
| DEBUG_POOL
,
3887 // Done with the lower layer network protocol
3889 pSocketBinding
= pPort
->pSocketBinding
;
3890 if ( NULL
!= pPort
->pProtocol
.v
) {
3891 Status
= gBS
->CloseProtocol ( pPort
->Handle
,
3892 pSocketBinding
->pNetworkProtocolGuid
,
3893 pLayer
->ImageHandle
,
3895 if ( !EFI_ERROR ( Status
)) {
3896 DEBUG (( DebugFlags
,
3897 "0x%08x: Network protocol GUID closed on controller 0x%08x\r\n",
3902 DEBUG (( DEBUG_ERROR
| DebugFlags
,
3903 "ERROR - Failed to close network protocol GUID on controller 0x%08x, Status: %r\r\n",
3906 ASSERT ( EFI_SUCCESS
== Status
);
3911 // Done with the network port
3913 pServiceBinding
= pPort
->pServiceBinding
;
3914 if ( NULL
!= pPort
->Handle
) {
3915 Status
= pServiceBinding
->DestroyChild ( pServiceBinding
,
3917 if ( !EFI_ERROR ( Status
)) {
3918 DEBUG (( DebugFlags
| DEBUG_POOL
,
3919 "0x%08x: %s port handle destroyed\r\n",
3921 pSocketBinding
->pName
));
3924 DEBUG (( DEBUG_ERROR
| DebugFlags
| DEBUG_POOL
,
3925 "ERROR - Failed to destroy the %s port handle, Status: %r\r\n",
3926 pSocketBinding
->pName
,
3928 ASSERT ( EFI_SUCCESS
== Status
);
3933 // Release the port structure
3935 Status
= gBS
->FreePool ( pPort
);
3936 if ( !EFI_ERROR ( Status
)) {
3937 DEBUG (( DebugFlags
| DEBUG_POOL
,
3938 "0x%08x: Free pPort, %d bytes\r\n",
3940 sizeof ( *pPort
)));
3943 DEBUG (( DEBUG_ERROR
| DebugFlags
| DEBUG_POOL
,
3944 "ERROR - Failed to free pPort: 0x%08x, Status: %r\r\n",
3947 ASSERT ( EFI_SUCCESS
== Status
);
3951 // Mark the socket as closed if necessary
3953 if ( NULL
== pSocket
->pPortList
) {
3954 pSocket
->State
= SOCKET_STATE_CLOSED
;
3955 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
3956 "0x%08x: Socket State: SOCKET_STATE_CLOSED\r\n",
3961 // Return the operation status
3963 DBG_EXIT_STATUS ( Status
);
3968 /** Port close state 3.
3970 This routine attempts to complete the port close operation.
3972 This routine is called by the TCP layer upon completion of
3973 the close operation and by ::EslSocketPortCloseTxDone.
3974 See the \ref PortCloseStateMachine section.
3976 @param[in] Event The close completion event
3977 @param[in] pPort Address of an ::ESL_PORT structure.
3980 EslSocketPortCloseComplete (
3989 VERIFY_AT_TPL ( TPL_SOCKETS
);
3991 // Update the port state
3992 pPort
->State
= PORT_STATE_CLOSE_DONE
;
3993 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
3994 "0x%08x: Port Close State: PORT_STATE_CLOSE_DONE\r\n",
3997 // Shutdown the receive operation on the port
3998 if ( NULL
!= pPort
->pfnRxCancel
) {
3999 pIo
= pPort
->pRxActive
;
4000 while ( NULL
!= pIo
) {
4001 EslSocketRxCancel ( pPort
, pIo
);
4006 // Determine if the receive operation is pending
4007 Status
= EslSocketPortCloseRxDone ( pPort
);
4008 DBG_EXIT_STATUS ( Status
);
4013 /** Port close state 4.
4015 This routine determines the state of the receive operations and
4016 continues the close operation after the pending receive operations
4019 This routine is called by
4021 <li>::EslSocketPortCloseComplete</li>
4022 <li>::EslSocketPortCloseTxDone</li>
4023 <li>::EslSocketRxComplete</li>
4025 to determine the state of the receive operations.
4026 See the \ref PortCloseStateMachine section.
4028 @param[in] pPort Address of an ::ESL_PORT structure.
4030 @retval EFI_SUCCESS The port is closed
4031 @retval EFI_NOT_READY The port is still closing
4032 @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
4033 most likely the routine was called already.
4036 EslSocketPortCloseRxDone (
4045 // Verify the socket layer synchronization
4047 VERIFY_TPL ( TPL_SOCKETS
);
4050 // Verify that the port is closing
4052 Status
= EFI_ALREADY_STARTED
;
4053 if ( PORT_STATE_CLOSE_DONE
== pPort
->State
) {
4055 // Determine if the receive operation is pending
4057 Status
= EFI_NOT_READY
;
4058 if ( NULL
== pPort
->pRxActive
) {
4060 // The receive operation is complete
4061 // Update the port state
4063 pPort
->State
= PORT_STATE_CLOSE_RX_DONE
;
4064 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4065 "0x%08x: Port Close State: PORT_STATE_CLOSE_RX_DONE\r\n",
4069 // Complete the port close operation
4071 Status
= EslSocketPortClose ( pPort
);
4074 DEBUG_CODE_BEGIN ();
4078 // Display the outstanding receive operations
4080 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4081 "0x%08x: Port Close: Receive still pending!\r\n",
4083 pIo
= pPort
->pRxActive
;
4084 while ( NULL
!= pIo
) {
4085 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4086 "0x%08x: Packet pending on network adapter\r\n",
4096 // Return the operation status
4098 DBG_EXIT_STATUS ( Status
);
4103 /** Start the close operation on a port, state 1.
4105 This routine marks the port as closed and initiates the \ref
4106 PortCloseStateMachine. The first step is to allow the \ref
4107 TransmitEngine to run down.
4109 This routine is called by ::EslSocketCloseStart to initiate the socket
4110 network specific close operation on the socket.
4112 @param[in] pPort Address of an ::ESL_PORT structure.
4113 @param[in] bCloseNow Set TRUE to abort active transfers
4114 @param[in] DebugFlags Flags for debug messages
4116 @retval EFI_SUCCESS The port is closed, not normally returned
4117 @retval EFI_NOT_READY The port has started the closing process
4118 @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
4119 most likely the routine was called already.
4122 EslSocketPortCloseStart (
4123 IN ESL_PORT
* pPort
,
4124 IN BOOLEAN bCloseNow
,
4128 ESL_SOCKET
* pSocket
;
4134 // Verify the socket layer synchronization
4136 VERIFY_TPL ( TPL_SOCKETS
);
4139 // Mark the port as closing
4141 Status
= EFI_ALREADY_STARTED
;
4142 pSocket
= pPort
->pSocket
;
4143 pSocket
->errno
= EALREADY
;
4144 if ( PORT_STATE_CLOSE_STARTED
> pPort
->State
) {
4147 // Update the port state
4149 pPort
->State
= PORT_STATE_CLOSE_STARTED
;
4150 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4151 "0x%08x: Port Close State: PORT_STATE_CLOSE_STARTED\r\n",
4153 pPort
->bCloseNow
= bCloseNow
;
4154 pPort
->DebugFlags
= DebugFlags
;
4157 // Determine if transmits are complete
4159 Status
= EslSocketPortCloseTxDone ( pPort
);
4163 // Return the operation status
4165 DBG_EXIT_STATUS ( Status
);
4170 /** Port close state 2.
4172 This routine determines the state of the transmit engine and
4173 continue the close operation after the transmission is complete.
4174 The next step is to stop the \ref ReceiveEngine.
4175 See the \ref PortCloseStateMachine section.
4177 This routine is called by ::EslSocketPortCloseStart to determine
4178 if the transmission is complete.
4180 @param[in] pPort Address of an ::ESL_PORT structure.
4182 @retval EFI_SUCCESS The port is closed, not normally returned
4183 @retval EFI_NOT_READY The port is still closing
4184 @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
4185 most likely the routine was called already.
4189 EslSocketPortCloseTxDone (
4194 ESL_SOCKET
* pSocket
;
4200 // Verify the socket layer synchronization
4202 VERIFY_TPL ( TPL_SOCKETS
);
4205 // All transmissions are complete or must be stopped
4206 // Mark the port as TX complete
4208 Status
= EFI_ALREADY_STARTED
;
4209 if ( PORT_STATE_CLOSE_STARTED
== pPort
->State
) {
4211 // Verify that the transmissions are complete
4213 pSocket
= pPort
->pSocket
;
4214 if ( pPort
->bCloseNow
4215 || ( EFI_SUCCESS
!= pSocket
->TxError
)
4216 || (( NULL
== pPort
->pTxActive
)
4217 && ( NULL
== pPort
->pTxOobActive
))) {
4219 // Update the port state
4221 pPort
->State
= PORT_STATE_CLOSE_TX_DONE
;
4222 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4223 "0x%08x: Port Close State: PORT_STATE_CLOSE_TX_DONE\r\n",
4228 // Skip the close operation if the port is not configured
4230 Status
= EFI_SUCCESS
;
4231 pSocket
= pPort
->pSocket
;
4232 if (( pPort
->bConfigured
)
4233 && ( NULL
!= pSocket
->pApi
->pfnPortCloseOp
)) {
4235 // Start the close operation
4237 Status
= pSocket
->pApi
->pfnPortCloseOp ( pPort
);
4238 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4239 "0x%08x: Port Close: Close operation still pending!\r\n",
4241 ASSERT ( EFI_SUCCESS
== Status
);
4245 // The receive operation is complete
4246 // Update the port state
4248 EslSocketPortCloseComplete ( NULL
, pPort
);
4253 // Transmissions are still active, exit
4255 Status
= EFI_NOT_READY
;
4256 pSocket
->errno
= EAGAIN
;
4257 DEBUG_CODE_BEGIN ( );
4259 ESL_PACKET
* pPacket
;
4261 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4262 "0x%08x: Port Close: Transmits are still pending!\r\n",
4266 // Display the pending urgent transmit packets
4268 pPacket
= pSocket
->pTxOobPacketListHead
;
4269 while ( NULL
!= pPacket
) {
4270 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4271 "0x%08x: Packet pending on urgent TX list, %d bytes\r\n",
4273 pPacket
->PacketSize
));
4274 pPacket
= pPacket
->pNext
;
4277 pIo
= pPort
->pTxOobActive
;
4278 while ( NULL
!= pIo
) {
4279 pPacket
= pIo
->pPacket
;
4280 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4281 "0x%08x: Packet active %d bytes, pIo: 0x%08x\r\n",
4283 pPacket
->PacketSize
,
4289 // Display the pending normal transmit packets
4291 pPacket
= pSocket
->pTxPacketListHead
;
4292 while ( NULL
!= pPacket
) {
4293 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4294 "0x%08x: Packet pending on normal TX list, %d bytes\r\n",
4296 pPacket
->PacketSize
));
4297 pPacket
= pPacket
->pNext
;
4300 pIo
= pPort
->pTxActive
;
4301 while ( NULL
!= pIo
) {
4302 pPacket
= pIo
->pPacket
;
4303 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4304 "0x%08x: Packet active %d bytes, pIo: 0x%08x\r\n",
4306 pPacket
->PacketSize
,
4316 // Return the operation status
4318 DBG_EXIT_STATUS ( Status
);
4323 /** Receive data from a network connection.
4325 This routine calls the network specific routine to remove the
4326 next portion of data from the receive queue and return it to the
4329 The ::recvfrom routine calls this routine to determine if any data
4330 is received from the remote system. Note that the other routines
4331 ::recv and ::read are layered on top of ::recvfrom.
4333 @param[in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
4334 @param[in] Flags Message control flags
4335 @param[in] BufferLength Length of the the buffer
4336 @param[in] pBuffer Address of a buffer to receive the data.
4337 @param[in] pDataLength Number of received data bytes in the buffer.
4338 @param[out] pAddress Network address to receive the remote system address
4339 @param[in,out] pAddressLength Length of the remote network address structure
4340 @param[out] pErrno Address to receive the errno value upon completion.
4342 @retval EFI_SUCCESS - Socket data successfully received
4346 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
4348 IN
size_t BufferLength
,
4350 OUT
size_t * pDataLength
,
4351 OUT
struct sockaddr
* pAddress
,
4352 IN OUT socklen_t
* pAddressLength
,
4357 struct sockaddr_in v4
;
4358 struct sockaddr_in6 v6
;
4360 socklen_t AddressLength
;
4361 BOOLEAN bConsumePacket
;
4362 BOOLEAN bUrgentQueue
;
4364 ESL_PACKET
* pNextPacket
;
4365 ESL_PACKET
* pPacket
;
4367 ESL_PACKET
** ppQueueHead
;
4368 ESL_PACKET
** ppQueueTail
;
4369 struct sockaddr
* pRemoteAddress
;
4370 size_t * pRxDataBytes
;
4371 ESL_SOCKET
* pSocket
;
4374 EFI_TPL TplPrevious
;
4381 Status
= EFI_SUCCESS
;
4384 // Validate the socket
4387 if ( NULL
!= pSocketProtocol
) {
4388 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
4391 // Validate the return address parameters
4393 if (( NULL
== pAddress
) || ( NULL
!= pAddressLength
)) {
4395 // Return the transmit error if necessary
4397 if ( EFI_SUCCESS
!= pSocket
->TxError
) {
4398 pSocket
->errno
= EIO
;
4399 Status
= pSocket
->TxError
;
4400 pSocket
->TxError
= EFI_SUCCESS
;
4404 // Verify the socket state
4406 Status
= EslSocketIsConfigured ( pSocket
);
4407 if ( !EFI_ERROR ( Status
)) {
4409 // Validate the buffer length
4411 if (( NULL
== pDataLength
)
4412 || ( NULL
== pBuffer
)) {
4413 if ( NULL
== pDataLength
) {
4415 "ERROR - pDataLength is NULL!\r\n" ));
4419 "ERROR - pBuffer is NULL!\r\n" ));
4421 Status
= EFI_INVALID_PARAMETER
;
4422 pSocket
->errno
= EFAULT
;
4428 if ( NULL
== pSocket
->pApi
->pfnReceive
) {
4429 Status
= EFI_UNSUPPORTED
;
4430 pSocket
->errno
= ENOTSUP
;
4434 // Zero the receive address if being returned
4436 pRemoteAddress
= NULL
;
4437 if ( NULL
!= pAddress
) {
4438 pRemoteAddress
= (struct sockaddr
*)&Addr
;
4439 ZeroMem ( pRemoteAddress
, sizeof ( Addr
));
4440 pRemoteAddress
->sa_family
= pSocket
->pApi
->AddressFamily
;
4441 pRemoteAddress
->sa_len
= (UINT8
)pSocket
->pApi
->AddressLength
;
4445 // Synchronize with the socket layer
4447 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
4452 Status
= EFI_UNSUPPORTED
;
4453 pSocket
->errno
= ENOTCONN
;
4456 // Verify that the socket is connected
4458 if ( SOCKET_STATE_CONNECTED
== pSocket
->State
) {
4460 // Poll the network to increase performance
4462 EslSocketRxPoll ( pSocket
);
4467 pPort
= pSocket
->pPortList
;
4468 if ( NULL
!= pPort
) {
4470 // Determine the queue head
4472 bUrgentQueue
= (BOOLEAN
)( 0 != ( Flags
& MSG_OOB
));
4473 if ( bUrgentQueue
) {
4474 ppQueueHead
= &pSocket
->pRxOobPacketListHead
;
4475 ppQueueTail
= &pSocket
->pRxOobPacketListTail
;
4476 pRxDataBytes
= &pSocket
->RxOobBytes
;
4479 ppQueueHead
= &pSocket
->pRxPacketListHead
;
4480 ppQueueTail
= &pSocket
->pRxPacketListTail
;
4481 pRxDataBytes
= &pSocket
->RxBytes
;
4485 // Determine if there is any data on the queue
4488 pPacket
= *ppQueueHead
;
4489 if ( NULL
!= pPacket
) {
4491 // Copy the received data
4495 // Attempt to receive a packet
4498 bConsumePacket
= (BOOLEAN
)( 0 == ( Flags
& MSG_PEEK
));
4499 pBuffer
= pSocket
->pApi
->pfnReceive ( pPort
,
4505 (struct sockaddr
*)&Addr
,
4507 *pDataLength
+= DataLength
;
4508 BufferLength
-= DataLength
;
4511 // Determine if the data is being read
4513 pNextPacket
= pPacket
->pNext
;
4514 if ( bConsumePacket
) {
4516 // All done with this packet
4517 // Account for any discarded data
4519 pSocket
->pApi
->pfnPacketFree ( pPacket
, pRxDataBytes
);
4520 if ( 0 != SkipBytes
) {
4522 "0x%08x: Port, packet read, skipping over 0x%08x bytes\r\n",
4528 // Remove this packet from the queue
4530 *ppQueueHead
= pPacket
->pNext
;
4531 if ( NULL
== *ppQueueHead
) {
4532 *ppQueueTail
= NULL
;
4536 // Move the packet to the free queue
4538 pPacket
->pNext
= pSocket
->pRxFree
;
4539 pSocket
->pRxFree
= pPacket
;
4541 "0x%08x: Port freeing packet 0x%08x\r\n",
4546 // Restart the receive operation if necessary
4548 if (( NULL
!= pPort
->pRxFree
)
4549 && ( MAX_RX_DATA
> pSocket
->RxBytes
)) {
4550 EslSocketRxStart ( pPort
);
4555 // Get the next packet
4557 pPacket
= pNextPacket
;
4558 } while (( SOCK_STREAM
== pSocket
->Type
)
4559 && ( NULL
!= pPacket
)
4560 && ( 0 < BufferLength
));
4563 // Successful operation
4565 Status
= EFI_SUCCESS
;
4570 // The queue is empty
4571 // Determine if it is time to return the receive error
4573 if ( EFI_ERROR ( pSocket
->RxError
)
4574 && ( NULL
== pSocket
->pRxPacketListHead
)
4575 && ( NULL
== pSocket
->pRxOobPacketListHead
)) {
4576 Status
= pSocket
->RxError
;
4577 pSocket
->RxError
= EFI_SUCCESS
;
4580 pSocket
->errno
= EIO
;
4583 case EFI_CONNECTION_FIN
:
4585 // Continue to return zero bytes received when the
4586 // peer has successfully closed the connection
4588 pSocket
->RxError
= EFI_CONNECTION_FIN
;
4591 Status
= EFI_SUCCESS
;
4594 case EFI_CONNECTION_REFUSED
:
4595 pSocket
->errno
= ECONNREFUSED
;
4598 case EFI_CONNECTION_RESET
:
4599 pSocket
->errno
= ECONNRESET
;
4602 case EFI_HOST_UNREACHABLE
:
4603 pSocket
->errno
= EHOSTUNREACH
;
4606 case EFI_NETWORK_UNREACHABLE
:
4607 pSocket
->errno
= ENETUNREACH
;
4610 case EFI_PORT_UNREACHABLE
:
4611 pSocket
->errno
= EPROTONOSUPPORT
;
4614 case EFI_PROTOCOL_UNREACHABLE
:
4615 pSocket
->errno
= ENOPROTOOPT
;
4620 Status
= EFI_NOT_READY
;
4621 pSocket
->errno
= EAGAIN
;
4628 // Release the socket layer synchronization
4630 RESTORE_TPL ( TplPrevious
);
4632 if (( !EFI_ERROR ( Status
)) && ( NULL
!= pAddress
)) {
4634 // Return the remote address if requested, truncate if necessary
4636 AddressLength
= pRemoteAddress
->sa_len
;
4637 if ( AddressLength
> *pAddressLength
) {
4638 AddressLength
= *pAddressLength
;
4641 "Returning the remote address, 0x%016x bytes --> 0x%16x\r\n", *pAddressLength
, pAddress
));
4642 ZeroMem ( pAddress
, *pAddressLength
);
4643 CopyMem ( pAddress
, &Addr
, AddressLength
);
4646 // Update the address length
4648 *pAddressLength
= pRemoteAddress
->sa_len
;
4659 // Bad return address pointer and length
4661 Status
= EFI_INVALID_PARAMETER
;
4662 pSocket
->errno
= EINVAL
;
4667 // Return the operation status
4669 if ( NULL
!= pErrno
) {
4670 if ( NULL
!= pSocket
) {
4671 *pErrno
= pSocket
->errno
;
4674 Status
= EFI_INVALID_PARAMETER
;
4678 DBG_EXIT_STATUS ( Status
);
4683 /** Cancel the receive operations.
4685 This routine cancels a pending receive operation.
4686 See the \ref ReceiveEngine section.
4688 This routine is called by ::EslSocketShutdown when the socket
4689 layer is being shutdown.
4691 @param[in] pPort Address of an ::ESL_PORT structure
4692 @param[in] pIo Address of an ::ESL_IO_MGMT structure
4696 IN ESL_PORT
* pPort
,
4697 IN ESL_IO_MGMT
* pIo
4705 // Cancel the outstanding receive
4707 Status
= pPort
->pfnRxCancel ( pPort
->pProtocol
.v
,
4709 if ( !EFI_ERROR ( Status
)) {
4710 DEBUG (( pPort
->DebugFlags
| DEBUG_CLOSE
| DEBUG_INFO
,
4711 "0x%08x: Packet receive aborted on port: 0x%08x\r\n",
4716 DEBUG (( pPort
->DebugFlags
| DEBUG_CLOSE
| DEBUG_INFO
,
4717 "0x%08x: Packet receive pending on Port 0x%08x, Status: %r\r\n",
4726 /** Process the receive completion.
4728 This routine queues the data in FIFO order in either the urgent
4729 or normal data queues depending upon the type of data received.
4730 See the \ref ReceiveEngine section.
4732 This routine is called when some data is received by:
4734 <li>::EslIp4RxComplete</li>
4735 <li>::EslTcp4RxComplete</li>
4736 <li>::EslUdp4RxComplete</li>
4739 @param[in] pIo Address of an ::ESL_IO_MGMT structure
4740 @param[in] Status Receive status
4741 @param[in] LengthInBytes Length of the receive data
4742 @param[in] bUrgent TRUE if urgent data is received and FALSE
4746 EslSocketRxComplete (
4747 IN ESL_IO_MGMT
* pIo
,
4748 IN EFI_STATUS Status
,
4749 IN UINTN LengthInBytes
,
4753 BOOLEAN bUrgentQueue
;
4754 ESL_IO_MGMT
* pIoNext
;
4755 ESL_PACKET
* pPacket
;
4757 ESL_PACKET
* pPrevious
;
4758 ESL_PACKET
** ppQueueHead
;
4759 ESL_PACKET
** ppQueueTail
;
4761 ESL_SOCKET
* pSocket
;
4764 VERIFY_AT_TPL ( TPL_SOCKETS
);
4767 // Locate the active receive packet
4769 pPacket
= pIo
->pPacket
;
4771 pSocket
= pPort
->pSocket
;
4777 // +-------------+ +-------------+ +-------------+
4778 // Active | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
4779 // +-------------+ +-------------+ +-------------+
4781 // +-------------+ +-------------+ +-------------+
4782 // Free | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
4783 // +-------------+ +-------------+ +-------------+
4789 // Remove the IO structure from the active list
4790 // The following code searches for the entry in the list and does not
4791 // assume that the receive operations complete in the order they were
4792 // issued to the UEFI network layer.
4794 pIoNext
= pPort
->pRxActive
;
4795 while (( NULL
!= pIoNext
) && ( pIoNext
!= pIo
) && ( pIoNext
->pNext
!= pIo
))
4797 pIoNext
= pIoNext
->pNext
;
4799 ASSERT ( NULL
!= pIoNext
);
4800 if ( pIoNext
== pIo
) {
4801 pPort
->pRxActive
= pIo
->pNext
; // Beginning of list
4804 pIoNext
->pNext
= pIo
->pNext
; // Middle of list
4808 // Free the IO structure
4810 pIo
->pNext
= pPort
->pRxFree
;
4811 pPort
->pRxFree
= pIo
;
4814 // pRxOobPacketListHead pRxOobPacketListTail
4817 // +------------+ +------------+ +------------+
4818 // Urgent Data | ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL
4819 // +------------+ +------------+ +------------+
4821 // +------------+ +------------+ +------------+
4822 // Normal Data | ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL
4823 // +------------+ +------------+ +------------+
4826 // pRxPacketListHead pRxPacketListTail
4829 // Determine the queue to use
4831 bUrgentQueue
= (BOOLEAN
)( bUrgent
4832 && pSocket
->pApi
->bOobSupported
4833 && ( !pSocket
->bOobInLine
));
4834 if ( bUrgentQueue
) {
4835 ppQueueHead
= &pSocket
->pRxOobPacketListHead
;
4836 ppQueueTail
= &pSocket
->pRxOobPacketListTail
;
4837 pRxBytes
= &pSocket
->RxOobBytes
;
4840 ppQueueHead
= &pSocket
->pRxPacketListHead
;
4841 ppQueueTail
= &pSocket
->pRxPacketListTail
;
4842 pRxBytes
= &pSocket
->RxBytes
;
4846 // Determine if this receive was successful
4848 if (( !EFI_ERROR ( Status
))
4849 && ( PORT_STATE_CLOSE_STARTED
> pPort
->State
)
4850 && ( !pSocket
->bRxDisable
)) {
4852 // Account for the received data
4854 *pRxBytes
+= LengthInBytes
;
4857 // Log the received data
4859 DEBUG (( DEBUG_RX
| DEBUG_INFO
,
4860 "0x%08x: Packet queued on %s queue of port 0x%08x with 0x%08x bytes of %s data\r\n",
4862 bUrgentQueue
? L
"urgent" : L
"normal",
4865 bUrgent
? L
"urgent" : L
"normal" ));
4868 // Add the packet to the list tail.
4870 pPacket
->pNext
= NULL
;
4871 pPrevious
= *ppQueueTail
;
4872 if ( NULL
== pPrevious
) {
4873 *ppQueueHead
= pPacket
;
4876 pPrevious
->pNext
= pPacket
;
4878 *ppQueueTail
= pPacket
;
4881 // Attempt to restart this receive operation
4883 if ( pSocket
->MaxRxBuf
> pSocket
->RxBytes
) {
4884 EslSocketRxStart ( pPort
);
4888 "0x%08x: Port RX suspended, 0x%08x bytes queued\r\n",
4890 pSocket
->RxBytes
));
4894 if ( EFI_ERROR ( Status
)) {
4895 DEBUG (( DEBUG_RX
| DEBUG_INFO
,
4896 "ERROR - Receive error on port 0x%08x, packet 0x%08x, Status:%r\r\n",
4903 // Account for the receive bytes and release the driver's buffer
4905 if ( !EFI_ERROR ( Status
)) {
4906 *pRxBytes
+= LengthInBytes
;
4907 pSocket
->pApi
->pfnPacketFree ( pPacket
, pRxBytes
);
4911 // Receive error, free the packet save the error
4913 EslSocketPacketFree ( pPacket
, DEBUG_RX
);
4914 if ( !EFI_ERROR ( pSocket
->RxError
)) {
4915 pSocket
->RxError
= Status
;
4919 // Update the port state
4921 if ( PORT_STATE_CLOSE_STARTED
<= pPort
->State
) {
4922 if ( PORT_STATE_CLOSE_DONE
== pPort
->State
) {
4923 EslSocketPortCloseRxDone ( pPort
);
4927 if ( EFI_ERROR ( Status
)) {
4928 DEBUG (( DEBUG_RX
| DEBUG_INFO
,
4929 "0x%08x: Port state: PORT_STATE_RX_ERROR, Status: %r\r\n",
4932 pPort
->State
= PORT_STATE_RX_ERROR
;
4941 /** Poll a socket for pending receive activity.
4943 This routine is called at elivated TPL and extends the idle
4944 loop which polls a socket down into the LAN driver layer to
4945 determine if there is any receive activity.
4947 The ::EslSocketPoll, ::EslSocketReceive and ::EslSocketTransmit
4948 routines call this routine when there is nothing to do.
4950 @param[in] pSocket Address of an ::EFI_SOCKET structure.
4954 IN ESL_SOCKET
* pSocket
4959 DEBUG (( DEBUG_POLL
, "Entering EslSocketRxPoll\r\n" ));
4962 // Increase the network performance by extending the
4963 // polling (idle) loop down into the LAN driver
4965 pPort
= pSocket
->pPortList
;
4966 while ( NULL
!= pPort
) {
4968 // Poll the LAN adapter
4970 pPort
->pfnRxPoll ( pPort
->pProtocol
.v
);
4973 // Locate the next LAN adapter
4975 pPort
= pPort
->pLinkSocket
;
4978 DEBUG (( DEBUG_POLL
, "Exiting EslSocketRxPoll\r\n" ));
4982 /** Start a receive operation.
4984 This routine posts a receive buffer to the network adapter.
4985 See the \ref ReceiveEngine section.
4987 This support routine is called by:
4989 <li>::EslIp4Receive to restart the receive engine to release flow control.</li>
4990 <li>::EslIp4RxComplete to continue the operation of the receive engine if flow control is not being applied.</li>
4991 <li>::EslIp4SocketIsConfigured to start the receive engine for the new socket.</li>
4992 <li>::EslTcp4ListenComplete to start the recevie engine for the new socket.</li>
4993 <li>::EslTcp4Receive to restart the receive engine to release flow control.</li>
4994 <li>::EslTcp4RxComplete to continue the operation of the receive engine if flow control is not being applied.</li>
4995 <li>::EslUdp4Receive to restart the receive engine to release flow control.</li>
4996 <li>::EslUdp4RxComplete to continue the operation of the receive engine if flow control is not being applied.</li>
4997 <li>::EslUdp4SocketIsConfigured to start the recevie engine for the new socket.</li>
5000 @param[in] pPort Address of an ::ESL_PORT structure.
5009 ESL_PACKET
* pPacket
;
5010 ESL_SOCKET
* pSocket
;
5016 // Determine if a receive is already pending
5018 Status
= EFI_SUCCESS
;
5020 pSocket
= pPort
->pSocket
;
5021 if ( !EFI_ERROR ( pPort
->pSocket
->RxError
)) {
5022 if (( NULL
!= pPort
->pRxFree
)
5023 && ( !pSocket
->bRxDisable
)
5024 && ( PORT_STATE_CLOSE_STARTED
> pPort
->State
)) {
5026 // Start all of the pending receive operations
5028 while ( NULL
!= pPort
->pRxFree
) {
5030 // Determine if there are any free packets
5032 pPacket
= pSocket
->pRxFree
;
5033 if ( NULL
!= pPacket
) {
5035 // Remove this packet from the free list
5037 pSocket
->pRxFree
= pPacket
->pNext
;
5039 "0x%08x: Port removed packet 0x%08x from free list\r\n",
5045 // Allocate a packet structure
5047 Status
= EslSocketPacketAllocate ( &pPacket
,
5048 pSocket
->pApi
->RxPacketBytes
,
5049 pSocket
->pApi
->RxZeroBytes
,
5051 if ( EFI_ERROR ( Status
)) {
5053 DEBUG (( DEBUG_ERROR
| DEBUG_RX
,
5054 "0x%08x: Port failed to allocate RX packet, Status: %r\r\n",
5062 // Connect the IO and packet structures
5064 pIo
= pPort
->pRxFree
;
5065 pIo
->pPacket
= pPacket
;
5068 // Eliminate the need for IP4 and UDP4 specific routines by
5069 // clearing the RX data pointer here.
5071 // No driver buffer for this packet
5073 // +--------------------+
5076 // | +---------------+
5078 // | | RxData --> NULL
5079 // +----+---------------+
5081 pBuffer
= (UINT8
*)pIo
;
5082 pBuffer
= &pBuffer
[ pSocket
->pApi
->RxBufferOffset
];
5083 *(VOID
**)pBuffer
= NULL
;
5086 // Network specific receive packet initialization
5088 if ( NULL
!= pSocket
->pApi
->pfnRxStart
) {
5089 pSocket
->pApi
->pfnRxStart ( pPort
, pIo
);
5093 // Start the receive on the packet
5095 Status
= pPort
->pfnRxStart ( pPort
->pProtocol
.v
, &pIo
->Token
);
5096 if ( !EFI_ERROR ( Status
)) {
5097 DEBUG (( DEBUG_RX
| DEBUG_INFO
,
5098 "0x%08x: Packet receive pending on port 0x%08x\r\n",
5102 // Allocate the receive control structure
5104 pPort
->pRxFree
= pIo
->pNext
;
5107 // Mark this receive as pending
5109 pIo
->pNext
= pPort
->pRxActive
;
5110 pPort
->pRxActive
= pIo
;
5114 DEBUG (( DEBUG_RX
| DEBUG_INFO
,
5115 "ERROR - Failed to post a receive on port 0x%08x, Status: %r\r\n",
5118 if ( !EFI_ERROR ( pSocket
->RxError
)) {
5120 // Save the error status
5122 pSocket
->RxError
= Status
;
5128 pIo
->pPacket
= NULL
;
5129 pPacket
->pNext
= pSocket
->pRxFree
;
5130 pSocket
->pRxFree
= pPacket
;
5136 if ( NULL
== pPort
->pRxFree
) {
5137 DEBUG (( DEBUG_RX
| DEBUG_INFO
,
5138 "0x%08x: Port, no available ESL_IO_MGMT structures\r\n",
5141 if ( pSocket
->bRxDisable
) {
5142 DEBUG (( DEBUG_RX
| DEBUG_INFO
,
5143 "0x%08x: Port, receive disabled!\r\n",
5146 if ( PORT_STATE_CLOSE_STARTED
<= pPort
->State
) {
5147 DEBUG (( DEBUG_RX
| DEBUG_INFO
,
5148 "0x%08x: Port, is closing!\r\n",
5154 DEBUG (( DEBUG_ERROR
| DEBUG_RX
,
5155 "ERROR - Previous receive error, Status: %r\r\n",
5156 pPort
->pSocket
->RxError
));
5163 /** Shutdown the socket receive and transmit operations.
5165 This routine sets a flag to stop future transmissions and calls
5166 the network specific layer to cancel the pending receive operation.
5168 The ::shutdown routine calls this routine to stop receive and transmit
5169 operations on the socket.
5171 @param[in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
5172 @param[in] How Which operations to stop
5173 @param[out] pErrno Address to receive the errno value upon completion.
5175 @retval EFI_SUCCESS - Socket operations successfully shutdown
5179 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
5186 ESL_SOCKET
* pSocket
;
5188 EFI_TPL TplPrevious
;
5195 Status
= EFI_SUCCESS
;
5198 // Validate the socket
5201 if ( NULL
!= pSocketProtocol
) {
5202 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
5205 // Verify that the socket is connected
5207 if ( pSocket
->bConnected
) {
5209 // Validate the How value
5211 if (( SHUT_RD
<= How
) && ( SHUT_RDWR
>= How
)) {
5213 // Synchronize with the socket layer
5215 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
5218 // Disable the receiver if requested
5220 if (( SHUT_RD
== How
) || ( SHUT_RDWR
== How
)) {
5221 pSocket
->bRxDisable
= TRUE
;
5225 // Disable the transmitter if requested
5227 if (( SHUT_WR
== How
) || ( SHUT_RDWR
== How
)) {
5228 pSocket
->bTxDisable
= TRUE
;
5232 // Cancel the pending receive operations
5234 if ( pSocket
->bRxDisable
) {
5236 // Walk the list of ports
5238 pPort
= pSocket
->pPortList
;
5239 while ( NULL
!= pPort
) {
5241 // Walk the list of active receive operations
5243 pIo
= pPort
->pRxActive
;
5244 while ( NULL
!= pIo
) {
5245 EslSocketRxCancel ( pPort
, pIo
);
5249 // Set the next port
5251 pPort
= pPort
->pLinkSocket
;
5256 // Release the socket layer synchronization
5258 RESTORE_TPL ( TplPrevious
);
5262 // Invalid How value
5264 pSocket
->errno
= EINVAL
;
5265 Status
= EFI_INVALID_PARAMETER
;
5270 // The socket is not connected
5272 pSocket
->errno
= ENOTCONN
;
5273 Status
= EFI_NOT_STARTED
;
5278 // Return the operation status
5280 if ( NULL
!= pErrno
) {
5281 if ( NULL
!= pSocket
) {
5282 *pErrno
= pSocket
->errno
;
5285 Status
= EFI_INVALID_PARAMETER
;
5289 DBG_EXIT_STATUS ( Status
);
5294 /** Send data using a network connection.
5296 This routine calls the network specific layer to queue the data
5297 for transmission. Eventually the buffer will reach the head of
5298 the queue and will get transmitted over the network by the
5299 \ref TransmitEngine. For datagram
5300 sockets (SOCK_DGRAM and SOCK_RAW) there is no guarantee that
5301 the data reaches the application running on the remote system.
5303 The ::sendto routine calls this routine to send data to the remote
5304 system. Note that ::send and ::write are layered on top of ::sendto.
5306 @param[in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
5307 @param[in] Flags Message control flags
5308 @param[in] BufferLength Length of the the buffer
5309 @param[in] pBuffer Address of a buffer containing the data to send
5310 @param[in] pDataLength Address to receive the number of data bytes sent
5311 @param[in] pAddress Network address of the remote system address
5312 @param[in] AddressLength Length of the remote network address structure
5313 @param[out] pErrno Address to receive the errno value upon completion.
5315 @retval EFI_SUCCESS - Socket data successfully queued for transmit
5319 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
5321 IN
size_t BufferLength
,
5322 IN CONST UINT8
* pBuffer
,
5323 OUT
size_t * pDataLength
,
5324 IN
const struct sockaddr
* pAddress
,
5325 IN socklen_t AddressLength
,
5329 ESL_SOCKET
* pSocket
;
5331 EFI_TPL TplPrevious
;
5338 Status
= EFI_SUCCESS
;
5341 // Validate the socket
5344 if ( NULL
!= pSocketProtocol
) {
5345 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
5348 // Return the transmit error if necessary
5350 if ( EFI_SUCCESS
!= pSocket
->TxError
) {
5351 pSocket
->errno
= EIO
;
5352 Status
= pSocket
->TxError
;
5353 pSocket
->TxError
= EFI_SUCCESS
;
5357 // Verify the socket state
5359 Status
= EslSocketIsConfigured ( pSocket
);
5360 if ( !EFI_ERROR ( Status
)) {
5362 // Verify that transmit is still allowed
5364 if ( !pSocket
->bTxDisable
) {
5366 // Validate the buffer length
5368 if (( NULL
== pDataLength
)
5369 && ( 0 > pDataLength
)
5370 && ( NULL
== pBuffer
)) {
5371 if ( NULL
== pDataLength
) {
5373 "ERROR - pDataLength is NULL!\r\n" ));
5375 else if ( NULL
== pBuffer
) {
5377 "ERROR - pBuffer is NULL!\r\n" ));
5381 "ERROR - Data length < 0!\r\n" ));
5383 Status
= EFI_INVALID_PARAMETER
;
5384 pSocket
->errno
= EFAULT
;
5388 // Validate the remote network address
5390 if (( NULL
!= pAddress
)
5391 && ( AddressLength
< pAddress
->sa_len
)) {
5393 "ERROR - Invalid sin_len field in address\r\n" ));
5394 Status
= EFI_INVALID_PARAMETER
;
5395 pSocket
->errno
= EFAULT
;
5401 if ( NULL
== pSocket
->pApi
->pfnTransmit
) {
5402 Status
= EFI_UNSUPPORTED
;
5403 pSocket
->errno
= ENOTSUP
;
5407 // Synchronize with the socket layer
5409 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
5412 // Poll the network to increase performance
5414 EslSocketRxPoll ( pSocket
);
5417 // Attempt to buffer the packet for transmission
5419 Status
= pSocket
->pApi
->pfnTransmit ( pSocket
,
5428 // Release the socket layer synchronization
5430 RESTORE_TPL ( TplPrevious
);
5437 // The transmitter was shutdown
5439 pSocket
->errno
= EPIPE
;
5440 Status
= EFI_NOT_STARTED
;
5447 // Return the operation status
5449 if ( NULL
!= pErrno
) {
5450 if ( NULL
!= pSocket
) {
5451 *pErrno
= pSocket
->errno
;
5454 Status
= EFI_INVALID_PARAMETER
;
5458 DBG_EXIT_STATUS ( Status
);
5463 /** Complete the transmit operation.
5465 This support routine handles the transmit completion processing for
5466 the various network layers. It frees the ::ESL_IO_MGMT structure
5467 and and frees packet resources by calling ::EslSocketPacketFree.
5468 Transmit errors are logged in ESL_SOCKET::TxError.
5469 See the \ref TransmitEngine section.
5471 This routine is called by:
5473 <li>::EslIp4TxComplete</li>
5474 <li>::EslTcp4TxComplete</li>
5475 <li>::EslTcp4TxOobComplete</li>
5476 <li>::EslUdp4TxComplete</li>
5479 @param[in] pIo Address of an ::ESL_IO_MGMT structure
5480 @param[in] LengthInBytes Length of the data in bytes
5481 @param[in] Status Transmit operation status
5482 @param[in] pQueueType Zero terminated string describing queue type
5483 @param[in] ppQueueHead Transmit queue head address
5484 @param[in] ppQueueTail Transmit queue tail address
5485 @param[in] ppActive Active transmit queue address
5486 @param[in] ppFree Free transmit queue address
5489 EslSocketTxComplete (
5490 IN ESL_IO_MGMT
* pIo
,
5491 IN UINT32 LengthInBytes
,
5492 IN EFI_STATUS Status
,
5493 IN CONST CHAR8
* pQueueType
,
5494 IN ESL_PACKET
** ppQueueHead
,
5495 IN ESL_PACKET
** ppQueueTail
,
5496 IN ESL_IO_MGMT
** ppActive
,
5497 IN ESL_IO_MGMT
** ppFree
5500 ESL_PACKET
* pCurrentPacket
;
5501 ESL_IO_MGMT
* pIoNext
;
5502 ESL_PACKET
* pNextPacket
;
5503 ESL_PACKET
* pPacket
;
5505 ESL_SOCKET
* pSocket
;
5508 VERIFY_AT_TPL ( TPL_SOCKETS
);
5511 // Locate the active transmit packet
5513 pPacket
= pIo
->pPacket
;
5515 pSocket
= pPort
->pSocket
;
5520 pIo
->pPacket
= NULL
;
5523 // Remove the IO structure from the active list
5525 pIoNext
= *ppActive
;
5526 while (( NULL
!= pIoNext
) && ( pIoNext
!= pIo
) && ( pIoNext
->pNext
!= pIo
))
5528 pIoNext
= pIoNext
->pNext
;
5530 ASSERT ( NULL
!= pIoNext
);
5531 if ( pIoNext
== pIo
) {
5532 *ppActive
= pIo
->pNext
; // Beginning of list
5535 pIoNext
->pNext
= pIo
->pNext
; // Middle of list
5539 // Free the IO structure
5541 pIo
->pNext
= *ppFree
;
5545 // Display the results
5547 DEBUG (( DEBUG_TX
| DEBUG_INFO
,
5548 "0x%08x: pIo Released\r\n",
5552 // Save any transmit error
5554 if ( EFI_ERROR ( Status
)) {
5555 if ( !EFI_ERROR ( pSocket
->TxError
)) {
5556 pSocket
->TxError
= Status
;
5558 DEBUG (( DEBUG_TX
| DEBUG_INFO
,
5559 "ERROR - Transmit failure for %apacket 0x%08x, Status: %r\r\n",
5565 // Empty the normal transmit list
5567 pCurrentPacket
= pPacket
;
5568 pNextPacket
= *ppQueueHead
;
5569 while ( NULL
!= pNextPacket
) {
5570 pPacket
= pNextPacket
;
5571 pNextPacket
= pPacket
->pNext
;
5572 EslSocketPacketFree ( pPacket
, DEBUG_TX
);
5574 *ppQueueHead
= NULL
;
5575 *ppQueueTail
= NULL
;
5576 pPacket
= pCurrentPacket
;
5579 DEBUG (( DEBUG_TX
| DEBUG_INFO
,
5580 "0x%08x: %apacket transmitted %d bytes successfully\r\n",
5586 // Verify the transmit engine is still running
5588 if ( !pPort
->bCloseNow
) {
5590 // Start the next packet transmission
5592 EslSocketTxStart ( pPort
,
5601 // Release this packet
5603 EslSocketPacketFree ( pPacket
, DEBUG_TX
);
5606 // Finish the close operation if necessary
5608 if ( PORT_STATE_CLOSE_STARTED
<= pPort
->State
) {
5610 // Indicate that the transmit is complete
5612 EslSocketPortCloseTxDone ( pPort
);
5619 /** Transmit data using a network connection.
5621 This support routine starts a transmit operation on the
5622 underlying network layer.
5624 The network specific code calls this routine to start a
5625 transmit operation. See the \ref TransmitEngine section.
5627 @param[in] pPort Address of an ::ESL_PORT structure
5628 @param[in] ppQueueHead Transmit queue head address
5629 @param[in] ppQueueTail Transmit queue tail address
5630 @param[in] ppActive Active transmit queue address
5631 @param[in] ppFree Free transmit queue address
5635 IN ESL_PORT
* pPort
,
5636 IN ESL_PACKET
** ppQueueHead
,
5637 IN ESL_PACKET
** ppQueueTail
,
5638 IN ESL_IO_MGMT
** ppActive
,
5639 IN ESL_IO_MGMT
** ppFree
5644 ESL_PACKET
* pNextPacket
;
5645 ESL_PACKET
* pPacket
;
5646 VOID
** ppTokenData
;
5647 ESL_SOCKET
* pSocket
;
5655 Status
= EFI_SUCCESS
;
5658 // Get the packet from the queue head
5660 pPacket
= *ppQueueHead
;
5662 if (( NULL
!= pPacket
) && ( NULL
!= pIo
)) {
5663 pSocket
= pPort
->pSocket
;
5665 // *ppQueueHead: pSocket->pRxPacketListHead or pSocket->pRxOobPacketListHead
5668 // +------------+ +------------+ +------------+
5669 // Data | ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL
5670 // +------------+ +------------+ +------------+
5673 // *ppQueueTail: pSocket->pRxPacketListTail or pSocket->pRxOobPacketListTail
5676 // Remove the packet from the queue
5678 pNextPacket
= pPacket
->pNext
;
5679 *ppQueueHead
= pNextPacket
;
5680 if ( NULL
== pNextPacket
) {
5681 *ppQueueTail
= NULL
;
5683 pPacket
->pNext
= NULL
;
5686 // Eliminate the need for IP4 and UDP4 specific routines by
5687 // connecting the token with the TX data control structure here.
5689 // +--------------------+ +--------------------+
5690 // | ESL_IO_MGMT | | ESL_PACKET |
5692 // | +---------------+ +----------------+ |
5693 // | | Token | | Buffer Length | |
5694 // | | TxData --> | Buffer Address | |
5695 // | | | +----------------+---+
5696 // | | Event | | Data Buffer |
5697 // +----+---------------+ | |
5698 // +--------------------+
5700 // Compute the address of the TxData pointer in the token
5702 pBuffer
= (UINT8
*)&pIo
->Token
;
5703 pBuffer
= &pBuffer
[ pSocket
->TxTokenOffset
];
5704 ppTokenData
= (VOID
**)pBuffer
;
5707 // Compute the address of the TX data control structure in the packet
5709 // * EFI_IP4_TRANSMIT_DATA
5710 // * EFI_TCP4_TRANSMIT_DATA
5711 // * EFI_UDP4_TRANSMIT_DATA
5713 pBuffer
= (UINT8
*)pPacket
;
5714 pBuffer
= &pBuffer
[ pSocket
->TxPacketOffset
];
5717 // Connect the token to the transmit data control structure
5719 *ppTokenData
= (VOID
**)pBuffer
;
5722 // Display the results
5724 DEBUG (( DEBUG_TX
| DEBUG_INFO
,
5725 "0x%08x: pIo allocated for pPacket: 0x%08x\r\n",
5730 // Start the transmit operation
5732 Status
= pPort
->pfnTxStart ( pPort
->pProtocol
.v
,
5734 if ( !EFI_ERROR ( Status
)) {
5736 // Connect the structures
5738 pIo
->pPacket
= pPacket
;
5741 // +-------------+ +-------------+ +-------------+
5742 // Free | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
5743 // +-------------+ +-------------+ +-------------+
5746 // *ppFree: pPort->pTxFree or pTxOobFree
5749 // Remove the IO structure from the queue
5751 *ppFree
= pIo
->pNext
;
5754 // *ppActive: pPort->pTxActive or pTxOobActive
5757 // +-------------+ +-------------+ +-------------+
5758 // Active | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
5759 // +-------------+ +-------------+ +-------------+
5762 // Mark this packet as active
5764 pIo
->pPacket
= pPacket
;
5765 pIo
->pNext
= *ppActive
;
5770 // Display the transmit error
5772 DEBUG (( DEBUG_TX
| DEBUG_INFO
,
5773 "0x%08x, 0x%08x: pIo, pPacket transmit failure: %r\r\n",
5777 if ( EFI_SUCCESS
== pSocket
->TxError
) {
5778 pSocket
->TxError
= Status
;
5782 // Free the IO structure
5784 pIo
->pNext
= *ppFree
;
5788 // Discard the transmit buffer
5790 EslSocketPacketFree ( pPacket
, DEBUG_TX
);