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