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.
19 Accept a network connection.
21 The SocketAccept routine waits for a network connection to the socket.
22 It is able to return the remote network address to the caller if
25 @param [in] pSocket Address of the socket structure.
27 @param [in] pSockAddr Address of a buffer to receive the remote
30 @param [in, out] pSockAddrLength Length in bytes of the address buffer.
31 On output specifies the length of the
32 remote network address.
34 @retval EFI_SUCCESS Remote address is available
35 @retval Others Remote address not available
40 IN DT_SOCKET
* pSocket
,
41 IN
struct sockaddr
* pSockAddr
,
42 IN OUT socklen_t
* pSockAddrLength
46 struct sockaddr_in
* pRemoteAddress
;
47 DT_TCP4_CONTEXT
* pTcp4
;
54 // Validate the socket length
56 pRemoteAddress
= (struct sockaddr_in
*) pSockAddr
;
57 if (( NULL
== pSockAddrLength
)
58 || ( sizeof ( *pRemoteAddress
) > *pSockAddrLength
)) {
60 // Invalid socket address
62 Status
= EFI_INVALID_PARAMETER
;
63 pSocket
->errno
= EINVAL
;
64 DEBUG (( DEBUG_ACCEPT
,
65 "ERROR - Invalid address length\r\n" ));
74 // Locate the address context
76 pPort
= pSocket
->pPortList
;
77 pTcp4
= &pPort
->Context
.Tcp4
;
80 // Fill-in the remote address structure
82 ZeroMem ( pRemoteAddress
, sizeof ( *pRemoteAddress
));
83 pRemoteAddress
->sin_len
= sizeof ( *pRemoteAddress
);
84 pRemoteAddress
->sin_family
= AF_INET
;
85 pRemoteAddress
->sin_port
= SwapBytes16 ( pTcp4
->ConfigData
.AccessPoint
.RemotePort
);
86 RemoteAddress
= pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[3];
88 RemoteAddress
|= pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[2];
90 RemoteAddress
|= pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[1];
92 RemoteAddress
|= pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[0];
93 pRemoteAddress
->sin_addr
.s_addr
= RemoteAddress
;
97 // Return the operation status
99 DBG_EXIT_STATUS ( Status
);
105 Bind a name to a socket.
107 The ::TcpBind4 routine connects a name to a TCP4 stack on the local machine.
109 @param [in] pSocket Address of the socket structure.
111 @param [in] pSockAddr Address of a sockaddr structure that contains the
112 connection point on the local machine. An IPv4 address
113 of INADDR_ANY specifies that the connection is made to
114 all of the network stacks on the platform. Specifying a
115 specific IPv4 address restricts the connection to the
116 network stack supporting that address. Specifying zero
117 for the port causes the network layer to assign a port
118 number from the dynamic range. Specifying a specific
119 port number causes the network layer to use that port.
121 @param [in] SockAddrLen Specifies the length in bytes of the sockaddr structure.
123 @retval EFI_SUCCESS - Socket successfully created
128 IN DT_SOCKET
* pSocket
,
129 IN
const struct sockaddr
* pSockAddr
,
130 IN socklen_t SockAddrLength
133 EFI_HANDLE ChildHandle
;
136 DT_SERVICE
* pService
;
137 CONST
struct sockaddr_in
* pIp4Address
;
138 EFI_SERVICE_BINDING_PROTOCOL
* pTcp4Service
;
140 EFI_STATUS TempStatus
;
145 // Verify the socket layer synchronization
147 VERIFY_TPL ( TPL_SOCKETS
);
153 Status
= EFI_SUCCESS
;
156 // Validate the address length
158 pIp4Address
= (CONST
struct sockaddr_in
*) pSockAddr
;
159 if ( SockAddrLength
>= ( sizeof ( *pIp4Address
)
160 - sizeof ( pIp4Address
->sin_zero
))) {
163 // Walk the list of services
166 pService
= pLayer
->pTcp4List
;
167 while ( NULL
!= pService
) {
169 // Create the TCP port
171 pTcp4Service
= pService
->pInterface
;
173 Status
= pTcp4Service
->CreateChild ( pTcp4Service
,
175 if ( !EFI_ERROR ( Status
)) {
176 DEBUG (( DEBUG_BIND
| DEBUG_POOL
,
177 "0x%08x: Tcp4 port handle created\r\n",
183 Status
= EslTcpPortAllocate4 ( pSocket
,
186 (UINT8
*) &pIp4Address
->sin_addr
.s_addr
,
187 SwapBytes16 ( pIp4Address
->sin_port
),
192 DEBUG (( DEBUG_BIND
| DEBUG_POOL
,
193 "ERROR - Failed to open Tcp4 port handle, Status: %r\r\n",
199 // Close the port if necessary
201 if (( EFI_ERROR ( Status
)) && ( NULL
!= ChildHandle
)) {
202 TempStatus
= pTcp4Service
->DestroyChild ( pTcp4Service
,
204 if ( !EFI_ERROR ( TempStatus
)) {
205 DEBUG (( DEBUG_BIND
| DEBUG_POOL
,
206 "0x%08x: Tcp4 port handle destroyed\r\n",
210 DEBUG (( DEBUG_ERROR
| DEBUG_BIND
| DEBUG_POOL
,
211 "ERROR - Failed to destroy the Tcp4 port handle 0x%08x, Status: %r\r\n",
214 ASSERT ( EFI_SUCCESS
== TempStatus
);
219 // Set the next service
221 pService
= pService
->pNext
;
225 // Verify that at least one network connection was found
227 if ( NULL
== pSocket
->pPortList
) {
228 DEBUG (( DEBUG_BIND
| DEBUG_POOL
| DEBUG_INIT
,
229 "Socket address %d.%d.%d.%d (0x%08x) is not available!\r\n",
230 ( pIp4Address
->sin_addr
.s_addr
>> 24 ) & 0xff,
231 ( pIp4Address
->sin_addr
.s_addr
>> 16 ) & 0xff,
232 ( pIp4Address
->sin_addr
.s_addr
>> 8 ) & 0xff,
233 pIp4Address
->sin_addr
.s_addr
& 0xff,
234 pIp4Address
->sin_addr
.s_addr
));
235 pSocket
->errno
= EADDRNOTAVAIL
;
236 Status
= EFI_INVALID_PARAMETER
;
241 "ERROR - Invalid TCP4 address length: %d\r\n",
243 Status
= EFI_INVALID_PARAMETER
;
244 pSocket
->errno
= EINVAL
;
248 // Return the operation status
250 DBG_EXIT_STATUS ( Status
);
256 Attempt to connect to a remote TCP port
258 @param [in] pSocket Address of the socket structure.
260 @retval EFI_SUCCESS The connection was successfully established.
261 @retval EFI_NOT_READY The connection is in progress, call this routine again.
262 @retval Others The connection attempt failed.
266 EslTcpConnectAttempt4 (
267 IN DT_SOCKET
* pSocket
271 DT_TCP4_CONTEXT
* pTcp4
;
272 EFI_TCP4_PROTOCOL
* pTcp4Protocol
;
278 // Determine if any more local adapters are available
280 pPort
= pSocket
->pPortList
;
281 if ( NULL
!= pPort
) {
283 // Configure the port
285 pTcp4
= &pPort
->Context
.Tcp4
;
286 pTcp4
->ConfigData
.AccessPoint
.ActiveFlag
= TRUE
;
287 pTcp4
->ConfigData
.TimeToLive
= 255;
288 pTcp4Protocol
= pTcp4
->pProtocol
;
289 Status
= pTcp4Protocol
->Configure ( pTcp4Protocol
,
290 &pTcp4
->ConfigData
);
291 if ( EFI_ERROR ( Status
)) {
292 DEBUG (( DEBUG_CONNECT
,
293 "ERROR - Failed to configure the Tcp4 port, Status: %r\r\n",
296 case EFI_ACCESS_DENIED
:
297 pSocket
->errno
= EACCES
;
301 case EFI_DEVICE_ERROR
:
302 pSocket
->errno
= EIO
;
305 case EFI_INVALID_PARAMETER
:
306 pSocket
->errno
= EADDRNOTAVAIL
;
310 pSocket
->errno
= EAFNOSUPPORT
;
313 case EFI_OUT_OF_RESOURCES
:
314 pSocket
->errno
= ENOBUFS
;
317 case EFI_UNSUPPORTED
:
318 pSocket
->errno
= EOPNOTSUPP
;
323 DEBUG (( DEBUG_CONNECT
,
324 "0x%08x: Port configured\r\n",
326 pTcp4
->bConfigured
= TRUE
;
329 // Attempt the connection to the remote system
331 Status
= pTcp4Protocol
->Connect ( pTcp4Protocol
,
332 &pTcp4
->ConnectToken
);
333 if ( !EFI_ERROR ( Status
)) {
335 // Connection in progress
337 pSocket
->errno
= EINPROGRESS
;
338 Status
= EFI_NOT_READY
;
339 DEBUG (( DEBUG_CONNECT
,
340 "0x%08x: Port attempting connection to %d.%d.%d.%d:%d\r\n",
342 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[0],
343 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[1],
344 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[2],
345 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[3],
346 pTcp4
->ConfigData
.AccessPoint
.RemotePort
));
352 pSocket
->errno
= EINVAL
;
353 DEBUG (( DEBUG_CONNECT
,
354 "ERROR - Port 0x%08x not connected, Status: %r\r\n",
362 // No more local adapters available
364 pSocket
->errno
= ENETUNREACH
;
365 Status
= EFI_NO_RESPONSE
;
369 // Return the operation status
371 DBG_EXIT_STATUS ( Status
);
377 Process the remote connection attempt
379 A connection attempt to a remote system has just completed when
380 this routine is invoked. Release the port in the case of an
381 error and start a connection attempt on the next port. If the
382 connection attempt was successful, then release all of the other
385 @param Event The connect completion event
387 @param pPort The DT_PORT structure address
391 EslTcpConnectComplete4 (
396 BOOLEAN bRemoveFirstPort
;
397 BOOLEAN bRemovePorts
;
400 DT_TCP4_CONTEXT
* pTcp4
;
406 // Locate the TCP context
408 pSocket
= pPort
->pSocket
;
409 pTcp4
= &pPort
->Context
.Tcp4
;
412 // Get the connection status
414 bRemoveFirstPort
= FALSE
;
415 bRemovePorts
= FALSE
;
416 Status
= pTcp4
->ConnectToken
.CompletionToken
.Status
;
417 pSocket
->ConnectStatus
= Status
;
418 if ( !EFI_ERROR ( Status
)) {
420 // The connection was successful
422 DEBUG (( DEBUG_CONNECT
,
423 "0x%08x: Port connected to %d.%d.%d.%d:%d\r\n",
425 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[0],
426 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[1],
427 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[2],
428 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[3],
429 pTcp4
->ConfigData
.AccessPoint
.RemotePort
));
432 // Remove the rest of the ports
438 // The connection failed
440 DEBUG (( DEBUG_CONNECT
,
441 "0x%08x: Port connection to %d.%d.%d.%d:%d failed, Status: %r\r\n",
443 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[0],
444 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[1],
445 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[2],
446 pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[3],
447 pTcp4
->ConfigData
.AccessPoint
.RemotePort
,
451 // Close the current port
453 Status
= EslTcpPortClose4 ( pPort
);
454 if ( !EFI_ERROR ( Status
)) {
455 DEBUG (( DEBUG_CONNECT
,
456 "0x%08x: Port closed\r\n",
460 DEBUG (( DEBUG_CONNECT
,
461 "ERROR - Failed to close port 0x%08x, Status: %r\r\n",
467 // Try to connect using the next port
469 Status
= EslTcpConnectAttempt4 ( pSocket
);
470 if ( EFI_NOT_READY
!= Status
) {
471 pSocket
->ConnectStatus
= Status
;
472 bRemoveFirstPort
= TRUE
;
477 // Remove the ports if necessary
479 if ( bRemoveFirstPort
|| bRemovePorts
) {
481 // Remove the first port if necessary
483 pPort
= pSocket
->pPortList
;
484 if (( !bRemoveFirstPort
) && ( NULL
!= pPort
)) {
485 pPort
= pPort
->pLinkSocket
;
489 // Remove the rest of the list
491 while ( NULL
!= pPort
) {
492 pNextPort
= pPort
->pLinkSocket
;
493 EslTcpPortClose4 ( pPort
);
494 if ( !EFI_ERROR ( Status
)) {
495 DEBUG (( DEBUG_CONNECT
,
496 "0x%08x: Port closed\r\n",
500 DEBUG (( DEBUG_CONNECT
,
501 "ERROR - Failed to close port 0x%08x, Status: %r\r\n",
509 // Notify the poll routine
511 pSocket
->bConnected
= TRUE
;
519 Poll for completion of the connection attempt.
521 The ::TcpConnectPoll4 routine determines when the connection
522 attempt transitions from being in process to being complete.
524 @param [in] pSocket Address of the socket structure.
526 @retval EFI_SUCCESS The connection was successfully established.
527 @retval EFI_NOT_READY The connection is in progress, call this routine again.
528 @retval Others The connection attempt failed.
533 IN DT_SOCKET
* pSocket
541 // Determine if the connection is complete
543 if ( !pSocket
->bConnected
) {
547 pSocket
->errno
= EAGAIN
;
548 Status
= EFI_NOT_READY
;
552 // The connection processing is complete
554 pSocket
->bConnected
= FALSE
;
557 // Translate the connection status
559 Status
= pSocket
->ConnectStatus
;
562 case EFI_DEVICE_ERROR
:
563 pSocket
->errno
= EIO
;
567 pSocket
->errno
= ECONNREFUSED
;
570 case EFI_INVALID_PARAMETER
:
571 pSocket
->errno
= EINVAL
;
575 case EFI_NO_RESPONSE
:
576 pSocket
->errno
= EHOSTUNREACH
;
580 pSocket
->errno
= ENETDOWN
;
583 case EFI_OUT_OF_RESOURCES
:
584 pSocket
->errno
= ENOMEM
;
589 pSocket
->bConfigured
= TRUE
;
593 pSocket
->errno
= ETIMEDOUT
;
596 case EFI_UNSUPPORTED
:
597 pSocket
->errno
= ENOTSUP
;
601 pSocket
->errno
= ECONNRESET
;
607 // Return the initialization status
609 DBG_EXIT_STATUS ( Status
);
615 Connect to a remote system via the network.
617 The ::TcpConnectStart4= routine starts the connection processing
620 @param [in] pSocket Address of the socket structure.
622 @param [in] pSockAddr Network address of the remote system.
624 @param [in] SockAddrLength Length in bytes of the network address.
626 @retval EFI_SUCCESS The connection was successfully established.
627 @retval EFI_NOT_READY The connection is in progress, call this routine again.
628 @retval Others The connection attempt failed.
632 EslTcpConnectStart4 (
633 IN DT_SOCKET
* pSocket
,
634 IN
const struct sockaddr
* pSockAddr
,
635 IN socklen_t SockAddrLength
638 struct sockaddr_in LocalAddress
;
640 DT_TCP4_CONTEXT
* pTcp4
;
641 CONST
struct sockaddr_in
* pIp4Address
;
647 // Validate the address length
649 Status
= EFI_SUCCESS
;
650 pIp4Address
= (CONST
struct sockaddr_in
*) pSockAddr
;
651 if ( SockAddrLength
>= ( sizeof ( *pIp4Address
)
652 - sizeof ( pIp4Address
->sin_zero
))) {
654 // Determine if BIND was already called
656 if ( NULL
== pSocket
->pPortList
) {
658 // Allow any local port
660 ZeroMem ( &LocalAddress
, sizeof ( LocalAddress
));
661 LocalAddress
.sin_len
= sizeof ( LocalAddress
);
662 LocalAddress
.sin_family
= AF_INET
;
663 Status
= EslSocketBind ( &pSocket
->SocketProtocol
,
664 (struct sockaddr
*)&LocalAddress
,
665 LocalAddress
.sin_len
,
668 if ( NULL
!= pSocket
->pPortList
) {
670 // Walk the list of ports
672 pPort
= pSocket
->pPortList
;
673 while ( NULL
!= pPort
) {
675 // Set the remote address
677 pTcp4
= &pPort
->Context
.Tcp4
;
678 *(UINT32
*)&pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
= pIp4Address
->sin_addr
.s_addr
;
679 pTcp4
->ConfigData
.AccessPoint
.RemotePort
= SwapBytes16 ( pIp4Address
->sin_port
);
684 pPort
= pPort
->pLinkSocket
;
688 // Attempt a connection using the first adapter
690 Status
= EslTcpConnectAttempt4 ( pSocket
);
694 DEBUG (( DEBUG_CONNECT
,
695 "ERROR - Invalid TCP4 address length: %d\r\n",
697 Status
= EFI_INVALID_PARAMETER
;
698 pSocket
->errno
= EINVAL
;
702 // Return the initialization status
704 DBG_EXIT_STATUS ( Status
);
710 Initialize the TCP4 service.
712 This routine initializes the TCP4 service after its service binding
713 protocol was located on a controller.
715 @param [in] pService DT_SERVICE structure address
717 @retval EFI_SUCCESS The service was properly initialized
718 @retval other A failure occurred during the service initialization
724 IN DT_SERVICE
* pService
733 // Identify the service
735 pService
->NetworkType
= NETWORK_TYPE_TCP4
;
738 // Connect this service to the service list
741 pService
->pNext
= pLayer
->pTcp4List
;
742 pLayer
->pTcp4List
= pService
;
745 // Assume the list is empty
747 Status
= EFI_SUCCESS
;
750 // Return the initialization status
752 DBG_EXIT_STATUS ( Status
);
758 Get the local socket address
760 @param [in] pSocket Address of the socket structure.
762 @param [out] pAddress Network address to receive the local system address
764 @param [in,out] pAddressLength Length of the local network address structure
766 @retval EFI_SUCCESS - Address available
767 @retval Other - Failed to get the address
771 EslTcpGetLocalAddress4 (
772 IN DT_SOCKET
* pSocket
,
773 OUT
struct sockaddr
* pAddress
,
774 IN OUT socklen_t
* pAddressLength
777 socklen_t LengthInBytes
;
779 struct sockaddr_in
* pLocalAddress
;
780 DT_TCP4_CONTEXT
* pTcp4
;
786 // Verify the socket layer synchronization
788 VERIFY_TPL ( TPL_SOCKETS
);
791 // Verify that there is just a single connection
793 pPort
= pSocket
->pPortList
;
794 if (( NULL
!= pPort
) && ( NULL
== pPort
->pLinkSocket
)) {
796 // Verify the address length
798 LengthInBytes
= sizeof ( struct sockaddr_in
);
799 if ( LengthInBytes
<= * pAddressLength
) {
801 // Return the local address
803 pTcp4
= &pPort
->Context
.Tcp4
;
804 pLocalAddress
= (struct sockaddr_in
*)pAddress
;
805 ZeroMem ( pLocalAddress
, LengthInBytes
);
806 pLocalAddress
->sin_family
= AF_INET
;
807 pLocalAddress
->sin_len
= (uint8_t)LengthInBytes
;
808 pLocalAddress
->sin_port
= SwapBytes16 ( pTcp4
->ConfigData
.AccessPoint
.StationPort
);
809 CopyMem ( &pLocalAddress
->sin_addr
,
810 &pTcp4
->ConfigData
.AccessPoint
.StationAddress
.Addr
[0],
811 sizeof ( pLocalAddress
->sin_addr
));
813 Status
= EFI_SUCCESS
;
816 pSocket
->errno
= EINVAL
;
817 Status
= EFI_INVALID_PARAMETER
;
821 pSocket
->errno
= ENOTCONN
;
822 Status
= EFI_NOT_STARTED
;
826 // Return the operation status
828 DBG_EXIT_STATUS ( Status
);
834 Get the remote socket address
836 @param [in] pSocket Address of the socket structure.
838 @param [out] pAddress Network address to receive the remote system address
840 @param [in,out] pAddressLength Length of the remote network address structure
842 @retval EFI_SUCCESS - Address available
843 @retval Other - Failed to get the address
847 EslTcpGetRemoteAddress4 (
848 IN DT_SOCKET
* pSocket
,
849 OUT
struct sockaddr
* pAddress
,
850 IN OUT socklen_t
* pAddressLength
853 socklen_t LengthInBytes
;
855 struct sockaddr_in
* pRemoteAddress
;
856 DT_TCP4_CONTEXT
* pTcp4
;
862 // Verify the socket layer synchronization
864 VERIFY_TPL ( TPL_SOCKETS
);
867 // Verify that there is just a single connection
869 pPort
= pSocket
->pPortList
;
870 if (( NULL
!= pPort
) && ( NULL
== pPort
->pLinkSocket
)) {
872 // Verify the address length
874 LengthInBytes
= sizeof ( struct sockaddr_in
);
875 if ( LengthInBytes
<= * pAddressLength
) {
877 // Return the local address
879 pTcp4
= &pPort
->Context
.Tcp4
;
880 pRemoteAddress
= (struct sockaddr_in
*)pAddress
;
881 ZeroMem ( pRemoteAddress
, LengthInBytes
);
882 pRemoteAddress
->sin_family
= AF_INET
;
883 pRemoteAddress
->sin_len
= (uint8_t)LengthInBytes
;
884 pRemoteAddress
->sin_port
= SwapBytes16 ( pTcp4
->ConfigData
.AccessPoint
.RemotePort
);
885 CopyMem ( &pRemoteAddress
->sin_addr
,
886 &pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[0],
887 sizeof ( pRemoteAddress
->sin_addr
));
889 Status
= EFI_SUCCESS
;
892 pSocket
->errno
= EINVAL
;
893 Status
= EFI_INVALID_PARAMETER
;
897 pSocket
->errno
= ENOTCONN
;
898 Status
= EFI_NOT_STARTED
;
902 // Return the operation status
904 DBG_EXIT_STATUS ( Status
);
910 Establish the known port to listen for network connections.
912 The ::Tcp4Listen routine places the port into a state that enables connection
913 attempts. Connections are placed into FIFO order in a queue to be serviced
914 by the application. The application calls the ::Tcp4Accept routine to remove
915 the next connection from the queue and get the associated socket. The
916 <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.html">POSIX</a>
917 documentation for the listen routine is available online for reference.
919 @param [in] pSocket Address of the socket structure.
921 @retval EFI_SUCCESS - Socket successfully created
922 @retval Other - Failed to enable the socket for listen
927 IN DT_SOCKET
* pSocket
932 DT_TCP4_CONTEXT
* pTcp4
;
933 EFI_TCP4_PROTOCOL
* pTcp4Protocol
;
939 // Verify the socket layer synchronization
941 VERIFY_TPL ( TPL_SOCKETS
);
944 // Use for/break instead of goto
948 // Assume no ports are available
950 pSocket
->errno
= EOPNOTSUPP
;
951 Status
= EFI_NOT_READY
;
954 // Walk the list of ports
956 pPort
= pSocket
->pPortList
;
957 while ( NULL
!= pPort
) {
964 // Use for/break insteak of goto
968 // Create the listen completion event
970 pTcp4
= &pPort
->Context
.Tcp4
;
971 Status
= gBS
->CreateEvent ( EVT_NOTIFY_SIGNAL
,
973 (EFI_EVENT_NOTIFY
)EslTcpListenComplete4
,
975 &pTcp4
->ListenToken
.CompletionToken
.Event
);
976 if ( EFI_ERROR ( Status
)) {
977 DEBUG (( DEBUG_ERROR
| DEBUG_LISTEN
,
978 "ERROR - Failed to create the listen completion event, Status: %r\r\n",
980 pSocket
->errno
= ENOMEM
;
984 "0x%08x: Created listen completion event\r\n",
985 pTcp4
->ListenToken
.CompletionToken
.Event
));
988 // Configure the port
990 pTcp4Protocol
= pTcp4
->pProtocol
;
991 Status
= pTcp4Protocol
->Configure ( pTcp4Protocol
,
992 &pTcp4
->ConfigData
);
993 if ( EFI_ERROR ( Status
)) {
994 DEBUG (( DEBUG_LISTEN
,
995 "ERROR - Failed to configure the Tcp4 port, Status: %r\r\n",
998 case EFI_ACCESS_DENIED
:
999 pSocket
->errno
= EACCES
;
1003 case EFI_DEVICE_ERROR
:
1004 pSocket
->errno
= EIO
;
1007 case EFI_INVALID_PARAMETER
:
1008 pSocket
->errno
= EADDRNOTAVAIL
;
1011 case EFI_NO_MAPPING
:
1012 pSocket
->errno
= EAFNOSUPPORT
;
1015 case EFI_OUT_OF_RESOURCES
:
1016 pSocket
->errno
= ENOBUFS
;
1019 case EFI_UNSUPPORTED
:
1020 pSocket
->errno
= EOPNOTSUPP
;
1025 DEBUG (( DEBUG_LISTEN
,
1026 "0x%08x: Port configured\r\n",
1028 pTcp4
->bConfigured
= TRUE
;
1031 // Start the listen operation on the port
1033 Status
= pTcp4Protocol
->Accept ( pTcp4Protocol
,
1034 &pTcp4
->ListenToken
);
1035 if ( EFI_ERROR ( Status
)) {
1036 DEBUG (( DEBUG_LISTEN
,
1037 "ERROR - Failed Tcp4 accept, Status: %r\r\n",
1040 case EFI_ACCESS_DENIED
:
1041 pSocket
->errno
= EACCES
;
1045 case EFI_DEVICE_ERROR
:
1046 pSocket
->errno
= EIO
;
1049 case EFI_INVALID_PARAMETER
:
1050 pSocket
->errno
= EADDRNOTAVAIL
;
1053 case EFI_NOT_STARTED
:
1054 pSocket
->errno
= ENETDOWN
;
1057 case EFI_OUT_OF_RESOURCES
:
1058 pSocket
->errno
= ENOBUFS
;
1063 DEBUG (( DEBUG_LISTEN
,
1064 "0x%08x: Listen pending on Port\r\n",
1068 // Listen is pending on this port
1074 // Get the next port
1076 pNextPort
= pPort
->pLinkSocket
;
1079 // Close the port upon error
1081 if ( EFI_ERROR ( Status
))
1083 EslTcpPortCloseStart4 ( pPort
, TRUE
, DEBUG_LISTEN
);
1087 // Set the next port
1093 // Determine if any ports are in the listen state
1095 if ( NULL
== pSocket
->pPortList
) {
1097 // No ports in the listen state
1099 pSocket
->MaxFifoDepth
= 0;
1102 // Return the last error detected
1108 // Mark the socket as configured
1110 pSocket
->bConfigured
= TRUE
;
1115 DEBUG (( DEBUG_LISTEN
,
1116 "0x%08x: pSocket - Listen pending on socket\r\n",
1122 // Return the operation status
1124 DBG_EXIT_STATUS ( Status
);
1130 Process the connection attempt
1132 A system has initiated a connection attempt with a socket in the
1133 listen state. Attempt to complete the connection.
1135 @param Event The listen completion event
1137 @param pPort The DT_PORT structure address
1141 EslTcpListenComplete4 (
1146 EFI_HANDLE ChildHandle
;
1147 EFI_TCP4_CONFIG_DATA
* pConfigData
;
1150 DT_SOCKET
* pNewSocket
;
1151 DT_SOCKET
* pSocket
;
1152 DT_TCP4_CONTEXT
* pTcp4
;
1153 EFI_TCP4_PROTOCOL
* pTcp4Protocol
;
1155 EFI_HANDLE TcpPortHandle
;
1156 EFI_STATUS TempStatus
;
1163 Status
= EFI_SUCCESS
;
1166 // Determine if this connection fits into the connection FIFO
1168 pSocket
= pPort
->pSocket
;
1169 TcpPortHandle
= pPort
->Context
.Tcp4
.ListenToken
.NewChildHandle
;
1170 if (( SOCKET_STATE_LISTENING
== pSocket
->State
)
1171 && ( pSocket
->MaxFifoDepth
> pSocket
->FifoDepth
)) {
1173 // Allocate a socket for this connection
1176 pLayer
= &mEslLayer
;
1177 Status
= EslSocketAllocate ( &ChildHandle
,
1180 if ( !EFI_ERROR ( Status
)) {
1182 // Clone the socket parameters
1184 pNewSocket
->Domain
= pSocket
->Domain
;
1185 pNewSocket
->Protocol
= pSocket
->Protocol
;
1186 pNewSocket
->Type
= pSocket
->Type
;
1189 // Allocate a port for this connection
1191 pTcp4
= &pPort
->Context
.Tcp4
;
1192 Status
= EslTcpPortAllocate4 ( pNewSocket
,
1195 &pTcp4
->ConfigData
.AccessPoint
.StationAddress
.Addr
[0],
1199 if ( !EFI_ERROR ( Status
)) {
1201 // Restart the listen operation on the port
1203 pTcp4Protocol
= pTcp4
->pProtocol
;
1204 Status
= pTcp4Protocol
->Accept ( pTcp4Protocol
,
1205 &pTcp4
->ListenToken
);
1208 // Close the TCP port using SocketClose
1210 TcpPortHandle
= NULL
;
1211 pTcp4
= &pNewPort
->Context
.Tcp4
;
1212 pTcp4
->bConfigured
= TRUE
;
1215 // Check for an accept call error
1217 if ( !EFI_ERROR ( Status
)) {
1219 // Get the port configuration
1221 pConfigData
= &pTcp4
->ConfigData
;
1222 pConfigData
->ControlOption
= &pTcp4
->Option
;
1223 pTcp4Protocol
= pTcp4
->pProtocol
;
1224 Status
= pTcp4Protocol
->GetModeData ( pTcp4Protocol
,
1230 if ( !EFI_ERROR ( Status
)) {
1232 // Add the new socket to the connection FIFO
1234 if ( NULL
== pSocket
->pFifoTail
) {
1238 pSocket
->pFifoHead
= pNewSocket
;
1242 // Add to end of list.
1244 pSocket
->pFifoTail
->pNextConnection
= pNewSocket
;
1246 pSocket
->pFifoTail
= pNewSocket
;
1247 pSocket
->FifoDepth
+= 1;
1250 // Update the socket state
1252 pNewSocket
->State
= SOCKET_STATE_IN_FIFO
;
1255 // Log the connection
1257 DEBUG (( DEBUG_CONNECTION
| DEBUG_INFO
,
1258 "0x%08x: Socket on port %d.%d.%d.%d:%d connected to %d.%d.%d.%d:%d\r\n",
1260 pConfigData
->AccessPoint
.StationAddress
.Addr
[0],
1261 pConfigData
->AccessPoint
.StationAddress
.Addr
[1],
1262 pConfigData
->AccessPoint
.StationAddress
.Addr
[2],
1263 pConfigData
->AccessPoint
.StationAddress
.Addr
[3],
1264 pConfigData
->AccessPoint
.StationPort
,
1265 pConfigData
->AccessPoint
.RemoteAddress
.Addr
[0],
1266 pConfigData
->AccessPoint
.RemoteAddress
.Addr
[1],
1267 pConfigData
->AccessPoint
.RemoteAddress
.Addr
[2],
1268 pConfigData
->AccessPoint
.RemoteAddress
.Addr
[3],
1269 pConfigData
->AccessPoint
.RemotePort
));
1270 DEBUG (( DEBUG_CONNECTION
| DEBUG_INFO
,
1271 "0x%08x: Listen socket adding socket 0x%08x to FIFO, depth: %d\r\n",
1274 pSocket
->FifoDepth
));
1277 // Start the receive operation
1279 EslTcpRxStart4 ( pNewPort
);
1282 DEBUG (( DEBUG_ERROR
| DEBUG_CONNECTION
| DEBUG_INFO
,
1283 "ERROR - GetModeData failed on port 0x%08x, Status: %r\r\n",
1290 // The listen failed on this port
1292 DEBUG (( DEBUG_LISTEN
| DEBUG_INFO
,
1293 "ERROR - Listen failed on port 0x%08x, Status: %r\r\n",
1298 // Close the listening port
1300 EslTcpPortCloseStart4 ( pPort
, TRUE
, DEBUG_LISTEN
);
1305 // Done with the socket if necessary
1307 if ( EFI_ERROR ( Status
)) {
1308 TempStatus
= EslSocketCloseStart ( &pNewSocket
->SocketProtocol
,
1311 ASSERT ( EFI_SUCCESS
== TempStatus
);
1316 DEBUG (( DEBUG_CONNECTION
,
1317 "0x%08x: Socket FIFO full, connection refused\r\n",
1321 // The FIFO is full or the socket is in the wrong state
1323 Status
= EFI_BUFFER_TOO_SMALL
;
1327 // Close the connection if necessary
1329 if (( EFI_ERROR ( Status
))
1330 && ( NULL
== TcpPortHandle
)) {
1332 // TODO: Finish this code path
1333 // The new connection does not fit into the connection FIFO
1337 // Release the resources
1346 Allocate and initialize a DT_PORT structure.
1348 @param [in] pSocket Address of the socket structure.
1349 @param [in] pService Address of the DT_SERVICE structure.
1350 @param [in] ChildHandle TCP4 child handle
1351 @param [in] pIpAddress Buffer containing IP4 network address of the local host
1352 @param [in] PortNumber Tcp4 port number
1353 @param [in] DebugFlags Flags for debug messages
1354 @param [out] ppPort Buffer to receive new DT_PORT structure address
1356 @retval EFI_SUCCESS - Socket successfully created
1360 EslTcpPortAllocate4 (
1361 IN DT_SOCKET
* pSocket
,
1362 IN DT_SERVICE
* pService
,
1363 IN EFI_HANDLE ChildHandle
,
1364 IN CONST UINT8
* pIpAddress
,
1365 IN UINT16 PortNumber
,
1366 IN UINTN DebugFlags
,
1367 OUT DT_PORT
** ppPort
1370 UINTN LengthInBytes
;
1371 EFI_TCP4_ACCESS_POINT
* pAccessPoint
;
1374 DT_TCP4_CONTEXT
* pTcp4
;
1380 // Use for/break instead of goto
1383 // Allocate a port structure
1385 pLayer
= &mEslLayer
;
1386 LengthInBytes
= sizeof ( *pPort
);
1387 Status
= gBS
->AllocatePool ( EfiRuntimeServicesData
,
1390 if ( EFI_ERROR ( Status
)) {
1391 DEBUG (( DEBUG_ERROR
| DebugFlags
| DEBUG_POOL
| DEBUG_INIT
,
1392 "ERROR - Failed to allocate the port structure, Status: %r\r\n",
1394 pSocket
->errno
= ENOMEM
;
1398 DEBUG (( DebugFlags
| DEBUG_POOL
| DEBUG_INIT
,
1399 "0x%08x: Allocate pPort, %d bytes\r\n",
1404 // Initialize the port
1406 ZeroMem ( pPort
, LengthInBytes
);
1407 pPort
->Signature
= PORT_SIGNATURE
;
1408 pPort
->pService
= pService
;
1409 pPort
->pSocket
= pSocket
;
1410 pPort
->pfnCloseStart
= EslTcpPortCloseStart4
;
1411 pPort
->DebugFlags
= DebugFlags
;
1414 // Allocate the receive event
1416 pTcp4
= &pPort
->Context
.Tcp4
;
1417 Status
= gBS
->CreateEvent ( EVT_NOTIFY_SIGNAL
,
1419 (EFI_EVENT_NOTIFY
)EslTcpRxComplete4
,
1421 &pTcp4
->RxToken
.CompletionToken
.Event
);
1422 if ( EFI_ERROR ( Status
)) {
1423 DEBUG (( DEBUG_ERROR
| DebugFlags
,
1424 "ERROR - Failed to create the receive event, Status: %r\r\n",
1426 pSocket
->errno
= ENOMEM
;
1429 DEBUG (( DEBUG_RX
| DEBUG_POOL
,
1430 "0x%08x: Created receive event\r\n",
1431 pTcp4
->RxToken
.CompletionToken
.Event
));
1434 // Allocate the urgent transmit event
1436 Status
= gBS
->CreateEvent ( EVT_NOTIFY_SIGNAL
,
1438 (EFI_EVENT_NOTIFY
)EslTcpTxOobComplete4
,
1440 &pTcp4
->TxOobToken
.CompletionToken
.Event
);
1441 if ( EFI_ERROR ( Status
)) {
1442 DEBUG (( DEBUG_ERROR
| DebugFlags
,
1443 "ERROR - Failed to create the urgent transmit event, Status: %r\r\n",
1445 pSocket
->errno
= ENOMEM
;
1448 DEBUG (( DEBUG_CLOSE
| DEBUG_POOL
,
1449 "0x%08x: Created urgent transmit event\r\n",
1450 pTcp4
->TxOobToken
.CompletionToken
.Event
));
1453 // Allocate the normal transmit event
1455 Status
= gBS
->CreateEvent ( EVT_NOTIFY_SIGNAL
,
1457 (EFI_EVENT_NOTIFY
)EslTcpTxComplete4
,
1459 &pTcp4
->TxToken
.CompletionToken
.Event
);
1460 if ( EFI_ERROR ( Status
)) {
1461 DEBUG (( DEBUG_ERROR
| DebugFlags
,
1462 "ERROR - Failed to create the normal transmit event, Status: %r\r\n",
1464 pSocket
->errno
= ENOMEM
;
1467 DEBUG (( DEBUG_CLOSE
| DEBUG_POOL
,
1468 "0x%08x: Created normal transmit event\r\n",
1469 pTcp4
->TxToken
.CompletionToken
.Event
));
1472 // Allocate the close event
1474 Status
= gBS
->CreateEvent ( EVT_NOTIFY_SIGNAL
,
1476 (EFI_EVENT_NOTIFY
)EslTcpPortCloseComplete4
,
1478 &pTcp4
->CloseToken
.CompletionToken
.Event
);
1479 if ( EFI_ERROR ( Status
)) {
1480 DEBUG (( DEBUG_ERROR
| DebugFlags
,
1481 "ERROR - Failed to create the close event, Status: %r\r\n",
1483 pSocket
->errno
= ENOMEM
;
1486 DEBUG (( DEBUG_CLOSE
| DEBUG_POOL
,
1487 "0x%08x: Created close event\r\n",
1488 pTcp4
->CloseToken
.CompletionToken
.Event
));
1491 // Allocate the connection event
1493 Status
= gBS
->CreateEvent ( EVT_NOTIFY_SIGNAL
,
1495 (EFI_EVENT_NOTIFY
)EslTcpConnectComplete4
,
1497 &pTcp4
->ConnectToken
.CompletionToken
.Event
);
1498 if ( EFI_ERROR ( Status
)) {
1499 DEBUG (( DEBUG_ERROR
| DebugFlags
,
1500 "ERROR - Failed to create the connect event, Status: %r\r\n",
1502 pSocket
->errno
= ENOMEM
;
1505 DEBUG (( DEBUG_CLOSE
| DEBUG_POOL
,
1506 "0x%08x: Created connect event\r\n",
1507 pTcp4
->ConnectToken
.CompletionToken
.Event
));
1510 // Open the port protocol
1512 Status
= gBS
->OpenProtocol (
1514 &gEfiTcp4ProtocolGuid
,
1515 (VOID
**) &pTcp4
->pProtocol
,
1516 pLayer
->ImageHandle
,
1518 EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL
);
1519 if ( EFI_ERROR ( Status
)) {
1520 DEBUG (( DEBUG_ERROR
| DebugFlags
,
1521 "ERROR - Failed to open gEfiTcp4ProtocolGuid on controller 0x%08x\r\n",
1523 pSocket
->errno
= EEXIST
;
1526 DEBUG (( DebugFlags
,
1527 "0x%08x: gEfiTcp4ProtocolGuid opened on controller 0x%08x\r\n",
1532 // Set the port address
1534 pTcp4
->Handle
= ChildHandle
;
1535 pAccessPoint
= &pPort
->Context
.Tcp4
.ConfigData
.AccessPoint
;
1536 pAccessPoint
->StationPort
= PortNumber
;
1537 if (( 0 == pIpAddress
[0])
1538 && ( 0 == pIpAddress
[1])
1539 && ( 0 == pIpAddress
[2])
1540 && ( 0 == pIpAddress
[3])) {
1541 pAccessPoint
->UseDefaultAddress
= TRUE
;
1544 pAccessPoint
->StationAddress
.Addr
[0] = pIpAddress
[0];
1545 pAccessPoint
->StationAddress
.Addr
[1] = pIpAddress
[1];
1546 pAccessPoint
->StationAddress
.Addr
[2] = pIpAddress
[2];
1547 pAccessPoint
->StationAddress
.Addr
[3] = pIpAddress
[3];
1548 pAccessPoint
->SubnetMask
.Addr
[0] = 0xff;
1549 pAccessPoint
->SubnetMask
.Addr
[1] = 0xff;
1550 pAccessPoint
->SubnetMask
.Addr
[2] = 0xff;
1551 pAccessPoint
->SubnetMask
.Addr
[3] = 0xff;
1553 pAccessPoint
->ActiveFlag
= FALSE
;
1554 pTcp4
->ConfigData
.TimeToLive
= 255;
1557 // Verify the socket layer synchronization
1559 VERIFY_TPL ( TPL_SOCKETS
);
1562 // Add this port to the socket
1564 pPort
->pLinkSocket
= pSocket
->pPortList
;
1565 pSocket
->pPortList
= pPort
;
1566 DEBUG (( DebugFlags
,
1567 "0x%08x: Socket adding port: 0x%08x\r\n",
1572 // Add this port to the service
1574 pPort
->pLinkService
= pService
->pPortList
;
1575 pService
->pPortList
= pPort
;
1585 // Clean up after the error if necessary
1587 if (( EFI_ERROR ( Status
)) && ( NULL
!= pPort
)) {
1591 EslTcpPortClose4 ( pPort
);
1594 // Return the operation status
1596 DBG_EXIT_STATUS ( Status
);
1604 This routine releases the resources allocated by
1605 ::TcpPortAllocate4().
1607 @param [in] pPort Address of the port structure.
1609 @retval EFI_SUCCESS The port is closed
1610 @retval other Port close error
1620 DT_PACKET
* pPacket
;
1621 DT_PORT
* pPreviousPort
;
1622 DT_SERVICE
* pService
;
1623 DT_SOCKET
* pSocket
;
1624 EFI_SERVICE_BINDING_PROTOCOL
* pTcp4Service
;
1625 DT_TCP4_CONTEXT
* pTcp4
;
1631 // Verify the socket layer synchronization
1633 VERIFY_TPL ( TPL_SOCKETS
);
1636 // Locate the port in the socket list
1638 Status
= EFI_SUCCESS
;
1639 pLayer
= &mEslLayer
;
1640 DebugFlags
= pPort
->DebugFlags
;
1641 pSocket
= pPort
->pSocket
;
1642 pPreviousPort
= pSocket
->pPortList
;
1643 if ( pPreviousPort
== pPort
) {
1645 // Remove this port from the head of the socket list
1647 pSocket
->pPortList
= pPort
->pLinkSocket
;
1651 // Locate the port in the middle of the socket list
1653 while (( NULL
!= pPreviousPort
)
1654 && ( pPreviousPort
->pLinkSocket
!= pPort
)) {
1655 pPreviousPort
= pPreviousPort
->pLinkSocket
;
1657 if ( NULL
!= pPreviousPort
) {
1659 // Remove the port from the middle of the socket list
1661 pPreviousPort
->pLinkSocket
= pPort
->pLinkSocket
;
1666 // Locate the port in the service list
1668 pService
= pPort
->pService
;
1669 pPreviousPort
= pService
->pPortList
;
1670 if ( pPreviousPort
== pPort
) {
1672 // Remove this port from the head of the service list
1674 pService
->pPortList
= pPort
->pLinkService
;
1678 // Locate the port in the middle of the service list
1680 while (( NULL
!= pPreviousPort
)
1681 && ( pPreviousPort
->pLinkService
!= pPort
)) {
1682 pPreviousPort
= pPreviousPort
->pLinkService
;
1684 if ( NULL
!= pPreviousPort
) {
1686 // Remove the port from the middle of the service list
1688 pPreviousPort
->pLinkService
= pPort
->pLinkService
;
1693 // Empty the urgent receive queue
1695 pTcp4
= &pPort
->Context
.Tcp4
;
1696 while ( NULL
!= pSocket
->pRxOobPacketListHead
) {
1697 pPacket
= pSocket
->pRxOobPacketListHead
;
1698 pSocket
->pRxOobPacketListHead
= pPacket
->pNext
;
1699 pSocket
->RxOobBytes
-= pPacket
->Op
.Tcp4Rx
.ValidBytes
;
1700 EslSocketPacketFree ( pPacket
, DEBUG_RX
);
1702 pSocket
->pRxOobPacketListTail
= NULL
;
1703 ASSERT ( 0 == pSocket
->RxOobBytes
);
1706 // Empty the receive queue
1708 while ( NULL
!= pSocket
->pRxPacketListHead
) {
1709 pPacket
= pSocket
->pRxPacketListHead
;
1710 pSocket
->pRxPacketListHead
= pPacket
->pNext
;
1711 pSocket
->RxBytes
-= pPacket
->Op
.Tcp4Rx
.ValidBytes
;
1712 EslSocketPacketFree ( pPacket
, DEBUG_RX
);
1714 pSocket
->pRxPacketListTail
= NULL
;
1715 ASSERT ( 0 == pSocket
->RxBytes
);
1718 // Empty the receive free queue
1720 while ( NULL
!= pSocket
->pRxFree
) {
1721 pPacket
= pSocket
->pRxFree
;
1722 pSocket
->pRxFree
= pPacket
->pNext
;
1723 EslSocketPacketFree ( pPacket
, DEBUG_RX
);
1727 // Done with the connect event
1729 if ( NULL
!= pTcp4
->ConnectToken
.CompletionToken
.Event
) {
1730 Status
= gBS
->CloseEvent ( pTcp4
->ConnectToken
.CompletionToken
.Event
);
1731 if ( !EFI_ERROR ( Status
)) {
1732 DEBUG (( DebugFlags
| DEBUG_POOL
,
1733 "0x%08x: Closed connect event\r\n",
1734 pTcp4
->ConnectToken
.CompletionToken
.Event
));
1737 DEBUG (( DEBUG_ERROR
| DebugFlags
,
1738 "ERROR - Failed to close the connect event, Status: %r\r\n",
1740 ASSERT ( EFI_SUCCESS
== Status
);
1745 // Done with the close event
1747 if ( NULL
!= pTcp4
->CloseToken
.CompletionToken
.Event
) {
1748 Status
= gBS
->CloseEvent ( pTcp4
->CloseToken
.CompletionToken
.Event
);
1749 if ( !EFI_ERROR ( Status
)) {
1750 DEBUG (( DebugFlags
| DEBUG_POOL
,
1751 "0x%08x: Closed close event\r\n",
1752 pTcp4
->CloseToken
.CompletionToken
.Event
));
1755 DEBUG (( DEBUG_ERROR
| DebugFlags
,
1756 "ERROR - Failed to close the close event, Status: %r\r\n",
1758 ASSERT ( EFI_SUCCESS
== Status
);
1763 // Done with the listen completion event
1765 if ( NULL
!= pTcp4
->ListenToken
.CompletionToken
.Event
) {
1766 Status
= gBS
->CloseEvent ( pTcp4
->ListenToken
.CompletionToken
.Event
);
1767 if ( !EFI_ERROR ( Status
)) {
1768 DEBUG (( DebugFlags
| DEBUG_POOL
,
1769 "0x%08x: Closed listen completion event\r\n",
1770 pTcp4
->ListenToken
.CompletionToken
.Event
));
1773 DEBUG (( DEBUG_ERROR
| DebugFlags
,
1774 "ERROR - Failed to close the listen completion event, Status: %r\r\n",
1776 ASSERT ( EFI_SUCCESS
== Status
);
1781 // Done with the receive event
1783 if ( NULL
!= pTcp4
->RxToken
.CompletionToken
.Event
) {
1784 Status
= gBS
->CloseEvent ( pTcp4
->RxToken
.CompletionToken
.Event
);
1785 if ( !EFI_ERROR ( Status
)) {
1786 DEBUG (( DebugFlags
| DEBUG_POOL
,
1787 "0x%08x: Closed receive event\r\n",
1788 pTcp4
->RxToken
.CompletionToken
.Event
));
1791 DEBUG (( DEBUG_ERROR
| DebugFlags
,
1792 "ERROR - Failed to close the receive event, Status: %r\r\n",
1794 ASSERT ( EFI_SUCCESS
== Status
);
1799 // Done with the normal transmit event
1801 if ( NULL
!= pTcp4
->TxToken
.CompletionToken
.Event
) {
1802 Status
= gBS
->CloseEvent ( pTcp4
->TxToken
.CompletionToken
.Event
);
1803 if ( !EFI_ERROR ( Status
)) {
1804 DEBUG (( DebugFlags
| DEBUG_POOL
,
1805 "0x%08x: Closed normal transmit event\r\n",
1806 pTcp4
->TxToken
.CompletionToken
.Event
));
1809 DEBUG (( DEBUG_ERROR
| DebugFlags
,
1810 "ERROR - Failed to close the normal transmit event, Status: %r\r\n",
1812 ASSERT ( EFI_SUCCESS
== Status
);
1817 // Done with the urgent transmit event
1819 if ( NULL
!= pTcp4
->TxOobToken
.CompletionToken
.Event
) {
1820 Status
= gBS
->CloseEvent ( pTcp4
->TxOobToken
.CompletionToken
.Event
);
1821 if ( !EFI_ERROR ( Status
)) {
1822 DEBUG (( DebugFlags
| DEBUG_POOL
,
1823 "0x%08x: Closed urgent transmit event\r\n",
1824 pTcp4
->TxOobToken
.CompletionToken
.Event
));
1827 DEBUG (( DEBUG_ERROR
| DebugFlags
,
1828 "ERROR - Failed to close the urgent transmit event, Status: %r\r\n",
1830 ASSERT ( EFI_SUCCESS
== Status
);
1835 // Done with the TCP protocol
1837 pTcp4Service
= pService
->pInterface
;
1838 if ( NULL
!= pTcp4
->pProtocol
) {
1839 Status
= gBS
->CloseProtocol ( pTcp4
->Handle
,
1840 &gEfiTcp4ProtocolGuid
,
1841 pLayer
->ImageHandle
,
1843 if ( !EFI_ERROR ( Status
)) {
1844 DEBUG (( DebugFlags
,
1845 "0x%08x: gEfiTcp4ProtocolGuid closed on controller 0x%08x\r\n",
1850 DEBUG (( DEBUG_ERROR
| DebugFlags
,
1851 "ERROR - Failed to close gEfiTcp4ProtocolGuid opened on controller 0x%08x, Status: %r\r\n",
1854 ASSERT ( EFI_SUCCESS
== Status
);
1859 // Done with the TCP port
1861 if ( NULL
!= pTcp4
->Handle
) {
1862 Status
= pTcp4Service
->DestroyChild ( pTcp4Service
,
1864 if ( !EFI_ERROR ( Status
)) {
1865 DEBUG (( DebugFlags
| DEBUG_POOL
,
1866 "0x%08x: Tcp4 port handle destroyed\r\n",
1870 DEBUG (( DEBUG_ERROR
| DebugFlags
| DEBUG_POOL
,
1871 "ERROR - Failed to destroy the Tcp4 port handle, Status: %r\r\n",
1873 ASSERT ( EFI_SUCCESS
== Status
);
1878 // Release the port structure
1880 Status
= gBS
->FreePool ( pPort
);
1881 if ( !EFI_ERROR ( Status
)) {
1882 DEBUG (( DebugFlags
| DEBUG_POOL
,
1883 "0x%08x: Free pPort, %d bytes\r\n",
1885 sizeof ( *pPort
)));
1888 DEBUG (( DEBUG_ERROR
| DebugFlags
| DEBUG_POOL
,
1889 "ERROR - Failed to free pPort: 0x%08x, Status: %r\r\n",
1892 ASSERT ( EFI_SUCCESS
== Status
);
1896 // Return the operation status
1898 DBG_EXIT_STATUS ( Status
);
1904 Process the port close completion
1906 @param Event The close completion event
1908 @param pPort The DT_PORT structure address
1912 EslTcpPortCloseComplete4 (
1922 // Update the port state
1924 pPort
->State
= PORT_STATE_CLOSE_DONE
;
1927 // Release the resources once the receive operation completes
1929 Status
= EslTcpPortCloseRxDone4 ( pPort
);
1930 DBG_EXIT_STATUS ( Status
);
1935 Start the close operation on a TCP4 port, state 1.
1937 Closing a port goes through the following states:
1938 1. Port close starting - Mark the port as closing and wait for transmission to complete
1939 2. Port TX close done - Transmissions complete, close the port and abort the receives
1940 3. Port RX close done - Receive operations complete, close the port
1941 4. Port closed - Release the port resources
1943 @param [in] pPort Address of the port structure.
1944 @param [in] bCloseNow Set TRUE to abort active transfers
1945 @param [in] DebugFlags Flags for debug messages
1947 @retval EFI_SUCCESS The port is closed, not normally returned
1948 @retval EFI_NOT_READY The port has started the closing process
1949 @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
1950 most likely the routine was called already.
1954 EslTcpPortCloseStart4 (
1956 IN BOOLEAN bCloseNow
,
1960 DT_SOCKET
* pSocket
;
1966 // Verify the socket layer synchronization
1968 VERIFY_TPL ( TPL_SOCKETS
);
1971 // Mark the port as closing
1973 Status
= EFI_ALREADY_STARTED
;
1974 pSocket
= pPort
->pSocket
;
1975 pSocket
->errno
= EALREADY
;
1976 if ( PORT_STATE_CLOSE_STARTED
> pPort
->State
) {
1979 // Update the port state
1981 pPort
->State
= PORT_STATE_CLOSE_STARTED
;
1982 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
1983 "0x%08x: Port Close State: PORT_STATE_CLOSE_STARTED\r\n",
1985 pPort
->bCloseNow
= bCloseNow
;
1986 pPort
->DebugFlags
= DebugFlags
;
1989 // Determine if transmits are complete
1991 Status
= EslTcpPortCloseTxDone4 ( pPort
);
1995 // Return the operation status
1997 DBG_EXIT_STATUS ( Status
);
2005 Continue the close operation after the receive is complete.
2007 @param [in] pPort Address of the port structure.
2009 @retval EFI_SUCCESS The port is closed
2010 @retval EFI_NOT_READY The port is still closing
2011 @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
2012 most likely the routine was called already.
2016 EslTcpPortCloseRxDone4 (
2020 PORT_STATE PortState
;
2021 DT_TCP4_CONTEXT
* pTcp4
;
2027 // Verify the socket layer synchronization
2029 VERIFY_TPL ( TPL_SOCKETS
);
2032 // Verify that the port is closing
2034 Status
= EFI_ALREADY_STARTED
;
2035 PortState
= pPort
->State
;
2036 if (( PORT_STATE_CLOSE_TX_DONE
== PortState
)
2037 || ( PORT_STATE_CLOSE_DONE
== PortState
)) {
2039 // Determine if the receive operation is pending
2041 Status
= EFI_NOT_READY
;
2042 pTcp4
= &pPort
->Context
.Tcp4
;
2043 if ( NULL
== pTcp4
->pReceivePending
) {
2045 // The receive operation is complete
2046 // Update the port state
2048 pPort
->State
= PORT_STATE_CLOSE_RX_DONE
;
2049 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
2050 "0x%08x: Port Close State: PORT_STATE_CLOSE_RX_DONE\r\n",
2054 // Determine if the close operation has completed
2056 if ( PORT_STATE_CLOSE_DONE
== PortState
) {
2058 // The close operation has completed
2059 // Release the port resources
2061 Status
= EslTcpPortClose4 ( pPort
);
2065 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
2066 "0x%08x: Port Close: Close operation still pending!\r\n",
2071 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
2072 "0x%08x: Port Close: Receive still pending!\r\n",
2078 // Return the operation status
2080 DBG_EXIT_STATUS ( Status
);
2088 Continue the close operation after the transmission is complete.
2090 @param [in] pPort Address of the port structure.
2092 @retval EFI_SUCCESS The port is closed, not normally returned
2093 @retval EFI_NOT_READY The port is still closing
2094 @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
2095 most likely the routine was called already.
2099 EslTcpPortCloseTxDone4 (
2103 DT_SOCKET
* pSocket
;
2104 DT_TCP4_CONTEXT
* pTcp4
;
2105 EFI_TCP4_PROTOCOL
* pTcp4Protocol
;
2111 // Verify the socket layer synchronization
2113 VERIFY_TPL ( TPL_SOCKETS
);
2116 // All transmissions are complete or must be stopped
2117 // Mark the port as TX complete
2119 Status
= EFI_ALREADY_STARTED
;
2120 if ( PORT_STATE_CLOSE_STARTED
== pPort
->State
) {
2122 // Verify that the transmissions are complete
2124 pSocket
= pPort
->pSocket
;
2125 if ( pPort
->bCloseNow
2126 || ( EFI_SUCCESS
!= pSocket
->TxError
)
2127 || (( 0 == pSocket
->TxOobBytes
)
2128 && ( 0 == pSocket
->TxBytes
))) {
2130 // Start the close operation on the port
2132 pTcp4
= &pPort
->Context
.Tcp4
;
2133 pTcp4
->CloseToken
.AbortOnClose
= FALSE
;
2134 pTcp4Protocol
= pTcp4
->pProtocol
;
2135 if ( !pTcp4
->bConfigured
) {
2137 // Skip the close operation since the port is not
2140 // Update the port state
2142 pPort
->State
= PORT_STATE_CLOSE_DONE
;
2143 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
2144 "0x%08x: Port Close State: PORT_STATE_CLOSE_DONE\r\n",
2146 Status
= EFI_SUCCESS
;
2150 // Close the configured port
2152 Status
= pTcp4Protocol
->Close ( pTcp4Protocol
,
2153 &pTcp4
->CloseToken
);
2154 if ( !EFI_ERROR ( Status
)) {
2155 DEBUG (( pPort
->DebugFlags
| DEBUG_CLOSE
| DEBUG_INFO
,
2156 "0x%08x: Port close started\r\n",
2160 // Update the port state
2162 pPort
->State
= PORT_STATE_CLOSE_TX_DONE
;
2163 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
2164 "0x%08x: Port Close State: PORT_STATE_CLOSE_TX_DONE\r\n",
2168 DEBUG (( DEBUG_ERROR
| pPort
->DebugFlags
| DEBUG_CLOSE
| DEBUG_INFO
,
2169 "ERROR - Close failed on port 0x%08x, Status: %r\r\n",
2172 ASSERT ( EFI_SUCCESS
== Status
);
2177 // Determine if the receive operation is pending
2179 if ( !EFI_ERROR ( Status
)) {
2180 Status
= EslTcpPortCloseRxDone4 ( pPort
);
2185 // Transmissions are still active, exit
2187 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
2188 "0x%08x: Port Close: Transmits are still pending!\r\n",
2190 Status
= EFI_NOT_READY
;
2191 pSocket
->errno
= EAGAIN
;
2196 // Return the operation status
2198 DBG_EXIT_STATUS ( Status
);
2204 Receive data from a network connection.
2207 @param [in] pSocket Address of a DT_SOCKET structure
2209 @param [in] Flags Message control flags
2211 @param [in] BufferLength Length of the the buffer
2213 @param [in] pBuffer Address of a buffer to receive the data.
2215 @param [in] pDataLength Number of received data bytes in the buffer.
2217 @param [out] pAddress Network address to receive the remote system address
2219 @param [in,out] pAddressLength Length of the remote network address structure
2221 @retval EFI_SUCCESS - Socket data successfully received
2226 IN DT_SOCKET
* pSocket
,
2228 IN
size_t BufferLength
,
2230 OUT
size_t * pDataLength
,
2231 OUT
struct sockaddr
* pAddress
,
2232 IN OUT socklen_t
* pAddressLength
2235 socklen_t AddressLength
;
2237 in_addr_t IpAddress
;
2238 size_t LengthInBytes
;
2239 DT_PACKET
* pPacket
;
2241 DT_PACKET
** ppQueueHead
;
2242 DT_PACKET
** ppQueueTail
;
2243 struct sockaddr_in
* pRemoteAddress
;
2244 size_t * pRxDataBytes
;
2245 DT_TCP4_CONTEXT
* pTcp4
;
2246 struct sockaddr_in RemoteAddress
;
2254 Status
= EFI_UNSUPPORTED
;
2255 pSocket
->errno
= ENOTCONN
;
2258 // Verify that the socket is connected
2260 if (( SOCKET_STATE_CONNECTED
== pSocket
->State
)
2261 || ( PORT_STATE_RX_ERROR
== pSocket
->State
)) {
2265 pPort
= pSocket
->pPortList
;
2266 if ( NULL
!= pPort
) {
2268 // Determine the queue head
2270 pTcp4
= &pPort
->Context
.Tcp4
;
2271 if ( 0 != ( Flags
& MSG_OOB
)) {
2272 ppQueueHead
= &pSocket
->pRxOobPacketListHead
;
2273 ppQueueTail
= &pSocket
->pRxOobPacketListTail
;
2274 pRxDataBytes
= &pSocket
->RxOobBytes
;
2277 ppQueueHead
= &pSocket
->pRxPacketListHead
;
2278 ppQueueTail
= &pSocket
->pRxPacketListTail
;
2279 pRxDataBytes
= &pSocket
->RxBytes
;
2283 // Determine if there is any data on the queue
2285 pPacket
= *ppQueueHead
;
2286 if ( NULL
!= pPacket
) {
2288 // Validate the return address parameters
2290 if (( NULL
== pAddress
) || ( NULL
!= pAddressLength
)) {
2292 // Return the remote system address if requested
2294 if ( NULL
!= pAddress
) {
2296 // Build the remote address
2298 ZeroMem ( &RemoteAddress
, sizeof ( RemoteAddress
));
2299 RemoteAddress
.sin_len
= sizeof ( RemoteAddress
);
2300 RemoteAddress
.sin_family
= AF_INET
;
2301 IpAddress
= pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[3];
2303 IpAddress
|= pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[2];
2305 IpAddress
|= pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[1];
2307 IpAddress
|= pTcp4
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[0];
2308 RemoteAddress
.sin_addr
.s_addr
= IpAddress
;
2309 RemoteAddress
.sin_port
= SwapBytes16 ( pTcp4
->ConfigData
.AccessPoint
.RemotePort
);
2314 pRemoteAddress
= (struct sockaddr_in
*)pAddress
;
2315 AddressLength
= sizeof ( *pRemoteAddress
);
2316 if ( AddressLength
> *pAddressLength
) {
2317 AddressLength
= *pAddressLength
;
2319 CopyMem ( pRemoteAddress
,
2324 // Update the address length
2326 *pAddressLength
= AddressLength
;
2330 // Copy the received data
2335 // Determine the amount of received data
2337 BytesToCopy
= pPacket
->Op
.Tcp4Rx
.ValidBytes
;
2338 if (( BufferLength
- LengthInBytes
) < BytesToCopy
) {
2339 BytesToCopy
= BufferLength
- LengthInBytes
;
2341 LengthInBytes
+= BytesToCopy
;
2344 // Move the data into the buffer
2347 "0x%08x: Port copy packet 0x%08x data into 0x%08x, 0x%08x bytes\r\n",
2352 CopyMem ( pBuffer
, pPacket
->Op
.Tcp4Rx
.pBuffer
, BytesToCopy
);
2355 // Determine if the data is being read
2357 if ( 0 == ( Flags
& MSG_PEEK
)) {
2359 // Account for the bytes consumed
2361 pPacket
->Op
.Tcp4Rx
.pBuffer
+= BytesToCopy
;
2362 pPacket
->Op
.Tcp4Rx
.ValidBytes
-= BytesToCopy
;
2363 *pRxDataBytes
-= BytesToCopy
;
2365 "0x%08x: Port account for 0x%08x bytes\r\n",
2370 // Determine if the entire packet was consumed
2372 if (( 0 == pPacket
->Op
.Tcp4Rx
.ValidBytes
)
2373 || ( SOCK_STREAM
!= pSocket
->Type
)) {
2375 // All done with this packet
2376 // Account for any discarded data
2378 *pRxDataBytes
-= pPacket
->Op
.Tcp4Rx
.ValidBytes
;
2379 if ( 0 != pPacket
->Op
.Tcp4Rx
.ValidBytes
) {
2381 "0x%08x: Port, packet read, skipping over 0x%08x bytes\r\n",
2383 pPacket
->Op
.Tcp4Rx
.ValidBytes
));
2387 // Remove this packet from the queue
2389 *ppQueueHead
= pPacket
->pNext
;
2390 if ( NULL
== *ppQueueHead
) {
2391 *ppQueueTail
= NULL
;
2395 // Move the packet to the free queue
2397 pPacket
->pNext
= pSocket
->pRxFree
;
2398 pSocket
->pRxFree
= pPacket
;
2400 "0x%08x: Port freeing packet 0x%08x\r\n",
2405 // Restart this receive operation if necessary
2407 if (( NULL
== pTcp4
->pReceivePending
)
2408 && ( MAX_RX_DATA
> pSocket
->RxBytes
)) {
2409 EslTcpRxStart4 ( pPort
);
2415 // Get the next packet
2417 pPacket
= *ppQueueHead
;
2418 } while (( SOCK_STREAM
== pSocket
->Type
)
2419 && ( NULL
!= pPacket
)
2420 && ( 0 == ( Flags
& MSG_PEEK
))
2421 && ( BufferLength
> LengthInBytes
));
2424 // Return the data length
2426 *pDataLength
= LengthInBytes
;
2429 // Successful operation
2431 Status
= EFI_SUCCESS
;
2436 // Bad return address pointer and length
2438 Status
= EFI_INVALID_PARAMETER
;
2439 pSocket
->errno
= EINVAL
;
2444 // The queue is empty
2445 // Determine if it is time to return the receive error
2447 if ( EFI_ERROR ( pSocket
->RxError
)
2448 && ( NULL
== pSocket
->pRxPacketListHead
)
2449 && ( NULL
== pSocket
->pRxOobPacketListHead
)) {
2450 Status
= pSocket
->RxError
;
2453 pSocket
->errno
= EIO
;
2456 case EFI_CONNECTION_FIN
:
2457 pSocket
->errno
= ESHUTDOWN
;
2460 case EFI_CONNECTION_REFUSED
:
2461 pSocket
->errno
= ECONNREFUSED
;
2464 case EFI_CONNECTION_RESET
:
2465 pSocket
->errno
= ECONNRESET
;
2468 case EFI_HOST_UNREACHABLE
:
2469 pSocket
->errno
= EHOSTUNREACH
;
2472 case EFI_NETWORK_UNREACHABLE
:
2473 pSocket
->errno
= ENETUNREACH
;
2476 case EFI_PORT_UNREACHABLE
:
2477 pSocket
->errno
= EPROTONOSUPPORT
;
2480 case EFI_PROTOCOL_UNREACHABLE
:
2481 pSocket
->errno
= ENOPROTOOPT
;
2484 pSocket
->RxError
= EFI_SUCCESS
;
2487 Status
= EFI_NOT_READY
;
2488 pSocket
->errno
= EAGAIN
;
2495 // Return the operation status
2497 DBG_EXIT_STATUS ( Status
);
2503 Cancel the receive operations
2505 @param [in] pSocket Address of a DT_SOCKET structure
2507 @retval EFI_SUCCESS - The cancel was successful
2512 IN DT_SOCKET
* pSocket
2515 DT_PACKET
* pPacket
;
2517 DT_TCP4_CONTEXT
* pTcp4
;
2518 EFI_TCP4_PROTOCOL
* pTcp4Protocol
;
2526 Status
= EFI_NOT_FOUND
;
2531 pPort
= pSocket
->pPortList
;
2532 if ( NULL
!= pPort
) {
2534 // Determine if a receive is pending
2536 pTcp4
= &pPort
->Context
.Tcp4
;
2537 pPacket
= pTcp4
->pReceivePending
;
2538 if ( NULL
!= pPacket
) {
2540 // Attempt to cancel the receive operation
2542 pTcp4Protocol
= pTcp4
->pProtocol
;
2543 Status
= pTcp4Protocol
->Cancel ( pTcp4Protocol
,
2544 &pTcp4
->RxToken
.CompletionToken
);
2545 if ( EFI_NOT_FOUND
== Status
) {
2547 // The receive is complete
2549 Status
= EFI_SUCCESS
;
2555 // Return the operation status
2557 DBG_EXIT_STATUS ( Status
);
2563 Process the receive completion
2565 Buffer the data that was just received.
2567 @param Event The receive completion event
2569 @param pPort The DT_PORT structure address
2579 size_t LengthInBytes
;
2580 DT_PACKET
* pPacket
;
2581 DT_PACKET
* pPrevious
;
2582 DT_SOCKET
* pSocket
;
2583 DT_TCP4_CONTEXT
* pTcp4
;
2589 // Mark this receive complete
2591 pTcp4
= &pPort
->Context
.Tcp4
;
2592 pPacket
= pTcp4
->pReceivePending
;
2593 pTcp4
->pReceivePending
= NULL
;
2596 // Determine if this receive was successful
2598 pSocket
= pPort
->pSocket
;
2599 Status
= pTcp4
->RxToken
.CompletionToken
.Status
;
2600 if (( !EFI_ERROR ( Status
)) && ( !pSocket
->bRxDisable
)) {
2602 // Set the buffer size and address
2604 pPacket
->Op
.Tcp4Rx
.pBuffer
= pPacket
->Op
.Tcp4Rx
.RxData
.FragmentTable
[0].FragmentBuffer
;
2605 LengthInBytes
= pPacket
->Op
.Tcp4Rx
.RxData
.DataLength
;
2606 pPacket
->Op
.Tcp4Rx
.ValidBytes
= LengthInBytes
;
2607 pPacket
->pNext
= NULL
;
2610 // Queue this packet
2612 bUrgent
= pPacket
->Op
.Tcp4Rx
.RxData
.UrgentFlag
;
2615 // Add packet to the urgent list
2617 pPrevious
= pSocket
->pRxOobPacketListTail
;
2618 if ( NULL
== pPrevious
) {
2619 pSocket
->pRxOobPacketListHead
= pPacket
;
2622 pPrevious
->pNext
= pPacket
;
2624 pSocket
->pRxOobPacketListTail
= pPacket
;
2627 // Account for the urgent data
2629 pSocket
->RxOobBytes
+= LengthInBytes
;
2633 // Add packet to the normal list
2635 pPrevious
= pSocket
->pRxPacketListTail
;
2636 if ( NULL
== pPrevious
) {
2637 pSocket
->pRxPacketListHead
= pPacket
;
2640 pPrevious
->pNext
= pPacket
;
2642 pSocket
->pRxPacketListTail
= pPacket
;
2645 // Account for the normal data
2647 pSocket
->RxBytes
+= LengthInBytes
;
2651 // Log the received data
2653 DEBUG (( DEBUG_RX
| DEBUG_INFO
,
2654 "0x%08x: Packet queued on port 0x%08x with 0x%08x bytes of %s data\r\n",
2658 bUrgent
? L
"urgent" : L
"normal" ));
2661 // Attempt to restart this receive operation
2663 if ( pSocket
->MaxRxBuf
> pSocket
->RxBytes
) {
2664 EslTcpRxStart4 ( pPort
);
2668 "0x%08x: Port RX suspended, 0x%08x bytes queued\r\n",
2670 pSocket
->RxBytes
));
2675 DEBUG (( DEBUG_RX
| DEBUG_INFO
,
2676 "ERROR - Receiving packet 0x%08x, on port 0x%08x, Status:%r\r\n",
2682 // Receive error, free the packet save the error
2684 EslSocketPacketFree ( pPacket
, DEBUG_RX
);
2685 if ( !EFI_ERROR ( pSocket
->RxError
)) {
2686 pSocket
->RxError
= Status
;
2690 // Update the port state
2692 if ( PORT_STATE_CLOSE_STARTED
<= pPort
->State
) {
2693 EslTcpPortCloseRxDone4 ( pPort
);
2696 if ( EFI_ERROR ( Status
)) {
2697 pPort
->State
= PORT_STATE_RX_ERROR
;
2707 Start a receive operation
2709 @param [in] pPort Address of the DT_PORT structure.
2717 size_t LengthInBytes
;
2718 DT_PACKET
* pPacket
;
2719 DT_SOCKET
* pSocket
;
2720 DT_TCP4_CONTEXT
* pTcp4
;
2721 EFI_TCP4_PROTOCOL
* pTcp4Protocol
;
2727 // Determine if a receive is already pending
2729 Status
= EFI_SUCCESS
;
2731 pSocket
= pPort
->pSocket
;
2732 pTcp4
= &pPort
->Context
.Tcp4
;
2733 if ( !EFI_ERROR ( pPort
->pSocket
->RxError
)) {
2734 if (( NULL
== pTcp4
->pReceivePending
)
2735 && ( PORT_STATE_CLOSE_STARTED
> pPort
->State
)) {
2737 // Determine if there are any free packets
2739 pPacket
= pSocket
->pRxFree
;
2740 LengthInBytes
= sizeof ( pPacket
->Op
.Tcp4Rx
.Buffer
);
2741 if ( NULL
!= pPacket
) {
2743 // Remove this packet from the free list
2745 pSocket
->pRxFree
= pPacket
->pNext
;
2747 "0x%08x: Port removed packet 0x%08x from free list\r\n",
2753 // Allocate a packet structure
2755 Status
= EslSocketPacketAllocate ( &pPacket
,
2756 sizeof ( pPacket
->Op
.Tcp4Rx
),
2758 if ( EFI_ERROR ( Status
)) {
2760 DEBUG (( DEBUG_ERROR
| DEBUG_RX
,
2761 "0x%08x: Port failed to allocate RX packet, Status: %r\r\n",
2768 // Determine if a packet is available
2770 if ( NULL
!= pPacket
) {
2772 // Initialize the buffer for receive
2774 pTcp4
->RxToken
.Packet
.RxData
= &pPacket
->Op
.Tcp4Rx
.RxData
;
2775 pPacket
->Op
.Tcp4Rx
.RxData
.DataLength
= (UINT32
) LengthInBytes
;
2776 pPacket
->Op
.Tcp4Rx
.RxData
.FragmentCount
= 1;
2777 pPacket
->Op
.Tcp4Rx
.RxData
.FragmentTable
[0].FragmentLength
= (UINT32
) LengthInBytes
;
2778 pPacket
->Op
.Tcp4Rx
.RxData
.FragmentTable
[0].FragmentBuffer
= &pPacket
->Op
.Tcp4Rx
.Buffer
[0];
2779 pTcp4
->pReceivePending
= pPacket
;
2782 // Start the receive on the packet
2784 pTcp4Protocol
= pTcp4
->pProtocol
;
2785 Status
= pTcp4Protocol
->Receive ( pTcp4Protocol
,
2787 if ( !EFI_ERROR ( Status
)) {
2788 DEBUG (( DEBUG_RX
| DEBUG_INFO
,
2789 "0x%08x: Packet receive pending on port 0x%08x\r\n",
2794 DEBUG (( DEBUG_RX
| DEBUG_INFO
,
2795 "ERROR - Failed to post a receive on port 0x%08x, Status: %r\r\n",
2798 pTcp4
->pReceivePending
= NULL
;
2799 if ( !EFI_ERROR ( pSocket
->RxError
)) {
2801 // Save the error status
2803 pSocket
->RxError
= Status
;
2815 Shutdown the TCP4 service.
2817 This routine undoes the work performed by ::TcpInitialize4.
2819 @param [in] pService DT_SERVICE structure address
2825 IN DT_SERVICE
* pService
2830 DT_SERVICE
* pPreviousService
;
2835 // Verify the socket layer synchronization
2837 VERIFY_TPL ( TPL_SOCKETS
);
2840 // Walk the list of ports
2843 pPort
= pService
->pPortList
;
2844 if ( NULL
!= pPort
) {
2846 // Remove the port from the port list
2848 pService
->pPortList
= pPort
->pLinkService
;
2854 // pPort->pfnClosePort ( pPort, DEBUG_LISTEN | DEBUG_CONNECTION );
2856 } while ( NULL
!= pPort
);
2859 // Remove the service from the service list
2861 pLayer
= &mEslLayer
;
2862 pPreviousService
= pLayer
->pTcp4List
;
2863 if ( pService
== pPreviousService
) {
2865 // Remove the service from the beginning of the list
2867 pLayer
->pTcp4List
= pService
->pNext
;
2871 // Remove the service from the middle of the list
2873 while ( NULL
!= pPreviousService
) {
2874 if ( pService
== pPreviousService
->pNext
) {
2875 pPreviousService
->pNext
= pService
->pNext
;
2886 Determine if the socket is configured.
2889 @param [in] pSocket Address of a DT_SOCKET structure
2891 @retval EFI_SUCCESS - The port is connected
2892 @retval EFI_NOT_STARTED - The port is not connected
2896 EslTcpSocketIsConfigured4 (
2897 IN DT_SOCKET
* pSocket
2905 // Determine the socket configuration status
2907 Status
= pSocket
->bConfigured
? EFI_SUCCESS
: EFI_NOT_STARTED
;
2910 // Return the port connected state.
2912 DBG_EXIT_STATUS ( Status
);
2918 Buffer data for transmission over a network connection.
2920 This routine is called by the socket layer API to buffer
2921 data for transmission. When necessary, this routine will
2922 start the transmit engine that performs the data transmission
2923 on the network connection.
2925 The transmit engine uses two queues, one for urgent (out-of-band)
2926 data and the other for normal data. The urgent data is provided
2927 to TCP as soon as it is available, allowing the TCP layer to
2928 schedule transmission of the urgent data between packets of normal
2931 Transmission errors are returned during the next transmission or
2932 during the close operation. Only buffering errors are returned
2933 during the current transmission attempt.
2935 @param [in] pSocket Address of a DT_SOCKET structure
2937 @param [in] Flags Message control flags
2939 @param [in] BufferLength Length of the the buffer
2941 @param [in] pBuffer Address of a buffer to receive the data.
2943 @param [in] pDataLength Number of received data bytes in the buffer.
2945 @retval EFI_SUCCESS - Socket data successfully buffered
2950 IN DT_SOCKET
* pSocket
,
2952 IN
size_t BufferLength
,
2953 IN CONST UINT8
* pBuffer
,
2954 OUT
size_t * pDataLength
2958 DT_PACKET
* pPacket
;
2959 DT_PACKET
* pPreviousPacket
;
2960 DT_PACKET
** ppPacket
;
2961 DT_PACKET
** ppQueueHead
;
2962 DT_PACKET
** ppQueueTail
;
2964 DT_TCP4_CONTEXT
* pTcp4
;
2965 EFI_TCP4_IO_TOKEN
* pToken
;
2967 EFI_TCP4_TRANSMIT_DATA
* pTxData
;
2969 EFI_TPL TplPrevious
;
2976 Status
= EFI_UNSUPPORTED
;
2977 pSocket
->errno
= ENOTCONN
;
2981 // Verify that the socket is connected
2983 if ( SOCKET_STATE_CONNECTED
== pSocket
->State
) {
2987 pPort
= pSocket
->pPortList
;
2988 if ( NULL
!= pPort
) {
2990 // Determine the queue head
2992 pTcp4
= &pPort
->Context
.Tcp4
;
2993 bUrgent
= (BOOLEAN
)( 0 != ( Flags
& MSG_OOB
));
2995 ppQueueHead
= &pSocket
->pTxOobPacketListHead
;
2996 ppQueueTail
= &pSocket
->pTxOobPacketListTail
;
2997 ppPacket
= &pTcp4
->pTxOobPacket
;
2998 pToken
= &pTcp4
->TxOobToken
;
2999 pTxBytes
= &pSocket
->TxOobBytes
;
3002 ppQueueHead
= &pSocket
->pTxPacketListHead
;
3003 ppQueueTail
= &pSocket
->pTxPacketListTail
;
3004 ppPacket
= &pTcp4
->pTxPacket
;
3005 pToken
= &pTcp4
->TxToken
;
3006 pTxBytes
= &pSocket
->TxBytes
;
3010 // Verify that there is enough room to buffer another
3011 // transmit operation
3013 if ( pSocket
->MaxTxBuf
> *pTxBytes
) {
3015 // Attempt to allocate the packet
3017 Status
= EslSocketPacketAllocate ( &pPacket
,
3018 sizeof ( pPacket
->Op
.Tcp4Tx
)
3019 - sizeof ( pPacket
->Op
.Tcp4Tx
.Buffer
)
3022 if ( !EFI_ERROR ( Status
)) {
3024 // Initialize the transmit operation
3026 pTxData
= &pPacket
->Op
.Tcp4Tx
.TxData
;
3027 pTxData
->Push
= TRUE
;
3028 pTxData
->Urgent
= bUrgent
;
3029 pTxData
->DataLength
= (UINT32
) BufferLength
;
3030 pTxData
->FragmentCount
= 1;
3031 pTxData
->FragmentTable
[0].FragmentLength
= (UINT32
) BufferLength
;
3032 pTxData
->FragmentTable
[0].FragmentBuffer
= &pPacket
->Op
.Tcp4Tx
.Buffer
[0];
3035 // Copy the data into the buffer
3037 CopyMem ( &pPacket
->Op
.Tcp4Tx
.Buffer
[0],
3042 // Synchronize with the socket layer
3044 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
3047 // Stop transmission after an error
3049 if ( !EFI_ERROR ( pSocket
->TxError
)) {
3051 // Display the request
3054 "Send %d %s bytes from 0x%08x\r\n",
3056 bUrgent
? L
"urgent" : L
"normal",
3060 // Queue the data for transmission
3062 pPacket
->pNext
= NULL
;
3063 pPreviousPacket
= *ppQueueTail
;
3064 if ( NULL
== pPreviousPacket
) {
3065 *ppQueueHead
= pPacket
;
3068 pPreviousPacket
->pNext
= pPacket
;
3070 *ppQueueTail
= pPacket
;
3072 "0x%08x: Packet on %s transmit list\r\n",
3074 bUrgent
? L
"urgent" : L
"normal" ));
3077 // Account for the buffered data
3079 *pTxBytes
+= BufferLength
;
3080 *pDataLength
= BufferLength
;
3083 // Start the transmit engine if it is idle
3085 if ( NULL
== *ppPacket
) {
3086 EslTcpTxStart4 ( pSocket
->pPortList
,
3095 // Previous transmit error
3096 // Stop transmission
3098 Status
= pSocket
->TxError
;
3099 pSocket
->errno
= EIO
;
3104 EslSocketPacketFree ( pPacket
, DEBUG_TX
);
3108 // Release the socket layer synchronization
3110 RESTORE_TPL ( TplPrevious
);
3114 // Packet allocation failed
3116 pSocket
->errno
= ENOMEM
;
3121 // Not enough buffer space available
3123 pSocket
->errno
= EAGAIN
;
3124 Status
= EFI_NOT_READY
;
3130 // Return the operation status
3132 DBG_EXIT_STATUS ( Status
);
3138 Process the normal data transmit completion
3140 @param Event The normal transmit completion event
3142 @param pPort The DT_PORT structure address
3151 UINT32 LengthInBytes
;
3152 DT_PACKET
* pCurrentPacket
;
3153 DT_PACKET
* pNextPacket
;
3154 DT_PACKET
* pPacket
;
3155 DT_SOCKET
* pSocket
;
3156 DT_TCP4_CONTEXT
* pTcp4
;
3162 // Locate the active transmit packet
3164 pSocket
= pPort
->pSocket
;
3165 pTcp4
= &pPort
->Context
.Tcp4
;
3166 pPacket
= pTcp4
->pTxPacket
;
3169 // Mark this packet as complete
3171 pTcp4
->pTxPacket
= NULL
;
3172 LengthInBytes
= pPacket
->Op
.Tcp4Tx
.TxData
.DataLength
;
3173 pSocket
->TxBytes
-= LengthInBytes
;
3176 // Save any transmit error
3178 Status
= pTcp4
->TxToken
.CompletionToken
.Status
;
3179 if ( EFI_ERROR ( Status
)) {
3180 if ( !EFI_ERROR ( pSocket
->TxError
)) {
3181 pSocket
->TxError
= Status
;
3183 DEBUG (( DEBUG_TX
| DEBUG_INFO
,
3184 "ERROR - Transmit failure for packet 0x%08x, Status: %r\r\n",
3189 // Empty the normal transmit list
3191 pCurrentPacket
= pPacket
;
3192 pNextPacket
= pSocket
->pTxPacketListHead
;
3193 while ( NULL
!= pNextPacket
) {
3194 pPacket
= pNextPacket
;
3195 pNextPacket
= pPacket
->pNext
;
3196 EslSocketPacketFree ( pPacket
, DEBUG_TX
);
3198 pSocket
->pTxPacketListHead
= NULL
;
3199 pSocket
->pTxPacketListTail
= NULL
;
3200 pPacket
= pCurrentPacket
;
3204 DEBUG (( DEBUG_TX
| DEBUG_INFO
,
3205 "0x%08x: Packet transmitted %d bytes successfully\r\n",
3210 // Verify the transmit engine is still running
3212 if ( !pPort
->bCloseNow
) {
3214 // Start the next packet transmission
3216 EslTcpTxStart4 ( pPort
,
3218 &pSocket
->pTxPacketListHead
,
3219 &pSocket
->pTxPacketListTail
,
3220 &pTcp4
->pTxPacket
);
3225 // Release this packet
3227 EslSocketPacketFree ( pPacket
, DEBUG_TX
);
3230 // Finish the close operation if necessary
3232 if ( PORT_STATE_CLOSE_STARTED
<= pPort
->State
) {
3234 // Indicate that the transmit is complete
3236 EslTcpPortCloseTxDone4 ( pPort
);
3243 Process the urgent data transmit completion
3245 @param Event The urgent transmit completion event
3247 @param pPort The DT_PORT structure address
3251 EslTcpTxOobComplete4 (
3256 UINT32 LengthInBytes
;
3257 DT_PACKET
* pCurrentPacket
;
3258 DT_PACKET
* pNextPacket
;
3259 DT_PACKET
* pPacket
;
3260 DT_SOCKET
* pSocket
;
3261 DT_TCP4_CONTEXT
* pTcp4
;
3267 // Locate the active transmit packet
3269 pSocket
= pPort
->pSocket
;
3270 pTcp4
= &pPort
->Context
.Tcp4
;
3271 pPacket
= pTcp4
->pTxOobPacket
;
3274 // Mark this packet as complete
3276 pTcp4
->pTxOobPacket
= NULL
;
3277 LengthInBytes
= pPacket
->Op
.Tcp4Tx
.TxData
.DataLength
;
3278 pSocket
->TxOobBytes
-= LengthInBytes
;
3281 // Save any transmit error
3283 Status
= pTcp4
->TxOobToken
.CompletionToken
.Status
;
3284 if ( EFI_ERROR ( Status
)) {
3285 if ( !EFI_ERROR ( Status
)) {
3286 pSocket
->TxError
= Status
;
3288 DEBUG (( DEBUG_TX
| DEBUG_INFO
,
3289 "ERROR - Transmit failure for urgent packet 0x%08x, Status: %r\r\n",
3295 // Empty the OOB transmit list
3297 pCurrentPacket
= pPacket
;
3298 pNextPacket
= pSocket
->pTxOobPacketListHead
;
3299 while ( NULL
!= pNextPacket
) {
3300 pPacket
= pNextPacket
;
3301 pNextPacket
= pPacket
->pNext
;
3302 EslSocketPacketFree ( pPacket
, DEBUG_TX
);
3304 pSocket
->pTxOobPacketListHead
= NULL
;
3305 pSocket
->pTxOobPacketListTail
= NULL
;
3306 pPacket
= pCurrentPacket
;
3310 DEBUG (( DEBUG_TX
| DEBUG_INFO
,
3311 "0x%08x: Urgent packet transmitted %d bytes successfully\r\n",
3316 // Verify the transmit engine is still running
3318 if ( !pPort
->bCloseNow
) {
3320 // Start the next packet transmission
3322 EslTcpTxStart4 ( pPort
,
3324 &pSocket
->pTxOobPacketListHead
,
3325 &pSocket
->pTxOobPacketListTail
,
3326 &pTcp4
->pTxOobPacket
);
3331 // Release this packet
3333 EslSocketPacketFree ( pPacket
, DEBUG_TX
);
3336 // Finish the close operation if necessary
3338 if ( PORT_STATE_CLOSE_STARTED
<= pPort
->State
) {
3340 // Indicate that the transmit is complete
3342 EslTcpPortCloseTxDone4 ( pPort
);
3349 Transmit data using a network connection.
3352 @param [in] pPort Address of a DT_PORT structure
3353 @param [in] pToken Address of either the OOB or normal transmit token
3354 @param [in] ppQueueHead Transmit queue head address
3355 @param [in] ppQueueTail Transmit queue tail address
3356 @param [in] ppPacket Active transmit packet address
3362 IN EFI_TCP4_IO_TOKEN
* pToken
,
3363 IN DT_PACKET
** ppQueueHead
,
3364 IN DT_PACKET
** ppQueueTail
,
3365 IN DT_PACKET
** ppPacket
3368 DT_PACKET
* pNextPacket
;
3369 DT_PACKET
* pPacket
;
3370 DT_SOCKET
* pSocket
;
3371 EFI_TCP4_PROTOCOL
* pTcp4Protocol
;
3379 Status
= EFI_SUCCESS
;
3382 // Get the packet from the queue head
3384 pPacket
= *ppQueueHead
;
3385 if ( NULL
!= pPacket
) {
3387 // Remove the packet from the queue
3389 pNextPacket
= pPacket
->pNext
;
3390 *ppQueueHead
= pNextPacket
;
3391 if ( NULL
== pNextPacket
) {
3392 *ppQueueTail
= NULL
;
3396 // Set the packet as active
3398 *ppPacket
= pPacket
;
3401 // Start the transmit operation
3403 pTcp4Protocol
= pPort
->Context
.Tcp4
.pProtocol
;
3404 pToken
->Packet
.TxData
= &pPacket
->Op
.Tcp4Tx
.TxData
;
3405 Status
= pTcp4Protocol
->Transmit ( pTcp4Protocol
, pToken
);
3406 if ( EFI_ERROR ( Status
)) {
3407 pSocket
= pPort
->pSocket
;
3408 if ( EFI_SUCCESS
== pSocket
->TxError
) {
3409 pSocket
->TxError
= Status
;