Home | History | Annotate | Download | only in EfiSocketLib
      1 /** @file
      2   Implement the socket support for the socket layer.
      3 
      4   Socket States:
      5   * Bound - pSocket->PortList is not NULL
      6   * Listen - AcceptWait event is not NULL
      7 
      8   Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>
      9   This program and the accompanying materials are licensed and made available under
     10   the terms and conditions of the BSD License that accompanies this distribution.
     11   The full text of the license may be found at
     12   http://opensource.org/licenses/bsd-license.php
     13 
     14   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     15   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     16 
     17 
     18   \section DataStructures Data Structures
     19 
     20   <code><pre>
     21 
     22                 +---------------+   +-------------+   +-------------+
     23   Service Lists | ::ESL_SERVICE |-->| ESL_SERVICE |-->| ESL_SERVICE |--> NULL (pNext)
     24                 +---------------+   +-------------+   +-------------+
     25                   ^                       | (pPortList)    |
     26     pUdp4List ^   | pTcp4List             |                |
     27               |   |                       |                |
     28           ^   |   |                       |                |
     29  pIp4List |   |   |                       |                |
     30         +---------------+                 |                |
     31         | ::ESL_LAYER   | ::mEslLayer     |                |
     32         +---------------+                 |                |
     33                   | (pSocketList)         |                |
     34     Socket List   V                       V                V
     35                 +---------------+   +-------------+   +-------------+
     36                 | ::ESL_SOCKET  |-->| ::ESL_PORT  |-->|   ESL_PORT  |--> NULL (pLinkSocket)
     37                 +---------------+   +-------------+   +-------------+
     38                   |                       |                |
     39                   |                       |                V
     40                   V                       V               NULL
     41                 +-------------+   +-------------+
     42                 | ESL_SOCKET  |-->|   ESL_PORT  |--> NULL
     43                 +-------------+   +-------------+
     44                   |    | | | |            |
     45                   V    | | | |            V
     46                  NULL  | | | |           NULL
     47                (pNext) | | | |     (pLinkService)
     48                        | | | |                                     pRxPacketListHead
     49                        | | | `-----------------------------------------------.
     50                        | | |                     pRxOobPacketListHead        |
     51                        | | `--------------------------------.                |
     52                        | |      pTxPacketListHead           |                |
     53                        | `---------------.                  |                |
     54   pTxOobPacketListHead |                 |                  |                |
     55                        V                 V                  V                V
     56                   +--------------+    +------------+    +------------+    +------------+
     57                   | ::ESL_PACKET |    | ESL_PACKET |    | ESL_PACKET |    | ESL_PACKET |
     58                   +--------------+    +------------+    +------------+    +------------+
     59                          |                 |                |                |
     60                          V                 V                V                V
     61                   +------------+    +------------+    +------------+    +------------+
     62                   | ESL_PACKET |    | ESL_PACKET |    | ESL_PACKET |    | ESL_PACKET |
     63                   +------------+    +------------+    +------------+    +------------+
     64                          |                 |                |                |
     65                          V                 V                V                V
     66                         NULL              NULL             NULL             NULL
     67                        (pNext)
     68 
     69   </pre></code>
     70 
     71   ::mEslLayer is the one and only ::ESL_LAYER structure.  It connects directly or
     72   indirectly to the other data structures.  The ESL_LAYER structure has a unique
     73   service list for each of the network protocol interfaces.
     74 
     75   ::ESL_SERVICE manages the network interfaces for a given transport type (IP4, TCP4, UDP4, etc.)
     76 
     77   ::ESL_SOCKET manages the activity for a single socket instance.  As such, it contains
     78   the ::EFI_SOCKET_PROTOCOL structure which the BSD socket library uses as the object
     79   reference and the API into the EFI socket library.
     80 
     81   ::ESL_PORT manages the connection with a single instance of the lower layer network.
     82   This structure is the socket equivalent of an IP connection or a TCP or UDP port.
     83 
     84   ::ESL_PACKET buffers data for transmit and receive.  There are four queues connected
     85   to the ::ESL_SOCKET that manage the data:
     86   <ul>
     87     <li>ESL_SOCKET::pRxPacketListHead - Normal (low) priority receive data</li>
     88     <li>ESL_SOCKET::pRxOobPacketListHead - High (out-of-band or urgent) priority receive data</li>
     89     <li>ESL_SOCKET::pTxPacketListHead - Normal (low) priority transmit data</li>
     90     <li>ESL_SOCKET::pTxOobPacketListHead - High (out-of-band or urgent) priority transmit data</li>
     91   </ul>
     92   The selection of the transmit queue is controlled by the MSG_OOB flag on the transmit
     93   request as well as the socket option SO_OOBINLINE.  The receive queue is selected by
     94   the URGENT data flag for TCP and the setting of the socket option SO_OOBINLINE.
     95 
     96   Data structure synchronization is done by raising TPL to TPL_SOCKET.  Modifying
     97   critical elements within the data structures must be done at this TPL.  TPL is then
     98   restored to the previous level.  Note that the code verifies that all callbacks are
     99   entering at TPL_SOCKETS for proper data structure synchronization.
    100 
    101   \section PortCloseStateMachine Port Close State Machine
    102 
    103   The port close state machine walks the port through the necessary
    104   states to stop activity on the port and get it into a state where
    105   the resources may be released.  The state machine consists of the
    106   following arcs and states:
    107 
    108   <code><pre>
    109 
    110       +--------------------------+
    111       |          Open            |
    112       +--------------------------+
    113                    |
    114                    |  ::EslSocketPortCloseStart
    115                    V
    116       +--------------------------+
    117       | PORT_STATE_CLOSE_STARTED |
    118       +--------------------------+
    119                    |
    120                    |  ::EslSocketPortCloseTxDone
    121                    V
    122       +--------------------------+
    123       | PORT_STATE_CLOSE_TX_DONE |
    124       +--------------------------+
    125                    |
    126                    |  ::EslSocketPortCloseComplete
    127                    V
    128       +--------------------------+
    129       |  PORT_STATE_CLOSE_DONE   |
    130       +--------------------------+
    131                    |
    132                    |  ::EslSocketPortCloseRxDone
    133                    V
    134       +--------------------------+
    135       | PORT_STATE_CLOSE_RX_DONE |
    136       +--------------------------+
    137                    |
    138                    |  ::EslSocketPortClose
    139                    V
    140       +--------------------------+
    141       |          Closed          |
    142       +--------------------------+
    143 
    144   </pre></code>
    145 
    146   <ul>
    147     <li>Arc: ::EslSocketPortCloseStart - Marks the port as closing and
    148       initiates the port close operation</li>
    149     <li>State: PORT_STATE_CLOSE_STARTED</li>
    150     <li>Arc: ::EslSocketPortCloseTxDone - Waits until all of the transmit
    151       operations to complete.  After all of the transmits are complete,
    152       this routine initiates the network specific close operation by calling
    153       through ESL_PROTOCOL_API::pfnPortCloseOp.  One such routine is
    154       ::EslTcp4PortCloseOp.
    155     </li>
    156     <li>State: PORT_STATE_CLOSE_TX_DONE</li>
    157     <li>Arc: ::EslSocketPortCloseComplete - Called when the close operation is
    158       complete.  After the transition to PORT_STATE_CLOSE_DONE,
    159       this routine calls ::EslSocketRxCancel to abort the pending receive operations.
    160     </li>
    161     <li>State: PORT_STATE_CLOSE_DONE</li>
    162     <li>Arc: ::EslSocketPortCloseRxDone - Waits until all of the receive
    163       operation have been cancelled.  After the transition to
    164       PORT_STATE_CLOSE_RX_DONE, this routine calls ::EslSocketPortClose.
    165     </li>
    166     <li>State: PORT_STATE_CLOSE_RX_DONE</li>
    167     <li>Arc: ::EslSocketPortClose - This routine discards any receive buffers
    168       using a network specific support routine via ESL_PROTOCOL_API::pfnPacketFree.
    169       This routine then releases the port resources allocated by ::EslSocketPortAllocate
    170       and calls the network specific port close routine (e.g. ::EslTcp4PortClose)
    171       via ESL_PROTOCOL_API::pfnPortClose to release any network specific resources.
    172     </li>
    173   </ul>
    174 
    175 
    176   \section ReceiveEngine Receive Engine
    177 
    178   The receive path accepts data from the network and queues (buffers) it for the
    179   application.  Flow control is applied once a maximum amount of buffering is reached
    180   and is released when the buffer usage drops below that limit.  Eventually the
    181   application requests data from the socket which removes entries from the queue and
    182   returns the data.
    183 
    184   The receive engine is the state machine which reads data from the network and
    185   fills the queue with received packets.  The receive engine uses two data structures
    186   to manage the network receive opeations and the buffers.
    187 
    188   At a high level, the ::ESL_IO_MGMT structures are managing the tokens and
    189   events for the interface to the UEFI network stack.  The ::ESL_PACKET
    190   structures are managing the receive data buffers.  The receive engine
    191   connects these two structures in the network specific receive completion
    192   routines.
    193 
    194 <code><pre>
    195 
    196       +------------------+
    197       |     ::ESL_PORT     |
    198       |                  |
    199       +------------------+
    200       |    ::ESL_IO_MGMT   |
    201       +------------------+
    202       |    ESL_IO_MGMT   |
    203       +------------------+
    204       .                  .
    205       .    ESL_IO_MGMT   .
    206       .                  .
    207       +------------------+
    208 
    209 </pre></code>
    210 
    211   The ::ESL_IO_MGMT structures are allocated as part of the ::ESL_PORT structure in
    212   ::EslSocketPortAllocate.  The ESL_IO_MGMT structures are separated and placed on
    213   the free list by calling ::EslSocketIoInit.  The ESL_IO_MGMT structure contains
    214   the network layer specific receive completion token and event.  The receive engine
    215   is eventually shutdown by ::EslSocketPortCloseTxDone and the resources in these
    216   structures are released in ::EslSocketPortClose by a call to ::EslSocketIoFree.
    217 
    218 <code><pre>
    219 
    220          pPort->pRxActive
    221                 |
    222                 V
    223           +-------------+   +-------------+   +-------------+
    224   Active  | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
    225           +-------------+   +-------------+   +-------------+
    226 
    227           +-------------+   +-------------+   +-------------+
    228   Free    | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
    229           +-------------+   +-------------+   +-------------+
    230                 ^
    231                 |
    232           pPort->pRxFree
    233 </pre></code>
    234 
    235   The receive engine is started by calling ::EslSocketRxStart.  Flow control pauses
    236   the receive engine by stopping the calls to EslSocketRxStart when the amount of
    237   receive data waiting for the application meets or exceeds MAX_RX_DATA.  After
    238   the application reads enough data that the amount of buffering drops below this
    239   limit, the calls to EslSockeRxStart continue which releases the flow control.
    240 
    241   Receive flow control is applied when the port is created, since no receive
    242   operation are pending to the low layer network driver.  The flow control gets
    243   released when the low layer network port is configured or the first receive
    244   operation is posted.  Flow control remains in the released state until the
    245   maximum buffer space is consumed.  During this time, ::EslSocketRxComplete
    246   calls ::EslSocketRxStart.  Flow control is applied in EslSocketRxComplete
    247   by skipping the call to EslSocketRxStart.  Flow control is eventually
    248   released in ::EslSocketReceive when the buffer space drops below the
    249   maximum amount causing EslSocketReceive to call EslSocketRxStart.
    250 
    251 <code><pre>
    252 
    253                     +------------+   +------------+
    254     High     .----->| ESL_PACKET |-->| ESL_PACKET |--> NULL (pNext)
    255   Priority   |      +------------+   +------------+
    256              |
    257              | pRxOobPacketListHead
    258        +------------+
    259        | ::ESL_SOCKET |
    260        +------------+
    261              | pRxPacketListHead
    262     Low      |
    263   Priority   |      +------------+   +------------+   +------------+
    264              `----->| ::ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL
    265                     +------------+   +------------+   +------------+
    266 
    267 </pre></code>
    268 
    269   ::EslSocketRxStart connects an ::ESL_PACKET structure to the ::ESL_IO_MGMT structure
    270   and then calls the network layer to start the receive operation.  Upon
    271   receive completion, ::EslSocketRxComplete breaks the connection between these
    272   structrues and places the ESL_IO_MGMT structure onto the ESL_PORT::pRxFree list to
    273   make token and event available for another receive operation.  EslSocketRxComplete
    274   then queues the ESL_PACKET structure (data packet) to either the
    275   ESL_SOCKET::pRxOobPacketListTail or ESL_SOCKET::pRxPacketListTail depending on
    276   whether urgent or normal data was received.  Finally ::EslSocketRxComplete attempts
    277   to start another receive operation.
    278 
    279 <code><pre>
    280 
    281   Setup for IP4 and UDP4
    282 
    283       +--------------------+
    284       | ESL_IO_MGMT        |
    285       |                    |
    286       |    +---------------+
    287       |    | Token         |
    288       |    |        RxData --> NULL
    289       +----+---------------+
    290          |
    291          V
    292       +--------------------+
    293       | ESL_PACKET         |
    294       |                    |
    295       |    +---------------+
    296       |    |       pRxData --> NULL
    297       +----+---------------+
    298 
    299   Completion for IP4 and UDP4
    300 
    301       +--------------------+   +----------------------+
    302       | ESL_IO_MGMT        |   |      Data Buffer     |
    303       |                    |   |     (Driver owned)   |
    304       |    +---------------+   +----------------------+
    305       |    | Token         |               ^
    306       |    |      Rx Event |               |
    307       |    |               |   +----------------------+
    308       |    |        RxData --> | EFI_IP4_RECEIVE_DATA |
    309       +----+---------------+   |    (Driver owned)    |
    310          |                     +----------------------+
    311          V                                 ^
    312       +--------------------+               .
    313       | ESL_PACKET         |               .
    314       |                    |               .
    315       |    +---------------+               .
    316       |    |       pRxData --> NULL  .......
    317       +----+---------------+
    318 
    319 
    320   Setup and completion for TCP4
    321 
    322       +--------------------+   +--------------------------+
    323       | ESL_IO_MGMT        |-->| ESL_PACKET               |
    324       |                    |   |                          |
    325       |    +---------------+   +----------------------+   |
    326       |    | Token         |   | EFI_IP4_RECEIVE_DATA |   |
    327       |    |        RxData --> |                      |   |
    328       |    |               |   +----------------------+---+
    329       |    |        Event  |   |       Data Buffer        |
    330       +----+---------------+   |                          |
    331                                |                          |
    332                                +--------------------------+
    333 
    334 </pre></code>
    335 
    336   To minimize the number of buffer copies, the data is not copied until the
    337   application makes a receive call.  At this point socket performs a single copy
    338   in the receive path to move the data from the buffer filled by the network layer
    339   into the application's buffer.
    340 
    341   The IP4 and UDP4 drivers go one step further to reduce buffer copies.  They
    342   allow the socket layer to hold on to the actual receive buffer until the
    343   application has performed a receive operation or closes the socket.  Both
    344   of theses operations return the buffer to the lower layer network driver
    345   by calling ESL_PROTOCOL_API::pfnPacketFree.
    346 
    347   When a socket application wants to receive data it indirectly calls
    348   ::EslSocketReceive to remove data from one of the receive data queues.  This routine
    349   removes the next available packet from ESL_SOCKET::pRxOobPacketListHead or
    350   ESL_SOCKET::pRxPacketListHead and copies the data from the packet
    351   into the application's buffer.  For SOCK_STREAM sockets, if the packet
    352   contains more data then the ESL_PACKET structures remains at the head of the
    353   receive queue for the next application receive
    354   operation.  For SOCK_DGRAM, SOCK_RAW and SOCK_SEQ_PACKET sockets, the ::ESL_PACKET
    355   structure is removed from the head of the receive queue and any remaining data is
    356   discarded as the packet is placed on the free queue.
    357 
    358   During socket layer shutdown, ::EslSocketShutdown calls ::EslSocketRxCancel to
    359   cancel any pending receive operations.  EslSocketRxCancel calls the network specific
    360   cancel routine using ESL_PORT::pfnRxCancel.
    361 
    362 
    363   \section TransmitEngine Transmit Engine
    364 
    365   Application calls to ::EslSocketTransmit cause data to be copied into a buffer.
    366   The buffer exists as an extension to an ESL_PACKET structure and the structure
    367   is placed at the end of the transmit queue.
    368 
    369 <code><pre>
    370 
    371      *ppQueueHead: pSocket->pRxPacketListHead or pSocket->pRxOobPacketListHead
    372           |
    373           V
    374         +------------+   +------------+   +------------+
    375   Data  | ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL
    376         +------------+   +------------+   +------------+
    377                                                      ^
    378                                                      |
    379      *ppQueueTail: pSocket->pRxPacketListTail or pSocket->pRxOobPacketListTail
    380 
    381 </pre></code>
    382 
    383   There are actually two transmit queues the normal or low priority queue which is
    384   the default and the urgent or high priority queue which is addressed by specifying
    385   the MSG_OOB flag during the transmit request.  Associated with each queue is a
    386   transmit engine which is responsible for sending the data in that queue.
    387 
    388   The transmit engine is the state machine which removes entries from the head
    389   of the transmit queue and causes the data to be sent over the network.
    390 
    391 <code><pre>
    392 
    393       +--------------------+   +--------------------+
    394       | ESL_IO_MGMT        |   | ESL_PACKET         |
    395       |                    |   |                    |
    396       |    +---------------+   +----------------+   |
    397       |    | Token         |   | Buffer Length  |   |
    398       |    |        TxData --> | Buffer Address |   |
    399       |    |               |   +----------------+---+
    400       |    |        Event  |   | Data Buffer        |
    401       +----+---------------+   |                    |
    402                                +--------------------+
    403 </pre></code>
    404 
    405   At a high level, the transmit engine uses a couple of data structures
    406   to manage the data flow.  The ::ESL_IO_MGMT structures manage the tokens and
    407   events for the interface to the UEFI network stack.  The ::ESL_PACKET
    408   structures manage the data buffers that get sent.  The transmit
    409   engine connects these two structures prior to transmission and disconnects
    410   them upon completion.
    411 
    412 <code><pre>
    413 
    414          pPort->pTxActive or pTxOobActive
    415                 |
    416                 V
    417           +-------------+   +-------------+   +-------------+
    418   Active  | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
    419           +-------------+   +-------------+   +-------------+
    420 
    421           +-------------+   +-------------+   +-------------+
    422   Free    | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
    423           +-------------+   +-------------+   +-------------+
    424                 ^
    425                 |
    426           pPort->pTxFree or pTxOobFree
    427 
    428 </pre></code>
    429 
    430   The transmit engine manages multiple transmit operations using the
    431   active and free lists shown above.  ::EslSocketPortAllocate allocates the
    432   ::ESL_IO_MGMT structures as an extension to the ::ESL_PORT structure.
    433   This routine places the ESL_IO_MGMT structures on the free list by calling
    434   ::EslSocketIoInit.  During their lifetime, the ESL_IO_MGMT structures
    435   will move from the free list to the active list and back again.  The
    436   active list contains the packets that are actively being processed by
    437   the UEFI network stack.  Eventually the ESL_IO_MGMT structures will be
    438   removed from the free list and be deallocated by the EslSocketPortClose
    439   routine.
    440 
    441   The network specific code calls the ::EslSocketTxStart routine
    442   to hand a packet to the network stack.  EslSocketTxStart connects
    443   the transmit packet (::ESL_PACKET) to an ::ESL_IO_MGMT structure
    444   and then queues the result to one of the active lists:
    445   ESL_PORT::pTxActive or ESL_PORT::pTxOobActive.  The routine then
    446   hands the packet to the network stack.
    447 
    448   Upon completion, the network specific TxComplete routine calls
    449   ::EslSocketTxComplete to disconnect the transmit packet from the
    450   ESL_IO_MGMT structure and frees the ::ESL_PACKET structure by calling
    451   ::EslSocketPacketFree.  The routine places the ::ESL_IO_MGMT structure
    452   into the free list either ESL_PORT::pTxFree or ESL_PORT::pTxOobFree.
    453   EslSocketTxComplete then starts the next transmit operation while
    454   the socket is active or calls the ::EslSocketPortCloseTxDone routine
    455   when the socket is shutting down.
    456 
    457 **/
    458 
    459 #include "Socket.h"
    460 
    461 
    462 /** Socket driver connection points
    463 
    464   List the network stack connection points for the socket driver.
    465 **/
    466 CONST ESL_SOCKET_BINDING cEslSocketBinding[] = {
    467   { L"Ip4",
    468     &gEfiIp4ServiceBindingProtocolGuid,
    469     &gEfiIp4ProtocolGuid,
    470     &mEslIp4ServiceGuid,
    471     OFFSET_OF ( ESL_LAYER, pIp4List ),
    472     4,    //  RX buffers
    473     4,    //  TX buffers
    474     0 },  //  TX Oob buffers
    475   { L"Tcp4",
    476     &gEfiTcp4ServiceBindingProtocolGuid,
    477     &gEfiTcp4ProtocolGuid,
    478     &mEslTcp4ServiceGuid,
    479     OFFSET_OF ( ESL_LAYER, pTcp4List ),
    480     4,    //  RX buffers
    481     4,    //  TX buffers
    482     4 },  //  TX Oob buffers
    483   { L"Tcp6",
    484     &gEfiTcp6ServiceBindingProtocolGuid,
    485     &gEfiTcp6ProtocolGuid,
    486     &mEslTcp6ServiceGuid,
    487     OFFSET_OF ( ESL_LAYER, pTcp6List ),
    488     4,    //  RX buffers
    489     4,    //  TX buffers
    490     4 },  //  TX Oob buffers
    491   { L"Udp4",
    492     &gEfiUdp4ServiceBindingProtocolGuid,
    493     &gEfiUdp4ProtocolGuid,
    494     &mEslUdp4ServiceGuid,
    495     OFFSET_OF ( ESL_LAYER, pUdp4List ),
    496     4,    //  RX buffers
    497     4,    //  TX buffers
    498     0 },  //  TX Oob buffers
    499   { L"Udp6",
    500     &gEfiUdp6ServiceBindingProtocolGuid,
    501     &gEfiUdp6ProtocolGuid,
    502     &mEslUdp6ServiceGuid,
    503     OFFSET_OF ( ESL_LAYER, pUdp6List ),
    504     4,    //  RX buffers
    505     4,    //  TX buffers
    506     0 }   //  TX Oob buffers
    507 };
    508 
    509 CONST UINTN cEslSocketBindingEntries = DIM ( cEslSocketBinding );
    510 
    511 /// APIs to support the various socket types for the v4 network stack.
    512 CONST ESL_PROTOCOL_API * cEslAfInetApi[] = {
    513   NULL,             //  0
    514   &cEslTcp4Api,     //  SOCK_STREAM
    515   &cEslUdp4Api,     //  SOCK_DGRAM
    516   &cEslIp4Api,      //  SOCK_RAW
    517   NULL,             //  SOCK_RDM
    518   &cEslTcp4Api      //  SOCK_SEQPACKET
    519 };
    520 
    521 /// Number of entries in the v4 API array ::cEslAfInetApi.
    522 CONST int cEslAfInetApiSize = DIM ( cEslAfInetApi );
    523 
    524 
    525 /// APIs to support the various socket types for the v6 network stack.
    526 CONST ESL_PROTOCOL_API * cEslAfInet6Api[] = {
    527   NULL,             //  0
    528   &cEslTcp6Api,     //  SOCK_STREAM
    529   &cEslUdp6Api,     //  SOCK_DGRAM
    530   NULL,             //  SOCK_RAW
    531   NULL,             //  SOCK_RDM
    532   &cEslTcp6Api      //  SOCK_SEQPACKET
    533 };
    534 
    535 /// Number of entries in the v6 API array ::cEslAfInet6Api.
    536 CONST int cEslAfInet6ApiSize = DIM ( cEslAfInet6Api );
    537 
    538 
    539 /// Global management structure for the socket layer.
    540 ESL_LAYER mEslLayer;
    541 
    542 
    543 /** Initialize an endpoint for network communication.
    544 
    545   This routine initializes the communication endpoint.
    546 
    547   The ::socket routine calls this routine indirectly to create
    548   the communication endpoint.
    549 
    550   @param[in] pSocketProtocol Address of the socket protocol structure.
    551   @param[in]  domain   Select the family of protocols for the client or server
    552                        application.  See the ::socket documentation for values.
    553   @param[in]  type     Specifies how to make the network connection.
    554                        See the ::socket documentation for values.
    555   @param[in]  protocol Specifies the lower layer protocol to use.
    556                        See the ::socket documentation for values.
    557   @param[out] pErrno   Address to receive the errno value upon completion.
    558 
    559   @retval EFI_SUCCESS - Socket successfully created
    560   @retval EFI_INVALID_PARAMETER - Invalid domain value, errno = EAFNOSUPPORT
    561   @retval EFI_INVALID_PARAMETER - Invalid type value, errno = EINVAL
    562   @retval EFI_INVALID_PARAMETER - Invalid protocol value, errno = EINVAL
    563  **/
    564 EFI_STATUS
    565 EslSocket (
    566   IN EFI_SOCKET_PROTOCOL * pSocketProtocol,
    567   IN int domain,
    568   IN int type,
    569   IN int protocol,
    570   IN int * pErrno
    571   )
    572 {
    573   CONST ESL_PROTOCOL_API * pApi;
    574   CONST ESL_PROTOCOL_API ** ppApiArray;
    575   CONST ESL_PROTOCOL_API ** ppApiArrayEnd;
    576   int ApiArraySize;
    577   ESL_SOCKET * pSocket;
    578   EFI_STATUS Status;
    579   int errno;
    580 
    581   DBG_ENTER ( );
    582 
    583   //  Locate the socket
    584   pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
    585 
    586   //  Set the default domain if necessary
    587   if ( AF_UNSPEC == domain ) {
    588     domain = AF_INET;
    589   }
    590 
    591   //  Assume success
    592   errno = 0;
    593   Status = EFI_SUCCESS;
    594 
    595   //  Use break instead of goto
    596   for ( ; ; ) {
    597     //  Validate the domain value
    598     if (( AF_INET != domain )
    599       && ( AF_INET6 != domain )
    600       && ( AF_LOCAL != domain )) {
    601       DEBUG (( DEBUG_ERROR | DEBUG_SOCKET,
    602                 "ERROR - Invalid domain value\r\n" ));
    603       Status = EFI_INVALID_PARAMETER;
    604       errno = EAFNOSUPPORT;
    605       break;
    606     }
    607 
    608     //  Determine the protocol APIs
    609     ppApiArray = NULL;
    610     ApiArraySize = 0;
    611     if (( AF_INET == domain )
    612       || ( AF_LOCAL == domain )) {
    613       ppApiArray = &cEslAfInetApi[0];
    614       ApiArraySize = cEslAfInetApiSize;
    615     }
    616     else {
    617       ppApiArray = &cEslAfInet6Api[0];
    618       ApiArraySize = cEslAfInet6ApiSize;
    619     }
    620 
    621     //  Set the default type if necessary
    622     if ( 0 == type ) {
    623       type = SOCK_STREAM;
    624     }
    625 
    626     //  Validate the type value
    627     if (( type >= ApiArraySize )
    628       || ( NULL == ppApiArray )
    629       || ( NULL == ppApiArray[ type ])) {
    630       DEBUG (( DEBUG_ERROR | DEBUG_SOCKET,
    631                 "ERROR - Invalid type value\r\n" ));
    632       //  The socket type is not supported
    633       Status = EFI_INVALID_PARAMETER;
    634       errno = EPROTOTYPE;
    635       break;
    636     }
    637 
    638     //  Set the default protocol if necessary
    639     pApi = ppApiArray[ type ];
    640     if ( 0 == protocol ) {
    641       protocol = pApi->DefaultProtocol;
    642     }
    643 
    644     //  Validate the protocol value
    645     if (( pApi->DefaultProtocol != protocol )
    646       && ( SOCK_RAW != type )) {
    647       Status = EFI_INVALID_PARAMETER;
    648 
    649       //  Assume that the driver supports this protocol
    650       ppApiArray = &cEslAfInetApi[0];
    651       ppApiArrayEnd = &ppApiArray [ cEslAfInetApiSize ];
    652       while ( ppApiArrayEnd > ppApiArray ) {
    653         pApi = *ppApiArray;
    654         if ( protocol == pApi->DefaultProtocol ) {
    655           break;
    656         }
    657         ppApiArray += 1;
    658       }
    659       if ( ppApiArrayEnd <= ppApiArray ) {
    660         //  Verify against the IPv6 table
    661         ppApiArray = &cEslAfInet6Api[0];
    662         ppApiArrayEnd = &ppApiArray [ cEslAfInet6ApiSize ];
    663         while ( ppApiArrayEnd > ppApiArray ) {
    664           pApi = *ppApiArray;
    665           if ( protocol == pApi->DefaultProtocol ) {
    666             break;
    667           }
    668           ppApiArray += 1;
    669         }
    670       }
    671       if ( ppApiArrayEnd <= ppApiArray ) {
    672         DEBUG (( DEBUG_ERROR | DEBUG_SOCKET,
    673                   "ERROR - The protocol is not supported!\r\n" ));
    674         errno = EPROTONOSUPPORT;
    675         break;
    676       }
    677 
    678       //  The driver does not support this protocol
    679       DEBUG (( DEBUG_ERROR | DEBUG_SOCKET,
    680                 "ERROR - The protocol does not support this socket type!\r\n" ));
    681       errno = EPROTONOSUPPORT;
    682       errno = EPROTOTYPE;
    683       break;
    684     }
    685     //  Save the socket attributes
    686     pSocket->pApi = pApi;
    687     pSocket->Domain = domain;
    688     pSocket->Type = type;
    689     pSocket->Protocol = protocol;
    690 
    691     //  Done
    692     break;
    693   }
    694   //  Return the operation status
    695   if ( NULL != pErrno ) {
    696     *pErrno = errno;
    697   }
    698   DBG_EXIT_STATUS ( Status );
    699   return Status;
    700 }
    701 
    702 
    703 /** Accept a network connection.
    704 
    705   This routine calls the network specific layer to remove the next
    706   connection from the FIFO.
    707 
    708   The ::accept calls this routine to poll for a network
    709   connection to the socket.  When a connection is available
    710   this routine returns the ::EFI_SOCKET_PROTOCOL structure address
    711   associated with the new socket and the remote network address
    712   if requested.
    713 
    714   @param[in]      pSocketProtocol   Address of an ::EFI_SOCKET_PROTOCOL structure.
    715   @param[in]      pSockAddr         Address of a buffer to receive the remote
    716                                     network address.
    717   @param[in,out]  pSockAddrLength   Length in bytes of the address buffer.
    718                                     On output specifies the length of the
    719                                     remote network address.
    720   @param[out]     ppSocketProtocol  Address of a buffer to receive the
    721                                     ::EFI_SOCKET_PROTOCOL instance
    722                                     associated with the new socket.
    723   @param[out]     pErrno            Address to receive the errno value upon completion.
    724 
    725   @retval EFI_SUCCESS   New connection successfully created
    726   @retval EFI_NOT_READY No connection is available
    727  **/
    728 EFI_STATUS
    729 EslSocketAccept (
    730   IN EFI_SOCKET_PROTOCOL * pSocketProtocol,
    731   IN struct sockaddr * pSockAddr,
    732   IN OUT socklen_t * pSockAddrLength,
    733   IN EFI_SOCKET_PROTOCOL ** ppSocketProtocol,
    734   IN int * pErrno
    735   )
    736 {
    737   ESL_SOCKET * pNewSocket;
    738   ESL_SOCKET * pSocket;
    739   EFI_STATUS Status;
    740   EFI_TPL TplPrevious;
    741 
    742   DBG_ENTER ( );
    743 
    744   //
    745   //  Assume success
    746   //
    747   Status = EFI_SUCCESS;
    748 
    749   //
    750   //  Validate the socket
    751   //
    752   pSocket = NULL;
    753   pNewSocket = NULL;
    754   if ( NULL != pSocketProtocol ) {
    755     pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
    756 
    757     //
    758     //  Verify the API
    759     //
    760     if ( NULL == pSocket->pApi->pfnAccept ) {
    761       Status = EFI_UNSUPPORTED;
    762       pSocket->errno = ENOTSUP;
    763     }
    764     else {
    765       //
    766       //  Validate the sockaddr
    767       //
    768       if (( NULL != pSockAddr )
    769         && ( NULL == pSockAddrLength )) {
    770         DEBUG (( DEBUG_ACCEPT,
    771                   "ERROR - pSockAddr is NULL!\r\n" ));
    772         Status = EFI_INVALID_PARAMETER;
    773         pSocket->errno = EFAULT;
    774       }
    775       else {
    776         //
    777         //  Synchronize with the socket layer
    778         //
    779         RAISE_TPL ( TplPrevious, TPL_SOCKETS );
    780 
    781         //
    782         //  Verify that the socket is in the listen state
    783         //
    784         if ( SOCKET_STATE_LISTENING != pSocket->State ) {
    785           DEBUG (( DEBUG_ACCEPT,
    786                     "ERROR - Socket is not listening!\r\n" ));
    787           if ( NULL == pSocket->pApi->pfnAccept ) {
    788             //
    789             //  Socket does not support listen
    790             //
    791             pSocket->errno = EOPNOTSUPP;
    792             Status = EFI_UNSUPPORTED;
    793           }
    794           else {
    795             //
    796             //  Socket supports listen, but not in listen state
    797             //
    798             pSocket->errno = EINVAL;
    799             Status = EFI_NOT_STARTED;
    800           }
    801         }
    802         else {
    803           //
    804           //  Determine if a socket is available
    805           //
    806           if ( 0 == pSocket->FifoDepth ) {
    807             //
    808             //  No connections available
    809             //  Determine if any ports are available
    810             //
    811             if ( NULL == pSocket->pPortList ) {
    812               //
    813               //  No ports available
    814               //
    815               Status = EFI_DEVICE_ERROR;
    816               pSocket->errno = EINVAL;
    817 
    818               //
    819               //  Update the socket state
    820               //
    821               pSocket->State = SOCKET_STATE_NO_PORTS;
    822             }
    823             else {
    824               //
    825               //  Ports are available
    826               //  No connection requests at this time
    827               //
    828               Status = EFI_NOT_READY;
    829               pSocket->errno = EAGAIN;
    830             }
    831           }
    832           else {
    833 
    834             //
    835             //  Attempt to accept the connection and
    836             //  get the remote network address
    837             //
    838             pNewSocket = pSocket->pFifoHead;
    839             ASSERT ( NULL != pNewSocket );
    840             Status = pSocket->pApi->pfnAccept ( pNewSocket,
    841                                                 pSockAddr,
    842                                                 pSockAddrLength );
    843             if ( !EFI_ERROR ( Status )) {
    844               //
    845               //  Remove the new socket from the list
    846               //
    847               pSocket->pFifoHead = pNewSocket->pNextConnection;
    848               if ( NULL == pSocket->pFifoHead ) {
    849                 pSocket->pFifoTail = NULL;
    850               }
    851 
    852               //
    853               //  Account for this socket
    854               //
    855               pSocket->FifoDepth -= 1;
    856 
    857               //
    858               //  Update the new socket's state
    859               //
    860               pNewSocket->State = SOCKET_STATE_CONNECTED;
    861               pNewSocket->bConfigured = TRUE;
    862               DEBUG (( DEBUG_ACCEPT,
    863                         "0x%08x: Socket connected\r\n",
    864                         pNewSocket ));
    865             }
    866           }
    867         }
    868 
    869         //
    870         //  Release the socket layer synchronization
    871         //
    872         RESTORE_TPL ( TplPrevious );
    873       }
    874     }
    875   }
    876 
    877   //
    878   //  Return the new socket
    879   //
    880   if (( NULL != ppSocketProtocol )
    881     && ( NULL != pNewSocket )) {
    882     *ppSocketProtocol = &pNewSocket->SocketProtocol;
    883   }
    884 
    885   //
    886   //  Return the operation status
    887   //
    888   if ( NULL != pErrno ) {
    889     if ( NULL != pSocket ) {
    890       *pErrno = pSocket->errno;
    891     }
    892     else {
    893       Status = EFI_INVALID_PARAMETER;
    894       *pErrno = ENOTSOCK;
    895     }
    896   }
    897   DBG_EXIT_STATUS ( Status );
    898   return Status;
    899 }
    900 
    901 
    902 /** Allocate and initialize a ESL_SOCKET structure.
    903 
    904   This support function allocates an ::ESL_SOCKET structure
    905   and installs a protocol on ChildHandle.  If pChildHandle is a
    906   pointer to NULL, then a new handle is created and returned in
    907   pChildHandle.  If pChildHandle is not a pointer to NULL, then
    908   the protocol installs on the existing pChildHandle.
    909 
    910   @param[in,out]  pChildHandle  Pointer to the handle of the child to create.
    911                                 If it is NULL, then a new handle is created.
    912                                 If it is a pointer to an existing UEFI handle,
    913                                 then the protocol is added to the existing UEFI
    914                                 handle.
    915   @param[in]      DebugFlags    Flags for debug messages
    916   @param[in,out]  ppSocket      The buffer to receive an ::ESL_SOCKET structure address.
    917 
    918   @retval EFI_SUCCESS           The protocol was added to ChildHandle.
    919   @retval EFI_INVALID_PARAMETER ChildHandle is NULL.
    920   @retval EFI_OUT_OF_RESOURCES  There are not enough resources available to create
    921                                 the child
    922   @retval other                 The child handle was not created
    923 **/
    924 EFI_STATUS
    925 EFIAPI
    926 EslSocketAllocate (
    927   IN OUT EFI_HANDLE * pChildHandle,
    928   IN     UINTN DebugFlags,
    929   IN OUT ESL_SOCKET ** ppSocket
    930   )
    931 {
    932   UINTN LengthInBytes;
    933   ESL_LAYER * pLayer;
    934   ESL_SOCKET * pSocket;
    935   EFI_STATUS Status;
    936   EFI_TPL TplPrevious;
    937 
    938   DBG_ENTER ( );
    939 
    940   //
    941   //  Create a socket structure
    942   //
    943   LengthInBytes = sizeof ( *pSocket );
    944   pSocket = (ESL_SOCKET *) AllocateZeroPool ( LengthInBytes );
    945   if ( NULL != pSocket ) {
    946     DEBUG (( DebugFlags | DEBUG_POOL | DEBUG_INIT,
    947               "0x%08x: Allocate pSocket, %d bytes\r\n",
    948               pSocket,
    949               LengthInBytes ));
    950 
    951     //
    952     //  Initialize the socket protocol
    953     //
    954     pSocket->Signature = SOCKET_SIGNATURE;
    955     pSocket->SocketProtocol.pfnAccept = EslSocketAccept;
    956     pSocket->SocketProtocol.pfnBind = EslSocketBind;
    957     pSocket->SocketProtocol.pfnClosePoll = EslSocketClosePoll;
    958     pSocket->SocketProtocol.pfnCloseStart = EslSocketCloseStart;
    959     pSocket->SocketProtocol.pfnConnect = EslSocketConnect;
    960     pSocket->SocketProtocol.pfnGetLocal = EslSocketGetLocalAddress;
    961     pSocket->SocketProtocol.pfnGetPeer = EslSocketGetPeerAddress;
    962     pSocket->SocketProtocol.pfnListen = EslSocketListen;
    963     pSocket->SocketProtocol.pfnOptionGet = EslSocketOptionGet;
    964     pSocket->SocketProtocol.pfnOptionSet = EslSocketOptionSet;
    965     pSocket->SocketProtocol.pfnPoll = EslSocketPoll;
    966     pSocket->SocketProtocol.pfnReceive = EslSocketReceive;
    967     pSocket->SocketProtocol.pfnShutdown = EslSocketShutdown;
    968     pSocket->SocketProtocol.pfnSocket = EslSocket;
    969     pSocket->SocketProtocol.pfnTransmit = EslSocketTransmit;
    970 
    971     pSocket->MaxRxBuf = MAX_RX_DATA;
    972     pSocket->MaxTxBuf = MAX_TX_DATA;
    973 
    974     //
    975     //  Install the socket protocol on the specified handle
    976     //
    977     Status = gBS->InstallMultipleProtocolInterfaces (
    978                     pChildHandle,
    979                     &gEfiSocketProtocolGuid,
    980                     &pSocket->SocketProtocol,
    981                     NULL
    982                     );
    983     if ( !EFI_ERROR ( Status )) {
    984       DEBUG (( DebugFlags | DEBUG_POOL | DEBUG_INIT | DEBUG_INFO,
    985                 "Installed: gEfiSocketProtocolGuid on   0x%08x\r\n",
    986                 *pChildHandle ));
    987       pSocket->SocketProtocol.SocketHandle = *pChildHandle;
    988 
    989       //
    990       //  Synchronize with the socket layer
    991       //
    992       RAISE_TPL ( TplPrevious, TPL_SOCKETS );
    993 
    994       //
    995       //  Add this socket to the list
    996       //
    997       pLayer = &mEslLayer;
    998       pSocket->pNext = pLayer->pSocketList;
    999       pLayer->pSocketList = pSocket;
   1000 
   1001       //
   1002       //  Release the socket layer synchronization
   1003       //
   1004       RESTORE_TPL ( TplPrevious );
   1005 
   1006       //
   1007       //  Return the socket structure address
   1008       //
   1009       *ppSocket = pSocket;
   1010     }
   1011     else {
   1012       DEBUG (( DEBUG_ERROR | DebugFlags | DEBUG_POOL | DEBUG_INIT,
   1013                 "ERROR - Failed to install gEfiSocketProtocolGuid on 0x%08x, Status: %r\r\n",
   1014                 *pChildHandle,
   1015                 Status ));
   1016     }
   1017 
   1018     //
   1019     //  Release the socket if necessary
   1020     //
   1021     if ( EFI_ERROR ( Status )) {
   1022       gBS->FreePool ( pSocket );
   1023       DEBUG (( DebugFlags | DEBUG_POOL | DEBUG_INIT,
   1024                 "0x%08x: Free pSocket, %d bytes\r\n",
   1025                 pSocket,
   1026                 sizeof ( *pSocket )));
   1027       pSocket = NULL;
   1028     }
   1029   }
   1030   else {
   1031     Status = EFI_OUT_OF_RESOURCES;
   1032   }
   1033 
   1034   //
   1035   //  Return the operation status
   1036   //
   1037   DBG_EXIT_STATUS ( Status );
   1038   return Status;
   1039 }
   1040 
   1041 
   1042 /** Bind a name to a socket.
   1043 
   1044   This routine calls the network specific layer to save the network
   1045   address of the local connection point.
   1046 
   1047   The ::bind routine calls this routine to connect a name
   1048   (network address and port) to a socket on the local machine.
   1049 
   1050   @param[in]  pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
   1051   @param[in]  pSockAddr       Address of a sockaddr structure that contains the
   1052                               connection point on the local machine.  An IPv4 address
   1053                               of INADDR_ANY specifies that the connection is made to
   1054                               all of the network stacks on the platform.  Specifying a
   1055                               specific IPv4 address restricts the connection to the
   1056                               network stack supporting that address.  Specifying zero
   1057                               for the port causes the network layer to assign a port
   1058                               number from the dynamic range.  Specifying a specific
   1059                               port number causes the network layer to use that port.
   1060   @param[in]  SockAddrLength  Specifies the length in bytes of the sockaddr structure.
   1061   @param[out] pErrno          Address to receive the errno value upon completion.
   1062 
   1063   @retval EFI_SUCCESS - Socket successfully created
   1064 **/
   1065 EFI_STATUS
   1066 EslSocketBind (
   1067   IN EFI_SOCKET_PROTOCOL * pSocketProtocol,
   1068   IN CONST struct sockaddr * pSockAddr,
   1069   IN socklen_t SockAddrLength,
   1070   OUT int * pErrno
   1071   )
   1072 {
   1073   EFI_HANDLE ChildHandle;
   1074   UINT8 * pBuffer;
   1075   ESL_PORT * pPort;
   1076   ESL_SERVICE ** ppServiceListHead;
   1077   ESL_SOCKET * pSocket;
   1078   ESL_SERVICE * pService;
   1079   EFI_SERVICE_BINDING_PROTOCOL * pServiceBinding;
   1080   EFI_STATUS Status;
   1081   EFI_TPL TplPrevious;
   1082 
   1083   DBG_ENTER ( );
   1084 
   1085   //
   1086   //  Assume success
   1087   //
   1088   Status = EFI_SUCCESS;
   1089 
   1090   //
   1091   //  Validate the socket
   1092   //
   1093   pSocket = NULL;
   1094   if ( NULL != pSocketProtocol ) {
   1095     pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
   1096 
   1097     //
   1098     //  Validate the structure pointer
   1099     //
   1100     pSocket->errno = 0;
   1101     if ( NULL == pSockAddr ) {
   1102       DEBUG (( DEBUG_BIND,
   1103                 "ERROR - pSockAddr is NULL!\r\n" ));
   1104       Status = EFI_INVALID_PARAMETER;
   1105       pSocket->errno = EFAULT;
   1106     }
   1107 
   1108     //
   1109     //  Validate the local address length
   1110     //
   1111     else if ( SockAddrLength < pSocket->pApi->MinimumAddressLength ) {
   1112       DEBUG (( DEBUG_BIND,
   1113                 "ERROR - Invalid bind name length: %d\r\n",
   1114                 SockAddrLength ));
   1115       Status = EFI_INVALID_PARAMETER;
   1116       pSocket->errno = EINVAL;
   1117     }
   1118 
   1119     //
   1120     //  Validate the shutdown state
   1121     //
   1122     else if ( pSocket->bRxDisable || pSocket->bTxDisable ) {
   1123       DEBUG (( DEBUG_BIND,
   1124                 "ERROR - Shutdown has been called on socket 0x%08x\r\n",
   1125                 pSocket ));
   1126       pSocket->errno = EINVAL;
   1127       Status = EFI_INVALID_PARAMETER;
   1128     }
   1129 
   1130     //
   1131     //  Verify the socket state
   1132     //
   1133     else if ( SOCKET_STATE_NOT_CONFIGURED != pSocket->State ) {
   1134       DEBUG (( DEBUG_BIND,
   1135                 "ERROR - The socket 0x%08x is already configured!\r\n",
   1136                 pSocket ));
   1137       pSocket->errno = EINVAL;
   1138       Status = EFI_ALREADY_STARTED;
   1139     }
   1140     else {
   1141       //
   1142       //  Synchronize with the socket layer
   1143       //
   1144       RAISE_TPL ( TplPrevious, TPL_SOCKETS );
   1145 
   1146       //
   1147       //  Assume no ports are available
   1148       //
   1149       pSocket->errno = EADDRNOTAVAIL;
   1150       Status = EFI_INVALID_PARAMETER;
   1151 
   1152       //
   1153       //  Walk the list of services
   1154       //
   1155       pBuffer = (UINT8 *)&mEslLayer;
   1156       pBuffer = &pBuffer[ pSocket->pApi->ServiceListOffset ];
   1157       ppServiceListHead = (ESL_SERVICE **)pBuffer;
   1158       pService = *ppServiceListHead;
   1159       while ( NULL != pService ) {
   1160         //
   1161         //  Create the port
   1162         //
   1163         pServiceBinding = pService->pServiceBinding;
   1164         ChildHandle = NULL;
   1165         Status = pServiceBinding->CreateChild ( pServiceBinding,
   1166                                                 &ChildHandle );
   1167         if ( !EFI_ERROR ( Status )) {
   1168           DEBUG (( DEBUG_BIND | DEBUG_POOL,
   1169                     "0x%08x: %s port handle created\r\n",
   1170                     ChildHandle,
   1171                     pService->pSocketBinding->pName ));
   1172 
   1173           //
   1174           //  Open the port
   1175           //
   1176           Status = EslSocketPortAllocate ( pSocket,
   1177                                            pService,
   1178                                            ChildHandle,
   1179                                            pSockAddr,
   1180                                            TRUE,
   1181                                            DEBUG_BIND,
   1182                                            &pPort );
   1183         }
   1184         else {
   1185           DEBUG (( DEBUG_BIND | DEBUG_POOL,
   1186                     "ERROR - Failed to open %s port handle, Status: %r\r\n",
   1187                     pService->pSocketBinding->pName,
   1188                     Status ));
   1189         }
   1190 
   1191         //
   1192         //  Set the next service
   1193         //
   1194         pService = pService->pNext;
   1195       }
   1196 
   1197       //
   1198       //  Verify that at least one network connection was found
   1199       //
   1200       if ( NULL != pSocket->pPortList ) {
   1201         Status = EFI_SUCCESS;
   1202       }
   1203       else {
   1204         if ( EADDRNOTAVAIL == pSocket->errno ) {
   1205           DEBUG (( DEBUG_BIND | DEBUG_POOL | DEBUG_INIT,
   1206                     "ERROR - Socket address is not available!\r\n" ));
   1207         }
   1208         if ( EADDRINUSE == pSocket->errno ) {
   1209           DEBUG (( DEBUG_BIND | DEBUG_POOL | DEBUG_INIT,
   1210                     "ERROR - Socket address is in use!\r\n" ));
   1211         }
   1212         Status = EFI_INVALID_PARAMETER;
   1213       }
   1214 
   1215       //
   1216       //  Mark this socket as bound if successful
   1217       //
   1218       if ( !EFI_ERROR ( Status )) {
   1219         pSocket->State = SOCKET_STATE_BOUND;
   1220         pSocket->errno = 0;
   1221       }
   1222 
   1223       //
   1224       //  Release the socket layer synchronization
   1225       //
   1226       RESTORE_TPL ( TplPrevious );
   1227     }
   1228   }
   1229 
   1230   //
   1231   //  Return the operation status
   1232   //
   1233   if ( NULL != pErrno ) {
   1234     if ( NULL != pSocket ) {
   1235       *pErrno = pSocket->errno;
   1236     }
   1237     else {
   1238       Status = EFI_INVALID_PARAMETER;
   1239       *pErrno = ENOTSOCK;
   1240     }
   1241   }
   1242   DBG_EXIT_STATUS ( Status );
   1243   return Status;
   1244 }
   1245 
   1246 
   1247 /** Test the bind configuration.
   1248 
   1249   @param[in] pPort        Address of the ::ESL_PORT structure.
   1250   @param[in] ErrnoValue   errno value if test fails
   1251 
   1252   @retval EFI_SUCCESS   The connection was successfully established.
   1253   @retval Others        The connection attempt failed.
   1254 **/
   1255 EFI_STATUS
   1256 EslSocketBindTest (
   1257   IN ESL_PORT * pPort,
   1258   IN int ErrnoValue
   1259   )
   1260 {
   1261   UINT8 * pBuffer;
   1262   VOID * pConfigData;
   1263   EFI_STATUS Status;
   1264 
   1265   DBG_ENTER ( );
   1266 
   1267   //
   1268   //  Locate the configuration data
   1269   //
   1270   pBuffer = (UINT8 *)pPort;
   1271   pBuffer = &pBuffer [ pPort->pSocket->pApi->ConfigDataOffset ];
   1272   pConfigData = (VOID *)pBuffer;
   1273 
   1274   //
   1275   //  Validate that the port is connected
   1276   //
   1277   Status = pPort->pSocket->pApi->pfnVerifyLocalIpAddress ( pPort, pBuffer );
   1278   if ( EFI_ERROR ( Status )) {
   1279     DEBUG (( DEBUG_WARN | DEBUG_BIND,
   1280               "WARNING - Port 0x%08x invalid IP address: %r\r\n",
   1281               pPort,
   1282               Status ));
   1283     pPort->pSocket->errno = ErrnoValue;
   1284   }
   1285   else {
   1286     //
   1287     //  Attempt to use this configuration
   1288     //
   1289     Status = pPort->pfnConfigure ( pPort->pProtocol.v, pConfigData );
   1290     if ( EFI_ERROR ( Status )) {
   1291       DEBUG (( DEBUG_WARN | DEBUG_BIND,
   1292                 "WARNING - Port 0x%08x failed configuration, Status: %r\r\n",
   1293                 pPort,
   1294                 Status ));
   1295       pPort->pSocket->errno = ErrnoValue;
   1296     }
   1297     else {
   1298       //
   1299       //  Reset the port
   1300       //
   1301       Status = pPort->pfnConfigure ( pPort->pProtocol.v, NULL );
   1302       if ( EFI_ERROR ( Status )) {
   1303         DEBUG (( DEBUG_ERROR | DEBUG_BIND,
   1304                   "ERROR - Port 0x%08x failed configuration reset, Status: %r\r\n",
   1305                   pPort,
   1306                   Status ));
   1307         ASSERT ( EFI_SUCCESS == Status );
   1308       }
   1309     }
   1310   }
   1311 
   1312   //
   1313   //  Return the operation status
   1314   //
   1315   DBG_EXIT_STATUS ( Status );
   1316   return Status;
   1317 }
   1318 
   1319 
   1320 /** Determine if the socket is closed.
   1321 
   1322   This routine checks the state of the socket to determine if
   1323   the network specific layer has completed the close operation.
   1324 
   1325   The ::close routine polls this routine to determine when the
   1326   close operation is complete.  The close operation needs to
   1327   reverse the operations of the ::EslSocketAllocate routine.
   1328 
   1329   @param[in]  pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
   1330   @param[out] pErrno          Address to receive the errno value upon completion.
   1331 
   1332   @retval EFI_SUCCESS     Socket successfully closed
   1333   @retval EFI_NOT_READY   Close still in progress
   1334   @retval EFI_ALREADY     Close operation already in progress
   1335   @retval Other           Failed to close the socket
   1336 **/
   1337 EFI_STATUS
   1338 EslSocketClosePoll (
   1339   IN EFI_SOCKET_PROTOCOL * pSocketProtocol,
   1340   IN int * pErrno
   1341   )
   1342 {
   1343   int errno;
   1344   ESL_LAYER * pLayer;
   1345   ESL_SOCKET * pNextSocket;
   1346   ESL_SOCKET * pSocket;
   1347   EFI_STATUS Status;
   1348   EFI_TPL TplPrevious;
   1349 
   1350   DBG_ENTER ( );
   1351 
   1352   //
   1353   //  Assume success
   1354   //
   1355   errno = 0;
   1356   Status = EFI_SUCCESS;
   1357 
   1358   //
   1359   //  Synchronize with the socket layer
   1360   //
   1361   RAISE_TPL ( TplPrevious, TPL_SOCKETS );
   1362 
   1363   //
   1364   //  Locate the socket
   1365   //
   1366   pLayer = &mEslLayer;
   1367   pNextSocket = pLayer->pSocketList;
   1368   pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
   1369   while ( NULL != pNextSocket ) {
   1370     if ( pNextSocket == pSocket ) {
   1371       //
   1372       //  Determine if the socket is in the closing state
   1373       //
   1374       if ( SOCKET_STATE_CLOSED == pSocket->State ) {
   1375         //
   1376         //  Walk the list of ports
   1377         //
   1378         if ( NULL == pSocket->pPortList ) {
   1379           //
   1380           //  All the ports are closed
   1381           //  Close the WaitAccept event if necessary
   1382           //
   1383           if ( NULL != pSocket->WaitAccept ) {
   1384             Status = gBS->CloseEvent ( pSocket->WaitAccept );
   1385             if ( !EFI_ERROR ( Status )) {
   1386               DEBUG (( DEBUG_SOCKET | DEBUG_CLOSE | DEBUG_POOL,
   1387                         "0x%08x: Closed WaitAccept event\r\n",
   1388                         pSocket->WaitAccept ));
   1389               //
   1390               //  Return the transmit status
   1391               //
   1392               Status = pSocket->TxError;
   1393               if ( EFI_ERROR ( Status )) {
   1394                 pSocket->errno = EIO;
   1395               }
   1396             }
   1397             else {
   1398               DEBUG (( DEBUG_ERROR | DEBUG_SOCKET | DEBUG_CLOSE | DEBUG_POOL,
   1399                         "ERROR - Failed to close the WaitAccept event, Status: %r\r\n",
   1400                         Status ));
   1401               ASSERT ( EFI_SUCCESS == Status );
   1402             }
   1403           }
   1404         }
   1405         else {
   1406           //
   1407           //  At least one port is still open
   1408           //
   1409           Status = EFI_NOT_READY;
   1410           errno = EAGAIN;
   1411         }
   1412       }
   1413       else {
   1414         //
   1415         //  SocketCloseStart was not called
   1416         //
   1417         Status = EFI_NOT_STARTED;
   1418         errno = EPERM;
   1419       }
   1420       break;
   1421     }
   1422 
   1423     //
   1424     //  Set the next socket
   1425     //
   1426     pNextSocket = pNextSocket->pNext;
   1427   }
   1428 
   1429   //
   1430   //  Handle the error case where the socket was already closed
   1431   //
   1432   if ( NULL == pSocket ) {
   1433     //
   1434     //  Socket not found
   1435     //
   1436     Status = EFI_NOT_FOUND;
   1437     errno = ENOTSOCK;
   1438   }
   1439 
   1440   //
   1441   //  Release the socket layer synchronization
   1442   //
   1443   RESTORE_TPL ( TplPrevious );
   1444 
   1445   //
   1446   //  Return the operation status
   1447   //
   1448   if ( NULL != pErrno ) {
   1449     *pErrno = errno;
   1450   }
   1451   DBG_EXIT_STATUS ( Status );
   1452   return Status;
   1453 }
   1454 
   1455 
   1456 /** Start the close operation on the socket.
   1457 
   1458   This routine calls the network specific layer to initiate the
   1459   close state machine.  This routine then calls the network
   1460   specific layer to determine if the close state machine has gone
   1461   to completion.  The result from this poll is returned to the
   1462   caller.
   1463 
   1464   The ::close routine calls this routine to start the close
   1465   operation which reverses the operations of the
   1466   ::EslSocketAllocate routine.  The close routine then polls
   1467   the ::EslSocketClosePoll routine to determine when the
   1468   socket is closed.
   1469 
   1470   @param[in] pSocketProtocol  Address of an ::EFI_SOCKET_PROTOCOL structure.
   1471   @param[in] bCloseNow        Boolean to control close behavior
   1472   @param[out] pErrno          Address to receive the errno value upon completion.
   1473 
   1474   @retval EFI_SUCCESS     Socket successfully closed
   1475   @retval EFI_NOT_READY   Close still in progress
   1476   @retval EFI_ALREADY     Close operation already in progress
   1477   @retval Other           Failed to close the socket
   1478 **/
   1479 EFI_STATUS
   1480 EslSocketCloseStart (
   1481   IN EFI_SOCKET_PROTOCOL * pSocketProtocol,
   1482   IN BOOLEAN bCloseNow,
   1483   IN int * pErrno
   1484   )
   1485 {
   1486   int errno;
   1487   ESL_PORT * pNextPort;
   1488   ESL_PORT * pPort;
   1489   ESL_SOCKET * pSocket;
   1490   EFI_STATUS Status;
   1491   EFI_TPL TplPrevious;
   1492 
   1493   DBG_ENTER ( );
   1494 
   1495   //
   1496   //  Assume success
   1497   //
   1498   Status = EFI_SUCCESS;
   1499   errno = 0;
   1500 
   1501   //
   1502   //  Synchronize with the socket layer
   1503   //
   1504   RAISE_TPL ( TplPrevious, TPL_SOCKETS );
   1505 
   1506   //
   1507   //  Determine if the socket is already closed
   1508   //
   1509   pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
   1510   if ( SOCKET_STATE_CLOSED > pSocket->State ) {
   1511     //
   1512     //  Update the socket state
   1513     //
   1514     pSocket->State = SOCKET_STATE_CLOSED;
   1515 
   1516     //
   1517     //  Walk the list of ports
   1518     //
   1519     pPort = pSocket->pPortList;
   1520     while ( NULL != pPort ) {
   1521       //
   1522       //  Start closing the ports
   1523       //
   1524       pNextPort = pPort->pLinkSocket;
   1525       Status = EslSocketPortCloseStart ( pPort,
   1526                                          bCloseNow,
   1527                                          DEBUG_CLOSE | DEBUG_LISTEN | DEBUG_CONNECTION );
   1528       if (( EFI_SUCCESS != Status )
   1529         && ( EFI_NOT_READY != Status )) {
   1530         errno = EIO;
   1531         break;
   1532       }
   1533 
   1534       //
   1535       //  Set the next port
   1536       //
   1537       pPort = pNextPort;
   1538     }
   1539 
   1540     //
   1541     //  Attempt to finish closing the socket
   1542     //
   1543     if ( NULL == pPort ) {
   1544       Status = EslSocketClosePoll ( pSocketProtocol, &errno );
   1545     }
   1546   }
   1547   else {
   1548     Status = EFI_NOT_READY;
   1549     errno = EAGAIN;
   1550   }
   1551 
   1552   //
   1553   //  Release the socket layer synchronization
   1554   //
   1555   RESTORE_TPL ( TplPrevious );
   1556 
   1557   //
   1558   //  Return the operation status
   1559   //
   1560   if ( NULL != pErrno ) {
   1561     *pErrno = errno;
   1562   }
   1563   DBG_EXIT_STATUS ( Status );
   1564   return Status;
   1565 }
   1566 
   1567 
   1568 /** Connect to a remote system via the network.
   1569 
   1570   This routine calls the network specific layer to establish
   1571   the remote system address and establish the connection to
   1572   the remote system.
   1573 
   1574   The ::connect routine calls this routine to establish a
   1575   connection with the specified remote system.  This routine
   1576   is designed to be polled by the connect routine for completion
   1577   of the network connection.
   1578 
   1579   @param[in]  pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
   1580   @param[in]  pSockAddr       Network address of the remote system.
   1581   @param[in]  SockAddrLength  Length in bytes of the network address.
   1582   @param[out] pErrno          Address to receive the errno value upon completion.
   1583 
   1584   @retval EFI_SUCCESS     The connection was successfully established.
   1585   @retval EFI_NOT_READY   The connection is in progress, call this routine again.
   1586   @retval Others          The connection attempt failed.
   1587  **/
   1588 EFI_STATUS
   1589 EslSocketConnect (
   1590   IN EFI_SOCKET_PROTOCOL * pSocketProtocol,
   1591   IN const struct sockaddr * pSockAddr,
   1592   IN socklen_t SockAddrLength,
   1593   IN int * pErrno
   1594   )
   1595 {
   1596   struct sockaddr_in6 LocalAddress;
   1597   ESL_PORT * pPort;
   1598   ESL_SOCKET * pSocket;
   1599   EFI_STATUS Status;
   1600   EFI_TPL TplPrevious;
   1601 
   1602   DEBUG (( DEBUG_CONNECT, "Entering SocketConnect\r\n" ));
   1603 
   1604   //
   1605   //  Assume success
   1606   //
   1607   Status = EFI_SUCCESS;
   1608 
   1609   //
   1610   //  Validate the socket
   1611   //
   1612   pSocket = NULL;
   1613   if ( NULL != pSocketProtocol ) {
   1614     pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
   1615 
   1616     //
   1617     //  Validate the name length
   1618     //
   1619     if ( SockAddrLength < ( sizeof ( struct sockaddr ) - sizeof ( pSockAddr->sa_data ))) {
   1620       DEBUG (( DEBUG_CONNECT,
   1621                 "ERROR - Invalid bind name length: %d\r\n",
   1622                 SockAddrLength ));
   1623       Status = EFI_INVALID_PARAMETER;
   1624       pSocket->errno = EINVAL;
   1625     }
   1626     else {
   1627       //
   1628       //  Assume success
   1629       //
   1630       pSocket->errno = 0;
   1631 
   1632       //
   1633       //  Synchronize with the socket layer
   1634       //
   1635       RAISE_TPL ( TplPrevious, TPL_SOCKETS );
   1636 
   1637       //
   1638       //  Validate the socket state
   1639       //
   1640       switch ( pSocket->State ) {
   1641       default:
   1642         //
   1643         //  Wrong socket state
   1644         //
   1645         pSocket->errno = EIO;
   1646         Status = EFI_DEVICE_ERROR;
   1647         break;
   1648 
   1649       case SOCKET_STATE_NOT_CONFIGURED:
   1650       case SOCKET_STATE_BOUND:
   1651         //
   1652         //  Validate the address length
   1653         //
   1654         if ( SockAddrLength >= pSocket->pApi->MinimumAddressLength ) {
   1655           //
   1656           //  Verify the API
   1657           //
   1658           if ( NULL == pSocket->pApi->pfnRemoteAddrSet ) {
   1659             //
   1660             //  Already connected
   1661             //
   1662             pSocket->errno = ENOTSUP;
   1663             Status = EFI_UNSUPPORTED;
   1664           }
   1665           else {
   1666             //
   1667             //  Determine if BIND was already called
   1668             //
   1669             if ( NULL == pSocket->pPortList ) {
   1670               //
   1671               //  Allow any local port
   1672               //
   1673               ZeroMem ( &LocalAddress, sizeof ( LocalAddress ));
   1674               LocalAddress.sin6_len = (uint8_t)pSocket->pApi->MinimumAddressLength;
   1675               LocalAddress.sin6_family = pSocket->pApi->AddressFamily;
   1676               Status = EslSocketBind ( &pSocket->SocketProtocol,
   1677                                        (struct sockaddr *)&LocalAddress,
   1678                                        LocalAddress.sin6_len,
   1679                                        &pSocket->errno );
   1680             }
   1681             if ( NULL != pSocket->pPortList ) {
   1682               //
   1683               //  Walk the list of ports
   1684               //
   1685               pPort = pSocket->pPortList;
   1686               while ( NULL != pPort ) {
   1687                 //
   1688                 //  Set the remote address
   1689                 //
   1690                 Status = pSocket->pApi->pfnRemoteAddrSet ( pPort,
   1691                                                            pSockAddr,
   1692                                                            SockAddrLength );
   1693                 if ( EFI_ERROR ( Status )) {
   1694                   break;
   1695                 }
   1696 
   1697                 //
   1698                 //  Set the next port
   1699                 //
   1700                 pPort = pPort->pLinkSocket;
   1701               }
   1702 
   1703               //
   1704               //  Verify the API
   1705               //
   1706               if (( !EFI_ERROR ( Status ))
   1707                 && ( NULL != pSocket->pApi->pfnConnectStart )) {
   1708                 //
   1709                 //  Initiate the connection with the remote system
   1710                 //
   1711                 Status = pSocket->pApi->pfnConnectStart ( pSocket );
   1712 
   1713                 //
   1714                 //  Set the next state if connecting
   1715                 //
   1716                 if ( EFI_NOT_READY == Status ) {
   1717                   pSocket->State = SOCKET_STATE_CONNECTING;
   1718                 }
   1719               }
   1720             }
   1721           }
   1722         }
   1723         else {
   1724           DEBUG (( DEBUG_CONNECT,
   1725                     "ERROR - Invalid address length: %d\r\n",
   1726                     SockAddrLength ));
   1727           Status = EFI_INVALID_PARAMETER;
   1728           pSocket->errno = EINVAL;
   1729         }
   1730         break;
   1731 
   1732       case SOCKET_STATE_CONNECTING:
   1733         //
   1734         //  Poll the network adapter
   1735         //
   1736         EslSocketRxPoll ( pSocket );
   1737 
   1738         //
   1739         //  Poll for connection completion
   1740         //
   1741         if ( NULL == pSocket->pApi->pfnConnectPoll ) {
   1742           //
   1743           //  Already connected
   1744           //
   1745           pSocket->errno = EISCONN;
   1746           Status = EFI_ALREADY_STARTED;
   1747         }
   1748         else {
   1749           Status = pSocket->pApi->pfnConnectPoll ( pSocket );
   1750 
   1751           //
   1752           //  Set the next state if connected
   1753           //
   1754           if ( EFI_NOT_READY != Status ) {
   1755             if ( EFI_ERROR ( Status )) {
   1756               pSocket->State = SOCKET_STATE_BOUND;
   1757             }
   1758           }
   1759         }
   1760         break;
   1761 
   1762       case SOCKET_STATE_CONNECTED:
   1763         //
   1764         //  Connected
   1765         //
   1766         Status = EFI_SUCCESS;
   1767         break;
   1768       }
   1769 
   1770       //
   1771       //  Release the socket layer synchronization
   1772       //
   1773       RESTORE_TPL ( TplPrevious );
   1774     }
   1775   }
   1776 
   1777   //
   1778   //  Return the operation status
   1779   //
   1780   if ( NULL != pErrno ) {
   1781     if ( NULL != pSocket ) {
   1782       *pErrno = pSocket->errno;
   1783     }
   1784     else {
   1785       //
   1786       //  Bad socket protocol
   1787       //
   1788       DEBUG (( DEBUG_ERROR | DEBUG_CONNECT,
   1789                 "ERROR - pSocketProtocol invalid!\r\n" ));
   1790       Status = EFI_INVALID_PARAMETER;
   1791       *pErrno = ENOTSOCK;
   1792     }
   1793   }
   1794 
   1795   //
   1796   //  Return the operation status
   1797   //
   1798   DEBUG (( DEBUG_CONNECT, "Exiting SocketConnect, Status: %r\r\n", Status ));
   1799   return Status;
   1800 }
   1801 
   1802 
   1803 /** Copy a fragmented buffer into a destination buffer.
   1804 
   1805   This support routine copies a fragmented buffer to the caller specified buffer.
   1806 
   1807   This routine is called by ::EslIp4Receive and ::EslUdp4Receive.
   1808 
   1809   @param[in]  FragmentCount   Number of fragments in the table
   1810   @param[in]  pFragmentTable  Address of an EFI_IP4_FRAGMENT_DATA structure
   1811   @param[in]  BufferLength    Length of the the buffer
   1812   @param[in]  pBuffer         Address of a buffer to receive the data.
   1813   @param[in]  pDataLength     Number of received data bytes in the buffer.
   1814 
   1815   @return   Returns the address of the next free byte in the buffer.
   1816 **/
   1817 UINT8 *
   1818 EslSocketCopyFragmentedBuffer (
   1819   IN UINT32 FragmentCount,
   1820   IN EFI_IP4_FRAGMENT_DATA * pFragmentTable,
   1821   IN size_t BufferLength,
   1822   IN UINT8 * pBuffer,
   1823   OUT size_t * pDataLength
   1824   )
   1825 {
   1826   size_t BytesToCopy;
   1827   UINT32 Fragment;
   1828   UINT8 * pBufferEnd;
   1829   UINT8 * pData;
   1830 
   1831   DBG_ENTER ( );
   1832 
   1833   //
   1834   //  Validate the IP and UDP structures are identical
   1835   //
   1836   ASSERT ( OFFSET_OF ( EFI_IP4_FRAGMENT_DATA, FragmentLength )
   1837            == OFFSET_OF ( EFI_UDP4_FRAGMENT_DATA, FragmentLength ));
   1838   ASSERT ( OFFSET_OF ( EFI_IP4_FRAGMENT_DATA, FragmentBuffer )
   1839            == OFFSET_OF ( EFI_UDP4_FRAGMENT_DATA, FragmentBuffer ));
   1840 
   1841   //
   1842   //  Copy the received data
   1843   //
   1844   Fragment = 0;
   1845   pBufferEnd = &pBuffer [ BufferLength ];
   1846   while (( pBufferEnd > pBuffer ) && ( FragmentCount > Fragment )) {
   1847     //
   1848     //  Determine the amount of received data
   1849     //
   1850     pData = pFragmentTable[Fragment].FragmentBuffer;
   1851     BytesToCopy = pFragmentTable[Fragment].FragmentLength;
   1852     if (((size_t)( pBufferEnd - pBuffer )) < BytesToCopy ) {
   1853       BytesToCopy = pBufferEnd - pBuffer;
   1854     }
   1855 
   1856     //
   1857     //  Move the data into the buffer
   1858     //
   1859     DEBUG (( DEBUG_RX,
   1860               "0x%08x --> 0x%08x: Copy data 0x%08x bytes\r\n",
   1861               pData,
   1862               pBuffer,
   1863               BytesToCopy ));
   1864     CopyMem ( pBuffer, pData, BytesToCopy );
   1865     pBuffer += BytesToCopy;
   1866     Fragment += 1;
   1867   }
   1868 
   1869   //
   1870   //  Return the data length and the buffer address
   1871   //
   1872   *pDataLength = BufferLength - ( pBufferEnd - pBuffer );
   1873   DBG_EXIT_HEX ( pBuffer );
   1874   return pBuffer;
   1875 }
   1876 
   1877 
   1878 /** Free the socket.
   1879 
   1880   This routine frees the socket structure and handle resources.
   1881 
   1882   The ::close routine calls EslServiceFreeProtocol which then calls
   1883   this routine to free the socket context structure and close the
   1884   handle.
   1885 
   1886   @param[in]  pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
   1887   @param[out] pErrno          Address to receive the errno value upon completion.
   1888 
   1889   @retval EFI_SUCCESS   The socket resources were returned successfully.
   1890 **/
   1891 EFI_STATUS
   1892 EslSocketFree (
   1893   IN EFI_SOCKET_PROTOCOL * pSocketProtocol,
   1894   IN int * pErrno
   1895   )
   1896 {
   1897   EFI_HANDLE ChildHandle;
   1898   int errno;
   1899   ESL_LAYER * pLayer;
   1900   ESL_SOCKET * pSocket;
   1901   ESL_SOCKET * pSocketPrevious;
   1902   EFI_STATUS Status;
   1903   EFI_TPL TplPrevious;
   1904 
   1905   DBG_ENTER ( );
   1906 
   1907   //
   1908   //  Assume failure
   1909   //
   1910   errno = EIO;
   1911   pSocket = NULL;
   1912   Status = EFI_INVALID_PARAMETER;
   1913 
   1914   //
   1915   //  Validate the socket
   1916   //
   1917   pLayer = &mEslLayer;
   1918   if ( NULL != pSocketProtocol ) {
   1919     pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
   1920 
   1921     //
   1922     //  Synchronize with the socket layer
   1923     //
   1924     RAISE_TPL ( TplPrevious, TPL_SOCKETS );
   1925 
   1926     //
   1927     //  Walk the socket list
   1928     //
   1929     pSocketPrevious = pLayer->pSocketList;
   1930     if ( NULL != pSocketPrevious ) {
   1931       if ( pSocket == pSocketPrevious ) {
   1932         //
   1933         //  Remove the socket from the head of the list
   1934         //
   1935         pLayer->pSocketList = pSocket->pNext;
   1936       }
   1937       else {
   1938         //
   1939         //  Find the socket in the middle of the list
   1940         //
   1941         while (( NULL != pSocketPrevious )
   1942           && ( pSocket != pSocketPrevious->pNext )) {
   1943           //
   1944           //  Set the next socket
   1945           //
   1946           pSocketPrevious = pSocketPrevious->pNext;
   1947         }
   1948         if ( NULL != pSocketPrevious ) {
   1949           //
   1950           //  Remove the socket from the middle of the list
   1951           //
   1952           pSocketPrevious = pSocket->pNext;
   1953         }
   1954       }
   1955     }
   1956     else {
   1957       DEBUG (( DEBUG_ERROR | DEBUG_POOL,
   1958                 "ERROR - Socket list is empty!\r\n" ));
   1959     }
   1960 
   1961     //
   1962     //  Release the socket layer synchronization
   1963     //
   1964     RESTORE_TPL ( TplPrevious );
   1965 
   1966     //
   1967     //  Determine if the socket was found
   1968     //
   1969     if ( NULL != pSocketPrevious ) {
   1970       pSocket->pNext = NULL;
   1971 
   1972       //
   1973       //  Remove the socket protocol
   1974       //
   1975       ChildHandle = pSocket->SocketProtocol.SocketHandle;
   1976       Status = gBS->UninstallMultipleProtocolInterfaces (
   1977                 ChildHandle,
   1978                 &gEfiSocketProtocolGuid,
   1979                 &pSocket->SocketProtocol,
   1980                 NULL );
   1981       if ( !EFI_ERROR ( Status )) {
   1982         DEBUG (( DEBUG_POOL | DEBUG_INFO,
   1983                     "Removed:   gEfiSocketProtocolGuid from 0x%08x\r\n",
   1984                     ChildHandle ));
   1985 
   1986         //
   1987         //  Free the socket structure
   1988         //
   1989         Status = gBS->FreePool ( pSocket );
   1990         if ( !EFI_ERROR ( Status )) {
   1991           DEBUG (( DEBUG_POOL,
   1992                     "0x%08x: Free pSocket, %d bytes\r\n",
   1993                     pSocket,
   1994                     sizeof ( *pSocket )));
   1995           errno = 0;
   1996         }
   1997         else {
   1998           DEBUG (( DEBUG_ERROR | DEBUG_POOL,
   1999                     "ERROR - Failed to free pSocket 0x%08x, Status: %r\r\n",
   2000                     pSocket,
   2001                     Status ));
   2002         }
   2003       }
   2004       else {
   2005         DEBUG (( DEBUG_ERROR | DEBUG_POOL | DEBUG_INFO,
   2006                     "ERROR - Failed to remove gEfiSocketProtocolGuid from 0x%08x, Status: %r\r\n",
   2007                     ChildHandle,
   2008                     Status ));
   2009       }
   2010     }
   2011     else {
   2012       DEBUG (( DEBUG_ERROR | DEBUG_INFO,
   2013                 "ERROR - The socket was not in the socket list!\r\n" ));
   2014       Status = EFI_NOT_FOUND;
   2015     }
   2016   }
   2017   else {
   2018     DEBUG (( DEBUG_ERROR,
   2019               "ERROR - Invalid parameter pSocketProtocol is NULL\r\n" ));
   2020   }
   2021 
   2022   //
   2023   //  Return the errno value if possible
   2024   //
   2025   if ( NULL != pErrno ) {
   2026     *pErrno = errno;
   2027   }
   2028 
   2029   //
   2030   //  Return the operation status
   2031   //
   2032   DBG_EXIT_STATUS ( Status );
   2033   return Status;
   2034 }
   2035 
   2036 
   2037 /** Get the local address.
   2038 
   2039   This routine calls the network specific layer to get the network
   2040   address of the local host connection point.
   2041 
   2042   The ::getsockname routine calls this routine to obtain the network
   2043   address associated with the local host connection point.
   2044 
   2045   @param[in]      pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
   2046   @param[out]     pAddress        Network address to receive the local system address
   2047   @param[in,out]  pAddressLength  Length of the local network address structure
   2048   @param[out]     pErrno          Address to receive the errno value upon completion.
   2049 
   2050   @retval EFI_SUCCESS - Local address successfully returned
   2051  **/
   2052 EFI_STATUS
   2053 EslSocketGetLocalAddress (
   2054   IN EFI_SOCKET_PROTOCOL * pSocketProtocol,
   2055   OUT struct sockaddr * pAddress,
   2056   IN OUT socklen_t * pAddressLength,
   2057   IN int * pErrno
   2058   )
   2059 {
   2060   socklen_t LengthInBytes;
   2061   ESL_PORT * pPort;
   2062   ESL_SOCKET * pSocket;
   2063   EFI_STATUS Status;
   2064   EFI_TPL TplPrevious;
   2065 
   2066   DBG_ENTER ( );
   2067 
   2068   //
   2069   //  Assume success
   2070   //
   2071   Status = EFI_SUCCESS;
   2072 
   2073   //
   2074   //  Validate the socket
   2075   //
   2076   pSocket = NULL;
   2077   if ( NULL != pSocketProtocol ) {
   2078     pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
   2079 
   2080     //
   2081     //  Verify the socket state
   2082     //
   2083     EslSocketIsConfigured ( pSocket );
   2084     if ( pSocket->bAddressSet ) {
   2085       //
   2086       //  Verify the address buffer and length address
   2087       //
   2088       if (( NULL != pAddress ) && ( NULL != pAddressLength )) {
   2089         //
   2090         //  Verify the API
   2091         //
   2092         if ( NULL == pSocket->pApi->pfnLocalAddrGet ) {
   2093           Status = EFI_UNSUPPORTED;
   2094           pSocket->errno = ENOTSUP;
   2095         }
   2096         else {
   2097           //
   2098           //  Synchronize with the socket layer
   2099           //
   2100           RAISE_TPL ( TplPrevious, TPL_SOCKETS );
   2101 
   2102           //
   2103           //  Verify that there is just a single connection
   2104           //
   2105           pPort = pSocket->pPortList;
   2106           if ( NULL != pPort ) {
   2107             //
   2108             //  Verify the address length
   2109             //
   2110             LengthInBytes = pSocket->pApi->AddressLength;
   2111             if (( LengthInBytes <= *pAddressLength )
   2112               && ( 255 >= LengthInBytes )) {
   2113               //
   2114               //  Return the local address and address length
   2115               //
   2116               ZeroMem ( pAddress, LengthInBytes );
   2117               pAddress->sa_len = (uint8_t)LengthInBytes;
   2118               *pAddressLength = pAddress->sa_len;
   2119               pSocket->pApi->pfnLocalAddrGet ( pPort, pAddress );
   2120               pSocket->errno = 0;
   2121               Status = EFI_SUCCESS;
   2122             }
   2123             else {
   2124               pSocket->errno = EINVAL;
   2125               Status = EFI_INVALID_PARAMETER;
   2126             }
   2127           }
   2128           else {
   2129             pSocket->errno = ENOTCONN;
   2130             Status = EFI_NOT_STARTED;
   2131           }
   2132 
   2133           //
   2134           //  Release the socket layer synchronization
   2135           //
   2136           RESTORE_TPL ( TplPrevious );
   2137         }
   2138       }
   2139       else {
   2140         pSocket->errno = EINVAL;
   2141         Status = EFI_INVALID_PARAMETER;
   2142       }
   2143     }
   2144     else {
   2145       //
   2146       //  Address not set
   2147       //
   2148       Status = EFI_NOT_STARTED;
   2149       pSocket->errno = EADDRNOTAVAIL;
   2150     }
   2151   }
   2152 
   2153   //
   2154   //  Return the operation status
   2155   //
   2156   if ( NULL != pErrno ) {
   2157     if ( NULL != pSocket ) {
   2158       *pErrno = pSocket->errno;
   2159     }
   2160     else {
   2161       Status = EFI_INVALID_PARAMETER;
   2162       *pErrno = ENOTSOCK;
   2163     }
   2164   }
   2165   DBG_EXIT_STATUS ( Status );
   2166   return Status;
   2167 }
   2168 
   2169 
   2170 /** Get the peer address.
   2171 
   2172   This routine calls the network specific layer to get the remote
   2173   system connection point.
   2174 
   2175   The ::getpeername routine calls this routine to obtain the network
   2176   address of the remote connection point.
   2177 
   2178   @param[in]      pSocketProtocol   Address of an ::EFI_SOCKET_PROTOCOL structure.
   2179   @param[out]     pAddress          Network address to receive the remote system address
   2180   @param[in,out]  pAddressLength    Length of the remote network address structure
   2181   @param[out]     pErrno            Address to receive the errno value upon completion.
   2182 
   2183   @retval EFI_SUCCESS - Remote address successfully returned
   2184  **/
   2185 EFI_STATUS
   2186 EslSocketGetPeerAddress (
   2187   IN EFI_SOCKET_PROTOCOL * pSocketProtocol,
   2188   OUT struct sockaddr * pAddress,
   2189   IN OUT socklen_t * pAddressLength,
   2190   IN int * pErrno
   2191   )
   2192 {
   2193   socklen_t LengthInBytes;
   2194   ESL_PORT * pPort;
   2195   ESL_SOCKET * pSocket;
   2196   EFI_STATUS Status;
   2197   EFI_TPL TplPrevious;
   2198 
   2199   DBG_ENTER ( );
   2200 
   2201   //
   2202   //  Assume success
   2203   //
   2204   Status = EFI_SUCCESS;
   2205 
   2206   //
   2207   //  Validate the socket
   2208   //
   2209   pSocket = NULL;
   2210   if ( NULL != pSocketProtocol ) {
   2211     pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
   2212 
   2213     //
   2214     //  Verify the socket state
   2215     //
   2216     Status = EslSocketIsConfigured ( pSocket );
   2217     if ( !EFI_ERROR ( Status )) {
   2218       //
   2219       //  Verify the API
   2220       //
   2221       if ( NULL == pSocket->pApi->pfnRemoteAddrGet ) {
   2222         Status = EFI_UNSUPPORTED;
   2223         pSocket->errno = ENOTSUP;
   2224       }
   2225       else {
   2226         //
   2227         //  Verify the address buffer and length address
   2228         //
   2229         if (( NULL != pAddress ) && ( NULL != pAddressLength )) {
   2230           //
   2231           //  Verify the socket state
   2232           //
   2233           if ( SOCKET_STATE_CONNECTED == pSocket->State ) {
   2234             //
   2235             //  Synchronize with the socket layer
   2236             //
   2237             RAISE_TPL ( TplPrevious, TPL_SOCKETS );
   2238 
   2239             //
   2240             //  Verify that there is just a single connection
   2241             //
   2242             pPort = pSocket->pPortList;
   2243             if (( NULL != pPort ) && ( NULL == pPort->pLinkSocket )) {
   2244               //
   2245               //  Verify the address length
   2246               //
   2247               LengthInBytes = pSocket->pApi->AddressLength;
   2248               if ( LengthInBytes <= *pAddressLength ) {
   2249                 //
   2250                 //  Return the local address
   2251                 //
   2252                 ZeroMem ( pAddress, LengthInBytes );
   2253                 pAddress->sa_len = (uint8_t)LengthInBytes;
   2254                 *pAddressLength = pAddress->sa_len;
   2255                 pSocket->pApi->pfnRemoteAddrGet ( pPort, pAddress );
   2256                 pSocket->errno = 0;
   2257                 Status = EFI_SUCCESS;
   2258               }
   2259               else {
   2260                 pSocket->errno = EINVAL;
   2261                 Status = EFI_INVALID_PARAMETER;
   2262               }
   2263             }
   2264             else {
   2265               pSocket->errno = ENOTCONN;
   2266               Status = EFI_NOT_STARTED;
   2267             }
   2268 
   2269             //
   2270             //  Release the socket layer synchronization
   2271             //
   2272             RESTORE_TPL ( TplPrevious );
   2273           }
   2274           else {
   2275             pSocket->errno = ENOTCONN;
   2276             Status = EFI_NOT_STARTED;
   2277           }
   2278         }
   2279         else {
   2280           pSocket->errno = EINVAL;
   2281           Status = EFI_INVALID_PARAMETER;
   2282         }
   2283       }
   2284     }
   2285   }
   2286 
   2287   //
   2288   //  Return the operation status
   2289   //
   2290   if ( NULL != pErrno ) {
   2291     if ( NULL != pSocket ) {
   2292       *pErrno = pSocket->errno;
   2293     }
   2294     else {
   2295       Status = EFI_INVALID_PARAMETER;
   2296       *pErrno = ENOTSOCK;
   2297     }
   2298   }
   2299   DBG_EXIT_STATUS ( Status );
   2300   return Status;
   2301 }
   2302 
   2303 
   2304 /** Free the ESL_IO_MGMT event and structure.
   2305 
   2306   This support routine walks the free list to close the event in
   2307   the ESL_IO_MGMT structure and remove the structure from the free
   2308   list.
   2309 
   2310   See the \ref TransmitEngine section.
   2311 
   2312   @param[in]  pPort         Address of an ::ESL_PORT structure
   2313   @param[in]  ppFreeQueue   Address of the free queue head
   2314   @param[in]  DebugFlags    Flags for debug messages
   2315   @param[in]  pEventName    Zero terminated string containing the event name
   2316 
   2317   @retval EFI_SUCCESS - The structures were properly initialized
   2318 **/
   2319 EFI_STATUS
   2320 EslSocketIoFree (
   2321   IN ESL_PORT * pPort,
   2322   IN ESL_IO_MGMT ** ppFreeQueue,
   2323   IN UINTN DebugFlags,
   2324   IN CHAR8 * pEventName
   2325   )
   2326 {
   2327   UINT8 * pBuffer;
   2328   EFI_EVENT * pEvent;
   2329   ESL_IO_MGMT * pIo;
   2330   ESL_SOCKET * pSocket;
   2331   EFI_STATUS Status;
   2332 
   2333   DBG_ENTER ( );
   2334 
   2335   //
   2336   //  Assume success
   2337   //
   2338   Status = EFI_SUCCESS;
   2339 
   2340   //
   2341   //  Walk the list of IO structures
   2342   //
   2343   pSocket = pPort->pSocket;
   2344   while ( *ppFreeQueue ) {
   2345     //
   2346     //  Free the event for this structure
   2347     //
   2348     pIo = *ppFreeQueue;
   2349     pBuffer = (UINT8 *)pIo;
   2350     pBuffer = &pBuffer[ pSocket->TxTokenEventOffset ];
   2351     pEvent = (EFI_EVENT *)pBuffer;
   2352     Status = gBS->CloseEvent ( *pEvent );
   2353     if ( EFI_ERROR ( Status )) {
   2354       DEBUG (( DEBUG_ERROR | DebugFlags,
   2355                 "ERROR - Failed to close the %a event, Status: %r\r\n",
   2356                 pEventName,
   2357                 Status ));
   2358       pSocket->errno = ENOMEM;
   2359       break;
   2360     }
   2361     DEBUG (( DebugFlags,
   2362               "0x%08x: Closed %a event 0x%08x\r\n",
   2363               pIo,
   2364               pEventName,
   2365               *pEvent ));
   2366 
   2367     //
   2368     //  Remove this structure from the queue
   2369     //
   2370     *ppFreeQueue = pIo->pNext;
   2371   }
   2372 
   2373   //
   2374   //  Return the operation status
   2375   //
   2376   DBG_EXIT_STATUS ( Status );
   2377   return Status;
   2378 }
   2379 
   2380 
   2381 /** Initialize the ESL_IO_MGMT structures.
   2382 
   2383   This support routine initializes the ESL_IO_MGMT structure and
   2384   places them on to a free list.
   2385 
   2386   This routine is called by ::EslSocketPortAllocate routines to prepare
   2387   the transmit engines.  See the \ref TransmitEngine section.
   2388 
   2389   @param[in]        pPort         Address of an ::ESL_PORT structure
   2390   @param[in, out]   ppIo          Address containing the first structure address.  Upon
   2391                                   return this buffer contains the next structure address.
   2392   @param[in]        TokenCount    Number of structures to initialize
   2393   @param[in]        ppFreeQueue   Address of the free queue head
   2394   @param[in]        DebugFlags    Flags for debug messages
   2395   @param[in]        pEventName    Zero terminated string containing the event name
   2396   @param[in]        pfnCompletion Completion routine address
   2397 
   2398   @retval EFI_SUCCESS - The structures were properly initialized
   2399 **/
   2400 EFI_STATUS
   2401 EslSocketIoInit (
   2402   IN ESL_PORT * pPort,
   2403   IN ESL_IO_MGMT ** ppIo,
   2404   IN UINTN TokenCount,
   2405   IN ESL_IO_MGMT ** ppFreeQueue,
   2406   IN UINTN DebugFlags,
   2407   IN CHAR8 * pEventName,
   2408   IN PFN_API_IO_COMPLETE pfnCompletion
   2409   )
   2410 {
   2411   ESL_IO_MGMT * pEnd;
   2412   EFI_EVENT * pEvent;
   2413   ESL_IO_MGMT * pIo;
   2414   ESL_SOCKET * pSocket;
   2415   EFI_STATUS Status;
   2416 
   2417   DBG_ENTER ( );
   2418 
   2419   //
   2420   //  Assume success
   2421   //
   2422   Status = EFI_SUCCESS;
   2423 
   2424   //
   2425   //  Walk the list of IO structures
   2426   //
   2427   pSocket = pPort->pSocket;
   2428   pIo = *ppIo;
   2429   pEnd = &pIo [ TokenCount ];
   2430   while ( pEnd > pIo ) {
   2431     //
   2432     //  Initialize the IO structure
   2433     //
   2434     pIo->pPort = pPort;
   2435     pIo->pPacket = NULL;
   2436 
   2437     //
   2438     //  Allocate the event for this structure
   2439     //
   2440     pEvent = (EFI_EVENT *)&(((UINT8 *)pIo)[ pSocket->TxTokenEventOffset ]);
   2441     Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL,
   2442                                 TPL_SOCKETS,
   2443                                 (EFI_EVENT_NOTIFY)pfnCompletion,
   2444                                 pIo,
   2445                                 pEvent );
   2446     if ( EFI_ERROR ( Status )) {
   2447       DEBUG (( DEBUG_ERROR | DebugFlags,
   2448                 "ERROR - Failed to create the %a event, Status: %r\r\n",
   2449                 pEventName,
   2450                 Status ));
   2451       pSocket->errno = ENOMEM;
   2452       break;
   2453     }
   2454     DEBUG (( DebugFlags,
   2455               "0x%08x: Created %a event 0x%08x\r\n",
   2456               pIo,
   2457               pEventName,
   2458               *pEvent ));
   2459 
   2460     //
   2461     //  Add this structure to the queue
   2462     //
   2463     pIo->pNext = *ppFreeQueue;
   2464     *ppFreeQueue = pIo;
   2465 
   2466     //
   2467     //  Set the next structure
   2468     //
   2469     pIo += 1;
   2470   }
   2471 
   2472   //
   2473   //  Save the next structure
   2474   //
   2475   *ppIo = pIo;
   2476 
   2477   //
   2478   //  Return the operation status
   2479   //
   2480   DBG_EXIT_STATUS ( Status );
   2481   return Status;
   2482 }
   2483 
   2484 
   2485 /** Determine if the socket is configured.
   2486 
   2487   This support routine is called to determine if the socket if the
   2488   configuration call was made to the network layer.  The following
   2489   routines call this routine to verify that they may be successful
   2490   in their operations:
   2491   <ul>
   2492     <li>::EslSocketGetLocalAddress</li>
   2493     <li>::EslSocketGetPeerAddress</li>
   2494     <li>::EslSocketPoll</li>
   2495     <li>::EslSocketReceive</li>
   2496     <li>::EslSocketTransmit</li>
   2497   </ul>
   2498 
   2499   @param[in]  pSocket       Address of an ::ESL_SOCKET structure
   2500 
   2501   @retval EFI_SUCCESS - The socket is configured
   2502 **/
   2503 EFI_STATUS
   2504 EslSocketIsConfigured (
   2505   IN ESL_SOCKET * pSocket
   2506   )
   2507 {
   2508   EFI_STATUS Status;
   2509   EFI_TPL TplPrevious;
   2510 
   2511   //
   2512   //  Assume success
   2513   //
   2514   Status = EFI_SUCCESS;
   2515 
   2516   //
   2517   //  Verify the socket state
   2518   //
   2519   if ( !pSocket->bConfigured ) {
   2520     DBG_ENTER ( );
   2521 
   2522     //
   2523     //  Verify the API
   2524     //
   2525     if ( NULL == pSocket->pApi->pfnIsConfigured ) {
   2526       Status = EFI_UNSUPPORTED;
   2527       pSocket->errno = ENOTSUP;
   2528     }
   2529     else {
   2530       //
   2531       //  Synchronize with the socket layer
   2532       //
   2533       RAISE_TPL ( TplPrevious, TPL_SOCKETS );
   2534 
   2535       //
   2536       //  Determine if the socket is configured
   2537       //
   2538       Status = pSocket->pApi->pfnIsConfigured ( pSocket );
   2539 
   2540       //
   2541       //  Release the socket layer synchronization
   2542       //
   2543       RESTORE_TPL ( TplPrevious );
   2544 
   2545       //
   2546       //  Set errno if a failure occurs
   2547       //
   2548       if ( EFI_ERROR ( Status )) {
   2549         pSocket->errno = EADDRNOTAVAIL;
   2550       }
   2551     }
   2552 
   2553     DBG_EXIT_STATUS ( Status );
   2554   }
   2555 
   2556   //
   2557   //  Return the configuration status
   2558   //
   2559   return Status;
   2560 }
   2561 
   2562 
   2563 /** Establish the known port to listen for network connections.
   2564 
   2565   This routine calls into the network protocol layer to establish
   2566   a handler that is called upon connection completion.  The handler
   2567   is responsible for inserting the connection into the FIFO.
   2568 
   2569   The ::listen routine indirectly calls this routine to place the
   2570   socket into a state that enables connection attempts.  Connections
   2571   are placed in a FIFO that is serviced by the application.  The
   2572   application calls the ::accept (::EslSocketAccept) routine to
   2573   remove the next connection from the FIFO and get the associated
   2574   socket and address.
   2575 
   2576   @param[in]  pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
   2577   @param[in]  Backlog         Backlog specifies the maximum FIFO depth for
   2578                               the connections waiting for the application
   2579                               to call accept.  Connection attempts received
   2580                               while the queue is full are refused.
   2581   @param[out] pErrno          Address to receive the errno value upon completion.
   2582 
   2583   @retval EFI_SUCCESS - Socket successfully created
   2584   @retval Other - Failed to enable the socket for listen
   2585 **/
   2586 EFI_STATUS
   2587 EslSocketListen (
   2588   IN EFI_SOCKET_PROTOCOL * pSocketProtocol,
   2589   IN INT32 Backlog,
   2590   OUT int * pErrno
   2591   )
   2592 {
   2593   ESL_SOCKET * pSocket;
   2594   EFI_STATUS Status;
   2595   EFI_STATUS TempStatus;
   2596   EFI_TPL TplPrevious;
   2597 
   2598   DBG_ENTER ( );
   2599 
   2600   //
   2601   //  Assume success
   2602   //
   2603   Status = EFI_SUCCESS;
   2604 
   2605   //
   2606   //  Validate the socket
   2607   //
   2608   pSocket = NULL;
   2609   if ( NULL != pSocketProtocol ) {
   2610     pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
   2611 
   2612     //
   2613     //  Verify the API
   2614     //
   2615     if ( NULL == pSocket->pApi->pfnListen ) {
   2616       Status = EFI_UNSUPPORTED;
   2617       pSocket->errno = ENOTSUP;
   2618     }
   2619     else {
   2620       //
   2621       //  Assume success
   2622       //
   2623       pSocket->Status = EFI_SUCCESS;
   2624       pSocket->errno = 0;
   2625 
   2626       //
   2627       //  Verify that the bind operation was successful
   2628       //
   2629       if ( SOCKET_STATE_BOUND == pSocket->State ) {
   2630         //
   2631         //  Synchronize with the socket layer
   2632         //
   2633         RAISE_TPL ( TplPrevious, TPL_SOCKETS );
   2634 
   2635         //
   2636         //  Create the event for SocketAccept completion
   2637         //
   2638         Status = gBS->CreateEvent ( 0,
   2639                                     TPL_SOCKETS,
   2640                                     NULL,
   2641                                     NULL,
   2642                                     &pSocket->WaitAccept );
   2643         if ( !EFI_ERROR ( Status )) {
   2644           DEBUG (( DEBUG_POOL,
   2645                     "0x%08x: Created WaitAccept event\r\n",
   2646                     pSocket->WaitAccept ));
   2647           //
   2648           //  Set the maximum FIFO depth
   2649           //
   2650           if ( 0 >= Backlog ) {
   2651             Backlog = MAX_PENDING_CONNECTIONS;
   2652           }
   2653           else {
   2654             if ( SOMAXCONN < Backlog ) {
   2655               Backlog = SOMAXCONN;
   2656             }
   2657             else {
   2658               pSocket->MaxFifoDepth = Backlog;
   2659             }
   2660           }
   2661 
   2662           //
   2663           //  Initiate the connection attempt listen
   2664           //
   2665           Status = pSocket->pApi->pfnListen ( pSocket );
   2666 
   2667           //
   2668           //  Place the socket in the listen state if successful
   2669           //
   2670           if ( !EFI_ERROR ( Status )) {
   2671             pSocket->State = SOCKET_STATE_LISTENING;
   2672             pSocket->bListenCalled = TRUE;
   2673           }
   2674           else {
   2675             //
   2676             //  Not waiting for SocketAccept to complete
   2677             //
   2678             TempStatus = gBS->CloseEvent ( pSocket->WaitAccept );
   2679             if ( !EFI_ERROR ( TempStatus )) {
   2680               DEBUG (( DEBUG_POOL,
   2681                         "0x%08x: Closed WaitAccept event\r\n",
   2682                         pSocket->WaitAccept ));
   2683               pSocket->WaitAccept = NULL;
   2684             }
   2685             else {
   2686               DEBUG (( DEBUG_ERROR | DEBUG_POOL,
   2687                         "ERROR - Failed to close WaitAccept event, Status: %r\r\n",
   2688                         TempStatus ));
   2689               ASSERT ( EFI_SUCCESS == TempStatus );
   2690             }
   2691           }
   2692         }
   2693         else {
   2694           DEBUG (( DEBUG_ERROR | DEBUG_LISTEN,
   2695                     "ERROR - Failed to create the WaitAccept event, Status: %r\r\n",
   2696                     Status ));
   2697           pSocket->errno = ENOMEM;
   2698         }
   2699 
   2700         //
   2701         //  Release the socket layer synchronization
   2702         //
   2703         RESTORE_TPL ( TplPrevious );
   2704       }
   2705       else {
   2706         DEBUG (( DEBUG_ERROR | DEBUG_LISTEN,
   2707                   "ERROR - Bind operation must be performed first!\r\n" ));
   2708         pSocket->errno = ( SOCKET_STATE_NOT_CONFIGURED == pSocket->State ) ? EDESTADDRREQ
   2709                                                                            : EINVAL;
   2710         Status = EFI_NO_MAPPING;
   2711       }
   2712     }
   2713   }
   2714 
   2715   //
   2716   //  Return the operation status
   2717   //
   2718   if ( NULL != pErrno ) {
   2719     if ( NULL != pSocket ) {
   2720       *pErrno = pSocket->errno;
   2721     }
   2722     else {
   2723       Status = EFI_INVALID_PARAMETER;
   2724       *pErrno = ENOTSOCK;
   2725     }
   2726   }
   2727   DBG_EXIT_STATUS ( Status );
   2728   return Status;
   2729 }
   2730 
   2731 
   2732 /** Get the socket options.
   2733 
   2734   This routine handles the socket level options and passes the
   2735   others to the network specific layer.
   2736 
   2737   The ::getsockopt routine calls this routine to retrieve the
   2738   socket options one at a time by name.
   2739 
   2740   @param[in]      pSocketProtocol   Address of an ::EFI_SOCKET_PROTOCOL structure.
   2741   @param[in]      level             Option protocol level
   2742   @param[in]      OptionName        Name of the option
   2743   @param[out]     pOptionValue      Buffer to receive the option value
   2744   @param[in,out]  pOptionLength     Length of the buffer in bytes,
   2745                                     upon return length of the option value in bytes
   2746   @param[out]     pErrno            Address to receive the errno value upon completion.
   2747 
   2748   @retval EFI_SUCCESS - Socket data successfully received
   2749  **/
   2750 EFI_STATUS
   2751 EslSocketOptionGet (
   2752   IN EFI_SOCKET_PROTOCOL * pSocketProtocol,
   2753   IN int level,
   2754   IN int OptionName,
   2755   OUT void * __restrict pOptionValue,
   2756   IN OUT socklen_t * __restrict pOptionLength,
   2757   IN int * pErrno
   2758   )
   2759 {
   2760   int errno;
   2761   socklen_t LengthInBytes;
   2762   socklen_t MaxBytes;
   2763   CONST UINT8 * pOptionData;
   2764   ESL_SOCKET * pSocket;
   2765   EFI_STATUS Status;
   2766 
   2767   DBG_ENTER ( );
   2768 
   2769   //
   2770   //  Assume failure
   2771   //
   2772   errno = EINVAL;
   2773   Status = EFI_INVALID_PARAMETER;
   2774 
   2775   //
   2776   //  Validate the socket
   2777   //
   2778   pSocket = NULL;
   2779   if ( NULL == pSocketProtocol ) {
   2780     DEBUG (( DEBUG_OPTION, "ERROR - pSocketProtocol is NULL!\r\n" ));
   2781   }
   2782   else if ( NULL == pOptionValue ) {
   2783     DEBUG (( DEBUG_OPTION, "ERROR - No option buffer specified\r\n" ));
   2784   }
   2785   else if ( NULL == pOptionLength ) {
   2786     DEBUG (( DEBUG_OPTION, "ERROR - Option length not specified!\r\n" ));
   2787   }
   2788   else {
   2789     pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
   2790     LengthInBytes = 0;
   2791     MaxBytes = *pOptionLength;
   2792     pOptionData = NULL;
   2793     switch ( level ) {
   2794     default:
   2795       //
   2796       //  See if the protocol will handle the option
   2797       //
   2798       if ( NULL != pSocket->pApi->pfnOptionGet ) {
   2799         if ( pSocket->pApi->DefaultProtocol == level ) {
   2800           Status = pSocket->pApi->pfnOptionGet ( pSocket,
   2801                                                  OptionName,
   2802                                                  (CONST void ** __restrict)&pOptionData,
   2803                                                  &LengthInBytes );
   2804           errno = pSocket->errno;
   2805           break;
   2806         }
   2807         else {
   2808           //
   2809           //  Protocol not supported
   2810           //
   2811           DEBUG (( DEBUG_OPTION,
   2812                     "ERROR - The socket does not support this protocol!\r\n" ));
   2813         }
   2814       }
   2815       else {
   2816         //
   2817         //  Protocol level not supported
   2818         //
   2819         DEBUG (( DEBUG_OPTION,
   2820                   "ERROR - %a does not support any options!\r\n",
   2821                   pSocket->pApi->pName ));
   2822       }
   2823       errno = ENOPROTOOPT;
   2824       Status = EFI_INVALID_PARAMETER;
   2825       break;
   2826 
   2827     case SOL_SOCKET:
   2828       switch ( OptionName ) {
   2829       default:
   2830         //
   2831         //  Socket option not supported
   2832         //
   2833         DEBUG (( DEBUG_INFO | DEBUG_OPTION, "ERROR - Invalid socket option!\r\n" ));
   2834         errno = EINVAL;
   2835         Status = EFI_INVALID_PARAMETER;
   2836         break;
   2837 
   2838       case SO_ACCEPTCONN:
   2839         //
   2840         //  Return the listen flag
   2841         //
   2842         pOptionData = (CONST UINT8 *)&pSocket->bListenCalled;
   2843         LengthInBytes = sizeof ( pSocket->bListenCalled );
   2844         break;
   2845 
   2846       case SO_DEBUG:
   2847         //
   2848         //  Return the debug flags
   2849         //
   2850         pOptionData = (CONST UINT8 *)&pSocket->bOobInLine;
   2851         LengthInBytes = sizeof ( pSocket->bOobInLine );
   2852         break;
   2853 
   2854       case SO_OOBINLINE:
   2855         //
   2856         //  Return the out-of-band inline flag
   2857         //
   2858         pOptionData = (CONST UINT8 *)&pSocket->bOobInLine;
   2859         LengthInBytes = sizeof ( pSocket->bOobInLine );
   2860         break;
   2861 
   2862       case SO_RCVTIMEO:
   2863         //
   2864         //  Return the receive timeout
   2865         //
   2866         pOptionData = (CONST UINT8 *)&pSocket->RxTimeout;
   2867         LengthInBytes = sizeof ( pSocket->RxTimeout );
   2868         break;
   2869 
   2870       case SO_RCVBUF:
   2871         //
   2872         //  Return the maximum receive buffer size
   2873         //
   2874         pOptionData = (CONST UINT8 *)&pSocket->MaxRxBuf;
   2875         LengthInBytes = sizeof ( pSocket->MaxRxBuf );
   2876         break;
   2877 
   2878       case SO_REUSEADDR:
   2879         //
   2880         //  Return the address reuse flag
   2881         //
   2882         pOptionData = (UINT8 *)&pSocket->bReUseAddr;
   2883         LengthInBytes = sizeof ( pSocket->bReUseAddr );
   2884         break;
   2885 
   2886       case SO_SNDBUF:
   2887         //
   2888         //  Return the maximum transmit buffer size
   2889         //
   2890         pOptionData = (CONST UINT8 *)&pSocket->MaxTxBuf;
   2891         LengthInBytes = sizeof ( pSocket->MaxTxBuf );
   2892         break;
   2893 
   2894       case SO_TYPE:
   2895         //
   2896         //  Return the socket type
   2897         //
   2898         pOptionData = (CONST UINT8 *)&pSocket->Type;
   2899         LengthInBytes = sizeof ( pSocket->Type );
   2900         break;
   2901       }
   2902       break;
   2903     }
   2904 
   2905     //
   2906     //  Return the option length
   2907     //
   2908     *pOptionLength = LengthInBytes;
   2909 
   2910     //
   2911     //  Determine if the option is present
   2912     //
   2913     if ( 0 != LengthInBytes ) {
   2914       //
   2915       //  Silently truncate the value length
   2916       //
   2917       if ( LengthInBytes > MaxBytes ) {
   2918         DEBUG (( DEBUG_OPTION,
   2919                   "INFO - Truncating option from %d to %d bytes\r\n",
   2920                   LengthInBytes,
   2921                   MaxBytes ));
   2922         LengthInBytes = MaxBytes;
   2923       }
   2924 
   2925       //
   2926       //  Return the value
   2927       //
   2928       CopyMem ( pOptionValue, pOptionData, LengthInBytes );
   2929 
   2930       //
   2931       //  Zero fill any remaining space
   2932       //
   2933       if ( LengthInBytes < MaxBytes ) {
   2934         ZeroMem ( &((UINT8 *)pOptionValue)[LengthInBytes], MaxBytes - LengthInBytes );
   2935       }
   2936       errno = 0;
   2937       Status = EFI_SUCCESS;
   2938     }
   2939   }
   2940 
   2941   //
   2942   //  Return the operation status
   2943   //
   2944   if ( NULL != pErrno ) {
   2945     *pErrno = errno;
   2946   }
   2947   DBG_EXIT_STATUS ( Status );
   2948   return Status;
   2949 }
   2950 
   2951 
   2952 /** Set the socket options.
   2953 
   2954   This routine handles the socket level options and passes the
   2955   others to the network specific layer.
   2956 
   2957   The ::setsockopt routine calls this routine to adjust the socket
   2958   options one at a time by name.
   2959 
   2960   @param[in]  pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
   2961   @param[in]  level           Option protocol level
   2962   @param[in]  OptionName      Name of the option
   2963   @param[in]  pOptionValue    Buffer containing the option value
   2964   @param[in]  OptionLength    Length of the buffer in bytes
   2965   @param[out] pErrno          Address to receive the errno value upon completion.
   2966 
   2967   @retval EFI_SUCCESS - Option successfully set
   2968 **/
   2969 EFI_STATUS
   2970 EslSocketOptionSet (
   2971   IN EFI_SOCKET_PROTOCOL * pSocketProtocol,
   2972   IN int level,
   2973   IN int OptionName,
   2974   IN CONST void * pOptionValue,
   2975   IN socklen_t OptionLength,
   2976   IN int * pErrno
   2977   )
   2978 {
   2979   BOOLEAN bTrueFalse;
   2980   int errno;
   2981   socklen_t LengthInBytes;
   2982   UINT8 * pOptionData;
   2983   ESL_SOCKET * pSocket;
   2984   EFI_STATUS Status;
   2985 
   2986   DBG_ENTER ( );
   2987 
   2988   //
   2989   //  Assume failure
   2990   //
   2991   errno = EINVAL;
   2992   Status = EFI_INVALID_PARAMETER;
   2993 
   2994   //
   2995   //  Validate the socket
   2996   //
   2997   pSocket = NULL;
   2998   if ( NULL == pSocketProtocol ) {
   2999     DEBUG (( DEBUG_OPTION, "ERROR - pSocketProtocol is NULL!\r\n" ));
   3000   }
   3001   else if ( NULL == pOptionValue ) {
   3002     DEBUG (( DEBUG_OPTION, "ERROR - No option buffer specified\r\n" ));
   3003   }
   3004   else
   3005   {
   3006     pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
   3007     if ( pSocket->bRxDisable || pSocket->bTxDisable ) {
   3008       DEBUG (( DEBUG_OPTION, "ERROR - Socket has been shutdown!\r\n" ));
   3009     }
   3010     else {
   3011       LengthInBytes = 0;
   3012       pOptionData = NULL;
   3013       switch ( level ) {
   3014       default:
   3015         //
   3016         //  See if the protocol will handle the option
   3017         //
   3018         if ( NULL != pSocket->pApi->pfnOptionSet ) {
   3019           if ( pSocket->pApi->DefaultProtocol == level ) {
   3020             Status = pSocket->pApi->pfnOptionSet ( pSocket,
   3021                                                    OptionName,
   3022                                                    pOptionValue,
   3023                                                    OptionLength );
   3024             errno = pSocket->errno;
   3025             break;
   3026           }
   3027           else {
   3028             //
   3029             //  Protocol not supported
   3030             //
   3031             DEBUG (( DEBUG_OPTION,
   3032                       "ERROR - The socket does not support this protocol!\r\n" ));
   3033           }
   3034         }
   3035         else {
   3036           //
   3037           //  Protocol level not supported
   3038           //
   3039           DEBUG (( DEBUG_OPTION,
   3040                     "ERROR - %a does not support any options!\r\n",
   3041                     pSocket->pApi->pName ));
   3042         }
   3043         errno = ENOPROTOOPT;
   3044         Status = EFI_INVALID_PARAMETER;
   3045         break;
   3046 
   3047       case SOL_SOCKET:
   3048         switch ( OptionName ) {
   3049         default:
   3050           //
   3051           //  Option not supported
   3052           //
   3053           DEBUG (( DEBUG_OPTION,
   3054                     "ERROR - Sockets does not support this option!\r\n" ));
   3055           errno = EINVAL;
   3056           Status = EFI_INVALID_PARAMETER;
   3057           break;
   3058 
   3059         case SO_DEBUG:
   3060           //
   3061           //  Set the debug flags
   3062           //
   3063           pOptionData = (UINT8 *)&pSocket->bOobInLine;
   3064           LengthInBytes = sizeof ( pSocket->bOobInLine );
   3065           break;
   3066 
   3067         case SO_OOBINLINE:
   3068           pOptionData = (UINT8 *)&pSocket->bOobInLine;
   3069           LengthInBytes = sizeof ( pSocket->bOobInLine );
   3070 
   3071           //
   3072           //  Validate the option length
   3073           //
   3074           if ( sizeof ( UINT32 ) == OptionLength ) {
   3075             //
   3076             //  Restrict the input to TRUE or FALSE
   3077             //
   3078             bTrueFalse = TRUE;
   3079             if ( 0 == *(UINT32 *)pOptionValue ) {
   3080               bTrueFalse = FALSE;
   3081             }
   3082             pOptionValue = &bTrueFalse;
   3083           }
   3084           else {
   3085             //
   3086             //  Force an invalid option length error
   3087             //
   3088             OptionLength = LengthInBytes - 1;
   3089           }
   3090           break;
   3091 
   3092         case SO_RCVTIMEO:
   3093           //
   3094           //  Return the receive timeout
   3095           //
   3096           pOptionData = (UINT8 *)&pSocket->RxTimeout;
   3097           LengthInBytes = sizeof ( pSocket->RxTimeout );
   3098           break;
   3099 
   3100         case SO_RCVBUF:
   3101           //
   3102           //  Return the maximum receive buffer size
   3103           //
   3104           pOptionData = (UINT8 *)&pSocket->MaxRxBuf;
   3105           LengthInBytes = sizeof ( pSocket->MaxRxBuf );
   3106           break;
   3107 
   3108         case SO_REUSEADDR:
   3109           //
   3110           //  Return the address reuse flag
   3111           //
   3112           pOptionData = (UINT8 *)&pSocket->bReUseAddr;
   3113           LengthInBytes = sizeof ( pSocket->bReUseAddr );
   3114           break;
   3115 
   3116         case SO_SNDBUF:
   3117           //
   3118           //  Send buffer size
   3119           //
   3120           //
   3121           //  Return the maximum transmit buffer size
   3122           //
   3123           pOptionData = (UINT8 *)&pSocket->MaxTxBuf;
   3124           LengthInBytes = sizeof ( pSocket->MaxTxBuf );
   3125           break;
   3126         }
   3127         break;
   3128       }
   3129 
   3130       //
   3131       //  Determine if an option was found
   3132       //
   3133       if ( 0 != LengthInBytes ) {
   3134         //
   3135         //  Validate the option length
   3136         //
   3137         if ( LengthInBytes <= OptionLength ) {
   3138           //
   3139           //  Set the option value
   3140           //
   3141           CopyMem ( pOptionData, pOptionValue, LengthInBytes );
   3142           errno = 0;
   3143           Status = EFI_SUCCESS;
   3144         }
   3145         else {
   3146           DEBUG (( DEBUG_OPTION,
   3147                     "ERROR - Buffer to small, %d bytes < %d bytes!\r\n",
   3148                     OptionLength,
   3149                     LengthInBytes ));
   3150         }
   3151       }
   3152     }
   3153   }
   3154 
   3155   //
   3156   //  Return the operation status
   3157   //
   3158   if ( NULL != pErrno ) {
   3159     *pErrno = errno;
   3160   }
   3161   DBG_EXIT_STATUS ( Status );
   3162   return Status;
   3163 }
   3164 
   3165 
   3166 /**  Allocate a packet for a receive or transmit operation.
   3167 
   3168   This support routine is called by ::EslSocketRxStart and the
   3169   network specific TxBuffer routines to get buffer space for the
   3170   next operation.
   3171 
   3172   @param[in]  ppPacket      Address to receive the ::ESL_PACKET structure
   3173   @param[in]  LengthInBytes Length of the packet structure
   3174   @param[in]  ZeroBytes     Length of packet to zero
   3175   @param[in]  DebugFlags    Flags for debug messages
   3176 
   3177   @retval EFI_SUCCESS - The packet was allocated successfully
   3178 **/
   3179 EFI_STATUS
   3180 EslSocketPacketAllocate (
   3181   IN ESL_PACKET ** ppPacket,
   3182   IN size_t LengthInBytes,
   3183   IN size_t ZeroBytes,
   3184   IN UINTN DebugFlags
   3185   )
   3186 {
   3187   ESL_PACKET * pPacket;
   3188   EFI_STATUS Status;
   3189 
   3190   DBG_ENTER ( );
   3191 
   3192   //
   3193   //  Allocate a packet structure
   3194   //
   3195   LengthInBytes += sizeof ( *pPacket )
   3196                 - sizeof ( pPacket->Op );
   3197   Status = gBS->AllocatePool ( EfiRuntimeServicesData,
   3198                                LengthInBytes,
   3199                                (VOID **)&pPacket );
   3200   if ( !EFI_ERROR ( Status )) {
   3201     DEBUG (( DebugFlags | DEBUG_POOL,
   3202               "0x%08x: Allocate pPacket, %d bytes\r\n",
   3203               pPacket,
   3204               LengthInBytes ));
   3205     if ( 0 != ZeroBytes ) {
   3206       ZeroMem ( &pPacket->Op, ZeroBytes );
   3207     }
   3208     pPacket->PacketSize = LengthInBytes;
   3209   }
   3210   else {
   3211     DEBUG (( DebugFlags | DEBUG_POOL | DEBUG_INFO,
   3212               "ERROR - Packet allocation failed for %d bytes, Status: %r\r\n",
   3213               LengthInBytes,
   3214               Status ));
   3215     pPacket = NULL;
   3216   }
   3217 
   3218   //
   3219   //  Return the packet
   3220   //
   3221   *ppPacket = pPacket;
   3222 
   3223   //
   3224   //  Return the operation status
   3225   //
   3226   DBG_EXIT_STATUS ( Status );
   3227   return Status;
   3228 }
   3229 
   3230 
   3231 /** Free a packet used for receive or transmit operation.
   3232 
   3233   This support routine is called by the network specific Close
   3234   and TxComplete routines and during error cases in RxComplete
   3235   and TxBuffer.  Note that the network layers typically place
   3236   receive packets on the ESL_SOCKET::pRxFree list for reuse.
   3237 
   3238   @param[in]  pPacket     Address of an ::ESL_PACKET structure
   3239   @param[in]  DebugFlags  Flags for debug messages
   3240 
   3241   @retval EFI_SUCCESS - The packet was allocated successfully
   3242 **/
   3243 EFI_STATUS
   3244 EslSocketPacketFree (
   3245   IN ESL_PACKET * pPacket,
   3246   IN UINTN DebugFlags
   3247   )
   3248 {
   3249   UINTN LengthInBytes;
   3250   EFI_STATUS Status;
   3251 
   3252   DBG_ENTER ( );
   3253 
   3254   //
   3255   //  Free a packet structure
   3256   //
   3257   LengthInBytes = pPacket->PacketSize;
   3258   Status = gBS->FreePool ( pPacket );
   3259   if ( !EFI_ERROR ( Status )) {
   3260     DEBUG (( DebugFlags | DEBUG_POOL,
   3261               "0x%08x: Free pPacket, %d bytes\r\n",
   3262               pPacket,
   3263               LengthInBytes ));
   3264   }
   3265   else {
   3266     DEBUG (( DebugFlags | DEBUG_POOL | DEBUG_INFO,
   3267               "ERROR - Failed to free packet 0x%08x, Status: %r\r\n",
   3268               pPacket,
   3269               Status ));
   3270   }
   3271 
   3272   //
   3273   //  Return the operation status
   3274   //
   3275   DBG_EXIT_STATUS ( Status );
   3276   return Status;
   3277 }
   3278 
   3279 
   3280 /** Poll a socket for pending activity.
   3281 
   3282   This routine builds a detected event mask which is returned to
   3283   the caller in the buffer provided.
   3284 
   3285   The ::poll routine calls this routine to determine if the socket
   3286   needs to be serviced as a result of connection, error, receive or
   3287   transmit activity.
   3288 
   3289   @param[in]  pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
   3290   @param[in]  Events          Events of interest for this socket
   3291   @param[in]  pEvents         Address to receive the detected events
   3292   @param[out] pErrno          Address to receive the errno value upon completion.
   3293 
   3294   @retval EFI_SUCCESS - Socket successfully polled
   3295   @retval EFI_INVALID_PARAMETER - When pEvents is NULL
   3296 **/
   3297 EFI_STATUS
   3298 EslSocketPoll (
   3299   IN EFI_SOCKET_PROTOCOL * pSocketProtocol,
   3300   IN short Events,
   3301   IN short * pEvents,
   3302   IN int * pErrno
   3303   )
   3304 {
   3305   short DetectedEvents;
   3306   ESL_SOCKET * pSocket;
   3307   EFI_STATUS Status;
   3308   EFI_TPL TplPrevious;
   3309   short ValidEvents;
   3310   int   _errno = EINVAL;
   3311 
   3312   DEBUG (( DEBUG_POLL, "Entering SocketPoll\r\n" ));
   3313 
   3314   //
   3315   //  Assume success
   3316   //
   3317   Status = EFI_SUCCESS;
   3318   DetectedEvents = 0;
   3319   pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
   3320   pSocket->errno = 0;
   3321 
   3322   //
   3323   //  Verify the socket state
   3324   //
   3325   Status = EslSocketIsConfigured ( pSocket );
   3326   if ( !EFI_ERROR ( Status )) {
   3327     //
   3328     //  Check for invalid events
   3329     //
   3330     ValidEvents = POLLIN
   3331                 | POLLPRI
   3332                 | POLLOUT | POLLWRNORM
   3333                 | POLLERR
   3334                 | POLLHUP
   3335                 | POLLNVAL
   3336                 | POLLRDNORM
   3337                 | POLLRDBAND
   3338                 | POLLWRBAND ;
   3339     if ( 0 != ( Events & ( ~ValidEvents ))) {
   3340       DetectedEvents |= POLLNVAL;
   3341       DEBUG (( DEBUG_INFO | DEBUG_POLL,
   3342                 "ERROR - Invalid event mask, Valid Events: 0x%04x, Invalid Events: 0x%04x\r\n",
   3343                 Events & ValidEvents,
   3344                 Events & ( ~ValidEvents )));
   3345     }
   3346     else {
   3347       //
   3348       //  Synchronize with the socket layer
   3349       //
   3350       RAISE_TPL ( TplPrevious, TPL_SOCKETS );
   3351 
   3352       //
   3353       //  Increase the network performance by extending the
   3354       //  polling (idle) loop down into the LAN driver
   3355       //
   3356       EslSocketRxPoll ( pSocket );
   3357 
   3358       //
   3359       //  Release the socket layer synchronization
   3360       //
   3361       RESTORE_TPL ( TplPrevious );
   3362 
   3363       //
   3364       //  Check for pending connections
   3365       //
   3366       if ( 0 != pSocket->FifoDepth ) {
   3367         //
   3368         //  A connection is waiting for an accept call
   3369         //  See posix connect documentation at
   3370         //  http://pubs.opengroup.org/onlinepubs/9699919799/functions/accept.htm
   3371         //
   3372         DetectedEvents |= POLLIN | POLLRDNORM;
   3373       }
   3374       if ( pSocket->bConnected ) {
   3375         //
   3376         //  A connection is present
   3377         //  See posix connect documentation at
   3378         //  http://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.htm
   3379         //
   3380         DetectedEvents |= POLLOUT | POLLWRNORM;
   3381       }
   3382 
   3383       //
   3384       //  The following bits are set based upon the POSIX poll documentation at
   3385       //  http://pubs.opengroup.org/onlinepubs/9699919799/functions/poll.html
   3386       //
   3387 
   3388       //
   3389       //  Check for urgent receive data
   3390       //
   3391       if ( 0 < pSocket->RxOobBytes ) {
   3392         DetectedEvents |= POLLRDBAND | POLLPRI | POLLIN;
   3393       }
   3394 
   3395       //
   3396       //  Check for normal receive data
   3397       //
   3398       if (( 0 < pSocket->RxBytes )
   3399         || ( EFI_SUCCESS != pSocket->RxError )) {
   3400         DetectedEvents |= POLLRDNORM | POLLIN;
   3401       }
   3402 
   3403       //
   3404       //  Handle the receive errors
   3405       //
   3406       if (( EFI_SUCCESS != pSocket->RxError )
   3407         && ( 0 == ( DetectedEvents & POLLIN ))) {
   3408         DetectedEvents |= POLLERR | POLLIN | POLLRDNORM | POLLRDBAND;
   3409       }
   3410 
   3411       //
   3412       //  Check for urgent transmit data buffer space
   3413       //
   3414       if (( MAX_TX_DATA > pSocket->TxOobBytes )
   3415         || ( EFI_SUCCESS != pSocket->TxError )) {
   3416         DetectedEvents |= POLLWRBAND;
   3417       }
   3418 
   3419       //
   3420       //  Check for normal transmit data buffer space
   3421       //
   3422       if (( MAX_TX_DATA > pSocket->TxBytes )
   3423         || ( EFI_SUCCESS != pSocket->TxError )) {
   3424         DetectedEvents |= POLLWRNORM;
   3425       }
   3426 
   3427       //
   3428       //  Handle the transmit error
   3429       //
   3430       if ( EFI_ERROR ( pSocket->TxError )) {
   3431         DetectedEvents |= POLLERR;
   3432       }
   3433       _errno = pSocket->errno;
   3434     }
   3435   }
   3436 
   3437   //
   3438   //  Return the detected events
   3439   //
   3440   *pEvents = DetectedEvents & ( Events
   3441                               | POLLERR
   3442                               | POLLHUP
   3443                               | POLLNVAL );
   3444   if ( NULL != pErrno ) {
   3445     *pErrno = _errno;
   3446   }
   3447   //
   3448   //  Return the operation status
   3449   //
   3450   DEBUG (( DEBUG_POLL, "Exiting SocketPoll, Status: %r\r\n", Status ));
   3451   return Status;
   3452 }
   3453 
   3454 
   3455 /** Allocate and initialize a ESL_PORT structure.
   3456 
   3457   This routine initializes an ::ESL_PORT structure for use by
   3458   the socket.  This routine calls a routine via
   3459   ESL_PROTOCOL_API::pfnPortAllocate to initialize the network
   3460   specific resources.  The resources are released later by the
   3461   \ref PortCloseStateMachine.
   3462 
   3463   This support routine is called by:
   3464   <ul>
   3465     <li>::EslSocketBind</li>
   3466     <li>::EslTcp4ListenComplete</li>
   3467   </ul>
   3468   to connect the socket with the underlying network adapter
   3469   to the socket.
   3470 
   3471   @param[in]  pSocket     Address of an ::ESL_SOCKET structure.
   3472   @param[in]  pService    Address of an ::ESL_SERVICE structure.
   3473   @param[in]  ChildHandle Network protocol child handle
   3474   @param[in]  pSockAddr   Address of a sockaddr structure that contains the
   3475                           connection point on the local machine.  An IPv4 address
   3476                           of INADDR_ANY specifies that the connection is made to
   3477                           all of the network stacks on the platform.  Specifying a
   3478                           specific IPv4 address restricts the connection to the
   3479                           network stack supporting that address.  Specifying zero
   3480                           for the port causes the network layer to assign a port
   3481                           number from the dynamic range.  Specifying a specific
   3482                           port number causes the network layer to use that port.
   3483   @param[in]  bBindTest   TRUE if EslSocketBindTest should be called
   3484   @param[in]  DebugFlags  Flags for debug messages
   3485   @param[out] ppPort      Buffer to receive new ::ESL_PORT structure address
   3486 
   3487   @retval EFI_SUCCESS - Socket successfully created
   3488 **/
   3489 EFI_STATUS
   3490 EslSocketPortAllocate (
   3491   IN ESL_SOCKET * pSocket,
   3492   IN ESL_SERVICE * pService,
   3493   IN EFI_HANDLE ChildHandle,
   3494   IN CONST struct sockaddr * pSockAddr,
   3495   IN BOOLEAN bBindTest,
   3496   IN UINTN DebugFlags,
   3497   OUT ESL_PORT ** ppPort
   3498   )
   3499 {
   3500   UINTN LengthInBytes;
   3501   UINT8 * pBuffer;
   3502   ESL_IO_MGMT * pIo;
   3503   ESL_LAYER * pLayer;
   3504   ESL_PORT * pPort;
   3505   EFI_SERVICE_BINDING_PROTOCOL * pServiceBinding;
   3506   CONST ESL_SOCKET_BINDING * pSocketBinding;
   3507   EFI_STATUS Status;
   3508   EFI_STATUS TempStatus;
   3509 
   3510   DBG_ENTER ( );
   3511 
   3512   //
   3513   //  Verify the socket layer synchronization
   3514   //
   3515   VERIFY_TPL ( TPL_SOCKETS );
   3516 
   3517   //
   3518   //  Use for/break instead of goto
   3519   pSocketBinding = pService->pSocketBinding;
   3520   for ( ; ; ) {
   3521     //
   3522     //  Allocate a port structure
   3523     //
   3524     pLayer = &mEslLayer;
   3525     LengthInBytes = sizeof ( *pPort )
   3526                   + ESL_STRUCTURE_ALIGNMENT_BYTES
   3527                   + (( pSocketBinding->RxIo
   3528                        + pSocketBinding->TxIoNormal
   3529                        + pSocketBinding->TxIoUrgent )
   3530                      * sizeof ( ESL_IO_MGMT ));
   3531     pPort = (ESL_PORT *) AllocateZeroPool ( LengthInBytes );
   3532     if ( NULL == pPort ) {
   3533       Status = EFI_OUT_OF_RESOURCES;
   3534       pSocket->errno = ENOMEM;
   3535       break;
   3536     }
   3537     DEBUG (( DebugFlags | DEBUG_POOL | DEBUG_INIT,
   3538               "0x%08x: Allocate pPort, %d bytes\r\n",
   3539               pPort,
   3540               LengthInBytes ));
   3541 
   3542     //
   3543     //  Initialize the port
   3544     //
   3545     pPort->DebugFlags = DebugFlags;
   3546     pPort->Handle = ChildHandle;
   3547     pPort->pService = pService;
   3548     pPort->pServiceBinding = pService->pServiceBinding;
   3549     pPort->pSocket = pSocket;
   3550     pPort->pSocketBinding = pService->pSocketBinding;
   3551     pPort->Signature = PORT_SIGNATURE;
   3552 
   3553     //
   3554     //  Open the port protocol
   3555     //
   3556     Status = gBS->OpenProtocol ( pPort->Handle,
   3557                                  pSocketBinding->pNetworkProtocolGuid,
   3558                                  &pPort->pProtocol.v,
   3559                                  pLayer->ImageHandle,
   3560                                  NULL,
   3561                                  EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL );
   3562     if ( EFI_ERROR ( Status )) {
   3563       DEBUG (( DEBUG_ERROR | DebugFlags,
   3564                 "ERROR - Failed to open network protocol GUID on controller 0x%08x\r\n",
   3565                 pPort->Handle ));
   3566       pSocket->errno = EEXIST;
   3567       break;
   3568     }
   3569     DEBUG (( DebugFlags,
   3570               "0x%08x: Network protocol GUID opened on controller 0x%08x\r\n",
   3571               pPort->pProtocol.v,
   3572               pPort->Handle ));
   3573 
   3574     //
   3575     //  Initialize the port specific resources
   3576     //
   3577     Status = pSocket->pApi->pfnPortAllocate ( pPort,
   3578                                               DebugFlags );
   3579     if ( EFI_ERROR ( Status )) {
   3580       break;
   3581     }
   3582 
   3583     //
   3584     //  Set the local address
   3585     //
   3586     Status = pSocket->pApi->pfnLocalAddrSet ( pPort, pSockAddr, bBindTest );
   3587     if ( EFI_ERROR ( Status )) {
   3588       break;
   3589     }
   3590 
   3591     //
   3592     //  Test the address/port configuration
   3593     //
   3594     if ( bBindTest ) {
   3595       Status = EslSocketBindTest ( pPort, pSocket->pApi->BindTestErrno );
   3596       if ( EFI_ERROR ( Status )) {
   3597         break;
   3598       }
   3599     }
   3600 
   3601     //
   3602     //  Initialize the receive structures
   3603     //
   3604     pBuffer = (UINT8 *)&pPort[ 1 ];
   3605     pBuffer = &pBuffer[ ESL_STRUCTURE_ALIGNMENT_BYTES ];
   3606     pBuffer = (UINT8 *)( ESL_STRUCTURE_ALIGNMENT_MASK & (UINTN)pBuffer );
   3607     pIo = (ESL_IO_MGMT *)pBuffer;
   3608     if (( 0 != pSocketBinding->RxIo )
   3609       && ( NULL != pSocket->pApi->pfnRxComplete )) {
   3610       Status = EslSocketIoInit ( pPort,
   3611                                  &pIo,
   3612                                  pSocketBinding->RxIo,
   3613                                  &pPort->pRxFree,
   3614                                  DebugFlags | DEBUG_POOL,
   3615                                  "receive",
   3616                                  pSocket->pApi->pfnRxComplete );
   3617       if ( EFI_ERROR ( Status )) {
   3618         break;
   3619       }
   3620     }
   3621 
   3622     //
   3623     //  Initialize the urgent transmit structures
   3624     //
   3625     if (( 0 != pSocketBinding->TxIoUrgent )
   3626       && ( NULL != pSocket->pApi->pfnTxOobComplete )) {
   3627       Status = EslSocketIoInit ( pPort,
   3628                                  &pIo,
   3629                                  pSocketBinding->TxIoUrgent,
   3630                                  &pPort->pTxOobFree,
   3631                                  DebugFlags | DEBUG_POOL,
   3632                                  "urgent transmit",
   3633                                  pSocket->pApi->pfnTxOobComplete );
   3634       if ( EFI_ERROR ( Status )) {
   3635         break;
   3636       }
   3637     }
   3638 
   3639     //
   3640     //  Initialize the normal transmit structures
   3641     //
   3642     if (( 0 != pSocketBinding->TxIoNormal )
   3643       && ( NULL != pSocket->pApi->pfnTxComplete )) {
   3644       Status = EslSocketIoInit ( pPort,
   3645                                  &pIo,
   3646                                  pSocketBinding->TxIoNormal,
   3647                                  &pPort->pTxFree,
   3648                                  DebugFlags | DEBUG_POOL,
   3649                                  "normal transmit",
   3650                                  pSocket->pApi->pfnTxComplete );
   3651       if ( EFI_ERROR ( Status )) {
   3652         break;
   3653       }
   3654     }
   3655 
   3656     //
   3657     //  Add this port to the socket
   3658     //
   3659     pPort->pLinkSocket = pSocket->pPortList;
   3660     pSocket->pPortList = pPort;
   3661     DEBUG (( DebugFlags,
   3662               "0x%08x: Socket adding port: 0x%08x\r\n",
   3663               pSocket,
   3664               pPort ));
   3665 
   3666     //
   3667     //  Add this port to the service
   3668     //
   3669     pPort->pLinkService = pService->pPortList;
   3670     pService->pPortList = pPort;
   3671 
   3672     //
   3673     //  Return the port
   3674     //
   3675     *ppPort = pPort;
   3676     break;
   3677   }
   3678 
   3679   //
   3680   //  Clean up after the error if necessary
   3681   //
   3682   if ( EFI_ERROR ( Status )) {
   3683     if ( NULL != pPort ) {
   3684       //
   3685       //  Close the port
   3686       //
   3687       EslSocketPortClose ( pPort );
   3688     }
   3689     else {
   3690       //
   3691       //  Close the port if necessary
   3692       //
   3693       pServiceBinding = pService->pServiceBinding;
   3694       TempStatus = pServiceBinding->DestroyChild ( pServiceBinding,
   3695                                                    ChildHandle );
   3696       if ( !EFI_ERROR ( TempStatus )) {
   3697         DEBUG (( DEBUG_BIND | DEBUG_POOL,
   3698                   "0x%08x: %s port handle destroyed\r\n",
   3699                   ChildHandle,
   3700                   pSocketBinding->pName ));
   3701       }
   3702       else {
   3703         DEBUG (( DEBUG_ERROR | DEBUG_BIND | DEBUG_POOL,
   3704                   "ERROR - Failed to destroy the %s port handle 0x%08x, Status: %r\r\n",
   3705                   pSocketBinding->pName,
   3706                   ChildHandle,
   3707                   TempStatus ));
   3708         ASSERT ( EFI_SUCCESS == TempStatus );
   3709       }
   3710     }
   3711   }
   3712   //
   3713   //  Return the operation status
   3714   //
   3715   DBG_EXIT_STATUS ( Status );
   3716   return Status;
   3717 }
   3718 
   3719 
   3720 /** Close a port.
   3721 
   3722   This routine releases the resources allocated by ::EslSocketPortAllocate.
   3723   This routine calls ESL_PROTOCOL_API::pfnPortClose to release the network
   3724   specific resources.
   3725 
   3726   This routine is called by:
   3727   <ul>
   3728     <li>::EslSocketPortAllocate - Port initialization failure</li>
   3729     <li>::EslSocketPortCloseRxDone - Last step of close processing</li>
   3730     <li>::EslTcp4ConnectComplete - Connection failure and reducing the port list to a single port</li>
   3731   </ul>
   3732   See the \ref PortCloseStateMachine section.
   3733 
   3734   @param[in]  pPort       Address of an ::ESL_PORT structure.
   3735 
   3736   @retval EFI_SUCCESS     The port is closed
   3737   @retval other           Port close error
   3738 **/
   3739 EFI_STATUS
   3740 EslSocketPortClose (
   3741   IN ESL_PORT * pPort
   3742   )
   3743 {
   3744   UINTN DebugFlags;
   3745   ESL_LAYER * pLayer;
   3746   ESL_PACKET * pPacket;
   3747   ESL_PORT * pPreviousPort;
   3748   ESL_SERVICE * pService;
   3749   EFI_SERVICE_BINDING_PROTOCOL * pServiceBinding;
   3750   CONST ESL_SOCKET_BINDING * pSocketBinding;
   3751   ESL_SOCKET * pSocket;
   3752   EFI_STATUS Status;
   3753 
   3754   DBG_ENTER ( );
   3755 
   3756   //
   3757   //  Verify the socket layer synchronization
   3758   //
   3759   VERIFY_TPL ( TPL_SOCKETS );
   3760 
   3761   //
   3762   //  Locate the port in the socket list
   3763   //
   3764   Status = EFI_SUCCESS;
   3765   pLayer = &mEslLayer;
   3766   DebugFlags = pPort->DebugFlags;
   3767   pSocket = pPort->pSocket;
   3768   pPreviousPort = pSocket->pPortList;
   3769   if ( pPreviousPort == pPort ) {
   3770     //
   3771     //  Remove this port from the head of the socket list
   3772     //
   3773     pSocket->pPortList = pPort->pLinkSocket;
   3774   }
   3775   else {
   3776     //
   3777     //  Locate the port in the middle of the socket list
   3778     //
   3779     while (( NULL != pPreviousPort )
   3780       && ( pPreviousPort->pLinkSocket != pPort )) {
   3781       pPreviousPort = pPreviousPort->pLinkSocket;
   3782     }
   3783     if ( NULL != pPreviousPort ) {
   3784       //
   3785       //  Remove the port from the middle of the socket list
   3786       //
   3787       pPreviousPort->pLinkSocket = pPort->pLinkSocket;
   3788     }
   3789   }
   3790 
   3791   //
   3792   //  Locate the port in the service list
   3793   //  Note that the port may not be in the service list
   3794   //  if the service has been shutdown.
   3795   //
   3796   pService = pPort->pService;
   3797   if ( NULL != pService ) {
   3798     pPreviousPort = pService->pPortList;
   3799     if ( pPreviousPort == pPort ) {
   3800       //
   3801       //  Remove this port from the head of the service list
   3802       //
   3803       pService->pPortList = pPort->pLinkService;
   3804     }
   3805     else {
   3806       //
   3807       //  Locate the port in the middle of the service list
   3808       //
   3809       while (( NULL != pPreviousPort )
   3810         && ( pPreviousPort->pLinkService != pPort )) {
   3811         pPreviousPort = pPreviousPort->pLinkService;
   3812       }
   3813       if ( NULL != pPreviousPort ) {
   3814         //
   3815         //  Remove the port from the middle of the service list
   3816         //
   3817         pPreviousPort->pLinkService = pPort->pLinkService;
   3818       }
   3819     }
   3820   }
   3821 
   3822   //
   3823   //  Empty the urgent receive queue
   3824   //
   3825   while ( NULL != pSocket->pRxOobPacketListHead ) {
   3826     pPacket = pSocket->pRxOobPacketListHead;
   3827     pSocket->pRxOobPacketListHead = pPacket->pNext;
   3828     pSocket->pApi->pfnPacketFree ( pPacket, &pSocket->RxOobBytes );
   3829     EslSocketPacketFree ( pPacket, DEBUG_RX );
   3830   }
   3831   pSocket->pRxOobPacketListTail = NULL;
   3832   ASSERT ( 0 == pSocket->RxOobBytes );
   3833 
   3834   //
   3835   //  Empty the receive queue
   3836   //
   3837   while ( NULL != pSocket->pRxPacketListHead ) {
   3838     pPacket = pSocket->pRxPacketListHead;
   3839     pSocket->pRxPacketListHead = pPacket->pNext;
   3840     pSocket->pApi->pfnPacketFree ( pPacket, &pSocket->RxBytes );
   3841     EslSocketPacketFree ( pPacket, DEBUG_RX );
   3842   }
   3843   pSocket->pRxPacketListTail = NULL;
   3844   ASSERT ( 0 == pSocket->RxBytes );
   3845 
   3846   //
   3847   //  Empty the receive free queue
   3848   //
   3849   while ( NULL != pSocket->pRxFree ) {
   3850     pPacket = pSocket->pRxFree;
   3851     pSocket->pRxFree = pPacket->pNext;
   3852     EslSocketPacketFree ( pPacket, DEBUG_RX );
   3853   }
   3854 
   3855   //
   3856   //  Release the network specific resources
   3857   //
   3858   if ( NULL != pSocket->pApi->pfnPortClose ) {
   3859     Status = pSocket->pApi->pfnPortClose ( pPort );
   3860   }
   3861 
   3862   //
   3863   //  Done with the normal transmit events
   3864   //
   3865   Status = EslSocketIoFree ( pPort,
   3866                              &pPort->pTxFree,
   3867                              DebugFlags | DEBUG_POOL,
   3868                              "normal transmit" );
   3869 
   3870   //
   3871   //  Done with the urgent transmit events
   3872   //
   3873   Status = EslSocketIoFree ( pPort,
   3874                              &pPort->pTxOobFree,
   3875                              DebugFlags | DEBUG_POOL,
   3876                              "urgent transmit" );
   3877 
   3878   //
   3879   //  Done with the receive events
   3880   //
   3881   Status = EslSocketIoFree ( pPort,
   3882                              &pPort->pRxFree,
   3883                              DebugFlags | DEBUG_POOL,
   3884                              "receive" );
   3885 
   3886   //
   3887   //  Done with the lower layer network protocol
   3888   //
   3889   pSocketBinding = pPort->pSocketBinding;
   3890   if ( NULL != pPort->pProtocol.v ) {
   3891     Status = gBS->CloseProtocol ( pPort->Handle,
   3892                                   pSocketBinding->pNetworkProtocolGuid,
   3893                                   pLayer->ImageHandle,
   3894                                   NULL );
   3895     if ( !EFI_ERROR ( Status )) {
   3896       DEBUG (( DebugFlags,
   3897                 "0x%08x: Network protocol GUID closed on controller 0x%08x\r\n",
   3898                 pPort->pProtocol.v,
   3899                 pPort->Handle ));
   3900     }
   3901     else {
   3902       DEBUG (( DEBUG_ERROR | DebugFlags,
   3903                 "ERROR - Failed to close network protocol GUID on controller 0x%08x, Status: %r\r\n",
   3904                 pPort->Handle,
   3905                 Status ));
   3906       ASSERT ( EFI_SUCCESS == Status );
   3907     }
   3908   }
   3909 
   3910   //
   3911   //  Done with the network port
   3912   //
   3913   pServiceBinding = pPort->pServiceBinding;
   3914   if ( NULL != pPort->Handle ) {
   3915     Status = pServiceBinding->DestroyChild ( pServiceBinding,
   3916                                              pPort->Handle );
   3917     if ( !EFI_ERROR ( Status )) {
   3918       DEBUG (( DebugFlags | DEBUG_POOL,
   3919                 "0x%08x: %s port handle destroyed\r\n",
   3920                 pPort->Handle,
   3921                 pSocketBinding->pName ));
   3922     }
   3923     else {
   3924       DEBUG (( DEBUG_ERROR | DebugFlags | DEBUG_POOL,
   3925                 "ERROR - Failed to destroy the %s port handle, Status: %r\r\n",
   3926                 pSocketBinding->pName,
   3927                 Status ));
   3928       ASSERT ( EFI_SUCCESS == Status );
   3929     }
   3930   }
   3931 
   3932   //
   3933   //  Release the port structure
   3934   //
   3935   Status = gBS->FreePool ( pPort );
   3936   if ( !EFI_ERROR ( Status )) {
   3937     DEBUG (( DebugFlags | DEBUG_POOL,
   3938               "0x%08x: Free pPort, %d bytes\r\n",
   3939               pPort,
   3940               sizeof ( *pPort )));
   3941   }
   3942   else {
   3943     DEBUG (( DEBUG_ERROR | DebugFlags | DEBUG_POOL,
   3944               "ERROR - Failed to free pPort: 0x%08x, Status: %r\r\n",
   3945               pPort,
   3946               Status ));
   3947     ASSERT ( EFI_SUCCESS == Status );
   3948   }
   3949 
   3950   //
   3951   //  Mark the socket as closed if necessary
   3952   //
   3953   if ( NULL == pSocket->pPortList ) {
   3954     pSocket->State = SOCKET_STATE_CLOSED;
   3955     DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
   3956               "0x%08x: Socket State: SOCKET_STATE_CLOSED\r\n",
   3957               pSocket ));
   3958   }
   3959 
   3960   //
   3961   //  Return the operation status
   3962   //
   3963   DBG_EXIT_STATUS ( Status );
   3964   return Status;
   3965 }
   3966 
   3967 
   3968 /** Port close state 3.
   3969 
   3970   This routine attempts to complete the port close operation.
   3971 
   3972   This routine is called by the TCP layer upon completion of
   3973   the close operation and by ::EslSocketPortCloseTxDone.
   3974   See the \ref PortCloseStateMachine section.
   3975 
   3976   @param[in]  Event     The close completion event
   3977   @param[in]  pPort     Address of an ::ESL_PORT structure.
   3978 **/
   3979 VOID
   3980 EslSocketPortCloseComplete (
   3981   IN EFI_EVENT Event,
   3982   IN ESL_PORT * pPort
   3983   )
   3984 {
   3985   ESL_IO_MGMT * pIo;
   3986   EFI_STATUS Status;
   3987 
   3988   DBG_ENTER ( );
   3989   VERIFY_AT_TPL ( TPL_SOCKETS );
   3990 
   3991   //  Update the port state
   3992   pPort->State = PORT_STATE_CLOSE_DONE;
   3993   DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
   3994             "0x%08x: Port Close State: PORT_STATE_CLOSE_DONE\r\n",
   3995             pPort ));
   3996 
   3997   //  Shutdown the receive operation on the port
   3998   if ( NULL != pPort->pfnRxCancel ) {
   3999     pIo = pPort->pRxActive;
   4000     while ( NULL != pIo ) {
   4001       EslSocketRxCancel ( pPort, pIo );
   4002       pIo = pIo->pNext;
   4003     }
   4004   }
   4005 
   4006   //  Determine if the receive operation is pending
   4007   Status = EslSocketPortCloseRxDone ( pPort );
   4008   DBG_EXIT_STATUS ( Status );
   4009   --Status;
   4010 }
   4011 
   4012 
   4013 /** Port close state 4.
   4014 
   4015   This routine determines the state of the receive operations and
   4016   continues the close operation after the pending receive operations
   4017   are cancelled.
   4018 
   4019   This routine is called by
   4020   <ul>
   4021     <li>::EslSocketPortCloseComplete</li>
   4022     <li>::EslSocketPortCloseTxDone</li>
   4023     <li>::EslSocketRxComplete</li>
   4024   </ul>
   4025   to determine the state of the receive operations.
   4026   See the \ref PortCloseStateMachine section.
   4027 
   4028   @param[in]  pPort       Address of an ::ESL_PORT structure.
   4029 
   4030   @retval EFI_SUCCESS         The port is closed
   4031   @retval EFI_NOT_READY       The port is still closing
   4032   @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
   4033                               most likely the routine was called already.
   4034 **/
   4035 EFI_STATUS
   4036 EslSocketPortCloseRxDone (
   4037   IN ESL_PORT * pPort
   4038   )
   4039 {
   4040   EFI_STATUS Status;
   4041 
   4042   DBG_ENTER ( );
   4043 
   4044   //
   4045   //  Verify the socket layer synchronization
   4046   //
   4047   VERIFY_TPL ( TPL_SOCKETS );
   4048 
   4049   //
   4050   //  Verify that the port is closing
   4051   //
   4052   Status = EFI_ALREADY_STARTED;
   4053   if ( PORT_STATE_CLOSE_DONE == pPort->State ) {
   4054     //
   4055     //  Determine if the receive operation is pending
   4056     //
   4057     Status = EFI_NOT_READY;
   4058     if ( NULL == pPort->pRxActive ) {
   4059       //
   4060       //  The receive operation is complete
   4061       //  Update the port state
   4062       //
   4063       pPort->State = PORT_STATE_CLOSE_RX_DONE;
   4064       DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
   4065                 "0x%08x: Port Close State: PORT_STATE_CLOSE_RX_DONE\r\n",
   4066                 pPort ));
   4067 
   4068       //
   4069       //  Complete the port close operation
   4070       //
   4071       Status = EslSocketPortClose ( pPort );
   4072     }
   4073     else {
   4074       DEBUG_CODE_BEGIN ();
   4075       {
   4076         ESL_IO_MGMT * pIo;
   4077         //
   4078         //  Display the outstanding receive operations
   4079         //
   4080         DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
   4081                   "0x%08x: Port Close: Receive still pending!\r\n",
   4082                   pPort ));
   4083         pIo = pPort->pRxActive;
   4084         while ( NULL != pIo ) {
   4085           DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
   4086                     "0x%08x: Packet pending on network adapter\r\n",
   4087                     pIo->pPacket ));
   4088           pIo = pIo->pNext;
   4089         }
   4090       }
   4091       DEBUG_CODE_END ( );
   4092     }
   4093   }
   4094 
   4095   //
   4096   //  Return the operation status
   4097   //
   4098   DBG_EXIT_STATUS ( Status );
   4099   return Status;
   4100 }
   4101 
   4102 
   4103 /** Start the close operation on a port, state 1.
   4104 
   4105   This routine marks the port as closed and initiates the \ref
   4106   PortCloseStateMachine. The first step is to allow the \ref
   4107   TransmitEngine to run down.
   4108 
   4109   This routine is called by ::EslSocketCloseStart to initiate the socket
   4110   network specific close operation on the socket.
   4111 
   4112   @param[in]  pPort       Address of an ::ESL_PORT structure.
   4113   @param[in]  bCloseNow   Set TRUE to abort active transfers
   4114   @param[in]  DebugFlags  Flags for debug messages
   4115 
   4116   @retval EFI_SUCCESS         The port is closed, not normally returned
   4117   @retval EFI_NOT_READY       The port has started the closing process
   4118   @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
   4119                               most likely the routine was called already.
   4120 **/
   4121 EFI_STATUS
   4122 EslSocketPortCloseStart (
   4123   IN ESL_PORT * pPort,
   4124   IN BOOLEAN bCloseNow,
   4125   IN UINTN DebugFlags
   4126   )
   4127 {
   4128   ESL_SOCKET * pSocket;
   4129   EFI_STATUS Status;
   4130 
   4131   DBG_ENTER ( );
   4132 
   4133   //
   4134   //  Verify the socket layer synchronization
   4135   //
   4136   VERIFY_TPL ( TPL_SOCKETS );
   4137 
   4138   //
   4139   //  Mark the port as closing
   4140   //
   4141   Status = EFI_ALREADY_STARTED;
   4142   pSocket = pPort->pSocket;
   4143   pSocket->errno = EALREADY;
   4144   if ( PORT_STATE_CLOSE_STARTED > pPort->State ) {
   4145 
   4146     //
   4147     //  Update the port state
   4148     //
   4149     pPort->State = PORT_STATE_CLOSE_STARTED;
   4150     DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
   4151               "0x%08x: Port Close State: PORT_STATE_CLOSE_STARTED\r\n",
   4152               pPort ));
   4153     pPort->bCloseNow = bCloseNow;
   4154     pPort->DebugFlags = DebugFlags;
   4155 
   4156     //
   4157     //  Determine if transmits are complete
   4158     //
   4159     Status = EslSocketPortCloseTxDone ( pPort );
   4160   }
   4161 
   4162   //
   4163   //  Return the operation status
   4164   //
   4165   DBG_EXIT_STATUS ( Status );
   4166   return Status;
   4167 }
   4168 
   4169 
   4170 /** Port close state 2.
   4171 
   4172   This routine determines the state of the transmit engine and
   4173   continue the close operation after the transmission is complete.
   4174   The next step is to stop the \ref ReceiveEngine.
   4175   See the \ref PortCloseStateMachine section.
   4176 
   4177   This routine is called by ::EslSocketPortCloseStart to determine
   4178   if the transmission is complete.
   4179 
   4180   @param[in]  pPort           Address of an ::ESL_PORT structure.
   4181 
   4182   @retval EFI_SUCCESS         The port is closed, not normally returned
   4183   @retval EFI_NOT_READY       The port is still closing
   4184   @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
   4185                               most likely the routine was called already.
   4186 
   4187 **/
   4188 EFI_STATUS
   4189 EslSocketPortCloseTxDone (
   4190   IN ESL_PORT * pPort
   4191   )
   4192 {
   4193   ESL_IO_MGMT * pIo;
   4194   ESL_SOCKET * pSocket;
   4195   EFI_STATUS Status;
   4196 
   4197   DBG_ENTER ( );
   4198 
   4199   //
   4200   //  Verify the socket layer synchronization
   4201   //
   4202   VERIFY_TPL ( TPL_SOCKETS );
   4203 
   4204   //
   4205   //  All transmissions are complete or must be stopped
   4206   //  Mark the port as TX complete
   4207   //
   4208   Status = EFI_ALREADY_STARTED;
   4209   if ( PORT_STATE_CLOSE_STARTED == pPort->State ) {
   4210     //
   4211     //  Verify that the transmissions are complete
   4212     //
   4213     pSocket = pPort->pSocket;
   4214     if ( pPort->bCloseNow
   4215          || ( EFI_SUCCESS != pSocket->TxError )
   4216          || (( NULL == pPort->pTxActive )
   4217                 && ( NULL == pPort->pTxOobActive ))) {
   4218       //
   4219       //  Update the port state
   4220       //
   4221       pPort->State = PORT_STATE_CLOSE_TX_DONE;
   4222       DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
   4223                 "0x%08x: Port Close State: PORT_STATE_CLOSE_TX_DONE\r\n",
   4224                 pPort ));
   4225 
   4226       //
   4227       //  Close the port
   4228       //  Skip the close operation if the port is not configured
   4229       //
   4230       Status = EFI_SUCCESS;
   4231       pSocket = pPort->pSocket;
   4232       if (( pPort->bConfigured )
   4233         && ( NULL != pSocket->pApi->pfnPortCloseOp )) {
   4234           //
   4235           //  Start the close operation
   4236           //
   4237           Status = pSocket->pApi->pfnPortCloseOp ( pPort );
   4238           DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
   4239                     "0x%08x: Port Close: Close operation still pending!\r\n",
   4240                     pPort ));
   4241           ASSERT ( EFI_SUCCESS == Status );
   4242       }
   4243       else {
   4244         //
   4245         //  The receive operation is complete
   4246         //  Update the port state
   4247         //
   4248         EslSocketPortCloseComplete ( NULL, pPort );
   4249       }
   4250     }
   4251     else {
   4252       //
   4253       //  Transmissions are still active, exit
   4254       //
   4255       Status = EFI_NOT_READY;
   4256       pSocket->errno = EAGAIN;
   4257       DEBUG_CODE_BEGIN ( );
   4258       {
   4259         ESL_PACKET * pPacket;
   4260 
   4261         DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
   4262                   "0x%08x: Port Close: Transmits are still pending!\r\n",
   4263                   pPort ));
   4264 
   4265         //
   4266         //  Display the pending urgent transmit packets
   4267         //
   4268         pPacket = pSocket->pTxOobPacketListHead;
   4269         while ( NULL != pPacket ) {
   4270           DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
   4271                     "0x%08x: Packet pending on urgent TX list, %d bytes\r\n",
   4272                     pPacket,
   4273                     pPacket->PacketSize ));
   4274           pPacket = pPacket->pNext;
   4275         }
   4276 
   4277         pIo = pPort->pTxOobActive;
   4278         while ( NULL != pIo ) {
   4279           pPacket = pIo->pPacket;
   4280           DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
   4281                     "0x%08x: Packet active %d bytes, pIo: 0x%08x\r\n",
   4282                     pPacket,
   4283                     pPacket->PacketSize,
   4284                     pIo ));
   4285           pIo = pIo->pNext;
   4286         }
   4287 
   4288         //
   4289         //  Display the pending normal transmit packets
   4290         //
   4291         pPacket = pSocket->pTxPacketListHead;
   4292         while ( NULL != pPacket ) {
   4293           DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
   4294                     "0x%08x: Packet pending on normal TX list, %d bytes\r\n",
   4295                     pPacket,
   4296                     pPacket->PacketSize ));
   4297           pPacket = pPacket->pNext;
   4298         }
   4299 
   4300         pIo = pPort->pTxActive;
   4301         while ( NULL != pIo ) {
   4302           pPacket = pIo->pPacket;
   4303           DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
   4304                     "0x%08x: Packet active %d bytes, pIo: 0x%08x\r\n",
   4305                     pPacket,
   4306                     pPacket->PacketSize,
   4307                     pIo ));
   4308           pIo = pIo->pNext;
   4309         }
   4310       }
   4311       DEBUG_CODE_END ();
   4312     }
   4313   }
   4314 
   4315   //
   4316   //  Return the operation status
   4317   //
   4318   DBG_EXIT_STATUS ( Status );
   4319   return Status;
   4320 }
   4321 
   4322 
   4323 /** Receive data from a network connection.
   4324 
   4325   This routine calls the network specific routine to remove the
   4326   next portion of data from the receive queue and return it to the
   4327   caller.
   4328 
   4329   The ::recvfrom routine calls this routine to determine if any data
   4330   is received from the remote system.  Note that the other routines
   4331   ::recv and ::read are layered on top of ::recvfrom.
   4332 
   4333   @param[in]      pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
   4334   @param[in]      Flags           Message control flags
   4335   @param[in]      BufferLength    Length of the the buffer
   4336   @param[in]      pBuffer         Address of a buffer to receive the data.
   4337   @param[in]      pDataLength     Number of received data bytes in the buffer.
   4338   @param[out]     pAddress        Network address to receive the remote system address
   4339   @param[in,out]  pAddressLength  Length of the remote network address structure
   4340   @param[out]     pErrno          Address to receive the errno value upon completion.
   4341 
   4342   @retval EFI_SUCCESS - Socket data successfully received
   4343 **/
   4344 EFI_STATUS
   4345 EslSocketReceive (
   4346   IN EFI_SOCKET_PROTOCOL * pSocketProtocol,
   4347   IN INT32 Flags,
   4348   IN size_t BufferLength,
   4349   IN UINT8 * pBuffer,
   4350   OUT size_t * pDataLength,
   4351   OUT struct sockaddr * pAddress,
   4352   IN OUT socklen_t * pAddressLength,
   4353   IN int * pErrno
   4354   )
   4355 {
   4356   union {
   4357     struct sockaddr_in v4;
   4358     struct sockaddr_in6 v6;
   4359   } Addr;
   4360   socklen_t AddressLength;
   4361   BOOLEAN bConsumePacket;
   4362   BOOLEAN bUrgentQueue;
   4363   size_t DataLength;
   4364   ESL_PACKET * pNextPacket;
   4365   ESL_PACKET * pPacket;
   4366   ESL_PORT * pPort;
   4367   ESL_PACKET ** ppQueueHead;
   4368   ESL_PACKET ** ppQueueTail;
   4369   struct sockaddr * pRemoteAddress;
   4370   size_t * pRxDataBytes;
   4371   ESL_SOCKET * pSocket;
   4372   size_t SkipBytes;
   4373   EFI_STATUS Status;
   4374   EFI_TPL TplPrevious;
   4375 
   4376   DBG_ENTER ( );
   4377 
   4378   //
   4379   //  Assume success
   4380   //
   4381   Status = EFI_SUCCESS;
   4382 
   4383   //
   4384   //  Validate the socket
   4385   //
   4386   pSocket = NULL;
   4387   if ( NULL != pSocketProtocol ) {
   4388     pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
   4389 
   4390     //
   4391     //  Validate the return address parameters
   4392     //
   4393     if (( NULL == pAddress ) || ( NULL != pAddressLength )) {
   4394       //
   4395       //  Return the transmit error if necessary
   4396       //
   4397       if ( EFI_SUCCESS != pSocket->TxError ) {
   4398         pSocket->errno = EIO;
   4399         Status = pSocket->TxError;
   4400         pSocket->TxError = EFI_SUCCESS;
   4401       }
   4402       else {
   4403         //
   4404         //  Verify the socket state
   4405         //
   4406         Status = EslSocketIsConfigured ( pSocket );
   4407         if ( !EFI_ERROR ( Status )) {
   4408           //
   4409           //  Validate the buffer length
   4410           //
   4411           if (( NULL == pDataLength )
   4412             || ( NULL == pBuffer )) {
   4413             if ( NULL == pDataLength ) {
   4414               DEBUG (( DEBUG_RX,
   4415                         "ERROR - pDataLength is NULL!\r\n" ));
   4416             }
   4417             else {
   4418               DEBUG (( DEBUG_RX,
   4419                         "ERROR - pBuffer is NULL!\r\n" ));
   4420             }
   4421             Status = EFI_INVALID_PARAMETER;
   4422             pSocket->errno = EFAULT;
   4423           }
   4424           else {
   4425             //
   4426             //  Verify the API
   4427             //
   4428             if ( NULL == pSocket->pApi->pfnReceive ) {
   4429               Status = EFI_UNSUPPORTED;
   4430               pSocket->errno = ENOTSUP;
   4431             }
   4432             else {
   4433               //
   4434               //  Zero the receive address if being returned
   4435               //
   4436               pRemoteAddress = NULL;
   4437               if ( NULL != pAddress ) {
   4438                 pRemoteAddress = (struct sockaddr *)&Addr;
   4439                 ZeroMem ( pRemoteAddress, sizeof ( Addr ));
   4440                 pRemoteAddress->sa_family = pSocket->pApi->AddressFamily;
   4441                 pRemoteAddress->sa_len = (UINT8)pSocket->pApi->AddressLength;
   4442               }
   4443 
   4444               //
   4445               //  Synchronize with the socket layer
   4446               //
   4447               RAISE_TPL ( TplPrevious, TPL_SOCKETS );
   4448 
   4449               //
   4450               //  Assume failure
   4451               //
   4452               Status = EFI_UNSUPPORTED;
   4453               pSocket->errno = ENOTCONN;
   4454 
   4455               //
   4456               //  Verify that the socket is connected
   4457               //
   4458               if ( SOCKET_STATE_CONNECTED == pSocket->State ) {
   4459                 //
   4460                 //  Poll the network to increase performance
   4461                 //
   4462                 EslSocketRxPoll ( pSocket );
   4463 
   4464                 //
   4465                 //  Locate the port
   4466                 //
   4467                 pPort = pSocket->pPortList;
   4468                 if ( NULL != pPort ) {
   4469                   //
   4470                   //  Determine the queue head
   4471                   //
   4472                   bUrgentQueue = (BOOLEAN)( 0 != ( Flags & MSG_OOB ));
   4473                   if ( bUrgentQueue ) {
   4474                     ppQueueHead = &pSocket->pRxOobPacketListHead;
   4475                     ppQueueTail = &pSocket->pRxOobPacketListTail;
   4476                     pRxDataBytes = &pSocket->RxOobBytes;
   4477                   }
   4478                   else {
   4479                     ppQueueHead = &pSocket->pRxPacketListHead;
   4480                     ppQueueTail = &pSocket->pRxPacketListTail;
   4481                     pRxDataBytes = &pSocket->RxBytes;
   4482                   }
   4483 
   4484                   //
   4485                   //  Determine if there is any data on the queue
   4486                   //
   4487                   *pDataLength = 0;
   4488                   pPacket = *ppQueueHead;
   4489                   if ( NULL != pPacket ) {
   4490                     //
   4491                     //  Copy the received data
   4492                     //
   4493                     do {
   4494                       //
   4495                       //  Attempt to receive a packet
   4496                       //
   4497                       SkipBytes = 0;
   4498                       bConsumePacket = (BOOLEAN)( 0 == ( Flags & MSG_PEEK ));
   4499                       pBuffer = pSocket->pApi->pfnReceive ( pPort,
   4500                                                             pPacket,
   4501                                                             &bConsumePacket,
   4502                                                             BufferLength,
   4503                                                             pBuffer,
   4504                                                             &DataLength,
   4505                                                             (struct sockaddr *)&Addr,
   4506                                                             &SkipBytes );
   4507                       *pDataLength += DataLength;
   4508                       BufferLength -= DataLength;
   4509 
   4510                       //
   4511                       //  Determine if the data is being read
   4512                       //
   4513                       pNextPacket = pPacket->pNext;
   4514                       if ( bConsumePacket ) {
   4515                         //
   4516                         //  All done with this packet
   4517                         //  Account for any discarded data
   4518                         //
   4519                         pSocket->pApi->pfnPacketFree ( pPacket, pRxDataBytes );
   4520                         if ( 0 != SkipBytes ) {
   4521                           DEBUG (( DEBUG_RX,
   4522                                     "0x%08x: Port, packet read, skipping over 0x%08x bytes\r\n",
   4523                                     pPort,
   4524                                     SkipBytes ));
   4525                         }
   4526 
   4527                         //
   4528                         //  Remove this packet from the queue
   4529                         //
   4530                         *ppQueueHead = pPacket->pNext;
   4531                         if ( NULL == *ppQueueHead ) {
   4532                           *ppQueueTail = NULL;
   4533                         }
   4534 
   4535                         //
   4536                         //  Move the packet to the free queue
   4537                         //
   4538                         pPacket->pNext = pSocket->pRxFree;
   4539                         pSocket->pRxFree = pPacket;
   4540                         DEBUG (( DEBUG_RX,
   4541                                   "0x%08x: Port freeing packet 0x%08x\r\n",
   4542                                   pPort,
   4543                                   pPacket ));
   4544 
   4545                         //
   4546                         //  Restart the receive operation if necessary
   4547                         //
   4548                         if (( NULL != pPort->pRxFree )
   4549                           && ( MAX_RX_DATA > pSocket->RxBytes )) {
   4550                             EslSocketRxStart ( pPort );
   4551                         }
   4552                       }
   4553 
   4554                       //
   4555                       //  Get the next packet
   4556                       //
   4557                       pPacket = pNextPacket;
   4558                     } while (( SOCK_STREAM == pSocket->Type )
   4559                           && ( NULL != pPacket )
   4560                           && ( 0 < BufferLength ));
   4561 
   4562                     //
   4563                     //  Successful operation
   4564                     //
   4565                     Status = EFI_SUCCESS;
   4566                     pSocket->errno = 0;
   4567                   }
   4568                   else {
   4569                     //
   4570                     //  The queue is empty
   4571                     //  Determine if it is time to return the receive error
   4572                     //
   4573                     if ( EFI_ERROR ( pSocket->RxError )
   4574                       && ( NULL == pSocket->pRxPacketListHead )
   4575                       && ( NULL == pSocket->pRxOobPacketListHead )) {
   4576                       Status = pSocket->RxError;
   4577                       pSocket->RxError = EFI_SUCCESS;
   4578                       switch ( Status ) {
   4579                       default:
   4580                         pSocket->errno = EIO;
   4581                         break;
   4582 
   4583                       case EFI_CONNECTION_FIN:
   4584                         //
   4585                         //  Continue to return zero bytes received when the
   4586                         //  peer has successfully closed the connection
   4587                         //
   4588                         pSocket->RxError = EFI_CONNECTION_FIN;
   4589                         *pDataLength = 0;
   4590                         pSocket->errno = 0;
   4591                         Status = EFI_SUCCESS;
   4592                         break;
   4593 
   4594                       case EFI_CONNECTION_REFUSED:
   4595                         pSocket->errno = ECONNREFUSED;
   4596                         break;
   4597 
   4598                       case EFI_CONNECTION_RESET:
   4599                         pSocket->errno = ECONNRESET;
   4600                         break;
   4601 
   4602                       case EFI_HOST_UNREACHABLE:
   4603                         pSocket->errno = EHOSTUNREACH;
   4604                         break;
   4605 
   4606                       case EFI_NETWORK_UNREACHABLE:
   4607                         pSocket->errno = ENETUNREACH;
   4608                         break;
   4609 
   4610                       case EFI_PORT_UNREACHABLE:
   4611                         pSocket->errno = EPROTONOSUPPORT;
   4612                         break;
   4613 
   4614                       case EFI_PROTOCOL_UNREACHABLE:
   4615                         pSocket->errno = ENOPROTOOPT;
   4616                         break;
   4617                       }
   4618                     }
   4619                     else {
   4620                       Status = EFI_NOT_READY;
   4621                       pSocket->errno = EAGAIN;
   4622                     }
   4623                   }
   4624                 }
   4625               }
   4626 
   4627               //
   4628               //  Release the socket layer synchronization
   4629               //
   4630               RESTORE_TPL ( TplPrevious );
   4631 
   4632               if (( !EFI_ERROR ( Status )) && ( NULL != pAddress )) {
   4633                 //
   4634                 //  Return the remote address if requested, truncate if necessary
   4635                 //
   4636                 AddressLength = pRemoteAddress->sa_len;
   4637                 if ( AddressLength > *pAddressLength ) {
   4638                   AddressLength = *pAddressLength;
   4639                 }
   4640                 DEBUG (( DEBUG_RX,
   4641                           "Returning the remote address, 0x%016x bytes --> 0x%16x\r\n", *pAddressLength, pAddress ));
   4642                 ZeroMem ( pAddress, *pAddressLength );
   4643                 CopyMem ( pAddress, &Addr, AddressLength );
   4644 
   4645                 //
   4646                 //  Update the address length
   4647                 //
   4648                 *pAddressLength = pRemoteAddress->sa_len;
   4649               }
   4650             }
   4651           }
   4652         }
   4653       }
   4654 
   4655 
   4656     }
   4657     else {
   4658       //
   4659       //  Bad return address pointer and length
   4660       //
   4661       Status = EFI_INVALID_PARAMETER;
   4662       pSocket->errno = EINVAL;
   4663     }
   4664   }
   4665 
   4666   //
   4667   //  Return the operation status
   4668   //
   4669   if ( NULL != pErrno ) {
   4670     if ( NULL != pSocket ) {
   4671       *pErrno = pSocket->errno;
   4672     }
   4673     else {
   4674       Status = EFI_INVALID_PARAMETER;
   4675       *pErrno = ENOTSOCK;
   4676     }
   4677   }
   4678   DBG_EXIT_STATUS ( Status );
   4679   return Status;
   4680 }
   4681 
   4682 
   4683 /** Cancel the receive operations.
   4684 
   4685   This routine cancels a pending receive operation.
   4686   See the \ref ReceiveEngine section.
   4687 
   4688   This routine is called by ::EslSocketShutdown when the socket
   4689   layer is being shutdown.
   4690 
   4691   @param[in]  pPort     Address of an ::ESL_PORT structure
   4692   @param[in]  pIo       Address of an ::ESL_IO_MGMT structure
   4693 **/
   4694 VOID
   4695 EslSocketRxCancel (
   4696   IN ESL_PORT * pPort,
   4697   IN ESL_IO_MGMT * pIo
   4698   )
   4699 {
   4700   EFI_STATUS Status;
   4701 
   4702   DBG_ENTER ( );
   4703 
   4704   //
   4705   //  Cancel the outstanding receive
   4706   //
   4707   Status = pPort->pfnRxCancel ( pPort->pProtocol.v,
   4708                                 &pIo->Token );
   4709   if ( !EFI_ERROR ( Status )) {
   4710     DEBUG (( pPort->DebugFlags | DEBUG_CLOSE | DEBUG_INFO,
   4711               "0x%08x: Packet receive aborted on port: 0x%08x\r\n",
   4712               pIo->pPacket,
   4713               pPort ));
   4714   }
   4715   else {
   4716     DEBUG (( pPort->DebugFlags | DEBUG_CLOSE | DEBUG_INFO,
   4717               "0x%08x: Packet receive pending on Port 0x%08x, Status: %r\r\n",
   4718               pIo->pPacket,
   4719               pPort,
   4720               Status ));
   4721   }
   4722   DBG_EXIT ( );
   4723 }
   4724 
   4725 
   4726 /** Process the receive completion.
   4727 
   4728   This routine queues the data in FIFO order in either the urgent
   4729   or normal data queues depending upon the type of data received.
   4730   See the \ref ReceiveEngine section.
   4731 
   4732   This routine is called when some data is received by:
   4733   <ul>
   4734     <li>::EslIp4RxComplete</li>
   4735     <li>::EslTcp4RxComplete</li>
   4736     <li>::EslUdp4RxComplete</li>
   4737   </ul>
   4738 
   4739   @param[in]  pIo           Address of an ::ESL_IO_MGMT structure
   4740   @param[in]  Status        Receive status
   4741   @param[in]  LengthInBytes Length of the receive data
   4742   @param[in]  bUrgent       TRUE if urgent data is received and FALSE
   4743                             for normal data.
   4744 **/
   4745 VOID
   4746 EslSocketRxComplete (
   4747   IN ESL_IO_MGMT * pIo,
   4748   IN EFI_STATUS Status,
   4749   IN UINTN LengthInBytes,
   4750   IN BOOLEAN bUrgent
   4751   )
   4752 {
   4753   BOOLEAN bUrgentQueue;
   4754   ESL_IO_MGMT * pIoNext;
   4755   ESL_PACKET * pPacket;
   4756   ESL_PORT * pPort;
   4757   ESL_PACKET * pPrevious;
   4758   ESL_PACKET ** ppQueueHead;
   4759   ESL_PACKET ** ppQueueTail;
   4760   size_t * pRxBytes;
   4761   ESL_SOCKET * pSocket;
   4762 
   4763   DBG_ENTER ( );
   4764   VERIFY_AT_TPL ( TPL_SOCKETS );
   4765 
   4766   //
   4767   //  Locate the active receive packet
   4768   //
   4769   pPacket = pIo->pPacket;
   4770   pPort = pIo->pPort;
   4771   pSocket = pPort->pSocket;
   4772 
   4773   //
   4774   //         pPort->pRxActive
   4775   //                |
   4776   //                V
   4777   //          +-------------+   +-------------+   +-------------+
   4778   //  Active  | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
   4779   //          +-------------+   +-------------+   +-------------+
   4780   //
   4781   //          +-------------+   +-------------+   +-------------+
   4782   //  Free    | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
   4783   //          +-------------+   +-------------+   +-------------+
   4784   //                ^
   4785   //                |
   4786   //          pPort->pRxFree
   4787   //
   4788   //
   4789   //  Remove the IO structure from the active list
   4790   //  The following code searches for the entry in the list and does not
   4791   //  assume that the receive operations complete in the order they were
   4792   //  issued to the UEFI network layer.
   4793   //
   4794   pIoNext = pPort->pRxActive;
   4795   while (( NULL != pIoNext ) && ( pIoNext != pIo ) && ( pIoNext->pNext != pIo ))
   4796   {
   4797     pIoNext = pIoNext->pNext;
   4798   }
   4799   ASSERT ( NULL != pIoNext );
   4800   if ( pIoNext == pIo ) {
   4801     pPort->pRxActive = pIo->pNext;  //  Beginning of list
   4802   }
   4803   else {
   4804     pIoNext->pNext = pIo->pNext;    //  Middle of list
   4805   }
   4806 
   4807   //
   4808   //  Free the IO structure
   4809   //
   4810   pIo->pNext = pPort->pRxFree;
   4811   pPort->pRxFree = pIo;
   4812 
   4813   //
   4814   //            pRxOobPacketListHead              pRxOobPacketListTail
   4815   //                      |                                 |
   4816   //                      V                                 V
   4817   //               +------------+   +------------+   +------------+
   4818   //  Urgent Data  | ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL
   4819   //               +------------+   +------------+   +------------+
   4820   //
   4821   //               +------------+   +------------+   +------------+
   4822   //  Normal Data  | ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL
   4823   //               +------------+   +------------+   +------------+
   4824   //                      ^                                 ^
   4825   //                      |                                 |
   4826   //              pRxPacketListHead                pRxPacketListTail
   4827   //
   4828   //
   4829   //  Determine the queue to use
   4830   //
   4831   bUrgentQueue = (BOOLEAN)( bUrgent
   4832                && pSocket->pApi->bOobSupported
   4833                && ( !pSocket->bOobInLine ));
   4834   if ( bUrgentQueue ) {
   4835     ppQueueHead = &pSocket->pRxOobPacketListHead;
   4836     ppQueueTail = &pSocket->pRxOobPacketListTail;
   4837     pRxBytes = &pSocket->RxOobBytes;
   4838   }
   4839   else {
   4840     ppQueueHead = &pSocket->pRxPacketListHead;
   4841     ppQueueTail = &pSocket->pRxPacketListTail;
   4842     pRxBytes = &pSocket->RxBytes;
   4843   }
   4844 
   4845   //
   4846   //  Determine if this receive was successful
   4847   //
   4848   if (( !EFI_ERROR ( Status ))
   4849     && ( PORT_STATE_CLOSE_STARTED > pPort->State )
   4850     && ( !pSocket->bRxDisable )) {
   4851     //
   4852     //  Account for the received data
   4853     //
   4854     *pRxBytes += LengthInBytes;
   4855 
   4856     //
   4857     //  Log the received data
   4858     //
   4859     DEBUG (( DEBUG_RX | DEBUG_INFO,
   4860               "0x%08x: Packet queued on %s queue of port 0x%08x with 0x%08x bytes of %s data\r\n",
   4861               pPacket,
   4862               bUrgentQueue ? L"urgent" : L"normal",
   4863               pPort,
   4864               LengthInBytes,
   4865               bUrgent ? L"urgent" : L"normal" ));
   4866 
   4867     //
   4868     //  Add the packet to the list tail.
   4869     //
   4870     pPacket->pNext = NULL;
   4871     pPrevious = *ppQueueTail;
   4872     if ( NULL == pPrevious ) {
   4873       *ppQueueHead = pPacket;
   4874     }
   4875     else {
   4876       pPrevious->pNext = pPacket;
   4877     }
   4878     *ppQueueTail = pPacket;
   4879 
   4880     //
   4881     //  Attempt to restart this receive operation
   4882     //
   4883     if ( pSocket->MaxRxBuf > pSocket->RxBytes ) {
   4884       EslSocketRxStart ( pPort );
   4885     }
   4886     else {
   4887       DEBUG (( DEBUG_RX,
   4888                 "0x%08x: Port RX suspended, 0x%08x bytes queued\r\n",
   4889                 pPort,
   4890                 pSocket->RxBytes ));
   4891     }
   4892   }
   4893   else {
   4894     if ( EFI_ERROR ( Status )) {
   4895         DEBUG (( DEBUG_RX | DEBUG_INFO,
   4896                   "ERROR - Receive error on port 0x%08x, packet 0x%08x, Status:%r\r\n",
   4897                   pPort,
   4898                   pPacket,
   4899                   Status ));
   4900     }
   4901 
   4902     //
   4903     //  Account for the receive bytes and release the driver's buffer
   4904     //
   4905     if ( !EFI_ERROR ( Status )) {
   4906       *pRxBytes += LengthInBytes;
   4907       pSocket->pApi->pfnPacketFree ( pPacket, pRxBytes );
   4908     }
   4909 
   4910     //
   4911     //  Receive error, free the packet save the error
   4912     //
   4913     EslSocketPacketFree ( pPacket, DEBUG_RX );
   4914     if ( !EFI_ERROR ( pSocket->RxError )) {
   4915       pSocket->RxError = Status;
   4916     }
   4917 
   4918     //
   4919     //  Update the port state
   4920     //
   4921     if ( PORT_STATE_CLOSE_STARTED <= pPort->State ) {
   4922       if ( PORT_STATE_CLOSE_DONE == pPort->State ) {
   4923         EslSocketPortCloseRxDone ( pPort );
   4924       }
   4925     }
   4926     else {
   4927       if ( EFI_ERROR ( Status )) {
   4928         DEBUG (( DEBUG_RX | DEBUG_INFO,
   4929                   "0x%08x: Port state: PORT_STATE_RX_ERROR, Status: %r\r\n",
   4930                   pPort,
   4931                   Status ));
   4932         pPort->State = PORT_STATE_RX_ERROR;
   4933       }
   4934     }
   4935   }
   4936 
   4937   DBG_EXIT ( );
   4938 }
   4939 
   4940 
   4941 /** Poll a socket for pending receive activity.
   4942 
   4943   This routine is called at elivated TPL and extends the idle
   4944   loop which polls a socket down into the LAN driver layer to
   4945   determine if there is any receive activity.
   4946 
   4947   The ::EslSocketPoll, ::EslSocketReceive and ::EslSocketTransmit
   4948   routines call this routine when there is nothing to do.
   4949 
   4950   @param[in]  pSocket   Address of an ::EFI_SOCKET structure.
   4951  **/
   4952 VOID
   4953 EslSocketRxPoll (
   4954   IN ESL_SOCKET * pSocket
   4955   )
   4956 {
   4957   ESL_PORT * pPort;
   4958 
   4959   DEBUG (( DEBUG_POLL, "Entering EslSocketRxPoll\r\n" ));
   4960 
   4961   //
   4962   //  Increase the network performance by extending the
   4963   //  polling (idle) loop down into the LAN driver
   4964   //
   4965   pPort = pSocket->pPortList;
   4966   while ( NULL != pPort ) {
   4967     //
   4968     //  Poll the LAN adapter
   4969     //
   4970     pPort->pfnRxPoll ( pPort->pProtocol.v );
   4971 
   4972     //
   4973     //  Locate the next LAN adapter
   4974     //
   4975     pPort = pPort->pLinkSocket;
   4976   }
   4977 
   4978   DEBUG (( DEBUG_POLL, "Exiting EslSocketRxPoll\r\n" ));
   4979 }
   4980 
   4981 
   4982 /** Start a receive operation.
   4983 
   4984   This routine posts a receive buffer to the network adapter.
   4985   See the \ref ReceiveEngine section.
   4986 
   4987   This support routine is called by:
   4988   <ul>
   4989     <li>::EslIp4Receive to restart the receive engine to release flow control.</li>
   4990     <li>::EslIp4RxComplete to continue the operation of the receive engine if flow control is not being applied.</li>
   4991     <li>::EslIp4SocketIsConfigured to start the receive engine for the new socket.</li>
   4992     <li>::EslTcp4ListenComplete to start the recevie engine for the new socket.</li>
   4993     <li>::EslTcp4Receive to restart the receive engine to release flow control.</li>
   4994     <li>::EslTcp4RxComplete to continue the operation of the receive engine if flow control is not being applied.</li>
   4995     <li>::EslUdp4Receive to restart the receive engine to release flow control.</li>
   4996     <li>::EslUdp4RxComplete to continue the operation of the receive engine if flow control is not being applied.</li>
   4997     <li>::EslUdp4SocketIsConfigured to start the recevie engine for the new socket.</li>
   4998   </ul>
   4999 
   5000   @param[in]  pPort       Address of an ::ESL_PORT structure.
   5001 **/
   5002 VOID
   5003 EslSocketRxStart (
   5004   IN ESL_PORT * pPort
   5005   )
   5006 {
   5007   UINT8 * pBuffer;
   5008   ESL_IO_MGMT * pIo;
   5009   ESL_PACKET * pPacket;
   5010   ESL_SOCKET * pSocket;
   5011   EFI_STATUS Status;
   5012 
   5013   DBG_ENTER ( );
   5014 
   5015   //
   5016   //  Determine if a receive is already pending
   5017   //
   5018   Status = EFI_SUCCESS;
   5019   pPacket = NULL;
   5020   pSocket = pPort->pSocket;
   5021   if ( !EFI_ERROR ( pPort->pSocket->RxError )) {
   5022     if (( NULL != pPort->pRxFree )
   5023       && ( !pSocket->bRxDisable )
   5024       && ( PORT_STATE_CLOSE_STARTED > pPort->State )) {
   5025       //
   5026       //  Start all of the pending receive operations
   5027       //
   5028       while ( NULL != pPort->pRxFree ) {
   5029         //
   5030         //  Determine if there are any free packets
   5031         //
   5032         pPacket = pSocket->pRxFree;
   5033         if ( NULL != pPacket ) {
   5034           //
   5035           //  Remove this packet from the free list
   5036           //
   5037           pSocket->pRxFree = pPacket->pNext;
   5038           DEBUG (( DEBUG_RX,
   5039                     "0x%08x: Port removed packet 0x%08x from free list\r\n",
   5040                     pPort,
   5041                     pPacket ));
   5042         }
   5043         else {
   5044           //
   5045           //  Allocate a packet structure
   5046           //
   5047           Status = EslSocketPacketAllocate ( &pPacket,
   5048                                              pSocket->pApi->RxPacketBytes,
   5049                                              pSocket->pApi->RxZeroBytes,
   5050                                              DEBUG_RX );
   5051           if ( EFI_ERROR ( Status )) {
   5052             pPacket = NULL;
   5053             DEBUG (( DEBUG_ERROR | DEBUG_RX,
   5054                       "0x%08x: Port failed to allocate RX packet, Status: %r\r\n",
   5055                       pPort,
   5056                       Status ));
   5057             break;
   5058           }
   5059         }
   5060 
   5061         //
   5062         //  Connect the IO and packet structures
   5063         //
   5064         pIo = pPort->pRxFree;
   5065         pIo->pPacket = pPacket;
   5066 
   5067         //
   5068         //  Eliminate the need for IP4 and UDP4 specific routines by
   5069         //  clearing the RX data pointer here.
   5070         //
   5071         //  No driver buffer for this packet
   5072         //
   5073         //    +--------------------+
   5074         //    | ESL_IO_MGMT        |
   5075         //    |                    |
   5076         //    |    +---------------+
   5077         //    |    | Token         |
   5078         //    |    |        RxData --> NULL
   5079         //    +----+---------------+
   5080         //
   5081         pBuffer = (UINT8 *)pIo;
   5082         pBuffer = &pBuffer[ pSocket->pApi->RxBufferOffset ];
   5083         *(VOID **)pBuffer = NULL;
   5084 
   5085         //
   5086         //  Network specific receive packet initialization
   5087         //
   5088         if ( NULL != pSocket->pApi->pfnRxStart ) {
   5089           pSocket->pApi->pfnRxStart ( pPort, pIo );
   5090         }
   5091 
   5092         //
   5093         //  Start the receive on the packet
   5094         //
   5095         Status = pPort->pfnRxStart ( pPort->pProtocol.v, &pIo->Token );
   5096         if ( !EFI_ERROR ( Status )) {
   5097           DEBUG (( DEBUG_RX | DEBUG_INFO,
   5098                     "0x%08x: Packet receive pending on port 0x%08x\r\n",
   5099                     pPacket,
   5100                     pPort ));
   5101           //
   5102           //  Allocate the receive control structure
   5103           //
   5104           pPort->pRxFree = pIo->pNext;
   5105 
   5106           //
   5107           //  Mark this receive as pending
   5108           //
   5109           pIo->pNext = pPort->pRxActive;
   5110           pPort->pRxActive = pIo;
   5111 
   5112         }
   5113         else {
   5114           DEBUG (( DEBUG_RX | DEBUG_INFO,
   5115                     "ERROR - Failed to post a receive on port 0x%08x, Status: %r\r\n",
   5116                     pPort,
   5117                     Status ));
   5118           if ( !EFI_ERROR ( pSocket->RxError )) {
   5119             //
   5120             //  Save the error status
   5121             //
   5122             pSocket->RxError = Status;
   5123           }
   5124 
   5125           //
   5126           //  Free the packet
   5127           //
   5128           pIo->pPacket = NULL;
   5129           pPacket->pNext = pSocket->pRxFree;
   5130           pSocket->pRxFree = pPacket;
   5131           break;
   5132         }
   5133       }
   5134     }
   5135     else {
   5136       if ( NULL == pPort->pRxFree ) {
   5137         DEBUG (( DEBUG_RX | DEBUG_INFO,
   5138                   "0x%08x: Port, no available ESL_IO_MGMT structures\r\n",
   5139                   pPort));
   5140       }
   5141       if ( pSocket->bRxDisable ) {
   5142         DEBUG (( DEBUG_RX | DEBUG_INFO,
   5143                   "0x%08x: Port, receive disabled!\r\n",
   5144                   pPort ));
   5145       }
   5146       if ( PORT_STATE_CLOSE_STARTED <= pPort->State ) {
   5147         DEBUG (( DEBUG_RX | DEBUG_INFO,
   5148                   "0x%08x: Port, is closing!\r\n",
   5149                   pPort ));
   5150       }
   5151     }
   5152   }
   5153   else {
   5154     DEBUG (( DEBUG_ERROR | DEBUG_RX,
   5155               "ERROR - Previous receive error, Status: %r\r\n",
   5156                pPort->pSocket->RxError ));
   5157   }
   5158 
   5159   DBG_EXIT ( );
   5160 }
   5161 
   5162 
   5163 /** Shutdown the socket receive and transmit operations.
   5164 
   5165   This routine sets a flag to stop future transmissions and calls
   5166   the network specific layer to cancel the pending receive operation.
   5167 
   5168   The ::shutdown routine calls this routine to stop receive and transmit
   5169   operations on the socket.
   5170 
   5171   @param[in]  pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
   5172   @param[in]  How             Which operations to stop
   5173   @param[out] pErrno          Address to receive the errno value upon completion.
   5174 
   5175   @retval EFI_SUCCESS - Socket operations successfully shutdown
   5176 **/
   5177 EFI_STATUS
   5178 EslSocketShutdown (
   5179   IN EFI_SOCKET_PROTOCOL * pSocketProtocol,
   5180   IN int How,
   5181   IN int * pErrno
   5182   )
   5183 {
   5184   ESL_IO_MGMT * pIo;
   5185   ESL_PORT * pPort;
   5186   ESL_SOCKET * pSocket;
   5187   EFI_STATUS Status;
   5188   EFI_TPL TplPrevious;
   5189 
   5190   DBG_ENTER ( );
   5191 
   5192   //
   5193   //  Assume success
   5194   //
   5195   Status = EFI_SUCCESS;
   5196 
   5197   //
   5198   //  Validate the socket
   5199   //
   5200   pSocket = NULL;
   5201   if ( NULL != pSocketProtocol ) {
   5202     pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
   5203 
   5204     //
   5205     //  Verify that the socket is connected
   5206     //
   5207     if ( pSocket->bConnected ) {
   5208       //
   5209       //  Validate the How value
   5210       //
   5211       if (( SHUT_RD <= How ) && ( SHUT_RDWR >= How )) {
   5212         //
   5213         //  Synchronize with the socket layer
   5214         //
   5215         RAISE_TPL ( TplPrevious, TPL_SOCKETS );
   5216 
   5217         //
   5218         //  Disable the receiver if requested
   5219         //
   5220         if (( SHUT_RD == How ) || ( SHUT_RDWR == How )) {
   5221           pSocket->bRxDisable = TRUE;
   5222         }
   5223 
   5224         //
   5225         //  Disable the transmitter if requested
   5226         //
   5227         if (( SHUT_WR == How ) || ( SHUT_RDWR == How )) {
   5228           pSocket->bTxDisable = TRUE;
   5229         }
   5230 
   5231         //
   5232         //  Cancel the pending receive operations
   5233         //
   5234         if ( pSocket->bRxDisable ) {
   5235           //
   5236           //  Walk the list of ports
   5237           //
   5238           pPort = pSocket->pPortList;
   5239           while ( NULL != pPort ) {
   5240             //
   5241             //  Walk the list of active receive operations
   5242             //
   5243             pIo = pPort->pRxActive;
   5244             while ( NULL != pIo ) {
   5245               EslSocketRxCancel ( pPort, pIo );
   5246             }
   5247 
   5248             //
   5249             //  Set the next port
   5250             //
   5251             pPort = pPort->pLinkSocket;
   5252           }
   5253         }
   5254 
   5255         //
   5256         //  Release the socket layer synchronization
   5257         //
   5258         RESTORE_TPL ( TplPrevious );
   5259       }
   5260       else {
   5261         //
   5262         //  Invalid How value
   5263         //
   5264         pSocket->errno = EINVAL;
   5265         Status = EFI_INVALID_PARAMETER;
   5266       }
   5267     }
   5268     else {
   5269       //
   5270       //  The socket is not connected
   5271       //
   5272       pSocket->errno = ENOTCONN;
   5273       Status = EFI_NOT_STARTED;
   5274     }
   5275   }
   5276 
   5277   //
   5278   //  Return the operation status
   5279   //
   5280   if ( NULL != pErrno ) {
   5281     if ( NULL != pSocket ) {
   5282       *pErrno = pSocket->errno;
   5283     }
   5284     else {
   5285       Status = EFI_INVALID_PARAMETER;
   5286       *pErrno = ENOTSOCK;
   5287     }
   5288   }
   5289   DBG_EXIT_STATUS ( Status );
   5290   return Status;
   5291 }
   5292 
   5293 
   5294 /** Send data using a network connection.
   5295 
   5296   This routine calls the network specific layer to queue the data
   5297   for transmission.  Eventually the buffer will reach the head of
   5298   the queue and will get transmitted over the network by the
   5299   \ref TransmitEngine.  For datagram
   5300   sockets (SOCK_DGRAM and SOCK_RAW) there is no guarantee that
   5301   the data reaches the application running on the remote system.
   5302 
   5303   The ::sendto routine calls this routine to send data to the remote
   5304   system.  Note that ::send and ::write are layered on top of ::sendto.
   5305 
   5306   @param[in]  pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
   5307   @param[in]  Flags           Message control flags
   5308   @param[in]  BufferLength    Length of the the buffer
   5309   @param[in]  pBuffer         Address of a buffer containing the data to send
   5310   @param[in]  pDataLength     Address to receive the number of data bytes sent
   5311   @param[in]  pAddress        Network address of the remote system address
   5312   @param[in]  AddressLength   Length of the remote network address structure
   5313   @param[out] pErrno          Address to receive the errno value upon completion.
   5314 
   5315   @retval EFI_SUCCESS - Socket data successfully queued for transmit
   5316 **/
   5317 EFI_STATUS
   5318 EslSocketTransmit (
   5319   IN EFI_SOCKET_PROTOCOL * pSocketProtocol,
   5320   IN int Flags,
   5321   IN size_t BufferLength,
   5322   IN CONST UINT8 * pBuffer,
   5323   OUT size_t * pDataLength,
   5324   IN const struct sockaddr * pAddress,
   5325   IN socklen_t AddressLength,
   5326   IN int * pErrno
   5327   )
   5328 {
   5329   ESL_SOCKET * pSocket;
   5330   EFI_STATUS Status;
   5331   EFI_TPL TplPrevious;
   5332 
   5333   DBG_ENTER ( );
   5334 
   5335   //
   5336   //  Assume success
   5337   //
   5338   Status = EFI_SUCCESS;
   5339 
   5340   //
   5341   //  Validate the socket
   5342   //
   5343   pSocket = NULL;
   5344   if ( NULL != pSocketProtocol ) {
   5345     pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
   5346 
   5347     //
   5348     //  Return the transmit error if necessary
   5349     //
   5350     if ( EFI_SUCCESS != pSocket->TxError ) {
   5351       pSocket->errno = EIO;
   5352       Status = pSocket->TxError;
   5353       pSocket->TxError = EFI_SUCCESS;
   5354     }
   5355     else {
   5356       //
   5357       //  Verify the socket state
   5358       //
   5359       Status = EslSocketIsConfigured ( pSocket );
   5360       if ( !EFI_ERROR ( Status )) {
   5361         //
   5362         //  Verify that transmit is still allowed
   5363         //
   5364         if ( !pSocket->bTxDisable ) {
   5365           //
   5366           //  Validate the buffer length
   5367           //
   5368           if (( NULL == pDataLength )
   5369             && ( 0 > pDataLength )
   5370             && ( NULL == pBuffer )) {
   5371             if ( NULL == pDataLength ) {
   5372               DEBUG (( DEBUG_RX,
   5373                         "ERROR - pDataLength is NULL!\r\n" ));
   5374             }
   5375             else if ( NULL == pBuffer ) {
   5376               DEBUG (( DEBUG_RX,
   5377                         "ERROR - pBuffer is NULL!\r\n" ));
   5378             }
   5379             else {
   5380               DEBUG (( DEBUG_RX,
   5381                         "ERROR - Data length < 0!\r\n" ));
   5382             }
   5383             Status = EFI_INVALID_PARAMETER;
   5384             pSocket->errno = EFAULT;
   5385           }
   5386           else {
   5387             //
   5388             //  Validate the remote network address
   5389             //
   5390             if (( NULL != pAddress )
   5391               && ( AddressLength < pAddress->sa_len )) {
   5392               DEBUG (( DEBUG_TX,
   5393                         "ERROR - Invalid sin_len field in address\r\n" ));
   5394               Status = EFI_INVALID_PARAMETER;
   5395               pSocket->errno = EFAULT;
   5396             }
   5397             else {
   5398               //
   5399               //  Verify the API
   5400               //
   5401               if ( NULL == pSocket->pApi->pfnTransmit ) {
   5402                 Status = EFI_UNSUPPORTED;
   5403                 pSocket->errno = ENOTSUP;
   5404               }
   5405               else {
   5406                 //
   5407                 //  Synchronize with the socket layer
   5408                 //
   5409                 RAISE_TPL ( TplPrevious, TPL_SOCKETS );
   5410 
   5411                 //
   5412                 //  Poll the network to increase performance
   5413                 //
   5414                 EslSocketRxPoll ( pSocket );
   5415 
   5416                 //
   5417                 //  Attempt to buffer the packet for transmission
   5418                 //
   5419                 Status = pSocket->pApi->pfnTransmit ( pSocket,
   5420                                                       Flags,
   5421                                                       BufferLength,
   5422                                                       pBuffer,
   5423                                                       pDataLength,
   5424                                                       pAddress,
   5425                                                       AddressLength );
   5426 
   5427                 //
   5428                 //  Release the socket layer synchronization
   5429                 //
   5430                 RESTORE_TPL ( TplPrevious );
   5431               }
   5432             }
   5433           }
   5434         }
   5435         else {
   5436           //
   5437           //  The transmitter was shutdown
   5438           //
   5439           pSocket->errno = EPIPE;
   5440           Status = EFI_NOT_STARTED;
   5441         }
   5442       }
   5443     }
   5444   }
   5445 
   5446   //
   5447   //  Return the operation status
   5448   //
   5449   if ( NULL != pErrno ) {
   5450     if ( NULL != pSocket ) {
   5451       *pErrno = pSocket->errno;
   5452     }
   5453     else {
   5454       Status = EFI_INVALID_PARAMETER;
   5455       *pErrno = ENOTSOCK;
   5456     }
   5457   }
   5458   DBG_EXIT_STATUS ( Status );
   5459   return Status;
   5460 }
   5461 
   5462 
   5463 /** Complete the transmit operation.
   5464 
   5465   This support routine handles the transmit completion processing for
   5466   the various network layers.  It frees the ::ESL_IO_MGMT structure
   5467   and and frees packet resources by calling ::EslSocketPacketFree.
   5468   Transmit errors are logged in ESL_SOCKET::TxError.
   5469   See the \ref TransmitEngine section.
   5470 
   5471   This routine is called by:
   5472   <ul>
   5473     <li>::EslIp4TxComplete</li>
   5474     <li>::EslTcp4TxComplete</li>
   5475     <li>::EslTcp4TxOobComplete</li>
   5476     <li>::EslUdp4TxComplete</li>
   5477   </ul>
   5478 
   5479   @param[in]  pIo             Address of an ::ESL_IO_MGMT structure
   5480   @param[in]  LengthInBytes   Length of the data in bytes
   5481   @param[in]  Status          Transmit operation status
   5482   @param[in]  pQueueType      Zero terminated string describing queue type
   5483   @param[in]  ppQueueHead     Transmit queue head address
   5484   @param[in]  ppQueueTail     Transmit queue tail address
   5485   @param[in]  ppActive        Active transmit queue address
   5486   @param[in]  ppFree          Free transmit queue address
   5487 **/
   5488 VOID
   5489 EslSocketTxComplete (
   5490   IN ESL_IO_MGMT * pIo,
   5491   IN UINT32 LengthInBytes,
   5492   IN EFI_STATUS Status,
   5493   IN CONST CHAR8 * pQueueType,
   5494   IN ESL_PACKET ** ppQueueHead,
   5495   IN ESL_PACKET ** ppQueueTail,
   5496   IN ESL_IO_MGMT ** ppActive,
   5497   IN ESL_IO_MGMT ** ppFree
   5498   )
   5499 {
   5500   ESL_PACKET * pCurrentPacket;
   5501   ESL_IO_MGMT * pIoNext;
   5502   ESL_PACKET * pNextPacket;
   5503   ESL_PACKET * pPacket;
   5504   ESL_PORT * pPort;
   5505   ESL_SOCKET * pSocket;
   5506 
   5507   DBG_ENTER ( );
   5508   VERIFY_AT_TPL ( TPL_SOCKETS );
   5509 
   5510   //
   5511   //  Locate the active transmit packet
   5512   //
   5513   pPacket = pIo->pPacket;
   5514   pPort = pIo->pPort;
   5515   pSocket = pPort->pSocket;
   5516 
   5517   //
   5518   //  No more packet
   5519   //
   5520   pIo->pPacket = NULL;
   5521 
   5522   //
   5523   //  Remove the IO structure from the active list
   5524   //
   5525   pIoNext = *ppActive;
   5526   while (( NULL != pIoNext ) && ( pIoNext != pIo ) && ( pIoNext->pNext != pIo ))
   5527   {
   5528     pIoNext = pIoNext->pNext;
   5529   }
   5530   ASSERT ( NULL != pIoNext );
   5531   if ( pIoNext == pIo ) {
   5532     *ppActive = pIo->pNext;       //  Beginning of list
   5533   }
   5534   else {
   5535     pIoNext->pNext = pIo->pNext;  //  Middle of list
   5536   }
   5537 
   5538   //
   5539   //  Free the IO structure
   5540   //
   5541   pIo->pNext = *ppFree;
   5542   *ppFree = pIo;
   5543 
   5544   //
   5545   //  Display the results
   5546   //
   5547   DEBUG (( DEBUG_TX | DEBUG_INFO,
   5548             "0x%08x: pIo Released\r\n",
   5549             pIo ));
   5550 
   5551   //
   5552   //  Save any transmit error
   5553   //
   5554   if ( EFI_ERROR ( Status )) {
   5555     if ( !EFI_ERROR ( pSocket->TxError )) {
   5556       pSocket->TxError = Status;
   5557     }
   5558     DEBUG (( DEBUG_TX | DEBUG_INFO,
   5559               "ERROR - Transmit failure for %apacket 0x%08x, Status: %r\r\n",
   5560               pQueueType,
   5561               pPacket,
   5562               Status ));
   5563 
   5564     //
   5565     //  Empty the normal transmit list
   5566     //
   5567     pCurrentPacket = pPacket;
   5568     pNextPacket = *ppQueueHead;
   5569     while ( NULL != pNextPacket ) {
   5570       pPacket = pNextPacket;
   5571       pNextPacket = pPacket->pNext;
   5572       EslSocketPacketFree ( pPacket, DEBUG_TX );
   5573     }
   5574     *ppQueueHead = NULL;
   5575     *ppQueueTail = NULL;
   5576     pPacket = pCurrentPacket;
   5577   }
   5578   else {
   5579     DEBUG (( DEBUG_TX | DEBUG_INFO,
   5580               "0x%08x: %apacket transmitted %d bytes successfully\r\n",
   5581               pPacket,
   5582               pQueueType,
   5583               LengthInBytes ));
   5584 
   5585     //
   5586     //  Verify the transmit engine is still running
   5587     //
   5588     if ( !pPort->bCloseNow ) {
   5589       //
   5590       //  Start the next packet transmission
   5591       //
   5592       EslSocketTxStart ( pPort,
   5593                          ppQueueHead,
   5594                          ppQueueTail,
   5595                          ppActive,
   5596                          ppFree );
   5597     }
   5598   }
   5599 
   5600   //
   5601   //  Release this packet
   5602   //
   5603   EslSocketPacketFree ( pPacket, DEBUG_TX );
   5604 
   5605   //
   5606   //  Finish the close operation if necessary
   5607   //
   5608   if ( PORT_STATE_CLOSE_STARTED <= pPort->State ) {
   5609     //
   5610     //  Indicate that the transmit is complete
   5611     //
   5612     EslSocketPortCloseTxDone ( pPort );
   5613   }
   5614 
   5615   DBG_EXIT ( );
   5616 }
   5617 
   5618 
   5619 /** Transmit data using a network connection.
   5620 
   5621   This support routine starts a transmit operation on the
   5622   underlying network layer.
   5623 
   5624   The network specific code calls this routine to start a
   5625   transmit operation.  See the \ref TransmitEngine section.
   5626 
   5627   @param[in]  pPort           Address of an ::ESL_PORT structure
   5628   @param[in]  ppQueueHead     Transmit queue head address
   5629   @param[in]  ppQueueTail     Transmit queue tail address
   5630   @param[in]  ppActive        Active transmit queue address
   5631   @param[in]  ppFree          Free transmit queue address
   5632 **/
   5633 VOID
   5634 EslSocketTxStart (
   5635   IN ESL_PORT * pPort,
   5636   IN ESL_PACKET ** ppQueueHead,
   5637   IN ESL_PACKET ** ppQueueTail,
   5638   IN ESL_IO_MGMT ** ppActive,
   5639   IN ESL_IO_MGMT ** ppFree
   5640   )
   5641 {
   5642   UINT8 * pBuffer;
   5643   ESL_IO_MGMT * pIo;
   5644   ESL_PACKET * pNextPacket;
   5645   ESL_PACKET * pPacket;
   5646   VOID ** ppTokenData;
   5647   ESL_SOCKET * pSocket;
   5648   EFI_STATUS Status;
   5649 
   5650   DBG_ENTER ( );
   5651 
   5652   //
   5653   //  Assume success
   5654   //
   5655   Status = EFI_SUCCESS;
   5656 
   5657   //
   5658   //  Get the packet from the queue head
   5659   //
   5660   pPacket = *ppQueueHead;
   5661   pIo = *ppFree;
   5662   if (( NULL != pPacket ) && ( NULL != pIo )) {
   5663     pSocket = pPort->pSocket;
   5664     //
   5665     //     *ppQueueHead: pSocket->pRxPacketListHead or pSocket->pRxOobPacketListHead
   5666     //          |
   5667     //          V
   5668     //        +------------+   +------------+   +------------+
   5669     //  Data  | ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL
   5670     //        +------------+   +------------+   +------------+
   5671     //                                                     ^
   5672     //                                                     |
   5673     //     *ppQueueTail: pSocket->pRxPacketListTail or pSocket->pRxOobPacketListTail
   5674     //
   5675     //
   5676     //  Remove the packet from the queue
   5677     //
   5678     pNextPacket = pPacket->pNext;
   5679     *ppQueueHead = pNextPacket;
   5680     if ( NULL == pNextPacket ) {
   5681       *ppQueueTail = NULL;
   5682     }
   5683     pPacket->pNext = NULL;
   5684 
   5685     //
   5686     //  Eliminate the need for IP4 and UDP4 specific routines by
   5687     //  connecting the token with the TX data control structure here.
   5688     //
   5689     //    +--------------------+   +--------------------+
   5690     //    | ESL_IO_MGMT        |   | ESL_PACKET         |
   5691     //    |                    |   |                    |
   5692     //    |    +---------------+   +----------------+   |
   5693     //    |    | Token         |   | Buffer Length  |   |
   5694     //    |    |        TxData --> | Buffer Address |   |
   5695     //    |    |               |   +----------------+---+
   5696     //    |    |        Event  |   | Data Buffer        |
   5697     //    +----+---------------+   |                    |
   5698     //                             +--------------------+
   5699     //
   5700     //  Compute the address of the TxData pointer in the token
   5701     //
   5702     pBuffer = (UINT8 *)&pIo->Token;
   5703     pBuffer = &pBuffer[ pSocket->TxTokenOffset ];
   5704     ppTokenData = (VOID **)pBuffer;
   5705 
   5706     //
   5707     //  Compute the address of the TX data control structure in the packet
   5708     //
   5709     //      * EFI_IP4_TRANSMIT_DATA
   5710     //      * EFI_TCP4_TRANSMIT_DATA
   5711     //      * EFI_UDP4_TRANSMIT_DATA
   5712     //
   5713     pBuffer = (UINT8 *)pPacket;
   5714     pBuffer = &pBuffer[ pSocket->TxPacketOffset ];
   5715 
   5716     //
   5717     //  Connect the token to the transmit data control structure
   5718     //
   5719     *ppTokenData = (VOID **)pBuffer;
   5720 
   5721     //
   5722     //  Display the results
   5723     //
   5724     DEBUG (( DEBUG_TX | DEBUG_INFO,
   5725               "0x%08x: pIo allocated for pPacket: 0x%08x\r\n",
   5726               pIo,
   5727               pPacket ));
   5728 
   5729     //
   5730     //  Start the transmit operation
   5731     //
   5732     Status = pPort->pfnTxStart ( pPort->pProtocol.v,
   5733                                  &pIo->Token );
   5734     if ( !EFI_ERROR ( Status )) {
   5735       //
   5736       //  Connect the structures
   5737       //
   5738       pIo->pPacket = pPacket;
   5739 
   5740       //
   5741       //          +-------------+   +-------------+   +-------------+
   5742       //  Free    | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
   5743       //          +-------------+   +-------------+   +-------------+
   5744       //              ^
   5745       //              |
   5746       //          *ppFree:  pPort->pTxFree or pTxOobFree
   5747       //
   5748       //
   5749       //  Remove the IO structure from the queue
   5750       //
   5751       *ppFree = pIo->pNext;
   5752 
   5753       //
   5754       //         *ppActive:  pPort->pTxActive or pTxOobActive
   5755       //             |
   5756       //             V
   5757       //          +-------------+   +-------------+   +-------------+
   5758       //  Active  | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
   5759       //          +-------------+   +-------------+   +-------------+
   5760       //
   5761       //
   5762       //  Mark this packet as active
   5763       //
   5764       pIo->pPacket = pPacket;
   5765       pIo->pNext = *ppActive;
   5766       *ppActive = pIo;
   5767     }
   5768     else {
   5769       //
   5770       //  Display the transmit error
   5771       //
   5772       DEBUG (( DEBUG_TX | DEBUG_INFO,
   5773                 "0x%08x, 0x%08x: pIo, pPacket transmit failure: %r\r\n",
   5774                 pIo,
   5775                 pPacket,
   5776                 Status ));
   5777       if ( EFI_SUCCESS == pSocket->TxError ) {
   5778         pSocket->TxError = Status;
   5779       }
   5780 
   5781       //
   5782       //  Free the IO structure
   5783       //
   5784       pIo->pNext = *ppFree;
   5785       *ppFree = pIo;
   5786 
   5787       //
   5788       //  Discard the transmit buffer
   5789       //
   5790       EslSocketPacketFree ( pPacket, DEBUG_TX );
   5791     }
   5792   }
   5793 
   5794   DBG_EXIT ( );
   5795 }
   5796