2012-02-09 20:16:44 +01:00
/** @file
Implement the TCP6 driver support for the socket layer .
Copyright ( c ) 2011 , Intel Corporation
All rights reserved . This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution . The full text of the license may be found at
http : //opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN " AS IS " BASIS ,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND , EITHER EXPRESS OR IMPLIED .
\ section ConnectionManagement Connection Management
The : : EslTcp6Listen routine initially places the SOCK_STREAM or
SOCK_SEQPACKET socket into a listen state . When a remote machine
makes a connection to the socket , the TCPv6 network layer calls
: : EslTcp6ListenComplete to complete the connection processing .
EslTcp6ListenComplete manages the connections by placing them in
FIFO order in a queue to be serviced by the application . When the
number of connections exceeds the backlog ( ESL_SOCKET : : MaxFifoDepth ) ,
the new connection is closed . Eventually , the application indirectly
calls : : EslTcp6Accept to remove the next connection from the queue
and get the associated socket .
* */
# include "Socket.h"
/**
Attempt to connect to a remote TCP port
This routine starts the connection processing for a SOCK_STREAM
or SOCK_SEQPAKCET socket using the TCPv6 network layer . It
configures the local TCPv6 connection point and then attempts to
connect to a remote system . Upon completion , the
: : EslTcp6ConnectComplete routine gets called with the connection
status .
This routine is called by : : EslSocketConnect to initiate the TCPv6
network specific connect operations . The connection processing is
initiated by this routine and finished by : : EslTcp6ConnectComplete .
This pair of routines walks through the list of local TCPv6
connection points until a connection to the remote system is
made .
@ param [ in ] pSocket Address of an : : ESL_SOCKET structure .
@ retval EFI_SUCCESS The connection was successfully established .
@ retval EFI_NOT_READY The connection is in progress , call this routine again .
@ retval Others The connection attempt failed .
* */
EFI_STATUS
EslTcp6ConnectStart (
IN ESL_SOCKET * pSocket
) ;
/**
Process the connection attempt
A system has initiated a connection attempt with a socket in the
listen state . Attempt to complete the connection .
The TCPv6 layer calls this routine when a connection is made to
the socket in the listen state . See the
\ ref ConnectionManagement section .
@ param [ in ] Event The listen completion event
@ param [ in ] pPort Address of an : : ESL_PORT structure .
* */
VOID
EslTcp6ListenComplete (
IN EFI_EVENT Event ,
IN ESL_PORT * pPort
) ;
/**
Accept a network connection .
This routine waits for a network connection to the socket and
returns the remote network address to the caller if requested .
This routine is called by : : EslSocketAccept to handle the TCPv6 protocol
specific accept operations for SOCK_STREAM and SOCK_SEQPACKET sockets .
See the \ ref ConnectionManagement section .
@ param [ in ] pSocket Address of an : : ESL_SOCKET structure .
@ param [ in ] pSockAddr Address of a buffer to receive the remote
network address .
@ param [ in , out ] pSockAddrLength Length in bytes of the address buffer .
On output specifies the length of the
remote network address .
@ retval EFI_SUCCESS Remote address is available
@ retval Others Remote address not available
* */
EFI_STATUS
EslTcp6Accept (
IN ESL_SOCKET * pSocket ,
IN struct sockaddr * pSockAddr ,
IN OUT socklen_t * pSockAddrLength
)
{
ESL_PORT * pPort ;
struct sockaddr_in6 * pRemoteAddress ;
ESL_TCP6_CONTEXT * pTcp6 ;
EFI_STATUS Status ;
DBG_ENTER ( ) ;
//
// Validate the socket length
//
pRemoteAddress = ( struct sockaddr_in6 * ) pSockAddr ;
if ( ( NULL = = pSockAddrLength )
| | ( sizeof ( * pRemoteAddress ) > * pSockAddrLength ) ) {
//
// Invalid socket address
//
Status = EFI_INVALID_PARAMETER ;
pSocket - > errno = EINVAL ;
DEBUG ( ( DEBUG_ACCEPT ,
" ERROR - Invalid address length \r \n " ) ) ;
}
else {
//
// Assume success
//
Status = EFI_SUCCESS ;
//
// Locate the address context
//
pPort = pSocket - > pPortList ;
pTcp6 = & pPort - > Context . Tcp6 ;
//
// Fill-in the remote address structure
//
ZeroMem ( pRemoteAddress , sizeof ( * pRemoteAddress ) ) ;
pRemoteAddress - > sin6_len = sizeof ( * pRemoteAddress ) ;
pRemoteAddress - > sin6_family = AF_INET6 ;
pRemoteAddress - > sin6_port = SwapBytes16 ( pTcp6 - > ConfigData . AccessPoint . RemotePort ) ;
CopyMem ( & pRemoteAddress - > sin6_addr . __u6_addr . __u6_addr8 [ 0 ] ,
& pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 0 ] ,
sizeof ( pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr ) ) ;
}
//
// Return the operation status
//
DBG_EXIT_STATUS ( Status ) ;
return Status ;
}
/**
Process the remote connection completion event .
This routine handles the completion of a connection attempt . It
releases the port ( TCPv6 adapter connection ) in the case of an
error and start a connection attempt on the next port . If the
connection attempt was successful then this routine releases all
of the other ports .
This routine is called by the TCPv6 layer when a connect request
completes . It sets the ESL_SOCKET : : bConnected flag to notify the
: : EslTcp6ConnectComplete routine that the connection is available .
The flag is set when the connection is established or no more ports
exist in the list . The connection status is passed via
ESL_SOCKET : : ConnectStatus .
@ param [ in ] Event The connect completion event
@ param [ in ] pPort Address of an : : ESL_PORT structure .
* */
VOID
EslTcp6ConnectComplete (
IN EFI_EVENT Event ,
IN ESL_PORT * pPort
)
{
BOOLEAN bRemoveFirstPort ;
BOOLEAN bRemovePorts ;
ESL_PORT * pNextPort ;
ESL_SOCKET * pSocket ;
ESL_TCP6_CONTEXT * pTcp6 ;
EFI_STATUS Status ;
DBG_ENTER ( ) ;
//
// Locate the TCP context
//
pSocket = pPort - > pSocket ;
pTcp6 = & pPort - > Context . Tcp6 ;
//
// Get the connection status
//
bRemoveFirstPort = FALSE ;
bRemovePorts = FALSE ;
Status = pTcp6 - > ConnectToken . CompletionToken . Status ;
pSocket - > ConnectStatus = Status ;
if ( ! EFI_ERROR ( Status ) ) {
//
// The connection was successful
//
DEBUG ( ( DEBUG_CONNECT ,
" 0x%08x: Port connected to [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d \r \n " ,
pPort ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 0 ] ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 1 ] ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 2 ] ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 3 ] ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 4 ] ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 5 ] ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 6 ] ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 7 ] ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 8 ] ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 9 ] ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 10 ] ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 11 ] ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 12 ] ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 13 ] ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 14 ] ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 15 ] ,
pTcp6 - > ConfigData . AccessPoint . RemotePort ) ) ;
//
// Remove the rest of the ports
//
bRemovePorts = TRUE ;
}
else {
//
// The connection failed
//
DEBUG ( ( DEBUG_CONNECT ,
" 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 " ,
pPort ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 0 ] ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 1 ] ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 2 ] ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 3 ] ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 4 ] ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 5 ] ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 6 ] ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 7 ] ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 8 ] ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 9 ] ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 10 ] ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 11 ] ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 12 ] ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 13 ] ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 14 ] ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 15 ] ,
pTcp6 - > ConfigData . AccessPoint . RemotePort ,
Status ) ) ;
//
// Close the current port
//
Status = EslSocketPortClose ( pPort ) ;
if ( ! EFI_ERROR ( Status ) ) {
DEBUG ( ( DEBUG_CONNECT ,
" 0x%08x: Port closed \r \n " ,
pPort ) ) ;
}
else {
DEBUG ( ( DEBUG_CONNECT ,
" ERROR - Failed to close port 0x%08x, Status: %r \r \n " ,
pPort ,
Status ) ) ;
}
//
// Try to connect using the next port
//
Status = EslTcp6ConnectStart ( pSocket ) ;
if ( EFI_NOT_READY ! = Status ) {
pSocket - > ConnectStatus = Status ;
bRemoveFirstPort = TRUE ;
}
}
//
// Remove the ports if necessary
//
if ( bRemoveFirstPort | | bRemovePorts ) {
//
// Remove the first port if necessary
//
pPort = pSocket - > pPortList ;
if ( ( ! bRemoveFirstPort ) & & ( NULL ! = pPort ) ) {
pPort = pPort - > pLinkSocket ;
}
//
// Remove the rest of the list
//
while ( NULL ! = pPort ) {
pNextPort = pPort - > pLinkSocket ;
EslSocketPortClose ( pPort ) ;
if ( ! EFI_ERROR ( Status ) ) {
DEBUG ( ( DEBUG_CONNECT ,
" 0x%08x: Port closed \r \n " ,
pPort ) ) ;
}
else {
DEBUG ( ( DEBUG_CONNECT ,
" ERROR - Failed to close port 0x%08x, Status: %r \r \n " ,
pPort ,
Status ) ) ;
}
pPort = pNextPort ;
}
//
// Notify the poll routine
//
pSocket - > bConnected = TRUE ;
}
DBG_EXIT ( ) ;
}
/**
Poll for completion of the connection attempt .
This routine polls the ESL_SOCKET : : bConnected flag to determine
when the connection attempt is complete .
This routine is called from : : EslSocketConnect to determine when
the connection is complete . The ESL_SOCKET : : bConnected flag is
set by : : EslTcp6ConnectComplete when the TCPv6 layer establishes
a connection or runs out of local network adapters . This routine
gets the connection status from ESL_SOCKET : : ConnectStatus .
@ param [ in ] pSocket Address of an : : ESL_SOCKET structure .
@ retval EFI_SUCCESS The connection was successfully established .
@ retval EFI_NOT_READY The connection is in progress , call this routine again .
@ retval Others The connection attempt failed .
* */
EFI_STATUS
EslTcp6ConnectPoll (
IN ESL_SOCKET * pSocket
)
{
EFI_STATUS Status ;
DBG_ENTER ( ) ;
//
// Determine if the connection is complete
//
if ( ! pSocket - > bConnected ) {
//
// Not connected
//
pSocket - > errno = EAGAIN ;
Status = EFI_NOT_READY ;
}
else {
//
// The connection processing is complete
//
pSocket - > bConnected = FALSE ;
//
// Translate the connection status
//
Status = pSocket - > ConnectStatus ;
switch ( Status ) {
default :
case EFI_DEVICE_ERROR :
pSocket - > errno = EIO ;
break ;
case EFI_ABORTED :
pSocket - > errno = ECONNREFUSED ;
break ;
case EFI_INVALID_PARAMETER :
pSocket - > errno = EINVAL ;
break ;
case EFI_NO_MAPPING :
case EFI_NO_RESPONSE :
pSocket - > errno = EHOSTUNREACH ;
break ;
case EFI_NO_MEDIA :
pSocket - > errno = ENETDOWN ;
break ;
case EFI_OUT_OF_RESOURCES :
pSocket - > errno = ENOMEM ;
break ;
case EFI_SUCCESS :
pSocket - > errno = 0 ;
pSocket - > bConfigured = TRUE ;
break ;
case EFI_TIMEOUT :
pSocket - > errno = ETIMEDOUT ;
break ;
case EFI_UNSUPPORTED :
pSocket - > errno = ENOTSUP ;
break ;
case 0x80000069 :
pSocket - > errno = ECONNRESET ;
break ;
}
}
//
// Return the initialization status
//
DBG_EXIT_STATUS ( Status ) ;
return Status ;
}
/**
Attempt to connect to a remote TCP port
This routine starts the connection processing for a SOCK_STREAM
or SOCK_SEQPAKCET socket using the TCPv6 network layer . It
configures the local TCPv6 connection point and then attempts to
connect to a remote system . Upon completion , the
: : EslTcp6ConnectComplete routine gets called with the connection
status .
This routine is called by : : EslSocketConnect to initiate the TCPv6
network specific connect operations . The connection processing is
initiated by this routine and finished by : : EslTcp6ConnectComplete .
This pair of routines walks through the list of local TCPv6
connection points until a connection to the remote system is
made .
@ param [ in ] pSocket Address of an : : ESL_SOCKET structure .
@ retval EFI_SUCCESS The connection was successfully established .
@ retval EFI_NOT_READY The connection is in progress , call this routine again .
@ retval Others The connection attempt failed .
* */
EFI_STATUS
EslTcp6ConnectStart (
IN ESL_SOCKET * pSocket
)
{
ESL_PORT * pPort ;
ESL_TCP6_CONTEXT * pTcp6 ;
EFI_TCP6_PROTOCOL * pTcp6Protocol ;
EFI_STATUS Status ;
DBG_ENTER ( ) ;
//
// Determine if any more local adapters are available
//
pPort = pSocket - > pPortList ;
if ( NULL ! = pPort ) {
//
// Configure the port
//
pTcp6 = & pPort - > Context . Tcp6 ;
pTcp6 - > ConfigData . AccessPoint . ActiveFlag = TRUE ;
pTcp6 - > ConfigData . TrafficClass = 0 ;
pTcp6 - > ConfigData . HopLimit = 255 ;
pTcp6Protocol = pPort - > pProtocol . TCPv6 ;
Status = pTcp6Protocol - > Configure ( pTcp6Protocol ,
& pTcp6 - > ConfigData ) ;
if ( EFI_ERROR ( Status ) ) {
DEBUG ( ( DEBUG_CONNECT ,
" ERROR - Failed to configure the Tcp6 port, Status: %r \r \n " ,
Status ) ) ;
switch ( Status ) {
case EFI_ACCESS_DENIED :
pSocket - > errno = EACCES ;
break ;
default :
case EFI_DEVICE_ERROR :
pSocket - > errno = EIO ;
break ;
case EFI_INVALID_PARAMETER :
pSocket - > errno = EADDRNOTAVAIL ;
break ;
case EFI_NO_MAPPING :
pSocket - > errno = EAFNOSUPPORT ;
break ;
case EFI_OUT_OF_RESOURCES :
pSocket - > errno = ENOBUFS ;
break ;
case EFI_UNSUPPORTED :
pSocket - > errno = EOPNOTSUPP ;
break ;
}
}
else {
DEBUG ( ( DEBUG_CONNECT ,
" 0x%08x: Port configured \r \n " ,
pPort ) ) ;
pPort - > bConfigured = TRUE ;
//
// Attempt the connection to the remote system
//
Status = pTcp6Protocol - > Connect ( pTcp6Protocol ,
& pTcp6 - > ConnectToken ) ;
if ( ! EFI_ERROR ( Status ) ) {
//
// Connection in progress
//
pSocket - > errno = EINPROGRESS ;
Status = EFI_NOT_READY ;
DEBUG ( ( DEBUG_CONNECT ,
" 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 " ,
pPort ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 0 ] ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 1 ] ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 2 ] ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 3 ] ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 4 ] ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 5 ] ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 6 ] ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 7 ] ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 8 ] ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 9 ] ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 10 ] ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 11 ] ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 12 ] ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 13 ] ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 14 ] ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 15 ] ,
pTcp6 - > ConfigData . AccessPoint . RemotePort ) ) ;
}
else {
//
// Connection error
//
DEBUG ( ( DEBUG_CONNECT ,
" ERROR - Port 0x%08x not connected, Status: %r \r \n " ,
pPort ,
Status ) ) ;
//
// Determine the errno value
//
switch ( Status ) {
default :
pSocket - > errno = EIO ;
break ;
case EFI_OUT_OF_RESOURCES :
pSocket - > errno = ENOBUFS ;
break ;
case EFI_TIMEOUT :
pSocket - > errno = ETIMEDOUT ;
break ;
case EFI_NETWORK_UNREACHABLE :
pSocket - > errno = ENETDOWN ;
break ;
case EFI_HOST_UNREACHABLE :
pSocket - > errno = EHOSTUNREACH ;
break ;
case EFI_PORT_UNREACHABLE :
case EFI_PROTOCOL_UNREACHABLE :
case EFI_CONNECTION_REFUSED :
pSocket - > errno = ECONNREFUSED ;
break ;
case EFI_CONNECTION_RESET :
pSocket - > errno = ECONNRESET ;
break ;
}
}
}
}
else {
//
// No more local adapters available
//
pSocket - > errno = ENETUNREACH ;
Status = EFI_NO_RESPONSE ;
}
//
// Return the operation status
//
DBG_EXIT_STATUS ( Status ) ;
return Status ;
}
/**
Establish the known port to listen for network connections .
This routine places the port into a state that enables connection
attempts .
This routine is called by : : EslSocketListen to handle the network
specifics of the listen operation for SOCK_STREAM and SOCK_SEQPACKET
sockets . See the \ ref ConnectionManagement section .
@ param [ in ] pSocket Address of an : : ESL_SOCKET structure .
@ retval EFI_SUCCESS - Socket successfully created
@ retval Other - Failed to enable the socket for listen
* */
EFI_STATUS
EslTcp6Listen (
IN ESL_SOCKET * pSocket
)
{
ESL_PORT * pNextPort ;
ESL_PORT * pPort ;
ESL_TCP6_CONTEXT * pTcp6 ;
EFI_TCP6_PROTOCOL * pTcp6Protocol ;
EFI_STATUS Status ;
DBG_ENTER ( ) ;
//
// Verify the socket layer synchronization
//
VERIFY_TPL ( TPL_SOCKETS ) ;
//
// Use for/break instead of goto
//
for ( ; ; ) {
//
// Assume no ports are available
//
pSocket - > errno = EOPNOTSUPP ;
Status = EFI_NOT_READY ;
//
// Walk the list of ports
//
pPort = pSocket - > pPortList ;
while ( NULL ! = pPort ) {
//
// Assume success
//
pSocket - > errno = 0 ;
//
// Use for/break insteak of goto
//
for ( ; ; ) {
//
// Create the listen completion event
//
pTcp6 = & pPort - > Context . Tcp6 ;
Status = gBS - > CreateEvent ( EVT_NOTIFY_SIGNAL ,
TPL_SOCKETS ,
( EFI_EVENT_NOTIFY ) EslTcp6ListenComplete ,
pPort ,
& pTcp6 - > ListenToken . CompletionToken . Event ) ;
if ( EFI_ERROR ( Status ) ) {
DEBUG ( ( DEBUG_ERROR | DEBUG_LISTEN ,
" ERROR - Failed to create the listen completion event, Status: %r \r \n " ,
Status ) ) ;
pSocket - > errno = ENOMEM ;
break ;
}
DEBUG ( ( DEBUG_POOL ,
" 0x%08x: Created listen completion event \r \n " ,
pTcp6 - > ListenToken . CompletionToken . Event ) ) ;
//
// Configure the port
//
pTcp6Protocol = pPort - > pProtocol . TCPv6 ;
Status = pTcp6Protocol - > Configure ( pTcp6Protocol ,
& pTcp6 - > ConfigData ) ;
if ( EFI_ERROR ( Status ) ) {
DEBUG ( ( DEBUG_LISTEN ,
" ERROR - Failed to configure the Tcp6 port, Status: %r \r \n " ,
Status ) ) ;
switch ( Status ) {
case EFI_ACCESS_DENIED :
pSocket - > errno = EACCES ;
break ;
default :
case EFI_DEVICE_ERROR :
pSocket - > errno = EIO ;
break ;
case EFI_INVALID_PARAMETER :
pSocket - > errno = EADDRNOTAVAIL ;
break ;
case EFI_NO_MAPPING :
pSocket - > errno = EAFNOSUPPORT ;
break ;
case EFI_OUT_OF_RESOURCES :
pSocket - > errno = ENOBUFS ;
break ;
case EFI_UNSUPPORTED :
pSocket - > errno = EOPNOTSUPP ;
break ;
}
break ;
}
DEBUG ( ( DEBUG_LISTEN ,
" 0x%08x: Port configured \r \n " ,
pPort ) ) ;
pPort - > bConfigured = TRUE ;
//
// Start the listen operation on the port
//
Status = pTcp6Protocol - > Accept ( pTcp6Protocol ,
& pTcp6 - > ListenToken ) ;
if ( EFI_ERROR ( Status ) ) {
DEBUG ( ( DEBUG_LISTEN ,
" ERROR - Failed Tcp6 accept, Status: %r \r \n " ,
Status ) ) ;
switch ( Status ) {
case EFI_ACCESS_DENIED :
pSocket - > errno = EACCES ;
break ;
default :
case EFI_DEVICE_ERROR :
pSocket - > errno = EIO ;
break ;
case EFI_INVALID_PARAMETER :
pSocket - > errno = EADDRNOTAVAIL ;
break ;
case EFI_NOT_STARTED :
pSocket - > errno = ENETDOWN ;
break ;
case EFI_OUT_OF_RESOURCES :
pSocket - > errno = ENOBUFS ;
break ;
}
break ;
}
DEBUG ( ( DEBUG_LISTEN ,
" 0x%08x: Listen pending on Port \r \n " ,
pPort ) ) ;
//
// Listen is pending on this port
//
break ;
}
//
// Get the next port
//
pNextPort = pPort - > pLinkSocket ;
//
// Close the port upon error
//
if ( EFI_ERROR ( Status ) ) {
EslSocketPortCloseStart ( pPort , TRUE , DEBUG_LISTEN ) ;
}
//
// Set the next port
//
pPort = pNextPort ;
}
//
// Determine if any ports are in the listen state
//
if ( NULL = = pSocket - > pPortList ) {
//
// No ports in the listen state
//
pSocket - > MaxFifoDepth = 0 ;
//
// Return the last error detected
//
break ;
}
//
// Mark the socket as configured
//
pSocket - > bConfigured = TRUE ;
//
// All done
//
DEBUG ( ( DEBUG_LISTEN ,
" 0x%08x: pSocket - Listen pending on socket \r \n " ,
pSocket ) ) ;
break ;
}
//
// Return the operation status
//
DBG_EXIT_STATUS ( Status ) ;
return Status ;
}
/**
Process the connection attempt
A system has initiated a connection attempt with a socket in the
listen state . Attempt to complete the connection .
The TCPv6 layer calls this routine when a connection is made to
the socket in the listen state . See the
\ ref ConnectionManagement section .
@ param [ in ] Event The listen completion event
@ param [ in ] pPort Address of an : : ESL_PORT structure .
* */
VOID
EslTcp6ListenComplete (
IN EFI_EVENT Event ,
IN ESL_PORT * pPort
)
{
EFI_HANDLE ChildHandle ;
struct sockaddr_in6 LocalAddress ;
EFI_TCP6_CONFIG_DATA * pConfigData ;
ESL_LAYER * pLayer ;
ESL_PORT * pNewPort ;
ESL_SOCKET * pNewSocket ;
ESL_SOCKET * pSocket ;
ESL_TCP6_CONTEXT * pTcp6 ;
EFI_TCP6_PROTOCOL * pTcp6Protocol ;
EFI_STATUS Status ;
EFI_HANDLE TcpPortHandle ;
EFI_STATUS TempStatus ;
DBG_ENTER ( ) ;
VERIFY_AT_TPL ( TPL_SOCKETS ) ;
//
// Assume success
//
Status = EFI_SUCCESS ;
//
// Determine if this connection fits into the connection FIFO
//
pSocket = pPort - > pSocket ;
TcpPortHandle = pPort - > Context . Tcp6 . ListenToken . NewChildHandle ;
if ( ( SOCKET_STATE_LISTENING = = pSocket - > State )
& & ( pSocket - > MaxFifoDepth > pSocket - > FifoDepth ) ) {
//
// Allocate a socket for this connection
//
ChildHandle = NULL ;
pLayer = & mEslLayer ;
Status = EslSocketAllocate ( & ChildHandle ,
DEBUG_CONNECTION ,
& pNewSocket ) ;
if ( ! EFI_ERROR ( Status ) ) {
//
// Clone the socket parameters
//
pNewSocket - > pApi = pSocket - > pApi ;
pNewSocket - > Domain = pSocket - > Domain ;
pNewSocket - > Protocol = pSocket - > Protocol ;
pNewSocket - > Type = pSocket - > Type ;
//
// Build the local address
//
pTcp6 = & pPort - > Context . Tcp6 ;
LocalAddress . sin6_len = ( uint8_t ) pNewSocket - > pApi - > MinimumAddressLength ;
LocalAddress . sin6_family = AF_INET6 ;
LocalAddress . sin6_port = 0 ;
CopyMem ( & LocalAddress . sin6_addr . __u6_addr . __u6_addr8 [ 0 ] ,
& pTcp6 - > ConfigData . AccessPoint . StationAddress . Addr [ 0 ] ,
sizeof ( pTcp6 - > ConfigData . AccessPoint . StationAddress . Addr ) ) ;
//
// Allocate a port for this connection
// Note in this instance Configure may not be called with NULL!
//
Status = EslSocketPortAllocate ( pNewSocket ,
pPort - > pService ,
TcpPortHandle ,
( struct sockaddr * ) & LocalAddress ,
FALSE ,
DEBUG_CONNECTION ,
& pNewPort ) ;
if ( ! EFI_ERROR ( Status ) ) {
//
// Restart the listen operation on the port
//
pTcp6Protocol = pPort - > pProtocol . TCPv6 ;
Status = pTcp6Protocol - > Accept ( pTcp6Protocol ,
& pTcp6 - > ListenToken ) ;
//
// Close the TCP port using SocketClose
//
TcpPortHandle = NULL ;
pTcp6 = & pNewPort - > Context . Tcp6 ;
//
// Check for an accept call error
//
if ( ! EFI_ERROR ( Status ) ) {
//
// Get the port configuration
//
pNewPort - > bConfigured = TRUE ;
pConfigData = & pTcp6 - > ConfigData ;
pConfigData - > ControlOption = & pTcp6 - > Option ;
pTcp6Protocol = pNewPort - > pProtocol . TCPv6 ;
Status = pTcp6Protocol - > GetModeData ( pTcp6Protocol ,
NULL ,
pConfigData ,
NULL ,
NULL ,
NULL ) ;
if ( ! EFI_ERROR ( Status ) ) {
//
// Add the new socket to the connection FIFO
//
if ( NULL = = pSocket - > pFifoTail ) {
//
// First connection
//
pSocket - > pFifoHead = pNewSocket ;
}
else {
//
// Add to end of list.
//
pSocket - > pFifoTail - > pNextConnection = pNewSocket ;
}
pSocket - > pFifoTail = pNewSocket ;
pSocket - > FifoDepth + = 1 ;
//
// Update the socket state
//
pNewSocket - > State = SOCKET_STATE_IN_FIFO ;
//
// Log the connection
//
DEBUG ( ( DEBUG_CONNECTION | DEBUG_INFO ,
" 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 " ,
pNewSocket ,
pConfigData - > AccessPoint . StationAddress . Addr [ 0 ] ,
pConfigData - > AccessPoint . StationAddress . Addr [ 1 ] ,
pConfigData - > AccessPoint . StationAddress . Addr [ 2 ] ,
pConfigData - > AccessPoint . StationAddress . Addr [ 3 ] ,
pConfigData - > AccessPoint . StationAddress . Addr [ 4 ] ,
pConfigData - > AccessPoint . StationAddress . Addr [ 5 ] ,
pConfigData - > AccessPoint . StationAddress . Addr [ 6 ] ,
pConfigData - > AccessPoint . StationAddress . Addr [ 7 ] ,
pConfigData - > AccessPoint . StationAddress . Addr [ 8 ] ,
pConfigData - > AccessPoint . StationAddress . Addr [ 9 ] ,
pConfigData - > AccessPoint . StationAddress . Addr [ 10 ] ,
pConfigData - > AccessPoint . StationAddress . Addr [ 11 ] ,
pConfigData - > AccessPoint . StationAddress . Addr [ 12 ] ,
pConfigData - > AccessPoint . StationAddress . Addr [ 13 ] ,
pConfigData - > AccessPoint . StationAddress . Addr [ 14 ] ,
pConfigData - > AccessPoint . StationAddress . Addr [ 15 ] ,
pConfigData - > AccessPoint . StationPort ,
pConfigData - > AccessPoint . RemoteAddress . Addr [ 0 ] ,
pConfigData - > AccessPoint . RemoteAddress . Addr [ 1 ] ,
pConfigData - > AccessPoint . RemoteAddress . Addr [ 2 ] ,
pConfigData - > AccessPoint . RemoteAddress . Addr [ 3 ] ,
pConfigData - > AccessPoint . RemoteAddress . Addr [ 4 ] ,
pConfigData - > AccessPoint . RemoteAddress . Addr [ 5 ] ,
pConfigData - > AccessPoint . RemoteAddress . Addr [ 6 ] ,
pConfigData - > AccessPoint . RemoteAddress . Addr [ 7 ] ,
pConfigData - > AccessPoint . RemoteAddress . Addr [ 8 ] ,
pConfigData - > AccessPoint . RemoteAddress . Addr [ 9 ] ,
pConfigData - > AccessPoint . RemoteAddress . Addr [ 10 ] ,
pConfigData - > AccessPoint . RemoteAddress . Addr [ 11 ] ,
pConfigData - > AccessPoint . RemoteAddress . Addr [ 12 ] ,
pConfigData - > AccessPoint . RemoteAddress . Addr [ 13 ] ,
pConfigData - > AccessPoint . RemoteAddress . Addr [ 14 ] ,
pConfigData - > AccessPoint . RemoteAddress . Addr [ 15 ] ,
pConfigData - > AccessPoint . RemotePort ) ) ;
DEBUG ( ( DEBUG_CONNECTION | DEBUG_INFO ,
" 0x%08x: Listen socket adding socket 0x%08x to FIFO, depth: %d \r \n " ,
pSocket ,
pNewSocket ,
pSocket - > FifoDepth ) ) ;
//
// Start the receive operation
//
EslSocketRxStart ( pNewPort ) ;
}
else {
DEBUG ( ( DEBUG_ERROR | DEBUG_CONNECTION | DEBUG_INFO ,
" ERROR - GetModeData failed on port 0x%08x, Status: %r \r \n " ,
pNewPort ,
Status ) ) ;
}
}
else {
//
// The listen failed on this port
//
DEBUG ( ( DEBUG_LISTEN | DEBUG_INFO ,
" ERROR - Listen failed on port 0x%08x, Status: %r \r \n " ,
pPort ,
Status ) ) ;
//
// Close the listening port
//
EslSocketPortCloseStart ( pPort , TRUE , DEBUG_LISTEN ) ;
}
}
//
// Done with the socket if necessary
//
if ( EFI_ERROR ( Status ) ) {
TempStatus = EslSocketCloseStart ( & pNewSocket - > SocketProtocol ,
TRUE ,
& pSocket - > errno ) ;
ASSERT ( EFI_SUCCESS = = TempStatus ) ;
}
}
}
else {
DEBUG ( ( DEBUG_CONNECTION ,
" 0x%08x: Socket FIFO full, connection refused \r \n " ,
pSocket ) ) ;
//
// The FIFO is full or the socket is in the wrong state
//
Status = EFI_BUFFER_TOO_SMALL ;
}
//
// Close the connection if necessary
//
if ( ( EFI_ERROR ( Status ) )
& & ( NULL = = TcpPortHandle ) ) {
//
// TODO: Finish this code path
// The new connection does not fit into the connection FIFO
//
// Process:
// Call close
// Release the resources
}
DBG_EXIT ( ) ;
}
/**
Get the local socket address .
This routine returns the IPv6 address and TCP port number associated
with the local socket .
This routine is called by : : EslSocketGetLocalAddress to determine the
network address for the SOCK_STREAM or SOCK_SEQPACKET socket .
@ param [ in ] pPort Address of an : : ESL_PORT structure .
@ param [ out ] pSockAddr Network address to receive the local system address
* */
VOID
EslTcp6LocalAddressGet (
IN ESL_PORT * pPort ,
OUT struct sockaddr * pSockAddr
)
{
struct sockaddr_in6 * pLocalAddress ;
ESL_TCP6_CONTEXT * pTcp6 ;
DBG_ENTER ( ) ;
//
// Return the local address
//
pTcp6 = & pPort - > Context . Tcp6 ;
pLocalAddress = ( struct sockaddr_in6 * ) pSockAddr ;
pLocalAddress - > sin6_family = AF_INET6 ;
pLocalAddress - > sin6_port = SwapBytes16 ( pTcp6 - > ConfigData . AccessPoint . StationPort ) ;
CopyMem ( & pLocalAddress - > sin6_addr ,
& pTcp6 - > ConfigData . AccessPoint . StationAddress . Addr [ 0 ] ,
sizeof ( pLocalAddress - > sin6_addr ) ) ;
DBG_EXIT ( ) ;
}
/**
Set the local port address .
This routine sets the local port address .
This support routine is called by : : EslSocketPortAllocate .
@ param [ in ] pPort Address of an ESL_PORT structure
@ param [ in ] pSockAddr Address of a sockaddr structure that contains the
connection point on the local machine . An IPv6 address
of INADDR_ANY specifies that the connection is made to
all of the network stacks on the platform . Specifying a
specific IPv6 address restricts the connection to the
network stack supporting that address . Specifying zero
for the port causes the network layer to assign a port
number from the dynamic range . Specifying a specific
port number causes the network layer to use that port .
@ param [ in ] bBindTest TRUE = run bind testing
@ retval EFI_SUCCESS The operation was successful
* */
EFI_STATUS
EslTcp6LocalAddressSet (
IN ESL_PORT * pPort ,
IN CONST struct sockaddr * pSockAddr ,
IN BOOLEAN bBindTest
)
{
EFI_TCP6_ACCESS_POINT * pAccessPoint ;
CONST struct sockaddr_in6 * pIpAddress ;
EFI_STATUS Status ;
DBG_ENTER ( ) ;
//
// Validate the address
//
pIpAddress = ( struct sockaddr_in6 * ) pSockAddr ;
//
// TODO: Fix the following check
//
/*
if ( INADDR_BROADCAST = = pIpAddress - > sin6_addr . s_addr ) {
//
// The local address must not be the broadcast address
//
Status = EFI_INVALID_PARAMETER ;
pPort - > pSocket - > errno = EADDRNOTAVAIL ;
}
else {
*/
{
//
// Set the local address
//
pAccessPoint = & pPort - > Context . Tcp6 . ConfigData . AccessPoint ;
CopyMem ( & pAccessPoint - > StationAddress . Addr [ 0 ] ,
& pIpAddress - > sin6_addr . __u6_addr . __u6_addr8 [ 0 ] ,
sizeof ( pIpAddress - > sin6_addr . __u6_addr . __u6_addr8 [ 0 ] ) ) ;
//
// Validate the IP address
//
pAccessPoint - > StationPort = 0 ;
Status = bBindTest ? EslSocketBindTest ( pPort , EADDRNOTAVAIL )
: EFI_SUCCESS ;
if ( ! EFI_ERROR ( Status ) ) {
//
// Set the port number
//
pAccessPoint - > StationPort = SwapBytes16 ( pIpAddress - > sin6_port ) ;
2012-02-24 19:45:09 +01:00
pPort - > pSocket - > bAddressSet = TRUE ;
2012-02-09 20:16:44 +01:00
//
// Display the local address
//
DEBUG ( ( DEBUG_BIND ,
" 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 " ,
pPort ,
pAccessPoint - > StationAddress . Addr [ 0 ] ,
pAccessPoint - > StationAddress . Addr [ 1 ] ,
pAccessPoint - > StationAddress . Addr [ 2 ] ,
pAccessPoint - > StationAddress . Addr [ 3 ] ,
pAccessPoint - > StationAddress . Addr [ 4 ] ,
pAccessPoint - > StationAddress . Addr [ 5 ] ,
pAccessPoint - > StationAddress . Addr [ 6 ] ,
pAccessPoint - > StationAddress . Addr [ 7 ] ,
pAccessPoint - > StationAddress . Addr [ 8 ] ,
pAccessPoint - > StationAddress . Addr [ 9 ] ,
pAccessPoint - > StationAddress . Addr [ 10 ] ,
pAccessPoint - > StationAddress . Addr [ 11 ] ,
pAccessPoint - > StationAddress . Addr [ 12 ] ,
pAccessPoint - > StationAddress . Addr [ 13 ] ,
pAccessPoint - > StationAddress . Addr [ 14 ] ,
pAccessPoint - > StationAddress . Addr [ 15 ] ,
pAccessPoint - > StationPort ) ) ;
}
}
//
// Return the operation status
//
DBG_EXIT_STATUS ( Status ) ;
return Status ;
}
/**
Free a receive packet
This routine performs the network specific operations necessary
to free a receive packet .
This routine is called by : : EslSocketPortCloseTxDone to free a
receive packet .
@ param [ in ] pPacket Address of an : : ESL_PACKET structure .
@ param [ in , out ] pRxBytes Address of the count of RX bytes
* */
VOID
EslTcp6PacketFree (
IN ESL_PACKET * pPacket ,
IN OUT size_t * pRxBytes
)
{
DBG_ENTER ( ) ;
//
// Account for the receive bytes
//
* pRxBytes - = pPacket - > Op . Tcp6Rx . RxData . DataLength ;
DBG_EXIT ( ) ;
}
/**
Initialize the network specific portions of an : : ESL_PORT structure .
This routine initializes the network specific portions of an
: : ESL_PORT structure for use by the socket .
This support routine is called by : : EslSocketPortAllocate
to connect the socket with the underlying network adapter
running the TCPv6 protocol .
@ param [ in ] pPort Address of an ESL_PORT structure
@ param [ in ] DebugFlags Flags for debug messages
@ retval EFI_SUCCESS - Socket successfully created
* */
EFI_STATUS
EslTcp6PortAllocate (
IN ESL_PORT * pPort ,
IN UINTN DebugFlags
)
{
EFI_TCP6_ACCESS_POINT * pAccessPoint ;
ESL_SOCKET * pSocket ;
ESL_TCP6_CONTEXT * pTcp6 ;
EFI_STATUS Status ;
DBG_ENTER ( ) ;
//
// Use for/break instead of goto
for ( ; ; ) {
//
// Allocate the close event
//
pSocket = pPort - > pSocket ;
pTcp6 = & pPort - > Context . Tcp6 ;
Status = gBS - > CreateEvent ( EVT_NOTIFY_SIGNAL ,
TPL_SOCKETS ,
( EFI_EVENT_NOTIFY ) EslSocketPortCloseComplete ,
pPort ,
& pTcp6 - > CloseToken . CompletionToken . Event ) ;
if ( EFI_ERROR ( Status ) ) {
DEBUG ( ( DEBUG_ERROR | DebugFlags ,
" ERROR - Failed to create the close event, Status: %r \r \n " ,
Status ) ) ;
pSocket - > errno = ENOMEM ;
break ;
}
DEBUG ( ( DEBUG_CLOSE | DEBUG_POOL ,
" 0x%08x: Created close event \r \n " ,
pTcp6 - > CloseToken . CompletionToken . Event ) ) ;
//
// Allocate the connection event
//
Status = gBS - > CreateEvent ( EVT_NOTIFY_SIGNAL ,
TPL_SOCKETS ,
( EFI_EVENT_NOTIFY ) EslTcp6ConnectComplete ,
pPort ,
& pTcp6 - > ConnectToken . CompletionToken . Event ) ;
if ( EFI_ERROR ( Status ) ) {
DEBUG ( ( DEBUG_ERROR | DebugFlags ,
" ERROR - Failed to create the connect event, Status: %r \r \n " ,
Status ) ) ;
pSocket - > errno = ENOMEM ;
break ;
}
DEBUG ( ( DEBUG_CLOSE | DEBUG_POOL ,
" 0x%08x: Created connect event \r \n " ,
pTcp6 - > ConnectToken . CompletionToken . Event ) ) ;
//
// Initialize the port
//
pSocket - > TxPacketOffset = OFFSET_OF ( ESL_PACKET , Op . Tcp6Tx . TxData ) ;
pSocket - > TxTokenEventOffset = OFFSET_OF ( ESL_IO_MGMT , Token . Tcp6Tx . CompletionToken . Event ) ;
pSocket - > TxTokenOffset = OFFSET_OF ( EFI_TCP6_IO_TOKEN , Packet . TxData ) ;
//
// Save the cancel, receive and transmit addresses
// pPort->pfnRxCancel = NULL; since the UEFI implementation returns EFI_UNSUPPORTED
//
pPort - > pfnConfigure = ( PFN_NET_CONFIGURE ) pPort - > pProtocol . TCPv6 - > Configure ;
pPort - > pfnRxPoll = ( PFN_NET_POLL ) pPort - > pProtocol . TCPv6 - > Poll ;
pPort - > pfnRxStart = ( PFN_NET_IO_START ) pPort - > pProtocol . TCPv6 - > Receive ;
pPort - > pfnTxStart = ( PFN_NET_IO_START ) pPort - > pProtocol . TCPv6 - > Transmit ;
//
// Set the configuration flags
//
pAccessPoint = & pPort - > Context . Tcp6 . ConfigData . AccessPoint ;
pAccessPoint - > ActiveFlag = FALSE ;
pTcp6 - > ConfigData . TrafficClass = 0 ;
pTcp6 - > ConfigData . HopLimit = 255 ;
break ;
}
//
// Return the operation status
//
DBG_EXIT_STATUS ( Status ) ;
return Status ;
}
/**
Close a Tcp6 port .
This routine releases the network specific resources allocated by
: : EslTcp6PortAllocate .
This routine is called by : : EslSocketPortClose .
See the \ ref PortCloseStateMachine section .
@ param [ in ] pPort Address of an : : ESL_PORT structure .
@ retval EFI_SUCCESS The port is closed
@ retval other Port close error
* */
EFI_STATUS
EslTcp6PortClose (
IN ESL_PORT * pPort
)
{
UINTN DebugFlags ;
ESL_TCP6_CONTEXT * pTcp6 ;
EFI_STATUS Status ;
DBG_ENTER ( ) ;
//
// Locate the port in the socket list
//
Status = EFI_SUCCESS ;
DebugFlags = pPort - > DebugFlags ;
pTcp6 = & pPort - > Context . Tcp6 ;
//
// Done with the connect event
//
if ( NULL ! = pTcp6 - > ConnectToken . CompletionToken . Event ) {
Status = gBS - > CloseEvent ( pTcp6 - > ConnectToken . CompletionToken . Event ) ;
if ( ! EFI_ERROR ( Status ) ) {
DEBUG ( ( DebugFlags | DEBUG_POOL ,
" 0x%08x: Closed connect event \r \n " ,
pTcp6 - > ConnectToken . CompletionToken . Event ) ) ;
}
else {
DEBUG ( ( DEBUG_ERROR | DebugFlags ,
" ERROR - Failed to close the connect event, Status: %r \r \n " ,
Status ) ) ;
ASSERT ( EFI_SUCCESS = = Status ) ;
}
}
//
// Done with the close event
//
if ( NULL ! = pTcp6 - > CloseToken . CompletionToken . Event ) {
Status = gBS - > CloseEvent ( pTcp6 - > CloseToken . CompletionToken . Event ) ;
if ( ! EFI_ERROR ( Status ) ) {
DEBUG ( ( DebugFlags | DEBUG_POOL ,
" 0x%08x: Closed close event \r \n " ,
pTcp6 - > CloseToken . CompletionToken . Event ) ) ;
}
else {
DEBUG ( ( DEBUG_ERROR | DebugFlags ,
" ERROR - Failed to close the close event, Status: %r \r \n " ,
Status ) ) ;
ASSERT ( EFI_SUCCESS = = Status ) ;
}
}
//
// Done with the listen completion event
//
if ( NULL ! = pTcp6 - > ListenToken . CompletionToken . Event ) {
Status = gBS - > CloseEvent ( pTcp6 - > ListenToken . CompletionToken . Event ) ;
if ( ! EFI_ERROR ( Status ) ) {
DEBUG ( ( DebugFlags | DEBUG_POOL ,
" 0x%08x: Closed listen completion event \r \n " ,
pTcp6 - > ListenToken . CompletionToken . Event ) ) ;
}
else {
DEBUG ( ( DEBUG_ERROR | DebugFlags ,
" ERROR - Failed to close the listen completion event, Status: %r \r \n " ,
Status ) ) ;
ASSERT ( EFI_SUCCESS = = Status ) ;
}
}
//
// Return the operation status
//
DBG_EXIT_STATUS ( Status ) ;
return Status ;
}
/**
Perform the network specific close operation on the port .
This routine performs a cancel operations on the TCPv6 port to
shutdown the receive operations on the port .
This routine is called by the : : EslSocketPortCloseTxDone
routine after the port completes all of the transmission .
@ param [ in ] pPort Address of an : : ESL_PORT structure .
@ retval EFI_SUCCESS The port is closed , not normally returned
@ retval EFI_NOT_READY The port is still closing
@ retval EFI_ALREADY_STARTED Error , the port is in the wrong state ,
most likely the routine was called already .
* */
EFI_STATUS
EslTcp6PortCloseOp (
IN ESL_PORT * pPort
)
{
ESL_TCP6_CONTEXT * pTcp6 ;
EFI_TCP6_PROTOCOL * pTcp6Protocol ;
EFI_STATUS Status ;
DBG_ENTER ( ) ;
//
// Close the configured port
//
Status = EFI_SUCCESS ;
pTcp6 = & pPort - > Context . Tcp6 ;
pTcp6Protocol = pPort - > pProtocol . TCPv6 ;
pTcp6 - > CloseToken . AbortOnClose = pPort - > bCloseNow ;
Status = pTcp6Protocol - > Close ( pTcp6Protocol ,
& pTcp6 - > CloseToken ) ;
if ( ! EFI_ERROR ( Status ) ) {
DEBUG ( ( pPort - > DebugFlags | DEBUG_CLOSE | DEBUG_INFO ,
" 0x%08x: Port close started \r \n " ,
pPort ) ) ;
}
else {
DEBUG ( ( DEBUG_ERROR | pPort - > DebugFlags | DEBUG_CLOSE | DEBUG_INFO ,
" ERROR - Close failed on port 0x%08x, Status: %r \r \n " ,
pPort ,
Status ) ) ;
}
//
// Return the operation status
//
DBG_EXIT_STATUS ( Status ) ;
return Status ;
}
/**
Receive data from a network connection .
This routine attempts to return buffered data to the caller . The
data is removed from the urgent queue if the message flag MSG_OOB
is specified , otherwise data is removed from the normal queue .
See the \ ref ReceiveEngine section .
This routine is called by : : EslSocketReceive to handle the network
specific receive operation to support SOCK_STREAM and SOCK_SEQPACKET
sockets .
@ param [ in ] pPort Address of an : : ESL_PORT structure .
@ param [ in ] pPacket Address of an : : ESL_PACKET structure .
@ param [ in ] pbConsumePacket Address of a BOOLEAN indicating if the packet is to be consumed
@ param [ in ] BufferLength Length of the the buffer
@ param [ in ] pBuffer Address of a buffer to receive the data .
@ param [ in ] pDataLength Number of received data bytes in the buffer .
@ param [ out ] pAddress Network address to receive the remote system address
@ param [ out ] pSkipBytes Address to receive the number of bytes skipped
@ return Returns the address of the next free byte in the buffer .
* */
UINT8 *
EslTcp6Receive (
IN ESL_PORT * pPort ,
IN ESL_PACKET * pPacket ,
IN BOOLEAN * pbConsumePacket ,
IN size_t BufferLength ,
IN UINT8 * pBuffer ,
OUT size_t * pDataLength ,
OUT struct sockaddr * pAddress ,
OUT size_t * pSkipBytes
)
{
size_t DataLength ;
struct sockaddr_in6 * pRemoteAddress ;
ESL_TCP6_CONTEXT * pTcp6 ;
DBG_ENTER ( ) ;
//
// Return the remote system address if requested
//
if ( NULL ! = pAddress ) {
//
// Build the remote address
//
pTcp6 = & pPort - > Context . Tcp6 ;
DEBUG ( ( DEBUG_RX ,
" Getting packet remote address: [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d \r \n " ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 0 ] ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 1 ] ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 2 ] ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 3 ] ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 4 ] ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 5 ] ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 6 ] ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 7 ] ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 8 ] ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 9 ] ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 10 ] ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 11 ] ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 12 ] ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 13 ] ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 14 ] ,
pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 15 ] ,
pTcp6 - > ConfigData . AccessPoint . RemotePort ) ) ;
pRemoteAddress = ( struct sockaddr_in6 * ) pAddress ;
CopyMem ( & pRemoteAddress - > sin6_addr ,
& pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 0 ] ,
sizeof ( pRemoteAddress - > sin6_addr ) ) ;
pRemoteAddress - > sin6_port = SwapBytes16 ( pTcp6 - > ConfigData . AccessPoint . RemotePort ) ;
}
//
// Determine the amount of received data
//
DataLength = pPacket - > ValidBytes ;
if ( BufferLength < DataLength ) {
DataLength = BufferLength ;
}
//
// Move the data into the buffer
//
DEBUG ( ( DEBUG_RX ,
" 0x%08x: Port copy packet 0x%08x data into 0x%08x, 0x%08x bytes \r \n " ,
pPort ,
pPacket ,
pBuffer ,
DataLength ) ) ;
CopyMem ( pBuffer , pPacket - > pBuffer , DataLength ) ;
2012-03-05 20:05:47 +01:00
//
// Set the next buffer address
//
pBuffer + = DataLength ;
2012-02-09 20:16:44 +01:00
//
// Determine if the data is being read
//
if ( * pbConsumePacket ) {
//
// Account for the bytes consumed
//
pPacket - > pBuffer + = DataLength ;
pPacket - > ValidBytes - = DataLength ;
DEBUG ( ( DEBUG_RX ,
" 0x%08x: Port account for 0x%08x bytes \r \n " ,
pPort ,
DataLength ) ) ;
//
// Determine if the entire packet was consumed
//
if ( ( 0 = = pPacket - > ValidBytes )
| | ( SOCK_STREAM ! = pPort - > pSocket - > Type ) ) {
//
// All done with this packet
// Account for any discarded data
//
* pSkipBytes = pPacket - > ValidBytes ;
}
else
{
//
// More data to consume later
//
* pbConsumePacket = FALSE ;
}
}
//
// Return the data length and the buffer address
//
* pDataLength = DataLength ;
DBG_EXIT_HEX ( pBuffer ) ;
return pBuffer ;
}
/**
Get the remote socket address .
This routine returns the address of the remote connection point
associated with the SOCK_STREAM or SOCK_SEQPACKET socket .
This routine is called by : : EslSocketGetPeerAddress to detemine
the TCPv6 address and por number associated with the network adapter .
@ param [ in ] pPort Address of an : : ESL_PORT structure .
@ param [ out ] pAddress Network address to receive the remote system address
* */
VOID
EslTcp6RemoteAddressGet (
IN ESL_PORT * pPort ,
OUT struct sockaddr * pAddress
)
{
struct sockaddr_in6 * pRemoteAddress ;
ESL_TCP6_CONTEXT * pTcp6 ;
DBG_ENTER ( ) ;
//
// Return the remote address
//
pTcp6 = & pPort - > Context . Tcp6 ;
pRemoteAddress = ( struct sockaddr_in6 * ) pAddress ;
pRemoteAddress - > sin6_family = AF_INET6 ;
pRemoteAddress - > sin6_port = SwapBytes16 ( pTcp6 - > ConfigData . AccessPoint . RemotePort ) ;
CopyMem ( & pRemoteAddress - > sin6_addr ,
& pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 0 ] ,
sizeof ( pRemoteAddress - > sin6_addr ) ) ;
DBG_EXIT ( ) ;
}
/**
Set the remote address
This routine sets the remote address in the port .
This routine is called by : : EslSocketConnect to specify the
remote network address .
@ param [ in ] pPort Address of an : : ESL_PORT structure .
@ param [ in ] pSockAddr Network address of the remote system .
@ param [ in ] SockAddrLength Length in bytes of the network address .
@ retval EFI_SUCCESS The operation was successful
* */
EFI_STATUS
EslTcp6RemoteAddressSet (
IN ESL_PORT * pPort ,
IN CONST struct sockaddr * pSockAddr ,
IN socklen_t SockAddrLength
)
{
CONST struct sockaddr_in6 * pRemoteAddress ;
ESL_TCP6_CONTEXT * pTcp6 ;
EFI_STATUS Status ;
DBG_ENTER ( ) ;
//
// Set the remote address
//
pTcp6 = & pPort - > Context . Tcp6 ;
pRemoteAddress = ( struct sockaddr_in6 * ) pSockAddr ;
CopyMem ( & pTcp6 - > ConfigData . AccessPoint . RemoteAddress . Addr [ 0 ] ,
& pRemoteAddress - > sin6_addr . __u6_addr . __u6_addr8 [ 0 ] ,
sizeof ( pRemoteAddress - > sin6_addr . __u6_addr . __u6_addr8 ) ) ;
pTcp6 - > ConfigData . AccessPoint . RemotePort = SwapBytes16 ( pRemoteAddress - > sin6_port ) ;
Status = EFI_SUCCESS ;
//
// TODO: Fix the following check
//
/*
if ( INADDR_BROADCAST = = pRemoteAddress - > sin6_addr . s_addr ) {
DEBUG ( ( DEBUG_CONNECT ,
" ERROR - Invalid remote address \r \n " ) ) ;
Status = EFI_INVALID_PARAMETER ;
pPort - > pSocket - > errno = EAFNOSUPPORT ;
}
*/
//
// Return the operation status
//
DBG_EXIT_STATUS ( Status ) ;
return Status ;
}
/**
Process the receive completion
This routine queues the data in FIFO order in either the urgent
or normal data queues depending upon the type of data received .
See the \ ref ReceiveEngine section .
This routine is called by the TCPv6 driver when some data is
received .
Buffer the data that was just received .
@ param [ in ] Event The receive completion event
@ param [ in ] pIo Address of an : : ESL_IO_MGMT structure
* */
VOID
EslTcp6RxComplete (
IN EFI_EVENT Event ,
IN ESL_IO_MGMT * pIo
)
{
BOOLEAN bUrgent ;
size_t LengthInBytes ;
ESL_PACKET * pPacket ;
EFI_STATUS Status ;
DBG_ENTER ( ) ;
//
// Get the operation status.
//
Status = pIo - > Token . Tcp6Rx . CompletionToken . Status ;
//
// +--------------------+ +---------------------------+
// | ESL_IO_MGMT | | ESL_PACKET |
// | | | |
// | +---------------+ +-----------------------+ |
// | | Token | | EFI_Tcp6_RECEIVE_DATA | |
// | | RxData --> | | |
// | | | +-----------------------+---+
// | | Event | | Data Buffer |
// +----+---------------+ | |
// | |
// +---------------------------+
//
//
// Duplicate the buffer address and length for use by the
// buffer handling code in EslTcp6Receive. These fields are
// used when a partial read is done of the data from the
// packet.
//
pPacket = pIo - > pPacket ;
pPacket - > pBuffer = pPacket - > Op . Tcp6Rx . RxData . FragmentTable [ 0 ] . FragmentBuffer ;
LengthInBytes = pPacket - > Op . Tcp6Rx . RxData . DataLength ;
pPacket - > ValidBytes = LengthInBytes ;
//
// Get the data type so that it may be linked to the
// correct receive buffer list on the ESL_SOCKET structure
//
bUrgent = pPacket - > Op . Tcp6Rx . RxData . UrgentFlag ;
//
// Complete this request
//
EslSocketRxComplete ( pIo , Status , LengthInBytes , bUrgent ) ;
DBG_EXIT ( ) ;
}
/**
Start a receive operation
This routine posts a receive buffer to the TCPv6 driver .
See the \ ref ReceiveEngine section .
This support routine is called by EslSocketRxStart .
@ param [ in ] pPort Address of an : : ESL_PORT structure .
@ param [ in ] pIo Address of an : : ESL_IO_MGMT structure .
* */
VOID
EslTcp6RxStart (
IN ESL_PORT * pPort ,
IN ESL_IO_MGMT * pIo
)
{
ESL_PACKET * pPacket ;
DBG_ENTER ( ) ;
//
// Initialize the buffer for receive
//
pPacket = pIo - > pPacket ;
pIo - > Token . Tcp6Rx . Packet . RxData = & pPacket - > Op . Tcp6Rx . RxData ;
pPacket - > Op . Tcp6Rx . RxData . DataLength = sizeof ( pPacket - > Op . Tcp6Rx . Buffer ) ;
pPacket - > Op . Tcp6Rx . RxData . FragmentCount = 1 ;
pPacket - > Op . Tcp6Rx . RxData . FragmentTable [ 0 ] . FragmentLength = pPacket - > Op . Tcp6Rx . RxData . DataLength ;
pPacket - > Op . Tcp6Rx . RxData . FragmentTable [ 0 ] . FragmentBuffer = & pPacket - > Op . Tcp6Rx . Buffer [ 0 ] ;
DBG_EXIT ( ) ;
}
/**
Determine if the socket is configured .
This routine uses the flag ESL_SOCKET : : bConfigured to determine
if the network layer ' s configuration routine has been called .
This routine is called by EslSocketIsConfigured to verify
that the socket has been configured .
@ param [ in ] pSocket Address of an : : ESL_SOCKET structure .
@ retval EFI_SUCCESS - The port is connected
@ retval EFI_NOT_STARTED - The port is not connected
* */
EFI_STATUS
EslTcp6SocketIsConfigured (
IN ESL_SOCKET * pSocket
)
{
EFI_STATUS Status ;
DBG_ENTER ( ) ;
//
// Determine the socket configuration status
//
Status = pSocket - > bConfigured ? EFI_SUCCESS : EFI_NOT_STARTED ;
//
// Return the port connected state.
//
DBG_EXIT_STATUS ( Status ) ;
return Status ;
}
/**
Buffer data for transmission over a network connection .
This routine buffers data for the transmit engine in one of two
queues , one for urgent ( out - of - band ) data and the other for normal
data . The urgent data is provided to TCP as soon as it is available ,
allowing the TCP layer to schedule transmission of the urgent data
between packets of normal data .
This routine is called by : : EslSocketTransmit to buffer
data for transmission . When the \ ref TransmitEngine has resources ,
this routine will start the transmission of the next buffer on
the network connection .
Transmission errors are returned during the next transmission or
during the close operation . Only buffering errors are returned
during the current transmission attempt .
@ param [ in ] pSocket Address of an : : ESL_SOCKET structure
@ param [ in ] Flags Message control flags
@ param [ in ] BufferLength Length of the the buffer
@ param [ in ] pBuffer Address of a buffer to receive the data .
@ param [ in ] pDataLength Number of received data bytes in the buffer .
@ param [ in ] pAddress Network address of the remote system address
@ param [ in ] AddressLength Length of the remote network address structure
@ retval EFI_SUCCESS - Socket data successfully buffered
* */
EFI_STATUS
EslTcp6TxBuffer (
IN ESL_SOCKET * pSocket ,
IN int Flags ,
IN size_t BufferLength ,
IN CONST UINT8 * pBuffer ,
OUT size_t * pDataLength ,
IN const struct sockaddr * pAddress ,
IN socklen_t AddressLength
)
{
BOOLEAN bUrgent ;
BOOLEAN bUrgentQueue ;
ESL_PACKET * pPacket ;
ESL_IO_MGMT * * ppActive ;
ESL_IO_MGMT * * ppFree ;
ESL_PORT * pPort ;
ESL_PACKET * * ppQueueHead ;
ESL_PACKET * * ppQueueTail ;
ESL_PACKET * pPreviousPacket ;
ESL_TCP6_CONTEXT * pTcp6 ;
size_t * pTxBytes ;
EFI_TCP6_TRANSMIT_DATA * pTxData ;
EFI_STATUS Status ;
EFI_TPL TplPrevious ;
DBG_ENTER ( ) ;
//
// Assume failure
//
Status = EFI_UNSUPPORTED ;
pSocket - > errno = ENOTCONN ;
* pDataLength = 0 ;
//
// Verify that the socket is connected
//
if ( SOCKET_STATE_CONNECTED = = pSocket - > State ) {
//
// Locate the port
//
pPort = pSocket - > pPortList ;
if ( NULL ! = pPort ) {
//
// Determine the queue head
//
pTcp6 = & pPort - > Context . Tcp6 ;
bUrgent = ( BOOLEAN ) ( 0 ! = ( Flags & MSG_OOB ) ) ;
bUrgentQueue = bUrgent
& & ( ! pSocket - > bOobInLine )
& & pSocket - > pApi - > bOobSupported ;
if ( bUrgentQueue ) {
ppQueueHead = & pSocket - > pTxOobPacketListHead ;
ppQueueTail = & pSocket - > pTxOobPacketListTail ;
ppActive = & pPort - > pTxOobActive ;
ppFree = & pPort - > pTxOobFree ;
pTxBytes = & pSocket - > TxOobBytes ;
}
else {
ppQueueHead = & pSocket - > pTxPacketListHead ;
ppQueueTail = & pSocket - > pTxPacketListTail ;
ppActive = & pPort - > pTxActive ;
ppFree = & pPort - > pTxFree ;
pTxBytes = & pSocket - > TxBytes ;
}
//
// Verify that there is enough room to buffer another
// transmit operation
//
if ( pSocket - > MaxTxBuf > * pTxBytes ) {
if ( pPort - > bTxFlowControl ) {
DEBUG ( ( DEBUG_TX ,
" TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT \r \n 0x%08x: pPort, TX flow control released, Max bytes: %d > %d bufferred bytes \r \n " ,
pPort ,
pSocket - > MaxTxBuf ,
* pTxBytes ) ) ;
pPort - > bTxFlowControl = FALSE ;
}
//
// Attempt to allocate the packet
//
Status = EslSocketPacketAllocate ( & pPacket ,
sizeof ( pPacket - > Op . Tcp6Tx )
- sizeof ( pPacket - > Op . Tcp6Tx . Buffer )
+ BufferLength ,
0 ,
DEBUG_TX ) ;
if ( ! EFI_ERROR ( Status ) ) {
//
// Initialize the transmit operation
//
pTxData = & pPacket - > Op . Tcp6Tx . TxData ;
pTxData - > Push = TRUE | | bUrgent ;
pTxData - > Urgent = bUrgent ;
pTxData - > DataLength = ( UINT32 ) BufferLength ;
pTxData - > FragmentCount = 1 ;
pTxData - > FragmentTable [ 0 ] . FragmentLength = ( UINT32 ) BufferLength ;
pTxData - > FragmentTable [ 0 ] . FragmentBuffer = & pPacket - > Op . Tcp6Tx . Buffer [ 0 ] ;
//
// Copy the data into the buffer
//
CopyMem ( & pPacket - > Op . Tcp6Tx . Buffer [ 0 ] ,
pBuffer ,
BufferLength ) ;
//
// Synchronize with the socket layer
//
RAISE_TPL ( TplPrevious , TPL_SOCKETS ) ;
//
// Stop transmission after an error
//
if ( ! EFI_ERROR ( pSocket - > TxError ) ) {
//
// Display the request
//
DEBUG ( ( DEBUG_TX ,
" Send %d %s bytes from 0x%08x \r \n " ,
BufferLength ,
bUrgent ? L " urgent " : L " normal " ,
pBuffer ) ) ;
//
// Queue the data for transmission
//
pPacket - > pNext = NULL ;
pPreviousPacket = * ppQueueTail ;
if ( NULL = = pPreviousPacket ) {
* ppQueueHead = pPacket ;
}
else {
pPreviousPacket - > pNext = pPacket ;
}
* ppQueueTail = pPacket ;
DEBUG ( ( DEBUG_TX ,
" 0x%08x: Packet on %s transmit list \r \n " ,
pPacket ,
bUrgentQueue ? L " urgent " : L " normal " ) ) ;
//
// Account for the buffered data
//
* pTxBytes + = BufferLength ;
* pDataLength = BufferLength ;
//
// Start the transmit engine if it is idle
//
if ( NULL ! = * ppFree ) {
EslSocketTxStart ( pPort ,
ppQueueHead ,
ppQueueTail ,
ppActive ,
ppFree ) ;
}
}
else {
//
// Previous transmit error
// Stop transmission
//
Status = pSocket - > TxError ;
pSocket - > errno = EIO ;
//
// Free the packet
//
EslSocketPacketFree ( pPacket , DEBUG_TX ) ;
}
//
// Release the socket layer synchronization
//
RESTORE_TPL ( TplPrevious ) ;
}
else {
//
// Packet allocation failed
//
pSocket - > errno = ENOMEM ;
}
}
else {
if ( ! pPort - > bTxFlowControl ) {
DEBUG ( ( DEBUG_TX ,
" 0x%08x: pPort, TX flow control applied, Max bytes %d <= %d bufferred bytes \r \n TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT \r \n " ,
pPort ,
pSocket - > MaxTxBuf ,
* pTxBytes ) ) ;
pPort - > bTxFlowControl = TRUE ;
}
//
// Not enough buffer space available
//
pSocket - > errno = EAGAIN ;
Status = EFI_NOT_READY ;
}
}
}
//
// Return the operation status
//
DBG_EXIT_STATUS ( Status ) ;
return Status ;
}
/**
Process the normal data transmit completion
This routine use : : EslSocketTxComplete to perform the transmit
completion processing for normal data .
This routine is called by the TCPv6 network layer when a
normal data transmit request completes .
@ param [ in ] Event The normal transmit completion event
@ param [ in ] pIo The ESL_IO_MGMT structure address
* */
VOID
EslTcp6TxComplete (
IN EFI_EVENT Event ,
IN ESL_IO_MGMT * pIo
)
{
UINT32 LengthInBytes ;
ESL_PACKET * pPacket ;
ESL_PORT * pPort ;
ESL_SOCKET * pSocket ;
EFI_STATUS Status ;
DBG_ENTER ( ) ;
//
// Locate the active transmit packet
//
pPacket = pIo - > pPacket ;
pPort = pIo - > pPort ;
pSocket = pPort - > pSocket ;
//
// Get the transmit length and status
//
LengthInBytes = pPacket - > Op . Tcp6Tx . TxData . DataLength ;
pSocket - > TxBytes - = LengthInBytes ;
Status = pIo - > Token . Tcp6Tx . CompletionToken . Status ;
//
// Complete the transmit operation
//
EslSocketTxComplete ( pIo ,
LengthInBytes ,
Status ,
" Normal " ,
& pSocket - > pTxPacketListHead ,
& pSocket - > pTxPacketListTail ,
& pPort - > pTxActive ,
& pPort - > pTxFree ) ;
DBG_EXIT ( ) ;
}
/**
Process the urgent data transmit completion
This routine use : : EslSocketTxComplete to perform the transmit
completion processing for urgent data .
This routine is called by the TCPv6 network layer when a
urgent data transmit request completes .
@ param [ in ] Event The urgent transmit completion event
@ param [ in ] pIo The ESL_IO_MGMT structure address
* */
VOID
EslTcp6TxOobComplete (
IN EFI_EVENT Event ,
IN ESL_IO_MGMT * pIo
)
{
UINT32 LengthInBytes ;
ESL_PACKET * pPacket ;
ESL_PORT * pPort ;
ESL_SOCKET * pSocket ;
EFI_STATUS Status ;
DBG_ENTER ( ) ;
//
// Locate the active transmit packet
//
pPacket = pIo - > pPacket ;
pPort = pIo - > pPort ;
pSocket = pPort - > pSocket ;
//
// Get the transmit length and status
//
LengthInBytes = pPacket - > Op . Tcp6Tx . TxData . DataLength ;
pSocket - > TxOobBytes - = LengthInBytes ;
Status = pIo - > Token . Tcp6Tx . CompletionToken . Status ;
//
// Complete the transmit operation
//
EslSocketTxComplete ( pIo ,
LengthInBytes ,
Status ,
" Urgent " ,
& pSocket - > pTxOobPacketListHead ,
& pSocket - > pTxOobPacketListTail ,
& pPort - > pTxOobActive ,
& pPort - > pTxOobFree ) ;
DBG_EXIT ( ) ;
}
/**
Interface between the socket layer and the network specific
code that supports SOCK_STREAM and SOCK_SEQPACKET sockets
over TCPv6 .
* */
CONST ESL_PROTOCOL_API cEslTcp6Api = {
" TCPv6 " ,
IPPROTO_TCP ,
OFFSET_OF ( ESL_PORT , Context . Tcp6 . ConfigData ) ,
OFFSET_OF ( ESL_LAYER , pTcp6List ) ,
sizeof ( struct sockaddr_in6 ) ,
sizeof ( struct sockaddr_in6 ) ,
AF_INET6 ,
sizeof ( ( ( ESL_PACKET * ) 0 ) - > Op . Tcp6Rx ) ,
OFFSET_OF ( ESL_PACKET , Op . Tcp6Rx . Buffer ) - OFFSET_OF ( ESL_PACKET , Op ) ,
OFFSET_OF ( ESL_IO_MGMT , Token . Tcp6Rx . Packet . RxData ) ,
TRUE ,
EADDRINUSE ,
EslTcp6Accept ,
EslTcp6ConnectPoll ,
EslTcp6ConnectStart ,
EslTcp6SocketIsConfigured ,
EslTcp6LocalAddressGet ,
EslTcp6LocalAddressSet ,
EslTcp6Listen ,
NULL , // OptionGet
NULL , // OptionSet
EslTcp6PacketFree ,
EslTcp6PortAllocate ,
EslTcp6PortClose ,
EslTcp6PortCloseOp ,
FALSE ,
EslTcp6Receive ,
EslTcp6RemoteAddressGet ,
EslTcp6RemoteAddressSet ,
EslTcp6RxComplete ,
EslTcp6RxStart ,
EslTcp6TxBuffer ,
EslTcp6TxComplete ,
EslTcp6TxOobComplete
} ;