Removed variables that had no effect on code behavior. Fifo.c::FIFO_Dequeue: Replaced instances of "Self->ElementSize" with preexisting variable "SizeOfElement". IIOutilities.c::IIO_GetInChar: Fixed variable of wrong, but compatible, type and made updating of housekeeping variables dependent upon successful completion of reading from the buffer. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Olivier Martin <olivier.martin@arm.com> Reviewed by: Daryl McDaniel <daryl.mcdaniel@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@16276 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			2597 lines
		
	
	
		
			80 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			2597 lines
		
	
	
		
			80 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  Implement the TCP6 driver support for the socket layer.
 | 
						|
 | 
						|
  Copyright (c) 2011 - 2014, Intel Corporation. All rights reserved.<BR>
 | 
						|
  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 ));
 | 
						|
 | 
						|
    //
 | 
						|
    //  Start the receive operations
 | 
						|
    //
 | 
						|
    pSocket->bConfigured = TRUE;
 | 
						|
    pSocket->State = SOCKET_STATE_CONNECTED;
 | 
						|
    EslSocketRxStart ( pPort );
 | 
						|
 | 
						|
    //
 | 
						|
    //  Remove the rest of the ports
 | 
						|
    //
 | 
						|
    bRemovePorts = TRUE;
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    //
 | 
						|
    //  The connection failed
 | 
						|
    //
 | 
						|
    if ( pPort->bConfigured ) {
 | 
						|
      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 ) {
 | 
						|
      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 = ECONNABORTED;
 | 
						|
        break;
 | 
						|
 | 
						|
      case EFI_ACCESS_DENIED:
 | 
						|
        pSocket->errno = EACCES;
 | 
						|
        break;
 | 
						|
 | 
						|
      case EFI_CONNECTION_RESET:
 | 
						|
        pSocket->errno = ECONNRESET;
 | 
						|
        break;
 | 
						|
 | 
						|
      case EFI_INVALID_PARAMETER:
 | 
						|
        pSocket->errno = EADDRNOTAVAIL;
 | 
						|
        break;
 | 
						|
 | 
						|
      case EFI_HOST_UNREACHABLE:
 | 
						|
      case EFI_NO_RESPONSE:
 | 
						|
        pSocket->errno = EHOSTUNREACH;
 | 
						|
        break;
 | 
						|
 | 
						|
      case EFI_NO_MAPPING:
 | 
						|
        pSocket->errno = EAFNOSUPPORT;
 | 
						|
        break;
 | 
						|
 | 
						|
      case EFI_NO_MEDIA:
 | 
						|
      case EFI_NETWORK_UNREACHABLE:
 | 
						|
        pSocket->errno = ENETDOWN;
 | 
						|
        break;
 | 
						|
 | 
						|
      case EFI_OUT_OF_RESOURCES:
 | 
						|
        pSocket->errno = ENOBUFS;
 | 
						|
        break;
 | 
						|
 | 
						|
      case EFI_PORT_UNREACHABLE:
 | 
						|
      case EFI_PROTOCOL_UNREACHABLE:
 | 
						|
      case EFI_CONNECTION_REFUSED:
 | 
						|
        pSocket->errno = ECONNREFUSED;
 | 
						|
        break;
 | 
						|
 | 
						|
      case EFI_SUCCESS:
 | 
						|
        pSocket->errno = 0;
 | 
						|
        break;
 | 
						|
 | 
						|
      case EFI_TIMEOUT:
 | 
						|
        pSocket->errno = ETIMEDOUT;
 | 
						|
        break;
 | 
						|
 | 
						|
      case EFI_UNSUPPORTED:
 | 
						|
        pSocket->errno = EOPNOTSUPP;
 | 
						|
        break;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    //  Display the translation
 | 
						|
    //
 | 
						|
    DEBUG (( DEBUG_CONNECT,
 | 
						|
              "ERROR - errno: %d, Status: %r\r\n",
 | 
						|
              pSocket->errno,
 | 
						|
              Status ));
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  //  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_SIMPLE_NETWORK_MODE SnpModeData;
 | 
						|
  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 ));
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      DEBUG (( DEBUG_CONNECT,
 | 
						|
                "0x%08x: Port configured\r\n",
 | 
						|
                pPort ));
 | 
						|
      pPort->bConfigured = TRUE;
 | 
						|
 | 
						|
      //
 | 
						|
      //  Verify the port connection
 | 
						|
      //
 | 
						|
      Status = pTcp6Protocol->GetModeData ( pTcp6Protocol,
 | 
						|
                                            NULL,
 | 
						|
                                            NULL,
 | 
						|
                                            NULL,
 | 
						|
                                            NULL,
 | 
						|
                                            &SnpModeData );
 | 
						|
      if ( !EFI_ERROR ( Status )) {
 | 
						|
        if ( SnpModeData.MediaPresentSupported
 | 
						|
          && ( !SnpModeData.MediaPresent )) {
 | 
						|
          //
 | 
						|
          //  Port is not connected to the network
 | 
						|
          //
 | 
						|
          Status = EFI_NO_MEDIA;
 | 
						|
        }
 | 
						|
        else {
 | 
						|
          //
 | 
						|
          //  Attempt the connection to the remote system
 | 
						|
          //
 | 
						|
          Status = pTcp6Protocol->Connect ( pTcp6Protocol,
 | 
						|
                                            &pTcp6->ConnectToken );
 | 
						|
        }
 | 
						|
      }
 | 
						|
      if ( EFI_ERROR ( Status )) {
 | 
						|
        //
 | 
						|
        //  Connection error
 | 
						|
        //
 | 
						|
        DEBUG (( DEBUG_CONNECT,
 | 
						|
                  "ERROR - Port 0x%08x not connected, Status: %r\r\n",
 | 
						|
                  pPort,
 | 
						|
                  Status ));
 | 
						|
      }
 | 
						|
    }
 | 
						|
    if ( !EFI_ERROR ( Status )) {
 | 
						|
      //
 | 
						|
      //  Connection in progress
 | 
						|
      //
 | 
						|
      pSocket->errno = EINPROGRESS;
 | 
						|
      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 {
 | 
						|
      //
 | 
						|
      //  Error return path is through EslTcp6ConnectComplete to
 | 
						|
      //  enable retry on other ports
 | 
						|
      //
 | 
						|
      //  Status to errno translation gets done in EslTcp4ConnectPoll
 | 
						|
      //
 | 
						|
      pTcp6->ConnectToken.CompletionToken.Status = Status;
 | 
						|
 | 
						|
      //
 | 
						|
      //  Continue with the next port
 | 
						|
      //
 | 
						|
      gBS->CheckEvent ( pTcp6->ConnectToken.CompletionToken.Event );
 | 
						|
      gBS->SignalEvent ( pTcp6->ConnectToken.CompletionToken.Event );
 | 
						|
    }
 | 
						|
    Status = EFI_NOT_READY;
 | 
						|
  }
 | 
						|
  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;
 | 
						|
    Status = EFI_SUCCESS;
 | 
						|
    pSocket->errno = 0;
 | 
						|
 | 
						|
    //
 | 
						|
    //  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_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;
 | 
						|
    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 );
 | 
						|
      pPort->pSocket->bAddressSet = TRUE;
 | 
						|
 | 
						|
      //
 | 
						|
      //  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 );
 | 
						|
 | 
						|
  //
 | 
						|
  //  Set the next buffer address
 | 
						|
  //
 | 
						|
  pBuffer += DataLength;
 | 
						|
 | 
						|
  //
 | 
						|
  //  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;
 | 
						|
  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
 | 
						|
      //
 | 
						|
      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\n0x%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\nTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT\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 ( );
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Verify the adapter's IP address
 | 
						|
 | 
						|
  This support routine is called by EslSocketBindTest.
 | 
						|
 | 
						|
  @param [in] pPort       Address of an ::ESL_PORT structure.
 | 
						|
  @param [in] pConfigData Address of the configuration data
 | 
						|
 | 
						|
  @retval EFI_SUCCESS - The IP address is valid
 | 
						|
  @retval EFI_NOT_STARTED - The IP address is invalid
 | 
						|
 | 
						|
 **/
 | 
						|
