Home | History | Annotate | Download | only in EfiSocketLib
      1 /** @file
      2   Implement the TCP6 driver support for the socket layer.
      3 
      4   Copyright (c) 2011 - 2014, Intel Corporation. All rights reserved.<BR>
      5   This program and the accompanying materials are licensed and made available
      6   under the terms and conditions of the BSD License which accompanies this
      7   distribution.  The full text of the license may be found at
      8   http://opensource.org/licenses/bsd-license.php.
      9 
     10   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 
     14   \section ConnectionManagement Connection Management
     15 
     16   The ::EslTcp6Listen routine initially places the SOCK_STREAM or
     17   SOCK_SEQPACKET socket into a listen state.   When a remote machine
     18   makes a connection to the socket, the TCPv6 network layer calls
     19   ::EslTcp6ListenComplete to complete the connection processing.
     20   EslTcp6ListenComplete manages the connections by placing them in
     21   FIFO order in a queue to be serviced by the application.  When the
     22   number of connections exceeds the backlog (ESL_SOCKET::MaxFifoDepth),
     23   the new connection is closed.  Eventually, the application indirectly
     24   calls ::EslTcp6Accept to remove the next connection from the queue
     25   and get the associated socket.
     26 
     27 **/
     28 
     29 #include "Socket.h"
     30 
     31 
     32 /**
     33   Attempt to connect to a remote TCP port
     34 
     35   This routine starts the connection processing for a SOCK_STREAM
     36   or SOCK_SEQPAKCET socket using the TCPv6 network layer.  It
     37   configures the local TCPv6 connection point and then attempts to
     38   connect to a remote system.  Upon completion, the
     39   ::EslTcp6ConnectComplete routine gets called with the connection
     40   status.
     41 
     42   This routine is called by ::EslSocketConnect to initiate the TCPv6
     43   network specific connect operations.  The connection processing is
     44   initiated by this routine and finished by ::EslTcp6ConnectComplete.
     45   This pair of routines walks through the list of local TCPv6
     46   connection points until a connection to the remote system is
     47   made.
     48 
     49   @param [in] pSocket   Address of an ::ESL_SOCKET structure.
     50 
     51   @retval EFI_SUCCESS   The connection was successfully established.
     52   @retval EFI_NOT_READY The connection is in progress, call this routine again.
     53   @retval Others        The connection attempt failed.
     54 
     55  **/
     56 EFI_STATUS
     57 EslTcp6ConnectStart (
     58   IN ESL_SOCKET * pSocket
     59   );
     60 
     61 
     62 /**
     63   Process the connection attempt
     64 
     65   A system has initiated a connection attempt with a socket in the
     66   listen state.  Attempt to complete the connection.
     67 
     68   The TCPv6 layer calls this routine when a connection is made to
     69   the socket in the listen state.  See the
     70   \ref ConnectionManagement section.
     71 
     72   @param [in] Event     The listen completion event
     73 
     74   @param [in] pPort     Address of an ::ESL_PORT structure.
     75 
     76 **/
     77 VOID
     78 EslTcp6ListenComplete (
     79   IN EFI_EVENT Event,
     80   IN ESL_PORT * pPort
     81   );
     82 
     83 
     84 /**
     85   Accept a network connection.
     86 
     87   This routine waits for a network connection to the socket and
     88   returns the remote network address to the caller if requested.
     89 
     90   This routine is called by ::EslSocketAccept to handle the TCPv6 protocol
     91   specific accept operations for SOCK_STREAM and SOCK_SEQPACKET sockets.
     92   See the \ref ConnectionManagement section.
     93 
     94   @param [in] pSocket   Address of an ::ESL_SOCKET structure.
     95 
     96   @param [in] pSockAddr       Address of a buffer to receive the remote
     97                               network address.
     98 
     99   @param [in, out] pSockAddrLength  Length in bytes of the address buffer.
    100                                     On output specifies the length of the
    101                                     remote network address.
    102 
    103   @retval EFI_SUCCESS   Remote address is available
    104   @retval Others        Remote address not available
    105 
    106  **/
    107 EFI_STATUS
    108 EslTcp6Accept (
    109   IN ESL_SOCKET * pSocket,
    110   IN struct sockaddr * pSockAddr,
    111   IN OUT socklen_t * pSockAddrLength
    112   )
    113 {
    114   ESL_PORT * pPort;
    115   struct sockaddr_in6 * pRemoteAddress;
    116   ESL_TCP6_CONTEXT * pTcp6;
    117   EFI_STATUS Status;
    118 
    119   DBG_ENTER ( );
    120 
    121   //
    122   //  Validate the socket length
    123   //
    124   pRemoteAddress = (struct sockaddr_in6 *) pSockAddr;
    125   if (( NULL == pSockAddrLength )
    126     || ( sizeof ( *pRemoteAddress ) > *pSockAddrLength )) {
    127     //
    128     //  Invalid socket address
    129     //
    130     Status = EFI_INVALID_PARAMETER;
    131     pSocket->errno = EINVAL;
    132     DEBUG (( DEBUG_ACCEPT,
    133               "ERROR - Invalid address length\r\n" ));
    134   }
    135   else {
    136     //
    137     //  Assume success
    138     //
    139     Status = EFI_SUCCESS;
    140 
    141     //
    142     //  Locate the address context
    143     //
    144     pPort = pSocket->pPortList;
    145     pTcp6 = &pPort->Context.Tcp6;
    146 
    147     //
    148     //  Fill-in the remote address structure
    149     //
    150     ZeroMem ( pRemoteAddress, sizeof ( *pRemoteAddress ));
    151     pRemoteAddress->sin6_len = sizeof ( *pRemoteAddress );
    152     pRemoteAddress->sin6_family = AF_INET6;
    153     pRemoteAddress->sin6_port = SwapBytes16 ( pTcp6->ConfigData.AccessPoint.RemotePort );
    154     CopyMem ( &pRemoteAddress->sin6_addr.__u6_addr.__u6_addr8 [ 0 ],
    155               &pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[0],
    156               sizeof ( pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr ));
    157   }
    158 
    159   //
    160   //  Return the operation status
    161   //
    162   DBG_EXIT_STATUS ( Status );
    163   return Status;
    164 }
    165 
    166 
    167 /**
    168   Process the remote connection completion event.
    169 
    170   This routine handles the completion of a connection attempt.  It
    171   releases the port (TCPv6 adapter connection) in the case of an
    172   error and start a connection attempt on the next port.  If the
    173   connection attempt was successful then this routine releases all
    174   of the other ports.
    175 
    176   This routine is called by the TCPv6 layer when a connect request
    177   completes.  It sets the ESL_SOCKET::bConnected flag to notify the
    178   ::EslTcp6ConnectComplete routine that the connection is available.
    179   The flag is set when the connection is established or no more ports
    180   exist in the list.  The connection status is passed via
    181   ESL_SOCKET::ConnectStatus.
    182 
    183   @param [in] Event     The connect completion event
    184 
    185   @param [in] pPort     Address of an ::ESL_PORT structure.
    186 
    187 **/
    188 VOID
    189 EslTcp6ConnectComplete (
    190   IN EFI_EVENT Event,
    191   IN ESL_PORT * pPort
    192   )
    193 {
    194   BOOLEAN bRemoveFirstPort;
    195   BOOLEAN bRemovePorts;
    196   ESL_PORT * pNextPort;
    197   ESL_SOCKET * pSocket;
    198   ESL_TCP6_CONTEXT * pTcp6;
    199   EFI_STATUS Status;
    200 
    201   DBG_ENTER ( );
    202 
    203   //
    204   //  Locate the TCP context
    205   //
    206   pSocket = pPort->pSocket;
    207   pTcp6 = &pPort->Context.Tcp6;
    208 
    209   //
    210   //  Get the connection status
    211   //
    212   bRemoveFirstPort = FALSE;
    213   bRemovePorts = FALSE;
    214   Status = pTcp6->ConnectToken.CompletionToken.Status;
    215   pSocket->ConnectStatus = Status;
    216   if ( !EFI_ERROR ( Status )) {
    217     //
    218     //  The connection was successful
    219     //
    220     DEBUG (( DEBUG_CONNECT,
    221               "0x%08x: Port connected to [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d\r\n",
    222               pPort,
    223               pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[0],
    224               pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[1],
    225               pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[2],
    226               pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[3],
    227               pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[4],
    228               pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[5],
    229               pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[6],
    230               pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[7],
    231               pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[8],
    232               pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[9],
    233               pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[10],
    234               pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[11],
    235               pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[12],
    236               pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[13],
    237               pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[14],
    238               pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[15],
    239               pTcp6->ConfigData.AccessPoint.RemotePort ));
    240 
    241     //
    242     //  Start the receive operations
    243     //
    244     pSocket->bConfigured = TRUE;
    245     pSocket->State = SOCKET_STATE_CONNECTED;
    246     EslSocketRxStart ( pPort );
    247 
    248     //
    249     //  Remove the rest of the ports
    250     //
    251     bRemovePorts = TRUE;
    252   }
    253   else {
    254     //
    255     //  The connection failed
    256     //
    257     if ( pPort->bConfigured ) {
    258       DEBUG (( DEBUG_CONNECT,
    259                 "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",
    260                 pPort,
    261                 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[0],
    262                 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[1],
    263                 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[2],
    264                 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[3],
    265                 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[4],
    266                 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[5],
    267                 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[6],
    268                 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[7],
    269                 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[8],
    270                 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[9],
    271                 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[10],
    272                 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[11],
    273                 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[12],
    274                 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[13],
    275                 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[14],
    276                 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[15],
    277                 pTcp6->ConfigData.AccessPoint.RemotePort,
    278                 Status ));
    279     }
    280 
    281     //
    282     //  Close the current port
    283     //
    284     Status = EslSocketPortClose ( pPort );
    285     if ( !EFI_ERROR ( Status )) {
    286       DEBUG (( DEBUG_CONNECT,
    287               "0x%08x: Port closed\r\n",
    288               pPort ));
    289     }
    290     else {
    291       DEBUG (( DEBUG_CONNECT,
    292                 "ERROR - Failed to close port 0x%08x, Status: %r\r\n",
    293                 pPort,
    294                 Status ));
    295     }
    296 
    297     //
    298     //  Try to connect using the next port
    299     //
    300     Status = EslTcp6ConnectStart ( pSocket );
    301     if ( EFI_NOT_READY != Status ) {
    302       bRemoveFirstPort = TRUE;
    303     }
    304   }
    305 
    306   //
    307   //  Remove the ports if necessary
    308   //
    309   if ( bRemoveFirstPort || bRemovePorts ) {
    310     //
    311     //  Remove the first port if necessary
    312     //
    313     pPort = pSocket->pPortList;
    314     if (( !bRemoveFirstPort ) && ( NULL != pPort )) {
    315       pPort = pPort->pLinkSocket;
    316     }
    317 
    318     //
    319     //  Remove the rest of the list
    320     //
    321     while ( NULL != pPort ) {
    322       pNextPort = pPort->pLinkSocket;
    323       EslSocketPortClose ( pPort );
    324       if ( !EFI_ERROR ( Status )) {
    325         DEBUG (( DEBUG_CONNECT,
    326                 "0x%08x: Port closed\r\n",
    327                 pPort ));
    328       }
    329       else {
    330         DEBUG (( DEBUG_CONNECT,
    331                   "ERROR - Failed to close port 0x%08x, Status: %r\r\n",
    332                   pPort,
    333                   Status ));
    334       }
    335       pPort = pNextPort;
    336     }
    337 
    338     //
    339     //  Notify the poll routine
    340     //
    341     pSocket->bConnected = TRUE;
    342   }
    343 
    344   DBG_EXIT ( );
    345 }
    346 
    347 
    348 /**
    349   Poll for completion of the connection attempt.
    350 
    351   This routine polls the ESL_SOCKET::bConnected flag to determine
    352   when the connection attempt is complete.
    353 
    354   This routine is called from ::EslSocketConnect to determine when
    355   the connection is complete.  The ESL_SOCKET::bConnected flag is
    356   set by ::EslTcp6ConnectComplete when the TCPv6 layer establishes
    357   a connection or runs out of local network adapters.  This routine
    358   gets the connection status from ESL_SOCKET::ConnectStatus.
    359 
    360   @param [in] pSocket   Address of an ::ESL_SOCKET structure.
    361 
    362   @retval EFI_SUCCESS   The connection was successfully established.
    363   @retval EFI_NOT_READY The connection is in progress, call this routine again.
    364   @retval Others        The connection attempt failed.
    365 
    366  **/
    367 EFI_STATUS
    368 EslTcp6ConnectPoll (
    369   IN ESL_SOCKET * pSocket
    370   )
    371 {
    372   EFI_STATUS Status;
    373 
    374   DBG_ENTER ( );
    375 
    376   //
    377   //  Determine if the connection is complete
    378   //
    379   if ( !pSocket->bConnected ) {
    380     //
    381     //  Not connected
    382     //
    383     pSocket->errno = EAGAIN;
    384     Status = EFI_NOT_READY;
    385   }
    386   else {
    387     //
    388     //  The connection processing is complete
    389     //
    390     pSocket->bConnected = FALSE;
    391 
    392     //
    393     //  Translate the connection status
    394     //
    395     Status = pSocket->ConnectStatus;
    396     switch ( Status ) {
    397       default:
    398       case EFI_DEVICE_ERROR:
    399         pSocket->errno = EIO;
    400         break;
    401 
    402       case EFI_ABORTED:
    403         pSocket->errno = ECONNABORTED;
    404         break;
    405 
    406       case EFI_ACCESS_DENIED:
    407         pSocket->errno = EACCES;
    408         break;
    409 
    410       case EFI_CONNECTION_RESET:
    411         pSocket->errno = ECONNRESET;
    412         break;
    413 
    414       case EFI_INVALID_PARAMETER:
    415         pSocket->errno = EADDRNOTAVAIL;
    416         break;
    417 
    418       case EFI_HOST_UNREACHABLE:
    419       case EFI_NO_RESPONSE:
    420         pSocket->errno = EHOSTUNREACH;
    421         break;
    422 
    423       case EFI_NO_MAPPING:
    424         pSocket->errno = EAFNOSUPPORT;
    425         break;
    426 
    427       case EFI_NO_MEDIA:
    428       case EFI_NETWORK_UNREACHABLE:
    429         pSocket->errno = ENETDOWN;
    430         break;
    431 
    432       case EFI_OUT_OF_RESOURCES:
    433         pSocket->errno = ENOBUFS;
    434         break;
    435 
    436       case EFI_PORT_UNREACHABLE:
    437       case EFI_PROTOCOL_UNREACHABLE:
    438       case EFI_CONNECTION_REFUSED:
    439         pSocket->errno = ECONNREFUSED;
    440         break;
    441 
    442       case EFI_SUCCESS:
    443         pSocket->errno = 0;
    444         break;
    445 
    446       case EFI_TIMEOUT:
    447         pSocket->errno = ETIMEDOUT;
    448         break;
    449 
    450       case EFI_UNSUPPORTED:
    451         pSocket->errno = EOPNOTSUPP;
    452         break;
    453     }
    454 
    455     //
    456     //  Display the translation
    457     //
    458     DEBUG (( DEBUG_CONNECT,
    459               "ERROR - errno: %d, Status: %r\r\n",
    460               pSocket->errno,
    461               Status ));
    462   }
    463 
    464   //
    465   //  Return the initialization status
    466   //
    467   DBG_EXIT_STATUS ( Status );
    468   return Status;
    469 }
    470 
    471 
    472 /**
    473   Attempt to connect to a remote TCP port
    474 
    475   This routine starts the connection processing for a SOCK_STREAM
    476   or SOCK_SEQPAKCET socket using the TCPv6 network layer.  It
    477   configures the local TCPv6 connection point and then attempts to
    478   connect to a remote system.  Upon completion, the
    479   ::EslTcp6ConnectComplete routine gets called with the connection
    480   status.
    481 
    482   This routine is called by ::EslSocketConnect to initiate the TCPv6
    483   network specific connect operations.  The connection processing is
    484   initiated by this routine and finished by ::EslTcp6ConnectComplete.
    485   This pair of routines walks through the list of local TCPv6
    486   connection points until a connection to the remote system is
    487   made.
    488 
    489   @param [in] pSocket   Address of an ::ESL_SOCKET structure.
    490 
    491   @retval EFI_SUCCESS   The connection was successfully established.
    492   @retval EFI_NOT_READY The connection is in progress, call this routine again.
    493   @retval Others        The connection attempt failed.
    494 
    495  **/
    496 EFI_STATUS
    497 EslTcp6ConnectStart (
    498   IN ESL_SOCKET * pSocket
    499   )
    500 {
    501   ESL_PORT * pPort;
    502   ESL_TCP6_CONTEXT * pTcp6;
    503   EFI_TCP6_PROTOCOL * pTcp6Protocol;
    504   EFI_SIMPLE_NETWORK_MODE SnpModeData;
    505   EFI_STATUS Status;
    506 
    507   DBG_ENTER ( );
    508 
    509   //
    510   //  Determine if any more local adapters are available
    511   //
    512   pPort = pSocket->pPortList;
    513   if ( NULL != pPort ) {
    514     //
    515     //  Configure the port
    516     //
    517     pTcp6 = &pPort->Context.Tcp6;
    518     pTcp6->ConfigData.AccessPoint.ActiveFlag = TRUE;
    519     pTcp6->ConfigData.TrafficClass = 0;
    520     pTcp6->ConfigData.HopLimit = 255;
    521     pTcp6Protocol = pPort->pProtocol.TCPv6;
    522     Status = pTcp6Protocol->Configure ( pTcp6Protocol,
    523                                         &pTcp6->ConfigData );
    524     if ( EFI_ERROR ( Status )) {
    525       DEBUG (( DEBUG_CONNECT,
    526                 "ERROR - Failed to configure the Tcp6 port, Status: %r\r\n",
    527                 Status ));
    528     }
    529     else {
    530       DEBUG (( DEBUG_CONNECT,
    531                 "0x%08x: Port configured\r\n",
    532                 pPort ));
    533       pPort->bConfigured = TRUE;
    534 
    535       //
    536       //  Verify the port connection
    537       //
    538       Status = pTcp6Protocol->GetModeData ( pTcp6Protocol,
    539                                             NULL,
    540                                             NULL,
    541                                             NULL,
    542                                             NULL,
    543                                             &SnpModeData );
    544       if ( !EFI_ERROR ( Status )) {
    545         if ( SnpModeData.MediaPresentSupported
    546           && ( !SnpModeData.MediaPresent )) {
    547           //
    548           //  Port is not connected to the network
    549           //
    550           Status = EFI_NO_MEDIA;
    551         }
    552         else {
    553           //
    554           //  Attempt the connection to the remote system
    555           //
    556           Status = pTcp6Protocol->Connect ( pTcp6Protocol,
    557                                             &pTcp6->ConnectToken );
    558         }
    559       }
    560       if ( EFI_ERROR ( Status )) {
    561         //
    562         //  Connection error
    563         //
    564         DEBUG (( DEBUG_CONNECT,
    565                   "ERROR - Port 0x%08x not connected, Status: %r\r\n",
    566                   pPort,
    567                   Status ));
    568       }
    569     }
    570     if ( !EFI_ERROR ( Status )) {
    571       //
    572       //  Connection in progress
    573       //
    574       pSocket->errno = EINPROGRESS;
    575       DEBUG (( DEBUG_CONNECT,
    576                 "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",
    577                 pPort,
    578                 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[0],
    579                 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[1],
    580                 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[2],
    581                 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[3],
    582                 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[4],
    583                 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[5],
    584                 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[6],
    585                 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[7],
    586                 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[8],
    587                 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[9],
    588                 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[10],
    589                 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[11],
    590                 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[12],
    591                 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[13],
    592                 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[14],
    593                 pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[15],
    594                 pTcp6->ConfigData.AccessPoint.RemotePort ));
    595     }
    596     else {
    597       //
    598       //  Error return path is through EslTcp6ConnectComplete to
    599       //  enable retry on other ports
    600       //
    601       //  Status to errno translation gets done in EslTcp4ConnectPoll
    602       //
    603       pTcp6->ConnectToken.CompletionToken.Status = Status;
    604 
    605       //
    606       //  Continue with the next port
    607       //
    608       gBS->CheckEvent ( pTcp6->ConnectToken.CompletionToken.Event );
    609       gBS->SignalEvent ( pTcp6->ConnectToken.CompletionToken.Event );
    610     }
    611     Status = EFI_NOT_READY;
    612   }
    613   else {
    614     //
    615     //  No more local adapters available
    616     //
    617     pSocket->errno = ENETUNREACH;
    618     Status = EFI_NO_RESPONSE;
    619   }
    620 
    621   //
    622   //  Return the operation status
    623   //
    624   DBG_EXIT_STATUS ( Status );
    625   return Status;
    626 }
    627 
    628 
    629 /**
    630   Establish the known port to listen for network connections.
    631 
    632   This routine places the port into a state that enables connection
    633   attempts.
    634 
    635   This routine is called by ::EslSocketListen to handle the network
    636   specifics of the listen operation for SOCK_STREAM and SOCK_SEQPACKET
    637   sockets.  See the \ref ConnectionManagement section.
    638 
    639   @param [in] pSocket   Address of an ::ESL_SOCKET structure.
    640 
    641   @retval EFI_SUCCESS - Socket successfully created
    642   @retval Other - Failed to enable the socket for listen
    643 
    644 **/
    645 EFI_STATUS
    646 EslTcp6Listen (
    647   IN ESL_SOCKET * pSocket
    648   )
    649 {
    650   ESL_PORT * pNextPort;
    651   ESL_PORT * pPort;
    652   ESL_TCP6_CONTEXT * pTcp6;
    653   EFI_TCP6_PROTOCOL * pTcp6Protocol;
    654   EFI_STATUS Status;
    655 
    656   DBG_ENTER ( );
    657 
    658   //
    659   //  Verify the socket layer synchronization
    660   //
    661   VERIFY_TPL ( TPL_SOCKETS );
    662 
    663   //
    664   //  Use for/break instead of goto
    665   //
    666   for ( ; ; ) {
    667     //
    668     //  Assume no ports are available
    669     //
    670     pSocket->errno = EOPNOTSUPP;
    671     Status = EFI_NOT_READY;
    672 
    673     //
    674     //  Walk the list of ports
    675     //
    676     pPort = pSocket->pPortList;
    677     while ( NULL != pPort ) {
    678       //
    679       //  Assume success
    680       //
    681       pSocket->errno = 0;
    682 
    683       //
    684       //  Use for/break insteak of goto
    685       //
    686       for ( ; ; ) {
    687         //
    688         //  Create the listen completion event
    689         //
    690         pTcp6 = &pPort->Context.Tcp6;
    691         Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL,
    692                                     TPL_SOCKETS,
    693                                     (EFI_EVENT_NOTIFY)EslTcp6ListenComplete,
    694                                     pPort,
    695                                     &pTcp6->ListenToken.CompletionToken.Event );
    696         if ( EFI_ERROR ( Status )) {
    697           DEBUG (( DEBUG_ERROR | DEBUG_LISTEN,
    698                     "ERROR - Failed to create the listen completion event, Status: %r\r\n",
    699                     Status ));
    700           pSocket->errno = ENOMEM;
    701           break;
    702         }
    703         DEBUG (( DEBUG_POOL,
    704                   "0x%08x: Created listen completion event\r\n",
    705                   pTcp6->ListenToken.CompletionToken.Event ));
    706 
    707         //
    708         //  Configure the port
    709         //
    710         pTcp6Protocol = pPort->pProtocol.TCPv6;
    711         Status = pTcp6Protocol->Configure ( pTcp6Protocol,
    712                                             &pTcp6->ConfigData );
    713         if ( EFI_ERROR ( Status )) {
    714           DEBUG (( DEBUG_LISTEN,
    715                     "ERROR - Failed to configure the Tcp6 port, Status: %r\r\n",
    716                     Status ));
    717           switch ( Status ) {
    718           case EFI_ACCESS_DENIED:
    719             pSocket->errno = EACCES;
    720             break;
    721 
    722           default:
    723           case EFI_DEVICE_ERROR:
    724             pSocket->errno = EIO;
    725             break;
    726 
    727           case EFI_INVALID_PARAMETER:
    728             pSocket->errno = EADDRNOTAVAIL;
    729             break;
    730 
    731           case EFI_NO_MAPPING:
    732             pSocket->errno = EAFNOSUPPORT;
    733             break;
    734 
    735           case EFI_OUT_OF_RESOURCES:
    736             pSocket->errno = ENOBUFS;
    737             break;
    738 
    739           case EFI_UNSUPPORTED:
    740             pSocket->errno = EOPNOTSUPP;
    741             break;
    742           }
    743           break;
    744         }
    745         DEBUG (( DEBUG_LISTEN,
    746                   "0x%08x: Port configured\r\n",
    747                   pPort ));
    748         pPort->bConfigured = TRUE;
    749 
    750         //
    751         //  Start the listen operation on the port
    752         //
    753         Status = pTcp6Protocol->Accept ( pTcp6Protocol,
    754                                          &pTcp6->ListenToken );
    755         if ( EFI_ERROR ( Status )) {
    756           DEBUG (( DEBUG_LISTEN,
    757                     "ERROR - Failed Tcp6 accept, Status: %r\r\n",
    758                     Status ));
    759           switch ( Status ) {
    760           case EFI_ACCESS_DENIED:
    761             pSocket->errno = EACCES;
    762             break;
    763 
    764           default:
    765           case EFI_DEVICE_ERROR:
    766             pSocket->errno = EIO;
    767             break;
    768 
    769           case EFI_INVALID_PARAMETER:
    770             pSocket->errno = EADDRNOTAVAIL;
    771             break;
    772 
    773           case EFI_NOT_STARTED:
    774             pSocket->errno = ENETDOWN;
    775             break;
    776 
    777           case EFI_OUT_OF_RESOURCES:
    778             pSocket->errno = ENOBUFS;
    779             break;
    780           }
    781           break;
    782         }
    783         DEBUG (( DEBUG_LISTEN,
    784                   "0x%08x: Listen pending on Port\r\n",
    785                   pPort ));
    786 
    787         //
    788         //  Listen is pending on this port
    789         //
    790         break;
    791       }
    792 
    793       //
    794       //  Get the next port
    795       //
    796       pNextPort = pPort->pLinkSocket;
    797 
    798       //
    799       //  Close the port upon error
    800       //
    801       if ( EFI_ERROR ( Status )) {
    802         EslSocketPortCloseStart ( pPort, TRUE, DEBUG_LISTEN );
    803       }
    804 
    805       //
    806       //  Set the next port
    807       //
    808       pPort = pNextPort;
    809     }
    810 
    811     //
    812     //  Determine if any ports are in the listen state
    813     //
    814     if ( NULL == pSocket->pPortList ) {
    815       //
    816       //  No ports in the listen state
    817       //
    818       pSocket->MaxFifoDepth = 0;
    819 
    820       //
    821       //  Return the last error detected
    822       //
    823       break;
    824     }
    825 
    826     //
    827     //  Mark the socket as configured
    828     //
    829     pSocket->bConfigured = TRUE;
    830     Status = EFI_SUCCESS;
    831     pSocket->errno = 0;
    832 
    833     //
    834     //  All done
    835     //
    836     DEBUG (( DEBUG_LISTEN,
    837               "0x%08x: pSocket - Listen pending on socket\r\n",
    838               pSocket ));
    839     break;
    840   }
    841 
    842   //
    843   //  Return the operation status
    844   //
    845   DBG_EXIT_STATUS ( Status );
    846   return Status;
    847 }
    848 
    849 
    850 /**
    851   Process the connection attempt
    852 
    853   A system has initiated a connection attempt with a socket in the
    854   listen state.  Attempt to complete the connection.
    855 
    856   The TCPv6 layer calls this routine when a connection is made to
    857   the socket in the listen state.  See the
    858   \ref ConnectionManagement section.
    859 
    860   @param [in] Event     The listen completion event
    861 
    862   @param [in] pPort     Address of an ::ESL_PORT structure.
    863 
    864 **/
    865 VOID
    866 EslTcp6ListenComplete (
    867   IN EFI_EVENT Event,
    868   IN ESL_PORT * pPort
    869   )
    870 {
    871   EFI_HANDLE ChildHandle;
    872   struct sockaddr_in6 LocalAddress;
    873   EFI_TCP6_CONFIG_DATA * pConfigData;
    874   ESL_PORT * pNewPort;
    875   ESL_SOCKET * pNewSocket;
    876   ESL_SOCKET * pSocket;
    877   ESL_TCP6_CONTEXT * pTcp6;
    878   EFI_TCP6_PROTOCOL * pTcp6Protocol;
    879   EFI_STATUS Status;
    880   EFI_HANDLE TcpPortHandle;
    881   EFI_STATUS TempStatus;
    882 
    883   DBG_ENTER ( );
    884   VERIFY_AT_TPL ( TPL_SOCKETS );
    885 
    886   //
    887   //  Assume success
    888   //
    889   Status = EFI_SUCCESS;
    890 
    891   //
    892   //  Determine if this connection fits into the connection FIFO
    893   //
    894   pSocket = pPort->pSocket;
    895   TcpPortHandle = pPort->Context.Tcp6.ListenToken.NewChildHandle;
    896   if (( SOCKET_STATE_LISTENING == pSocket->State )
    897     && ( pSocket->MaxFifoDepth > pSocket->FifoDepth )) {
    898     //
    899     //  Allocate a socket for this connection
    900     //
    901     ChildHandle = NULL;
    902     Status = EslSocketAllocate ( &ChildHandle,
    903                                  DEBUG_CONNECTION,
    904                                  &pNewSocket );
    905     if ( !EFI_ERROR ( Status )) {
    906       //
    907       //  Clone the socket parameters
    908       //
    909       pNewSocket->pApi = pSocket->pApi;
    910       pNewSocket->Domain = pSocket->Domain;
    911       pNewSocket->Protocol = pSocket->Protocol;
    912       pNewSocket->Type = pSocket->Type;
    913 
    914       //
    915       //  Build the local address
    916       //
    917       pTcp6 = &pPort->Context.Tcp6;
    918       LocalAddress.sin6_len = (uint8_t)pNewSocket->pApi->MinimumAddressLength;
    919       LocalAddress.sin6_family = AF_INET6;
    920       LocalAddress.sin6_port = 0;
    921       CopyMem ( &LocalAddress.sin6_addr.__u6_addr.__u6_addr8 [ 0 ],
    922                 &pTcp6->ConfigData.AccessPoint.StationAddress.Addr [ 0 ],
    923                 sizeof ( pTcp6->ConfigData.AccessPoint.StationAddress.Addr ));
    924 
    925       //
    926       //  Allocate a port for this connection
    927       //  Note in this instance Configure may not be called with NULL!
    928       //
    929       Status = EslSocketPortAllocate ( pNewSocket,
    930                                        pPort->pService,
    931                                        TcpPortHandle,
    932                                        (struct sockaddr *)&LocalAddress,
    933                                        FALSE,
    934                                        DEBUG_CONNECTION,
    935                                        &pNewPort );
    936       if ( !EFI_ERROR ( Status )) {
    937         //
    938         //  Restart the listen operation on the port
    939         //
    940         pTcp6Protocol = pPort->pProtocol.TCPv6;
    941         Status = pTcp6Protocol->Accept ( pTcp6Protocol,
    942                                          &pTcp6->ListenToken );
    943 
    944         //
    945         //  Close the TCP port using SocketClose
    946         //
    947         TcpPortHandle = NULL;
    948         pTcp6 = &pNewPort->Context.Tcp6;
    949 
    950         //
    951         //  Check for an accept call error
    952         //
    953         if ( !EFI_ERROR ( Status )) {
    954           //
    955           //  Get the port configuration
    956           //
    957           pNewPort->bConfigured = TRUE;
    958           pConfigData = &pTcp6->ConfigData;
    959           pConfigData->ControlOption = &pTcp6->Option;
    960           pTcp6Protocol = pNewPort->pProtocol.TCPv6;
    961           Status = pTcp6Protocol->GetModeData ( pTcp6Protocol,
    962                                                 NULL,
    963                                                 pConfigData,
    964                                                 NULL,
    965                                                 NULL,
    966                                                 NULL );
    967           if ( !EFI_ERROR ( Status )) {
    968             //
    969             //  Add the new socket to the connection FIFO
    970             //
    971             if ( NULL == pSocket->pFifoTail ) {
    972               //
    973               //  First connection
    974               //
    975               pSocket->pFifoHead = pNewSocket;
    976             }
    977             else {
    978               //
    979               //  Add to end of list.
    980               //
    981               pSocket->pFifoTail->pNextConnection = pNewSocket;
    982             }
    983             pSocket->pFifoTail = pNewSocket;
    984             pSocket->FifoDepth += 1;
    985 
    986             //
    987             //  Update the socket state
    988             //
    989             pNewSocket->State = SOCKET_STATE_IN_FIFO;
    990 
    991             //
    992             //  Log the connection
    993             //
    994             DEBUG (( DEBUG_CONNECTION | DEBUG_INFO,
    995                       "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",
    996                       pNewSocket,
    997                       pConfigData->AccessPoint.StationAddress.Addr[0],
    998                       pConfigData->AccessPoint.StationAddress.Addr[1],
    999                       pConfigData->AccessPoint.StationAddress.Addr[2],
   1000                       pConfigData->AccessPoint.StationAddress.Addr[3],
   1001                       pConfigData->AccessPoint.StationAddress.Addr[4],
   1002                       pConfigData->AccessPoint.StationAddress.Addr[5],
   1003                       pConfigData->AccessPoint.StationAddress.Addr[6],
   1004                       pConfigData->AccessPoint.StationAddress.Addr[7],
   1005                       pConfigData->AccessPoint.StationAddress.Addr[8],
   1006                       pConfigData->AccessPoint.StationAddress.Addr[9],
   1007                       pConfigData->AccessPoint.StationAddress.Addr[10],
   1008                       pConfigData->AccessPoint.StationAddress.Addr[11],
   1009                       pConfigData->AccessPoint.StationAddress.Addr[12],
   1010                       pConfigData->AccessPoint.StationAddress.Addr[13],
   1011                       pConfigData->AccessPoint.StationAddress.Addr[14],
   1012                       pConfigData->AccessPoint.StationAddress.Addr[15],
   1013                       pConfigData->AccessPoint.StationPort,
   1014                       pConfigData->AccessPoint.RemoteAddress.Addr[0],
   1015                       pConfigData->AccessPoint.RemoteAddress.Addr[1],
   1016                       pConfigData->AccessPoint.RemoteAddress.Addr[2],
   1017                       pConfigData->AccessPoint.RemoteAddress.Addr[3],
   1018                       pConfigData->AccessPoint.RemoteAddress.Addr[4],
   1019                       pConfigData->AccessPoint.RemoteAddress.Addr[5],
   1020                       pConfigData->AccessPoint.RemoteAddress.Addr[6],
   1021                       pConfigData->AccessPoint.RemoteAddress.Addr[7],
   1022                       pConfigData->AccessPoint.RemoteAddress.Addr[8],
   1023                       pConfigData->AccessPoint.RemoteAddress.Addr[9],
   1024                       pConfigData->AccessPoint.RemoteAddress.Addr[10],
   1025                       pConfigData->AccessPoint.RemoteAddress.Addr[11],
   1026                       pConfigData->AccessPoint.RemoteAddress.Addr[12],
   1027                       pConfigData->AccessPoint.RemoteAddress.Addr[13],
   1028                       pConfigData->AccessPoint.RemoteAddress.Addr[14],
   1029                       pConfigData->AccessPoint.RemoteAddress.Addr[15],
   1030                       pConfigData->AccessPoint.RemotePort ));
   1031             DEBUG (( DEBUG_CONNECTION | DEBUG_INFO,
   1032                       "0x%08x: Listen socket adding socket 0x%08x to FIFO, depth: %d\r\n",
   1033                       pSocket,
   1034                       pNewSocket,
   1035                       pSocket->FifoDepth ));
   1036 
   1037             //
   1038             //  Start the receive operation
   1039             //
   1040             EslSocketRxStart ( pNewPort );
   1041           }
   1042           else {
   1043             DEBUG (( DEBUG_ERROR | DEBUG_CONNECTION | DEBUG_INFO,
   1044                       "ERROR - GetModeData failed on port 0x%08x, Status: %r\r\n",
   1045                       pNewPort,
   1046                       Status ));
   1047           }
   1048         }
   1049         else {
   1050           //
   1051           //  The listen failed on this port
   1052           //
   1053           DEBUG (( DEBUG_LISTEN | DEBUG_INFO,
   1054                     "ERROR - Listen failed on port 0x%08x, Status: %r\r\n",
   1055                     pPort,
   1056                     Status ));
   1057 
   1058           //
   1059           //  Close the listening port
   1060           //
   1061           EslSocketPortCloseStart ( pPort, TRUE, DEBUG_LISTEN );
   1062         }
   1063       }
   1064 
   1065       //
   1066       //  Done with the socket if necessary
   1067       //
   1068       if ( EFI_ERROR ( Status )) {
   1069         TempStatus = EslSocketCloseStart ( &pNewSocket->SocketProtocol,
   1070                                            TRUE,
   1071                                            &pSocket->errno );
   1072         ASSERT ( EFI_SUCCESS == TempStatus );
   1073       }
   1074     }
   1075   }
   1076   else {
   1077     DEBUG (( DEBUG_CONNECTION,
   1078               "0x%08x: Socket FIFO full, connection refused\r\n",
   1079               pSocket ));
   1080 
   1081     //
   1082     //  The FIFO is full or the socket is in the wrong state
   1083     //
   1084     Status = EFI_BUFFER_TOO_SMALL;
   1085   }
   1086 
   1087   //
   1088   //  Close the connection if necessary
   1089   //
   1090   if (( EFI_ERROR ( Status ))
   1091     && ( NULL == TcpPortHandle )) {
   1092     //
   1093     // TODO: Finish this code path
   1094     //  The new connection does not fit into the connection FIFO
   1095     //
   1096     //  Process:
   1097     //    Call close
   1098     //    Release the resources
   1099 
   1100   }
   1101 
   1102   DBG_EXIT ( );
   1103 }
   1104 
   1105 
   1106 /**
   1107   Get the local socket address.
   1108 
   1109   This routine returns the IPv6 address and TCP port number associated
   1110   with the local socket.
   1111 
   1112   This routine is called by ::EslSocketGetLocalAddress to determine the
   1113   network address for the SOCK_STREAM or SOCK_SEQPACKET socket.
   1114 
   1115   @param [in] pPort       Address of an ::ESL_PORT structure.
   1116 
   1117   @param [out] pSockAddr  Network address to receive the local system address
   1118 
   1119 **/
   1120 VOID
   1121 EslTcp6LocalAddressGet (
   1122   IN ESL_PORT * pPort,
   1123   OUT struct sockaddr * pSockAddr
   1124   )
   1125 {
   1126   struct sockaddr_in6 * pLocalAddress;
   1127   ESL_TCP6_CONTEXT * pTcp6;
   1128 
   1129   DBG_ENTER ( );
   1130 
   1131   //
   1132   //  Return the local address
   1133   //
   1134   pTcp6 = &pPort->Context.Tcp6;
   1135   pLocalAddress = (struct sockaddr_in6 *)pSockAddr;
   1136   pLocalAddress->sin6_family = AF_INET6;
   1137   pLocalAddress->sin6_port = SwapBytes16 ( pTcp6->ConfigData.AccessPoint.StationPort );
   1138   CopyMem ( &pLocalAddress->sin6_addr,
   1139             &pTcp6->ConfigData.AccessPoint.StationAddress.Addr[0],
   1140             sizeof ( pLocalAddress->sin6_addr ));
   1141 
   1142   DBG_EXIT ( );
   1143 }
   1144 
   1145 
   1146 /**
   1147   Set the local port address.
   1148 
   1149   This routine sets the local port address.
   1150 
   1151   This support routine is called by ::EslSocketPortAllocate.
   1152 
   1153   @param [in] pPort       Address of an ESL_PORT structure
   1154   @param [in] pSockAddr   Address of a sockaddr structure that contains the
   1155                           connection point on the local machine.  An IPv6 address
   1156                           of INADDR_ANY specifies that the connection is made to
   1157                           all of the network stacks on the platform.  Specifying a
   1158                           specific IPv6 address restricts the connection to the
   1159                           network stack supporting that address.  Specifying zero
   1160                           for the port causes the network layer to assign a port
   1161                           number from the dynamic range.  Specifying a specific
   1162                           port number causes the network layer to use that port.
   1163 
   1164   @param [in] bBindTest   TRUE = run bind testing
   1165 
   1166   @retval EFI_SUCCESS     The operation was successful
   1167 
   1168  **/
   1169 EFI_STATUS
   1170 EslTcp6LocalAddressSet (
   1171   IN ESL_PORT * pPort,
   1172   IN CONST struct sockaddr * pSockAddr,
   1173   IN BOOLEAN bBindTest
   1174   )
   1175 {
   1176   EFI_TCP6_ACCESS_POINT * pAccessPoint;
   1177   CONST struct sockaddr_in6 * pIpAddress;
   1178   EFI_STATUS Status;
   1179 
   1180   DBG_ENTER ( );
   1181 
   1182   //
   1183   //  Validate the address
   1184   //
   1185   pIpAddress = (struct sockaddr_in6 *)pSockAddr;
   1186 //
   1187 // TODO: Fix the following check
   1188 //
   1189 /*
   1190   if ( INADDR_BROADCAST == pIpAddress->sin6_addr.s_addr ) {
   1191     //
   1192     //  The local address must not be the broadcast address
   1193     //
   1194     Status = EFI_INVALID_PARAMETER;
   1195     pPort->pSocket->errno = EADDRNOTAVAIL;
   1196   }
   1197   else {
   1198 */
   1199 {
   1200     //
   1201     //  Set the local address
   1202     //
   1203     pAccessPoint = &pPort->Context.Tcp6.ConfigData.AccessPoint;
   1204     CopyMem ( &pAccessPoint->StationAddress.Addr[0],
   1205               &pIpAddress->sin6_addr.__u6_addr.__u6_addr8 [ 0 ],
   1206               sizeof ( pIpAddress->sin6_addr.__u6_addr.__u6_addr8 [ 0 ]));
   1207 
   1208     //
   1209     //  Validate the IP address
   1210     //
   1211     pAccessPoint->StationPort = 0;
   1212     Status = bBindTest ? EslSocketBindTest ( pPort, EADDRNOTAVAIL )
   1213                        : EFI_SUCCESS;
   1214     if ( !EFI_ERROR ( Status )) {
   1215       //
   1216       //  Set the port number
   1217       //
   1218       pAccessPoint->StationPort = SwapBytes16 ( pIpAddress->sin6_port );
   1219       pPort->pSocket->bAddressSet = TRUE;
   1220 
   1221       //
   1222       //  Display the local address
   1223       //
   1224       DEBUG (( DEBUG_BIND,
   1225                 "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",
   1226                 pPort,
   1227                 pAccessPoint->StationAddress.Addr[0],
   1228                 pAccessPoint->StationAddress.Addr[1],
   1229                 pAccessPoint->StationAddress.Addr[2],
   1230                 pAccessPoint->StationAddress.Addr[3],
   1231                 pAccessPoint->StationAddress.Addr[4],
   1232                 pAccessPoint->StationAddress.Addr[5],
   1233                 pAccessPoint->StationAddress.Addr[6],
   1234                 pAccessPoint->StationAddress.Addr[7],
   1235                 pAccessPoint->StationAddress.Addr[8],
   1236                 pAccessPoint->StationAddress.Addr[9],
   1237                 pAccessPoint->StationAddress.Addr[10],
   1238                 pAccessPoint->StationAddress.Addr[11],
   1239                 pAccessPoint->StationAddress.Addr[12],
   1240                 pAccessPoint->StationAddress.Addr[13],
   1241                 pAccessPoint->StationAddress.Addr[14],
   1242                 pAccessPoint->StationAddress.Addr[15],
   1243                 pAccessPoint->StationPort ));
   1244     }
   1245   }
   1246 
   1247   //
   1248   //  Return the operation status
   1249   //
   1250   DBG_EXIT_STATUS ( Status );
   1251   return Status;
   1252 }
   1253 
   1254 
   1255 /**
   1256   Free a receive packet
   1257 
   1258   This routine performs the network specific operations necessary
   1259   to free a receive packet.
   1260 
   1261   This routine is called by ::EslSocketPortCloseTxDone to free a
   1262   receive packet.
   1263 
   1264   @param [in] pPacket         Address of an ::ESL_PACKET structure.
   1265   @param [in, out] pRxBytes   Address of the count of RX bytes
   1266 
   1267 **/
   1268 VOID
   1269 EslTcp6PacketFree (
   1270   IN ESL_PACKET * pPacket,
   1271   IN OUT size_t * pRxBytes
   1272   )
   1273 {
   1274   DBG_ENTER ( );
   1275 
   1276   //
   1277   //  Account for the receive bytes
   1278   //
   1279   *pRxBytes -= pPacket->Op.Tcp6Rx.RxData.DataLength;
   1280   DBG_EXIT ( );
   1281 }
   1282 
   1283 
   1284 /**
   1285   Initialize the network specific portions of an ::ESL_PORT structure.
   1286 
   1287   This routine initializes the network specific portions of an
   1288   ::ESL_PORT structure for use by the socket.
   1289 
   1290   This support routine is called by ::EslSocketPortAllocate
   1291   to connect the socket with the underlying network adapter
   1292   running the TCPv6 protocol.
   1293 
   1294   @param [in] pPort       Address of an ESL_PORT structure
   1295   @param [in] DebugFlags  Flags for debug messages
   1296 
   1297   @retval EFI_SUCCESS - Socket successfully created
   1298 
   1299  **/
   1300 EFI_STATUS
   1301 EslTcp6PortAllocate (
   1302   IN ESL_PORT * pPort,
   1303   IN UINTN DebugFlags
   1304   )
   1305 {
   1306   EFI_TCP6_ACCESS_POINT * pAccessPoint;
   1307   ESL_SOCKET * pSocket;
   1308   ESL_TCP6_CONTEXT * pTcp6;
   1309   EFI_STATUS Status;
   1310 
   1311   DBG_ENTER ( );
   1312 
   1313   //
   1314   //  Use for/break instead of goto
   1315   for ( ; ; ) {
   1316     //
   1317     //  Allocate the close event
   1318     //
   1319     pSocket = pPort->pSocket;
   1320     pTcp6 = &pPort->Context.Tcp6;
   1321     Status = gBS->CreateEvent (  EVT_NOTIFY_SIGNAL,
   1322                                  TPL_SOCKETS,
   1323                                  (EFI_EVENT_NOTIFY)EslSocketPortCloseComplete,
   1324                                  pPort,
   1325                                  &pTcp6->CloseToken.CompletionToken.Event);
   1326     if ( EFI_ERROR ( Status )) {
   1327       DEBUG (( DEBUG_ERROR | DebugFlags,
   1328                 "ERROR - Failed to create the close event, Status: %r\r\n",
   1329                 Status ));
   1330       pSocket->errno = ENOMEM;
   1331       break;
   1332     }
   1333     DEBUG (( DEBUG_CLOSE | DEBUG_POOL,
   1334               "0x%08x: Created close event\r\n",
   1335               pTcp6->CloseToken.CompletionToken.Event ));
   1336 
   1337     //
   1338     //  Allocate the connection event
   1339     //
   1340     Status = gBS->CreateEvent (  EVT_NOTIFY_SIGNAL,
   1341                                  TPL_SOCKETS,
   1342                                  (EFI_EVENT_NOTIFY)EslTcp6ConnectComplete,
   1343                                  pPort,
   1344                                  &pTcp6->ConnectToken.CompletionToken.Event);
   1345     if ( EFI_ERROR ( Status )) {
   1346       DEBUG (( DEBUG_ERROR | DebugFlags,
   1347                 "ERROR - Failed to create the connect event, Status: %r\r\n",
   1348                 Status ));
   1349       pSocket->errno = ENOMEM;
   1350       break;
   1351     }
   1352     DEBUG (( DEBUG_CLOSE | DEBUG_POOL,
   1353               "0x%08x: Created connect event\r\n",
   1354               pTcp6->ConnectToken.CompletionToken.Event ));
   1355 
   1356     //
   1357     //  Initialize the port
   1358     //
   1359     pSocket->TxPacketOffset = OFFSET_OF ( ESL_PACKET, Op.Tcp6Tx.TxData );
   1360     pSocket->TxTokenEventOffset = OFFSET_OF ( ESL_IO_MGMT, Token.Tcp6Tx.CompletionToken.Event );
   1361     pSocket->TxTokenOffset = OFFSET_OF ( EFI_TCP6_IO_TOKEN, Packet.TxData );
   1362 
   1363     //
   1364     //  Save the cancel, receive and transmit addresses
   1365     //  pPort->pfnRxCancel = NULL; since the UEFI implementation returns EFI_UNSUPPORTED
   1366     //
   1367     pPort->pfnConfigure = (PFN_NET_CONFIGURE)pPort->pProtocol.TCPv6->Configure;
   1368     pPort->pfnRxPoll = (PFN_NET_POLL)pPort->pProtocol.TCPv6->Poll;
   1369     pPort->pfnRxStart = (PFN_NET_IO_START)pPort->pProtocol.TCPv6->Receive;
   1370     pPort->pfnTxStart = (PFN_NET_IO_START)pPort->pProtocol.TCPv6->Transmit;
   1371 
   1372     //
   1373     //  Set the configuration flags
   1374     //
   1375     pAccessPoint = &pPort->Context.Tcp6.ConfigData.AccessPoint;
   1376     pAccessPoint->ActiveFlag = FALSE;
   1377     pTcp6->ConfigData.TrafficClass = 0;
   1378     pTcp6->ConfigData.HopLimit = 255;
   1379     break;
   1380   }
   1381 
   1382   //
   1383   //  Return the operation status
   1384   //
   1385   DBG_EXIT_STATUS ( Status );
   1386   return Status;
   1387 }
   1388 
   1389 
   1390 /**
   1391   Close a Tcp6 port.
   1392 
   1393   This routine releases the network specific resources allocated by
   1394   ::EslTcp6PortAllocate.
   1395 
   1396   This routine is called by ::EslSocketPortClose.
   1397   See the \ref PortCloseStateMachine section.
   1398 
   1399   @param [in] pPort       Address of an ::ESL_PORT structure.
   1400 
   1401   @retval EFI_SUCCESS     The port is closed
   1402   @retval other           Port close error
   1403 
   1404 **/
   1405 EFI_STATUS
   1406 EslTcp6PortClose (
   1407   IN ESL_PORT * pPort
   1408   )
   1409 {
   1410   UINTN DebugFlags;
   1411   ESL_TCP6_CONTEXT * pTcp6;
   1412   EFI_STATUS Status;
   1413 
   1414   DBG_ENTER ( );
   1415 
   1416   //
   1417   //  Locate the port in the socket list
   1418   //
   1419   Status = EFI_SUCCESS;
   1420   DebugFlags = pPort->DebugFlags;
   1421   pTcp6 = &pPort->Context.Tcp6;
   1422 
   1423   //
   1424   //  Done with the connect event
   1425   //
   1426   if ( NULL != pTcp6->ConnectToken.CompletionToken.Event ) {
   1427     Status = gBS->CloseEvent ( pTcp6->ConnectToken.CompletionToken.Event );
   1428     if ( !EFI_ERROR ( Status )) {
   1429       DEBUG (( DebugFlags | DEBUG_POOL,
   1430                 "0x%08x: Closed connect event\r\n",
   1431                 pTcp6->ConnectToken.CompletionToken.Event ));
   1432     }
   1433     else {
   1434       DEBUG (( DEBUG_ERROR | DebugFlags,
   1435                 "ERROR - Failed to close the connect event, Status: %r\r\n",
   1436                 Status ));
   1437       ASSERT ( EFI_SUCCESS == Status );
   1438     }
   1439   }
   1440 
   1441   //
   1442   //  Done with the close event
   1443   //
   1444   if ( NULL != pTcp6->CloseToken.CompletionToken.Event ) {
   1445     Status = gBS->CloseEvent ( pTcp6->CloseToken.CompletionToken.Event );
   1446     if ( !EFI_ERROR ( Status )) {
   1447       DEBUG (( DebugFlags | DEBUG_POOL,
   1448                 "0x%08x: Closed close event\r\n",
   1449                 pTcp6->CloseToken.CompletionToken.Event ));
   1450     }
   1451     else {
   1452       DEBUG (( DEBUG_ERROR | DebugFlags,
   1453                 "ERROR - Failed to close the close event, Status: %r\r\n",
   1454                 Status ));
   1455       ASSERT ( EFI_SUCCESS == Status );
   1456     }
   1457   }
   1458 
   1459   //
   1460   //  Done with the listen completion event
   1461   //
   1462   if ( NULL != pTcp6->ListenToken.CompletionToken.Event ) {
   1463     Status = gBS->CloseEvent ( pTcp6->ListenToken.CompletionToken.Event );
   1464     if ( !EFI_ERROR ( Status )) {
   1465       DEBUG (( DebugFlags | DEBUG_POOL,
   1466                 "0x%08x: Closed listen completion event\r\n",
   1467                 pTcp6->ListenToken.CompletionToken.Event ));
   1468     }
   1469     else {
   1470       DEBUG (( DEBUG_ERROR | DebugFlags,
   1471                 "ERROR - Failed to close the listen completion event, Status: %r\r\n",
   1472                 Status ));
   1473       ASSERT ( EFI_SUCCESS == Status );
   1474     }
   1475   }
   1476 
   1477   //
   1478   //  Return the operation status
   1479   //
   1480   DBG_EXIT_STATUS ( Status );
   1481   return Status;
   1482 }
   1483 
   1484 
   1485 /**
   1486   Perform the network specific close operation on the port.
   1487 
   1488   This routine performs a cancel operations on the TCPv6 port to
   1489   shutdown the receive operations on the port.
   1490 
   1491   This routine is called by the ::EslSocketPortCloseTxDone
   1492   routine after the port completes all of the transmission.
   1493 
   1494   @param [in] pPort           Address of an ::ESL_PORT structure.
   1495 
   1496   @retval EFI_SUCCESS         The port is closed, not normally returned
   1497   @retval EFI_NOT_READY       The port is still closing
   1498   @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
   1499                               most likely the routine was called already.
   1500 
   1501 **/
   1502 EFI_STATUS
   1503 EslTcp6PortCloseOp (
   1504   IN ESL_PORT * pPort
   1505   )
   1506 {
   1507   ESL_TCP6_CONTEXT * pTcp6;
   1508   EFI_TCP6_PROTOCOL * pTcp6Protocol;
   1509   EFI_STATUS Status;
   1510 
   1511   DBG_ENTER ( );
   1512 
   1513   //
   1514   //  Close the configured port
   1515   //
   1516   Status = EFI_SUCCESS;
   1517   pTcp6 = &pPort->Context.Tcp6;
   1518   pTcp6Protocol = pPort->pProtocol.TCPv6;
   1519   pTcp6->CloseToken.AbortOnClose = pPort->bCloseNow;
   1520   Status = pTcp6Protocol->Close ( pTcp6Protocol,
   1521                                   &pTcp6->CloseToken );
   1522   if ( !EFI_ERROR ( Status )) {
   1523     DEBUG (( pPort->DebugFlags | DEBUG_CLOSE | DEBUG_INFO,
   1524               "0x%08x: Port close started\r\n",
   1525               pPort ));
   1526   }
   1527   else {
   1528     DEBUG (( DEBUG_ERROR | pPort->DebugFlags | DEBUG_CLOSE | DEBUG_INFO,
   1529              "ERROR - Close failed on port 0x%08x, Status: %r\r\n",
   1530              pPort,
   1531              Status ));
   1532   }
   1533 
   1534   //
   1535   //  Return the operation status
   1536   //
   1537   DBG_EXIT_STATUS ( Status );
   1538   return Status;
   1539 }
   1540 
   1541 
   1542 /**
   1543   Receive data from a network connection.
   1544 
   1545   This routine attempts to return buffered data to the caller.  The
   1546   data is removed from the urgent queue if the message flag MSG_OOB
   1547   is specified, otherwise data is removed from the normal queue.
   1548   See the \ref ReceiveEngine section.
   1549 
   1550   This routine is called by ::EslSocketReceive to handle the network
   1551   specific receive operation to support SOCK_STREAM and SOCK_SEQPACKET
   1552   sockets.
   1553 
   1554   @param [in] pPort           Address of an ::ESL_PORT structure.
   1555 
   1556   @param [in] pPacket         Address of an ::ESL_PACKET structure.
   1557 
   1558   @param [in] pbConsumePacket Address of a BOOLEAN indicating if the packet is to be consumed
   1559 
   1560   @param [in] BufferLength    Length of the the buffer
   1561 
   1562   @param [in] pBuffer         Address of a buffer to receive the data.
   1563 
   1564   @param [in] pDataLength     Number of received data bytes in the buffer.
   1565 
   1566   @param [out] pAddress       Network address to receive the remote system address
   1567 
   1568   @param [out] pSkipBytes     Address to receive the number of bytes skipped
   1569 
   1570   @return   Returns the address of the next free byte in the buffer.
   1571 
   1572  **/
   1573 UINT8 *
   1574 EslTcp6Receive (
   1575   IN ESL_PORT * pPort,
   1576   IN ESL_PACKET * pPacket,
   1577   IN BOOLEAN * pbConsumePacket,
   1578   IN size_t BufferLength,
   1579   IN UINT8 * pBuffer,
   1580   OUT size_t * pDataLength,
   1581   OUT struct sockaddr * pAddress,
   1582   OUT size_t * pSkipBytes
   1583   )
   1584 {
   1585   size_t DataLength;
   1586   struct sockaddr_in6 * pRemoteAddress;
   1587   ESL_TCP6_CONTEXT * pTcp6;
   1588 
   1589   DBG_ENTER ( );
   1590 
   1591   //
   1592   //  Return the remote system address if requested
   1593   //
   1594   if ( NULL != pAddress ) {
   1595     //
   1596     //  Build the remote address
   1597     //
   1598     pTcp6 = &pPort->Context.Tcp6;
   1599     DEBUG (( DEBUG_RX,
   1600               "Getting packet remote address: [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d\r\n",
   1601               pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[0],
   1602               pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[1],
   1603               pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[2],
   1604               pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[3],
   1605               pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[4],
   1606               pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[5],
   1607               pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[6],
   1608               pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[7],
   1609               pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[8],
   1610               pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[9],
   1611               pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[10],
   1612               pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[11],
   1613               pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[12],
   1614               pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[13],
   1615               pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[14],
   1616               pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[15],
   1617               pTcp6->ConfigData.AccessPoint.RemotePort ));
   1618     pRemoteAddress = (struct sockaddr_in6 *)pAddress;
   1619     CopyMem ( &pRemoteAddress->sin6_addr,
   1620               &pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[0],
   1621               sizeof ( pRemoteAddress->sin6_addr ));
   1622     pRemoteAddress->sin6_port = SwapBytes16 ( pTcp6->ConfigData.AccessPoint.RemotePort );
   1623   }
   1624 
   1625   //
   1626   //  Determine the amount of received data
   1627   //
   1628   DataLength = pPacket->ValidBytes;
   1629   if ( BufferLength < DataLength ) {
   1630     DataLength = BufferLength;
   1631   }
   1632 
   1633   //
   1634   //  Move the data into the buffer
   1635   //
   1636   DEBUG (( DEBUG_RX,
   1637             "0x%08x: Port copy packet 0x%08x data into 0x%08x, 0x%08x bytes\r\n",
   1638             pPort,
   1639             pPacket,
   1640             pBuffer,
   1641             DataLength ));
   1642   CopyMem ( pBuffer, pPacket->pBuffer, DataLength );
   1643 
   1644   //
   1645   //  Set the next buffer address
   1646   //
   1647   pBuffer += DataLength;
   1648 
   1649   //
   1650   //  Determine if the data is being read
   1651   //
   1652   if ( *pbConsumePacket ) {
   1653     //
   1654     //  Account for the bytes consumed
   1655     //
   1656     pPacket->pBuffer += DataLength;
   1657     pPacket->ValidBytes -= DataLength;
   1658     DEBUG (( DEBUG_RX,
   1659               "0x%08x: Port account for 0x%08x bytes\r\n",
   1660               pPort,
   1661               DataLength ));
   1662 
   1663     //
   1664     //  Determine if the entire packet was consumed
   1665     //
   1666     if (( 0 == pPacket->ValidBytes )
   1667       || ( SOCK_STREAM != pPort->pSocket->Type )) {
   1668       //
   1669       //  All done with this packet
   1670       //  Account for any discarded data
   1671       //
   1672       *pSkipBytes = pPacket->ValidBytes;
   1673     }
   1674     else
   1675     {
   1676       //
   1677       //  More data to consume later
   1678       //
   1679       *pbConsumePacket = FALSE;
   1680     }
   1681   }
   1682 
   1683   //
   1684   //  Return the data length and the buffer address
   1685   //
   1686   *pDataLength = DataLength;
   1687   DBG_EXIT_HEX ( pBuffer );
   1688   return pBuffer;
   1689 }
   1690 
   1691 
   1692 /**
   1693   Get the remote socket address.
   1694 
   1695   This routine returns the address of the remote connection point
   1696   associated with the SOCK_STREAM or SOCK_SEQPACKET socket.
   1697 
   1698   This routine is called by ::EslSocketGetPeerAddress to detemine
   1699   the TCPv6 address and por number associated with the network adapter.
   1700 
   1701   @param [in] pPort       Address of an ::ESL_PORT structure.
   1702 
   1703   @param [out] pAddress   Network address to receive the remote system address
   1704 
   1705 **/
   1706 VOID
   1707 EslTcp6RemoteAddressGet (
   1708   IN ESL_PORT * pPort,
   1709   OUT struct sockaddr * pAddress
   1710   )
   1711 {
   1712   struct sockaddr_in6 * pRemoteAddress;
   1713   ESL_TCP6_CONTEXT * pTcp6;
   1714 
   1715   DBG_ENTER ( );
   1716 
   1717   //
   1718   //  Return the remote address
   1719   //
   1720   pTcp6 = &pPort->Context.Tcp6;
   1721   pRemoteAddress = (struct sockaddr_in6 *)pAddress;
   1722   pRemoteAddress->sin6_family = AF_INET6;
   1723   pRemoteAddress->sin6_port = SwapBytes16 ( pTcp6->ConfigData.AccessPoint.RemotePort );
   1724   CopyMem ( &pRemoteAddress->sin6_addr,
   1725             &pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr[0],
   1726             sizeof ( pRemoteAddress->sin6_addr ));
   1727 
   1728   DBG_EXIT ( );
   1729 }
   1730 
   1731 
   1732 /**
   1733   Set the remote address
   1734 
   1735   This routine sets the remote address in the port.
   1736 
   1737   This routine is called by ::EslSocketConnect to specify the
   1738   remote network address.
   1739 
   1740   @param [in] pPort           Address of an ::ESL_PORT structure.
   1741 
   1742   @param [in] pSockAddr       Network address of the remote system.
   1743 
   1744   @param [in] SockAddrLength  Length in bytes of the network address.
   1745 
   1746   @retval EFI_SUCCESS     The operation was successful
   1747 
   1748  **/
   1749 EFI_STATUS
   1750 EslTcp6RemoteAddressSet (
   1751   IN ESL_PORT * pPort,
   1752   IN CONST struct sockaddr * pSockAddr,
   1753   IN socklen_t SockAddrLength
   1754   )
   1755 {
   1756   CONST struct sockaddr_in6 * pRemoteAddress;
   1757   ESL_TCP6_CONTEXT * pTcp6;
   1758   EFI_STATUS Status;
   1759 
   1760   DBG_ENTER ( );
   1761 
   1762   //
   1763   //  Set the remote address
   1764   //
   1765   pTcp6 = &pPort->Context.Tcp6;
   1766   pRemoteAddress = (struct sockaddr_in6 *)pSockAddr;
   1767   CopyMem ( &pTcp6->ConfigData.AccessPoint.RemoteAddress.Addr [ 0 ],
   1768             &pRemoteAddress->sin6_addr.__u6_addr.__u6_addr8 [ 0 ],
   1769             sizeof ( pRemoteAddress->sin6_addr.__u6_addr.__u6_addr8 ));
   1770   pTcp6->ConfigData.AccessPoint.RemotePort = SwapBytes16 ( pRemoteAddress->sin6_port );
   1771   Status = EFI_SUCCESS;
   1772 
   1773 //
   1774 // TODO: Fix the following check
   1775 //
   1776 /*
   1777   if ( INADDR_BROADCAST == pRemoteAddress->sin6_addr.s_addr ) {
   1778     DEBUG (( DEBUG_CONNECT,
   1779               "ERROR - Invalid remote address\r\n" ));
   1780     Status = EFI_INVALID_PARAMETER;
   1781     pPort->pSocket->errno = EAFNOSUPPORT;
   1782   }
   1783 */
   1784 
   1785   //
   1786   //  Return the operation status
   1787   //
   1788   DBG_EXIT_STATUS ( Status );
   1789   return Status;
   1790 }
   1791 
   1792 
   1793 /**
   1794   Process the receive completion
   1795 
   1796   This routine queues the data in FIFO order in either the urgent
   1797   or normal data queues depending upon the type of data received.
   1798   See the \ref ReceiveEngine section.
   1799 
   1800   This routine is called by the TCPv6 driver when some data is
   1801   received.
   1802 
   1803   Buffer the data that was just received.
   1804 
   1805   @param [in] Event     The receive completion event
   1806 
   1807   @param [in] pIo       Address of an ::ESL_IO_MGMT structure
   1808 
   1809 **/
   1810 VOID
   1811 EslTcp6RxComplete (
   1812   IN EFI_EVENT Event,
   1813   IN ESL_IO_MGMT * pIo
   1814   )
   1815 {
   1816   BOOLEAN bUrgent;
   1817   size_t LengthInBytes;
   1818   ESL_PACKET * pPacket;
   1819   EFI_STATUS Status;
   1820 
   1821   DBG_ENTER ( );
   1822 
   1823   //
   1824   //  Get the operation status.
   1825   //
   1826   Status = pIo->Token.Tcp6Rx.CompletionToken.Status;
   1827 
   1828   //
   1829   //      +--------------------+   +---------------------------+
   1830   //      | ESL_IO_MGMT        |   | ESL_PACKET                |
   1831   //      |                    |   |                           |
   1832   //      |    +---------------+   +-----------------------+   |
   1833   //      |    | Token         |   | EFI_Tcp6_RECEIVE_DATA |   |
   1834   //      |    |        RxData --> |                       |   |
   1835   //      |    |               |   +-----------------------+---+
   1836   //      |    |        Event  |   |       Data Buffer         |
   1837   //      +----+---------------+   |                           |
   1838   //                               |                           |
   1839   //                               +---------------------------+
   1840   //
   1841   //
   1842   //  Duplicate the buffer address and length for use by the
   1843   //  buffer handling code in EslTcp6Receive.  These fields are
   1844   //  used when a partial read is done of the data from the
   1845   //  packet.
   1846   //
   1847   pPacket = pIo->pPacket;
   1848   pPacket->pBuffer = pPacket->Op.Tcp6Rx.RxData.FragmentTable[0].FragmentBuffer;
   1849   LengthInBytes = pPacket->Op.Tcp6Rx.RxData.DataLength;
   1850   pPacket->ValidBytes = LengthInBytes;
   1851 
   1852   //
   1853   //  Get the data type so that it may be linked to the
   1854   //  correct receive buffer list on the ESL_SOCKET structure
   1855   //
   1856   bUrgent = pPacket->Op.Tcp6Rx.RxData.UrgentFlag;
   1857 
   1858   //
   1859   //  Complete this request
   1860   //
   1861   EslSocketRxComplete ( pIo, Status, LengthInBytes, bUrgent );
   1862   DBG_EXIT ( );
   1863 }
   1864 
   1865 
   1866 /**
   1867   Start a receive operation
   1868 
   1869   This routine posts a receive buffer to the TCPv6 driver.
   1870   See the \ref ReceiveEngine section.
   1871 
   1872   This support routine is called by EslSocketRxStart.
   1873 
   1874   @param [in] pPort       Address of an ::ESL_PORT structure.
   1875   @param [in] pIo         Address of an ::ESL_IO_MGMT structure.
   1876 
   1877  **/
   1878 VOID
   1879 EslTcp6RxStart (
   1880   IN ESL_PORT * pPort,
   1881   IN ESL_IO_MGMT * pIo
   1882   )
   1883 {
   1884   ESL_PACKET * pPacket;
   1885 
   1886   DBG_ENTER ( );
   1887 
   1888   //
   1889   //  Initialize the buffer for receive
   1890   //
   1891   pPacket = pIo->pPacket;
   1892   pIo->Token.Tcp6Rx.Packet.RxData = &pPacket->Op.Tcp6Rx.RxData;
   1893   pPacket->Op.Tcp6Rx.RxData.DataLength = sizeof ( pPacket->Op.Tcp6Rx.Buffer );
   1894   pPacket->Op.Tcp6Rx.RxData.FragmentCount = 1;
   1895   pPacket->Op.Tcp6Rx.RxData.FragmentTable[0].FragmentLength = pPacket->Op.Tcp6Rx.RxData.DataLength;
   1896   pPacket->Op.Tcp6Rx.RxData.FragmentTable[0].FragmentBuffer = &pPacket->Op.Tcp6Rx.Buffer[0];
   1897 
   1898   DBG_EXIT ( );
   1899 }
   1900 
   1901 
   1902 /**
   1903   Determine if the socket is configured.
   1904 
   1905   This routine uses the flag ESL_SOCKET::bConfigured to determine
   1906   if the network layer's configuration routine has been called.
   1907 
   1908   This routine is called by EslSocketIsConfigured to verify
   1909   that the socket has been configured.
   1910 
   1911   @param [in] pSocket   Address of an ::ESL_SOCKET structure.
   1912 
   1913   @retval EFI_SUCCESS - The port is connected
   1914   @retval EFI_NOT_STARTED - The port is not connected
   1915 
   1916  **/
   1917  EFI_STATUS
   1918  EslTcp6SocketIsConfigured (
   1919   IN ESL_SOCKET * pSocket
   1920   )
   1921 {
   1922   EFI_STATUS Status;
   1923 
   1924   DBG_ENTER ( );
   1925 
   1926   //
   1927   //  Determine the socket configuration status
   1928   //
   1929   Status = pSocket->bConfigured ? EFI_SUCCESS : EFI_NOT_STARTED;
   1930 
   1931   //
   1932   //  Return the port connected state.
   1933   //
   1934   DBG_EXIT_STATUS ( Status );
   1935   return Status;
   1936 }
   1937 
   1938 
   1939 /**
   1940   Buffer data for transmission over a network connection.
   1941 
   1942   This routine buffers data for the transmit engine in one of two
   1943   queues, one for urgent (out-of-band) data and the other for normal
   1944   data.  The urgent data is provided to TCP as soon as it is available,
   1945   allowing the TCP layer to schedule transmission of the urgent data
   1946   between packets of normal data.
   1947 
   1948   This routine is called by ::EslSocketTransmit to buffer
   1949   data for transmission.  When the \ref TransmitEngine has resources,
   1950   this routine will start the transmission of the next buffer on
   1951   the network connection.
   1952 
   1953   Transmission errors are returned during the next transmission or
   1954   during the close operation.  Only buffering errors are returned
   1955   during the current transmission attempt.
   1956 
   1957   @param [in] pSocket         Address of an ::ESL_SOCKET structure
   1958 
   1959   @param [in] Flags           Message control flags
   1960 
   1961   @param [in] BufferLength    Length of the the buffer
   1962 
   1963   @param [in] pBuffer         Address of a buffer to receive the data.
   1964 
   1965   @param [in] pDataLength     Number of received data bytes in the buffer.
   1966 
   1967   @param [in] pAddress        Network address of the remote system address
   1968 
   1969   @param [in] AddressLength   Length of the remote network address structure
   1970 
   1971   @retval EFI_SUCCESS - Socket data successfully buffered
   1972 
   1973  **/
   1974 EFI_STATUS
   1975 EslTcp6TxBuffer (
   1976   IN ESL_SOCKET * pSocket,
   1977   IN int Flags,
   1978   IN size_t BufferLength,
   1979   IN CONST UINT8 * pBuffer,
   1980   OUT size_t * pDataLength,
   1981   IN const struct sockaddr * pAddress,
   1982   IN socklen_t AddressLength
   1983   )
   1984 {
   1985   BOOLEAN bUrgent;
   1986   BOOLEAN bUrgentQueue;
   1987   ESL_PACKET * pPacket;
   1988   ESL_IO_MGMT ** ppActive;
   1989   ESL_IO_MGMT ** ppFree;
   1990   ESL_PORT * pPort;
   1991   ESL_PACKET ** ppQueueHead;
   1992   ESL_PACKET ** ppQueueTail;
   1993   ESL_PACKET * pPreviousPacket;
   1994   size_t * pTxBytes;
   1995   EFI_TCP6_TRANSMIT_DATA * pTxData;
   1996   EFI_STATUS Status;
   1997   EFI_TPL TplPrevious;
   1998 
   1999   DBG_ENTER ( );
   2000 
   2001   //
   2002   //  Assume failure
   2003   //
   2004   Status = EFI_UNSUPPORTED;
   2005   pSocket->errno = ENOTCONN;
   2006   *pDataLength = 0;
   2007 
   2008   //
   2009   //  Verify that the socket is connected
   2010   //
   2011   if ( SOCKET_STATE_CONNECTED == pSocket->State ) {
   2012     //
   2013     //  Locate the port
   2014     //
   2015     pPort = pSocket->pPortList;
   2016     if ( NULL != pPort ) {
   2017       //
   2018       //  Determine the queue head
   2019       //
   2020       bUrgent = (BOOLEAN)( 0 != ( Flags & MSG_OOB ));
   2021       bUrgentQueue = bUrgent
   2022                     && ( !pSocket->bOobInLine )
   2023                     && pSocket->pApi->bOobSupported;
   2024       if ( bUrgentQueue ) {
   2025         ppQueueHead = &pSocket->pTxOobPacketListHead;
   2026         ppQueueTail = &pSocket->pTxOobPacketListTail;
   2027         ppActive = &pPort->pTxOobActive;
   2028         ppFree = &pPort->pTxOobFree;
   2029         pTxBytes = &pSocket->TxOobBytes;
   2030       }
   2031       else {
   2032         ppQueueHead = &pSocket->pTxPacketListHead;
   2033         ppQueueTail = &pSocket->pTxPacketListTail;
   2034         ppActive = &pPort->pTxActive;
   2035         ppFree = &pPort->pTxFree;
   2036         pTxBytes = &pSocket->TxBytes;
   2037       }
   2038 
   2039       //
   2040       //  Verify that there is enough room to buffer another
   2041       //  transmit operation
   2042       //
   2043       if ( pSocket->MaxTxBuf > *pTxBytes ) {
   2044         if ( pPort->bTxFlowControl ) {
   2045           DEBUG (( DEBUG_TX,
   2046                     "TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT\r\n0x%08x: pPort, TX flow control released, Max bytes: %d > %d bufferred bytes\r\n",
   2047                     pPort,
   2048                     pSocket->MaxTxBuf,
   2049                     *pTxBytes ));
   2050           pPort->bTxFlowControl = FALSE;
   2051         }
   2052 
   2053         //
   2054         //  Attempt to allocate the packet
   2055         //
   2056         Status = EslSocketPacketAllocate ( &pPacket,
   2057                                            sizeof ( pPacket->Op.Tcp6Tx )
   2058                                            - sizeof ( pPacket->Op.Tcp6Tx.Buffer )
   2059                                            + BufferLength,
   2060                                            0,
   2061                                            DEBUG_TX );
   2062         if ( !EFI_ERROR ( Status )) {
   2063           //
   2064           //  Initialize the transmit operation
   2065           //
   2066           pTxData = &pPacket->Op.Tcp6Tx.TxData;
   2067           pTxData->Push = TRUE || bUrgent;
   2068           pTxData->Urgent = bUrgent;
   2069           pTxData->DataLength = (UINT32) BufferLength;
   2070           pTxData->FragmentCount = 1;
   2071           pTxData->FragmentTable[0].FragmentLength = (UINT32) BufferLength;
   2072           pTxData->FragmentTable[0].FragmentBuffer = &pPacket->Op.Tcp6Tx.Buffer[0];
   2073 
   2074           //
   2075           //  Copy the data into the buffer
   2076           //
   2077           CopyMem ( &pPacket->Op.Tcp6Tx.Buffer[0],
   2078                     pBuffer,
   2079                     BufferLength );
   2080 
   2081           //
   2082           //  Synchronize with the socket layer
   2083           //
   2084           RAISE_TPL ( TplPrevious, TPL_SOCKETS );
   2085 
   2086           //
   2087           //  Stop transmission after an error
   2088           //
   2089           if ( !EFI_ERROR ( pSocket->TxError )) {
   2090             //
   2091             //  Display the request
   2092             //
   2093             DEBUG (( DEBUG_TX,
   2094                       "Send %d %s bytes from 0x%08x\r\n",
   2095                       BufferLength,
   2096                       bUrgent ? L"urgent" : L"normal",
   2097                       pBuffer ));
   2098 
   2099             //
   2100             //  Queue the data for transmission
   2101             //
   2102             pPacket->pNext = NULL;
   2103             pPreviousPacket = *ppQueueTail;
   2104             if ( NULL == pPreviousPacket ) {
   2105               *ppQueueHead = pPacket;
   2106             }
   2107             else {
   2108               pPreviousPacket->pNext = pPacket;
   2109             }
   2110             *ppQueueTail = pPacket;
   2111             DEBUG (( DEBUG_TX,
   2112                       "0x%08x: Packet on %s transmit list\r\n",
   2113                       pPacket,
   2114                       bUrgentQueue ? L"urgent" : L"normal" ));
   2115 
   2116             //
   2117             //  Account for the buffered data
   2118             //
   2119             *pTxBytes += BufferLength;
   2120             *pDataLength = BufferLength;
   2121 
   2122             //
   2123             //  Start the transmit engine if it is idle
   2124             //
   2125             if ( NULL != *ppFree ) {
   2126               EslSocketTxStart ( pPort,
   2127                                  ppQueueHead,
   2128                                  ppQueueTail,
   2129                                  ppActive,
   2130                                  ppFree );
   2131             }
   2132           }
   2133           else {
   2134             //
   2135             //  Previous transmit error
   2136             //  Stop transmission
   2137             //
   2138             Status = pSocket->TxError;
   2139             pSocket->errno = EIO;
   2140 
   2141             //
   2142             //  Free the packet
   2143             //
   2144             EslSocketPacketFree ( pPacket, DEBUG_TX );
   2145           }
   2146 
   2147           //
   2148           //  Release the socket layer synchronization
   2149           //
   2150           RESTORE_TPL ( TplPrevious );
   2151         }
   2152         else {
   2153           //
   2154           //  Packet allocation failed
   2155           //
   2156           pSocket->errno = ENOMEM;
   2157         }
   2158       }
   2159       else {
   2160         if ( !pPort->bTxFlowControl ) {
   2161           DEBUG (( DEBUG_TX,
   2162                     "0x%08x: pPort, TX flow control applied, Max bytes %d <= %d bufferred bytes\r\nTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT\r\n",
   2163                     pPort,
   2164                     pSocket->MaxTxBuf,
   2165                     *pTxBytes ));
   2166           pPort->bTxFlowControl = TRUE;
   2167         }
   2168         //
   2169         //  Not enough buffer space available
   2170         //
   2171         pSocket->errno = EAGAIN;
   2172         Status = EFI_NOT_READY;
   2173       }
   2174     }
   2175   }
   2176 
   2177   //
   2178   //  Return the operation status
   2179   //
   2180   DBG_EXIT_STATUS ( Status );
   2181   return Status;
   2182 }
   2183 
   2184 
   2185 /**
   2186   Process the normal data transmit completion
   2187 
   2188   This routine use ::EslSocketTxComplete to perform the transmit
   2189   completion processing for normal data.
   2190 
   2191   This routine is called by the TCPv6 network layer when a
   2192   normal data transmit request completes.
   2193 
   2194   @param [in] Event     The normal transmit completion event
   2195 
   2196   @param [in] pIo       The ESL_IO_MGMT structure address
   2197 
   2198 **/
   2199 VOID
   2200 EslTcp6TxComplete (
   2201   IN EFI_EVENT Event,
   2202   IN ESL_IO_MGMT * pIo
   2203   )
   2204 {
   2205   UINT32 LengthInBytes;
   2206   ESL_PACKET * pPacket;
   2207   ESL_PORT * pPort;
   2208   ESL_SOCKET * pSocket;
   2209   EFI_STATUS Status;
   2210 
   2211   DBG_ENTER ( );
   2212 
   2213   //
   2214   //  Locate the active transmit packet
   2215   //
   2216   pPacket = pIo->pPacket;
   2217   pPort = pIo->pPort;
   2218   pSocket = pPort->pSocket;
   2219 
   2220   //
   2221   //  Get the transmit length and status
   2222   //
   2223   LengthInBytes = pPacket->Op.Tcp6Tx.TxData.DataLength;
   2224   pSocket->TxBytes -= LengthInBytes;
   2225   Status = pIo->Token.Tcp6Tx.CompletionToken.Status;
   2226 
   2227   //
   2228   //  Complete the transmit operation
   2229   //
   2230   EslSocketTxComplete ( pIo,
   2231                         LengthInBytes,
   2232                         Status,
   2233                         "Normal ",
   2234                         &pSocket->pTxPacketListHead,
   2235                         &pSocket->pTxPacketListTail,
   2236                         &pPort->pTxActive,
   2237                         &pPort->pTxFree );
   2238   DBG_EXIT ( );
   2239 }
   2240 
   2241 
   2242 /**
   2243   Process the urgent data transmit completion
   2244 
   2245   This routine use ::EslSocketTxComplete to perform the transmit
   2246   completion processing for urgent data.
   2247 
   2248   This routine is called by the TCPv6 network layer when a
   2249   urgent data transmit request completes.
   2250 
   2251   @param [in] Event     The urgent transmit completion event
   2252 
   2253   @param [in] pIo       The ESL_IO_MGMT structure address
   2254 
   2255 **/
   2256 VOID
   2257 EslTcp6TxOobComplete (
   2258   IN EFI_EVENT Event,
   2259   IN ESL_IO_MGMT * pIo
   2260   )
   2261 {
   2262   UINT32 LengthInBytes;
   2263   ESL_PACKET * pPacket;
   2264   ESL_PORT * pPort;
   2265   ESL_SOCKET * pSocket;
   2266   EFI_STATUS Status;
   2267 
   2268   DBG_ENTER ( );
   2269 
   2270   //
   2271   //  Locate the active transmit packet
   2272   //
   2273   pPacket = pIo->pPacket;
   2274   pPort = pIo->pPort;
   2275   pSocket = pPort->pSocket;
   2276 
   2277   //
   2278   //  Get the transmit length and status
   2279   //
   2280   LengthInBytes = pPacket->Op.Tcp6Tx.TxData.DataLength;
   2281   pSocket->TxOobBytes -= LengthInBytes;
   2282   Status = pIo->Token.Tcp6Tx.CompletionToken.Status;
   2283 
   2284   //
   2285   //  Complete the transmit operation
   2286   //
   2287   EslSocketTxComplete ( pIo,
   2288                         LengthInBytes,
   2289                         Status,
   2290                         "Urgent ",
   2291                         &pSocket->pTxOobPacketListHead,
   2292                         &pSocket->pTxOobPacketListTail,
   2293                         &pPort->pTxOobActive,
   2294                         &pPort->pTxOobFree );
   2295   DBG_EXIT ( );
   2296 }
   2297 
   2298 
   2299 /**
   2300   Verify the adapter's IP address
   2301 
   2302   This support routine is called by EslSocketBindTest.
   2303 
   2304   @param [in] pPort       Address of an ::ESL_PORT structure.
   2305   @param [in] pConfigData Address of the configuration data
   2306 
   2307   @retval EFI_SUCCESS - The IP address is valid
   2308   @retval EFI_NOT_STARTED - The IP address is invalid
   2309 
   2310  **/
   2311 EFI_STATUS
   2312 EslTcp6VerifyLocalIpAddress (
   2313   IN ESL_PORT * pPort,
   2314   IN EFI_TCP6_CONFIG_DATA * pConfigData
   2315   )
   2316 {
   2317   UINTN AddressCount;
   2318   EFI_IP6_ADDRESS_INFO * pAddressInfo;
   2319   UINTN DataSize;
   2320   EFI_TCP6_ACCESS_POINT * pAccess;
   2321   EFI_IP6_CONFIG_INTERFACE_INFO * pIpConfigData;
   2322   EFI_IP6_CONFIG_PROTOCOL * pIpConfigProtocol;
   2323   ESL_SERVICE * pService;
   2324   EFI_STATUS Status;
   2325 
   2326   DBG_ENTER ( );
   2327 
   2328   //
   2329   //  Use break instead of goto
   2330   //
   2331   pIpConfigData = NULL;
   2332   for ( ; ; ) {
   2333     //
   2334     //  Determine if the IP address is specified
   2335     //
   2336     pAccess = &pConfigData->AccessPoint;
   2337     DEBUG (( DEBUG_BIND,
   2338               "Requested IP address: %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x\r\n",
   2339               pAccess->StationAddress.Addr[0],
   2340               pAccess->StationAddress.Addr[1],
   2341               pAccess->StationAddress.Addr[2],
   2342               pAccess->StationAddress.Addr[3],
   2343               pAccess->StationAddress.Addr[4],
   2344               pAccess->StationAddress.Addr[5],
   2345               pAccess->StationAddress.Addr[6],
   2346               pAccess->StationAddress.Addr[7],
   2347               pAccess->StationAddress.Addr[8],
   2348               pAccess->StationAddress.Addr[9],
   2349               pAccess->StationAddress.Addr[10],
   2350               pAccess->StationAddress.Addr[11],
   2351               pAccess->StationAddress.Addr[12],
   2352               pAccess->StationAddress.Addr[13],
   2353               pAccess->StationAddress.Addr[14],
   2354               pAccess->StationAddress.Addr[15]));
   2355     if (( 0 == pAccess->StationAddress.Addr [ 0 ])
   2356       && ( 0 == pAccess->StationAddress.Addr [ 1 ])
   2357       && ( 0 == pAccess->StationAddress.Addr [ 2 ])
   2358       && ( 0 == pAccess->StationAddress.Addr [ 3 ])
   2359       && ( 0 == pAccess->StationAddress.Addr [ 4 ])
   2360       && ( 0 == pAccess->StationAddress.Addr [ 5 ])
   2361       && ( 0 == pAccess->StationAddress.Addr [ 6 ])
   2362       && ( 0 == pAccess->StationAddress.Addr [ 7 ])
   2363       && ( 0 == pAccess->StationAddress.Addr [ 8 ])
   2364       && ( 0 == pAccess->StationAddress.Addr [ 9 ])
   2365       && ( 0 == pAccess->StationAddress.Addr [ 10 ])
   2366       && ( 0 == pAccess->StationAddress.Addr [ 11 ])
   2367       && ( 0 == pAccess->StationAddress.Addr [ 12 ])
   2368       && ( 0 == pAccess->StationAddress.Addr [ 13 ])
   2369       && ( 0 == pAccess->StationAddress.Addr [ 14 ])
   2370       && ( 0 == pAccess->StationAddress.Addr [ 15 ]))
   2371     {
   2372       Status = EFI_SUCCESS;
   2373       break;
   2374     }
   2375 
   2376     //
   2377     //  Open the configuration protocol
   2378     //
   2379     pService = pPort->pService;
   2380     Status = gBS->OpenProtocol ( pService->Controller,
   2381                                  &gEfiIp6ConfigProtocolGuid,
   2382                                  (VOID **)&pIpConfigProtocol,
   2383                                  NULL,
   2384                                  NULL,
   2385                                  EFI_OPEN_PROTOCOL_GET_PROTOCOL );
   2386     if ( EFI_ERROR ( Status )) {
   2387       DEBUG (( DEBUG_ERROR,
   2388                 "ERROR - IP Configuration Protocol not available, Status: %r\r\n",
   2389                 Status ));
   2390       break;
   2391     }
   2392 
   2393     //
   2394     //  Get the IP configuration data size
   2395     //
   2396     DataSize = 0;
   2397     Status = pIpConfigProtocol->GetData ( pIpConfigProtocol,
   2398                                           Ip6ConfigDataTypeInterfaceInfo,
   2399                                           &DataSize,
   2400                                           NULL );
   2401     if ( EFI_BUFFER_TOO_SMALL != Status ) {
   2402       DEBUG (( DEBUG_ERROR,
   2403                 "ERROR - Failed to get IP Configuration data size, Status: %r\r\n",
   2404                 Status ));
   2405       break;
   2406     }
   2407 
   2408     //
   2409     //  Allocate the configuration data buffer
   2410     //
   2411     pIpConfigData = AllocatePool ( DataSize );
   2412     if ( NULL == pIpConfigData ) {
   2413       DEBUG (( DEBUG_ERROR,
   2414                 "ERROR - Not enough memory to allocate IP Configuration data!\r\n" ));
   2415       Status = EFI_OUT_OF_RESOURCES;
   2416       break;
   2417     }
   2418 
   2419     //
   2420     //  Get the IP configuration
   2421     //
   2422     Status = pIpConfigProtocol->GetData ( pIpConfigProtocol,
   2423                                           Ip6ConfigDataTypeInterfaceInfo,
   2424                                           &DataSize,
   2425                                           pIpConfigData );
   2426     if ( EFI_ERROR ( Status )) {
   2427       DEBUG (( DEBUG_ERROR,
   2428                 "ERROR - Failed to return IP Configuration data, Status: %r\r\n",
   2429                 Status ));
   2430       break;
   2431     }
   2432 
   2433     //
   2434     //  Display the current configuration
   2435     //
   2436     DEBUG (( DEBUG_BIND,
   2437               "Actual adapter IP address: %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x\r\n",
   2438               pIpConfigData->HwAddress.Addr [ 0 ],
   2439               pIpConfigData->HwAddress.Addr [ 1 ],
   2440               pIpConfigData->HwAddress.Addr [ 2 ],
   2441               pIpConfigData->HwAddress.Addr [ 3 ],
   2442               pIpConfigData->HwAddress.Addr [ 4 ],
   2443               pIpConfigData->HwAddress.Addr [ 5 ],
   2444               pIpConfigData->HwAddress.Addr [ 6 ],
   2445               pIpConfigData->HwAddress.Addr [ 7 ],
   2446               pIpConfigData->HwAddress.Addr [ 8 ],
   2447               pIpConfigData->HwAddress.Addr [ 9 ],
   2448               pIpConfigData->HwAddress.Addr [ 10 ],
   2449               pIpConfigData->HwAddress.Addr [ 11 ],
   2450               pIpConfigData->HwAddress.Addr [ 12 ],
   2451               pIpConfigData->HwAddress.Addr [ 13 ],
   2452               pIpConfigData->HwAddress.Addr [ 14 ],
   2453               pIpConfigData->HwAddress.Addr [ 15 ]));
   2454 
   2455     //
   2456     //  Validate the hardware address
   2457     //
   2458     Status = EFI_SUCCESS;
   2459     if (( 16 == pIpConfigData->HwAddressSize )
   2460       && ( pAccess->StationAddress.Addr [ 0 ] == pIpConfigData->HwAddress.Addr [ 0 ])
   2461       && ( pAccess->StationAddress.Addr [ 1 ] == pIpConfigData->HwAddress.Addr [ 1 ])
   2462       && ( pAccess->StationAddress.Addr [ 2 ] == pIpConfigData->HwAddress.Addr [ 2 ])
   2463       && ( pAccess->StationAddress.Addr [ 3 ] == pIpConfigData->HwAddress.Addr [ 3 ])
   2464       && ( pAccess->StationAddress.Addr [ 4 ] == pIpConfigData->HwAddress.Addr [ 4 ])
   2465       && ( pAccess->StationAddress.Addr [ 5 ] == pIpConfigData->HwAddress.Addr [ 5 ])
   2466       && ( pAccess->StationAddress.Addr [ 6 ] == pIpConfigData->HwAddress.Addr [ 6 ])
   2467       && ( pAccess->StationAddress.Addr [ 7 ] == pIpConfigData->HwAddress.Addr [ 7 ])
   2468       && ( pAccess->StationAddress.Addr [ 8 ] == pIpConfigData->HwAddress.Addr [ 8 ])
   2469       && ( pAccess->StationAddress.Addr [ 9 ] == pIpConfigData->HwAddress.Addr [ 9 ])
   2470       && ( pAccess->StationAddress.Addr [ 10 ] == pIpConfigData->HwAddress.Addr [ 10 ])
   2471       && ( pAccess->StationAddress.Addr [ 11 ] == pIpConfigData->HwAddress.Addr [ 11 ])
   2472       && ( pAccess->StationAddress.Addr [ 12 ] == pIpConfigData->HwAddress.Addr [ 12 ])
   2473       && ( pAccess->StationAddress.Addr [ 13 ] == pIpConfigData->HwAddress.Addr [ 13 ])
   2474       && ( pAccess->StationAddress.Addr [ 14 ] == pIpConfigData->HwAddress.Addr [ 14 ])
   2475       && ( pAccess->StationAddress.Addr [ 15 ] == pIpConfigData->HwAddress.Addr [ 15 ])) {
   2476       break;
   2477     }
   2478 
   2479     //
   2480     //  Walk the list of other IP addresses assigned to this adapter
   2481     //
   2482     for ( AddressCount = 0; pIpConfigData->AddressInfoCount > AddressCount; AddressCount += 1 ) {
   2483       pAddressInfo = &pIpConfigData->AddressInfo [ AddressCount ];
   2484 
   2485       //
   2486       //  Display the IP address
   2487       //
   2488       DEBUG (( DEBUG_BIND,
   2489                 "Actual adapter IP address: %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x\r\n",
   2490                 pAddressInfo->Address.Addr [ 0 ],
   2491                 pAddressInfo->Address.Addr [ 1 ],
   2492                 pAddressInfo->Address.Addr [ 2 ],
   2493                 pAddressInfo->Address.Addr [ 3 ],
   2494                 pAddressInfo->Address.Addr [ 4 ],
   2495                 pAddressInfo->Address.Addr [ 5 ],
   2496                 pAddressInfo->Address.Addr [ 6 ],
   2497                 pAddressInfo->Address.Addr [ 7 ],
   2498                 pAddressInfo->Address.Addr [ 8 ],
   2499                 pAddressInfo->Address.Addr [ 9 ],
   2500                 pAddressInfo->Address.Addr [ 10 ],
   2501                 pAddressInfo->Address.Addr [ 11 ],
   2502                 pAddressInfo->Address.Addr [ 12 ],
   2503                 pAddressInfo->Address.Addr [ 13 ],
   2504                 pAddressInfo->Address.Addr [ 14 ],
   2505                 pAddressInfo->Address.Addr [ 15 ]));
   2506 
   2507       //
   2508       //  Validate the IP address
   2509       //
   2510       if (( pAccess->StationAddress.Addr [ 0 ] == pAddressInfo->Address.Addr [ 0 ])
   2511         && ( pAccess->StationAddress.Addr [ 1 ] == pAddressInfo->Address.Addr [ 1 ])
   2512         && ( pAccess->StationAddress.Addr [ 2 ] == pAddressInfo->Address.Addr [ 2 ])
   2513         && ( pAccess->StationAddress.Addr [ 3 ] == pAddressInfo->Address.Addr [ 3 ])
   2514         && ( pAccess->StationAddress.Addr [ 4 ] == pAddressInfo->Address.Addr [ 4 ])
   2515         && ( pAccess->StationAddress.Addr [ 5 ] == pAddressInfo->Address.Addr [ 5 ])
   2516         && ( pAccess->StationAddress.Addr [ 6 ] == pAddressInfo->Address.Addr [ 6 ])
   2517         && ( pAccess->StationAddress.Addr [ 7 ] == pAddressInfo->Address.Addr [ 7 ])
   2518         && ( pAccess->StationAddress.Addr [ 8 ] == pAddressInfo->Address.Addr [ 8 ])
   2519         && ( pAccess->StationAddress.Addr [ 9 ] == pAddressInfo->Address.Addr [ 9 ])
   2520         && ( pAccess->StationAddress.Addr [ 10 ] == pAddressInfo->Address.Addr [ 10 ])
   2521         && ( pAccess->StationAddress.Addr [ 11 ] == pAddressInfo->Address.Addr [ 11 ])
   2522         && ( pAccess->StationAddress.Addr [ 12 ] == pAddressInfo->Address.Addr [ 12 ])
   2523         && ( pAccess->StationAddress.Addr [ 13 ] == pAddressInfo->Address.Addr [ 13 ])
   2524         && ( pAccess->StationAddress.Addr [ 14 ] == pAddressInfo->Address.Addr [ 14 ])
   2525         && ( pAccess->StationAddress.Addr [ 15 ] == pAddressInfo->Address.Addr [ 15 ])) {
   2526         break;
   2527       }
   2528     }
   2529     if ( pIpConfigData->AddressInfoCount > AddressCount ) {
   2530       break;
   2531     }
   2532 
   2533     //
   2534     //  The IP address did not match
   2535     //
   2536     Status = EFI_NOT_STARTED;
   2537     break;
   2538   }
   2539 
   2540   //
   2541   //  Free the buffer if necessary
   2542   //
   2543   if ( NULL != pIpConfigData ) {
   2544     FreePool ( pIpConfigData );
   2545   }
   2546 
   2547   //
   2548   //  Return the IP address status
   2549   //
   2550   DBG_EXIT_STATUS ( Status );
   2551   return Status;
   2552 }
   2553 
   2554 
   2555 /**
   2556   Interface between the socket layer and the network specific
   2557   code that supports SOCK_STREAM and SOCK_SEQPACKET sockets
   2558   over TCPv6.
   2559 **/
   2560 CONST ESL_PROTOCOL_API cEslTcp6Api = {
   2561   "TCPv6",
   2562   IPPROTO_TCP,
   2563   OFFSET_OF ( ESL_PORT, Context.Tcp6.ConfigData ),
   2564   OFFSET_OF ( ESL_LAYER, pTcp6List ),
   2565   sizeof ( struct sockaddr_in6 ),
   2566   sizeof ( struct sockaddr_in6 ),
   2567   AF_INET6,
   2568   sizeof (((ESL_PACKET *)0 )->Op.Tcp6Rx ),
   2569   OFFSET_OF ( ESL_PACKET, Op.Tcp6Rx.Buffer ) - OFFSET_OF ( ESL_PACKET, Op ),
   2570   OFFSET_OF ( ESL_IO_MGMT, Token.Tcp6Rx.Packet.RxData ),
   2571   TRUE,
   2572   EADDRINUSE,
   2573   EslTcp6Accept,
   2574   EslTcp6ConnectPoll,
   2575   EslTcp6ConnectStart,
   2576   EslTcp6SocketIsConfigured,
   2577   EslTcp6LocalAddressGet,
   2578   EslTcp6LocalAddressSet,
   2579   EslTcp6Listen,
   2580   NULL,   //  OptionGet
   2581   NULL,   //  OptionSet
   2582   EslTcp6PacketFree,
   2583   EslTcp6PortAllocate,
   2584   EslTcp6PortClose,
   2585   EslTcp6PortCloseOp,
   2586   FALSE,
   2587   EslTcp6Receive,
   2588   EslTcp6RemoteAddressGet,
   2589   EslTcp6RemoteAddressSet,
   2590   EslTcp6RxComplete,
   2591   EslTcp6RxStart,
   2592   EslTcp6TxBuffer,
   2593   EslTcp6TxComplete,
   2594   EslTcp6TxOobComplete,
   2595   (PFN_API_VERIFY_LOCAL_IP_ADDRESS)EslTcp6VerifyLocalIpAddress
   2596 };
   2597