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
;
461 // Determine if any more local adapters are available
463 pPort
= pSocket
->pPortList
;
464 if ( NULL
!= pPort
) {
466 // Configure the port
468 pTcp4
= &pPort
->Context
.Tcp4
;
469 pTcp4
->ConfigData
.AccessPoint
.ActiveFlag
= TRUE
;
470 pTcp4
->ConfigData
.TimeToLive
= 255;
471 pTcp4Protocol
= pPort
->pProtocol
.TCPv4
;
472 Status
= pTcp4Protocol
->Configure ( pTcp4Protocol
,
473 &pTcp4
->ConfigData
);
474 if ( EFI_ERROR ( Status
)) {
475 DEBUG (( DEBUG_CONNECT
,
476 "ERROR - Failed to configure the Tcp4 port, Status: %r\r\n",
479 case EFI_ACCESS_DENIED
:
480 pSocket
->errno
= EACCES
;
484 case EFI_DEVICE_ERROR
:
485 pSocket
->errno
= EIO
;
488 case EFI_INVALID_PARAMETER
:
489 pSocket
->errno
= EADDRNOTAVAIL
;
493 pSocket
->errno
= EAFNOSUPPORT
;
496 case EFI_OUT_OF_RESOURCES
:
497 pSocket
->errno
= ENOBUFS
;
500 case EFI_UNSUPPORTED
:
501 pSocket
->errno
= EOPNOTSUPP
;
506 DEBUG (( DEBUG_CONNECT
,
507 "0x%08x: Port configured\r\n",
509 pPort
->bConfigured
= TRUE
;
512 // Attempt the connection to the remote system
514 Status
= pTcp4Protocol
->Connect ( pTcp4Protocol
,
515 &pTcp4
->ConnectToken
);
516 if ( !EFI_ERROR ( Status
)) {
518 // Connection in progress
520 pSocket
->errno
= EINPROGRESS
;
521 Status
= EFI_NOT_READY
;
522 DEBUG (( DEBUG_CONNECT
,
523 "0x%08x: Port attempting connection to %d.%d.%d.%d:%d\r\n",
525 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[0],
526 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[1],
527 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[2],
528 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[3],
529 pTcp4
->ConfigData
.AccessPoint
.RemotePort
));
535 DEBUG (( DEBUG_CONNECT
,
536 "ERROR - Port 0x%08x not connected, Status: %r\r\n",
540 // Determine the errno value
544 pSocket
->errno
= EIO
;
547 case EFI_OUT_OF_RESOURCES
:
548 pSocket
->errno
= ENOBUFS
;
552 pSocket
->errno
= ETIMEDOUT
;
555 case EFI_NETWORK_UNREACHABLE
:
556 pSocket
->errno
= ENETDOWN
;
559 case EFI_HOST_UNREACHABLE
:
560 pSocket
->errno
= EHOSTUNREACH
;
563 case EFI_PORT_UNREACHABLE
:
564 case EFI_PROTOCOL_UNREACHABLE
:
565 case EFI_CONNECTION_REFUSED
:
566 pSocket
->errno
= ECONNREFUSED
;
569 case EFI_CONNECTION_RESET
:
570 pSocket
->errno
= ECONNRESET
;
578 // No more local adapters available
580 pSocket
->errno
= ENETUNREACH
;
581 Status
= EFI_NO_RESPONSE
;
585 // Return the operation status
587 DBG_EXIT_STATUS ( Status
);
593 Establish the known port to listen for network connections.
595 This routine places the port into a state that enables connection
598 This routine is called by ::EslSocketListen to handle the network
599 specifics of the listen operation for SOCK_STREAM and SOCK_SEQPACKET
600 sockets. See the \ref ConnectionManagement section.
602 @param [in] pSocket Address of an ::ESL_SOCKET structure.
604 @retval EFI_SUCCESS - Socket successfully created
605 @retval Other - Failed to enable the socket for listen
610 IN ESL_SOCKET
* pSocket
613 ESL_PORT
* pNextPort
;
615 ESL_TCP4_CONTEXT
* pTcp4
;
616 EFI_TCP4_PROTOCOL
* pTcp4Protocol
;
622 // Verify the socket layer synchronization
624 VERIFY_TPL ( TPL_SOCKETS
);
627 // Use for/break instead of goto
631 // Assume no ports are available
633 pSocket
->errno
= EOPNOTSUPP
;
634 Status
= EFI_NOT_READY
;
637 // Walk the list of ports
639 pPort
= pSocket
->pPortList
;
640 while ( NULL
!= pPort
) {
647 // Use for/break insteak of goto
651 // Create the listen completion event
653 pTcp4
= &pPort
->Context
.Tcp4
;
654 Status
= gBS
->CreateEvent ( EVT_NOTIFY_SIGNAL
,
656 (EFI_EVENT_NOTIFY
)EslTcp4ListenComplete
,
658 &pTcp4
->ListenToken
.CompletionToken
.Event
);
659 if ( EFI_ERROR ( Status
)) {
660 DEBUG (( DEBUG_ERROR
| DEBUG_LISTEN
,
661 "ERROR - Failed to create the listen completion event, Status: %r\r\n",
663 pSocket
->errno
= ENOMEM
;
667 "0x%08x: Created listen completion event\r\n",
668 pTcp4
->ListenToken
.CompletionToken
.Event
));
671 // Configure the port
673 pTcp4Protocol
= pPort
->pProtocol
.TCPv4
;
674 Status
= pTcp4Protocol
->Configure ( pTcp4Protocol
,
675 &pTcp4
->ConfigData
);
676 if ( EFI_ERROR ( Status
)) {
677 DEBUG (( DEBUG_LISTEN
,
678 "ERROR - Failed to configure the Tcp4 port, Status: %r\r\n",
681 case EFI_ACCESS_DENIED
:
682 pSocket
->errno
= EACCES
;
686 case EFI_DEVICE_ERROR
:
687 pSocket
->errno
= EIO
;
690 case EFI_INVALID_PARAMETER
:
691 pSocket
->errno
= EADDRNOTAVAIL
;
695 pSocket
->errno
= EAFNOSUPPORT
;
698 case EFI_OUT_OF_RESOURCES
:
699 pSocket
->errno
= ENOBUFS
;
702 case EFI_UNSUPPORTED
:
703 pSocket
->errno
= EOPNOTSUPP
;
708 DEBUG (( DEBUG_LISTEN
,
709 "0x%08x: Port configured\r\n",
711 pPort
->bConfigured
= TRUE
;
714 // Start the listen operation on the port
716 Status
= pTcp4Protocol
->Accept ( pTcp4Protocol
,
717 &pTcp4
->ListenToken
);
718 if ( EFI_ERROR ( Status
)) {
719 DEBUG (( DEBUG_LISTEN
,
720 "ERROR - Failed Tcp4 accept, Status: %r\r\n",
723 case EFI_ACCESS_DENIED
:
724 pSocket
->errno
= EACCES
;
728 case EFI_DEVICE_ERROR
:
729 pSocket
->errno
= EIO
;
732 case EFI_INVALID_PARAMETER
:
733 pSocket
->errno
= EADDRNOTAVAIL
;
736 case EFI_NOT_STARTED
:
737 pSocket
->errno
= ENETDOWN
;
740 case EFI_OUT_OF_RESOURCES
:
741 pSocket
->errno
= ENOBUFS
;
746 DEBUG (( DEBUG_LISTEN
,
747 "0x%08x: Listen pending on Port\r\n",
751 // Listen is pending on this port
759 pNextPort
= pPort
->pLinkSocket
;
762 // Close the port upon error
764 if ( EFI_ERROR ( Status
)) {
765 EslSocketPortCloseStart ( pPort
, TRUE
, DEBUG_LISTEN
);
775 // Determine if any ports are in the listen state
777 if ( NULL
== pSocket
->pPortList
) {
779 // No ports in the listen state
781 pSocket
->MaxFifoDepth
= 0;
784 // Return the last error detected
790 // Mark the socket as configured
792 pSocket
->bConfigured
= TRUE
;
797 DEBUG (( DEBUG_LISTEN
,
798 "0x%08x: pSocket - Listen pending on socket\r\n",
804 // Return the operation status
806 DBG_EXIT_STATUS ( Status
);
812 Process the connection attempt
814 A system has initiated a connection attempt with a socket in the
815 listen state. Attempt to complete the connection.
817 The TCPv4 layer calls this routine when a connection is made to
818 the socket in the listen state. See the
819 \ref ConnectionManagement section.
821 @param [in] Event The listen completion event
823 @param [in] pPort Address of an ::ESL_PORT structure.
827 EslTcp4ListenComplete (
832 EFI_HANDLE ChildHandle
;
833 struct sockaddr_in LocalAddress
;
834 EFI_TCP4_CONFIG_DATA
* pConfigData
;
837 ESL_SOCKET
* pNewSocket
;
838 ESL_SOCKET
* pSocket
;
839 ESL_TCP4_CONTEXT
* pTcp4
;
840 EFI_TCP4_PROTOCOL
* pTcp4Protocol
;
842 EFI_HANDLE TcpPortHandle
;
843 EFI_STATUS TempStatus
;
846 VERIFY_AT_TPL ( TPL_SOCKETS
);
851 Status
= EFI_SUCCESS
;
854 // Determine if this connection fits into the connection FIFO
856 pSocket
= pPort
->pSocket
;
857 TcpPortHandle
= pPort
->Context
.Tcp4
.ListenToken
.NewChildHandle
;
858 if (( SOCKET_STATE_LISTENING
== pSocket
->State
)
859 && ( pSocket
->MaxFifoDepth
> pSocket
->FifoDepth
)) {
861 // Allocate a socket for this connection
865 Status
= EslSocketAllocate ( &ChildHandle
,
868 if ( !EFI_ERROR ( Status
)) {
870 // Clone the socket parameters
872 pNewSocket
->pApi
= pSocket
->pApi
;
873 pNewSocket
->Domain
= pSocket
->Domain
;
874 pNewSocket
->Protocol
= pSocket
->Protocol
;
875 pNewSocket
->Type
= pSocket
->Type
;
878 // Build the local address
880 pTcp4
= &pPort
->Context
.Tcp4
;
881 LocalAddress
.sin_len
= (uint8_t)pNewSocket
->pApi
->MinimumAddressLength
;
882 LocalAddress
.sin_family
= AF_INET
;
883 LocalAddress
.sin_port
= 0;
884 LocalAddress
.sin_addr
.s_addr
= *(UINT32
*)&pTcp4
->ConfigData
.AccessPoint
.StationAddress
.Addr
[0];
887 // Allocate a port for this connection
888 // Note in this instance Configure may not be called with NULL!
890 Status
= EslSocketPortAllocate ( pNewSocket
,
893 (struct sockaddr
*)&LocalAddress
,
897 if ( !EFI_ERROR ( Status
)) {
899 // Restart the listen operation on the port
901 pTcp4Protocol
= pPort
->pProtocol
.TCPv4
;
902 Status
= pTcp4Protocol
->Accept ( pTcp4Protocol
,
903 &pTcp4
->ListenToken
);
906 // Close the TCP port using SocketClose
908 TcpPortHandle
= NULL
;
909 pTcp4
= &pNewPort
->Context
.Tcp4
;
912 // Check for an accept call error
914 if ( !EFI_ERROR ( Status
)) {
916 // Get the port configuration
918 pNewPort
->bConfigured
= TRUE
;
919 pConfigData
= &pTcp4
->ConfigData
;
920 pConfigData
->ControlOption
= &pTcp4
->Option
;
921 pTcp4Protocol
= pNewPort
->pProtocol
.TCPv4
;
922 Status
= pTcp4Protocol
->GetModeData ( pTcp4Protocol
,
928 if ( !EFI_ERROR ( Status
)) {
930 // Add the new socket to the connection FIFO
932 if ( NULL
== pSocket
->pFifoTail
) {
936 pSocket
->pFifoHead
= pNewSocket
;
940 // Add to end of list.
942 pSocket
->pFifoTail
->pNextConnection
= pNewSocket
;
944 pSocket
->pFifoTail
= pNewSocket
;
945 pSocket
->FifoDepth
+= 1;
948 // Update the socket state
950 pNewSocket
->State
= SOCKET_STATE_IN_FIFO
;
953 // Log the connection
955 DEBUG (( DEBUG_CONNECTION
| DEBUG_INFO
,
956 "0x%08x: Socket on port %d.%d.%d.%d:%d connected to %d.%d.%d.%d:%d\r\n",
958 pConfigData
->AccessPoint
.StationAddress
.Addr
[0],
959 pConfigData
->AccessPoint
.StationAddress
.Addr
[1],
960 pConfigData
->AccessPoint
.StationAddress
.Addr
[2],
961 pConfigData
->AccessPoint
.StationAddress
.Addr
[3],
962 pConfigData
->AccessPoint
.StationPort
,
963 pConfigData
->AccessPoint
.RemoteAddress
.Addr
[0],
964 pConfigData
->AccessPoint
.RemoteAddress
.Addr
[1],
965 pConfigData
->AccessPoint
.RemoteAddress
.Addr
[2],
966 pConfigData
->AccessPoint
.RemoteAddress
.Addr
[3],
967 pConfigData
->AccessPoint
.RemotePort
));
968 DEBUG (( DEBUG_CONNECTION
| DEBUG_INFO
,
969 "0x%08x: Listen socket adding socket 0x%08x to FIFO, depth: %d\r\n",
972 pSocket
->FifoDepth
));
975 // Start the receive operation
977 EslSocketRxStart ( pNewPort
);
980 DEBUG (( DEBUG_ERROR
| DEBUG_CONNECTION
| DEBUG_INFO
,
981 "ERROR - GetModeData failed on port 0x%08x, Status: %r\r\n",
988 // The listen failed on this port
990 DEBUG (( DEBUG_LISTEN
| DEBUG_INFO
,
991 "ERROR - Listen failed on port 0x%08x, Status: %r\r\n",
996 // Close the listening port
998 EslSocketPortCloseStart ( pPort
, TRUE
, DEBUG_LISTEN
);
1003 // Done with the socket if necessary
1005 if ( EFI_ERROR ( Status
)) {
1006 TempStatus
= EslSocketCloseStart ( &pNewSocket
->SocketProtocol
,
1009 ASSERT ( EFI_SUCCESS
== TempStatus
);
1014 DEBUG (( DEBUG_CONNECTION
,
1015 "0x%08x: Socket FIFO full, connection refused\r\n",
1019 // The FIFO is full or the socket is in the wrong state
1021 Status
= EFI_BUFFER_TOO_SMALL
;
1025 // Close the connection if necessary
1027 if (( EFI_ERROR ( Status
))
1028 && ( NULL
== TcpPortHandle
)) {
1030 // TODO: Finish this code path
1031 // The new connection does not fit into the connection FIFO
1035 // Release the resources
1044 Get the local socket address.
1046 This routine returns the IPv4 address and TCP port number associated
1047 with the local socket.
1049 This routine is called by ::EslSocketGetLocalAddress to determine the
1050 network address for the SOCK_STREAM or SOCK_SEQPACKET socket.
1052 @param [in] pPort Address of an ::ESL_PORT structure.
1054 @param [out] pSockAddr Network address to receive the local system address
1058 EslTcp4LocalAddressGet (
1059 IN ESL_PORT
* pPort
,
1060 OUT
struct sockaddr
* pSockAddr
1063 struct sockaddr_in
* pLocalAddress
;
1064 ESL_TCP4_CONTEXT
* pTcp4
;
1069 // Return the local address
1071 pTcp4
= &pPort
->Context
.Tcp4
;
1072 pLocalAddress
= (struct sockaddr_in
*)pSockAddr
;
1073 pLocalAddress
->sin_family
= AF_INET
;
1074 pLocalAddress
->sin_port
= SwapBytes16 ( pTcp4
->ConfigData
.AccessPoint
.StationPort
);
1075 CopyMem ( &pLocalAddress
->sin_addr
,
1076 &pTcp4
->ConfigData
.AccessPoint
.StationAddress
.Addr
[0],
1077 sizeof ( pLocalAddress
->sin_addr
));
1084 Set the local port address.
1086 This routine sets the local port address.
1088 This support routine is called by ::EslSocketPortAllocate.
1090 @param [in] pPort Address of an ESL_PORT structure
1091 @param [in] pSockAddr Address of a sockaddr structure that contains the
1092 connection point on the local machine. An IPv4 address
1093 of INADDR_ANY specifies that the connection is made to
1094 all of the network stacks on the platform. Specifying a
1095 specific IPv4 address restricts the connection to the
1096 network stack supporting that address. Specifying zero
1097 for the port causes the network layer to assign a port
1098 number from the dynamic range. Specifying a specific
1099 port number causes the network layer to use that port.
1101 @param [in] bBindTest TRUE = run bind testing
1103 @retval EFI_SUCCESS The operation was successful
1107 EslTcp4LocalAddressSet (
1108 IN ESL_PORT
* pPort
,
1109 IN CONST
struct sockaddr
* pSockAddr
,
1110 IN BOOLEAN bBindTest
1113 EFI_TCP4_ACCESS_POINT
* pAccessPoint
;
1114 CONST
struct sockaddr_in
* pIpAddress
;
1115 CONST UINT8
* pIpv4Address
;
1121 // Validate the address
1123 pIpAddress
= (struct sockaddr_in
*)pSockAddr
;
1124 if ( INADDR_BROADCAST
== pIpAddress
->sin_addr
.s_addr
) {
1126 // The local address must not be the broadcast address
1128 Status
= EFI_INVALID_PARAMETER
;
1129 pPort
->pSocket
->errno
= EADDRNOTAVAIL
;
1133 // Set the local address
1135 pIpv4Address
= (UINT8
*)&pIpAddress
->sin_addr
.s_addr
;
1136 pAccessPoint
= &pPort
->Context
.Tcp4
.ConfigData
.AccessPoint
;
1137 pAccessPoint
->StationAddress
.Addr
[0] = pIpv4Address
[0];
1138 pAccessPoint
->StationAddress
.Addr
[1] = pIpv4Address
[1];
1139 pAccessPoint
->StationAddress
.Addr
[2] = pIpv4Address
[2];
1140 pAccessPoint
->StationAddress
.Addr
[3] = pIpv4Address
[3];
1143 // Determine if the default address is used
1145 pAccessPoint
->UseDefaultAddress
= (BOOLEAN
)( 0 == pIpAddress
->sin_addr
.s_addr
);
1148 // Set the subnet mask
1150 if ( pAccessPoint
->UseDefaultAddress
) {
1151 pAccessPoint
->SubnetMask
.Addr
[0] = 0;
1152 pAccessPoint
->SubnetMask
.Addr
[1] = 0;
1153 pAccessPoint
->SubnetMask
.Addr
[2] = 0;
1154 pAccessPoint
->SubnetMask
.Addr
[3] = 0;
1157 pAccessPoint
->SubnetMask
.Addr
[0] = 0xff;
1158 pAccessPoint
->SubnetMask
.Addr
[1] = 0xff;
1159 pAccessPoint
->SubnetMask
.Addr
[2] = 0xff;
1160 pAccessPoint
->SubnetMask
.Addr
[3] = 0xff;
1164 // Validate the IP address
1166 pAccessPoint
->StationPort
= 0;
1167 Status
= bBindTest
? EslSocketBindTest ( pPort
, EADDRNOTAVAIL
)
1169 if ( !EFI_ERROR ( Status
)) {
1171 // Set the port number
1173 pAccessPoint
->StationPort
= SwapBytes16 ( pIpAddress
->sin_port
);
1176 // Display the local address
1178 DEBUG (( DEBUG_BIND
,
1179 "0x%08x: Port, Local TCP4 Address: %d.%d.%d.%d:%d\r\n",
1181 pAccessPoint
->StationAddress
.Addr
[0],
1182 pAccessPoint
->StationAddress
.Addr
[1],
1183 pAccessPoint
->StationAddress
.Addr
[2],
1184 pAccessPoint
->StationAddress
.Addr
[3],
1185 pAccessPoint
->StationPort
));
1190 // Return the operation status
1192 DBG_EXIT_STATUS ( Status
);
1198 Free a receive packet
1200 This routine performs the network specific operations necessary
1201 to free a receive packet.
1203 This routine is called by ::EslSocketPortCloseTxDone to free a
1206 @param [in] pPacket Address of an ::ESL_PACKET structure.
1207 @param [in, out] pRxBytes Address of the count of RX bytes
1212 IN ESL_PACKET
* pPacket
,
1213 IN OUT
size_t * pRxBytes
1219 // Account for the receive bytes
1221 *pRxBytes
-= pPacket
->Op
.Tcp4Rx
.RxData
.DataLength
;
1227 Initialize the network specific portions of an ::ESL_PORT structure.
1229 This routine initializes the network specific portions of an
1230 ::ESL_PORT structure for use by the socket.
1232 This support routine is called by ::EslSocketPortAllocate
1233 to connect the socket with the underlying network adapter
1234 running the TCPv4 protocol.
1236 @param [in] pPort Address of an ESL_PORT structure
1237 @param [in] DebugFlags Flags for debug messages
1239 @retval EFI_SUCCESS - Socket successfully created
1243 EslTcp4PortAllocate (
1244 IN ESL_PORT
* pPort
,
1248 EFI_TCP4_ACCESS_POINT
* pAccessPoint
;
1249 ESL_SOCKET
* pSocket
;
1250 ESL_TCP4_CONTEXT
* pTcp4
;
1256 // Use for/break instead of goto
1259 // Allocate the close event
1261 pSocket
= pPort
->pSocket
;
1262 pTcp4
= &pPort
->Context
.Tcp4
;
1263 Status
= gBS
->CreateEvent ( EVT_NOTIFY_SIGNAL
,
1265 (EFI_EVENT_NOTIFY
)EslSocketPortCloseComplete
,
1267 &pTcp4
->CloseToken
.CompletionToken
.Event
);
1268 if ( EFI_ERROR ( Status
)) {
1269 DEBUG (( DEBUG_ERROR
| DebugFlags
,
1270 "ERROR - Failed to create the close event, Status: %r\r\n",
1272 pSocket
->errno
= ENOMEM
;
1275 DEBUG (( DEBUG_CLOSE
| DEBUG_POOL
,
1276 "0x%08x: Created close event\r\n",
1277 pTcp4
->CloseToken
.CompletionToken
.Event
));
1280 // Allocate the connection event
1282 Status
= gBS
->CreateEvent ( EVT_NOTIFY_SIGNAL
,
1284 (EFI_EVENT_NOTIFY
)EslTcp4ConnectComplete
,
1286 &pTcp4
->ConnectToken
.CompletionToken
.Event
);
1287 if ( EFI_ERROR ( Status
)) {
1288 DEBUG (( DEBUG_ERROR
| DebugFlags
,
1289 "ERROR - Failed to create the connect event, Status: %r\r\n",
1291 pSocket
->errno
= ENOMEM
;
1294 DEBUG (( DEBUG_CLOSE
| DEBUG_POOL
,
1295 "0x%08x: Created connect event\r\n",
1296 pTcp4
->ConnectToken
.CompletionToken
.Event
));
1299 // Initialize the port
1301 pSocket
->TxPacketOffset
= OFFSET_OF ( ESL_PACKET
, Op
.Tcp4Tx
.TxData
);
1302 pSocket
->TxTokenEventOffset
= OFFSET_OF ( ESL_IO_MGMT
, Token
.Tcp4Tx
.CompletionToken
.Event
);
1303 pSocket
->TxTokenOffset
= OFFSET_OF ( EFI_TCP4_IO_TOKEN
, Packet
.TxData
);
1306 // Save the cancel, receive and transmit addresses
1307 // pPort->pfnRxCancel = NULL; since the UEFI implementation returns EFI_UNSUPPORTED
1309 pPort
->pfnConfigure
= (PFN_NET_CONFIGURE
)pPort
->pProtocol
.TCPv4
->Configure
;
1310 pPort
->pfnRxStart
= (PFN_NET_IO_START
)pPort
->pProtocol
.TCPv4
->Receive
;
1311 pPort
->pfnTxStart
= (PFN_NET_IO_START
)pPort
->pProtocol
.TCPv4
->Transmit
;
1314 // Set the configuration flags
1316 pAccessPoint
= &pPort
->Context
.Tcp4
.ConfigData
.AccessPoint
;
1317 pAccessPoint
->ActiveFlag
= FALSE
;
1318 pTcp4
->ConfigData
.TimeToLive
= 255;
1323 // Return the operation status
1325 DBG_EXIT_STATUS ( Status
);
1333 This routine releases the network specific resources allocated by
1334 ::EslTcp4PortAllocate.
1336 This routine is called by ::EslSocketPortClose.
1337 See the \ref PortCloseStateMachine section.
1339 @param [in] pPort Address of an ::ESL_PORT structure.
1341 @retval EFI_SUCCESS The port is closed
1342 @retval other Port close error
1351 ESL_TCP4_CONTEXT
* pTcp4
;
1357 // Locate the port in the socket list
1359 Status
= EFI_SUCCESS
;
1360 DebugFlags
= pPort
->DebugFlags
;
1361 pTcp4
= &pPort
->Context
.Tcp4
;
1364 // Done with the connect event
1366 if ( NULL
!= pTcp4
->ConnectToken
.CompletionToken
.Event
) {
1367 Status
= gBS
->CloseEvent ( pTcp4
->ConnectToken
.CompletionToken
.Event
);
1368 if ( !EFI_ERROR ( Status
)) {
1369 DEBUG (( DebugFlags
| DEBUG_POOL
,
1370 "0x%08x: Closed connect event\r\n",
1371 pTcp4
->ConnectToken
.CompletionToken
.Event
));
1374 DEBUG (( DEBUG_ERROR
| DebugFlags
,
1375 "ERROR - Failed to close the connect event, Status: %r\r\n",
1377 ASSERT ( EFI_SUCCESS
== Status
);
1382 // Done with the close event
1384 if ( NULL
!= pTcp4
->CloseToken
.CompletionToken
.Event
) {
1385 Status
= gBS
->CloseEvent ( pTcp4
->CloseToken
.CompletionToken
.Event
);
1386 if ( !EFI_ERROR ( Status
)) {
1387 DEBUG (( DebugFlags
| DEBUG_POOL
,
1388 "0x%08x: Closed close event\r\n",
1389 pTcp4
->CloseToken
.CompletionToken
.Event
));
1392 DEBUG (( DEBUG_ERROR
| DebugFlags
,
1393 "ERROR - Failed to close the close event, Status: %r\r\n",
1395 ASSERT ( EFI_SUCCESS
== Status
);
1400 // Done with the listen completion event
1402 if ( NULL
!= pTcp4
->ListenToken
.CompletionToken
.Event
) {
1403 Status
= gBS
->CloseEvent ( pTcp4
->ListenToken
.CompletionToken
.Event
);
1404 if ( !EFI_ERROR ( Status
)) {
1405 DEBUG (( DebugFlags
| DEBUG_POOL
,
1406 "0x%08x: Closed listen completion event\r\n",
1407 pTcp4
->ListenToken
.CompletionToken
.Event
));
1410 DEBUG (( DEBUG_ERROR
| DebugFlags
,
1411 "ERROR - Failed to close the listen completion event, Status: %r\r\n",
1413 ASSERT ( EFI_SUCCESS
== Status
);
1418 // Return the operation status
1420 DBG_EXIT_STATUS ( Status
);
1426 Perform the network specific close operation on the port.
1428 This routine performs a cancel operations on the TCPv4 port to
1429 shutdown the receive operations on the port.
1431 This routine is called by the ::EslSocketPortCloseTxDone
1432 routine after the port completes all of the transmission.
1434 @param [in] pPort Address of an ::ESL_PORT structure.
1436 @retval EFI_SUCCESS The port is closed, not normally returned
1437 @retval EFI_NOT_READY The port is still closing
1438 @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
1439 most likely the routine was called already.
1443 EslTcp4PortCloseOp (
1447 ESL_TCP4_CONTEXT
* pTcp4
;
1448 EFI_TCP4_PROTOCOL
* pTcp4Protocol
;
1454 // Close the configured port
1456 Status
= EFI_SUCCESS
;
1457 pTcp4
= &pPort
->Context
.Tcp4
;
1458 pTcp4Protocol
= pPort
->pProtocol
.TCPv4
;
1459 pTcp4
->CloseToken
.AbortOnClose
= pPort
->bCloseNow
;
1460 Status
= pTcp4Protocol
->Close ( pTcp4Protocol
,
1461 &pTcp4
->CloseToken
);
1462 if ( !EFI_ERROR ( Status
)) {
1463 DEBUG (( pPort
->DebugFlags
| DEBUG_CLOSE
| DEBUG_INFO
,
1464 "0x%08x: Port close started\r\n",
1468 DEBUG (( DEBUG_ERROR
| pPort
->DebugFlags
| DEBUG_CLOSE
| DEBUG_INFO
,
1469 "ERROR - Close failed on port 0x%08x, Status: %r\r\n",
1475 // Return the operation status
1477 DBG_EXIT_STATUS ( Status
);
1483 Receive data from a network connection.
1485 This routine attempts to return buffered data to the caller. The
1486 data is removed from the urgent queue if the message flag MSG_OOB
1487 is specified, otherwise data is removed from the normal queue.
1488 See the \ref ReceiveEngine section.
1490 This routine is called by ::EslSocketReceive to handle the network
1491 specific receive operation to support SOCK_STREAM and SOCK_SEQPACKET
1494 @param [in] pPort Address of an ::ESL_PORT structure.
1496 @param [in] pPacket Address of an ::ESL_PACKET structure.
1498 @param [in] pbConsumePacket Address of a BOOLEAN indicating if the packet is to be consumed
1500 @param [in] BufferLength Length of the the buffer
1502 @param [in] pBuffer Address of a buffer to receive the data.
1504 @param [in] pDataLength Number of received data bytes in the buffer.
1506 @param [out] pAddress Network address to receive the remote system address
1508 @param [out] pSkipBytes Address to receive the number of bytes skipped
1510 @return Returns the address of the next free byte in the buffer.
1515 IN ESL_PORT
* pPort
,
1516 IN ESL_PACKET
* pPacket
,
1517 IN BOOLEAN
* pbConsumePacket
,
1518 IN
size_t BufferLength
,
1520 OUT
size_t * pDataLength
,
1521 OUT
struct sockaddr
* pAddress
,
1522 OUT
size_t * pSkipBytes
1526 struct sockaddr_in
* pRemoteAddress
;
1527 ESL_TCP4_CONTEXT
* pTcp4
;
1532 // Return the remote system address if requested
1534 if ( NULL
!= pAddress
) {
1536 // Build the remote address
1538 pTcp4
= &pPort
->Context
.Tcp4
;
1540 "Getting packet remote address: %d.%d.%d.%d:%d\r\n",
1541 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[0],
1542 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[1],
1543 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[2],
1544 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[3],
1545 pTcp4
->ConfigData
.AccessPoint
.RemotePort
));
1546 pRemoteAddress
= (struct sockaddr_in
*)pAddress
;
1547 CopyMem ( &pRemoteAddress
->sin_addr
,
1548 &pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[0],
1549 sizeof ( pRemoteAddress
->sin_addr
));
1550 pRemoteAddress
->sin_port
= SwapBytes16 ( pTcp4
->ConfigData
.AccessPoint
.RemotePort
);
1554 // Determine the amount of received data
1556 DataLength
= pPacket
->ValidBytes
;
1557 if ( BufferLength
< DataLength
) {
1558 DataLength
= BufferLength
;
1562 // Move the data into the buffer
1565 "0x%08x: Port copy packet 0x%08x data into 0x%08x, 0x%08x bytes\r\n",
1570 CopyMem ( pBuffer
, pPacket
->pBuffer
, DataLength
);
1573 // Determine if the data is being read
1575 if ( *pbConsumePacket
) {
1577 // Account for the bytes consumed
1579 pPacket
->pBuffer
+= DataLength
;
1580 pPacket
->ValidBytes
-= DataLength
;
1582 "0x%08x: Port account for 0x%08x bytes\r\n",
1587 // Determine if the entire packet was consumed
1589 if (( 0 == pPacket
->ValidBytes
)
1590 || ( SOCK_STREAM
!= pPort
->pSocket
->Type
)) {
1592 // All done with this packet
1593 // Account for any discarded data
1595 *pSkipBytes
= pPacket
->ValidBytes
;
1600 // More data to consume later
1602 *pbConsumePacket
= FALSE
;
1607 // Return the data length and the buffer address
1609 *pDataLength
= DataLength
;
1610 DBG_EXIT_HEX ( pBuffer
);
1616 Get the remote socket address.
1618 This routine returns the address of the remote connection point
1619 associated with the SOCK_STREAM or SOCK_SEQPACKET socket.
1621 This routine is called by ::EslSocketGetPeerAddress to detemine
1622 the TCPv4 address and por number associated with the network adapter.
1624 @param [in] pPort Address of an ::ESL_PORT structure.
1626 @param [out] pAddress Network address to receive the remote system address
1630 EslTcp4RemoteAddressGet (
1631 IN ESL_PORT
* pPort
,
1632 OUT
struct sockaddr
* pAddress
1635 struct sockaddr_in
* pRemoteAddress
;
1636 ESL_TCP4_CONTEXT
* pTcp4
;
1641 // Return the remote address
1643 pTcp4
= &pPort
->Context
.Tcp4
;
1644 pRemoteAddress
= (struct sockaddr_in
*)pAddress
;
1645 pRemoteAddress
->sin_family
= AF_INET
;
1646 pRemoteAddress
->sin_port
= SwapBytes16 ( pTcp4
->ConfigData
.AccessPoint
.RemotePort
);
1647 CopyMem ( &pRemoteAddress
->sin_addr
,
1648 &pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[0],
1649 sizeof ( pRemoteAddress
->sin_addr
));
1656 Set the remote address
1658 This routine sets the remote address in the port.
1660 This routine is called by ::EslSocketConnect to specify the
1661 remote network address.
1663 @param [in] pPort Address of an ::ESL_PORT structure.
1665 @param [in] pSockAddr Network address of the remote system.
1667 @param [in] SockAddrLength Length in bytes of the network address.
1669 @retval EFI_SUCCESS The operation was successful
1673 EslTcp4RemoteAddressSet (
1674 IN ESL_PORT
* pPort
,
1675 IN CONST
struct sockaddr
* pSockAddr
,
1676 IN socklen_t SockAddrLength
1679 CONST
struct sockaddr_in
* pRemoteAddress
;
1680 ESL_TCP4_CONTEXT
* pTcp4
;
1686 // Set the remote address
1688 pTcp4
= &pPort
->Context
.Tcp4
;
1689 pRemoteAddress
= (struct sockaddr_in
*)pSockAddr
;
1690 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[0] = (UINT8
)( pRemoteAddress
->sin_addr
.s_addr
);
1691 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[1] = (UINT8
)( pRemoteAddress
->sin_addr
.s_addr
>> 8 );
1692 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[2] = (UINT8
)( pRemoteAddress
->sin_addr
.s_addr
>> 16 );
1693 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[3] = (UINT8
)( pRemoteAddress
->sin_addr
.s_addr
>> 24 );
1694 pTcp4
->ConfigData
.AccessPoint
.RemotePort
= SwapBytes16 ( pRemoteAddress
->sin_port
);
1695 Status
= EFI_SUCCESS
;
1696 if ( INADDR_BROADCAST
== pRemoteAddress
->sin_addr
.s_addr
) {
1697 DEBUG (( DEBUG_CONNECT
,
1698 "ERROR - Invalid remote address\r\n" ));
1699 Status
= EFI_INVALID_PARAMETER
;
1700 pPort
->pSocket
->errno
= EAFNOSUPPORT
;
1704 // Return the operation status
1706 DBG_EXIT_STATUS ( Status
);
1712 Process the receive completion
1714 This routine queues the data in FIFO order in either the urgent
1715 or normal data queues depending upon the type of data received.
1716 See the \ref ReceiveEngine section.
1718 This routine is called by the TCPv4 driver when some data is
1721 Buffer the data that was just received.
1723 @param [in] Event The receive completion event
1725 @param [in] pIo Address of an ::ESL_IO_MGMT structure
1731 IN ESL_IO_MGMT
* pIo
1735 size_t LengthInBytes
;
1736 ESL_PACKET
* pPacket
;
1742 // Get the operation status.
1744 Status
= pIo
->Token
.Tcp4Rx
.CompletionToken
.Status
;
1747 // +--------------------+ +---------------------------+
1748 // | ESL_IO_MGMT | | ESL_PACKET |
1750 // | +---------------+ +-----------------------+ |
1751 // | | Token | | EFI_TCP4_RECEIVE_DATA | |
1752 // | | RxData --> | | |
1753 // | | | +-----------------------+---+
1754 // | | Event | | Data Buffer |
1755 // +----+---------------+ | |
1757 // +---------------------------+
1760 // Duplicate the buffer address and length for use by the
1761 // buffer handling code in EslTcp4Receive. These fields are
1762 // used when a partial read is done of the data from the
1765 pPacket
= pIo
->pPacket
;
1766 pPacket
->pBuffer
= pPacket
->Op
.Tcp4Rx
.RxData
.FragmentTable
[0].FragmentBuffer
;
1767 LengthInBytes
= pPacket
->Op
.Tcp4Rx
.RxData
.DataLength
;
1768 pPacket
->ValidBytes
= LengthInBytes
;
1771 // Get the data type so that it may be linked to the
1772 // correct receive buffer list on the ESL_SOCKET structure
1774 bUrgent
= pPacket
->Op
.Tcp4Rx
.RxData
.UrgentFlag
;
1777 // Complete this request
1779 EslSocketRxComplete ( pIo
, Status
, LengthInBytes
, bUrgent
);
1785 Start a receive operation
1787 This routine posts a receive buffer to the TCPv4 driver.
1788 See the \ref ReceiveEngine section.
1790 This support routine is called by EslSocketRxStart.
1792 @param [in] pPort Address of an ::ESL_PORT structure.
1793 @param [in] pIo Address of an ::ESL_IO_MGMT structure.
1798 IN ESL_PORT
* pPort
,
1799 IN ESL_IO_MGMT
* pIo
1802 ESL_PACKET
* pPacket
;
1807 // Initialize the buffer for receive
1809 pPacket
= pIo
->pPacket
;
1810 pIo
->Token
.Tcp4Rx
.Packet
.RxData
= &pPacket
->Op
.Tcp4Rx
.RxData
;
1811 pPacket
->Op
.Tcp4Rx
.RxData
.DataLength
= sizeof ( pPacket
->Op
.Tcp4Rx
.Buffer
);
1812 pPacket
->Op
.Tcp4Rx
.RxData
.FragmentCount
= 1;
1813 pPacket
->Op
.Tcp4Rx
.RxData
.FragmentTable
[0].FragmentLength
= pPacket
->Op
.Tcp4Rx
.RxData
.DataLength
;
1814 pPacket
->Op
.Tcp4Rx
.RxData
.FragmentTable
[0].FragmentBuffer
= &pPacket
->Op
.Tcp4Rx
.Buffer
[0];
1821 Determine if the socket is configured.
1823 This routine uses the flag ESL_SOCKET::bConfigured to determine
1824 if the network layer's configuration routine has been called.
1826 This routine is called by EslSocketIsConfigured to verify
1827 that the socket has been configured.
1829 @param [in] pSocket Address of an ::ESL_SOCKET structure.
1831 @retval EFI_SUCCESS - The port is connected
1832 @retval EFI_NOT_STARTED - The port is not connected
1836 EslTcp4SocketIsConfigured (
1837 IN ESL_SOCKET
* pSocket
1845 // Determine the socket configuration status
1847 Status
= pSocket
->bConfigured
? EFI_SUCCESS
: EFI_NOT_STARTED
;
1850 // Return the port connected state.
1852 DBG_EXIT_STATUS ( Status
);
1858 Buffer data for transmission over a network connection.
1860 This routine buffers data for the transmit engine in one of two
1861 queues, one for urgent (out-of-band) data and the other for normal
1862 data. The urgent data is provided to TCP as soon as it is available,
1863 allowing the TCP layer to schedule transmission of the urgent data
1864 between packets of normal data.
1866 This routine is called by ::EslSocketTransmit to buffer
1867 data for transmission. When the \ref TransmitEngine has resources,
1868 this routine will start the transmission of the next buffer on
1869 the network connection.
1871 Transmission errors are returned during the next transmission or
1872 during the close operation. Only buffering errors are returned
1873 during the current transmission attempt.
1875 @param [in] pSocket Address of an ::ESL_SOCKET structure
1877 @param [in] Flags Message control flags
1879 @param [in] BufferLength Length of the the buffer
1881 @param [in] pBuffer Address of a buffer to receive the data.
1883 @param [in] pDataLength Number of received data bytes in the buffer.
1885 @param [in] pAddress Network address of the remote system address
1887 @param [in] AddressLength Length of the remote network address structure
1889 @retval EFI_SUCCESS - Socket data successfully buffered
1894 IN ESL_SOCKET
* pSocket
,
1896 IN
size_t BufferLength
,
1897 IN CONST UINT8
* pBuffer
,
1898 OUT
size_t * pDataLength
,
1899 IN
const struct sockaddr
* pAddress
,
1900 IN socklen_t AddressLength
1904 BOOLEAN bUrgentQueue
;
1905 ESL_PACKET
* pPacket
;
1906 ESL_IO_MGMT
** ppActive
;
1907 ESL_IO_MGMT
** ppFree
;
1909 ESL_PACKET
** ppQueueHead
;
1910 ESL_PACKET
** ppQueueTail
;
1911 ESL_PACKET
* pPreviousPacket
;
1912 ESL_TCP4_CONTEXT
* pTcp4
;
1914 EFI_TCP4_TRANSMIT_DATA
* pTxData
;
1916 EFI_TPL TplPrevious
;
1923 Status
= EFI_UNSUPPORTED
;
1924 pSocket
->errno
= ENOTCONN
;
1928 // Verify that the socket is connected
1930 if ( SOCKET_STATE_CONNECTED
== pSocket
->State
) {
1934 pPort
= pSocket
->pPortList
;
1935 if ( NULL
!= pPort
) {
1937 // Determine the queue head
1939 pTcp4
= &pPort
->Context
.Tcp4
;
1940 bUrgent
= (BOOLEAN
)( 0 != ( Flags
& MSG_OOB
));
1941 bUrgentQueue
= bUrgent
1942 && ( !pSocket
->bOobInLine
)
1943 && pSocket
->pApi
->bOobSupported
;
1944 if ( bUrgentQueue
) {
1945 ppQueueHead
= &pSocket
->pTxOobPacketListHead
;
1946 ppQueueTail
= &pSocket
->pTxOobPacketListTail
;
1947 ppActive
= &pPort
->pTxOobActive
;
1948 ppFree
= &pPort
->pTxOobFree
;
1949 pTxBytes
= &pSocket
->TxOobBytes
;
1952 ppQueueHead
= &pSocket
->pTxPacketListHead
;
1953 ppQueueTail
= &pSocket
->pTxPacketListTail
;
1954 ppActive
= &pPort
->pTxActive
;
1955 ppFree
= &pPort
->pTxFree
;
1956 pTxBytes
= &pSocket
->TxBytes
;
1960 // Verify that there is enough room to buffer another
1961 // transmit operation
1963 if ( pSocket
->MaxTxBuf
> *pTxBytes
) {
1964 if ( pPort
->bTxFlowControl
) {
1966 "TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT\r\n0x%08x: pPort, TX flow control released, Max bytes: %d > %d bufferred bytes\r\n",
1970 pPort
->bTxFlowControl
= FALSE
;
1974 // Attempt to allocate the packet
1976 Status
= EslSocketPacketAllocate ( &pPacket
,
1977 sizeof ( pPacket
->Op
.Tcp4Tx
)
1978 - sizeof ( pPacket
->Op
.Tcp4Tx
.Buffer
)
1982 if ( !EFI_ERROR ( Status
)) {
1984 // Initialize the transmit operation
1986 pTxData
= &pPacket
->Op
.Tcp4Tx
.TxData
;
1987 pTxData
->Push
= TRUE
|| bUrgent
;
1988 pTxData
->Urgent
= bUrgent
;
1989 pTxData
->DataLength
= (UINT32
) BufferLength
;
1990 pTxData
->FragmentCount
= 1;
1991 pTxData
->FragmentTable
[0].FragmentLength
= (UINT32
) BufferLength
;
1992 pTxData
->FragmentTable
[0].FragmentBuffer
= &pPacket
->Op
.Tcp4Tx
.Buffer
[0];
1995 // Copy the data into the buffer
1997 CopyMem ( &pPacket
->Op
.Tcp4Tx
.Buffer
[0],
2002 // Synchronize with the socket layer
2004 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
2007 // Stop transmission after an error
2009 if ( !EFI_ERROR ( pSocket
->TxError
)) {
2011 // Display the request
2014 "Send %d %s bytes from 0x%08x\r\n",
2016 bUrgent
? L
"urgent" : L
"normal",
2020 // Queue the data for transmission
2022 pPacket
->pNext
= NULL
;
2023 pPreviousPacket
= *ppQueueTail
;
2024 if ( NULL
== pPreviousPacket
) {
2025 *ppQueueHead
= pPacket
;
2028 pPreviousPacket
->pNext
= pPacket
;
2030 *ppQueueTail
= pPacket
;
2032 "0x%08x: Packet on %s transmit list\r\n",
2034 bUrgentQueue
? L
"urgent" : L
"normal" ));
2037 // Account for the buffered data
2039 *pTxBytes
+= BufferLength
;
2040 *pDataLength
= BufferLength
;
2043 // Start the transmit engine if it is idle
2045 if ( NULL
!= *ppFree
) {
2046 EslSocketTxStart ( pPort
,
2055 // Previous transmit error
2056 // Stop transmission
2058 Status
= pSocket
->TxError
;
2059 pSocket
->errno
= EIO
;
2064 EslSocketPacketFree ( pPacket
, DEBUG_TX
);
2068 // Release the socket layer synchronization
2070 RESTORE_TPL ( TplPrevious
);
2074 // Packet allocation failed
2076 pSocket
->errno
= ENOMEM
;
2080 if ( !pPort
->bTxFlowControl
) {
2082 "0x%08x: pPort, TX flow control applied, Max bytes %d <= %d bufferred bytes\r\nTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT\r\n",
2086 pPort
->bTxFlowControl
= TRUE
;
2089 // Not enough buffer space available
2091 pSocket
->errno
= EAGAIN
;
2092 Status
= EFI_NOT_READY
;
2098 // Return the operation status
2100 DBG_EXIT_STATUS ( Status
);
2106 Process the normal data transmit completion
2108 This routine use ::EslSocketTxComplete to perform the transmit
2109 completion processing for normal data.
2111 This routine is called by the TCPv4 network layer when a
2112 normal data transmit request completes.
2114 @param [in] Event The normal transmit completion event
2116 @param [in] pIo The ESL_IO_MGMT structure address
2122 IN ESL_IO_MGMT
* pIo
2125 UINT32 LengthInBytes
;
2126 ESL_PACKET
* pPacket
;
2128 ESL_SOCKET
* pSocket
;
2134 // Locate the active transmit packet
2136 pPacket
= pIo
->pPacket
;
2138 pSocket
= pPort
->pSocket
;
2141 // Get the transmit length and status
2143 LengthInBytes
= pPacket
->Op
.Tcp4Tx
.TxData
.DataLength
;
2144 pSocket
->TxBytes
-= LengthInBytes
;
2145 Status
= pIo
->Token
.Tcp4Tx
.CompletionToken
.Status
;
2148 // Complete the transmit operation
2150 EslSocketTxComplete ( pIo
,
2154 &pSocket
->pTxPacketListHead
,
2155 &pSocket
->pTxPacketListTail
,
2163 Process the urgent data transmit completion
2165 This routine use ::EslSocketTxComplete to perform the transmit
2166 completion processing for urgent data.
2168 This routine is called by the TCPv4 network layer when a
2169 urgent data transmit request completes.
2171 @param [in] Event The urgent transmit completion event
2173 @param [in] pIo The ESL_IO_MGMT structure address
2177 EslTcp4TxOobComplete (
2179 IN ESL_IO_MGMT
* pIo
2182 UINT32 LengthInBytes
;
2183 ESL_PACKET
* pPacket
;
2185 ESL_SOCKET
* pSocket
;
2191 // Locate the active transmit packet
2193 pPacket
= pIo
->pPacket
;
2195 pSocket
= pPort
->pSocket
;
2198 // Get the transmit length and status
2200 LengthInBytes
= pPacket
->Op
.Tcp4Tx
.TxData
.DataLength
;
2201 pSocket
->TxOobBytes
-= LengthInBytes
;
2202 Status
= pIo
->Token
.Tcp4Tx
.CompletionToken
.Status
;
2205 // Complete the transmit operation
2207 EslSocketTxComplete ( pIo
,
2211 &pSocket
->pTxOobPacketListHead
,
2212 &pSocket
->pTxOobPacketListTail
,
2213 &pPort
->pTxOobActive
,
2214 &pPort
->pTxOobFree
);
2220 Interface between the socket layer and the network specific
2221 code that supports SOCK_STREAM and SOCK_SEQPACKET sockets
2224 CONST ESL_PROTOCOL_API cEslTcp4Api
= {
2227 OFFSET_OF ( ESL_PORT
, Context
.Tcp4
.ConfigData
),
2228 OFFSET_OF ( ESL_LAYER
, pTcp4List
),
2229 OFFSET_OF ( struct sockaddr_in
, sin_zero
),
2230 sizeof ( struct sockaddr_in
),
2232 sizeof (((ESL_PACKET
*)0 )->Op
.Tcp4Rx
),
2233 OFFSET_OF ( ESL_PACKET
, Op
.Tcp4Rx
.Buffer
) - OFFSET_OF ( ESL_PACKET
, Op
),
2234 OFFSET_OF ( ESL_IO_MGMT
, Token
.Tcp4Rx
.Packet
.RxData
),
2239 EslTcp4ConnectStart
,
2240 EslTcp4SocketIsConfigured
,
2241 EslTcp4LocalAddressGet
,
2242 EslTcp4LocalAddressSet
,
2247 EslTcp4PortAllocate
,
2252 EslTcp4RemoteAddressGet
,
2253 EslTcp4RemoteAddressSet
,
2258 EslTcp4TxOobComplete