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 DEBUG (( DEBUG_CONNECT
,
245 "0x%08x: Port connection to %d.%d.%d.%d:%d failed, Status: %r\r\n",
247 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[0],
248 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[1],
249 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[2],
250 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[3],
251 pTcp4
->ConfigData
.AccessPoint
.RemotePort
,
255 // Close the current port
257 Status
= EslSocketPortClose ( pPort
);
258 if ( !EFI_ERROR ( Status
)) {
259 DEBUG (( DEBUG_CONNECT
,
260 "0x%08x: Port closed\r\n",
264 DEBUG (( DEBUG_CONNECT
,
265 "ERROR - Failed to close port 0x%08x, Status: %r\r\n",
271 // Try to connect using the next port
273 Status
= EslTcp4ConnectStart ( pSocket
);
274 if ( EFI_NOT_READY
!= Status
) {
275 pSocket
->ConnectStatus
= Status
;
276 bRemoveFirstPort
= TRUE
;
281 // Remove the ports if necessary
283 if ( bRemoveFirstPort
|| bRemovePorts
) {
285 // Remove the first port if necessary
287 pPort
= pSocket
->pPortList
;
288 if (( !bRemoveFirstPort
) && ( NULL
!= pPort
)) {
289 pPort
= pPort
->pLinkSocket
;
293 // Remove the rest of the list
295 while ( NULL
!= pPort
) {
296 pNextPort
= pPort
->pLinkSocket
;
297 EslSocketPortClose ( pPort
);
298 if ( !EFI_ERROR ( Status
)) {
299 DEBUG (( DEBUG_CONNECT
,
300 "0x%08x: Port closed\r\n",
304 DEBUG (( DEBUG_CONNECT
,
305 "ERROR - Failed to close port 0x%08x, Status: %r\r\n",
313 // Notify the poll routine
315 pSocket
->bConnected
= TRUE
;
323 Poll for completion of the connection attempt.
325 This routine polls the ESL_SOCKET::bConnected flag to determine
326 when the connection attempt is complete.
328 This routine is called from ::EslSocketConnect to determine when
329 the connection is complete. The ESL_SOCKET::bConnected flag is
330 set by ::EslTcp4ConnectComplete when the TCPv4 layer establishes
331 a connection or runs out of local network adapters. This routine
332 gets the connection status from ESL_SOCKET::ConnectStatus.
334 @param [in] pSocket Address of an ::ESL_SOCKET structure.
336 @retval EFI_SUCCESS The connection was successfully established.
337 @retval EFI_NOT_READY The connection is in progress, call this routine again.
338 @retval Others The connection attempt failed.
343 IN ESL_SOCKET
* pSocket
351 // Determine if the connection is complete
353 if ( !pSocket
->bConnected
) {
357 pSocket
->errno
= EAGAIN
;
358 Status
= EFI_NOT_READY
;
362 // The connection processing is complete
364 pSocket
->bConnected
= FALSE
;
367 // Translate the connection status
369 Status
= pSocket
->ConnectStatus
;
372 case EFI_DEVICE_ERROR
:
373 pSocket
->errno
= EIO
;
377 pSocket
->errno
= ECONNREFUSED
;
380 case EFI_INVALID_PARAMETER
:
381 pSocket
->errno
= EINVAL
;
385 case EFI_NO_RESPONSE
:
386 pSocket
->errno
= EHOSTUNREACH
;
390 pSocket
->errno
= ENETDOWN
;
393 case EFI_OUT_OF_RESOURCES
:
394 pSocket
->errno
= ENOMEM
;
399 pSocket
->bConfigured
= TRUE
;
403 pSocket
->errno
= ETIMEDOUT
;
406 case EFI_UNSUPPORTED
:
407 pSocket
->errno
= ENOTSUP
;
411 pSocket
->errno
= ECONNRESET
;
417 // Return the initialization status
419 DBG_EXIT_STATUS ( Status
);
425 Attempt to connect to a remote TCP port
427 This routine starts the connection processing for a SOCK_STREAM
428 or SOCK_SEQPAKCET socket using the TCPv4 network layer. It
429 configures the local TCPv4 connection point and then attempts to
430 connect to a remote system. Upon completion, the
431 ::EslTcp4ConnectComplete routine gets called with the connection
434 This routine is called by ::EslSocketConnect to initiate the TCPv4
435 network specific connect operations. The connection processing is
436 initiated by this routine and finished by ::EslTcp4ConnectComplete.
437 This pair of routines walks through the list of local TCPv4
438 connection points until a connection to the remote system is
441 @param [in] pSocket Address of an ::ESL_SOCKET structure.
443 @retval EFI_SUCCESS The connection was successfully established.
444 @retval EFI_NOT_READY The connection is in progress, call this routine again.
445 @retval Others The connection attempt failed.
449 EslTcp4ConnectStart (
450 IN ESL_SOCKET
* pSocket
454 ESL_TCP4_CONTEXT
* pTcp4
;
455 EFI_TCP4_PROTOCOL
* pTcp4Protocol
;
456 EFI_SIMPLE_NETWORK_MODE SnpModeData
;
462 // Determine if any more local adapters are available
464 pPort
= pSocket
->pPortList
;
465 if ( NULL
!= pPort
) {
467 // Configure the port
469 pTcp4
= &pPort
->Context
.Tcp4
;
470 pTcp4
->ConfigData
.AccessPoint
.ActiveFlag
= TRUE
;
471 pTcp4
->ConfigData
.TimeToLive
= 255;
472 pTcp4Protocol
= pPort
->pProtocol
.TCPv4
;
473 Status
= pTcp4Protocol
->Configure ( pTcp4Protocol
,
474 &pTcp4
->ConfigData
);
475 if ( EFI_ERROR ( Status
)) {
476 DEBUG (( DEBUG_CONNECT
,
477 "ERROR - Failed to configure the Tcp4 port, Status: %r\r\n",
480 case EFI_ACCESS_DENIED
:
481 pSocket
->errno
= EACCES
;
485 case EFI_DEVICE_ERROR
:
486 pSocket
->errno
= EIO
;
489 case EFI_INVALID_PARAMETER
:
490 pSocket
->errno
= EADDRNOTAVAIL
;
494 pSocket
->errno
= EAFNOSUPPORT
;
497 case EFI_OUT_OF_RESOURCES
:
498 pSocket
->errno
= ENOBUFS
;
501 case EFI_UNSUPPORTED
:
502 pSocket
->errno
= EOPNOTSUPP
;
507 DEBUG (( DEBUG_CONNECT
,
508 "0x%08x: Port configured\r\n",
510 pPort
->bConfigured
= TRUE
;
513 // Verify the port connection
515 pTcp4Protocol
= pPort
->pProtocol
.TCPv4
;
516 Status
= pTcp4Protocol
->GetModeData ( pTcp4Protocol
,
522 if ( !EFI_ERROR ( Status
)) {
523 if ( SnpModeData
.MediaPresentSupported
524 && ( !SnpModeData
.MediaPresent
)) {
526 // Port is not connected to the network
528 Status
= EFI_NO_MEDIA
;
532 // Attempt the connection to the remote system
534 Status
= pTcp4Protocol
->Connect ( pTcp4Protocol
,
535 &pTcp4
->ConnectToken
);
538 if ( !EFI_ERROR ( Status
)) {
540 // Connection in progress
542 pSocket
->errno
= EINPROGRESS
;
543 Status
= EFI_NOT_READY
;
544 DEBUG (( DEBUG_CONNECT
,
545 "0x%08x: Port attempting connection to %d.%d.%d.%d:%d\r\n",
547 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[0],
548 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[1],
549 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[2],
550 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[3],
551 pTcp4
->ConfigData
.AccessPoint
.RemotePort
));
557 DEBUG (( DEBUG_CONNECT
,
558 "ERROR - Port 0x%08x not connected, Status: %r\r\n",
562 // Determine the errno value
566 pSocket
->errno
= EIO
;
569 case EFI_OUT_OF_RESOURCES
:
570 pSocket
->errno
= ENOBUFS
;
574 pSocket
->errno
= ETIMEDOUT
;
578 case EFI_NETWORK_UNREACHABLE
:
579 pSocket
->errno
= ENETDOWN
;
582 case EFI_HOST_UNREACHABLE
:
583 pSocket
->errno
= EHOSTUNREACH
;
586 case EFI_PORT_UNREACHABLE
:
587 case EFI_PROTOCOL_UNREACHABLE
:
588 case EFI_CONNECTION_REFUSED
:
589 pSocket
->errno
= ECONNREFUSED
;
592 case EFI_CONNECTION_RESET
:
593 pSocket
->errno
= ECONNRESET
;
601 // No more local adapters available
603 pSocket
->errno
= ENETUNREACH
;
604 Status
= EFI_NO_RESPONSE
;
608 // Return the operation status
610 DBG_EXIT_STATUS ( Status
);
616 Establish the known port to listen for network connections.
618 This routine places the port into a state that enables connection
621 This routine is called by ::EslSocketListen to handle the network
622 specifics of the listen operation for SOCK_STREAM and SOCK_SEQPACKET
623 sockets. See the \ref ConnectionManagement section.
625 @param [in] pSocket Address of an ::ESL_SOCKET structure.
627 @retval EFI_SUCCESS - Socket successfully created
628 @retval Other - Failed to enable the socket for listen
633 IN ESL_SOCKET
* pSocket
636 ESL_PORT
* pNextPort
;
638 ESL_TCP4_CONTEXT
* pTcp4
;
639 EFI_TCP4_PROTOCOL
* pTcp4Protocol
;
645 // Verify the socket layer synchronization
647 VERIFY_TPL ( TPL_SOCKETS
);
650 // Use for/break instead of goto
654 // Assume no ports are available
656 pSocket
->errno
= EOPNOTSUPP
;
657 Status
= EFI_NOT_READY
;
660 // Walk the list of ports
662 pPort
= pSocket
->pPortList
;
663 while ( NULL
!= pPort
) {
670 // Use for/break insteak of goto
674 // Create the listen completion event
676 pTcp4
= &pPort
->Context
.Tcp4
;
677 Status
= gBS
->CreateEvent ( EVT_NOTIFY_SIGNAL
,
679 (EFI_EVENT_NOTIFY
)EslTcp4ListenComplete
,
681 &pTcp4
->ListenToken
.CompletionToken
.Event
);
682 if ( EFI_ERROR ( Status
)) {
683 DEBUG (( DEBUG_ERROR
| DEBUG_LISTEN
,
684 "ERROR - Failed to create the listen completion event, Status: %r\r\n",
686 pSocket
->errno
= ENOMEM
;
690 "0x%08x: Created listen completion event\r\n",
691 pTcp4
->ListenToken
.CompletionToken
.Event
));
694 // Configure the port
696 pTcp4Protocol
= pPort
->pProtocol
.TCPv4
;
697 Status
= pTcp4Protocol
->Configure ( pTcp4Protocol
,
698 &pTcp4
->ConfigData
);
699 if ( EFI_ERROR ( Status
)) {
700 DEBUG (( DEBUG_LISTEN
,
701 "ERROR - Failed to configure the Tcp4 port, Status: %r\r\n",
704 case EFI_ACCESS_DENIED
:
705 pSocket
->errno
= EACCES
;
709 case EFI_DEVICE_ERROR
:
710 pSocket
->errno
= EIO
;
713 case EFI_INVALID_PARAMETER
:
714 pSocket
->errno
= EADDRNOTAVAIL
;
718 pSocket
->errno
= EAFNOSUPPORT
;
721 case EFI_OUT_OF_RESOURCES
:
722 pSocket
->errno
= ENOBUFS
;
725 case EFI_UNSUPPORTED
:
726 pSocket
->errno
= EOPNOTSUPP
;
731 DEBUG (( DEBUG_LISTEN
,
732 "0x%08x: Port configured\r\n",
734 pPort
->bConfigured
= TRUE
;
737 // Start the listen operation on the port
739 Status
= pTcp4Protocol
->Accept ( pTcp4Protocol
,
740 &pTcp4
->ListenToken
);
741 if ( EFI_ERROR ( Status
)) {
742 DEBUG (( DEBUG_LISTEN
,
743 "ERROR - Failed Tcp4 accept, Status: %r\r\n",
746 case EFI_ACCESS_DENIED
:
747 pSocket
->errno
= EACCES
;
751 case EFI_DEVICE_ERROR
:
752 pSocket
->errno
= EIO
;
755 case EFI_INVALID_PARAMETER
:
756 pSocket
->errno
= EADDRNOTAVAIL
;
759 case EFI_NOT_STARTED
:
760 pSocket
->errno
= ENETDOWN
;
763 case EFI_OUT_OF_RESOURCES
:
764 pSocket
->errno
= ENOBUFS
;
769 DEBUG (( DEBUG_LISTEN
,
770 "0x%08x: Listen pending on Port\r\n",
774 // Listen is pending on this port
782 pNextPort
= pPort
->pLinkSocket
;
785 // Close the port upon error
787 if ( EFI_ERROR ( Status
)) {
788 EslSocketPortCloseStart ( pPort
, TRUE
, DEBUG_LISTEN
);
798 // Determine if any ports are in the listen state
800 if ( NULL
== pSocket
->pPortList
) {
802 // No ports in the listen state
804 pSocket
->MaxFifoDepth
= 0;
807 // Return the last error detected
813 // Mark the socket as configured
815 pSocket
->bConfigured
= TRUE
;
820 DEBUG (( DEBUG_LISTEN
,
821 "0x%08x: pSocket - Listen pending on socket\r\n",
827 // Return the operation status
829 DBG_EXIT_STATUS ( Status
);
835 Process the connection attempt
837 A system has initiated a connection attempt with a socket in the
838 listen state. Attempt to complete the connection.
840 The TCPv4 layer calls this routine when a connection is made to
841 the socket in the listen state. See the
842 \ref ConnectionManagement section.
844 @param [in] Event The listen completion event
846 @param [in] pPort Address of an ::ESL_PORT structure.
850 EslTcp4ListenComplete (
855 EFI_HANDLE ChildHandle
;
856 struct sockaddr_in LocalAddress
;
857 EFI_TCP4_CONFIG_DATA
* pConfigData
;
860 ESL_SOCKET
* pNewSocket
;
861 ESL_SOCKET
* pSocket
;
862 ESL_TCP4_CONTEXT
* pTcp4
;
863 EFI_TCP4_PROTOCOL
* pTcp4Protocol
;
865 EFI_HANDLE TcpPortHandle
;
866 EFI_STATUS TempStatus
;
869 VERIFY_AT_TPL ( TPL_SOCKETS
);
874 Status
= EFI_SUCCESS
;
877 // Determine if this connection fits into the connection FIFO
879 pSocket
= pPort
->pSocket
;
880 TcpPortHandle
= pPort
->Context
.Tcp4
.ListenToken
.NewChildHandle
;
881 if (( SOCKET_STATE_LISTENING
== pSocket
->State
)
882 && ( pSocket
->MaxFifoDepth
> pSocket
->FifoDepth
)) {
884 // Allocate a socket for this connection
888 Status
= EslSocketAllocate ( &ChildHandle
,
891 if ( !EFI_ERROR ( Status
)) {
893 // Clone the socket parameters
895 pNewSocket
->pApi
= pSocket
->pApi
;
896 pNewSocket
->Domain
= pSocket
->Domain
;
897 pNewSocket
->Protocol
= pSocket
->Protocol
;
898 pNewSocket
->Type
= pSocket
->Type
;
901 // Build the local address
903 pTcp4
= &pPort
->Context
.Tcp4
;
904 LocalAddress
.sin_len
= (uint8_t)pNewSocket
->pApi
->MinimumAddressLength
;
905 LocalAddress
.sin_family
= AF_INET
;
906 LocalAddress
.sin_port
= 0;
907 LocalAddress
.sin_addr
.s_addr
= *(UINT32
*)&pTcp4
->ConfigData
.AccessPoint
.StationAddress
.Addr
[0];
910 // Allocate a port for this connection
911 // Note in this instance Configure may not be called with NULL!
913 Status
= EslSocketPortAllocate ( pNewSocket
,
916 (struct sockaddr
*)&LocalAddress
,
920 if ( !EFI_ERROR ( Status
)) {
922 // Restart the listen operation on the port
924 pTcp4Protocol
= pPort
->pProtocol
.TCPv4
;
925 Status
= pTcp4Protocol
->Accept ( pTcp4Protocol
,
926 &pTcp4
->ListenToken
);
929 // Close the TCP port using SocketClose
931 TcpPortHandle
= NULL
;
932 pTcp4
= &pNewPort
->Context
.Tcp4
;
935 // Check for an accept call error
937 if ( !EFI_ERROR ( Status
)) {
939 // Get the port configuration
941 pNewPort
->bConfigured
= TRUE
;
942 pConfigData
= &pTcp4
->ConfigData
;
943 pConfigData
->ControlOption
= &pTcp4
->Option
;
944 pTcp4Protocol
= pNewPort
->pProtocol
.TCPv4
;
945 Status
= pTcp4Protocol
->GetModeData ( pTcp4Protocol
,
951 if ( !EFI_ERROR ( Status
)) {
953 // Add the new socket to the connection FIFO
955 if ( NULL
== pSocket
->pFifoTail
) {
959 pSocket
->pFifoHead
= pNewSocket
;
963 // Add to end of list.
965 pSocket
->pFifoTail
->pNextConnection
= pNewSocket
;
967 pSocket
->pFifoTail
= pNewSocket
;
968 pSocket
->FifoDepth
+= 1;
971 // Update the socket state
973 pNewSocket
->State
= SOCKET_STATE_IN_FIFO
;
976 // Log the connection
978 DEBUG (( DEBUG_CONNECTION
| DEBUG_INFO
,
979 "0x%08x: Socket on port %d.%d.%d.%d:%d connected to %d.%d.%d.%d:%d\r\n",
981 pConfigData
->AccessPoint
.StationAddress
.Addr
[0],
982 pConfigData
->AccessPoint
.StationAddress
.Addr
[1],
983 pConfigData
->AccessPoint
.StationAddress
.Addr
[2],
984 pConfigData
->AccessPoint
.StationAddress
.Addr
[3],
985 pConfigData
->AccessPoint
.StationPort
,
986 pConfigData
->AccessPoint
.RemoteAddress
.Addr
[0],
987 pConfigData
->AccessPoint
.RemoteAddress
.Addr
[1],
988 pConfigData
->AccessPoint
.RemoteAddress
.Addr
[2],
989 pConfigData
->AccessPoint
.RemoteAddress
.Addr
[3],
990 pConfigData
->AccessPoint
.RemotePort
));
991 DEBUG (( DEBUG_CONNECTION
| DEBUG_INFO
,
992 "0x%08x: Listen socket adding socket 0x%08x to FIFO, depth: %d\r\n",
995 pSocket
->FifoDepth
));
998 // Start the receive operation
1000 EslSocketRxStart ( pNewPort
);
1003 DEBUG (( DEBUG_ERROR
| DEBUG_CONNECTION
| DEBUG_INFO
,
1004 "ERROR - GetModeData failed on port 0x%08x, Status: %r\r\n",
1011 // The listen failed on this port
1013 DEBUG (( DEBUG_LISTEN
| DEBUG_INFO
,
1014 "ERROR - Listen failed on port 0x%08x, Status: %r\r\n",
1019 // Close the listening port
1021 EslSocketPortCloseStart ( pPort
, TRUE
, DEBUG_LISTEN
);
1026 // Done with the socket if necessary
1028 if ( EFI_ERROR ( Status
)) {
1029 TempStatus
= EslSocketCloseStart ( &pNewSocket
->SocketProtocol
,
1032 ASSERT ( EFI_SUCCESS
== TempStatus
);
1037 DEBUG (( DEBUG_CONNECTION
,
1038 "0x%08x: Socket FIFO full, connection refused\r\n",
1042 // The FIFO is full or the socket is in the wrong state
1044 Status
= EFI_BUFFER_TOO_SMALL
;
1048 // Close the connection if necessary
1050 if (( EFI_ERROR ( Status
))
1051 && ( NULL
== TcpPortHandle
)) {
1053 // TODO: Finish this code path
1054 // The new connection does not fit into the connection FIFO
1058 // Release the resources
1067 Get the local socket address.
1069 This routine returns the IPv4 address and TCP port number associated
1070 with the local socket.
1072 This routine is called by ::EslSocketGetLocalAddress to determine the
1073 network address for the SOCK_STREAM or SOCK_SEQPACKET socket.
1075 @param [in] pPort Address of an ::ESL_PORT structure.
1077 @param [out] pSockAddr Network address to receive the local system address
1081 EslTcp4LocalAddressGet (
1082 IN ESL_PORT
* pPort
,
1083 OUT
struct sockaddr
* pSockAddr
1086 struct sockaddr_in
* pLocalAddress
;
1087 ESL_TCP4_CONTEXT
* pTcp4
;
1092 // Return the local address
1094 pTcp4
= &pPort
->Context
.Tcp4
;
1095 pLocalAddress
= (struct sockaddr_in
*)pSockAddr
;
1096 pLocalAddress
->sin_family
= AF_INET
;
1097 pLocalAddress
->sin_port
= SwapBytes16 ( pTcp4
->ConfigData
.AccessPoint
.StationPort
);
1098 CopyMem ( &pLocalAddress
->sin_addr
,
1099 &pTcp4
->ConfigData
.AccessPoint
.StationAddress
.Addr
[0],
1100 sizeof ( pLocalAddress
->sin_addr
));
1107 Set the local port address.
1109 This routine sets the local port address.
1111 This support routine is called by ::EslSocketPortAllocate.
1113 @param [in] pPort Address of an ESL_PORT structure
1114 @param [in] pSockAddr Address of a sockaddr structure that contains the
1115 connection point on the local machine. An IPv4 address
1116 of INADDR_ANY specifies that the connection is made to
1117 all of the network stacks on the platform. Specifying a
1118 specific IPv4 address restricts the connection to the
1119 network stack supporting that address. Specifying zero
1120 for the port causes the network layer to assign a port
1121 number from the dynamic range. Specifying a specific
1122 port number causes the network layer to use that port.
1124 @param [in] bBindTest TRUE = run bind testing
1126 @retval EFI_SUCCESS The operation was successful
1130 EslTcp4LocalAddressSet (
1131 IN ESL_PORT
* pPort
,
1132 IN CONST
struct sockaddr
* pSockAddr
,
1133 IN BOOLEAN bBindTest
1136 EFI_TCP4_ACCESS_POINT
* pAccessPoint
;
1137 CONST
struct sockaddr_in
* pIpAddress
;
1138 CONST UINT8
* pIpv4Address
;
1144 // Validate the address
1146 pIpAddress
= (struct sockaddr_in
*)pSockAddr
;
1147 if ( INADDR_BROADCAST
== pIpAddress
->sin_addr
.s_addr
) {
1149 // The local address must not be the broadcast address
1151 Status
= EFI_INVALID_PARAMETER
;
1152 pPort
->pSocket
->errno
= EADDRNOTAVAIL
;
1156 // Set the local address
1158 pIpv4Address
= (UINT8
*)&pIpAddress
->sin_addr
.s_addr
;
1159 pAccessPoint
= &pPort
->Context
.Tcp4
.ConfigData
.AccessPoint
;
1160 pAccessPoint
->StationAddress
.Addr
[0] = pIpv4Address
[0];
1161 pAccessPoint
->StationAddress
.Addr
[1] = pIpv4Address
[1];
1162 pAccessPoint
->StationAddress
.Addr
[2] = pIpv4Address
[2];
1163 pAccessPoint
->StationAddress
.Addr
[3] = pIpv4Address
[3];
1166 // Determine if the default address is used
1168 pAccessPoint
->UseDefaultAddress
= (BOOLEAN
)( 0 == pIpAddress
->sin_addr
.s_addr
);
1171 // Set the subnet mask
1173 if ( pAccessPoint
->UseDefaultAddress
) {
1174 pAccessPoint
->SubnetMask
.Addr
[0] = 0;
1175 pAccessPoint
->SubnetMask
.Addr
[1] = 0;
1176 pAccessPoint
->SubnetMask
.Addr
[2] = 0;
1177 pAccessPoint
->SubnetMask
.Addr
[3] = 0;
1180 pAccessPoint
->SubnetMask
.Addr
[0] = 0xff;
1181 pAccessPoint
->SubnetMask
.Addr
[1] = 0xff;
1182 pAccessPoint
->SubnetMask
.Addr
[2] = 0xff;
1183 pAccessPoint
->SubnetMask
.Addr
[3] = 0xff;
1187 // Validate the IP address
1189 pAccessPoint
->StationPort
= 0;
1190 Status
= bBindTest
? EslSocketBindTest ( pPort
, EADDRNOTAVAIL
)
1192 if ( !EFI_ERROR ( Status
)) {
1194 // Set the port number
1196 pAccessPoint
->StationPort
= SwapBytes16 ( pIpAddress
->sin_port
);
1197 pPort
->pSocket
->bAddressSet
= TRUE
;
1200 // Display the local address
1202 DEBUG (( DEBUG_BIND
,
1203 "0x%08x: Port, Local TCP4 Address: %d.%d.%d.%d:%d\r\n",
1205 pAccessPoint
->StationAddress
.Addr
[0],
1206 pAccessPoint
->StationAddress
.Addr
[1],
1207 pAccessPoint
->StationAddress
.Addr
[2],
1208 pAccessPoint
->StationAddress
.Addr
[3],
1209 pAccessPoint
->StationPort
));
1214 // Return the operation status
1216 DBG_EXIT_STATUS ( Status
);
1222 Free a receive packet
1224 This routine performs the network specific operations necessary
1225 to free a receive packet.
1227 This routine is called by ::EslSocketPortCloseTxDone to free a
1230 @param [in] pPacket Address of an ::ESL_PACKET structure.
1231 @param [in, out] pRxBytes Address of the count of RX bytes
1236 IN ESL_PACKET
* pPacket
,
1237 IN OUT
size_t * pRxBytes
1243 // Account for the receive bytes
1245 *pRxBytes
-= pPacket
->Op
.Tcp4Rx
.RxData
.DataLength
;
1251 Initialize the network specific portions of an ::ESL_PORT structure.
1253 This routine initializes the network specific portions of an
1254 ::ESL_PORT structure for use by the socket.
1256 This support routine is called by ::EslSocketPortAllocate
1257 to connect the socket with the underlying network adapter
1258 running the TCPv4 protocol.
1260 @param [in] pPort Address of an ESL_PORT structure
1261 @param [in] DebugFlags Flags for debug messages
1263 @retval EFI_SUCCESS - Socket successfully created
1267 EslTcp4PortAllocate (
1268 IN ESL_PORT
* pPort
,
1272 EFI_TCP4_ACCESS_POINT
* pAccessPoint
;
1273 ESL_SOCKET
* pSocket
;
1274 ESL_TCP4_CONTEXT
* pTcp4
;
1280 // Use for/break instead of goto
1283 // Allocate the close event
1285 pSocket
= pPort
->pSocket
;
1286 pTcp4
= &pPort
->Context
.Tcp4
;
1287 Status
= gBS
->CreateEvent ( EVT_NOTIFY_SIGNAL
,
1289 (EFI_EVENT_NOTIFY
)EslSocketPortCloseComplete
,
1291 &pTcp4
->CloseToken
.CompletionToken
.Event
);
1292 if ( EFI_ERROR ( Status
)) {
1293 DEBUG (( DEBUG_ERROR
| DebugFlags
,
1294 "ERROR - Failed to create the close event, Status: %r\r\n",
1296 pSocket
->errno
= ENOMEM
;
1299 DEBUG (( DEBUG_CLOSE
| DEBUG_POOL
,
1300 "0x%08x: Created close event\r\n",
1301 pTcp4
->CloseToken
.CompletionToken
.Event
));
1304 // Allocate the connection event
1306 Status
= gBS
->CreateEvent ( EVT_NOTIFY_SIGNAL
,
1308 (EFI_EVENT_NOTIFY
)EslTcp4ConnectComplete
,
1310 &pTcp4
->ConnectToken
.CompletionToken
.Event
);
1311 if ( EFI_ERROR ( Status
)) {
1312 DEBUG (( DEBUG_ERROR
| DebugFlags
,
1313 "ERROR - Failed to create the connect event, Status: %r\r\n",
1315 pSocket
->errno
= ENOMEM
;
1318 DEBUG (( DEBUG_CLOSE
| DEBUG_POOL
,
1319 "0x%08x: Created connect event\r\n",
1320 pTcp4
->ConnectToken
.CompletionToken
.Event
));
1323 // Initialize the port
1325 pSocket
->TxPacketOffset
= OFFSET_OF ( ESL_PACKET
, Op
.Tcp4Tx
.TxData
);
1326 pSocket
->TxTokenEventOffset
= OFFSET_OF ( ESL_IO_MGMT
, Token
.Tcp4Tx
.CompletionToken
.Event
);
1327 pSocket
->TxTokenOffset
= OFFSET_OF ( EFI_TCP4_IO_TOKEN
, Packet
.TxData
);
1330 // Save the cancel, receive and transmit addresses
1331 // pPort->pfnRxCancel = NULL; since the UEFI implementation returns EFI_UNSUPPORTED
1333 pPort
->pfnConfigure
= (PFN_NET_CONFIGURE
)pPort
->pProtocol
.TCPv4
->Configure
;
1334 pPort
->pfnRxPoll
= (PFN_NET_POLL
)pPort
->pProtocol
.TCPv4
->Poll
;
1335 pPort
->pfnRxStart
= (PFN_NET_IO_START
)pPort
->pProtocol
.TCPv4
->Receive
;
1336 pPort
->pfnTxStart
= (PFN_NET_IO_START
)pPort
->pProtocol
.TCPv4
->Transmit
;
1339 // Set the configuration flags
1341 pAccessPoint
= &pPort
->Context
.Tcp4
.ConfigData
.AccessPoint
;
1342 pAccessPoint
->ActiveFlag
= FALSE
;
1343 pTcp4
->ConfigData
.TimeToLive
= 255;
1348 // Return the operation status
1350 DBG_EXIT_STATUS ( Status
);
1358 This routine releases the network specific resources allocated by
1359 ::EslTcp4PortAllocate.
1361 This routine is called by ::EslSocketPortClose.
1362 See the \ref PortCloseStateMachine section.
1364 @param [in] pPort Address of an ::ESL_PORT structure.
1366 @retval EFI_SUCCESS The port is closed
1367 @retval other Port close error
1376 ESL_TCP4_CONTEXT
* pTcp4
;
1382 // Locate the port in the socket list
1384 Status
= EFI_SUCCESS
;
1385 DebugFlags
= pPort
->DebugFlags
;
1386 pTcp4
= &pPort
->Context
.Tcp4
;
1389 // Done with the connect event
1391 if ( NULL
!= pTcp4
->ConnectToken
.CompletionToken
.Event
) {
1392 Status
= gBS
->CloseEvent ( pTcp4
->ConnectToken
.CompletionToken
.Event
);
1393 if ( !EFI_ERROR ( Status
)) {
1394 DEBUG (( DebugFlags
| DEBUG_POOL
,
1395 "0x%08x: Closed connect event\r\n",
1396 pTcp4
->ConnectToken
.CompletionToken
.Event
));
1399 DEBUG (( DEBUG_ERROR
| DebugFlags
,
1400 "ERROR - Failed to close the connect event, Status: %r\r\n",
1402 ASSERT ( EFI_SUCCESS
== Status
);
1407 // Done with the close event
1409 if ( NULL
!= pTcp4
->CloseToken
.CompletionToken
.Event
) {
1410 Status
= gBS
->CloseEvent ( pTcp4
->CloseToken
.CompletionToken
.Event
);
1411 if ( !EFI_ERROR ( Status
)) {
1412 DEBUG (( DebugFlags
| DEBUG_POOL
,
1413 "0x%08x: Closed close event\r\n",
1414 pTcp4
->CloseToken
.CompletionToken
.Event
));
1417 DEBUG (( DEBUG_ERROR
| DebugFlags
,
1418 "ERROR - Failed to close the close event, Status: %r\r\n",
1420 ASSERT ( EFI_SUCCESS
== Status
);
1425 // Done with the listen completion event
1427 if ( NULL
!= pTcp4
->ListenToken
.CompletionToken
.Event
) {
1428 Status
= gBS
->CloseEvent ( pTcp4
->ListenToken
.CompletionToken
.Event
);
1429 if ( !EFI_ERROR ( Status
)) {
1430 DEBUG (( DebugFlags
| DEBUG_POOL
,
1431 "0x%08x: Closed listen completion event\r\n",
1432 pTcp4
->ListenToken
.CompletionToken
.Event
));
1435 DEBUG (( DEBUG_ERROR
| DebugFlags
,
1436 "ERROR - Failed to close the listen completion event, Status: %r\r\n",
1438 ASSERT ( EFI_SUCCESS
== Status
);
1443 // Return the operation status
1445 DBG_EXIT_STATUS ( Status
);
1451 Perform the network specific close operation on the port.
1453 This routine performs a cancel operations on the TCPv4 port to
1454 shutdown the receive operations on the port.
1456 This routine is called by the ::EslSocketPortCloseTxDone
1457 routine after the port completes all of the transmission.
1459 @param [in] pPort Address of an ::ESL_PORT structure.
1461 @retval EFI_SUCCESS The port is closed, not normally returned
1462 @retval EFI_NOT_READY The port is still closing
1463 @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
1464 most likely the routine was called already.
1468 EslTcp4PortCloseOp (
1472 ESL_TCP4_CONTEXT
* pTcp4
;
1473 EFI_TCP4_PROTOCOL
* pTcp4Protocol
;
1479 // Close the configured port
1481 Status
= EFI_SUCCESS
;
1482 pTcp4
= &pPort
->Context
.Tcp4
;
1483 pTcp4Protocol
= pPort
->pProtocol
.TCPv4
;
1484 pTcp4
->CloseToken
.AbortOnClose
= pPort
->bCloseNow
;
1485 Status
= pTcp4Protocol
->Close ( pTcp4Protocol
,
1486 &pTcp4
->CloseToken
);
1487 if ( !EFI_ERROR ( Status
)) {
1488 DEBUG (( pPort
->DebugFlags
| DEBUG_CLOSE
| DEBUG_INFO
,
1489 "0x%08x: Port close started\r\n",
1493 DEBUG (( DEBUG_ERROR
| pPort
->DebugFlags
| DEBUG_CLOSE
| DEBUG_INFO
,
1494 "ERROR - Close failed on port 0x%08x, Status: %r\r\n",
1500 // Return the operation status
1502 DBG_EXIT_STATUS ( Status
);
1508 Receive data from a network connection.
1510 This routine attempts to return buffered data to the caller. The
1511 data is removed from the urgent queue if the message flag MSG_OOB
1512 is specified, otherwise data is removed from the normal queue.
1513 See the \ref ReceiveEngine section.
1515 This routine is called by ::EslSocketReceive to handle the network
1516 specific receive operation to support SOCK_STREAM and SOCK_SEQPACKET
1519 @param [in] pPort Address of an ::ESL_PORT structure.
1521 @param [in] pPacket Address of an ::ESL_PACKET structure.
1523 @param [in] pbConsumePacket Address of a BOOLEAN indicating if the packet is to be consumed
1525 @param [in] BufferLength Length of the the buffer
1527 @param [in] pBuffer Address of a buffer to receive the data.
1529 @param [in] pDataLength Number of received data bytes in the buffer.
1531 @param [out] pAddress Network address to receive the remote system address
1533 @param [out] pSkipBytes Address to receive the number of bytes skipped
1535 @return Returns the address of the next free byte in the buffer.
1540 IN ESL_PORT
* pPort
,
1541 IN ESL_PACKET
* pPacket
,
1542 IN BOOLEAN
* pbConsumePacket
,
1543 IN
size_t BufferLength
,
1545 OUT
size_t * pDataLength
,
1546 OUT
struct sockaddr
* pAddress
,
1547 OUT
size_t * pSkipBytes
1551 struct sockaddr_in
* pRemoteAddress
;
1552 ESL_TCP4_CONTEXT
* pTcp4
;
1557 // Return the remote system address if requested
1559 if ( NULL
!= pAddress
) {
1561 // Build the remote address
1563 pTcp4
= &pPort
->Context
.Tcp4
;
1565 "Getting packet remote address: %d.%d.%d.%d:%d\r\n",
1566 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[0],
1567 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[1],
1568 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[2],
1569 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[3],
1570 pTcp4
->ConfigData
.AccessPoint
.RemotePort
));
1571 pRemoteAddress
= (struct sockaddr_in
*)pAddress
;
1572 CopyMem ( &pRemoteAddress
->sin_addr
,
1573 &pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[0],
1574 sizeof ( pRemoteAddress
->sin_addr
));
1575 pRemoteAddress
->sin_port
= SwapBytes16 ( pTcp4
->ConfigData
.AccessPoint
.RemotePort
);
1579 // Determine the amount of received data
1581 DataLength
= pPacket
->ValidBytes
;
1582 if ( BufferLength
< DataLength
) {
1583 DataLength
= BufferLength
;
1587 // Move the data into the buffer
1590 "0x%08x: Port copy packet 0x%08x data into 0x%08x, 0x%08x bytes\r\n",
1595 CopyMem ( pBuffer
, pPacket
->pBuffer
, DataLength
);
1598 // Set the next buffer address
1600 pBuffer
+= DataLength
;
1603 // Determine if the data is being read
1605 if ( *pbConsumePacket
) {
1607 // Account for the bytes consumed
1609 pPacket
->pBuffer
+= DataLength
;
1610 pPacket
->ValidBytes
-= DataLength
;
1612 "0x%08x: Port account for 0x%08x bytes\r\n",
1617 // Determine if the entire packet was consumed
1619 if (( 0 == pPacket
->ValidBytes
)
1620 || ( SOCK_STREAM
!= pPort
->pSocket
->Type
)) {
1622 // All done with this packet
1623 // Account for any discarded data
1625 *pSkipBytes
= pPacket
->ValidBytes
;
1630 // More data to consume later
1632 *pbConsumePacket
= FALSE
;
1637 // Return the data length and the buffer address
1639 *pDataLength
= DataLength
;
1640 DBG_EXIT_HEX ( pBuffer
);
1646 Get the remote socket address.
1648 This routine returns the address of the remote connection point
1649 associated with the SOCK_STREAM or SOCK_SEQPACKET socket.
1651 This routine is called by ::EslSocketGetPeerAddress to detemine
1652 the TCPv4 address and por number associated with the network adapter.
1654 @param [in] pPort Address of an ::ESL_PORT structure.
1656 @param [out] pAddress Network address to receive the remote system address
1660 EslTcp4RemoteAddressGet (
1661 IN ESL_PORT
* pPort
,
1662 OUT
struct sockaddr
* pAddress
1665 struct sockaddr_in
* pRemoteAddress
;
1666 ESL_TCP4_CONTEXT
* pTcp4
;
1671 // Return the remote address
1673 pTcp4
= &pPort
->Context
.Tcp4
;
1674 pRemoteAddress
= (struct sockaddr_in
*)pAddress
;
1675 pRemoteAddress
->sin_family
= AF_INET
;
1676 pRemoteAddress
->sin_port
= SwapBytes16 ( pTcp4
->ConfigData
.AccessPoint
.RemotePort
);
1677 CopyMem ( &pRemoteAddress
->sin_addr
,
1678 &pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[0],
1679 sizeof ( pRemoteAddress
->sin_addr
));
1686 Set the remote address
1688 This routine sets the remote address in the port.
1690 This routine is called by ::EslSocketConnect to specify the
1691 remote network address.
1693 @param [in] pPort Address of an ::ESL_PORT structure.
1695 @param [in] pSockAddr Network address of the remote system.
1697 @param [in] SockAddrLength Length in bytes of the network address.
1699 @retval EFI_SUCCESS The operation was successful
1703 EslTcp4RemoteAddressSet (
1704 IN ESL_PORT
* pPort
,
1705 IN CONST
struct sockaddr
* pSockAddr
,
1706 IN socklen_t SockAddrLength
1709 CONST
struct sockaddr_in
* pRemoteAddress
;
1710 ESL_TCP4_CONTEXT
* pTcp4
;
1716 // Set the remote address
1718 pTcp4
= &pPort
->Context
.Tcp4
;
1719 pRemoteAddress
= (struct sockaddr_in
*)pSockAddr
;
1720 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[0] = (UINT8
)( pRemoteAddress
->sin_addr
.s_addr
);
1721 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[1] = (UINT8
)( pRemoteAddress
->sin_addr
.s_addr
>> 8 );
1722 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[2] = (UINT8
)( pRemoteAddress
->sin_addr
.s_addr
>> 16 );
1723 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[3] = (UINT8
)( pRemoteAddress
->sin_addr
.s_addr
>> 24 );
1724 pTcp4
->ConfigData
.AccessPoint
.RemotePort
= SwapBytes16 ( pRemoteAddress
->sin_port
);
1725 Status
= EFI_SUCCESS
;
1726 if ( INADDR_BROADCAST
== pRemoteAddress
->sin_addr
.s_addr
) {
1727 DEBUG (( DEBUG_CONNECT
,
1728 "ERROR - Invalid remote address\r\n" ));
1729 Status
= EFI_INVALID_PARAMETER
;
1730 pPort
->pSocket
->errno
= EAFNOSUPPORT
;
1734 // Return the operation status
1736 DBG_EXIT_STATUS ( Status
);
1742 Process the receive completion
1744 This routine queues the data in FIFO order in either the urgent
1745 or normal data queues depending upon the type of data received.
1746 See the \ref ReceiveEngine section.
1748 This routine is called by the TCPv4 driver when some data is
1751 Buffer the data that was just received.
1753 @param [in] Event The receive completion event
1755 @param [in] pIo Address of an ::ESL_IO_MGMT structure
1761 IN ESL_IO_MGMT
* pIo
1765 size_t LengthInBytes
;
1766 ESL_PACKET
* pPacket
;
1772 // Get the operation status.
1774 Status
= pIo
->Token
.Tcp4Rx
.CompletionToken
.Status
;
1777 // +--------------------+ +---------------------------+
1778 // | ESL_IO_MGMT | | ESL_PACKET |
1780 // | +---------------+ +-----------------------+ |
1781 // | | Token | | EFI_TCP4_RECEIVE_DATA | |
1782 // | | RxData --> | | |
1783 // | | | +-----------------------+---+
1784 // | | Event | | Data Buffer |
1785 // +----+---------------+ | |
1787 // +---------------------------+
1790 // Duplicate the buffer address and length for use by the
1791 // buffer handling code in EslTcp4Receive. These fields are
1792 // used when a partial read is done of the data from the
1795 pPacket
= pIo
->pPacket
;
1796 pPacket
->pBuffer
= pPacket
->Op
.Tcp4Rx
.RxData
.FragmentTable
[0].FragmentBuffer
;
1797 LengthInBytes
= pPacket
->Op
.Tcp4Rx
.RxData
.DataLength
;
1798 pPacket
->ValidBytes
= LengthInBytes
;
1801 // Get the data type so that it may be linked to the
1802 // correct receive buffer list on the ESL_SOCKET structure
1804 bUrgent
= pPacket
->Op
.Tcp4Rx
.RxData
.UrgentFlag
;
1807 // Complete this request
1809 EslSocketRxComplete ( pIo
, Status
, LengthInBytes
, bUrgent
);
1815 Start a receive operation
1817 This routine posts a receive buffer to the TCPv4 driver.
1818 See the \ref ReceiveEngine section.
1820 This support routine is called by EslSocketRxStart.
1822 @param [in] pPort Address of an ::ESL_PORT structure.
1823 @param [in] pIo Address of an ::ESL_IO_MGMT structure.
1828 IN ESL_PORT
* pPort
,
1829 IN ESL_IO_MGMT
* pIo
1832 ESL_PACKET
* pPacket
;
1837 // Initialize the buffer for receive
1839 pPacket
= pIo
->pPacket
;
1840 pIo
->Token
.Tcp4Rx
.Packet
.RxData
= &pPacket
->Op
.Tcp4Rx
.RxData
;
1841 pPacket
->Op
.Tcp4Rx
.RxData
.DataLength
= sizeof ( pPacket
->Op
.Tcp4Rx
.Buffer
);
1842 pPacket
->Op
.Tcp4Rx
.RxData
.FragmentCount
= 1;
1843 pPacket
->Op
.Tcp4Rx
.RxData
.FragmentTable
[0].FragmentLength
= pPacket
->Op
.Tcp4Rx
.RxData
.DataLength
;
1844 pPacket
->Op
.Tcp4Rx
.RxData
.FragmentTable
[0].FragmentBuffer
= &pPacket
->Op
.Tcp4Rx
.Buffer
[0];
1851 Determine if the socket is configured.
1853 This routine uses the flag ESL_SOCKET::bConfigured to determine
1854 if the network layer's configuration routine has been called.
1856 This routine is called by EslSocketIsConfigured to verify
1857 that the socket has been configured.
1859 @param [in] pSocket Address of an ::ESL_SOCKET structure.
1861 @retval EFI_SUCCESS - The port is connected
1862 @retval EFI_NOT_STARTED - The port is not connected
1866 EslTcp4SocketIsConfigured (
1867 IN ESL_SOCKET
* pSocket
1875 // Determine the socket configuration status
1877 Status
= pSocket
->bConfigured
? EFI_SUCCESS
: EFI_NOT_STARTED
;
1880 // Return the port connected state.
1882 DBG_EXIT_STATUS ( Status
);
1888 Buffer data for transmission over a network connection.
1890 This routine buffers data for the transmit engine in one of two
1891 queues, one for urgent (out-of-band) data and the other for normal
1892 data. The urgent data is provided to TCP as soon as it is available,
1893 allowing the TCP layer to schedule transmission of the urgent data
1894 between packets of normal data.
1896 This routine is called by ::EslSocketTransmit to buffer
1897 data for transmission. When the \ref TransmitEngine has resources,
1898 this routine will start the transmission of the next buffer on
1899 the network connection.
1901 Transmission errors are returned during the next transmission or
1902 during the close operation. Only buffering errors are returned
1903 during the current transmission attempt.
1905 @param [in] pSocket Address of an ::ESL_SOCKET structure
1907 @param [in] Flags Message control flags
1909 @param [in] BufferLength Length of the the buffer
1911 @param [in] pBuffer Address of a buffer to receive the data.
1913 @param [in] pDataLength Number of received data bytes in the buffer.
1915 @param [in] pAddress Network address of the remote system address
1917 @param [in] AddressLength Length of the remote network address structure
1919 @retval EFI_SUCCESS - Socket data successfully buffered
1924 IN ESL_SOCKET
* pSocket
,
1926 IN
size_t BufferLength
,
1927 IN CONST UINT8
* pBuffer
,
1928 OUT
size_t * pDataLength
,
1929 IN
const struct sockaddr
* pAddress
,
1930 IN socklen_t AddressLength
1934 BOOLEAN bUrgentQueue
;
1935 ESL_PACKET
* pPacket
;
1936 ESL_IO_MGMT
** ppActive
;
1937 ESL_IO_MGMT
** ppFree
;
1939 ESL_PACKET
** ppQueueHead
;
1940 ESL_PACKET
** ppQueueTail
;
1941 ESL_PACKET
* pPreviousPacket
;
1942 ESL_TCP4_CONTEXT
* pTcp4
;
1944 EFI_TCP4_TRANSMIT_DATA
* pTxData
;
1946 EFI_TPL TplPrevious
;
1953 Status
= EFI_UNSUPPORTED
;
1954 pSocket
->errno
= ENOTCONN
;
1958 // Verify that the socket is connected
1960 if ( SOCKET_STATE_CONNECTED
== pSocket
->State
) {
1964 pPort
= pSocket
->pPortList
;
1965 if ( NULL
!= pPort
) {
1967 // Determine the queue head
1969 pTcp4
= &pPort
->Context
.Tcp4
;
1970 bUrgent
= (BOOLEAN
)( 0 != ( Flags
& MSG_OOB
));
1971 bUrgentQueue
= bUrgent
1972 && ( !pSocket
->bOobInLine
)
1973 && pSocket
->pApi
->bOobSupported
;
1974 if ( bUrgentQueue
) {
1975 ppQueueHead
= &pSocket
->pTxOobPacketListHead
;
1976 ppQueueTail
= &pSocket
->pTxOobPacketListTail
;
1977 ppActive
= &pPort
->pTxOobActive
;
1978 ppFree
= &pPort
->pTxOobFree
;
1979 pTxBytes
= &pSocket
->TxOobBytes
;
1982 ppQueueHead
= &pSocket
->pTxPacketListHead
;
1983 ppQueueTail
= &pSocket
->pTxPacketListTail
;
1984 ppActive
= &pPort
->pTxActive
;
1985 ppFree
= &pPort
->pTxFree
;
1986 pTxBytes
= &pSocket
->TxBytes
;
1990 // Verify that there is enough room to buffer another
1991 // transmit operation
1993 if ( pSocket
->MaxTxBuf
> *pTxBytes
) {
1994 if ( pPort
->bTxFlowControl
) {
1996 "TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT\r\n0x%08x: pPort, TX flow control released, Max bytes: %d > %d bufferred bytes\r\n",
2000 pPort
->bTxFlowControl
= FALSE
;
2004 // Attempt to allocate the packet
2006 Status
= EslSocketPacketAllocate ( &pPacket
,
2007 sizeof ( pPacket
->Op
.Tcp4Tx
)
2008 - sizeof ( pPacket
->Op
.Tcp4Tx
.Buffer
)
2012 if ( !EFI_ERROR ( Status
)) {
2014 // Initialize the transmit operation
2016 pTxData
= &pPacket
->Op
.Tcp4Tx
.TxData
;
2017 pTxData
->Push
= TRUE
|| bUrgent
;
2018 pTxData
->Urgent
= bUrgent
;
2019 pTxData
->DataLength
= (UINT32
) BufferLength
;
2020 pTxData
->FragmentCount
= 1;
2021 pTxData
->FragmentTable
[0].FragmentLength
= (UINT32
) BufferLength
;
2022 pTxData
->FragmentTable
[0].FragmentBuffer
= &pPacket
->Op
.Tcp4Tx
.Buffer
[0];
2025 // Copy the data into the buffer
2027 CopyMem ( &pPacket
->Op
.Tcp4Tx
.Buffer
[0],
2032 // Synchronize with the socket layer
2034 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
2037 // Stop transmission after an error
2039 if ( !EFI_ERROR ( pSocket
->TxError
)) {
2041 // Display the request
2044 "Send %d %s bytes from 0x%08x\r\n",
2046 bUrgent
? L
"urgent" : L
"normal",
2050 // Queue the data for transmission
2052 pPacket
->pNext
= NULL
;
2053 pPreviousPacket
= *ppQueueTail
;
2054 if ( NULL
== pPreviousPacket
) {
2055 *ppQueueHead
= pPacket
;
2058 pPreviousPacket
->pNext
= pPacket
;
2060 *ppQueueTail
= pPacket
;
2062 "0x%08x: Packet on %s transmit list\r\n",
2064 bUrgentQueue
? L
"urgent" : L
"normal" ));
2067 // Account for the buffered data
2069 *pTxBytes
+= BufferLength
;
2070 *pDataLength
= BufferLength
;
2073 // Start the transmit engine if it is idle
2075 if ( NULL
!= *ppFree
) {
2076 EslSocketTxStart ( pPort
,
2085 // Previous transmit error
2086 // Stop transmission
2088 Status
= pSocket
->TxError
;
2089 pSocket
->errno
= EIO
;
2094 EslSocketPacketFree ( pPacket
, DEBUG_TX
);
2098 // Release the socket layer synchronization
2100 RESTORE_TPL ( TplPrevious
);
2104 // Packet allocation failed
2106 pSocket
->errno
= ENOMEM
;
2110 if ( !pPort
->bTxFlowControl
) {
2112 "0x%08x: pPort, TX flow control applied, Max bytes %d <= %d bufferred bytes\r\nTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT\r\n",
2116 pPort
->bTxFlowControl
= TRUE
;
2119 // Not enough buffer space available
2121 pSocket
->errno
= EAGAIN
;
2122 Status
= EFI_NOT_READY
;
2128 // Return the operation status
2130 DBG_EXIT_STATUS ( Status
);
2136 Process the normal data transmit completion
2138 This routine use ::EslSocketTxComplete to perform the transmit
2139 completion processing for normal data.
2141 This routine is called by the TCPv4 network layer when a
2142 normal data transmit request completes.
2144 @param [in] Event The normal transmit completion event
2146 @param [in] pIo The ESL_IO_MGMT structure address
2152 IN ESL_IO_MGMT
* pIo
2155 UINT32 LengthInBytes
;
2156 ESL_PACKET
* pPacket
;
2158 ESL_SOCKET
* pSocket
;
2164 // Locate the active transmit packet
2166 pPacket
= pIo
->pPacket
;
2168 pSocket
= pPort
->pSocket
;
2171 // Get the transmit length and status
2173 LengthInBytes
= pPacket
->Op
.Tcp4Tx
.TxData
.DataLength
;
2174 pSocket
->TxBytes
-= LengthInBytes
;
2175 Status
= pIo
->Token
.Tcp4Tx
.CompletionToken
.Status
;
2178 // Complete the transmit operation
2180 EslSocketTxComplete ( pIo
,
2184 &pSocket
->pTxPacketListHead
,
2185 &pSocket
->pTxPacketListTail
,
2193 Process the urgent data transmit completion
2195 This routine use ::EslSocketTxComplete to perform the transmit
2196 completion processing for urgent data.
2198 This routine is called by the TCPv4 network layer when a
2199 urgent data transmit request completes.
2201 @param [in] Event The urgent transmit completion event
2203 @param [in] pIo The ESL_IO_MGMT structure address
2207 EslTcp4TxOobComplete (
2209 IN ESL_IO_MGMT
* pIo
2212 UINT32 LengthInBytes
;
2213 ESL_PACKET
* pPacket
;
2215 ESL_SOCKET
* pSocket
;
2221 // Locate the active transmit packet
2223 pPacket
= pIo
->pPacket
;
2225 pSocket
= pPort
->pSocket
;
2228 // Get the transmit length and status
2230 LengthInBytes
= pPacket
->Op
.Tcp4Tx
.TxData
.DataLength
;
2231 pSocket
->TxOobBytes
-= LengthInBytes
;
2232 Status
= pIo
->Token
.Tcp4Tx
.CompletionToken
.Status
;
2235 // Complete the transmit operation
2237 EslSocketTxComplete ( pIo
,
2241 &pSocket
->pTxOobPacketListHead
,
2242 &pSocket
->pTxOobPacketListTail
,
2243 &pPort
->pTxOobActive
,
2244 &pPort
->pTxOobFree
);
2250 Interface between the socket layer and the network specific
2251 code that supports SOCK_STREAM and SOCK_SEQPACKET sockets
2254 CONST ESL_PROTOCOL_API cEslTcp4Api
= {
2257 OFFSET_OF ( ESL_PORT
, Context
.Tcp4
.ConfigData
),
2258 OFFSET_OF ( ESL_LAYER
, pTcp4List
),
2259 OFFSET_OF ( struct sockaddr_in
, sin_zero
),
2260 sizeof ( struct sockaddr_in
),
2262 sizeof (((ESL_PACKET
*)0 )->Op
.Tcp4Rx
),
2263 OFFSET_OF ( ESL_PACKET
, Op
.Tcp4Rx
.Buffer
) - OFFSET_OF ( ESL_PACKET
, Op
),
2264 OFFSET_OF ( ESL_IO_MGMT
, Token
.Tcp4Rx
.Packet
.RxData
),
2269 EslTcp4ConnectStart
,
2270 EslTcp4SocketIsConfigured
,
2271 EslTcp4LocalAddressGet
,
2272 EslTcp4LocalAddressSet
,
2277 EslTcp4PortAllocate
,
2282 EslTcp4RemoteAddressGet
,
2283 EslTcp4RemoteAddressSet
,
2288 EslTcp4TxOobComplete