Removed variables that had no effect on code behavior. Normalized comment formatting. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Olivier Martin <olivier.martin@arm.com> Reviewed by: Daryl McDaniel <daryl.mcdaniel@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@16286 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			5796 lines
		
	
	
		
			172 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			5796 lines
		
	
	
		
			172 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  Implement the socket support for the socket layer.
 | 
						|
 | 
						|
  Socket States:
 | 
						|
  * Bound - pSocket->PortList is not NULL
 | 
						|
  * Listen - AcceptWait event is not NULL
 | 
						|
 | 
						|
  Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>
 | 
						|
  This program and the accompanying materials are licensed and made available under
 | 
						|
  the terms and conditions of the BSD License that accompanies this distribution.
 | 
						|
  The full text of the license may be found at
 | 
						|
  http://opensource.org/licenses/bsd-license.php
 | 
						|
 | 
						|
  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | 
						|
  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | 
						|
 | 
						|
 | 
						|
  \section DataStructures Data Structures
 | 
						|
 | 
						|
  <code><pre>
 | 
						|
 | 
						|
                +---------------+   +-------------+   +-------------+
 | 
						|
  Service Lists | ::ESL_SERVICE |-->| ESL_SERVICE |-->| ESL_SERVICE |--> NULL (pNext)
 | 
						|
                +---------------+   +-------------+   +-------------+
 | 
						|
                  ^                       | (pPortList)    |
 | 
						|
    pUdp4List ^   | pTcp4List             |                |
 | 
						|
              |   |                       |                |
 | 
						|
          ^   |   |                       |                |
 | 
						|
 pIp4List |   |   |                       |                |
 | 
						|
        +---------------+                 |                |
 | 
						|
        | ::ESL_LAYER   | ::mEslLayer     |                |
 | 
						|
        +---------------+                 |                |
 | 
						|
                  | (pSocketList)         |                |
 | 
						|
    Socket List   V                       V                V
 | 
						|
                +---------------+   +-------------+   +-------------+
 | 
						|
                | ::ESL_SOCKET  |-->| ::ESL_PORT  |-->|   ESL_PORT  |--> NULL (pLinkSocket)
 | 
						|
                +---------------+   +-------------+   +-------------+
 | 
						|
                  |                       |                |
 | 
						|
                  |                       |                V
 | 
						|
                  V                       V               NULL
 | 
						|
                +-------------+   +-------------+
 | 
						|
                | ESL_SOCKET  |-->|   ESL_PORT  |--> NULL
 | 
						|
                +-------------+   +-------------+
 | 
						|
                  |    | | | |            |
 | 
						|
                  V    | | | |            V
 | 
						|
                 NULL  | | | |           NULL
 | 
						|
               (pNext) | | | |     (pLinkService)
 | 
						|
                       | | | |                                     pRxPacketListHead
 | 
						|
                       | | | `-----------------------------------------------.
 | 
						|
                       | | |                     pRxOobPacketListHead        |
 | 
						|
                       | | `--------------------------------.                |
 | 
						|
                       | |      pTxPacketListHead           |                |
 | 
						|
                       | `---------------.                  |                |
 | 
						|
  pTxOobPacketListHead |                 |                  |                |
 | 
						|
                       V                 V                  V                V
 | 
						|
                  +--------------+    +------------+    +------------+    +------------+
 | 
						|
                  | ::ESL_PACKET |    | ESL_PACKET |    | ESL_PACKET |    | ESL_PACKET |
 | 
						|
                  +--------------+    +------------+    +------------+    +------------+
 | 
						|
                         |                 |                |                |
 | 
						|
                         V                 V                V                V
 | 
						|
                  +------------+    +------------+    +------------+    +------------+
 | 
						|
                  | ESL_PACKET |    | ESL_PACKET |    | ESL_PACKET |    | ESL_PACKET |
 | 
						|
                  +------------+    +------------+    +------------+    +------------+
 | 
						|
                         |                 |                |                |
 | 
						|
                         V                 V                V                V
 | 
						|
                        NULL              NULL             NULL             NULL
 | 
						|
                       (pNext)
 | 
						|
 | 
						|
  </pre></code>
 | 
						|
 | 
						|
  ::mEslLayer is the one and only ::ESL_LAYER structure.  It connects directly or
 | 
						|
  indirectly to the other data structures.  The ESL_LAYER structure has a unique
 | 
						|
  service list for each of the network protocol interfaces.
 | 
						|
 | 
						|
  ::ESL_SERVICE manages the network interfaces for a given transport type (IP4, TCP4, UDP4, etc.)
 | 
						|
 | 
						|
  ::ESL_SOCKET manages the activity for a single socket instance.  As such, it contains
 | 
						|
  the ::EFI_SOCKET_PROTOCOL structure which the BSD socket library uses as the object
 | 
						|
  reference and the API into the EFI socket library.
 | 
						|
 | 
						|
  ::ESL_PORT manages the connection with a single instance of the lower layer network.
 | 
						|
  This structure is the socket equivalent of an IP connection or a TCP or UDP port.
 | 
						|
 | 
						|
  ::ESL_PACKET buffers data for transmit and receive.  There are four queues connected
 | 
						|
  to the ::ESL_SOCKET that manage the data:
 | 
						|
  <ul>
 | 
						|
    <li>ESL_SOCKET::pRxPacketListHead - Normal (low) priority receive data</li>
 | 
						|
    <li>ESL_SOCKET::pRxOobPacketListHead - High (out-of-band or urgent) priority receive data</li>
 | 
						|
    <li>ESL_SOCKET::pTxPacketListHead - Normal (low) priority transmit data</li>
 | 
						|
    <li>ESL_SOCKET::pTxOobPacketListHead - High (out-of-band or urgent) priority transmit data</li>
 | 
						|
  </ul>
 | 
						|
  The selection of the transmit queue is controlled by the MSG_OOB flag on the transmit
 | 
						|
  request as well as the socket option SO_OOBINLINE.  The receive queue is selected by
 | 
						|
  the URGENT data flag for TCP and the setting of the socket option SO_OOBINLINE.
 | 
						|
 | 
						|
  Data structure synchronization is done by raising TPL to TPL_SOCKET.  Modifying
 | 
						|
  critical elements within the data structures must be done at this TPL.  TPL is then
 | 
						|
  restored to the previous level.  Note that the code verifies that all callbacks are
 | 
						|
  entering at TPL_SOCKETS for proper data structure synchronization.
 | 
						|
 | 
						|
  \section PortCloseStateMachine Port Close State Machine
 | 
						|
 | 
						|
  The port close state machine walks the port through the necessary
 | 
						|
  states to stop activity on the port and get it into a state where
 | 
						|
  the resources may be released.  The state machine consists of the
 | 
						|
  following arcs and states:
 | 
						|
 | 
						|
  <code><pre>
 | 
						|
 | 
						|
      +--------------------------+
 | 
						|
      |          Open            |
 | 
						|
      +--------------------------+
 | 
						|
                   |
 | 
						|
                   |  ::EslSocketPortCloseStart
 | 
						|
                   V
 | 
						|
      +--------------------------+
 | 
						|
      | PORT_STATE_CLOSE_STARTED |
 | 
						|
      +--------------------------+
 | 
						|
                   |
 | 
						|
                   |  ::EslSocketPortCloseTxDone
 | 
						|
                   V
 | 
						|
      +--------------------------+
 | 
						|
      | PORT_STATE_CLOSE_TX_DONE |
 | 
						|
      +--------------------------+
 | 
						|
                   |
 | 
						|
                   |  ::EslSocketPortCloseComplete
 | 
						|
                   V
 | 
						|
      +--------------------------+
 | 
						|
      |  PORT_STATE_CLOSE_DONE   |
 | 
						|
      +--------------------------+
 | 
						|
                   |
 | 
						|
                   |  ::EslSocketPortCloseRxDone
 | 
						|
                   V
 | 
						|
      +--------------------------+
 | 
						|
      | PORT_STATE_CLOSE_RX_DONE |
 | 
						|
      +--------------------------+
 | 
						|
                   |
 | 
						|
                   |  ::EslSocketPortClose
 | 
						|
                   V
 | 
						|
      +--------------------------+
 | 
						|
      |          Closed          |
 | 
						|
      +--------------------------+
 | 
						|
 | 
						|
  </pre></code>
 | 
						|
 | 
						|
  <ul>
 | 
						|
    <li>Arc: ::EslSocketPortCloseStart - Marks the port as closing and
 | 
						|
      initiates the port close operation</li>
 | 
						|
    <li>State: PORT_STATE_CLOSE_STARTED</li>
 | 
						|
    <li>Arc: ::EslSocketPortCloseTxDone - Waits until all of the transmit
 | 
						|
      operations to complete.  After all of the transmits are complete,
 | 
						|
      this routine initiates the network specific close operation by calling
 | 
						|
      through ESL_PROTOCOL_API::pfnPortCloseOp.  One such routine is
 | 
						|
      ::EslTcp4PortCloseOp.
 | 
						|
    </li>
 | 
						|
    <li>State: PORT_STATE_CLOSE_TX_DONE</li>
 | 
						|
    <li>Arc: ::EslSocketPortCloseComplete - Called when the close operation is
 | 
						|
      complete.  After the transition to PORT_STATE_CLOSE_DONE,
 | 
						|
      this routine calls ::EslSocketRxCancel to abort the pending receive operations.
 | 
						|
    </li>
 | 
						|
    <li>State: PORT_STATE_CLOSE_DONE</li>
 | 
						|
    <li>Arc: ::EslSocketPortCloseRxDone - Waits until all of the receive
 | 
						|
      operation have been cancelled.  After the transition to
 | 
						|
      PORT_STATE_CLOSE_RX_DONE, this routine calls ::EslSocketPortClose.
 | 
						|
    </li>
 | 
						|
    <li>State: PORT_STATE_CLOSE_RX_DONE</li>
 | 
						|
    <li>Arc: ::EslSocketPortClose - This routine discards any receive buffers
 | 
						|
      using a network specific support routine via ESL_PROTOCOL_API::pfnPacketFree.
 | 
						|
      This routine then releases the port resources allocated by ::EslSocketPortAllocate
 | 
						|
      and calls the network specific port close routine (e.g. ::EslTcp4PortClose)
 | 
						|
      via ESL_PROTOCOL_API::pfnPortClose to release any network specific resources.
 | 
						|
    </li>
 | 
						|
  </ul>
 | 
						|
 | 
						|
 | 
						|
  \section ReceiveEngine Receive Engine
 | 
						|
 | 
						|
  The receive path accepts data from the network and queues (buffers) it for the
 | 
						|
  application.  Flow control is applied once a maximum amount of buffering is reached
 | 
						|
  and is released when the buffer usage drops below that limit.  Eventually the
 | 
						|
  application requests data from the socket which removes entries from the queue and
 | 
						|
  returns the data.
 | 
						|
 | 
						|
  The receive engine is the state machine which reads data from the network and
 | 
						|
  fills the queue with received packets.  The receive engine uses two data structures
 | 
						|
  to manage the network receive opeations and the buffers.
 | 
						|
 | 
						|
  At a high level, the ::ESL_IO_MGMT structures are managing the tokens and
 | 
						|
  events for the interface to the UEFI network stack.  The ::ESL_PACKET
 | 
						|
  structures are managing the receive data buffers.  The receive engine
 | 
						|
  connects these two structures in the network specific receive completion
 | 
						|
  routines.
 | 
						|
 | 
						|
<code><pre>
 | 
						|
 | 
						|
      +------------------+
 | 
						|
      |     ::ESL_PORT     |
 | 
						|
      |                  |
 | 
						|
      +------------------+
 | 
						|
      |    ::ESL_IO_MGMT   |
 | 
						|
      +------------------+
 | 
						|
      |    ESL_IO_MGMT   |
 | 
						|
      +------------------+
 | 
						|
      .                  .
 | 
						|
      .    ESL_IO_MGMT   .
 | 
						|
      .                  .
 | 
						|
      +------------------+
 | 
						|
 | 
						|
</pre></code>
 | 
						|
 | 
						|
  The ::ESL_IO_MGMT structures are allocated as part of the ::ESL_PORT structure in
 | 
						|
  ::EslSocketPortAllocate.  The ESL_IO_MGMT structures are separated and placed on
 | 
						|
  the free list by calling ::EslSocketIoInit.  The ESL_IO_MGMT structure contains
 | 
						|
  the network layer specific receive completion token and event.  The receive engine
 | 
						|
  is eventually shutdown by ::EslSocketPortCloseTxDone and the resources in these
 | 
						|
  structures are released in ::EslSocketPortClose by a call to ::EslSocketIoFree.
 | 
						|
 | 
						|
<code><pre>
 | 
						|
 | 
						|
         pPort->pRxActive
 | 
						|
                |
 | 
						|
                V
 | 
						|
          +-------------+   +-------------+   +-------------+
 | 
						|
  Active  | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
 | 
						|
          +-------------+   +-------------+   +-------------+
 | 
						|
 | 
						|
          +-------------+   +-------------+   +-------------+
 | 
						|
  Free    | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
 | 
						|
          +-------------+   +-------------+   +-------------+
 | 
						|
                ^
 | 
						|
                |
 | 
						|
          pPort->pRxFree
 | 
						|
</pre></code>
 | 
						|
 | 
						|
  The receive engine is started by calling ::EslSocketRxStart.  Flow control pauses
 | 
						|
  the receive engine by stopping the calls to EslSocketRxStart when the amount of
 | 
						|
  receive data waiting for the application meets or exceeds MAX_RX_DATA.  After
 | 
						|
  the application reads enough data that the amount of buffering drops below this
 | 
						|
  limit, the calls to EslSockeRxStart continue which releases the flow control.
 | 
						|
 | 
						|
  Receive flow control is applied when the port is created, since no receive
 | 
						|
  operation are pending to the low layer network driver.  The flow control gets
 | 
						|
  released when the low layer network port is configured or the first receive
 | 
						|
  operation is posted.  Flow control remains in the released state until the
 | 
						|
  maximum buffer space is consumed.  During this time, ::EslSocketRxComplete
 | 
						|
  calls ::EslSocketRxStart.  Flow control is applied in EslSocketRxComplete
 | 
						|
  by skipping the call to EslSocketRxStart.  Flow control is eventually
 | 
						|
  released in ::EslSocketReceive when the buffer space drops below the
 | 
						|
  maximum amount causing EslSocketReceive to call EslSocketRxStart.
 | 
						|
 | 
						|
<code><pre>
 | 
						|
 | 
						|
                    +------------+   +------------+
 | 
						|
    High     .----->| ESL_PACKET |-->| ESL_PACKET |--> NULL (pNext)
 | 
						|
  Priority   |      +------------+   +------------+
 | 
						|
             |
 | 
						|
             | pRxOobPacketListHead
 | 
						|
       +------------+
 | 
						|
       | ::ESL_SOCKET |
 | 
						|
       +------------+
 | 
						|
             | pRxPacketListHead
 | 
						|
    Low      |
 | 
						|
  Priority   |      +------------+   +------------+   +------------+
 | 
						|
             `----->| ::ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL
 | 
						|
                    +------------+   +------------+   +------------+
 | 
						|
 | 
						|
</pre></code>
 | 
						|
 | 
						|
  ::EslSocketRxStart connects an ::ESL_PACKET structure to the ::ESL_IO_MGMT structure
 | 
						|
  and then calls the network layer to start the receive operation.  Upon
 | 
						|
  receive completion, ::EslSocketRxComplete breaks the connection between these
 | 
						|
  structrues and places the ESL_IO_MGMT structure onto the ESL_PORT::pRxFree list to
 | 
						|
  make token and event available for another receive operation.  EslSocketRxComplete
 | 
						|
  then queues the ESL_PACKET structure (data packet) to either the
 | 
						|
  ESL_SOCKET::pRxOobPacketListTail or ESL_SOCKET::pRxPacketListTail depending on
 | 
						|
  whether urgent or normal data was received.  Finally ::EslSocketRxComplete attempts
 | 
						|
  to start another receive operation.
 | 
						|
 | 
						|
<code><pre>
 | 
						|
 | 
						|
  Setup for IP4 and UDP4
 | 
						|
 | 
						|
      +--------------------+
 | 
						|
      | ESL_IO_MGMT        |
 | 
						|
      |                    |
 | 
						|
      |    +---------------+
 | 
						|
      |    | Token         |
 | 
						|
      |    |        RxData --> NULL
 | 
						|
      +----+---------------+
 | 
						|
         |
 | 
						|
         V
 | 
						|
      +--------------------+
 | 
						|
      | ESL_PACKET         |
 | 
						|
      |                    |
 | 
						|
      |    +---------------+
 | 
						|
      |    |       pRxData --> NULL
 | 
						|
      +----+---------------+
 | 
						|
 | 
						|
  Completion for IP4 and UDP4
 | 
						|
 | 
						|
      +--------------------+   +----------------------+
 | 
						|
      | ESL_IO_MGMT        |   |      Data Buffer     |
 | 
						|
      |                    |   |     (Driver owned)   |
 | 
						|
      |    +---------------+   +----------------------+
 | 
						|
      |    | Token         |               ^
 | 
						|
      |    |      Rx Event |               |
 | 
						|
      |    |               |   +----------------------+
 | 
						|
      |    |        RxData --> | EFI_IP4_RECEIVE_DATA |
 | 
						|
      +----+---------------+   |    (Driver owned)    |
 | 
						|
         |                     +----------------------+
 | 
						|
         V                                 ^
 | 
						|
      +--------------------+               .
 | 
						|
      | ESL_PACKET         |               .
 | 
						|
      |                    |               .
 | 
						|
      |    +---------------+               .
 | 
						|
      |    |       pRxData --> NULL  .......
 | 
						|
      +----+---------------+
 | 
						|
 | 
						|
 | 
						|
  Setup and completion for TCP4
 | 
						|
 | 
						|
      +--------------------+   +--------------------------+
 | 
						|
      | ESL_IO_MGMT        |-->| ESL_PACKET               |
 | 
						|
      |                    |   |                          |
 | 
						|
      |    +---------------+   +----------------------+   |
 | 
						|
      |    | Token         |   | EFI_IP4_RECEIVE_DATA |   |
 | 
						|
      |    |        RxData --> |                      |   |
 | 
						|
      |    |               |   +----------------------+---+
 | 
						|
      |    |        Event  |   |       Data Buffer        |
 | 
						|
      +----+---------------+   |                          |
 | 
						|
                               |                          |
 | 
						|
                               +--------------------------+
 | 
						|
 | 
						|
</pre></code>
 | 
						|
 | 
						|
  To minimize the number of buffer copies, the data is not copied until the
 | 
						|
  application makes a receive call.  At this point socket performs a single copy
 | 
						|
  in the receive path to move the data from the buffer filled by the network layer
 | 
						|
  into the application's buffer.
 | 
						|
 | 
						|
  The IP4 and UDP4 drivers go one step further to reduce buffer copies.  They
 | 
						|
  allow the socket layer to hold on to the actual receive buffer until the
 | 
						|
  application has performed a receive operation or closes the socket.  Both
 | 
						|
  of theses operations return the buffer to the lower layer network driver
 | 
						|
  by calling ESL_PROTOCOL_API::pfnPacketFree.
 | 
						|
 | 
						|
  When a socket application wants to receive data it indirectly calls
 | 
						|
  ::EslSocketReceive to remove data from one of the receive data queues.  This routine
 | 
						|
  removes the next available packet from ESL_SOCKET::pRxOobPacketListHead or
 | 
						|
  ESL_SOCKET::pRxPacketListHead and copies the data from the packet
 | 
						|
  into the application's buffer.  For SOCK_STREAM sockets, if the packet
 | 
						|
  contains more data then the ESL_PACKET structures remains at the head of the
 | 
						|
  receive queue for the next application receive
 | 
						|
  operation.  For SOCK_DGRAM, SOCK_RAW and SOCK_SEQ_PACKET sockets, the ::ESL_PACKET
 | 
						|
  structure is removed from the head of the receive queue and any remaining data is
 | 
						|
  discarded as the packet is placed on the free queue.
 | 
						|
 | 
						|
  During socket layer shutdown, ::EslSocketShutdown calls ::EslSocketRxCancel to
 | 
						|
  cancel any pending receive operations.  EslSocketRxCancel calls the network specific
 | 
						|
  cancel routine using ESL_PORT::pfnRxCancel.
 | 
						|
 | 
						|
 | 
						|
  \section TransmitEngine Transmit Engine
 | 
						|
 | 
						|
  Application calls to ::EslSocketTransmit cause data to be copied into a buffer.
 | 
						|
  The buffer exists as an extension to an ESL_PACKET structure and the structure
 | 
						|
  is placed at the end of the transmit queue.
 | 
						|
 | 
						|
<code><pre>
 | 
						|
 | 
						|
     *ppQueueHead: pSocket->pRxPacketListHead or pSocket->pRxOobPacketListHead
 | 
						|
          |
 | 
						|
          V
 | 
						|
        +------------+   +------------+   +------------+
 | 
						|
  Data  | ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL
 | 
						|
        +------------+   +------------+   +------------+
 | 
						|
                                                     ^
 | 
						|
                                                     |
 | 
						|
     *ppQueueTail: pSocket->pRxPacketListTail or pSocket->pRxOobPacketListTail
 | 
						|
 | 
						|
</pre></code>
 | 
						|
 | 
						|
  There are actually two transmit queues the normal or low priority queue which is
 | 
						|
  the default and the urgent or high priority queue which is addressed by specifying
 | 
						|
  the MSG_OOB flag during the transmit request.  Associated with each queue is a
 | 
						|
  transmit engine which is responsible for sending the data in that queue.
 | 
						|
 | 
						|
  The transmit engine is the state machine which removes entries from the head
 | 
						|
  of the transmit queue and causes the data to be sent over the network.
 | 
						|
 | 
						|
<code><pre>
 | 
						|
 | 
						|
      +--------------------+   +--------------------+
 | 
						|
      | ESL_IO_MGMT        |   | ESL_PACKET         |
 | 
						|
      |                    |   |                    |
 | 
						|
      |    +---------------+   +----------------+   |
 | 
						|
      |    | Token         |   | Buffer Length  |   |
 | 
						|
      |    |        TxData --> | Buffer Address |   |
 | 
						|
      |    |               |   +----------------+---+
 | 
						|
      |    |        Event  |   | Data Buffer        |
 | 
						|
      +----+---------------+   |                    |
 | 
						|
                               +--------------------+
 | 
						|
</pre></code>
 | 
						|
 | 
						|
  At a high level, the transmit engine uses a couple of data structures
 | 
						|
  to manage the data flow.  The ::ESL_IO_MGMT structures manage the tokens and
 | 
						|
  events for the interface to the UEFI network stack.  The ::ESL_PACKET
 | 
						|
  structures manage the data buffers that get sent.  The transmit
 | 
						|
  engine connects these two structures prior to transmission and disconnects
 | 
						|
  them upon completion.
 | 
						|
 | 
						|
<code><pre>
 | 
						|
 | 
						|
         pPort->pTxActive or pTxOobActive
 | 
						|
                |
 | 
						|
                V
 | 
						|
          +-------------+   +-------------+   +-------------+
 | 
						|
  Active  | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
 | 
						|
          +-------------+   +-------------+   +-------------+
 | 
						|
 | 
						|
          +-------------+   +-------------+   +-------------+
 | 
						|
  Free    | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
 | 
						|
          +-------------+   +-------------+   +-------------+
 | 
						|
                ^
 | 
						|
                |
 | 
						|
          pPort->pTxFree or pTxOobFree
 | 
						|
 | 
						|
</pre></code>
 | 
						|
 | 
						|
  The transmit engine manages multiple transmit operations using the
 | 
						|
  active and free lists shown above.  ::EslSocketPortAllocate allocates the
 | 
						|
  ::ESL_IO_MGMT structures as an extension to the ::ESL_PORT structure.
 | 
						|
  This routine places the ESL_IO_MGMT structures on the free list by calling
 | 
						|
  ::EslSocketIoInit.  During their lifetime, the ESL_IO_MGMT structures
 | 
						|
  will move from the free list to the active list and back again.  The
 | 
						|
  active list contains the packets that are actively being processed by
 | 
						|
  the UEFI network stack.  Eventually the ESL_IO_MGMT structures will be
 | 
						|
  removed from the free list and be deallocated by the EslSocketPortClose
 | 
						|
  routine.
 | 
						|
 | 
						|
  The network specific code calls the ::EslSocketTxStart routine
 | 
						|
  to hand a packet to the network stack.  EslSocketTxStart connects
 | 
						|
  the transmit packet (::ESL_PACKET) to an ::ESL_IO_MGMT structure
 | 
						|
  and then queues the result to one of the active lists:
 | 
						|
  ESL_PORT::pTxActive or ESL_PORT::pTxOobActive.  The routine then
 | 
						|
  hands the packet to the network stack.
 | 
						|
 | 
						|
  Upon completion, the network specific TxComplete routine calls
 | 
						|
  ::EslSocketTxComplete to disconnect the transmit packet from the
 | 
						|
  ESL_IO_MGMT structure and frees the ::ESL_PACKET structure by calling
 | 
						|
  ::EslSocketPacketFree.  The routine places the ::ESL_IO_MGMT structure
 | 
						|
  into the free list either ESL_PORT::pTxFree or ESL_PORT::pTxOobFree.
 | 
						|
  EslSocketTxComplete then starts the next transmit operation while
 | 
						|
  the socket is active or calls the ::EslSocketPortCloseTxDone routine
 | 
						|
  when the socket is shutting down.
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#include "Socket.h"
 | 
						|
 | 
						|
 | 
						|
/** Socket driver connection points
 | 
						|
 | 
						|
  List the network stack connection points for the socket driver.
 | 
						|
**/
 | 
						|
CONST ESL_SOCKET_BINDING cEslSocketBinding[] = {
 | 
						|
  { L"Ip4",
 | 
						|
    &gEfiIp4ServiceBindingProtocolGuid,
 | 
						|
    &gEfiIp4ProtocolGuid,
 | 
						|
    &mEslIp4ServiceGuid,
 | 
						|
    OFFSET_OF ( ESL_LAYER, pIp4List ),
 | 
						|
    4,    //  RX buffers
 | 
						|
    4,    //  TX buffers
 | 
						|
    0 },  //  TX Oob buffers
 | 
						|
  { L"Tcp4",
 | 
						|
    &gEfiTcp4ServiceBindingProtocolGuid,
 | 
						|
    &gEfiTcp4ProtocolGuid,
 | 
						|
    &mEslTcp4ServiceGuid,
 | 
						|
    OFFSET_OF ( ESL_LAYER, pTcp4List ),
 | 
						|
    4,    //  RX buffers
 | 
						|
    4,    //  TX buffers
 | 
						|
    4 },  //  TX Oob buffers
 | 
						|
  { L"Tcp6",
 | 
						|
    &gEfiTcp6ServiceBindingProtocolGuid,
 | 
						|
    &gEfiTcp6ProtocolGuid,
 | 
						|
    &mEslTcp6ServiceGuid,
 | 
						|
    OFFSET_OF ( ESL_LAYER, pTcp6List ),
 | 
						|
    4,    //  RX buffers
 | 
						|
    4,    //  TX buffers
 | 
						|
    4 },  //  TX Oob buffers
 | 
						|
  { L"Udp4",
 | 
						|
    &gEfiUdp4ServiceBindingProtocolGuid,
 | 
						|
    &gEfiUdp4ProtocolGuid,
 | 
						|
    &mEslUdp4ServiceGuid,
 | 
						|
    OFFSET_OF ( ESL_LAYER, pUdp4List ),
 | 
						|
    4,    //  RX buffers
 | 
						|
    4,    //  TX buffers
 | 
						|
    0 },  //  TX Oob buffers
 | 
						|
  { L"Udp6",
 | 
						|
    &gEfiUdp6ServiceBindingProtocolGuid,
 | 
						|
    &gEfiUdp6ProtocolGuid,
 | 
						|
    &mEslUdp6ServiceGuid,
 | 
						|
    OFFSET_OF ( ESL_LAYER, pUdp6List ),
 | 
						|
    4,    //  RX buffers
 | 
						|
    4,    //  TX buffers
 | 
						|
    0 }   //  TX Oob buffers
 | 
						|
};
 | 
						|
 | 
						|
CONST UINTN cEslSocketBindingEntries = DIM ( cEslSocketBinding );
 | 
						|
 | 
						|
/// APIs to support the various socket types for the v4 network stack.
 | 
						|
CONST ESL_PROTOCOL_API * cEslAfInetApi[] = {
 | 
						|
  NULL,             //  0
 | 
						|
  &cEslTcp4Api,     //  SOCK_STREAM
 | 
						|
  &cEslUdp4Api,     //  SOCK_DGRAM
 | 
						|
  &cEslIp4Api,      //  SOCK_RAW
 | 
						|
  NULL,             //  SOCK_RDM
 | 
						|
  &cEslTcp4Api      //  SOCK_SEQPACKET
 | 
						|
};
 | 
						|
 | 
						|
/// Number of entries in the v4 API array ::cEslAfInetApi.
 | 
						|
CONST int cEslAfInetApiSize = DIM ( cEslAfInetApi );
 | 
						|
 | 
						|
 | 
						|
/// APIs to support the various socket types for the v6 network stack.
 | 
						|
CONST ESL_PROTOCOL_API * cEslAfInet6Api[] = {
 | 
						|
  NULL,             //  0
 | 
						|
  &cEslTcp6Api,     //  SOCK_STREAM
 | 
						|
  &cEslUdp6Api,     //  SOCK_DGRAM
 | 
						|
  NULL,             //  SOCK_RAW
 | 
						|
  NULL,             //  SOCK_RDM
 | 
						|
  &cEslTcp6Api      //  SOCK_SEQPACKET
 | 
						|
};
 | 
						|
 | 
						|
/// Number of entries in the v6 API array ::cEslAfInet6Api.
 | 
						|
CONST int cEslAfInet6ApiSize = DIM ( cEslAfInet6Api );
 | 
						|
 | 
						|
 | 
						|
/// Global management structure for the socket layer.
 | 
						|
ESL_LAYER mEslLayer;
 | 
						|
 | 
						|
 | 
						|
/** Initialize an endpoint for network communication.
 | 
						|
 | 
						|
  This routine initializes the communication endpoint.
 | 
						|
 | 
						|
  The ::socket routine calls this routine indirectly to create
 | 
						|
  the communication endpoint.
 | 
						|
 | 
						|
  @param[in] pSocketProtocol Address of the socket protocol structure.
 | 
						|
  @param[in]  domain   Select the family of protocols for the client or server
 | 
						|
                       application.  See the ::socket documentation for values.
 | 
						|
  @param[in]  type     Specifies how to make the network connection.
 | 
						|
                       See the ::socket documentation for values.
 | 
						|
  @param[in]  protocol Specifies the lower layer protocol to use.
 | 
						|
                       See the ::socket documentation for values.
 | 
						|
  @param[out] pErrno   Address to receive the errno value upon completion.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS - Socket successfully created
 | 
						|
  @retval EFI_INVALID_PARAMETER - Invalid domain value, errno = EAFNOSUPPORT
 | 
						|
  @retval EFI_INVALID_PARAMETER - Invalid type value, errno = EINVAL
 | 
						|
  @retval EFI_INVALID_PARAMETER - Invalid protocol value, errno = EINVAL
 | 
						|
 **/
 | 
						|
