2 Implement the TCP4 driver support for the socket layer.
4 Copyright (c) 2011, Intel Corporation
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14 \section ConnectionManagement Connection Management
16 The ::EslTcp4Listen routine initially places the SOCK_STREAM or
17 SOCK_SEQPACKET socket into a listen state. When a remote machine
18 makes a connection to the socket, the TCPv4 network layer calls
19 ::EslTcp4ListenComplete to complete the connection processing.
20 EslTcp4ListenComplete manages the connections by placing them in
21 FIFO order in a queue to be serviced by the application. When the
22 number of connections exceeds the backlog (ESL_SOCKET::MaxFifoDepth),
23 the new connection is closed. Eventually, the application indirectly
24 calls ::EslTcp4Accept to remove the next connection from the queue
25 and get the associated socket.
33 Attempt to connect to a remote TCP port
35 This routine starts the connection processing for a SOCK_STREAM
36 or SOCK_SEQPAKCET socket using the TCPv4 network layer. It
37 configures the local TCPv4 connection point and then attempts to
38 connect to a remote system. Upon completion, the
39 ::EslTcp4ConnectComplete routine gets called with the connection
42 This routine is called by ::EslSocketConnect to initiate the TCPv4
43 network specific connect operations. The connection processing is
44 initiated by this routine and finished by ::EslTcp4ConnectComplete.
45 This pair of routines walks through the list of local TCPv4
46 connection points until a connection to the remote system is
49 @param [in] pSocket Address of an ::ESL_SOCKET structure.
51 @retval EFI_SUCCESS The connection was successfully established.
52 @retval EFI_NOT_READY The connection is in progress, call this routine again.
53 @retval Others The connection attempt failed.
58 IN ESL_SOCKET
* pSocket
63 Process the connection attempt
65 A system has initiated a connection attempt with a socket in the
66 listen state. Attempt to complete the connection.
68 The TCPv4 layer calls this routine when a connection is made to
69 the socket in the listen state. See the
70 \ref ConnectionManagement section.
72 @param [in] Event The listen completion event
74 @param [in] pPort Address of an ::ESL_PORT structure.
78 EslTcp4ListenComplete (
85 Accept a network connection.
87 This routine waits for a network connection to the socket and
88 returns the remote network address to the caller if requested.
90 This routine is called by ::EslSocketAccept to handle the TCPv4 protocol
91 specific accept operations for SOCK_STREAM and SOCK_SEQPACKET sockets.
92 See the \ref ConnectionManagement section.
94 @param [in] pSocket Address of an ::ESL_SOCKET structure.
96 @param [in] pSockAddr Address of a buffer to receive the remote
99 @param [in, out] pSockAddrLength Length in bytes of the address buffer.
100 On output specifies the length of the
101 remote network address.
103 @retval EFI_SUCCESS Remote address is available
104 @retval Others Remote address not available
109 IN ESL_SOCKET
* pSocket
,
110 IN
struct sockaddr
* pSockAddr
,
111 IN OUT socklen_t
* pSockAddrLength
115 struct sockaddr_in
* pRemoteAddress
;
116 ESL_TCP4_CONTEXT
* pTcp4
;
117 UINT32 RemoteAddress
;
123 // Validate the socket length
125 pRemoteAddress
= (struct sockaddr_in
*) pSockAddr
;
126 if (( NULL
== pSockAddrLength
)
127 || ( sizeof ( *pRemoteAddress
) > *pSockAddrLength
)) {
129 // Invalid socket address
131 Status
= EFI_INVALID_PARAMETER
;
132 pSocket
->errno
= EINVAL
;
133 DEBUG (( DEBUG_ACCEPT
,
134 "ERROR - Invalid address length\r\n" ));
140 Status
= EFI_SUCCESS
;
143 // Locate the address context
145 pPort
= pSocket
->pPortList
;
146 pTcp4
= &pPort
->Context
.Tcp4
;
149 // Fill-in the remote address structure
151 ZeroMem ( pRemoteAddress
, sizeof ( *pRemoteAddress
));
152 pRemoteAddress
->sin_len
= sizeof ( *pRemoteAddress
);
153 pRemoteAddress
->sin_family
= AF_INET
;
154 pRemoteAddress
->sin_port
= SwapBytes16 ( pTcp4
->ConfigData
.AccessPoint
.RemotePort
);
155 RemoteAddress
= pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[3];
157 RemoteAddress
|= pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[2];
159 RemoteAddress
|= pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[1];
161 RemoteAddress
|= pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[0];
162 pRemoteAddress
->sin_addr
.s_addr
= RemoteAddress
;
166 // Return the operation status
168 DBG_EXIT_STATUS ( Status
);
174 Process the remote connection completion event.
176 This routine handles the completion of a connection attempt. It
177 releases the port (TCPv4 adapter connection) in the case of an
178 error and start a connection attempt on the next port. If the
179 connection attempt was successful then this routine releases all
182 This routine is called by the TCPv4 layer when a connect request
183 completes. It sets the ESL_SOCKET::bConnected flag to notify the
184 ::EslTcp4ConnectComplete routine that the connection is available.
185 The flag is set when the connection is established or no more ports
186 exist in the list. The connection status is passed via
187 ESL_SOCKET::ConnectStatus.
189 @param [in] Event The connect completion event
191 @param [in] pPort Address of an ::ESL_PORT structure.
195 EslTcp4ConnectComplete (
200 BOOLEAN bRemoveFirstPort
;
201 BOOLEAN bRemovePorts
;
202 ESL_PORT
* pNextPort
;
203 ESL_SOCKET
* pSocket
;
204 ESL_TCP4_CONTEXT
* pTcp4
;
210 // Locate the TCP context
212 pSocket
= pPort
->pSocket
;
213 pTcp4
= &pPort
->Context
.Tcp4
;
216 // Get the connection status
218 bRemoveFirstPort
= FALSE
;
219 bRemovePorts
= FALSE
;
220 Status
= pTcp4
->ConnectToken
.CompletionToken
.Status
;
221 pSocket
->ConnectStatus
= Status
;
222 if ( !EFI_ERROR ( Status
)) {
224 // The connection was successful
226 DEBUG (( DEBUG_CONNECT
,
227 "0x%08x: Port connected to %d.%d.%d.%d:%d\r\n",
229 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[0],
230 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[1],
231 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[2],
232 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[3],
233 pTcp4
->ConfigData
.AccessPoint
.RemotePort
));
236 // Remove the rest of the ports
242 // The connection failed
244 if ( pPort
->bConfigured
) {
245 DEBUG (( DEBUG_CONNECT
,
246 "0x%08x: Port connection to %d.%d.%d.%d:%d failed, Status: %r\r\n",
248 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[0],
249 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[1],
250 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[2],
251 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[3],
252 pTcp4
->ConfigData
.AccessPoint
.RemotePort
,
257 // Close the current port
259 Status
= EslSocketPortClose ( pPort
);
260 if ( !EFI_ERROR ( Status
)) {
261 DEBUG (( DEBUG_CONNECT
,
262 "0x%08x: Port closed\r\n",
266 DEBUG (( DEBUG_CONNECT
,
267 "ERROR - Failed to close port 0x%08x, Status: %r\r\n",
273 // Try to connect using the next port
275 Status
= EslTcp4ConnectStart ( pSocket
);
276 if ( EFI_NOT_READY
!= Status
) {
277 bRemoveFirstPort
= TRUE
;
282 // Remove the ports if necessary
284 if ( bRemoveFirstPort
|| bRemovePorts
) {
286 // Remove the first port if necessary
288 pPort
= pSocket
->pPortList
;
289 if (( !bRemoveFirstPort
) && ( NULL
!= pPort
)) {
290 pPort
= pPort
->pLinkSocket
;
294 // Remove the rest of the list
296 while ( NULL
!= pPort
) {
297 pNextPort
= pPort
->pLinkSocket
;
298 EslSocketPortClose ( pPort
);
299 if ( !EFI_ERROR ( Status
)) {
300 DEBUG (( DEBUG_CONNECT
,
301 "0x%08x: Port closed\r\n",
305 DEBUG (( DEBUG_CONNECT
,
306 "ERROR - Failed to close port 0x%08x, Status: %r\r\n",
314 // Notify the poll routine
316 pSocket
->bConnected
= TRUE
;
324 Poll for completion of the connection attempt.
326 This routine polls the ESL_SOCKET::bConnected flag to determine
327 when the connection attempt is complete.
329 This routine is called from ::EslSocketConnect to determine when
330 the connection is complete. The ESL_SOCKET::bConnected flag is
331 set by ::EslTcp4ConnectComplete when the TCPv4 layer establishes
332 a connection or runs out of local network adapters. This routine
333 gets the connection status from ESL_SOCKET::ConnectStatus.
335 @param [in] pSocket Address of an ::ESL_SOCKET structure.
337 @retval EFI_SUCCESS The connection was successfully established.
338 @retval EFI_NOT_READY The connection is in progress, call this routine again.
339 @retval Others The connection attempt failed.
344 IN ESL_SOCKET
* pSocket
352 // Determine if the connection is complete
354 if ( !pSocket
->bConnected
) {
358 pSocket
->errno
= EAGAIN
;
359 Status
= EFI_NOT_READY
;
363 // The connection processing is complete
365 pSocket
->bConnected
= FALSE
;
368 // Translate the connection status
370 Status
= pSocket
->ConnectStatus
;
373 case EFI_DEVICE_ERROR
:
374 pSocket
->errno
= EIO
;
378 pSocket
->errno
= ECONNABORTED
;
381 case EFI_ACCESS_DENIED
:
382 pSocket
->errno
= EACCES
;
385 case EFI_CONNECTION_RESET
:
386 pSocket
->errno
= ECONNRESET
;
389 case EFI_INVALID_PARAMETER
:
390 pSocket
->errno
= EADDRNOTAVAIL
;
393 case EFI_HOST_UNREACHABLE
:
394 case EFI_NO_RESPONSE
:
395 pSocket
->errno
= EHOSTUNREACH
;
399 pSocket
->errno
= EAFNOSUPPORT
;
403 case EFI_NETWORK_UNREACHABLE
:
404 pSocket
->errno
= ENETDOWN
;
407 case EFI_OUT_OF_RESOURCES
:
408 pSocket
->errno
= ENOBUFS
;
411 case EFI_PORT_UNREACHABLE
:
412 case EFI_PROTOCOL_UNREACHABLE
:
413 case EFI_CONNECTION_REFUSED
:
414 pSocket
->errno
= ECONNREFUSED
;
419 pSocket
->bConfigured
= TRUE
;
423 pSocket
->errno
= ETIMEDOUT
;
426 case EFI_UNSUPPORTED
:
427 pSocket
->errno
= EOPNOTSUPP
;
432 // Display the translation
434 DEBUG (( DEBUG_CONNECT
,
435 "ERROR - errno: %d, Status: %r\r\n",
441 // Return the initialization status
443 DBG_EXIT_STATUS ( Status
);
449 Attempt to connect to a remote TCP port
451 This routine starts the connection processing for a SOCK_STREAM
452 or SOCK_SEQPAKCET socket using the TCPv4 network layer. It
453 configures the local TCPv4 connection point and then attempts to
454 connect to a remote system. Upon completion, the
455 ::EslTcp4ConnectComplete routine gets called with the connection
458 This routine is called by ::EslSocketConnect to initiate the TCPv4
459 network specific connect operations. The connection processing is
460 initiated by this routine and finished by ::EslTcp4ConnectComplete.
461 This pair of routines walks through the list of local TCPv4
462 connection points until a connection to the remote system is
465 @param [in] pSocket Address of an ::ESL_SOCKET structure.
467 @retval EFI_SUCCESS The connection was successfully established.
468 @retval EFI_NOT_READY The connection is in progress, call this routine again.
469 @retval Others The connection attempt failed.
473 EslTcp4ConnectStart (
474 IN ESL_SOCKET
* pSocket
478 ESL_TCP4_CONTEXT
* pTcp4
;
479 EFI_TCP4_PROTOCOL
* pTcp4Protocol
;
480 EFI_SIMPLE_NETWORK_MODE SnpModeData
;
486 // Determine if any more local adapters are available
488 pPort
= pSocket
->pPortList
;
489 if ( NULL
!= pPort
) {
491 // Configure the port
493 pTcp4
= &pPort
->Context
.Tcp4
;
494 pTcp4
->ConfigData
.AccessPoint
.ActiveFlag
= TRUE
;
495 pTcp4
->ConfigData
.TimeToLive
= 255;
496 pTcp4Protocol
= pPort
->pProtocol
.TCPv4
;
497 Status
= pTcp4Protocol
->Configure ( pTcp4Protocol
,
498 &pTcp4
->ConfigData
);
499 if ( EFI_ERROR ( Status
)) {
500 DEBUG (( DEBUG_CONNECT
,
501 "ERROR - Failed to configure the Tcp4 port, Status: %r\r\n",
505 DEBUG (( DEBUG_CONNECT
,
506 "0x%08x: Port configured\r\n",
508 pPort
->bConfigured
= TRUE
;
511 // Verify the port connection
513 Status
= pTcp4Protocol
->GetModeData ( pTcp4Protocol
,
519 if ( !EFI_ERROR ( Status
)) {
520 if ( SnpModeData
.MediaPresentSupported
521 && ( !SnpModeData
.MediaPresent
)) {
523 // Port is not connected to the network
525 Status
= EFI_NO_MEDIA
;
529 // Attempt the connection to the remote system
531 Status
= pTcp4Protocol
->Connect ( pTcp4Protocol
,
532 &pTcp4
->ConnectToken
);
535 if ( EFI_ERROR ( Status
)) {
539 DEBUG (( DEBUG_CONNECT
,
540 "ERROR - Port 0x%08x not connected, Status: %r\r\n",
545 if ( !EFI_ERROR ( Status
)) {
547 // Connection in progress
549 pSocket
->errno
= EINPROGRESS
;
550 DEBUG (( DEBUG_CONNECT
,
551 "0x%08x: Port attempting connection to %d.%d.%d.%d:%d\r\n",
553 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[0],
554 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[1],
555 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[2],
556 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[3],
557 pTcp4
->ConfigData
.AccessPoint
.RemotePort
));
561 // Error return path is through EslTcp4ConnectComplete to
562 // enable retry on other ports
564 // Status to errno translation gets done in EslTcp4ConnectPoll
566 pTcp4
->ConnectToken
.CompletionToken
.Status
= Status
;
569 // Continue with the next port
571 gBS
->CheckEvent ( pTcp4
->ConnectToken
.CompletionToken
.Event
);
572 gBS
->SignalEvent ( pTcp4
->ConnectToken
.CompletionToken
.Event
);
574 Status
= EFI_NOT_READY
;
578 // No more local adapters available
580 pSocket
->errno
= ENETUNREACH
;
581 Status
= EFI_NO_RESPONSE
;
585 // Return the operation status
587 DBG_EXIT_STATUS ( Status
);
593 Establish the known port to listen for network connections.
595 This routine places the port into a state that enables connection
598 This routine is called by ::EslSocketListen to handle the network
599 specifics of the listen operation for SOCK_STREAM and SOCK_SEQPACKET
600 sockets. See the \ref ConnectionManagement section.
602 @param [in] pSocket Address of an ::ESL_SOCKET structure.
604 @retval EFI_SUCCESS - Socket successfully created
605 @retval Other - Failed to enable the socket for listen
610 IN ESL_SOCKET
* pSocket
613 ESL_PORT
* pNextPort
;
615 ESL_TCP4_CONTEXT
* pTcp4
;
616 EFI_TCP4_PROTOCOL
* pTcp4Protocol
;
622 // Verify the socket layer synchronization
624 VERIFY_TPL ( TPL_SOCKETS
);
627 // Use for/break instead of goto
631 // Assume no ports are available
633 pSocket
->errno
= EOPNOTSUPP
;
634 Status
= EFI_NOT_READY
;
637 // Walk the list of ports
639 pPort
= pSocket
->pPortList
;
640 while ( NULL
!= pPort
) {
647 // Use for/break insteak of goto
651 // Create the listen completion event
653 pTcp4
= &pPort
->Context
.Tcp4
;
654 Status
= gBS
->CreateEvent ( EVT_NOTIFY_SIGNAL
,
656 (EFI_EVENT_NOTIFY
)EslTcp4ListenComplete
,
658 &pTcp4
->ListenToken
.CompletionToken
.Event
);
659 if ( EFI_ERROR ( Status
)) {
660 DEBUG (( DEBUG_ERROR
| DEBUG_LISTEN
,
661 "ERROR - Failed to create the listen completion event, Status: %r\r\n",
663 pSocket
->errno
= ENOMEM
;
667 "0x%08x: Created listen completion event\r\n",
668 pTcp4
->ListenToken
.CompletionToken
.Event
));
671 // Configure the port
673 pTcp4Protocol
= pPort
->pProtocol
.TCPv4
;
674 Status
= pTcp4Protocol
->Configure ( pTcp4Protocol
,
675 &pTcp4
->ConfigData
);
676 if ( EFI_ERROR ( Status
)) {
677 DEBUG (( DEBUG_LISTEN
,
678 "ERROR - Failed to configure the Tcp4 port, Status: %r\r\n",
681 case EFI_ACCESS_DENIED
:
682 pSocket
->errno
= EACCES
;
686 case EFI_DEVICE_ERROR
:
687 pSocket
->errno
= EIO
;
690 case EFI_INVALID_PARAMETER
:
691 pSocket
->errno
= EADDRNOTAVAIL
;
695 pSocket
->errno
= EAFNOSUPPORT
;
698 case EFI_OUT_OF_RESOURCES
:
699 pSocket
->errno
= ENOBUFS
;
702 case EFI_UNSUPPORTED
:
703 pSocket
->errno
= EOPNOTSUPP
;
708 DEBUG (( DEBUG_LISTEN
,
709 "0x%08x: Port configured\r\n",
711 pPort
->bConfigured
= TRUE
;
714 // Start the listen operation on the port
716 Status
= pTcp4Protocol
->Accept ( pTcp4Protocol
,
717 &pTcp4
->ListenToken
);
718 if ( EFI_ERROR ( Status
)) {
719 DEBUG (( DEBUG_LISTEN
,
720 "ERROR - Failed Tcp4 accept, Status: %r\r\n",
723 case EFI_ACCESS_DENIED
:
724 pSocket
->errno
= EACCES
;
728 case EFI_DEVICE_ERROR
:
729 pSocket
->errno
= EIO
;
732 case EFI_INVALID_PARAMETER
:
733 pSocket
->errno
= EADDRNOTAVAIL
;
736 case EFI_NOT_STARTED
:
737 pSocket
->errno
= ENETDOWN
;
740 case EFI_OUT_OF_RESOURCES
:
741 pSocket
->errno
= ENOBUFS
;
746 DEBUG (( DEBUG_LISTEN
,
747 "0x%08x: Listen pending on Port\r\n",
751 // Listen is pending on this port
759 pNextPort
= pPort
->pLinkSocket
;
762 // Close the port upon error
764 if ( EFI_ERROR ( Status
)) {
765 EslSocketPortCloseStart ( pPort
, TRUE
, DEBUG_LISTEN
);
775 // Determine if any ports are in the listen state
777 if ( NULL
== pSocket
->pPortList
) {
779 // No ports in the listen state
781 pSocket
->MaxFifoDepth
= 0;
784 // Return the last error detected
790 // Mark the socket as configured
792 pSocket
->bConfigured
= TRUE
;
793 Status
= EFI_SUCCESS
;
799 DEBUG (( DEBUG_LISTEN
,
800 "0x%08x: pSocket - Listen pending on socket\r\n",
806 // Return the operation status
808 DBG_EXIT_STATUS ( Status
);
814 Process the connection attempt
816 A system has initiated a connection attempt with a socket in the
817 listen state. Attempt to complete the connection.
819 The TCPv4 layer calls this routine when a connection is made to
820 the socket in the listen state. See the
821 \ref ConnectionManagement section.
823 @param [in] Event The listen completion event
825 @param [in] pPort Address of an ::ESL_PORT structure.
829 EslTcp4ListenComplete (
834 EFI_HANDLE ChildHandle
;
835 struct sockaddr_in LocalAddress
;
836 EFI_TCP4_CONFIG_DATA
* pConfigData
;
839 ESL_SOCKET
* pNewSocket
;
840 ESL_SOCKET
* pSocket
;
841 ESL_TCP4_CONTEXT
* pTcp4
;
842 EFI_TCP4_PROTOCOL
* pTcp4Protocol
;
844 EFI_HANDLE TcpPortHandle
;
845 EFI_STATUS TempStatus
;
848 VERIFY_AT_TPL ( TPL_SOCKETS
);
853 Status
= EFI_SUCCESS
;
856 // Determine if this connection fits into the connection FIFO
858 pSocket
= pPort
->pSocket
;
859 TcpPortHandle
= pPort
->Context
.Tcp4
.ListenToken
.NewChildHandle
;
860 if (( SOCKET_STATE_LISTENING
== pSocket
->State
)
861 && ( pSocket
->MaxFifoDepth
> pSocket
->FifoDepth
)) {
863 // Allocate a socket for this connection
867 Status
= EslSocketAllocate ( &ChildHandle
,
870 if ( !EFI_ERROR ( Status
)) {
872 // Clone the socket parameters
874 pNewSocket
->pApi
= pSocket
->pApi
;
875 pNewSocket
->Domain
= pSocket
->Domain
;
876 pNewSocket
->Protocol
= pSocket
->Protocol
;
877 pNewSocket
->Type
= pSocket
->Type
;
880 // Build the local address
882 pTcp4
= &pPort
->Context
.Tcp4
;
883 LocalAddress
.sin_len
= (uint8_t)pNewSocket
->pApi
->MinimumAddressLength
;
884 LocalAddress
.sin_family
= AF_INET
;
885 LocalAddress
.sin_port
= 0;
886 LocalAddress
.sin_addr
.s_addr
= *(UINT32
*)&pTcp4
->ConfigData
.AccessPoint
.StationAddress
.Addr
[0];
889 // Allocate a port for this connection
890 // Note in this instance Configure may not be called with NULL!
892 Status
= EslSocketPortAllocate ( pNewSocket
,
895 (struct sockaddr
*)&LocalAddress
,
899 if ( !EFI_ERROR ( Status
)) {
901 // Restart the listen operation on the port
903 pTcp4Protocol
= pPort
->pProtocol
.TCPv4
;
904 Status
= pTcp4Protocol
->Accept ( pTcp4Protocol
,
905 &pTcp4
->ListenToken
);
908 // Close the TCP port using SocketClose
910 TcpPortHandle
= NULL
;
911 pTcp4
= &pNewPort
->Context
.Tcp4
;
914 // Check for an accept call error
916 if ( !EFI_ERROR ( Status
)) {
918 // Get the port configuration
920 pNewPort
->bConfigured
= TRUE
;
921 pConfigData
= &pTcp4
->ConfigData
;
922 pConfigData
->ControlOption
= &pTcp4
->Option
;
923 pTcp4Protocol
= pNewPort
->pProtocol
.TCPv4
;
924 Status
= pTcp4Protocol
->GetModeData ( pTcp4Protocol
,
930 if ( !EFI_ERROR ( Status
)) {
932 // Add the new socket to the connection FIFO
934 if ( NULL
== pSocket
->pFifoTail
) {
938 pSocket
->pFifoHead
= pNewSocket
;
942 // Add to end of list.
944 pSocket
->pFifoTail
->pNextConnection
= pNewSocket
;
946 pSocket
->pFifoTail
= pNewSocket
;
947 pSocket
->FifoDepth
+= 1;
950 // Update the socket state
952 pNewSocket
->State
= SOCKET_STATE_IN_FIFO
;
955 // Log the connection
957 DEBUG (( DEBUG_CONNECTION
| DEBUG_INFO
,
958 "0x%08x: Socket on port %d.%d.%d.%d:%d connected to %d.%d.%d.%d:%d\r\n",
960 pConfigData
->AccessPoint
.StationAddress
.Addr
[0],
961 pConfigData
->AccessPoint
.StationAddress
.Addr
[1],
962 pConfigData
->AccessPoint
.StationAddress
.Addr
[2],
963 pConfigData
->AccessPoint
.StationAddress
.Addr
[3],
964 pConfigData
->AccessPoint
.StationPort
,
965 pConfigData
->AccessPoint
.RemoteAddress
.Addr
[0],
966 pConfigData
->AccessPoint
.RemoteAddress
.Addr
[1],
967 pConfigData
->AccessPoint
.RemoteAddress
.Addr
[2],
968 pConfigData
->AccessPoint
.RemoteAddress
.Addr
[3],
969 pConfigData
->AccessPoint
.RemotePort
));
970 DEBUG (( DEBUG_CONNECTION
| DEBUG_INFO
,
971 "0x%08x: Listen socket adding socket 0x%08x to FIFO, depth: %d\r\n",
974 pSocket
->FifoDepth
));
977 // Start the receive operation
979 EslSocketRxStart ( pNewPort
);
982 DEBUG (( DEBUG_ERROR
| DEBUG_CONNECTION
| DEBUG_INFO
,
983 "ERROR - GetModeData failed on port 0x%08x, Status: %r\r\n",
990 // The listen failed on this port
992 DEBUG (( DEBUG_LISTEN
| DEBUG_INFO
,
993 "ERROR - Listen failed on port 0x%08x, Status: %r\r\n",
998 // Close the listening port
1000 EslSocketPortCloseStart ( pPort
, TRUE
, DEBUG_LISTEN
);
1005 // Done with the socket if necessary
1007 if ( EFI_ERROR ( Status
)) {
1008 TempStatus
= EslSocketCloseStart ( &pNewSocket
->SocketProtocol
,
1011 ASSERT ( EFI_SUCCESS
== TempStatus
);
1016 DEBUG (( DEBUG_CONNECTION
,
1017 "0x%08x: Socket FIFO full, connection refused\r\n",
1021 // The FIFO is full or the socket is in the wrong state
1023 Status
= EFI_BUFFER_TOO_SMALL
;
1027 // Close the connection if necessary
1029 if (( EFI_ERROR ( Status
))
1030 && ( NULL
== TcpPortHandle
)) {
1032 // TODO: Finish this code path
1033 // The new connection does not fit into the connection FIFO
1037 // Release the resources
1046 Get the local socket address.
1048 This routine returns the IPv4 address and TCP port number associated
1049 with the local socket.
1051 This routine is called by ::EslSocketGetLocalAddress to determine the
1052 network address for the SOCK_STREAM or SOCK_SEQPACKET socket.
1054 @param [in] pPort Address of an ::ESL_PORT structure.
1056 @param [out] pSockAddr Network address to receive the local system address
1060 EslTcp4LocalAddressGet (
1061 IN ESL_PORT
* pPort
,
1062 OUT
struct sockaddr
* pSockAddr
1065 struct sockaddr_in
* pLocalAddress
;
1066 ESL_TCP4_CONTEXT
* pTcp4
;
1071 // Return the local address
1073 pTcp4
= &pPort
->Context
.Tcp4
;
1074 pLocalAddress
= (struct sockaddr_in
*)pSockAddr
;
1075 pLocalAddress
->sin_family
= AF_INET
;
1076 pLocalAddress
->sin_port
= SwapBytes16 ( pTcp4
->ConfigData
.AccessPoint
.StationPort
);
1077 CopyMem ( &pLocalAddress
->sin_addr
,
1078 &pTcp4
->ConfigData
.AccessPoint
.StationAddress
.Addr
[0],
1079 sizeof ( pLocalAddress
->sin_addr
));
1086 Set the local port address.
1088 This routine sets the local port address.
1090 This support routine is called by ::EslSocketPortAllocate.
1092 @param [in] pPort Address of an ESL_PORT 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] bBindTest TRUE = run bind testing
1105 @retval EFI_SUCCESS The operation was successful
1109 EslTcp4LocalAddressSet (
1110 IN ESL_PORT
* pPort
,
1111 IN CONST
struct sockaddr
* pSockAddr
,
1112 IN BOOLEAN bBindTest
1115 EFI_TCP4_ACCESS_POINT
* pAccessPoint
;
1116 CONST
struct sockaddr_in
* pIpAddress
;
1117 CONST UINT8
* pIpv4Address
;
1123 // Validate the address
1125 pIpAddress
= (struct sockaddr_in
*)pSockAddr
;
1126 if ( INADDR_BROADCAST
== pIpAddress
->sin_addr
.s_addr
) {
1128 // The local address must not be the broadcast address
1130 Status
= EFI_INVALID_PARAMETER
;
1131 pPort
->pSocket
->errno
= EADDRNOTAVAIL
;
1135 // Set the local address
1137 pIpv4Address
= (UINT8
*)&pIpAddress
->sin_addr
.s_addr
;
1138 pAccessPoint
= &pPort
->Context
.Tcp4
.ConfigData
.AccessPoint
;
1139 pAccessPoint
->StationAddress
.Addr
[0] = pIpv4Address
[0];
1140 pAccessPoint
->StationAddress
.Addr
[1] = pIpv4Address
[1];
1141 pAccessPoint
->StationAddress
.Addr
[2] = pIpv4Address
[2];
1142 pAccessPoint
->StationAddress
.Addr
[3] = pIpv4Address
[3];
1145 // Determine if the default address is used
1147 pAccessPoint
->UseDefaultAddress
= (BOOLEAN
)( 0 == pIpAddress
->sin_addr
.s_addr
);
1150 // Set the subnet mask
1152 if ( pAccessPoint
->UseDefaultAddress
) {
1153 pAccessPoint
->SubnetMask
.Addr
[0] = 0;
1154 pAccessPoint
->SubnetMask
.Addr
[1] = 0;
1155 pAccessPoint
->SubnetMask
.Addr
[2] = 0;
1156 pAccessPoint
->SubnetMask
.Addr
[3] = 0;
1159 pAccessPoint
->SubnetMask
.Addr
[0] = 0xff;
1160 pAccessPoint
->SubnetMask
.Addr
[1] = ( 128 <= pAccessPoint
->StationAddress
.Addr
[0]) ? 0xff : 0;
1161 pAccessPoint
->SubnetMask
.Addr
[2] = ( 192 <= pAccessPoint
->StationAddress
.Addr
[0]) ? 0xff : 0;
1162 pAccessPoint
->SubnetMask
.Addr
[3] = ( 224 <= pAccessPoint
->StationAddress
.Addr
[0]) ? 0xff : 0;
1166 // Validate the IP address
1168 pAccessPoint
->StationPort
= 0;
1169 Status
= bBindTest
? EslSocketBindTest ( pPort
, EADDRNOTAVAIL
)
1171 if ( !EFI_ERROR ( Status
)) {
1173 // Set the port number
1175 pAccessPoint
->StationPort
= SwapBytes16 ( pIpAddress
->sin_port
);
1176 pPort
->pSocket
->bAddressSet
= TRUE
;
1179 // Display the local address
1181 DEBUG (( DEBUG_BIND
,
1182 "0x%08x: Port, Local TCP4 Address: %d.%d.%d.%d:%d\r\n",
1184 pAccessPoint
->StationAddress
.Addr
[0],
1185 pAccessPoint
->StationAddress
.Addr
[1],
1186 pAccessPoint
->StationAddress
.Addr
[2],
1187 pAccessPoint
->StationAddress
.Addr
[3],
1188 pAccessPoint
->StationPort
));
1193 // Return the operation status
1195 DBG_EXIT_STATUS ( Status
);
1201 Free a receive packet
1203 This routine performs the network specific operations necessary
1204 to free a receive packet.
1206 This routine is called by ::EslSocketPortCloseTxDone to free a
1209 @param [in] pPacket Address of an ::ESL_PACKET structure.
1210 @param [in, out] pRxBytes Address of the count of RX bytes
1215 IN ESL_PACKET
* pPacket
,
1216 IN OUT
size_t * pRxBytes
1222 // Account for the receive bytes
1224 *pRxBytes
-= pPacket
->Op
.Tcp4Rx
.RxData
.DataLength
;
1230 Initialize the network specific portions of an ::ESL_PORT structure.
1232 This routine initializes the network specific portions of an
1233 ::ESL_PORT structure for use by the socket.
1235 This support routine is called by ::EslSocketPortAllocate
1236 to connect the socket with the underlying network adapter
1237 running the TCPv4 protocol.
1239 @param [in] pPort Address of an ESL_PORT structure
1240 @param [in] DebugFlags Flags for debug messages
1242 @retval EFI_SUCCESS - Socket successfully created
1246 EslTcp4PortAllocate (
1247 IN ESL_PORT
* pPort
,
1251 EFI_TCP4_ACCESS_POINT
* pAccessPoint
;
1252 ESL_SOCKET
* pSocket
;
1253 ESL_TCP4_CONTEXT
* pTcp4
;
1259 // Use for/break instead of goto
1262 // Allocate the close event
1264 pSocket
= pPort
->pSocket
;
1265 pTcp4
= &pPort
->Context
.Tcp4
;
1266 Status
= gBS
->CreateEvent ( EVT_NOTIFY_SIGNAL
,
1268 (EFI_EVENT_NOTIFY
)EslSocketPortCloseComplete
,
1270 &pTcp4
->CloseToken
.CompletionToken
.Event
);
1271 if ( EFI_ERROR ( Status
)) {
1272 DEBUG (( DEBUG_ERROR
| DebugFlags
,
1273 "ERROR - Failed to create the close event, Status: %r\r\n",
1275 pSocket
->errno
= ENOMEM
;
1278 DEBUG (( DEBUG_CLOSE
| DEBUG_POOL
,
1279 "0x%08x: Created close event\r\n",
1280 pTcp4
->CloseToken
.CompletionToken
.Event
));
1283 // Allocate the connection event
1285 Status
= gBS
->CreateEvent ( EVT_NOTIFY_SIGNAL
,
1287 (EFI_EVENT_NOTIFY
)EslTcp4ConnectComplete
,
1289 &pTcp4
->ConnectToken
.CompletionToken
.Event
);
1290 if ( EFI_ERROR ( Status
)) {
1291 DEBUG (( DEBUG_ERROR
| DebugFlags
,
1292 "ERROR - Failed to create the connect event, Status: %r\r\n",
1294 pSocket
->errno
= ENOMEM
;
1297 DEBUG (( DEBUG_CLOSE
| DEBUG_POOL
,
1298 "0x%08x: Created connect event\r\n",
1299 pTcp4
->ConnectToken
.CompletionToken
.Event
));
1302 // Initialize the port
1304 pSocket
->TxPacketOffset
= OFFSET_OF ( ESL_PACKET
, Op
.Tcp4Tx
.TxData
);
1305 pSocket
->TxTokenEventOffset
= OFFSET_OF ( ESL_IO_MGMT
, Token
.Tcp4Tx
.CompletionToken
.Event
);
1306 pSocket
->TxTokenOffset
= OFFSET_OF ( EFI_TCP4_IO_TOKEN
, Packet
.TxData
);
1309 // Save the cancel, receive and transmit addresses
1310 // pPort->pfnRxCancel = NULL; since the UEFI implementation returns EFI_UNSUPPORTED
1312 pPort
->pfnConfigure
= (PFN_NET_CONFIGURE
)pPort
->pProtocol
.TCPv4
->Configure
;
1313 pPort
->pfnRxPoll
= (PFN_NET_POLL
)pPort
->pProtocol
.TCPv4
->Poll
;
1314 pPort
->pfnRxStart
= (PFN_NET_IO_START
)pPort
->pProtocol
.TCPv4
->Receive
;
1315 pPort
->pfnTxStart
= (PFN_NET_IO_START
)pPort
->pProtocol
.TCPv4
->Transmit
;
1318 // Set the configuration flags
1320 pAccessPoint
= &pPort
->Context
.Tcp4
.ConfigData
.AccessPoint
;
1321 pAccessPoint
->ActiveFlag
= FALSE
;
1322 pTcp4
->ConfigData
.TimeToLive
= 255;
1327 // Return the operation status
1329 DBG_EXIT_STATUS ( Status
);
1337 This routine releases the network specific resources allocated by
1338 ::EslTcp4PortAllocate.
1340 This routine is called by ::EslSocketPortClose.
1341 See the \ref PortCloseStateMachine section.
1343 @param [in] pPort Address of an ::ESL_PORT structure.
1345 @retval EFI_SUCCESS The port is closed
1346 @retval other Port close error
1355 ESL_TCP4_CONTEXT
* pTcp4
;
1361 // Locate the port in the socket list
1363 Status
= EFI_SUCCESS
;
1364 DebugFlags
= pPort
->DebugFlags
;
1365 pTcp4
= &pPort
->Context
.Tcp4
;
1368 // Done with the connect event
1370 if ( NULL
!= pTcp4
->ConnectToken
.CompletionToken
.Event
) {
1371 Status
= gBS
->CloseEvent ( pTcp4
->ConnectToken
.CompletionToken
.Event
);
1372 if ( !EFI_ERROR ( Status
)) {
1373 DEBUG (( DebugFlags
| DEBUG_POOL
,
1374 "0x%08x: Closed connect event\r\n",
1375 pTcp4
->ConnectToken
.CompletionToken
.Event
));
1378 DEBUG (( DEBUG_ERROR
| DebugFlags
,
1379 "ERROR - Failed to close the connect event, Status: %r\r\n",
1381 ASSERT ( EFI_SUCCESS
== Status
);
1386 // Done with the close event
1388 if ( NULL
!= pTcp4
->CloseToken
.CompletionToken
.Event
) {
1389 Status
= gBS
->CloseEvent ( pTcp4
->CloseToken
.CompletionToken
.Event
);
1390 if ( !EFI_ERROR ( Status
)) {
1391 DEBUG (( DebugFlags
| DEBUG_POOL
,
1392 "0x%08x: Closed close event\r\n",
1393 pTcp4
->CloseToken
.CompletionToken
.Event
));
1396 DEBUG (( DEBUG_ERROR
| DebugFlags
,
1397 "ERROR - Failed to close the close event, Status: %r\r\n",
1399 ASSERT ( EFI_SUCCESS
== Status
);
1404 // Done with the listen completion event
1406 if ( NULL
!= pTcp4
->ListenToken
.CompletionToken
.Event
) {
1407 Status
= gBS
->CloseEvent ( pTcp4
->ListenToken
.CompletionToken
.Event
);
1408 if ( !EFI_ERROR ( Status
)) {
1409 DEBUG (( DebugFlags
| DEBUG_POOL
,
1410 "0x%08x: Closed listen completion event\r\n",
1411 pTcp4
->ListenToken
.CompletionToken
.Event
));
1414 DEBUG (( DEBUG_ERROR
| DebugFlags
,
1415 "ERROR - Failed to close the listen completion event, Status: %r\r\n",
1417 ASSERT ( EFI_SUCCESS
== Status
);
1422 // Return the operation status
1424 DBG_EXIT_STATUS ( Status
);
1430 Perform the network specific close operation on the port.
1432 This routine performs a cancel operations on the TCPv4 port to
1433 shutdown the receive operations on the port.
1435 This routine is called by the ::EslSocketPortCloseTxDone
1436 routine after the port completes all of the transmission.
1438 @param [in] pPort Address of an ::ESL_PORT structure.
1440 @retval EFI_SUCCESS The port is closed, not normally returned
1441 @retval EFI_NOT_READY The port is still closing
1442 @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
1443 most likely the routine was called already.
1447 EslTcp4PortCloseOp (
1451 ESL_TCP4_CONTEXT
* pTcp4
;
1452 EFI_TCP4_PROTOCOL
* pTcp4Protocol
;
1458 // Close the configured port
1460 Status
= EFI_SUCCESS
;
1461 pTcp4
= &pPort
->Context
.Tcp4
;
1462 pTcp4Protocol
= pPort
->pProtocol
.TCPv4
;
1463 pTcp4
->CloseToken
.AbortOnClose
= pPort
->bCloseNow
;
1464 Status
= pTcp4Protocol
->Close ( pTcp4Protocol
,
1465 &pTcp4
->CloseToken
);
1466 if ( !EFI_ERROR ( Status
)) {
1467 DEBUG (( pPort
->DebugFlags
| DEBUG_CLOSE
| DEBUG_INFO
,
1468 "0x%08x: Port close started\r\n",
1472 DEBUG (( DEBUG_ERROR
| pPort
->DebugFlags
| DEBUG_CLOSE
| DEBUG_INFO
,
1473 "ERROR - Close failed on port 0x%08x, Status: %r\r\n",
1479 // Return the operation status
1481 DBG_EXIT_STATUS ( Status
);
1487 Receive data from a network connection.
1489 This routine attempts to return buffered data to the caller. The
1490 data is removed from the urgent queue if the message flag MSG_OOB
1491 is specified, otherwise data is removed from the normal queue.
1492 See the \ref ReceiveEngine section.
1494 This routine is called by ::EslSocketReceive to handle the network
1495 specific receive operation to support SOCK_STREAM and SOCK_SEQPACKET
1498 @param [in] pPort Address of an ::ESL_PORT structure.
1500 @param [in] pPacket Address of an ::ESL_PACKET structure.
1502 @param [in] pbConsumePacket Address of a BOOLEAN indicating if the packet is to be consumed
1504 @param [in] BufferLength Length of the the buffer
1506 @param [in] pBuffer Address of a buffer to receive the data.
1508 @param [in] pDataLength Number of received data bytes in the buffer.
1510 @param [out] pAddress Network address to receive the remote system address
1512 @param [out] pSkipBytes Address to receive the number of bytes skipped
1514 @return Returns the address of the next free byte in the buffer.
1519 IN ESL_PORT
* pPort
,
1520 IN ESL_PACKET
* pPacket
,
1521 IN BOOLEAN
* pbConsumePacket
,
1522 IN
size_t BufferLength
,
1524 OUT
size_t * pDataLength
,
1525 OUT
struct sockaddr
* pAddress
,
1526 OUT
size_t * pSkipBytes
1530 struct sockaddr_in
* pRemoteAddress
;
1531 ESL_TCP4_CONTEXT
* pTcp4
;
1536 // Return the remote system address if requested
1538 if ( NULL
!= pAddress
) {
1540 // Build the remote address
1542 pTcp4
= &pPort
->Context
.Tcp4
;
1544 "Getting packet remote address: %d.%d.%d.%d:%d\r\n",
1545 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[0],
1546 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[1],
1547 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[2],
1548 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[3],
1549 pTcp4
->ConfigData
.AccessPoint
.RemotePort
));
1550 pRemoteAddress
= (struct sockaddr_in
*)pAddress
;
1551 CopyMem ( &pRemoteAddress
->sin_addr
,
1552 &pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[0],
1553 sizeof ( pRemoteAddress
->sin_addr
));
1554 pRemoteAddress
->sin_port
= SwapBytes16 ( pTcp4
->ConfigData
.AccessPoint
.RemotePort
);
1558 // Determine the amount of received data
1560 DataLength
= pPacket
->ValidBytes
;
1561 if ( BufferLength
< DataLength
) {
1562 DataLength
= BufferLength
;
1566 // Move the data into the buffer
1569 "0x%08x: Port copy packet 0x%08x data into 0x%08x, 0x%08x bytes\r\n",
1574 CopyMem ( pBuffer
, pPacket
->pBuffer
, DataLength
);
1577 // Set the next buffer address
1579 pBuffer
+= DataLength
;
1582 // Determine if the data is being read
1584 if ( *pbConsumePacket
) {
1586 // Account for the bytes consumed
1588 pPacket
->pBuffer
+= DataLength
;
1589 pPacket
->ValidBytes
-= DataLength
;
1591 "0x%08x: Port account for 0x%08x bytes\r\n",
1596 // Determine if the entire packet was consumed
1598 if (( 0 == pPacket
->ValidBytes
)
1599 || ( SOCK_STREAM
!= pPort
->pSocket
->Type
)) {
1601 // All done with this packet
1602 // Account for any discarded data
1604 *pSkipBytes
= pPacket
->ValidBytes
;
1609 // More data to consume later
1611 *pbConsumePacket
= FALSE
;
1616 // Return the data length and the buffer address
1618 *pDataLength
= DataLength
;
1619 DBG_EXIT_HEX ( pBuffer
);
1625 Get the remote socket address.
1627 This routine returns the address of the remote connection point
1628 associated with the SOCK_STREAM or SOCK_SEQPACKET socket.
1630 This routine is called by ::EslSocketGetPeerAddress to detemine
1631 the TCPv4 address and por number associated with the network adapter.
1633 @param [in] pPort Address of an ::ESL_PORT structure.
1635 @param [out] pAddress Network address to receive the remote system address
1639 EslTcp4RemoteAddressGet (
1640 IN ESL_PORT
* pPort
,
1641 OUT
struct sockaddr
* pAddress
1644 struct sockaddr_in
* pRemoteAddress
;
1645 ESL_TCP4_CONTEXT
* pTcp4
;
1650 // Return the remote address
1652 pTcp4
= &pPort
->Context
.Tcp4
;
1653 pRemoteAddress
= (struct sockaddr_in
*)pAddress
;
1654 pRemoteAddress
->sin_family
= AF_INET
;
1655 pRemoteAddress
->sin_port
= SwapBytes16 ( pTcp4
->ConfigData
.AccessPoint
.RemotePort
);
1656 CopyMem ( &pRemoteAddress
->sin_addr
,
1657 &pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[0],
1658 sizeof ( pRemoteAddress
->sin_addr
));
1665 Set the remote address
1667 This routine sets the remote address in the port.
1669 This routine is called by ::EslSocketConnect to specify the
1670 remote network address.
1672 @param [in] pPort Address of an ::ESL_PORT structure.
1674 @param [in] pSockAddr Network address of the remote system.
1676 @param [in] SockAddrLength Length in bytes of the network address.
1678 @retval EFI_SUCCESS The operation was successful
1682 EslTcp4RemoteAddressSet (
1683 IN ESL_PORT
* pPort
,
1684 IN CONST
struct sockaddr
* pSockAddr
,
1685 IN socklen_t SockAddrLength
1688 CONST
struct sockaddr_in
* pRemoteAddress
;
1689 ESL_TCP4_CONTEXT
* pTcp4
;
1695 // Set the remote address
1697 pTcp4
= &pPort
->Context
.Tcp4
;
1698 pRemoteAddress
= (struct sockaddr_in
*)pSockAddr
;
1699 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[0] = (UINT8
)( pRemoteAddress
->sin_addr
.s_addr
);
1700 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[1] = (UINT8
)( pRemoteAddress
->sin_addr
.s_addr
>> 8 );
1701 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[2] = (UINT8
)( pRemoteAddress
->sin_addr
.s_addr
>> 16 );
1702 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[3] = (UINT8
)( pRemoteAddress
->sin_addr
.s_addr
>> 24 );
1703 pTcp4
->ConfigData
.AccessPoint
.RemotePort
= SwapBytes16 ( pRemoteAddress
->sin_port
);
1704 Status
= EFI_SUCCESS
;
1705 if ( INADDR_BROADCAST
== pRemoteAddress
->sin_addr
.s_addr
) {
1706 DEBUG (( DEBUG_CONNECT
,
1707 "ERROR - Invalid remote address\r\n" ));
1708 Status
= EFI_INVALID_PARAMETER
;
1709 pPort
->pSocket
->errno
= EAFNOSUPPORT
;
1713 // Return the operation status
1715 DBG_EXIT_STATUS ( Status
);
1721 Process the receive completion
1723 This routine queues the data in FIFO order in either the urgent
1724 or normal data queues depending upon the type of data received.
1725 See the \ref ReceiveEngine section.
1727 This routine is called by the TCPv4 driver when some data is
1730 Buffer the data that was just received.
1732 @param [in] Event The receive completion event
1734 @param [in] pIo Address of an ::ESL_IO_MGMT structure
1740 IN ESL_IO_MGMT
* pIo
1744 size_t LengthInBytes
;
1745 ESL_PACKET
* pPacket
;
1751 // Get the operation status.
1753 Status
= pIo
->Token
.Tcp4Rx
.CompletionToken
.Status
;
1756 // +--------------------+ +---------------------------+
1757 // | ESL_IO_MGMT | | ESL_PACKET |
1759 // | +---------------+ +-----------------------+ |
1760 // | | Token | | EFI_TCP4_RECEIVE_DATA | |
1761 // | | RxData --> | | |
1762 // | | | +-----------------------+---+
1763 // | | Event | | Data Buffer |
1764 // +----+---------------+ | |
1766 // +---------------------------+
1769 // Duplicate the buffer address and length for use by the
1770 // buffer handling code in EslTcp4Receive. These fields are
1771 // used when a partial read is done of the data from the
1774 pPacket
= pIo
->pPacket
;
1775 pPacket
->pBuffer
= pPacket
->Op
.Tcp4Rx
.RxData
.FragmentTable
[0].FragmentBuffer
;
1776 LengthInBytes
= pPacket
->Op
.Tcp4Rx
.RxData
.DataLength
;
1777 pPacket
->ValidBytes
= LengthInBytes
;
1780 // Get the data type so that it may be linked to the
1781 // correct receive buffer list on the ESL_SOCKET structure
1783 bUrgent
= pPacket
->Op
.Tcp4Rx
.RxData
.UrgentFlag
;
1786 // Complete this request
1788 EslSocketRxComplete ( pIo
, Status
, LengthInBytes
, bUrgent
);
1794 Start a receive operation
1796 This routine posts a receive buffer to the TCPv4 driver.
1797 See the \ref ReceiveEngine section.
1799 This support routine is called by EslSocketRxStart.
1801 @param [in] pPort Address of an ::ESL_PORT structure.
1802 @param [in] pIo Address of an ::ESL_IO_MGMT structure.
1807 IN ESL_PORT
* pPort
,
1808 IN ESL_IO_MGMT
* pIo
1811 ESL_PACKET
* pPacket
;
1816 // Initialize the buffer for receive
1818 pPacket
= pIo
->pPacket
;
1819 pIo
->Token
.Tcp4Rx
.Packet
.RxData
= &pPacket
->Op
.Tcp4Rx
.RxData
;
1820 pPacket
->Op
.Tcp4Rx
.RxData
.DataLength
= sizeof ( pPacket
->Op
.Tcp4Rx
.Buffer
);
1821 pPacket
->Op
.Tcp4Rx
.RxData
.FragmentCount
= 1;
1822 pPacket
->Op
.Tcp4Rx
.RxData
.FragmentTable
[0].FragmentLength
= pPacket
->Op
.Tcp4Rx
.RxData
.DataLength
;
1823 pPacket
->Op
.Tcp4Rx
.RxData
.FragmentTable
[0].FragmentBuffer
= &pPacket
->Op
.Tcp4Rx
.Buffer
[0];
1830 Determine if the socket is configured.
1832 This routine uses the flag ESL_SOCKET::bConfigured to determine
1833 if the network layer's configuration routine has been called.
1835 This routine is called by EslSocketIsConfigured to verify
1836 that the socket has been configured.
1838 @param [in] pSocket Address of an ::ESL_SOCKET structure.
1840 @retval EFI_SUCCESS - The port is connected
1841 @retval EFI_NOT_STARTED - The port is not connected
1845 EslTcp4SocketIsConfigured (
1846 IN ESL_SOCKET
* pSocket
1854 // Determine the socket configuration status
1856 Status
= pSocket
->bConfigured
? EFI_SUCCESS
: EFI_NOT_STARTED
;
1859 // Return the port connected state.
1861 DBG_EXIT_STATUS ( Status
);
1867 Buffer data for transmission over a network connection.
1869 This routine buffers data for the transmit engine in one of two
1870 queues, one for urgent (out-of-band) data and the other for normal
1871 data. The urgent data is provided to TCP as soon as it is available,
1872 allowing the TCP layer to schedule transmission of the urgent data
1873 between packets of normal data.
1875 This routine is called by ::EslSocketTransmit to buffer
1876 data for transmission. When the \ref TransmitEngine has resources,
1877 this routine will start the transmission of the next buffer on
1878 the network connection.
1880 Transmission errors are returned during the next transmission or
1881 during the close operation. Only buffering errors are returned
1882 during the current transmission attempt.
1884 @param [in] pSocket Address of an ::ESL_SOCKET structure
1886 @param [in] Flags Message control flags
1888 @param [in] BufferLength Length of the the buffer
1890 @param [in] pBuffer Address of a buffer to receive the data.
1892 @param [in] pDataLength Number of received data bytes in the buffer.
1894 @param [in] pAddress Network address of the remote system address
1896 @param [in] AddressLength Length of the remote network address structure
1898 @retval EFI_SUCCESS - Socket data successfully buffered
1903 IN ESL_SOCKET
* pSocket
,
1905 IN
size_t BufferLength
,
1906 IN CONST UINT8
* pBuffer
,
1907 OUT
size_t * pDataLength
,
1908 IN
const struct sockaddr
* pAddress
,
1909 IN socklen_t AddressLength
1913 BOOLEAN bUrgentQueue
;
1914 ESL_PACKET
* pPacket
;
1915 ESL_IO_MGMT
** ppActive
;
1916 ESL_IO_MGMT
** ppFree
;
1918 ESL_PACKET
** ppQueueHead
;
1919 ESL_PACKET
** ppQueueTail
;
1920 ESL_PACKET
* pPreviousPacket
;
1921 ESL_TCP4_CONTEXT
* pTcp4
;
1923 EFI_TCP4_TRANSMIT_DATA
* pTxData
;
1925 EFI_TPL TplPrevious
;
1932 Status
= EFI_UNSUPPORTED
;
1933 pSocket
->errno
= ENOTCONN
;
1937 // Verify that the socket is connected
1939 if ( SOCKET_STATE_CONNECTED
== pSocket
->State
) {
1943 pPort
= pSocket
->pPortList
;
1944 if ( NULL
!= pPort
) {
1946 // Determine the queue head
1948 pTcp4
= &pPort
->Context
.Tcp4
;
1949 bUrgent
= (BOOLEAN
)( 0 != ( Flags
& MSG_OOB
));
1950 bUrgentQueue
= bUrgent
1951 && ( !pSocket
->bOobInLine
)
1952 && pSocket
->pApi
->bOobSupported
;
1953 if ( bUrgentQueue
) {
1954 ppQueueHead
= &pSocket
->pTxOobPacketListHead
;
1955 ppQueueTail
= &pSocket
->pTxOobPacketListTail
;
1956 ppActive
= &pPort
->pTxOobActive
;
1957 ppFree
= &pPort
->pTxOobFree
;
1958 pTxBytes
= &pSocket
->TxOobBytes
;
1961 ppQueueHead
= &pSocket
->pTxPacketListHead
;
1962 ppQueueTail
= &pSocket
->pTxPacketListTail
;
1963 ppActive
= &pPort
->pTxActive
;
1964 ppFree
= &pPort
->pTxFree
;
1965 pTxBytes
= &pSocket
->TxBytes
;
1969 // Verify that there is enough room to buffer another
1970 // transmit operation
1972 if ( pSocket
->MaxTxBuf
> *pTxBytes
) {
1973 if ( pPort
->bTxFlowControl
) {
1975 "TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT\r\n0x%08x: pPort, TX flow control released, Max bytes: %d > %d bufferred bytes\r\n",
1979 pPort
->bTxFlowControl
= FALSE
;
1983 // Attempt to allocate the packet
1985 Status
= EslSocketPacketAllocate ( &pPacket
,
1986 sizeof ( pPacket
->Op
.Tcp4Tx
)
1987 - sizeof ( pPacket
->Op
.Tcp4Tx
.Buffer
)
1991 if ( !EFI_ERROR ( Status
)) {
1993 // Initialize the transmit operation
1995 pTxData
= &pPacket
->Op
.Tcp4Tx
.TxData
;
1996 pTxData
->Push
= TRUE
|| bUrgent
;
1997 pTxData
->Urgent
= bUrgent
;
1998 pTxData
->DataLength
= (UINT32
) BufferLength
;
1999 pTxData
->FragmentCount
= 1;
2000 pTxData
->FragmentTable
[0].FragmentLength
= (UINT32
) BufferLength
;
2001 pTxData
->FragmentTable
[0].FragmentBuffer
= &pPacket
->Op
.Tcp4Tx
.Buffer
[0];
2004 // Copy the data into the buffer
2006 CopyMem ( &pPacket
->Op
.Tcp4Tx
.Buffer
[0],
2011 // Synchronize with the socket layer
2013 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
2016 // Stop transmission after an error
2018 if ( !EFI_ERROR ( pSocket
->TxError
)) {
2020 // Display the request
2023 "Send %d %s bytes from 0x%08x\r\n",
2025 bUrgent
? L
"urgent" : L
"normal",
2029 // Queue the data for transmission
2031 pPacket
->pNext
= NULL
;
2032 pPreviousPacket
= *ppQueueTail
;
2033 if ( NULL
== pPreviousPacket
) {
2034 *ppQueueHead
= pPacket
;
2037 pPreviousPacket
->pNext
= pPacket
;
2039 *ppQueueTail
= pPacket
;
2041 "0x%08x: Packet on %s transmit list\r\n",
2043 bUrgentQueue
? L
"urgent" : L
"normal" ));
2046 // Account for the buffered data
2048 *pTxBytes
+= BufferLength
;
2049 *pDataLength
= BufferLength
;
2052 // Start the transmit engine if it is idle
2054 if ( NULL
!= *ppFree
) {
2055 EslSocketTxStart ( pPort
,
2064 // Previous transmit error
2065 // Stop transmission
2067 Status
= pSocket
->TxError
;
2068 pSocket
->errno
= EIO
;
2073 EslSocketPacketFree ( pPacket
, DEBUG_TX
);
2077 // Release the socket layer synchronization
2079 RESTORE_TPL ( TplPrevious
);
2083 // Packet allocation failed
2085 pSocket
->errno
= ENOMEM
;
2089 if ( !pPort
->bTxFlowControl
) {
2091 "0x%08x: pPort, TX flow control applied, Max bytes %d <= %d bufferred bytes\r\nTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT\r\n",
2095 pPort
->bTxFlowControl
= TRUE
;
2098 // Not enough buffer space available
2100 pSocket
->errno
= EAGAIN
;
2101 Status
= EFI_NOT_READY
;
2107 // Return the operation status
2109 DBG_EXIT_STATUS ( Status
);
2115 Process the normal data transmit completion
2117 This routine use ::EslSocketTxComplete to perform the transmit
2118 completion processing for normal data.
2120 This routine is called by the TCPv4 network layer when a
2121 normal data transmit request completes.
2123 @param [in] Event The normal transmit completion event
2125 @param [in] pIo The ESL_IO_MGMT structure address
2131 IN ESL_IO_MGMT
* pIo
2134 UINT32 LengthInBytes
;
2135 ESL_PACKET
* pPacket
;
2137 ESL_SOCKET
* pSocket
;
2143 // Locate the active transmit packet
2145 pPacket
= pIo
->pPacket
;
2147 pSocket
= pPort
->pSocket
;
2150 // Get the transmit length and status
2152 LengthInBytes
= pPacket
->Op
.Tcp4Tx
.TxData
.DataLength
;
2153 pSocket
->TxBytes
-= LengthInBytes
;
2154 Status
= pIo
->Token
.Tcp4Tx
.CompletionToken
.Status
;
2157 // Complete the transmit operation
2159 EslSocketTxComplete ( pIo
,
2163 &pSocket
->pTxPacketListHead
,
2164 &pSocket
->pTxPacketListTail
,
2172 Process the urgent data transmit completion
2174 This routine use ::EslSocketTxComplete to perform the transmit
2175 completion processing for urgent data.
2177 This routine is called by the TCPv4 network layer when a
2178 urgent data transmit request completes.
2180 @param [in] Event The urgent transmit completion event
2182 @param [in] pIo The ESL_IO_MGMT structure address
2186 EslTcp4TxOobComplete (
2188 IN ESL_IO_MGMT
* pIo
2191 UINT32 LengthInBytes
;
2192 ESL_PACKET
* pPacket
;
2194 ESL_SOCKET
* pSocket
;
2200 // Locate the active transmit packet
2202 pPacket
= pIo
->pPacket
;
2204 pSocket
= pPort
->pSocket
;
2207 // Get the transmit length and status
2209 LengthInBytes
= pPacket
->Op
.Tcp4Tx
.TxData
.DataLength
;
2210 pSocket
->TxOobBytes
-= LengthInBytes
;
2211 Status
= pIo
->Token
.Tcp4Tx
.CompletionToken
.Status
;
2214 // Complete the transmit operation
2216 EslSocketTxComplete ( pIo
,
2220 &pSocket
->pTxOobPacketListHead
,
2221 &pSocket
->pTxOobPacketListTail
,
2222 &pPort
->pTxOobActive
,
2223 &pPort
->pTxOobFree
);
2229 Verify the adapter's IP address
2231 This support routine is called by EslSocketBindTest.
2233 @param [in] pPort Address of an ::ESL_PORT structure.
2234 @param [in] pConfigData Address of the configuration data
2236 @retval EFI_SUCCESS - The IP address is valid
2237 @retval EFI_NOT_STARTED - The IP address is invalid
2241 EslTcp4VerifyLocalIpAddress (
2242 IN ESL_PORT
* pPort
,
2243 IN EFI_TCP4_CONFIG_DATA
* pConfigData
2247 EFI_TCP4_ACCESS_POINT
* pAccess
;
2248 EFI_IP4_IPCONFIG_DATA
* pIpConfigData
;
2249 EFI_IP4_CONFIG_PROTOCOL
* pIpConfigProtocol
;
2250 ESL_SERVICE
* pService
;
2256 // Use break instead of goto
2258 pIpConfigData
= NULL
;
2261 // Determine if the IP address is specified
2263 pAccess
= &pConfigData
->AccessPoint
;
2264 DEBUG (( DEBUG_BIND
,
2265 "UseDefaultAddress: %s\r\n",
2266 pAccess
->UseDefaultAddress
? L
"TRUE" : L
"FALSE" ));
2267 DEBUG (( DEBUG_BIND
,
2268 "Requested IP address: %d.%d.%d.%d\r\n",
2269 pAccess
->StationAddress
.Addr
[ 0 ],
2270 pAccess
->StationAddress
.Addr
[ 1 ],
2271 pAccess
->StationAddress
.Addr
[ 2 ],
2272 pAccess
->StationAddress
.Addr
[ 3 ]));
2273 if ( pAccess
->UseDefaultAddress
2274 || (( 0 == pAccess
->StationAddress
.Addr
[ 0 ])
2275 && ( 0 == pAccess
->StationAddress
.Addr
[ 1 ])
2276 && ( 0 == pAccess
->StationAddress
.Addr
[ 2 ])
2277 && ( 0 == pAccess
->StationAddress
.Addr
[ 3 ])))
2279 Status
= EFI_SUCCESS
;
2284 // Open the configuration protocol
2286 pService
= pPort
->pService
;
2287 Status
= gBS
->OpenProtocol ( pService
->Controller
,
2288 &gEfiIp4ConfigProtocolGuid
,
2289 (VOID
**)&pIpConfigProtocol
,
2292 EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
2293 if ( EFI_ERROR ( Status
)) {
2294 DEBUG (( DEBUG_ERROR
,
2295 "ERROR - IP Configuration Protocol not available, Status: %r\r\n",
2301 // Get the IP configuration data size
2304 Status
= pIpConfigProtocol
->GetData ( pIpConfigProtocol
,
2307 if ( EFI_BUFFER_TOO_SMALL
!= Status
) {
2308 DEBUG (( DEBUG_ERROR
,
2309 "ERROR - Failed to get IP Configuration data size, Status: %r\r\n",
2315 // Allocate the configuration data buffer
2317 pIpConfigData
= AllocatePool ( DataSize
);
2318 if ( NULL
== pIpConfigData
) {
2319 DEBUG (( DEBUG_ERROR
,
2320 "ERROR - Not enough memory to allocate IP Configuration data!\r\n" ));
2321 Status
= EFI_OUT_OF_RESOURCES
;
2326 // Get the IP configuration
2328 Status
= pIpConfigProtocol
->GetData ( pIpConfigProtocol
,
2331 if ( EFI_ERROR ( Status
)) {
2332 DEBUG (( DEBUG_ERROR
,
2333 "ERROR - Failed to return IP Configuration data, Status: %r\r\n",
2339 // Display the current configuration
2341 DEBUG (( DEBUG_BIND
,
2342 "Actual adapter IP address: %d.%d.%d.%d\r\n",
2343 pIpConfigData
->StationAddress
.Addr
[ 0 ],
2344 pIpConfigData
->StationAddress
.Addr
[ 1 ],
2345 pIpConfigData
->StationAddress
.Addr
[ 2 ],
2346 pIpConfigData
->StationAddress
.Addr
[ 3 ]));
2349 // Assume the port is not configured
2351 Status
= EFI_SUCCESS
;
2352 if (( pAccess
->StationAddress
.Addr
[ 0 ] == pIpConfigData
->StationAddress
.Addr
[ 0 ])
2353 && ( pAccess
->StationAddress
.Addr
[ 1 ] == pIpConfigData
->StationAddress
.Addr
[ 1 ])
2354 && ( pAccess
->StationAddress
.Addr
[ 2 ] == pIpConfigData
->StationAddress
.Addr
[ 2 ])
2355 && ( pAccess
->StationAddress
.Addr
[ 3 ] == pIpConfigData
->StationAddress
.Addr
[ 3 ])) {
2360 // The IP address did not match
2362 Status
= EFI_NOT_STARTED
;
2367 // Free the buffer if necessary
2369 if ( NULL
!= pIpConfigData
) {
2370 FreePool ( pIpConfigData
);
2374 // Return the IP address status
2376 DBG_EXIT_STATUS ( Status
);
2382 Interface between the socket layer and the network specific
2383 code that supports SOCK_STREAM and SOCK_SEQPACKET sockets
2386 CONST ESL_PROTOCOL_API cEslTcp4Api
= {
2389 OFFSET_OF ( ESL_PORT
, Context
.Tcp4
.ConfigData
),
2390 OFFSET_OF ( ESL_LAYER
, pTcp4List
),
2391 OFFSET_OF ( struct sockaddr_in
, sin_zero
),
2392 sizeof ( struct sockaddr_in
),
2394 sizeof (((ESL_PACKET
*)0 )->Op
.Tcp4Rx
),
2395 OFFSET_OF ( ESL_PACKET
, Op
.Tcp4Rx
.Buffer
) - OFFSET_OF ( ESL_PACKET
, Op
),
2396 OFFSET_OF ( ESL_IO_MGMT
, Token
.Tcp4Rx
.Packet
.RxData
),
2401 EslTcp4ConnectStart
,
2402 EslTcp4SocketIsConfigured
,
2403 EslTcp4LocalAddressGet
,
2404 EslTcp4LocalAddressSet
,
2409 EslTcp4PortAllocate
,
2414 EslTcp4RemoteAddressGet
,
2415 EslTcp4RemoteAddressSet
,
2420 EslTcp4TxOobComplete
,
2421 EslTcp4VerifyLocalIpAddress