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 Status
= pTcp4Protocol
->GetModeData ( pTcp4Protocol
,
521 if ( !EFI_ERROR ( Status
)) {
522 if ( SnpModeData
.MediaPresentSupported
523 && ( !SnpModeData
.MediaPresent
)) {
525 // Port is not connected to the network
527 pTcp4
->ConnectToken
.CompletionToken
.Status
= EFI_NO_MEDIA
;
530 // Continue with the next port
532 gBS
->CheckEvent ( pTcp4
->ConnectToken
.CompletionToken
.Event
);
533 gBS
->SignalEvent ( pTcp4
->ConnectToken
.CompletionToken
.Event
);
536 // Connection in progress
538 Status
= EFI_SUCCESS
;
542 // Attempt the connection to the remote system
544 Status
= pTcp4Protocol
->Connect ( pTcp4Protocol
,
545 &pTcp4
->ConnectToken
);
548 if ( !EFI_ERROR ( Status
)) {
550 // Connection in progress
552 pSocket
->errno
= EINPROGRESS
;
553 Status
= EFI_NOT_READY
;
554 DEBUG (( DEBUG_CONNECT
,
555 "0x%08x: Port attempting connection to %d.%d.%d.%d:%d\r\n",
557 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[0],
558 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[1],
559 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[2],
560 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[3],
561 pTcp4
->ConfigData
.AccessPoint
.RemotePort
));
567 DEBUG (( DEBUG_CONNECT
,
568 "ERROR - Port 0x%08x not connected, Status: %r\r\n",
572 // Determine the errno value
576 pSocket
->errno
= EIO
;
579 case EFI_OUT_OF_RESOURCES
:
580 pSocket
->errno
= ENOBUFS
;
584 pSocket
->errno
= ETIMEDOUT
;
588 case EFI_NETWORK_UNREACHABLE
:
589 pSocket
->errno
= ENETDOWN
;
592 case EFI_HOST_UNREACHABLE
:
593 pSocket
->errno
= EHOSTUNREACH
;
596 case EFI_PORT_UNREACHABLE
:
597 case EFI_PROTOCOL_UNREACHABLE
:
598 case EFI_CONNECTION_REFUSED
:
599 pSocket
->errno
= ECONNREFUSED
;
602 case EFI_CONNECTION_RESET
:
603 pSocket
->errno
= ECONNRESET
;
611 // No more local adapters available
613 pSocket
->errno
= ENETUNREACH
;
614 Status
= EFI_NO_RESPONSE
;
618 // Return the operation status
620 DBG_EXIT_STATUS ( Status
);
626 Establish the known port to listen for network connections.
628 This routine places the port into a state that enables connection
631 This routine is called by ::EslSocketListen to handle the network
632 specifics of the listen operation for SOCK_STREAM and SOCK_SEQPACKET
633 sockets. See the \ref ConnectionManagement section.
635 @param [in] pSocket Address of an ::ESL_SOCKET structure.
637 @retval EFI_SUCCESS - Socket successfully created
638 @retval Other - Failed to enable the socket for listen
643 IN ESL_SOCKET
* pSocket
646 ESL_PORT
* pNextPort
;
648 ESL_TCP4_CONTEXT
* pTcp4
;
649 EFI_TCP4_PROTOCOL
* pTcp4Protocol
;
655 // Verify the socket layer synchronization
657 VERIFY_TPL ( TPL_SOCKETS
);
660 // Use for/break instead of goto
664 // Assume no ports are available
666 pSocket
->errno
= EOPNOTSUPP
;
667 Status
= EFI_NOT_READY
;
670 // Walk the list of ports
672 pPort
= pSocket
->pPortList
;
673 while ( NULL
!= pPort
) {
680 // Use for/break insteak of goto
684 // Create the listen completion event
686 pTcp4
= &pPort
->Context
.Tcp4
;
687 Status
= gBS
->CreateEvent ( EVT_NOTIFY_SIGNAL
,
689 (EFI_EVENT_NOTIFY
)EslTcp4ListenComplete
,
691 &pTcp4
->ListenToken
.CompletionToken
.Event
);
692 if ( EFI_ERROR ( Status
)) {
693 DEBUG (( DEBUG_ERROR
| DEBUG_LISTEN
,
694 "ERROR - Failed to create the listen completion event, Status: %r\r\n",
696 pSocket
->errno
= ENOMEM
;
700 "0x%08x: Created listen completion event\r\n",
701 pTcp4
->ListenToken
.CompletionToken
.Event
));
704 // Configure the port
706 pTcp4Protocol
= pPort
->pProtocol
.TCPv4
;
707 Status
= pTcp4Protocol
->Configure ( pTcp4Protocol
,
708 &pTcp4
->ConfigData
);
709 if ( EFI_ERROR ( Status
)) {
710 DEBUG (( DEBUG_LISTEN
,
711 "ERROR - Failed to configure the Tcp4 port, Status: %r\r\n",
714 case EFI_ACCESS_DENIED
:
715 pSocket
->errno
= EACCES
;
719 case EFI_DEVICE_ERROR
:
720 pSocket
->errno
= EIO
;
723 case EFI_INVALID_PARAMETER
:
724 pSocket
->errno
= EADDRNOTAVAIL
;
728 pSocket
->errno
= EAFNOSUPPORT
;
731 case EFI_OUT_OF_RESOURCES
:
732 pSocket
->errno
= ENOBUFS
;
735 case EFI_UNSUPPORTED
:
736 pSocket
->errno
= EOPNOTSUPP
;
741 DEBUG (( DEBUG_LISTEN
,
742 "0x%08x: Port configured\r\n",
744 pPort
->bConfigured
= TRUE
;
747 // Start the listen operation on the port
749 Status
= pTcp4Protocol
->Accept ( pTcp4Protocol
,
750 &pTcp4
->ListenToken
);
751 if ( EFI_ERROR ( Status
)) {
752 DEBUG (( DEBUG_LISTEN
,
753 "ERROR - Failed Tcp4 accept, Status: %r\r\n",
756 case EFI_ACCESS_DENIED
:
757 pSocket
->errno
= EACCES
;
761 case EFI_DEVICE_ERROR
:
762 pSocket
->errno
= EIO
;
765 case EFI_INVALID_PARAMETER
:
766 pSocket
->errno
= EADDRNOTAVAIL
;
769 case EFI_NOT_STARTED
:
770 pSocket
->errno
= ENETDOWN
;
773 case EFI_OUT_OF_RESOURCES
:
774 pSocket
->errno
= ENOBUFS
;
779 DEBUG (( DEBUG_LISTEN
,
780 "0x%08x: Listen pending on Port\r\n",
784 // Listen is pending on this port
792 pNextPort
= pPort
->pLinkSocket
;
795 // Close the port upon error
797 if ( EFI_ERROR ( Status
)) {
798 EslSocketPortCloseStart ( pPort
, TRUE
, DEBUG_LISTEN
);
808 // Determine if any ports are in the listen state
810 if ( NULL
== pSocket
->pPortList
) {
812 // No ports in the listen state
814 pSocket
->MaxFifoDepth
= 0;
817 // Return the last error detected
823 // Mark the socket as configured
825 pSocket
->bConfigured
= TRUE
;
830 DEBUG (( DEBUG_LISTEN
,
831 "0x%08x: pSocket - Listen pending on socket\r\n",
837 // Return the operation status
839 DBG_EXIT_STATUS ( Status
);
845 Process the connection attempt
847 A system has initiated a connection attempt with a socket in the
848 listen state. Attempt to complete the connection.
850 The TCPv4 layer calls this routine when a connection is made to
851 the socket in the listen state. See the
852 \ref ConnectionManagement section.
854 @param [in] Event The listen completion event
856 @param [in] pPort Address of an ::ESL_PORT structure.
860 EslTcp4ListenComplete (
865 EFI_HANDLE ChildHandle
;
866 struct sockaddr_in LocalAddress
;
867 EFI_TCP4_CONFIG_DATA
* pConfigData
;
870 ESL_SOCKET
* pNewSocket
;
871 ESL_SOCKET
* pSocket
;
872 ESL_TCP4_CONTEXT
* pTcp4
;
873 EFI_TCP4_PROTOCOL
* pTcp4Protocol
;
875 EFI_HANDLE TcpPortHandle
;
876 EFI_STATUS TempStatus
;
879 VERIFY_AT_TPL ( TPL_SOCKETS
);
884 Status
= EFI_SUCCESS
;
887 // Determine if this connection fits into the connection FIFO
889 pSocket
= pPort
->pSocket
;
890 TcpPortHandle
= pPort
->Context
.Tcp4
.ListenToken
.NewChildHandle
;
891 if (( SOCKET_STATE_LISTENING
== pSocket
->State
)
892 && ( pSocket
->MaxFifoDepth
> pSocket
->FifoDepth
)) {
894 // Allocate a socket for this connection
898 Status
= EslSocketAllocate ( &ChildHandle
,
901 if ( !EFI_ERROR ( Status
)) {
903 // Clone the socket parameters
905 pNewSocket
->pApi
= pSocket
->pApi
;
906 pNewSocket
->Domain
= pSocket
->Domain
;
907 pNewSocket
->Protocol
= pSocket
->Protocol
;
908 pNewSocket
->Type
= pSocket
->Type
;
911 // Build the local address
913 pTcp4
= &pPort
->Context
.Tcp4
;
914 LocalAddress
.sin_len
= (uint8_t)pNewSocket
->pApi
->MinimumAddressLength
;
915 LocalAddress
.sin_family
= AF_INET
;
916 LocalAddress
.sin_port
= 0;
917 LocalAddress
.sin_addr
.s_addr
= *(UINT32
*)&pTcp4
->ConfigData
.AccessPoint
.StationAddress
.Addr
[0];
920 // Allocate a port for this connection
921 // Note in this instance Configure may not be called with NULL!
923 Status
= EslSocketPortAllocate ( pNewSocket
,
926 (struct sockaddr
*)&LocalAddress
,
930 if ( !EFI_ERROR ( Status
)) {
932 // Restart the listen operation on the port
934 pTcp4Protocol
= pPort
->pProtocol
.TCPv4
;
935 Status
= pTcp4Protocol
->Accept ( pTcp4Protocol
,
936 &pTcp4
->ListenToken
);
939 // Close the TCP port using SocketClose
941 TcpPortHandle
= NULL
;
942 pTcp4
= &pNewPort
->Context
.Tcp4
;
945 // Check for an accept call error
947 if ( !EFI_ERROR ( Status
)) {
949 // Get the port configuration
951 pNewPort
->bConfigured
= TRUE
;
952 pConfigData
= &pTcp4
->ConfigData
;
953 pConfigData
->ControlOption
= &pTcp4
->Option
;
954 pTcp4Protocol
= pNewPort
->pProtocol
.TCPv4
;
955 Status
= pTcp4Protocol
->GetModeData ( pTcp4Protocol
,
961 if ( !EFI_ERROR ( Status
)) {
963 // Add the new socket to the connection FIFO
965 if ( NULL
== pSocket
->pFifoTail
) {
969 pSocket
->pFifoHead
= pNewSocket
;
973 // Add to end of list.
975 pSocket
->pFifoTail
->pNextConnection
= pNewSocket
;
977 pSocket
->pFifoTail
= pNewSocket
;
978 pSocket
->FifoDepth
+= 1;
981 // Update the socket state
983 pNewSocket
->State
= SOCKET_STATE_IN_FIFO
;
986 // Log the connection
988 DEBUG (( DEBUG_CONNECTION
| DEBUG_INFO
,
989 "0x%08x: Socket on port %d.%d.%d.%d:%d connected to %d.%d.%d.%d:%d\r\n",
991 pConfigData
->AccessPoint
.StationAddress
.Addr
[0],
992 pConfigData
->AccessPoint
.StationAddress
.Addr
[1],
993 pConfigData
->AccessPoint
.StationAddress
.Addr
[2],
994 pConfigData
->AccessPoint
.StationAddress
.Addr
[3],
995 pConfigData
->AccessPoint
.StationPort
,
996 pConfigData
->AccessPoint
.RemoteAddress
.Addr
[0],
997 pConfigData
->AccessPoint
.RemoteAddress
.Addr
[1],
998 pConfigData
->AccessPoint
.RemoteAddress
.Addr
[2],
999 pConfigData
->AccessPoint
.RemoteAddress
.Addr
[3],
1000 pConfigData
->AccessPoint
.RemotePort
));
1001 DEBUG (( DEBUG_CONNECTION
| DEBUG_INFO
,
1002 "0x%08x: Listen socket adding socket 0x%08x to FIFO, depth: %d\r\n",
1005 pSocket
->FifoDepth
));
1008 // Start the receive operation
1010 EslSocketRxStart ( pNewPort
);
1013 DEBUG (( DEBUG_ERROR
| DEBUG_CONNECTION
| DEBUG_INFO
,
1014 "ERROR - GetModeData failed on port 0x%08x, Status: %r\r\n",
1021 // The listen failed on this port
1023 DEBUG (( DEBUG_LISTEN
| DEBUG_INFO
,
1024 "ERROR - Listen failed on port 0x%08x, Status: %r\r\n",
1029 // Close the listening port
1031 EslSocketPortCloseStart ( pPort
, TRUE
, DEBUG_LISTEN
);
1036 // Done with the socket if necessary
1038 if ( EFI_ERROR ( Status
)) {
1039 TempStatus
= EslSocketCloseStart ( &pNewSocket
->SocketProtocol
,
1042 ASSERT ( EFI_SUCCESS
== TempStatus
);
1047 DEBUG (( DEBUG_CONNECTION
,
1048 "0x%08x: Socket FIFO full, connection refused\r\n",
1052 // The FIFO is full or the socket is in the wrong state
1054 Status
= EFI_BUFFER_TOO_SMALL
;
1058 // Close the connection if necessary
1060 if (( EFI_ERROR ( Status
))
1061 && ( NULL
== TcpPortHandle
)) {
1063 // TODO: Finish this code path
1064 // The new connection does not fit into the connection FIFO
1068 // Release the resources
1077 Get the local socket address.
1079 This routine returns the IPv4 address and TCP port number associated
1080 with the local socket.
1082 This routine is called by ::EslSocketGetLocalAddress to determine the
1083 network address for the SOCK_STREAM or SOCK_SEQPACKET socket.
1085 @param [in] pPort Address of an ::ESL_PORT structure.
1087 @param [out] pSockAddr Network address to receive the local system address
1091 EslTcp4LocalAddressGet (
1092 IN ESL_PORT
* pPort
,
1093 OUT
struct sockaddr
* pSockAddr
1096 struct sockaddr_in
* pLocalAddress
;
1097 ESL_TCP4_CONTEXT
* pTcp4
;
1102 // Return the local address
1104 pTcp4
= &pPort
->Context
.Tcp4
;
1105 pLocalAddress
= (struct sockaddr_in
*)pSockAddr
;
1106 pLocalAddress
->sin_family
= AF_INET
;
1107 pLocalAddress
->sin_port
= SwapBytes16 ( pTcp4
->ConfigData
.AccessPoint
.StationPort
);
1108 CopyMem ( &pLocalAddress
->sin_addr
,
1109 &pTcp4
->ConfigData
.AccessPoint
.StationAddress
.Addr
[0],
1110 sizeof ( pLocalAddress
->sin_addr
));
1117 Set the local port address.
1119 This routine sets the local port address.
1121 This support routine is called by ::EslSocketPortAllocate.
1123 @param [in] pPort Address of an ESL_PORT structure
1124 @param [in] pSockAddr Address of a sockaddr structure that contains the
1125 connection point on the local machine. An IPv4 address
1126 of INADDR_ANY specifies that the connection is made to
1127 all of the network stacks on the platform. Specifying a
1128 specific IPv4 address restricts the connection to the
1129 network stack supporting that address. Specifying zero
1130 for the port causes the network layer to assign a port
1131 number from the dynamic range. Specifying a specific
1132 port number causes the network layer to use that port.
1134 @param [in] bBindTest TRUE = run bind testing
1136 @retval EFI_SUCCESS The operation was successful
1140 EslTcp4LocalAddressSet (
1141 IN ESL_PORT
* pPort
,
1142 IN CONST
struct sockaddr
* pSockAddr
,
1143 IN BOOLEAN bBindTest
1146 EFI_TCP4_ACCESS_POINT
* pAccessPoint
;
1147 CONST
struct sockaddr_in
* pIpAddress
;
1148 CONST UINT8
* pIpv4Address
;
1154 // Validate the address
1156 pIpAddress
= (struct sockaddr_in
*)pSockAddr
;
1157 if ( INADDR_BROADCAST
== pIpAddress
->sin_addr
.s_addr
) {
1159 // The local address must not be the broadcast address
1161 Status
= EFI_INVALID_PARAMETER
;
1162 pPort
->pSocket
->errno
= EADDRNOTAVAIL
;
1166 // Set the local address
1168 pIpv4Address
= (UINT8
*)&pIpAddress
->sin_addr
.s_addr
;
1169 pAccessPoint
= &pPort
->Context
.Tcp4
.ConfigData
.AccessPoint
;
1170 pAccessPoint
->StationAddress
.Addr
[0] = pIpv4Address
[0];
1171 pAccessPoint
->StationAddress
.Addr
[1] = pIpv4Address
[1];
1172 pAccessPoint
->StationAddress
.Addr
[2] = pIpv4Address
[2];
1173 pAccessPoint
->StationAddress
.Addr
[3] = pIpv4Address
[3];
1176 // Determine if the default address is used
1178 pAccessPoint
->UseDefaultAddress
= (BOOLEAN
)( 0 == pIpAddress
->sin_addr
.s_addr
);
1181 // Set the subnet mask
1183 if ( pAccessPoint
->UseDefaultAddress
) {
1184 pAccessPoint
->SubnetMask
.Addr
[0] = 0;
1185 pAccessPoint
->SubnetMask
.Addr
[1] = 0;
1186 pAccessPoint
->SubnetMask
.Addr
[2] = 0;
1187 pAccessPoint
->SubnetMask
.Addr
[3] = 0;
1190 pAccessPoint
->SubnetMask
.Addr
[0] = 0xff;
1191 pAccessPoint
->SubnetMask
.Addr
[1] = 0xff;
1192 pAccessPoint
->SubnetMask
.Addr
[2] = 0xff;
1193 pAccessPoint
->SubnetMask
.Addr
[3] = 0xff;
1197 // Validate the IP address
1199 pAccessPoint
->StationPort
= 0;
1200 Status
= bBindTest
? EslSocketBindTest ( pPort
, EADDRNOTAVAIL
)
1202 if ( !EFI_ERROR ( Status
)) {
1204 // Set the port number
1206 pAccessPoint
->StationPort
= SwapBytes16 ( pIpAddress
->sin_port
);
1207 pPort
->pSocket
->bAddressSet
= TRUE
;
1210 // Display the local address
1212 DEBUG (( DEBUG_BIND
,
1213 "0x%08x: Port, Local TCP4 Address: %d.%d.%d.%d:%d\r\n",
1215 pAccessPoint
->StationAddress
.Addr
[0],
1216 pAccessPoint
->StationAddress
.Addr
[1],
1217 pAccessPoint
->StationAddress
.Addr
[2],
1218 pAccessPoint
->StationAddress
.Addr
[3],
1219 pAccessPoint
->StationPort
));
1224 // Return the operation status
1226 DBG_EXIT_STATUS ( Status
);
1232 Free a receive packet
1234 This routine performs the network specific operations necessary
1235 to free a receive packet.
1237 This routine is called by ::EslSocketPortCloseTxDone to free a
1240 @param [in] pPacket Address of an ::ESL_PACKET structure.
1241 @param [in, out] pRxBytes Address of the count of RX bytes
1246 IN ESL_PACKET
* pPacket
,
1247 IN OUT
size_t * pRxBytes
1253 // Account for the receive bytes
1255 *pRxBytes
-= pPacket
->Op
.Tcp4Rx
.RxData
.DataLength
;
1261 Initialize the network specific portions of an ::ESL_PORT structure.
1263 This routine initializes the network specific portions of an
1264 ::ESL_PORT structure for use by the socket.
1266 This support routine is called by ::EslSocketPortAllocate
1267 to connect the socket with the underlying network adapter
1268 running the TCPv4 protocol.
1270 @param [in] pPort Address of an ESL_PORT structure
1271 @param [in] DebugFlags Flags for debug messages
1273 @retval EFI_SUCCESS - Socket successfully created
1277 EslTcp4PortAllocate (
1278 IN ESL_PORT
* pPort
,
1282 EFI_TCP4_ACCESS_POINT
* pAccessPoint
;
1283 ESL_SOCKET
* pSocket
;
1284 ESL_TCP4_CONTEXT
* pTcp4
;
1290 // Use for/break instead of goto
1293 // Allocate the close event
1295 pSocket
= pPort
->pSocket
;
1296 pTcp4
= &pPort
->Context
.Tcp4
;
1297 Status
= gBS
->CreateEvent ( EVT_NOTIFY_SIGNAL
,
1299 (EFI_EVENT_NOTIFY
)EslSocketPortCloseComplete
,
1301 &pTcp4
->CloseToken
.CompletionToken
.Event
);
1302 if ( EFI_ERROR ( Status
)) {
1303 DEBUG (( DEBUG_ERROR
| DebugFlags
,
1304 "ERROR - Failed to create the close event, Status: %r\r\n",
1306 pSocket
->errno
= ENOMEM
;
1309 DEBUG (( DEBUG_CLOSE
| DEBUG_POOL
,
1310 "0x%08x: Created close event\r\n",
1311 pTcp4
->CloseToken
.CompletionToken
.Event
));
1314 // Allocate the connection event
1316 Status
= gBS
->CreateEvent ( EVT_NOTIFY_SIGNAL
,
1318 (EFI_EVENT_NOTIFY
)EslTcp4ConnectComplete
,
1320 &pTcp4
->ConnectToken
.CompletionToken
.Event
);
1321 if ( EFI_ERROR ( Status
)) {
1322 DEBUG (( DEBUG_ERROR
| DebugFlags
,
1323 "ERROR - Failed to create the connect event, Status: %r\r\n",
1325 pSocket
->errno
= ENOMEM
;
1328 DEBUG (( DEBUG_CLOSE
| DEBUG_POOL
,
1329 "0x%08x: Created connect event\r\n",
1330 pTcp4
->ConnectToken
.CompletionToken
.Event
));
1333 // Initialize the port
1335 pSocket
->TxPacketOffset
= OFFSET_OF ( ESL_PACKET
, Op
.Tcp4Tx
.TxData
);
1336 pSocket
->TxTokenEventOffset
= OFFSET_OF ( ESL_IO_MGMT
, Token
.Tcp4Tx
.CompletionToken
.Event
);
1337 pSocket
->TxTokenOffset
= OFFSET_OF ( EFI_TCP4_IO_TOKEN
, Packet
.TxData
);
1340 // Save the cancel, receive and transmit addresses
1341 // pPort->pfnRxCancel = NULL; since the UEFI implementation returns EFI_UNSUPPORTED
1343 pPort
->pfnConfigure
= (PFN_NET_CONFIGURE
)pPort
->pProtocol
.TCPv4
->Configure
;
1344 pPort
->pfnRxPoll
= (PFN_NET_POLL
)pPort
->pProtocol
.TCPv4
->Poll
;
1345 pPort
->pfnRxStart
= (PFN_NET_IO_START
)pPort
->pProtocol
.TCPv4
->Receive
;
1346 pPort
->pfnTxStart
= (PFN_NET_IO_START
)pPort
->pProtocol
.TCPv4
->Transmit
;
1349 // Set the configuration flags
1351 pAccessPoint
= &pPort
->Context
.Tcp4
.ConfigData
.AccessPoint
;
1352 pAccessPoint
->ActiveFlag
= FALSE
;
1353 pTcp4
->ConfigData
.TimeToLive
= 255;
1358 // Return the operation status
1360 DBG_EXIT_STATUS ( Status
);
1368 This routine releases the network specific resources allocated by
1369 ::EslTcp4PortAllocate.
1371 This routine is called by ::EslSocketPortClose.
1372 See the \ref PortCloseStateMachine section.
1374 @param [in] pPort Address of an ::ESL_PORT structure.
1376 @retval EFI_SUCCESS The port is closed
1377 @retval other Port close error
1386 ESL_TCP4_CONTEXT
* pTcp4
;
1392 // Locate the port in the socket list
1394 Status
= EFI_SUCCESS
;
1395 DebugFlags
= pPort
->DebugFlags
;
1396 pTcp4
= &pPort
->Context
.Tcp4
;
1399 // Done with the connect event
1401 if ( NULL
!= pTcp4
->ConnectToken
.CompletionToken
.Event
) {
1402 Status
= gBS
->CloseEvent ( pTcp4
->ConnectToken
.CompletionToken
.Event
);
1403 if ( !EFI_ERROR ( Status
)) {
1404 DEBUG (( DebugFlags
| DEBUG_POOL
,
1405 "0x%08x: Closed connect event\r\n",
1406 pTcp4
->ConnectToken
.CompletionToken
.Event
));
1409 DEBUG (( DEBUG_ERROR
| DebugFlags
,
1410 "ERROR - Failed to close the connect event, Status: %r\r\n",
1412 ASSERT ( EFI_SUCCESS
== Status
);
1417 // Done with the close event
1419 if ( NULL
!= pTcp4
->CloseToken
.CompletionToken
.Event
) {
1420 Status
= gBS
->CloseEvent ( pTcp4
->CloseToken
.CompletionToken
.Event
);
1421 if ( !EFI_ERROR ( Status
)) {
1422 DEBUG (( DebugFlags
| DEBUG_POOL
,
1423 "0x%08x: Closed close event\r\n",
1424 pTcp4
->CloseToken
.CompletionToken
.Event
));
1427 DEBUG (( DEBUG_ERROR
| DebugFlags
,
1428 "ERROR - Failed to close the close event, Status: %r\r\n",
1430 ASSERT ( EFI_SUCCESS
== Status
);
1435 // Done with the listen completion event
1437 if ( NULL
!= pTcp4
->ListenToken
.CompletionToken
.Event
) {
1438 Status
= gBS
->CloseEvent ( pTcp4
->ListenToken
.CompletionToken
.Event
);
1439 if ( !EFI_ERROR ( Status
)) {
1440 DEBUG (( DebugFlags
| DEBUG_POOL
,
1441 "0x%08x: Closed listen completion event\r\n",
1442 pTcp4
->ListenToken
.CompletionToken
.Event
));
1445 DEBUG (( DEBUG_ERROR
| DebugFlags
,
1446 "ERROR - Failed to close the listen completion event, Status: %r\r\n",
1448 ASSERT ( EFI_SUCCESS
== Status
);
1453 // Return the operation status
1455 DBG_EXIT_STATUS ( Status
);
1461 Perform the network specific close operation on the port.
1463 This routine performs a cancel operations on the TCPv4 port to
1464 shutdown the receive operations on the port.
1466 This routine is called by the ::EslSocketPortCloseTxDone
1467 routine after the port completes all of the transmission.
1469 @param [in] pPort Address of an ::ESL_PORT structure.
1471 @retval EFI_SUCCESS The port is closed, not normally returned
1472 @retval EFI_NOT_READY The port is still closing
1473 @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
1474 most likely the routine was called already.
1478 EslTcp4PortCloseOp (
1482 ESL_TCP4_CONTEXT
* pTcp4
;
1483 EFI_TCP4_PROTOCOL
* pTcp4Protocol
;
1489 // Close the configured port
1491 Status
= EFI_SUCCESS
;
1492 pTcp4
= &pPort
->Context
.Tcp4
;
1493 pTcp4Protocol
= pPort
->pProtocol
.TCPv4
;
1494 pTcp4
->CloseToken
.AbortOnClose
= pPort
->bCloseNow
;
1495 Status
= pTcp4Protocol
->Close ( pTcp4Protocol
,
1496 &pTcp4
->CloseToken
);
1497 if ( !EFI_ERROR ( Status
)) {
1498 DEBUG (( pPort
->DebugFlags
| DEBUG_CLOSE
| DEBUG_INFO
,
1499 "0x%08x: Port close started\r\n",
1503 DEBUG (( DEBUG_ERROR
| pPort
->DebugFlags
| DEBUG_CLOSE
| DEBUG_INFO
,
1504 "ERROR - Close failed on port 0x%08x, Status: %r\r\n",
1510 // Return the operation status
1512 DBG_EXIT_STATUS ( Status
);
1518 Receive data from a network connection.
1520 This routine attempts to return buffered data to the caller. The
1521 data is removed from the urgent queue if the message flag MSG_OOB
1522 is specified, otherwise data is removed from the normal queue.
1523 See the \ref ReceiveEngine section.
1525 This routine is called by ::EslSocketReceive to handle the network
1526 specific receive operation to support SOCK_STREAM and SOCK_SEQPACKET
1529 @param [in] pPort Address of an ::ESL_PORT structure.
1531 @param [in] pPacket Address of an ::ESL_PACKET structure.
1533 @param [in] pbConsumePacket Address of a BOOLEAN indicating if the packet is to be consumed
1535 @param [in] BufferLength Length of the the buffer
1537 @param [in] pBuffer Address of a buffer to receive the data.
1539 @param [in] pDataLength Number of received data bytes in the buffer.
1541 @param [out] pAddress Network address to receive the remote system address
1543 @param [out] pSkipBytes Address to receive the number of bytes skipped
1545 @return Returns the address of the next free byte in the buffer.
1550 IN ESL_PORT
* pPort
,
1551 IN ESL_PACKET
* pPacket
,
1552 IN BOOLEAN
* pbConsumePacket
,
1553 IN
size_t BufferLength
,
1555 OUT
size_t * pDataLength
,
1556 OUT
struct sockaddr
* pAddress
,
1557 OUT
size_t * pSkipBytes
1561 struct sockaddr_in
* pRemoteAddress
;
1562 ESL_TCP4_CONTEXT
* pTcp4
;
1567 // Return the remote system address if requested
1569 if ( NULL
!= pAddress
) {
1571 // Build the remote address
1573 pTcp4
= &pPort
->Context
.Tcp4
;
1575 "Getting packet remote address: %d.%d.%d.%d:%d\r\n",
1576 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[0],
1577 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[1],
1578 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[2],
1579 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[3],
1580 pTcp4
->ConfigData
.AccessPoint
.RemotePort
));
1581 pRemoteAddress
= (struct sockaddr_in
*)pAddress
;
1582 CopyMem ( &pRemoteAddress
->sin_addr
,
1583 &pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[0],
1584 sizeof ( pRemoteAddress
->sin_addr
));
1585 pRemoteAddress
->sin_port
= SwapBytes16 ( pTcp4
->ConfigData
.AccessPoint
.RemotePort
);
1589 // Determine the amount of received data
1591 DataLength
= pPacket
->ValidBytes
;
1592 if ( BufferLength
< DataLength
) {
1593 DataLength
= BufferLength
;
1597 // Move the data into the buffer
1600 "0x%08x: Port copy packet 0x%08x data into 0x%08x, 0x%08x bytes\r\n",
1605 CopyMem ( pBuffer
, pPacket
->pBuffer
, DataLength
);
1608 // Set the next buffer address
1610 pBuffer
+= DataLength
;
1613 // Determine if the data is being read
1615 if ( *pbConsumePacket
) {
1617 // Account for the bytes consumed
1619 pPacket
->pBuffer
+= DataLength
;
1620 pPacket
->ValidBytes
-= DataLength
;
1622 "0x%08x: Port account for 0x%08x bytes\r\n",
1627 // Determine if the entire packet was consumed
1629 if (( 0 == pPacket
->ValidBytes
)
1630 || ( SOCK_STREAM
!= pPort
->pSocket
->Type
)) {
1632 // All done with this packet
1633 // Account for any discarded data
1635 *pSkipBytes
= pPacket
->ValidBytes
;
1640 // More data to consume later
1642 *pbConsumePacket
= FALSE
;
1647 // Return the data length and the buffer address
1649 *pDataLength
= DataLength
;
1650 DBG_EXIT_HEX ( pBuffer
);
1656 Get the remote socket address.
1658 This routine returns the address of the remote connection point
1659 associated with the SOCK_STREAM or SOCK_SEQPACKET socket.
1661 This routine is called by ::EslSocketGetPeerAddress to detemine
1662 the TCPv4 address and por number associated with the network adapter.
1664 @param [in] pPort Address of an ::ESL_PORT structure.
1666 @param [out] pAddress Network address to receive the remote system address
1670 EslTcp4RemoteAddressGet (
1671 IN ESL_PORT
* pPort
,
1672 OUT
struct sockaddr
* pAddress
1675 struct sockaddr_in
* pRemoteAddress
;
1676 ESL_TCP4_CONTEXT
* pTcp4
;
1681 // Return the remote address
1683 pTcp4
= &pPort
->Context
.Tcp4
;
1684 pRemoteAddress
= (struct sockaddr_in
*)pAddress
;
1685 pRemoteAddress
->sin_family
= AF_INET
;
1686 pRemoteAddress
->sin_port
= SwapBytes16 ( pTcp4
->ConfigData
.AccessPoint
.RemotePort
);
1687 CopyMem ( &pRemoteAddress
->sin_addr
,
1688 &pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[0],
1689 sizeof ( pRemoteAddress
->sin_addr
));
1696 Set the remote address
1698 This routine sets the remote address in the port.
1700 This routine is called by ::EslSocketConnect to specify the
1701 remote network address.
1703 @param [in] pPort Address of an ::ESL_PORT structure.
1705 @param [in] pSockAddr Network address of the remote system.
1707 @param [in] SockAddrLength Length in bytes of the network address.
1709 @retval EFI_SUCCESS The operation was successful
1713 EslTcp4RemoteAddressSet (
1714 IN ESL_PORT
* pPort
,
1715 IN CONST
struct sockaddr
* pSockAddr
,
1716 IN socklen_t SockAddrLength
1719 CONST
struct sockaddr_in
* pRemoteAddress
;
1720 ESL_TCP4_CONTEXT
* pTcp4
;
1726 // Set the remote address
1728 pTcp4
= &pPort
->Context
.Tcp4
;
1729 pRemoteAddress
= (struct sockaddr_in
*)pSockAddr
;
1730 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[0] = (UINT8
)( pRemoteAddress
->sin_addr
.s_addr
);
1731 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[1] = (UINT8
)( pRemoteAddress
->sin_addr
.s_addr
>> 8 );
1732 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[2] = (UINT8
)( pRemoteAddress
->sin_addr
.s_addr
>> 16 );
1733 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[3] = (UINT8
)( pRemoteAddress
->sin_addr
.s_addr
>> 24 );
1734 pTcp4
->ConfigData
.AccessPoint
.RemotePort
= SwapBytes16 ( pRemoteAddress
->sin_port
);
1735 Status
= EFI_SUCCESS
;
1736 if ( INADDR_BROADCAST
== pRemoteAddress
->sin_addr
.s_addr
) {
1737 DEBUG (( DEBUG_CONNECT
,
1738 "ERROR - Invalid remote address\r\n" ));
1739 Status
= EFI_INVALID_PARAMETER
;
1740 pPort
->pSocket
->errno
= EAFNOSUPPORT
;
1744 // Return the operation status
1746 DBG_EXIT_STATUS ( Status
);
1752 Process the receive completion
1754 This routine queues the data in FIFO order in either the urgent
1755 or normal data queues depending upon the type of data received.
1756 See the \ref ReceiveEngine section.
1758 This routine is called by the TCPv4 driver when some data is
1761 Buffer the data that was just received.
1763 @param [in] Event The receive completion event
1765 @param [in] pIo Address of an ::ESL_IO_MGMT structure
1771 IN ESL_IO_MGMT
* pIo
1775 size_t LengthInBytes
;
1776 ESL_PACKET
* pPacket
;
1782 // Get the operation status.
1784 Status
= pIo
->Token
.Tcp4Rx
.CompletionToken
.Status
;
1787 // +--------------------+ +---------------------------+
1788 // | ESL_IO_MGMT | | ESL_PACKET |
1790 // | +---------------+ +-----------------------+ |
1791 // | | Token | | EFI_TCP4_RECEIVE_DATA | |
1792 // | | RxData --> | | |
1793 // | | | +-----------------------+---+
1794 // | | Event | | Data Buffer |
1795 // +----+---------------+ | |
1797 // +---------------------------+
1800 // Duplicate the buffer address and length for use by the
1801 // buffer handling code in EslTcp4Receive. These fields are
1802 // used when a partial read is done of the data from the
1805 pPacket
= pIo
->pPacket
;
1806 pPacket
->pBuffer
= pPacket
->Op
.Tcp4Rx
.RxData
.FragmentTable
[0].FragmentBuffer
;
1807 LengthInBytes
= pPacket
->Op
.Tcp4Rx
.RxData
.DataLength
;
1808 pPacket
->ValidBytes
= LengthInBytes
;
1811 // Get the data type so that it may be linked to the
1812 // correct receive buffer list on the ESL_SOCKET structure
1814 bUrgent
= pPacket
->Op
.Tcp4Rx
.RxData
.UrgentFlag
;
1817 // Complete this request
1819 EslSocketRxComplete ( pIo
, Status
, LengthInBytes
, bUrgent
);
1825 Start a receive operation
1827 This routine posts a receive buffer to the TCPv4 driver.
1828 See the \ref ReceiveEngine section.
1830 This support routine is called by EslSocketRxStart.
1832 @param [in] pPort Address of an ::ESL_PORT structure.
1833 @param [in] pIo Address of an ::ESL_IO_MGMT structure.
1838 IN ESL_PORT
* pPort
,
1839 IN ESL_IO_MGMT
* pIo
1842 ESL_PACKET
* pPacket
;
1847 // Initialize the buffer for receive
1849 pPacket
= pIo
->pPacket
;
1850 pIo
->Token
.Tcp4Rx
.Packet
.RxData
= &pPacket
->Op
.Tcp4Rx
.RxData
;
1851 pPacket
->Op
.Tcp4Rx
.RxData
.DataLength
= sizeof ( pPacket
->Op
.Tcp4Rx
.Buffer
);
1852 pPacket
->Op
.Tcp4Rx
.RxData
.FragmentCount
= 1;
1853 pPacket
->Op
.Tcp4Rx
.RxData
.FragmentTable
[0].FragmentLength
= pPacket
->Op
.Tcp4Rx
.RxData
.DataLength
;
1854 pPacket
->Op
.Tcp4Rx
.RxData
.FragmentTable
[0].FragmentBuffer
= &pPacket
->Op
.Tcp4Rx
.Buffer
[0];
1861 Determine if the socket is configured.
1863 This routine uses the flag ESL_SOCKET::bConfigured to determine
1864 if the network layer's configuration routine has been called.
1866 This routine is called by EslSocketIsConfigured to verify
1867 that the socket has been configured.
1869 @param [in] pSocket Address of an ::ESL_SOCKET structure.
1871 @retval EFI_SUCCESS - The port is connected
1872 @retval EFI_NOT_STARTED - The port is not connected
1876 EslTcp4SocketIsConfigured (
1877 IN ESL_SOCKET
* pSocket
1885 // Determine the socket configuration status
1887 Status
= pSocket
->bConfigured
? EFI_SUCCESS
: EFI_NOT_STARTED
;
1890 // Return the port connected state.
1892 DBG_EXIT_STATUS ( Status
);
1898 Buffer data for transmission over a network connection.
1900 This routine buffers data for the transmit engine in one of two
1901 queues, one for urgent (out-of-band) data and the other for normal
1902 data. The urgent data is provided to TCP as soon as it is available,
1903 allowing the TCP layer to schedule transmission of the urgent data
1904 between packets of normal data.
1906 This routine is called by ::EslSocketTransmit to buffer
1907 data for transmission. When the \ref TransmitEngine has resources,
1908 this routine will start the transmission of the next buffer on
1909 the network connection.
1911 Transmission errors are returned during the next transmission or
1912 during the close operation. Only buffering errors are returned
1913 during the current transmission attempt.
1915 @param [in] pSocket Address of an ::ESL_SOCKET structure
1917 @param [in] Flags Message control flags
1919 @param [in] BufferLength Length of the the buffer
1921 @param [in] pBuffer Address of a buffer to receive the data.
1923 @param [in] pDataLength Number of received data bytes in the buffer.
1925 @param [in] pAddress Network address of the remote system address
1927 @param [in] AddressLength Length of the remote network address structure
1929 @retval EFI_SUCCESS - Socket data successfully buffered
1934 IN ESL_SOCKET
* pSocket
,
1936 IN
size_t BufferLength
,
1937 IN CONST UINT8
* pBuffer
,
1938 OUT
size_t * pDataLength
,
1939 IN
const struct sockaddr
* pAddress
,
1940 IN socklen_t AddressLength
1944 BOOLEAN bUrgentQueue
;
1945 ESL_PACKET
* pPacket
;
1946 ESL_IO_MGMT
** ppActive
;
1947 ESL_IO_MGMT
** ppFree
;
1949 ESL_PACKET
** ppQueueHead
;
1950 ESL_PACKET
** ppQueueTail
;
1951 ESL_PACKET
* pPreviousPacket
;
1952 ESL_TCP4_CONTEXT
* pTcp4
;
1954 EFI_TCP4_TRANSMIT_DATA
* pTxData
;
1956 EFI_TPL TplPrevious
;
1963 Status
= EFI_UNSUPPORTED
;
1964 pSocket
->errno
= ENOTCONN
;
1968 // Verify that the socket is connected
1970 if ( SOCKET_STATE_CONNECTED
== pSocket
->State
) {
1974 pPort
= pSocket
->pPortList
;
1975 if ( NULL
!= pPort
) {
1977 // Determine the queue head
1979 pTcp4
= &pPort
->Context
.Tcp4
;
1980 bUrgent
= (BOOLEAN
)( 0 != ( Flags
& MSG_OOB
));
1981 bUrgentQueue
= bUrgent
1982 && ( !pSocket
->bOobInLine
)
1983 && pSocket
->pApi
->bOobSupported
;
1984 if ( bUrgentQueue
) {
1985 ppQueueHead
= &pSocket
->pTxOobPacketListHead
;
1986 ppQueueTail
= &pSocket
->pTxOobPacketListTail
;
1987 ppActive
= &pPort
->pTxOobActive
;
1988 ppFree
= &pPort
->pTxOobFree
;
1989 pTxBytes
= &pSocket
->TxOobBytes
;
1992 ppQueueHead
= &pSocket
->pTxPacketListHead
;
1993 ppQueueTail
= &pSocket
->pTxPacketListTail
;
1994 ppActive
= &pPort
->pTxActive
;
1995 ppFree
= &pPort
->pTxFree
;
1996 pTxBytes
= &pSocket
->TxBytes
;
2000 // Verify that there is enough room to buffer another
2001 // transmit operation
2003 if ( pSocket
->MaxTxBuf
> *pTxBytes
) {
2004 if ( pPort
->bTxFlowControl
) {
2006 "TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT\r\n0x%08x: pPort, TX flow control released, Max bytes: %d > %d bufferred bytes\r\n",
2010 pPort
->bTxFlowControl
= FALSE
;
2014 // Attempt to allocate the packet
2016 Status
= EslSocketPacketAllocate ( &pPacket
,
2017 sizeof ( pPacket
->Op
.Tcp4Tx
)
2018 - sizeof ( pPacket
->Op
.Tcp4Tx
.Buffer
)
2022 if ( !EFI_ERROR ( Status
)) {
2024 // Initialize the transmit operation
2026 pTxData
= &pPacket
->Op
.Tcp4Tx
.TxData
;
2027 pTxData
->Push
= TRUE
|| bUrgent
;
2028 pTxData
->Urgent
= bUrgent
;
2029 pTxData
->DataLength
= (UINT32
) BufferLength
;
2030 pTxData
->FragmentCount
= 1;
2031 pTxData
->FragmentTable
[0].FragmentLength
= (UINT32
) BufferLength
;
2032 pTxData
->FragmentTable
[0].FragmentBuffer
= &pPacket
->Op
.Tcp4Tx
.Buffer
[0];
2035 // Copy the data into the buffer
2037 CopyMem ( &pPacket
->Op
.Tcp4Tx
.Buffer
[0],
2042 // Synchronize with the socket layer
2044 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
2047 // Stop transmission after an error
2049 if ( !EFI_ERROR ( pSocket
->TxError
)) {
2051 // Display the request
2054 "Send %d %s bytes from 0x%08x\r\n",
2056 bUrgent
? L
"urgent" : L
"normal",
2060 // Queue the data for transmission
2062 pPacket
->pNext
= NULL
;
2063 pPreviousPacket
= *ppQueueTail
;
2064 if ( NULL
== pPreviousPacket
) {
2065 *ppQueueHead
= pPacket
;
2068 pPreviousPacket
->pNext
= pPacket
;
2070 *ppQueueTail
= pPacket
;
2072 "0x%08x: Packet on %s transmit list\r\n",
2074 bUrgentQueue
? L
"urgent" : L
"normal" ));
2077 // Account for the buffered data
2079 *pTxBytes
+= BufferLength
;
2080 *pDataLength
= BufferLength
;
2083 // Start the transmit engine if it is idle
2085 if ( NULL
!= *ppFree
) {
2086 EslSocketTxStart ( pPort
,
2095 // Previous transmit error
2096 // Stop transmission
2098 Status
= pSocket
->TxError
;
2099 pSocket
->errno
= EIO
;
2104 EslSocketPacketFree ( pPacket
, DEBUG_TX
);
2108 // Release the socket layer synchronization
2110 RESTORE_TPL ( TplPrevious
);
2114 // Packet allocation failed
2116 pSocket
->errno
= ENOMEM
;
2120 if ( !pPort
->bTxFlowControl
) {
2122 "0x%08x: pPort, TX flow control applied, Max bytes %d <= %d bufferred bytes\r\nTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT\r\n",
2126 pPort
->bTxFlowControl
= TRUE
;
2129 // Not enough buffer space available
2131 pSocket
->errno
= EAGAIN
;
2132 Status
= EFI_NOT_READY
;
2138 // Return the operation status
2140 DBG_EXIT_STATUS ( Status
);
2146 Process the normal data transmit completion
2148 This routine use ::EslSocketTxComplete to perform the transmit
2149 completion processing for normal data.
2151 This routine is called by the TCPv4 network layer when a
2152 normal data transmit request completes.
2154 @param [in] Event The normal transmit completion event
2156 @param [in] pIo The ESL_IO_MGMT structure address
2162 IN ESL_IO_MGMT
* pIo
2165 UINT32 LengthInBytes
;
2166 ESL_PACKET
* pPacket
;
2168 ESL_SOCKET
* pSocket
;
2174 // Locate the active transmit packet
2176 pPacket
= pIo
->pPacket
;
2178 pSocket
= pPort
->pSocket
;
2181 // Get the transmit length and status
2183 LengthInBytes
= pPacket
->Op
.Tcp4Tx
.TxData
.DataLength
;
2184 pSocket
->TxBytes
-= LengthInBytes
;
2185 Status
= pIo
->Token
.Tcp4Tx
.CompletionToken
.Status
;
2188 // Complete the transmit operation
2190 EslSocketTxComplete ( pIo
,
2194 &pSocket
->pTxPacketListHead
,
2195 &pSocket
->pTxPacketListTail
,
2203 Process the urgent data transmit completion
2205 This routine use ::EslSocketTxComplete to perform the transmit
2206 completion processing for urgent data.
2208 This routine is called by the TCPv4 network layer when a
2209 urgent data transmit request completes.
2211 @param [in] Event The urgent transmit completion event
2213 @param [in] pIo The ESL_IO_MGMT structure address
2217 EslTcp4TxOobComplete (
2219 IN ESL_IO_MGMT
* pIo
2222 UINT32 LengthInBytes
;
2223 ESL_PACKET
* pPacket
;
2225 ESL_SOCKET
* pSocket
;
2231 // Locate the active transmit packet
2233 pPacket
= pIo
->pPacket
;
2235 pSocket
= pPort
->pSocket
;
2238 // Get the transmit length and status
2240 LengthInBytes
= pPacket
->Op
.Tcp4Tx
.TxData
.DataLength
;
2241 pSocket
->TxOobBytes
-= LengthInBytes
;
2242 Status
= pIo
->Token
.Tcp4Tx
.CompletionToken
.Status
;
2245 // Complete the transmit operation
2247 EslSocketTxComplete ( pIo
,
2251 &pSocket
->pTxOobPacketListHead
,
2252 &pSocket
->pTxOobPacketListTail
,
2253 &pPort
->pTxOobActive
,
2254 &pPort
->pTxOobFree
);
2260 Interface between the socket layer and the network specific
2261 code that supports SOCK_STREAM and SOCK_SEQPACKET sockets
2264 CONST ESL_PROTOCOL_API cEslTcp4Api
= {
2267 OFFSET_OF ( ESL_PORT
, Context
.Tcp4
.ConfigData
),
2268 OFFSET_OF ( ESL_LAYER
, pTcp4List
),
2269 OFFSET_OF ( struct sockaddr_in
, sin_zero
),
2270 sizeof ( struct sockaddr_in
),
2272 sizeof (((ESL_PACKET
*)0 )->Op
.Tcp4Rx
),
2273 OFFSET_OF ( ESL_PACKET
, Op
.Tcp4Rx
.Buffer
) - OFFSET_OF ( ESL_PACKET
, Op
),
2274 OFFSET_OF ( ESL_IO_MGMT
, Token
.Tcp4Rx
.Packet
.RxData
),
2279 EslTcp4ConnectStart
,
2280 EslTcp4SocketIsConfigured
,
2281 EslTcp4LocalAddressGet
,
2282 EslTcp4LocalAddressSet
,
2287 EslTcp4PortAllocate
,
2292 EslTcp4RemoteAddressGet
,
2293 EslTcp4RemoteAddressSet
,
2298 EslTcp4TxOobComplete