2 Implement the socket support for the socket layer.
5 * Bound - pSocket->PortList is not NULL
6 * Listen - AcceptWait event is not NULL
8 Copyright (c) 2011, Intel Corporation
9 All rights reserved. This program and the accompanying materials
10 are licensed and made available under the terms and conditions of the BSD License
11 which accompanies this distribution. The full text of the license may be found at
12 http://opensource.org/licenses/bsd-license.php
14 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
15 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 \section DataStructures Data Structures
22 +-------------+ +-------------+ +-------------+
23 Service Lists | ::ESL_SERVICE |-->| ESL_SERVICE |-->| ESL_SERVICE |--> NULL (pNext)
24 +-------------+ +-------------+ +-------------+
26 pUdp4List ^ | pTcp4List | |
31 | ::ESL_LAYER | ::mEslLayer | |
35 +-------------+ +-------------+ +-------------+
36 | ::ESL_SOCKET |-->| ::ESL_PORT |-->| ESL_PORT |--> NULL (pLinkSocket)
37 +-------------+ +-------------+ +-------------+
41 +-------------+ +-------------+
42 | ESL_SOCKET |-->| ESL_PORT |--> NULL
43 +-------------+ +-------------+
47 (pNext) | | | | (pLinkService)
48 | | | | pRxPacketListHead
49 | | | `-----------------------------------------------.
50 | | | pRxOobPacketListHead |
51 | | `--------------------------------. |
52 | | pTxPacketListHead | |
53 | `---------------. | |
54 pTxOobPacketListHead | | | |
56 +------------+ +------------+ +------------+ +------------+
57 | ::ESL_PACKET | | ESL_PACKET | | ESL_PACKET | | ESL_PACKET |
58 +------------+ +------------+ +------------+ +------------+
61 +------------+ +------------+ +------------+ +------------+
62 | ESL_PACKET | | ESL_PACKET | | ESL_PACKET | | ESL_PACKET |
63 +------------+ +------------+ +------------+ +------------+
71 ::mEslLayer is the one and only ::ESL_LAYER structure. It connects directly or
72 indirectly to the other data structures. The ESL_LAYER structure has a unique
73 service list for each of the network protocol interfaces.
75 ::ESL_SERVICE manages the network interfaces for a given transport type (IP4, TCP4, UDP4, etc.)
77 ::ESL_SOCKET manages the activity for a single socket instance. As such, it contains
78 the ::EFI_SOCKET_PROTOCOL structure which the BSD socket library uses as the object
79 reference and the API into the EFI socket library.
81 ::ESL_PORT manages the connection with a single instance of the lower layer network.
82 This structure is the socket equivalent of an IP connection or a TCP or UDP port.
84 ::ESL_PACKET buffers data for transmit and receive. There are four queues connected
85 to the ::ESL_SOCKET that manage the data:
87 <li>ESL_SOCKET::pRxPacketListHead - Normal (low) priority receive data</li>
88 <li>ESL_SOCKET::pRxOobPacketListHead - High (out-of-band or urgent) priority receive data</li>
89 <li>ESL_SOCKET::pTxPacketListHead - Normal (low) priority transmit data</li>
90 <li>ESL_SOCKET::pTxOobPacketListHead - High (out-of-band or urgent) priority transmit data</li>
92 The selection of the transmit queue is controlled by the MSG_OOB flag on the transmit
93 request as well as the socket option SO_OOBINLINE. The receive queue is selected by
94 the URGENT data flag for TCP and the setting of the socket option SO_OOBINLINE.
96 Data structure synchronization is done by raising TPL to TPL_SOCKET. Modifying
97 critical elements within the data structures must be done at this TPL. TPL is then
98 restored to the previous level. Note that the code verifies that all callbacks are
99 entering at TPL_SOCKETS for proper data structure synchronization.
101 \section PortCloseStateMachine Port Close State Machine
103 The port close state machine walks the port through the necessary
104 states to stop activity on the port and get it into a state where
105 the resources may be released. The state machine consists of the
106 following arcs and states:
110 +--------------------------+
112 +--------------------------+
114 | ::EslSocketPortCloseStart
116 +--------------------------+
117 | PORT_STATE_CLOSE_STARTED |
118 +--------------------------+
120 | ::EslSocketPortCloseTxDone
122 +--------------------------+
123 | PORT_STATE_CLOSE_TX_DONE |
124 +--------------------------+
126 | ::EslSocketPortCloseComplete
128 +--------------------------+
129 | PORT_STATE_CLOSE_DONE |
130 +--------------------------+
132 | ::EslSocketPortCloseRxDone
134 +--------------------------+
135 | PORT_STATE_CLOSE_RX_DONE |
136 +--------------------------+
138 | ::EslSocketPortClose
140 +--------------------------+
142 +--------------------------+
147 <li>Arc: ::EslSocketPortCloseStart - Marks the port as closing and
148 initiates the port close operation</li>
149 <li>State: PORT_STATE_CLOSE_STARTED</li>
150 <li>Arc: ::EslSocketPortCloseTxDone - Waits until all of the transmit
151 operations to complete. After all of the transmits are complete,
152 this routine initiates the network specific close operation by calling
153 through ESL_PROTOCOL_API::pfnPortCloseOp. One such routine is
154 ::EslTcp4PortCloseOp.
156 <li>State: PORT_STATE_CLOSE_TX_DONE</li>
157 <li>Arc: ::EslSocketPortCloseComplete - Called when the close operation is
158 complete. After the transition to PORT_STATE_CLOSE_DONE,
159 this routine calls ::EslSocketRxCancel to abort the pending receive operations.
161 <li>State: PORT_STATE_CLOSE_DONE</li>
162 <li>Arc: ::EslSocketPortCloseRxDone - Waits until all of the receive
163 operation have been cancelled. After the transition to
164 PORT_STATE_CLOSE_RX_DONE, this routine calls ::EslSocketPortClose.
166 <li>State: PORT_STATE_CLOSE_RX_DONE</li>
167 <li>Arc: ::EslSocketPortClose - This routine discards any receive buffers
168 using a network specific support routine via ESL_PROTOCOL_API::pfnPacketFree.
169 This routine then releases the port resources allocated by ::EslSocketPortAllocate
170 and calls the network specific port close routine (e.g. ::EslTcp4PortClose)
171 via ESL_PROTOCOL_API::pfnPortClose to release any network specific resources.
176 \section ReceiveEngine Receive Engine
178 The receive path accepts data from the network and queues (buffers) it for the
179 application. Flow control is applied once a maximum amount of buffering is reached
180 and is released when the buffer usage drops below that limit. Eventually the
181 application requests data from the socket which removes entries from the queue and
184 The receive engine is the state machine which reads data from the network and
185 fills the queue with received packets. The receive engine uses two data structures
186 to manage the network receive opeations and the buffers.
188 At a high level, the ::ESL_IO_MGMT structures are managing the tokens and
189 events for the interface to the UEFI network stack. The ::ESL_PACKET
190 structures are managing the receive data buffers. The receive engine
191 connects these two structures in the network specific receive completion
211 The ::ESL_IO_MGMT structures are allocated as part of the ::ESL_PORT structure in
212 ::EslSocketPortAllocate. The ESL_IO_MGMT structures are separated and placed on
213 the free list by calling ::EslSocketIoInit. The ESL_IO_MGMT structure contains
214 the network layer specific receive completion token and event. The receive engine
215 is eventually shutdown by ::EslSocketPortCloseTxDone and the resources in these
216 structures are released in ::EslSocketPortClose by a call to ::EslSocketIoFree.
223 +-------------+ +-------------+ +-------------+
224 Active | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
225 +-------------+ +-------------+ +-------------+
227 +-------------+ +-------------+ +-------------+
228 Free | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
229 +-------------+ +-------------+ +-------------+
235 The receive engine is started by calling ::EslSocketRxStart. Flow control pauses
236 the receive engine by stopping the calls to EslSocketRxStart when the amount of
237 receive data waiting for the application meets or exceeds MAX_RX_DATA. After
238 the application reads enough data that the amount of buffering drops below this
239 limit, the calls to EslSockeRxStart continue which releases the flow control.
241 Receive flow control is applied when the port is created, since no receive
242 operation are pending to the low layer network driver. The flow control gets
243 released when the low layer network port is configured or the first receive
244 operation is posted. Flow control remains in the released state until the
245 maximum buffer space is consumed. During this time, ::EslSocketRxComplete
246 calls ::EslSocketRxStart. Flow control is applied in EslSocketRxComplete
247 by skipping the call to EslSocketRxStart. Flow control is eventually
248 released in ::EslSocketReceive when the buffer space drops below the
249 maximum amount causing EslSocketReceive to call EslSocketRxStart.
253 +------------+ +------------+
254 High .----->| ESL_PACKET |-->| ESL_PACKET |--> NULL (pNext)
255 Priority | +------------+ +------------+
257 | pRxOobPacketListHead
263 Priority | +------------+ +------------+ +------------+
264 `----->| ::ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL
265 +------------+ +------------+ +------------+
269 ::EslSocketRxStart connects an ::ESL_PACKET structure to the ::ESL_IO_MGMT structure
270 and then calls the network layer to start the receive operation. Upon
271 receive completion, ::EslSocketRxComplete breaks the connection between these
272 structrues and places the ESL_IO_MGMT structure onto the ESL_PORT::pRxFree list to
273 make token and event available for another receive operation. EslSocketRxComplete
274 then queues the ESL_PACKET structure (data packet) to either the
275 ESL_SOCKET::pRxOobPacketListTail or ESL_SOCKET::pRxPacketListTail depending on
276 whether urgent or normal data was received. Finally ::EslSocketRxComplete attempts
277 to start another receive operation.
281 Setup for IP4 and UDP4
283 +--------------------+
289 +----+---------------+
292 +--------------------+
297 +----+---------------+
299 Completion for IP4 and UDP4
301 +--------------------+ +----------------------+
302 | ESL_IO_MGMT | | Data Buffer |
303 | | | (Driver owned) |
304 | +---------------+ +----------------------+
307 | | | +----------------------+
308 | | RxData --> | EFI_IP4_RECEIVE_DATA |
309 +----+---------------+ | (Driver owned) |
310 | +----------------------+
312 +--------------------+ .
315 | +---------------+ .
316 | | pRxData --> NULL .......
317 +----+---------------+
320 Setup and completion for TCP4
322 +--------------------+ +--------------------------+
323 | ESL_IO_MGMT |-->| ESL_PACKET |
325 | +---------------+ +----------------------+ |
326 | | Token | | EFI_IP4_RECEIVE_DATA | |
328 | | | +----------------------+---+
329 | | Event | | Data Buffer |
330 +----+---------------+ | |
332 +--------------------------+
336 To minimize the number of buffer copies, the data is not copied until the
337 application makes a receive call. At this point socket performs a single copy
338 in the receive path to move the data from the buffer filled by the network layer
339 into the application's buffer.
341 The IP4 and UDP4 drivers go one step further to reduce buffer copies. They
342 allow the socket layer to hold on to the actual receive buffer until the
343 application has performed a receive operation or closes the socket. Both
344 of theses operations return the buffer to the lower layer network driver
345 by calling ESL_PROTOCOL_API::pfnPacketFree.
347 When a socket application wants to receive data it indirectly calls
348 ::EslSocketReceive to remove data from one of the receive data queues. This routine
349 removes the next available packet from ESL_SOCKET::pRxOobPacketListHead or
350 ESL_SOCKET::pRxPacketListHead and copies the data from the packet
351 into the application's buffer. For SOCK_STREAM sockets, if the packet
352 contains more data then the ESL_PACKET structures remains at the head of the
353 receive queue for the next application receive
354 operation. For SOCK_DGRAM, SOCK_RAW and SOCK_SEQ_PACKET sockets, the ::ESL_PACKET
355 structure is removed from the head of the receive queue and any remaining data is
356 discarded as the packet is placed on the free queue.
358 During socket layer shutdown, ::EslSocketShutdown calls ::EslSocketRxCancel to
359 cancel any pending receive operations. EslSocketRxCancel calls the network specific
360 cancel routine using ESL_PORT::pfnRxCancel.
363 \section TransmitEngine Transmit Engine
365 Application calls to ::EslSocketTransmit cause data to be copied into a buffer.
366 The buffer exists as an extension to an ESL_PACKET structure and the structure
367 is placed at the end of the transmit queue.
371 *ppQueueHead: pSocket->pRxPacketListHead or pSocket->pRxOobPacketListHead
374 +------------+ +------------+ +------------+
375 Data | ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL
376 +------------+ +------------+ +------------+
379 *ppQueueTail: pSocket->pRxPacketListTail or pSocket->pRxOobPacketListTail
383 There are actually two transmit queues the normal or low priority queue which is
384 the default and the urgent or high priority queue which is addressed by specifying
385 the MSG_OOB flag during the transmit request. Associated with each queue is a
386 transmit engine which is responsible for sending the data in that queue.
388 The transmit engine is the state machine which removes entries from the head
389 of the transmit queue and causes the data to be sent over the network.
393 +--------------------+ +--------------------+
394 | ESL_IO_MGMT | | ESL_PACKET |
396 | +---------------+ +----------------+ |
397 | | Token | | Buffer Length | |
398 | | TxData --> | Buffer Address | |
399 | | | +----------------+---+
400 | | Event | | Data Buffer |
401 +----+---------------+ | |
402 +--------------------+
405 At a high level, the transmit engine uses a couple of data structures
406 to manage the data flow. The ::ESL_IO_MGMT structures manage the tokens and
407 events for the interface to the UEFI network stack. The ::ESL_PACKET
408 structures manage the data buffers that get sent. The transmit
409 engine connects these two structures prior to transmission and disconnects
410 them upon completion.
414 pPort->pTxActive or pTxOobActive
417 +-------------+ +-------------+ +-------------+
418 Active | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
419 +-------------+ +-------------+ +-------------+
421 +-------------+ +-------------+ +-------------+
422 Free | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
423 +-------------+ +-------------+ +-------------+
426 pPort->pTxFree or pTxOobFree
430 The transmit engine manages multiple transmit operations using the
431 active and free lists shown above. ::EslSocketPortAllocate allocates the
432 ::ESL_IO_MGMT structures as an extension to the ::ESL_PORT structure.
433 This routine places the ESL_IO_MGMT structures on the free list by calling
434 ::EslSocketIoInit. During their lifetime, the ESL_IO_MGMT structures
435 will move from the free list to the active list and back again. The
436 active list contains the packets that are actively being processed by
437 the UEFI network stack. Eventually the ESL_IO_MGMT structures will be
438 removed from the free list and be deallocated by the EslSocketPortClose
441 The network specific code calls the ::EslSocketTxStart routine
442 to hand a packet to the network stack. EslSocketTxStart connects
443 the transmit packet (::ESL_PACKET) to an ::ESL_IO_MGMT structure
444 and then queues the result to one of the active lists:
445 ESL_PORT::pTxActive or ESL_PORT::pTxOobActive. The routine then
446 hands the packet to the network stack.
448 Upon completion, the network specific TxComplete routine calls
449 ::EslSocketTxComplete to disconnect the transmit packet from the
450 ESL_IO_MGMT structure and frees the ::ESL_PACKET structure by calling
451 ::EslSocketPacketFree. The routine places the ::ESL_IO_MGMT structure
452 into the free list either ESL_PORT::pTxFree or ESL_PORT::pTxOobFree.
453 EslSocketTxComplete then starts the next transmit operation while
454 the socket is active or calls the ::EslSocketPortCloseTxDone routine
455 when the socket is shutting down.
463 Socket driver connection points
465 List the network stack connection points for the socket driver.
467 CONST ESL_SOCKET_BINDING cEslSocketBinding
[] = {
469 &gEfiIp4ServiceBindingProtocolGuid
,
470 &gEfiIp4ProtocolGuid
,
472 OFFSET_OF ( ESL_LAYER
, pIp4List
),
475 0 }, // TX Oob buffers
477 &gEfiTcp4ServiceBindingProtocolGuid
,
478 &gEfiTcp4ProtocolGuid
,
479 &mEslTcp4ServiceGuid
,
480 OFFSET_OF ( ESL_LAYER
, pTcp4List
),
483 4 }, // TX Oob buffers
485 &gEfiTcp6ServiceBindingProtocolGuid
,
486 &gEfiTcp6ProtocolGuid
,
487 &mEslTcp6ServiceGuid
,
488 OFFSET_OF ( ESL_LAYER
, pTcp6List
),
491 4 }, // TX Oob buffers
493 &gEfiUdp4ServiceBindingProtocolGuid
,
494 &gEfiUdp4ProtocolGuid
,
495 &mEslUdp4ServiceGuid
,
496 OFFSET_OF ( ESL_LAYER
, pUdp4List
),
499 0 }, // TX Oob buffers
501 &gEfiUdp6ServiceBindingProtocolGuid
,
502 &gEfiUdp6ProtocolGuid
,
503 &mEslUdp6ServiceGuid
,
504 OFFSET_OF ( ESL_LAYER
, pUdp6List
),
507 0 } // TX Oob buffers
510 CONST UINTN cEslSocketBindingEntries
= DIM ( cEslSocketBinding
);
513 APIs to support the various socket types for the v4 network stack.
515 CONST ESL_PROTOCOL_API
* cEslAfInetApi
[] = {
517 &cEslTcp4Api
, // SOCK_STREAM
518 &cEslUdp4Api
, // SOCK_DGRAM
519 &cEslIp4Api
, // SOCK_RAW
521 &cEslTcp4Api
// SOCK_SEQPACKET
525 Number of entries in the v4 API array ::cEslAfInetApi.
527 CONST
int cEslAfInetApiSize
= DIM ( cEslAfInetApi
);
531 APIs to support the various socket types for the v6 network stack.
533 CONST ESL_PROTOCOL_API
* cEslAfInet6Api
[] = {
535 &cEslTcp6Api
, // SOCK_STREAM
536 &cEslUdp6Api
, // SOCK_DGRAM
539 &cEslTcp6Api
// SOCK_SEQPACKET
543 Number of entries in the v6 API array ::cEslAfInet6Api.
545 CONST
int cEslAfInet6ApiSize
= DIM ( cEslAfInet6Api
);
549 Global management structure for the socket layer.
555 Initialize an endpoint for network communication.
557 This routine initializes the communication endpoint.
559 The ::socket routine calls this routine indirectly to create
560 the communication endpoint.
562 @param [in] pSocketProtocol Address of the socket protocol structure.
563 @param [in] domain Select the family of protocols for the client or server
564 application. See the ::socket documentation for values.
565 @param [in] type Specifies how to make the network connection.
566 See the ::socket documentation for values.
567 @param [in] protocol Specifies the lower layer protocol to use.
568 See the ::socket documentation for values.
569 @param [out] pErrno Address to receive the errno value upon completion.
571 @retval EFI_SUCCESS - Socket successfully created
572 @retval EFI_INVALID_PARAMETER - Invalid domain value, errno = EAFNOSUPPORT
573 @retval EFI_INVALID_PARAMETER - Invalid type value, errno = EINVAL
574 @retval EFI_INVALID_PARAMETER - Invalid protocol value, errno = EINVAL
579 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
586 CONST ESL_PROTOCOL_API
* pApi
;
587 CONST ESL_PROTOCOL_API
** ppApiArray
;
588 CONST ESL_PROTOCOL_API
** ppApiArrayEnd
;
590 ESL_SOCKET
* pSocket
;
599 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
602 // Set the default domain if necessary
604 if ( AF_UNSPEC
== domain
) {
612 Status
= EFI_SUCCESS
;
615 // Use break instead of goto
619 // Validate the domain value
621 if (( AF_INET
!= domain
)
622 && ( AF_INET6
!= domain
)
623 && ( AF_LOCAL
!= domain
)) {
624 DEBUG (( DEBUG_ERROR
| DEBUG_SOCKET
,
625 "ERROR - Invalid domain value\r\n" ));
626 Status
= EFI_INVALID_PARAMETER
;
627 errno
= EAFNOSUPPORT
;
632 // Determine the protocol APIs
636 if (( AF_INET
== domain
)
637 || ( AF_LOCAL
== domain
)) {
638 ppApiArray
= &cEslAfInetApi
[0];
639 ApiArraySize
= cEslAfInetApiSize
;
642 ppApiArray
= &cEslAfInet6Api
[0];
643 ApiArraySize
= cEslAfInet6ApiSize
;
647 // Set the default type if necessary
654 // Validate the type value
656 if (( type
>= ApiArraySize
)
657 || ( NULL
== ppApiArray
)
658 || ( NULL
== ppApiArray
[ type
])) {
659 DEBUG (( DEBUG_ERROR
| DEBUG_SOCKET
,
660 "ERROR - Invalid type value\r\n" ));
662 // The socket type is not supported
664 Status
= EFI_INVALID_PARAMETER
;
670 // Set the default protocol if necessary
672 pApi
= ppApiArray
[ type
];
673 if ( 0 == protocol
) {
674 protocol
= pApi
->DefaultProtocol
;
678 // Validate the protocol value
680 if (( pApi
->DefaultProtocol
!= protocol
)
681 && ( SOCK_RAW
!= type
)) {
682 Status
= EFI_INVALID_PARAMETER
;
685 // Assume that the driver supports this protocol
687 ppApiArray
= &cEslAfInetApi
[0];
688 ppApiArrayEnd
= &ppApiArray
[ cEslAfInetApiSize
];
689 while ( ppApiArrayEnd
> ppApiArray
) {
691 if ( protocol
== pApi
->DefaultProtocol
) {
696 if ( ppApiArrayEnd
<= ppApiArray
) {
698 // Verify against the IPv6 table
700 ppApiArray
= &cEslAfInet6Api
[0];
701 ppApiArrayEnd
= &ppApiArray
[ cEslAfInet6ApiSize
];
702 while ( ppApiArrayEnd
> ppApiArray
) {
704 if ( protocol
== pApi
->DefaultProtocol
) {
710 if ( ppApiArrayEnd
<= ppApiArray
) {
711 DEBUG (( DEBUG_ERROR
| DEBUG_SOCKET
,
712 "ERROR - The protocol is not supported!\r\n" ));
713 errno
= EPROTONOSUPPORT
;
718 // The driver does not support this protocol
720 DEBUG (( DEBUG_ERROR
| DEBUG_SOCKET
,
721 "ERROR - The protocol does not support this socket type!\r\n" ));
722 errno
= EPROTONOSUPPORT
;
728 // Save the socket attributes
730 pSocket
->pApi
= pApi
;
731 pSocket
->Domain
= domain
;
732 pSocket
->Type
= type
;
733 pSocket
->Protocol
= protocol
;
742 // Return the operation status
744 if ( NULL
!= pErrno
) {
747 DBG_EXIT_STATUS ( Status
);
753 Accept a network connection.
755 This routine calls the network specific layer to remove the next
756 connection from the FIFO.
758 The ::accept calls this routine to poll for a network
759 connection to the socket. When a connection is available
760 this routine returns the ::EFI_SOCKET_PROTOCOL structure address
761 associated with the new socket and the remote network address
764 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
766 @param [in] pSockAddr Address of a buffer to receive the remote
769 @param [in, out] pSockAddrLength Length in bytes of the address buffer.
770 On output specifies the length of the
771 remote network address.
773 @param [out] ppSocketProtocol Address of a buffer to receive the
774 ::EFI_SOCKET_PROTOCOL instance
775 associated with the new socket.
777 @param [out] pErrno Address to receive the errno value upon completion.
779 @retval EFI_SUCCESS New connection successfully created
780 @retval EFI_NOT_READY No connection is available
785 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
786 IN
struct sockaddr
* pSockAddr
,
787 IN OUT socklen_t
* pSockAddrLength
,
788 IN EFI_SOCKET_PROTOCOL
** ppSocketProtocol
,
792 ESL_SOCKET
* pNewSocket
;
793 ESL_SOCKET
* pSocket
;
802 Status
= EFI_SUCCESS
;
805 // Validate the socket
809 if ( NULL
!= pSocketProtocol
) {
810 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
815 if ( NULL
== pSocket
->pApi
->pfnAccept
) {
816 Status
= EFI_UNSUPPORTED
;
817 pSocket
->errno
= ENOTSUP
;
821 // Validate the sockaddr
823 if (( NULL
!= pSockAddr
)
824 && ( NULL
== pSockAddrLength
)) {
825 DEBUG (( DEBUG_ACCEPT
,
826 "ERROR - pSockAddr is NULL!\r\n" ));
827 Status
= EFI_INVALID_PARAMETER
;
828 pSocket
->errno
= EFAULT
;
832 // Synchronize with the socket layer
834 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
837 // Verify that the socket is in the listen state
839 if ( SOCKET_STATE_LISTENING
!= pSocket
->State
) {
840 DEBUG (( DEBUG_ACCEPT
,
841 "ERROR - Socket is not listening!\r\n" ));
842 if ( NULL
== pSocket
->pApi
->pfnAccept
) {
844 // Socket does not support listen
846 pSocket
->errno
= EOPNOTSUPP
;
847 Status
= EFI_UNSUPPORTED
;
851 // Socket supports listen, but not in listen state
853 pSocket
->errno
= EINVAL
;
854 Status
= EFI_NOT_STARTED
;
859 // Determine if a socket is available
861 if ( 0 == pSocket
->FifoDepth
) {
863 // No connections available
864 // Determine if any ports are available
866 if ( NULL
== pSocket
->pPortList
) {
868 // No ports available
870 Status
= EFI_DEVICE_ERROR
;
871 pSocket
->errno
= EINVAL
;
874 // Update the socket state
876 pSocket
->State
= SOCKET_STATE_NO_PORTS
;
880 // Ports are available
881 // No connection requests at this time
883 Status
= EFI_NOT_READY
;
884 pSocket
->errno
= EAGAIN
;
890 // Attempt to accept the connection and
891 // get the remote network address
893 pNewSocket
= pSocket
->pFifoHead
;
894 ASSERT ( NULL
!= pNewSocket
);
895 Status
= pSocket
->pApi
->pfnAccept ( pNewSocket
,
898 if ( !EFI_ERROR ( Status
)) {
900 // Remove the new socket from the list
902 pSocket
->pFifoHead
= pNewSocket
->pNextConnection
;
903 if ( NULL
== pSocket
->pFifoHead
) {
904 pSocket
->pFifoTail
= NULL
;
908 // Account for this socket
910 pSocket
->FifoDepth
-= 1;
913 // Update the new socket's state
915 pNewSocket
->State
= SOCKET_STATE_CONNECTED
;
916 pNewSocket
->bConfigured
= TRUE
;
917 DEBUG (( DEBUG_ACCEPT
,
918 "0x%08x: Socket connected\r\n",
925 // Release the socket layer synchronization
927 RESTORE_TPL ( TplPrevious
);
933 // Return the new socket
935 if (( NULL
!= ppSocketProtocol
)
936 && ( NULL
!= pNewSocket
)) {
937 *ppSocketProtocol
= &pNewSocket
->SocketProtocol
;
941 // Return the operation status
943 if ( NULL
!= pErrno
) {
944 if ( NULL
!= pSocket
) {
945 *pErrno
= pSocket
->errno
;
948 Status
= EFI_INVALID_PARAMETER
;
952 DBG_EXIT_STATUS ( Status
);
958 Allocate and initialize a ESL_SOCKET structure.
960 This support function allocates an ::ESL_SOCKET structure
961 and installs a protocol on ChildHandle. If pChildHandle is a
962 pointer to NULL, then a new handle is created and returned in
963 pChildHandle. If pChildHandle is not a pointer to NULL, then
964 the protocol installs on the existing pChildHandle.
966 @param [in, out] pChildHandle Pointer to the handle of the child to create.
967 If it is NULL, then a new handle is created.
968 If it is a pointer to an existing UEFI handle,
969 then the protocol is added to the existing UEFI
971 @param [in] DebugFlags Flags for debug messages
972 @param [in, out] ppSocket The buffer to receive an ::ESL_SOCKET structure address.
974 @retval EFI_SUCCESS The protocol was added to ChildHandle.
975 @retval EFI_INVALID_PARAMETER ChildHandle is NULL.
976 @retval EFI_OUT_OF_RESOURCES There are not enough resources available to create
978 @retval other The child handle was not created
984 IN OUT EFI_HANDLE
* pChildHandle
,
986 IN OUT ESL_SOCKET
** ppSocket
991 ESL_SOCKET
* pSocket
;
998 // Create a socket structure
1000 LengthInBytes
= sizeof ( *pSocket
);
1001 pSocket
= (ESL_SOCKET
*) AllocateZeroPool ( LengthInBytes
);
1002 if ( NULL
!= pSocket
) {
1003 DEBUG (( DebugFlags
| DEBUG_POOL
| DEBUG_INIT
,
1004 "0x%08x: Allocate pSocket, %d bytes\r\n",
1009 // Initialize the socket protocol
1011 pSocket
->Signature
= SOCKET_SIGNATURE
;
1012 pSocket
->SocketProtocol
.pfnAccept
= EslSocketAccept
;
1013 pSocket
->SocketProtocol
.pfnBind
= EslSocketBind
;
1014 pSocket
->SocketProtocol
.pfnClosePoll
= EslSocketClosePoll
;
1015 pSocket
->SocketProtocol
.pfnCloseStart
= EslSocketCloseStart
;
1016 pSocket
->SocketProtocol
.pfnConnect
= EslSocketConnect
;
1017 pSocket
->SocketProtocol
.pfnGetLocal
= EslSocketGetLocalAddress
;
1018 pSocket
->SocketProtocol
.pfnGetPeer
= EslSocketGetPeerAddress
;
1019 pSocket
->SocketProtocol
.pfnListen
= EslSocketListen
;
1020 pSocket
->SocketProtocol
.pfnOptionGet
= EslSocketOptionGet
;
1021 pSocket
->SocketProtocol
.pfnOptionSet
= EslSocketOptionSet
;
1022 pSocket
->SocketProtocol
.pfnPoll
= EslSocketPoll
;
1023 pSocket
->SocketProtocol
.pfnReceive
= EslSocketReceive
;
1024 pSocket
->SocketProtocol
.pfnShutdown
= EslSocketShutdown
;
1025 pSocket
->SocketProtocol
.pfnSocket
= EslSocket
;
1026 pSocket
->SocketProtocol
.pfnTransmit
= EslSocketTransmit
;
1028 pSocket
->MaxRxBuf
= MAX_RX_DATA
;
1029 pSocket
->MaxTxBuf
= MAX_TX_DATA
;
1032 // Install the socket protocol on the specified handle
1034 Status
= gBS
->InstallMultipleProtocolInterfaces (
1036 &gEfiSocketProtocolGuid
,
1037 &pSocket
->SocketProtocol
,
1040 if ( !EFI_ERROR ( Status
)) {
1041 DEBUG (( DebugFlags
| DEBUG_POOL
| DEBUG_INIT
| DEBUG_INFO
,
1042 "Installed: gEfiSocketProtocolGuid on 0x%08x\r\n",
1044 pSocket
->SocketProtocol
.SocketHandle
= *pChildHandle
;
1047 // Synchronize with the socket layer
1049 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
1052 // Add this socket to the list
1054 pLayer
= &mEslLayer
;
1055 pSocket
->pNext
= pLayer
->pSocketList
;
1056 pLayer
->pSocketList
= pSocket
;
1059 // Release the socket layer synchronization
1061 RESTORE_TPL ( TplPrevious
);
1064 // Return the socket structure address
1066 *ppSocket
= pSocket
;
1069 DEBUG (( DEBUG_ERROR
| DebugFlags
| DEBUG_POOL
| DEBUG_INIT
,
1070 "ERROR - Failed to install gEfiSocketProtocolGuid on 0x%08x, Status: %r\r\n",
1076 // Release the socket if necessary
1078 if ( EFI_ERROR ( Status
)) {
1079 gBS
->FreePool ( pSocket
);
1080 DEBUG (( DebugFlags
| DEBUG_POOL
| DEBUG_INIT
,
1081 "0x%08x: Free pSocket, %d bytes\r\n",
1083 sizeof ( *pSocket
)));
1088 Status
= EFI_OUT_OF_RESOURCES
;
1092 // Return the operation status
1094 DBG_EXIT_STATUS ( Status
);
1100 Bind a name to a socket.
1102 This routine calls the network specific layer to save the network
1103 address of the local connection point.
1105 The ::bind routine calls this routine to connect a name
1106 (network address and port) to a socket on the local machine.
1108 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
1110 @param [in] pSockAddr Address of a sockaddr structure that contains the
1111 connection point on the local machine. An IPv4 address
1112 of INADDR_ANY specifies that the connection is made to
1113 all of the network stacks on the platform. Specifying a
1114 specific IPv4 address restricts the connection to the
1115 network stack supporting that address. Specifying zero
1116 for the port causes the network layer to assign a port
1117 number from the dynamic range. Specifying a specific
1118 port number causes the network layer to use that port.
1120 @param [in] SockAddrLength Specifies the length in bytes of the sockaddr structure.
1122 @param [out] pErrno Address to receive the errno value upon completion.
1124 @retval EFI_SUCCESS - Socket successfully created
1129 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
1130 IN CONST
struct sockaddr
* pSockAddr
,
1131 IN socklen_t SockAddrLength
,
1135 EFI_HANDLE ChildHandle
;
1138 ESL_SERVICE
** ppServiceListHead
;
1139 ESL_SOCKET
* pSocket
;
1140 ESL_SERVICE
* pService
;
1141 EFI_SERVICE_BINDING_PROTOCOL
* pServiceBinding
;
1143 EFI_TPL TplPrevious
;
1150 Status
= EFI_SUCCESS
;
1153 // Validate the socket
1156 if ( NULL
!= pSocketProtocol
) {
1157 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
1160 // Validate the structure pointer
1163 if ( NULL
== pSockAddr
) {
1164 DEBUG (( DEBUG_BIND
,
1165 "ERROR - pSockAddr is NULL!\r\n" ));
1166 Status
= EFI_INVALID_PARAMETER
;
1167 pSocket
->errno
= EFAULT
;
1171 // Validate the local address length
1173 else if ( SockAddrLength
< pSocket
->pApi
->MinimumAddressLength
) {
1174 DEBUG (( DEBUG_BIND
,
1175 "ERROR - Invalid bind name length: %d\r\n",
1177 Status
= EFI_INVALID_PARAMETER
;
1178 pSocket
->errno
= EINVAL
;
1182 // Validate the shutdown state
1184 else if ( pSocket
->bRxDisable
|| pSocket
->bTxDisable
) {
1185 DEBUG (( DEBUG_BIND
,
1186 "ERROR - Shutdown has been called on socket 0x%08x\r\n",
1188 pSocket
->errno
= EINVAL
;
1189 Status
= EFI_INVALID_PARAMETER
;
1193 // Verify the socket state
1195 else if ( SOCKET_STATE_NOT_CONFIGURED
!= pSocket
->State
) {
1196 DEBUG (( DEBUG_BIND
,
1197 "ERROR - The socket 0x%08x is already configured!\r\n",
1199 pSocket
->errno
= EINVAL
;
1200 Status
= EFI_ALREADY_STARTED
;
1204 // Synchronize with the socket layer
1206 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
1209 // Assume no ports are available
1211 pSocket
->errno
= EADDRNOTAVAIL
;
1212 Status
= EFI_INVALID_PARAMETER
;
1215 // Walk the list of services
1217 pBuffer
= (UINT8
*)&mEslLayer
;
1218 pBuffer
= &pBuffer
[ pSocket
->pApi
->ServiceListOffset
];
1219 ppServiceListHead
= (ESL_SERVICE
**)pBuffer
;
1220 pService
= *ppServiceListHead
;
1221 while ( NULL
!= pService
) {
1225 pServiceBinding
= pService
->pServiceBinding
;
1227 Status
= pServiceBinding
->CreateChild ( pServiceBinding
,
1229 if ( !EFI_ERROR ( Status
)) {
1230 DEBUG (( DEBUG_BIND
| DEBUG_POOL
,
1231 "0x%08x: %s port handle created\r\n",
1233 pService
->pSocketBinding
->pName
));
1238 Status
= EslSocketPortAllocate ( pSocket
,
1247 DEBUG (( DEBUG_BIND
| DEBUG_POOL
,
1248 "ERROR - Failed to open %s port handle, Status: %r\r\n",
1249 pService
->pSocketBinding
->pName
,
1254 // Set the next service
1256 pService
= pService
->pNext
;
1260 // Verify that at least one network connection was found
1262 if ( NULL
!= pSocket
->pPortList
) {
1263 Status
= EFI_SUCCESS
;
1266 if ( EADDRNOTAVAIL
== pSocket
->errno
) {
1267 DEBUG (( DEBUG_BIND
| DEBUG_POOL
| DEBUG_INIT
,
1268 "ERROR - Socket address is not available!\r\n" ));
1270 if ( EADDRINUSE
== pSocket
->errno
) {
1271 DEBUG (( DEBUG_BIND
| DEBUG_POOL
| DEBUG_INIT
,
1272 "ERROR - Socket address is in use!\r\n" ));
1274 Status
= EFI_INVALID_PARAMETER
;
1278 // Mark this socket as bound if successful
1280 if ( !EFI_ERROR ( Status
)) {
1281 pSocket
->State
= SOCKET_STATE_BOUND
;
1286 // Release the socket layer synchronization
1288 RESTORE_TPL ( TplPrevious
);
1293 // Return the operation status
1295 if ( NULL
!= pErrno
) {
1296 if ( NULL
!= pSocket
) {
1297 *pErrno
= pSocket
->errno
;
1300 Status
= EFI_INVALID_PARAMETER
;
1304 DBG_EXIT_STATUS ( Status
);
1310 Test the bind configuration.
1312 @param [in] pPort Address of the ::ESL_PORT structure.
1313 @param [in] ErrnoValue errno value if test fails
1315 @retval EFI_SUCCESS The connection was successfully established.
1316 @retval Others The connection attempt failed.
1321 IN ESL_PORT
* pPort
,
1332 // Locate the configuration data
1334 pBuffer
= (UINT8
*)pPort
;
1335 pBuffer
= &pBuffer
[ pPort
->pSocket
->pApi
->ConfigDataOffset
];
1336 pConfigData
= (VOID
*)pBuffer
;
1339 // Attempt to use this configuration
1341 Status
= pPort
->pfnConfigure ( pPort
->pProtocol
.v
, pConfigData
);
1342 if ( EFI_ERROR ( Status
)) {
1343 DEBUG (( DEBUG_WARN
| DEBUG_BIND
,
1344 "WARNING - Port 0x%08x failed configuration, Status: %r\r\n",
1347 pPort
->pSocket
->errno
= ErrnoValue
;
1353 Status
= pPort
->pfnConfigure ( pPort
->pProtocol
.v
, NULL
);
1354 if ( EFI_ERROR ( Status
)) {
1355 DEBUG (( DEBUG_ERROR
| DEBUG_BIND
,
1356 "ERROR - Port 0x%08x failed configuration reset, Status: %r\r\n",
1359 ASSERT ( EFI_SUCCESS
== Status
);
1364 // Return the operation status
1366 DBG_EXIT_STATUS ( Status
);
1372 Determine if the socket is closed
1374 This routine checks the state of the socket to determine if
1375 the network specific layer has completed the close operation.
1377 The ::close routine polls this routine to determine when the
1378 close operation is complete. The close operation needs to
1379 reverse the operations of the ::EslSocketAllocate routine.
1381 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
1382 @param [out] pErrno Address to receive the errno value upon completion.
1384 @retval EFI_SUCCESS Socket successfully closed
1385 @retval EFI_NOT_READY Close still in progress
1386 @retval EFI_ALREADY Close operation already in progress
1387 @retval Other Failed to close the socket
1391 EslSocketClosePoll (
1392 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
1398 ESL_SOCKET
* pNextSocket
;
1399 ESL_SOCKET
* pSocket
;
1401 EFI_TPL TplPrevious
;
1409 Status
= EFI_SUCCESS
;
1412 // Synchronize with the socket layer
1414 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
1417 // Locate the socket
1419 pLayer
= &mEslLayer
;
1420 pNextSocket
= pLayer
->pSocketList
;
1421 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
1422 while ( NULL
!= pNextSocket
) {
1423 if ( pNextSocket
== pSocket
) {
1425 // Determine if the socket is in the closing state
1427 if ( SOCKET_STATE_CLOSED
== pSocket
->State
) {
1429 // Walk the list of ports
1431 if ( NULL
== pSocket
->pPortList
) {
1433 // All the ports are closed
1434 // Close the WaitAccept event if necessary
1436 if ( NULL
!= pSocket
->WaitAccept
) {
1437 Status
= gBS
->CloseEvent ( pSocket
->WaitAccept
);
1438 if ( !EFI_ERROR ( Status
)) {
1439 DEBUG (( DEBUG_SOCKET
| DEBUG_CLOSE
| DEBUG_POOL
,
1440 "0x%08x: Closed WaitAccept event\r\n",
1441 pSocket
->WaitAccept
));
1443 // Return the transmit status
1445 Status
= pSocket
->TxError
;
1446 if ( EFI_ERROR ( Status
)) {
1447 pSocket
->errno
= EIO
;
1451 DEBUG (( DEBUG_ERROR
| DEBUG_SOCKET
| DEBUG_CLOSE
| DEBUG_POOL
,
1452 "ERROR - Failed to close the WaitAccept event, Status: %r\r\n",
1454 ASSERT ( EFI_SUCCESS
== Status
);
1460 // At least one port is still open
1462 Status
= EFI_NOT_READY
;
1468 // SocketCloseStart was not called
1470 Status
= EFI_NOT_STARTED
;
1477 // Set the next socket
1479 pNextSocket
= pNextSocket
->pNext
;
1483 // Handle the error case where the socket was already closed
1485 if ( NULL
== pSocket
) {
1489 Status
= EFI_NOT_FOUND
;
1494 // Release the socket layer synchronization
1496 RESTORE_TPL ( TplPrevious
);
1499 // Return the operation status
1501 if ( NULL
!= pErrno
) {
1504 DBG_EXIT_STATUS ( Status
);
1510 Start the close operation on the socket
1512 This routine calls the network specific layer to initiate the
1513 close state machine. This routine then calls the network
1514 specific layer to determine if the close state machine has gone
1515 to completion. The result from this poll is returned to the
1518 The ::close routine calls this routine to start the close
1519 operation which reverses the operations of the
1520 ::EslSocketAllocate routine. The close routine then polls
1521 the ::EslSocketClosePoll routine to determine when the
1524 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
1525 @param [in] bCloseNow Boolean to control close behavior
1526 @param [out] pErrno Address to receive the errno value upon completion.
1528 @retval EFI_SUCCESS Socket successfully closed
1529 @retval EFI_NOT_READY Close still in progress
1530 @retval EFI_ALREADY Close operation already in progress
1531 @retval Other Failed to close the socket
1535 EslSocketCloseStart (
1536 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
1537 IN BOOLEAN bCloseNow
,
1542 ESL_PORT
* pNextPort
;
1544 ESL_SOCKET
* pSocket
;
1546 EFI_TPL TplPrevious
;
1553 Status
= EFI_SUCCESS
;
1557 // Synchronize with the socket layer
1559 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
1562 // Determine if the socket is already closed
1564 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
1565 if ( SOCKET_STATE_CLOSED
> pSocket
->State
) {
1567 // Update the socket state
1569 pSocket
->State
= SOCKET_STATE_CLOSED
;
1572 // Walk the list of ports
1574 pPort
= pSocket
->pPortList
;
1575 while ( NULL
!= pPort
) {
1577 // Start closing the ports
1579 pNextPort
= pPort
->pLinkSocket
;
1580 Status
= EslSocketPortCloseStart ( pPort
,
1582 DEBUG_CLOSE
| DEBUG_LISTEN
| DEBUG_CONNECTION
);
1583 if (( EFI_SUCCESS
!= Status
)
1584 && ( EFI_NOT_READY
!= Status
)) {
1590 // Set the next port
1596 // Attempt to finish closing the socket
1598 if ( NULL
== pPort
) {
1599 Status
= EslSocketClosePoll ( pSocketProtocol
, &errno
);
1603 Status
= EFI_NOT_READY
;
1608 // Release the socket layer synchronization
1610 RESTORE_TPL ( TplPrevious
);
1613 // Return the operation status
1615 if ( NULL
!= pErrno
) {
1618 DBG_EXIT_STATUS ( Status
);
1624 Connect to a remote system via the network.
1626 This routine calls the network specific layer to establish
1627 the remote system address and establish the connection to
1630 The ::connect routine calls this routine to establish a
1631 connection with the specified remote system. This routine
1632 is designed to be polled by the connect routine for completion
1633 of the network connection.
1635 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
1637 @param [in] pSockAddr Network address of the remote system.
1639 @param [in] SockAddrLength Length in bytes of the network address.
1641 @param [out] pErrno Address to receive the errno value upon completion.
1643 @retval EFI_SUCCESS The connection was successfully established.
1644 @retval EFI_NOT_READY The connection is in progress, call this routine again.
1645 @retval Others The connection attempt failed.
1650 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
1651 IN
const struct sockaddr
* pSockAddr
,
1652 IN socklen_t SockAddrLength
,
1656 struct sockaddr_in6 LocalAddress
;
1658 ESL_SOCKET
* pSocket
;
1660 EFI_TPL TplPrevious
;
1662 DEBUG (( DEBUG_CONNECT
, "Entering SocketConnect\r\n" ));
1667 Status
= EFI_SUCCESS
;
1670 // Validate the socket
1673 if ( NULL
!= pSocketProtocol
) {
1674 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
1677 // Validate the name length
1679 if ( SockAddrLength
< ( sizeof ( struct sockaddr
) - sizeof ( pSockAddr
->sa_data
))) {
1680 DEBUG (( DEBUG_CONNECT
,
1681 "ERROR - Invalid bind name length: %d\r\n",
1683 Status
= EFI_INVALID_PARAMETER
;
1684 pSocket
->errno
= EINVAL
;
1693 // Synchronize with the socket layer
1695 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
1698 // Validate the socket state
1700 switch ( pSocket
->State
) {
1703 // Wrong socket state
1705 pSocket
->errno
= EIO
;
1706 Status
= EFI_DEVICE_ERROR
;
1709 case SOCKET_STATE_NOT_CONFIGURED
:
1710 case SOCKET_STATE_BOUND
:
1712 // Validate the address length
1714 if ( SockAddrLength
>= pSocket
->pApi
->MinimumAddressLength
) {
1718 if ( NULL
== pSocket
->pApi
->pfnRemoteAddrSet
) {
1720 // Already connected
1722 pSocket
->errno
= ENOTSUP
;
1723 Status
= EFI_UNSUPPORTED
;
1727 // Determine if BIND was already called
1729 if ( NULL
== pSocket
->pPortList
) {
1731 // Allow any local port
1733 ZeroMem ( &LocalAddress
, sizeof ( LocalAddress
));
1734 LocalAddress
.sin6_len
= (uint8_t)pSocket
->pApi
->MinimumAddressLength
;
1735 LocalAddress
.sin6_family
= pSocket
->pApi
->AddressFamily
;
1736 Status
= EslSocketBind ( &pSocket
->SocketProtocol
,
1737 (struct sockaddr
*)&LocalAddress
,
1738 LocalAddress
.sin6_len
,
1741 if ( NULL
!= pSocket
->pPortList
) {
1743 // Walk the list of ports
1745 pPort
= pSocket
->pPortList
;
1746 while ( NULL
!= pPort
) {
1748 // Set the remote address
1750 Status
= pSocket
->pApi
->pfnRemoteAddrSet ( pPort
,
1753 if ( EFI_ERROR ( Status
)) {
1758 // Set the next port
1760 pPort
= pPort
->pLinkSocket
;
1766 if (( !EFI_ERROR ( Status
))
1767 && ( NULL
!= pSocket
->pApi
->pfnConnectStart
)) {
1769 // Initiate the connection with the remote system
1771 Status
= pSocket
->pApi
->pfnConnectStart ( pSocket
);
1774 // Set the next state if connecting
1776 if ( EFI_NOT_READY
== Status
) {
1777 pSocket
->State
= SOCKET_STATE_CONNECTING
;
1784 DEBUG (( DEBUG_CONNECT
,
1785 "ERROR - Invalid address length: %d\r\n",
1787 Status
= EFI_INVALID_PARAMETER
;
1788 pSocket
->errno
= EINVAL
;
1792 case SOCKET_STATE_CONNECTING
:
1794 // Poll for connection completion
1796 if ( NULL
== pSocket
->pApi
->pfnConnectPoll
) {
1798 // Already connected
1800 pSocket
->errno
= EISCONN
;
1801 Status
= EFI_ALREADY_STARTED
;
1804 Status
= pSocket
->pApi
->pfnConnectPoll ( pSocket
);
1807 // Set the next state if connected
1809 if ( EFI_NOT_READY
!= Status
) {
1810 if ( !EFI_ERROR ( Status
)) {
1811 pSocket
->State
= SOCKET_STATE_CONNECTED
;
1814 // Start the receive operations
1816 EslSocketRxStart ( pSocket
->pPortList
);
1819 pSocket
->State
= SOCKET_STATE_BOUND
;
1825 case SOCKET_STATE_CONNECTED
:
1827 // Already connected
1829 pSocket
->errno
= EISCONN
;
1830 Status
= EFI_ALREADY_STARTED
;
1835 // Release the socket layer synchronization
1837 RESTORE_TPL ( TplPrevious
);
1842 // Return the operation status
1844 if ( NULL
!= pErrno
) {
1845 if ( NULL
!= pSocket
) {
1846 *pErrno
= pSocket
->errno
;
1850 // Bad socket protocol
1852 DEBUG (( DEBUG_ERROR
| DEBUG_CONNECT
,
1853 "ERROR - pSocketProtocol invalid!\r\n" ));
1854 Status
= EFI_INVALID_PARAMETER
;
1860 // Return the operation status
1862 DEBUG (( DEBUG_CONNECT
, "Exiting SocketConnect, Status: %r\r\n", Status
));
1868 Copy a fragmented buffer into a destination buffer.
1870 This support routine copies a fragmented buffer to the caller specified buffer.
1872 This routine is called by ::EslIp4Receive and ::EslUdp4Receive.
1874 @param [in] FragmentCount Number of fragments in the table
1876 @param [in] pFragmentTable Address of an EFI_IP4_FRAGMENT_DATA structure
1878 @param [in] BufferLength Length of the the buffer
1880 @param [in] pBuffer Address of a buffer to receive the data.
1882 @param [in] pDataLength Number of received data bytes in the buffer.
1884 @return Returns the address of the next free byte in the buffer.
1888 EslSocketCopyFragmentedBuffer (
1889 IN UINT32 FragmentCount
,
1890 IN EFI_IP4_FRAGMENT_DATA
* pFragmentTable
,
1891 IN
size_t BufferLength
,
1893 OUT
size_t * pDataLength
1904 // Validate the IP and UDP structures are identical
1906 ASSERT ( OFFSET_OF ( EFI_IP4_FRAGMENT_DATA
, FragmentLength
)
1907 == OFFSET_OF ( EFI_UDP4_FRAGMENT_DATA
, FragmentLength
));
1908 ASSERT ( OFFSET_OF ( EFI_IP4_FRAGMENT_DATA
, FragmentBuffer
)
1909 == OFFSET_OF ( EFI_UDP4_FRAGMENT_DATA
, FragmentBuffer
));
1912 // Copy the received data
1915 pBufferEnd
= &pBuffer
[ BufferLength
];
1916 while (( pBufferEnd
> pBuffer
) && ( FragmentCount
> Fragment
)) {
1918 // Determine the amount of received data
1920 pData
= pFragmentTable
[Fragment
].FragmentBuffer
;
1921 BytesToCopy
= pFragmentTable
[Fragment
].FragmentLength
;
1922 if (((size_t)( pBufferEnd
- pBuffer
)) < BytesToCopy
) {
1923 BytesToCopy
= pBufferEnd
- pBuffer
;
1927 // Move the data into the buffer
1930 "0x%08x --> 0x%08x: Copy data 0x%08x bytes\r\n",
1934 CopyMem ( pBuffer
, pData
, BytesToCopy
);
1935 pBuffer
+= BytesToCopy
;
1940 // Return the data length and the buffer address
1942 *pDataLength
= BufferLength
- ( pBufferEnd
- pBuffer
);
1943 DBG_EXIT_HEX ( pBuffer
);
1951 This routine frees the socket structure and handle resources.
1953 The ::close routine calls EslServiceFreeProtocol which then calls
1954 this routine to free the socket context structure and close the
1957 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
1959 @param [out] pErrno Address to receive the errno value upon completion.
1961 @retval EFI_SUCCESS The socket resources were returned successfully.
1966 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
1970 EFI_HANDLE ChildHandle
;
1973 ESL_SOCKET
* pSocket
;
1974 ESL_SOCKET
* pSocketPrevious
;
1976 EFI_TPL TplPrevious
;
1985 Status
= EFI_INVALID_PARAMETER
;
1988 // Validate the socket
1990 pLayer
= &mEslLayer
;
1991 if ( NULL
!= pSocketProtocol
) {
1992 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
1995 // Synchronize with the socket layer
1997 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
2000 // Walk the socket list
2002 pSocketPrevious
= pLayer
->pSocketList
;
2003 if ( NULL
!= pSocketPrevious
) {
2004 if ( pSocket
== pSocketPrevious
) {
2006 // Remove the socket from the head of the list
2008 pLayer
->pSocketList
= pSocket
->pNext
;
2012 // Find the socket in the middle of the list
2014 while (( NULL
!= pSocketPrevious
)
2015 && ( pSocket
!= pSocketPrevious
->pNext
)) {
2017 // Set the next socket
2019 pSocketPrevious
= pSocketPrevious
->pNext
;
2021 if ( NULL
!= pSocketPrevious
) {
2023 // Remove the socket from the middle of the list
2025 pSocketPrevious
= pSocket
->pNext
;
2030 DEBUG (( DEBUG_ERROR
| DEBUG_POOL
,
2031 "ERROR - Socket list is empty!\r\n" ));
2035 // Release the socket layer synchronization
2037 RESTORE_TPL ( TplPrevious
);
2040 // Determine if the socket was found
2042 if ( NULL
!= pSocketPrevious
) {
2043 pSocket
->pNext
= NULL
;
2046 // Remove the socket protocol
2048 ChildHandle
= pSocket
->SocketProtocol
.SocketHandle
;
2049 Status
= gBS
->UninstallMultipleProtocolInterfaces (
2051 &gEfiSocketProtocolGuid
,
2052 &pSocket
->SocketProtocol
,
2054 if ( !EFI_ERROR ( Status
)) {
2055 DEBUG (( DEBUG_POOL
| DEBUG_INFO
,
2056 "Removed: gEfiSocketProtocolGuid from 0x%08x\r\n",
2060 // Free the socket structure
2062 Status
= gBS
->FreePool ( pSocket
);
2063 if ( !EFI_ERROR ( Status
)) {
2064 DEBUG (( DEBUG_POOL
,
2065 "0x%08x: Free pSocket, %d bytes\r\n",
2067 sizeof ( *pSocket
)));
2071 DEBUG (( DEBUG_ERROR
| DEBUG_POOL
,
2072 "ERROR - Failed to free pSocket 0x%08x, Status: %r\r\n",
2078 DEBUG (( DEBUG_ERROR
| DEBUG_POOL
| DEBUG_INFO
,
2079 "ERROR - Failed to remove gEfiSocketProtocolGuid from 0x%08x, Status: %r\r\n",
2085 DEBUG (( DEBUG_ERROR
| DEBUG_INFO
,
2086 "ERROR - The socket was not in the socket list!\r\n" ));
2087 Status
= EFI_NOT_FOUND
;
2091 DEBUG (( DEBUG_ERROR
,
2092 "ERROR - Invalid parameter pSocketProtocol is NULL\r\n" ));
2096 // Return the errno value if possible
2098 if ( NULL
!= pErrno
) {
2103 // Return the operation status
2105 DBG_EXIT_STATUS ( Status
);
2111 Get the local address.
2113 This routine calls the network specific layer to get the network
2114 address of the local host connection point.
2116 The ::getsockname routine calls this routine to obtain the network
2117 address associated with the local host connection point.
2119 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
2121 @param [out] pAddress Network address to receive the local system address
2123 @param [in,out] pAddressLength Length of the local network address structure
2125 @param [out] pErrno Address to receive the errno value upon completion.
2127 @retval EFI_SUCCESS - Local address successfully returned
2131 EslSocketGetLocalAddress (
2132 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
2133 OUT
struct sockaddr
* pAddress
,
2134 IN OUT socklen_t
* pAddressLength
,
2138 socklen_t LengthInBytes
;
2140 ESL_SOCKET
* pSocket
;
2142 EFI_TPL TplPrevious
;
2149 Status
= EFI_SUCCESS
;
2152 // Validate the socket
2155 if ( NULL
!= pSocketProtocol
) {
2156 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
2159 // Verify the socket state
2161 EslSocketIsConfigured ( pSocket
);
2162 if ( pSocket
->bAddressSet
) {
2164 // Verify the address buffer and length address
2166 if (( NULL
!= pAddress
) && ( NULL
!= pAddressLength
)) {
2170 if ( NULL
== pSocket
->pApi
->pfnLocalAddrGet
) {
2171 Status
= EFI_UNSUPPORTED
;
2172 pSocket
->errno
= ENOTSUP
;
2176 // Synchronize with the socket layer
2178 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
2181 // Verify that there is just a single connection
2183 pPort
= pSocket
->pPortList
;
2184 if ( NULL
!= pPort
) {
2186 // Verify the address length
2188 LengthInBytes
= pSocket
->pApi
->AddressLength
;
2189 if (( LengthInBytes
<= *pAddressLength
)
2190 && ( 255 >= LengthInBytes
)) {
2192 // Return the local address and address length
2194 ZeroMem ( pAddress
, LengthInBytes
);
2195 pAddress
->sa_len
= (uint8_t)LengthInBytes
;
2196 *pAddressLength
= pAddress
->sa_len
;
2197 pSocket
->pApi
->pfnLocalAddrGet ( pPort
, pAddress
);
2199 Status
= EFI_SUCCESS
;
2202 pSocket
->errno
= EINVAL
;
2203 Status
= EFI_INVALID_PARAMETER
;
2207 pSocket
->errno
= ENOTCONN
;
2208 Status
= EFI_NOT_STARTED
;
2212 // Release the socket layer synchronization
2214 RESTORE_TPL ( TplPrevious
);
2218 pSocket
->errno
= EINVAL
;
2219 Status
= EFI_INVALID_PARAMETER
;
2226 Status
= EFI_NOT_STARTED
;
2227 pSocket
->errno
= EADDRNOTAVAIL
;
2232 // Return the operation status
2234 if ( NULL
!= pErrno
) {
2235 if ( NULL
!= pSocket
) {
2236 *pErrno
= pSocket
->errno
;
2239 Status
= EFI_INVALID_PARAMETER
;
2243 DBG_EXIT_STATUS ( Status
);
2249 Get the peer address.
2251 This routine calls the network specific layer to get the remote
2252 system connection point.
2254 The ::getpeername routine calls this routine to obtain the network
2255 address of the remote connection point.
2257 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
2259 @param [out] pAddress Network address to receive the remote system address
2261 @param [in,out] pAddressLength Length of the remote network address structure
2263 @param [out] pErrno Address to receive the errno value upon completion.
2265 @retval EFI_SUCCESS - Remote address successfully returned
2269 EslSocketGetPeerAddress (
2270 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
2271 OUT
struct sockaddr
* pAddress
,
2272 IN OUT socklen_t
* pAddressLength
,
2276 socklen_t LengthInBytes
;
2278 ESL_SOCKET
* pSocket
;
2280 EFI_TPL TplPrevious
;
2287 Status
= EFI_SUCCESS
;
2290 // Validate the socket
2293 if ( NULL
!= pSocketProtocol
) {
2294 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
2297 // Verify the socket state
2299 Status
= EslSocketIsConfigured ( pSocket
);
2300 if ( !EFI_ERROR ( Status
)) {
2304 if ( NULL
== pSocket
->pApi
->pfnRemoteAddrGet
) {
2305 Status
= EFI_UNSUPPORTED
;
2306 pSocket
->errno
= ENOTSUP
;
2310 // Verify the address buffer and length address
2312 if (( NULL
!= pAddress
) && ( NULL
!= pAddressLength
)) {
2314 // Verify the socket state
2316 if ( SOCKET_STATE_CONNECTED
== pSocket
->State
) {
2318 // Synchronize with the socket layer
2320 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
2323 // Verify that there is just a single connection
2325 pPort
= pSocket
->pPortList
;
2326 if (( NULL
!= pPort
) && ( NULL
== pPort
->pLinkSocket
)) {
2328 // Verify the address length
2330 LengthInBytes
= pSocket
->pApi
->AddressLength
;
2331 if ( LengthInBytes
<= *pAddressLength
) {
2333 // Return the local address
2335 ZeroMem ( pAddress
, LengthInBytes
);
2336 pAddress
->sa_len
= (uint8_t)LengthInBytes
;
2337 *pAddressLength
= pAddress
->sa_len
;
2338 pSocket
->pApi
->pfnRemoteAddrGet ( pPort
, pAddress
);
2340 Status
= EFI_SUCCESS
;
2343 pSocket
->errno
= EINVAL
;
2344 Status
= EFI_INVALID_PARAMETER
;
2348 pSocket
->errno
= ENOTCONN
;
2349 Status
= EFI_NOT_STARTED
;
2353 // Release the socket layer synchronization
2355 RESTORE_TPL ( TplPrevious
);
2358 pSocket
->errno
= ENOTCONN
;
2359 Status
= EFI_NOT_STARTED
;
2363 pSocket
->errno
= EINVAL
;
2364 Status
= EFI_INVALID_PARAMETER
;
2371 // Return the operation status
2373 if ( NULL
!= pErrno
) {
2374 if ( NULL
!= pSocket
) {
2375 *pErrno
= pSocket
->errno
;
2378 Status
= EFI_INVALID_PARAMETER
;
2382 DBG_EXIT_STATUS ( Status
);
2388 Free the ESL_IO_MGMT event and structure
2390 This support routine walks the free list to close the event in
2391 the ESL_IO_MGMT structure and remove the structure from the free
2394 See the \ref TransmitEngine section.
2396 @param [in] pPort Address of an ::ESL_PORT structure
2397 @param [in] ppFreeQueue Address of the free queue head
2398 @param [in] DebugFlags Flags for debug messages
2399 @param [in] pEventName Zero terminated string containing the event name
2401 @retval EFI_SUCCESS - The structures were properly initialized
2406 IN ESL_PORT
* pPort
,
2407 IN ESL_IO_MGMT
** ppFreeQueue
,
2408 IN UINTN DebugFlags
,
2409 IN CHAR8
* pEventName
2415 ESL_SOCKET
* pSocket
;
2423 Status
= EFI_SUCCESS
;
2426 // Walk the list of IO structures
2428 pSocket
= pPort
->pSocket
;
2429 while ( *ppFreeQueue
) {
2431 // Free the event for this structure
2434 pBuffer
= (UINT8
*)pIo
;
2435 pBuffer
= &pBuffer
[ pSocket
->TxTokenEventOffset
];
2436 pEvent
= (EFI_EVENT
*)pBuffer
;
2437 Status
= gBS
->CloseEvent ( *pEvent
);
2438 if ( EFI_ERROR ( Status
)) {
2439 DEBUG (( DEBUG_ERROR
| DebugFlags
,
2440 "ERROR - Failed to close the %a event, Status: %r\r\n",
2443 pSocket
->errno
= ENOMEM
;
2446 DEBUG (( DebugFlags
,
2447 "0x%08x: Closed %a event 0x%08x\r\n",
2453 // Remove this structure from the queue
2455 *ppFreeQueue
= pIo
->pNext
;
2459 // Return the operation status
2461 DBG_EXIT_STATUS ( Status
);
2467 Initialize the ESL_IO_MGMT structures
2469 This support routine initializes the ESL_IO_MGMT structure and
2470 places them on to a free list.
2472 This routine is called by ::EslSocketPortAllocate routines to prepare
2473 the transmit engines. See the \ref TransmitEngine section.
2475 @param [in] pPort Address of an ::ESL_PORT structure
2476 @param [in, out] ppIo Address containing the first structure address. Upon
2477 return this buffer contains the next structure address.
2478 @param [in] TokenCount Number of structures to initialize
2479 @param [in] ppFreeQueue Address of the free queue head
2480 @param [in] DebugFlags Flags for debug messages
2481 @param [in] pEventName Zero terminated string containing the event name
2482 @param [in] pfnCompletion Completion routine address
2484 @retval EFI_SUCCESS - The structures were properly initialized
2489 IN ESL_PORT
* pPort
,
2490 IN ESL_IO_MGMT
** ppIo
,
2491 IN UINTN TokenCount
,
2492 IN ESL_IO_MGMT
** ppFreeQueue
,
2493 IN UINTN DebugFlags
,
2494 IN CHAR8
* pEventName
,
2495 IN PFN_API_IO_COMPLETE pfnCompletion
2501 ESL_SOCKET
* pSocket
;
2509 Status
= EFI_SUCCESS
;
2512 // Walk the list of IO structures
2514 pSocket
= pPort
->pSocket
;
2516 pEnd
= &pIo
[ TokenCount
];
2517 while ( pEnd
> pIo
) {
2519 // Initialize the IO structure
2522 pIo
->pPacket
= NULL
;
2525 // Allocate the event for this structure
2527 pEvent
= (EFI_EVENT
*)&(((UINT8
*)pIo
)[ pSocket
->TxTokenEventOffset
]);
2528 Status
= gBS
->CreateEvent ( EVT_NOTIFY_SIGNAL
,
2530 (EFI_EVENT_NOTIFY
)pfnCompletion
,
2533 if ( EFI_ERROR ( Status
)) {
2534 DEBUG (( DEBUG_ERROR
| DebugFlags
,
2535 "ERROR - Failed to create the %a event, Status: %r\r\n",
2538 pSocket
->errno
= ENOMEM
;
2541 DEBUG (( DebugFlags
,
2542 "0x%08x: Created %a event 0x%08x\r\n",
2548 // Add this structure to the queue
2550 pIo
->pNext
= *ppFreeQueue
;
2554 // Set the next structure
2560 // Save the next structure
2565 // Return the operation status
2567 DBG_EXIT_STATUS ( Status
);
2573 Determine if the socket is configured
2575 This support routine is called to determine if the socket if the
2576 configuration call was made to the network layer. The following
2577 routines call this routine to verify that they may be successful
2578 in their operations:
2580 <li>::EslSocketGetLocalAddress</li>
2581 <li>::EslSocketGetPeerAddress</li>
2582 <li>::EslSocketPoll</li>
2583 <li>::EslSocketReceive</li>
2584 <li>::EslSocketTransmit</li>
2587 @param [in] pSocket Address of an ::ESL_SOCKET structure
2589 @retval EFI_SUCCESS - The socket is configured
2593 EslSocketIsConfigured (
2594 IN ESL_SOCKET
* pSocket
2598 EFI_TPL TplPrevious
;
2603 Status
= EFI_SUCCESS
;
2606 // Verify the socket state
2608 if ( !pSocket
->bConfigured
) {
2614 if ( NULL
== pSocket
->pApi
->pfnIsConfigured
) {
2615 Status
= EFI_UNSUPPORTED
;
2616 pSocket
->errno
= ENOTSUP
;
2620 // Synchronize with the socket layer
2622 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
2625 // Determine if the socket is configured
2627 Status
= pSocket
->pApi
->pfnIsConfigured ( pSocket
);
2630 // Release the socket layer synchronization
2632 RESTORE_TPL ( TplPrevious
);
2635 // Set errno if a failure occurs
2637 if ( EFI_ERROR ( Status
)) {
2638 pSocket
->errno
= EADDRNOTAVAIL
;
2642 DBG_EXIT_STATUS ( Status
);
2646 // Return the configuration status
2653 Establish the known port to listen for network connections.
2655 This routine calls into the network protocol layer to establish
2656 a handler that is called upon connection completion. The handler
2657 is responsible for inserting the connection into the FIFO.
2659 The ::listen routine indirectly calls this routine to place the
2660 socket into a state that enables connection attempts. Connections
2661 are placed in a FIFO that is serviced by the application. The
2662 application calls the ::accept (::EslSocketAccept) routine to
2663 remove the next connection from the FIFO and get the associated
2666 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
2668 @param [in] Backlog Backlog specifies the maximum FIFO depth for
2669 the connections waiting for the application
2670 to call accept. Connection attempts received
2671 while the queue is full are refused.
2673 @param [out] pErrno Address to receive the errno value upon completion.
2675 @retval EFI_SUCCESS - Socket successfully created
2676 @retval Other - Failed to enable the socket for listen
2681 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
2686 ESL_SOCKET
* pSocket
;
2688 EFI_STATUS TempStatus
;
2689 EFI_TPL TplPrevious
;
2696 Status
= EFI_SUCCESS
;
2699 // Validate the socket
2702 if ( NULL
!= pSocketProtocol
) {
2703 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
2708 if ( NULL
== pSocket
->pApi
->pfnListen
) {
2709 Status
= EFI_UNSUPPORTED
;
2710 pSocket
->errno
= ENOTSUP
;
2716 pSocket
->Status
= EFI_SUCCESS
;
2720 // Verify that the bind operation was successful
2722 if ( SOCKET_STATE_BOUND
== pSocket
->State
) {
2724 // Synchronize with the socket layer
2726 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
2729 // Create the event for SocketAccept completion
2731 Status
= gBS
->CreateEvent ( 0,
2735 &pSocket
->WaitAccept
);
2736 if ( !EFI_ERROR ( Status
)) {
2737 DEBUG (( DEBUG_POOL
,
2738 "0x%08x: Created WaitAccept event\r\n",
2739 pSocket
->WaitAccept
));
2741 // Set the maximum FIFO depth
2743 if ( 0 >= Backlog
) {
2744 Backlog
= MAX_PENDING_CONNECTIONS
;
2747 if ( SOMAXCONN
< Backlog
) {
2748 Backlog
= SOMAXCONN
;
2751 pSocket
->MaxFifoDepth
= Backlog
;
2756 // Initiate the connection attempt listen
2758 Status
= pSocket
->pApi
->pfnListen ( pSocket
);
2761 // Place the socket in the listen state if successful
2763 if ( !EFI_ERROR ( Status
)) {
2764 pSocket
->State
= SOCKET_STATE_LISTENING
;
2765 pSocket
->bListenCalled
= TRUE
;
2769 // Not waiting for SocketAccept to complete
2771 TempStatus
= gBS
->CloseEvent ( pSocket
->WaitAccept
);
2772 if ( !EFI_ERROR ( TempStatus
)) {
2773 DEBUG (( DEBUG_POOL
,
2774 "0x%08x: Closed WaitAccept event\r\n",
2775 pSocket
->WaitAccept
));
2776 pSocket
->WaitAccept
= NULL
;
2779 DEBUG (( DEBUG_ERROR
| DEBUG_POOL
,
2780 "ERROR - Failed to close WaitAccept event, Status: %r\r\n",
2782 ASSERT ( EFI_SUCCESS
== TempStatus
);
2787 DEBUG (( DEBUG_ERROR
| DEBUG_LISTEN
,
2788 "ERROR - Failed to create the WaitAccept event, Status: %r\r\n",
2790 pSocket
->errno
= ENOMEM
;
2794 // Release the socket layer synchronization
2796 RESTORE_TPL ( TplPrevious
);
2799 DEBUG (( DEBUG_ERROR
| DEBUG_LISTEN
,
2800 "ERROR - Bind operation must be performed first!\r\n" ));
2801 pSocket
->errno
= ( SOCKET_STATE_NOT_CONFIGURED
== pSocket
->State
) ? EDESTADDRREQ
2803 Status
= EFI_NO_MAPPING
;
2809 // Return the operation status
2811 if ( NULL
!= pErrno
) {
2812 if ( NULL
!= pSocket
) {
2813 *pErrno
= pSocket
->errno
;
2816 Status
= EFI_INVALID_PARAMETER
;
2820 DBG_EXIT_STATUS ( Status
);
2826 Get the socket options
2828 This routine handles the socket level options and passes the
2829 others to the network specific layer.
2831 The ::getsockopt routine calls this routine to retrieve the
2832 socket options one at a time by name.
2834 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
2835 @param [in] level Option protocol level
2836 @param [in] OptionName Name of the option
2837 @param [out] pOptionValue Buffer to receive the option value
2838 @param [in,out] pOptionLength Length of the buffer in bytes,
2839 upon return length of the option value in bytes
2840 @param [out] pErrno Address to receive the errno value upon completion.
2842 @retval EFI_SUCCESS - Socket data successfully received
2846 EslSocketOptionGet (
2847 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
2850 OUT
void * __restrict pOptionValue
,
2851 IN OUT socklen_t
* __restrict pOptionLength
,
2856 socklen_t LengthInBytes
;
2858 CONST UINT8
* pOptionData
;
2859 ESL_SOCKET
* pSocket
;
2868 Status
= EFI_INVALID_PARAMETER
;
2871 // Validate the socket
2874 if ( NULL
== pSocketProtocol
) {
2875 DEBUG (( DEBUG_OPTION
, "ERROR - pSocketProtocol is NULL!\r\n" ));
2877 else if ( NULL
== pOptionValue
) {
2878 DEBUG (( DEBUG_OPTION
, "ERROR - No option buffer specified\r\n" ));
2880 else if ( NULL
== pOptionLength
) {
2881 DEBUG (( DEBUG_OPTION
, "ERROR - Option length not specified!\r\n" ));
2884 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
2886 MaxBytes
= *pOptionLength
;
2891 // See if the protocol will handle the option
2893 if ( NULL
!= pSocket
->pApi
->pfnOptionGet
) {
2894 if ( pSocket
->pApi
->DefaultProtocol
== level
) {
2895 Status
= pSocket
->pApi
->pfnOptionGet ( pSocket
,
2897 (CONST
void ** __restrict
)&pOptionData
,
2899 errno
= pSocket
->errno
;
2904 // Protocol not supported
2906 DEBUG (( DEBUG_OPTION
,
2907 "ERROR - The socket does not support this protocol!\r\n" ));
2912 // Protocol level not supported
2914 DEBUG (( DEBUG_OPTION
,
2915 "ERROR - %a does not support any options!\r\n",
2916 pSocket
->pApi
->pName
));
2918 errno
= ENOPROTOOPT
;
2919 Status
= EFI_INVALID_PARAMETER
;
2923 switch ( OptionName
) {
2926 // Socket option not supported
2928 DEBUG (( DEBUG_INFO
| DEBUG_OPTION
, "ERROR - Invalid socket option!\r\n" ));
2930 Status
= EFI_INVALID_PARAMETER
;
2935 // Return the listen flag
2937 pOptionData
= (CONST UINT8
*)&pSocket
->bListenCalled
;
2938 LengthInBytes
= sizeof ( pSocket
->bListenCalled
);
2943 // Return the debug flags
2945 pOptionData
= (CONST UINT8
*)&pSocket
->bOobInLine
;
2946 LengthInBytes
= sizeof ( pSocket
->bOobInLine
);
2951 // Return the out-of-band inline flag
2953 pOptionData
= (CONST UINT8
*)&pSocket
->bOobInLine
;
2954 LengthInBytes
= sizeof ( pSocket
->bOobInLine
);
2959 // Return the receive timeout
2961 pOptionData
= (CONST UINT8
*)&pSocket
->RxTimeout
;
2962 LengthInBytes
= sizeof ( pSocket
->RxTimeout
);
2967 // Return the maximum receive buffer size
2969 pOptionData
= (CONST UINT8
*)&pSocket
->MaxRxBuf
;
2970 LengthInBytes
= sizeof ( pSocket
->MaxRxBuf
);
2975 // Return the address reuse flag
2977 pOptionData
= (UINT8
*)&pSocket
->bReUseAddr
;
2978 LengthInBytes
= sizeof ( pSocket
->bReUseAddr
);
2983 // Return the maximum transmit buffer size
2985 pOptionData
= (CONST UINT8
*)&pSocket
->MaxTxBuf
;
2986 LengthInBytes
= sizeof ( pSocket
->MaxTxBuf
);
2991 // Return the socket type
2993 pOptionData
= (CONST UINT8
*)&pSocket
->Type
;
2994 LengthInBytes
= sizeof ( pSocket
->Type
);
3001 // Return the option length
3003 *pOptionLength
= LengthInBytes
;
3006 // Determine if the option is present
3008 if ( 0 != LengthInBytes
) {
3010 // Silently truncate the value length
3012 if ( LengthInBytes
> MaxBytes
) {
3013 DEBUG (( DEBUG_OPTION
,
3014 "INFO - Truncating option from %d to %d bytes\r\n",
3017 LengthInBytes
= MaxBytes
;
3023 CopyMem ( pOptionValue
, pOptionData
, LengthInBytes
);
3026 // Zero fill any remaining space
3028 if ( LengthInBytes
< MaxBytes
) {
3029 ZeroMem ( &((UINT8
*)pOptionValue
)[LengthInBytes
], MaxBytes
- LengthInBytes
);
3032 Status
= EFI_SUCCESS
;
3037 // Return the operation status
3039 if ( NULL
!= pErrno
) {
3042 DBG_EXIT_STATUS ( Status
);
3048 Set the socket options
3050 This routine handles the socket level options and passes the
3051 others to the network specific layer.
3053 The ::setsockopt routine calls this routine to adjust the socket
3054 options one at a time by name.
3056 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
3057 @param [in] level Option protocol level
3058 @param [in] OptionName Name of the option
3059 @param [in] pOptionValue Buffer containing the option value
3060 @param [in] OptionLength Length of the buffer in bytes
3061 @param [out] pErrno Address to receive the errno value upon completion.
3063 @retval EFI_SUCCESS - Option successfully set
3067 EslSocketOptionSet (
3068 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
3071 IN CONST
void * pOptionValue
,
3072 IN socklen_t OptionLength
,
3078 socklen_t LengthInBytes
;
3079 UINT8
* pOptionData
;
3080 ESL_SOCKET
* pSocket
;
3089 Status
= EFI_INVALID_PARAMETER
;
3092 // Validate the socket
3095 if ( NULL
== pSocketProtocol
) {
3096 DEBUG (( DEBUG_OPTION
, "ERROR - pSocketProtocol is NULL!\r\n" ));
3098 else if ( NULL
== pOptionValue
) {
3099 DEBUG (( DEBUG_OPTION
, "ERROR - No option buffer specified\r\n" ));
3103 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
3104 if ( pSocket
->bRxDisable
|| pSocket
->bTxDisable
) {
3105 DEBUG (( DEBUG_OPTION
, "ERROR - Socket has been shutdown!\r\n" ));
3113 // See if the protocol will handle the option
3115 if ( NULL
!= pSocket
->pApi
->pfnOptionSet
) {
3116 if ( pSocket
->pApi
->DefaultProtocol
== level
) {
3117 Status
= pSocket
->pApi
->pfnOptionSet ( pSocket
,
3121 errno
= pSocket
->errno
;
3126 // Protocol not supported
3128 DEBUG (( DEBUG_OPTION
,
3129 "ERROR - The socket does not support this protocol!\r\n" ));
3134 // Protocol level not supported
3136 DEBUG (( DEBUG_OPTION
,
3137 "ERROR - %a does not support any options!\r\n",
3138 pSocket
->pApi
->pName
));
3140 errno
= ENOPROTOOPT
;
3141 Status
= EFI_INVALID_PARAMETER
;
3145 switch ( OptionName
) {
3148 // Option not supported
3150 DEBUG (( DEBUG_OPTION
,
3151 "ERROR - Sockets does not support this option!\r\n" ));
3153 Status
= EFI_INVALID_PARAMETER
;
3158 // Set the debug flags
3160 pOptionData
= (UINT8
*)&pSocket
->bOobInLine
;
3161 LengthInBytes
= sizeof ( pSocket
->bOobInLine
);
3165 pOptionData
= (UINT8
*)&pSocket
->bOobInLine
;
3166 LengthInBytes
= sizeof ( pSocket
->bOobInLine
);
3169 // Validate the option length
3171 if ( sizeof ( UINT32
) == OptionLength
) {
3173 // Restrict the input to TRUE or FALSE
3176 if ( 0 == *(UINT32
*)pOptionValue
) {
3179 pOptionValue
= &bTrueFalse
;
3183 // Force an invalid option length error
3185 OptionLength
= LengthInBytes
- 1;
3191 // Return the receive timeout
3193 pOptionData
= (UINT8
*)&pSocket
->RxTimeout
;
3194 LengthInBytes
= sizeof ( pSocket
->RxTimeout
);
3199 // Return the maximum receive buffer size
3201 pOptionData
= (UINT8
*)&pSocket
->MaxRxBuf
;
3202 LengthInBytes
= sizeof ( pSocket
->MaxRxBuf
);
3207 // Return the address reuse flag
3209 pOptionData
= (UINT8
*)&pSocket
->bReUseAddr
;
3210 LengthInBytes
= sizeof ( pSocket
->bReUseAddr
);
3218 // Return the maximum transmit buffer size
3220 pOptionData
= (UINT8
*)&pSocket
->MaxTxBuf
;
3221 LengthInBytes
= sizeof ( pSocket
->MaxTxBuf
);
3228 // Determine if an option was found
3230 if ( 0 != LengthInBytes
) {
3232 // Validate the option length
3234 if ( LengthInBytes
<= OptionLength
) {
3236 // Set the option value
3238 CopyMem ( pOptionData
, pOptionValue
, LengthInBytes
);
3240 Status
= EFI_SUCCESS
;
3243 DEBUG (( DEBUG_OPTION
,
3244 "ERROR - Buffer to small, %d bytes < %d bytes!\r\n",
3253 // Return the operation status
3255 if ( NULL
!= pErrno
) {
3258 DBG_EXIT_STATUS ( Status
);
3264 Allocate a packet for a receive or transmit operation
3266 This support routine is called by ::EslSocketRxStart and the
3267 network specific TxBuffer routines to get buffer space for the
3270 @param [in] ppPacket Address to receive the ::ESL_PACKET structure
3271 @param [in] LengthInBytes Length of the packet structure
3272 @param [in] ZeroBytes Length of packet to zero
3273 @param [in] DebugFlags Flags for debug messages
3275 @retval EFI_SUCCESS - The packet was allocated successfully
3279 EslSocketPacketAllocate (
3280 IN ESL_PACKET
** ppPacket
,
3281 IN
size_t LengthInBytes
,
3282 IN
size_t ZeroBytes
,
3286 ESL_PACKET
* pPacket
;
3292 // Allocate a packet structure
3294 LengthInBytes
+= sizeof ( *pPacket
)
3295 - sizeof ( pPacket
->Op
);
3296 Status
= gBS
->AllocatePool ( EfiRuntimeServicesData
,
3298 (VOID
**)&pPacket
);
3299 if ( !EFI_ERROR ( Status
)) {
3300 DEBUG (( DebugFlags
| DEBUG_POOL
,
3301 "0x%08x: Allocate pPacket, %d bytes\r\n",
3304 if ( 0 != ZeroBytes
) {
3305 ZeroMem ( &pPacket
->Op
, ZeroBytes
);
3307 pPacket
->PacketSize
= LengthInBytes
;
3310 DEBUG (( DebugFlags
| DEBUG_POOL
| DEBUG_INFO
,
3311 "ERROR - Packet allocation failed for %d bytes, Status: %r\r\n",
3318 // Return the packet
3320 *ppPacket
= pPacket
;
3323 // Return the operation status
3325 DBG_EXIT_STATUS ( Status
);
3331 Free a packet used for receive or transmit operation
3333 This support routine is called by the network specific Close
3334 and TxComplete routines and during error cases in RxComplete
3335 and TxBuffer. Note that the network layers typically place
3336 receive packets on the ESL_SOCKET::pRxFree list for reuse.
3338 @param [in] pPacket Address of an ::ESL_PACKET structure
3339 @param [in] DebugFlags Flags for debug messages
3341 @retval EFI_SUCCESS - The packet was allocated successfully
3345 EslSocketPacketFree (
3346 IN ESL_PACKET
* pPacket
,
3350 UINTN LengthInBytes
;
3356 // Free a packet structure
3358 LengthInBytes
= pPacket
->PacketSize
;
3359 Status
= gBS
->FreePool ( pPacket
);
3360 if ( !EFI_ERROR ( Status
)) {
3361 DEBUG (( DebugFlags
| DEBUG_POOL
,
3362 "0x%08x: Free pPacket, %d bytes\r\n",
3367 DEBUG (( DebugFlags
| DEBUG_POOL
| DEBUG_INFO
,
3368 "ERROR - Failed to free packet 0x%08x, Status: %r\r\n",
3374 // Return the operation status
3376 DBG_EXIT_STATUS ( Status
);
3382 Poll a socket for pending activity.
3384 This routine builds a detected event mask which is returned to
3385 the caller in the buffer provided.
3387 The ::poll routine calls this routine to determine if the socket
3388 needs to be serviced as a result of connection, error, receive or
3391 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
3393 @param [in] Events Events of interest for this socket
3395 @param [in] pEvents Address to receive the detected events
3397 @param [out] pErrno Address to receive the errno value upon completion.
3399 @retval EFI_SUCCESS - Socket successfully polled
3400 @retval EFI_INVALID_PARAMETER - When pEvents is NULL
3405 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
3411 short DetectedEvents
;
3412 ESL_SOCKET
* pSocket
;
3414 EFI_TPL TplPrevious
;
3417 DEBUG (( DEBUG_POLL
, "Entering SocketPoll\r\n" ));
3422 Status
= EFI_SUCCESS
;
3424 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
3428 // Verify the socket state
3430 Status
= EslSocketIsConfigured ( pSocket
);
3431 if ( !EFI_ERROR ( Status
)) {
3433 // Check for invalid events
3435 ValidEvents
= POLLIN
3437 | POLLOUT
| POLLWRNORM
3444 if ( 0 != ( Events
& ( ~ValidEvents
))) {
3445 DetectedEvents
|= POLLNVAL
;
3446 DEBUG (( DEBUG_INFO
| DEBUG_POLL
,
3447 "ERROR - Invalid event mask, Valid Events: 0x%04x, Invalid Events: 0x%04x\r\n",
3448 Events
& ValidEvents
,
3449 Events
& ( ~ValidEvents
)));
3453 // Synchronize with the socket layer
3455 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
3458 // Increase the network performance by extending the
3459 // polling (idle) loop down into the LAN driver
3461 EslSocketRxPoll ( pSocket
);
3464 // Release the socket layer synchronization
3466 RESTORE_TPL ( TplPrevious
);
3469 // Check for pending connections
3471 if ( 0 != pSocket
->FifoDepth
) {
3473 // A connection is waiting for an accept call
3474 // See posix connect documentation at
3475 // http://pubs.opengroup.org/onlinepubs/9699919799/functions/accept.htm
3477 DetectedEvents
|= POLLIN
| POLLRDNORM
;
3479 if ( pSocket
->bConnected
) {
3481 // A connection is present
3482 // See posix connect documentation at
3483 // http://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.htm
3485 DetectedEvents
|= POLLOUT
| POLLWRNORM
;
3489 // The following bits are set based upon the POSIX poll documentation at
3490 // http://pubs.opengroup.org/onlinepubs/9699919799/functions/poll.html
3494 // Check for urgent receive data
3496 if ( 0 < pSocket
->RxOobBytes
) {
3497 DetectedEvents
|= POLLRDBAND
| POLLPRI
| POLLIN
;
3501 // Check for normal receive data
3503 if (( 0 < pSocket
->RxBytes
)
3504 || ( EFI_SUCCESS
!= pSocket
->RxError
)) {
3505 DetectedEvents
|= POLLRDNORM
| POLLIN
;
3509 // Handle the receive errors
3511 if (( EFI_SUCCESS
!= pSocket
->RxError
)
3512 && ( 0 == ( DetectedEvents
& POLLIN
))) {
3513 DetectedEvents
|= POLLERR
| POLLIN
| POLLRDNORM
| POLLRDBAND
;
3517 // Check for urgent transmit data buffer space
3519 if (( MAX_TX_DATA
> pSocket
->TxOobBytes
)
3520 || ( EFI_SUCCESS
!= pSocket
->TxError
)) {
3521 DetectedEvents
|= POLLWRBAND
;
3525 // Check for normal transmit data buffer space
3527 if (( MAX_TX_DATA
> pSocket
->TxBytes
)
3528 || ( EFI_SUCCESS
!= pSocket
->TxError
)) {
3529 DetectedEvents
|= POLLWRNORM
;
3533 // Handle the transmit error
3535 if ( EFI_ERROR ( pSocket
->TxError
)) {
3536 DetectedEvents
|= POLLERR
;
3542 // Return the detected events
3544 *pEvents
= DetectedEvents
& ( Events
3550 // Return the operation status
3552 DEBUG (( DEBUG_POLL
, "Exiting SocketPoll, Status: %r\r\n", Status
));
3558 Allocate and initialize a ESL_PORT structure.
3560 This routine initializes an ::ESL_PORT structure for use by
3561 the socket. This routine calls a routine via
3562 ESL_PROTOCOL_API::pfnPortAllocate to initialize the network
3563 specific resources. The resources are released later by the
3564 \ref PortCloseStateMachine.
3566 This support routine is called by:
3568 <li>::EslSocketBind</li>
3569 <li>::EslTcp4ListenComplete</li>
3571 to connect the socket with the underlying network adapter
3574 @param [in] pSocket Address of an ::ESL_SOCKET structure.
3575 @param [in] pService Address of an ::ESL_SERVICE structure.
3576 @param [in] ChildHandle Network protocol child handle
3577 @param [in] pSockAddr Address of a sockaddr structure that contains the
3578 connection point on the local machine. An IPv4 address
3579 of INADDR_ANY specifies that the connection is made to
3580 all of the network stacks on the platform. Specifying a
3581 specific IPv4 address restricts the connection to the
3582 network stack supporting that address. Specifying zero
3583 for the port causes the network layer to assign a port
3584 number from the dynamic range. Specifying a specific
3585 port number causes the network layer to use that port.
3586 @param [in] bBindTest TRUE if EslSocketBindTest should be called
3587 @param [in] DebugFlags Flags for debug messages
3588 @param [out] ppPort Buffer to receive new ::ESL_PORT structure address
3590 @retval EFI_SUCCESS - Socket successfully created
3594 EslSocketPortAllocate (
3595 IN ESL_SOCKET
* pSocket
,
3596 IN ESL_SERVICE
* pService
,
3597 IN EFI_HANDLE ChildHandle
,
3598 IN CONST
struct sockaddr
* pSockAddr
,
3599 IN BOOLEAN bBindTest
,
3600 IN UINTN DebugFlags
,
3601 OUT ESL_PORT
** ppPort
3604 UINTN LengthInBytes
;
3609 EFI_SERVICE_BINDING_PROTOCOL
* pServiceBinding
;
3610 CONST ESL_SOCKET_BINDING
* pSocketBinding
;
3612 EFI_STATUS TempStatus
;
3617 // Verify the socket layer synchronization
3619 VERIFY_TPL ( TPL_SOCKETS
);
3622 // Use for/break instead of goto
3623 pSocketBinding
= pService
->pSocketBinding
;
3626 // Allocate a port structure
3628 pLayer
= &mEslLayer
;
3629 LengthInBytes
= sizeof ( *pPort
)
3630 + ESL_STRUCTURE_ALIGNMENT_BYTES
3631 + (( pSocketBinding
->RxIo
3632 + pSocketBinding
->TxIoNormal
3633 + pSocketBinding
->TxIoUrgent
)
3634 * sizeof ( ESL_IO_MGMT
));
3635 pPort
= (ESL_PORT
*) AllocateZeroPool ( LengthInBytes
);
3636 if ( NULL
== pPort
) {
3637 Status
= EFI_OUT_OF_RESOURCES
;
3638 pSocket
->errno
= ENOMEM
;
3641 DEBUG (( DebugFlags
| DEBUG_POOL
| DEBUG_INIT
,
3642 "0x%08x: Allocate pPort, %d bytes\r\n",
3647 // Initialize the port
3649 pPort
->DebugFlags
= DebugFlags
;
3650 pPort
->Handle
= ChildHandle
;
3651 pPort
->pService
= pService
;
3652 pPort
->pServiceBinding
= pService
->pServiceBinding
;
3653 pPort
->pSocket
= pSocket
;
3654 pPort
->pSocketBinding
= pService
->pSocketBinding
;
3655 pPort
->Signature
= PORT_SIGNATURE
;
3658 // Open the port protocol
3660 Status
= gBS
->OpenProtocol ( pPort
->Handle
,
3661 pSocketBinding
->pNetworkProtocolGuid
,
3662 &pPort
->pProtocol
.v
,
3663 pLayer
->ImageHandle
,
3665 EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL
);
3666 if ( EFI_ERROR ( Status
)) {
3667 DEBUG (( DEBUG_ERROR
| DebugFlags
,
3668 "ERROR - Failed to open network protocol GUID on controller 0x%08x\r\n",
3670 pSocket
->errno
= EEXIST
;
3673 DEBUG (( DebugFlags
,
3674 "0x%08x: Network protocol GUID opened on controller 0x%08x\r\n",
3679 // Initialize the port specific resources
3681 Status
= pSocket
->pApi
->pfnPortAllocate ( pPort
,
3683 if ( EFI_ERROR ( Status
)) {
3688 // Set the local address
3690 Status
= pSocket
->pApi
->pfnLocalAddrSet ( pPort
, pSockAddr
, bBindTest
);
3691 if ( EFI_ERROR ( Status
)) {
3696 // Test the address/port configuration
3699 Status
= EslSocketBindTest ( pPort
, pSocket
->pApi
->BindTestErrno
);
3700 if ( EFI_ERROR ( Status
)) {
3706 // Initialize the receive structures
3708 pBuffer
= (UINT8
*)&pPort
[ 1 ];
3709 pBuffer
= &pBuffer
[ ESL_STRUCTURE_ALIGNMENT_BYTES
];
3710 pBuffer
= (UINT8
*)( ESL_STRUCTURE_ALIGNMENT_MASK
& (UINTN
)pBuffer
);
3711 pIo
= (ESL_IO_MGMT
*)pBuffer
;
3712 if (( 0 != pSocketBinding
->RxIo
)
3713 && ( NULL
!= pSocket
->pApi
->pfnRxComplete
)) {
3714 Status
= EslSocketIoInit ( pPort
,
3716 pSocketBinding
->RxIo
,
3718 DebugFlags
| DEBUG_POOL
,
3720 pSocket
->pApi
->pfnRxComplete
);
3721 if ( EFI_ERROR ( Status
)) {
3727 // Initialize the urgent transmit structures
3729 if (( 0 != pSocketBinding
->TxIoUrgent
)
3730 && ( NULL
!= pSocket
->pApi
->pfnTxOobComplete
)) {
3731 Status
= EslSocketIoInit ( pPort
,
3733 pSocketBinding
->TxIoUrgent
,
3735 DebugFlags
| DEBUG_POOL
,
3737 pSocket
->pApi
->pfnTxOobComplete
);
3738 if ( EFI_ERROR ( Status
)) {
3744 // Initialize the normal transmit structures
3746 if (( 0 != pSocketBinding
->TxIoNormal
)
3747 && ( NULL
!= pSocket
->pApi
->pfnTxComplete
)) {
3748 Status
= EslSocketIoInit ( pPort
,
3750 pSocketBinding
->TxIoNormal
,
3752 DebugFlags
| DEBUG_POOL
,
3754 pSocket
->pApi
->pfnTxComplete
);
3755 if ( EFI_ERROR ( Status
)) {
3761 // Add this port to the socket
3763 pPort
->pLinkSocket
= pSocket
->pPortList
;
3764 pSocket
->pPortList
= pPort
;
3765 DEBUG (( DebugFlags
,
3766 "0x%08x: Socket adding port: 0x%08x\r\n",
3771 // Add this port to the service
3773 pPort
->pLinkService
= pService
->pPortList
;
3774 pService
->pPortList
= pPort
;
3784 // Clean up after the error if necessary
3786 if ( EFI_ERROR ( Status
)) {
3787 if ( NULL
!= pPort
) {
3791 EslSocketPortClose ( pPort
);
3795 // Close the port if necessary
3797 pServiceBinding
= pService
->pServiceBinding
;
3798 TempStatus
= pServiceBinding
->DestroyChild ( pServiceBinding
,
3800 if ( !EFI_ERROR ( TempStatus
)) {
3801 DEBUG (( DEBUG_BIND
| DEBUG_POOL
,
3802 "0x%08x: %s port handle destroyed\r\n",
3804 pSocketBinding
->pName
));
3807 DEBUG (( DEBUG_ERROR
| DEBUG_BIND
| DEBUG_POOL
,
3808 "ERROR - Failed to destroy the %s port handle 0x%08x, Status: %r\r\n",
3809 pSocketBinding
->pName
,
3812 ASSERT ( EFI_SUCCESS
== TempStatus
);
3817 // Return the operation status
3819 DBG_EXIT_STATUS ( Status
);
3827 This routine releases the resources allocated by ::EslSocketPortAllocate.
3828 This routine calls ESL_PROTOCOL_API::pfnPortClose to release the network
3831 This routine is called by:
3833 <li>::EslSocketPortAllocate - Port initialization failure</li>
3834 <li>::EslSocketPortCloseRxDone - Last step of close processing</li>
3835 <li>::EslTcp4ConnectComplete - Connection failure and reducing the port list to a single port</li>
3837 See the \ref PortCloseStateMachine section.
3839 @param [in] pPort Address of an ::ESL_PORT structure.
3841 @retval EFI_SUCCESS The port is closed
3842 @retval other Port close error
3846 EslSocketPortClose (
3852 ESL_PACKET
* pPacket
;
3853 ESL_PORT
* pPreviousPort
;
3854 ESL_SERVICE
* pService
;
3855 EFI_SERVICE_BINDING_PROTOCOL
* pServiceBinding
;
3856 CONST ESL_SOCKET_BINDING
* pSocketBinding
;
3857 ESL_SOCKET
* pSocket
;
3863 // Verify the socket layer synchronization
3865 VERIFY_TPL ( TPL_SOCKETS
);
3868 // Locate the port in the socket list
3870 Status
= EFI_SUCCESS
;
3871 pLayer
= &mEslLayer
;
3872 DebugFlags
= pPort
->DebugFlags
;
3873 pSocket
= pPort
->pSocket
;
3874 pPreviousPort
= pSocket
->pPortList
;
3875 if ( pPreviousPort
== pPort
) {
3877 // Remove this port from the head of the socket list
3879 pSocket
->pPortList
= pPort
->pLinkSocket
;
3883 // Locate the port in the middle of the socket list
3885 while (( NULL
!= pPreviousPort
)
3886 && ( pPreviousPort
->pLinkSocket
!= pPort
)) {
3887 pPreviousPort
= pPreviousPort
->pLinkSocket
;
3889 if ( NULL
!= pPreviousPort
) {
3891 // Remove the port from the middle of the socket list
3893 pPreviousPort
->pLinkSocket
= pPort
->pLinkSocket
;
3898 // Locate the port in the service list
3899 // Note that the port may not be in the service list
3900 // if the service has been shutdown.
3902 pService
= pPort
->pService
;
3903 if ( NULL
!= pService
) {
3904 pPreviousPort
= pService
->pPortList
;
3905 if ( pPreviousPort
== pPort
) {
3907 // Remove this port from the head of the service list
3909 pService
->pPortList
= pPort
->pLinkService
;
3913 // Locate the port in the middle of the service list
3915 while (( NULL
!= pPreviousPort
)
3916 && ( pPreviousPort
->pLinkService
!= pPort
)) {
3917 pPreviousPort
= pPreviousPort
->pLinkService
;
3919 if ( NULL
!= pPreviousPort
) {
3921 // Remove the port from the middle of the service list
3923 pPreviousPort
->pLinkService
= pPort
->pLinkService
;
3929 // Empty the urgent receive queue
3931 while ( NULL
!= pSocket
->pRxOobPacketListHead
) {
3932 pPacket
= pSocket
->pRxOobPacketListHead
;
3933 pSocket
->pRxOobPacketListHead
= pPacket
->pNext
;
3934 pSocket
->pApi
->pfnPacketFree ( pPacket
, &pSocket
->RxOobBytes
);
3935 EslSocketPacketFree ( pPacket
, DEBUG_RX
);
3937 pSocket
->pRxOobPacketListTail
= NULL
;
3938 ASSERT ( 0 == pSocket
->RxOobBytes
);
3941 // Empty the receive queue
3943 while ( NULL
!= pSocket
->pRxPacketListHead
) {
3944 pPacket
= pSocket
->pRxPacketListHead
;
3945 pSocket
->pRxPacketListHead
= pPacket
->pNext
;
3946 pSocket
->pApi
->pfnPacketFree ( pPacket
, &pSocket
->RxBytes
);
3947 EslSocketPacketFree ( pPacket
, DEBUG_RX
);
3949 pSocket
->pRxPacketListTail
= NULL
;
3950 ASSERT ( 0 == pSocket
->RxBytes
);
3953 // Empty the receive free queue
3955 while ( NULL
!= pSocket
->pRxFree
) {
3956 pPacket
= pSocket
->pRxFree
;
3957 pSocket
->pRxFree
= pPacket
->pNext
;
3958 EslSocketPacketFree ( pPacket
, DEBUG_RX
);
3962 // Release the network specific resources
3964 if ( NULL
!= pSocket
->pApi
->pfnPortClose
) {
3965 Status
= pSocket
->pApi
->pfnPortClose ( pPort
);
3969 // Done with the normal transmit events
3971 Status
= EslSocketIoFree ( pPort
,
3973 DebugFlags
| DEBUG_POOL
,
3974 "normal transmit" );
3977 // Done with the urgent transmit events
3979 Status
= EslSocketIoFree ( pPort
,
3981 DebugFlags
| DEBUG_POOL
,
3982 "urgent transmit" );
3985 // Done with the receive events
3987 Status
= EslSocketIoFree ( pPort
,
3989 DebugFlags
| DEBUG_POOL
,
3993 // Done with the lower layer network protocol
3995 pSocketBinding
= pPort
->pSocketBinding
;
3996 if ( NULL
!= pPort
->pProtocol
.v
) {
3997 Status
= gBS
->CloseProtocol ( pPort
->Handle
,
3998 pSocketBinding
->pNetworkProtocolGuid
,
3999 pLayer
->ImageHandle
,
4001 if ( !EFI_ERROR ( Status
)) {
4002 DEBUG (( DebugFlags
,
4003 "0x%08x: Network protocol GUID closed on controller 0x%08x\r\n",
4008 DEBUG (( DEBUG_ERROR
| DebugFlags
,
4009 "ERROR - Failed to close network protocol GUID on controller 0x%08x, Status: %r\r\n",
4012 ASSERT ( EFI_SUCCESS
== Status
);
4017 // Done with the network port
4019 pServiceBinding
= pPort
->pServiceBinding
;
4020 if ( NULL
!= pPort
->Handle
) {
4021 Status
= pServiceBinding
->DestroyChild ( pServiceBinding
,
4023 if ( !EFI_ERROR ( Status
)) {
4024 DEBUG (( DebugFlags
| DEBUG_POOL
,
4025 "0x%08x: %s port handle destroyed\r\n",
4027 pSocketBinding
->pName
));
4030 DEBUG (( DEBUG_ERROR
| DebugFlags
| DEBUG_POOL
,
4031 "ERROR - Failed to destroy the %s port handle, Status: %r\r\n",
4032 pSocketBinding
->pName
,
4034 ASSERT ( EFI_SUCCESS
== Status
);
4039 // Release the port structure
4041 Status
= gBS
->FreePool ( pPort
);
4042 if ( !EFI_ERROR ( Status
)) {
4043 DEBUG (( DebugFlags
| DEBUG_POOL
,
4044 "0x%08x: Free pPort, %d bytes\r\n",
4046 sizeof ( *pPort
)));
4049 DEBUG (( DEBUG_ERROR
| DebugFlags
| DEBUG_POOL
,
4050 "ERROR - Failed to free pPort: 0x%08x, Status: %r\r\n",
4053 ASSERT ( EFI_SUCCESS
== Status
);
4057 // Mark the socket as closed if necessary
4059 if ( NULL
== pSocket
->pPortList
) {
4060 pSocket
->State
= SOCKET_STATE_CLOSED
;
4061 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4062 "0x%08x: Socket State: SOCKET_STATE_CLOSED\r\n",
4067 // Return the operation status
4069 DBG_EXIT_STATUS ( Status
);
4077 This routine attempts to complete the port close operation.
4079 This routine is called by the TCP layer upon completion of
4080 the close operation and by ::EslSocketPortCloseTxDone.
4081 See the \ref PortCloseStateMachine section.
4083 @param [in] Event The close completion event
4085 @param [in] pPort Address of an ::ESL_PORT structure.
4089 EslSocketPortCloseComplete (
4098 VERIFY_AT_TPL ( TPL_SOCKETS
);
4101 // Update the port state
4103 pPort
->State
= PORT_STATE_CLOSE_DONE
;
4104 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4105 "0x%08x: Port Close State: PORT_STATE_CLOSE_DONE\r\n",
4109 // Shutdown the receive operation on the port
4111 if ( NULL
!= pPort
->pfnRxCancel
) {
4112 pIo
= pPort
->pRxActive
;
4113 while ( NULL
!= pIo
) {
4114 EslSocketRxCancel ( pPort
, pIo
);
4120 // Determine if the receive operation is pending
4122 Status
= EslSocketPortCloseRxDone ( pPort
);
4123 DBG_EXIT_STATUS ( Status
);
4130 This routine determines the state of the receive operations and
4131 continues the close operation after the pending receive operations
4134 This routine is called by
4136 <li>::EslSocketPortCloseComplete</li>
4137 <li>::EslSocketPortCloseTxDone</li>
4138 <li>::EslSocketRxComplete</li>
4140 to determine the state of the receive operations.
4141 See the \ref PortCloseStateMachine section.
4143 @param [in] pPort Address of an ::ESL_PORT structure.
4145 @retval EFI_SUCCESS The port is closed
4146 @retval EFI_NOT_READY The port is still closing
4147 @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
4148 most likely the routine was called already.
4152 EslSocketPortCloseRxDone (
4161 // Verify the socket layer synchronization
4163 VERIFY_TPL ( TPL_SOCKETS
);
4166 // Verify that the port is closing
4168 Status
= EFI_ALREADY_STARTED
;
4169 if ( PORT_STATE_CLOSE_DONE
== pPort
->State
) {
4171 // Determine if the receive operation is pending
4173 Status
= EFI_NOT_READY
;
4174 if ( NULL
== pPort
->pRxActive
) {
4176 // The receive operation is complete
4177 // Update the port state
4179 pPort
->State
= PORT_STATE_CLOSE_RX_DONE
;
4180 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4181 "0x%08x: Port Close State: PORT_STATE_CLOSE_RX_DONE\r\n",
4185 // Complete the port close operation
4187 Status
= EslSocketPortClose ( pPort
);
4190 DEBUG_CODE_BEGIN ();
4194 // Display the outstanding receive operations
4196 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4197 "0x%08x: Port Close: Receive still pending!\r\n",
4199 pIo
= pPort
->pRxActive
;
4200 while ( NULL
!= pIo
) {
4201 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4202 "0x%08x: Packet pending on network adapter\r\n",
4212 // Return the operation status
4214 DBG_EXIT_STATUS ( Status
);
4220 Start the close operation on a port, state 1.
4222 This routine marks the port as closed and initiates the \ref
4223 PortCloseStateMachine. The first step is to allow the \ref
4224 TransmitEngine to run down.
4226 This routine is called by ::EslSocketCloseStart to initiate the socket
4227 network specific close operation on the socket.
4229 @param [in] pPort Address of an ::ESL_PORT structure.
4230 @param [in] bCloseNow Set TRUE to abort active transfers
4231 @param [in] DebugFlags Flags for debug messages
4233 @retval EFI_SUCCESS The port is closed, not normally returned
4234 @retval EFI_NOT_READY The port has started the closing process
4235 @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
4236 most likely the routine was called already.
4240 EslSocketPortCloseStart (
4241 IN ESL_PORT
* pPort
,
4242 IN BOOLEAN bCloseNow
,
4246 ESL_SOCKET
* pSocket
;
4252 // Verify the socket layer synchronization
4254 VERIFY_TPL ( TPL_SOCKETS
);
4257 // Mark the port as closing
4259 Status
= EFI_ALREADY_STARTED
;
4260 pSocket
= pPort
->pSocket
;
4261 pSocket
->errno
= EALREADY
;
4262 if ( PORT_STATE_CLOSE_STARTED
> pPort
->State
) {
4265 // Update the port state
4267 pPort
->State
= PORT_STATE_CLOSE_STARTED
;
4268 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4269 "0x%08x: Port Close State: PORT_STATE_CLOSE_STARTED\r\n",
4271 pPort
->bCloseNow
= bCloseNow
;
4272 pPort
->DebugFlags
= DebugFlags
;
4275 // Determine if transmits are complete
4277 Status
= EslSocketPortCloseTxDone ( pPort
);
4281 // Return the operation status
4283 DBG_EXIT_STATUS ( Status
);
4291 This routine determines the state of the transmit engine and
4292 continue the close operation after the transmission is complete.
4293 The next step is to stop the \ref ReceiveEngine.
4294 See the \ref PortCloseStateMachine section.
4296 This routine is called by ::EslSocketPortCloseStart to determine
4297 if the transmission is complete.
4299 @param [in] pPort Address of an ::ESL_PORT structure.
4301 @retval EFI_SUCCESS The port is closed, not normally returned
4302 @retval EFI_NOT_READY The port is still closing
4303 @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
4304 most likely the routine was called already.
4308 EslSocketPortCloseTxDone (
4313 ESL_SOCKET
* pSocket
;
4319 // Verify the socket layer synchronization
4321 VERIFY_TPL ( TPL_SOCKETS
);
4324 // All transmissions are complete or must be stopped
4325 // Mark the port as TX complete
4327 Status
= EFI_ALREADY_STARTED
;
4328 if ( PORT_STATE_CLOSE_STARTED
== pPort
->State
) {
4330 // Verify that the transmissions are complete
4332 pSocket
= pPort
->pSocket
;
4333 if ( pPort
->bCloseNow
4334 || ( EFI_SUCCESS
!= pSocket
->TxError
)
4335 || (( NULL
== pPort
->pTxActive
)
4336 && ( NULL
== pPort
->pTxOobActive
))) {
4338 // Update the port state
4340 pPort
->State
= PORT_STATE_CLOSE_TX_DONE
;
4341 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4342 "0x%08x: Port Close State: PORT_STATE_CLOSE_TX_DONE\r\n",
4347 // Skip the close operation if the port is not configured
4349 Status
= EFI_SUCCESS
;
4350 pSocket
= pPort
->pSocket
;
4351 if (( pPort
->bConfigured
)
4352 && ( NULL
!= pSocket
->pApi
->pfnPortCloseOp
)) {
4354 // Start the close operation
4356 Status
= pSocket
->pApi
->pfnPortCloseOp ( pPort
);
4357 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4358 "0x%08x: Port Close: Close operation still pending!\r\n",
4360 ASSERT ( EFI_SUCCESS
== Status
);
4364 // The receive operation is complete
4365 // Update the port state
4367 EslSocketPortCloseComplete ( NULL
, pPort
);
4372 // Transmissions are still active, exit
4374 Status
= EFI_NOT_READY
;
4375 pSocket
->errno
= EAGAIN
;
4376 DEBUG_CODE_BEGIN ( );
4378 ESL_PACKET
* pPacket
;
4380 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4381 "0x%08x: Port Close: Transmits are still pending!\r\n",
4385 // Display the pending urgent transmit packets
4387 pPacket
= pSocket
->pTxOobPacketListHead
;
4388 while ( NULL
!= pPacket
) {
4389 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4390 "0x%08x: Packet pending on urgent TX list, %d bytes\r\n",
4392 pPacket
->PacketSize
));
4393 pPacket
= pPacket
->pNext
;
4396 pIo
= pPort
->pTxOobActive
;
4397 while ( NULL
!= pIo
) {
4398 pPacket
= pIo
->pPacket
;
4399 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4400 "0x%08x: Packet active %d bytes, pIo: 0x%08x\r\n",
4402 pPacket
->PacketSize
,
4408 // Display the pending normal transmit packets
4410 pPacket
= pSocket
->pTxPacketListHead
;
4411 while ( NULL
!= pPacket
) {
4412 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4413 "0x%08x: Packet pending on normal TX list, %d bytes\r\n",
4415 pPacket
->PacketSize
));
4416 pPacket
= pPacket
->pNext
;
4419 pIo
= pPort
->pTxActive
;
4420 while ( NULL
!= pIo
) {
4421 pPacket
= pIo
->pPacket
;
4422 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4423 "0x%08x: Packet active %d bytes, pIo: 0x%08x\r\n",
4425 pPacket
->PacketSize
,
4435 // Return the operation status
4437 DBG_EXIT_STATUS ( Status
);
4443 Receive data from a network connection.
4445 This routine calls the network specific routine to remove the
4446 next portion of data from the receive queue and return it to the
4449 The ::recvfrom routine calls this routine to determine if any data
4450 is received from the remote system. Note that the other routines
4451 ::recv and ::read are layered on top of ::recvfrom.
4453 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
4455 @param [in] Flags Message control flags
4457 @param [in] BufferLength Length of the the buffer
4459 @param [in] pBuffer Address of a buffer to receive the data.
4461 @param [in] pDataLength Number of received data bytes in the buffer.
4463 @param [out] pAddress Network address to receive the remote system address
4465 @param [in,out] pAddressLength Length of the remote network address structure
4467 @param [out] pErrno Address to receive the errno value upon completion.
4469 @retval EFI_SUCCESS - Socket data successfully received
4474 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
4476 IN
size_t BufferLength
,
4478 OUT
size_t * pDataLength
,
4479 OUT
struct sockaddr
* pAddress
,
4480 IN OUT socklen_t
* pAddressLength
,
4485 struct sockaddr_in v4
;
4486 struct sockaddr_in6 v6
;
4488 socklen_t AddressLength
;
4489 BOOLEAN bConsumePacket
;
4490 BOOLEAN bUrgentQueue
;
4492 ESL_PACKET
* pNextPacket
;
4493 ESL_PACKET
* pPacket
;
4495 ESL_PACKET
** ppQueueHead
;
4496 ESL_PACKET
** ppQueueTail
;
4497 struct sockaddr
* pRemoteAddress
;
4498 size_t * pRxDataBytes
;
4499 ESL_SOCKET
* pSocket
;
4502 EFI_TPL TplPrevious
;
4509 Status
= EFI_SUCCESS
;
4512 // Validate the socket
4515 if ( NULL
!= pSocketProtocol
) {
4516 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
4519 // Validate the return address parameters
4521 if (( NULL
== pAddress
) || ( NULL
!= pAddressLength
)) {
4523 // Return the transmit error if necessary
4525 if ( EFI_SUCCESS
!= pSocket
->TxError
) {
4526 pSocket
->errno
= EIO
;
4527 Status
= pSocket
->TxError
;
4528 pSocket
->TxError
= EFI_SUCCESS
;
4532 // Verify the socket state
4534 Status
= EslSocketIsConfigured ( pSocket
);
4535 if ( !EFI_ERROR ( Status
)) {
4537 // Validate the buffer length
4539 if (( NULL
== pDataLength
)
4540 || ( NULL
== pBuffer
)) {
4541 if ( NULL
== pDataLength
) {
4543 "ERROR - pDataLength is NULL!\r\n" ));
4547 "ERROR - pBuffer is NULL!\r\n" ));
4549 Status
= EFI_INVALID_PARAMETER
;
4550 pSocket
->errno
= EFAULT
;
4556 if ( NULL
== pSocket
->pApi
->pfnReceive
) {
4557 Status
= EFI_UNSUPPORTED
;
4558 pSocket
->errno
= ENOTSUP
;
4562 // Zero the receive address if being returned
4564 pRemoteAddress
= NULL
;
4565 if ( NULL
!= pAddress
) {
4566 pRemoteAddress
= (struct sockaddr
*)&Addr
;
4567 ZeroMem ( pRemoteAddress
, sizeof ( Addr
));
4568 pRemoteAddress
->sa_family
= pSocket
->pApi
->AddressFamily
;
4569 pRemoteAddress
->sa_len
= (UINT8
)pSocket
->pApi
->AddressLength
;
4573 // Synchronize with the socket layer
4575 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
4580 Status
= EFI_UNSUPPORTED
;
4581 pSocket
->errno
= ENOTCONN
;
4584 // Verify that the socket is connected
4586 if ( SOCKET_STATE_CONNECTED
== pSocket
->State
) {
4588 // Poll the network to increase performance
4590 EslSocketRxPoll ( pSocket
);
4595 pPort
= pSocket
->pPortList
;
4596 if ( NULL
!= pPort
) {
4598 // Determine the queue head
4600 bUrgentQueue
= (BOOLEAN
)( 0 != ( Flags
& MSG_OOB
));
4601 if ( bUrgentQueue
) {
4602 ppQueueHead
= &pSocket
->pRxOobPacketListHead
;
4603 ppQueueTail
= &pSocket
->pRxOobPacketListTail
;
4604 pRxDataBytes
= &pSocket
->RxOobBytes
;
4607 ppQueueHead
= &pSocket
->pRxPacketListHead
;
4608 ppQueueTail
= &pSocket
->pRxPacketListTail
;
4609 pRxDataBytes
= &pSocket
->RxBytes
;
4613 // Determine if there is any data on the queue
4616 pPacket
= *ppQueueHead
;
4617 if ( NULL
!= pPacket
) {
4619 // Copy the received data
4623 // Attempt to receive a packet
4626 bConsumePacket
= (BOOLEAN
)( 0 == ( Flags
& MSG_PEEK
));
4627 pBuffer
= pSocket
->pApi
->pfnReceive ( pPort
,
4633 (struct sockaddr
*)&Addr
,
4635 *pDataLength
+= DataLength
;
4636 BufferLength
-= DataLength
;
4639 // Determine if the data is being read
4641 pNextPacket
= pPacket
->pNext
;
4642 if ( bConsumePacket
) {
4644 // All done with this packet
4645 // Account for any discarded data
4647 pSocket
->pApi
->pfnPacketFree ( pPacket
, pRxDataBytes
);
4648 if ( 0 != SkipBytes
) {
4650 "0x%08x: Port, packet read, skipping over 0x%08x bytes\r\n",
4656 // Remove this packet from the queue
4658 *ppQueueHead
= pPacket
->pNext
;
4659 if ( NULL
== *ppQueueHead
) {
4660 *ppQueueTail
= NULL
;
4664 // Move the packet to the free queue
4666 pPacket
->pNext
= pSocket
->pRxFree
;
4667 pSocket
->pRxFree
= pPacket
;
4669 "0x%08x: Port freeing packet 0x%08x\r\n",
4674 // Restart the receive operation if necessary
4676 if (( NULL
!= pPort
->pRxFree
)
4677 && ( MAX_RX_DATA
> pSocket
->RxBytes
)) {
4678 EslSocketRxStart ( pPort
);
4683 // Get the next packet
4685 pPacket
= pNextPacket
;
4686 } while (( SOCK_STREAM
== pSocket
->Type
)
4687 && ( NULL
!= pPacket
)
4688 && ( 0 < BufferLength
));
4691 // Successful operation
4693 Status
= EFI_SUCCESS
;
4698 // The queue is empty
4699 // Determine if it is time to return the receive error
4701 if ( EFI_ERROR ( pSocket
->RxError
)
4702 && ( NULL
== pSocket
->pRxPacketListHead
)
4703 && ( NULL
== pSocket
->pRxOobPacketListHead
)) {
4704 Status
= pSocket
->RxError
;
4705 pSocket
->RxError
= EFI_SUCCESS
;
4708 pSocket
->errno
= EIO
;
4711 case EFI_CONNECTION_FIN
:
4713 // Continue to return zero bytes received when the
4714 // peer has successfully closed the connection
4716 pSocket
->RxError
= EFI_CONNECTION_FIN
;
4719 Status
= EFI_SUCCESS
;
4722 case EFI_CONNECTION_REFUSED
:
4723 pSocket
->errno
= ECONNREFUSED
;
4726 case EFI_CONNECTION_RESET
:
4727 pSocket
->errno
= ECONNRESET
;
4730 case EFI_HOST_UNREACHABLE
:
4731 pSocket
->errno
= EHOSTUNREACH
;
4734 case EFI_NETWORK_UNREACHABLE
:
4735 pSocket
->errno
= ENETUNREACH
;
4738 case EFI_PORT_UNREACHABLE
:
4739 pSocket
->errno
= EPROTONOSUPPORT
;
4742 case EFI_PROTOCOL_UNREACHABLE
:
4743 pSocket
->errno
= ENOPROTOOPT
;
4748 Status
= EFI_NOT_READY
;
4749 pSocket
->errno
= EAGAIN
;
4756 // Release the socket layer synchronization
4758 RESTORE_TPL ( TplPrevious
);
4760 if (( !EFI_ERROR ( Status
)) && ( NULL
!= pAddress
)) {
4762 // Return the remote address if requested, truncate if necessary
4764 AddressLength
= pRemoteAddress
->sa_len
;
4765 if ( AddressLength
> *pAddressLength
) {
4766 AddressLength
= *pAddressLength
;
4769 "Returning the remote address, 0x%016x bytes --> 0x%16x\r\n", *pAddressLength
, pAddress
));
4770 ZeroMem ( pAddress
, *pAddressLength
);
4771 CopyMem ( pAddress
, &Addr
, AddressLength
);
4774 // Update the address length
4776 *pAddressLength
= pRemoteAddress
->sa_len
;
4787 // Bad return address pointer and length
4789 Status
= EFI_INVALID_PARAMETER
;
4790 pSocket
->errno
= EINVAL
;
4795 // Return the operation status
4797 if ( NULL
!= pErrno
) {
4798 if ( NULL
!= pSocket
) {
4799 *pErrno
= pSocket
->errno
;
4802 Status
= EFI_INVALID_PARAMETER
;
4806 DBG_EXIT_STATUS ( Status
);
4812 Cancel the receive operations
4814 This routine cancels a pending receive operation.
4815 See the \ref ReceiveEngine section.
4817 This routine is called by ::EslSocketShutdown when the socket
4818 layer is being shutdown.
4820 @param [in] pPort Address of an ::ESL_PORT structure
4821 @param [in] pIo Address of an ::ESL_IO_MGMT structure
4826 IN ESL_PORT
* pPort
,
4827 IN ESL_IO_MGMT
* pIo
4835 // Cancel the outstanding receive
4837 Status
= pPort
->pfnRxCancel ( pPort
->pProtocol
.v
,
4839 if ( !EFI_ERROR ( Status
)) {
4840 DEBUG (( pPort
->DebugFlags
| DEBUG_CLOSE
| DEBUG_INFO
,
4841 "0x%08x: Packet receive aborted on port: 0x%08x\r\n",
4846 DEBUG (( pPort
->DebugFlags
| DEBUG_CLOSE
| DEBUG_INFO
,
4847 "0x%08x: Packet receive pending on Port 0x%08x, Status: %r\r\n",
4857 Process the receive completion
4859 This routine queues the data in FIFO order in either the urgent
4860 or normal data queues depending upon the type of data received.
4861 See the \ref ReceiveEngine section.
4863 This routine is called when some data is received by:
4865 <li>::EslIp4RxComplete</li>
4866 <li>::EslTcp4RxComplete</li>
4867 <li>::EslUdp4RxComplete</li>
4870 @param [in] pIo Address of an ::ESL_IO_MGMT structure
4871 @param [in] Status Receive status
4872 @param [in] LengthInBytes Length of the receive data
4873 @param [in] bUrgent TRUE if urgent data is received and FALSE
4878 EslSocketRxComplete (
4879 IN ESL_IO_MGMT
* pIo
,
4880 IN EFI_STATUS Status
,
4881 IN UINTN LengthInBytes
,
4885 BOOLEAN bUrgentQueue
;
4886 ESL_IO_MGMT
* pIoNext
;
4887 ESL_PACKET
* pPacket
;
4889 ESL_PACKET
* pPrevious
;
4890 ESL_PACKET
** ppQueueHead
;
4891 ESL_PACKET
** ppQueueTail
;
4893 ESL_SOCKET
* pSocket
;
4896 VERIFY_AT_TPL ( TPL_SOCKETS
);
4899 // Locate the active receive packet
4901 pPacket
= pIo
->pPacket
;
4903 pSocket
= pPort
->pSocket
;
4909 // +-------------+ +-------------+ +-------------+
4910 // Active | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
4911 // +-------------+ +-------------+ +-------------+
4913 // +-------------+ +-------------+ +-------------+
4914 // Free | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
4915 // +-------------+ +-------------+ +-------------+
4921 // Remove the IO structure from the active list
4922 // The following code searches for the entry in the list and does not
4923 // assume that the receive operations complete in the order they were
4924 // issued to the UEFI network layer.
4926 pIoNext
= pPort
->pRxActive
;
4927 while (( NULL
!= pIoNext
) && ( pIoNext
!= pIo
) && ( pIoNext
->pNext
!= pIo
))
4929 pIoNext
= pIoNext
->pNext
;
4931 ASSERT ( NULL
!= pIoNext
);
4932 if ( pIoNext
== pIo
) {
4933 pPort
->pRxActive
= pIo
->pNext
; // Beginning of list
4936 pIoNext
->pNext
= pIo
->pNext
; // Middle of list
4940 // Free the IO structure
4942 pIo
->pNext
= pPort
->pRxFree
;
4943 pPort
->pRxFree
= pIo
;
4946 // pRxOobPacketListHead pRxOobPacketListTail
4949 // +------------+ +------------+ +------------+
4950 // Urgent Data | ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL
4951 // +------------+ +------------+ +------------+
4953 // +------------+ +------------+ +------------+
4954 // Normal Data | ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL
4955 // +------------+ +------------+ +------------+
4958 // pRxPacketListHead pRxPacketListTail
4961 // Determine the queue to use
4963 bUrgentQueue
= (BOOLEAN
)( bUrgent
4964 && pSocket
->pApi
->bOobSupported
4965 && ( !pSocket
->bOobInLine
));
4966 if ( bUrgentQueue
) {
4967 ppQueueHead
= &pSocket
->pRxOobPacketListHead
;
4968 ppQueueTail
= &pSocket
->pRxOobPacketListTail
;
4969 pRxBytes
= &pSocket
->RxOobBytes
;
4972 ppQueueHead
= &pSocket
->pRxPacketListHead
;
4973 ppQueueTail
= &pSocket
->pRxPacketListTail
;
4974 pRxBytes
= &pSocket
->RxBytes
;
4978 // Determine if this receive was successful
4980 if (( !EFI_ERROR ( Status
))
4981 && ( PORT_STATE_CLOSE_STARTED
> pPort
->State
)
4982 && ( !pSocket
->bRxDisable
)) {
4984 // Account for the received data
4986 *pRxBytes
+= LengthInBytes
;
4989 // Log the received data
4991 DEBUG (( DEBUG_RX
| DEBUG_INFO
,
4992 "0x%08x: Packet queued on %s queue of port 0x%08x with 0x%08x bytes of %s data\r\n",
4994 bUrgentQueue
? L
"urgent" : L
"normal",
4997 bUrgent
? L
"urgent" : L
"normal" ));
5000 // Add the packet to the list tail.
5002 pPacket
->pNext
= NULL
;
5003 pPrevious
= *ppQueueTail
;
5004 if ( NULL
== pPrevious
) {
5005 *ppQueueHead
= pPacket
;
5008 pPrevious
->pNext
= pPacket
;
5010 *ppQueueTail
= pPacket
;
5013 // Attempt to restart this receive operation
5015 if ( pSocket
->MaxRxBuf
> pSocket
->RxBytes
) {
5016 EslSocketRxStart ( pPort
);
5020 "0x%08x: Port RX suspended, 0x%08x bytes queued\r\n",
5022 pSocket
->RxBytes
));
5026 if ( EFI_ERROR ( Status
)) {
5027 DEBUG (( DEBUG_RX
| DEBUG_INFO
,
5028 "ERROR - Receive error on port 0x%08x, packet 0x%08x, Status:%r\r\n",
5035 // Account for the receive bytes and release the driver's buffer
5037 if ( !EFI_ERROR ( Status
)) {
5038 *pRxBytes
+= LengthInBytes
;
5039 pSocket
->pApi
->pfnPacketFree ( pPacket
, pRxBytes
);
5043 // Receive error, free the packet save the error
5045 EslSocketPacketFree ( pPacket
, DEBUG_RX
);
5046 if ( !EFI_ERROR ( pSocket
->RxError
)) {
5047 pSocket
->RxError
= Status
;
5051 // Update the port state
5053 if ( PORT_STATE_CLOSE_STARTED
<= pPort
->State
) {
5054 if ( PORT_STATE_CLOSE_DONE
== pPort
->State
) {
5055 EslSocketPortCloseRxDone ( pPort
);
5059 if ( EFI_ERROR ( Status
)) {
5060 DEBUG (( DEBUG_RX
| DEBUG_INFO
,
5061 "0x%08x: Port state: PORT_STATE_RX_ERROR, Status: %r\r\n",
5064 pPort
->State
= PORT_STATE_RX_ERROR
;
5074 Poll a socket for pending receive activity.
5076 This routine is called at elivated TPL and extends the idle
5077 loop which polls a socket down into the LAN driver layer to
5078 determine if there is any receive activity.
5080 The ::EslSocketPoll, ::EslSocketReceive and ::EslSocketTransmit
5081 routines call this routine when there is nothing to do.
5083 @param [in] pSocket Address of an ::EFI_SOCKET structure.
5088 IN ESL_SOCKET
* pSocket
5093 DEBUG (( DEBUG_POLL
, "Entering EslSocketRxPoll\r\n" ));
5096 // Increase the network performance by extending the
5097 // polling (idle) loop down into the LAN driver
5099 pPort
= pSocket
->pPortList
;
5100 while ( NULL
!= pPort
) {
5102 // Poll the LAN adapter
5104 pPort
->pfnRxPoll ( pPort
->pProtocol
.v
);
5107 // Locate the next LAN adapter
5109 pPort
= pPort
->pLinkSocket
;
5112 DEBUG (( DEBUG_POLL
, "Exiting EslSocketRxPoll\r\n" ));
5117 Start a receive operation
5119 This routine posts a receive buffer to the network adapter.
5120 See the \ref ReceiveEngine section.
5122 This support routine is called by:
5124 <li>::EslIp4Receive to restart the receive engine to release flow control.</li>
5125 <li>::EslIp4RxComplete to continue the operation of the receive engine if flow control is not being applied.</li>
5126 <li>::EslIp4SocketIsConfigured to start the recevie engine for the new socket.</li>
5127 <li>::EslTcp4ListenComplete to start the recevie engine for the new socket.</li>
5128 <li>::EslTcp4Receive to restart the receive engine to release flow control.</li>
5129 <li>::EslTcp4RxComplete to continue the operation of the receive engine if flow control is not being applied.</li>
5130 <li>::EslUdp4Receive to restart the receive engine to release flow control.</li>
5131 <li>::EslUdp4RxComplete to continue the operation of the receive engine if flow control is not being applied.</li>
5132 <li>::EslUdp4SocketIsConfigured to start the recevie engine for the new socket.</li>
5135 @param [in] pPort Address of an ::ESL_PORT structure.
5145 ESL_PACKET
* pPacket
;
5146 ESL_SOCKET
* pSocket
;
5152 // Determine if a receive is already pending
5154 Status
= EFI_SUCCESS
;
5156 pSocket
= pPort
->pSocket
;
5157 if ( !EFI_ERROR ( pPort
->pSocket
->RxError
)) {
5158 if (( NULL
!= pPort
->pRxFree
)
5159 && ( !pSocket
->bRxDisable
)
5160 && ( PORT_STATE_CLOSE_STARTED
> pPort
->State
)) {
5162 // Start all of the pending receive operations
5164 while ( NULL
!= pPort
->pRxFree
) {
5166 // Determine if there are any free packets
5168 pPacket
= pSocket
->pRxFree
;
5169 if ( NULL
!= pPacket
) {
5171 // Remove this packet from the free list
5173 pSocket
->pRxFree
= pPacket
->pNext
;
5175 "0x%08x: Port removed packet 0x%08x from free list\r\n",
5181 // Allocate a packet structure
5183 Status
= EslSocketPacketAllocate ( &pPacket
,
5184 pSocket
->pApi
->RxPacketBytes
,
5185 pSocket
->pApi
->RxZeroBytes
,
5187 if ( EFI_ERROR ( Status
)) {
5189 DEBUG (( DEBUG_ERROR
| DEBUG_RX
,
5190 "0x%08x: Port failed to allocate RX packet, Status: %r\r\n",
5198 // Connect the IO and packet structures
5200 pIo
= pPort
->pRxFree
;
5201 pIo
->pPacket
= pPacket
;
5204 // Eliminate the need for IP4 and UDP4 specific routines by
5205 // clearing the RX data pointer here.
5207 // No driver buffer for this packet
5209 // +--------------------+
5212 // | +---------------+
5214 // | | RxData --> NULL
5215 // +----+---------------+
5217 pBuffer
= (UINT8
*)pIo
;
5218 pBuffer
= &pBuffer
[ pSocket
->pApi
->RxBufferOffset
];
5219 *(VOID
**)pBuffer
= NULL
;
5222 // Network specific receive packet initialization
5224 if ( NULL
!= pSocket
->pApi
->pfnRxStart
) {
5225 pSocket
->pApi
->pfnRxStart ( pPort
, pIo
);
5229 // Start the receive on the packet
5231 Status
= pPort
->pfnRxStart ( pPort
->pProtocol
.v
, &pIo
->Token
);
5232 if ( !EFI_ERROR ( Status
)) {
5233 DEBUG (( DEBUG_RX
| DEBUG_INFO
,
5234 "0x%08x: Packet receive pending on port 0x%08x\r\n",
5238 // Allocate the receive control structure
5240 pPort
->pRxFree
= pIo
->pNext
;
5243 // Mark this receive as pending
5245 pIo
->pNext
= pPort
->pRxActive
;
5246 pPort
->pRxActive
= pIo
;
5250 DEBUG (( DEBUG_RX
| DEBUG_INFO
,
5251 "ERROR - Failed to post a receive on port 0x%08x, Status: %r\r\n",
5254 if ( !EFI_ERROR ( pSocket
->RxError
)) {
5256 // Save the error status
5258 pSocket
->RxError
= Status
;
5264 pIo
->pPacket
= NULL
;
5265 pPacket
->pNext
= pSocket
->pRxFree
;
5266 pSocket
->pRxFree
= pPacket
;
5272 if ( NULL
== pPort
->pRxFree
) {
5273 DEBUG (( DEBUG_RX
| DEBUG_INFO
,
5274 "0x%08x: Port, no available ESL_IO_MGMT structures\r\n",
5277 if ( pSocket
->bRxDisable
) {
5278 DEBUG (( DEBUG_RX
| DEBUG_INFO
,
5279 "0x%08x: Port, receive disabled!\r\n",
5282 if ( PORT_STATE_CLOSE_STARTED
<= pPort
->State
) {
5283 DEBUG (( DEBUG_RX
| DEBUG_INFO
,
5284 "0x%08x: Port, is closing!\r\n",
5290 DEBUG (( DEBUG_ERROR
| DEBUG_RX
,
5291 "ERROR - Previous receive error, Status: %r\r\n",
5292 pPort
->pSocket
->RxError
));
5300 Shutdown the socket receive and transmit operations
5302 This routine sets a flag to stop future transmissions and calls
5303 the network specific layer to cancel the pending receive operation.
5305 The ::shutdown routine calls this routine to stop receive and transmit
5306 operations on the socket.
5308 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
5310 @param [in] How Which operations to stop
5312 @param [out] pErrno Address to receive the errno value upon completion.
5314 @retval EFI_SUCCESS - Socket operations successfully shutdown
5319 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
5326 ESL_SOCKET
* pSocket
;
5328 EFI_TPL TplPrevious
;
5335 Status
= EFI_SUCCESS
;
5338 // Validate the socket
5341 if ( NULL
!= pSocketProtocol
) {
5342 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
5345 // Verify that the socket is connected
5347 if ( pSocket
->bConnected
) {
5349 // Validate the How value
5351 if (( SHUT_RD
<= How
) && ( SHUT_RDWR
>= How
)) {
5353 // Synchronize with the socket layer
5355 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
5358 // Disable the receiver if requested
5360 if (( SHUT_RD
== How
) || ( SHUT_RDWR
== How
)) {
5361 pSocket
->bRxDisable
= TRUE
;
5365 // Disable the transmitter if requested
5367 if (( SHUT_WR
== How
) || ( SHUT_RDWR
== How
)) {
5368 pSocket
->bTxDisable
= TRUE
;
5372 // Cancel the pending receive operations
5374 if ( pSocket
->bRxDisable
) {
5376 // Walk the list of ports
5378 pPort
= pSocket
->pPortList
;
5379 while ( NULL
!= pPort
) {
5381 // Walk the list of active receive operations
5383 pIo
= pPort
->pRxActive
;
5384 while ( NULL
!= pIo
) {
5385 EslSocketRxCancel ( pPort
, pIo
);
5389 // Set the next port
5391 pPort
= pPort
->pLinkSocket
;
5396 // Release the socket layer synchronization
5398 RESTORE_TPL ( TplPrevious
);
5402 // Invalid How value
5404 pSocket
->errno
= EINVAL
;
5405 Status
= EFI_INVALID_PARAMETER
;
5410 // The socket is not connected
5412 pSocket
->errno
= ENOTCONN
;
5413 Status
= EFI_NOT_STARTED
;
5418 // Return the operation status
5420 if ( NULL
!= pErrno
) {
5421 if ( NULL
!= pSocket
) {
5422 *pErrno
= pSocket
->errno
;
5425 Status
= EFI_INVALID_PARAMETER
;
5429 DBG_EXIT_STATUS ( Status
);
5435 Send data using a network connection.
5437 This routine calls the network specific layer to queue the data
5438 for transmission. Eventually the buffer will reach the head of
5439 the queue and will get transmitted over the network by the
5440 \ref TransmitEngine. For datagram
5441 sockets (SOCK_DGRAM and SOCK_RAW) there is no guarantee that
5442 the data reaches the application running on the remote system.
5444 The ::sendto routine calls this routine to send data to the remote
5445 system. Note that ::send and ::write are layered on top of ::sendto.
5447 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
5449 @param [in] Flags Message control flags
5451 @param [in] BufferLength Length of the the buffer
5453 @param [in] pBuffer Address of a buffer containing the data to send
5455 @param [in] pDataLength Address to receive the number of data bytes sent
5457 @param [in] pAddress Network address of the remote system address
5459 @param [in] AddressLength Length of the remote network address structure
5461 @param [out] pErrno Address to receive the errno value upon completion.
5463 @retval EFI_SUCCESS - Socket data successfully queued for transmit
5468 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
5470 IN
size_t BufferLength
,
5471 IN CONST UINT8
* pBuffer
,
5472 OUT
size_t * pDataLength
,
5473 IN
const struct sockaddr
* pAddress
,
5474 IN socklen_t AddressLength
,
5478 ESL_SOCKET
* pSocket
;
5480 EFI_TPL TplPrevious
;
5487 Status
= EFI_SUCCESS
;
5490 // Validate the socket
5493 if ( NULL
!= pSocketProtocol
) {
5494 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
5497 // Return the transmit error if necessary
5499 if ( EFI_SUCCESS
!= pSocket
->TxError
) {
5500 pSocket
->errno
= EIO
;
5501 Status
= pSocket
->TxError
;
5502 pSocket
->TxError
= EFI_SUCCESS
;
5506 // Verify the socket state
5508 Status
= EslSocketIsConfigured ( pSocket
);
5509 if ( !EFI_ERROR ( Status
)) {
5511 // Verify that transmit is still allowed
5513 if ( !pSocket
->bTxDisable
) {
5515 // Validate the buffer length
5517 if (( NULL
== pDataLength
)
5518 && ( 0 > pDataLength
)
5519 && ( NULL
== pBuffer
)) {
5520 if ( NULL
== pDataLength
) {
5522 "ERROR - pDataLength is NULL!\r\n" ));
5524 else if ( NULL
== pBuffer
) {
5526 "ERROR - pBuffer is NULL!\r\n" ));
5530 "ERROR - Data length < 0!\r\n" ));
5532 Status
= EFI_INVALID_PARAMETER
;
5533 pSocket
->errno
= EFAULT
;
5537 // Validate the remote network address
5539 if (( NULL
!= pAddress
)
5540 && ( AddressLength
< pAddress
->sa_len
)) {
5542 "ERROR - Invalid sin_len field in address\r\n" ));
5543 Status
= EFI_INVALID_PARAMETER
;
5544 pSocket
->errno
= EFAULT
;
5550 if ( NULL
== pSocket
->pApi
->pfnTransmit
) {
5551 Status
= EFI_UNSUPPORTED
;
5552 pSocket
->errno
= ENOTSUP
;
5556 // Synchronize with the socket layer
5558 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
5561 // Poll the network to increase performance
5563 EslSocketRxPoll ( pSocket
);
5566 // Attempt to buffer the packet for transmission
5568 Status
= pSocket
->pApi
->pfnTransmit ( pSocket
,
5577 // Release the socket layer synchronization
5579 RESTORE_TPL ( TplPrevious
);
5586 // The transmitter was shutdown
5588 pSocket
->errno
= EPIPE
;
5589 Status
= EFI_NOT_STARTED
;
5596 // Return the operation status
5598 if ( NULL
!= pErrno
) {
5599 if ( NULL
!= pSocket
) {
5600 *pErrno
= pSocket
->errno
;
5603 Status
= EFI_INVALID_PARAMETER
;
5607 DBG_EXIT_STATUS ( Status
);
5613 Complete the transmit operation
5615 This support routine handles the transmit completion processing for
5616 the various network layers. It frees the ::ESL_IO_MGMT structure
5617 and and frees packet resources by calling ::EslSocketPacketFree.
5618 Transmit errors are logged in ESL_SOCKET::TxError.
5619 See the \ref TransmitEngine section.
5621 This routine is called by:
5623 <li>::EslIp4TxComplete</li>
5624 <li>::EslTcp4TxComplete</li>
5625 <li>::EslTcp4TxOobComplete</li>
5626 <li>::EslUdp4TxComplete</li>
5629 @param [in] pIo Address of an ::ESL_IO_MGMT structure
5630 @param [in] LengthInBytes Length of the data in bytes
5631 @param [in] Status Transmit operation status
5632 @param [in] pQueueType Zero terminated string describing queue type
5633 @param [in] ppQueueHead Transmit queue head address
5634 @param [in] ppQueueTail Transmit queue tail address
5635 @param [in] ppActive Active transmit queue address
5636 @param [in] ppFree Free transmit queue address
5640 EslSocketTxComplete (
5641 IN ESL_IO_MGMT
* pIo
,
5642 IN UINT32 LengthInBytes
,
5643 IN EFI_STATUS Status
,
5644 IN CONST CHAR8
* pQueueType
,
5645 IN ESL_PACKET
** ppQueueHead
,
5646 IN ESL_PACKET
** ppQueueTail
,
5647 IN ESL_IO_MGMT
** ppActive
,
5648 IN ESL_IO_MGMT
** ppFree
5651 ESL_PACKET
* pCurrentPacket
;
5652 ESL_IO_MGMT
* pIoNext
;
5653 ESL_PACKET
* pNextPacket
;
5654 ESL_PACKET
* pPacket
;
5656 ESL_SOCKET
* pSocket
;
5659 VERIFY_AT_TPL ( TPL_SOCKETS
);
5662 // Locate the active transmit packet
5664 pPacket
= pIo
->pPacket
;
5666 pSocket
= pPort
->pSocket
;
5671 pIo
->pPacket
= NULL
;
5674 // Remove the IO structure from the active list
5676 pIoNext
= *ppActive
;
5677 while (( NULL
!= pIoNext
) && ( pIoNext
!= pIo
) && ( pIoNext
->pNext
!= pIo
))
5679 pIoNext
= pIoNext
->pNext
;
5681 ASSERT ( NULL
!= pIoNext
);
5682 if ( pIoNext
== pIo
) {
5683 *ppActive
= pIo
->pNext
; // Beginning of list
5686 pIoNext
->pNext
= pIo
->pNext
; // Middle of list
5690 // Free the IO structure
5692 pIo
->pNext
= *ppFree
;
5696 // Display the results
5698 DEBUG (( DEBUG_TX
| DEBUG_INFO
,
5699 "0x%08x: pIo Released\r\n",
5703 // Save any transmit error
5705 if ( EFI_ERROR ( Status
)) {
5706 if ( !EFI_ERROR ( pSocket
->TxError
)) {
5707 pSocket
->TxError
= Status
;
5709 DEBUG (( DEBUG_TX
| DEBUG_INFO
,
5710 "ERROR - Transmit failure for %apacket 0x%08x, Status: %r\r\n",
5716 // Empty the normal transmit list
5718 pCurrentPacket
= pPacket
;
5719 pNextPacket
= *ppQueueHead
;
5720 while ( NULL
!= pNextPacket
) {
5721 pPacket
= pNextPacket
;
5722 pNextPacket
= pPacket
->pNext
;
5723 EslSocketPacketFree ( pPacket
, DEBUG_TX
);
5725 *ppQueueHead
= NULL
;
5726 *ppQueueTail
= NULL
;
5727 pPacket
= pCurrentPacket
;
5730 DEBUG (( DEBUG_TX
| DEBUG_INFO
,
5731 "0x%08x: %apacket transmitted %d bytes successfully\r\n",
5737 // Verify the transmit engine is still running
5739 if ( !pPort
->bCloseNow
) {
5741 // Start the next packet transmission
5743 EslSocketTxStart ( pPort
,
5752 // Release this packet
5754 EslSocketPacketFree ( pPacket
, DEBUG_TX
);
5757 // Finish the close operation if necessary
5759 if ( PORT_STATE_CLOSE_STARTED
<= pPort
->State
) {
5761 // Indicate that the transmit is complete
5763 EslSocketPortCloseTxDone ( pPort
);
5771 Transmit data using a network connection.
5773 This support routine starts a transmit operation on the
5774 underlying network layer.
5776 The network specific code calls this routine to start a
5777 transmit operation. See the \ref TransmitEngine section.
5779 @param [in] pPort Address of an ::ESL_PORT structure
5780 @param [in] ppQueueHead Transmit queue head address
5781 @param [in] ppQueueTail Transmit queue tail address
5782 @param [in] ppActive Active transmit queue address
5783 @param [in] ppFree Free transmit queue address
5788 IN ESL_PORT
* pPort
,
5789 IN ESL_PACKET
** ppQueueHead
,
5790 IN ESL_PACKET
** ppQueueTail
,
5791 IN ESL_IO_MGMT
** ppActive
,
5792 IN ESL_IO_MGMT
** ppFree
5797 ESL_PACKET
* pNextPacket
;
5798 ESL_PACKET
* pPacket
;
5799 VOID
** ppTokenData
;
5800 ESL_SOCKET
* pSocket
;
5808 Status
= EFI_SUCCESS
;
5811 // Get the packet from the queue head
5813 pPacket
= *ppQueueHead
;
5815 if (( NULL
!= pPacket
) && ( NULL
!= pIo
)) {
5816 pSocket
= pPort
->pSocket
;
5818 // *ppQueueHead: pSocket->pRxPacketListHead or pSocket->pRxOobPacketListHead
5821 // +------------+ +------------+ +------------+
5822 // Data | ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL
5823 // +------------+ +------------+ +------------+
5826 // *ppQueueTail: pSocket->pRxPacketListTail or pSocket->pRxOobPacketListTail
5829 // Remove the packet from the queue
5831 pNextPacket
= pPacket
->pNext
;
5832 *ppQueueHead
= pNextPacket
;
5833 if ( NULL
== pNextPacket
) {
5834 *ppQueueTail
= NULL
;
5836 pPacket
->pNext
= NULL
;
5839 // Eliminate the need for IP4 and UDP4 specific routines by
5840 // connecting the token with the TX data control structure here.
5842 // +--------------------+ +--------------------+
5843 // | ESL_IO_MGMT | | ESL_PACKET |
5845 // | +---------------+ +----------------+ |
5846 // | | Token | | Buffer Length | |
5847 // | | TxData --> | Buffer Address | |
5848 // | | | +----------------+---+
5849 // | | Event | | Data Buffer |
5850 // +----+---------------+ | |
5851 // +--------------------+
5853 // Compute the address of the TxData pointer in the token
5855 pBuffer
= (UINT8
*)&pIo
->Token
;
5856 pBuffer
= &pBuffer
[ pSocket
->TxTokenOffset
];
5857 ppTokenData
= (VOID
**)pBuffer
;
5860 // Compute the address of the TX data control structure in the packet
5862 // * EFI_IP4_TRANSMIT_DATA
5863 // * EFI_TCP4_TRANSMIT_DATA
5864 // * EFI_UDP4_TRANSMIT_DATA
5866 pBuffer
= (UINT8
*)pPacket
;
5867 pBuffer
= &pBuffer
[ pSocket
->TxPacketOffset
];
5870 // Connect the token to the transmit data control structure
5872 *ppTokenData
= (VOID
**)pBuffer
;
5875 // Display the results
5877 DEBUG (( DEBUG_TX
| DEBUG_INFO
,
5878 "0x%08x: pIo allocated for pPacket: 0x%08x\r\n",
5883 // Start the transmit operation
5885 Status
= pPort
->pfnTxStart ( pPort
->pProtocol
.v
,
5887 if ( !EFI_ERROR ( Status
)) {
5889 // Connect the structures
5891 pIo
->pPacket
= pPacket
;
5894 // +-------------+ +-------------+ +-------------+
5895 // Free | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
5896 // +-------------+ +-------------+ +-------------+
5899 // *ppFree: pPort->pTxFree or pTxOobFree
5902 // Remove the IO structure from the queue
5904 *ppFree
= pIo
->pNext
;
5907 // *ppActive: pPort->pTxActive or pTxOobActive
5910 // +-------------+ +-------------+ +-------------+
5911 // Active | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
5912 // +-------------+ +-------------+ +-------------+
5915 // Mark this packet as active
5917 pIo
->pPacket
= pPacket
;
5918 pIo
->pNext
= *ppActive
;
5922 if ( EFI_SUCCESS
== pSocket
->TxError
) {
5923 pSocket
->TxError
= Status
;
5927 // Discard the transmit buffer
5929 EslSocketPacketFree ( pPacket
, DEBUG_TX
);