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 // Start the receive operations
238 pSocket
->bConfigured
= TRUE
;
239 pSocket
->State
= SOCKET_STATE_CONNECTED
;
240 EslSocketRxStart ( pPort
);
243 // Remove the rest of the ports
249 // The connection failed
251 if ( pPort
->bConfigured
) {
252 DEBUG (( DEBUG_CONNECT
,
253 "0x%08x: Port connection to %d.%d.%d.%d:%d failed, Status: %r\r\n",
255 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[0],
256 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[1],
257 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[2],
258 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[3],
259 pTcp4
->ConfigData
.AccessPoint
.RemotePort
,
264 // Close the current port
266 Status
= EslSocketPortClose ( pPort
);
267 if ( !EFI_ERROR ( Status
)) {
268 DEBUG (( DEBUG_CONNECT
,
269 "0x%08x: Port closed\r\n",
273 DEBUG (( DEBUG_CONNECT
,
274 "ERROR - Failed to close port 0x%08x, Status: %r\r\n",
280 // Try to connect using the next port
282 Status
= EslTcp4ConnectStart ( pSocket
);
283 if ( EFI_NOT_READY
!= Status
) {
284 bRemoveFirstPort
= TRUE
;
289 // Remove the ports if necessary
291 if ( bRemoveFirstPort
|| bRemovePorts
) {
293 // Remove the first port if necessary
295 pPort
= pSocket
->pPortList
;
296 if (( !bRemoveFirstPort
) && ( NULL
!= pPort
)) {
297 pPort
= pPort
->pLinkSocket
;
301 // Remove the rest of the list
303 while ( NULL
!= pPort
) {
304 pNextPort
= pPort
->pLinkSocket
;
305 EslSocketPortClose ( pPort
);
306 if ( !EFI_ERROR ( Status
)) {
307 DEBUG (( DEBUG_CONNECT
,
308 "0x%08x: Port closed\r\n",
312 DEBUG (( DEBUG_CONNECT
,
313 "ERROR - Failed to close port 0x%08x, Status: %r\r\n",
321 // Notify the poll routine
323 pSocket
->bConnected
= TRUE
;
331 Poll for completion of the connection attempt.
333 This routine polls the ESL_SOCKET::bConnected flag to determine
334 when the connection attempt is complete.
336 This routine is called from ::EslSocketConnect to determine when
337 the connection is complete. The ESL_SOCKET::bConnected flag is
338 set by ::EslTcp4ConnectComplete when the TCPv4 layer establishes
339 a connection or runs out of local network adapters. This routine
340 gets the connection status from ESL_SOCKET::ConnectStatus.
342 @param [in] pSocket Address of an ::ESL_SOCKET structure.
344 @retval EFI_SUCCESS The connection was successfully established.
345 @retval EFI_NOT_READY The connection is in progress, call this routine again.
346 @retval Others The connection attempt failed.
351 IN ESL_SOCKET
* pSocket
359 // Determine if the connection is complete
361 if ( !pSocket
->bConnected
) {
365 pSocket
->errno
= EAGAIN
;
366 Status
= EFI_NOT_READY
;
370 // The connection processing is complete
372 pSocket
->bConnected
= FALSE
;
375 // Translate the connection status
377 Status
= pSocket
->ConnectStatus
;
380 case EFI_DEVICE_ERROR
:
381 pSocket
->errno
= EIO
;
385 pSocket
->errno
= ECONNABORTED
;
388 case EFI_ACCESS_DENIED
:
389 pSocket
->errno
= EACCES
;
392 case EFI_CONNECTION_RESET
:
393 pSocket
->errno
= ECONNRESET
;
396 case EFI_INVALID_PARAMETER
:
397 pSocket
->errno
= EADDRNOTAVAIL
;
400 case EFI_HOST_UNREACHABLE
:
401 case EFI_NO_RESPONSE
:
402 pSocket
->errno
= EHOSTUNREACH
;
406 pSocket
->errno
= EAFNOSUPPORT
;
410 case EFI_NETWORK_UNREACHABLE
:
411 pSocket
->errno
= ENETDOWN
;
414 case EFI_OUT_OF_RESOURCES
:
415 pSocket
->errno
= ENOBUFS
;
418 case EFI_PORT_UNREACHABLE
:
419 case EFI_PROTOCOL_UNREACHABLE
:
420 case EFI_CONNECTION_REFUSED
:
421 pSocket
->errno
= ECONNREFUSED
;
429 pSocket
->errno
= ETIMEDOUT
;
432 case EFI_UNSUPPORTED
:
433 pSocket
->errno
= EOPNOTSUPP
;
438 // Display the translation
440 DEBUG (( DEBUG_CONNECT
,
441 "ERROR - errno: %d, Status: %r\r\n",
447 // Return the initialization status
449 DBG_EXIT_STATUS ( Status
);
455 Attempt to connect to a remote TCP port
457 This routine starts the connection processing for a SOCK_STREAM
458 or SOCK_SEQPAKCET socket using the TCPv4 network layer. It
459 configures the local TCPv4 connection point and then attempts to
460 connect to a remote system. Upon completion, the
461 ::EslTcp4ConnectComplete routine gets called with the connection
464 This routine is called by ::EslSocketConnect to initiate the TCPv4
465 network specific connect operations. The connection processing is
466 initiated by this routine and finished by ::EslTcp4ConnectComplete.
467 This pair of routines walks through the list of local TCPv4
468 connection points until a connection to the remote system is
471 @param [in] pSocket Address of an ::ESL_SOCKET structure.
473 @retval EFI_SUCCESS The connection was successfully established.
474 @retval EFI_NOT_READY The connection is in progress, call this routine again.
475 @retval Others The connection attempt failed.
479 EslTcp4ConnectStart (
480 IN ESL_SOCKET
* pSocket
484 ESL_TCP4_CONTEXT
* pTcp4
;
485 EFI_TCP4_PROTOCOL
* pTcp4Protocol
;
486 EFI_SIMPLE_NETWORK_MODE SnpModeData
;
492 // Determine if any more local adapters are available
494 pPort
= pSocket
->pPortList
;
495 if ( NULL
!= pPort
) {
497 // Configure the port
499 pTcp4
= &pPort
->Context
.Tcp4
;
500 pTcp4
->ConfigData
.AccessPoint
.ActiveFlag
= TRUE
;
501 pTcp4
->ConfigData
.TimeToLive
= 255;
502 pTcp4Protocol
= pPort
->pProtocol
.TCPv4
;
503 Status
= pTcp4Protocol
->Configure ( pTcp4Protocol
,
504 &pTcp4
->ConfigData
);
505 if ( EFI_ERROR ( Status
)) {
506 DEBUG (( DEBUG_CONNECT
,
507 "ERROR - Failed to configure the Tcp4 port, Status: %r\r\n",
511 DEBUG (( DEBUG_CONNECT
,
512 "0x%08x: Port configured\r\n",
514 pPort
->bConfigured
= TRUE
;
517 // Verify the port connection
519 Status
= pTcp4Protocol
->GetModeData ( pTcp4Protocol
,
525 if ( !EFI_ERROR ( Status
)) {
526 if ( SnpModeData
.MediaPresentSupported
527 && ( !SnpModeData
.MediaPresent
)) {
529 // Port is not connected to the network
531 Status
= EFI_NO_MEDIA
;
535 // Attempt the connection to the remote system
537 Status
= pTcp4Protocol
->Connect ( pTcp4Protocol
,
538 &pTcp4
->ConnectToken
);
541 if ( EFI_ERROR ( Status
)) {
545 DEBUG (( DEBUG_CONNECT
,
546 "ERROR - Port 0x%08x not connected, Status: %r\r\n",
551 if ( !EFI_ERROR ( Status
)) {
553 // Connection in progress
555 pSocket
->errno
= EINPROGRESS
;
556 DEBUG (( DEBUG_CONNECT
,
557 "0x%08x: Port attempting connection to %d.%d.%d.%d:%d\r\n",
559 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[0],
560 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[1],
561 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[2],
562 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[3],
563 pTcp4
->ConfigData
.AccessPoint
.RemotePort
));
567 // Error return path is through EslTcp4ConnectComplete to
568 // enable retry on other ports
570 // Status to errno translation gets done in EslTcp4ConnectPoll
572 pTcp4
->ConnectToken
.CompletionToken
.Status
= Status
;
575 // Continue with the next port
577 gBS
->CheckEvent ( pTcp4
->ConnectToken
.CompletionToken
.Event
);
578 gBS
->SignalEvent ( pTcp4
->ConnectToken
.CompletionToken
.Event
);
580 Status
= EFI_NOT_READY
;
584 // No more local adapters available
586 pSocket
->errno
= ENETUNREACH
;
587 Status
= EFI_NO_RESPONSE
;
591 // Return the operation status
593 DBG_EXIT_STATUS ( Status
);
599 Establish the known port to listen for network connections.
601 This routine places the port into a state that enables connection
604 This routine is called by ::EslSocketListen to handle the network
605 specifics of the listen operation for SOCK_STREAM and SOCK_SEQPACKET
606 sockets. See the \ref ConnectionManagement section.
608 @param [in] pSocket Address of an ::ESL_SOCKET structure.
610 @retval EFI_SUCCESS - Socket successfully created
611 @retval Other - Failed to enable the socket for listen
616 IN ESL_SOCKET
* pSocket
619 ESL_PORT
* pNextPort
;
621 ESL_TCP4_CONTEXT
* pTcp4
;
622 EFI_TCP4_PROTOCOL
* pTcp4Protocol
;
628 // Verify the socket layer synchronization
630 VERIFY_TPL ( TPL_SOCKETS
);
633 // Use for/break instead of goto
637 // Assume no ports are available
639 pSocket
->errno
= EOPNOTSUPP
;
640 Status
= EFI_NOT_READY
;
643 // Walk the list of ports
645 pPort
= pSocket
->pPortList
;
646 while ( NULL
!= pPort
) {
653 // Use for/break insteak of goto
657 // Create the listen completion event
659 pTcp4
= &pPort
->Context
.Tcp4
;
660 Status
= gBS
->CreateEvent ( EVT_NOTIFY_SIGNAL
,
662 (EFI_EVENT_NOTIFY
)EslTcp4ListenComplete
,
664 &pTcp4
->ListenToken
.CompletionToken
.Event
);
665 if ( EFI_ERROR ( Status
)) {
666 DEBUG (( DEBUG_ERROR
| DEBUG_LISTEN
,
667 "ERROR - Failed to create the listen completion event, Status: %r\r\n",
669 pSocket
->errno
= ENOMEM
;
673 "0x%08x: Created listen completion event\r\n",
674 pTcp4
->ListenToken
.CompletionToken
.Event
));
677 // Configure the port
679 pTcp4Protocol
= pPort
->pProtocol
.TCPv4
;
680 Status
= pTcp4Protocol
->Configure ( pTcp4Protocol
,
681 &pTcp4
->ConfigData
);
682 if ( EFI_ERROR ( Status
)) {
683 DEBUG (( DEBUG_LISTEN
,
684 "ERROR - Failed to configure the Tcp4 port, Status: %r\r\n",
687 case EFI_ACCESS_DENIED
:
688 pSocket
->errno
= EACCES
;
692 case EFI_DEVICE_ERROR
:
693 pSocket
->errno
= EIO
;
696 case EFI_INVALID_PARAMETER
:
697 pSocket
->errno
= EADDRNOTAVAIL
;
701 pSocket
->errno
= EAFNOSUPPORT
;
704 case EFI_OUT_OF_RESOURCES
:
705 pSocket
->errno
= ENOBUFS
;
708 case EFI_UNSUPPORTED
:
709 pSocket
->errno
= EOPNOTSUPP
;
714 DEBUG (( DEBUG_LISTEN
,
715 "0x%08x: Port configured\r\n",
717 pPort
->bConfigured
= TRUE
;
720 // Start the listen operation on the port
722 Status
= pTcp4Protocol
->Accept ( pTcp4Protocol
,
723 &pTcp4
->ListenToken
);
724 if ( EFI_ERROR ( Status
)) {
725 DEBUG (( DEBUG_LISTEN
,
726 "ERROR - Failed Tcp4 accept, Status: %r\r\n",
729 case EFI_ACCESS_DENIED
:
730 pSocket
->errno
= EACCES
;
734 case EFI_DEVICE_ERROR
:
735 pSocket
->errno
= EIO
;
738 case EFI_INVALID_PARAMETER
:
739 pSocket
->errno
= EADDRNOTAVAIL
;
742 case EFI_NOT_STARTED
:
743 pSocket
->errno
= ENETDOWN
;
746 case EFI_OUT_OF_RESOURCES
:
747 pSocket
->errno
= ENOBUFS
;
752 DEBUG (( DEBUG_LISTEN
,
753 "0x%08x: Listen pending on Port\r\n",
757 // Listen is pending on this port
765 pNextPort
= pPort
->pLinkSocket
;
768 // Close the port upon error
770 if ( EFI_ERROR ( Status
)) {
771 EslSocketPortCloseStart ( pPort
, TRUE
, DEBUG_LISTEN
);
781 // Determine if any ports are in the listen state
783 if ( NULL
== pSocket
->pPortList
) {
785 // No ports in the listen state
787 pSocket
->MaxFifoDepth
= 0;
790 // Return the last error detected
796 // Mark the socket as configured
798 pSocket
->bConfigured
= TRUE
;
799 Status
= EFI_SUCCESS
;
805 DEBUG (( DEBUG_LISTEN
,
806 "0x%08x: pSocket - Listen pending on socket\r\n",
812 // Return the operation status
814 DBG_EXIT_STATUS ( Status
);
820 Process the connection attempt
822 A system has initiated a connection attempt with a socket in the
823 listen state. Attempt to complete the connection.
825 The TCPv4 layer calls this routine when a connection is made to
826 the socket in the listen state. See the
827 \ref ConnectionManagement section.
829 @param [in] Event The listen completion event
831 @param [in] pPort Address of an ::ESL_PORT structure.
835 EslTcp4ListenComplete (
840 EFI_HANDLE ChildHandle
;
841 struct sockaddr_in LocalAddress
;
842 EFI_TCP4_CONFIG_DATA
* pConfigData
;
845 ESL_SOCKET
* pNewSocket
;
846 ESL_SOCKET
* pSocket
;
847 ESL_TCP4_CONTEXT
* pTcp4
;
848 EFI_TCP4_PROTOCOL
* pTcp4Protocol
;
850 EFI_HANDLE TcpPortHandle
;
851 EFI_STATUS TempStatus
;
854 VERIFY_AT_TPL ( TPL_SOCKETS
);
859 Status
= EFI_SUCCESS
;
862 // Determine if this connection fits into the connection FIFO
864 pSocket
= pPort
->pSocket
;
865 TcpPortHandle
= pPort
->Context
.Tcp4
.ListenToken
.NewChildHandle
;
866 if (( SOCKET_STATE_LISTENING
== pSocket
->State
)
867 && ( pSocket
->MaxFifoDepth
> pSocket
->FifoDepth
)) {
869 // Allocate a socket for this connection
873 Status
= EslSocketAllocate ( &ChildHandle
,
876 if ( !EFI_ERROR ( Status
)) {
878 // Clone the socket parameters
880 pNewSocket
->pApi
= pSocket
->pApi
;
881 pNewSocket
->Domain
= pSocket
->Domain
;
882 pNewSocket
->Protocol
= pSocket
->Protocol
;
883 pNewSocket
->Type
= pSocket
->Type
;
886 // Build the local address
888 pTcp4
= &pPort
->Context
.Tcp4
;
889 LocalAddress
.sin_len
= (uint8_t)pNewSocket
->pApi
->MinimumAddressLength
;
890 LocalAddress
.sin_family
= AF_INET
;
891 LocalAddress
.sin_port
= 0;
892 LocalAddress
.sin_addr
.s_addr
= *(UINT32
*)&pTcp4
->ConfigData
.AccessPoint
.StationAddress
.Addr
[0];
895 // Allocate a port for this connection
896 // Note in this instance Configure may not be called with NULL!
898 Status
= EslSocketPortAllocate ( pNewSocket
,
901 (struct sockaddr
*)&LocalAddress
,
905 if ( !EFI_ERROR ( Status
)) {
907 // Restart the listen operation on the port
909 pTcp4Protocol
= pPort
->pProtocol
.TCPv4
;
910 Status
= pTcp4Protocol
->Accept ( pTcp4Protocol
,
911 &pTcp4
->ListenToken
);
914 // Close the TCP port using SocketClose
916 TcpPortHandle
= NULL
;
917 pTcp4
= &pNewPort
->Context
.Tcp4
;
920 // Check for an accept call error
922 if ( !EFI_ERROR ( Status
)) {
924 // Get the port configuration
926 pNewPort
->bConfigured
= TRUE
;
927 pConfigData
= &pTcp4
->ConfigData
;
928 pConfigData
->ControlOption
= &pTcp4
->Option
;
929 pTcp4Protocol
= pNewPort
->pProtocol
.TCPv4
;
930 Status
= pTcp4Protocol
->GetModeData ( pTcp4Protocol
,
936 if ( !EFI_ERROR ( Status
)) {
938 // Add the new socket to the connection FIFO
940 if ( NULL
== pSocket
->pFifoTail
) {
944 pSocket
->pFifoHead
= pNewSocket
;
948 // Add to end of list.
950 pSocket
->pFifoTail
->pNextConnection
= pNewSocket
;
952 pSocket
->pFifoTail
= pNewSocket
;
953 pSocket
->FifoDepth
+= 1;
956 // Update the socket state
958 pNewSocket
->State
= SOCKET_STATE_IN_FIFO
;
961 // Log the connection
963 DEBUG (( DEBUG_CONNECTION
| DEBUG_INFO
,
964 "0x%08x: Socket on port %d.%d.%d.%d:%d connected to %d.%d.%d.%d:%d\r\n",
966 pConfigData
->AccessPoint
.StationAddress
.Addr
[0],
967 pConfigData
->AccessPoint
.StationAddress
.Addr
[1],
968 pConfigData
->AccessPoint
.StationAddress
.Addr
[2],
969 pConfigData
->AccessPoint
.StationAddress
.Addr
[3],
970 pConfigData
->AccessPoint
.StationPort
,
971 pConfigData
->AccessPoint
.RemoteAddress
.Addr
[0],
972 pConfigData
->AccessPoint
.RemoteAddress
.Addr
[1],
973 pConfigData
->AccessPoint
.RemoteAddress
.Addr
[2],
974 pConfigData
->AccessPoint
.RemoteAddress
.Addr
[3],
975 pConfigData
->AccessPoint
.RemotePort
));
976 DEBUG (( DEBUG_CONNECTION
| DEBUG_INFO
,
977 "0x%08x: Listen socket adding socket 0x%08x to FIFO, depth: %d\r\n",
980 pSocket
->FifoDepth
));
983 // Start the receive operation
985 EslSocketRxStart ( pNewPort
);
988 DEBUG (( DEBUG_ERROR
| DEBUG_CONNECTION
| DEBUG_INFO
,
989 "ERROR - GetModeData failed on port 0x%08x, Status: %r\r\n",
996 // The listen failed on this port
998 DEBUG (( DEBUG_LISTEN
| DEBUG_INFO
,
999 "ERROR - Listen failed on port 0x%08x, Status: %r\r\n",
1004 // Close the listening port
1006 EslSocketPortCloseStart ( pPort
, TRUE
, DEBUG_LISTEN
);
1011 // Done with the socket if necessary
1013 if ( EFI_ERROR ( Status
)) {
1014 TempStatus
= EslSocketCloseStart ( &pNewSocket
->SocketProtocol
,
1017 ASSERT ( EFI_SUCCESS
== TempStatus
);
1022 DEBUG (( DEBUG_CONNECTION
,
1023 "0x%08x: Socket FIFO full, connection refused\r\n",
1027 // The FIFO is full or the socket is in the wrong state
1029 Status
= EFI_BUFFER_TOO_SMALL
;
1033 // Close the connection if necessary
1035 if (( EFI_ERROR ( Status
))
1036 && ( NULL
== TcpPortHandle
)) {
1038 // TODO: Finish this code path
1039 // The new connection does not fit into the connection FIFO
1043 // Release the resources
1052 Get the local socket address.
1054 This routine returns the IPv4 address and TCP port number associated
1055 with the local socket.
1057 This routine is called by ::EslSocketGetLocalAddress to determine the
1058 network address for the SOCK_STREAM or SOCK_SEQPACKET socket.
1060 @param [in] pPort Address of an ::ESL_PORT structure.
1062 @param [out] pSockAddr Network address to receive the local system address
1066 EslTcp4LocalAddressGet (
1067 IN ESL_PORT
* pPort
,
1068 OUT
struct sockaddr
* pSockAddr
1071 struct sockaddr_in
* pLocalAddress
;
1072 ESL_TCP4_CONTEXT
* pTcp4
;
1077 // Return the local address
1079 pTcp4
= &pPort
->Context
.Tcp4
;
1080 pLocalAddress
= (struct sockaddr_in
*)pSockAddr
;
1081 pLocalAddress
->sin_family
= AF_INET
;
1082 pLocalAddress
->sin_port
= SwapBytes16 ( pTcp4
->ConfigData
.AccessPoint
.StationPort
);
1083 CopyMem ( &pLocalAddress
->sin_addr
,
1084 &pTcp4
->ConfigData
.AccessPoint
.StationAddress
.Addr
[0],
1085 sizeof ( pLocalAddress
->sin_addr
));
1092 Set the local port address.
1094 This routine sets the local port address.
1096 This support routine is called by ::EslSocketPortAllocate.
1098 @param [in] pPort Address of an ESL_PORT structure
1099 @param [in] pSockAddr Address of a sockaddr structure that contains the
1100 connection point on the local machine. An IPv4 address
1101 of INADDR_ANY specifies that the connection is made to
1102 all of the network stacks on the platform. Specifying a
1103 specific IPv4 address restricts the connection to the
1104 network stack supporting that address. Specifying zero
1105 for the port causes the network layer to assign a port
1106 number from the dynamic range. Specifying a specific
1107 port number causes the network layer to use that port.
1109 @param [in] bBindTest TRUE = run bind testing
1111 @retval EFI_SUCCESS The operation was successful
1115 EslTcp4LocalAddressSet (
1116 IN ESL_PORT
* pPort
,
1117 IN CONST
struct sockaddr
* pSockAddr
,
1118 IN BOOLEAN bBindTest
1121 EFI_TCP4_ACCESS_POINT
* pAccessPoint
;
1122 CONST
struct sockaddr_in
* pIpAddress
;
1123 CONST UINT8
* pIpv4Address
;
1129 // Validate the address
1131 pIpAddress
= (struct sockaddr_in
*)pSockAddr
;
1132 if ( INADDR_BROADCAST
== pIpAddress
->sin_addr
.s_addr
) {
1134 // The local address must not be the broadcast address
1136 Status
= EFI_INVALID_PARAMETER
;
1137 pPort
->pSocket
->errno
= EADDRNOTAVAIL
;
1141 // Set the local address
1143 pIpv4Address
= (UINT8
*)&pIpAddress
->sin_addr
.s_addr
;
1144 pAccessPoint
= &pPort
->Context
.Tcp4
.ConfigData
.AccessPoint
;
1145 pAccessPoint
->StationAddress
.Addr
[0] = pIpv4Address
[0];
1146 pAccessPoint
->StationAddress
.Addr
[1] = pIpv4Address
[1];
1147 pAccessPoint
->StationAddress
.Addr
[2] = pIpv4Address
[2];
1148 pAccessPoint
->StationAddress
.Addr
[3] = pIpv4Address
[3];
1151 // Determine if the default address is used
1153 pAccessPoint
->UseDefaultAddress
= (BOOLEAN
)( 0 == pIpAddress
->sin_addr
.s_addr
);
1156 // Set the subnet mask
1158 if ( pAccessPoint
->UseDefaultAddress
) {
1159 pAccessPoint
->SubnetMask
.Addr
[0] = 0;
1160 pAccessPoint
->SubnetMask
.Addr
[1] = 0;
1161 pAccessPoint
->SubnetMask
.Addr
[2] = 0;
1162 pAccessPoint
->SubnetMask
.Addr
[3] = 0;
1165 pAccessPoint
->SubnetMask
.Addr
[0] = 0xff;
1166 pAccessPoint
->SubnetMask
.Addr
[1] = ( 128 <= pAccessPoint
->StationAddress
.Addr
[0]) ? 0xff : 0;
1167 pAccessPoint
->SubnetMask
.Addr
[2] = ( 192 <= pAccessPoint
->StationAddress
.Addr
[0]) ? 0xff : 0;
1168 pAccessPoint
->SubnetMask
.Addr
[3] = ( 224 <= pAccessPoint
->StationAddress
.Addr
[0]) ? 0xff : 0;
1172 // Validate the IP address
1174 pAccessPoint
->StationPort
= 0;
1175 Status
= bBindTest
? EslSocketBindTest ( pPort
, EADDRNOTAVAIL
)
1177 if ( !EFI_ERROR ( Status
)) {
1179 // Set the port number
1181 pAccessPoint
->StationPort
= SwapBytes16 ( pIpAddress
->sin_port
);
1182 pPort
->pSocket
->bAddressSet
= TRUE
;
1185 // Display the local address
1187 DEBUG (( DEBUG_BIND
,
1188 "0x%08x: Port, Local TCP4 Address: %d.%d.%d.%d:%d\r\n",
1190 pAccessPoint
->StationAddress
.Addr
[0],
1191 pAccessPoint
->StationAddress
.Addr
[1],
1192 pAccessPoint
->StationAddress
.Addr
[2],
1193 pAccessPoint
->StationAddress
.Addr
[3],
1194 pAccessPoint
->StationPort
));
1199 // Return the operation status
1201 DBG_EXIT_STATUS ( Status
);
1207 Free a receive packet
1209 This routine performs the network specific operations necessary
1210 to free a receive packet.
1212 This routine is called by ::EslSocketPortCloseTxDone to free a
1215 @param [in] pPacket Address of an ::ESL_PACKET structure.
1216 @param [in, out] pRxBytes Address of the count of RX bytes
1221 IN ESL_PACKET
* pPacket
,
1222 IN OUT
size_t * pRxBytes
1228 // Account for the receive bytes
1230 *pRxBytes
-= pPacket
->Op
.Tcp4Rx
.RxData
.DataLength
;
1236 Initialize the network specific portions of an ::ESL_PORT structure.
1238 This routine initializes the network specific portions of an
1239 ::ESL_PORT structure for use by the socket.
1241 This support routine is called by ::EslSocketPortAllocate
1242 to connect the socket with the underlying network adapter
1243 running the TCPv4 protocol.
1245 @param [in] pPort Address of an ESL_PORT structure
1246 @param [in] DebugFlags Flags for debug messages
1248 @retval EFI_SUCCESS - Socket successfully created
1252 EslTcp4PortAllocate (
1253 IN ESL_PORT
* pPort
,
1257 EFI_TCP4_ACCESS_POINT
* pAccessPoint
;
1258 ESL_SOCKET
* pSocket
;
1259 ESL_TCP4_CONTEXT
* pTcp4
;
1265 // Use for/break instead of goto
1268 // Allocate the close event
1270 pSocket
= pPort
->pSocket
;
1271 pTcp4
= &pPort
->Context
.Tcp4
;
1272 Status
= gBS
->CreateEvent ( EVT_NOTIFY_SIGNAL
,
1274 (EFI_EVENT_NOTIFY
)EslSocketPortCloseComplete
,
1276 &pTcp4
->CloseToken
.CompletionToken
.Event
);
1277 if ( EFI_ERROR ( Status
)) {
1278 DEBUG (( DEBUG_ERROR
| DebugFlags
,
1279 "ERROR - Failed to create the close event, Status: %r\r\n",
1281 pSocket
->errno
= ENOMEM
;
1284 DEBUG (( DEBUG_CLOSE
| DEBUG_POOL
,
1285 "0x%08x: Created close event\r\n",
1286 pTcp4
->CloseToken
.CompletionToken
.Event
));
1289 // Allocate the connection event
1291 Status
= gBS
->CreateEvent ( EVT_NOTIFY_SIGNAL
,
1293 (EFI_EVENT_NOTIFY
)EslTcp4ConnectComplete
,
1295 &pTcp4
->ConnectToken
.CompletionToken
.Event
);
1296 if ( EFI_ERROR ( Status
)) {
1297 DEBUG (( DEBUG_ERROR
| DebugFlags
,
1298 "ERROR - Failed to create the connect event, Status: %r\r\n",
1300 pSocket
->errno
= ENOMEM
;
1303 DEBUG (( DEBUG_CLOSE
| DEBUG_POOL
,
1304 "0x%08x: Created connect event\r\n",
1305 pTcp4
->ConnectToken
.CompletionToken
.Event
));
1308 // Initialize the port
1310 pSocket
->TxPacketOffset
= OFFSET_OF ( ESL_PACKET
, Op
.Tcp4Tx
.TxData
);
1311 pSocket
->TxTokenEventOffset
= OFFSET_OF ( ESL_IO_MGMT
, Token
.Tcp4Tx
.CompletionToken
.Event
);
1312 pSocket
->TxTokenOffset
= OFFSET_OF ( EFI_TCP4_IO_TOKEN
, Packet
.TxData
);
1315 // Save the cancel, receive and transmit addresses
1316 // pPort->pfnRxCancel = NULL; since the UEFI implementation returns EFI_UNSUPPORTED
1318 pPort
->pfnConfigure
= (PFN_NET_CONFIGURE
)pPort
->pProtocol
.TCPv4
->Configure
;
1319 pPort
->pfnRxPoll
= (PFN_NET_POLL
)pPort
->pProtocol
.TCPv4
->Poll
;
1320 pPort
->pfnRxStart
= (PFN_NET_IO_START
)pPort
->pProtocol
.TCPv4
->Receive
;
1321 pPort
->pfnTxStart
= (PFN_NET_IO_START
)pPort
->pProtocol
.TCPv4
->Transmit
;
1324 // Set the configuration flags
1326 pAccessPoint
= &pPort
->Context
.Tcp4
.ConfigData
.AccessPoint
;
1327 pAccessPoint
->ActiveFlag
= FALSE
;
1328 pTcp4
->ConfigData
.TimeToLive
= 255;
1333 // Return the operation status
1335 DBG_EXIT_STATUS ( Status
);
1343 This routine releases the network specific resources allocated by
1344 ::EslTcp4PortAllocate.
1346 This routine is called by ::EslSocketPortClose.
1347 See the \ref PortCloseStateMachine section.
1349 @param [in] pPort Address of an ::ESL_PORT structure.
1351 @retval EFI_SUCCESS The port is closed
1352 @retval other Port close error
1361 ESL_TCP4_CONTEXT
* pTcp4
;
1367 // Locate the port in the socket list
1369 Status
= EFI_SUCCESS
;
1370 DebugFlags
= pPort
->DebugFlags
;
1371 pTcp4
= &pPort
->Context
.Tcp4
;
1374 // Done with the connect event
1376 if ( NULL
!= pTcp4
->ConnectToken
.CompletionToken
.Event
) {
1377 Status
= gBS
->CloseEvent ( pTcp4
->ConnectToken
.CompletionToken
.Event
);
1378 if ( !EFI_ERROR ( Status
)) {
1379 DEBUG (( DebugFlags
| DEBUG_POOL
,
1380 "0x%08x: Closed connect event\r\n",
1381 pTcp4
->ConnectToken
.CompletionToken
.Event
));
1384 DEBUG (( DEBUG_ERROR
| DebugFlags
,
1385 "ERROR - Failed to close the connect event, Status: %r\r\n",
1387 ASSERT ( EFI_SUCCESS
== Status
);
1392 // Done with the close event
1394 if ( NULL
!= pTcp4
->CloseToken
.CompletionToken
.Event
) {
1395 Status
= gBS
->CloseEvent ( pTcp4
->CloseToken
.CompletionToken
.Event
);
1396 if ( !EFI_ERROR ( Status
)) {
1397 DEBUG (( DebugFlags
| DEBUG_POOL
,
1398 "0x%08x: Closed close event\r\n",
1399 pTcp4
->CloseToken
.CompletionToken
.Event
));
1402 DEBUG (( DEBUG_ERROR
| DebugFlags
,
1403 "ERROR - Failed to close the close event, Status: %r\r\n",
1405 ASSERT ( EFI_SUCCESS
== Status
);
1410 // Done with the listen completion event
1412 if ( NULL
!= pTcp4
->ListenToken
.CompletionToken
.Event
) {
1413 Status
= gBS
->CloseEvent ( pTcp4
->ListenToken
.CompletionToken
.Event
);
1414 if ( !EFI_ERROR ( Status
)) {
1415 DEBUG (( DebugFlags
| DEBUG_POOL
,
1416 "0x%08x: Closed listen completion event\r\n",
1417 pTcp4
->ListenToken
.CompletionToken
.Event
));
1420 DEBUG (( DEBUG_ERROR
| DebugFlags
,
1421 "ERROR - Failed to close the listen completion event, Status: %r\r\n",
1423 ASSERT ( EFI_SUCCESS
== Status
);
1428 // Return the operation status
1430 DBG_EXIT_STATUS ( Status
);
1436 Perform the network specific close operation on the port.
1438 This routine performs a cancel operations on the TCPv4 port to
1439 shutdown the receive operations on the port.
1441 This routine is called by the ::EslSocketPortCloseTxDone
1442 routine after the port completes all of the transmission.
1444 @param [in] pPort Address of an ::ESL_PORT structure.
1446 @retval EFI_SUCCESS The port is closed, not normally returned
1447 @retval EFI_NOT_READY The port is still closing
1448 @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
1449 most likely the routine was called already.
1453 EslTcp4PortCloseOp (
1457 ESL_TCP4_CONTEXT
* pTcp4
;
1458 EFI_TCP4_PROTOCOL
* pTcp4Protocol
;
1464 // Close the configured port
1466 Status
= EFI_SUCCESS
;
1467 pTcp4
= &pPort
->Context
.Tcp4
;
1468 pTcp4Protocol
= pPort
->pProtocol
.TCPv4
;
1469 pTcp4
->CloseToken
.AbortOnClose
= pPort
->bCloseNow
;
1470 Status
= pTcp4Protocol
->Close ( pTcp4Protocol
,
1471 &pTcp4
->CloseToken
);
1472 if ( !EFI_ERROR ( Status
)) {
1473 DEBUG (( pPort
->DebugFlags
| DEBUG_CLOSE
| DEBUG_INFO
,
1474 "0x%08x: Port close started\r\n",
1478 DEBUG (( DEBUG_ERROR
| pPort
->DebugFlags
| DEBUG_CLOSE
| DEBUG_INFO
,
1479 "ERROR - Close failed on port 0x%08x, Status: %r\r\n",
1485 // Return the operation status
1487 DBG_EXIT_STATUS ( Status
);
1493 Receive data from a network connection.
1495 This routine attempts to return buffered data to the caller. The
1496 data is removed from the urgent queue if the message flag MSG_OOB
1497 is specified, otherwise data is removed from the normal queue.
1498 See the \ref ReceiveEngine section.
1500 This routine is called by ::EslSocketReceive to handle the network
1501 specific receive operation to support SOCK_STREAM and SOCK_SEQPACKET
1504 @param [in] pPort Address of an ::ESL_PORT structure.
1506 @param [in] pPacket Address of an ::ESL_PACKET structure.
1508 @param [in] pbConsumePacket Address of a BOOLEAN indicating if the packet is to be consumed
1510 @param [in] BufferLength Length of the the buffer
1512 @param [in] pBuffer Address of a buffer to receive the data.
1514 @param [in] pDataLength Number of received data bytes in the buffer.
1516 @param [out] pAddress Network address to receive the remote system address
1518 @param [out] pSkipBytes Address to receive the number of bytes skipped
1520 @return Returns the address of the next free byte in the buffer.
1525 IN ESL_PORT
* pPort
,
1526 IN ESL_PACKET
* pPacket
,
1527 IN BOOLEAN
* pbConsumePacket
,
1528 IN
size_t BufferLength
,
1530 OUT
size_t * pDataLength
,
1531 OUT
struct sockaddr
* pAddress
,
1532 OUT
size_t * pSkipBytes
1536 struct sockaddr_in
* pRemoteAddress
;
1537 ESL_TCP4_CONTEXT
* pTcp4
;
1542 // Return the remote system address if requested
1544 if ( NULL
!= pAddress
) {
1546 // Build the remote address
1548 pTcp4
= &pPort
->Context
.Tcp4
;
1550 "Getting packet remote address: %d.%d.%d.%d:%d\r\n",
1551 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[0],
1552 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[1],
1553 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[2],
1554 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[3],
1555 pTcp4
->ConfigData
.AccessPoint
.RemotePort
));
1556 pRemoteAddress
= (struct sockaddr_in
*)pAddress
;
1557 CopyMem ( &pRemoteAddress
->sin_addr
,
1558 &pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[0],
1559 sizeof ( pRemoteAddress
->sin_addr
));
1560 pRemoteAddress
->sin_port
= SwapBytes16 ( pTcp4
->ConfigData
.AccessPoint
.RemotePort
);
1564 // Determine the amount of received data
1566 DataLength
= pPacket
->ValidBytes
;
1567 if ( BufferLength
< DataLength
) {
1568 DataLength
= BufferLength
;
1572 // Move the data into the buffer
1575 "0x%08x: Port copy packet 0x%08x data into 0x%08x, 0x%08x bytes\r\n",
1580 CopyMem ( pBuffer
, pPacket
->pBuffer
, DataLength
);
1583 // Set the next buffer address
1585 pBuffer
+= DataLength
;
1588 // Determine if the data is being read
1590 if ( *pbConsumePacket
) {
1592 // Account for the bytes consumed
1594 pPacket
->pBuffer
+= DataLength
;
1595 pPacket
->ValidBytes
-= DataLength
;
1597 "0x%08x: Port account for 0x%08x bytes\r\n",
1602 // Determine if the entire packet was consumed
1604 if (( 0 == pPacket
->ValidBytes
)
1605 || ( SOCK_STREAM
!= pPort
->pSocket
->Type
)) {
1607 // All done with this packet
1608 // Account for any discarded data
1610 *pSkipBytes
= pPacket
->ValidBytes
;
1615 // More data to consume later
1617 *pbConsumePacket
= FALSE
;
1622 // Return the data length and the buffer address
1624 *pDataLength
= DataLength
;
1625 DBG_EXIT_HEX ( pBuffer
);
1631 Get the remote socket address.
1633 This routine returns the address of the remote connection point
1634 associated with the SOCK_STREAM or SOCK_SEQPACKET socket.
1636 This routine is called by ::EslSocketGetPeerAddress to detemine
1637 the TCPv4 address and por number associated with the network adapter.
1639 @param [in] pPort Address of an ::ESL_PORT structure.
1641 @param [out] pAddress Network address to receive the remote system address
1645 EslTcp4RemoteAddressGet (
1646 IN ESL_PORT
* pPort
,
1647 OUT
struct sockaddr
* pAddress
1650 struct sockaddr_in
* pRemoteAddress
;
1651 ESL_TCP4_CONTEXT
* pTcp4
;
1656 // Return the remote address
1658 pTcp4
= &pPort
->Context
.Tcp4
;
1659 pRemoteAddress
= (struct sockaddr_in
*)pAddress
;
1660 pRemoteAddress
->sin_family
= AF_INET
;
1661 pRemoteAddress
->sin_port
= SwapBytes16 ( pTcp4
->ConfigData
.AccessPoint
.RemotePort
);
1662 CopyMem ( &pRemoteAddress
->sin_addr
,
1663 &pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[0],
1664 sizeof ( pRemoteAddress
->sin_addr
));
1671 Set the remote address
1673 This routine sets the remote address in the port.
1675 This routine is called by ::EslSocketConnect to specify the
1676 remote network address.
1678 @param [in] pPort Address of an ::ESL_PORT structure.
1680 @param [in] pSockAddr Network address of the remote system.
1682 @param [in] SockAddrLength Length in bytes of the network address.
1684 @retval EFI_SUCCESS The operation was successful
1688 EslTcp4RemoteAddressSet (
1689 IN ESL_PORT
* pPort
,
1690 IN CONST
struct sockaddr
* pSockAddr
,
1691 IN socklen_t SockAddrLength
1694 CONST
struct sockaddr_in
* pRemoteAddress
;
1695 ESL_TCP4_CONTEXT
* pTcp4
;
1701 // Set the remote address
1703 pTcp4
= &pPort
->Context
.Tcp4
;
1704 pRemoteAddress
= (struct sockaddr_in
*)pSockAddr
;
1705 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[0] = (UINT8
)( pRemoteAddress
->sin_addr
.s_addr
);
1706 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[1] = (UINT8
)( pRemoteAddress
->sin_addr
.s_addr
>> 8 );
1707 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[2] = (UINT8
)( pRemoteAddress
->sin_addr
.s_addr
>> 16 );
1708 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[3] = (UINT8
)( pRemoteAddress
->sin_addr
.s_addr
>> 24 );
1709 pTcp4
->ConfigData
.AccessPoint
.RemotePort
= SwapBytes16 ( pRemoteAddress
->sin_port
);
1710 Status
= EFI_SUCCESS
;
1711 if ( INADDR_BROADCAST
== pRemoteAddress
->sin_addr
.s_addr
) {
1712 DEBUG (( DEBUG_CONNECT
,
1713 "ERROR - Invalid remote address\r\n" ));
1714 Status
= EFI_INVALID_PARAMETER
;
1715 pPort
->pSocket
->errno
= EAFNOSUPPORT
;
1719 // Return the operation status
1721 DBG_EXIT_STATUS ( Status
);
1727 Process the receive completion
1729 This routine queues the data in FIFO order in either the urgent
1730 or normal data queues depending upon the type of data received.
1731 See the \ref ReceiveEngine section.
1733 This routine is called by the TCPv4 driver when some data is
1736 Buffer the data that was just received.
1738 @param [in] Event The receive completion event
1740 @param [in] pIo Address of an ::ESL_IO_MGMT structure
1746 IN ESL_IO_MGMT
* pIo
1750 size_t LengthInBytes
;
1751 ESL_PACKET
* pPacket
;
1757 // Get the operation status.
1759 Status
= pIo
->Token
.Tcp4Rx
.CompletionToken
.Status
;
1762 // +--------------------+ +---------------------------+
1763 // | ESL_IO_MGMT | | ESL_PACKET |
1765 // | +---------------+ +-----------------------+ |
1766 // | | Token | | EFI_TCP4_RECEIVE_DATA | |
1767 // | | RxData --> | | |
1768 // | | | +-----------------------+---+
1769 // | | Event | | Data Buffer |
1770 // +----+---------------+ | |
1772 // +---------------------------+
1775 // Duplicate the buffer address and length for use by the
1776 // buffer handling code in EslTcp4Receive. These fields are
1777 // used when a partial read is done of the data from the
1780 pPacket
= pIo
->pPacket
;
1781 pPacket
->pBuffer
= pPacket
->Op
.Tcp4Rx
.RxData
.FragmentTable
[0].FragmentBuffer
;
1782 LengthInBytes
= pPacket
->Op
.Tcp4Rx
.RxData
.DataLength
;
1783 pPacket
->ValidBytes
= LengthInBytes
;
1786 // Get the data type so that it may be linked to the
1787 // correct receive buffer list on the ESL_SOCKET structure
1789 bUrgent
= pPacket
->Op
.Tcp4Rx
.RxData
.UrgentFlag
;
1792 // Complete this request
1794 EslSocketRxComplete ( pIo
, Status
, LengthInBytes
, bUrgent
);
1800 Start a receive operation
1802 This routine posts a receive buffer to the TCPv4 driver.
1803 See the \ref ReceiveEngine section.
1805 This support routine is called by EslSocketRxStart.
1807 @param [in] pPort Address of an ::ESL_PORT structure.
1808 @param [in] pIo Address of an ::ESL_IO_MGMT structure.
1813 IN ESL_PORT
* pPort
,
1814 IN ESL_IO_MGMT
* pIo
1817 ESL_PACKET
* pPacket
;
1822 // Initialize the buffer for receive
1824 pPacket
= pIo
->pPacket
;
1825 pIo
->Token
.Tcp4Rx
.Packet
.RxData
= &pPacket
->Op
.Tcp4Rx
.RxData
;
1826 pPacket
->Op
.Tcp4Rx
.RxData
.DataLength
= sizeof ( pPacket
->Op
.Tcp4Rx
.Buffer
);
1827 pPacket
->Op
.Tcp4Rx
.RxData
.FragmentCount
= 1;
1828 pPacket
->Op
.Tcp4Rx
.RxData
.FragmentTable
[0].FragmentLength
= pPacket
->Op
.Tcp4Rx
.RxData
.DataLength
;
1829 pPacket
->Op
.Tcp4Rx
.RxData
.FragmentTable
[0].FragmentBuffer
= &pPacket
->Op
.Tcp4Rx
.Buffer
[0];
1836 Determine if the socket is configured.
1838 This routine uses the flag ESL_SOCKET::bConfigured to determine
1839 if the network layer's configuration routine has been called.
1841 This routine is called by EslSocketIsConfigured to verify
1842 that the socket has been configured.
1844 @param [in] pSocket Address of an ::ESL_SOCKET structure.
1846 @retval EFI_SUCCESS - The port is connected
1847 @retval EFI_NOT_STARTED - The port is not connected
1851 EslTcp4SocketIsConfigured (
1852 IN ESL_SOCKET
* pSocket
1860 // Determine the socket configuration status
1862 Status
= pSocket
->bConfigured
? EFI_SUCCESS
: EFI_NOT_STARTED
;
1865 // Return the port connected state.
1867 DBG_EXIT_STATUS ( Status
);
1873 Buffer data for transmission over a network connection.
1875 This routine buffers data for the transmit engine in one of two
1876 queues, one for urgent (out-of-band) data and the other for normal
1877 data. The urgent data is provided to TCP as soon as it is available,
1878 allowing the TCP layer to schedule transmission of the urgent data
1879 between packets of normal data.
1881 This routine is called by ::EslSocketTransmit to buffer
1882 data for transmission. When the \ref TransmitEngine has resources,
1883 this routine will start the transmission of the next buffer on
1884 the network connection.
1886 Transmission errors are returned during the next transmission or
1887 during the close operation. Only buffering errors are returned
1888 during the current transmission attempt.
1890 @param [in] pSocket Address of an ::ESL_SOCKET structure
1892 @param [in] Flags Message control flags
1894 @param [in] BufferLength Length of the the buffer
1896 @param [in] pBuffer Address of a buffer to receive the data.
1898 @param [in] pDataLength Number of received data bytes in the buffer.
1900 @param [in] pAddress Network address of the remote system address
1902 @param [in] AddressLength Length of the remote network address structure
1904 @retval EFI_SUCCESS - Socket data successfully buffered
1909 IN ESL_SOCKET
* pSocket
,
1911 IN
size_t BufferLength
,
1912 IN CONST UINT8
* pBuffer
,
1913 OUT
size_t * pDataLength
,
1914 IN
const struct sockaddr
* pAddress
,
1915 IN socklen_t AddressLength
1919 BOOLEAN bUrgentQueue
;
1920 ESL_PACKET
* pPacket
;
1921 ESL_IO_MGMT
** ppActive
;
1922 ESL_IO_MGMT
** ppFree
;
1924 ESL_PACKET
** ppQueueHead
;
1925 ESL_PACKET
** ppQueueTail
;
1926 ESL_PACKET
* pPreviousPacket
;
1927 ESL_TCP4_CONTEXT
* pTcp4
;
1929 EFI_TCP4_TRANSMIT_DATA
* pTxData
;
1931 EFI_TPL TplPrevious
;
1938 Status
= EFI_UNSUPPORTED
;
1939 pSocket
->errno
= ENOTCONN
;
1943 // Verify that the socket is connected
1945 if ( SOCKET_STATE_CONNECTED
== pSocket
->State
) {
1949 pPort
= pSocket
->pPortList
;
1950 if ( NULL
!= pPort
) {
1952 // Determine the queue head
1954 pTcp4
= &pPort
->Context
.Tcp4
;
1955 bUrgent
= (BOOLEAN
)( 0 != ( Flags
& MSG_OOB
));
1956 bUrgentQueue
= bUrgent
1957 && ( !pSocket
->bOobInLine
)
1958 && pSocket
->pApi
->bOobSupported
;
1959 if ( bUrgentQueue
) {
1960 ppQueueHead
= &pSocket
->pTxOobPacketListHead
;
1961 ppQueueTail
= &pSocket
->pTxOobPacketListTail
;
1962 ppActive
= &pPort
->pTxOobActive
;
1963 ppFree
= &pPort
->pTxOobFree
;
1964 pTxBytes
= &pSocket
->TxOobBytes
;
1967 ppQueueHead
= &pSocket
->pTxPacketListHead
;
1968 ppQueueTail
= &pSocket
->pTxPacketListTail
;
1969 ppActive
= &pPort
->pTxActive
;
1970 ppFree
= &pPort
->pTxFree
;
1971 pTxBytes
= &pSocket
->TxBytes
;
1975 // Verify that there is enough room to buffer another
1976 // transmit operation
1978 if ( pSocket
->MaxTxBuf
> *pTxBytes
) {
1979 if ( pPort
->bTxFlowControl
) {
1981 "TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT\r\n0x%08x: pPort, TX flow control released, Max bytes: %d > %d bufferred bytes\r\n",
1985 pPort
->bTxFlowControl
= FALSE
;
1989 // Attempt to allocate the packet
1991 Status
= EslSocketPacketAllocate ( &pPacket
,
1992 sizeof ( pPacket
->Op
.Tcp4Tx
)
1993 - sizeof ( pPacket
->Op
.Tcp4Tx
.Buffer
)
1997 if ( !EFI_ERROR ( Status
)) {
1999 // Initialize the transmit operation
2001 pTxData
= &pPacket
->Op
.Tcp4Tx
.TxData
;
2002 pTxData
->Push
= TRUE
|| bUrgent
;
2003 pTxData
->Urgent
= bUrgent
;
2004 pTxData
->DataLength
= (UINT32
) BufferLength
;
2005 pTxData
->FragmentCount
= 1;
2006 pTxData
->FragmentTable
[0].FragmentLength
= (UINT32
) BufferLength
;
2007 pTxData
->FragmentTable
[0].FragmentBuffer
= &pPacket
->Op
.Tcp4Tx
.Buffer
[0];
2010 // Copy the data into the buffer
2012 CopyMem ( &pPacket
->Op
.Tcp4Tx
.Buffer
[0],
2017 // Synchronize with the socket layer
2019 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
2022 // Stop transmission after an error
2024 if ( !EFI_ERROR ( pSocket
->TxError
)) {
2026 // Display the request
2029 "Send %d %s bytes from 0x%08x\r\n",
2031 bUrgent
? L
"urgent" : L
"normal",
2035 // Queue the data for transmission
2037 pPacket
->pNext
= NULL
;
2038 pPreviousPacket
= *ppQueueTail
;
2039 if ( NULL
== pPreviousPacket
) {
2040 *ppQueueHead
= pPacket
;
2043 pPreviousPacket
->pNext
= pPacket
;
2045 *ppQueueTail
= pPacket
;
2047 "0x%08x: Packet on %s transmit list\r\n",
2049 bUrgentQueue
? L
"urgent" : L
"normal" ));
2052 // Account for the buffered data
2054 *pTxBytes
+= BufferLength
;
2055 *pDataLength
= BufferLength
;
2058 // Start the transmit engine if it is idle
2060 if ( NULL
!= *ppFree
) {
2061 EslSocketTxStart ( pPort
,
2070 // Previous transmit error
2071 // Stop transmission
2073 Status
= pSocket
->TxError
;
2074 pSocket
->errno
= EIO
;
2079 EslSocketPacketFree ( pPacket
, DEBUG_TX
);
2083 // Release the socket layer synchronization
2085 RESTORE_TPL ( TplPrevious
);
2089 // Packet allocation failed
2091 pSocket
->errno
= ENOMEM
;
2095 if ( !pPort
->bTxFlowControl
) {
2097 "0x%08x: pPort, TX flow control applied, Max bytes %d <= %d bufferred bytes\r\nTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT\r\n",
2101 pPort
->bTxFlowControl
= TRUE
;
2104 // Not enough buffer space available
2106 pSocket
->errno
= EAGAIN
;
2107 Status
= EFI_NOT_READY
;
2113 // Return the operation status
2115 DBG_EXIT_STATUS ( Status
);
2121 Process the normal data transmit completion
2123 This routine use ::EslSocketTxComplete to perform the transmit
2124 completion processing for normal data.
2126 This routine is called by the TCPv4 network layer when a
2127 normal data transmit request completes.
2129 @param [in] Event The normal transmit completion event
2131 @param [in] pIo The ESL_IO_MGMT structure address
2137 IN ESL_IO_MGMT
* pIo
2140 UINT32 LengthInBytes
;
2141 ESL_PACKET
* pPacket
;
2143 ESL_SOCKET
* pSocket
;
2149 // Locate the active transmit packet
2151 pPacket
= pIo
->pPacket
;
2153 pSocket
= pPort
->pSocket
;
2156 // Get the transmit length and status
2158 LengthInBytes
= pPacket
->Op
.Tcp4Tx
.TxData
.DataLength
;
2159 pSocket
->TxBytes
-= LengthInBytes
;
2160 Status
= pIo
->Token
.Tcp4Tx
.CompletionToken
.Status
;
2163 // Complete the transmit operation
2165 EslSocketTxComplete ( pIo
,
2169 &pSocket
->pTxPacketListHead
,
2170 &pSocket
->pTxPacketListTail
,
2178 Process the urgent data transmit completion
2180 This routine use ::EslSocketTxComplete to perform the transmit
2181 completion processing for urgent data.
2183 This routine is called by the TCPv4 network layer when a
2184 urgent data transmit request completes.
2186 @param [in] Event The urgent transmit completion event
2188 @param [in] pIo The ESL_IO_MGMT structure address
2192 EslTcp4TxOobComplete (
2194 IN ESL_IO_MGMT
* pIo
2197 UINT32 LengthInBytes
;
2198 ESL_PACKET
* pPacket
;
2200 ESL_SOCKET
* pSocket
;
2206 // Locate the active transmit packet
2208 pPacket
= pIo
->pPacket
;
2210 pSocket
= pPort
->pSocket
;
2213 // Get the transmit length and status
2215 LengthInBytes
= pPacket
->Op
.Tcp4Tx
.TxData
.DataLength
;
2216 pSocket
->TxOobBytes
-= LengthInBytes
;
2217 Status
= pIo
->Token
.Tcp4Tx
.CompletionToken
.Status
;
2220 // Complete the transmit operation
2222 EslSocketTxComplete ( pIo
,
2226 &pSocket
->pTxOobPacketListHead
,
2227 &pSocket
->pTxOobPacketListTail
,
2228 &pPort
->pTxOobActive
,
2229 &pPort
->pTxOobFree
);
2235 Verify the adapter's IP address
2237 This support routine is called by EslSocketBindTest.
2239 @param [in] pPort Address of an ::ESL_PORT structure.
2240 @param [in] pConfigData Address of the configuration data
2242 @retval EFI_SUCCESS - The IP address is valid
2243 @retval EFI_NOT_STARTED - The IP address is invalid
2247 EslTcp4VerifyLocalIpAddress (
2248 IN ESL_PORT
* pPort
,
2249 IN EFI_TCP4_CONFIG_DATA
* pConfigData
2253 EFI_TCP4_ACCESS_POINT
* pAccess
;
2254 EFI_IP4_IPCONFIG_DATA
* pIpConfigData
;
2255 EFI_IP4_CONFIG_PROTOCOL
* pIpConfigProtocol
;
2256 ESL_SERVICE
* pService
;
2262 // Use break instead of goto
2264 pIpConfigData
= NULL
;
2267 // Determine if the IP address is specified
2269 pAccess
= &pConfigData
->AccessPoint
;
2270 DEBUG (( DEBUG_BIND
,
2271 "UseDefaultAddress: %s\r\n",
2272 pAccess
->UseDefaultAddress
? L
"TRUE" : L
"FALSE" ));
2273 DEBUG (( DEBUG_BIND
,
2274 "Requested IP address: %d.%d.%d.%d\r\n",
2275 pAccess
->StationAddress
.Addr
[ 0 ],
2276 pAccess
->StationAddress
.Addr
[ 1 ],
2277 pAccess
->StationAddress
.Addr
[ 2 ],
2278 pAccess
->StationAddress
.Addr
[ 3 ]));
2279 if ( pAccess
->UseDefaultAddress
2280 || (( 0 == pAccess
->StationAddress
.Addr
[ 0 ])
2281 && ( 0 == pAccess
->StationAddress
.Addr
[ 1 ])
2282 && ( 0 == pAccess
->StationAddress
.Addr
[ 2 ])
2283 && ( 0 == pAccess
->StationAddress
.Addr
[ 3 ])))
2285 Status
= EFI_SUCCESS
;
2290 // Open the configuration protocol
2292 pService
= pPort
->pService
;
2293 Status
= gBS
->OpenProtocol ( pService
->Controller
,
2294 &gEfiIp4ConfigProtocolGuid
,
2295 (VOID
**)&pIpConfigProtocol
,
2298 EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
2299 if ( EFI_ERROR ( Status
)) {
2300 DEBUG (( DEBUG_ERROR
,
2301 "ERROR - IP Configuration Protocol not available, Status: %r\r\n",
2307 // Get the IP configuration data size
2310 Status
= pIpConfigProtocol
->GetData ( pIpConfigProtocol
,
2313 if ( EFI_BUFFER_TOO_SMALL
!= Status
) {
2314 DEBUG (( DEBUG_ERROR
,
2315 "ERROR - Failed to get IP Configuration data size, Status: %r\r\n",
2321 // Allocate the configuration data buffer
2323 pIpConfigData
= AllocatePool ( DataSize
);
2324 if ( NULL
== pIpConfigData
) {
2325 DEBUG (( DEBUG_ERROR
,
2326 "ERROR - Not enough memory to allocate IP Configuration data!\r\n" ));
2327 Status
= EFI_OUT_OF_RESOURCES
;
2332 // Get the IP configuration
2334 Status
= pIpConfigProtocol
->GetData ( pIpConfigProtocol
,
2337 if ( EFI_ERROR ( Status
)) {
2338 DEBUG (( DEBUG_ERROR
,
2339 "ERROR - Failed to return IP Configuration data, Status: %r\r\n",
2345 // Display the current configuration
2347 DEBUG (( DEBUG_BIND
,
2348 "Actual adapter IP address: %d.%d.%d.%d\r\n",
2349 pIpConfigData
->StationAddress
.Addr
[ 0 ],
2350 pIpConfigData
->StationAddress
.Addr
[ 1 ],
2351 pIpConfigData
->StationAddress
.Addr
[ 2 ],
2352 pIpConfigData
->StationAddress
.Addr
[ 3 ]));
2355 // Assume the port is not configured
2357 Status
= EFI_SUCCESS
;
2358 if (( pAccess
->StationAddress
.Addr
[ 0 ] == pIpConfigData
->StationAddress
.Addr
[ 0 ])
2359 && ( pAccess
->StationAddress
.Addr
[ 1 ] == pIpConfigData
->StationAddress
.Addr
[ 1 ])
2360 && ( pAccess
->StationAddress
.Addr
[ 2 ] == pIpConfigData
->StationAddress
.Addr
[ 2 ])
2361 && ( pAccess
->StationAddress
.Addr
[ 3 ] == pIpConfigData
->StationAddress
.Addr
[ 3 ])) {
2366 // The IP address did not match
2368 Status
= EFI_NOT_STARTED
;
2373 // Free the buffer if necessary
2375 if ( NULL
!= pIpConfigData
) {
2376 FreePool ( pIpConfigData
);
2380 // Return the IP address status
2382 DBG_EXIT_STATUS ( Status
);
2388 Interface between the socket layer and the network specific
2389 code that supports SOCK_STREAM and SOCK_SEQPACKET sockets
2392 CONST ESL_PROTOCOL_API cEslTcp4Api
= {
2395 OFFSET_OF ( ESL_PORT
, Context
.Tcp4
.ConfigData
),
2396 OFFSET_OF ( ESL_LAYER
, pTcp4List
),
2397 OFFSET_OF ( struct sockaddr_in
, sin_zero
),
2398 sizeof ( struct sockaddr_in
),
2400 sizeof (((ESL_PACKET
*)0 )->Op
.Tcp4Rx
),
2401 OFFSET_OF ( ESL_PACKET
, Op
.Tcp4Rx
.Buffer
) - OFFSET_OF ( ESL_PACKET
, Op
),
2402 OFFSET_OF ( ESL_IO_MGMT
, Token
.Tcp4Rx
.Packet
.RxData
),
2407 EslTcp4ConnectStart
,
2408 EslTcp4SocketIsConfigured
,
2409 EslTcp4LocalAddressGet
,
2410 EslTcp4LocalAddressSet
,
2415 EslTcp4PortAllocate
,
2420 EslTcp4RemoteAddressGet
,
2421 EslTcp4RemoteAddressSet
,
2426 EslTcp4TxOobComplete
,
2427 (PFN_API_VERIFY_LOCAL_IP_ADDRESS
)EslTcp4VerifyLocalIpAddress