EFI_STATUS
 | 
						|
EslSocket (
 | 
						|
  IN EFI_SOCKET_PROTOCOL * pSocketProtocol,
 | 
						|
  IN int domain,
 | 
						|
  IN int type,
 | 
						|
  IN int protocol,
 | 
						|
  IN int * pErrno
 | 
						|
  )
 | 
						|
{
 | 
						|
  CONST ESL_PROTOCOL_API * pApi;
 | 
						|
  CONST ESL_PROTOCOL_API ** ppApiArray;
 | 
						|
  CONST ESL_PROTOCOL_API ** ppApiArrayEnd;
 | 
						|
  int ApiArraySize;
 | 
						|
  ESL_SOCKET * pSocket;
 | 
						|
  EFI_STATUS Status;
 | 
						|
  int errno;
 | 
						|
 | 
						|
  DBG_ENTER ( );
 | 
						|
 | 
						|
  //  Locate the socket
 | 
						|
  pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
 | 
						|
 | 
						|
  //  Set the default domain if necessary
 | 
						|
  if ( AF_UNSPEC == domain ) {
 | 
						|
    domain = AF_INET;
 | 
						|
  }
 | 
						|
 | 
						|
  //  Assume success
 | 
						|
  errno = 0;
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
 | 
						|
  //  Use break instead of goto
 | 
						|
  for ( ; ; ) {
 | 
						|
    //  Validate the domain value
 | 
						|
    if (( AF_INET != domain )
 | 
						|
      && ( AF_INET6 != domain )
 | 
						|
      && ( AF_LOCAL != domain )) {
 | 
						|
      DEBUG (( DEBUG_ERROR | DEBUG_SOCKET,
 | 
						|
                "ERROR - Invalid domain value\r\n" ));
 | 
						|
      Status = EFI_INVALID_PARAMETER;
 | 
						|
      errno = EAFNOSUPPORT;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    //  Determine the protocol APIs
 | 
						|
    ppApiArray = NULL;
 | 
						|
    ApiArraySize = 0;
 | 
						|
    if (( AF_INET == domain )
 | 
						|
      || ( AF_LOCAL == domain )) {
 | 
						|
      ppApiArray = &cEslAfInetApi[0];
 | 
						|
      ApiArraySize = cEslAfInetApiSize;
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      ppApiArray = &cEslAfInet6Api[0];
 | 
						|
      ApiArraySize = cEslAfInet6ApiSize;
 | 
						|
    }
 | 
						|
 | 
						|
    //  Set the default type if necessary
 | 
						|
    if ( 0 == type ) {
 | 
						|
      type = SOCK_STREAM;
 | 
						|
    }
 | 
						|
 | 
						|
    //  Validate the type value
 | 
						|
    if (( type >= ApiArraySize )
 | 
						|
      || ( NULL == ppApiArray )
 | 
						|
      || ( NULL == ppApiArray[ type ])) {
 | 
						|
      DEBUG (( DEBUG_ERROR | DEBUG_SOCKET,
 | 
						|
                "ERROR - Invalid type value\r\n" ));
 | 
						|
      //  The socket type is not supported
 | 
						|
      Status = EFI_INVALID_PARAMETER;
 | 
						|
      errno = EPROTOTYPE;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    //  Set the default protocol if necessary
 | 
						|
    pApi = ppApiArray[ type ];
 | 
						|
    if ( 0 == protocol ) {
 | 
						|
      protocol = pApi->DefaultProtocol;
 | 
						|
    }
 | 
						|
 | 
						|
    //  Validate the protocol value
 | 
						|
    if (( pApi->DefaultProtocol != protocol )
 | 
						|
      && ( SOCK_RAW != type )) {
 | 
						|
      Status = EFI_INVALID_PARAMETER;
 | 
						|
 | 
						|
      //  Assume that the driver supports this protocol
 | 
						|
      ppApiArray = &cEslAfInetApi[0];
 | 
						|
      ppApiArrayEnd = &ppApiArray [ cEslAfInetApiSize ];
 | 
						|
      while ( ppApiArrayEnd > ppApiArray ) {
 | 
						|
        pApi = *ppApiArray;
 | 
						|
        if ( protocol == pApi->DefaultProtocol ) {
 | 
						|
          break;
 | 
						|
        }
 | 
						|
        ppApiArray += 1;
 | 
						|
      }
 | 
						|
      if ( ppApiArrayEnd <= ppApiArray ) {
 | 
						|
        //  Verify against the IPv6 table
 | 
						|
        ppApiArray = &cEslAfInet6Api[0];
 | 
						|
        ppApiArrayEnd = &ppApiArray [ cEslAfInet6ApiSize ];
 | 
						|
        while ( ppApiArrayEnd > ppApiArray ) {
 | 
						|
          pApi = *ppApiArray;
 | 
						|
          if ( protocol == pApi->DefaultProtocol ) {
 | 
						|
            break;
 | 
						|
          }
 | 
						|
          ppApiArray += 1;
 | 
						|
        }
 | 
						|
      }
 | 
						|
      if ( ppApiArrayEnd <= ppApiArray ) {
 | 
						|
        DEBUG (( DEBUG_ERROR | DEBUG_SOCKET,
 | 
						|
                  "ERROR - The protocol is not supported!\r\n" ));
 | 
						|
        errno = EPROTONOSUPPORT;
 | 
						|
        break;
 | 
						|
      }
 | 
						|
 | 
						|
      //  The driver does not support this protocol
 | 
						|
      DEBUG (( DEBUG_ERROR | DEBUG_SOCKET,
 | 
						|
                "ERROR - The protocol does not support this socket type!\r\n" ));
 | 
						|
      errno = EPROTONOSUPPORT;
 | 
						|
      errno = EPROTOTYPE;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    //  Save the socket attributes
 | 
						|
    pSocket->pApi = pApi;
 | 
						|
    pSocket->Domain = domain;
 | 
						|
    pSocket->Type = type;
 | 
						|
    pSocket->Protocol = protocol;
 | 
						|
 | 
						|
    //  Done
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  //  Return the operation status
 | 
						|
  if ( NULL != pErrno ) {
 | 
						|
    *pErrno = errno;
 | 
						|
  }
 | 
						|
  DBG_EXIT_STATUS ( Status );
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/** Accept a network connection.
 | 
						|
 | 
						|
  This routine calls the network specific layer to remove the next
 | 
						|
  connection from the FIFO.
 | 
						|
 | 
						|
  The ::accept calls this routine to poll for a network
 | 
						|
  connection to the socket.  When a connection is available
 | 
						|
  this routine returns the ::EFI_SOCKET_PROTOCOL structure address
 | 
						|
  associated with the new socket and the remote network address
 | 
						|
  if requested.
 | 
						|
 | 
						|
  @param[in]      pSocketProtocol   Address of an ::EFI_SOCKET_PROTOCOL structure.
 | 
						|
  @param[in]      pSockAddr         Address of a buffer to receive the remote
 | 
						|
                                    network address.
 | 
						|
  @param[in,out]  pSockAddrLength   Length in bytes of the address buffer.
 | 
						|
                                    On output specifies the length of the
 | 
						|
                                    remote network address.
 | 
						|
  @param[out]     ppSocketProtocol  Address of a buffer to receive the
 | 
						|
                                    ::EFI_SOCKET_PROTOCOL instance
 | 
						|
                                    associated with the new socket.
 | 
						|
  @param[out]     pErrno            Address to receive the errno value upon completion.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS   New connection successfully created
 | 
						|
  @retval EFI_NOT_READY No connection is available
 | 
						|
 **/
 | 
						|
EFI_STATUS
 | 
						|
EslSocketAccept (
 | 
						|
  IN EFI_SOCKET_PROTOCOL * pSocketProtocol,
 | 
						|
  IN struct sockaddr * pSockAddr,
 | 
						|
  IN OUT socklen_t * pSockAddrLength,
 | 
						|
  IN EFI_SOCKET_PROTOCOL ** ppSocketProtocol,
 | 
						|
  IN int * pErrno
 | 
						|
  )
 | 
						|
{
 | 
						|
  ESL_SOCKET * pNewSocket;
 | 
						|
  ESL_SOCKET * pSocket;
 | 
						|
  EFI_STATUS Status;
 | 
						|
  EFI_TPL TplPrevious;
 | 
						|
 | 
						|
  DBG_ENTER ( );
 | 
						|
 | 
						|
  //
 | 
						|
  //  Assume success
 | 
						|
  //
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
 | 
						|
  //
 | 
						|
  //  Validate the socket
 | 
						|
  //
 | 
						|
  pSocket = NULL;
 | 
						|
  pNewSocket = NULL;
 | 
						|
  if ( NULL != pSocketProtocol ) {
 | 
						|
    pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
 | 
						|
 | 
						|
    //
 | 
						|
    //  Verify the API
 | 
						|
    //
 | 
						|
    if ( NULL == pSocket->pApi->pfnAccept ) {
 | 
						|
      Status = EFI_UNSUPPORTED;
 | 
						|
      pSocket->errno = ENOTSUP;
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      //
 | 
						|
      //  Validate the sockaddr
 | 
						|
      //
 | 
						|
      if (( NULL != pSockAddr )
 | 
						|
        && ( NULL == pSockAddrLength )) {
 | 
						|
        DEBUG (( DEBUG_ACCEPT,
 | 
						|
                  "ERROR - pSockAddr is NULL!\r\n" ));
 | 
						|
        Status = EFI_INVALID_PARAMETER;
 | 
						|
        pSocket->errno = EFAULT;
 | 
						|
      }
 | 
						|
      else {
 | 
						|
        //
 | 
						|
        //  Synchronize with the socket layer
 | 
						|
        //
 | 
						|
        RAISE_TPL ( TplPrevious, TPL_SOCKETS );
 | 
						|
 | 
						|
        //
 | 
						|
        //  Verify that the socket is in the listen state
 | 
						|
        //
 | 
						|
        if ( SOCKET_STATE_LISTENING != pSocket->State ) {
 | 
						|
          DEBUG (( DEBUG_ACCEPT,
 | 
						|
                    "ERROR - Socket is not listening!\r\n" ));
 | 
						|
          if ( NULL == pSocket->pApi->pfnAccept ) {
 | 
						|
            //
 | 
						|
            //  Socket does not support listen
 | 
						|
            //
 | 
						|
            pSocket->errno = EOPNOTSUPP;
 | 
						|
            Status = EFI_UNSUPPORTED;
 | 
						|
          }
 | 
						|
          else {
 | 
						|
            //
 | 
						|
            //  Socket supports listen, but not in listen state
 | 
						|
            //
 | 
						|
            pSocket->errno = EINVAL;
 | 
						|
            Status = EFI_NOT_STARTED;
 | 
						|
          }
 | 
						|
        }
 | 
						|
        else {
 | 
						|
          //
 | 
						|
          //  Determine if a socket is available
 | 
						|
          //
 | 
						|
          if ( 0 == pSocket->FifoDepth ) {
 | 
						|
            //
 | 
						|
            //  No connections available
 | 
						|
            //  Determine if any ports are available
 | 
						|
            //
 | 
						|
            if ( NULL == pSocket->pPortList ) {
 | 
						|
              //
 | 
						|
              //  No ports available
 | 
						|
              //
 | 
						|
              Status = EFI_DEVICE_ERROR;
 | 
						|
              pSocket->errno = EINVAL;
 | 
						|
 | 
						|
              //
 | 
						|
              //  Update the socket state
 | 
						|
              //
 | 
						|
              pSocket->State = SOCKET_STATE_NO_PORTS;
 | 
						|
            }
 | 
						|
            else {
 | 
						|
              //
 | 
						|
              //  Ports are available
 | 
						|
              //  No connection requests at this time
 | 
						|
              //
 | 
						|
              Status = EFI_NOT_READY;
 | 
						|
              pSocket->errno = EAGAIN;
 | 
						|
            }
 | 
						|
          }
 | 
						|
          else {
 | 
						|
 | 
						|
            //
 | 
						|
            //  Attempt to accept the connection and
 | 
						|
            //  get the remote network address
 | 
						|
            //
 | 
						|
            pNewSocket = pSocket->pFifoHead;
 | 
						|
            ASSERT ( NULL != pNewSocket );
 | 
						|
            Status = pSocket->pApi->pfnAccept ( pNewSocket,
 | 
						|
                                                pSockAddr,
 | 
						|
                                                pSockAddrLength );
 | 
						|
            if ( !EFI_ERROR ( Status )) {
 | 
						|
              //
 | 
						|
              //  Remove the new socket from the list
 | 
						|
              //
 | 
						|
              pSocket->pFifoHead = pNewSocket->pNextConnection;
 | 
						|
              if ( NULL == pSocket->pFifoHead ) {
 | 
						|
                pSocket->pFifoTail = NULL;
 | 
						|
              }
 | 
						|
 | 
						|
              //
 | 
						|
              //  Account for this socket
 | 
						|
              //
 | 
						|
              pSocket->FifoDepth -= 1;
 | 
						|
 | 
						|
              //
 | 
						|
              //  Update the new socket's state
 | 
						|
              //
 | 
						|
              pNewSocket->State = SOCKET_STATE_CONNECTED;
 | 
						|
              pNewSocket->bConfigured = TRUE;
 | 
						|
              DEBUG (( DEBUG_ACCEPT,
 | 
						|
                        "0x%08x: Socket connected\r\n",
 | 
						|
                        pNewSocket ));
 | 
						|
            }
 | 
						|
          }
 | 
						|
        }
 | 
						|
 | 
						|
        //
 | 
						|
        //  Release the socket layer synchronization
 | 
						|
        //
 | 
						|
        RESTORE_TPL ( TplPrevious );
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  //  Return the new socket
 | 
						|
  //
 | 
						|
  if (( NULL != ppSocketProtocol )
 | 
						|
    && ( NULL != pNewSocket )) {
 | 
						|
    *ppSocketProtocol = &pNewSocket->SocketProtocol;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  //  Return the operation status
 | 
						|
  //
 | 
						|
  if ( NULL != pErrno ) {
 | 
						|
    if ( NULL != pSocket ) {
 | 
						|
      *pErrno = pSocket->errno;
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      Status = EFI_INVALID_PARAMETER;
 | 
						|
      *pErrno = ENOTSOCK;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  DBG_EXIT_STATUS ( Status );
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/** Allocate and initialize a ESL_SOCKET structure.
 | 
						|
 | 
						|
  This support function allocates an ::ESL_SOCKET structure
 | 
						|
  and installs a protocol on ChildHandle.  If pChildHandle is a
 | 
						|
  pointer to NULL, then a new handle is created and returned in
 | 
						|
  pChildHandle.  If pChildHandle is not a pointer to NULL, then
 | 
						|
  the protocol installs on the existing pChildHandle.
 | 
						|
 | 
						|
  @param[in,out]  pChildHandle  Pointer to the handle of the child to create.
 | 
						|
                                If it is NULL, then a new handle is created.
 | 
						|
                                If it is a pointer to an existing UEFI handle,
 | 
						|
                                then the protocol is added to the existing UEFI
 | 
						|
                                handle.
 | 
						|
  @param[in]      DebugFlags    Flags for debug messages
 | 
						|
  @param[in,out]  ppSocket      The buffer to receive an ::ESL_SOCKET structure address.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The protocol was added to ChildHandle.
 | 
						|
  @retval EFI_INVALID_PARAMETER ChildHandle is NULL.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES  There are not enough resources available to create
 | 
						|
                                the child
 | 
						|
  @retval other                 The child handle was not created
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
EslSocketAllocate (
 | 
						|
  IN OUT EFI_HANDLE * pChildHandle,
 | 
						|
  IN     UINTN DebugFlags,
 | 
						|
  IN OUT ESL_SOCKET ** ppSocket
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN LengthInBytes;
 | 
						|
  ESL_LAYER * pLayer;
 | 
						|
  ESL_SOCKET * pSocket;
 | 
						|
  EFI_STATUS Status;
 | 
						|
  EFI_TPL TplPrevious;
 | 
						|
 | 
						|
  DBG_ENTER ( );
 | 
						|
 | 
						|
  //
 | 
						|
  //  Create a socket structure
 | 
						|
  //
 | 
						|
  LengthInBytes = sizeof ( *pSocket );
 | 
						|
  pSocket = (ESL_SOCKET *) AllocateZeroPool ( LengthInBytes );
 | 
						|
  if ( NULL != pSocket ) {
 | 
						|
    DEBUG (( DebugFlags | DEBUG_POOL | DEBUG_INIT,
 | 
						|
              "0x%08x: Allocate pSocket, %d bytes\r\n",
 | 
						|
              pSocket,
 | 
						|
              LengthInBytes ));
 | 
						|
 | 
						|
    //
 | 
						|
    //  Initialize the socket protocol
 | 
						|
    //
 | 
						|
    pSocket->Signature = SOCKET_SIGNATURE;
 | 
						|
    pSocket->SocketProtocol.pfnAccept = EslSocketAccept;
 | 
						|
    pSocket->SocketProtocol.pfnBind = EslSocketBind;
 | 
						|
    pSocket->SocketProtocol.pfnClosePoll = EslSocketClosePoll;
 | 
						|
    pSocket->SocketProtocol.pfnCloseStart = EslSocketCloseStart;
 | 
						|
    pSocket->SocketProtocol.pfnConnect = EslSocketConnect;
 | 
						|
    pSocket->SocketProtocol.pfnGetLocal = EslSocketGetLocalAddress;
 | 
						|
    pSocket->SocketProtocol.pfnGetPeer = EslSocketGetPeerAddress;
 | 
						|
    pSocket->SocketProtocol.pfnListen = EslSocketListen;
 | 
						|
    pSocket->SocketProtocol.pfnOptionGet = EslSocketOptionGet;
 | 
						|
    pSocket->SocketProtocol.pfnOptionSet = EslSocketOptionSet;
 | 
						|
    pSocket->SocketProtocol.pfnPoll = EslSocketPoll;
 | 
						|
    pSocket->SocketProtocol.pfnReceive = EslSocketReceive;
 | 
						|
    pSocket->SocketProtocol.pfnShutdown = EslSocketShutdown;
 | 
						|
    pSocket->SocketProtocol.pfnSocket = EslSocket;
 | 
						|
    pSocket->SocketProtocol.pfnTransmit = EslSocketTransmit;
 | 
						|
 | 
						|
    pSocket->MaxRxBuf = MAX_RX_DATA;
 | 
						|
    pSocket->MaxTxBuf = MAX_TX_DATA;
 | 
						|
 | 
						|
    //
 | 
						|
    //  Install the socket protocol on the specified handle
 | 
						|
    //
 | 
						|
    Status = gBS->InstallMultipleProtocolInterfaces (
 | 
						|
                    pChildHandle,
 | 
						|
                    &gEfiSocketProtocolGuid,
 | 
						|
                    &pSocket->SocketProtocol,
 | 
						|
                    NULL
 | 
						|
                    );
 | 
						|
    if ( !EFI_ERROR ( Status )) {
 | 
						|
      DEBUG (( DebugFlags | DEBUG_POOL | DEBUG_INIT | DEBUG_INFO,
 | 
						|
                "Installed: gEfiSocketProtocolGuid on   0x%08x\r\n",
 | 
						|
                *pChildHandle ));
 | 
						|
      pSocket->SocketProtocol.SocketHandle = *pChildHandle;
 | 
						|
 | 
						|
      //
 | 
						|
      //  Synchronize with the socket layer
 | 
						|
      //
 | 
						|
      RAISE_TPL ( TplPrevious, TPL_SOCKETS );
 | 
						|
 | 
						|
      //
 | 
						|
      //  Add this socket to the list
 | 
						|
      //
 | 
						|
      pLayer = &mEslLayer;
 | 
						|
      pSocket->pNext = pLayer->pSocketList;
 | 
						|
      pLayer->pSocketList = pSocket;
 | 
						|
 | 
						|
      //
 | 
						|
      //  Release the socket layer synchronization
 | 
						|
      //
 | 
						|
      RESTORE_TPL ( TplPrevious );
 | 
						|
 | 
						|
      //
 | 
						|
      //  Return the socket structure address
 | 
						|
      //
 | 
						|
      *ppSocket = pSocket;
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      DEBUG (( DEBUG_ERROR | DebugFlags | DEBUG_POOL | DEBUG_INIT,
 | 
						|
                "ERROR - Failed to install gEfiSocketProtocolGuid on 0x%08x, Status: %r\r\n",
 | 
						|
                *pChildHandle,
 | 
						|
                Status ));
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    //  Release the socket if necessary
 | 
						|
    //
 | 
						|
    if ( EFI_ERROR ( Status )) {
 | 
						|
      gBS->FreePool ( pSocket );
 | 
						|
      DEBUG (( DebugFlags | DEBUG_POOL | DEBUG_INIT,
 | 
						|
                "0x%08x: Free pSocket, %d bytes\r\n",
 | 
						|
                pSocket,
 | 
						|
                sizeof ( *pSocket )));
 | 
						|
      pSocket = NULL;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    Status = EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  //  Return the operation status
 | 
						|
  //
 | 
						|
  DBG_EXIT_STATUS ( Status );
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/** Bind a name to a socket.
 | 
						|
 | 
						|
  This routine calls the network specific layer to save the network
 | 
						|
  address of the local connection point.
 | 
						|
 | 
						|
  The ::bind routine calls this routine to connect a name
 | 
						|
  (network address and port) to a socket on the local machine.
 | 
						|
 | 
						|
  @param[in]  pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
 | 
						|
  @param[in]  pSockAddr       Address of a sockaddr structure that contains the
 | 
						|
                              connection point on the local machine.  An IPv4 address
 | 
						|
                              of INADDR_ANY specifies that the connection is made to
 | 
						|
                              all of the network stacks on the platform.  Specifying a
 | 
						|
                              specific IPv4 address restricts the connection to the
 | 
						|
                              network stack supporting that address.  Specifying zero
 | 
						|
                              for the port causes the network layer to assign a port
 | 
						|
                              number from the dynamic range.  Specifying a specific
 | 
						|
                              port number causes the network layer to use that port.
 | 
						|
  @param[in]  SockAddrLength  Specifies the length in bytes of the sockaddr structure.
 | 
						|
  @param[out] pErrno          Address to receive the errno value upon completion.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS - Socket successfully created
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EslSocketBind (
 | 
						|
  IN EFI_SOCKET_PROTOCOL * pSocketProtocol,
 | 
						|
  IN CONST struct sockaddr * pSockAddr,
 | 
						|
  IN socklen_t SockAddrLength,
 | 
						|
  OUT int * pErrno
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_HANDLE ChildHandle;
 | 
						|
  UINT8 * pBuffer;
 | 
						|
  ESL_PORT * pPort;
 | 
						|
  ESL_SERVICE ** ppServiceListHead;
 | 
						|
  ESL_SOCKET * pSocket;
 | 
						|
  ESL_SERVICE * pService;
 | 
						|
  EFI_SERVICE_BINDING_PROTOCOL * pServiceBinding;
 | 
						|
  EFI_STATUS Status;
 | 
						|
  EFI_TPL TplPrevious;
 | 
						|
 | 
						|
  DBG_ENTER ( );
 | 
						|
 | 
						|
  //
 | 
						|
  //  Assume success
 | 
						|
  //
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
 | 
						|
  //
 | 
						|
  //  Validate the socket
 | 
						|
  //
 | 
						|
  pSocket = NULL;
 | 
						|
  if ( NULL != pSocketProtocol ) {
 | 
						|
    pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
 | 
						|
 | 
						|
    //
 | 
						|
    //  Validate the structure pointer
 | 
						|
    //
 | 
						|
    pSocket->errno = 0;
 | 
						|
    if ( NULL == pSockAddr ) {
 | 
						|
      DEBUG (( DEBUG_BIND,
 | 
						|
                "ERROR - pSockAddr is NULL!\r\n" ));
 | 
						|
      Status = EFI_INVALID_PARAMETER;
 | 
						|
      pSocket->errno = EFAULT;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    //  Validate the local address length
 | 
						|
    //
 | 
						|
    else if ( SockAddrLength < pSocket->pApi->MinimumAddressLength ) {
 | 
						|
      DEBUG (( DEBUG_BIND,
 | 
						|
                "ERROR - Invalid bind name length: %d\r\n",
 | 
						|
                SockAddrLength ));
 | 
						|
      Status = EFI_INVALID_PARAMETER;
 | 
						|
      pSocket->errno = EINVAL;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    //  Validate the shutdown state
 | 
						|
    //
 | 
						|
    else if ( pSocket->bRxDisable || pSocket->bTxDisable ) {
 | 
						|
      DEBUG (( DEBUG_BIND,
 | 
						|
                "ERROR - Shutdown has been called on socket 0x%08x\r\n",
 | 
						|
                pSocket ));
 | 
						|
      pSocket->errno = EINVAL;
 | 
						|
      Status = EFI_INVALID_PARAMETER;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    //  Verify the socket state
 | 
						|
    //
 | 
						|
    else if ( SOCKET_STATE_NOT_CONFIGURED != pSocket->State ) {
 | 
						|
      DEBUG (( DEBUG_BIND,
 | 
						|
                "ERROR - The socket 0x%08x is already configured!\r\n",
 | 
						|
                pSocket ));
 | 
						|
      pSocket->errno = EINVAL;
 | 
						|
      Status = EFI_ALREADY_STARTED;
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      //
 | 
						|
      //  Synchronize with the socket layer
 | 
						|
      //
 | 
						|
      RAISE_TPL ( TplPrevious, TPL_SOCKETS );
 | 
						|
 | 
						|
      //
 | 
						|
      //  Assume no ports are available
 | 
						|
      //
 | 
						|
      pSocket->errno = EADDRNOTAVAIL;
 | 
						|
      Status = EFI_INVALID_PARAMETER;
 | 
						|
 | 
						|
      //
 | 
						|
      //  Walk the list of services
 | 
						|
      //
 | 
						|
      pBuffer = (UINT8 *)&mEslLayer;
 | 
						|
      pBuffer = &pBuffer[ pSocket->pApi->ServiceListOffset ];
 | 
						|
      ppServiceListHead = (ESL_SERVICE **)pBuffer;
 | 
						|
      pService = *ppServiceListHead;
 | 
						|
      while ( NULL != pService ) {
 | 
						|
        //
 | 
						|
        //  Create the port
 | 
						|
        //
 | 
						|
        pServiceBinding = pService->pServiceBinding;
 | 
						|
        ChildHandle = NULL;
 | 
						|
        Status = pServiceBinding->CreateChild ( pServiceBinding,
 | 
						|
                                                &ChildHandle );
 | 
						|
        if ( !EFI_ERROR ( Status )) {
 | 
						|
          DEBUG (( DEBUG_BIND | DEBUG_POOL,
 | 
						|
                    "0x%08x: %s port handle created\r\n",
 | 
						|
                    ChildHandle,
 | 
						|
                    pService->pSocketBinding->pName ));
 | 
						|
 | 
						|
          //
 | 
						|
          //  Open the port
 | 
						|
          //
 | 
						|
          Status = EslSocketPortAllocate ( pSocket,
 | 
						|
                                           pService,
 | 
						|
                                           ChildHandle,
 | 
						|
                                           pSockAddr,
 | 
						|
                                           TRUE,
 | 
						|
                                           DEBUG_BIND,
 | 
						|
                                           &pPort );
 | 
						|
        }
 | 
						|
        else {
 | 
						|
          DEBUG (( DEBUG_BIND | DEBUG_POOL,
 | 
						|
                    "ERROR - Failed to open %s port handle, Status: %r\r\n",
 | 
						|
                    pService->pSocketBinding->pName,
 | 
						|
                    Status ));
 | 
						|
        }
 | 
						|
 | 
						|
        //
 | 
						|
        //  Set the next service
 | 
						|
        //
 | 
						|
        pService = pService->pNext;
 | 
						|
      }
 | 
						|
 | 
						|
      //
 | 
						|
      //  Verify that at least one network connection was found
 | 
						|
      //
 | 
						|
      if ( NULL != pSocket->pPortList ) {
 | 
						|
        Status = EFI_SUCCESS;
 | 
						|
      }
 | 
						|
      else {
 | 
						|
        if ( EADDRNOTAVAIL == pSocket->errno ) {
 | 
						|
          DEBUG (( DEBUG_BIND | DEBUG_POOL | DEBUG_INIT,
 | 
						|
                    "ERROR - Socket address is not available!\r\n" ));
 | 
						|
        }
 | 
						|
        if ( EADDRINUSE == pSocket->errno ) {
 | 
						|
          DEBUG (( DEBUG_BIND | DEBUG_POOL | DEBUG_INIT,
 | 
						|
                    "ERROR - Socket address is in use!\r\n" ));
 | 
						|
        }
 | 
						|
        Status = EFI_INVALID_PARAMETER;
 | 
						|
      }
 | 
						|
 | 
						|
      //
 | 
						|
      //  Mark this socket as bound if successful
 | 
						|
      //
 | 
						|
      if ( !EFI_ERROR ( Status )) {
 | 
						|
        pSocket->State = SOCKET_STATE_BOUND;
 | 
						|
        pSocket->errno = 0;
 | 
						|
      }
 | 
						|
 | 
						|
      //
 | 
						|
      //  Release the socket layer synchronization
 | 
						|
      //
 | 
						|
      RESTORE_TPL ( TplPrevious );
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  //  Return the operation status
 | 
						|
  //
 | 
						|
  if ( NULL != pErrno ) {
 | 
						|
    if ( NULL != pSocket ) {
 | 
						|
      *pErrno = pSocket->errno;
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      Status = EFI_INVALID_PARAMETER;
 | 
						|
      *pErrno = ENOTSOCK;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  DBG_EXIT_STATUS ( Status );
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/** Test the bind configuration.
 | 
						|
 | 
						|
  @param[in] pPort        Address of the ::ESL_PORT structure.
 | 
						|
  @param[in] ErrnoValue   errno value if test fails
 | 
						|
 | 
						|
  @retval EFI_SUCCESS   The connection was successfully established.
 | 
						|
  @retval Others        The connection attempt failed.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EslSocketBindTest (
 | 
						|
  IN ESL_PORT * pPort,
 | 
						|
  IN int ErrnoValue
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT8 * pBuffer;
 | 
						|
  VOID * pConfigData;
 | 
						|
  EFI_STATUS Status;
 | 
						|
 | 
						|
  DBG_ENTER ( );
 | 
						|
 | 
						|
  //
 | 
						|
  //  Locate the configuration data
 | 
						|
  //
 | 
						|
  pBuffer = (UINT8 *)pPort;
 | 
						|
  pBuffer = &pBuffer [ pPort->pSocket->pApi->ConfigDataOffset ];
 | 
						|
  pConfigData = (VOID *)pBuffer;
 | 
						|
 | 
						|
  //
 | 
						|
  //  Validate that the port is connected
 | 
						|
  //
 | 
						|
  Status = pPort->pSocket->pApi->pfnVerifyLocalIpAddress ( pPort, pBuffer );
 | 
						|
  if ( EFI_ERROR ( Status )) {
 | 
						|
    DEBUG (( DEBUG_WARN | DEBUG_BIND,
 | 
						|
              "WARNING - Port 0x%08x invalid IP address: %r\r\n",
 | 
						|
              pPort,
 | 
						|
              Status ));
 | 
						|
    pPort->pSocket->errno = ErrnoValue;
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    //
 | 
						|
    //  Attempt to use this configuration
 | 
						|
    //
 | 
						|
    Status = pPort->pfnConfigure ( pPort->pProtocol.v, pConfigData );
 | 
						|
    if ( EFI_ERROR ( Status )) {
 | 
						|
      DEBUG (( DEBUG_WARN | DEBUG_BIND,
 | 
						|
                "WARNING - Port 0x%08x failed configuration, Status: %r\r\n",
 | 
						|
                pPort,
 | 
						|
                Status ));
 | 
						|
      pPort->pSocket->errno = ErrnoValue;
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      //
 | 
						|
      //  Reset the port
 | 
						|
      //
 | 
						|
      Status = pPort->pfnConfigure ( pPort->pProtocol.v, NULL );
 | 
						|
      if ( EFI_ERROR ( Status )) {
 | 
						|
        DEBUG (( DEBUG_ERROR | DEBUG_BIND,
 | 
						|
                  "ERROR - Port 0x%08x failed configuration reset, Status: %r\r\n",
 | 
						|
                  pPort,
 | 
						|
                  Status ));
 | 
						|
        ASSERT ( EFI_SUCCESS == Status );
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  //  Return the operation status
 | 
						|
  //
 | 
						|
  DBG_EXIT_STATUS ( Status );
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/** Determine if the socket is closed.
 | 
						|
 | 
						|
  This routine checks the state of the socket to determine if
 | 
						|
  the network specific layer has completed the close operation.
 | 
						|
 | 
						|
  The ::close routine polls this routine to determine when the
 | 
						|
  close operation is complete.  The close operation needs to
 | 
						|
  reverse the operations of the ::EslSocketAllocate routine.
 | 
						|
 | 
						|
  @param[in]  pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
 | 
						|
  @param[out] pErrno          Address to receive the errno value upon completion.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS     Socket successfully closed
 | 
						|
  @retval EFI_NOT_READY   Close still in progress
 | 
						|
  @retval EFI_ALREADY     Close operation already in progress
 | 
						|
  @retval Other           Failed to close the socket
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EslSocketClosePoll (
 | 
						|
  IN EFI_SOCKET_PROTOCOL * pSocketProtocol,
 | 
						|
  IN int * pErrno
 | 
						|
  )
 | 
						|
{
 | 
						|
  int errno;
 | 
						|
  ESL_LAYER * pLayer;
 | 
						|
  ESL_SOCKET * pNextSocket;
 | 
						|
  ESL_SOCKET * pSocket;
 | 
						|
  EFI_STATUS Status;
 | 
						|
  EFI_TPL TplPrevious;
 | 
						|
 | 
						|
  DBG_ENTER ( );
 | 
						|
 | 
						|
  //
 | 
						|
  //  Assume success
 | 
						|
  //
 | 
						|
  errno = 0;
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
 | 
						|
  //
 | 
						|
  //  Synchronize with the socket layer
 | 
						|
  //
 | 
						|
  RAISE_TPL ( TplPrevious, TPL_SOCKETS );
 | 
						|
 | 
						|
  //
 | 
						|
  //  Locate the socket
 | 
						|
  //
 | 
						|
  pLayer = &mEslLayer;
 | 
						|
  pNextSocket = pLayer->pSocketList;
 | 
						|
  pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
 | 
						|
  while ( NULL != pNextSocket ) {
 | 
						|
    if ( pNextSocket == pSocket ) {
 | 
						|
      //
 | 
						|
      //  Determine if the socket is in the closing state
 | 
						|
      //
 | 
						|
      if ( SOCKET_STATE_CLOSED == pSocket->State ) {
 | 
						|
        //
 | 
						|
        //  Walk the list of ports
 | 
						|
        //
 | 
						|
        if ( NULL == pSocket->pPortList ) {
 | 
						|
          //
 | 
						|
          //  All the ports are closed
 | 
						|
          //  Close the WaitAccept event if necessary
 | 
						|
          //
 | 
						|
          if ( NULL != pSocket->WaitAccept ) {
 | 
						|
            Status = gBS->CloseEvent ( pSocket->WaitAccept );
 | 
						|
            if ( !EFI_ERROR ( Status )) {
 | 
						|
              DEBUG (( DEBUG_SOCKET | DEBUG_CLOSE | DEBUG_POOL,
 | 
						|
                        "0x%08x: Closed WaitAccept event\r\n",
 | 
						|
                        pSocket->WaitAccept ));
 | 
						|
              //
 | 
						|
              //  Return the transmit status
 | 
						|
              //
 | 
						|
              Status = pSocket->TxError;
 | 
						|
              if ( EFI_ERROR ( Status )) {
 | 
						|
                pSocket->errno = EIO;
 | 
						|
              }
 | 
						|
            }
 | 
						|
            else {
 | 
						|
              DEBUG (( DEBUG_ERROR | DEBUG_SOCKET | DEBUG_CLOSE | DEBUG_POOL,
 | 
						|
                        "ERROR - Failed to close the WaitAccept event, Status: %r\r\n",
 | 
						|
                        Status ));
 | 
						|
              ASSERT ( EFI_SUCCESS == Status );
 | 
						|
            }
 | 
						|
          }
 | 
						|
        }
 | 
						|
        else {
 | 
						|
          //
 | 
						|
          //  At least one port is still open
 | 
						|
          //
 | 
						|
          Status = EFI_NOT_READY;
 | 
						|
          errno = EAGAIN;
 | 
						|
        }
 | 
						|
      }
 | 
						|
      else {
 | 
						|
        //
 | 
						|
        //  SocketCloseStart was not called
 | 
						|
        //
 | 
						|
        Status = EFI_NOT_STARTED;
 | 
						|
        errno = EPERM;
 | 
						|
      }
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    //  Set the next socket
 | 
						|
    //
 | 
						|
    pNextSocket = pNextSocket->pNext;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  //  Handle the error case where the socket was already closed
 | 
						|
  //
 | 
						|
  if ( NULL == pSocket ) {
 | 
						|
    //
 | 
						|
    //  Socket not found
 | 
						|
    //
 | 
						|
    Status = EFI_NOT_FOUND;
 | 
						|
    errno = ENOTSOCK;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  //  Release the socket layer synchronization
 | 
						|
  //
 | 
						|
  RESTORE_TPL ( TplPrevious );
 | 
						|
 | 
						|
  //
 | 
						|
  //  Return the operation status
 | 
						|
  //
 | 
						|
  if ( NULL != pErrno ) {
 | 
						|
    *pErrno = errno;
 | 
						|
  }
 | 
						|
  DBG_EXIT_STATUS ( Status );
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/** Start the close operation on the socket.
 | 
						|
 | 
						|
  This routine calls the network specific layer to initiate the
 | 
						|
  close state machine.  This routine then calls the network
 | 
						|
  specific layer to determine if the close state machine has gone
 | 
						|
  to completion.  The result from this poll is returned to the
 | 
						|
  caller.
 | 
						|
 | 
						|
  The ::close routine calls this routine to start the close
 | 
						|
  operation which reverses the operations of the
 | 
						|
  ::EslSocketAllocate routine.  The close routine then polls
 | 
						|
  the ::EslSocketClosePoll routine to determine when the
 | 
						|
  socket is closed.
 | 
						|
 | 
						|
  @param[in] pSocketProtocol  Address of an ::EFI_SOCKET_PROTOCOL structure.
 | 
						|
  @param[in] bCloseNow        Boolean to control close behavior
 | 
						|
  @param[out] pErrno          Address to receive the errno value upon completion.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS     Socket successfully closed
 | 
						|
  @retval EFI_NOT_READY   Close still in progress
 | 
						|
  @retval EFI_ALREADY     Close operation already in progress
 | 
						|
  @retval Other           Failed to close the socket
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EslSocketCloseStart (
 | 
						|
  IN EFI_SOCKET_PROTOCOL * pSocketProtocol,
 | 
						|
  IN BOOLEAN bCloseNow,
 | 
						|
  IN int * pErrno
 | 
						|
  )
 | 
						|
{
 | 
						|
  int errno;
 | 
						|
  ESL_PORT * pNextPort;
 | 
						|
  ESL_PORT * pPort;
 | 
						|
  ESL_SOCKET * pSocket;
 | 
						|
  EFI_STATUS Status;
 | 
						|
  EFI_TPL TplPrevious;
 | 
						|
 | 
						|
  DBG_ENTER ( );
 | 
						|
 | 
						|
  //
 | 
						|
  //  Assume success
 | 
						|
  //
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
  errno = 0;
 | 
						|
 | 
						|
  //
 | 
						|
  //  Synchronize with the socket layer
 | 
						|
  //
 | 
						|
  RAISE_TPL ( TplPrevious, TPL_SOCKETS );
 | 
						|
 | 
						|
  //
 | 
						|
  //  Determine if the socket is already closed
 | 
						|
  //
 | 
						|
  pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
 | 
						|
  if ( SOCKET_STATE_CLOSED > pSocket->State ) {
 | 
						|
    //
 | 
						|
    //  Update the socket state
 | 
						|
    //
 | 
						|
    pSocket->State = SOCKET_STATE_CLOSED;
 | 
						|
 | 
						|
    //
 | 
						|
    //  Walk the list of ports
 | 
						|
    //
 | 
						|
    pPort = pSocket->pPortList;
 | 
						|
    while ( NULL != pPort ) {
 | 
						|
      //
 | 
						|
      //  Start closing the ports
 | 
						|
      //
 | 
						|
      pNextPort = pPort->pLinkSocket;
 | 
						|
      Status = EslSocketPortCloseStart ( pPort,
 | 
						|
                                         bCloseNow,
 | 
						|
                                         DEBUG_CLOSE | DEBUG_LISTEN | DEBUG_CONNECTION );
 | 
						|
      if (( EFI_SUCCESS != Status )
 | 
						|
        && ( EFI_NOT_READY != Status )) {
 | 
						|
        errno = EIO;
 | 
						|
        break;
 | 
						|
      }
 | 
						|
 | 
						|
      //
 | 
						|
      //  Set the next port
 | 
						|
      //
 | 
						|
      pPort = pNextPort;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    //  Attempt to finish closing the socket
 | 
						|
    //
 | 
						|
    if ( NULL == pPort ) {
 | 
						|
      Status = EslSocketClosePoll ( pSocketProtocol, &errno );
 | 
						|
    }
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    Status = EFI_NOT_READY;
 | 
						|
    errno = EAGAIN;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  //  Release the socket layer synchronization
 | 
						|
  //
 | 
						|
  RESTORE_TPL ( TplPrevious );
 | 
						|
 | 
						|
  //
 | 
						|
  //  Return the operation status
 | 
						|
  //
 | 
						|
  if ( NULL != pErrno ) {
 | 
						|
    *pErrno = errno;
 | 
						|
  }
 | 
						|
  DBG_EXIT_STATUS ( Status );
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/** Connect to a remote system via the network.
 | 
						|
 | 
						|
  This routine calls the network specific layer to establish
 | 
						|
  the remote system address and establish the connection to
 | 
						|
  the remote system.
 | 
						|
 | 
						|
  The ::connect routine calls this routine to establish a
 | 
						|
  connection with the specified remote system.  This routine
 | 
						|
  is designed to be polled by the connect routine for completion
 | 
						|
  of the network connection.
 | 
						|
 | 
						|
  @param[in]  pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
 | 
						|
  @param[in]  pSockAddr       Network address of the remote system.
 | 
						|
  @param[in]  SockAddrLength  Length in bytes of the network address.
 | 
						|
  @param[out] pErrno          Address to receive the errno value upon completion.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS     The connection was successfully established.
 | 
						|
  @retval EFI_NOT_READY   The connection is in progress, call this routine again.
 | 
						|
  @retval Others          The connection attempt failed.
 | 
						|
 **/
 | 
						|
EFI_STATUS
 | 
						|
EslSocketConnect (
 | 
						|
  IN EFI_SOCKET_PROTOCOL * pSocketProtocol,
 | 
						|
  IN const struct sockaddr * pSockAddr,
 | 
						|
  IN socklen_t SockAddrLength,
 | 
						|
  IN int * pErrno
 | 
						|
  )
 | 
						|
{
 | 
						|
  struct sockaddr_in6 LocalAddress;
 | 
						|
  ESL_PORT * pPort;
 | 
						|
  ESL_SOCKET * pSocket;
 | 
						|
  EFI_STATUS Status;
 | 
						|
  EFI_TPL TplPrevious;
 | 
						|
 | 
						|
  DEBUG (( DEBUG_CONNECT, "Entering SocketConnect\r\n" ));
 | 
						|
 | 
						|
  //
 | 
						|
  //  Assume success
 | 
						|
  //
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
 | 
						|
  //
 | 
						|
  //  Validate the socket
 | 
						|
  //
 | 
						|
  pSocket = NULL;
 | 
						|
  if ( NULL != pSocketProtocol ) {
 | 
						|
    pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
 | 
						|
 | 
						|
    //
 | 
						|
    //  Validate the name length
 | 
						|
    //
 | 
						|
    if ( SockAddrLength < ( sizeof ( struct sockaddr ) - sizeof ( pSockAddr->sa_data ))) {
 | 
						|
      DEBUG (( DEBUG_CONNECT,
 | 
						|
                "ERROR - Invalid bind name length: %d\r\n",
 | 
						|
                SockAddrLength ));
 | 
						|
      Status = EFI_INVALID_PARAMETER;
 | 
						|
      pSocket->errno = EINVAL;
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      //
 | 
						|
      //  Assume success
 | 
						|
      //
 | 
						|
      pSocket->errno = 0;
 | 
						|
 | 
						|
      //
 | 
						|
      //  Synchronize with the socket layer
 | 
						|
      //
 | 
						|
      RAISE_TPL ( TplPrevious, TPL_SOCKETS );
 | 
						|
 | 
						|
      //
 | 
						|
      //  Validate the socket state
 | 
						|
      //
 | 
						|
      switch ( pSocket->State ) {
 | 
						|
      default:
 | 
						|
        //
 | 
						|
        //  Wrong socket state
 | 
						|
        //
 | 
						|
        pSocket->errno = EIO;
 | 
						|
        Status = EFI_DEVICE_ERROR;
 | 
						|
        break;
 | 
						|
 | 
						|
      case SOCKET_STATE_NOT_CONFIGURED:
 | 
						|
      case SOCKET_STATE_BOUND:
 | 
						|
        //
 | 
						|
        //  Validate the address length
 | 
						|
        //
 | 
						|
        if ( SockAddrLength >= pSocket->pApi->MinimumAddressLength ) {
 | 
						|
          //
 | 
						|
          //  Verify the API
 | 
						|
          //
 | 
						|
          if ( NULL == pSocket->pApi->pfnRemoteAddrSet ) {
 | 
						|
            //
 | 
						|
            //  Already connected
 | 
						|
            //
 | 
						|
            pSocket->errno = ENOTSUP;
 | 
						|
            Status = EFI_UNSUPPORTED;
 | 
						|
          }
 | 
						|
          else {
 | 
						|
            //
 | 
						|
            //  Determine if BIND was already called
 | 
						|
            //
 | 
						|
            if ( NULL == pSocket->pPortList ) {
 | 
						|
              //
 | 
						|
              //  Allow any local port
 | 
						|
              //
 | 
						|
              ZeroMem ( &LocalAddress, sizeof ( LocalAddress ));
 | 
						|
              LocalAddress.sin6_len = (uint8_t)pSocket->pApi->MinimumAddressLength;
 | 
						|
              LocalAddress.sin6_family = pSocket->pApi->AddressFamily;
 | 
						|
              Status = EslSocketBind ( &pSocket->SocketProtocol,
 | 
						|
                                       (struct sockaddr *)&LocalAddress,
 | 
						|
                                       LocalAddress.sin6_len,
 | 
						|
                                       &pSocket->errno );
 | 
						|
            }
 | 
						|
            if ( NULL != pSocket->pPortList ) {
 | 
						|
              //
 | 
						|
              //  Walk the list of ports
 | 
						|
              //
 | 
						|
              pPort = pSocket->pPortList;
 | 
						|
              while ( NULL != pPort ) {
 | 
						|
                //
 | 
						|
                //  Set the remote address
 | 
						|
                //
 | 
						|
                Status = pSocket->pApi->pfnRemoteAddrSet ( pPort,
 | 
						|
                                                           pSockAddr,
 | 
						|
                                                           SockAddrLength );
 | 
						|
                if ( EFI_ERROR ( Status )) {
 | 
						|
                  break;
 | 
						|
                }
 | 
						|
 | 
						|
                //
 | 
						|
                //  Set the next port
 | 
						|
                //
 | 
						|
                pPort = pPort->pLinkSocket;
 | 
						|
              }
 | 
						|
 | 
						|
              //
 | 
						|
              //  Verify the API
 | 
						|
              //
 | 
						|
              if (( !EFI_ERROR ( Status ))
 | 
						|
                && ( NULL != pSocket->pApi->pfnConnectStart )) {
 | 
						|
                //
 | 
						|
                //  Initiate the connection with the remote system
 | 
						|
                //
 | 
						|
                Status = pSocket->pApi->pfnConnectStart ( pSocket );
 | 
						|
 | 
						|
                //
 | 
						|
                //  Set the next state if connecting
 | 
						|
                //
 | 
						|
                if ( EFI_NOT_READY == Status ) {
 | 
						|
                  pSocket->State = SOCKET_STATE_CONNECTING;
 | 
						|
                }
 | 
						|
              }
 | 
						|
            }
 | 
						|
          }
 | 
						|
        }
 | 
						|
        else {
 | 
						|
          DEBUG (( DEBUG_CONNECT,
 | 
						|
                    "ERROR - Invalid address length: %d\r\n",
 | 
						|
                    SockAddrLength ));
 | 
						|
          Status = EFI_INVALID_PARAMETER;
 | 
						|
          pSocket->errno = EINVAL;
 | 
						|
        }
 | 
						|
        break;
 | 
						|
 | 
						|
      case SOCKET_STATE_CONNECTING:
 | 
						|
        //
 | 
						|
        //  Poll the network adapter
 | 
						|
        //
 | 
						|
        EslSocketRxPoll ( pSocket );
 | 
						|
 | 
						|
        //
 | 
						|
        //  Poll for connection completion
 | 
						|
        //
 | 
						|
        if ( NULL == pSocket->pApi->pfnConnectPoll ) {
 | 
						|
          //
 | 
						|
          //  Already connected
 | 
						|
          //
 | 
						|
          pSocket->errno = EISCONN;
 | 
						|
          Status = EFI_ALREADY_STARTED;
 | 
						|
        }
 | 
						|
        else {
 | 
						|
          Status = pSocket->pApi->pfnConnectPoll ( pSocket );
 | 
						|
 | 
						|
          //
 | 
						|
          //  Set the next state if connected
 | 
						|
          //
 | 
						|
          if ( EFI_NOT_READY != Status ) {
 | 
						|
            if ( EFI_ERROR ( Status )) {
 | 
						|
              pSocket->State = SOCKET_STATE_BOUND;
 | 
						|
            }
 | 
						|
          }
 | 
						|
        }
 | 
						|
        break;
 | 
						|
 | 
						|
      case SOCKET_STATE_CONNECTED:
 | 
						|
        //
 | 
						|
        //  Connected
 | 
						|
        //
 | 
						|
        Status = EFI_SUCCESS;
 | 
						|
        break;
 | 
						|
      }
 | 
						|
 | 
						|
      //
 | 
						|
      //  Release the socket layer synchronization
 | 
						|
      //
 | 
						|
      RESTORE_TPL ( TplPrevious );
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  //  Return the operation status
 | 
						|
  //
 | 
						|
  if ( NULL != pErrno ) {
 | 
						|
    if ( NULL != pSocket ) {
 | 
						|
      *pErrno = pSocket->errno;
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      //
 | 
						|
      //  Bad socket protocol
 | 
						|
      //
 | 
						|
      DEBUG (( DEBUG_ERROR | DEBUG_CONNECT,
 | 
						|
                "ERROR - pSocketProtocol invalid!\r\n" ));
 | 
						|
      Status = EFI_INVALID_PARAMETER;
 | 
						|
      *pErrno = ENOTSOCK;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  //  Return the operation status
 | 
						|
  //
 | 
						|
  DEBUG (( DEBUG_CONNECT, "Exiting SocketConnect, Status: %r\r\n", Status ));
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/** Copy a fragmented buffer into a destination buffer.
 | 
						|
 | 
						|
  This support routine copies a fragmented buffer to the caller specified buffer.
 | 
						|
 | 
						|
  This routine is called by ::EslIp4Receive and ::EslUdp4Receive.
 | 
						|
 | 
						|
  @param[in]  FragmentCount   Number of fragments in the table
 | 
						|
  @param[in]  pFragmentTable  Address of an EFI_IP4_FRAGMENT_DATA structure
 | 
						|
  @param[in]  BufferLength    Length of the the buffer
 | 
						|
  @param[in]  pBuffer         Address of a buffer to receive the data.
 | 
						|
  @param[in]  pDataLength     Number of received data bytes in the buffer.
 | 
						|
 | 
						|
  @return   Returns the address of the next free byte in the buffer.
 | 
						|
**/
 | 
						|
UINT8 *
 | 
						|
EslSocketCopyFragmentedBuffer (
 | 
						|
  IN UINT32 FragmentCount,
 | 
						|
  IN EFI_IP4_FRAGMENT_DATA * pFragmentTable,
 | 
						|
  IN size_t BufferLength,
 | 
						|
  IN UINT8 * pBuffer,
 | 
						|
  OUT size_t * pDataLength
 | 
						|
  )
 | 
						|
{
 | 
						|
  size_t BytesToCopy;
 | 
						|
  UINT32 Fragment;
 | 
						|
  UINT8 * pBufferEnd;
 | 
						|
  UINT8 * pData;
 | 
						|
 | 
						|
  DBG_ENTER ( );
 | 
						|
 | 
						|
  //
 | 
						|
  //  Validate the IP and UDP structures are identical
 | 
						|
  //
 | 
						|
  ASSERT ( OFFSET_OF ( EFI_IP4_FRAGMENT_DATA, FragmentLength )
 | 
						|
           == OFFSET_OF ( EFI_UDP4_FRAGMENT_DATA, FragmentLength ));
 | 
						|
  ASSERT ( OFFSET_OF ( EFI_IP4_FRAGMENT_DATA, FragmentBuffer )
 | 
						|
           == OFFSET_OF ( EFI_UDP4_FRAGMENT_DATA, FragmentBuffer ));
 | 
						|
 | 
						|
  //
 | 
						|
  //  Copy the received data
 | 
						|
  //
 | 
						|
  Fragment = 0;
 | 
						|
  pBufferEnd = &pBuffer [ BufferLength ];
 | 
						|
  while (( pBufferEnd > pBuffer ) && ( FragmentCount > Fragment )) {
 | 
						|
    //
 | 
						|
    //  Determine the amount of received data
 | 
						|
    //
 | 
						|
    pData = pFragmentTable[Fragment].FragmentBuffer;
 | 
						|
    BytesToCopy = pFragmentTable[Fragment].FragmentLength;
 | 
						|
    if (((size_t)( pBufferEnd - pBuffer )) < BytesToCopy ) {
 | 
						|
      BytesToCopy = pBufferEnd - pBuffer;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    //  Move the data into the buffer
 | 
						|
    //
 | 
						|
    DEBUG (( DEBUG_RX,
 | 
						|
              "0x%08x --> 0x%08x: Copy data 0x%08x bytes\r\n",
 | 
						|
              pData,
 | 
						|
              pBuffer,
 | 
						|
              BytesToCopy ));
 | 
						|
    CopyMem ( pBuffer, pData, BytesToCopy );
 | 
						|
    pBuffer += BytesToCopy;
 | 
						|
    Fragment += 1;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  //  Return the data length and the buffer address
 | 
						|
  //
 | 
						|
  *pDataLength = BufferLength - ( pBufferEnd - pBuffer );
 | 
						|
  DBG_EXIT_HEX ( pBuffer );
 | 
						|
  return pBuffer;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/** Free the socket.
 | 
						|
 | 
						|
  This routine frees the socket structure and handle resources.
 | 
						|
 | 
						|
  The ::close routine calls EslServiceFreeProtocol which then calls
 | 
						|
  this routine to free the socket context structure and close the
 | 
						|
  handle.
 | 
						|
 | 
						|
  @param[in]  pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
 | 
						|
  @param[out] pErrno          Address to receive the errno value upon completion.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS   The socket resources were returned successfully.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EslSocketFree (
 | 
						|
  IN EFI_SOCKET_PROTOCOL * pSocketProtocol,
 | 
						|
  IN int * pErrno
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_HANDLE ChildHandle;
 | 
						|
  int errno;
 | 
						|
  ESL_LAYER * pLayer;
 | 
						|
  ESL_SOCKET * pSocket;
 | 
						|
  ESL_SOCKET * pSocketPrevious;
 | 
						|
  EFI_STATUS Status;
 | 
						|
  EFI_TPL TplPrevious;
 | 
						|
 | 
						|
  DBG_ENTER ( );
 | 
						|
 | 
						|
  //
 | 
						|
  //  Assume failure
 | 
						|
  //
 | 
						|
  errno = EIO;
 | 
						|
  pSocket = NULL;
 | 
						|
  Status = EFI_INVALID_PARAMETER;
 | 
						|
 | 
						|
  //
 | 
						|
  //  Validate the socket
 | 
						|
  //
 | 
						|
  pLayer = &mEslLayer;
 | 
						|
  if ( NULL != pSocketProtocol ) {
 | 
						|
    pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
 | 
						|
 | 
						|
    //
 | 
						|
    //  Synchronize with the socket layer
 | 
						|
    //
 | 
						|
    RAISE_TPL ( TplPrevious, TPL_SOCKETS );
 | 
						|
 | 
						|
    //
 | 
						|
    //  Walk the socket list
 | 
						|
    //
 | 
						|
    pSocketPrevious = pLayer->pSocketList;
 | 
						|
    if ( NULL != pSocketPrevious ) {
 | 
						|
      if ( pSocket == pSocketPrevious ) {
 | 
						|
        //
 | 
						|
        //  Remove the socket from the head of the list
 | 
						|
        //
 | 
						|
        pLayer->pSocketList = pSocket->pNext;
 | 
						|
      }
 | 
						|
      else {
 | 
						|
        //
 | 
						|
        //  Find the socket in the middle of the list
 | 
						|
        //
 | 
						|
        while (( NULL != pSocketPrevious )
 | 
						|
          && ( pSocket != pSocketPrevious->pNext )) {
 | 
						|
          //
 | 
						|
          //  Set the next socket
 | 
						|
          //
 | 
						|
          pSocketPrevious = pSocketPrevious->pNext;
 | 
						|
        }
 | 
						|
        if ( NULL != pSocketPrevious ) {
 | 
						|
          //
 | 
						|
          //  Remove the socket from the middle of the list
 | 
						|
          //
 | 
						|
          pSocketPrevious = pSocket->pNext;
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      DEBUG (( DEBUG_ERROR | DEBUG_POOL,
 | 
						|
                "ERROR - Socket list is empty!\r\n" ));
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    //  Release the socket layer synchronization
 | 
						|
    //
 | 
						|
    RESTORE_TPL ( TplPrevious );
 | 
						|
 | 
						|
    //
 | 
						|
    //  Determine if the socket was found
 | 
						|
    //
 | 
						|
    if ( NULL != pSocketPrevious ) {
 | 
						|
      pSocket->pNext = NULL;
 | 
						|
 | 
						|
      //
 | 
						|
      //  Remove the socket protocol
 | 
						|
      //
 | 
						|
      ChildHandle = pSocket->SocketProtocol.SocketHandle;
 | 
						|
      Status = gBS->UninstallMultipleProtocolInterfaces (
 | 
						|
                ChildHandle,
 | 
						|
                &gEfiSocketProtocolGuid,
 | 
						|
                &pSocket->SocketProtocol,
 | 
						|
                NULL );
 | 
						|
      if ( !EFI_ERROR ( Status )) {
 | 
						|
        DEBUG (( DEBUG_POOL | DEBUG_INFO,
 | 
						|
                    "Removed:   gEfiSocketProtocolGuid from 0x%08x\r\n",
 | 
						|
                    ChildHandle ));
 | 
						|
 | 
						|
        //
 | 
						|
        //  Free the socket structure
 | 
						|
        //
 | 
						|
        Status = gBS->FreePool ( pSocket );
 | 
						|
        if ( !EFI_ERROR ( Status )) {
 | 
						|
          DEBUG (( DEBUG_POOL,
 | 
						|
                    "0x%08x: Free pSocket, %d bytes\r\n",
 | 
						|
                    pSocket,
 | 
						|
                    sizeof ( *pSocket )));
 | 
						|
          errno = 0;
 | 
						|
        }
 | 
						|
        else {
 | 
						|
          DEBUG (( DEBUG_ERROR | DEBUG_POOL,
 | 
						|
                    "ERROR - Failed to free pSocket 0x%08x, Status: %r\r\n",
 | 
						|
                    pSocket,
 | 
						|
                    Status ));
 | 
						|
        }
 | 
						|
      }
 | 
						|
      else {
 | 
						|
        DEBUG (( DEBUG_ERROR | DEBUG_POOL | DEBUG_INFO,
 | 
						|
                    "ERROR - Failed to remove gEfiSocketProtocolGuid from 0x%08x, Status: %r\r\n",
 | 
						|
                    ChildHandle,
 | 
						|
                    Status ));
 | 
						|
      }
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      DEBUG (( DEBUG_ERROR | DEBUG_INFO,
 | 
						|
                "ERROR - The socket was not in the socket list!\r\n" ));
 | 
						|
      Status = EFI_NOT_FOUND;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    DEBUG (( DEBUG_ERROR,
 | 
						|
              "ERROR - Invalid parameter pSocketProtocol is NULL\r\n" ));
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  //  Return the errno value if possible
 | 
						|
  //
 | 
						|
  if ( NULL != pErrno ) {
 | 
						|
    *pErrno = errno;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  //  Return the operation status
 | 
						|
  //
 | 
						|
  DBG_EXIT_STATUS ( Status );
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/** Get the local address.
 | 
						|
 | 
						|
  This routine calls the network specific layer to get the network
 | 
						|
  address of the local host connection point.
 | 
						|
 | 
						|
  The ::getsockname routine calls this routine to obtain the network
 | 
						|
  address associated with the local host connection point.
 | 
						|
 | 
						|
  @param[in]      pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
 | 
						|
  @param[out]     pAddress        Network address to receive the local system address
 | 
						|
  @param[in,out]  pAddressLength  Length of the local network address structure
 | 
						|
  @param[out]     pErrno          Address to receive the errno value upon completion.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS - Local address successfully returned
 | 
						|
 **/
 | 
						|
EFI_STATUS
 | 
						|
EslSocketGetLocalAddress (
 | 
						|
  IN EFI_SOCKET_PROTOCOL * pSocketProtocol,
 | 
						|
  OUT struct sockaddr * pAddress,
 | 
						|
  IN OUT socklen_t * pAddressLength,
 | 
						|
  IN int * pErrno
 | 
						|
  )
 | 
						|
{
 | 
						|
  socklen_t LengthInBytes;
 | 
						|
  ESL_PORT * pPort;
 | 
						|
  ESL_SOCKET * pSocket;
 | 
						|
  EFI_STATUS Status;
 | 
						|
  EFI_TPL TplPrevious;
 | 
						|
 | 
						|
  DBG_ENTER ( );
 | 
						|
 | 
						|
  //
 | 
						|
  //  Assume success
 | 
						|
  //
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
 | 
						|
  //
 | 
						|
  //  Validate the socket
 | 
						|
  //
 | 
						|
  pSocket = NULL;
 | 
						|
  if ( NULL != pSocketProtocol ) {
 | 
						|
    pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
 | 
						|
 | 
						|
    //
 | 
						|
    //  Verify the socket state
 | 
						|
    //
 | 
						|
    EslSocketIsConfigured ( pSocket );
 | 
						|
    if ( pSocket->bAddressSet ) {
 | 
						|
      //
 | 
						|
      //  Verify the address buffer and length address
 | 
						|
      //
 | 
						|
      if (( NULL != pAddress ) && ( NULL != pAddressLength )) {
 | 
						|
        //
 | 
						|
        //  Verify the API
 | 
						|
        //
 | 
						|
        if ( NULL == pSocket->pApi->pfnLocalAddrGet ) {
 | 
						|
          Status = EFI_UNSUPPORTED;
 | 
						|
          pSocket->errno = ENOTSUP;
 | 
						|
        }
 | 
						|
        else {
 | 
						|
          //
 | 
						|
          //  Synchronize with the socket layer
 | 
						|
          //
 | 
						|
          RAISE_TPL ( TplPrevious, TPL_SOCKETS );
 | 
						|
 | 
						|
          //
 | 
						|
          //  Verify that there is just a single connection
 | 
						|
          //
 | 
						|
          pPort = pSocket->pPortList;
 | 
						|
          if ( NULL != pPort ) {
 | 
						|
            //
 | 
						|
            //  Verify the address length
 | 
						|
            //
 | 
						|
            LengthInBytes = pSocket->pApi->AddressLength;
 | 
						|
            if (( LengthInBytes <= *pAddressLength )
 | 
						|
              && ( 255 >= LengthInBytes )) {
 | 
						|
              //
 | 
						|
              //  Return the local address and address length
 | 
						|
              //
 | 
						|
              ZeroMem ( pAddress, LengthInBytes );
 | 
						|
              pAddress->sa_len = (uint8_t)LengthInBytes;
 | 
						|
              *pAddressLength = pAddress->sa_len;
 | 
						|
              pSocket->pApi->pfnLocalAddrGet ( pPort, pAddress );
 | 
						|
              pSocket->errno = 0;
 | 
						|
              Status = EFI_SUCCESS;
 | 
						|
            }
 | 
						|
            else {
 | 
						|
              pSocket->errno = EINVAL;
 | 
						|
              Status = EFI_INVALID_PARAMETER;
 | 
						|
            }
 | 
						|
          }
 | 
						|
          else {
 | 
						|
            pSocket->errno = ENOTCONN;
 | 
						|
            Status = EFI_NOT_STARTED;
 | 
						|
          }
 | 
						|
 | 
						|
          //
 | 
						|
          //  Release the socket layer synchronization
 | 
						|
          //
 | 
						|
          RESTORE_TPL ( TplPrevious );
 | 
						|
        }
 | 
						|
      }
 | 
						|
      else {
 | 
						|
        pSocket->errno = EINVAL;
 | 
						|
        Status = EFI_INVALID_PARAMETER;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      //
 | 
						|
      //  Address not set
 | 
						|
      //
 | 
						|
      Status = EFI_NOT_STARTED;
 | 
						|
      pSocket->errno = EADDRNOTAVAIL;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  //  Return the operation status
 | 
						|
  //
 | 
						|
  if ( NULL != pErrno ) {
 | 
						|
    if ( NULL != pSocket ) {
 | 
						|
      *pErrno = pSocket->errno;
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      Status = EFI_INVALID_PARAMETER;
 | 
						|
      *pErrno = ENOTSOCK;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  DBG_EXIT_STATUS ( Status );
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/** Get the peer address.
 | 
						|
 | 
						|
  This routine calls the network specific layer to get the remote
 | 
						|
  system connection point.
 | 
						|
 | 
						|
  The ::getpeername routine calls this routine to obtain the network
 | 
						|
  address of the remote connection point.
 | 
						|
 | 
						|
  @param[in]      pSocketProtocol   Address of an ::EFI_SOCKET_PROTOCOL structure.
 | 
						|
  @param[out]     pAddress          Network address to receive the remote system address
 | 
						|
  @param[in,out]  pAddressLength    Length of the remote network address structure
 | 
						|
  @param[out]     pErrno            Address to receive the errno value upon completion.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS - Remote address successfully returned
 | 
						|
 **/
 | 
						|
EFI_STATUS
 | 
						|
EslSocketGetPeerAddress (
 | 
						|
  IN EFI_SOCKET_PROTOCOL * pSocketProtocol,
 | 
						|
  OUT struct sockaddr * pAddress,
 | 
						|
  IN OUT socklen_t * pAddressLength,
 | 
						|
  IN int * pErrno
 | 
						|
  )
 | 
						|
{
 | 
						|
  socklen_t LengthInBytes;
 | 
						|
  ESL_PORT * pPort;
 | 
						|
  ESL_SOCKET * pSocket;
 | 
						|
  EFI_STATUS Status;
 | 
						|
  EFI_TPL TplPrevious;
 | 
						|
 | 
						|
  DBG_ENTER ( );
 | 
						|
 | 
						|
  //
 | 
						|
  //  Assume success
 | 
						|
  //
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
 | 
						|
  //
 | 
						|
  //  Validate the socket
 | 
						|
  //
 | 
						|
  pSocket = NULL;
 | 
						|
  if ( NULL != pSocketProtocol ) {
 | 
						|
    pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
 | 
						|
 | 
						|
    //
 | 
						|
    //  Verify the socket state
 | 
						|
    //
 | 
						|
    Status = EslSocketIsConfigured ( pSocket );
 | 
						|
    if ( !EFI_ERROR ( Status )) {
 | 
						|
      //
 | 
						|
      //  Verify the API
 | 
						|
      //
 | 
						|
      if ( NULL == pSocket->pApi->pfnRemoteAddrGet ) {
 | 
						|
        Status = EFI_UNSUPPORTED;
 | 
						|
        pSocket->errno = ENOTSUP;
 | 
						|
      }
 | 
						|
      else {
 | 
						|
        //
 | 
						|
        //  Verify the address buffer and length address
 | 
						|
        //
 | 
						|
        if (( NULL != pAddress ) && ( NULL != pAddressLength )) {
 | 
						|
          //
 | 
						|
          //  Verify the socket state
 | 
						|
          //
 | 
						|
          if ( SOCKET_STATE_CONNECTED == pSocket->State ) {
 | 
						|
            //
 | 
						|
            //  Synchronize with the socket layer
 | 
						|
            //
 | 
						|
            RAISE_TPL ( TplPrevious, TPL_SOCKETS );
 | 
						|
 | 
						|
            //
 | 
						|
            //  Verify that there is just a single connection
 | 
						|
            //
 | 
						|
            pPort = pSocket->pPortList;
 | 
						|
            if (( NULL != pPort ) && ( NULL == pPort->pLinkSocket )) {
 | 
						|
              //
 | 
						|
              //  Verify the address length
 | 
						|
              //
 | 
						|
              LengthInBytes = pSocket->pApi->AddressLength;
 | 
						|
              if ( LengthInBytes <= *pAddressLength ) {
 | 
						|
                //
 | 
						|
                //  Return the local address
 | 
						|
                //
 | 
						|
                ZeroMem ( pAddress, LengthInBytes );
 | 
						|
                pAddress->sa_len = (uint8_t)LengthInBytes;
 | 
						|
                *pAddressLength = pAddress->sa_len;
 | 
						|
                pSocket->pApi->pfnRemoteAddrGet ( pPort, pAddress );
 | 
						|
                pSocket->errno = 0;
 | 
						|
                Status = EFI_SUCCESS;
 | 
						|
              }
 | 
						|
              else {
 | 
						|
                pSocket->errno = EINVAL;
 | 
						|
                Status = EFI_INVALID_PARAMETER;
 | 
						|
              }
 | 
						|
            }
 | 
						|
            else {
 | 
						|
              pSocket->errno = ENOTCONN;
 | 
						|
              Status = EFI_NOT_STARTED;
 | 
						|
            }
 | 
						|
 | 
						|
            //
 | 
						|
            //  Release the socket layer synchronization
 | 
						|
            //
 | 
						|
            RESTORE_TPL ( TplPrevious );
 | 
						|
          }
 | 
						|
          else {
 | 
						|
            pSocket->errno = ENOTCONN;
 | 
						|
            Status = EFI_NOT_STARTED;
 | 
						|
          }
 | 
						|
        }
 | 
						|
        else {
 | 
						|
          pSocket->errno = EINVAL;
 | 
						|
          Status = EFI_INVALID_PARAMETER;
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  //  Return the operation status
 | 
						|
  //
 | 
						|
  if ( NULL != pErrno ) {
 | 
						|
    if ( NULL != pSocket ) {
 | 
						|
      *pErrno = pSocket->errno;
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      Status = EFI_INVALID_PARAMETER;
 | 
						|
      *pErrno = ENOTSOCK;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  DBG_EXIT_STATUS ( Status );
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/** Free the ESL_IO_MGMT event and structure.
 | 
						|
 | 
						|
  This support routine walks the free list to close the event in
 | 
						|
  the ESL_IO_MGMT structure and remove the structure from the free
 | 
						|
  list.
 | 
						|
 | 
						|
  See the \ref TransmitEngine section.
 | 
						|
 | 
						|
  @param[in]  pPort         Address of an ::ESL_PORT structure
 | 
						|
  @param[in]  ppFreeQueue   Address of the free queue head
 | 
						|
  @param[in]  DebugFlags    Flags for debug messages
 | 
						|
  @param[in]  pEventName    Zero terminated string containing the event name
 | 
						|
 | 
						|
  @retval EFI_SUCCESS - The structures were properly initialized
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EslSocketIoFree (
 | 
						|
  IN ESL_PORT * pPort,
 | 
						|
  IN ESL_IO_MGMT ** ppFreeQueue,
 | 
						|
  IN UINTN DebugFlags,
 | 
						|
  IN CHAR8 * pEventName
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT8 * pBuffer;
 | 
						|
  EFI_EVENT * pEvent;
 | 
						|
  ESL_IO_MGMT * pIo;
 | 
						|
  ESL_SOCKET * pSocket;
 | 
						|
  EFI_STATUS Status;
 | 
						|
 | 
						|
  DBG_ENTER ( );
 | 
						|
 | 
						|
  //
 | 
						|
  //  Assume success
 | 
						|
  //
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
 | 
						|
  //
 | 
						|
  //  Walk the list of IO structures
 | 
						|
  //
 | 
						|
  pSocket = pPort->pSocket;
 | 
						|
  while ( *ppFreeQueue ) {
 | 
						|
    //
 | 
						|
    //  Free the event for this structure
 | 
						|
    //
 | 
						|
    pIo = *ppFreeQueue;
 | 
						|
    pBuffer = (UINT8 *)pIo;
 | 
						|
    pBuffer = &pBuffer[ pSocket->TxTokenEventOffset ];
 | 
						|
    pEvent = (EFI_EVENT *)pBuffer;
 | 
						|
    Status = gBS->CloseEvent ( *pEvent );
 | 
						|
    if ( EFI_ERROR ( Status )) {
 | 
						|
      DEBUG (( DEBUG_ERROR | DebugFlags,
 | 
						|
                "ERROR - Failed to close the %a event, Status: %r\r\n",
 | 
						|
                pEventName,
 | 
						|
                Status ));
 | 
						|
      pSocket->errno = ENOMEM;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    DEBUG (( DebugFlags,
 | 
						|
              "0x%08x: Closed %a event 0x%08x\r\n",
 | 
						|
              pIo,
 | 
						|
              pEventName,
 | 
						|
              *pEvent ));
 | 
						|
 | 
						|
    //
 | 
						|
    //  Remove this structure from the queue
 | 
						|
    //
 | 
						|
    *ppFreeQueue = pIo->pNext;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  //  Return the operation status
 | 
						|
  //
 | 
						|
  DBG_EXIT_STATUS ( Status );
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/** Initialize the ESL_IO_MGMT structures.
 | 
						|
 | 
						|
  This support routine initializes the ESL_IO_MGMT structure and
 | 
						|
  places them on to a free list.
 | 
						|
 | 
						|
  This routine is called by ::EslSocketPortAllocate routines to prepare
 | 
						|
  the transmit engines.  See the \ref TransmitEngine section.
 | 
						|
 | 
						|
  @param[in]        pPort         Address of an ::ESL_PORT structure
 | 
						|
  @param[in, out]   ppIo          Address containing the first structure address.  Upon
 | 
						|
                                  return this buffer contains the next structure address.
 | 
						|
  @param[in]        TokenCount    Number of structures to initialize
 | 
						|
  @param[in]        ppFreeQueue   Address of the free queue head
 | 
						|
  @param[in]        DebugFlags    Flags for debug messages
 | 
						|
  @param[in]        pEventName    Zero terminated string containing the event name
 | 
						|
  @param[in]        pfnCompletion Completion routine address
 | 
						|
 | 
						|
  @retval EFI_SUCCESS - The structures were properly initialized
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EslSocketIoInit (
 | 
						|
  IN ESL_PORT * pPort,
 | 
						|
  IN ESL_IO_MGMT ** ppIo,
 | 
						|
  IN UINTN TokenCount,
 | 
						|
  IN ESL_IO_MGMT ** ppFreeQueue,
 | 
						|
  IN UINTN DebugFlags,
 | 
						|
  IN CHAR8 * pEventName,
 | 
						|
  IN PFN_API_IO_COMPLETE pfnCompletion
 | 
						|
  )
 | 
						|
{
 | 
						|
  ESL_IO_MGMT * pEnd;
 | 
						|
  EFI_EVENT * pEvent;
 | 
						|
  ESL_IO_MGMT * pIo;
 | 
						|
  ESL_SOCKET * pSocket;
 | 
						|
  EFI_STATUS Status;
 | 
						|
 | 
						|
  DBG_ENTER ( );
 | 
						|
 | 
						|
  //
 | 
						|
  //  Assume success
 | 
						|
  //
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
 | 
						|
  //
 | 
						|
  //  Walk the list of IO structures
 | 
						|
  //
 | 
						|
  pSocket = pPort->pSocket;
 | 
						|
  pIo = *ppIo;
 | 
						|
  pEnd = &pIo [ TokenCount ];
 | 
						|
  while ( pEnd > pIo ) {
 | 
						|
    //
 | 
						|
    //  Initialize the IO structure
 | 
						|
    //
 | 
						|
    pIo->pPort = pPort;
 | 
						|
    pIo->pPacket = NULL;
 | 
						|
 | 
						|
    //
 | 
						|
    //  Allocate the event for this structure
 | 
						|
    //
 | 
						|
    pEvent = (EFI_EVENT *)&(((UINT8 *)pIo)[ pSocket->TxTokenEventOffset ]);
 | 
						|
    Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL,
 | 
						|
                                TPL_SOCKETS,
 | 
						|
                                (EFI_EVENT_NOTIFY)pfnCompletion,
 | 
						|
                                pIo,
 | 
						|
                                pEvent );
 | 
						|
    if ( EFI_ERROR ( Status )) {
 | 
						|
      DEBUG (( DEBUG_ERROR | DebugFlags,
 | 
						|
                "ERROR - Failed to create the %a event, Status: %r\r\n",
 | 
						|
                pEventName,
 | 
						|
                Status ));
 | 
						|
      pSocket->errno = ENOMEM;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    DEBUG (( DebugFlags,
 | 
						|
              "0x%08x: Created %a event 0x%08x\r\n",
 | 
						|
              pIo,
 | 
						|
              pEventName,
 | 
						|
              *pEvent ));
 | 
						|
 | 
						|
    //
 | 
						|
    //  Add this structure to the queue
 | 
						|
    //
 | 
						|
    pIo->pNext = *ppFreeQueue;
 | 
						|
    *ppFreeQueue = pIo;
 | 
						|
 | 
						|
    //
 | 
						|
    //  Set the next structure
 | 
						|
    //
 | 
						|
    pIo += 1;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  //  Save the next structure
 | 
						|
  //
 | 
						|
  *ppIo = pIo;
 | 
						|
 | 
						|
  //
 | 
						|
  //  Return the operation status
 | 
						|
  //
 | 
						|
  DBG_EXIT_STATUS ( Status );
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/** Determine if the socket is configured.
 | 
						|
 | 
						|
  This support routine is called to determine if the socket if the
 | 
						|
  configuration call was made to the network layer.  The following
 | 
						|
  routines call this routine to verify that they may be successful
 | 
						|
  in their operations:
 | 
						|
  <ul>
 | 
						|
    <li>::EslSocketGetLocalAddress</li>
 | 
						|
    <li>::EslSocketGetPeerAddress</li>
 | 
						|
    <li>::EslSocketPoll</li>
 | 
						|
    <li>::EslSocketReceive</li>
 | 
						|
    <li>::EslSocketTransmit</li>
 | 
						|
  </ul>
 | 
						|
 | 
						|
  @param[in]  pSocket       Address of an ::ESL_SOCKET structure
 | 
						|
 | 
						|
  @retval EFI_SUCCESS - The socket is configured
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EslSocketIsConfigured (
 | 
						|
  IN ESL_SOCKET * pSocket
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS Status;
 | 
						|
  EFI_TPL TplPrevious;
 | 
						|
 | 
						|
  //
 | 
						|
  //  Assume success
 | 
						|
  //
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
 | 
						|
  //
 | 
						|
  //  Verify the socket state
 | 
						|
  //
 | 
						|
  if ( !pSocket->bConfigured ) {
 | 
						|
    DBG_ENTER ( );
 | 
						|
 | 
						|
    //
 | 
						|
    //  Verify the API
 | 
						|
    //
 | 
						|
    if ( NULL == pSocket->pApi->pfnIsConfigured ) {
 | 
						|
      Status = EFI_UNSUPPORTED;
 | 
						|
      pSocket->errno = ENOTSUP;
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      //
 | 
						|
      //  Synchronize with the socket layer
 | 
						|
      //
 | 
						|
      RAISE_TPL ( TplPrevious, TPL_SOCKETS );
 | 
						|
 | 
						|
      //
 | 
						|
      //  Determine if the socket is configured
 | 
						|
      //
 | 
						|
      Status = pSocket->pApi->pfnIsConfigured ( pSocket );
 | 
						|
 | 
						|
      //
 | 
						|
      //  Release the socket layer synchronization
 | 
						|
      //
 | 
						|
      RESTORE_TPL ( TplPrevious );
 | 
						|
 | 
						|
      //
 | 
						|
      //  Set errno if a failure occurs
 | 
						|
      //
 | 
						|
      if ( EFI_ERROR ( Status )) {
 | 
						|
        pSocket->errno = EADDRNOTAVAIL;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    DBG_EXIT_STATUS ( Status );
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  //  Return the configuration status
 | 
						|
  //
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/** Establish the known port to listen for network connections.
 | 
						|
 | 
						|
  This routine calls into the network protocol layer to establish
 | 
						|
  a handler that is called upon connection completion.  The handler
 | 
						|
  is responsible for inserting the connection into the FIFO.
 | 
						|
 | 
						|
  The ::listen routine indirectly calls this routine to place the
 | 
						|
  socket into a state that enables connection attempts.  Connections
 | 
						|
  are placed in a FIFO that is serviced by the application.  The
 | 
						|
  application calls the ::accept (::EslSocketAccept) routine to
 | 
						|
  remove the next connection from the FIFO and get the associated
 | 
						|
  socket and address.
 | 
						|
 | 
						|
  @param[in]  pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
 | 
						|
  @param[in]  Backlog         Backlog specifies the maximum FIFO depth for
 | 
						|
                              the connections waiting for the application
 | 
						|
                              to call accept.  Connection attempts received
 | 
						|
                              while the queue is full are refused.
 | 
						|
  @param[out] pErrno          Address to receive the errno value upon completion.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS - Socket successfully created
 | 
						|
  @retval Other - Failed to enable the socket for listen
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EslSocketListen (
 | 
						|
  IN EFI_SOCKET_PROTOCOL * pSocketProtocol,
 | 
						|
  IN INT32 Backlog,
 | 
						|
  OUT int * pErrno
 | 
						|
  )
 | 
						|
{
 | 
						|
  ESL_SOCKET * pSocket;
 | 
						|
  EFI_STATUS Status;
 | 
						|
  EFI_STATUS TempStatus;
 | 
						|
  EFI_TPL TplPrevious;
 | 
						|
 | 
						|
  DBG_ENTER ( );
 | 
						|
 | 
						|
  //
 | 
						|
  //  Assume success
 | 
						|
  //
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
 | 
						|
  //
 | 
						|
  //  Validate the socket
 | 
						|
  //
 | 
						|
  pSocket = NULL;
 | 
						|
  if ( NULL != pSocketProtocol ) {
 | 
						|
    pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
 | 
						|
 | 
						|
    //
 | 
						|
    //  Verify the API
 | 
						|
    //
 | 
						|
    if ( NULL == pSocket->pApi->pfnListen ) {
 | 
						|
      Status = EFI_UNSUPPORTED;
 | 
						|
      pSocket->errno = ENOTSUP;
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      //
 | 
						|
      //  Assume success
 | 
						|
      //
 | 
						|
      pSocket->Status = EFI_SUCCESS;
 | 
						|
      pSocket->errno = 0;
 | 
						|
 | 
						|
      //
 | 
						|
      //  Verify that the bind operation was successful
 | 
						|
      //
 | 
						|
      if ( SOCKET_STATE_BOUND == pSocket->State ) {
 | 
						|
        //
 | 
						|
        //  Synchronize with the socket layer
 | 
						|
        //
 | 
						|
        RAISE_TPL ( TplPrevious, TPL_SOCKETS );
 | 
						|
 | 
						|
        //
 | 
						|
        //  Create the event for SocketAccept completion
 | 
						|
        //
 | 
						|
        Status = gBS->CreateEvent ( 0,
 | 
						|
                                    TPL_SOCKETS,
 | 
						|
                                    NULL,
 | 
						|
                                    NULL,
 | 
						|
                                    &pSocket->WaitAccept );
 | 
						|
        if ( !EFI_ERROR ( Status )) {
 | 
						|
          DEBUG (( DEBUG_POOL,
 | 
						|
                    "0x%08x: Created WaitAccept event\r\n",
 | 
						|
                    pSocket->WaitAccept ));
 | 
						|
          //
 | 
						|
          //  Set the maximum FIFO depth
 | 
						|
          //
 | 
						|
          if ( 0 >= Backlog ) {
 | 
						|
            Backlog = MAX_PENDING_CONNECTIONS;
 | 
						|
          }
 | 
						|
          else {
 | 
						|
            if ( SOMAXCONN < Backlog ) {
 | 
						|
              Backlog = SOMAXCONN;
 | 
						|
            }
 | 
						|
            else {
 | 
						|
              pSocket->MaxFifoDepth = Backlog;
 | 
						|
            }
 | 
						|
          }
 | 
						|
 | 
						|
          //
 | 
						|
          //  Initiate the connection attempt listen
 | 
						|
          //
 | 
						|
          Status = pSocket->pApi->pfnListen ( pSocket );
 | 
						|
 | 
						|
          //
 | 
						|
          //  Place the socket in the listen state if successful
 | 
						|
          //
 | 
						|
          if ( !EFI_ERROR ( Status )) {
 | 
						|
            pSocket->State = SOCKET_STATE_LISTENING;
 | 
						|
            pSocket->bListenCalled = TRUE;
 | 
						|
          }
 | 
						|
          else {
 | 
						|
            //
 | 
						|
            //  Not waiting for SocketAccept to complete
 | 
						|
            //
 | 
						|
            TempStatus = gBS->CloseEvent ( pSocket->WaitAccept );
 | 
						|
            if ( !EFI_ERROR ( TempStatus )) {
 | 
						|
              DEBUG (( DEBUG_POOL,
 | 
						|
                        "0x%08x: Closed WaitAccept event\r\n",
 | 
						|
                        pSocket->WaitAccept ));
 | 
						|
              pSocket->WaitAccept = NULL;
 | 
						|
            }
 | 
						|
            else {
 | 
						|
              DEBUG (( DEBUG_ERROR | DEBUG_POOL,
 | 
						|
                        "ERROR - Failed to close WaitAccept event, Status: %r\r\n",
 | 
						|
                        TempStatus ));
 | 
						|
              ASSERT ( EFI_SUCCESS == TempStatus );
 | 
						|
            }
 | 
						|
          }
 | 
						|
        }
 | 
						|
        else {
 | 
						|
          DEBUG (( DEBUG_ERROR | DEBUG_LISTEN,
 | 
						|
                    "ERROR - Failed to create the WaitAccept event, Status: %r\r\n",
 | 
						|
                    Status ));
 | 
						|
          pSocket->errno = ENOMEM;
 | 
						|
        }
 | 
						|
 | 
						|
        //
 | 
						|
        //  Release the socket layer synchronization
 | 
						|
        //
 | 
						|
        RESTORE_TPL ( TplPrevious );
 | 
						|
      }
 | 
						|
      else {
 | 
						|
        DEBUG (( DEBUG_ERROR | DEBUG_LISTEN,
 | 
						|
                  "ERROR - Bind operation must be performed first!\r\n" ));
 | 
						|
        pSocket->errno = ( SOCKET_STATE_NOT_CONFIGURED == pSocket->State ) ? EDESTADDRREQ
 | 
						|
                                                                           : EINVAL;
 | 
						|
        Status = EFI_NO_MAPPING;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  //  Return the operation status
 | 
						|
  //
 | 
						|
  if ( NULL != pErrno ) {
 | 
						|
    if ( NULL != pSocket ) {
 | 
						|
      *pErrno = pSocket->errno;
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      Status = EFI_INVALID_PARAMETER;
 | 
						|
      *pErrno = ENOTSOCK;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  DBG_EXIT_STATUS ( Status );
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/** Get the socket options.
 | 
						|
 | 
						|
  This routine handles the socket level options and passes the
 | 
						|
  others to the network specific layer.
 | 
						|
 | 
						|
  The ::getsockopt routine calls this routine to retrieve the
 | 
						|
  socket options one at a time by name.
 | 
						|
 | 
						|
  @param[in]      pSocketProtocol   Address of an ::EFI_SOCKET_PROTOCOL structure.
 | 
						|
  @param[in]      level             Option protocol level
 | 
						|
  @param[in]      OptionName        Name of the option
 | 
						|
  @param[out]     pOptionValue      Buffer to receive the option value
 | 
						|
  @param[in,out]  pOptionLength     Length of the buffer in bytes,
 | 
						|
                                    upon return length of the option value in bytes
 | 
						|
  @param[out]     pErrno            Address to receive the errno value upon completion.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS - Socket data successfully received
 | 
						|
 **/
 | 
						|
EFI_STATUS
 | 
						|
EslSocketOptionGet (
 | 
						|
  IN EFI_SOCKET_PROTOCOL * pSocketProtocol,
 | 
						|
  IN int level,
 | 
						|
  IN int OptionName,
 | 
						|
  OUT void * __restrict pOptionValue,
 | 
						|
  IN OUT socklen_t * __restrict pOptionLength,
 | 
						|
  IN int * pErrno
 | 
						|
  )
 | 
						|
{
 | 
						|
  int errno;
 | 
						|
  socklen_t LengthInBytes;
 | 
						|
  socklen_t MaxBytes;
 | 
						|
  CONST UINT8 * pOptionData;
 | 
						|
  ESL_SOCKET * pSocket;
 | 
						|
  EFI_STATUS Status;
 | 
						|
 | 
						|
  DBG_ENTER ( );
 | 
						|
 | 
						|
  //
 | 
						|
  //  Assume failure
 | 
						|
  //
 | 
						|
  errno = EINVAL;
 | 
						|
  Status = EFI_INVALID_PARAMETER;
 | 
						|
 | 
						|
  //
 | 
						|
  //  Validate the socket
 | 
						|
  //
 | 
						|
  pSocket = NULL;
 | 
						|
  if ( NULL == pSocketProtocol ) {
 | 
						|
    DEBUG (( DEBUG_OPTION, "ERROR - pSocketProtocol is NULL!\r\n" ));
 | 
						|
  }
 | 
						|
  else if ( NULL == pOptionValue ) {
 | 
						|
    DEBUG (( DEBUG_OPTION, "ERROR - No option buffer specified\r\n" ));
 | 
						|
  }
 | 
						|
  else if ( NULL == pOptionLength ) {
 | 
						|
    DEBUG (( DEBUG_OPTION, "ERROR - Option length not specified!\r\n" ));
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
 | 
						|
    LengthInBytes = 0;
 | 
						|
    MaxBytes = *pOptionLength;
 | 
						|
    pOptionData = NULL;
 | 
						|
    switch ( level ) {
 | 
						|
    default:
 | 
						|
      //
 | 
						|
      //  See if the protocol will handle the option
 | 
						|
      //
 | 
						|
      if ( NULL != pSocket->pApi->pfnOptionGet ) {
 | 
						|
        if ( pSocket->pApi->DefaultProtocol == level ) {
 | 
						|
          Status = pSocket->pApi->pfnOptionGet ( pSocket,
 | 
						|
                                                 OptionName,
 | 
						|
                                                 (CONST void ** __restrict)&pOptionData,
 | 
						|
                                                 &LengthInBytes );
 | 
						|
          errno = pSocket->errno;
 | 
						|
          break;
 | 
						|
        }
 | 
						|
        else {
 | 
						|
          //
 | 
						|
          //  Protocol not supported
 | 
						|
          //
 | 
						|
          DEBUG (( DEBUG_OPTION,
 | 
						|
                    "ERROR - The socket does not support this protocol!\r\n" ));
 | 
						|
        }
 | 
						|
      }
 | 
						|
      else {
 | 
						|
        //
 | 
						|
        //  Protocol level not supported
 | 
						|
        //
 | 
						|
        DEBUG (( DEBUG_OPTION,
 | 
						|
                  "ERROR - %a does not support any options!\r\n",
 | 
						|
                  pSocket->pApi->pName ));
 | 
						|
      }
 | 
						|
      errno = ENOPROTOOPT;
 | 
						|
      Status = EFI_INVALID_PARAMETER;
 | 
						|
      break;
 | 
						|
 | 
						|
    case SOL_SOCKET:
 | 
						|
      switch ( OptionName ) {
 | 
						|
      default:
 | 
						|
        //
 | 
						|
        //  Socket option not supported
 | 
						|
        //
 | 
						|
        DEBUG (( DEBUG_INFO | DEBUG_OPTION, "ERROR - Invalid socket option!\r\n" ));
 | 
						|
        errno = EINVAL;
 | 
						|
        Status = EFI_INVALID_PARAMETER;
 | 
						|
        break;
 | 
						|
 | 
						|
      case SO_ACCEPTCONN:
 | 
						|
        //
 | 
						|
        //  Return the listen flag
 | 
						|
        //
 | 
						|
        pOptionData = (CONST UINT8 *)&pSocket->bListenCalled;
 | 
						|
        LengthInBytes = sizeof ( pSocket->bListenCalled );
 | 
						|
        break;
 | 
						|
 | 
						|
      case SO_DEBUG:
 | 
						|
        //
 | 
						|
        //  Return the debug flags
 | 
						|
        //
 | 
						|
        pOptionData = (CONST UINT8 *)&pSocket->bOobInLine;
 | 
						|
        LengthInBytes = sizeof ( pSocket->bOobInLine );
 | 
						|
        break;
 | 
						|
 | 
						|
      case SO_OOBINLINE:
 | 
						|
        //
 | 
						|
        //  Return the out-of-band inline flag
 | 
						|
        //
 | 
						|
        pOptionData = (CONST UINT8 *)&pSocket->bOobInLine;
 | 
						|
        LengthInBytes = sizeof ( pSocket->bOobInLine );
 | 
						|
        break;
 | 
						|
 | 
						|
      case SO_RCVTIMEO:
 | 
						|
        //
 | 
						|
        //  Return the receive timeout
 | 
						|
        //
 | 
						|
        pOptionData = (CONST UINT8 *)&pSocket->RxTimeout;
 | 
						|
        LengthInBytes = sizeof ( pSocket->RxTimeout );
 | 
						|
        break;
 | 
						|
 | 
						|
      case SO_RCVBUF:
 | 
						|
        //
 | 
						|
        //  Return the maximum receive buffer size
 | 
						|
        //
 | 
						|
        pOptionData = (CONST UINT8 *)&pSocket->MaxRxBuf;
 | 
						|
        LengthInBytes = sizeof ( pSocket->MaxRxBuf );
 | 
						|
        break;
 | 
						|
 | 
						|
      case SO_REUSEADDR:
 | 
						|
        //
 | 
						|
        //  Return the address reuse flag
 | 
						|
        //
 | 
						|
        pOptionData = (UINT8 *)&pSocket->bReUseAddr;
 | 
						|
        LengthInBytes = sizeof ( pSocket->bReUseAddr );
 | 
						|
        break;
 | 
						|
 | 
						|
      case SO_SNDBUF:
 | 
						|
        //
 | 
						|
        //  Return the maximum transmit buffer size
 | 
						|
        //
 | 
						|
        pOptionData = (CONST UINT8 *)&pSocket->MaxTxBuf;
 | 
						|
        LengthInBytes = sizeof ( pSocket->MaxTxBuf );
 | 
						|
        break;
 | 
						|
 | 
						|
      case SO_TYPE:
 | 
						|
        //
 | 
						|
        //  Return the socket type
 | 
						|
        //
 | 
						|
        pOptionData = (CONST UINT8 *)&pSocket->Type;
 | 
						|
        LengthInBytes = sizeof ( pSocket->Type );
 | 
						|
        break;
 | 
						|
      }
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    //  Return the option length
 | 
						|
    //
 | 
						|
    *pOptionLength = LengthInBytes;
 | 
						|
 | 
						|
    //
 | 
						|
    //  Determine if the option is present
 | 
						|
    //
 | 
						|
    if ( 0 != LengthInBytes ) {
 | 
						|
      //
 | 
						|
      //  Silently truncate the value length
 | 
						|
      //
 | 
						|
      if ( LengthInBytes > MaxBytes ) {
 | 
						|
        DEBUG (( DEBUG_OPTION,
 | 
						|
                  "INFO - Truncating option from %d to %d bytes\r\n",
 | 
						|
                  LengthInBytes,
 | 
						|
                  MaxBytes ));
 | 
						|
        LengthInBytes = MaxBytes;
 | 
						|
      }
 | 
						|
 | 
						|
      //
 | 
						|
      //  Return the value
 | 
						|
      //
 | 
						|
      CopyMem ( pOptionValue, pOptionData, LengthInBytes );
 | 
						|
 | 
						|
      //
 | 
						|
      //  Zero fill any remaining space
 | 
						|
      //
 | 
						|
      if ( LengthInBytes < MaxBytes ) {
 | 
						|
        ZeroMem ( &((UINT8 *)pOptionValue)[LengthInBytes], MaxBytes - LengthInBytes );
 | 
						|
      }
 | 
						|
      errno = 0;
 | 
						|
      Status = EFI_SUCCESS;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  //  Return the operation status
 | 
						|
  //
 | 
						|
  if ( NULL != pErrno ) {
 | 
						|
    *pErrno = errno;
 | 
						|
  }
 | 
						|
  DBG_EXIT_STATUS ( Status );
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/** Set the socket options.
 | 
						|
 | 
						|
  This routine handles the socket level options and passes the
 | 
						|
  others to the network specific layer.
 | 
						|
 | 
						|
  The ::setsockopt routine calls this routine to adjust the socket
 | 
						|
  options one at a time by name.
 | 
						|
 | 
						|
  @param[in]  pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
 | 
						|
  @param[in]  level           Option protocol level
 | 
						|
  @param[in]  OptionName      Name of the option
 | 
						|
  @param[in]  pOptionValue    Buffer containing the option value
 | 
						|
  @param[in]  OptionLength    Length of the buffer in bytes
 | 
						|
  @param[out] pErrno          Address to receive the errno value upon completion.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS - Option successfully set
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EslSocketOptionSet (
 | 
						|
  IN EFI_SOCKET_PROTOCOL * pSocketProtocol,
 | 
						|
  IN int level,
 | 
						|
  IN int OptionName,
 | 
						|
  IN CONST void * pOptionValue,
 | 
						|
  IN socklen_t OptionLength,
 | 
						|
  IN int * pErrno
 | 
						|
  )
 | 
						|
{
 | 
						|
  BOOLEAN bTrueFalse;
 | 
						|
  int errno;
 | 
						|
  socklen_t LengthInBytes;
 | 
						|
  UINT8 * pOptionData;
 | 
						|
  ESL_SOCKET * pSocket;
 | 
						|
  EFI_STATUS Status;
 | 
						|
 | 
						|
  DBG_ENTER ( );
 | 
						|
 | 
						|
  //
 | 
						|
  //  Assume failure
 | 
						|
  //
 | 
						|
  errno = EINVAL;
 | 
						|
  Status = EFI_INVALID_PARAMETER;
 | 
						|
 | 
						|
  //
 | 
						|
  //  Validate the socket
 | 
						|
  //
 | 
						|
  pSocket = NULL;
 | 
						|
  if ( NULL == pSocketProtocol ) {
 | 
						|
    DEBUG (( DEBUG_OPTION, "ERROR - pSocketProtocol is NULL!\r\n" ));
 | 
						|
  }
 | 
						|
  else if ( NULL == pOptionValue ) {
 | 
						|
    DEBUG (( DEBUG_OPTION, "ERROR - No option buffer specified\r\n" ));
 | 
						|
  }
 | 
						|
  else
 | 
						|
  {
 | 
						|
    pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
 | 
						|
    if ( pSocket->bRxDisable || pSocket->bTxDisable ) {
 | 
						|
      DEBUG (( DEBUG_OPTION, "ERROR - Socket has been shutdown!\r\n" ));
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      LengthInBytes = 0;
 | 
						|
      pOptionData = NULL;
 | 
						|
      switch ( level ) {
 | 
						|
      default:
 | 
						|
        //
 | 
						|
        //  See if the protocol will handle the option
 | 
						|
        //
 | 
						|
        if ( NULL != pSocket->pApi->pfnOptionSet ) {
 | 
						|
          if ( pSocket->pApi->DefaultProtocol == level ) {
 | 
						|
            Status = pSocket->pApi->pfnOptionSet ( pSocket,
 | 
						|
                                                   OptionName,
 | 
						|
                                                   pOptionValue,
 | 
						|
                                                   OptionLength );
 | 
						|
            errno = pSocket->errno;
 | 
						|
            break;
 | 
						|
          }
 | 
						|
          else {
 | 
						|
            //
 | 
						|
            //  Protocol not supported
 | 
						|
            //
 | 
						|
            DEBUG (( DEBUG_OPTION,
 | 
						|
                      "ERROR - The socket does not support this protocol!\r\n" ));
 | 
						|
          }
 | 
						|
        }
 | 
						|
        else {
 | 
						|
          //
 | 
						|
          //  Protocol level not supported
 | 
						|
          //
 | 
						|
          DEBUG (( DEBUG_OPTION,
 | 
						|
                    "ERROR - %a does not support any options!\r\n",
 | 
						|
                    pSocket->pApi->pName ));
 | 
						|
        }
 | 
						|
        errno = ENOPROTOOPT;
 | 
						|
        Status = EFI_INVALID_PARAMETER;
 | 
						|
        break;
 | 
						|
 | 
						|
      case SOL_SOCKET:
 | 
						|
        switch ( OptionName ) {
 | 
						|
        default:
 | 
						|
          //
 | 
						|
          //  Option not supported
 | 
						|
          //
 | 
						|
          DEBUG (( DEBUG_OPTION,
 | 
						|
                    "ERROR - Sockets does not support this option!\r\n" ));
 | 
						|
          errno = EINVAL;
 | 
						|
          Status = EFI_INVALID_PARAMETER;
 | 
						|
          break;
 | 
						|
 | 
						|
        case SO_DEBUG:
 | 
						|
          //
 | 
						|
          //  Set the debug flags
 | 
						|
          //
 | 
						|
          pOptionData = (UINT8 *)&pSocket->bOobInLine;
 | 
						|
          LengthInBytes = sizeof ( pSocket->bOobInLine );
 | 
						|
          break;
 | 
						|
 | 
						|
        case SO_OOBINLINE:
 | 
						|
          pOptionData = (UINT8 *)&pSocket->bOobInLine;
 | 
						|
          LengthInBytes = sizeof ( pSocket->bOobInLine );
 | 
						|
 | 
						|
          //
 | 
						|
          //  Validate the option length
 | 
						|
          //
 | 
						|
          if ( sizeof ( UINT32 ) == OptionLength ) {
 | 
						|
            //
 | 
						|
            //  Restrict the input to TRUE or FALSE
 | 
						|
            //
 | 
						|
            bTrueFalse = TRUE;
 | 
						|
            if ( 0 == *(UINT32 *)pOptionValue ) {
 | 
						|
              bTrueFalse = FALSE;
 | 
						|
            }
 | 
						|
            pOptionValue = &bTrueFalse;
 | 
						|
          }
 | 
						|
          else {
 | 
						|
            //
 | 
						|
            //  Force an invalid option length error
 | 
						|
            //
 | 
						|
            OptionLength = LengthInBytes - 1;
 | 
						|
          }
 | 
						|
          break;
 | 
						|
 | 
						|
        case SO_RCVTIMEO:
 | 
						|
          //
 | 
						|
          //  Return the receive timeout
 | 
						|
          //
 | 
						|
          pOptionData = (UINT8 *)&pSocket->RxTimeout;
 | 
						|
          LengthInBytes = sizeof ( pSocket->RxTimeout );
 | 
						|
          break;
 | 
						|
 | 
						|
        case SO_RCVBUF:
 | 
						|
          //
 | 
						|
          //  Return the maximum receive buffer size
 | 
						|
          //
 | 
						|
          pOptionData = (UINT8 *)&pSocket->MaxRxBuf;
 | 
						|
          LengthInBytes = sizeof ( pSocket->MaxRxBuf );
 | 
						|
          break;
 | 
						|
 | 
						|
        case SO_REUSEADDR:
 | 
						|
          //
 | 
						|
          //  Return the address reuse flag
 | 
						|
          //
 | 
						|
          pOptionData = (UINT8 *)&pSocket->bReUseAddr;
 | 
						|
          LengthInBytes = sizeof ( pSocket->bReUseAddr );
 | 
						|
          break;
 | 
						|
 | 
						|
        case SO_SNDBUF:
 | 
						|
          //
 | 
						|
          //  Send buffer size
 | 
						|
          //
 | 
						|
          //
 | 
						|
          //  Return the maximum transmit buffer size
 | 
						|
          //
 | 
						|
          pOptionData = (UINT8 *)&pSocket->MaxTxBuf;
 | 
						|
          LengthInBytes = sizeof ( pSocket->MaxTxBuf );
 | 
						|
          break;
 | 
						|
        }
 | 
						|
        break;
 | 
						|
      }
 | 
						|
 | 
						|
      //
 | 
						|
      //  Determine if an option was found
 | 
						|
      //
 | 
						|
      if ( 0 != LengthInBytes ) {
 | 
						|
        //
 | 
						|
        //  Validate the option length
 | 
						|
        //
 | 
						|
        if ( LengthInBytes <= OptionLength ) {
 | 
						|
          //
 | 
						|
          //  Set the option value
 | 
						|
          //
 | 
						|
          CopyMem ( pOptionData, pOptionValue, LengthInBytes );
 | 
						|
          errno = 0;
 | 
						|
          Status = EFI_SUCCESS;
 | 
						|
        }
 | 
						|
        else {
 | 
						|
          DEBUG (( DEBUG_OPTION,
 | 
						|
                    "ERROR - Buffer to small, %d bytes < %d bytes!\r\n",
 | 
						|
                    OptionLength,
 | 
						|
                    LengthInBytes ));
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  //  Return the operation status
 | 
						|
  //
 | 
						|
  if ( NULL != pErrno ) {
 | 
						|
    *pErrno = errno;
 | 
						|
  }
 | 
						|
  DBG_EXIT_STATUS ( Status );
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**  Allocate a packet for a receive or transmit operation.
 | 
						|
 | 
						|
  This support routine is called by ::EslSocketRxStart and the
 | 
						|
  network specific TxBuffer routines to get buffer space for the
 | 
						|
  next operation.
 | 
						|
 | 
						|
  @param[in]  ppPacket      Address to receive the ::ESL_PACKET structure
 | 
						|
  @param[in]  LengthInBytes Length of the packet structure
 | 
						|
  @param[in]  ZeroBytes     Length of packet to zero
 | 
						|
  @param[in]  DebugFlags    Flags for debug messages
 | 
						|
 | 
						|
  @retval EFI_SUCCESS - The packet was allocated successfully
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EslSocketPacketAllocate (
 | 
						|
  IN ESL_PACKET ** ppPacket,
 | 
						|
  IN size_t LengthInBytes,
 | 
						|
  IN size_t ZeroBytes,
 | 
						|
  IN UINTN DebugFlags
 | 
						|
  )
 | 
						|
{
 | 
						|
  ESL_PACKET * pPacket;
 | 
						|
  EFI_STATUS Status;
 | 
						|
 | 
						|
  DBG_ENTER ( );
 | 
						|
 | 
						|
  //
 | 
						|
  //  Allocate a packet structure
 | 
						|
  //
 | 
						|
  LengthInBytes += sizeof ( *pPacket )
 | 
						|
                - sizeof ( pPacket->Op );
 | 
						|
  Status = gBS->AllocatePool ( EfiRuntimeServicesData,
 | 
						|
                               LengthInBytes,
 | 
						|
                               (VOID **)&pPacket );
 | 
						|
  if ( !EFI_ERROR ( Status )) {
 | 
						|
    DEBUG (( DebugFlags | DEBUG_POOL,
 | 
						|
              "0x%08x: Allocate pPacket, %d bytes\r\n",
 | 
						|
              pPacket,
 | 
						|
              LengthInBytes ));
 | 
						|
    if ( 0 != ZeroBytes ) {
 | 
						|
      ZeroMem ( &pPacket->Op, ZeroBytes );
 | 
						|
    }
 | 
						|
    pPacket->PacketSize = LengthInBytes;
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    DEBUG (( DebugFlags | DEBUG_POOL | DEBUG_INFO,
 | 
						|
              "ERROR - Packet allocation failed for %d bytes, Status: %r\r\n",
 | 
						|
              LengthInBytes,
 | 
						|
              Status ));
 | 
						|
    pPacket = NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  //  Return the packet
 | 
						|
  //
 | 
						|
  *ppPacket = pPacket;
 | 
						|
 | 
						|
  //
 | 
						|
  //  Return the operation status
 | 
						|
  //
 | 
						|
  DBG_EXIT_STATUS ( Status );
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/** Free a packet used for receive or transmit operation.
 | 
						|
 | 
						|
  This support routine is called by the network specific Close
 | 
						|
  and TxComplete routines and during error cases in RxComplete
 | 
						|
  and TxBuffer.  Note that the network layers typically place
 | 
						|
  receive packets on the ESL_SOCKET::pRxFree list for reuse.
 | 
						|
 | 
						|
  @param[in]  pPacket     Address of an ::ESL_PACKET structure
 | 
						|
  @param[in]  DebugFlags  Flags for debug messages
 | 
						|
 | 
						|
  @retval EFI_SUCCESS - The packet was allocated successfully
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EslSocketPacketFree (
 | 
						|
  IN ESL_PACKET * pPacket,
 | 
						|
  IN UINTN DebugFlags
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN LengthInBytes;
 | 
						|
  EFI_STATUS Status;
 | 
						|
 | 
						|
  DBG_ENTER ( );
 | 
						|
 | 
						|
  //
 | 
						|
  //  Free a packet structure
 | 
						|
  //
 | 
						|
  LengthInBytes = pPacket->PacketSize;
 | 
						|
  Status = gBS->FreePool ( pPacket );
 | 
						|
  if ( !EFI_ERROR ( Status )) {
 | 
						|
    DEBUG (( DebugFlags | DEBUG_POOL,
 | 
						|
              "0x%08x: Free pPacket, %d bytes\r\n",
 | 
						|
              pPacket,
 | 
						|
              LengthInBytes ));
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    DEBUG (( DebugFlags | DEBUG_POOL | DEBUG_INFO,
 | 
						|
              "ERROR - Failed to free packet 0x%08x, Status: %r\r\n",
 | 
						|
              pPacket,
 | 
						|
              Status ));
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  //  Return the operation status
 | 
						|
  //
 | 
						|
  DBG_EXIT_STATUS ( Status );
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/** Poll a socket for pending activity.
 | 
						|
 | 
						|
  This routine builds a detected event mask which is returned to
 | 
						|
  the caller in the buffer provided.
 | 
						|
 | 
						|
  The ::poll routine calls this routine to determine if the socket
 | 
						|
  needs to be serviced as a result of connection, error, receive or
 | 
						|
  transmit activity.
 | 
						|
 | 
						|
  @param[in]  pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
 | 
						|
  @param[in]  Events          Events of interest for this socket
 | 
						|
  @param[in]  pEvents         Address to receive the detected events
 | 
						|
  @param[out] pErrno          Address to receive the errno value upon completion.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS - Socket successfully polled
 | 
						|
  @retval EFI_INVALID_PARAMETER - When pEvents is NULL
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EslSocketPoll (
 | 
						|
  IN EFI_SOCKET_PROTOCOL * pSocketProtocol,
 | 
						|
  IN short Events,
 | 
						|
  IN short * pEvents,
 | 
						|
  IN int * pErrno
 | 
						|
  )
 | 
						|
{
 | 
						|
  short DetectedEvents;
 | 
						|
  ESL_SOCKET * pSocket;
 | 
						|
  EFI_STATUS Status;
 | 
						|
  EFI_TPL TplPrevious;
 | 
						|
  short ValidEvents;
 | 
						|
  int   _errno = EINVAL;
 | 
						|
 | 
						|
  DEBUG (( DEBUG_POLL, "Entering SocketPoll\r\n" ));
 | 
						|
 | 
						|
  //
 | 
						|
  //  Assume success
 | 
						|
  //
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
  DetectedEvents = 0;
 | 
						|
  pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
 | 
						|
  pSocket->errno = 0;
 | 
						|
 | 
						|
  //
 | 
						|
  //  Verify the socket state
 | 
						|
  //
 | 
						|
  Status = EslSocketIsConfigured ( pSocket );
 | 
						|
  if ( !EFI_ERROR ( Status )) {
 | 
						|
    //
 | 
						|
    //  Check for invalid events
 | 
						|
    //
 | 
						|
    ValidEvents = POLLIN
 | 
						|
                | POLLPRI
 | 
						|
                | POLLOUT | POLLWRNORM
 | 
						|
                | POLLERR
 | 
						|
                | POLLHUP
 | 
						|
                | POLLNVAL
 | 
						|
                | POLLRDNORM
 | 
						|
                | POLLRDBAND
 | 
						|
                | POLLWRBAND ;
 | 
						|
    if ( 0 != ( Events & ( ~ValidEvents ))) {
 | 
						|
      DetectedEvents |= POLLNVAL;
 | 
						|
      DEBUG (( DEBUG_INFO | DEBUG_POLL,
 | 
						|
                "ERROR - Invalid event mask, Valid Events: 0x%04x, Invalid Events: 0x%04x\r\n",
 | 
						|
                Events & ValidEvents,
 | 
						|
                Events & ( ~ValidEvents )));
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      //
 | 
						|
      //  Synchronize with the socket layer
 | 
						|
      //
 | 
						|
      RAISE_TPL ( TplPrevious, TPL_SOCKETS );
 | 
						|
 | 
						|
      //
 | 
						|
      //  Increase the network performance by extending the
 | 
						|
      //  polling (idle) loop down into the LAN driver
 | 
						|
      //
 | 
						|
      EslSocketRxPoll ( pSocket );
 | 
						|
 | 
						|
      //
 | 
						|
      //  Release the socket layer synchronization
 | 
						|
      //
 | 
						|
      RESTORE_TPL ( TplPrevious );
 | 
						|
 | 
						|
      //
 | 
						|
      //  Check for pending connections
 | 
						|
      //
 | 
						|
      if ( 0 != pSocket->FifoDepth ) {
 | 
						|
        //
 | 
						|
        //  A connection is waiting for an accept call
 | 
						|
        //  See posix connect documentation at
 | 
						|
        //  http://pubs.opengroup.org/onlinepubs/9699919799/functions/accept.htm
 | 
						|
        //
 | 
						|
        DetectedEvents |= POLLIN | POLLRDNORM;
 | 
						|
      }
 | 
						|
      if ( pSocket->bConnected ) {
 | 
						|
        //
 | 
						|
        //  A connection is present
 | 
						|
        //  See posix connect documentation at
 | 
						|
        //  http://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.htm
 | 
						|
        //
 | 
						|
        DetectedEvents |= POLLOUT | POLLWRNORM;
 | 
						|
      }
 | 
						|
 | 
						|
      //
 | 
						|
      //  The following bits are set based upon the POSIX poll documentation at
 | 
						|
      //  http://pubs.opengroup.org/onlinepubs/9699919799/functions/poll.html
 | 
						|
      //
 | 
						|
 | 
						|
      //
 | 
						|
      //  Check for urgent receive data
 | 
						|
      //
 | 
						|
      if ( 0 < pSocket->RxOobBytes ) {
 | 
						|
        DetectedEvents |= POLLRDBAND | POLLPRI | POLLIN;
 | 
						|
      }
 | 
						|
 | 
						|
      //
 | 
						|
      //  Check for normal receive data
 | 
						|
      //
 | 
						|
      if (( 0 < pSocket->RxBytes )
 | 
						|
        || ( EFI_SUCCESS != pSocket->RxError )) {
 | 
						|
        DetectedEvents |= POLLRDNORM | POLLIN;
 | 
						|
      }
 | 
						|
 | 
						|
      //
 | 
						|
      //  Handle the receive errors
 | 
						|
      //
 | 
						|
      if (( EFI_SUCCESS != pSocket->RxError )
 | 
						|
        && ( 0 == ( DetectedEvents & POLLIN ))) {
 | 
						|
        DetectedEvents |= POLLERR | POLLIN | POLLRDNORM | POLLRDBAND;
 | 
						|
      }
 | 
						|
 | 
						|
      //
 | 
						|
      //  Check for urgent transmit data buffer space
 | 
						|
      //
 | 
						|
      if (( MAX_TX_DATA > pSocket->TxOobBytes )
 | 
						|
        || ( EFI_SUCCESS != pSocket->TxError )) {
 | 
						|
        DetectedEvents |= POLLWRBAND;
 | 
						|
      }
 | 
						|
 | 
						|
      //
 | 
						|
      //  Check for normal transmit data buffer space
 | 
						|
      //
 | 
						|
      if (( MAX_TX_DATA > pSocket->TxBytes )
 | 
						|
        || ( EFI_SUCCESS != pSocket->TxError )) {
 | 
						|
        DetectedEvents |= POLLWRNORM;
 | 
						|
      }
 | 
						|
 | 
						|
      //
 | 
						|
      //  Handle the transmit error
 | 
						|
      //
 | 
						|
      if ( EFI_ERROR ( pSocket->TxError )) {
 | 
						|
        DetectedEvents |= POLLERR;
 | 
						|
      }
 | 
						|
      _errno = pSocket->errno;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  //  Return the detected events
 | 
						|
  //
 | 
						|
  *pEvents = DetectedEvents & ( Events
 | 
						|
                              | POLLERR
 | 
						|
                              | POLLHUP
 | 
						|
                              | POLLNVAL );
 | 
						|
  if ( NULL != pErrno ) {
 | 
						|
    *pErrno = _errno;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  //  Return the operation status
 | 
						|
  //
 | 
						|
  DEBUG (( DEBUG_POLL, "Exiting SocketPoll, Status: %r\r\n", Status ));
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/** Allocate and initialize a ESL_PORT structure.
 | 
						|
 | 
						|
  This routine initializes an ::ESL_PORT structure for use by
 | 
						|
  the socket.  This routine calls a routine via
 | 
						|
  ESL_PROTOCOL_API::pfnPortAllocate to initialize the network
 | 
						|
  specific resources.  The resources are released later by the
 | 
						|
  \ref PortCloseStateMachine.
 | 
						|
 | 
						|
  This support routine is called by:
 | 
						|
  <ul>
 | 
						|
    <li>::EslSocketBind</li>
 | 
						|
    <li>::EslTcp4ListenComplete</li>
 | 
						|
  </ul>
 | 
						|
  to connect the socket with the underlying network adapter
 | 
						|
  to the socket.
 | 
						|
 | 
						|
  @param[in]  pSocket     Address of an ::ESL_SOCKET structure.
 | 
						|
  @param[in]  pService    Address of an ::ESL_SERVICE structure.
 | 
						|
  @param[in]  ChildHandle Network protocol child handle
 | 
						|
  @param[in]  pSockAddr   Address of a sockaddr structure that contains the
 | 
						|
                          connection point on the local machine.  An IPv4 address
 | 
						|
                          of INADDR_ANY specifies that the connection is made to
 | 
						|
                          all of the network stacks on the platform.  Specifying a
 | 
						|
                          specific IPv4 address restricts the connection to the
 | 
						|
                          network stack supporting that address.  Specifying zero
 | 
						|
                          for the port causes the network layer to assign a port
 | 
						|
                          number from the dynamic range.  Specifying a specific
 | 
						|
                          port number causes the network layer to use that port.
 | 
						|
  @param[in]  bBindTest   TRUE if EslSocketBindTest should be called
 | 
						|
  @param[in]  DebugFlags  Flags for debug messages
 | 
						|
  @param[out] ppPort      Buffer to receive new ::ESL_PORT structure address
 | 
						|
 | 
						|
  @retval EFI_SUCCESS - Socket successfully created
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EslSocketPortAllocate (
 | 
						|
  IN ESL_SOCKET * pSocket,
 | 
						|
  IN ESL_SERVICE * pService,
 | 
						|
  IN EFI_HANDLE ChildHandle,
 | 
						|
  IN CONST struct sockaddr * pSockAddr,
 | 
						|
  IN BOOLEAN bBindTest,
 | 
						|
  IN UINTN DebugFlags,
 | 
						|
  OUT ESL_PORT ** ppPort
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN LengthInBytes;
 | 
						|
  UINT8 * pBuffer;
 | 
						|
  ESL_IO_MGMT * pIo;
 | 
						|
  ESL_LAYER * pLayer;
 | 
						|
  ESL_PORT * pPort;
 | 
						|
  EFI_SERVICE_BINDING_PROTOCOL * pServiceBinding;
 | 
						|
  CONST ESL_SOCKET_BINDING * pSocketBinding;
 | 
						|
  EFI_STATUS Status;
 | 
						|
  EFI_STATUS TempStatus;
 | 
						|
 | 
						|
  DBG_ENTER ( );
 | 
						|
 | 
						|
  //
 | 
						|
  //  Verify the socket layer synchronization
 | 
						|
  //
 | 
						|
  VERIFY_TPL ( TPL_SOCKETS );
 | 
						|
 | 
						|
  //
 | 
						|
  //  Use for/break instead of goto
 | 
						|
  pSocketBinding = pService->pSocketBinding;
 | 
						|
  for ( ; ; ) {
 | 
						|
    //
 | 
						|
    //  Allocate a port structure
 | 
						|
    //
 | 
						|
    pLayer = &mEslLayer;
 | 
						|
    LengthInBytes = sizeof ( *pPort )
 | 
						|
                  + ESL_STRUCTURE_ALIGNMENT_BYTES
 | 
						|
                  + (( pSocketBinding->RxIo
 | 
						|
                       + pSocketBinding->TxIoNormal
 | 
						|
                       + pSocketBinding->TxIoUrgent )
 | 
						|
                     * sizeof ( ESL_IO_MGMT ));
 | 
						|
    pPort = (ESL_PORT *) AllocateZeroPool ( LengthInBytes );
 | 
						|
    if ( NULL == pPort ) {
 | 
						|
      Status = EFI_OUT_OF_RESOURCES;
 | 
						|
      pSocket->errno = ENOMEM;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    DEBUG (( DebugFlags | DEBUG_POOL | DEBUG_INIT,
 | 
						|
              "0x%08x: Allocate pPort, %d bytes\r\n",
 | 
						|
              pPort,
 | 
						|
              LengthInBytes ));
 | 
						|
 | 
						|
    //
 | 
						|
    //  Initialize the port
 | 
						|
    //
 | 
						|
    pPort->DebugFlags = DebugFlags;
 | 
						|
    pPort->Handle = ChildHandle;
 | 
						|
    pPort->pService = pService;
 | 
						|
    pPort->pServiceBinding = pService->pServiceBinding;
 | 
						|
    pPort->pSocket = pSocket;
 | 
						|
    pPort->pSocketBinding = pService->pSocketBinding;
 | 
						|
    pPort->Signature = PORT_SIGNATURE;
 | 
						|
 | 
						|
    //
 | 
						|
    //  Open the port protocol
 | 
						|
    //
 | 
						|
    Status = gBS->OpenProtocol ( pPort->Handle,
 | 
						|
                                 pSocketBinding->pNetworkProtocolGuid,
 | 
						|
                                 &pPort->pProtocol.v,
 | 
						|
                                 pLayer->ImageHandle,
 | 
						|
                                 NULL,
 | 
						|
                                 EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL );
 | 
						|
    if ( EFI_ERROR ( Status )) {
 | 
						|
      DEBUG (( DEBUG_ERROR | DebugFlags,
 | 
						|
                "ERROR - Failed to open network protocol GUID on controller 0x%08x\r\n",
 | 
						|
                pPort->Handle ));
 | 
						|
      pSocket->errno = EEXIST;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    DEBUG (( DebugFlags,
 | 
						|
              "0x%08x: Network protocol GUID opened on controller 0x%08x\r\n",
 | 
						|
              pPort->pProtocol.v,
 | 
						|
              pPort->Handle ));
 | 
						|
 | 
						|
    //
 | 
						|
    //  Initialize the port specific resources
 | 
						|
    //
 | 
						|
    Status = pSocket->pApi->pfnPortAllocate ( pPort,
 | 
						|
                                              DebugFlags );
 | 
						|
    if ( EFI_ERROR ( Status )) {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    //  Set the local address
 | 
						|
    //
 | 
						|
    Status = pSocket->pApi->pfnLocalAddrSet ( pPort, pSockAddr, bBindTest );
 | 
						|
    if ( EFI_ERROR ( Status )) {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    //  Test the address/port configuration
 | 
						|
    //
 | 
						|
    if ( bBindTest ) {
 | 
						|
      Status = EslSocketBindTest ( pPort, pSocket->pApi->BindTestErrno );
 | 
						|
      if ( EFI_ERROR ( Status )) {
 | 
						|
        break;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    //  Initialize the receive structures
 | 
						|
    //
 | 
						|
    pBuffer = (UINT8 *)&pPort[ 1 ];
 | 
						|
    pBuffer = &pBuffer[ ESL_STRUCTURE_ALIGNMENT_BYTES ];
 | 
						|
    pBuffer = (UINT8 *)( ESL_STRUCTURE_ALIGNMENT_MASK & (UINTN)pBuffer );
 | 
						|
    pIo = (ESL_IO_MGMT *)pBuffer;
 | 
						|
    if (( 0 != pSocketBinding->RxIo )
 | 
						|
      && ( NULL != pSocket->pApi->pfnRxComplete )) {
 | 
						|
      Status = EslSocketIoInit ( pPort,
 | 
						|
                                 &pIo,
 | 
						|
                                 pSocketBinding->RxIo,
 | 
						|
                                 &pPort->pRxFree,
 | 
						|
                                 DebugFlags | DEBUG_POOL,
 | 
						|
                                 "receive",
 | 
						|
                                 pSocket->pApi->pfnRxComplete );
 | 
						|
      if ( EFI_ERROR ( Status )) {
 | 
						|
        break;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    //  Initialize the urgent transmit structures
 | 
						|
    //
 | 
						|
    if (( 0 != pSocketBinding->TxIoUrgent )
 | 
						|
      && ( NULL != pSocket->pApi->pfnTxOobComplete )) {
 | 
						|
      Status = EslSocketIoInit ( pPort,
 | 
						|
                                 &pIo,
 | 
						|
                                 pSocketBinding->TxIoUrgent,
 | 
						|
                                 &pPort->pTxOobFree,
 | 
						|
                                 DebugFlags | DEBUG_POOL,
 | 
						|
                                 "urgent transmit",
 | 
						|
                                 pSocket->pApi->pfnTxOobComplete );
 | 
						|
      if ( EFI_ERROR ( Status )) {
 | 
						|
        break;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    //  Initialize the normal transmit structures
 | 
						|
    //
 | 
						|
    if (( 0 != pSocketBinding->TxIoNormal )
 | 
						|
      && ( NULL != pSocket->pApi->pfnTxComplete )) {
 | 
						|
      Status = EslSocketIoInit ( pPort,
 | 
						|
                                 &pIo,
 | 
						|
                                 pSocketBinding->TxIoNormal,
 | 
						|
                                 &pPort->pTxFree,
 | 
						|
                                 DebugFlags | DEBUG_POOL,
 | 
						|
                                 "normal transmit",
 | 
						|
                                 pSocket->pApi->pfnTxComplete );
 | 
						|
      if ( EFI_ERROR ( Status )) {
 | 
						|
        break;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    //  Add this port to the socket
 | 
						|
    //
 | 
						|
    pPort->pLinkSocket = pSocket->pPortList;
 | 
						|
    pSocket->pPortList = pPort;
 | 
						|
    DEBUG (( DebugFlags,
 | 
						|
              "0x%08x: Socket adding port: 0x%08x\r\n",
 | 
						|
              pSocket,
 | 
						|
              pPort ));
 | 
						|
 | 
						|
    //
 | 
						|
    //  Add this port to the service
 | 
						|
    //
 | 
						|
    pPort->pLinkService = pService->pPortList;
 | 
						|
    pService->pPortList = pPort;
 | 
						|
 | 
						|
    //
 | 
						|
    //  Return the port
 | 
						|
    //
 | 
						|
    *ppPort = pPort;
 | 
						|
    break;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  //  Clean up after the error if necessary
 | 
						|
  //
 | 
						|
  if ( EFI_ERROR ( Status )) {
 | 
						|
    if ( NULL != pPort ) {
 | 
						|
      //
 | 
						|
      //  Close the port
 | 
						|
      //
 | 
						|
      EslSocketPortClose ( pPort );
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      //
 | 
						|
      //  Close the port if necessary
 | 
						|
      //
 | 
						|
      pServiceBinding = pService->pServiceBinding;
 | 
						|
      TempStatus = pServiceBinding->DestroyChild ( pServiceBinding,
 | 
						|
                                                   ChildHandle );
 | 
						|
      if ( !EFI_ERROR ( TempStatus )) {
 | 
						|
        DEBUG (( DEBUG_BIND | DEBUG_POOL,
 | 
						|
                  "0x%08x: %s port handle destroyed\r\n",
 | 
						|
                  ChildHandle,
 | 
						|
                  pSocketBinding->pName ));
 | 
						|
      }
 | 
						|
      else {
 | 
						|
        DEBUG (( DEBUG_ERROR | DEBUG_BIND | DEBUG_POOL,
 | 
						|
                  "ERROR - Failed to destroy the %s port handle 0x%08x, Status: %r\r\n",
 | 
						|
                  pSocketBinding->pName,
 | 
						|
                  ChildHandle,
 | 
						|
                  TempStatus ));
 | 
						|
        ASSERT ( EFI_SUCCESS == TempStatus );
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  //
 | 
						|
  //  Return the operation status
 | 
						|
  //
 | 
						|
  DBG_EXIT_STATUS ( Status );
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/** Close a port.
 | 
						|
 | 
						|
  This routine releases the resources allocated by ::EslSocketPortAllocate.
 | 
						|
  This routine calls ESL_PROTOCOL_API::pfnPortClose to release the network
 | 
						|
  specific resources.
 | 
						|
 | 
						|
  This routine is called by:
 | 
						|
  <ul>
 | 
						|
    <li>::EslSocketPortAllocate - Port initialization failure</li>
 | 
						|
    <li>::EslSocketPortCloseRxDone - Last step of close processing</li>
 | 
						|
    <li>::EslTcp4ConnectComplete - Connection failure and reducing the port list to a single port</li>
 | 
						|
  </ul>
 | 
						|
  See the \ref PortCloseStateMachine section.
 | 
						|
 | 
						|
  @param[in]  pPort       Address of an ::ESL_PORT structure.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS     The port is closed
 | 
						|
  @retval other           Port close error
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EslSocketPortClose (
 | 
						|
  IN ESL_PORT * pPort
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN DebugFlags;
 | 
						|
  ESL_LAYER * pLayer;
 | 
						|
  ESL_PACKET * pPacket;
 | 
						|
  ESL_PORT * pPreviousPort;
 | 
						|
  ESL_SERVICE * pService;
 | 
						|
  EFI_SERVICE_BINDING_PROTOCOL * pServiceBinding;
 | 
						|
  CONST ESL_SOCKET_BINDING * pSocketBinding;
 | 
						|
  ESL_SOCKET * pSocket;
 | 
						|
  EFI_STATUS Status;
 | 
						|
 | 
						|
  DBG_ENTER ( );
 | 
						|
 | 
						|
  //
 | 
						|
  //  Verify the socket layer synchronization
 | 
						|
  //
 | 
						|
  VERIFY_TPL ( TPL_SOCKETS );
 | 
						|
 | 
						|
  //
 | 
						|
  //  Locate the port in the socket list
 | 
						|
  //
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
  pLayer = &mEslLayer;
 | 
						|
  DebugFlags = pPort->DebugFlags;
 | 
						|
  pSocket = pPort->pSocket;
 | 
						|
  pPreviousPort = pSocket->pPortList;
 | 
						|
  if ( pPreviousPort == pPort ) {
 | 
						|
    //
 | 
						|
    //  Remove this port from the head of the socket list
 | 
						|
    //
 | 
						|
    pSocket->pPortList = pPort->pLinkSocket;
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    //
 | 
						|
    //  Locate the port in the middle of the socket list
 | 
						|
    //
 | 
						|
    while (( NULL != pPreviousPort )
 | 
						|
      && ( pPreviousPort->pLinkSocket != pPort )) {
 | 
						|
      pPreviousPort = pPreviousPort->pLinkSocket;
 | 
						|
    }
 | 
						|
    if ( NULL != pPreviousPort ) {
 | 
						|
      //
 | 
						|
      //  Remove the port from the middle of the socket list
 | 
						|
      //
 | 
						|
      pPreviousPort->pLinkSocket = pPort->pLinkSocket;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  //  Locate the port in the service list
 | 
						|
  //  Note that the port may not be in the service list
 | 
						|
  //  if the service has been shutdown.
 | 
						|
  //
 | 
						|
  pService = pPort->pService;
 | 
						|
  if ( NULL != pService ) {
 | 
						|
    pPreviousPort = pService->pPortList;
 | 
						|
    if ( pPreviousPort == pPort ) {
 | 
						|
      //
 | 
						|
      //  Remove this port from the head of the service list
 | 
						|
      //
 | 
						|
      pService->pPortList = pPort->pLinkService;
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      //
 | 
						|
      //  Locate the port in the middle of the service list
 | 
						|
      //
 | 
						|
      while (( NULL != pPreviousPort )
 | 
						|
        && ( pPreviousPort->pLinkService != pPort )) {
 | 
						|
        pPreviousPort = pPreviousPort->pLinkService;
 | 
						|
      }
 | 
						|
      if ( NULL != pPreviousPort ) {
 | 
						|
        //
 | 
						|
        //  Remove the port from the middle of the service list
 | 
						|
        //
 | 
						|
        pPreviousPort->pLinkService = pPort->pLinkService;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  //  Empty the urgent receive queue
 | 
						|
  //
 | 
						|
  while ( NULL != pSocket->pRxOobPacketListHead ) {
 | 
						|
    pPacket = pSocket->pRxOobPacketListHead;
 | 
						|
    pSocket->pRxOobPacketListHead = pPacket->pNext;
 | 
						|
    pSocket->pApi->pfnPacketFree ( pPacket, &pSocket->RxOobBytes );
 | 
						|
    EslSocketPacketFree ( pPacket, DEBUG_RX );
 | 
						|
  }
 | 
						|
  pSocket->pRxOobPacketListTail = NULL;
 | 
						|
  ASSERT ( 0 == pSocket->RxOobBytes );
 | 
						|
 | 
						|
  //
 | 
						|
  //  Empty the receive queue
 | 
						|
  //
 | 
						|
  while ( NULL != pSocket->pRxPacketListHead ) {
 | 
						|
    pPacket = pSocket->pRxPacketListHead;
 | 
						|
    pSocket->pRxPacketListHead = pPacket->pNext;
 | 
						|
    pSocket->pApi->pfnPacketFree ( pPacket, &pSocket->RxBytes );
 | 
						|
    EslSocketPacketFree ( pPacket, DEBUG_RX );
 | 
						|
  }
 | 
						|
  pSocket->pRxPacketListTail = NULL;
 | 
						|
  ASSERT ( 0 == pSocket->RxBytes );
 | 
						|
 | 
						|
  //
 | 
						|
  //  Empty the receive free queue
 | 
						|
  //
 | 
						|
  while ( NULL != pSocket->pRxFree ) {
 | 
						|
    pPacket = pSocket->pRxFree;
 | 
						|
    pSocket->pRxFree = pPacket->pNext;
 | 
						|
    EslSocketPacketFree ( pPacket, DEBUG_RX );
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  //  Release the network specific resources
 | 
						|
  //
 | 
						|
  if ( NULL != pSocket->pApi->pfnPortClose ) {
 | 
						|
    Status = pSocket->pApi->pfnPortClose ( pPort );
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  //  Done with the normal transmit events
 | 
						|
  //
 | 
						|
  Status = EslSocketIoFree ( pPort,
 | 
						|
                             &pPort->pTxFree,
 | 
						|
                             DebugFlags | DEBUG_POOL,
 | 
						|
                             "normal transmit" );
 | 
						|
 | 
						|
  //
 | 
						|
  //  Done with the urgent transmit events
 | 
						|
  //
 | 
						|
  Status = EslSocketIoFree ( pPort,
 | 
						|
                             &pPort->pTxOobFree,
 | 
						|
                             DebugFlags | DEBUG_POOL,
 | 
						|
                             "urgent transmit" );
 | 
						|
 | 
						|
  //
 | 
						|
  //  Done with the receive events
 | 
						|
  //
 | 
						|
  Status = EslSocketIoFree ( pPort,
 | 
						|
                             &pPort->pRxFree,
 | 
						|
                             DebugFlags | DEBUG_POOL,
 | 
						|
                             "receive" );
 | 
						|
 | 
						|
  //
 | 
						|
  //  Done with the lower layer network protocol
 | 
						|
  //
 | 
						|
  pSocketBinding = pPort->pSocketBinding;
 | 
						|
  if ( NULL != pPort->pProtocol.v ) {
 | 
						|
    Status = gBS->CloseProtocol ( pPort->Handle,
 | 
						|
                                  pSocketBinding->pNetworkProtocolGuid,
 | 
						|
                                  pLayer->ImageHandle,
 | 
						|
                                  NULL );
 | 
						|
    if ( !EFI_ERROR ( Status )) {
 | 
						|
      DEBUG (( DebugFlags,
 | 
						|
                "0x%08x: Network protocol GUID closed on controller 0x%08x\r\n",
 | 
						|
                pPort->pProtocol.v,
 | 
						|
                pPort->Handle ));
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      DEBUG (( DEBUG_ERROR | DebugFlags,
 | 
						|
                "ERROR - Failed to close network protocol GUID on controller 0x%08x, Status: %r\r\n",
 | 
						|
                pPort->Handle,
 | 
						|
                Status ));
 | 
						|
      ASSERT ( EFI_SUCCESS == Status );
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  //  Done with the network port
 | 
						|
  //
 | 
						|
  pServiceBinding = pPort->pServiceBinding;
 | 
						|
  if ( NULL != pPort->Handle ) {
 | 
						|
    Status = pServiceBinding->DestroyChild ( pServiceBinding,
 | 
						|
                                             pPort->Handle );
 | 
						|
    if ( !EFI_ERROR ( Status )) {
 | 
						|
      DEBUG (( DebugFlags | DEBUG_POOL,
 | 
						|
                "0x%08x: %s port handle destroyed\r\n",
 | 
						|
                pPort->Handle,
 | 
						|
                pSocketBinding->pName ));
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      DEBUG (( DEBUG_ERROR | DebugFlags | DEBUG_POOL,
 | 
						|
                "ERROR - Failed to destroy the %s port handle, Status: %r\r\n",
 | 
						|
                pSocketBinding->pName,
 | 
						|
                Status ));
 | 
						|
      ASSERT ( EFI_SUCCESS == Status );
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  //  Release the port structure
 | 
						|
  //
 | 
						|
  Status = gBS->FreePool ( pPort );
 | 
						|
  if ( !EFI_ERROR ( Status )) {
 | 
						|
    DEBUG (( DebugFlags | DEBUG_POOL,
 | 
						|
              "0x%08x: Free pPort, %d bytes\r\n",
 | 
						|
              pPort,
 | 
						|
              sizeof ( *pPort )));
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    DEBUG (( DEBUG_ERROR | DebugFlags | DEBUG_POOL,
 | 
						|
              "ERROR - Failed to free pPort: 0x%08x, Status: %r\r\n",
 | 
						|
              pPort,
 | 
						|
              Status ));
 | 
						|
    ASSERT ( EFI_SUCCESS == Status );
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  //  Mark the socket as closed if necessary
 | 
						|
  //
 | 
						|
  if ( NULL == pSocket->pPortList ) {
 | 
						|
    pSocket->State = SOCKET_STATE_CLOSED;
 | 
						|
    DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
 | 
						|
              "0x%08x: Socket State: SOCKET_STATE_CLOSED\r\n",
 | 
						|
              pSocket ));
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  //  Return the operation status
 | 
						|
  //
 | 
						|
  DBG_EXIT_STATUS ( Status );
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/** Port close state 3.
 | 
						|
 | 
						|
  This routine attempts to complete the port close operation.
 | 
						|
 | 
						|
  This routine is called by the TCP layer upon completion of
 | 
						|
  the close operation and by ::EslSocketPortCloseTxDone.
 | 
						|
  See the \ref PortCloseStateMachine section.
 | 
						|
 | 
						|
  @param[in]  Event     The close completion event
 | 
						|
  @param[in]  pPort     Address of an ::ESL_PORT structure.
 | 
						|
**/
 | 
						|
VOID
 | 
						|
EslSocketPortCloseComplete (
 | 
						|
  IN EFI_EVENT Event,
 | 
						|
  IN ESL_PORT * pPort
 | 
						|
  )
 | 
						|
{
 | 
						|
  ESL_IO_MGMT * pIo;
 | 
						|
  EFI_STATUS Status;
 | 
						|
 | 
						|
  DBG_ENTER ( );
 | 
						|
  VERIFY_AT_TPL ( TPL_SOCKETS );
 | 
						|
 | 
						|
  //  Update the port state
 | 
						|
  pPort->State = PORT_STATE_CLOSE_DONE;
 | 
						|
  DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
 | 
						|
            "0x%08x: Port Close State: PORT_STATE_CLOSE_DONE\r\n",
 | 
						|
            pPort ));
 | 
						|
 | 
						|
  //  Shutdown the receive operation on the port
 | 
						|
  if ( NULL != pPort->pfnRxCancel ) {
 | 
						|
    pIo = pPort->pRxActive;
 | 
						|
    while ( NULL != pIo ) {
 | 
						|
      EslSocketRxCancel ( pPort, pIo );
 | 
						|
      pIo = pIo->pNext;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //  Determine if the receive operation is pending
 | 
						|
  Status = EslSocketPortCloseRxDone ( pPort );
 | 
						|
  DBG_EXIT_STATUS ( Status );
 | 
						|
  --Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/** Port close state 4.
 | 
						|
 | 
						|
  This routine determines the state of the receive operations and
 | 
						|
  continues the close operation after the pending receive operations
 | 
						|
  are cancelled.
 | 
						|
 | 
						|
  This routine is called by
 | 
						|
  <ul>
 | 
						|
    <li>::EslSocketPortCloseComplete</li>
 | 
						|
    <li>::EslSocketPortCloseTxDone</li>
 | 
						|
    <li>::EslSocketRxComplete</li>
 | 
						|
  </ul>
 | 
						|
  to determine the state of the receive operations.
 | 
						|
  See the \ref PortCloseStateMachine section.
 | 
						|
 | 
						|
  @param[in]  pPort       Address of an ::ESL_PORT structure.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS         The port is closed
 | 
						|
  @retval EFI_NOT_READY       The port is still closing
 | 
						|
  @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
 | 
						|
                              most likely the routine was called already.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EslSocketPortCloseRxDone (
 | 
						|
  IN ESL_PORT * pPort
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS Status;
 | 
						|
 | 
						|
  DBG_ENTER ( );
 | 
						|
 | 
						|
  //
 | 
						|
  //  Verify the socket layer synchronization
 | 
						|
  //
 | 
						|
  VERIFY_TPL ( TPL_SOCKETS );
 | 
						|
 | 
						|
  //
 | 
						|
  //  Verify that the port is closing
 | 
						|
  //
 | 
						|
  Status = EFI_ALREADY_STARTED;
 | 
						|
  if ( PORT_STATE_CLOSE_DONE == pPort->State ) {
 | 
						|
    //
 | 
						|
    //  Determine if the receive operation is pending
 | 
						|
    //
 | 
						|
    Status = EFI_NOT_READY;
 | 
						|
    if ( NULL == pPort->pRxActive ) {
 | 
						|
      //
 | 
						|
      //  The receive operation is complete
 | 
						|
      //  Update the port state
 | 
						|
      //
 | 
						|
      pPort->State = PORT_STATE_CLOSE_RX_DONE;
 | 
						|
      DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
 | 
						|
                "0x%08x: Port Close State: PORT_STATE_CLOSE_RX_DONE\r\n",
 | 
						|
                pPort ));
 | 
						|
 | 
						|
      //
 | 
						|
      //  Complete the port close operation
 | 
						|
      //
 | 
						|
      Status = EslSocketPortClose ( pPort );
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      DEBUG_CODE_BEGIN ();
 | 
						|
      {
 | 
						|
        ESL_IO_MGMT * pIo;
 | 
						|
        //
 | 
						|
        //  Display the outstanding receive operations
 | 
						|
        //
 | 
						|
        DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
 | 
						|
                  "0x%08x: Port Close: Receive still pending!\r\n",
 | 
						|
                  pPort ));
 | 
						|
        pIo = pPort->pRxActive;
 | 
						|
        while ( NULL != pIo ) {
 | 
						|
          DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
 | 
						|
                    "0x%08x: Packet pending on network adapter\r\n",
 | 
						|
                    pIo->pPacket ));
 | 
						|
          pIo = pIo->pNext;
 | 
						|
        }
 | 
						|
      }
 | 
						|
      DEBUG_CODE_END ( );
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  //  Return the operation status
 | 
						|
  //
 | 
						|
  DBG_EXIT_STATUS ( Status );
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/** Start the close operation on a port, state 1.
 | 
						|
 | 
						|
  This routine marks the port as closed and initiates the \ref
 | 
						|
  PortCloseStateMachine. The first step is to allow the \ref
 | 
						|
  TransmitEngine to run down.
 | 
						|
 | 
						|
  This routine is called by ::EslSocketCloseStart to initiate the socket
 | 
						|
  network specific close operation on the socket.
 | 
						|
 | 
						|
  @param[in]  pPort       Address of an ::ESL_PORT structure.
 | 
						|
  @param[in]  bCloseNow   Set TRUE to abort active transfers
 | 
						|
  @param[in]  DebugFlags  Flags for debug messages
 | 
						|
 | 
						|
  @retval EFI_SUCCESS         The port is closed, not normally returned
 | 
						|
  @retval EFI_NOT_READY       The port has started the closing process
 | 
						|
  @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
 | 
						|
                              most likely the routine was called already.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EslSocketPortCloseStart (
 | 
						|
  IN ESL_PORT * pPort,
 | 
						|
  IN BOOLEAN bCloseNow,
 | 
						|
  IN UINTN DebugFlags
 | 
						|
  )
 | 
						|
{
 | 
						|
  ESL_SOCKET * pSocket;
 | 
						|
  EFI_STATUS Status;
 | 
						|
 | 
						|
  DBG_ENTER ( );
 | 
						|
 | 
						|
  //
 | 
						|
  //  Verify the socket layer synchronization
 | 
						|
  //
 | 
						|
  VERIFY_TPL ( TPL_SOCKETS );
 | 
						|
 | 
						|
  //
 | 
						|
  //  Mark the port as closing
 | 
						|
  //
 | 
						|
  Status = EFI_ALREADY_STARTED;
 | 
						|
  pSocket = pPort->pSocket;
 | 
						|
  pSocket->errno = EALREADY;
 | 
						|
  if ( PORT_STATE_CLOSE_STARTED > pPort->State ) {
 | 
						|
 | 
						|
    //
 | 
						|
    //  Update the port state
 | 
						|
    //
 | 
						|
    pPort->State = PORT_STATE_CLOSE_STARTED;
 | 
						|
    DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
 | 
						|
              "0x%08x: Port Close State: PORT_STATE_CLOSE_STARTED\r\n",
 | 
						|
              pPort ));
 | 
						|
    pPort->bCloseNow = bCloseNow;
 | 
						|
    pPort->DebugFlags = DebugFlags;
 | 
						|
 | 
						|
    //
 | 
						|
    //  Determine if transmits are complete
 | 
						|
    //
 | 
						|
    Status = EslSocketPortCloseTxDone ( pPort );
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  //  Return the operation status
 | 
						|
  //
 | 
						|
  DBG_EXIT_STATUS ( Status );
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/** Port close state 2.
 | 
						|
 | 
						|
  This routine determines the state of the transmit engine and
 | 
						|
  continue the close operation after the transmission is complete.
 | 
						|
  The next step is to stop the \ref ReceiveEngine.
 | 
						|
  See the \ref PortCloseStateMachine section.
 | 
						|
 | 
						|
  This routine is called by ::EslSocketPortCloseStart to determine
 | 
						|
  if the transmission is complete.
 | 
						|
 | 
						|
  @param[in]  pPort           Address of an ::ESL_PORT structure.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS         The port is closed, not normally returned
 | 
						|
  @retval EFI_NOT_READY       The port is still closing
 | 
						|
  @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
 | 
						|
                              most likely the routine was called already.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EslSocketPortCloseTxDone (
 | 
						|
  IN ESL_PORT * pPort
 | 
						|
  )
 | 
						|
{
 | 
						|
  ESL_IO_MGMT * pIo;
 | 
						|
  ESL_SOCKET * pSocket;
 | 
						|
  EFI_STATUS Status;
 | 
						|
 | 
						|
  DBG_ENTER ( );
 | 
						|
 | 
						|
  //
 | 
						|
  //  Verify the socket layer synchronization
 | 
						|
  //
 | 
						|
  VERIFY_TPL ( TPL_SOCKETS );
 | 
						|
 | 
						|
  //
 | 
						|
  //  All transmissions are complete or must be stopped
 | 
						|
  //  Mark the port as TX complete
 | 
						|
  //
 | 
						|
  Status = EFI_ALREADY_STARTED;
 | 
						|
  if ( PORT_STATE_CLOSE_STARTED == pPort->State ) {
 | 
						|
    //
 | 
						|
    //  Verify that the transmissions are complete
 | 
						|
    //
 | 
						|
    pSocket = pPort->pSocket;
 | 
						|
    if ( pPort->bCloseNow
 | 
						|
         || ( EFI_SUCCESS != pSocket->TxError )
 | 
						|
         || (( NULL == pPort->pTxActive )
 | 
						|
                && ( NULL == pPort->pTxOobActive ))) {
 | 
						|
      //
 | 
						|
      //  Update the port state
 | 
						|
      //
 | 
						|
      pPort->State = PORT_STATE_CLOSE_TX_DONE;
 | 
						|
      DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
 | 
						|
                "0x%08x: Port Close State: PORT_STATE_CLOSE_TX_DONE\r\n",
 | 
						|
                pPort ));
 | 
						|
 | 
						|
      //
 | 
						|
      //  Close the port
 | 
						|
      //  Skip the close operation if the port is not configured
 | 
						|
      //
 | 
						|
      Status = EFI_SUCCESS;
 | 
						|
      pSocket = pPort->pSocket;
 | 
						|
      if (( pPort->bConfigured )
 | 
						|
        && ( NULL != pSocket->pApi->pfnPortCloseOp )) {
 | 
						|
          //
 | 
						|
          //  Start the close operation
 | 
						|
          //
 | 
						|
          Status = pSocket->pApi->pfnPortCloseOp ( pPort );
 | 
						|
          DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
 | 
						|
                    "0x%08x: Port Close: Close operation still pending!\r\n",
 | 
						|
                    pPort ));
 | 
						|
          ASSERT ( EFI_SUCCESS == Status );
 | 
						|
      }
 | 
						|
      else {
 | 
						|
        //
 | 
						|
        //  The receive operation is complete
 | 
						|
        //  Update the port state
 | 
						|
        //
 | 
						|
        EslSocketPortCloseComplete ( NULL, pPort );
 | 
						|
      }
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      //
 | 
						|
      //  Transmissions are still active, exit
 | 
						|
      //
 | 
						|
      Status = EFI_NOT_READY;
 | 
						|
      pSocket->errno = EAGAIN;
 | 
						|
      DEBUG_CODE_BEGIN ( );
 | 
						|
      {
 | 
						|
        ESL_PACKET * pPacket;
 | 
						|
 | 
						|
        DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
 | 
						|
                  "0x%08x: Port Close: Transmits are still pending!\r\n",
 | 
						|
                  pPort ));
 | 
						|
 | 
						|
        //
 | 
						|
        //  Display the pending urgent transmit packets
 | 
						|
        //
 | 
						|
        pPacket = pSocket->pTxOobPacketListHead;
 | 
						|
        while ( NULL != pPacket ) {
 | 
						|
          DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
 | 
						|
                    "0x%08x: Packet pending on urgent TX list, %d bytes\r\n",
 | 
						|
                    pPacket,
 | 
						|
                    pPacket->PacketSize ));
 | 
						|
          pPacket = pPacket->pNext;
 | 
						|
        }
 | 
						|
 | 
						|
        pIo = pPort->pTxOobActive;
 | 
						|
        while ( NULL != pIo ) {
 | 
						|
          pPacket = pIo->pPacket;
 | 
						|
          DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
 | 
						|
                    "0x%08x: Packet active %d bytes, pIo: 0x%08x\r\n",
 | 
						|
                    pPacket,
 | 
						|
                    pPacket->PacketSize,
 | 
						|
                    pIo ));
 | 
						|
          pIo = pIo->pNext;
 | 
						|
        }
 | 
						|
 | 
						|
        //
 | 
						|
        //  Display the pending normal transmit packets
 | 
						|
        //
 | 
						|
        pPacket = pSocket->pTxPacketListHead;
 | 
						|
        while ( NULL != pPacket ) {
 | 
						|
          DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
 | 
						|
                    "0x%08x: Packet pending on normal TX list, %d bytes\r\n",
 | 
						|
                    pPacket,
 | 
						|
                    pPacket->PacketSize ));
 | 
						|
          pPacket = pPacket->pNext;
 | 
						|
        }
 | 
						|
 | 
						|
        pIo = pPort->pTxActive;
 | 
						|
        while ( NULL != pIo ) {
 | 
						|
          pPacket = pIo->pPacket;
 | 
						|
          DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
 | 
						|
                    "0x%08x: Packet active %d bytes, pIo: 0x%08x\r\n",
 | 
						|
                    pPacket,
 | 
						|
                    pPacket->PacketSize,
 | 
						|
                    pIo ));
 | 
						|
          pIo = pIo->pNext;
 | 
						|
        }
 | 
						|
      }
 | 
						|
      DEBUG_CODE_END ();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  //  Return the operation status
 | 
						|
  //
 | 
						|
  DBG_EXIT_STATUS ( Status );
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/** Receive data from a network connection.
 | 
						|
 | 
						|
  This routine calls the network specific routine to remove the
 | 
						|
  next portion of data from the receive queue and return it to the
 | 
						|
  caller.
 | 
						|
 | 
						|
  The ::recvfrom routine calls this routine to determine if any data
 | 
						|
  is received from the remote system.  Note that the other routines
 | 
						|
  ::recv and ::read are layered on top of ::recvfrom.
 | 
						|
 | 
						|
  @param[in]      pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
 | 
						|
  @param[in]      Flags           Message control flags
 | 
						|
  @param[in]      BufferLength    Length of the the buffer
 | 
						|
  @param[in]      pBuffer         Address of a buffer to receive the data.
 | 
						|
  @param[in]      pDataLength     Number of received data bytes in the buffer.
 | 
						|
  @param[out]     pAddress        Network address to receive the remote system address
 | 
						|
  @param[in,out]  pAddressLength  Length of the remote network address structure
 | 
						|
  @param[out]     pErrno          Address to receive the errno value upon completion.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS - Socket data successfully received
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EslSocketReceive (
 | 
						|
  IN EFI_SOCKET_PROTOCOL * pSocketProtocol,
 | 
						|
  IN INT32 Flags,
 | 
						|
  IN size_t BufferLength,
 | 
						|
  IN UINT8 * pBuffer,
 | 
						|
  OUT size_t * pDataLength,
 | 
						|
  OUT struct sockaddr * pAddress,
 | 
						|
  IN OUT socklen_t * pAddressLength,
 | 
						|
  IN int * pErrno
 | 
						|
  )
 | 
						|
{
 | 
						|
  union {
 | 
						|
    struct sockaddr_in v4;
 | 
						|
    struct sockaddr_in6 v6;
 | 
						|
  } Addr;
 | 
						|
  socklen_t AddressLength;
 | 
						|
  BOOLEAN bConsumePacket;
 | 
						|
  BOOLEAN bUrgentQueue;
 | 
						|
  size_t DataLength;
 | 
						|
  ESL_PACKET * pNextPacket;
 | 
						|
  ESL_PACKET * pPacket;
 | 
						|
  ESL_PORT * pPort;
 | 
						|
  ESL_PACKET ** ppQueueHead;
 | 
						|
  ESL_PACKET ** ppQueueTail;
 | 
						|
  struct sockaddr * pRemoteAddress;
 | 
						|
  size_t * pRxDataBytes;
 | 
						|
  ESL_SOCKET * pSocket;
 | 
						|
  size_t SkipBytes;
 | 
						|
  EFI_STATUS Status;
 | 
						|
  EFI_TPL TplPrevious;
 | 
						|
 | 
						|
  DBG_ENTER ( );
 | 
						|
 | 
						|
  //
 | 
						|
  //  Assume success
 | 
						|
  //
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
 | 
						|
  //
 | 
						|
  //  Validate the socket
 | 
						|
  //
 | 
						|
  pSocket = NULL;
 | 
						|
  if ( NULL != pSocketProtocol ) {
 | 
						|
    pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
 | 
						|
 | 
						|
    //
 | 
						|
    //  Validate the return address parameters
 | 
						|
    //
 | 
						|
    if (( NULL == pAddress ) || ( NULL != pAddressLength )) {
 | 
						|
      //
 | 
						|
      //  Return the transmit error if necessary
 | 
						|
      //
 | 
						|
      if ( EFI_SUCCESS != pSocket->TxError ) {
 | 
						|
        pSocket->errno = EIO;
 | 
						|
        Status = pSocket->TxError;
 | 
						|
        pSocket->TxError = EFI_SUCCESS;
 | 
						|
      }
 | 
						|
      else {
 | 
						|
        //
 | 
						|
        //  Verify the socket state
 | 
						|
        //
 | 
						|
        Status = EslSocketIsConfigured ( pSocket );
 | 
						|
        if ( !EFI_ERROR ( Status )) {
 | 
						|
          //
 | 
						|
          //  Validate the buffer length
 | 
						|
          //
 | 
						|
          if (( NULL == pDataLength )
 | 
						|
            || ( NULL == pBuffer )) {
 | 
						|
            if ( NULL == pDataLength ) {
 | 
						|
              DEBUG (( DEBUG_RX,
 | 
						|
                        "ERROR - pDataLength is NULL!\r\n" ));
 | 
						|
            }
 | 
						|
            else {
 | 
						|
              DEBUG (( DEBUG_RX,
 | 
						|
                        "ERROR - pBuffer is NULL!\r\n" ));
 | 
						|
            }
 | 
						|
            Status = EFI_INVALID_PARAMETER;
 | 
						|
            pSocket->errno = EFAULT;
 | 
						|
          }
 | 
						|
          else {
 | 
						|
            //
 | 
						|
            //  Verify the API
 | 
						|
            //
 | 
						|
            if ( NULL == pSocket->pApi->pfnReceive ) {
 | 
						|
              Status = EFI_UNSUPPORTED;
 | 
						|
              pSocket->errno = ENOTSUP;
 | 
						|
            }
 | 
						|
            else {
 | 
						|
              //
 | 
						|
              //  Zero the receive address if being returned
 | 
						|
              //
 | 
						|
              pRemoteAddress = NULL;
 | 
						|
              if ( NULL != pAddress ) {
 | 
						|
                pRemoteAddress = (struct sockaddr *)&Addr;
 | 
						|
                ZeroMem ( pRemoteAddress, sizeof ( Addr ));
 | 
						|
                pRemoteAddress->sa_family = pSocket->pApi->AddressFamily;
 | 
						|
                pRemoteAddress->sa_len = (UINT8)pSocket->pApi->AddressLength;
 | 
						|
              }
 | 
						|
 | 
						|
              //
 | 
						|
              //  Synchronize with the socket layer
 | 
						|
              //
 | 
						|
              RAISE_TPL ( TplPrevious, TPL_SOCKETS );
 | 
						|
 | 
						|
              //
 | 
						|
              //  Assume failure
 | 
						|
              //
 | 
						|
              Status = EFI_UNSUPPORTED;
 | 
						|
              pSocket->errno = ENOTCONN;
 | 
						|
 | 
						|
              //
 | 
						|
              //  Verify that the socket is connected
 | 
						|
              //
 | 
						|
              if ( SOCKET_STATE_CONNECTED == pSocket->State ) {
 | 
						|
                //
 | 
						|
                //  Poll the network to increase performance
 | 
						|
                //
 | 
						|
                EslSocketRxPoll ( pSocket );
 | 
						|
 | 
						|
                //
 | 
						|
                //  Locate the port
 | 
						|
                //
 | 
						|
                pPort = pSocket->pPortList;
 | 
						|
                if ( NULL != pPort ) {
 | 
						|
                  //
 | 
						|
                  //  Determine the queue head
 | 
						|
                  //
 | 
						|
                  bUrgentQueue = (BOOLEAN)( 0 != ( Flags & MSG_OOB ));
 | 
						|
                  if ( bUrgentQueue ) {
 | 
						|
                    ppQueueHead = &pSocket->pRxOobPacketListHead;
 | 
						|
                    ppQueueTail = &pSocket->pRxOobPacketListTail;
 | 
						|
                    pRxDataBytes = &pSocket->RxOobBytes;
 | 
						|
                  }
 | 
						|
                  else {
 | 
						|
                    ppQueueHead = &pSocket->pRxPacketListHead;
 | 
						|
                    ppQueueTail = &pSocket->pRxPacketListTail;
 | 
						|
                    pRxDataBytes = &pSocket->RxBytes;
 | 
						|
                  }
 | 
						|
 | 
						|
                  //
 | 
						|
                  //  Determine if there is any data on the queue
 | 
						|
                  //
 | 
						|
                  *pDataLength = 0;
 | 
						|
                  pPacket = *ppQueueHead;
 | 
						|
                  if ( NULL != pPacket ) {
 | 
						|
                    //
 | 
						|
                    //  Copy the received data
 | 
						|
                    //
 | 
						|
                    do {
 | 
						|
                      //
 | 
						|
                      //  Attempt to receive a packet
 | 
						|
                      //
 | 
						|
                      SkipBytes = 0;
 | 
						|
                      bConsumePacket = (BOOLEAN)( 0 == ( Flags & MSG_PEEK ));
 | 
						|
                      pBuffer = pSocket->pApi->pfnReceive ( pPort,
 | 
						|
                                                            pPacket,
 | 
						|
                                                            &bConsumePacket,
 | 
						|
                                                            BufferLength,
 | 
						|
                                                            pBuffer,
 | 
						|
                                                            &DataLength,
 | 
						|
                                                            (struct sockaddr *)&Addr,
 | 
						|
                                                            &SkipBytes );
 | 
						|
                      *pDataLength += DataLength;
 | 
						|
                      BufferLength -= DataLength;
 | 
						|
 | 
						|
                      //
 | 
						|
                      //  Determine if the data is being read
 | 
						|
                      //
 | 
						|
                      pNextPacket = pPacket->pNext;
 | 
						|
                      if ( bConsumePacket ) {
 | 
						|
                        //
 | 
						|
                        //  All done with this packet
 | 
						|
                        //  Account for any discarded data
 | 
						|
                        //
 | 
						|
                        pSocket->pApi->pfnPacketFree ( pPacket, pRxDataBytes );
 | 
						|
                        if ( 0 != SkipBytes ) {
 | 
						|
                          DEBUG (( DEBUG_RX,
 | 
						|
                                    "0x%08x: Port, packet read, skipping over 0x%08x bytes\r\n",
 | 
						|
                                    pPort,
 | 
						|
                                    SkipBytes ));
 | 
						|
                        }
 | 
						|
 | 
						|
                        //
 | 
						|
                        //  Remove this packet from the queue
 | 
						|
                        //
 | 
						|
                        *ppQueueHead = pPacket->pNext;
 | 
						|
                        if ( NULL == *ppQueueHead ) {
 | 
						|
                          *ppQueueTail = NULL;
 | 
						|
                        }
 | 
						|
 | 
						|
                        //
 | 
						|
                        //  Move the packet to the free queue
 | 
						|
                        //
 | 
						|
                        pPacket->pNext = pSocket->pRxFree;
 | 
						|
                        pSocket->pRxFree = pPacket;
 | 
						|
                        DEBUG (( DEBUG_RX,
 | 
						|
                                  "0x%08x: Port freeing packet 0x%08x\r\n",
 | 
						|
                                  pPort,
 | 
						|
                                  pPacket ));
 | 
						|
 | 
						|
                        //
 | 
						|
                        //  Restart the receive operation if necessary
 | 
						|
                        //
 | 
						|
                        if (( NULL != pPort->pRxFree )
 | 
						|
                          && ( MAX_RX_DATA > pSocket->RxBytes )) {
 | 
						|
                            EslSocketRxStart ( pPort );
 | 
						|
                        }
 | 
						|
                      }
 | 
						|
 | 
						|
                      //
 | 
						|
                      //  Get the next packet
 | 
						|
                      //
 | 
						|
                      pPacket = pNextPacket;
 | 
						|
                    } while (( SOCK_STREAM == pSocket->Type )
 | 
						|
                          && ( NULL != pPacket )
 | 
						|
                          && ( 0 < BufferLength ));
 | 
						|
 | 
						|
                    //
 | 
						|
                    //  Successful operation
 | 
						|
                    //
 | 
						|
                    Status = EFI_SUCCESS;
 | 
						|
                    pSocket->errno = 0;
 | 
						|
                  }
 | 
						|
                  else {
 | 
						|
                    //
 | 
						|
                    //  The queue is empty
 | 
						|
                    //  Determine if it is time to return the receive error
 | 
						|
                    //
 | 
						|
                    if ( EFI_ERROR ( pSocket->RxError )
 | 
						|
                      && ( NULL == pSocket->pRxPacketListHead )
 | 
						|
                      && ( NULL == pSocket->pRxOobPacketListHead )) {
 | 
						|
                      Status = pSocket->RxError;
 | 
						|
                      pSocket->RxError = EFI_SUCCESS;
 | 
						|
                      switch ( Status ) {
 | 
						|
                      default:
 | 
						|
                        pSocket->errno = EIO;
 | 
						|
                        break;
 | 
						|
 | 
						|
                      case EFI_CONNECTION_FIN:
 | 
						|
                        //
 | 
						|
                        //  Continue to return zero bytes received when the
 | 
						|
                        //  peer has successfully closed the connection
 | 
						|
                        //
 | 
						|
                        pSocket->RxError = EFI_CONNECTION_FIN;
 | 
						|
                        *pDataLength = 0;
 | 
						|
                        pSocket->errno = 0;
 | 
						|
                        Status = EFI_SUCCESS;
 | 
						|
                        break;
 | 
						|
 | 
						|
                      case EFI_CONNECTION_REFUSED:
 | 
						|
                        pSocket->errno = ECONNREFUSED;
 | 
						|
                        break;
 | 
						|
 | 
						|
                      case EFI_CONNECTION_RESET:
 | 
						|
                        pSocket->errno = ECONNRESET;
 | 
						|
                        break;
 | 
						|
 | 
						|
                      case EFI_HOST_UNREACHABLE:
 | 
						|
                        pSocket->errno = EHOSTUNREACH;
 | 
						|
                        break;
 | 
						|
 | 
						|
                      case EFI_NETWORK_UNREACHABLE:
 | 
						|
                        pSocket->errno = ENETUNREACH;
 | 
						|
                        break;
 | 
						|
 | 
						|
                      case EFI_PORT_UNREACHABLE:
 | 
						|
                        pSocket->errno = EPROTONOSUPPORT;
 | 
						|
                        break;
 | 
						|
 | 
						|
                      case EFI_PROTOCOL_UNREACHABLE:
 | 
						|
                        pSocket->errno = ENOPROTOOPT;
 | 
						|
                        break;
 | 
						|
                      }
 | 
						|
                    }
 | 
						|
                    else {
 | 
						|
                      Status = EFI_NOT_READY;
 | 
						|
                      pSocket->errno = EAGAIN;
 | 
						|
                    }
 | 
						|
                  }
 | 
						|
                }
 | 
						|
              }
 | 
						|
 | 
						|
              //
 | 
						|
              //  Release the socket layer synchronization
 | 
						|
              //
 | 
						|
              RESTORE_TPL ( TplPrevious );
 | 
						|
 | 
						|
              if (( !EFI_ERROR ( Status )) && ( NULL != pAddress )) {
 | 
						|
                //
 | 
						|
                //  Return the remote address if requested, truncate if necessary
 | 
						|
                //
 | 
						|
                AddressLength = pRemoteAddress->sa_len;
 | 
						|
                if ( AddressLength > *pAddressLength ) {
 | 
						|
                  AddressLength = *pAddressLength;
 | 
						|
                }
 | 
						|
                DEBUG (( DEBUG_RX,
 | 
						|
                          "Returning the remote address, 0x%016x bytes --> 0x%16x\r\n", *pAddressLength, pAddress ));
 | 
						|
                ZeroMem ( pAddress, *pAddressLength );
 | 
						|
                CopyMem ( pAddress, &Addr, AddressLength );
 | 
						|
 | 
						|
                //
 | 
						|
                //  Update the address length
 | 
						|
                //
 | 
						|
                *pAddressLength = pRemoteAddress->sa_len;
 | 
						|
              }
 | 
						|
            }
 | 
						|
          }
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      //
 | 
						|
      //  Bad return address pointer and length
 | 
						|
      //
 | 
						|
      Status = EFI_INVALID_PARAMETER;
 | 
						|
      pSocket->errno = EINVAL;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  //  Return the operation status
 | 
						|
  //
 | 
						|
  if ( NULL != pErrno ) {
 | 
						|
    if ( NULL != pSocket ) {
 | 
						|
      *pErrno = pSocket->errno;
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      Status = EFI_INVALID_PARAMETER;
 | 
						|
      *pErrno = ENOTSOCK;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  DBG_EXIT_STATUS ( Status );
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/** Cancel the receive operations.
 | 
						|
 | 
						|
  This routine cancels a pending receive operation.
 | 
						|
  See the \ref ReceiveEngine section.
 | 
						|
 | 
						|
  This routine is called by ::EslSocketShutdown when the socket
 | 
						|
  layer is being shutdown.
 | 
						|
 | 
						|
  @param[in]  pPort     Address of an ::ESL_PORT structure
 | 
						|
  @param[in]  pIo       Address of an ::ESL_IO_MGMT structure
 | 
						|
**/
 | 
						|
VOID
 | 
						|
EslSocketRxCancel (
 | 
						|
  IN ESL_PORT * pPort,
 | 
						|
  IN ESL_IO_MGMT * pIo
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS Status;
 | 
						|
 | 
						|
  DBG_ENTER ( );
 | 
						|
 | 
						|
  //
 | 
						|
  //  Cancel the outstanding receive
 | 
						|
  //
 | 
						|
  Status = pPort->pfnRxCancel ( pPort->pProtocol.v,
 | 
						|
                                &pIo->Token );
 | 
						|
  if ( !EFI_ERROR ( Status )) {
 | 
						|
    DEBUG (( pPort->DebugFlags | DEBUG_CLOSE | DEBUG_INFO,
 | 
						|
              "0x%08x: Packet receive aborted on port: 0x%08x\r\n",
 | 
						|
              pIo->pPacket,
 | 
						|
              pPort ));
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    DEBUG (( pPort->DebugFlags | DEBUG_CLOSE | DEBUG_INFO,
 | 
						|
              "0x%08x: Packet receive pending on Port 0x%08x, Status: %r\r\n",
 | 
						|
              pIo->pPacket,
 | 
						|
              pPort,
 | 
						|
              Status ));
 | 
						|
  }
 | 
						|
  DBG_EXIT ( );
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/** Process the receive completion.
 | 
						|
 | 
						|
  This routine queues the data in FIFO order in either the urgent
 | 
						|
  or normal data queues depending upon the type of data received.
 | 
						|
  See the \ref ReceiveEngine section.
 | 
						|
 | 
						|
  This routine is called when some data is received by:
 | 
						|
  <ul>
 | 
						|
    <li>::EslIp4RxComplete</li>
 | 
						|
    <li>::EslTcp4RxComplete</li>
 | 
						|
    <li>::EslUdp4RxComplete</li>
 | 
						|
  </ul>
 | 
						|
 | 
						|
  @param[in]  pIo           Address of an ::ESL_IO_MGMT structure
 | 
						|
  @param[in]  Status        Receive status
 | 
						|
  @param[in]  LengthInBytes Length of the receive data
 | 
						|
  @param[in]  bUrgent       TRUE if urgent data is received and FALSE
 | 
						|
                            for normal data.
 | 
						|
**/
 | 
						|
VOID
 | 
						|
EslSocketRxComplete (
 | 
						|
  IN ESL_IO_MGMT * pIo,
 | 
						|
  IN EFI_STATUS Status,
 | 
						|
  IN UINTN LengthInBytes,
 | 
						|
  IN BOOLEAN bUrgent
 | 
						|
  )
 | 
						|
{
 | 
						|
  BOOLEAN bUrgentQueue;
 | 
						|
  ESL_IO_MGMT * pIoNext;
 | 
						|
  ESL_PACKET * pPacket;
 | 
						|
  ESL_PORT * pPort;
 | 
						|
  ESL_PACKET * pPrevious;
 | 
						|
  ESL_PACKET ** ppQueueHead;
 | 
						|
  ESL_PACKET ** ppQueueTail;
 | 
						|
  size_t * pRxBytes;
 | 
						|
  ESL_SOCKET * pSocket;
 | 
						|
 | 
						|
  DBG_ENTER ( );
 | 
						|
  VERIFY_AT_TPL ( TPL_SOCKETS );
 | 
						|
 | 
						|
  //
 | 
						|
  //  Locate the active receive packet
 | 
						|
  //
 | 
						|
  pPacket = pIo->pPacket;
 | 
						|
  pPort = pIo->pPort;
 | 
						|
  pSocket = pPort->pSocket;
 | 
						|
 | 
						|
  //
 | 
						|
  //         pPort->pRxActive
 | 
						|
  //                |
 | 
						|
  //                V
 | 
						|
  //          +-------------+   +-------------+   +-------------+
 | 
						|
  //  Active  | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
 | 
						|
  //          +-------------+   +-------------+   +-------------+
 | 
						|
  //
 | 
						|
  //          +-------------+   +-------------+   +-------------+
 | 
						|
  //  Free    | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
 | 
						|
  //          +-------------+   +-------------+   +-------------+
 | 
						|
  //                ^
 | 
						|
  //                |
 | 
						|
  //          pPort->pRxFree
 | 
						|
  //
 | 
						|
  //
 | 
						|
  //  Remove the IO structure from the active list
 | 
						|
  //  The following code searches for the entry in the list and does not
 | 
						|
  //  assume that the receive operations complete in the order they were
 | 
						|
  //  issued to the UEFI network layer.
 | 
						|
  //
 | 
						|
  pIoNext = pPort->pRxActive;
 | 
						|
  while (( NULL != pIoNext ) && ( pIoNext != pIo ) && ( pIoNext->pNext != pIo ))
 | 
						|
  {
 | 
						|
    pIoNext = pIoNext->pNext;
 | 
						|
  }
 | 
						|
  ASSERT ( NULL != pIoNext );
 | 
						|
  if ( pIoNext == pIo ) {
 | 
						|
    pPort->pRxActive = pIo->pNext;  //  Beginning of list
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    pIoNext->pNext = pIo->pNext;    //  Middle of list
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  //  Free the IO structure
 | 
						|
  //
 | 
						|
  pIo->pNext = pPort->pRxFree;
 | 
						|
  pPort->pRxFree = pIo;
 | 
						|
 | 
						|
  //
 | 
						|
  //            pRxOobPacketListHead              pRxOobPacketListTail
 | 
						|
  //                      |                                 |
 | 
						|
  //                      V                                 V
 | 
						|
  //               +------------+   +------------+   +------------+
 | 
						|
  //  Urgent Data  | ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL
 | 
						|
  //               +------------+   +------------+   +------------+
 | 
						|
  //
 | 
						|
  //               +------------+   +------------+   +------------+
 | 
						|
  //  Normal Data  | ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL
 | 
						|
  //               +------------+   +------------+   +------------+
 | 
						|
  //                      ^                                 ^
 | 
						|
  //                      |                                 |
 | 
						|
  //              pRxPacketListHead                pRxPacketListTail
 | 
						|
  //
 | 
						|
  //
 | 
						|
  //  Determine the queue to use
 | 
						|
  //
 | 
						|
  bUrgentQueue = (BOOLEAN)( bUrgent
 | 
						|
               && pSocket->pApi->bOobSupported
 | 
						|
               && ( !pSocket->bOobInLine ));
 | 
						|
  if ( bUrgentQueue ) {
 | 
						|
    ppQueueHead = &pSocket->pRxOobPacketListHead;
 | 
						|
    ppQueueTail = &pSocket->pRxOobPacketListTail;
 | 
						|
    pRxBytes = &pSocket->RxOobBytes;
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    ppQueueHead = &pSocket->pRxPacketListHead;
 | 
						|
    ppQueueTail = &pSocket->pRxPacketListTail;
 | 
						|
    pRxBytes = &pSocket->RxBytes;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  //  Determine if this receive was successful
 | 
						|
  //
 | 
						|
  if (( !EFI_ERROR ( Status ))
 | 
						|
    && ( PORT_STATE_CLOSE_STARTED > pPort->State )
 | 
						|
    && ( !pSocket->bRxDisable )) {
 | 
						|
    //
 | 
						|
    //  Account for the received data
 | 
						|
    //
 | 
						|
    *pRxBytes += LengthInBytes;
 | 
						|
 | 
						|
    //
 | 
						|
    //  Log the received data
 | 
						|
    //
 | 
						|
    DEBUG (( DEBUG_RX | DEBUG_INFO,
 | 
						|
              "0x%08x: Packet queued on %s queue of port 0x%08x with 0x%08x bytes of %s data\r\n",
 | 
						|
              pPacket,
 | 
						|
              bUrgentQueue ? L"urgent" : L"normal",
 | 
						|
              pPort,
 | 
						|
              LengthInBytes,
 | 
						|
              bUrgent ? L"urgent" : L"normal" ));
 | 
						|
 | 
						|
    //
 | 
						|
    //  Add the packet to the list tail.
 | 
						|
    //
 | 
						|
    pPacket->pNext = NULL;
 | 
						|
    pPrevious = *ppQueueTail;
 | 
						|
    if ( NULL == pPrevious ) {
 | 
						|
      *ppQueueHead = pPacket;
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      pPrevious->pNext = pPacket;
 | 
						|
    }
 | 
						|
    *ppQueueTail = pPacket;
 | 
						|
 | 
						|
    //
 | 
						|
    //  Attempt to restart this receive operation
 | 
						|
    //
 | 
						|
    if ( pSocket->MaxRxBuf > pSocket->RxBytes ) {
 | 
						|
      EslSocketRxStart ( pPort );
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      DEBUG (( DEBUG_RX,
 | 
						|
                "0x%08x: Port RX suspended, 0x%08x bytes queued\r\n",
 | 
						|
                pPort,
 | 
						|
                pSocket->RxBytes ));
 | 
						|
    }
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    if ( EFI_ERROR ( Status )) {
 | 
						|
        DEBUG (( DEBUG_RX | DEBUG_INFO,
 | 
						|
                  "ERROR - Receive error on port 0x%08x, packet 0x%08x, Status:%r\r\n",
 | 
						|
                  pPort,
 | 
						|
                  pPacket,
 | 
						|
                  Status ));
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    //  Account for the receive bytes and release the driver's buffer
 | 
						|
    //
 | 
						|
    if ( !EFI_ERROR ( Status )) {
 | 
						|
      *pRxBytes += LengthInBytes;
 | 
						|
      pSocket->pApi->pfnPacketFree ( pPacket, pRxBytes );
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    //  Receive error, free the packet save the error
 | 
						|
    //
 | 
						|
    EslSocketPacketFree ( pPacket, DEBUG_RX );
 | 
						|
    if ( !EFI_ERROR ( pSocket->RxError )) {
 | 
						|
      pSocket->RxError = Status;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    //  Update the port state
 | 
						|
    //
 | 
						|
    if ( PORT_STATE_CLOSE_STARTED <= pPort->State ) {
 | 
						|
      if ( PORT_STATE_CLOSE_DONE == pPort->State ) {
 | 
						|
        EslSocketPortCloseRxDone ( pPort );
 | 
						|
      }
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      if ( EFI_ERROR ( Status )) {
 | 
						|
        DEBUG (( DEBUG_RX | DEBUG_INFO,
 | 
						|
                  "0x%08x: Port state: PORT_STATE_RX_ERROR, Status: %r\r\n",
 | 
						|
                  pPort,
 | 
						|
                  Status ));
 | 
						|
        pPort->State = PORT_STATE_RX_ERROR;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  DBG_EXIT ( );
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/** Poll a socket for pending receive activity.
 | 
						|
 | 
						|
  This routine is called at elivated TPL and extends the idle
 | 
						|
  loop which polls a socket down into the LAN driver layer to
 | 
						|
  determine if there is any receive activity.
 | 
						|
 | 
						|
  The ::EslSocketPoll, ::EslSocketReceive and ::EslSocketTransmit
 | 
						|
  routines call this routine when there is nothing to do.
 | 
						|
 | 
						|
  @param[in]  pSocket   Address of an ::EFI_SOCKET structure.
 | 
						|
 **/
 | 
						|
VOID
 | 
						|
EslSocketRxPoll (
 | 
						|
  IN ESL_SOCKET * pSocket
 | 
						|
  )
 | 
						|
{
 | 
						|
  ESL_PORT * pPort;
 | 
						|
 | 
						|
  DEBUG (( DEBUG_POLL, "Entering EslSocketRxPoll\r\n" ));
 | 
						|
 | 
						|
  //
 | 
						|
  //  Increase the network performance by extending the
 | 
						|
  //  polling (idle) loop down into the LAN driver
 | 
						|
  //
 | 
						|
  pPort = pSocket->pPortList;
 | 
						|
  while ( NULL != pPort ) {
 | 
						|
    //
 | 
						|
    //  Poll the LAN adapter
 | 
						|
    //
 | 
						|
    pPort->pfnRxPoll ( pPort->pProtocol.v );
 | 
						|
 | 
						|
    //
 | 
						|
    //  Locate the next LAN adapter
 | 
						|
    //
 | 
						|
    pPort = pPort->pLinkSocket;
 | 
						|
  }
 | 
						|
 | 
						|
  DEBUG (( DEBUG_POLL, "Exiting EslSocketRxPoll\r\n" ));
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/** Start a receive operation.
 | 
						|
 | 
						|
  This routine posts a receive buffer to the network adapter.
 | 
						|
  See the \ref ReceiveEngine section.
 | 
						|
 | 
						|
  This support routine is called by:
 | 
						|
  <ul>
 | 
						|
    <li>::EslIp4Receive to restart the receive engine to release flow control.</li>
 | 
						|
    <li>::EslIp4RxComplete to continue the operation of the receive engine if flow control is not being applied.</li>
 | 
						|
    <li>::EslIp4SocketIsConfigured to start the receive engine for the new socket.</li>
 | 
						|
    <li>::EslTcp4ListenComplete to start the recevie engine for the new socket.</li>
 | 
						|
    <li>::EslTcp4Receive to restart the receive engine to release flow control.</li>
 | 
						|
    <li>::EslTcp4RxComplete to continue the operation of the receive engine if flow control is not being applied.</li>
 | 
						|
    <li>::EslUdp4Receive to restart the receive engine to release flow control.</li>
 | 
						|
    <li>::EslUdp4RxComplete to continue the operation of the receive engine if flow control is not being applied.</li>
 | 
						|
    <li>::EslUdp4SocketIsConfigured to start the recevie engine for the new socket.</li>
 | 
						|
  </ul>
 | 
						|
 | 
						|
  @param[in]  pPort       Address of an ::ESL_PORT structure.
 | 
						|
**/
 | 
						|
VOID
 | 
						|
EslSocketRxStart (
 | 
						|
  IN ESL_PORT * pPort
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT8 * pBuffer;
 | 
						|
  ESL_IO_MGMT * pIo;
 | 
						|
  ESL_PACKET * pPacket;
 | 
						|
  ESL_SOCKET * pSocket;
 | 
						|
  EFI_STATUS Status;
 | 
						|
 | 
						|
  DBG_ENTER ( );
 | 
						|
 | 
						|
  //
 | 
						|
  //  Determine if a receive is already pending
 | 
						|
  //
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
  pPacket = NULL;
 | 
						|
  pSocket = pPort->pSocket;
 | 
						|
  if ( !EFI_ERROR ( pPort->pSocket->RxError )) {
 | 
						|
    if (( NULL != pPort->pRxFree )
 | 
						|
      && ( !pSocket->bRxDisable )
 | 
						|
      && ( PORT_STATE_CLOSE_STARTED > pPort->State )) {
 | 
						|
      //
 | 
						|
      //  Start all of the pending receive operations
 | 
						|
      //
 | 
						|
      while ( NULL != pPort->pRxFree ) {
 | 
						|
        //
 | 
						|
        //  Determine if there are any free packets
 | 
						|
        //
 | 
						|
        pPacket = pSocket->pRxFree;
 | 
						|
        if ( NULL != pPacket ) {
 | 
						|
          //
 | 
						|
          //  Remove this packet from the free list
 | 
						|
          //
 | 
						|
          pSocket->pRxFree = pPacket->pNext;
 | 
						|
          DEBUG (( DEBUG_RX,
 | 
						|
                    "0x%08x: Port removed packet 0x%08x from free list\r\n",
 | 
						|
                    pPort,
 | 
						|
                    pPacket ));
 | 
						|
        }
 | 
						|
        else {
 | 
						|
          //
 | 
						|
          //  Allocate a packet structure
 | 
						|
          //
 | 
						|
          Status = EslSocketPacketAllocate ( &pPacket,
 | 
						|
                                             pSocket->pApi->RxPacketBytes,
 | 
						|
                                             pSocket->pApi->RxZeroBytes,
 | 
						|
                                             DEBUG_RX );
 | 
						|
          if ( EFI_ERROR ( Status )) {
 | 
						|
            pPacket = NULL;
 | 
						|
            DEBUG (( DEBUG_ERROR | DEBUG_RX,
 | 
						|
                      "0x%08x: Port failed to allocate RX packet, Status: %r\r\n",
 | 
						|
                      pPort,
 | 
						|
                      Status ));
 | 
						|
            break;
 | 
						|
          }
 | 
						|
        }
 | 
						|
 | 
						|
        //
 | 
						|
        //  Connect the IO and packet structures
 | 
						|
        //
 | 
						|
        pIo = pPort->pRxFree;
 | 
						|
        pIo->pPacket = pPacket;
 | 
						|
 | 
						|
        //
 | 
						|
        //  Eliminate the need for IP4 and UDP4 specific routines by
 | 
						|
        //  clearing the RX data pointer here.
 | 
						|
        //
 | 
						|
        //  No driver buffer for this packet
 | 
						|
        //
 | 
						|
        //    +--------------------+
 | 
						|
        //    | ESL_IO_MGMT        |
 | 
						|
        //    |                    |
 | 
						|
        //    |    +---------------+
 | 
						|
        //    |    | Token         |
 | 
						|
        //    |    |        RxData --> NULL
 | 
						|
        //    +----+---------------+
 | 
						|
        //
 | 
						|
        pBuffer = (UINT8 *)pIo;
 | 
						|
        pBuffer = &pBuffer[ pSocket->pApi->RxBufferOffset ];
 | 
						|
        *(VOID **)pBuffer = NULL;
 | 
						|
 | 
						|
        //
 | 
						|
        //  Network specific receive packet initialization
 | 
						|
        //
 | 
						|
        if ( NULL != pSocket->pApi->pfnRxStart ) {
 | 
						|
          pSocket->pApi->pfnRxStart ( pPort, pIo );
 | 
						|
        }
 | 
						|
 | 
						|
        //
 | 
						|
        //  Start the receive on the packet
 | 
						|
        //
 | 
						|
        Status = pPort->pfnRxStart ( pPort->pProtocol.v, &pIo->Token );
 | 
						|
        if ( !EFI_ERROR ( Status )) {
 | 
						|
          DEBUG (( DEBUG_RX | DEBUG_INFO,
 | 
						|
                    "0x%08x: Packet receive pending on port 0x%08x\r\n",
 | 
						|
                    pPacket,
 | 
						|
                    pPort ));
 | 
						|
          //
 | 
						|
          //  Allocate the receive control structure
 | 
						|
          //
 | 
						|
          pPort->pRxFree = pIo->pNext;
 | 
						|
 | 
						|
          //
 | 
						|
          //  Mark this receive as pending
 | 
						|
          //
 | 
						|
          pIo->pNext = pPort->pRxActive;
 | 
						|
          pPort->pRxActive = pIo;
 | 
						|
 | 
						|
        }
 | 
						|
        else {
 | 
						|
          DEBUG (( DEBUG_RX | DEBUG_INFO,
 | 
						|
                    "ERROR - Failed to post a receive on port 0x%08x, Status: %r\r\n",
 | 
						|
                    pPort,
 | 
						|
                    Status ));
 | 
						|
          if ( !EFI_ERROR ( pSocket->RxError )) {
 | 
						|
            //
 | 
						|
            //  Save the error status
 | 
						|
            //
 | 
						|
            pSocket->RxError = Status;
 | 
						|
          }
 | 
						|
 | 
						|
          //
 | 
						|
          //  Free the packet
 | 
						|
          //
 | 
						|
          pIo->pPacket = NULL;
 | 
						|
          pPacket->pNext = pSocket->pRxFree;
 | 
						|
          pSocket->pRxFree = pPacket;
 | 
						|
          break;
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      if ( NULL == pPort->pRxFree ) {
 | 
						|
        DEBUG (( DEBUG_RX | DEBUG_INFO,
 | 
						|
                  "0x%08x: Port, no available ESL_IO_MGMT structures\r\n",
 | 
						|
                  pPort));
 | 
						|
      }
 | 
						|
      if ( pSocket->bRxDisable ) {
 | 
						|
        DEBUG (( DEBUG_RX | DEBUG_INFO,
 | 
						|
                  "0x%08x: Port, receive disabled!\r\n",
 | 
						|
                  pPort ));
 | 
						|
      }
 | 
						|
      if ( PORT_STATE_CLOSE_STARTED <= pPort->State ) {
 | 
						|
        DEBUG (( DEBUG_RX | DEBUG_INFO,
 | 
						|
                  "0x%08x: Port, is closing!\r\n",
 | 
						|
                  pPort ));
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    DEBUG (( DEBUG_ERROR | DEBUG_RX,
 | 
						|
              "ERROR - Previous receive error, Status: %r\r\n",
 | 
						|
               pPort->pSocket->RxError ));
 | 
						|
  }
 | 
						|
 | 
						|
  DBG_EXIT ( );
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/** Shutdown the socket receive and transmit operations.
 | 
						|
 | 
						|
  This routine sets a flag to stop future transmissions and calls
 | 
						|
  the network specific layer to cancel the pending receive operation.
 | 
						|
 | 
						|
  The ::shutdown routine calls this routine to stop receive and transmit
 | 
						|
  operations on the socket.
 | 
						|
 | 
						|
  @param[in]  pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
 | 
						|
  @param[in]  How             Which operations to stop
 | 
						|
  @param[out] pErrno          Address to receive the errno value upon completion.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS - Socket operations successfully shutdown
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EslSocketShutdown (
 | 
						|
  IN EFI_SOCKET_PROTOCOL * pSocketProtocol,
 | 
						|
  IN int How,
 | 
						|
  IN int * pErrno
 | 
						|
  )
 | 
						|
{
 | 
						|
  ESL_IO_MGMT * pIo;
 | 
						|
  ESL_PORT * pPort;
 | 
						|
  ESL_SOCKET * pSocket;
 | 
						|
  EFI_STATUS Status;
 | 
						|
  EFI_TPL TplPrevious;
 | 
						|
 | 
						|
  DBG_ENTER ( );
 | 
						|
 | 
						|
  //
 | 
						|
  //  Assume success
 | 
						|
  //
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
 | 
						|
  //
 | 
						|
  //  Validate the socket
 | 
						|
  //
 | 
						|
  pSocket = NULL;
 | 
						|
  if ( NULL != pSocketProtocol ) {
 | 
						|
    pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
 | 
						|
 | 
						|
    //
 | 
						|
    //  Verify that the socket is connected
 | 
						|
    //
 | 
						|
    if ( pSocket->bConnected ) {
 | 
						|
      //
 | 
						|
      //  Validate the How value
 | 
						|
      //
 | 
						|
      if (( SHUT_RD <= How ) && ( SHUT_RDWR >= How )) {
 | 
						|
        //
 | 
						|
        //  Synchronize with the socket layer
 | 
						|
        //
 | 
						|
        RAISE_TPL ( TplPrevious, TPL_SOCKETS );
 | 
						|
 | 
						|
        //
 | 
						|
        //  Disable the receiver if requested
 | 
						|
        //
 | 
						|
        if (( SHUT_RD == How ) || ( SHUT_RDWR == How )) {
 | 
						|
          pSocket->bRxDisable = TRUE;
 | 
						|
        }
 | 
						|
 | 
						|
        //
 | 
						|
        //  Disable the transmitter if requested
 | 
						|
        //
 | 
						|
        if (( SHUT_WR == How ) || ( SHUT_RDWR == How )) {
 | 
						|
          pSocket->bTxDisable = TRUE;
 | 
						|
        }
 | 
						|
 | 
						|
        //
 | 
						|
        //  Cancel the pending receive operations
 | 
						|
        //
 | 
						|
        if ( pSocket->bRxDisable ) {
 | 
						|
          //
 | 
						|
          //  Walk the list of ports
 | 
						|
          //
 | 
						|
          pPort = pSocket->pPortList;
 | 
						|
          while ( NULL != pPort ) {
 | 
						|
            //
 | 
						|
            //  Walk the list of active receive operations
 | 
						|
            //
 | 
						|
            pIo = pPort->pRxActive;
 | 
						|
            while ( NULL != pIo ) {
 | 
						|
              EslSocketRxCancel ( pPort, pIo );
 | 
						|
            }
 | 
						|
 | 
						|
            //
 | 
						|
            //  Set the next port
 | 
						|
            //
 | 
						|
            pPort = pPort->pLinkSocket;
 | 
						|
          }
 | 
						|
        }
 | 
						|
 | 
						|
        //
 | 
						|
        //  Release the socket layer synchronization
 | 
						|
        //
 | 
						|
        RESTORE_TPL ( TplPrevious );
 | 
						|
      }
 | 
						|
      else {
 | 
						|
        //
 | 
						|
        //  Invalid How value
 | 
						|
        //
 | 
						|
        pSocket->errno = EINVAL;
 | 
						|
        Status = EFI_INVALID_PARAMETER;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      //
 | 
						|
      //  The socket is not connected
 | 
						|
      //
 | 
						|
      pSocket->errno = ENOTCONN;
 | 
						|
      Status = EFI_NOT_STARTED;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  //  Return the operation status
 | 
						|
  //
 | 
						|
  if ( NULL != pErrno ) {
 | 
						|
    if ( NULL != pSocket ) {
 | 
						|
      *pErrno = pSocket->errno;
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      Status = EFI_INVALID_PARAMETER;
 | 
						|
      *pErrno = ENOTSOCK;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  DBG_EXIT_STATUS ( Status );
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/** Send data using a network connection.
 | 
						|
 | 
						|
  This routine calls the network specific layer to queue the data
 | 
						|
  for transmission.  Eventually the buffer will reach the head of
 | 
						|
  the queue and will get transmitted over the network by the
 | 
						|
  \ref TransmitEngine.  For datagram
 | 
						|
  sockets (SOCK_DGRAM and SOCK_RAW) there is no guarantee that
 | 
						|
  the data reaches the application running on the remote system.
 | 
						|
 | 
						|
  The ::sendto routine calls this routine to send data to the remote
 | 
						|
  system.  Note that ::send and ::write are layered on top of ::sendto.
 | 
						|
 | 
						|
  @param[in]  pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
 | 
						|
  @param[in]  Flags           Message control flags
 | 
						|
  @param[in]  BufferLength    Length of the the buffer
 | 
						|
  @param[in]  pBuffer         Address of a buffer containing the data to send
 | 
						|
  @param[in]  pDataLength     Address to receive the number of data bytes sent
 | 
						|
  @param[in]  pAddress        Network address of the remote system address
 | 
						|
  @param[in]  AddressLength   Length of the remote network address structure
 | 
						|
  @param[out] pErrno          Address to receive the errno value upon completion.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS - Socket data successfully queued for transmit
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EslSocketTransmit (
 | 
						|
  IN EFI_SOCKET_PROTOCOL * pSocketProtocol,
 | 
						|
  IN int Flags,
 | 
						|
  IN size_t BufferLength,
 | 
						|
  IN CONST UINT8 * pBuffer,
 | 
						|
  OUT size_t * pDataLength,
 | 
						|
  IN const struct sockaddr * pAddress,
 | 
						|
  IN socklen_t AddressLength,
 | 
						|
  IN int * pErrno
 | 
						|
  )
 | 
						|
{
 | 
						|
  ESL_SOCKET * pSocket;
 | 
						|
  EFI_STATUS Status;
 | 
						|
  EFI_TPL TplPrevious;
 | 
						|
 | 
						|
  DBG_ENTER ( );
 | 
						|
 | 
						|
  //
 | 
						|
  //  Assume success
 | 
						|
  //
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
 | 
						|
  //
 | 
						|
  //  Validate the socket
 | 
						|
  //
 | 
						|
  pSocket = NULL;
 | 
						|
  if ( NULL != pSocketProtocol ) {
 | 
						|
    pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );
 | 
						|
 | 
						|
    //
 | 
						|
    //  Return the transmit error if necessary
 | 
						|
    //
 | 
						|
    if ( EFI_SUCCESS != pSocket->TxError ) {
 | 
						|
      pSocket->errno = EIO;
 | 
						|
      Status = pSocket->TxError;
 | 
						|
      pSocket->TxError = EFI_SUCCESS;
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      //
 | 
						|
      //  Verify the socket state
 | 
						|
      //
 | 
						|
      Status = EslSocketIsConfigured ( pSocket );
 | 
						|
      if ( !EFI_ERROR ( Status )) {
 | 
						|
        //
 | 
						|
        //  Verify that transmit is still allowed
 | 
						|
        //
 | 
						|
        if ( !pSocket->bTxDisable ) {
 | 
						|
          //
 | 
						|
          //  Validate the buffer length
 | 
						|
          //
 | 
						|
          if (( NULL == pDataLength )
 | 
						|
            && ( 0 > pDataLength )
 | 
						|
            && ( NULL == pBuffer )) {
 | 
						|
            if ( NULL == pDataLength ) {
 | 
						|
              DEBUG (( DEBUG_RX,
 | 
						|
                        "ERROR - pDataLength is NULL!\r\n" ));
 | 
						|
            }
 | 
						|
            else if ( NULL == pBuffer ) {
 | 
						|
              DEBUG (( DEBUG_RX,
 | 
						|
                        "ERROR - pBuffer is NULL!\r\n" ));
 | 
						|
            }
 | 
						|
            else {
 | 
						|
              DEBUG (( DEBUG_RX,
 | 
						|
                        "ERROR - Data length < 0!\r\n" ));
 | 
						|
            }
 | 
						|
            Status = EFI_INVALID_PARAMETER;
 | 
						|
            pSocket->errno = EFAULT;
 | 
						|
          }
 | 
						|
          else {
 | 
						|
            //
 | 
						|
            //  Validate the remote network address
 | 
						|
            //
 | 
						|
            if (( NULL != pAddress )
 | 
						|
              && ( AddressLength < pAddress->sa_len )) {
 | 
						|
              DEBUG (( DEBUG_TX,
 | 
						|
                        "ERROR - Invalid sin_len field in address\r\n" ));
 | 
						|
              Status = EFI_INVALID_PARAMETER;
 | 
						|
              pSocket->errno = EFAULT;
 | 
						|
            }
 | 
						|
            else {
 | 
						|
              //
 | 
						|
              //  Verify the API
 | 
						|
              //
 | 
						|
              if ( NULL == pSocket->pApi->pfnTransmit ) {
 | 
						|
                Status = EFI_UNSUPPORTED;
 | 
						|
                pSocket->errno = ENOTSUP;
 | 
						|
              }
 | 
						|
              else {
 | 
						|
                //
 | 
						|
                //  Synchronize with the socket layer
 | 
						|
                //
 | 
						|
                RAISE_TPL ( TplPrevious, TPL_SOCKETS );
 | 
						|
 | 
						|
                //
 | 
						|
                //  Poll the network to increase performance
 | 
						|
                //
 | 
						|
                EslSocketRxPoll ( pSocket );
 | 
						|
 | 
						|
                //
 | 
						|
                //  Attempt to buffer the packet for transmission
 | 
						|
                //
 | 
						|
                Status = pSocket->pApi->pfnTransmit ( pSocket,
 | 
						|
                                                      Flags,
 | 
						|
                                                      BufferLength,
 | 
						|
                                                      pBuffer,
 | 
						|
                                                      pDataLength,
 | 
						|
                                                      pAddress,
 | 
						|
                                                      AddressLength );
 | 
						|
 | 
						|
                //
 | 
						|
                //  Release the socket layer synchronization
 | 
						|
                //
 | 
						|
                RESTORE_TPL ( TplPrevious );
 | 
						|
              }
 | 
						|
            }
 | 
						|
          }
 | 
						|
        }
 | 
						|
        else {
 | 
						|
          //
 | 
						|
          //  The transmitter was shutdown
 | 
						|
          //
 | 
						|
          pSocket->errno = EPIPE;
 | 
						|
          Status = EFI_NOT_STARTED;
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  //  Return the operation status
 | 
						|
  //
 | 
						|
  if ( NULL != pErrno ) {
 | 
						|
    if ( NULL != pSocket ) {
 | 
						|
      *pErrno = pSocket->errno;
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      Status = EFI_INVALID_PARAMETER;
 | 
						|
      *pErrno = ENOTSOCK;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  DBG_EXIT_STATUS ( Status );
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/** Complete the transmit operation.
 | 
						|
 | 
						|
  This support routine handles the transmit completion processing for
 | 
						|
  the various network layers.  It frees the ::ESL_IO_MGMT structure
 | 
						|
  and and frees packet resources by calling ::EslSocketPacketFree.
 | 
						|
  Transmit errors are logged in ESL_SOCKET::TxError.
 | 
						|
  See the \ref TransmitEngine section.
 | 
						|
 | 
						|
  This routine is called by:
 | 
						|
  <ul>
 | 
						|
    <li>::EslIp4TxComplete</li>
 | 
						|
    <li>::EslTcp4TxComplete</li>
 | 
						|
    <li>::EslTcp4TxOobComplete</li>
 | 
						|
    <li>::EslUdp4TxComplete</li>
 | 
						|
  </ul>
 | 
						|
 | 
						|
  @param[in]  pIo             Address of an ::ESL_IO_MGMT structure
 | 
						|
  @param[in]  LengthInBytes   Length of the data in bytes
 | 
						|
  @param[in]  Status          Transmit operation status
 | 
						|
  @param[in]  pQueueType      Zero terminated string describing queue type
 | 
						|
  @param[in]  ppQueueHead     Transmit queue head address
 | 
						|
  @param[in]  ppQueueTail     Transmit queue tail address
 | 
						|
  @param[in]  ppActive        Active transmit queue address
 | 
						|
  @param[in]  ppFree          Free transmit queue address
 | 
						|
**/
 | 
						|
VOID
 | 
						|
EslSocketTxComplete (
 | 
						|
  IN ESL_IO_MGMT * pIo,
 | 
						|
  IN UINT32 LengthInBytes,
 | 
						|
  IN EFI_STATUS Status,
 | 
						|
  IN CONST CHAR8 * pQueueType,
 | 
						|
  IN ESL_PACKET ** ppQueueHead,
 | 
						|
  IN ESL_PACKET ** ppQueueTail,
 | 
						|
  IN ESL_IO_MGMT ** ppActive,
 | 
						|
  IN ESL_IO_MGMT ** ppFree
 | 
						|
  )
 | 
						|
{
 | 
						|
  ESL_PACKET * pCurrentPacket;
 | 
						|
  ESL_IO_MGMT * pIoNext;
 | 
						|
  ESL_PACKET * pNextPacket;
 | 
						|
  ESL_PACKET * pPacket;
 | 
						|
  ESL_PORT * pPort;
 | 
						|
  ESL_SOCKET * pSocket;
 | 
						|
 | 
						|
  DBG_ENTER ( );
 | 
						|
  VERIFY_AT_TPL ( TPL_SOCKETS );
 | 
						|
 | 
						|
  //
 | 
						|
  //  Locate the active transmit packet
 | 
						|
  //
 | 
						|
  pPacket = pIo->pPacket;
 | 
						|
  pPort = pIo->pPort;
 | 
						|
  pSocket = pPort->pSocket;
 | 
						|
 | 
						|
  //
 | 
						|
  //  No more packet
 | 
						|
  //
 | 
						|
  pIo->pPacket = NULL;
 | 
						|
 | 
						|
  //
 | 
						|
  //  Remove the IO structure from the active list
 | 
						|
  //
 | 
						|
  pIoNext = *ppActive;
 | 
						|
  while (( NULL != pIoNext ) && ( pIoNext != pIo ) && ( pIoNext->pNext != pIo ))
 | 
						|
  {
 | 
						|
    pIoNext = pIoNext->pNext;
 | 
						|
  }
 | 
						|
  ASSERT ( NULL != pIoNext );
 | 
						|
  if ( pIoNext == pIo ) {
 | 
						|
    *ppActive = pIo->pNext;       //  Beginning of list
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    pIoNext->pNext = pIo->pNext;  //  Middle of list
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  //  Free the IO structure
 | 
						|
  //
 | 
						|
  pIo->pNext = *ppFree;
 | 
						|
  *ppFree = pIo;
 | 
						|
 | 
						|
  //
 | 
						|
  //  Display the results
 | 
						|
  //
 | 
						|
  DEBUG (( DEBUG_TX | DEBUG_INFO,
 | 
						|
            "0x%08x: pIo Released\r\n",
 | 
						|
            pIo ));
 | 
						|
 | 
						|
  //
 | 
						|
  //  Save any transmit error
 | 
						|
  //
 | 
						|
  if ( EFI_ERROR ( Status )) {
 | 
						|
    if ( !EFI_ERROR ( pSocket->TxError )) {
 | 
						|
      pSocket->TxError = Status;
 | 
						|
    }
 | 
						|
    DEBUG (( DEBUG_TX | DEBUG_INFO,
 | 
						|
              "ERROR - Transmit failure for %apacket 0x%08x, Status: %r\r\n",
 | 
						|
              pQueueType,
 | 
						|
              pPacket,
 | 
						|
              Status ));
 | 
						|
 | 
						|
    //
 | 
						|
    //  Empty the normal transmit list
 | 
						|
    //
 | 
						|
    pCurrentPacket = pPacket;
 | 
						|
    pNextPacket = *ppQueueHead;
 | 
						|
    while ( NULL != pNextPacket ) {
 | 
						|
      pPacket = pNextPacket;
 | 
						|
      pNextPacket = pPacket->pNext;
 | 
						|
      EslSocketPacketFree ( pPacket, DEBUG_TX );
 | 
						|
    }
 | 
						|
    *ppQueueHead = NULL;
 | 
						|
    *ppQueueTail = NULL;
 | 
						|
    pPacket = pCurrentPacket;
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    DEBUG (( DEBUG_TX | DEBUG_INFO,
 | 
						|
              "0x%08x: %apacket transmitted %d bytes successfully\r\n",
 | 
						|
              pPacket,
 | 
						|
              pQueueType,
 | 
						|
              LengthInBytes ));
 | 
						|
 | 
						|
    //
 | 
						|
    //  Verify the transmit engine is still running
 | 
						|
    //
 | 
						|
    if ( !pPort->bCloseNow ) {
 | 
						|
      //
 | 
						|
      //  Start the next packet transmission
 | 
						|
      //
 | 
						|
      EslSocketTxStart ( pPort,
 | 
						|
                         ppQueueHead,
 | 
						|
                         ppQueueTail,
 | 
						|
                         ppActive,
 | 
						|
                         ppFree );
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  //  Release this packet
 | 
						|
  //
 | 
						|
  EslSocketPacketFree ( pPacket, DEBUG_TX );
 | 
						|
 | 
						|
  //
 | 
						|
  //  Finish the close operation if necessary
 | 
						|
  //
 | 
						|
  if ( PORT_STATE_CLOSE_STARTED <= pPort->State ) {
 | 
						|
    //
 | 
						|
    //  Indicate that the transmit is complete
 | 
						|
    //
 | 
						|
    EslSocketPortCloseTxDone ( pPort );
 | 
						|
  }
 | 
						|
 | 
						|
  DBG_EXIT ( );
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/** Transmit data using a network connection.
 | 
						|
 | 
						|
  This support routine starts a transmit operation on the
 | 
						|
  underlying network layer.
 | 
						|
 | 
						|
  The network specific code calls this routine to start a
 | 
						|
  transmit operation.  See the \ref TransmitEngine section.
 | 
						|
 | 
						|
  @param[in]  pPort           Address of an ::ESL_PORT structure
 | 
						|
  @param[in]  ppQueueHead     Transmit queue head address
 | 
						|
  @param[in]  ppQueueTail     Transmit queue tail address
 | 
						|
  @param[in]  ppActive        Active transmit queue address
 | 
						|
  @param[in]  ppFree          Free transmit queue address
 | 
						|
**/
 | 
						|
VOID
 | 
						|
EslSocketTxStart (
 | 
						|
  IN ESL_PORT * pPort,
 | 
						|
  IN ESL_PACKET ** ppQueueHead,
 | 
						|
  IN ESL_PACKET ** ppQueueTail,
 | 
						|
  IN ESL_IO_MGMT ** ppActive,
 | 
						|
  IN ESL_IO_MGMT ** ppFree
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT8 * pBuffer;
 | 
						|
  ESL_IO_MGMT * pIo;
 | 
						|
  ESL_PACKET * pNextPacket;
 | 
						|
  ESL_PACKET * pPacket;
 | 
						|
  VOID ** ppTokenData;
 | 
						|
  ESL_SOCKET * pSocket;
 | 
						|
  EFI_STATUS Status;
 | 
						|
 | 
						|
  DBG_ENTER ( );
 | 
						|
 | 
						|
  //
 | 
						|
  //  Assume success
 | 
						|
  //
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
 | 
						|
  //
 | 
						|
  //  Get the packet from the queue head
 | 
						|
  //
 | 
						|
  pPacket = *ppQueueHead;
 | 
						|
  pIo = *ppFree;
 | 
						|
  if (( NULL != pPacket ) && ( NULL != pIo )) {
 | 
						|
    pSocket = pPort->pSocket;
 | 
						|
    //
 | 
						|
    //     *ppQueueHead: pSocket->pRxPacketListHead or pSocket->pRxOobPacketListHead
 | 
						|
    //          |
 | 
						|
    //          V
 | 
						|
    //        +------------+   +------------+   +------------+
 | 
						|
    //  Data  | ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL
 | 
						|
    //        +------------+   +------------+   +------------+
 | 
						|
    //                                                     ^
 | 
						|
    //                                                     |
 | 
						|
    //     *ppQueueTail: pSocket->pRxPacketListTail or pSocket->pRxOobPacketListTail
 | 
						|
    //
 | 
						|
    //
 | 
						|
    //  Remove the packet from the queue
 | 
						|
    //
 | 
						|
    pNextPacket = pPacket->pNext;
 | 
						|
    *ppQueueHead = pNextPacket;
 | 
						|
    if ( NULL == pNextPacket ) {
 | 
						|
      *ppQueueTail = NULL;
 | 
						|
    }
 | 
						|
    pPacket->pNext = NULL;
 | 
						|
 | 
						|
    //
 | 
						|
    //  Eliminate the need for IP4 and UDP4 specific routines by
 | 
						|
    //  connecting the token with the TX data control structure here.
 | 
						|
    //
 | 
						|
    //    +--------------------+   +--------------------+
 | 
						|
    //    | ESL_IO_MGMT        |   | ESL_PACKET         |
 | 
						|
    //    |                    |   |                    |
 | 
						|
    //    |    +---------------+   +----------------+   |
 | 
						|
    //    |    | Token         |   | Buffer Length  |   |
 | 
						|
    //    |    |        TxData --> | Buffer Address |   |
 | 
						|
    //    |    |               |   +----------------+---+
 | 
						|
    //    |    |        Event  |   | Data Buffer        |
 | 
						|
    //    +----+---------------+   |                    |
 | 
						|
    //                             +--------------------+
 | 
						|
    //
 | 
						|
    //  Compute the address of the TxData pointer in the token
 | 
						|
    //
 | 
						|
    pBuffer = (UINT8 *)&pIo->Token;
 | 
						|
    pBuffer = &pBuffer[ pSocket->TxTokenOffset ];
 | 
						|
    ppTokenData = (VOID **)pBuffer;
 | 
						|
 | 
						|
    //
 | 
						|
    //  Compute the address of the TX data control structure in the packet
 | 
						|
    //
 | 
						|
    //      * EFI_IP4_TRANSMIT_DATA
 | 
						|
    //      * EFI_TCP4_TRANSMIT_DATA
 | 
						|
    //      * EFI_UDP4_TRANSMIT_DATA
 | 
						|
    //
 | 
						|
    pBuffer = (UINT8 *)pPacket;
 | 
						|
    pBuffer = &pBuffer[ pSocket->TxPacketOffset ];
 | 
						|
 | 
						|
    //
 | 
						|
    //  Connect the token to the transmit data control structure
 | 
						|
    //
 | 
						|
    *ppTokenData = (VOID **)pBuffer;
 | 
						|
 | 
						|
    //
 | 
						|
    //  Display the results
 | 
						|
    //
 | 
						|
    DEBUG (( DEBUG_TX | DEBUG_INFO,
 | 
						|
              "0x%08x: pIo allocated for pPacket: 0x%08x\r\n",
 | 
						|
              pIo,
 | 
						|
              pPacket ));
 | 
						|
 | 
						|
    //
 | 
						|
    //  Start the transmit operation
 | 
						|
    //
 | 
						|
    Status = pPort->pfnTxStart ( pPort->pProtocol.v,
 | 
						|
                                 &pIo->Token );
 | 
						|
    if ( !EFI_ERROR ( Status )) {
 | 
						|
      //
 | 
						|
      //  Connect the structures
 | 
						|
      //
 | 
						|
      pIo->pPacket = pPacket;
 | 
						|
 | 
						|
      //
 | 
						|
      //          +-------------+   +-------------+   +-------------+
 | 
						|
      //  Free    | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
 | 
						|
      //          +-------------+   +-------------+   +-------------+
 | 
						|
      //              ^
 | 
						|
      //              |
 | 
						|
      //          *ppFree:  pPort->pTxFree or pTxOobFree
 | 
						|
      //
 | 
						|
      //
 | 
						|
      //  Remove the IO structure from the queue
 | 
						|
      //
 | 
						|
      *ppFree = pIo->pNext;
 | 
						|
 | 
						|
      //
 | 
						|
      //         *ppActive:  pPort->pTxActive or pTxOobActive
 | 
						|
      //             |
 | 
						|
      //             V
 | 
						|
      //          +-------------+   +-------------+   +-------------+
 | 
						|
      //  Active  | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
 | 
						|
      //          +-------------+   +-------------+   +-------------+
 | 
						|
      //
 | 
						|
      //
 | 
						|
      //  Mark this packet as active
 | 
						|
      //
 | 
						|
      pIo->pPacket = pPacket;
 | 
						|
      pIo->pNext = *ppActive;
 | 
						|
      *ppActive = pIo;
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      //
 | 
						|
      //  Display the transmit error
 | 
						|
      //
 | 
						|
      DEBUG (( DEBUG_TX | DEBUG_INFO,
 | 
						|
                "0x%08x, 0x%08x: pIo, pPacket transmit failure: %r\r\n",
 | 
						|
                pIo,
 | 
						|
                pPacket,
 | 
						|
                Status ));
 | 
						|
      if ( EFI_SUCCESS == pSocket->TxError ) {
 | 
						|
        pSocket->TxError = Status;
 | 
						|
      }
 | 
						|
 | 
						|
      //
 | 
						|
      //  Free the IO structure
 | 
						|
      //
 | 
						|
      pIo->pNext = *ppFree;
 | 
						|
      *ppFree = pIo;
 | 
						|
 | 
						|
      //
 | 
						|
      //  Discard the transmit buffer
 | 
						|
      //
 | 
						|
      EslSocketPacketFree ( pPacket, DEBUG_TX );
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  DBG_EXIT ( );
 | 
						|
}
 |