2 Implement the TCP6 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 ::EslTcp6Listen 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 TCPv6 network layer calls
19 ::EslTcp6ListenComplete to complete the connection processing.
20 EslTcp6ListenComplete 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 ::EslTcp6Accept 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 TCPv6 network layer. It
37 configures the local TCPv6 connection point and then attempts to
38 connect to a remote system. Upon completion, the
39 ::EslTcp6ConnectComplete routine gets called with the connection
42 This routine is called by ::EslSocketConnect to initiate the TCPv6
43 network specific connect operations. The connection processing is
44 initiated by this routine and finished by ::EslTcp6ConnectComplete.
45 This pair of routines walks through the list of local TCPv6
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 TCPv6 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 EslTcp6ListenComplete (
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 TCPv6 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_in6
* pRemoteAddress
;
116 ESL_TCP6_CONTEXT
* pTcp6
;
122 // Validate the socket length
124 pRemoteAddress
= (struct sockaddr_in6
*) pSockAddr
;
125 if (( NULL
== pSockAddrLength
)
126 || ( sizeof ( *pRemoteAddress
) > *pSockAddrLength
)) {
128 // Invalid socket address
130 Status
= EFI_INVALID_PARAMETER
;
131 pSocket
->errno
= EINVAL
;
132 DEBUG (( DEBUG_ACCEPT
,
133 "ERROR - Invalid address length\r\n" ));
139 Status
= EFI_SUCCESS
;
142 // Locate the address context
144 pPort
= pSocket
->pPortList
;
145 pTcp6
= &pPort
->Context
.Tcp6
;
148 // Fill-in the remote address structure
150 ZeroMem ( pRemoteAddress
, sizeof ( *pRemoteAddress
));
151 pRemoteAddress
->sin6_len
= sizeof ( *pRemoteAddress
);
152 pRemoteAddress
->sin6_family
= AF_INET6
;
153 pRemoteAddress
->sin6_port
= SwapBytes16 ( pTcp6
->ConfigData
.AccessPoint
.RemotePort
);
154 CopyMem ( &pRemoteAddress
->sin6_addr
.__u6_addr
.__u6_addr8
[ 0 ],
155 &pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[0],
156 sizeof ( pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
));
160 // Return the operation status
162 DBG_EXIT_STATUS ( Status
);
168 Process the remote connection completion event.
170 This routine handles the completion of a connection attempt. It
171 releases the port (TCPv6 adapter connection) in the case of an
172 error and start a connection attempt on the next port. If the
173 connection attempt was successful then this routine releases all
176 This routine is called by the TCPv6 layer when a connect request
177 completes. It sets the ESL_SOCKET::bConnected flag to notify the
178 ::EslTcp6ConnectComplete routine that the connection is available.
179 The flag is set when the connection is established or no more ports
180 exist in the list. The connection status is passed via
181 ESL_SOCKET::ConnectStatus.
183 @param [in] Event The connect completion event
185 @param [in] pPort Address of an ::ESL_PORT structure.
189 EslTcp6ConnectComplete (
194 BOOLEAN bRemoveFirstPort
;
195 BOOLEAN bRemovePorts
;
196 ESL_PORT
* pNextPort
;
197 ESL_SOCKET
* pSocket
;
198 ESL_TCP6_CONTEXT
* pTcp6
;
204 // Locate the TCP context
206 pSocket
= pPort
->pSocket
;
207 pTcp6
= &pPort
->Context
.Tcp6
;
210 // Get the connection status
212 bRemoveFirstPort
= FALSE
;
213 bRemovePorts
= FALSE
;
214 Status
= pTcp6
->ConnectToken
.CompletionToken
.Status
;
215 pSocket
->ConnectStatus
= Status
;
216 if ( !EFI_ERROR ( Status
)) {
218 // The connection was successful
220 DEBUG (( DEBUG_CONNECT
,
221 "0x%08x: Port connected to [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d\r\n",
223 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[0],
224 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[1],
225 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[2],
226 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[3],
227 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[4],
228 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[5],
229 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[6],
230 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[7],
231 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[8],
232 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[9],
233 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[10],
234 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[11],
235 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[12],
236 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[13],
237 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[14],
238 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[15],
239 pTcp6
->ConfigData
.AccessPoint
.RemotePort
));
242 // Remove the rest of the ports
248 // The connection failed
250 DEBUG (( DEBUG_CONNECT
,
251 "0x%08x: Port connection to [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d failed, Status: %r\r\n",
253 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[0],
254 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[1],
255 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[2],
256 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[3],
257 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[4],
258 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[5],
259 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[6],
260 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[7],
261 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[8],
262 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[9],
263 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[10],
264 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[11],
265 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[12],
266 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[13],
267 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[14],
268 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[15],
269 pTcp6
->ConfigData
.AccessPoint
.RemotePort
,
273 // Close the current port
275 Status
= EslSocketPortClose ( pPort
);
276 if ( !EFI_ERROR ( Status
)) {
277 DEBUG (( DEBUG_CONNECT
,
278 "0x%08x: Port closed\r\n",
282 DEBUG (( DEBUG_CONNECT
,
283 "ERROR - Failed to close port 0x%08x, Status: %r\r\n",
289 // Try to connect using the next port
291 Status
= EslTcp6ConnectStart ( pSocket
);
292 if ( EFI_NOT_READY
!= Status
) {
293 pSocket
->ConnectStatus
= Status
;
294 bRemoveFirstPort
= TRUE
;
299 // Remove the ports if necessary
301 if ( bRemoveFirstPort
|| bRemovePorts
) {
303 // Remove the first port if necessary
305 pPort
= pSocket
->pPortList
;
306 if (( !bRemoveFirstPort
) && ( NULL
!= pPort
)) {
307 pPort
= pPort
->pLinkSocket
;
311 // Remove the rest of the list
313 while ( NULL
!= pPort
) {
314 pNextPort
= pPort
->pLinkSocket
;
315 EslSocketPortClose ( pPort
);
316 if ( !EFI_ERROR ( Status
)) {
317 DEBUG (( DEBUG_CONNECT
,
318 "0x%08x: Port closed\r\n",
322 DEBUG (( DEBUG_CONNECT
,
323 "ERROR - Failed to close port 0x%08x, Status: %r\r\n",
331 // Notify the poll routine
333 pSocket
->bConnected
= TRUE
;
341 Poll for completion of the connection attempt.
343 This routine polls the ESL_SOCKET::bConnected flag to determine
344 when the connection attempt is complete.
346 This routine is called from ::EslSocketConnect to determine when
347 the connection is complete. The ESL_SOCKET::bConnected flag is
348 set by ::EslTcp6ConnectComplete when the TCPv6 layer establishes
349 a connection or runs out of local network adapters. This routine
350 gets the connection status from ESL_SOCKET::ConnectStatus.
352 @param [in] pSocket Address of an ::ESL_SOCKET structure.
354 @retval EFI_SUCCESS The connection was successfully established.
355 @retval EFI_NOT_READY The connection is in progress, call this routine again.
356 @retval Others The connection attempt failed.
361 IN ESL_SOCKET
* pSocket
369 // Determine if the connection is complete
371 if ( !pSocket
->bConnected
) {
375 pSocket
->errno
= EAGAIN
;
376 Status
= EFI_NOT_READY
;
380 // The connection processing is complete
382 pSocket
->bConnected
= FALSE
;
385 // Translate the connection status
387 Status
= pSocket
->ConnectStatus
;
390 case EFI_DEVICE_ERROR
:
391 pSocket
->errno
= EIO
;
395 pSocket
->errno
= ECONNREFUSED
;
398 case EFI_INVALID_PARAMETER
:
399 pSocket
->errno
= EINVAL
;
403 case EFI_NO_RESPONSE
:
404 pSocket
->errno
= EHOSTUNREACH
;
408 pSocket
->errno
= ENETDOWN
;
411 case EFI_OUT_OF_RESOURCES
:
412 pSocket
->errno
= ENOMEM
;
417 pSocket
->bConfigured
= TRUE
;
421 pSocket
->errno
= ETIMEDOUT
;
424 case EFI_UNSUPPORTED
:
425 pSocket
->errno
= ENOTSUP
;
429 pSocket
->errno
= ECONNRESET
;
435 // Return the initialization status
437 DBG_EXIT_STATUS ( Status
);
443 Attempt to connect to a remote TCP port
445 This routine starts the connection processing for a SOCK_STREAM
446 or SOCK_SEQPAKCET socket using the TCPv6 network layer. It
447 configures the local TCPv6 connection point and then attempts to
448 connect to a remote system. Upon completion, the
449 ::EslTcp6ConnectComplete routine gets called with the connection
452 This routine is called by ::EslSocketConnect to initiate the TCPv6
453 network specific connect operations. The connection processing is
454 initiated by this routine and finished by ::EslTcp6ConnectComplete.
455 This pair of routines walks through the list of local TCPv6
456 connection points until a connection to the remote system is
459 @param [in] pSocket Address of an ::ESL_SOCKET structure.
461 @retval EFI_SUCCESS The connection was successfully established.
462 @retval EFI_NOT_READY The connection is in progress, call this routine again.
463 @retval Others The connection attempt failed.
467 EslTcp6ConnectStart (
468 IN ESL_SOCKET
* pSocket
472 ESL_TCP6_CONTEXT
* pTcp6
;
473 EFI_TCP6_PROTOCOL
* pTcp6Protocol
;
479 // Determine if any more local adapters are available
481 pPort
= pSocket
->pPortList
;
482 if ( NULL
!= pPort
) {
484 // Configure the port
486 pTcp6
= &pPort
->Context
.Tcp6
;
487 pTcp6
->ConfigData
.AccessPoint
.ActiveFlag
= TRUE
;
488 pTcp6
->ConfigData
.TrafficClass
= 0;
489 pTcp6
->ConfigData
.HopLimit
= 255;
490 pTcp6Protocol
= pPort
->pProtocol
.TCPv6
;
491 Status
= pTcp6Protocol
->Configure ( pTcp6Protocol
,
492 &pTcp6
->ConfigData
);
493 if ( EFI_ERROR ( Status
)) {
494 DEBUG (( DEBUG_CONNECT
,
495 "ERROR - Failed to configure the Tcp6 port, Status: %r\r\n",
498 case EFI_ACCESS_DENIED
:
499 pSocket
->errno
= EACCES
;
503 case EFI_DEVICE_ERROR
:
504 pSocket
->errno
= EIO
;
507 case EFI_INVALID_PARAMETER
:
508 pSocket
->errno
= EADDRNOTAVAIL
;
512 pSocket
->errno
= EAFNOSUPPORT
;
515 case EFI_OUT_OF_RESOURCES
:
516 pSocket
->errno
= ENOBUFS
;
519 case EFI_UNSUPPORTED
:
520 pSocket
->errno
= EOPNOTSUPP
;
525 DEBUG (( DEBUG_CONNECT
,
526 "0x%08x: Port configured\r\n",
528 pPort
->bConfigured
= TRUE
;
531 // Attempt the connection to the remote system
533 Status
= pTcp6Protocol
->Connect ( pTcp6Protocol
,
534 &pTcp6
->ConnectToken
);
535 if ( !EFI_ERROR ( Status
)) {
537 // Connection in progress
539 pSocket
->errno
= EINPROGRESS
;
540 Status
= EFI_NOT_READY
;
541 DEBUG (( DEBUG_CONNECT
,
542 "0x%08x: Port attempting connection to [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d\r\n",
544 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[0],
545 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[1],
546 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[2],
547 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[3],
548 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[4],
549 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[5],
550 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[6],
551 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[7],
552 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[8],
553 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[9],
554 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[10],
555 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[11],
556 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[12],
557 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[13],
558 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[14],
559 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[15],
560 pTcp6
->ConfigData
.AccessPoint
.RemotePort
));
566 DEBUG (( DEBUG_CONNECT
,
567 "ERROR - Port 0x%08x not connected, Status: %r\r\n",
571 // Determine the errno value
575 pSocket
->errno
= EIO
;
578 case EFI_OUT_OF_RESOURCES
:
579 pSocket
->errno
= ENOBUFS
;
583 pSocket
->errno
= ETIMEDOUT
;
586 case EFI_NETWORK_UNREACHABLE
:
587 pSocket
->errno
= ENETDOWN
;
590 case EFI_HOST_UNREACHABLE
:
591 pSocket
->errno
= EHOSTUNREACH
;
594 case EFI_PORT_UNREACHABLE
:
595 case EFI_PROTOCOL_UNREACHABLE
:
596 case EFI_CONNECTION_REFUSED
:
597 pSocket
->errno
= ECONNREFUSED
;
600 case EFI_CONNECTION_RESET
:
601 pSocket
->errno
= ECONNRESET
;
609 // No more local adapters available
611 pSocket
->errno
= ENETUNREACH
;
612 Status
= EFI_NO_RESPONSE
;
616 // Return the operation status
618 DBG_EXIT_STATUS ( Status
);
624 Establish the known port to listen for network connections.
626 This routine places the port into a state that enables connection
629 This routine is called by ::EslSocketListen to handle the network
630 specifics of the listen operation for SOCK_STREAM and SOCK_SEQPACKET
631 sockets. See the \ref ConnectionManagement section.
633 @param [in] pSocket Address of an ::ESL_SOCKET structure.
635 @retval EFI_SUCCESS - Socket successfully created
636 @retval Other - Failed to enable the socket for listen
641 IN ESL_SOCKET
* pSocket
644 ESL_PORT
* pNextPort
;
646 ESL_TCP6_CONTEXT
* pTcp6
;
647 EFI_TCP6_PROTOCOL
* pTcp6Protocol
;
653 // Verify the socket layer synchronization
655 VERIFY_TPL ( TPL_SOCKETS
);
658 // Use for/break instead of goto
662 // Assume no ports are available
664 pSocket
->errno
= EOPNOTSUPP
;
665 Status
= EFI_NOT_READY
;
668 // Walk the list of ports
670 pPort
= pSocket
->pPortList
;
671 while ( NULL
!= pPort
) {
678 // Use for/break insteak of goto
682 // Create the listen completion event
684 pTcp6
= &pPort
->Context
.Tcp6
;
685 Status
= gBS
->CreateEvent ( EVT_NOTIFY_SIGNAL
,
687 (EFI_EVENT_NOTIFY
)EslTcp6ListenComplete
,
689 &pTcp6
->ListenToken
.CompletionToken
.Event
);
690 if ( EFI_ERROR ( Status
)) {
691 DEBUG (( DEBUG_ERROR
| DEBUG_LISTEN
,
692 "ERROR - Failed to create the listen completion event, Status: %r\r\n",
694 pSocket
->errno
= ENOMEM
;
698 "0x%08x: Created listen completion event\r\n",
699 pTcp6
->ListenToken
.CompletionToken
.Event
));
702 // Configure the port
704 pTcp6Protocol
= pPort
->pProtocol
.TCPv6
;
705 Status
= pTcp6Protocol
->Configure ( pTcp6Protocol
,
706 &pTcp6
->ConfigData
);
707 if ( EFI_ERROR ( Status
)) {
708 DEBUG (( DEBUG_LISTEN
,
709 "ERROR - Failed to configure the Tcp6 port, Status: %r\r\n",
712 case EFI_ACCESS_DENIED
:
713 pSocket
->errno
= EACCES
;
717 case EFI_DEVICE_ERROR
:
718 pSocket
->errno
= EIO
;
721 case EFI_INVALID_PARAMETER
:
722 pSocket
->errno
= EADDRNOTAVAIL
;
726 pSocket
->errno
= EAFNOSUPPORT
;
729 case EFI_OUT_OF_RESOURCES
:
730 pSocket
->errno
= ENOBUFS
;
733 case EFI_UNSUPPORTED
:
734 pSocket
->errno
= EOPNOTSUPP
;
739 DEBUG (( DEBUG_LISTEN
,
740 "0x%08x: Port configured\r\n",
742 pPort
->bConfigured
= TRUE
;
745 // Start the listen operation on the port
747 Status
= pTcp6Protocol
->Accept ( pTcp6Protocol
,
748 &pTcp6
->ListenToken
);
749 if ( EFI_ERROR ( Status
)) {
750 DEBUG (( DEBUG_LISTEN
,
751 "ERROR - Failed Tcp6 accept, Status: %r\r\n",
754 case EFI_ACCESS_DENIED
:
755 pSocket
->errno
= EACCES
;
759 case EFI_DEVICE_ERROR
:
760 pSocket
->errno
= EIO
;
763 case EFI_INVALID_PARAMETER
:
764 pSocket
->errno
= EADDRNOTAVAIL
;
767 case EFI_NOT_STARTED
:
768 pSocket
->errno
= ENETDOWN
;
771 case EFI_OUT_OF_RESOURCES
:
772 pSocket
->errno
= ENOBUFS
;
777 DEBUG (( DEBUG_LISTEN
,
778 "0x%08x: Listen pending on Port\r\n",
782 // Listen is pending on this port
790 pNextPort
= pPort
->pLinkSocket
;
793 // Close the port upon error
795 if ( EFI_ERROR ( Status
)) {
796 EslSocketPortCloseStart ( pPort
, TRUE
, DEBUG_LISTEN
);
806 // Determine if any ports are in the listen state
808 if ( NULL
== pSocket
->pPortList
) {
810 // No ports in the listen state
812 pSocket
->MaxFifoDepth
= 0;
815 // Return the last error detected
821 // Mark the socket as configured
823 pSocket
->bConfigured
= TRUE
;
828 DEBUG (( DEBUG_LISTEN
,
829 "0x%08x: pSocket - Listen pending on socket\r\n",
835 // Return the operation status
837 DBG_EXIT_STATUS ( Status
);
843 Process the connection attempt
845 A system has initiated a connection attempt with a socket in the
846 listen state. Attempt to complete the connection.
848 The TCPv6 layer calls this routine when a connection is made to
849 the socket in the listen state. See the
850 \ref ConnectionManagement section.
852 @param [in] Event The listen completion event
854 @param [in] pPort Address of an ::ESL_PORT structure.
858 EslTcp6ListenComplete (
863 EFI_HANDLE ChildHandle
;
864 struct sockaddr_in6 LocalAddress
;
865 EFI_TCP6_CONFIG_DATA
* pConfigData
;
868 ESL_SOCKET
* pNewSocket
;
869 ESL_SOCKET
* pSocket
;
870 ESL_TCP6_CONTEXT
* pTcp6
;
871 EFI_TCP6_PROTOCOL
* pTcp6Protocol
;
873 EFI_HANDLE TcpPortHandle
;
874 EFI_STATUS TempStatus
;
877 VERIFY_AT_TPL ( TPL_SOCKETS
);
882 Status
= EFI_SUCCESS
;
885 // Determine if this connection fits into the connection FIFO
887 pSocket
= pPort
->pSocket
;
888 TcpPortHandle
= pPort
->Context
.Tcp6
.ListenToken
.NewChildHandle
;
889 if (( SOCKET_STATE_LISTENING
== pSocket
->State
)
890 && ( pSocket
->MaxFifoDepth
> pSocket
->FifoDepth
)) {
892 // Allocate a socket for this connection
896 Status
= EslSocketAllocate ( &ChildHandle
,
899 if ( !EFI_ERROR ( Status
)) {
901 // Clone the socket parameters
903 pNewSocket
->pApi
= pSocket
->pApi
;
904 pNewSocket
->Domain
= pSocket
->Domain
;
905 pNewSocket
->Protocol
= pSocket
->Protocol
;
906 pNewSocket
->Type
= pSocket
->Type
;
909 // Build the local address
911 pTcp6
= &pPort
->Context
.Tcp6
;
912 LocalAddress
.sin6_len
= (uint8_t)pNewSocket
->pApi
->MinimumAddressLength
;
913 LocalAddress
.sin6_family
= AF_INET6
;
914 LocalAddress
.sin6_port
= 0;
915 CopyMem ( &LocalAddress
.sin6_addr
.__u6_addr
.__u6_addr8
[ 0 ],
916 &pTcp6
->ConfigData
.AccessPoint
.StationAddress
.Addr
[ 0 ],
917 sizeof ( pTcp6
->ConfigData
.AccessPoint
.StationAddress
.Addr
));
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 pTcp6Protocol
= pPort
->pProtocol
.TCPv6
;
935 Status
= pTcp6Protocol
->Accept ( pTcp6Protocol
,
936 &pTcp6
->ListenToken
);
939 // Close the TCP port using SocketClose
941 TcpPortHandle
= NULL
;
942 pTcp6
= &pNewPort
->Context
.Tcp6
;
945 // Check for an accept call error
947 if ( !EFI_ERROR ( Status
)) {
949 // Get the port configuration
951 pNewPort
->bConfigured
= TRUE
;
952 pConfigData
= &pTcp6
->ConfigData
;
953 pConfigData
->ControlOption
= &pTcp6
->Option
;
954 pTcp6Protocol
= pNewPort
->pProtocol
.TCPv6
;
955 Status
= pTcp6Protocol
->GetModeData ( pTcp6Protocol
,
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 [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d connected to [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%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
.StationAddress
.Addr
[4],
996 pConfigData
->AccessPoint
.StationAddress
.Addr
[5],
997 pConfigData
->AccessPoint
.StationAddress
.Addr
[6],
998 pConfigData
->AccessPoint
.StationAddress
.Addr
[7],
999 pConfigData
->AccessPoint
.StationAddress
.Addr
[8],
1000 pConfigData
->AccessPoint
.StationAddress
.Addr
[9],
1001 pConfigData
->AccessPoint
.StationAddress
.Addr
[10],
1002 pConfigData
->AccessPoint
.StationAddress
.Addr
[11],
1003 pConfigData
->AccessPoint
.StationAddress
.Addr
[12],
1004 pConfigData
->AccessPoint
.StationAddress
.Addr
[13],
1005 pConfigData
->AccessPoint
.StationAddress
.Addr
[14],
1006 pConfigData
->AccessPoint
.StationAddress
.Addr
[15],
1007 pConfigData
->AccessPoint
.StationPort
,
1008 pConfigData
->AccessPoint
.RemoteAddress
.Addr
[0],
1009 pConfigData
->AccessPoint
.RemoteAddress
.Addr
[1],
1010 pConfigData
->AccessPoint
.RemoteAddress
.Addr
[2],
1011 pConfigData
->AccessPoint
.RemoteAddress
.Addr
[3],
1012 pConfigData
->AccessPoint
.RemoteAddress
.Addr
[4],
1013 pConfigData
->AccessPoint
.RemoteAddress
.Addr
[5],
1014 pConfigData
->AccessPoint
.RemoteAddress
.Addr
[6],
1015 pConfigData
->AccessPoint
.RemoteAddress
.Addr
[7],
1016 pConfigData
->AccessPoint
.RemoteAddress
.Addr
[8],
1017 pConfigData
->AccessPoint
.RemoteAddress
.Addr
[9],
1018 pConfigData
->AccessPoint
.RemoteAddress
.Addr
[10],
1019 pConfigData
->AccessPoint
.RemoteAddress
.Addr
[11],
1020 pConfigData
->AccessPoint
.RemoteAddress
.Addr
[12],
1021 pConfigData
->AccessPoint
.RemoteAddress
.Addr
[13],
1022 pConfigData
->AccessPoint
.RemoteAddress
.Addr
[14],
1023 pConfigData
->AccessPoint
.RemoteAddress
.Addr
[15],
1024 pConfigData
->AccessPoint
.RemotePort
));
1025 DEBUG (( DEBUG_CONNECTION
| DEBUG_INFO
,
1026 "0x%08x: Listen socket adding socket 0x%08x to FIFO, depth: %d\r\n",
1029 pSocket
->FifoDepth
));
1032 // Start the receive operation
1034 EslSocketRxStart ( pNewPort
);
1037 DEBUG (( DEBUG_ERROR
| DEBUG_CONNECTION
| DEBUG_INFO
,
1038 "ERROR - GetModeData failed on port 0x%08x, Status: %r\r\n",
1045 // The listen failed on this port
1047 DEBUG (( DEBUG_LISTEN
| DEBUG_INFO
,
1048 "ERROR - Listen failed on port 0x%08x, Status: %r\r\n",
1053 // Close the listening port
1055 EslSocketPortCloseStart ( pPort
, TRUE
, DEBUG_LISTEN
);
1060 // Done with the socket if necessary
1062 if ( EFI_ERROR ( Status
)) {
1063 TempStatus
= EslSocketCloseStart ( &pNewSocket
->SocketProtocol
,
1066 ASSERT ( EFI_SUCCESS
== TempStatus
);
1071 DEBUG (( DEBUG_CONNECTION
,
1072 "0x%08x: Socket FIFO full, connection refused\r\n",
1076 // The FIFO is full or the socket is in the wrong state
1078 Status
= EFI_BUFFER_TOO_SMALL
;
1082 // Close the connection if necessary
1084 if (( EFI_ERROR ( Status
))
1085 && ( NULL
== TcpPortHandle
)) {
1087 // TODO: Finish this code path
1088 // The new connection does not fit into the connection FIFO
1092 // Release the resources
1101 Get the local socket address.
1103 This routine returns the IPv6 address and TCP port number associated
1104 with the local socket.
1106 This routine is called by ::EslSocketGetLocalAddress to determine the
1107 network address for the SOCK_STREAM or SOCK_SEQPACKET socket.
1109 @param [in] pPort Address of an ::ESL_PORT structure.
1111 @param [out] pSockAddr Network address to receive the local system address
1115 EslTcp6LocalAddressGet (
1116 IN ESL_PORT
* pPort
,
1117 OUT
struct sockaddr
* pSockAddr
1120 struct sockaddr_in6
* pLocalAddress
;
1121 ESL_TCP6_CONTEXT
* pTcp6
;
1126 // Return the local address
1128 pTcp6
= &pPort
->Context
.Tcp6
;
1129 pLocalAddress
= (struct sockaddr_in6
*)pSockAddr
;
1130 pLocalAddress
->sin6_family
= AF_INET6
;
1131 pLocalAddress
->sin6_port
= SwapBytes16 ( pTcp6
->ConfigData
.AccessPoint
.StationPort
);
1132 CopyMem ( &pLocalAddress
->sin6_addr
,
1133 &pTcp6
->ConfigData
.AccessPoint
.StationAddress
.Addr
[0],
1134 sizeof ( pLocalAddress
->sin6_addr
));
1141 Set the local port address.
1143 This routine sets the local port address.
1145 This support routine is called by ::EslSocketPortAllocate.
1147 @param [in] pPort Address of an ESL_PORT structure
1148 @param [in] pSockAddr Address of a sockaddr structure that contains the
1149 connection point on the local machine. An IPv6 address
1150 of INADDR_ANY specifies that the connection is made to
1151 all of the network stacks on the platform. Specifying a
1152 specific IPv6 address restricts the connection to the
1153 network stack supporting that address. Specifying zero
1154 for the port causes the network layer to assign a port
1155 number from the dynamic range. Specifying a specific
1156 port number causes the network layer to use that port.
1158 @param [in] bBindTest TRUE = run bind testing
1160 @retval EFI_SUCCESS The operation was successful
1164 EslTcp6LocalAddressSet (
1165 IN ESL_PORT
* pPort
,
1166 IN CONST
struct sockaddr
* pSockAddr
,
1167 IN BOOLEAN bBindTest
1170 EFI_TCP6_ACCESS_POINT
* pAccessPoint
;
1171 CONST
struct sockaddr_in6
* pIpAddress
;
1177 // Validate the address
1179 pIpAddress
= (struct sockaddr_in6
*)pSockAddr
;
1181 // TODO: Fix the following check
1184 if ( INADDR_BROADCAST == pIpAddress->sin6_addr.s_addr ) {
1186 // The local address must not be the broadcast address
1188 Status = EFI_INVALID_PARAMETER;
1189 pPort->pSocket->errno = EADDRNOTAVAIL;
1195 // Set the local address
1197 pAccessPoint
= &pPort
->Context
.Tcp6
.ConfigData
.AccessPoint
;
1198 CopyMem ( &pAccessPoint
->StationAddress
.Addr
[0],
1199 &pIpAddress
->sin6_addr
.__u6_addr
.__u6_addr8
[ 0 ],
1200 sizeof ( pIpAddress
->sin6_addr
.__u6_addr
.__u6_addr8
[ 0 ]));
1203 // Validate the IP address
1205 pAccessPoint
->StationPort
= 0;
1206 Status
= bBindTest
? EslSocketBindTest ( pPort
, EADDRNOTAVAIL
)
1208 if ( !EFI_ERROR ( Status
)) {
1210 // Set the port number
1212 pAccessPoint
->StationPort
= SwapBytes16 ( pIpAddress
->sin6_port
);
1213 pPort
->pSocket
->bAddressSet
= TRUE
;
1216 // Display the local address
1218 DEBUG (( DEBUG_BIND
,
1219 "0x%08x: Port, Local Tcp6 Address: [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d\r\n",
1221 pAccessPoint
->StationAddress
.Addr
[0],
1222 pAccessPoint
->StationAddress
.Addr
[1],
1223 pAccessPoint
->StationAddress
.Addr
[2],
1224 pAccessPoint
->StationAddress
.Addr
[3],
1225 pAccessPoint
->StationAddress
.Addr
[4],
1226 pAccessPoint
->StationAddress
.Addr
[5],
1227 pAccessPoint
->StationAddress
.Addr
[6],
1228 pAccessPoint
->StationAddress
.Addr
[7],
1229 pAccessPoint
->StationAddress
.Addr
[8],
1230 pAccessPoint
->StationAddress
.Addr
[9],
1231 pAccessPoint
->StationAddress
.Addr
[10],
1232 pAccessPoint
->StationAddress
.Addr
[11],
1233 pAccessPoint
->StationAddress
.Addr
[12],
1234 pAccessPoint
->StationAddress
.Addr
[13],
1235 pAccessPoint
->StationAddress
.Addr
[14],
1236 pAccessPoint
->StationAddress
.Addr
[15],
1237 pAccessPoint
->StationPort
));
1242 // Return the operation status
1244 DBG_EXIT_STATUS ( Status
);
1250 Free a receive packet
1252 This routine performs the network specific operations necessary
1253 to free a receive packet.
1255 This routine is called by ::EslSocketPortCloseTxDone to free a
1258 @param [in] pPacket Address of an ::ESL_PACKET structure.
1259 @param [in, out] pRxBytes Address of the count of RX bytes
1264 IN ESL_PACKET
* pPacket
,
1265 IN OUT
size_t * pRxBytes
1271 // Account for the receive bytes
1273 *pRxBytes
-= pPacket
->Op
.Tcp6Rx
.RxData
.DataLength
;
1279 Initialize the network specific portions of an ::ESL_PORT structure.
1281 This routine initializes the network specific portions of an
1282 ::ESL_PORT structure for use by the socket.
1284 This support routine is called by ::EslSocketPortAllocate
1285 to connect the socket with the underlying network adapter
1286 running the TCPv6 protocol.
1288 @param [in] pPort Address of an ESL_PORT structure
1289 @param [in] DebugFlags Flags for debug messages
1291 @retval EFI_SUCCESS - Socket successfully created
1295 EslTcp6PortAllocate (
1296 IN ESL_PORT
* pPort
,
1300 EFI_TCP6_ACCESS_POINT
* pAccessPoint
;
1301 ESL_SOCKET
* pSocket
;
1302 ESL_TCP6_CONTEXT
* pTcp6
;
1308 // Use for/break instead of goto
1311 // Allocate the close event
1313 pSocket
= pPort
->pSocket
;
1314 pTcp6
= &pPort
->Context
.Tcp6
;
1315 Status
= gBS
->CreateEvent ( EVT_NOTIFY_SIGNAL
,
1317 (EFI_EVENT_NOTIFY
)EslSocketPortCloseComplete
,
1319 &pTcp6
->CloseToken
.CompletionToken
.Event
);
1320 if ( EFI_ERROR ( Status
)) {
1321 DEBUG (( DEBUG_ERROR
| DebugFlags
,
1322 "ERROR - Failed to create the close event, Status: %r\r\n",
1324 pSocket
->errno
= ENOMEM
;
1327 DEBUG (( DEBUG_CLOSE
| DEBUG_POOL
,
1328 "0x%08x: Created close event\r\n",
1329 pTcp6
->CloseToken
.CompletionToken
.Event
));
1332 // Allocate the connection event
1334 Status
= gBS
->CreateEvent ( EVT_NOTIFY_SIGNAL
,
1336 (EFI_EVENT_NOTIFY
)EslTcp6ConnectComplete
,
1338 &pTcp6
->ConnectToken
.CompletionToken
.Event
);
1339 if ( EFI_ERROR ( Status
)) {
1340 DEBUG (( DEBUG_ERROR
| DebugFlags
,
1341 "ERROR - Failed to create the connect event, Status: %r\r\n",
1343 pSocket
->errno
= ENOMEM
;
1346 DEBUG (( DEBUG_CLOSE
| DEBUG_POOL
,
1347 "0x%08x: Created connect event\r\n",
1348 pTcp6
->ConnectToken
.CompletionToken
.Event
));
1351 // Initialize the port
1353 pSocket
->TxPacketOffset
= OFFSET_OF ( ESL_PACKET
, Op
.Tcp6Tx
.TxData
);
1354 pSocket
->TxTokenEventOffset
= OFFSET_OF ( ESL_IO_MGMT
, Token
.Tcp6Tx
.CompletionToken
.Event
);
1355 pSocket
->TxTokenOffset
= OFFSET_OF ( EFI_TCP6_IO_TOKEN
, Packet
.TxData
);
1358 // Save the cancel, receive and transmit addresses
1359 // pPort->pfnRxCancel = NULL; since the UEFI implementation returns EFI_UNSUPPORTED
1361 pPort
->pfnConfigure
= (PFN_NET_CONFIGURE
)pPort
->pProtocol
.TCPv6
->Configure
;
1362 pPort
->pfnRxPoll
= (PFN_NET_POLL
)pPort
->pProtocol
.TCPv6
->Poll
;
1363 pPort
->pfnRxStart
= (PFN_NET_IO_START
)pPort
->pProtocol
.TCPv6
->Receive
;
1364 pPort
->pfnTxStart
= (PFN_NET_IO_START
)pPort
->pProtocol
.TCPv6
->Transmit
;
1367 // Set the configuration flags
1369 pAccessPoint
= &pPort
->Context
.Tcp6
.ConfigData
.AccessPoint
;
1370 pAccessPoint
->ActiveFlag
= FALSE
;
1371 pTcp6
->ConfigData
.TrafficClass
= 0;
1372 pTcp6
->ConfigData
.HopLimit
= 255;
1377 // Return the operation status
1379 DBG_EXIT_STATUS ( Status
);
1387 This routine releases the network specific resources allocated by
1388 ::EslTcp6PortAllocate.
1390 This routine is called by ::EslSocketPortClose.
1391 See the \ref PortCloseStateMachine section.
1393 @param [in] pPort Address of an ::ESL_PORT structure.
1395 @retval EFI_SUCCESS The port is closed
1396 @retval other Port close error
1405 ESL_TCP6_CONTEXT
* pTcp6
;
1411 // Locate the port in the socket list
1413 Status
= EFI_SUCCESS
;
1414 DebugFlags
= pPort
->DebugFlags
;
1415 pTcp6
= &pPort
->Context
.Tcp6
;
1418 // Done with the connect event
1420 if ( NULL
!= pTcp6
->ConnectToken
.CompletionToken
.Event
) {
1421 Status
= gBS
->CloseEvent ( pTcp6
->ConnectToken
.CompletionToken
.Event
);
1422 if ( !EFI_ERROR ( Status
)) {
1423 DEBUG (( DebugFlags
| DEBUG_POOL
,
1424 "0x%08x: Closed connect event\r\n",
1425 pTcp6
->ConnectToken
.CompletionToken
.Event
));
1428 DEBUG (( DEBUG_ERROR
| DebugFlags
,
1429 "ERROR - Failed to close the connect event, Status: %r\r\n",
1431 ASSERT ( EFI_SUCCESS
== Status
);
1436 // Done with the close event
1438 if ( NULL
!= pTcp6
->CloseToken
.CompletionToken
.Event
) {
1439 Status
= gBS
->CloseEvent ( pTcp6
->CloseToken
.CompletionToken
.Event
);
1440 if ( !EFI_ERROR ( Status
)) {
1441 DEBUG (( DebugFlags
| DEBUG_POOL
,
1442 "0x%08x: Closed close event\r\n",
1443 pTcp6
->CloseToken
.CompletionToken
.Event
));
1446 DEBUG (( DEBUG_ERROR
| DebugFlags
,
1447 "ERROR - Failed to close the close event, Status: %r\r\n",
1449 ASSERT ( EFI_SUCCESS
== Status
);
1454 // Done with the listen completion event
1456 if ( NULL
!= pTcp6
->ListenToken
.CompletionToken
.Event
) {
1457 Status
= gBS
->CloseEvent ( pTcp6
->ListenToken
.CompletionToken
.Event
);
1458 if ( !EFI_ERROR ( Status
)) {
1459 DEBUG (( DebugFlags
| DEBUG_POOL
,
1460 "0x%08x: Closed listen completion event\r\n",
1461 pTcp6
->ListenToken
.CompletionToken
.Event
));
1464 DEBUG (( DEBUG_ERROR
| DebugFlags
,
1465 "ERROR - Failed to close the listen completion event, Status: %r\r\n",
1467 ASSERT ( EFI_SUCCESS
== Status
);
1472 // Return the operation status
1474 DBG_EXIT_STATUS ( Status
);
1480 Perform the network specific close operation on the port.
1482 This routine performs a cancel operations on the TCPv6 port to
1483 shutdown the receive operations on the port.
1485 This routine is called by the ::EslSocketPortCloseTxDone
1486 routine after the port completes all of the transmission.
1488 @param [in] pPort Address of an ::ESL_PORT structure.
1490 @retval EFI_SUCCESS The port is closed, not normally returned
1491 @retval EFI_NOT_READY The port is still closing
1492 @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
1493 most likely the routine was called already.
1497 EslTcp6PortCloseOp (
1501 ESL_TCP6_CONTEXT
* pTcp6
;
1502 EFI_TCP6_PROTOCOL
* pTcp6Protocol
;
1508 // Close the configured port
1510 Status
= EFI_SUCCESS
;
1511 pTcp6
= &pPort
->Context
.Tcp6
;
1512 pTcp6Protocol
= pPort
->pProtocol
.TCPv6
;
1513 pTcp6
->CloseToken
.AbortOnClose
= pPort
->bCloseNow
;
1514 Status
= pTcp6Protocol
->Close ( pTcp6Protocol
,
1515 &pTcp6
->CloseToken
);
1516 if ( !EFI_ERROR ( Status
)) {
1517 DEBUG (( pPort
->DebugFlags
| DEBUG_CLOSE
| DEBUG_INFO
,
1518 "0x%08x: Port close started\r\n",
1522 DEBUG (( DEBUG_ERROR
| pPort
->DebugFlags
| DEBUG_CLOSE
| DEBUG_INFO
,
1523 "ERROR - Close failed on port 0x%08x, Status: %r\r\n",
1529 // Return the operation status
1531 DBG_EXIT_STATUS ( Status
);
1537 Receive data from a network connection.
1539 This routine attempts to return buffered data to the caller. The
1540 data is removed from the urgent queue if the message flag MSG_OOB
1541 is specified, otherwise data is removed from the normal queue.
1542 See the \ref ReceiveEngine section.
1544 This routine is called by ::EslSocketReceive to handle the network
1545 specific receive operation to support SOCK_STREAM and SOCK_SEQPACKET
1548 @param [in] pPort Address of an ::ESL_PORT structure.
1550 @param [in] pPacket Address of an ::ESL_PACKET structure.
1552 @param [in] pbConsumePacket Address of a BOOLEAN indicating if the packet is to be consumed
1554 @param [in] BufferLength Length of the the buffer
1556 @param [in] pBuffer Address of a buffer to receive the data.
1558 @param [in] pDataLength Number of received data bytes in the buffer.
1560 @param [out] pAddress Network address to receive the remote system address
1562 @param [out] pSkipBytes Address to receive the number of bytes skipped
1564 @return Returns the address of the next free byte in the buffer.
1569 IN ESL_PORT
* pPort
,
1570 IN ESL_PACKET
* pPacket
,
1571 IN BOOLEAN
* pbConsumePacket
,
1572 IN
size_t BufferLength
,
1574 OUT
size_t * pDataLength
,
1575 OUT
struct sockaddr
* pAddress
,
1576 OUT
size_t * pSkipBytes
1580 struct sockaddr_in6
* pRemoteAddress
;
1581 ESL_TCP6_CONTEXT
* pTcp6
;
1586 // Return the remote system address if requested
1588 if ( NULL
!= pAddress
) {
1590 // Build the remote address
1592 pTcp6
= &pPort
->Context
.Tcp6
;
1594 "Getting packet remote address: [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d\r\n",
1595 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[0],
1596 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[1],
1597 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[2],
1598 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[3],
1599 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[4],
1600 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[5],
1601 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[6],
1602 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[7],
1603 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[8],
1604 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[9],
1605 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[10],
1606 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[11],
1607 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[12],
1608 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[13],
1609 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[14],
1610 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[15],
1611 pTcp6
->ConfigData
.AccessPoint
.RemotePort
));
1612 pRemoteAddress
= (struct sockaddr_in6
*)pAddress
;
1613 CopyMem ( &pRemoteAddress
->sin6_addr
,
1614 &pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[0],
1615 sizeof ( pRemoteAddress
->sin6_addr
));
1616 pRemoteAddress
->sin6_port
= SwapBytes16 ( pTcp6
->ConfigData
.AccessPoint
.RemotePort
);
1620 // Determine the amount of received data
1622 DataLength
= pPacket
->ValidBytes
;
1623 if ( BufferLength
< DataLength
) {
1624 DataLength
= BufferLength
;
1628 // Move the data into the buffer
1631 "0x%08x: Port copy packet 0x%08x data into 0x%08x, 0x%08x bytes\r\n",
1636 CopyMem ( pBuffer
, pPacket
->pBuffer
, DataLength
);
1639 // Set the next buffer address
1641 pBuffer
+= DataLength
;
1644 // Determine if the data is being read
1646 if ( *pbConsumePacket
) {
1648 // Account for the bytes consumed
1650 pPacket
->pBuffer
+= DataLength
;
1651 pPacket
->ValidBytes
-= DataLength
;
1653 "0x%08x: Port account for 0x%08x bytes\r\n",
1658 // Determine if the entire packet was consumed
1660 if (( 0 == pPacket
->ValidBytes
)
1661 || ( SOCK_STREAM
!= pPort
->pSocket
->Type
)) {
1663 // All done with this packet
1664 // Account for any discarded data
1666 *pSkipBytes
= pPacket
->ValidBytes
;
1671 // More data to consume later
1673 *pbConsumePacket
= FALSE
;
1678 // Return the data length and the buffer address
1680 *pDataLength
= DataLength
;
1681 DBG_EXIT_HEX ( pBuffer
);
1687 Get the remote socket address.
1689 This routine returns the address of the remote connection point
1690 associated with the SOCK_STREAM or SOCK_SEQPACKET socket.
1692 This routine is called by ::EslSocketGetPeerAddress to detemine
1693 the TCPv6 address and por number associated with the network adapter.
1695 @param [in] pPort Address of an ::ESL_PORT structure.
1697 @param [out] pAddress Network address to receive the remote system address
1701 EslTcp6RemoteAddressGet (
1702 IN ESL_PORT
* pPort
,
1703 OUT
struct sockaddr
* pAddress
1706 struct sockaddr_in6
* pRemoteAddress
;
1707 ESL_TCP6_CONTEXT
* pTcp6
;
1712 // Return the remote address
1714 pTcp6
= &pPort
->Context
.Tcp6
;
1715 pRemoteAddress
= (struct sockaddr_in6
*)pAddress
;
1716 pRemoteAddress
->sin6_family
= AF_INET6
;
1717 pRemoteAddress
->sin6_port
= SwapBytes16 ( pTcp6
->ConfigData
.AccessPoint
.RemotePort
);
1718 CopyMem ( &pRemoteAddress
->sin6_addr
,
1719 &pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[0],
1720 sizeof ( pRemoteAddress
->sin6_addr
));
1727 Set the remote address
1729 This routine sets the remote address in the port.
1731 This routine is called by ::EslSocketConnect to specify the
1732 remote network address.
1734 @param [in] pPort Address of an ::ESL_PORT structure.
1736 @param [in] pSockAddr Network address of the remote system.
1738 @param [in] SockAddrLength Length in bytes of the network address.
1740 @retval EFI_SUCCESS The operation was successful
1744 EslTcp6RemoteAddressSet (
1745 IN ESL_PORT
* pPort
,
1746 IN CONST
struct sockaddr
* pSockAddr
,
1747 IN socklen_t SockAddrLength
1750 CONST
struct sockaddr_in6
* pRemoteAddress
;
1751 ESL_TCP6_CONTEXT
* pTcp6
;
1757 // Set the remote address
1759 pTcp6
= &pPort
->Context
.Tcp6
;
1760 pRemoteAddress
= (struct sockaddr_in6
*)pSockAddr
;
1761 CopyMem ( &pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[ 0 ],
1762 &pRemoteAddress
->sin6_addr
.__u6_addr
.__u6_addr8
[ 0 ],
1763 sizeof ( pRemoteAddress
->sin6_addr
.__u6_addr
.__u6_addr8
));
1764 pTcp6
->ConfigData
.AccessPoint
.RemotePort
= SwapBytes16 ( pRemoteAddress
->sin6_port
);
1765 Status
= EFI_SUCCESS
;
1768 // TODO: Fix the following check
1771 if ( INADDR_BROADCAST == pRemoteAddress->sin6_addr.s_addr ) {
1772 DEBUG (( DEBUG_CONNECT,
1773 "ERROR - Invalid remote address\r\n" ));
1774 Status = EFI_INVALID_PARAMETER;
1775 pPort->pSocket->errno = EAFNOSUPPORT;
1780 // Return the operation status
1782 DBG_EXIT_STATUS ( Status
);
1788 Process the receive completion
1790 This routine queues the data in FIFO order in either the urgent
1791 or normal data queues depending upon the type of data received.
1792 See the \ref ReceiveEngine section.
1794 This routine is called by the TCPv6 driver when some data is
1797 Buffer the data that was just received.
1799 @param [in] Event The receive completion event
1801 @param [in] pIo Address of an ::ESL_IO_MGMT structure
1807 IN ESL_IO_MGMT
* pIo
1811 size_t LengthInBytes
;
1812 ESL_PACKET
* pPacket
;
1818 // Get the operation status.
1820 Status
= pIo
->Token
.Tcp6Rx
.CompletionToken
.Status
;
1823 // +--------------------+ +---------------------------+
1824 // | ESL_IO_MGMT | | ESL_PACKET |
1826 // | +---------------+ +-----------------------+ |
1827 // | | Token | | EFI_Tcp6_RECEIVE_DATA | |
1828 // | | RxData --> | | |
1829 // | | | +-----------------------+---+
1830 // | | Event | | Data Buffer |
1831 // +----+---------------+ | |
1833 // +---------------------------+
1836 // Duplicate the buffer address and length for use by the
1837 // buffer handling code in EslTcp6Receive. These fields are
1838 // used when a partial read is done of the data from the
1841 pPacket
= pIo
->pPacket
;
1842 pPacket
->pBuffer
= pPacket
->Op
.Tcp6Rx
.RxData
.FragmentTable
[0].FragmentBuffer
;
1843 LengthInBytes
= pPacket
->Op
.Tcp6Rx
.RxData
.DataLength
;
1844 pPacket
->ValidBytes
= LengthInBytes
;
1847 // Get the data type so that it may be linked to the
1848 // correct receive buffer list on the ESL_SOCKET structure
1850 bUrgent
= pPacket
->Op
.Tcp6Rx
.RxData
.UrgentFlag
;
1853 // Complete this request
1855 EslSocketRxComplete ( pIo
, Status
, LengthInBytes
, bUrgent
);
1861 Start a receive operation
1863 This routine posts a receive buffer to the TCPv6 driver.
1864 See the \ref ReceiveEngine section.
1866 This support routine is called by EslSocketRxStart.
1868 @param [in] pPort Address of an ::ESL_PORT structure.
1869 @param [in] pIo Address of an ::ESL_IO_MGMT structure.
1874 IN ESL_PORT
* pPort
,
1875 IN ESL_IO_MGMT
* pIo
1878 ESL_PACKET
* pPacket
;
1883 // Initialize the buffer for receive
1885 pPacket
= pIo
->pPacket
;
1886 pIo
->Token
.Tcp6Rx
.Packet
.RxData
= &pPacket
->Op
.Tcp6Rx
.RxData
;
1887 pPacket
->Op
.Tcp6Rx
.RxData
.DataLength
= sizeof ( pPacket
->Op
.Tcp6Rx
.Buffer
);
1888 pPacket
->Op
.Tcp6Rx
.RxData
.FragmentCount
= 1;
1889 pPacket
->Op
.Tcp6Rx
.RxData
.FragmentTable
[0].FragmentLength
= pPacket
->Op
.Tcp6Rx
.RxData
.DataLength
;
1890 pPacket
->Op
.Tcp6Rx
.RxData
.FragmentTable
[0].FragmentBuffer
= &pPacket
->Op
.Tcp6Rx
.Buffer
[0];
1897 Determine if the socket is configured.
1899 This routine uses the flag ESL_SOCKET::bConfigured to determine
1900 if the network layer's configuration routine has been called.
1902 This routine is called by EslSocketIsConfigured to verify
1903 that the socket has been configured.
1905 @param [in] pSocket Address of an ::ESL_SOCKET structure.
1907 @retval EFI_SUCCESS - The port is connected
1908 @retval EFI_NOT_STARTED - The port is not connected
1912 EslTcp6SocketIsConfigured (
1913 IN ESL_SOCKET
* pSocket
1921 // Determine the socket configuration status
1923 Status
= pSocket
->bConfigured
? EFI_SUCCESS
: EFI_NOT_STARTED
;
1926 // Return the port connected state.
1928 DBG_EXIT_STATUS ( Status
);
1934 Buffer data for transmission over a network connection.
1936 This routine buffers data for the transmit engine in one of two
1937 queues, one for urgent (out-of-band) data and the other for normal
1938 data. The urgent data is provided to TCP as soon as it is available,
1939 allowing the TCP layer to schedule transmission of the urgent data
1940 between packets of normal data.
1942 This routine is called by ::EslSocketTransmit to buffer
1943 data for transmission. When the \ref TransmitEngine has resources,
1944 this routine will start the transmission of the next buffer on
1945 the network connection.
1947 Transmission errors are returned during the next transmission or
1948 during the close operation. Only buffering errors are returned
1949 during the current transmission attempt.
1951 @param [in] pSocket Address of an ::ESL_SOCKET structure
1953 @param [in] Flags Message control flags
1955 @param [in] BufferLength Length of the the buffer
1957 @param [in] pBuffer Address of a buffer to receive the data.
1959 @param [in] pDataLength Number of received data bytes in the buffer.
1961 @param [in] pAddress Network address of the remote system address
1963 @param [in] AddressLength Length of the remote network address structure
1965 @retval EFI_SUCCESS - Socket data successfully buffered
1970 IN ESL_SOCKET
* pSocket
,
1972 IN
size_t BufferLength
,
1973 IN CONST UINT8
* pBuffer
,
1974 OUT
size_t * pDataLength
,
1975 IN
const struct sockaddr
* pAddress
,
1976 IN socklen_t AddressLength
1980 BOOLEAN bUrgentQueue
;
1981 ESL_PACKET
* pPacket
;
1982 ESL_IO_MGMT
** ppActive
;
1983 ESL_IO_MGMT
** ppFree
;
1985 ESL_PACKET
** ppQueueHead
;
1986 ESL_PACKET
** ppQueueTail
;
1987 ESL_PACKET
* pPreviousPacket
;
1988 ESL_TCP6_CONTEXT
* pTcp6
;
1990 EFI_TCP6_TRANSMIT_DATA
* pTxData
;
1992 EFI_TPL TplPrevious
;
1999 Status
= EFI_UNSUPPORTED
;
2000 pSocket
->errno
= ENOTCONN
;
2004 // Verify that the socket is connected
2006 if ( SOCKET_STATE_CONNECTED
== pSocket
->State
) {
2010 pPort
= pSocket
->pPortList
;
2011 if ( NULL
!= pPort
) {
2013 // Determine the queue head
2015 pTcp6
= &pPort
->Context
.Tcp6
;
2016 bUrgent
= (BOOLEAN
)( 0 != ( Flags
& MSG_OOB
));
2017 bUrgentQueue
= bUrgent
2018 && ( !pSocket
->bOobInLine
)
2019 && pSocket
->pApi
->bOobSupported
;
2020 if ( bUrgentQueue
) {
2021 ppQueueHead
= &pSocket
->pTxOobPacketListHead
;
2022 ppQueueTail
= &pSocket
->pTxOobPacketListTail
;
2023 ppActive
= &pPort
->pTxOobActive
;
2024 ppFree
= &pPort
->pTxOobFree
;
2025 pTxBytes
= &pSocket
->TxOobBytes
;
2028 ppQueueHead
= &pSocket
->pTxPacketListHead
;
2029 ppQueueTail
= &pSocket
->pTxPacketListTail
;
2030 ppActive
= &pPort
->pTxActive
;
2031 ppFree
= &pPort
->pTxFree
;
2032 pTxBytes
= &pSocket
->TxBytes
;
2036 // Verify that there is enough room to buffer another
2037 // transmit operation
2039 if ( pSocket
->MaxTxBuf
> *pTxBytes
) {
2040 if ( pPort
->bTxFlowControl
) {
2042 "TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT\r\n0x%08x: pPort, TX flow control released, Max bytes: %d > %d bufferred bytes\r\n",
2046 pPort
->bTxFlowControl
= FALSE
;
2050 // Attempt to allocate the packet
2052 Status
= EslSocketPacketAllocate ( &pPacket
,
2053 sizeof ( pPacket
->Op
.Tcp6Tx
)
2054 - sizeof ( pPacket
->Op
.Tcp6Tx
.Buffer
)
2058 if ( !EFI_ERROR ( Status
)) {
2060 // Initialize the transmit operation
2062 pTxData
= &pPacket
->Op
.Tcp6Tx
.TxData
;
2063 pTxData
->Push
= TRUE
|| bUrgent
;
2064 pTxData
->Urgent
= bUrgent
;
2065 pTxData
->DataLength
= (UINT32
) BufferLength
;
2066 pTxData
->FragmentCount
= 1;
2067 pTxData
->FragmentTable
[0].FragmentLength
= (UINT32
) BufferLength
;
2068 pTxData
->FragmentTable
[0].FragmentBuffer
= &pPacket
->Op
.Tcp6Tx
.Buffer
[0];
2071 // Copy the data into the buffer
2073 CopyMem ( &pPacket
->Op
.Tcp6Tx
.Buffer
[0],
2078 // Synchronize with the socket layer
2080 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
2083 // Stop transmission after an error
2085 if ( !EFI_ERROR ( pSocket
->TxError
)) {
2087 // Display the request
2090 "Send %d %s bytes from 0x%08x\r\n",
2092 bUrgent
? L
"urgent" : L
"normal",
2096 // Queue the data for transmission
2098 pPacket
->pNext
= NULL
;
2099 pPreviousPacket
= *ppQueueTail
;
2100 if ( NULL
== pPreviousPacket
) {
2101 *ppQueueHead
= pPacket
;
2104 pPreviousPacket
->pNext
= pPacket
;
2106 *ppQueueTail
= pPacket
;
2108 "0x%08x: Packet on %s transmit list\r\n",
2110 bUrgentQueue
? L
"urgent" : L
"normal" ));
2113 // Account for the buffered data
2115 *pTxBytes
+= BufferLength
;
2116 *pDataLength
= BufferLength
;
2119 // Start the transmit engine if it is idle
2121 if ( NULL
!= *ppFree
) {
2122 EslSocketTxStart ( pPort
,
2131 // Previous transmit error
2132 // Stop transmission
2134 Status
= pSocket
->TxError
;
2135 pSocket
->errno
= EIO
;
2140 EslSocketPacketFree ( pPacket
, DEBUG_TX
);
2144 // Release the socket layer synchronization
2146 RESTORE_TPL ( TplPrevious
);
2150 // Packet allocation failed
2152 pSocket
->errno
= ENOMEM
;
2156 if ( !pPort
->bTxFlowControl
) {
2158 "0x%08x: pPort, TX flow control applied, Max bytes %d <= %d bufferred bytes\r\nTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT\r\n",
2162 pPort
->bTxFlowControl
= TRUE
;
2165 // Not enough buffer space available
2167 pSocket
->errno
= EAGAIN
;
2168 Status
= EFI_NOT_READY
;
2174 // Return the operation status
2176 DBG_EXIT_STATUS ( Status
);
2182 Process the normal data transmit completion
2184 This routine use ::EslSocketTxComplete to perform the transmit
2185 completion processing for normal data.
2187 This routine is called by the TCPv6 network layer when a
2188 normal data transmit request completes.
2190 @param [in] Event The normal transmit completion event
2192 @param [in] pIo The ESL_IO_MGMT structure address
2198 IN ESL_IO_MGMT
* pIo
2201 UINT32 LengthInBytes
;
2202 ESL_PACKET
* pPacket
;
2204 ESL_SOCKET
* pSocket
;
2210 // Locate the active transmit packet
2212 pPacket
= pIo
->pPacket
;
2214 pSocket
= pPort
->pSocket
;
2217 // Get the transmit length and status
2219 LengthInBytes
= pPacket
->Op
.Tcp6Tx
.TxData
.DataLength
;
2220 pSocket
->TxBytes
-= LengthInBytes
;
2221 Status
= pIo
->Token
.Tcp6Tx
.CompletionToken
.Status
;
2224 // Complete the transmit operation
2226 EslSocketTxComplete ( pIo
,
2230 &pSocket
->pTxPacketListHead
,
2231 &pSocket
->pTxPacketListTail
,
2239 Process the urgent data transmit completion
2241 This routine use ::EslSocketTxComplete to perform the transmit
2242 completion processing for urgent data.
2244 This routine is called by the TCPv6 network layer when a
2245 urgent data transmit request completes.
2247 @param [in] Event The urgent transmit completion event
2249 @param [in] pIo The ESL_IO_MGMT structure address
2253 EslTcp6TxOobComplete (
2255 IN ESL_IO_MGMT
* pIo
2258 UINT32 LengthInBytes
;
2259 ESL_PACKET
* pPacket
;
2261 ESL_SOCKET
* pSocket
;
2267 // Locate the active transmit packet
2269 pPacket
= pIo
->pPacket
;
2271 pSocket
= pPort
->pSocket
;
2274 // Get the transmit length and status
2276 LengthInBytes
= pPacket
->Op
.Tcp6Tx
.TxData
.DataLength
;
2277 pSocket
->TxOobBytes
-= LengthInBytes
;
2278 Status
= pIo
->Token
.Tcp6Tx
.CompletionToken
.Status
;
2281 // Complete the transmit operation
2283 EslSocketTxComplete ( pIo
,
2287 &pSocket
->pTxOobPacketListHead
,
2288 &pSocket
->pTxOobPacketListTail
,
2289 &pPort
->pTxOobActive
,
2290 &pPort
->pTxOobFree
);
2296 Interface between the socket layer and the network specific
2297 code that supports SOCK_STREAM and SOCK_SEQPACKET sockets
2300 CONST ESL_PROTOCOL_API cEslTcp6Api
= {
2303 OFFSET_OF ( ESL_PORT
, Context
.Tcp6
.ConfigData
),
2304 OFFSET_OF ( ESL_LAYER
, pTcp6List
),
2305 sizeof ( struct sockaddr_in6
),
2306 sizeof ( struct sockaddr_in6
),
2308 sizeof (((ESL_PACKET
*)0 )->Op
.Tcp6Rx
),
2309 OFFSET_OF ( ESL_PACKET
, Op
.Tcp6Rx
.Buffer
) - OFFSET_OF ( ESL_PACKET
, Op
),
2310 OFFSET_OF ( ESL_IO_MGMT
, Token
.Tcp6Rx
.Packet
.RxData
),
2315 EslTcp6ConnectStart
,
2316 EslTcp6SocketIsConfigured
,
2317 EslTcp6LocalAddressGet
,
2318 EslTcp6LocalAddressSet
,
2323 EslTcp6PortAllocate
,
2328 EslTcp6RemoteAddressGet
,
2329 EslTcp6RemoteAddressSet
,
2334 EslTcp6TxOobComplete