EFI_STATUS
 | 
						|
EslTcp6VerifyLocalIpAddress (
 | 
						|
  IN ESL_PORT * pPort,
 | 
						|
  IN EFI_TCP6_CONFIG_DATA * pConfigData
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN AddressCount;
 | 
						|
  EFI_IP6_ADDRESS_INFO * pAddressInfo;
 | 
						|
  UINTN DataSize;
 | 
						|
  EFI_TCP6_ACCESS_POINT * pAccess;
 | 
						|
  EFI_IP6_CONFIG_INTERFACE_INFO * pIpConfigData;
 | 
						|
  EFI_IP6_CONFIG_PROTOCOL * pIpConfigProtocol;
 | 
						|
  ESL_SERVICE * pService;
 | 
						|
  EFI_STATUS Status;
 | 
						|
 | 
						|
  DBG_ENTER ( );
 | 
						|
 | 
						|
  //
 | 
						|
  //  Use break instead of goto
 | 
						|
  //
 | 
						|
  pIpConfigData = NULL;
 | 
						|
  for ( ; ; ) {
 | 
						|
    //
 | 
						|
    //  Determine if the IP address is specified
 | 
						|
    //
 | 
						|
    pAccess = &pConfigData->AccessPoint;
 | 
						|
    DEBUG (( DEBUG_BIND,
 | 
						|
              "Requested IP address: %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x\r\n",
 | 
						|
              pAccess->StationAddress.Addr[0],
 | 
						|
              pAccess->StationAddress.Addr[1],
 | 
						|
              pAccess->StationAddress.Addr[2],
 | 
						|
              pAccess->StationAddress.Addr[3],
 | 
						|
              pAccess->StationAddress.Addr[4],
 | 
						|
              pAccess->StationAddress.Addr[5],
 | 
						|
              pAccess->StationAddress.Addr[6],
 | 
						|
              pAccess->StationAddress.Addr[7],
 | 
						|
              pAccess->StationAddress.Addr[8],
 | 
						|
              pAccess->StationAddress.Addr[9],
 | 
						|
              pAccess->StationAddress.Addr[10],
 | 
						|
              pAccess->StationAddress.Addr[11],
 | 
						|
              pAccess->StationAddress.Addr[12],
 | 
						|
              pAccess->StationAddress.Addr[13],
 | 
						|
              pAccess->StationAddress.Addr[14],
 | 
						|
              pAccess->StationAddress.Addr[15]));
 | 
						|
    if (( 0 == pAccess->StationAddress.Addr [ 0 ])
 | 
						|
      && ( 0 == pAccess->StationAddress.Addr [ 1 ])
 | 
						|
      && ( 0 == pAccess->StationAddress.Addr [ 2 ])
 | 
						|
      && ( 0 == pAccess->StationAddress.Addr [ 3 ])
 | 
						|
      && ( 0 == pAccess->StationAddress.Addr [ 4 ])
 | 
						|
      && ( 0 == pAccess->StationAddress.Addr [ 5 ])
 | 
						|
      && ( 0 == pAccess->StationAddress.Addr [ 6 ])
 | 
						|
      && ( 0 == pAccess->StationAddress.Addr [ 7 ])
 | 
						|
      && ( 0 == pAccess->StationAddress.Addr [ 8 ])
 | 
						|
      && ( 0 == pAccess->StationAddress.Addr [ 9 ])
 | 
						|
      && ( 0 == pAccess->StationAddress.Addr [ 10 ])
 | 
						|
      && ( 0 == pAccess->StationAddress.Addr [ 11 ])
 | 
						|
      && ( 0 == pAccess->StationAddress.Addr [ 12 ])
 | 
						|
      && ( 0 == pAccess->StationAddress.Addr [ 13 ])
 | 
						|
      && ( 0 == pAccess->StationAddress.Addr [ 14 ])
 | 
						|
      && ( 0 == pAccess->StationAddress.Addr [ 15 ]))
 | 
						|
    {
 | 
						|
      Status = EFI_SUCCESS;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    //  Open the configuration protocol
 | 
						|
    //
 | 
						|
    pService = pPort->pService;
 | 
						|
    Status = gBS->OpenProtocol ( pService->Controller,
 | 
						|
                                 &gEfiIp6ConfigProtocolGuid,
 | 
						|
                                 (VOID **)&pIpConfigProtocol,
 | 
						|
                                 NULL,
 | 
						|
                                 NULL,
 | 
						|
                                 EFI_OPEN_PROTOCOL_GET_PROTOCOL );
 | 
						|
    if ( EFI_ERROR ( Status )) {
 | 
						|
      DEBUG (( DEBUG_ERROR,
 | 
						|
                "ERROR - IP Configuration Protocol not available, Status: %r\r\n",
 | 
						|
                Status ));
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    //  Get the IP configuration data size
 | 
						|
    //
 | 
						|
    DataSize = 0;
 | 
						|
    Status = pIpConfigProtocol->GetData ( pIpConfigProtocol,
 | 
						|
                                          Ip6ConfigDataTypeInterfaceInfo,
 | 
						|
                                          &DataSize,
 | 
						|
                                          NULL );
 | 
						|
    if ( EFI_BUFFER_TOO_SMALL != Status ) {
 | 
						|
      DEBUG (( DEBUG_ERROR,
 | 
						|
                "ERROR - Failed to get IP Configuration data size, Status: %r\r\n",
 | 
						|
                Status ));
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    //  Allocate the configuration data buffer
 | 
						|
    //
 | 
						|
    pIpConfigData = AllocatePool ( DataSize );
 | 
						|
    if ( NULL == pIpConfigData ) {
 | 
						|
      DEBUG (( DEBUG_ERROR,
 | 
						|
                "ERROR - Not enough memory to allocate IP Configuration data!\r\n" ));
 | 
						|
      Status = EFI_OUT_OF_RESOURCES;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    //  Get the IP configuration
 | 
						|
    //
 | 
						|
    Status = pIpConfigProtocol->GetData ( pIpConfigProtocol,
 | 
						|
                                          Ip6ConfigDataTypeInterfaceInfo,
 | 
						|
                                          &DataSize,
 | 
						|
                                          pIpConfigData );
 | 
						|
    if ( EFI_ERROR ( Status )) {
 | 
						|
      DEBUG (( DEBUG_ERROR,
 | 
						|
                "ERROR - Failed to return IP Configuration data, Status: %r\r\n",
 | 
						|
                Status ));
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    //  Display the current configuration
 | 
						|
    //
 | 
						|
    DEBUG (( DEBUG_BIND,
 | 
						|
              "Actual adapter IP address: %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x\r\n",
 | 
						|
              pIpConfigData->HwAddress.Addr [ 0 ],
 | 
						|
              pIpConfigData->HwAddress.Addr [ 1 ],
 | 
						|
              pIpConfigData->HwAddress.Addr [ 2 ],
 | 
						|
              pIpConfigData->HwAddress.Addr [ 3 ],
 | 
						|
              pIpConfigData->HwAddress.Addr [ 4 ],
 | 
						|
              pIpConfigData->HwAddress.Addr [ 5 ],
 | 
						|
              pIpConfigData->HwAddress.Addr [ 6 ],
 | 
						|
              pIpConfigData->HwAddress.Addr [ 7 ],
 | 
						|
              pIpConfigData->HwAddress.Addr [ 8 ],
 | 
						|
              pIpConfigData->HwAddress.Addr [ 9 ],
 | 
						|
              pIpConfigData->HwAddress.Addr [ 10 ],
 | 
						|
              pIpConfigData->HwAddress.Addr [ 11 ],
 | 
						|
              pIpConfigData->HwAddress.Addr [ 12 ],
 | 
						|
              pIpConfigData->HwAddress.Addr [ 13 ],
 | 
						|
              pIpConfigData->HwAddress.Addr [ 14 ],
 | 
						|
              pIpConfigData->HwAddress.Addr [ 15 ]));
 | 
						|
 | 
						|
    //
 | 
						|
    //  Validate the hardware address
 | 
						|
    //
 | 
						|
    Status = EFI_SUCCESS;
 | 
						|
    if (( 16 == pIpConfigData->HwAddressSize )
 | 
						|
      && ( pAccess->StationAddress.Addr [ 0 ] == pIpConfigData->HwAddress.Addr [ 0 ])
 | 
						|
      && ( pAccess->StationAddress.Addr [ 1 ] == pIpConfigData->HwAddress.Addr [ 1 ])
 | 
						|
      && ( pAccess->StationAddress.Addr [ 2 ] == pIpConfigData->HwAddress.Addr [ 2 ])
 | 
						|
      && ( pAccess->StationAddress.Addr [ 3 ] == pIpConfigData->HwAddress.Addr [ 3 ])
 | 
						|
      && ( pAccess->StationAddress.Addr [ 4 ] == pIpConfigData->HwAddress.Addr [ 4 ])
 | 
						|
      && ( pAccess->StationAddress.Addr [ 5 ] == pIpConfigData->HwAddress.Addr [ 5 ])
 | 
						|
      && ( pAccess->StationAddress.Addr [ 6 ] == pIpConfigData->HwAddress.Addr [ 6 ])
 | 
						|
      && ( pAccess->StationAddress.Addr [ 7 ] == pIpConfigData->HwAddress.Addr [ 7 ])
 | 
						|
      && ( pAccess->StationAddress.Addr [ 8 ] == pIpConfigData->HwAddress.Addr [ 8 ])
 | 
						|
      && ( pAccess->StationAddress.Addr [ 9 ] == pIpConfigData->HwAddress.Addr [ 9 ])
 | 
						|
      && ( pAccess->StationAddress.Addr [ 10 ] == pIpConfigData->HwAddress.Addr [ 10 ])
 | 
						|
      && ( pAccess->StationAddress.Addr [ 11 ] == pIpConfigData->HwAddress.Addr [ 11 ])
 | 
						|
      && ( pAccess->StationAddress.Addr [ 12 ] == pIpConfigData->HwAddress.Addr [ 12 ])
 | 
						|
      && ( pAccess->StationAddress.Addr [ 13 ] == pIpConfigData->HwAddress.Addr [ 13 ])
 | 
						|
      && ( pAccess->StationAddress.Addr [ 14 ] == pIpConfigData->HwAddress.Addr [ 14 ])
 | 
						|
      && ( pAccess->StationAddress.Addr [ 15 ] == pIpConfigData->HwAddress.Addr [ 15 ])) {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    //  Walk the list of other IP addresses assigned to this adapter
 | 
						|
    //
 | 
						|
    for ( AddressCount = 0; pIpConfigData->AddressInfoCount > AddressCount; AddressCount += 1 ) {
 | 
						|
      pAddressInfo = &pIpConfigData->AddressInfo [ AddressCount ];
 | 
						|
 | 
						|
      //
 | 
						|
      //  Display the IP address
 | 
						|
      //
 | 
						|
      DEBUG (( DEBUG_BIND,
 | 
						|
                "Actual adapter IP address: %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x\r\n",
 | 
						|
                pAddressInfo->Address.Addr [ 0 ],
 | 
						|
                pAddressInfo->Address.Addr [ 1 ],
 | 
						|
                pAddressInfo->Address.Addr [ 2 ],
 | 
						|
                pAddressInfo->Address.Addr [ 3 ],
 | 
						|
                pAddressInfo->Address.Addr [ 4 ],
 | 
						|
                pAddressInfo->Address.Addr [ 5 ],
 | 
						|
                pAddressInfo->Address.Addr [ 6 ],
 | 
						|
                pAddressInfo->Address.Addr [ 7 ],
 | 
						|
                pAddressInfo->Address.Addr [ 8 ],
 | 
						|
                pAddressInfo->Address.Addr [ 9 ],
 | 
						|
                pAddressInfo->Address.Addr [ 10 ],
 | 
						|
                pAddressInfo->Address.Addr [ 11 ],
 | 
						|
                pAddressInfo->Address.Addr [ 12 ],
 | 
						|
                pAddressInfo->Address.Addr [ 13 ],
 | 
						|
                pAddressInfo->Address.Addr [ 14 ],
 | 
						|
                pAddressInfo->Address.Addr [ 15 ]));
 | 
						|
 | 
						|
      //
 | 
						|
      //  Validate the IP address
 | 
						|
      //
 | 
						|
      if (( pAccess->StationAddress.Addr [ 0 ] == pAddressInfo->Address.Addr [ 0 ])
 | 
						|
        && ( pAccess->StationAddress.Addr [ 1 ] == pAddressInfo->Address.Addr [ 1 ])
 | 
						|
        && ( pAccess->StationAddress.Addr [ 2 ] == pAddressInfo->Address.Addr [ 2 ])
 | 
						|
        && ( pAccess->StationAddress.Addr [ 3 ] == pAddressInfo->Address.Addr [ 3 ])
 | 
						|
        && ( pAccess->StationAddress.Addr [ 4 ] == pAddressInfo->Address.Addr [ 4 ])
 | 
						|
        && ( pAccess->StationAddress.Addr [ 5 ] == pAddressInfo->Address.Addr [ 5 ])
 | 
						|
        && ( pAccess->StationAddress.Addr [ 6 ] == pAddressInfo->Address.Addr [ 6 ])
 | 
						|
        && ( pAccess->StationAddress.Addr [ 7 ] == pAddressInfo->Address.Addr [ 7 ])
 | 
						|
        && ( pAccess->StationAddress.Addr [ 8 ] == pAddressInfo->Address.Addr [ 8 ])
 | 
						|
        && ( pAccess->StationAddress.Addr [ 9 ] == pAddressInfo->Address.Addr [ 9 ])
 | 
						|
        && ( pAccess->StationAddress.Addr [ 10 ] == pAddressInfo->Address.Addr [ 10 ])
 | 
						|
        && ( pAccess->StationAddress.Addr [ 11 ] == pAddressInfo->Address.Addr [ 11 ])
 | 
						|
        && ( pAccess->StationAddress.Addr [ 12 ] == pAddressInfo->Address.Addr [ 12 ])
 | 
						|
        && ( pAccess->StationAddress.Addr [ 13 ] == pAddressInfo->Address.Addr [ 13 ])
 | 
						|
        && ( pAccess->StationAddress.Addr [ 14 ] == pAddressInfo->Address.Addr [ 14 ])
 | 
						|
        && ( pAccess->StationAddress.Addr [ 15 ] == pAddressInfo->Address.Addr [ 15 ])) {
 | 
						|
        break;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    if ( pIpConfigData->AddressInfoCount > AddressCount ) {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    //  The IP address did not match
 | 
						|
    //
 | 
						|
    Status = EFI_NOT_STARTED;
 | 
						|
    break;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  //  Free the buffer if necessary
 | 
						|
  //
 | 
						|
  if ( NULL != pIpConfigData ) {
 | 
						|
    FreePool ( pIpConfigData );
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  //  Return the IP address status
 | 
						|
  //
 | 
						|
  DBG_EXIT_STATUS ( Status );
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  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,
 | 
						|
  (PFN_API_VERIFY_LOCAL_IP_ADDRESS)EslTcp6VerifyLocalIpAddress
 | 
						|
};
 |