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
;
474 EFI_SIMPLE_NETWORK_MODE SnpModeData
;
480 // Determine if any more local adapters are available
482 pPort
= pSocket
->pPortList
;
483 if ( NULL
!= pPort
) {
485 // Configure the port
487 pTcp6
= &pPort
->Context
.Tcp6
;
488 pTcp6
->ConfigData
.AccessPoint
.ActiveFlag
= TRUE
;
489 pTcp6
->ConfigData
.TrafficClass
= 0;
490 pTcp6
->ConfigData
.HopLimit
= 255;
491 pTcp6Protocol
= pPort
->pProtocol
.TCPv6
;
492 Status
= pTcp6Protocol
->Configure ( pTcp6Protocol
,
493 &pTcp6
->ConfigData
);
494 if ( EFI_ERROR ( Status
)) {
495 DEBUG (( DEBUG_CONNECT
,
496 "ERROR - Failed to configure the Tcp6 port, Status: %r\r\n",
499 case EFI_ACCESS_DENIED
:
500 pSocket
->errno
= EACCES
;
504 case EFI_DEVICE_ERROR
:
505 pSocket
->errno
= EIO
;
508 case EFI_INVALID_PARAMETER
:
509 pSocket
->errno
= EADDRNOTAVAIL
;
513 pSocket
->errno
= EAFNOSUPPORT
;
516 case EFI_OUT_OF_RESOURCES
:
517 pSocket
->errno
= ENOBUFS
;
520 case EFI_UNSUPPORTED
:
521 pSocket
->errno
= EOPNOTSUPP
;
526 DEBUG (( DEBUG_CONNECT
,
527 "0x%08x: Port configured\r\n",
529 pPort
->bConfigured
= TRUE
;
532 // Verify the port connection
534 Status
= pTcp6Protocol
->GetModeData ( pTcp6Protocol
,
540 if ( !EFI_ERROR ( Status
)) {
541 if ( SnpModeData
.MediaPresentSupported
542 && ( !SnpModeData
.MediaPresent
)) {
544 // Port is not connected to the network
546 pTcp6
->ConnectToken
.CompletionToken
.Status
= EFI_NO_MEDIA
;
549 // Continue with the next port
551 gBS
->CheckEvent ( pTcp6
->ConnectToken
.CompletionToken
.Event
);
552 gBS
->SignalEvent ( pTcp6
->ConnectToken
.CompletionToken
.Event
);
555 // Connection in progress
557 Status
= EFI_SUCCESS
;
561 // Attempt the connection to the remote system
563 Status
= pTcp6Protocol
->Connect ( pTcp6Protocol
,
564 &pTcp6
->ConnectToken
);
567 if ( !EFI_ERROR ( Status
)) {
569 // Connection in progress
571 pSocket
->errno
= EINPROGRESS
;
572 Status
= EFI_NOT_READY
;
573 DEBUG (( DEBUG_CONNECT
,
574 "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",
576 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[0],
577 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[1],
578 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[2],
579 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[3],
580 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[4],
581 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[5],
582 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[6],
583 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[7],
584 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[8],
585 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[9],
586 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[10],
587 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[11],
588 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[12],
589 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[13],
590 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[14],
591 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[15],
592 pTcp6
->ConfigData
.AccessPoint
.RemotePort
));
598 DEBUG (( DEBUG_CONNECT
,
599 "ERROR - Port 0x%08x not connected, Status: %r\r\n",
603 // Determine the errno value
607 pSocket
->errno
= EIO
;
610 case EFI_OUT_OF_RESOURCES
:
611 pSocket
->errno
= ENOBUFS
;
615 pSocket
->errno
= ETIMEDOUT
;
619 case EFI_NETWORK_UNREACHABLE
:
620 pSocket
->errno
= ENETDOWN
;
623 case EFI_HOST_UNREACHABLE
:
624 pSocket
->errno
= EHOSTUNREACH
;
627 case EFI_PORT_UNREACHABLE
:
628 case EFI_PROTOCOL_UNREACHABLE
:
629 case EFI_CONNECTION_REFUSED
:
630 pSocket
->errno
= ECONNREFUSED
;
633 case EFI_CONNECTION_RESET
:
634 pSocket
->errno
= ECONNRESET
;
642 // No more local adapters available
644 pSocket
->errno
= ENETUNREACH
;
645 Status
= EFI_NO_RESPONSE
;
649 // Return the operation status
651 DBG_EXIT_STATUS ( Status
);
657 Establish the known port to listen for network connections.
659 This routine places the port into a state that enables connection
662 This routine is called by ::EslSocketListen to handle the network
663 specifics of the listen operation for SOCK_STREAM and SOCK_SEQPACKET
664 sockets. See the \ref ConnectionManagement section.
666 @param [in] pSocket Address of an ::ESL_SOCKET structure.
668 @retval EFI_SUCCESS - Socket successfully created
669 @retval Other - Failed to enable the socket for listen
674 IN ESL_SOCKET
* pSocket
677 ESL_PORT
* pNextPort
;
679 ESL_TCP6_CONTEXT
* pTcp6
;
680 EFI_TCP6_PROTOCOL
* pTcp6Protocol
;
686 // Verify the socket layer synchronization
688 VERIFY_TPL ( TPL_SOCKETS
);
691 // Use for/break instead of goto
695 // Assume no ports are available
697 pSocket
->errno
= EOPNOTSUPP
;
698 Status
= EFI_NOT_READY
;
701 // Walk the list of ports
703 pPort
= pSocket
->pPortList
;
704 while ( NULL
!= pPort
) {
711 // Use for/break insteak of goto
715 // Create the listen completion event
717 pTcp6
= &pPort
->Context
.Tcp6
;
718 Status
= gBS
->CreateEvent ( EVT_NOTIFY_SIGNAL
,
720 (EFI_EVENT_NOTIFY
)EslTcp6ListenComplete
,
722 &pTcp6
->ListenToken
.CompletionToken
.Event
);
723 if ( EFI_ERROR ( Status
)) {
724 DEBUG (( DEBUG_ERROR
| DEBUG_LISTEN
,
725 "ERROR - Failed to create the listen completion event, Status: %r\r\n",
727 pSocket
->errno
= ENOMEM
;
731 "0x%08x: Created listen completion event\r\n",
732 pTcp6
->ListenToken
.CompletionToken
.Event
));
735 // Configure the port
737 pTcp6Protocol
= pPort
->pProtocol
.TCPv6
;
738 Status
= pTcp6Protocol
->Configure ( pTcp6Protocol
,
739 &pTcp6
->ConfigData
);
740 if ( EFI_ERROR ( Status
)) {
741 DEBUG (( DEBUG_LISTEN
,
742 "ERROR - Failed to configure the Tcp6 port, Status: %r\r\n",
745 case EFI_ACCESS_DENIED
:
746 pSocket
->errno
= EACCES
;
750 case EFI_DEVICE_ERROR
:
751 pSocket
->errno
= EIO
;
754 case EFI_INVALID_PARAMETER
:
755 pSocket
->errno
= EADDRNOTAVAIL
;
759 pSocket
->errno
= EAFNOSUPPORT
;
762 case EFI_OUT_OF_RESOURCES
:
763 pSocket
->errno
= ENOBUFS
;
766 case EFI_UNSUPPORTED
:
767 pSocket
->errno
= EOPNOTSUPP
;
772 DEBUG (( DEBUG_LISTEN
,
773 "0x%08x: Port configured\r\n",
775 pPort
->bConfigured
= TRUE
;
778 // Start the listen operation on the port
780 Status
= pTcp6Protocol
->Accept ( pTcp6Protocol
,
781 &pTcp6
->ListenToken
);
782 if ( EFI_ERROR ( Status
)) {
783 DEBUG (( DEBUG_LISTEN
,
784 "ERROR - Failed Tcp6 accept, Status: %r\r\n",
787 case EFI_ACCESS_DENIED
:
788 pSocket
->errno
= EACCES
;
792 case EFI_DEVICE_ERROR
:
793 pSocket
->errno
= EIO
;
796 case EFI_INVALID_PARAMETER
:
797 pSocket
->errno
= EADDRNOTAVAIL
;
800 case EFI_NOT_STARTED
:
801 pSocket
->errno
= ENETDOWN
;
804 case EFI_OUT_OF_RESOURCES
:
805 pSocket
->errno
= ENOBUFS
;
810 DEBUG (( DEBUG_LISTEN
,
811 "0x%08x: Listen pending on Port\r\n",
815 // Listen is pending on this port
823 pNextPort
= pPort
->pLinkSocket
;
826 // Close the port upon error
828 if ( EFI_ERROR ( Status
)) {
829 EslSocketPortCloseStart ( pPort
, TRUE
, DEBUG_LISTEN
);
839 // Determine if any ports are in the listen state
841 if ( NULL
== pSocket
->pPortList
) {
843 // No ports in the listen state
845 pSocket
->MaxFifoDepth
= 0;
848 // Return the last error detected
854 // Mark the socket as configured
856 pSocket
->bConfigured
= TRUE
;
861 DEBUG (( DEBUG_LISTEN
,
862 "0x%08x: pSocket - Listen pending on socket\r\n",
868 // Return the operation status
870 DBG_EXIT_STATUS ( Status
);
876 Process the connection attempt
878 A system has initiated a connection attempt with a socket in the
879 listen state. Attempt to complete the connection.
881 The TCPv6 layer calls this routine when a connection is made to
882 the socket in the listen state. See the
883 \ref ConnectionManagement section.
885 @param [in] Event The listen completion event
887 @param [in] pPort Address of an ::ESL_PORT structure.
891 EslTcp6ListenComplete (
896 EFI_HANDLE ChildHandle
;
897 struct sockaddr_in6 LocalAddress
;
898 EFI_TCP6_CONFIG_DATA
* pConfigData
;
901 ESL_SOCKET
* pNewSocket
;
902 ESL_SOCKET
* pSocket
;
903 ESL_TCP6_CONTEXT
* pTcp6
;
904 EFI_TCP6_PROTOCOL
* pTcp6Protocol
;
906 EFI_HANDLE TcpPortHandle
;
907 EFI_STATUS TempStatus
;
910 VERIFY_AT_TPL ( TPL_SOCKETS
);
915 Status
= EFI_SUCCESS
;
918 // Determine if this connection fits into the connection FIFO
920 pSocket
= pPort
->pSocket
;
921 TcpPortHandle
= pPort
->Context
.Tcp6
.ListenToken
.NewChildHandle
;
922 if (( SOCKET_STATE_LISTENING
== pSocket
->State
)
923 && ( pSocket
->MaxFifoDepth
> pSocket
->FifoDepth
)) {
925 // Allocate a socket for this connection
929 Status
= EslSocketAllocate ( &ChildHandle
,
932 if ( !EFI_ERROR ( Status
)) {
934 // Clone the socket parameters
936 pNewSocket
->pApi
= pSocket
->pApi
;
937 pNewSocket
->Domain
= pSocket
->Domain
;
938 pNewSocket
->Protocol
= pSocket
->Protocol
;
939 pNewSocket
->Type
= pSocket
->Type
;
942 // Build the local address
944 pTcp6
= &pPort
->Context
.Tcp6
;
945 LocalAddress
.sin6_len
= (uint8_t)pNewSocket
->pApi
->MinimumAddressLength
;
946 LocalAddress
.sin6_family
= AF_INET6
;
947 LocalAddress
.sin6_port
= 0;
948 CopyMem ( &LocalAddress
.sin6_addr
.__u6_addr
.__u6_addr8
[ 0 ],
949 &pTcp6
->ConfigData
.AccessPoint
.StationAddress
.Addr
[ 0 ],
950 sizeof ( pTcp6
->ConfigData
.AccessPoint
.StationAddress
.Addr
));
953 // Allocate a port for this connection
954 // Note in this instance Configure may not be called with NULL!
956 Status
= EslSocketPortAllocate ( pNewSocket
,
959 (struct sockaddr
*)&LocalAddress
,
963 if ( !EFI_ERROR ( Status
)) {
965 // Restart the listen operation on the port
967 pTcp6Protocol
= pPort
->pProtocol
.TCPv6
;
968 Status
= pTcp6Protocol
->Accept ( pTcp6Protocol
,
969 &pTcp6
->ListenToken
);
972 // Close the TCP port using SocketClose
974 TcpPortHandle
= NULL
;
975 pTcp6
= &pNewPort
->Context
.Tcp6
;
978 // Check for an accept call error
980 if ( !EFI_ERROR ( Status
)) {
982 // Get the port configuration
984 pNewPort
->bConfigured
= TRUE
;
985 pConfigData
= &pTcp6
->ConfigData
;
986 pConfigData
->ControlOption
= &pTcp6
->Option
;
987 pTcp6Protocol
= pNewPort
->pProtocol
.TCPv6
;
988 Status
= pTcp6Protocol
->GetModeData ( pTcp6Protocol
,
994 if ( !EFI_ERROR ( Status
)) {
996 // Add the new socket to the connection FIFO
998 if ( NULL
== pSocket
->pFifoTail
) {
1002 pSocket
->pFifoHead
= pNewSocket
;
1006 // Add to end of list.
1008 pSocket
->pFifoTail
->pNextConnection
= pNewSocket
;
1010 pSocket
->pFifoTail
= pNewSocket
;
1011 pSocket
->FifoDepth
+= 1;
1014 // Update the socket state
1016 pNewSocket
->State
= SOCKET_STATE_IN_FIFO
;
1019 // Log the connection
1021 DEBUG (( DEBUG_CONNECTION
| DEBUG_INFO
,
1022 "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",
1024 pConfigData
->AccessPoint
.StationAddress
.Addr
[0],
1025 pConfigData
->AccessPoint
.StationAddress
.Addr
[1],
1026 pConfigData
->AccessPoint
.StationAddress
.Addr
[2],
1027 pConfigData
->AccessPoint
.StationAddress
.Addr
[3],
1028 pConfigData
->AccessPoint
.StationAddress
.Addr
[4],
1029 pConfigData
->AccessPoint
.StationAddress
.Addr
[5],
1030 pConfigData
->AccessPoint
.StationAddress
.Addr
[6],
1031 pConfigData
->AccessPoint
.StationAddress
.Addr
[7],
1032 pConfigData
->AccessPoint
.StationAddress
.Addr
[8],
1033 pConfigData
->AccessPoint
.StationAddress
.Addr
[9],
1034 pConfigData
->AccessPoint
.StationAddress
.Addr
[10],
1035 pConfigData
->AccessPoint
.StationAddress
.Addr
[11],
1036 pConfigData
->AccessPoint
.StationAddress
.Addr
[12],
1037 pConfigData
->AccessPoint
.StationAddress
.Addr
[13],
1038 pConfigData
->AccessPoint
.StationAddress
.Addr
[14],
1039 pConfigData
->AccessPoint
.StationAddress
.Addr
[15],
1040 pConfigData
->AccessPoint
.StationPort
,
1041 pConfigData
->AccessPoint
.RemoteAddress
.Addr
[0],
1042 pConfigData
->AccessPoint
.RemoteAddress
.Addr
[1],
1043 pConfigData
->AccessPoint
.RemoteAddress
.Addr
[2],
1044 pConfigData
->AccessPoint
.RemoteAddress
.Addr
[3],
1045 pConfigData
->AccessPoint
.RemoteAddress
.Addr
[4],
1046 pConfigData
->AccessPoint
.RemoteAddress
.Addr
[5],
1047 pConfigData
->AccessPoint
.RemoteAddress
.Addr
[6],
1048 pConfigData
->AccessPoint
.RemoteAddress
.Addr
[7],
1049 pConfigData
->AccessPoint
.RemoteAddress
.Addr
[8],
1050 pConfigData
->AccessPoint
.RemoteAddress
.Addr
[9],
1051 pConfigData
->AccessPoint
.RemoteAddress
.Addr
[10],
1052 pConfigData
->AccessPoint
.RemoteAddress
.Addr
[11],
1053 pConfigData
->AccessPoint
.RemoteAddress
.Addr
[12],
1054 pConfigData
->AccessPoint
.RemoteAddress
.Addr
[13],
1055 pConfigData
->AccessPoint
.RemoteAddress
.Addr
[14],
1056 pConfigData
->AccessPoint
.RemoteAddress
.Addr
[15],
1057 pConfigData
->AccessPoint
.RemotePort
));
1058 DEBUG (( DEBUG_CONNECTION
| DEBUG_INFO
,
1059 "0x%08x: Listen socket adding socket 0x%08x to FIFO, depth: %d\r\n",
1062 pSocket
->FifoDepth
));
1065 // Start the receive operation
1067 EslSocketRxStart ( pNewPort
);
1070 DEBUG (( DEBUG_ERROR
| DEBUG_CONNECTION
| DEBUG_INFO
,
1071 "ERROR - GetModeData failed on port 0x%08x, Status: %r\r\n",
1078 // The listen failed on this port
1080 DEBUG (( DEBUG_LISTEN
| DEBUG_INFO
,
1081 "ERROR - Listen failed on port 0x%08x, Status: %r\r\n",
1086 // Close the listening port
1088 EslSocketPortCloseStart ( pPort
, TRUE
, DEBUG_LISTEN
);
1093 // Done with the socket if necessary
1095 if ( EFI_ERROR ( Status
)) {
1096 TempStatus
= EslSocketCloseStart ( &pNewSocket
->SocketProtocol
,
1099 ASSERT ( EFI_SUCCESS
== TempStatus
);
1104 DEBUG (( DEBUG_CONNECTION
,
1105 "0x%08x: Socket FIFO full, connection refused\r\n",
1109 // The FIFO is full or the socket is in the wrong state
1111 Status
= EFI_BUFFER_TOO_SMALL
;
1115 // Close the connection if necessary
1117 if (( EFI_ERROR ( Status
))
1118 && ( NULL
== TcpPortHandle
)) {
1120 // TODO: Finish this code path
1121 // The new connection does not fit into the connection FIFO
1125 // Release the resources
1134 Get the local socket address.
1136 This routine returns the IPv6 address and TCP port number associated
1137 with the local socket.
1139 This routine is called by ::EslSocketGetLocalAddress to determine the
1140 network address for the SOCK_STREAM or SOCK_SEQPACKET socket.
1142 @param [in] pPort Address of an ::ESL_PORT structure.
1144 @param [out] pSockAddr Network address to receive the local system address
1148 EslTcp6LocalAddressGet (
1149 IN ESL_PORT
* pPort
,
1150 OUT
struct sockaddr
* pSockAddr
1153 struct sockaddr_in6
* pLocalAddress
;
1154 ESL_TCP6_CONTEXT
* pTcp6
;
1159 // Return the local address
1161 pTcp6
= &pPort
->Context
.Tcp6
;
1162 pLocalAddress
= (struct sockaddr_in6
*)pSockAddr
;
1163 pLocalAddress
->sin6_family
= AF_INET6
;
1164 pLocalAddress
->sin6_port
= SwapBytes16 ( pTcp6
->ConfigData
.AccessPoint
.StationPort
);
1165 CopyMem ( &pLocalAddress
->sin6_addr
,
1166 &pTcp6
->ConfigData
.AccessPoint
.StationAddress
.Addr
[0],
1167 sizeof ( pLocalAddress
->sin6_addr
));
1174 Set the local port address.
1176 This routine sets the local port address.
1178 This support routine is called by ::EslSocketPortAllocate.
1180 @param [in] pPort Address of an ESL_PORT structure
1181 @param [in] pSockAddr Address of a sockaddr structure that contains the
1182 connection point on the local machine. An IPv6 address
1183 of INADDR_ANY specifies that the connection is made to
1184 all of the network stacks on the platform. Specifying a
1185 specific IPv6 address restricts the connection to the
1186 network stack supporting that address. Specifying zero
1187 for the port causes the network layer to assign a port
1188 number from the dynamic range. Specifying a specific
1189 port number causes the network layer to use that port.
1191 @param [in] bBindTest TRUE = run bind testing
1193 @retval EFI_SUCCESS The operation was successful
1197 EslTcp6LocalAddressSet (
1198 IN ESL_PORT
* pPort
,
1199 IN CONST
struct sockaddr
* pSockAddr
,
1200 IN BOOLEAN bBindTest
1203 EFI_TCP6_ACCESS_POINT
* pAccessPoint
;
1204 CONST
struct sockaddr_in6
* pIpAddress
;
1210 // Validate the address
1212 pIpAddress
= (struct sockaddr_in6
*)pSockAddr
;
1214 // TODO: Fix the following check
1217 if ( INADDR_BROADCAST == pIpAddress->sin6_addr.s_addr ) {
1219 // The local address must not be the broadcast address
1221 Status = EFI_INVALID_PARAMETER;
1222 pPort->pSocket->errno = EADDRNOTAVAIL;
1228 // Set the local address
1230 pAccessPoint
= &pPort
->Context
.Tcp6
.ConfigData
.AccessPoint
;
1231 CopyMem ( &pAccessPoint
->StationAddress
.Addr
[0],
1232 &pIpAddress
->sin6_addr
.__u6_addr
.__u6_addr8
[ 0 ],
1233 sizeof ( pIpAddress
->sin6_addr
.__u6_addr
.__u6_addr8
[ 0 ]));
1236 // Validate the IP address
1238 pAccessPoint
->StationPort
= 0;
1239 Status
= bBindTest
? EslSocketBindTest ( pPort
, EADDRNOTAVAIL
)
1241 if ( !EFI_ERROR ( Status
)) {
1243 // Set the port number
1245 pAccessPoint
->StationPort
= SwapBytes16 ( pIpAddress
->sin6_port
);
1246 pPort
->pSocket
->bAddressSet
= TRUE
;
1249 // Display the local address
1251 DEBUG (( DEBUG_BIND
,
1252 "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",
1254 pAccessPoint
->StationAddress
.Addr
[0],
1255 pAccessPoint
->StationAddress
.Addr
[1],
1256 pAccessPoint
->StationAddress
.Addr
[2],
1257 pAccessPoint
->StationAddress
.Addr
[3],
1258 pAccessPoint
->StationAddress
.Addr
[4],
1259 pAccessPoint
->StationAddress
.Addr
[5],
1260 pAccessPoint
->StationAddress
.Addr
[6],
1261 pAccessPoint
->StationAddress
.Addr
[7],
1262 pAccessPoint
->StationAddress
.Addr
[8],
1263 pAccessPoint
->StationAddress
.Addr
[9],
1264 pAccessPoint
->StationAddress
.Addr
[10],
1265 pAccessPoint
->StationAddress
.Addr
[11],
1266 pAccessPoint
->StationAddress
.Addr
[12],
1267 pAccessPoint
->StationAddress
.Addr
[13],
1268 pAccessPoint
->StationAddress
.Addr
[14],
1269 pAccessPoint
->StationAddress
.Addr
[15],
1270 pAccessPoint
->StationPort
));
1275 // Return the operation status
1277 DBG_EXIT_STATUS ( Status
);
1283 Free a receive packet
1285 This routine performs the network specific operations necessary
1286 to free a receive packet.
1288 This routine is called by ::EslSocketPortCloseTxDone to free a
1291 @param [in] pPacket Address of an ::ESL_PACKET structure.
1292 @param [in, out] pRxBytes Address of the count of RX bytes
1297 IN ESL_PACKET
* pPacket
,
1298 IN OUT
size_t * pRxBytes
1304 // Account for the receive bytes
1306 *pRxBytes
-= pPacket
->Op
.Tcp6Rx
.RxData
.DataLength
;
1312 Initialize the network specific portions of an ::ESL_PORT structure.
1314 This routine initializes the network specific portions of an
1315 ::ESL_PORT structure for use by the socket.
1317 This support routine is called by ::EslSocketPortAllocate
1318 to connect the socket with the underlying network adapter
1319 running the TCPv6 protocol.
1321 @param [in] pPort Address of an ESL_PORT structure
1322 @param [in] DebugFlags Flags for debug messages
1324 @retval EFI_SUCCESS - Socket successfully created
1328 EslTcp6PortAllocate (
1329 IN ESL_PORT
* pPort
,
1333 EFI_TCP6_ACCESS_POINT
* pAccessPoint
;
1334 ESL_SOCKET
* pSocket
;
1335 ESL_TCP6_CONTEXT
* pTcp6
;
1341 // Use for/break instead of goto
1344 // Allocate the close event
1346 pSocket
= pPort
->pSocket
;
1347 pTcp6
= &pPort
->Context
.Tcp6
;
1348 Status
= gBS
->CreateEvent ( EVT_NOTIFY_SIGNAL
,
1350 (EFI_EVENT_NOTIFY
)EslSocketPortCloseComplete
,
1352 &pTcp6
->CloseToken
.CompletionToken
.Event
);
1353 if ( EFI_ERROR ( Status
)) {
1354 DEBUG (( DEBUG_ERROR
| DebugFlags
,
1355 "ERROR - Failed to create the close event, Status: %r\r\n",
1357 pSocket
->errno
= ENOMEM
;
1360 DEBUG (( DEBUG_CLOSE
| DEBUG_POOL
,
1361 "0x%08x: Created close event\r\n",
1362 pTcp6
->CloseToken
.CompletionToken
.Event
));
1365 // Allocate the connection event
1367 Status
= gBS
->CreateEvent ( EVT_NOTIFY_SIGNAL
,
1369 (EFI_EVENT_NOTIFY
)EslTcp6ConnectComplete
,
1371 &pTcp6
->ConnectToken
.CompletionToken
.Event
);
1372 if ( EFI_ERROR ( Status
)) {
1373 DEBUG (( DEBUG_ERROR
| DebugFlags
,
1374 "ERROR - Failed to create the connect event, Status: %r\r\n",
1376 pSocket
->errno
= ENOMEM
;
1379 DEBUG (( DEBUG_CLOSE
| DEBUG_POOL
,
1380 "0x%08x: Created connect event\r\n",
1381 pTcp6
->ConnectToken
.CompletionToken
.Event
));
1384 // Initialize the port
1386 pSocket
->TxPacketOffset
= OFFSET_OF ( ESL_PACKET
, Op
.Tcp6Tx
.TxData
);
1387 pSocket
->TxTokenEventOffset
= OFFSET_OF ( ESL_IO_MGMT
, Token
.Tcp6Tx
.CompletionToken
.Event
);
1388 pSocket
->TxTokenOffset
= OFFSET_OF ( EFI_TCP6_IO_TOKEN
, Packet
.TxData
);
1391 // Save the cancel, receive and transmit addresses
1392 // pPort->pfnRxCancel = NULL; since the UEFI implementation returns EFI_UNSUPPORTED
1394 pPort
->pfnConfigure
= (PFN_NET_CONFIGURE
)pPort
->pProtocol
.TCPv6
->Configure
;
1395 pPort
->pfnRxPoll
= (PFN_NET_POLL
)pPort
->pProtocol
.TCPv6
->Poll
;
1396 pPort
->pfnRxStart
= (PFN_NET_IO_START
)pPort
->pProtocol
.TCPv6
->Receive
;
1397 pPort
->pfnTxStart
= (PFN_NET_IO_START
)pPort
->pProtocol
.TCPv6
->Transmit
;
1400 // Set the configuration flags
1402 pAccessPoint
= &pPort
->Context
.Tcp6
.ConfigData
.AccessPoint
;
1403 pAccessPoint
->ActiveFlag
= FALSE
;
1404 pTcp6
->ConfigData
.TrafficClass
= 0;
1405 pTcp6
->ConfigData
.HopLimit
= 255;
1410 // Return the operation status
1412 DBG_EXIT_STATUS ( Status
);
1420 This routine releases the network specific resources allocated by
1421 ::EslTcp6PortAllocate.
1423 This routine is called by ::EslSocketPortClose.
1424 See the \ref PortCloseStateMachine section.
1426 @param [in] pPort Address of an ::ESL_PORT structure.
1428 @retval EFI_SUCCESS The port is closed
1429 @retval other Port close error
1438 ESL_TCP6_CONTEXT
* pTcp6
;
1444 // Locate the port in the socket list
1446 Status
= EFI_SUCCESS
;
1447 DebugFlags
= pPort
->DebugFlags
;
1448 pTcp6
= &pPort
->Context
.Tcp6
;
1451 // Done with the connect event
1453 if ( NULL
!= pTcp6
->ConnectToken
.CompletionToken
.Event
) {
1454 Status
= gBS
->CloseEvent ( pTcp6
->ConnectToken
.CompletionToken
.Event
);
1455 if ( !EFI_ERROR ( Status
)) {
1456 DEBUG (( DebugFlags
| DEBUG_POOL
,
1457 "0x%08x: Closed connect event\r\n",
1458 pTcp6
->ConnectToken
.CompletionToken
.Event
));
1461 DEBUG (( DEBUG_ERROR
| DebugFlags
,
1462 "ERROR - Failed to close the connect event, Status: %r\r\n",
1464 ASSERT ( EFI_SUCCESS
== Status
);
1469 // Done with the close event
1471 if ( NULL
!= pTcp6
->CloseToken
.CompletionToken
.Event
) {
1472 Status
= gBS
->CloseEvent ( pTcp6
->CloseToken
.CompletionToken
.Event
);
1473 if ( !EFI_ERROR ( Status
)) {
1474 DEBUG (( DebugFlags
| DEBUG_POOL
,
1475 "0x%08x: Closed close event\r\n",
1476 pTcp6
->CloseToken
.CompletionToken
.Event
));
1479 DEBUG (( DEBUG_ERROR
| DebugFlags
,
1480 "ERROR - Failed to close the close event, Status: %r\r\n",
1482 ASSERT ( EFI_SUCCESS
== Status
);
1487 // Done with the listen completion event
1489 if ( NULL
!= pTcp6
->ListenToken
.CompletionToken
.Event
) {
1490 Status
= gBS
->CloseEvent ( pTcp6
->ListenToken
.CompletionToken
.Event
);
1491 if ( !EFI_ERROR ( Status
)) {
1492 DEBUG (( DebugFlags
| DEBUG_POOL
,
1493 "0x%08x: Closed listen completion event\r\n",
1494 pTcp6
->ListenToken
.CompletionToken
.Event
));
1497 DEBUG (( DEBUG_ERROR
| DebugFlags
,
1498 "ERROR - Failed to close the listen completion event, Status: %r\r\n",
1500 ASSERT ( EFI_SUCCESS
== Status
);
1505 // Return the operation status
1507 DBG_EXIT_STATUS ( Status
);
1513 Perform the network specific close operation on the port.
1515 This routine performs a cancel operations on the TCPv6 port to
1516 shutdown the receive operations on the port.
1518 This routine is called by the ::EslSocketPortCloseTxDone
1519 routine after the port completes all of the transmission.
1521 @param [in] pPort Address of an ::ESL_PORT structure.
1523 @retval EFI_SUCCESS The port is closed, not normally returned
1524 @retval EFI_NOT_READY The port is still closing
1525 @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
1526 most likely the routine was called already.
1530 EslTcp6PortCloseOp (
1534 ESL_TCP6_CONTEXT
* pTcp6
;
1535 EFI_TCP6_PROTOCOL
* pTcp6Protocol
;
1541 // Close the configured port
1543 Status
= EFI_SUCCESS
;
1544 pTcp6
= &pPort
->Context
.Tcp6
;
1545 pTcp6Protocol
= pPort
->pProtocol
.TCPv6
;
1546 pTcp6
->CloseToken
.AbortOnClose
= pPort
->bCloseNow
;
1547 Status
= pTcp6Protocol
->Close ( pTcp6Protocol
,
1548 &pTcp6
->CloseToken
);
1549 if ( !EFI_ERROR ( Status
)) {
1550 DEBUG (( pPort
->DebugFlags
| DEBUG_CLOSE
| DEBUG_INFO
,
1551 "0x%08x: Port close started\r\n",
1555 DEBUG (( DEBUG_ERROR
| pPort
->DebugFlags
| DEBUG_CLOSE
| DEBUG_INFO
,
1556 "ERROR - Close failed on port 0x%08x, Status: %r\r\n",
1562 // Return the operation status
1564 DBG_EXIT_STATUS ( Status
);
1570 Receive data from a network connection.
1572 This routine attempts to return buffered data to the caller. The
1573 data is removed from the urgent queue if the message flag MSG_OOB
1574 is specified, otherwise data is removed from the normal queue.
1575 See the \ref ReceiveEngine section.
1577 This routine is called by ::EslSocketReceive to handle the network
1578 specific receive operation to support SOCK_STREAM and SOCK_SEQPACKET
1581 @param [in] pPort Address of an ::ESL_PORT structure.
1583 @param [in] pPacket Address of an ::ESL_PACKET structure.
1585 @param [in] pbConsumePacket Address of a BOOLEAN indicating if the packet is to be consumed
1587 @param [in] BufferLength Length of the the buffer
1589 @param [in] pBuffer Address of a buffer to receive the data.
1591 @param [in] pDataLength Number of received data bytes in the buffer.
1593 @param [out] pAddress Network address to receive the remote system address
1595 @param [out] pSkipBytes Address to receive the number of bytes skipped
1597 @return Returns the address of the next free byte in the buffer.
1602 IN ESL_PORT
* pPort
,
1603 IN ESL_PACKET
* pPacket
,
1604 IN BOOLEAN
* pbConsumePacket
,
1605 IN
size_t BufferLength
,
1607 OUT
size_t * pDataLength
,
1608 OUT
struct sockaddr
* pAddress
,
1609 OUT
size_t * pSkipBytes
1613 struct sockaddr_in6
* pRemoteAddress
;
1614 ESL_TCP6_CONTEXT
* pTcp6
;
1619 // Return the remote system address if requested
1621 if ( NULL
!= pAddress
) {
1623 // Build the remote address
1625 pTcp6
= &pPort
->Context
.Tcp6
;
1627 "Getting packet remote address: [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d\r\n",
1628 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[0],
1629 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[1],
1630 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[2],
1631 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[3],
1632 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[4],
1633 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[5],
1634 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[6],
1635 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[7],
1636 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[8],
1637 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[9],
1638 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[10],
1639 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[11],
1640 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[12],
1641 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[13],
1642 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[14],
1643 pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[15],
1644 pTcp6
->ConfigData
.AccessPoint
.RemotePort
));
1645 pRemoteAddress
= (struct sockaddr_in6
*)pAddress
;
1646 CopyMem ( &pRemoteAddress
->sin6_addr
,
1647 &pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[0],
1648 sizeof ( pRemoteAddress
->sin6_addr
));
1649 pRemoteAddress
->sin6_port
= SwapBytes16 ( pTcp6
->ConfigData
.AccessPoint
.RemotePort
);
1653 // Determine the amount of received data
1655 DataLength
= pPacket
->ValidBytes
;
1656 if ( BufferLength
< DataLength
) {
1657 DataLength
= BufferLength
;
1661 // Move the data into the buffer
1664 "0x%08x: Port copy packet 0x%08x data into 0x%08x, 0x%08x bytes\r\n",
1669 CopyMem ( pBuffer
, pPacket
->pBuffer
, DataLength
);
1672 // Set the next buffer address
1674 pBuffer
+= DataLength
;
1677 // Determine if the data is being read
1679 if ( *pbConsumePacket
) {
1681 // Account for the bytes consumed
1683 pPacket
->pBuffer
+= DataLength
;
1684 pPacket
->ValidBytes
-= DataLength
;
1686 "0x%08x: Port account for 0x%08x bytes\r\n",
1691 // Determine if the entire packet was consumed
1693 if (( 0 == pPacket
->ValidBytes
)
1694 || ( SOCK_STREAM
!= pPort
->pSocket
->Type
)) {
1696 // All done with this packet
1697 // Account for any discarded data
1699 *pSkipBytes
= pPacket
->ValidBytes
;
1704 // More data to consume later
1706 *pbConsumePacket
= FALSE
;
1711 // Return the data length and the buffer address
1713 *pDataLength
= DataLength
;
1714 DBG_EXIT_HEX ( pBuffer
);
1720 Get the remote socket address.
1722 This routine returns the address of the remote connection point
1723 associated with the SOCK_STREAM or SOCK_SEQPACKET socket.
1725 This routine is called by ::EslSocketGetPeerAddress to detemine
1726 the TCPv6 address and por number associated with the network adapter.
1728 @param [in] pPort Address of an ::ESL_PORT structure.
1730 @param [out] pAddress Network address to receive the remote system address
1734 EslTcp6RemoteAddressGet (
1735 IN ESL_PORT
* pPort
,
1736 OUT
struct sockaddr
* pAddress
1739 struct sockaddr_in6
* pRemoteAddress
;
1740 ESL_TCP6_CONTEXT
* pTcp6
;
1745 // Return the remote address
1747 pTcp6
= &pPort
->Context
.Tcp6
;
1748 pRemoteAddress
= (struct sockaddr_in6
*)pAddress
;
1749 pRemoteAddress
->sin6_family
= AF_INET6
;
1750 pRemoteAddress
->sin6_port
= SwapBytes16 ( pTcp6
->ConfigData
.AccessPoint
.RemotePort
);
1751 CopyMem ( &pRemoteAddress
->sin6_addr
,
1752 &pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[0],
1753 sizeof ( pRemoteAddress
->sin6_addr
));
1760 Set the remote address
1762 This routine sets the remote address in the port.
1764 This routine is called by ::EslSocketConnect to specify the
1765 remote network address.
1767 @param [in] pPort Address of an ::ESL_PORT structure.
1769 @param [in] pSockAddr Network address of the remote system.
1771 @param [in] SockAddrLength Length in bytes of the network address.
1773 @retval EFI_SUCCESS The operation was successful
1777 EslTcp6RemoteAddressSet (
1778 IN ESL_PORT
* pPort
,
1779 IN CONST
struct sockaddr
* pSockAddr
,
1780 IN socklen_t SockAddrLength
1783 CONST
struct sockaddr_in6
* pRemoteAddress
;
1784 ESL_TCP6_CONTEXT
* pTcp6
;
1790 // Set the remote address
1792 pTcp6
= &pPort
->Context
.Tcp6
;
1793 pRemoteAddress
= (struct sockaddr_in6
*)pSockAddr
;
1794 CopyMem ( &pTcp6
->ConfigData
.AccessPoint
.RemoteAddress
.Addr
[ 0 ],
1795 &pRemoteAddress
->sin6_addr
.__u6_addr
.__u6_addr8
[ 0 ],
1796 sizeof ( pRemoteAddress
->sin6_addr
.__u6_addr
.__u6_addr8
));
1797 pTcp6
->ConfigData
.AccessPoint
.RemotePort
= SwapBytes16 ( pRemoteAddress
->sin6_port
);
1798 Status
= EFI_SUCCESS
;
1801 // TODO: Fix the following check
1804 if ( INADDR_BROADCAST == pRemoteAddress->sin6_addr.s_addr ) {
1805 DEBUG (( DEBUG_CONNECT,
1806 "ERROR - Invalid remote address\r\n" ));
1807 Status = EFI_INVALID_PARAMETER;
1808 pPort->pSocket->errno = EAFNOSUPPORT;
1813 // Return the operation status
1815 DBG_EXIT_STATUS ( Status
);
1821 Process the receive completion
1823 This routine queues the data in FIFO order in either the urgent
1824 or normal data queues depending upon the type of data received.
1825 See the \ref ReceiveEngine section.
1827 This routine is called by the TCPv6 driver when some data is
1830 Buffer the data that was just received.
1832 @param [in] Event The receive completion event
1834 @param [in] pIo Address of an ::ESL_IO_MGMT structure
1840 IN ESL_IO_MGMT
* pIo
1844 size_t LengthInBytes
;
1845 ESL_PACKET
* pPacket
;
1851 // Get the operation status.
1853 Status
= pIo
->Token
.Tcp6Rx
.CompletionToken
.Status
;
1856 // +--------------------+ +---------------------------+
1857 // | ESL_IO_MGMT | | ESL_PACKET |
1859 // | +---------------+ +-----------------------+ |
1860 // | | Token | | EFI_Tcp6_RECEIVE_DATA | |
1861 // | | RxData --> | | |
1862 // | | | +-----------------------+---+
1863 // | | Event | | Data Buffer |
1864 // +----+---------------+ | |
1866 // +---------------------------+
1869 // Duplicate the buffer address and length for use by the
1870 // buffer handling code in EslTcp6Receive. These fields are
1871 // used when a partial read is done of the data from the
1874 pPacket
= pIo
->pPacket
;
1875 pPacket
->pBuffer
= pPacket
->Op
.Tcp6Rx
.RxData
.FragmentTable
[0].FragmentBuffer
;
1876 LengthInBytes
= pPacket
->Op
.Tcp6Rx
.RxData
.DataLength
;
1877 pPacket
->ValidBytes
= LengthInBytes
;
1880 // Get the data type so that it may be linked to the
1881 // correct receive buffer list on the ESL_SOCKET structure
1883 bUrgent
= pPacket
->Op
.Tcp6Rx
.RxData
.UrgentFlag
;
1886 // Complete this request
1888 EslSocketRxComplete ( pIo
, Status
, LengthInBytes
, bUrgent
);
1894 Start a receive operation
1896 This routine posts a receive buffer to the TCPv6 driver.
1897 See the \ref ReceiveEngine section.
1899 This support routine is called by EslSocketRxStart.
1901 @param [in] pPort Address of an ::ESL_PORT structure.
1902 @param [in] pIo Address of an ::ESL_IO_MGMT structure.
1907 IN ESL_PORT
* pPort
,
1908 IN ESL_IO_MGMT
* pIo
1911 ESL_PACKET
* pPacket
;
1916 // Initialize the buffer for receive
1918 pPacket
= pIo
->pPacket
;
1919 pIo
->Token
.Tcp6Rx
.Packet
.RxData
= &pPacket
->Op
.Tcp6Rx
.RxData
;
1920 pPacket
->Op
.Tcp6Rx
.RxData
.DataLength
= sizeof ( pPacket
->Op
.Tcp6Rx
.Buffer
);
1921 pPacket
->Op
.Tcp6Rx
.RxData
.FragmentCount
= 1;
1922 pPacket
->Op
.Tcp6Rx
.RxData
.FragmentTable
[0].FragmentLength
= pPacket
->Op
.Tcp6Rx
.RxData
.DataLength
;
1923 pPacket
->Op
.Tcp6Rx
.RxData
.FragmentTable
[0].FragmentBuffer
= &pPacket
->Op
.Tcp6Rx
.Buffer
[0];
1930 Determine if the socket is configured.
1932 This routine uses the flag ESL_SOCKET::bConfigured to determine
1933 if the network layer's configuration routine has been called.
1935 This routine is called by EslSocketIsConfigured to verify
1936 that the socket has been configured.
1938 @param [in] pSocket Address of an ::ESL_SOCKET structure.
1940 @retval EFI_SUCCESS - The port is connected
1941 @retval EFI_NOT_STARTED - The port is not connected
1945 EslTcp6SocketIsConfigured (
1946 IN ESL_SOCKET
* pSocket
1954 // Determine the socket configuration status
1956 Status
= pSocket
->bConfigured
? EFI_SUCCESS
: EFI_NOT_STARTED
;
1959 // Return the port connected state.
1961 DBG_EXIT_STATUS ( Status
);
1967 Buffer data for transmission over a network connection.
1969 This routine buffers data for the transmit engine in one of two
1970 queues, one for urgent (out-of-band) data and the other for normal
1971 data. The urgent data is provided to TCP as soon as it is available,
1972 allowing the TCP layer to schedule transmission of the urgent data
1973 between packets of normal data.
1975 This routine is called by ::EslSocketTransmit to buffer
1976 data for transmission. When the \ref TransmitEngine has resources,
1977 this routine will start the transmission of the next buffer on
1978 the network connection.
1980 Transmission errors are returned during the next transmission or
1981 during the close operation. Only buffering errors are returned
1982 during the current transmission attempt.
1984 @param [in] pSocket Address of an ::ESL_SOCKET structure
1986 @param [in] Flags Message control flags
1988 @param [in] BufferLength Length of the the buffer
1990 @param [in] pBuffer Address of a buffer to receive the data.
1992 @param [in] pDataLength Number of received data bytes in the buffer.
1994 @param [in] pAddress Network address of the remote system address
1996 @param [in] AddressLength Length of the remote network address structure
1998 @retval EFI_SUCCESS - Socket data successfully buffered
2003 IN ESL_SOCKET
* pSocket
,
2005 IN
size_t BufferLength
,
2006 IN CONST UINT8
* pBuffer
,
2007 OUT
size_t * pDataLength
,
2008 IN
const struct sockaddr
* pAddress
,
2009 IN socklen_t AddressLength
2013 BOOLEAN bUrgentQueue
;
2014 ESL_PACKET
* pPacket
;
2015 ESL_IO_MGMT
** ppActive
;
2016 ESL_IO_MGMT
** ppFree
;
2018 ESL_PACKET
** ppQueueHead
;
2019 ESL_PACKET
** ppQueueTail
;
2020 ESL_PACKET
* pPreviousPacket
;
2021 ESL_TCP6_CONTEXT
* pTcp6
;
2023 EFI_TCP6_TRANSMIT_DATA
* pTxData
;
2025 EFI_TPL TplPrevious
;
2032 Status
= EFI_UNSUPPORTED
;
2033 pSocket
->errno
= ENOTCONN
;
2037 // Verify that the socket is connected
2039 if ( SOCKET_STATE_CONNECTED
== pSocket
->State
) {
2043 pPort
= pSocket
->pPortList
;
2044 if ( NULL
!= pPort
) {
2046 // Determine the queue head
2048 pTcp6
= &pPort
->Context
.Tcp6
;
2049 bUrgent
= (BOOLEAN
)( 0 != ( Flags
& MSG_OOB
));
2050 bUrgentQueue
= bUrgent
2051 && ( !pSocket
->bOobInLine
)
2052 && pSocket
->pApi
->bOobSupported
;
2053 if ( bUrgentQueue
) {
2054 ppQueueHead
= &pSocket
->pTxOobPacketListHead
;
2055 ppQueueTail
= &pSocket
->pTxOobPacketListTail
;
2056 ppActive
= &pPort
->pTxOobActive
;
2057 ppFree
= &pPort
->pTxOobFree
;
2058 pTxBytes
= &pSocket
->TxOobBytes
;
2061 ppQueueHead
= &pSocket
->pTxPacketListHead
;
2062 ppQueueTail
= &pSocket
->pTxPacketListTail
;
2063 ppActive
= &pPort
->pTxActive
;
2064 ppFree
= &pPort
->pTxFree
;
2065 pTxBytes
= &pSocket
->TxBytes
;
2069 // Verify that there is enough room to buffer another
2070 // transmit operation
2072 if ( pSocket
->MaxTxBuf
> *pTxBytes
) {
2073 if ( pPort
->bTxFlowControl
) {
2075 "TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT\r\n0x%08x: pPort, TX flow control released, Max bytes: %d > %d bufferred bytes\r\n",
2079 pPort
->bTxFlowControl
= FALSE
;
2083 // Attempt to allocate the packet
2085 Status
= EslSocketPacketAllocate ( &pPacket
,
2086 sizeof ( pPacket
->Op
.Tcp6Tx
)
2087 - sizeof ( pPacket
->Op
.Tcp6Tx
.Buffer
)
2091 if ( !EFI_ERROR ( Status
)) {
2093 // Initialize the transmit operation
2095 pTxData
= &pPacket
->Op
.Tcp6Tx
.TxData
;
2096 pTxData
->Push
= TRUE
|| bUrgent
;
2097 pTxData
->Urgent
= bUrgent
;
2098 pTxData
->DataLength
= (UINT32
) BufferLength
;
2099 pTxData
->FragmentCount
= 1;
2100 pTxData
->FragmentTable
[0].FragmentLength
= (UINT32
) BufferLength
;
2101 pTxData
->FragmentTable
[0].FragmentBuffer
= &pPacket
->Op
.Tcp6Tx
.Buffer
[0];
2104 // Copy the data into the buffer
2106 CopyMem ( &pPacket
->Op
.Tcp6Tx
.Buffer
[0],
2111 // Synchronize with the socket layer
2113 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
2116 // Stop transmission after an error
2118 if ( !EFI_ERROR ( pSocket
->TxError
)) {
2120 // Display the request
2123 "Send %d %s bytes from 0x%08x\r\n",
2125 bUrgent
? L
"urgent" : L
"normal",
2129 // Queue the data for transmission
2131 pPacket
->pNext
= NULL
;
2132 pPreviousPacket
= *ppQueueTail
;
2133 if ( NULL
== pPreviousPacket
) {
2134 *ppQueueHead
= pPacket
;
2137 pPreviousPacket
->pNext
= pPacket
;
2139 *ppQueueTail
= pPacket
;
2141 "0x%08x: Packet on %s transmit list\r\n",
2143 bUrgentQueue
? L
"urgent" : L
"normal" ));
2146 // Account for the buffered data
2148 *pTxBytes
+= BufferLength
;
2149 *pDataLength
= BufferLength
;
2152 // Start the transmit engine if it is idle
2154 if ( NULL
!= *ppFree
) {
2155 EslSocketTxStart ( pPort
,
2164 // Previous transmit error
2165 // Stop transmission
2167 Status
= pSocket
->TxError
;
2168 pSocket
->errno
= EIO
;
2173 EslSocketPacketFree ( pPacket
, DEBUG_TX
);
2177 // Release the socket layer synchronization
2179 RESTORE_TPL ( TplPrevious
);
2183 // Packet allocation failed
2185 pSocket
->errno
= ENOMEM
;
2189 if ( !pPort
->bTxFlowControl
) {
2191 "0x%08x: pPort, TX flow control applied, Max bytes %d <= %d bufferred bytes\r\nTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT\r\n",
2195 pPort
->bTxFlowControl
= TRUE
;
2198 // Not enough buffer space available
2200 pSocket
->errno
= EAGAIN
;
2201 Status
= EFI_NOT_READY
;
2207 // Return the operation status
2209 DBG_EXIT_STATUS ( Status
);
2215 Process the normal data transmit completion
2217 This routine use ::EslSocketTxComplete to perform the transmit
2218 completion processing for normal data.
2220 This routine is called by the TCPv6 network layer when a
2221 normal data transmit request completes.
2223 @param [in] Event The normal transmit completion event
2225 @param [in] pIo The ESL_IO_MGMT structure address
2231 IN ESL_IO_MGMT
* pIo
2234 UINT32 LengthInBytes
;
2235 ESL_PACKET
* pPacket
;
2237 ESL_SOCKET
* pSocket
;
2243 // Locate the active transmit packet
2245 pPacket
= pIo
->pPacket
;
2247 pSocket
= pPort
->pSocket
;
2250 // Get the transmit length and status
2252 LengthInBytes
= pPacket
->Op
.Tcp6Tx
.TxData
.DataLength
;
2253 pSocket
->TxBytes
-= LengthInBytes
;
2254 Status
= pIo
->Token
.Tcp6Tx
.CompletionToken
.Status
;
2257 // Complete the transmit operation
2259 EslSocketTxComplete ( pIo
,
2263 &pSocket
->pTxPacketListHead
,
2264 &pSocket
->pTxPacketListTail
,
2272 Process the urgent data transmit completion
2274 This routine use ::EslSocketTxComplete to perform the transmit
2275 completion processing for urgent data.
2277 This routine is called by the TCPv6 network layer when a
2278 urgent data transmit request completes.
2280 @param [in] Event The urgent transmit completion event
2282 @param [in] pIo The ESL_IO_MGMT structure address
2286 EslTcp6TxOobComplete (
2288 IN ESL_IO_MGMT
* pIo
2291 UINT32 LengthInBytes
;
2292 ESL_PACKET
* pPacket
;
2294 ESL_SOCKET
* pSocket
;
2300 // Locate the active transmit packet
2302 pPacket
= pIo
->pPacket
;
2304 pSocket
= pPort
->pSocket
;
2307 // Get the transmit length and status
2309 LengthInBytes
= pPacket
->Op
.Tcp6Tx
.TxData
.DataLength
;
2310 pSocket
->TxOobBytes
-= LengthInBytes
;
2311 Status
= pIo
->Token
.Tcp6Tx
.CompletionToken
.Status
;
2314 // Complete the transmit operation
2316 EslSocketTxComplete ( pIo
,
2320 &pSocket
->pTxOobPacketListHead
,
2321 &pSocket
->pTxOobPacketListTail
,
2322 &pPort
->pTxOobActive
,
2323 &pPort
->pTxOobFree
);
2329 Interface between the socket layer and the network specific
2330 code that supports SOCK_STREAM and SOCK_SEQPACKET sockets
2333 CONST ESL_PROTOCOL_API cEslTcp6Api
= {
2336 OFFSET_OF ( ESL_PORT
, Context
.Tcp6
.ConfigData
),
2337 OFFSET_OF ( ESL_LAYER
, pTcp6List
),
2338 sizeof ( struct sockaddr_in6
),
2339 sizeof ( struct sockaddr_in6
),
2341 sizeof (((ESL_PACKET
*)0 )->Op
.Tcp6Rx
),
2342 OFFSET_OF ( ESL_PACKET
, Op
.Tcp6Rx
.Buffer
) - OFFSET_OF ( ESL_PACKET
, Op
),
2343 OFFSET_OF ( ESL_IO_MGMT
, Token
.Tcp6Rx
.Packet
.RxData
),
2348 EslTcp6ConnectStart
,
2349 EslTcp6SocketIsConfigured
,
2350 EslTcp6LocalAddressGet
,
2351 EslTcp6LocalAddressSet
,
2356 EslTcp6PortAllocate
,
2361 EslTcp6RemoteAddressGet
,
2362 EslTcp6RemoteAddressSet
,
2367 EslTcp6TxOobComplete