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 &gEfiUdp4ServiceBindingProtocolGuid
,
486 &gEfiUdp4ProtocolGuid
,
487 &mEslUdp4ServiceGuid
,
488 OFFSET_OF ( ESL_LAYER
, pUdp4List
),
491 0 } // TX Oob buffers
494 CONST UINTN cEslSocketBindingEntries
= DIM ( cEslSocketBinding
);
497 APIs to support the various socket types for the v4 network stack.
499 CONST ESL_PROTOCOL_API
* cEslAfInetApi
[] = {
501 &cEslTcp4Api
, // SOCK_STREAM
502 &cEslUdp4Api
, // SOCK_DGRAM
503 &cEslIp4Api
, // SOCK_RAW
505 &cEslTcp4Api
// SOCK_SEQPACKET
509 Number of entries in the v4 API array ::cEslAfInetApi.
511 CONST
int cEslAfInetApiSize
= DIM ( cEslAfInetApi
);
515 APIs to support the various socket types for the v6 network stack.
517 CONST ESL_PROTOCOL_API
* cEslAfInet6Api
[] = {
523 NULL
// SOCK_SEQPACKET
527 Number of entries in the v6 API array ::cEslAfInet6Api.
529 CONST
int cEslAfInet6ApiSize
= DIM ( cEslAfInet6Api
);
533 Global management structure for the socket layer.
539 Initialize an endpoint for network communication.
541 This routine initializes the communication endpoint.
543 The ::socket routine calls this routine indirectly to create
544 the communication endpoint.
546 @param [in] pSocketProtocol Address of the socket protocol structure.
547 @param [in] domain Select the family of protocols for the client or server
548 application. See the ::socket documentation for values.
549 @param [in] type Specifies how to make the network connection.
550 See the ::socket documentation for values.
551 @param [in] protocol Specifies the lower layer protocol to use.
552 See the ::socket documentation for values.
553 @param [out] pErrno Address to receive the errno value upon completion.
555 @retval EFI_SUCCESS - Socket successfully created
556 @retval EFI_INVALID_PARAMETER - Invalid domain value, errno = EAFNOSUPPORT
557 @retval EFI_INVALID_PARAMETER - Invalid type value, errno = EINVAL
558 @retval EFI_INVALID_PARAMETER - Invalid protocol value, errno = EINVAL
563 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
570 CONST ESL_PROTOCOL_API
* pApi
;
571 CONST ESL_PROTOCOL_API
** ppApiArray
;
572 CONST ESL_PROTOCOL_API
** ppApiArrayEnd
;
574 ESL_SOCKET
* pSocket
;
583 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
586 // Set the default domain if necessary
588 if ( AF_UNSPEC
== domain
) {
596 Status
= EFI_SUCCESS
;
599 // Use break instead of goto
603 // Validate the domain value
605 if (( AF_INET
!= domain
)
606 && ( AF_LOCAL
!= domain
)) {
607 DEBUG (( DEBUG_ERROR
| DEBUG_SOCKET
,
608 "ERROR - Invalid domain value\r\n" ));
609 Status
= EFI_INVALID_PARAMETER
;
610 errno
= EAFNOSUPPORT
;
615 // Determine the protocol APIs
619 if (( AF_INET
== domain
)
620 || ( AF_LOCAL
== domain
)) {
621 ppApiArray
= &cEslAfInetApi
[0];
622 ApiArraySize
= cEslAfInetApiSize
;
625 ppApiArray
= &cEslAfInet6Api
[0];
626 ApiArraySize
= cEslAfInet6ApiSize
;
630 // Set the default type if necessary
637 // Validate the type value
639 if (( type
>= ApiArraySize
)
640 || ( NULL
== ppApiArray
)
641 || ( NULL
== ppApiArray
[ type
])) {
642 DEBUG (( DEBUG_ERROR
| DEBUG_SOCKET
,
643 "ERROR - Invalid type value\r\n" ));
645 // The socket type is not supported
647 Status
= EFI_INVALID_PARAMETER
;
653 // Set the default protocol if necessary
655 pApi
= ppApiArray
[ type
];
656 if ( 0 == protocol
) {
657 protocol
= pApi
->DefaultProtocol
;
661 // Validate the protocol value
663 if (( pApi
->DefaultProtocol
!= protocol
)
664 && ( SOCK_RAW
!= type
)) {
665 Status
= EFI_INVALID_PARAMETER
;
668 // Assume that the driver supports this protocol
670 ppApiArray
= &cEslAfInetApi
[0];
671 ppApiArrayEnd
= &ppApiArray
[ cEslAfInetApiSize
];
672 while ( ppApiArrayEnd
> ppApiArray
) {
674 if ( protocol
== pApi
->DefaultProtocol
) {
679 if ( ppApiArrayEnd
<= ppApiArray
) {
681 // Verify against the IPv6 table
683 ppApiArray
= &cEslAfInet6Api
[0];
684 ppApiArrayEnd
= &ppApiArray
[ cEslAfInet6ApiSize
];
685 while ( ppApiArrayEnd
> ppApiArray
) {
687 if ( protocol
== pApi
->DefaultProtocol
) {
693 if ( ppApiArrayEnd
<= ppApiArray
) {
694 DEBUG (( DEBUG_ERROR
| DEBUG_SOCKET
,
695 "ERROR - The protocol is not supported!\r\n" ));
696 errno
= EPROTONOSUPPORT
;
701 // The driver does not support this protocol
703 DEBUG (( DEBUG_ERROR
| DEBUG_SOCKET
,
704 "ERROR - The protocol does not support this socket type!\r\n" ));
705 errno
= EPROTONOSUPPORT
;
711 // Save the socket attributes
713 pSocket
->pApi
= pApi
;
714 pSocket
->Domain
= domain
;
715 pSocket
->Type
= type
;
716 pSocket
->Protocol
= protocol
;
725 // Return the operation status
727 if ( NULL
!= pErrno
) {
730 DBG_EXIT_STATUS ( Status
);
736 Accept a network connection.
738 This routine calls the network specific layer to remove the next
739 connection from the FIFO.
741 The ::accept calls this routine to poll for a network
742 connection to the socket. When a connection is available
743 this routine returns the ::EFI_SOCKET_PROTOCOL structure address
744 associated with the new socket and the remote network address
747 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
749 @param [in] pSockAddr Address of a buffer to receive the remote
752 @param [in, out] pSockAddrLength Length in bytes of the address buffer.
753 On output specifies the length of the
754 remote network address.
756 @param [out] ppSocketProtocol Address of a buffer to receive the
757 ::EFI_SOCKET_PROTOCOL instance
758 associated with the new socket.
760 @param [out] pErrno Address to receive the errno value upon completion.
762 @retval EFI_SUCCESS New connection successfully created
763 @retval EFI_NOT_READY No connection is available
768 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
769 IN
struct sockaddr
* pSockAddr
,
770 IN OUT socklen_t
* pSockAddrLength
,
771 IN EFI_SOCKET_PROTOCOL
** ppSocketProtocol
,
775 ESL_SOCKET
* pNewSocket
;
776 ESL_SOCKET
* pSocket
;
785 Status
= EFI_SUCCESS
;
788 // Validate the socket
792 if ( NULL
!= pSocketProtocol
) {
793 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
798 if ( NULL
== pSocket
->pApi
->pfnAccept
) {
799 Status
= EFI_UNSUPPORTED
;
800 pSocket
->errno
= ENOTSUP
;
804 // Validate the sockaddr
806 if (( NULL
!= pSockAddr
)
807 && ( NULL
== pSockAddrLength
)) {
808 DEBUG (( DEBUG_ACCEPT
,
809 "ERROR - pSockAddr is NULL!\r\n" ));
810 Status
= EFI_INVALID_PARAMETER
;
811 pSocket
->errno
= EFAULT
;
815 // Synchronize with the socket layer
817 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
820 // Verify that the socket is in the listen state
822 if ( SOCKET_STATE_LISTENING
!= pSocket
->State
) {
823 DEBUG (( DEBUG_ACCEPT
,
824 "ERROR - Socket is not listening!\r\n" ));
825 if ( NULL
== pSocket
->pApi
->pfnAccept
) {
827 // Socket does not support listen
829 pSocket
->errno
= EOPNOTSUPP
;
830 Status
= EFI_UNSUPPORTED
;
834 // Socket supports listen, but not in listen state
836 pSocket
->errno
= EINVAL
;
837 Status
= EFI_NOT_STARTED
;
842 // Determine if a socket is available
844 if ( 0 == pSocket
->FifoDepth
) {
846 // No connections available
847 // Determine if any ports are available
849 if ( NULL
== pSocket
->pPortList
) {
851 // No ports available
853 Status
= EFI_DEVICE_ERROR
;
854 pSocket
->errno
= EINVAL
;
857 // Update the socket state
859 pSocket
->State
= SOCKET_STATE_NO_PORTS
;
863 // Ports are available
864 // No connection requests at this time
866 Status
= EFI_NOT_READY
;
867 pSocket
->errno
= EAGAIN
;
873 // Attempt to accept the connection and
874 // get the remote network address
876 pNewSocket
= pSocket
->pFifoHead
;
877 ASSERT ( NULL
!= pNewSocket
);
878 Status
= pSocket
->pApi
->pfnAccept ( pNewSocket
,
881 if ( !EFI_ERROR ( Status
)) {
883 // Remove the new socket from the list
885 pSocket
->pFifoHead
= pNewSocket
->pNextConnection
;
886 if ( NULL
== pSocket
->pFifoHead
) {
887 pSocket
->pFifoTail
= NULL
;
891 // Account for this socket
893 pSocket
->FifoDepth
-= 1;
896 // Update the new socket's state
898 pNewSocket
->State
= SOCKET_STATE_CONNECTED
;
899 pNewSocket
->bConfigured
= TRUE
;
900 DEBUG (( DEBUG_ACCEPT
,
901 "0x%08x: Socket connected\r\n",
908 // Release the socket layer synchronization
910 RESTORE_TPL ( TplPrevious
);
916 // Return the new socket
918 if (( NULL
!= ppSocketProtocol
)
919 && ( NULL
!= pNewSocket
)) {
920 *ppSocketProtocol
= &pNewSocket
->SocketProtocol
;
924 // Return the operation status
926 if ( NULL
!= pErrno
) {
927 if ( NULL
!= pSocket
) {
928 *pErrno
= pSocket
->errno
;
931 Status
= EFI_INVALID_PARAMETER
;
935 DBG_EXIT_STATUS ( Status
);
941 Allocate and initialize a ESL_SOCKET structure.
943 This support function allocates an ::ESL_SOCKET structure
944 and installs a protocol on ChildHandle. If pChildHandle is a
945 pointer to NULL, then a new handle is created and returned in
946 pChildHandle. If pChildHandle is not a pointer to NULL, then
947 the protocol installs on the existing pChildHandle.
949 @param [in, out] pChildHandle Pointer to the handle of the child to create.
950 If it is NULL, then a new handle is created.
951 If it is a pointer to an existing UEFI handle,
952 then the protocol is added to the existing UEFI
954 @param [in] DebugFlags Flags for debug messages
955 @param [in, out] ppSocket The buffer to receive an ::ESL_SOCKET structure address.
957 @retval EFI_SUCCESS The protocol was added to ChildHandle.
958 @retval EFI_INVALID_PARAMETER ChildHandle is NULL.
959 @retval EFI_OUT_OF_RESOURCES There are not enough resources available to create
961 @retval other The child handle was not created
967 IN OUT EFI_HANDLE
* pChildHandle
,
969 IN OUT ESL_SOCKET
** ppSocket
974 ESL_SOCKET
* pSocket
;
981 // Create a socket structure
983 LengthInBytes
= sizeof ( *pSocket
);
984 pSocket
= (ESL_SOCKET
*) AllocateZeroPool ( LengthInBytes
);
985 if ( NULL
!= pSocket
) {
986 DEBUG (( DebugFlags
| DEBUG_POOL
| DEBUG_INIT
,
987 "0x%08x: Allocate pSocket, %d bytes\r\n",
992 // Initialize the socket protocol
994 pSocket
->Signature
= SOCKET_SIGNATURE
;
995 pSocket
->SocketProtocol
.pfnAccept
= EslSocketAccept
;
996 pSocket
->SocketProtocol
.pfnBind
= EslSocketBind
;
997 pSocket
->SocketProtocol
.pfnClosePoll
= EslSocketClosePoll
;
998 pSocket
->SocketProtocol
.pfnCloseStart
= EslSocketCloseStart
;
999 pSocket
->SocketProtocol
.pfnConnect
= EslSocketConnect
;
1000 pSocket
->SocketProtocol
.pfnGetLocal
= EslSocketGetLocalAddress
;
1001 pSocket
->SocketProtocol
.pfnGetPeer
= EslSocketGetPeerAddress
;
1002 pSocket
->SocketProtocol
.pfnListen
= EslSocketListen
;
1003 pSocket
->SocketProtocol
.pfnOptionGet
= EslSocketOptionGet
;
1004 pSocket
->SocketProtocol
.pfnOptionSet
= EslSocketOptionSet
;
1005 pSocket
->SocketProtocol
.pfnPoll
= EslSocketPoll
;
1006 pSocket
->SocketProtocol
.pfnReceive
= EslSocketReceive
;
1007 pSocket
->SocketProtocol
.pfnShutdown
= EslSocketShutdown
;
1008 pSocket
->SocketProtocol
.pfnSocket
= EslSocket
;
1009 pSocket
->SocketProtocol
.pfnTransmit
= EslSocketTransmit
;
1011 pSocket
->MaxRxBuf
= MAX_RX_DATA
;
1012 pSocket
->MaxTxBuf
= MAX_TX_DATA
;
1015 // Install the socket protocol on the specified handle
1017 Status
= gBS
->InstallMultipleProtocolInterfaces (
1019 &gEfiSocketProtocolGuid
,
1020 &pSocket
->SocketProtocol
,
1023 if ( !EFI_ERROR ( Status
)) {
1024 DEBUG (( DebugFlags
| DEBUG_POOL
| DEBUG_INIT
| DEBUG_INFO
,
1025 "Installed: gEfiSocketProtocolGuid on 0x%08x\r\n",
1027 pSocket
->SocketProtocol
.SocketHandle
= *pChildHandle
;
1030 // Synchronize with the socket layer
1032 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
1035 // Add this socket to the list
1037 pLayer
= &mEslLayer
;
1038 pSocket
->pNext
= pLayer
->pSocketList
;
1039 pLayer
->pSocketList
= pSocket
;
1042 // Release the socket layer synchronization
1044 RESTORE_TPL ( TplPrevious
);
1047 // Return the socket structure address
1049 *ppSocket
= pSocket
;
1052 DEBUG (( DEBUG_ERROR
| DebugFlags
| DEBUG_POOL
| DEBUG_INIT
,
1053 "ERROR - Failed to install gEfiSocketProtocolGuid on 0x%08x, Status: %r\r\n",
1059 // Release the socket if necessary
1061 if ( EFI_ERROR ( Status
)) {
1062 gBS
->FreePool ( pSocket
);
1063 DEBUG (( DebugFlags
| DEBUG_POOL
| DEBUG_INIT
,
1064 "0x%08x: Free pSocket, %d bytes\r\n",
1066 sizeof ( *pSocket
)));
1071 Status
= EFI_OUT_OF_RESOURCES
;
1075 // Return the operation status
1077 DBG_EXIT_STATUS ( Status
);
1083 Bind a name to a socket.
1085 This routine calls the network specific layer to save the network
1086 address of the local connection point.
1088 The ::bind routine calls this routine to connect a name
1089 (network address and port) to a socket on the local machine.
1091 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
1093 @param [in] pSockAddr Address of a sockaddr structure that contains the
1094 connection point on the local machine. An IPv4 address
1095 of INADDR_ANY specifies that the connection is made to
1096 all of the network stacks on the platform. Specifying a
1097 specific IPv4 address restricts the connection to the
1098 network stack supporting that address. Specifying zero
1099 for the port causes the network layer to assign a port
1100 number from the dynamic range. Specifying a specific
1101 port number causes the network layer to use that port.
1103 @param [in] SockAddrLength Specifies the length in bytes of the sockaddr structure.
1105 @param [out] pErrno Address to receive the errno value upon completion.
1107 @retval EFI_SUCCESS - Socket successfully created
1112 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
1113 IN CONST
struct sockaddr
* pSockAddr
,
1114 IN socklen_t SockAddrLength
,
1118 EFI_HANDLE ChildHandle
;
1121 ESL_SERVICE
** ppServiceListHead
;
1122 ESL_SOCKET
* pSocket
;
1123 ESL_SERVICE
* pService
;
1124 EFI_SERVICE_BINDING_PROTOCOL
* pServiceBinding
;
1126 EFI_TPL TplPrevious
;
1133 Status
= EFI_SUCCESS
;
1136 // Validate the socket
1139 if ( NULL
!= pSocketProtocol
) {
1140 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
1143 // Validate the structure pointer
1146 if ( NULL
== pSockAddr
) {
1147 DEBUG (( DEBUG_BIND
,
1148 "ERROR - pSockAddr is NULL!\r\n" ));
1149 Status
= EFI_INVALID_PARAMETER
;
1150 pSocket
->errno
= EFAULT
;
1154 // Validate the local address length
1156 else if ( SockAddrLength
< pSocket
->pApi
->MinimumAddressLength
) {
1157 DEBUG (( DEBUG_BIND
,
1158 "ERROR - Invalid bind name length: %d\r\n",
1160 Status
= EFI_INVALID_PARAMETER
;
1161 pSocket
->errno
= EINVAL
;
1165 // Validate the shutdown state
1167 else if ( pSocket
->bRxDisable
|| pSocket
->bTxDisable
) {
1168 DEBUG (( DEBUG_BIND
,
1169 "ERROR - Shutdown has been called on socket 0x%08x\r\n",
1171 pSocket
->errno
= EINVAL
;
1172 Status
= EFI_INVALID_PARAMETER
;
1176 // Verify the socket state
1178 else if ( SOCKET_STATE_NOT_CONFIGURED
!= pSocket
->State
) {
1179 DEBUG (( DEBUG_BIND
,
1180 "ERROR - The socket 0x%08x is already configured!\r\n",
1182 pSocket
->errno
= EINVAL
;
1183 Status
= EFI_ALREADY_STARTED
;
1187 // Synchronize with the socket layer
1189 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
1192 // Assume no ports are available
1194 pSocket
->errno
= EADDRNOTAVAIL
;
1195 Status
= EFI_INVALID_PARAMETER
;
1198 // Walk the list of services
1200 pBuffer
= (UINT8
*)&mEslLayer
;
1201 pBuffer
= &pBuffer
[ pSocket
->pApi
->ServiceListOffset
];
1202 ppServiceListHead
= (ESL_SERVICE
**)pBuffer
;
1203 pService
= *ppServiceListHead
;
1204 while ( NULL
!= pService
) {
1208 pServiceBinding
= pService
->pServiceBinding
;
1210 Status
= pServiceBinding
->CreateChild ( pServiceBinding
,
1212 if ( !EFI_ERROR ( Status
)) {
1213 DEBUG (( DEBUG_BIND
| DEBUG_POOL
,
1214 "0x%08x: %s port handle created\r\n",
1216 pService
->pSocketBinding
->pName
));
1221 Status
= EslSocketPortAllocate ( pSocket
,
1230 DEBUG (( DEBUG_BIND
| DEBUG_POOL
,
1231 "ERROR - Failed to open %s port handle, Status: %r\r\n",
1232 pService
->pSocketBinding
->pName
,
1237 // Set the next service
1239 pService
= pService
->pNext
;
1243 // Verify that at least one network connection was found
1245 if ( NULL
== pSocket
->pPortList
) {
1246 if ( EADDRNOTAVAIL
== pSocket
->errno
) {
1247 DEBUG (( DEBUG_BIND
| DEBUG_POOL
| DEBUG_INIT
,
1248 "ERROR - Socket address is not available!\r\n" ));
1250 if ( EADDRINUSE
== pSocket
->errno
) {
1251 DEBUG (( DEBUG_BIND
| DEBUG_POOL
| DEBUG_INIT
,
1252 "ERROR - Socket address is in use!\r\n" ));
1254 Status
= EFI_INVALID_PARAMETER
;
1258 // Mark this socket as bound if successful
1260 if ( !EFI_ERROR ( Status
)) {
1261 pSocket
->State
= SOCKET_STATE_BOUND
;
1266 // Release the socket layer synchronization
1268 RESTORE_TPL ( TplPrevious
);
1273 // Return the operation status
1275 if ( NULL
!= pErrno
) {
1276 if ( NULL
!= pSocket
) {
1277 *pErrno
= pSocket
->errno
;
1280 Status
= EFI_INVALID_PARAMETER
;
1284 DBG_EXIT_STATUS ( Status
);
1290 Test the bind configuration.
1292 @param [in] pPort Address of the ::ESL_PORT structure.
1293 @param [in] ErrnoValue errno value if test fails
1295 @retval EFI_SUCCESS The connection was successfully established.
1296 @retval Others The connection attempt failed.
1301 IN ESL_PORT
* pPort
,
1312 // Locate the configuration data
1314 pBuffer
= (UINT8
*)pPort
;
1315 pBuffer
= &pBuffer
[ pPort
->pSocket
->pApi
->ConfigDataOffset
];
1316 pConfigData
= (VOID
*)pBuffer
;
1319 // Attempt to use this configuration
1321 Status
= pPort
->pfnConfigure ( pPort
->pProtocol
.v
, pConfigData
);
1322 if ( EFI_ERROR ( Status
)) {
1323 DEBUG (( DEBUG_WARN
| DEBUG_BIND
,
1324 "WARNING - Port 0x%08x failed configuration, Status: %r\r\n",
1327 pPort
->pSocket
->errno
= ErrnoValue
;
1333 Status
= pPort
->pfnConfigure ( pPort
->pProtocol
.v
, NULL
);
1334 if ( EFI_ERROR ( Status
)) {
1335 DEBUG (( DEBUG_ERROR
| DEBUG_BIND
,
1336 "ERROR - Port 0x%08x failed configuration reset, Status: %r\r\n",
1339 ASSERT ( EFI_SUCCESS
== Status
);
1344 // Return the operation status
1346 DBG_EXIT_STATUS ( Status
);
1352 Determine if the socket is closed
1354 This routine checks the state of the socket to determine if
1355 the network specific layer has completed the close operation.
1357 The ::close routine polls this routine to determine when the
1358 close operation is complete. The close operation needs to
1359 reverse the operations of the ::EslSocketAllocate routine.
1361 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
1362 @param [out] pErrno Address to receive the errno value upon completion.
1364 @retval EFI_SUCCESS Socket successfully closed
1365 @retval EFI_NOT_READY Close still in progress
1366 @retval EFI_ALREADY Close operation already in progress
1367 @retval Other Failed to close the socket
1371 EslSocketClosePoll (
1372 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
1378 ESL_SOCKET
* pNextSocket
;
1379 ESL_SOCKET
* pSocket
;
1381 EFI_TPL TplPrevious
;
1389 Status
= EFI_SUCCESS
;
1392 // Synchronize with the socket layer
1394 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
1397 // Locate the socket
1399 pLayer
= &mEslLayer
;
1400 pNextSocket
= pLayer
->pSocketList
;
1401 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
1402 while ( NULL
!= pNextSocket
) {
1403 if ( pNextSocket
== pSocket
) {
1405 // Determine if the socket is in the closing state
1407 if ( SOCKET_STATE_CLOSED
== pSocket
->State
) {
1409 // Walk the list of ports
1411 if ( NULL
== pSocket
->pPortList
) {
1413 // All the ports are closed
1414 // Close the WaitAccept event if necessary
1416 if ( NULL
!= pSocket
->WaitAccept
) {
1417 Status
= gBS
->CloseEvent ( pSocket
->WaitAccept
);
1418 if ( !EFI_ERROR ( Status
)) {
1419 DEBUG (( DEBUG_SOCKET
| DEBUG_CLOSE
| DEBUG_POOL
,
1420 "0x%08x: Closed WaitAccept event\r\n",
1421 pSocket
->WaitAccept
));
1423 // Return the transmit status
1425 Status
= pSocket
->TxError
;
1426 if ( EFI_ERROR ( Status
)) {
1427 pSocket
->errno
= EIO
;
1431 DEBUG (( DEBUG_ERROR
| DEBUG_SOCKET
| DEBUG_CLOSE
| DEBUG_POOL
,
1432 "ERROR - Failed to close the WaitAccept event, Status: %r\r\n",
1434 ASSERT ( EFI_SUCCESS
== Status
);
1440 // At least one port is still open
1442 Status
= EFI_NOT_READY
;
1448 // SocketCloseStart was not called
1450 Status
= EFI_NOT_STARTED
;
1457 // Set the next socket
1459 pNextSocket
= pNextSocket
->pNext
;
1463 // Handle the error case where the socket was already closed
1465 if ( NULL
== pSocket
) {
1469 Status
= EFI_NOT_FOUND
;
1474 // Release the socket layer synchronization
1476 RESTORE_TPL ( TplPrevious
);
1479 // Return the operation status
1481 if ( NULL
!= pErrno
) {
1484 DBG_EXIT_STATUS ( Status
);
1490 Start the close operation on the socket
1492 This routine calls the network specific layer to initiate the
1493 close state machine. This routine then calls the network
1494 specific layer to determine if the close state machine has gone
1495 to completion. The result from this poll is returned to the
1498 The ::close routine calls this routine to start the close
1499 operation which reverses the operations of the
1500 ::EslSocketAllocate routine. The close routine then polls
1501 the ::EslSocketClosePoll routine to determine when the
1504 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
1505 @param [in] bCloseNow Boolean to control close behavior
1506 @param [out] pErrno Address to receive the errno value upon completion.
1508 @retval EFI_SUCCESS Socket successfully closed
1509 @retval EFI_NOT_READY Close still in progress
1510 @retval EFI_ALREADY Close operation already in progress
1511 @retval Other Failed to close the socket
1515 EslSocketCloseStart (
1516 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
1517 IN BOOLEAN bCloseNow
,
1522 ESL_PORT
* pNextPort
;
1524 ESL_SOCKET
* pSocket
;
1526 EFI_TPL TplPrevious
;
1533 Status
= EFI_SUCCESS
;
1537 // Synchronize with the socket layer
1539 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
1542 // Determine if the socket is already closed
1544 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
1545 if ( SOCKET_STATE_CLOSED
> pSocket
->State
) {
1547 // Update the socket state
1549 pSocket
->State
= SOCKET_STATE_CLOSED
;
1552 // Walk the list of ports
1554 pPort
= pSocket
->pPortList
;
1555 while ( NULL
!= pPort
) {
1557 // Start closing the ports
1559 pNextPort
= pPort
->pLinkSocket
;
1560 Status
= EslSocketPortCloseStart ( pPort
,
1562 DEBUG_CLOSE
| DEBUG_LISTEN
| DEBUG_CONNECTION
);
1563 if (( EFI_SUCCESS
!= Status
)
1564 && ( EFI_NOT_READY
!= Status
)) {
1570 // Set the next port
1576 // Attempt to finish closing the socket
1578 if ( NULL
== pPort
) {
1579 Status
= EslSocketClosePoll ( pSocketProtocol
, &errno
);
1583 Status
= EFI_NOT_READY
;
1588 // Release the socket layer synchronization
1590 RESTORE_TPL ( TplPrevious
);
1593 // Return the operation status
1595 if ( NULL
!= pErrno
) {
1598 DBG_EXIT_STATUS ( Status
);
1604 Connect to a remote system via the network.
1606 This routine calls the network specific layer to establish
1607 the remote system address and establish the connection to
1610 The ::connect routine calls this routine to establish a
1611 connection with the specified remote system. This routine
1612 is designed to be polled by the connect routine for completion
1613 of the network connection.
1615 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
1617 @param [in] pSockAddr Network address of the remote system.
1619 @param [in] SockAddrLength Length in bytes of the network address.
1621 @param [out] pErrno Address to receive the errno value upon completion.
1623 @retval EFI_SUCCESS The connection was successfully established.
1624 @retval EFI_NOT_READY The connection is in progress, call this routine again.
1625 @retval Others The connection attempt failed.
1630 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
1631 IN
const struct sockaddr
* pSockAddr
,
1632 IN socklen_t SockAddrLength
,
1636 struct sockaddr_in6 LocalAddress
;
1638 ESL_SOCKET
* pSocket
;
1640 EFI_TPL TplPrevious
;
1642 DEBUG (( DEBUG_CONNECT
, "Entering SocketConnect\r\n" ));
1647 Status
= EFI_SUCCESS
;
1650 // Validate the socket
1653 if ( NULL
!= pSocketProtocol
) {
1654 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
1657 // Validate the name length
1659 if ( SockAddrLength
< ( sizeof ( struct sockaddr
) - sizeof ( pSockAddr
->sa_data
))) {
1660 DEBUG (( DEBUG_CONNECT
,
1661 "ERROR - Invalid bind name length: %d\r\n",
1663 Status
= EFI_INVALID_PARAMETER
;
1664 pSocket
->errno
= EINVAL
;
1673 // Synchronize with the socket layer
1675 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
1678 // Validate the socket state
1680 switch ( pSocket
->State
) {
1683 // Wrong socket state
1685 pSocket
->errno
= EIO
;
1686 Status
= EFI_DEVICE_ERROR
;
1689 case SOCKET_STATE_NOT_CONFIGURED
:
1690 case SOCKET_STATE_BOUND
:
1692 // Validate the address length
1694 if ( SockAddrLength
>= pSocket
->pApi
->MinimumAddressLength
) {
1698 if ( NULL
== pSocket
->pApi
->pfnRemoteAddrSet
) {
1700 // Already connected
1702 pSocket
->errno
= ENOTSUP
;
1703 Status
= EFI_UNSUPPORTED
;
1707 // Determine if BIND was already called
1709 if ( NULL
== pSocket
->pPortList
) {
1711 // Allow any local port
1713 ZeroMem ( &LocalAddress
, sizeof ( LocalAddress
));
1714 LocalAddress
.sin6_len
= (uint8_t)pSocket
->pApi
->MinimumAddressLength
;
1715 LocalAddress
.sin6_family
= pSocket
->pApi
->AddressFamily
;
1716 Status
= EslSocketBind ( &pSocket
->SocketProtocol
,
1717 (struct sockaddr
*)&LocalAddress
,
1718 LocalAddress
.sin6_len
,
1721 if ( NULL
!= pSocket
->pPortList
) {
1723 // Walk the list of ports
1725 pPort
= pSocket
->pPortList
;
1726 while ( NULL
!= pPort
) {
1728 // Set the remote address
1730 Status
= pSocket
->pApi
->pfnRemoteAddrSet ( pPort
,
1733 if ( EFI_ERROR ( Status
)) {
1738 // Set the next port
1740 pPort
= pPort
->pLinkSocket
;
1746 if (( !EFI_ERROR ( Status
))
1747 && ( NULL
!= pSocket
->pApi
->pfnConnectStart
)) {
1749 // Initiate the connection with the remote system
1751 Status
= pSocket
->pApi
->pfnConnectStart ( pSocket
);
1754 // Set the next state if connecting
1756 if ( EFI_NOT_READY
== Status
) {
1757 pSocket
->State
= SOCKET_STATE_CONNECTING
;
1764 DEBUG (( DEBUG_CONNECT
,
1765 "ERROR - Invalid address length: %d\r\n",
1767 Status
= EFI_INVALID_PARAMETER
;
1768 pSocket
->errno
= EINVAL
;
1772 case SOCKET_STATE_CONNECTING
:
1774 // Poll for connection completion
1776 if ( NULL
== pSocket
->pApi
->pfnConnectPoll
) {
1778 // Already connected
1780 pSocket
->errno
= EISCONN
;
1781 Status
= EFI_ALREADY_STARTED
;
1784 Status
= pSocket
->pApi
->pfnConnectPoll ( pSocket
);
1787 // Set the next state if connected
1789 if ( EFI_NOT_READY
!= Status
) {
1790 if ( !EFI_ERROR ( Status
)) {
1791 pSocket
->State
= SOCKET_STATE_CONNECTED
;
1794 pSocket
->State
= SOCKET_STATE_BOUND
;
1800 case SOCKET_STATE_CONNECTED
:
1802 // Already connected
1804 pSocket
->errno
= EISCONN
;
1805 Status
= EFI_ALREADY_STARTED
;
1810 // Release the socket layer synchronization
1812 RESTORE_TPL ( TplPrevious
);
1817 // Return the operation status
1819 if ( NULL
!= pErrno
) {
1820 if ( NULL
!= pSocket
) {
1821 *pErrno
= pSocket
->errno
;
1825 // Bad socket protocol
1827 DEBUG (( DEBUG_ERROR
| DEBUG_CONNECT
,
1828 "ERROR - pSocketProtocol invalid!\r\n" ));
1829 Status
= EFI_INVALID_PARAMETER
;
1835 // Return the operation status
1837 DEBUG (( DEBUG_CONNECT
, "Exiting SocketConnect, Status: %r\r\n", Status
));
1843 Copy a fragmented buffer into a destination buffer.
1845 This support routine copies a fragmented buffer to the caller specified buffer.
1847 This routine is called by ::EslIp4Receive and ::EslUdp4Receive.
1849 @param [in] FragmentCount Number of fragments in the table
1851 @param [in] pFragmentTable Address of an EFI_IP4_FRAGMENT_DATA structure
1853 @param [in] BufferLength Length of the the buffer
1855 @param [in] pBuffer Address of a buffer to receive the data.
1857 @param [in] pDataLength Number of received data bytes in the buffer.
1859 @return Returns the address of the next free byte in the buffer.
1863 EslSocketCopyFragmentedBuffer (
1864 IN UINT32 FragmentCount
,
1865 IN EFI_IP4_FRAGMENT_DATA
* pFragmentTable
,
1866 IN
size_t BufferLength
,
1868 OUT
size_t * pDataLength
1879 // Validate the IP and UDP structures are identical
1881 ASSERT ( OFFSET_OF ( EFI_IP4_FRAGMENT_DATA
, FragmentLength
)
1882 == OFFSET_OF ( EFI_UDP4_FRAGMENT_DATA
, FragmentLength
));
1883 ASSERT ( OFFSET_OF ( EFI_IP4_FRAGMENT_DATA
, FragmentBuffer
)
1884 == OFFSET_OF ( EFI_UDP4_FRAGMENT_DATA
, FragmentBuffer
));
1887 // Copy the received data
1890 pBufferEnd
= &pBuffer
[ BufferLength
];
1891 while (( pBufferEnd
> pBuffer
) && ( FragmentCount
> Fragment
)) {
1893 // Determine the amount of received data
1895 pData
= pFragmentTable
[Fragment
].FragmentBuffer
;
1896 BytesToCopy
= pFragmentTable
[Fragment
].FragmentLength
;
1897 if (((size_t)( pBufferEnd
- pBuffer
)) < BytesToCopy
) {
1898 BytesToCopy
= pBufferEnd
- pBuffer
;
1902 // Move the data into the buffer
1905 "0x%08x --> 0x%08x: Copy data 0x%08x bytes\r\n",
1909 CopyMem ( pBuffer
, pData
, BytesToCopy
);
1910 pBuffer
+= BytesToCopy
;
1915 // Return the data length and the buffer address
1917 *pDataLength
= BufferLength
- ( pBufferEnd
- pBuffer
);
1918 DBG_EXIT_HEX ( pBuffer
);
1924 Get the local address.
1926 This routine calls the network specific layer to get the network
1927 address of the local host connection point.
1929 The ::getsockname routine calls this routine to obtain the network
1930 address associated with the local host connection point.
1932 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
1934 @param [out] pAddress Network address to receive the local system address
1936 @param [in,out] pAddressLength Length of the local network address structure
1938 @param [out] pErrno Address to receive the errno value upon completion.
1940 @retval EFI_SUCCESS - Local address successfully returned
1944 EslSocketGetLocalAddress (
1945 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
1946 OUT
struct sockaddr
* pAddress
,
1947 IN OUT socklen_t
* pAddressLength
,
1951 socklen_t LengthInBytes
;
1953 ESL_SOCKET
* pSocket
;
1955 EFI_TPL TplPrevious
;
1962 Status
= EFI_SUCCESS
;
1965 // Validate the socket
1968 if ( NULL
!= pSocketProtocol
) {
1969 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
1972 // Verify the socket state
1974 Status
= EslSocketIsConfigured ( pSocket
);
1975 if ( !EFI_ERROR ( Status
)) {
1977 // Verify the address buffer and length address
1979 if (( NULL
!= pAddress
) && ( NULL
!= pAddressLength
)) {
1981 // Verify the socket state
1983 if ( SOCKET_STATE_CONNECTED
== pSocket
->State
) {
1987 if ( NULL
== pSocket
->pApi
->pfnLocalAddrGet
) {
1988 Status
= EFI_UNSUPPORTED
;
1989 pSocket
->errno
= ENOTSUP
;
1993 // Synchronize with the socket layer
1995 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
1998 // Verify that there is just a single connection
2000 pPort
= pSocket
->pPortList
;
2001 if (( NULL
!= pPort
) && ( NULL
== pPort
->pLinkSocket
)) {
2003 // Verify the address length
2005 LengthInBytes
= pSocket
->pApi
->AddressLength
;
2006 if (( LengthInBytes
<= *pAddressLength
)
2007 && ( 255 >= LengthInBytes
)) {
2009 // Return the local address and address length
2011 ZeroMem ( pAddress
, LengthInBytes
);
2012 pAddress
->sa_len
= (uint8_t)LengthInBytes
;
2013 *pAddressLength
= pAddress
->sa_len
;
2014 pSocket
->pApi
->pfnLocalAddrGet ( pPort
, pAddress
);
2016 Status
= EFI_SUCCESS
;
2019 pSocket
->errno
= EINVAL
;
2020 Status
= EFI_INVALID_PARAMETER
;
2024 pSocket
->errno
= ENOTCONN
;
2025 Status
= EFI_NOT_STARTED
;
2029 // Release the socket layer synchronization
2031 RESTORE_TPL ( TplPrevious
);
2035 pSocket
->errno
= ENOTCONN
;
2036 Status
= EFI_NOT_STARTED
;
2040 pSocket
->errno
= EINVAL
;
2041 Status
= EFI_INVALID_PARAMETER
;
2047 // Return the operation status
2049 if ( NULL
!= pErrno
) {
2050 if ( NULL
!= pSocket
) {
2051 *pErrno
= pSocket
->errno
;
2054 Status
= EFI_INVALID_PARAMETER
;
2058 DBG_EXIT_STATUS ( Status
);
2064 Get the peer address.
2066 This routine calls the network specific layer to get the remote
2067 system connection point.
2069 The ::getpeername routine calls this routine to obtain the network
2070 address of the remote connection point.
2072 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
2074 @param [out] pAddress Network address to receive the remote system address
2076 @param [in,out] pAddressLength Length of the remote network address structure
2078 @param [out] pErrno Address to receive the errno value upon completion.
2080 @retval EFI_SUCCESS - Remote address successfully returned
2084 EslSocketGetPeerAddress (
2085 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
2086 OUT
struct sockaddr
* pAddress
,
2087 IN OUT socklen_t
* pAddressLength
,
2091 socklen_t LengthInBytes
;
2093 ESL_SOCKET
* pSocket
;
2095 EFI_TPL TplPrevious
;
2102 Status
= EFI_SUCCESS
;
2105 // Validate the socket
2108 if ( NULL
!= pSocketProtocol
) {
2109 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
2112 // Verify the socket state
2114 Status
= EslSocketIsConfigured ( pSocket
);
2115 if ( !EFI_ERROR ( Status
)) {
2119 if ( NULL
== pSocket
->pApi
->pfnRemoteAddrGet
) {
2120 Status
= EFI_UNSUPPORTED
;
2121 pSocket
->errno
= ENOTSUP
;
2125 // Verify the address buffer and length address
2127 if (( NULL
!= pAddress
) && ( NULL
!= pAddressLength
)) {
2129 // Verify the socket state
2131 if ( SOCKET_STATE_CONNECTED
== pSocket
->State
) {
2133 // Synchronize with the socket layer
2135 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
2138 // Verify that there is just a single connection
2140 pPort
= pSocket
->pPortList
;
2141 if (( NULL
!= pPort
) && ( NULL
== pPort
->pLinkSocket
)) {
2143 // Verify the address length
2145 LengthInBytes
= pSocket
->pApi
->AddressLength
;
2146 if ( LengthInBytes
<= *pAddressLength
) {
2148 // Return the local address
2150 ZeroMem ( pAddress
, LengthInBytes
);
2151 pAddress
->sa_len
= (uint8_t)LengthInBytes
;
2152 *pAddressLength
= pAddress
->sa_len
;
2153 pSocket
->pApi
->pfnRemoteAddrGet ( pPort
, pAddress
);
2155 Status
= EFI_SUCCESS
;
2158 pSocket
->errno
= EINVAL
;
2159 Status
= EFI_INVALID_PARAMETER
;
2163 pSocket
->errno
= ENOTCONN
;
2164 Status
= EFI_NOT_STARTED
;
2168 // Release the socket layer synchronization
2170 RESTORE_TPL ( TplPrevious
);
2173 pSocket
->errno
= ENOTCONN
;
2174 Status
= EFI_NOT_STARTED
;
2178 pSocket
->errno
= EINVAL
;
2179 Status
= EFI_INVALID_PARAMETER
;
2186 // Return the operation status
2188 if ( NULL
!= pErrno
) {
2189 if ( NULL
!= pSocket
) {
2190 *pErrno
= pSocket
->errno
;
2193 Status
= EFI_INVALID_PARAMETER
;
2197 DBG_EXIT_STATUS ( Status
);
2203 Free the ESL_IO_MGMT event and structure
2205 This support routine walks the free list to close the event in
2206 the ESL_IO_MGMT structure and remove the structure from the free
2209 See the \ref TransmitEngine section.
2211 @param [in] pPort Address of an ::ESL_PORT structure
2212 @param [in] ppFreeQueue Address of the free queue head
2213 @param [in] DebugFlags Flags for debug messages
2214 @param [in] pEventName Zero terminated string containing the event name
2216 @retval EFI_SUCCESS - The structures were properly initialized
2221 IN ESL_PORT
* pPort
,
2222 IN ESL_IO_MGMT
** ppFreeQueue
,
2223 IN UINTN DebugFlags
,
2224 IN CHAR8
* pEventName
2230 ESL_SOCKET
* pSocket
;
2238 Status
= EFI_SUCCESS
;
2241 // Walk the list of IO structures
2243 pSocket
= pPort
->pSocket
;
2244 while ( *ppFreeQueue
) {
2246 // Free the event for this structure
2249 pBuffer
= (UINT8
*)pIo
;
2250 pBuffer
= &pBuffer
[ pSocket
->TxTokenEventOffset
];
2251 pEvent
= (EFI_EVENT
*)pBuffer
;
2252 Status
= gBS
->CloseEvent ( *pEvent
);
2253 if ( EFI_ERROR ( Status
)) {
2254 DEBUG (( DEBUG_ERROR
| DebugFlags
,
2255 "ERROR - Failed to close the %a event, Status: %r\r\n",
2258 pSocket
->errno
= ENOMEM
;
2261 DEBUG (( DebugFlags
,
2262 "0x%08x: Closed %a event 0x%08x\r\n",
2268 // Remove this structure from the queue
2270 *ppFreeQueue
= pIo
->pNext
;
2274 // Return the operation status
2276 DBG_EXIT_STATUS ( Status
);
2282 Initialize the ESL_IO_MGMT structures
2284 This support routine initializes the ESL_IO_MGMT structure and
2285 places them on to a free list.
2287 This routine is called by ::EslSocketPortAllocate routines to prepare
2288 the transmit engines. See the \ref TransmitEngine section.
2290 @param [in] pPort Address of an ::ESL_PORT structure
2291 @param [in, out] ppIo Address containing the first structure address. Upon
2292 return this buffer contains the next structure address.
2293 @param [in] TokenCount Number of structures to initialize
2294 @param [in] ppFreeQueue Address of the free queue head
2295 @param [in] DebugFlags Flags for debug messages
2296 @param [in] pEventName Zero terminated string containing the event name
2297 @param [in] pfnCompletion Completion routine address
2299 @retval EFI_SUCCESS - The structures were properly initialized
2304 IN ESL_PORT
* pPort
,
2305 IN ESL_IO_MGMT
** ppIo
,
2306 IN UINTN TokenCount
,
2307 IN ESL_IO_MGMT
** ppFreeQueue
,
2308 IN UINTN DebugFlags
,
2309 IN CHAR8
* pEventName
,
2310 IN PFN_API_IO_COMPLETE pfnCompletion
2316 ESL_SOCKET
* pSocket
;
2324 Status
= EFI_SUCCESS
;
2327 // Walk the list of IO structures
2329 pSocket
= pPort
->pSocket
;
2331 pEnd
= &pIo
[ TokenCount
];
2332 while ( pEnd
> pIo
) {
2334 // Initialize the IO structure
2337 pIo
->pPacket
= NULL
;
2340 // Allocate the event for this structure
2342 pEvent
= (EFI_EVENT
*)&(((UINT8
*)pIo
)[ pSocket
->TxTokenEventOffset
]);
2343 Status
= gBS
->CreateEvent ( EVT_NOTIFY_SIGNAL
,
2345 (EFI_EVENT_NOTIFY
)pfnCompletion
,
2348 if ( EFI_ERROR ( Status
)) {
2349 DEBUG (( DEBUG_ERROR
| DebugFlags
,
2350 "ERROR - Failed to create the %a event, Status: %r\r\n",
2353 pSocket
->errno
= ENOMEM
;
2356 DEBUG (( DebugFlags
,
2357 "0x%08x: Created %a event 0x%08x\r\n",
2363 // Add this structure to the queue
2365 pIo
->pNext
= *ppFreeQueue
;
2369 // Set the next structure
2375 // Save the next structure
2380 // Return the operation status
2382 DBG_EXIT_STATUS ( Status
);
2388 Determine if the socket is configured
2390 This support routine is called to determine if the socket if the
2391 configuration call was made to the network layer. The following
2392 routines call this routine to verify that they may be successful
2393 in their operations:
2395 <li>::EslSocketGetLocalAddress</li>
2396 <li>::EslSocketGetPeerAddress</li>
2397 <li>::EslSocketPoll</li>
2398 <li>::EslSocketReceive</li>
2399 <li>::EslSocketTransmit</li>
2402 @param [in] pSocket Address of an ::ESL_SOCKET structure
2404 @retval EFI_SUCCESS - The socket is configured
2408 EslSocketIsConfigured (
2409 IN ESL_SOCKET
* pSocket
2413 EFI_TPL TplPrevious
;
2418 Status
= EFI_SUCCESS
;
2421 // Verify the socket state
2423 if ( !pSocket
->bConfigured
) {
2429 if ( NULL
== pSocket
->pApi
->pfnIsConfigured
) {
2430 Status
= EFI_UNSUPPORTED
;
2431 pSocket
->errno
= ENOTSUP
;
2435 // Synchronize with the socket layer
2437 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
2440 // Determine if the socket is configured
2442 Status
= pSocket
->pApi
->pfnIsConfigured ( pSocket
);
2445 // Release the socket layer synchronization
2447 RESTORE_TPL ( TplPrevious
);
2450 // Set errno if a failure occurs
2452 if ( EFI_ERROR ( Status
)) {
2453 pSocket
->errno
= EADDRNOTAVAIL
;
2457 DBG_EXIT_STATUS ( Status
);
2461 // Return the configuration status
2468 Establish the known port to listen for network connections.
2470 This routine calls into the network protocol layer to establish
2471 a handler that is called upon connection completion. The handler
2472 is responsible for inserting the connection into the FIFO.
2474 The ::listen routine indirectly calls this routine to place the
2475 socket into a state that enables connection attempts. Connections
2476 are placed in a FIFO that is serviced by the application. The
2477 application calls the ::accept (::EslSocketAccept) routine to
2478 remove the next connection from the FIFO and get the associated
2481 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
2483 @param [in] Backlog Backlog specifies the maximum FIFO depth for
2484 the connections waiting for the application
2485 to call accept. Connection attempts received
2486 while the queue is full are refused.
2488 @param [out] pErrno Address to receive the errno value upon completion.
2490 @retval EFI_SUCCESS - Socket successfully created
2491 @retval Other - Failed to enable the socket for listen
2496 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
2501 ESL_SOCKET
* pSocket
;
2503 EFI_STATUS TempStatus
;
2504 EFI_TPL TplPrevious
;
2511 Status
= EFI_SUCCESS
;
2514 // Validate the socket
2517 if ( NULL
!= pSocketProtocol
) {
2518 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
2523 if ( NULL
== pSocket
->pApi
->pfnListen
) {
2524 Status
= EFI_UNSUPPORTED
;
2525 pSocket
->errno
= ENOTSUP
;
2531 pSocket
->Status
= EFI_SUCCESS
;
2535 // Verify that the bind operation was successful
2537 if ( SOCKET_STATE_BOUND
== pSocket
->State
) {
2539 // Synchronize with the socket layer
2541 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
2544 // Create the event for SocketAccept completion
2546 Status
= gBS
->CreateEvent ( 0,
2550 &pSocket
->WaitAccept
);
2551 if ( !EFI_ERROR ( Status
)) {
2552 DEBUG (( DEBUG_POOL
,
2553 "0x%08x: Created WaitAccept event\r\n",
2554 pSocket
->WaitAccept
));
2556 // Set the maximum FIFO depth
2558 if ( 0 >= Backlog
) {
2559 Backlog
= MAX_PENDING_CONNECTIONS
;
2562 if ( SOMAXCONN
< Backlog
) {
2563 Backlog
= SOMAXCONN
;
2566 pSocket
->MaxFifoDepth
= Backlog
;
2571 // Initiate the connection attempt listen
2573 Status
= pSocket
->pApi
->pfnListen ( pSocket
);
2576 // Place the socket in the listen state if successful
2578 if ( !EFI_ERROR ( Status
)) {
2579 pSocket
->State
= SOCKET_STATE_LISTENING
;
2580 pSocket
->bListenCalled
= TRUE
;
2584 // Not waiting for SocketAccept to complete
2586 TempStatus
= gBS
->CloseEvent ( pSocket
->WaitAccept
);
2587 if ( !EFI_ERROR ( TempStatus
)) {
2588 DEBUG (( DEBUG_POOL
,
2589 "0x%08x: Closed WaitAccept event\r\n",
2590 pSocket
->WaitAccept
));
2591 pSocket
->WaitAccept
= NULL
;
2594 DEBUG (( DEBUG_ERROR
| DEBUG_POOL
,
2595 "ERROR - Failed to close WaitAccept event, Status: %r\r\n",
2597 ASSERT ( EFI_SUCCESS
== TempStatus
);
2602 DEBUG (( DEBUG_ERROR
| DEBUG_LISTEN
,
2603 "ERROR - Failed to create the WaitAccept event, Status: %r\r\n",
2605 pSocket
->errno
= ENOMEM
;
2609 // Release the socket layer synchronization
2611 RESTORE_TPL ( TplPrevious
);
2614 DEBUG (( DEBUG_ERROR
| DEBUG_LISTEN
,
2615 "ERROR - Bind operation must be performed first!\r\n" ));
2616 pSocket
->errno
= ( SOCKET_STATE_NOT_CONFIGURED
== pSocket
->State
) ? EDESTADDRREQ
2618 Status
= EFI_NO_MAPPING
;
2624 // Return the operation status
2626 if ( NULL
!= pErrno
) {
2627 if ( NULL
!= pSocket
) {
2628 *pErrno
= pSocket
->errno
;
2631 Status
= EFI_INVALID_PARAMETER
;
2635 DBG_EXIT_STATUS ( Status
);
2641 Get the socket options
2643 This routine handles the socket level options and passes the
2644 others to the network specific layer.
2646 The ::getsockopt routine calls this routine to retrieve the
2647 socket options one at a time by name.
2649 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
2650 @param [in] level Option protocol level
2651 @param [in] OptionName Name of the option
2652 @param [out] pOptionValue Buffer to receive the option value
2653 @param [in,out] pOptionLength Length of the buffer in bytes,
2654 upon return length of the option value in bytes
2655 @param [out] pErrno Address to receive the errno value upon completion.
2657 @retval EFI_SUCCESS - Socket data successfully received
2661 EslSocketOptionGet (
2662 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
2665 OUT
void * __restrict pOptionValue
,
2666 IN OUT socklen_t
* __restrict pOptionLength
,
2671 socklen_t LengthInBytes
;
2673 CONST UINT8
* pOptionData
;
2674 ESL_SOCKET
* pSocket
;
2683 Status
= EFI_INVALID_PARAMETER
;
2686 // Validate the socket
2689 if ( NULL
== pSocketProtocol
) {
2690 DEBUG (( DEBUG_OPTION
, "ERROR - pSocketProtocol is NULL!\r\n" ));
2692 else if ( NULL
== pOptionValue
) {
2693 DEBUG (( DEBUG_OPTION
, "ERROR - No option buffer specified\r\n" ));
2695 else if ( NULL
== pOptionLength
) {
2696 DEBUG (( DEBUG_OPTION
, "ERROR - Option length not specified!\r\n" ));
2699 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
2701 MaxBytes
= *pOptionLength
;
2706 // See if the protocol will handle the option
2708 if ( NULL
!= pSocket
->pApi
->pfnOptionGet
) {
2709 if ( pSocket
->pApi
->DefaultProtocol
== level
) {
2710 Status
= pSocket
->pApi
->pfnOptionGet ( pSocket
,
2712 (CONST
void ** __restrict
)&pOptionData
,
2714 errno
= pSocket
->errno
;
2719 // Protocol not supported
2721 DEBUG (( DEBUG_OPTION
,
2722 "ERROR - The socket does not support this protocol!\r\n" ));
2727 // Protocol level not supported
2729 DEBUG (( DEBUG_OPTION
,
2730 "ERROR - %a does not support any options!\r\n",
2731 pSocket
->pApi
->pName
));
2733 errno
= ENOPROTOOPT
;
2734 Status
= EFI_INVALID_PARAMETER
;
2738 switch ( OptionName
) {
2741 // Socket option not supported
2743 DEBUG (( DEBUG_INFO
| DEBUG_OPTION
, "ERROR - Invalid socket option!\r\n" ));
2745 Status
= EFI_INVALID_PARAMETER
;
2750 // Return the listen flag
2752 pOptionData
= (CONST UINT8
*)&pSocket
->bListenCalled
;
2753 LengthInBytes
= sizeof ( pSocket
->bListenCalled
);
2758 // Return the debug flags
2760 pOptionData
= (CONST UINT8
*)&pSocket
->bOobInLine
;
2761 LengthInBytes
= sizeof ( pSocket
->bOobInLine
);
2766 // Return the out-of-band inline flag
2768 pOptionData
= (CONST UINT8
*)&pSocket
->bOobInLine
;
2769 LengthInBytes
= sizeof ( pSocket
->bOobInLine
);
2774 // Return the receive timeout
2776 pOptionData
= (CONST UINT8
*)&pSocket
->RxTimeout
;
2777 LengthInBytes
= sizeof ( pSocket
->RxTimeout
);
2782 // Return the maximum receive buffer size
2784 pOptionData
= (CONST UINT8
*)&pSocket
->MaxRxBuf
;
2785 LengthInBytes
= sizeof ( pSocket
->MaxRxBuf
);
2790 // Return the maximum transmit buffer size
2792 pOptionData
= (CONST UINT8
*)&pSocket
->MaxTxBuf
;
2793 LengthInBytes
= sizeof ( pSocket
->MaxTxBuf
);
2798 // Return the socket type
2800 pOptionData
= (CONST UINT8
*)&pSocket
->Type
;
2801 LengthInBytes
= sizeof ( pSocket
->Type
);
2808 // Return the option length
2810 *pOptionLength
= LengthInBytes
;
2813 // Determine if the option is present
2815 if ( 0 != LengthInBytes
) {
2817 // Silently truncate the value length
2819 if ( LengthInBytes
> MaxBytes
) {
2820 DEBUG (( DEBUG_OPTION
,
2821 "INFO - Truncating option from %d to %d bytes\r\n",
2824 LengthInBytes
= MaxBytes
;
2830 CopyMem ( pOptionValue
, pOptionData
, LengthInBytes
);
2833 // Zero fill any remaining space
2835 if ( LengthInBytes
< MaxBytes
) {
2836 ZeroMem ( &((UINT8
*)pOptionValue
)[LengthInBytes
], MaxBytes
- LengthInBytes
);
2839 Status
= EFI_SUCCESS
;
2844 // Return the operation status
2846 if ( NULL
!= pErrno
) {
2849 DBG_EXIT_STATUS ( Status
);
2855 Set the socket options
2857 This routine handles the socket level options and passes the
2858 others to the network specific layer.
2860 The ::setsockopt routine calls this routine to adjust the socket
2861 options one at a time by name.
2863 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
2864 @param [in] level Option protocol level
2865 @param [in] OptionName Name of the option
2866 @param [in] pOptionValue Buffer containing the option value
2867 @param [in] OptionLength Length of the buffer in bytes
2868 @param [out] pErrno Address to receive the errno value upon completion.
2870 @retval EFI_SUCCESS - Option successfully set
2874 EslSocketOptionSet (
2875 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
2878 IN CONST
void * pOptionValue
,
2879 IN socklen_t OptionLength
,
2885 socklen_t LengthInBytes
;
2886 UINT8
* pOptionData
;
2887 ESL_SOCKET
* pSocket
;
2896 Status
= EFI_INVALID_PARAMETER
;
2899 // Validate the socket
2902 if ( NULL
== pSocketProtocol
) {
2903 DEBUG (( DEBUG_OPTION
, "ERROR - pSocketProtocol is NULL!\r\n" ));
2905 else if ( NULL
== pOptionValue
) {
2906 DEBUG (( DEBUG_OPTION
, "ERROR - No option buffer specified\r\n" ));
2910 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
2911 if ( pSocket
->bRxDisable
|| pSocket
->bTxDisable
) {
2912 DEBUG (( DEBUG_OPTION
, "ERROR - Socket has been shutdown!\r\n" ));
2920 // See if the protocol will handle the option
2922 if ( NULL
!= pSocket
->pApi
->pfnOptionSet
) {
2923 if ( pSocket
->pApi
->DefaultProtocol
== level
) {
2924 Status
= pSocket
->pApi
->pfnOptionSet ( pSocket
,
2928 errno
= pSocket
->errno
;
2933 // Protocol not supported
2935 DEBUG (( DEBUG_OPTION
,
2936 "ERROR - The socket does not support this protocol!\r\n" ));
2941 // Protocol level not supported
2943 DEBUG (( DEBUG_OPTION
,
2944 "ERROR - %a does not support any options!\r\n",
2945 pSocket
->pApi
->pName
));
2947 errno
= ENOPROTOOPT
;
2948 Status
= EFI_INVALID_PARAMETER
;
2952 switch ( OptionName
) {
2955 // Option not supported
2957 DEBUG (( DEBUG_OPTION
,
2958 "ERROR - Sockets does not support this option!\r\n" ));
2960 Status
= EFI_INVALID_PARAMETER
;
2965 // Set the debug flags
2967 pOptionData
= (UINT8
*)&pSocket
->bOobInLine
;
2968 LengthInBytes
= sizeof ( pSocket
->bOobInLine
);
2972 pOptionData
= (UINT8
*)&pSocket
->bOobInLine
;
2973 LengthInBytes
= sizeof ( pSocket
->bOobInLine
);
2976 // Validate the option length
2978 if ( sizeof ( UINT32
) == OptionLength
) {
2980 // Restrict the input to TRUE or FALSE
2983 if ( 0 == *(UINT32
*)pOptionValue
) {
2986 pOptionValue
= &bTrueFalse
;
2990 // Force an invalid option length error
2992 OptionLength
= LengthInBytes
- 1;
2998 // Return the receive timeout
3000 pOptionData
= (UINT8
*)&pSocket
->RxTimeout
;
3001 LengthInBytes
= sizeof ( pSocket
->RxTimeout
);
3006 // Return the maximum receive buffer size
3008 pOptionData
= (UINT8
*)&pSocket
->MaxRxBuf
;
3009 LengthInBytes
= sizeof ( pSocket
->MaxRxBuf
);
3017 // Return the maximum transmit buffer size
3019 pOptionData
= (UINT8
*)&pSocket
->MaxTxBuf
;
3020 LengthInBytes
= sizeof ( pSocket
->MaxTxBuf
);
3027 // Determine if an option was found
3029 if ( 0 != LengthInBytes
) {
3031 // Validate the option length
3033 if ( LengthInBytes
<= OptionLength
) {
3035 // Set the option value
3037 CopyMem ( pOptionData
, pOptionValue
, LengthInBytes
);
3039 Status
= EFI_SUCCESS
;
3042 DEBUG (( DEBUG_OPTION
,
3043 "ERROR - Buffer to small, %d bytes < %d bytes!\r\n",
3052 // Return the operation status
3054 if ( NULL
!= pErrno
) {
3057 DBG_EXIT_STATUS ( Status
);
3063 Allocate a packet for a receive or transmit operation
3065 This support routine is called by ::EslSocketRxStart and the
3066 network specific TxBuffer routines to get buffer space for the
3069 @param [in] ppPacket Address to receive the ::ESL_PACKET structure
3070 @param [in] LengthInBytes Length of the packet structure
3071 @param [in] ZeroBytes Length of packet to zero
3072 @param [in] DebugFlags Flags for debug messages
3074 @retval EFI_SUCCESS - The packet was allocated successfully
3078 EslSocketPacketAllocate (
3079 IN ESL_PACKET
** ppPacket
,
3080 IN
size_t LengthInBytes
,
3081 IN
size_t ZeroBytes
,
3085 ESL_PACKET
* pPacket
;
3091 // Allocate a packet structure
3093 LengthInBytes
+= sizeof ( *pPacket
)
3094 - sizeof ( pPacket
->Op
);
3095 Status
= gBS
->AllocatePool ( EfiRuntimeServicesData
,
3097 (VOID
**)&pPacket
);
3098 if ( !EFI_ERROR ( Status
)) {
3099 DEBUG (( DebugFlags
| DEBUG_POOL
| DEBUG_INIT
,
3100 "0x%08x: Allocate pPacket, %d bytes\r\n",
3103 if ( 0 != ZeroBytes
) {
3104 ZeroMem ( &pPacket
->Op
, ZeroBytes
);
3106 pPacket
->PacketSize
= LengthInBytes
;
3109 DEBUG (( DebugFlags
| DEBUG_POOL
| DEBUG_INFO
,
3110 "ERROR - Packet allocation failed for %d bytes, Status: %r\r\n",
3117 // Return the packet
3119 *ppPacket
= pPacket
;
3122 // Return the operation status
3124 DBG_EXIT_STATUS ( Status
);
3130 Free a packet used for receive or transmit operation
3132 This support routine is called by the network specific Close
3133 and TxComplete routines and during error cases in RxComplete
3134 and TxBuffer. Note that the network layers typically place
3135 receive packets on the ESL_SOCKET::pRxFree list for reuse.
3137 @param [in] pPacket Address of an ::ESL_PACKET structure
3138 @param [in] DebugFlags Flags for debug messages
3140 @retval EFI_SUCCESS - The packet was allocated successfully
3144 EslSocketPacketFree (
3145 IN ESL_PACKET
* pPacket
,
3149 UINTN LengthInBytes
;
3155 // Allocate a packet structure
3157 LengthInBytes
= pPacket
->PacketSize
;
3158 Status
= gBS
->FreePool ( pPacket
);
3159 if ( !EFI_ERROR ( Status
)) {
3160 DEBUG (( DebugFlags
| DEBUG_POOL
,
3161 "0x%08x: Free pPacket, %d bytes\r\n",
3166 DEBUG (( DebugFlags
| DEBUG_POOL
| DEBUG_INFO
,
3167 "ERROR - Failed to free packet 0x%08x, Status: %r\r\n",
3173 // Return the operation status
3175 DBG_EXIT_STATUS ( Status
);
3181 Poll a socket for pending activity.
3183 This routine builds a detected event mask which is returned to
3184 the caller in the buffer provided.
3186 The ::poll routine calls this routine to determine if the socket
3187 needs to be serviced as a result of connection, error, receive or
3190 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
3192 @param [in] Events Events of interest for this socket
3194 @param [in] pEvents Address to receive the detected events
3196 @param [out] pErrno Address to receive the errno value upon completion.
3198 @retval EFI_SUCCESS - Socket successfully polled
3199 @retval EFI_INVALID_PARAMETER - When pEvents is NULL
3204 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
3210 short DetectedEvents
;
3211 ESL_SOCKET
* pSocket
;
3215 DEBUG (( DEBUG_POLL
, "Entering SocketPoll\r\n" ));
3220 Status
= EFI_SUCCESS
;
3222 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
3226 // Verify the socket state
3228 Status
= EslSocketIsConfigured ( pSocket
);
3229 if ( !EFI_ERROR ( Status
)) {
3231 // Check for invalid events
3233 ValidEvents
= POLLIN
3235 | POLLOUT
| POLLWRNORM
3242 if ( 0 != ( Events
& ( ~ValidEvents
))) {
3243 DetectedEvents
|= POLLNVAL
;
3244 DEBUG (( DEBUG_INFO
| DEBUG_POLL
,
3245 "ERROR - Invalid event mask, Valid Events: 0x%04x, Invalid Events: 0x%04x\r\n",
3246 Events
& ValidEvents
,
3247 Events
& ( ~ValidEvents
)));
3251 // Check for pending connections
3253 if ( 0 != pSocket
->FifoDepth
) {
3255 // A connection is waiting for an accept call
3256 // See posix connect documentation at
3257 // http://pubs.opengroup.org/onlinepubs/9699919799/functions/accept.htm
3259 DetectedEvents
|= POLLIN
| POLLRDNORM
;
3261 if ( pSocket
->bConnected
) {
3263 // A connection is present
3264 // See posix connect documentation at
3265 // http://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.htm
3267 DetectedEvents
|= POLLOUT
| POLLWRNORM
;
3271 // The following bits are set based upon the POSIX poll documentation at
3272 // http://pubs.opengroup.org/onlinepubs/9699919799/functions/poll.html
3276 // Check for urgent receive data
3278 if ( 0 < pSocket
->RxOobBytes
) {
3279 DetectedEvents
|= POLLRDBAND
| POLLPRI
| POLLIN
;
3283 // Check for normal receive data
3285 if (( 0 < pSocket
->RxBytes
)
3286 || ( EFI_SUCCESS
!= pSocket
->RxError
)) {
3287 DetectedEvents
|= POLLRDNORM
| POLLIN
;
3291 // Handle the receive errors
3293 if (( EFI_SUCCESS
!= pSocket
->RxError
)
3294 && ( 0 == ( DetectedEvents
& POLLIN
))) {
3295 DetectedEvents
|= POLLERR
| POLLIN
| POLLRDNORM
| POLLRDBAND
;
3299 // Check for urgent transmit data buffer space
3301 if (( MAX_TX_DATA
> pSocket
->TxOobBytes
)
3302 || ( EFI_SUCCESS
!= pSocket
->TxError
)) {
3303 DetectedEvents
|= POLLWRBAND
;
3307 // Check for normal transmit data buffer space
3309 if (( MAX_TX_DATA
> pSocket
->TxBytes
)
3310 || ( EFI_SUCCESS
!= pSocket
->TxError
)) {
3311 DetectedEvents
|= POLLWRNORM
;
3315 // Handle the transmit error
3317 if ( EFI_ERROR ( pSocket
->TxError
)) {
3318 DetectedEvents
|= POLLERR
;
3324 // Return the detected events
3326 *pEvents
= DetectedEvents
& ( Events
3332 // Return the operation status
3334 DEBUG (( DEBUG_POLL
, "Exiting SocketPoll, Status: %r\r\n", Status
));
3340 Allocate and initialize a ESL_PORT structure.
3342 This routine initializes an ::ESL_PORT structure for use by
3343 the socket. This routine calls a routine via
3344 ESL_PROTOCOL_API::pfnPortAllocate to initialize the network
3345 specific resources. The resources are released later by the
3346 \ref PortCloseStateMachine.
3348 This support routine is called by:
3350 <li>::EslSocketBind</li>
3351 <li>::EslTcp4ListenComplete</li>
3353 to connect the socket with the underlying network adapter
3356 @param [in] pSocket Address of an ::ESL_SOCKET structure.
3357 @param [in] pService Address of an ::ESL_SERVICE structure.
3358 @param [in] ChildHandle Network protocol child handle
3359 @param [in] pSockAddr Address of a sockaddr structure that contains the
3360 connection point on the local machine. An IPv4 address
3361 of INADDR_ANY specifies that the connection is made to
3362 all of the network stacks on the platform. Specifying a
3363 specific IPv4 address restricts the connection to the
3364 network stack supporting that address. Specifying zero
3365 for the port causes the network layer to assign a port
3366 number from the dynamic range. Specifying a specific
3367 port number causes the network layer to use that port.
3368 @param [in] bBindTest TRUE if EslSocketBindTest should be called
3369 @param [in] DebugFlags Flags for debug messages
3370 @param [out] ppPort Buffer to receive new ::ESL_PORT structure address
3372 @retval EFI_SUCCESS - Socket successfully created
3376 EslSocketPortAllocate (
3377 IN ESL_SOCKET
* pSocket
,
3378 IN ESL_SERVICE
* pService
,
3379 IN EFI_HANDLE ChildHandle
,
3380 IN CONST
struct sockaddr
* pSockAddr
,
3381 IN BOOLEAN bBindTest
,
3382 IN UINTN DebugFlags
,
3383 OUT ESL_PORT
** ppPort
3386 UINTN LengthInBytes
;
3391 EFI_SERVICE_BINDING_PROTOCOL
* pServiceBinding
;
3392 CONST ESL_SOCKET_BINDING
* pSocketBinding
;
3394 EFI_STATUS TempStatus
;
3399 // Verify the socket layer synchronization
3401 VERIFY_TPL ( TPL_SOCKETS
);
3404 // Use for/break instead of goto
3405 pSocketBinding
= pService
->pSocketBinding
;
3408 // Allocate a port structure
3410 pLayer
= &mEslLayer
;
3411 LengthInBytes
= sizeof ( *pPort
)
3412 + ESL_STRUCTURE_ALIGNMENT_BYTES
3413 + (( pSocketBinding
->RxIo
3414 + pSocketBinding
->TxIoNormal
3415 + pSocketBinding
->TxIoUrgent
)
3416 * sizeof ( ESL_IO_MGMT
));
3417 pPort
= (ESL_PORT
*) AllocateZeroPool ( LengthInBytes
);
3418 if ( NULL
== pPort
) {
3419 Status
= EFI_OUT_OF_RESOURCES
;
3420 pSocket
->errno
= ENOMEM
;
3423 DEBUG (( DebugFlags
| DEBUG_POOL
| DEBUG_INIT
,
3424 "0x%08x: Allocate pPort, %d bytes\r\n",
3429 // Initialize the port
3431 pPort
->DebugFlags
= DebugFlags
;
3432 pPort
->Handle
= ChildHandle
;
3433 pPort
->pService
= pService
;
3434 pPort
->pServiceBinding
= pService
->pServiceBinding
;
3435 pPort
->pSocket
= pSocket
;
3436 pPort
->pSocketBinding
= pService
->pSocketBinding
;
3437 pPort
->Signature
= PORT_SIGNATURE
;
3440 // Open the port protocol
3442 Status
= gBS
->OpenProtocol ( pPort
->Handle
,
3443 pSocketBinding
->pNetworkProtocolGuid
,
3444 &pPort
->pProtocol
.v
,
3445 pLayer
->ImageHandle
,
3447 EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL
);
3448 if ( EFI_ERROR ( Status
)) {
3449 DEBUG (( DEBUG_ERROR
| DebugFlags
,
3450 "ERROR - Failed to open network protocol GUID on controller 0x%08x\r\n",
3452 pSocket
->errno
= EEXIST
;
3455 DEBUG (( DebugFlags
,
3456 "0x%08x: Network protocol GUID opened on controller 0x%08x\r\n",
3461 // Initialize the port specific resources
3463 Status
= pSocket
->pApi
->pfnPortAllocate ( pPort
,
3465 if ( EFI_ERROR ( Status
)) {
3470 // Set the local address
3472 Status
= pSocket
->pApi
->pfnLocalAddrSet ( pPort
, pSockAddr
, bBindTest
);
3473 if ( EFI_ERROR ( Status
)) {
3478 // Test the address/port configuration
3481 Status
= EslSocketBindTest ( pPort
, pSocket
->pApi
->BindTestErrno
);
3482 if ( EFI_ERROR ( Status
)) {
3488 // Initialize the receive structures
3490 pBuffer
= (UINT8
*)&pPort
[ 1 ];
3491 pBuffer
= &pBuffer
[ ESL_STRUCTURE_ALIGNMENT_BYTES
];
3492 pBuffer
= (UINT8
*)( ESL_STRUCTURE_ALIGNMENT_MASK
& (UINTN
)pBuffer
);
3493 pIo
= (ESL_IO_MGMT
*)pBuffer
;
3494 if (( 0 != pSocketBinding
->RxIo
)
3495 && ( NULL
!= pSocket
->pApi
->pfnRxComplete
)) {
3496 Status
= EslSocketIoInit ( pPort
,
3498 pSocketBinding
->RxIo
,
3500 DebugFlags
| DEBUG_POOL
,
3502 pSocket
->pApi
->pfnRxComplete
);
3503 if ( EFI_ERROR ( Status
)) {
3509 // Initialize the urgent transmit structures
3511 if (( 0 != pSocketBinding
->TxIoUrgent
)
3512 && ( NULL
!= pSocket
->pApi
->pfnTxOobComplete
)) {
3513 Status
= EslSocketIoInit ( pPort
,
3515 pSocketBinding
->TxIoUrgent
,
3517 DebugFlags
| DEBUG_POOL
,
3519 pSocket
->pApi
->pfnTxOobComplete
);
3520 if ( EFI_ERROR ( Status
)) {
3526 // Initialize the normal transmit structures
3528 if (( 0 != pSocketBinding
->TxIoNormal
)
3529 && ( NULL
!= pSocket
->pApi
->pfnTxComplete
)) {
3530 Status
= EslSocketIoInit ( pPort
,
3532 pSocketBinding
->TxIoNormal
,
3534 DebugFlags
| DEBUG_POOL
,
3536 pSocket
->pApi
->pfnTxComplete
);
3537 if ( EFI_ERROR ( Status
)) {
3543 // Add this port to the socket
3545 pPort
->pLinkSocket
= pSocket
->pPortList
;
3546 pSocket
->pPortList
= pPort
;
3547 DEBUG (( DebugFlags
,
3548 "0x%08x: Socket adding port: 0x%08x\r\n",
3553 // Add this port to the service
3555 pPort
->pLinkService
= pService
->pPortList
;
3556 pService
->pPortList
= pPort
;
3566 // Clean up after the error if necessary
3568 if ( EFI_ERROR ( Status
)) {
3569 if ( NULL
!= pPort
) {
3573 EslSocketPortClose ( pPort
);
3577 // Close the port if necessary
3579 pServiceBinding
= pService
->pServiceBinding
;
3580 TempStatus
= pServiceBinding
->DestroyChild ( pServiceBinding
,
3582 if ( !EFI_ERROR ( TempStatus
)) {
3583 DEBUG (( DEBUG_BIND
| DEBUG_POOL
,
3584 "0x%08x: %s port handle destroyed\r\n",
3586 pSocketBinding
->pName
));
3589 DEBUG (( DEBUG_ERROR
| DEBUG_BIND
| DEBUG_POOL
,
3590 "ERROR - Failed to destroy the %s port handle 0x%08x, Status: %r\r\n",
3591 pSocketBinding
->pName
,
3594 ASSERT ( EFI_SUCCESS
== TempStatus
);
3599 // Return the operation status
3601 DBG_EXIT_STATUS ( Status
);
3609 This routine releases the resources allocated by ::EslSocketPortAllocate.
3610 This routine calls ESL_PROTOCOL_API::pfnPortClose to release the network
3613 This routine is called by:
3615 <li>::EslSocketPortAllocate - Port initialization failure</li>
3616 <li>::EslSocketPortCloseRxDone - Last step of close processing</li>
3617 <li>::EslTcp4ConnectComplete - Connection failure and reducing the port list to a single port</li>
3619 See the \ref PortCloseStateMachine section.
3621 @param [in] pPort Address of an ::ESL_PORT structure.
3623 @retval EFI_SUCCESS The port is closed
3624 @retval other Port close error
3628 EslSocketPortClose (
3634 ESL_PACKET
* pPacket
;
3635 ESL_PORT
* pPreviousPort
;
3636 ESL_SERVICE
* pService
;
3637 EFI_SERVICE_BINDING_PROTOCOL
* pServiceBinding
;
3638 CONST ESL_SOCKET_BINDING
* pSocketBinding
;
3639 ESL_SOCKET
* pSocket
;
3645 // Verify the socket layer synchronization
3647 VERIFY_TPL ( TPL_SOCKETS
);
3650 // Locate the port in the socket list
3652 Status
= EFI_SUCCESS
;
3653 pLayer
= &mEslLayer
;
3654 DebugFlags
= pPort
->DebugFlags
;
3655 pSocket
= pPort
->pSocket
;
3656 pPreviousPort
= pSocket
->pPortList
;
3657 if ( pPreviousPort
== pPort
) {
3659 // Remove this port from the head of the socket list
3661 pSocket
->pPortList
= pPort
->pLinkSocket
;
3665 // Locate the port in the middle of the socket list
3667 while (( NULL
!= pPreviousPort
)
3668 && ( pPreviousPort
->pLinkSocket
!= pPort
)) {
3669 pPreviousPort
= pPreviousPort
->pLinkSocket
;
3671 if ( NULL
!= pPreviousPort
) {
3673 // Remove the port from the middle of the socket list
3675 pPreviousPort
->pLinkSocket
= pPort
->pLinkSocket
;
3680 // Locate the port in the service list
3681 // Note that the port may not be in the service list
3682 // if the service has been shutdown.
3684 pService
= pPort
->pService
;
3685 if ( NULL
!= pService
) {
3686 pPreviousPort
= pService
->pPortList
;
3687 if ( pPreviousPort
== pPort
) {
3689 // Remove this port from the head of the service list
3691 pService
->pPortList
= pPort
->pLinkService
;
3695 // Locate the port in the middle of the service list
3697 while (( NULL
!= pPreviousPort
)
3698 && ( pPreviousPort
->pLinkService
!= pPort
)) {
3699 pPreviousPort
= pPreviousPort
->pLinkService
;
3701 if ( NULL
!= pPreviousPort
) {
3703 // Remove the port from the middle of the service list
3705 pPreviousPort
->pLinkService
= pPort
->pLinkService
;
3711 // Empty the urgent receive queue
3713 while ( NULL
!= pSocket
->pRxOobPacketListHead
) {
3714 pPacket
= pSocket
->pRxOobPacketListHead
;
3715 pSocket
->pRxOobPacketListHead
= pPacket
->pNext
;
3716 pSocket
->pApi
->pfnPacketFree ( pPacket
, &pSocket
->RxOobBytes
);
3717 EslSocketPacketFree ( pPacket
, DEBUG_RX
);
3719 pSocket
->pRxOobPacketListTail
= NULL
;
3720 ASSERT ( 0 == pSocket
->RxOobBytes
);
3723 // Empty the receive queue
3725 while ( NULL
!= pSocket
->pRxPacketListHead
) {
3726 pPacket
= pSocket
->pRxPacketListHead
;
3727 pSocket
->pRxPacketListHead
= pPacket
->pNext
;
3728 pSocket
->pApi
->pfnPacketFree ( pPacket
, &pSocket
->RxBytes
);
3729 EslSocketPacketFree ( pPacket
, DEBUG_RX
);
3731 pSocket
->pRxPacketListTail
= NULL
;
3732 ASSERT ( 0 == pSocket
->RxBytes
);
3735 // Empty the receive free queue
3737 while ( NULL
!= pSocket
->pRxFree
) {
3738 pPacket
= pSocket
->pRxFree
;
3739 pSocket
->pRxFree
= pPacket
->pNext
;
3740 EslSocketPacketFree ( pPacket
, DEBUG_RX
);
3744 // Release the network specific resources
3746 if ( NULL
!= pSocket
->pApi
->pfnPortClose
) {
3747 Status
= pSocket
->pApi
->pfnPortClose ( pPort
);
3751 // Done with the normal transmit events
3753 Status
= EslSocketIoFree ( pPort
,
3755 DebugFlags
| DEBUG_POOL
,
3756 "normal transmit" );
3759 // Done with the urgent transmit events
3761 Status
= EslSocketIoFree ( pPort
,
3763 DebugFlags
| DEBUG_POOL
,
3764 "urgent transmit" );
3767 // Done with the receive events
3769 Status
= EslSocketIoFree ( pPort
,
3771 DebugFlags
| DEBUG_POOL
,
3775 // Done with the lower layer network protocol
3777 pSocketBinding
= pPort
->pSocketBinding
;
3778 if ( NULL
!= pPort
->pProtocol
.v
) {
3779 Status
= gBS
->CloseProtocol ( pPort
->Handle
,
3780 pSocketBinding
->pNetworkProtocolGuid
,
3781 pLayer
->ImageHandle
,
3783 if ( !EFI_ERROR ( Status
)) {
3784 DEBUG (( DebugFlags
,
3785 "0x%08x: Network protocol GUID closed on controller 0x%08x\r\n",
3790 DEBUG (( DEBUG_ERROR
| DebugFlags
,
3791 "ERROR - Failed to close network protocol GUID on controller 0x%08x, Status: %r\r\n",
3794 ASSERT ( EFI_SUCCESS
== Status
);
3799 // Done with the network port
3801 pServiceBinding
= pPort
->pServiceBinding
;
3802 if ( NULL
!= pPort
->Handle
) {
3803 Status
= pServiceBinding
->DestroyChild ( pServiceBinding
,
3805 if ( !EFI_ERROR ( Status
)) {
3806 DEBUG (( DebugFlags
| DEBUG_POOL
,
3807 "0x%08x: %s port handle destroyed\r\n",
3809 pSocketBinding
->pName
));
3812 DEBUG (( DEBUG_ERROR
| DebugFlags
| DEBUG_POOL
,
3813 "ERROR - Failed to destroy the %s port handle, Status: %r\r\n",
3814 pSocketBinding
->pName
,
3816 ASSERT ( EFI_SUCCESS
== Status
);
3821 // Release the port structure
3823 Status
= gBS
->FreePool ( pPort
);
3824 if ( !EFI_ERROR ( Status
)) {
3825 DEBUG (( DebugFlags
| DEBUG_POOL
,
3826 "0x%08x: Free pPort, %d bytes\r\n",
3828 sizeof ( *pPort
)));
3831 DEBUG (( DEBUG_ERROR
| DebugFlags
| DEBUG_POOL
,
3832 "ERROR - Failed to free pPort: 0x%08x, Status: %r\r\n",
3835 ASSERT ( EFI_SUCCESS
== Status
);
3839 // Mark the socket as closed if necessary
3841 if ( NULL
== pSocket
->pPortList
) {
3842 pSocket
->State
= SOCKET_STATE_CLOSED
;
3843 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
3844 "0x%08x: Socket State: SOCKET_STATE_CLOSED\r\n",
3849 // Return the operation status
3851 DBG_EXIT_STATUS ( Status
);
3859 This routine attempts to complete the port close operation.
3861 This routine is called by the TCP layer upon completion of
3862 the close operation and by ::EslSocketPortCloseTxDone.
3863 See the \ref PortCloseStateMachine section.
3865 @param [in] Event The close completion event
3867 @param [in] pPort Address of an ::ESL_PORT structure.
3871 EslSocketPortCloseComplete (
3880 VERIFY_AT_TPL ( TPL_SOCKETS
);
3883 // Update the port state
3885 pPort
->State
= PORT_STATE_CLOSE_DONE
;
3886 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
3887 "0x%08x: Port Close State: PORT_STATE_CLOSE_DONE\r\n",
3891 // Shutdown the receive operation on the port
3893 if ( NULL
!= pPort
->pfnRxCancel
) {
3894 pIo
= pPort
->pRxActive
;
3895 while ( NULL
!= pIo
) {
3896 EslSocketRxCancel ( pPort
, pIo
);
3902 // Determine if the receive operation is pending
3904 Status
= EslSocketPortCloseRxDone ( pPort
);
3905 DBG_EXIT_STATUS ( Status
);
3912 This routine determines the state of the receive operations and
3913 continues the close operation after the pending receive operations
3916 This routine is called by
3918 <li>::EslSocketPortCloseComplete</li>
3919 <li>::EslSocketPortCloseTxDone</li>
3920 <li>::EslSocketRxComplete</li>
3922 to determine the state of the receive operations.
3923 See the \ref PortCloseStateMachine section.
3925 @param [in] pPort Address of an ::ESL_PORT structure.
3927 @retval EFI_SUCCESS The port is closed
3928 @retval EFI_NOT_READY The port is still closing
3929 @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
3930 most likely the routine was called already.
3934 EslSocketPortCloseRxDone (
3943 // Verify the socket layer synchronization
3945 VERIFY_TPL ( TPL_SOCKETS
);
3948 // Verify that the port is closing
3950 Status
= EFI_ALREADY_STARTED
;
3951 if ( PORT_STATE_CLOSE_DONE
== pPort
->State
) {
3953 // Determine if the receive operation is pending
3955 Status
= EFI_NOT_READY
;
3956 if ( NULL
== pPort
->pRxActive
) {
3958 // The receive operation is complete
3959 // Update the port state
3961 pPort
->State
= PORT_STATE_CLOSE_RX_DONE
;
3962 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
3963 "0x%08x: Port Close State: PORT_STATE_CLOSE_RX_DONE\r\n",
3967 // Complete the port close operation
3969 Status
= EslSocketPortClose ( pPort
);
3972 DEBUG_CODE_BEGIN ();
3976 // Display the outstanding receive operations
3978 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
3979 "0x%08x: Port Close: Receive still pending!\r\n",
3981 pIo
= pPort
->pRxActive
;
3982 while ( NULL
!= pIo
) {
3983 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
3984 "0x%08x: Packet pending on network adapter\r\n",
3994 // Return the operation status
3996 DBG_EXIT_STATUS ( Status
);
4002 Start the close operation on a port, state 1.
4004 This routine marks the port as closed and initiates the \ref
4005 PortCloseStateMachine. The first step is to allow the \ref
4006 TransmitEngine to run down.
4008 This routine is called by ::EslSocketCloseStart to initiate the socket
4009 network specific close operation on the socket.
4011 @param [in] pPort Address of an ::ESL_PORT structure.
4012 @param [in] bCloseNow Set TRUE to abort active transfers
4013 @param [in] DebugFlags Flags for debug messages
4015 @retval EFI_SUCCESS The port is closed, not normally returned
4016 @retval EFI_NOT_READY The port has started the closing process
4017 @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
4018 most likely the routine was called already.
4022 EslSocketPortCloseStart (
4023 IN ESL_PORT
* pPort
,
4024 IN BOOLEAN bCloseNow
,
4028 ESL_SOCKET
* pSocket
;
4034 // Verify the socket layer synchronization
4036 VERIFY_TPL ( TPL_SOCKETS
);
4039 // Mark the port as closing
4041 Status
= EFI_ALREADY_STARTED
;
4042 pSocket
= pPort
->pSocket
;
4043 pSocket
->errno
= EALREADY
;
4044 if ( PORT_STATE_CLOSE_STARTED
> pPort
->State
) {
4047 // Update the port state
4049 pPort
->State
= PORT_STATE_CLOSE_STARTED
;
4050 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4051 "0x%08x: Port Close State: PORT_STATE_CLOSE_STARTED\r\n",
4053 pPort
->bCloseNow
= bCloseNow
;
4054 pPort
->DebugFlags
= DebugFlags
;
4057 // Determine if transmits are complete
4059 Status
= EslSocketPortCloseTxDone ( pPort
);
4063 // Return the operation status
4065 DBG_EXIT_STATUS ( Status
);
4073 This routine determines the state of the transmit engine and
4074 continue the close operation after the transmission is complete.
4075 The next step is to stop the \ref ReceiveEngine.
4076 See the \ref PortCloseStateMachine section.
4078 This routine is called by ::EslSocketPortCloseStart to determine
4079 if the transmission is complete.
4081 @param [in] pPort Address of an ::ESL_PORT structure.
4083 @retval EFI_SUCCESS The port is closed, not normally returned
4084 @retval EFI_NOT_READY The port is still closing
4085 @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
4086 most likely the routine was called already.
4090 EslSocketPortCloseTxDone (
4095 ESL_SOCKET
* pSocket
;
4101 // Verify the socket layer synchronization
4103 VERIFY_TPL ( TPL_SOCKETS
);
4106 // All transmissions are complete or must be stopped
4107 // Mark the port as TX complete
4109 Status
= EFI_ALREADY_STARTED
;
4110 if ( PORT_STATE_CLOSE_STARTED
== pPort
->State
) {
4112 // Verify that the transmissions are complete
4114 pSocket
= pPort
->pSocket
;
4115 if ( pPort
->bCloseNow
4116 || ( EFI_SUCCESS
!= pSocket
->TxError
)
4117 || (( NULL
== pPort
->pTxActive
)
4118 && ( NULL
== pPort
->pTxOobActive
))) {
4120 // Update the port state
4122 pPort
->State
= PORT_STATE_CLOSE_TX_DONE
;
4123 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4124 "0x%08x: Port Close State: PORT_STATE_CLOSE_TX_DONE\r\n",
4129 // Skip the close operation if the port is not configured
4131 Status
= EFI_SUCCESS
;
4132 pSocket
= pPort
->pSocket
;
4133 if (( pPort
->bConfigured
)
4134 && ( NULL
!= pSocket
->pApi
->pfnPortCloseOp
)) {
4136 // Start the close operation
4138 Status
= pSocket
->pApi
->pfnPortCloseOp ( pPort
);
4139 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4140 "0x%08x: Port Close: Close operation still pending!\r\n",
4142 ASSERT ( EFI_SUCCESS
== Status
);
4146 // The receive operation is complete
4147 // Update the port state
4149 EslSocketPortCloseComplete ( NULL
, pPort
);
4154 // Transmissions are still active, exit
4156 Status
= EFI_NOT_READY
;
4157 pSocket
->errno
= EAGAIN
;
4158 DEBUG_CODE_BEGIN ( );
4160 ESL_PACKET
* pPacket
;
4162 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4163 "0x%08x: Port Close: Transmits are still pending!\r\n",
4167 // Display the pending urgent transmit packets
4169 pPacket
= pSocket
->pTxOobPacketListHead
;
4170 while ( NULL
!= pPacket
) {
4171 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4172 "0x%08x: Packet pending on urgent TX list, %d bytes\r\n",
4174 pPacket
->PacketSize
));
4175 pPacket
= pPacket
->pNext
;
4178 pIo
= pPort
->pTxOobActive
;
4179 while ( NULL
!= pIo
) {
4180 pPacket
= pIo
->pPacket
;
4181 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4182 "0x%08x: Packet active %d bytes, pIo: 0x%08x\r\n",
4184 pPacket
->PacketSize
,
4190 // Display the pending normal transmit packets
4192 pPacket
= pSocket
->pTxPacketListHead
;
4193 while ( NULL
!= pPacket
) {
4194 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4195 "0x%08x: Packet pending on normal TX list, %d bytes\r\n",
4197 pPacket
->PacketSize
));
4198 pPacket
= pPacket
->pNext
;
4201 pIo
= pPort
->pTxActive
;
4202 while ( NULL
!= pIo
) {
4203 pPacket
= pIo
->pPacket
;
4204 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4205 "0x%08x: Packet active %d bytes, pIo: 0x%08x\r\n",
4207 pPacket
->PacketSize
,
4217 // Return the operation status
4219 DBG_EXIT_STATUS ( Status
);
4225 Receive data from a network connection.
4227 This routine calls the network specific routine to remove the
4228 next portion of data from the receive queue and return it to the
4231 The ::recvfrom routine calls this routine to determine if any data
4232 is received from the remote system. Note that the other routines
4233 ::recv and ::read are layered on top of ::recvfrom.
4235 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
4237 @param [in] Flags Message control flags
4239 @param [in] BufferLength Length of the the buffer
4241 @param [in] pBuffer Address of a buffer to receive the data.
4243 @param [in] pDataLength Number of received data bytes in the buffer.
4245 @param [out] pAddress Network address to receive the remote system address
4247 @param [in,out] pAddressLength Length of the remote network address structure
4249 @param [out] pErrno Address to receive the errno value upon completion.
4251 @retval EFI_SUCCESS - Socket data successfully received
4256 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
4258 IN
size_t BufferLength
,
4260 OUT
size_t * pDataLength
,
4261 OUT
struct sockaddr
* pAddress
,
4262 IN OUT socklen_t
* pAddressLength
,
4267 struct sockaddr_in v4
;
4268 struct sockaddr_in6 v6
;
4270 socklen_t AddressLength
;
4271 BOOLEAN bConsumePacket
;
4272 BOOLEAN bUrgentQueue
;
4274 ESL_PACKET
* pNextPacket
;
4275 ESL_PACKET
* pPacket
;
4277 ESL_PACKET
** ppQueueHead
;
4278 ESL_PACKET
** ppQueueTail
;
4279 struct sockaddr
* pRemoteAddress
;
4280 size_t * pRxDataBytes
;
4281 ESL_SOCKET
* pSocket
;
4284 EFI_TPL TplPrevious
;
4291 Status
= EFI_SUCCESS
;
4294 // Validate the socket
4297 if ( NULL
!= pSocketProtocol
) {
4298 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
4301 // Validate the return address parameters
4303 if (( NULL
== pAddress
) || ( NULL
!= pAddressLength
)) {
4305 // Return the transmit error if necessary
4307 if ( EFI_SUCCESS
!= pSocket
->TxError
) {
4308 pSocket
->errno
= EIO
;
4309 Status
= pSocket
->TxError
;
4310 pSocket
->TxError
= EFI_SUCCESS
;
4314 // Verify the socket state
4316 Status
= EslSocketIsConfigured ( pSocket
);
4317 if ( !EFI_ERROR ( Status
)) {
4319 // Validate the buffer length
4321 if (( NULL
== pDataLength
)
4322 || ( NULL
== pBuffer
)) {
4323 if ( NULL
== pDataLength
) {
4325 "ERROR - pDataLength is NULL!\r\n" ));
4329 "ERROR - pBuffer is NULL!\r\n" ));
4331 Status
= EFI_INVALID_PARAMETER
;
4332 pSocket
->errno
= EFAULT
;
4338 if ( NULL
== pSocket
->pApi
->pfnReceive
) {
4339 Status
= EFI_UNSUPPORTED
;
4340 pSocket
->errno
= ENOTSUP
;
4344 // Zero the receive address if being returned
4346 pRemoteAddress
= NULL
;
4347 if ( NULL
!= pAddress
) {
4348 pRemoteAddress
= (struct sockaddr
*)&Addr
;
4349 ZeroMem ( pRemoteAddress
, sizeof ( Addr
));
4350 pRemoteAddress
->sa_family
= pSocket
->pApi
->AddressFamily
;
4351 pRemoteAddress
->sa_len
= (UINT8
)pSocket
->pApi
->AddressLength
;
4355 // Synchronize with the socket layer
4357 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
4362 Status
= EFI_UNSUPPORTED
;
4363 pSocket
->errno
= ENOTCONN
;
4366 // Verify that the socket is connected
4368 if ( SOCKET_STATE_CONNECTED
== pSocket
->State
) {
4372 pPort
= pSocket
->pPortList
;
4373 if ( NULL
!= pPort
) {
4375 // Determine the queue head
4377 bUrgentQueue
= (BOOLEAN
)( 0 != ( Flags
& MSG_OOB
));
4378 if ( bUrgentQueue
) {
4379 ppQueueHead
= &pSocket
->pRxOobPacketListHead
;
4380 ppQueueTail
= &pSocket
->pRxOobPacketListTail
;
4381 pRxDataBytes
= &pSocket
->RxOobBytes
;
4384 ppQueueHead
= &pSocket
->pRxPacketListHead
;
4385 ppQueueTail
= &pSocket
->pRxPacketListTail
;
4386 pRxDataBytes
= &pSocket
->RxBytes
;
4390 // Determine if there is any data on the queue
4393 pPacket
= *ppQueueHead
;
4394 if ( NULL
!= pPacket
) {
4396 // Copy the received data
4400 // Attempt to receive a packet
4403 bConsumePacket
= (BOOLEAN
)( 0 == ( Flags
& MSG_PEEK
));
4404 pBuffer
= pSocket
->pApi
->pfnReceive ( pPort
,
4410 (struct sockaddr
*)&Addr
,
4412 *pDataLength
+= DataLength
;
4413 BufferLength
-= DataLength
;
4416 // Determine if the data is being read
4418 pNextPacket
= pPacket
->pNext
;
4419 if ( bConsumePacket
) {
4421 // All done with this packet
4422 // Account for any discarded data
4424 pSocket
->pApi
->pfnPacketFree ( pPacket
, pRxDataBytes
);
4425 if ( 0 != SkipBytes
) {
4427 "0x%08x: Port, packet read, skipping over 0x%08x bytes\r\n",
4433 // Remove this packet from the queue
4435 *ppQueueHead
= pPacket
->pNext
;
4436 if ( NULL
== *ppQueueHead
) {
4437 *ppQueueTail
= NULL
;
4441 // Move the packet to the free queue
4443 pPacket
->pNext
= pSocket
->pRxFree
;
4444 pSocket
->pRxFree
= pPacket
;
4446 "0x%08x: Port freeing packet 0x%08x\r\n",
4451 // Restart the receive operation if necessary
4453 if (( NULL
!= pPort
->pRxFree
)
4454 && ( MAX_RX_DATA
> pSocket
->RxBytes
)) {
4455 EslSocketRxStart ( pPort
);
4460 // Get the next packet
4462 pPacket
= pNextPacket
;
4463 } while (( SOCK_STREAM
== pSocket
->Type
)
4464 && ( NULL
!= pPacket
)
4465 && ( 0 < BufferLength
));
4468 // Successful operation
4470 Status
= EFI_SUCCESS
;
4475 // The queue is empty
4476 // Determine if it is time to return the receive error
4478 if ( EFI_ERROR ( pSocket
->RxError
)
4479 && ( NULL
== pSocket
->pRxPacketListHead
)
4480 && ( NULL
== pSocket
->pRxOobPacketListHead
)) {
4481 Status
= pSocket
->RxError
;
4482 pSocket
->RxError
= EFI_SUCCESS
;
4485 pSocket
->errno
= EIO
;
4488 case EFI_CONNECTION_FIN
:
4490 // Continue to return zero bytes received when the
4491 // peer has successfully closed the connection
4493 pSocket
->RxError
= EFI_CONNECTION_FIN
;
4496 Status
= EFI_SUCCESS
;
4499 case EFI_CONNECTION_REFUSED
:
4500 pSocket
->errno
= ECONNREFUSED
;
4503 case EFI_CONNECTION_RESET
:
4504 pSocket
->errno
= ECONNRESET
;
4507 case EFI_HOST_UNREACHABLE
:
4508 pSocket
->errno
= EHOSTUNREACH
;
4511 case EFI_NETWORK_UNREACHABLE
:
4512 pSocket
->errno
= ENETUNREACH
;
4515 case EFI_PORT_UNREACHABLE
:
4516 pSocket
->errno
= EPROTONOSUPPORT
;
4519 case EFI_PROTOCOL_UNREACHABLE
:
4520 pSocket
->errno
= ENOPROTOOPT
;
4525 Status
= EFI_NOT_READY
;
4526 pSocket
->errno
= EAGAIN
;
4533 // Release the socket layer synchronization
4535 RESTORE_TPL ( TplPrevious
);
4537 if (( !EFI_ERROR ( Status
)) && ( NULL
!= pAddress
)) {
4539 // Return the remote address if requested, truncate if necessary
4541 AddressLength
= pRemoteAddress
->sa_len
;
4542 if ( AddressLength
> *pAddressLength
) {
4543 AddressLength
= *pAddressLength
;
4546 "Returning the remote address, 0x%016x bytes --> 0x%16x\r\n", *pAddressLength
, pAddress
));
4547 ZeroMem ( pAddress
, *pAddressLength
);
4548 CopyMem ( pAddress
, &Addr
, AddressLength
);
4551 // Update the address length
4553 *pAddressLength
= pRemoteAddress
->sa_len
;
4564 // Bad return address pointer and length
4566 Status
= EFI_INVALID_PARAMETER
;
4567 pSocket
->errno
= EINVAL
;
4572 // Return the operation status
4574 if ( NULL
!= pErrno
) {
4575 if ( NULL
!= pSocket
) {
4576 *pErrno
= pSocket
->errno
;
4579 Status
= EFI_INVALID_PARAMETER
;
4583 DBG_EXIT_STATUS ( Status
);
4589 Cancel the receive operations
4591 This routine cancels a pending receive operation.
4592 See the \ref ReceiveEngine section.
4594 This routine is called by ::EslSocketShutdown when the socket
4595 layer is being shutdown.
4597 @param [in] pPort Address of an ::ESL_PORT structure
4598 @param [in] pIo Address of an ::ESL_IO_MGMT structure
4603 IN ESL_PORT
* pPort
,
4604 IN ESL_IO_MGMT
* pIo
4612 // Cancel the outstanding receive
4614 Status
= pPort
->pfnRxCancel ( pPort
->pProtocol
.v
,
4616 if ( !EFI_ERROR ( Status
)) {
4617 DEBUG (( pPort
->DebugFlags
| DEBUG_CLOSE
| DEBUG_INFO
,
4618 "0x%08x: Packet receive aborted on port: 0x%08x\r\n",
4623 DEBUG (( pPort
->DebugFlags
| DEBUG_CLOSE
| DEBUG_INFO
,
4624 "0x%08x: Packet receive pending on Port 0x%08x, Status: %r\r\n",
4634 Process the receive completion
4636 This routine queues the data in FIFO order in either the urgent
4637 or normal data queues depending upon the type of data received.
4638 See the \ref ReceiveEngine section.
4640 This routine is called when some data is received by:
4642 <li>::EslIp4RxComplete</li>
4643 <li>::EslTcp4RxComplete</li>
4644 <li>::EslUdp4RxComplete</li>
4647 @param [in] pIo Address of an ::ESL_IO_MGMT structure
4648 @param [in] Status Receive status
4649 @param [in] LengthInBytes Length of the receive data
4650 @param [in] bUrgent TRUE if urgent data is received and FALSE
4655 EslSocketRxComplete (
4656 IN ESL_IO_MGMT
* pIo
,
4657 IN EFI_STATUS Status
,
4658 IN UINTN LengthInBytes
,
4662 BOOLEAN bUrgentQueue
;
4663 ESL_IO_MGMT
* pIoNext
;
4664 ESL_PACKET
* pPacket
;
4666 ESL_PACKET
* pPrevious
;
4667 ESL_PACKET
** ppQueueHead
;
4668 ESL_PACKET
** ppQueueTail
;
4670 ESL_SOCKET
* pSocket
;
4673 VERIFY_AT_TPL ( TPL_SOCKETS
);
4676 // Locate the active receive packet
4678 pPacket
= pIo
->pPacket
;
4680 pSocket
= pPort
->pSocket
;
4686 // +-------------+ +-------------+ +-------------+
4687 // Active | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
4688 // +-------------+ +-------------+ +-------------+
4690 // +-------------+ +-------------+ +-------------+
4691 // Free | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
4692 // +-------------+ +-------------+ +-------------+
4698 // Remove the IO structure from the active list
4699 // The following code searches for the entry in the list and does not
4700 // assume that the receive operations complete in the order they were
4701 // issued to the UEFI network layer.
4703 pIoNext
= pPort
->pRxActive
;
4704 while (( NULL
!= pIoNext
) && ( pIoNext
!= pIo
) && ( pIoNext
->pNext
!= pIo
))
4706 pIoNext
= pIoNext
->pNext
;
4708 ASSERT ( NULL
!= pIoNext
);
4709 if ( pIoNext
== pIo
) {
4710 pPort
->pRxActive
= pIo
->pNext
; // Beginning of list
4713 pIoNext
->pNext
= pIo
->pNext
; // Middle of list
4717 // Free the IO structure
4719 pIo
->pNext
= pPort
->pRxFree
;
4720 pPort
->pRxFree
= pIo
;
4723 // pRxOobPacketListHead pRxOobPacketListTail
4726 // +------------+ +------------+ +------------+
4727 // Urgent Data | ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL
4728 // +------------+ +------------+ +------------+
4730 // +------------+ +------------+ +------------+
4731 // Normal Data | ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL
4732 // +------------+ +------------+ +------------+
4735 // pRxPacketListHead pRxPacketListTail
4738 // Determine the queue to use
4740 bUrgentQueue
= (BOOLEAN
)( bUrgent
4741 && pSocket
->pApi
->bOobSupported
4742 && ( !pSocket
->bOobInLine
));
4743 if ( bUrgentQueue
) {
4744 ppQueueHead
= &pSocket
->pRxOobPacketListHead
;
4745 ppQueueTail
= &pSocket
->pRxOobPacketListTail
;
4746 pRxBytes
= &pSocket
->RxOobBytes
;
4749 ppQueueHead
= &pSocket
->pRxPacketListHead
;
4750 ppQueueTail
= &pSocket
->pRxPacketListTail
;
4751 pRxBytes
= &pSocket
->RxBytes
;
4755 // Determine if this receive was successful
4757 if (( !EFI_ERROR ( Status
))
4758 && ( PORT_STATE_CLOSE_STARTED
> pPort
->State
)
4759 && ( !pSocket
->bRxDisable
)) {
4761 // Account for the received data
4763 *pRxBytes
+= LengthInBytes
;
4766 // Log the received data
4768 DEBUG (( DEBUG_RX
| DEBUG_INFO
,
4769 "0x%08x: Packet queued on %s queue of port 0x%08x with 0x%08x bytes of %s data\r\n",
4771 bUrgentQueue
? L
"urgent" : L
"normal",
4774 bUrgent
? L
"urgent" : L
"normal" ));
4777 // Add the packet to the list tail.
4779 pPacket
->pNext
= NULL
;
4780 pPrevious
= *ppQueueTail
;
4781 if ( NULL
== pPrevious
) {
4782 *ppQueueHead
= pPacket
;
4785 pPrevious
->pNext
= pPacket
;
4787 *ppQueueTail
= pPacket
;
4790 // Attempt to restart this receive operation
4792 if ( pSocket
->MaxRxBuf
> pSocket
->RxBytes
) {
4793 EslSocketRxStart ( pPort
);
4797 "0x%08x: Port RX suspended, 0x%08x bytes queued\r\n",
4799 pSocket
->RxBytes
));
4803 if ( EFI_ERROR ( Status
)) {
4804 DEBUG (( DEBUG_RX
| DEBUG_INFO
,
4805 "ERROR - Receive error on port 0x%08x, packet 0x%08x, Status:%r\r\n",
4812 // Account for the receive bytes and release the driver's buffer
4814 if ( !EFI_ERROR ( Status
)) {
4815 *pRxBytes
+= LengthInBytes
;
4816 pSocket
->pApi
->pfnPacketFree ( pPacket
, pRxBytes
);
4820 // Receive error, free the packet save the error
4822 EslSocketPacketFree ( pPacket
, DEBUG_RX
);
4823 if ( !EFI_ERROR ( pSocket
->RxError
)) {
4824 pSocket
->RxError
= Status
;
4828 // Update the port state
4830 if ( PORT_STATE_CLOSE_STARTED
<= pPort
->State
) {
4831 if ( PORT_STATE_CLOSE_DONE
== pPort
->State
) {
4832 EslSocketPortCloseRxDone ( pPort
);
4836 if ( EFI_ERROR ( Status
)) {
4837 DEBUG (( DEBUG_RX
| DEBUG_INFO
,
4838 "0x%08x: Port state: PORT_STATE_RX_ERROR, Status: %r\r\n",
4841 pPort
->State
= PORT_STATE_RX_ERROR
;
4851 Start a receive operation
4853 This routine posts a receive buffer to the network adapter.
4854 See the \ref ReceiveEngine section.
4856 This support routine is called by:
4858 <li>::EslIp4Receive to restart the receive engine to release flow control.</li>
4859 <li>::EslIp4RxComplete to continue the operation of the receive engine if flow control is not being applied.</li>
4860 <li>::EslIp4SocketIsConfigured to start the recevie engine for the new socket.</li>
4861 <li>::EslTcp4ListenComplete to start the recevie engine for the new socket.</li>
4862 <li>::EslTcp4Receive to restart the receive engine to release flow control.</li>
4863 <li>::EslTcp4RxComplete to continue the operation of the receive engine if flow control is not being applied.</li>
4864 <li>::EslUdp4Receive to restart the receive engine to release flow control.</li>
4865 <li>::EslUdp4RxComplete to continue the operation of the receive engine if flow control is not being applied.</li>
4866 <li>::EslUdp4SocketIsConfigured to start the recevie engine for the new socket.</li>
4869 @param [in] pPort Address of an ::ESL_PORT structure.
4879 ESL_PACKET
* pPacket
;
4880 ESL_SOCKET
* pSocket
;
4886 // Determine if a receive is already pending
4888 Status
= EFI_SUCCESS
;
4890 pSocket
= pPort
->pSocket
;
4891 if ( !EFI_ERROR ( pPort
->pSocket
->RxError
)) {
4892 if (( NULL
!= pPort
->pRxFree
)
4893 && ( !pSocket
->bRxDisable
)
4894 && ( PORT_STATE_CLOSE_STARTED
> pPort
->State
)) {
4896 // Start all of the pending receive operations
4898 while ( NULL
!= pPort
->pRxFree
) {
4900 // Determine if there are any free packets
4902 pPacket
= pSocket
->pRxFree
;
4903 if ( NULL
!= pPacket
) {
4905 // Remove this packet from the free list
4907 pSocket
->pRxFree
= pPacket
->pNext
;
4909 "0x%08x: Port removed packet 0x%08x from free list\r\n",
4915 // Allocate a packet structure
4917 Status
= EslSocketPacketAllocate ( &pPacket
,
4918 pSocket
->pApi
->RxPacketBytes
,
4919 pSocket
->pApi
->RxZeroBytes
,
4921 if ( EFI_ERROR ( Status
)) {
4923 DEBUG (( DEBUG_ERROR
| DEBUG_RX
,
4924 "0x%08x: Port failed to allocate RX packet, Status: %r\r\n",
4932 // Connect the IO and packet structures
4934 pIo
= pPort
->pRxFree
;
4935 pIo
->pPacket
= pPacket
;
4938 // Eliminate the need for IP4 and UDP4 specific routines by
4939 // clearing the RX data pointer here.
4941 // No driver buffer for this packet
4943 // +--------------------+
4946 // | +---------------+
4948 // | | RxData --> NULL
4949 // +----+---------------+
4951 pBuffer
= (UINT8
*)pIo
;
4952 pBuffer
= &pBuffer
[ pSocket
->pApi
->RxBufferOffset
];
4953 *(VOID
**)pBuffer
= NULL
;
4956 // Network specific receive packet initialization
4958 if ( NULL
!= pSocket
->pApi
->pfnRxStart
) {
4959 pSocket
->pApi
->pfnRxStart ( pPort
, pIo
);
4963 // Start the receive on the packet
4965 Status
= pPort
->pfnRxStart ( pPort
->pProtocol
.v
, &pIo
->Token
);
4966 if ( !EFI_ERROR ( Status
)) {
4967 DEBUG (( DEBUG_RX
| DEBUG_INFO
,
4968 "0x%08x: Packet receive pending on port 0x%08x\r\n",
4972 // Allocate the receive control structure
4974 pPort
->pRxFree
= pIo
->pNext
;
4977 // Mark this receive as pending
4979 pIo
->pNext
= pPort
->pRxActive
;
4980 pPort
->pRxActive
= pIo
;
4984 DEBUG (( DEBUG_RX
| DEBUG_INFO
,
4985 "ERROR - Failed to post a receive on port 0x%08x, Status: %r\r\n",
4988 if ( !EFI_ERROR ( pSocket
->RxError
)) {
4990 // Save the error status
4992 pSocket
->RxError
= Status
;
4998 pIo
->pPacket
= NULL
;
4999 pPacket
->pNext
= pSocket
->pRxFree
;
5000 pSocket
->pRxFree
= pPacket
;
5006 if ( NULL
== pPort
->pRxFree
) {
5007 DEBUG (( DEBUG_RX
| DEBUG_INFO
,
5008 "0x%08x: Port, no available ESL_IO_MGMT structures\r\n",
5011 if ( pSocket
->bRxDisable
) {
5012 DEBUG (( DEBUG_RX
| DEBUG_INFO
,
5013 "0x%08x: Port, receive disabled!\r\n",
5016 if ( PORT_STATE_CLOSE_STARTED
<= pPort
->State
) {
5017 DEBUG (( DEBUG_RX
| DEBUG_INFO
,
5018 "0x%08x: Port, is closing!\r\n",
5024 DEBUG (( DEBUG_ERROR
| DEBUG_RX
,
5025 "ERROR - Previous receive error, Status: %r\r\n",
5026 pPort
->pSocket
->RxError
));
5034 Shutdown the socket receive and transmit operations
5036 This routine sets a flag to stop future transmissions and calls
5037 the network specific layer to cancel the pending receive operation.
5039 The ::shutdown routine calls this routine to stop receive and transmit
5040 operations on the socket.
5042 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
5044 @param [in] How Which operations to stop
5046 @param [out] pErrno Address to receive the errno value upon completion.
5048 @retval EFI_SUCCESS - Socket operations successfully shutdown
5053 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
5060 ESL_SOCKET
* pSocket
;
5062 EFI_TPL TplPrevious
;
5069 Status
= EFI_SUCCESS
;
5072 // Validate the socket
5075 if ( NULL
!= pSocketProtocol
) {
5076 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
5079 // Verify that the socket is connected
5081 if ( pSocket
->bConnected
) {
5083 // Validate the How value
5085 if (( SHUT_RD
<= How
) && ( SHUT_RDWR
>= How
)) {
5087 // Synchronize with the socket layer
5089 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
5092 // Disable the receiver if requested
5094 if (( SHUT_RD
== How
) || ( SHUT_RDWR
== How
)) {
5095 pSocket
->bRxDisable
= TRUE
;
5099 // Disable the transmitter if requested
5101 if (( SHUT_WR
== How
) || ( SHUT_RDWR
== How
)) {
5102 pSocket
->bTxDisable
= TRUE
;
5106 // Cancel the pending receive operations
5108 if ( pSocket
->bRxDisable
) {
5110 // Walk the list of ports
5112 pPort
= pSocket
->pPortList
;
5113 while ( NULL
!= pPort
) {
5115 // Walk the list of active receive operations
5117 pIo
= pPort
->pRxActive
;
5118 while ( NULL
!= pIo
) {
5119 EslSocketRxCancel ( pPort
, pIo
);
5123 // Set the next port
5125 pPort
= pPort
->pLinkSocket
;
5130 // Release the socket layer synchronization
5132 RESTORE_TPL ( TplPrevious
);
5136 // Invalid How value
5138 pSocket
->errno
= EINVAL
;
5139 Status
= EFI_INVALID_PARAMETER
;
5144 // The socket is not connected
5146 pSocket
->errno
= ENOTCONN
;
5147 Status
= EFI_NOT_STARTED
;
5152 // Return the operation status
5154 if ( NULL
!= pErrno
) {
5155 if ( NULL
!= pSocket
) {
5156 *pErrno
= pSocket
->errno
;
5159 Status
= EFI_INVALID_PARAMETER
;
5163 DBG_EXIT_STATUS ( Status
);
5169 Send data using a network connection.
5171 This routine calls the network specific layer to queue the data
5172 for transmission. Eventually the buffer will reach the head of
5173 the queue and will get transmitted over the network by the
5174 \ref TransmitEngine. For datagram
5175 sockets (SOCK_DGRAM and SOCK_RAW) there is no guarantee that
5176 the data reaches the application running on the remote system.
5178 The ::sendto routine calls this routine to send data to the remote
5179 system. Note that ::send and ::write are layered on top of ::sendto.
5181 @param [in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
5183 @param [in] Flags Message control flags
5185 @param [in] BufferLength Length of the the buffer
5187 @param [in] pBuffer Address of a buffer containing the data to send
5189 @param [in] pDataLength Address to receive the number of data bytes sent
5191 @param [in] pAddress Network address of the remote system address
5193 @param [in] AddressLength Length of the remote network address structure
5195 @param [out] pErrno Address to receive the errno value upon completion.
5197 @retval EFI_SUCCESS - Socket data successfully queued for transmit
5202 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
5204 IN
size_t BufferLength
,
5205 IN CONST UINT8
* pBuffer
,
5206 OUT
size_t * pDataLength
,
5207 IN
const struct sockaddr
* pAddress
,
5208 IN socklen_t AddressLength
,
5212 ESL_SOCKET
* pSocket
;
5214 EFI_TPL TplPrevious
;
5221 Status
= EFI_SUCCESS
;
5224 // Validate the socket
5227 if ( NULL
!= pSocketProtocol
) {
5228 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
5231 // Return the transmit error if necessary
5233 if ( EFI_SUCCESS
!= pSocket
->TxError
) {
5234 pSocket
->errno
= EIO
;
5235 Status
= pSocket
->TxError
;
5236 pSocket
->TxError
= EFI_SUCCESS
;
5240 // Verify the socket state
5242 Status
= EslSocketIsConfigured ( pSocket
);
5243 if ( !EFI_ERROR ( Status
)) {
5245 // Verify that transmit is still allowed
5247 if ( !pSocket
->bTxDisable
) {
5249 // Validate the buffer length
5251 if (( NULL
== pDataLength
)
5252 && ( 0 > pDataLength
)
5253 && ( NULL
== pBuffer
)) {
5254 if ( NULL
== pDataLength
) {
5256 "ERROR - pDataLength is NULL!\r\n" ));
5258 else if ( NULL
== pBuffer
) {
5260 "ERROR - pBuffer is NULL!\r\n" ));
5264 "ERROR - Data length < 0!\r\n" ));
5266 Status
= EFI_INVALID_PARAMETER
;
5267 pSocket
->errno
= EFAULT
;
5271 // Validate the remote network address
5273 if (( NULL
!= pAddress
)
5274 && ( AddressLength
< pAddress
->sa_len
)) {
5276 "ERROR - Invalid sin_len field in address\r\n" ));
5277 Status
= EFI_INVALID_PARAMETER
;
5278 pSocket
->errno
= EFAULT
;
5284 if ( NULL
== pSocket
->pApi
->pfnTransmit
) {
5285 Status
= EFI_UNSUPPORTED
;
5286 pSocket
->errno
= ENOTSUP
;
5290 // Synchronize with the socket layer
5292 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
5295 // Attempt to buffer the packet for transmission
5297 Status
= pSocket
->pApi
->pfnTransmit ( pSocket
,
5306 // Release the socket layer synchronization
5308 RESTORE_TPL ( TplPrevious
);
5315 // The transmitter was shutdown
5317 pSocket
->errno
= EPIPE
;
5318 Status
= EFI_NOT_STARTED
;
5325 // Return the operation status
5327 if ( NULL
!= pErrno
) {
5328 if ( NULL
!= pSocket
) {
5329 *pErrno
= pSocket
->errno
;
5332 Status
= EFI_INVALID_PARAMETER
;
5336 DBG_EXIT_STATUS ( Status
);
5342 Complete the transmit operation
5344 This support routine handles the transmit completion processing for
5345 the various network layers. It frees the ::ESL_IO_MGMT structure
5346 and and frees packet resources by calling ::EslSocketPacketFree.
5347 Transmit errors are logged in ESL_SOCKET::TxError.
5348 See the \ref TransmitEngine section.
5350 This routine is called by:
5352 <li>::EslIp4TxComplete</li>
5353 <li>::EslTcp4TxComplete</li>
5354 <li>::EslTcp4TxOobComplete</li>
5355 <li>::EslUdp4TxComplete</li>
5358 @param [in] pIo Address of an ::ESL_IO_MGMT structure
5359 @param [in] LengthInBytes Length of the data in bytes
5360 @param [in] Status Transmit operation status
5361 @param [in] pQueueType Zero terminated string describing queue type
5362 @param [in] ppQueueHead Transmit queue head address
5363 @param [in] ppQueueTail Transmit queue tail address
5364 @param [in] ppActive Active transmit queue address
5365 @param [in] ppFree Free transmit queue address
5369 EslSocketTxComplete (
5370 IN ESL_IO_MGMT
* pIo
,
5371 IN UINT32 LengthInBytes
,
5372 IN EFI_STATUS Status
,
5373 IN CONST CHAR8
* pQueueType
,
5374 IN ESL_PACKET
** ppQueueHead
,
5375 IN ESL_PACKET
** ppQueueTail
,
5376 IN ESL_IO_MGMT
** ppActive
,
5377 IN ESL_IO_MGMT
** ppFree
5380 ESL_PACKET
* pCurrentPacket
;
5381 ESL_IO_MGMT
* pIoNext
;
5382 ESL_PACKET
* pNextPacket
;
5383 ESL_PACKET
* pPacket
;
5385 ESL_SOCKET
* pSocket
;
5388 VERIFY_AT_TPL ( TPL_SOCKETS
);
5391 // Locate the active transmit packet
5393 pPacket
= pIo
->pPacket
;
5395 pSocket
= pPort
->pSocket
;
5400 pIo
->pPacket
= NULL
;
5403 // Remove the IO structure from the active list
5405 pIoNext
= *ppActive
;
5406 while (( NULL
!= pIoNext
) && ( pIoNext
!= pIo
) && ( pIoNext
->pNext
!= pIo
))
5408 pIoNext
= pIoNext
->pNext
;
5410 ASSERT ( NULL
!= pIoNext
);
5411 if ( pIoNext
== pIo
) {
5412 *ppActive
= pIo
->pNext
; // Beginning of list
5415 pIoNext
->pNext
= pIo
->pNext
; // Middle of list
5419 // Free the IO structure
5421 pIo
->pNext
= *ppFree
;
5425 // Display the results
5427 DEBUG (( DEBUG_TX
| DEBUG_INFO
,
5428 "0x%08x: pIo Released\r\n",
5432 // Save any transmit error
5434 if ( EFI_ERROR ( Status
)) {
5435 if ( !EFI_ERROR ( pSocket
->TxError
)) {
5436 pSocket
->TxError
= Status
;
5438 DEBUG (( DEBUG_TX
| DEBUG_INFO
,
5439 "ERROR - Transmit failure for %apacket 0x%08x, Status: %r\r\n",
5445 // Empty the normal transmit list
5447 pCurrentPacket
= pPacket
;
5448 pNextPacket
= *ppQueueHead
;
5449 while ( NULL
!= pNextPacket
) {
5450 pPacket
= pNextPacket
;
5451 pNextPacket
= pPacket
->pNext
;
5452 EslSocketPacketFree ( pPacket
, DEBUG_TX
);
5454 *ppQueueHead
= NULL
;
5455 *ppQueueTail
= NULL
;
5456 pPacket
= pCurrentPacket
;
5459 DEBUG (( DEBUG_TX
| DEBUG_INFO
,
5460 "0x%08x: %apacket transmitted %d bytes successfully\r\n",
5466 // Verify the transmit engine is still running
5468 if ( !pPort
->bCloseNow
) {
5470 // Start the next packet transmission
5472 EslSocketTxStart ( pPort
,
5481 // Release this packet
5483 EslSocketPacketFree ( pPacket
, DEBUG_TX
);
5486 // Finish the close operation if necessary
5488 if ( PORT_STATE_CLOSE_STARTED
<= pPort
->State
) {
5490 // Indicate that the transmit is complete
5492 EslSocketPortCloseTxDone ( pPort
);
5500 Transmit data using a network connection.
5502 This support routine starts a transmit operation on the
5503 underlying network layer.
5505 The network specific code calls this routine to start a
5506 transmit operation. See the \ref TransmitEngine section.
5508 @param [in] pPort Address of an ::ESL_PORT structure
5509 @param [in] ppQueueHead Transmit queue head address
5510 @param [in] ppQueueTail Transmit queue tail address
5511 @param [in] ppActive Active transmit queue address
5512 @param [in] ppFree Free transmit queue address
5517 IN ESL_PORT
* pPort
,
5518 IN ESL_PACKET
** ppQueueHead
,
5519 IN ESL_PACKET
** ppQueueTail
,
5520 IN ESL_IO_MGMT
** ppActive
,
5521 IN ESL_IO_MGMT
** ppFree
5526 ESL_PACKET
* pNextPacket
;
5527 ESL_PACKET
* pPacket
;
5528 VOID
** ppTokenData
;
5529 ESL_SOCKET
* pSocket
;
5537 Status
= EFI_SUCCESS
;
5540 // Get the packet from the queue head
5542 pPacket
= *ppQueueHead
;
5544 if (( NULL
!= pPacket
) && ( NULL
!= pIo
)) {
5545 pSocket
= pPort
->pSocket
;
5547 // *ppQueueHead: pSocket->pRxPacketListHead or pSocket->pRxOobPacketListHead
5550 // +------------+ +------------+ +------------+
5551 // Data | ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL
5552 // +------------+ +------------+ +------------+
5555 // *ppQueueTail: pSocket->pRxPacketListTail or pSocket->pRxOobPacketListTail
5558 // Remove the packet from the queue
5560 pNextPacket
= pPacket
->pNext
;
5561 *ppQueueHead
= pNextPacket
;
5562 if ( NULL
== pNextPacket
) {
5563 *ppQueueTail
= NULL
;
5565 pPacket
->pNext
= NULL
;
5568 // Eliminate the need for IP4 and UDP4 specific routines by
5569 // connecting the token with the TX data control structure here.
5571 // +--------------------+ +--------------------+
5572 // | ESL_IO_MGMT | | ESL_PACKET |
5574 // | +---------------+ +----------------+ |
5575 // | | Token | | Buffer Length | |
5576 // | | TxData --> | Buffer Address | |
5577 // | | | +----------------+---+
5578 // | | Event | | Data Buffer |
5579 // +----+---------------+ | |
5580 // +--------------------+
5582 // Compute the address of the TxData pointer in the token
5584 pBuffer
= (UINT8
*)&pIo
->Token
;
5585 pBuffer
= &pBuffer
[ pSocket
->TxTokenOffset
];
5586 ppTokenData
= (VOID
**)pBuffer
;
5589 // Compute the address of the TX data control structure in the packet
5591 // * EFI_IP4_TRANSMIT_DATA
5592 // * EFI_TCP4_TRANSMIT_DATA
5593 // * EFI_UDP4_TRANSMIT_DATA
5595 pBuffer
= (UINT8
*)pPacket
;
5596 pBuffer
= &pBuffer
[ pSocket
->TxPacketOffset
];
5599 // Connect the token to the transmit data control structure
5601 *ppTokenData
= (VOID
**)pBuffer
;
5604 // Display the results
5606 DEBUG (( DEBUG_TX
| DEBUG_INFO
,
5607 "0x%08x: pIo allocated for pPacket: 0x%08x\r\n",
5612 // Start the transmit operation
5614 Status
= pPort
->pfnTxStart ( pPort
->pProtocol
.v
,
5616 if ( !EFI_ERROR ( Status
)) {
5618 // Connect the structures
5620 pIo
->pPacket
= pPacket
;
5623 // +-------------+ +-------------+ +-------------+
5624 // Free | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
5625 // +-------------+ +-------------+ +-------------+
5628 // *ppFree: pPort->pTxFree or pTxOobFree
5631 // Remove the IO structure from the queue
5633 *ppFree
= pIo
->pNext
;
5636 // *ppActive: pPort->pTxActive or pTxOobActive
5639 // +-------------+ +-------------+ +-------------+
5640 // Active | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
5641 // +-------------+ +-------------+ +-------------+
5644 // Mark this packet as active
5646 pIo
->pPacket
= pPacket
;
5647 pIo
->pNext
= *ppActive
;
5651 if ( EFI_SUCCESS
== pSocket
->TxError
) {
5652 pSocket
->TxError
= Status
;
5656 // Discard the transmit buffer
5658 EslSocketPacketFree ( pPacket
, DEBUG_TX
);