hikey: Add UEFI sources for reference

UEFI needs to be built outside Android build system.
Please follow the instructions in README.

The sources correspond to:
https://github.com/96boards/edk2/commit/14eae0c12e71fd33c4c0fc51e4475e8db02566cf
https://github.com/96boards/arm-trusted-firmware/commit/e9b4909dcd75fc4ae7041cfb83d28ab9adb7afdf
https://github.com/96boards/l-loader/commit/6b784ad5c4ab00e2b1c6f53cd5f74054e5d00a78
https://git.linaro.org/uefi/uefi-tools.git/commit/abe618f8ab72034fff1ce46c9c006a2c6bd40a7e

Change-Id: Ieeefdb63e673e0c8e64e0a1f02c7bddc63b2c7fb
Signed-off-by: Vishal Bhoj <vishal.bhoj@linaro.org>
diff --git a/uefi/linaro-edk2/StdLib/EfiSocketLib/Udp4.c b/uefi/linaro-edk2/StdLib/EfiSocketLib/Udp4.c
new file mode 100644
index 0000000..7fece75
--- /dev/null
+++ b/uefi/linaro-edk2/StdLib/EfiSocketLib/Udp4.c
@@ -0,0 +1,1224 @@
+/** @file

+  Implement the UDP4 driver support for the socket layer.

+

+  Copyright (c) 2011, Intel Corporation

+  All rights reserved. This program and the accompanying materials

+  are licensed and made available under the terms and conditions of the BSD License

+  which accompanies this distribution.  The full text of the license may be found at

+  http://opensource.org/licenses/bsd-license.php

+

+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,

+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.

+

+**/

+

+#include "Socket.h"

+

+

+/**

+  Get the local socket address

+

+  This routine returns the IPv4 address and UDP port number associated

+  with the local socket.

+

+  This routine is called by ::EslSocketGetLocalAddress to determine the

+  network address for the SOCK_DGRAM socket.

+

+  @param [in] pPort       Address of an ::ESL_PORT structure.

+

+  @param [out] pSockAddr  Network address to receive the local system address

+

+**/

+VOID

+EslUdp4LocalAddressGet (

+  IN ESL_PORT * pPort,

+  OUT struct sockaddr * pSockAddr

+  )

+{

+  struct sockaddr_in * pLocalAddress;

+  ESL_UDP4_CONTEXT * pUdp4;

+

+  DBG_ENTER ( );

+

+  //

+  //  Return the local address

+  //

+  pUdp4 = &pPort->Context.Udp4;

+  pLocalAddress = (struct sockaddr_in *)pSockAddr;

+  pLocalAddress->sin_family = AF_INET;

+  pLocalAddress->sin_port = SwapBytes16 ( pUdp4->ConfigData.StationPort );

+  CopyMem ( &pLocalAddress->sin_addr,

+            &pUdp4->ConfigData.StationAddress.Addr[0],

+            sizeof ( pLocalAddress->sin_addr ));

+

+  DBG_EXIT ( );

+}

+

+

+/**

+  Set the local port address.

+

+  This routine sets the local port address.

+

+  This support routine is called by ::EslSocketPortAllocate.

+

+  @param [in] pPort       Address of an ESL_PORT structure

+  @param [in] pSockAddr   Address of a sockaddr structure that contains the

+                          connection point on the local machine.  An 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 = run bind testing

+

+  @retval EFI_SUCCESS     The operation was successful

+

+ **/

+EFI_STATUS

+EslUdp4LocalAddressSet (

+  IN ESL_PORT * pPort,

+  IN CONST struct sockaddr * pSockAddr,

+  IN BOOLEAN bBindTest

+  )

+{

+  EFI_UDP4_CONFIG_DATA * pConfig;

+  CONST struct sockaddr_in * pIpAddress;

+  CONST UINT8 * pIpv4Address;

+  EFI_STATUS Status;

+

+  DBG_ENTER ( );

+

+  //

+  //  Validate the address

+  //

+  pIpAddress = (struct sockaddr_in *)pSockAddr;

+  if ( INADDR_BROADCAST == pIpAddress->sin_addr.s_addr ) {

+    //

+    //  The local address must not be the broadcast address

+    //

+    Status = EFI_INVALID_PARAMETER;

+    pPort->pSocket->errno = EADDRNOTAVAIL;

+  }

+  else {

+    //

+    //  Set the local address

+    //

+    pIpAddress = (struct sockaddr_in *)pSockAddr;

+    pIpv4Address = (UINT8 *)&pIpAddress->sin_addr.s_addr;

+    pConfig = &pPort->Context.Udp4.ConfigData;

+    pConfig->StationAddress.Addr[0] = pIpv4Address[0];

+    pConfig->StationAddress.Addr[1] = pIpv4Address[1];

+    pConfig->StationAddress.Addr[2] = pIpv4Address[2];

+    pConfig->StationAddress.Addr[3] = pIpv4Address[3];

+

+    //

+    //  Determine if the default address is used

+    //

+    pConfig->UseDefaultAddress = (BOOLEAN)( 0 == pIpAddress->sin_addr.s_addr );

+    

+    //

+    //  Set the subnet mask

+    //

+    if ( pConfig->UseDefaultAddress ) {

+      pConfig->SubnetMask.Addr[0] = 0;

+      pConfig->SubnetMask.Addr[1] = 0;

+      pConfig->SubnetMask.Addr[2] = 0;

+      pConfig->SubnetMask.Addr[3] = 0;

+    }

+    else {

+      pConfig->SubnetMask.Addr[0] = 0xff;

+      pConfig->SubnetMask.Addr[1] = ( 128 <= pConfig->StationAddress.Addr[0]) ? 0xff : 0;

+      pConfig->SubnetMask.Addr[2] = ( 192 <= pConfig->StationAddress.Addr[0]) ? 0xff : 0;

+      pConfig->SubnetMask.Addr[3] = ( 224 <= pConfig->StationAddress.Addr[0]) ? 0xff : 0;

+    }

+

+    //

+    //  Validate the IP address

+    //

+    pConfig->StationPort = 0;

+    Status = bBindTest ? EslSocketBindTest ( pPort, EADDRNOTAVAIL )

+                       : EFI_SUCCESS;

+    if ( !EFI_ERROR ( Status )) {

+      //

+      //  Set the port number

+      //

+      pConfig->StationPort = SwapBytes16 ( pIpAddress->sin_port );

+

+      //

+      //  Display the local address

+      //

+      DEBUG (( DEBUG_BIND,

+                "0x%08x: Port, Local UDP4 Address: %d.%d.%d.%d:%d\r\n",

+                pPort,

+                pConfig->StationAddress.Addr[0],

+                pConfig->StationAddress.Addr[1],

+                pConfig->StationAddress.Addr[2],

+                pConfig->StationAddress.Addr[3],

+                pConfig->StationPort ));

+    }

+  }

+

+  //

+  //  Return the operation status

+  //

+  DBG_EXIT_STATUS ( Status );

+  return Status;

+}

+

+

+/**

+  Free a receive packet

+

+  This routine performs the network specific operations necessary

+  to free a receive packet.

+

+  This routine is called by ::EslSocketPortCloseTxDone to free a

+  receive packet.

+

+  @param [in] pPacket         Address of an ::ESL_PACKET structure.

+  @param [in, out] pRxBytes   Address of the count of RX bytes

+

+**/

+VOID

+EslUdp4PacketFree (

+  IN ESL_PACKET * pPacket,

+  IN OUT size_t * pRxBytes

+  )

+{

+  EFI_UDP4_RECEIVE_DATA * pRxData;

+

+  DBG_ENTER ( );

+

+  //

+  //  Account for the receive bytes

+  //

+  pRxData = pPacket->Op.Udp4Rx.pRxData;

+  *pRxBytes -= pRxData->DataLength;

+

+  //

+  //  Disconnect the buffer from the packet

+  //

+  pPacket->Op.Udp4Rx.pRxData = NULL;

+

+  //

+  //  Return the buffer to the UDP4 driver

+  //

+  gBS->SignalEvent ( pRxData->RecycleSignal );

+  DBG_EXIT ( );

+}

+

+

+/**

+  Initialize the network specific portions of an ::ESL_PORT structure.

+

+  This routine initializes the network specific portions of an

+  ::ESL_PORT structure for use by the socket.

+

+  This support routine is called by ::EslSocketPortAllocate

+  to connect the socket with the underlying network adapter

+  running the UDPv4 protocol.

+

+  @param [in] pPort       Address of an ESL_PORT structure

+  @param [in] DebugFlags  Flags for debug messages

+

+  @retval EFI_SUCCESS - Socket successfully created

+

+ **/

+EFI_STATUS

+EslUdp4PortAllocate (

+  IN ESL_PORT * pPort,

+  IN UINTN DebugFlags

+  )

+{

+  EFI_UDP4_CONFIG_DATA * pConfig;

+  ESL_SOCKET * pSocket;

+  EFI_STATUS Status;

+

+  DBG_ENTER ( );

+

+  //

+  //  Initialize the port

+  //

+  pSocket = pPort->pSocket;

+  pSocket->TxPacketOffset = OFFSET_OF ( ESL_PACKET, Op.Udp4Tx.TxData );

+  pSocket->TxTokenEventOffset = OFFSET_OF ( ESL_IO_MGMT, Token.Udp4Tx.Event );

+  pSocket->TxTokenOffset = OFFSET_OF ( EFI_UDP4_COMPLETION_TOKEN, Packet.TxData );

+

+  //

+  //  Save the cancel, receive and transmit addresses

+  //

+  pPort->pfnConfigure = (PFN_NET_CONFIGURE)pPort->pProtocol.UDPv4->Configure;

+  pPort->pfnRxCancel = (PFN_NET_IO_START)pPort->pProtocol.UDPv4->Cancel;

+  pPort->pfnRxPoll = (PFN_NET_POLL)pPort->pProtocol.UDPv4->Poll;

+  pPort->pfnRxStart = (PFN_NET_IO_START)pPort->pProtocol.UDPv4->Receive;

+  pPort->pfnTxStart = (PFN_NET_IO_START)pPort->pProtocol.UDPv4->Transmit;

+

+  //

+  //  Set the configuration flags

+  //

+  pConfig = &pPort->Context.Udp4.ConfigData;

+  pConfig->TimeToLive = 255;

+  pConfig->AcceptAnyPort = FALSE;

+  pConfig->AcceptBroadcast = FALSE;

+  pConfig->AcceptPromiscuous = FALSE;

+  pConfig->AllowDuplicatePort = TRUE;

+  pConfig->DoNotFragment = FALSE;

+  Status = EFI_SUCCESS;

+

+  //

+  //  Return the operation status

+  //

+  DBG_EXIT_STATUS ( Status );

+  return Status;

+}

+

+

+/**

+  Receive data from a network connection.

+

+  This routine attempts to return buffered data to the caller.  The

+  data is removed from the urgent queue if the message flag MSG_OOB

+  is specified, otherwise data is removed from the normal queue.

+  See the \ref ReceiveEngine section.

+

+  This routine is called by ::EslSocketReceive to handle the network

+  specific receive operation to support SOCK_DGRAM sockets.

+

+  @param [in] pPort           Address of an ::ESL_PORT structure.

+

+  @param [in] pPacket         Address of an ::ESL_PACKET structure.

+  

+  @param [in] pbConsumePacket Address of a BOOLEAN indicating if the packet is to be consumed

+  

+  @param [in] BufferLength    Length of the the buffer

+  

+  @param [in] pBuffer         Address of a buffer to receive the data.

+  

+  @param [in] pDataLength     Number of received data bytes in the buffer.

+

+  @param [out] pAddress       Network address to receive the remote system address

+

+  @param [out] pSkipBytes     Address to receive the number of bytes skipped

+

+  @return   Returns the address of the next free byte in the buffer.

+

+ **/

+UINT8 *

+EslUdp4Receive (

+  IN ESL_PORT * pPort,

+  IN ESL_PACKET * pPacket,

+  IN BOOLEAN * pbConsumePacket,

+  IN size_t BufferLength,

+  IN UINT8 * pBuffer,

+  OUT size_t * pDataLength,

+  OUT struct sockaddr * pAddress,

+  OUT size_t * pSkipBytes

+  )

+{

+  size_t DataBytes;

+  struct sockaddr_in * pRemoteAddress;

+  EFI_UDP4_RECEIVE_DATA * pRxData;

+

+  DBG_ENTER ( );

+

+  pRxData = pPacket->Op.Udp4Rx.pRxData;

+  //

+  //  Return the remote system address if requested

+  //

+  if ( NULL != pAddress ) {

+    //

+    //  Build the remote address

+    //

+    DEBUG (( DEBUG_RX,

+              "Getting packet remote address: %d.%d.%d.%d:%d\r\n",

+              pRxData->UdpSession.SourceAddress.Addr[0],

+              pRxData->UdpSession.SourceAddress.Addr[1],

+              pRxData->UdpSession.SourceAddress.Addr[2],

+              pRxData->UdpSession.SourceAddress.Addr[3],

+              pRxData->UdpSession.SourcePort ));

+    pRemoteAddress = (struct sockaddr_in *)pAddress;

+    CopyMem ( &pRemoteAddress->sin_addr,

+              &pRxData->UdpSession.SourceAddress.Addr[0],

+              sizeof ( pRemoteAddress->sin_addr ));

+    pRemoteAddress->sin_port = SwapBytes16 ( pRxData->UdpSession.SourcePort );

+  }

+

+  //

+  //  Copy the received data

+  //

+  pBuffer = EslSocketCopyFragmentedBuffer ( pRxData->FragmentCount,

+                                            (EFI_IP4_FRAGMENT_DATA *)&pRxData->FragmentTable[0],

+                                            BufferLength,

+                                            pBuffer,

+                                            &DataBytes );

+

+  //

+  //  Determine if the data is being read

+  //

+  if ( *pbConsumePacket ) {

+    //

+    //  Display for the bytes consumed

+    //

+    DEBUG (( DEBUG_RX,

+              "0x%08x: Port account for 0x%08x bytes\r\n",

+              pPort,

+              DataBytes ));

+

+    //

+    //  Account for any discarded data

+    //

+    *pSkipBytes = pRxData->DataLength - DataBytes;

+  }

+

+  //

+  //  Return the data length and the buffer address

+  //

+  *pDataLength = DataBytes;

+  DBG_EXIT_HEX ( pBuffer );

+  return pBuffer;

+}

+

+

+/**

+  Get the remote socket address

+

+  This routine returns the address of the remote connection point

+  associated with the SOCK_DGRAM socket.

+

+  This routine is called by ::EslSocketGetPeerAddress to detemine

+  the UDPv4 address and port number associated with the network adapter.

+

+  @param [in] pPort       Address of an ::ESL_PORT structure.

+

+  @param [out] pAddress   Network address to receive the remote system address

+

+**/

+VOID

+EslUdp4RemoteAddressGet (

+  IN ESL_PORT * pPort,

+  OUT struct sockaddr * pAddress

+  )

+{

+  struct sockaddr_in * pRemoteAddress;

+  ESL_UDP4_CONTEXT * pUdp4;

+

+  DBG_ENTER ( );

+

+  //

+  //  Return the remote address

+  //

+  pUdp4 = &pPort->Context.Udp4;

+  pRemoteAddress = (struct sockaddr_in *)pAddress;

+  pRemoteAddress->sin_family = AF_INET;

+  pRemoteAddress->sin_port = SwapBytes16 ( pUdp4->ConfigData.RemotePort );

+  CopyMem ( &pRemoteAddress->sin_addr,

+            &pUdp4->ConfigData.RemoteAddress.Addr[0],

+            sizeof ( pRemoteAddress->sin_addr ));

+

+  DBG_EXIT ( );

+}

+

+

+/**

+  Set the remote address

+

+  This routine sets the remote address in the port.

+

+  This routine is called by ::EslSocketConnect to specify the

+  remote network address.

+

+  @param [in] pPort           Address of an ::ESL_PORT structure.

+

+  @param [in] pSockAddr       Network address of the remote system.

+

+  @param [in] SockAddrLength  Length in bytes of the network address.

+

+  @retval EFI_SUCCESS     The operation was successful

+

+ **/

+EFI_STATUS

+EslUdp4RemoteAddressSet (

+  IN ESL_PORT * pPort,

+  IN CONST struct sockaddr * pSockAddr,

+  IN socklen_t SockAddrLength

+  )

+{

+  CONST struct sockaddr_in * pRemoteAddress;

+  ESL_UDP4_CONTEXT * pUdp4;

+  EFI_STATUS Status;

+

+  DBG_ENTER ( );

+

+  //

+  //  Set the remote address

+  //

+  pUdp4 = &pPort->Context.Udp4;

+  pRemoteAddress = (struct sockaddr_in *)pSockAddr;

+  pUdp4->ConfigData.RemoteAddress.Addr[0] = (UINT8)( pRemoteAddress->sin_addr.s_addr );

+  pUdp4->ConfigData.RemoteAddress.Addr[1] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 8 );

+  pUdp4->ConfigData.RemoteAddress.Addr[2] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 16 );

+  pUdp4->ConfigData.RemoteAddress.Addr[3] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 24 );

+  pUdp4->ConfigData.RemotePort = SwapBytes16 ( pRemoteAddress->sin_port );

+  pPort->pSocket->bAddressSet = TRUE;

+  Status = EFI_SUCCESS;

+

+  //

+  //  Return the operation status

+  //

+  DBG_EXIT_STATUS ( Status );

+  return Status;

+}

+

+

+/**

+  Process the receive completion

+

+  This routine keeps the UDPv4 driver's buffer and queues it in

+  in FIFO order to the data queue.  The UDP4 driver's buffer will

+  be returned by either ::EslUdp4Receive or ::EslSocketPortCloseTxDone.

+  See the \ref ReceiveEngine section.

+

+  This routine is called by the UDPv4 driver when data is

+  received.

+

+  @param [in] Event     The receive completion event

+

+  @param [in] pIo       Address of an ::ESL_IO_MGMT structure

+

+**/

+VOID

+EslUdp4RxComplete (

+  IN EFI_EVENT Event,

+  IN ESL_IO_MGMT * pIo

+  )

+{

+  size_t LengthInBytes;

+  ESL_PACKET * pPacket;

+  EFI_UDP4_RECEIVE_DATA * pRxData;

+  EFI_STATUS Status;

+  

+  DBG_ENTER ( );

+

+  //

+  //  Get the operation status.

+  //

+  Status = pIo->Token.Udp4Rx.Status;

+  

+  //

+  //  Get the packet length

+  //

+  pRxData = pIo->Token.Udp4Rx.Packet.RxData;

+  LengthInBytes = pRxData->DataLength;

+

+  //

+  //      +--------------------+   +-----------------------+

+  //      | ESL_IO_MGMT        |   |      Data Buffer      |

+  //      |                    |   |     (Driver owned)    |

+  //      |    +---------------+   +-----------------------+

+  //      |    | Token         |               ^

+  //      |    |      Rx Event |               |

+  //      |    |               |   +-----------------------+

+  //      |    |        RxData --> | EFI_UDP4_RECEIVE_DATA |

+  //      +----+---------------+   |     (Driver owned)    |

+  //                               +-----------------------+

+  //      +--------------------+               ^

+  //      | ESL_PACKET         |               .

+  //      |                    |               .

+  //      |    +---------------+               .

+  //      |    |       pRxData --> NULL  .......

+  //      +----+---------------+

+  //

+  //

+  //  Save the data in the packet

+  //

+  pPacket = pIo->pPacket;

+  pPacket->Op.Udp4Rx.pRxData = pRxData;

+

+  //

+  //  Complete this request

+  //

+  EslSocketRxComplete ( pIo, Status, LengthInBytes, FALSE );

+  DBG_EXIT ( );

+}

+

+

+/**

+  Determine if the socket is configured.

+

+  This routine uses the flag ESL_SOCKET::bConfigured to determine

+  if the network layer's configuration routine has been called.

+  This routine calls the bind and configuration routines if they

+  were not already called.  After the port is configured, the

+  \ref ReceiveEngine is started.

+

+  This routine is called by EslSocketIsConfigured to verify

+  that the socket is configured.

+

+  @param [in] pSocket         Address of an ::ESL_SOCKET structure

+

+  @retval EFI_SUCCESS - The port is connected

+  @retval EFI_NOT_STARTED - The port is not connected

+

+ **/

+ EFI_STATUS

+ EslUdp4SocketIsConfigured (

+  IN ESL_SOCKET * pSocket

+  )

+{

+  EFI_UDP4_CONFIG_DATA * pConfigData;

+  ESL_PORT * pPort;

+  ESL_PORT * pNextPort;

+  ESL_UDP4_CONTEXT * pUdp4;

+  EFI_UDP4_PROTOCOL * pUdp4Protocol;

+  EFI_STATUS Status;

+  struct sockaddr_in LocalAddress;

+

+  DBG_ENTER ( );

+

+  //

+  //  Assume success

+  //

+  Status = EFI_SUCCESS;

+

+  //

+  //  Configure the port if necessary

+  //

+  if ( !pSocket->bConfigured ) {

+    //

+    //  Fill in the port list if necessary

+    //

+    pSocket->errno = ENETDOWN;

+    if ( NULL == pSocket->pPortList ) {

+      LocalAddress.sin_len = sizeof ( LocalAddress );

+      LocalAddress.sin_family = AF_INET;

+      LocalAddress.sin_addr.s_addr = 0;

+      LocalAddress.sin_port = 0;

+      Status = EslSocketBind ( &pSocket->SocketProtocol,

+                               (struct sockaddr *)&LocalAddress,

+                               LocalAddress.sin_len,

+                               &pSocket->errno );

+    }

+

+    //

+    //  Walk the port list

+    //

+    pPort = pSocket->pPortList;

+    while ( NULL != pPort ) {

+      //

+      //  Attempt to configure the port

+      //

+      pNextPort = pPort->pLinkSocket;

+      pUdp4 = &pPort->Context.Udp4;

+      pUdp4Protocol = pPort->pProtocol.UDPv4;

+      pConfigData = &pUdp4->ConfigData;

+      DEBUG (( DEBUG_TX,

+                "0x%08x: pPort Configuring for %d.%d.%d.%d:%d --> %d.%d.%d.%d:%d\r\n",

+                pPort,

+                pConfigData->StationAddress.Addr[0],

+                pConfigData->StationAddress.Addr[1],

+                pConfigData->StationAddress.Addr[2],

+                pConfigData->StationAddress.Addr[3],

+                pConfigData->StationPort,

+                pConfigData->RemoteAddress.Addr[0],

+                pConfigData->RemoteAddress.Addr[1],

+                pConfigData->RemoteAddress.Addr[2],

+                pConfigData->RemoteAddress.Addr[3],

+                pConfigData->RemotePort ));

+      Status = pUdp4Protocol->Configure ( pUdp4Protocol,

+                                          pConfigData );

+      if ( !EFI_ERROR ( Status )) {

+        //

+        //  Update the configuration data

+        //

+        Status = pUdp4Protocol->GetModeData ( pUdp4Protocol,

+                                              pConfigData,

+                                              NULL,

+                                              NULL,

+                                              NULL );

+      }

+      if ( EFI_ERROR ( Status )) {

+        if ( !pSocket->bConfigured ) {

+          DEBUG (( DEBUG_LISTEN,

+                    "ERROR - Failed to configure the Udp4 port, Status: %r\r\n",

+                    Status ));

+          switch ( Status ) {

+          case EFI_ACCESS_DENIED:

+            pSocket->errno = EACCES;

+            break;

+

+          default:

+          case EFI_DEVICE_ERROR:

+            pSocket->errno = EIO;

+            break;

+

+          case EFI_INVALID_PARAMETER:

+            pSocket->errno = EADDRNOTAVAIL;

+            break;

+

+          case EFI_NO_MAPPING:

+            pSocket->errno = EAFNOSUPPORT;

+            break;

+

+          case EFI_OUT_OF_RESOURCES:

+            pSocket->errno = ENOBUFS;

+            break;

+

+          case EFI_UNSUPPORTED:

+            pSocket->errno = EOPNOTSUPP;

+            break;

+          }

+        }

+      }

+      else {

+        DEBUG (( DEBUG_TX,

+                  "0x%08x: pPort Configured for %d.%d.%d.%d:%d --> %d.%d.%d.%d:%d\r\n",

+                  pPort,

+                  pConfigData->StationAddress.Addr[0],

+                  pConfigData->StationAddress.Addr[1],

+                  pConfigData->StationAddress.Addr[2],

+                  pConfigData->StationAddress.Addr[3],

+                  pConfigData->StationPort,

+                  pConfigData->RemoteAddress.Addr[0],

+                  pConfigData->RemoteAddress.Addr[1],

+                  pConfigData->RemoteAddress.Addr[2],

+                  pConfigData->RemoteAddress.Addr[3],

+                  pConfigData->RemotePort ));

+        pPort->bConfigured = TRUE;

+        pSocket->bConfigured = TRUE;

+

+        //

+        //  Start the first read on the port

+        //

+        EslSocketRxStart ( pPort );

+

+        //

+        //  The socket is connected

+        //

+        pSocket->State = SOCKET_STATE_CONNECTED;

+        pSocket->errno = 0;

+      }

+

+      //

+      //  Set the next port

+      //

+      pPort = pNextPort;

+    }

+  }

+

+  //

+  //  Determine the socket configuration status

+  //

+  Status = pSocket->bConfigured ? EFI_SUCCESS : EFI_NOT_STARTED;

+  

+  //

+  //  Return the port connected state.

+  //

+  DBG_EXIT_STATUS ( Status );

+  return Status;

+}

+

+

+/**

+  Buffer data for transmission over a network connection.

+

+  This routine buffers data for the transmit engine in the normal

+  data queue.  When the \ref TransmitEngine has resources, this

+  routine will start the transmission of the next buffer on the

+  network connection.

+

+  This routine is called by ::EslSocketTransmit to buffer

+  data for transmission.  The data is copied into a local buffer

+  freeing the application buffer for reuse upon return.  When

+  necessary, this routine starts the transmit engine that

+  performs the data transmission on the network connection.  The

+  transmit engine transmits the data a packet at a time over the

+  network connection.

+

+  Transmission errors are returned during the next transmission or

+  during the close operation.  Only buffering errors are returned

+  during the current transmission attempt.

+

+  @param [in] pSocket         Address of an ::ESL_SOCKET structure

+

+  @param [in] Flags           Message control flags

+

+  @param [in] BufferLength    Length of the the buffer

+

+  @param [in] pBuffer         Address of a buffer to receive the data.

+

+  @param [in] pDataLength     Number of received data bytes in the buffer.

+

+  @param [in] pAddress        Network address of the remote system address

+

+  @param [in] AddressLength   Length of the remote network address structure

+

+  @retval EFI_SUCCESS - Socket data successfully buffered

+

+**/

+EFI_STATUS

+EslUdp4TxBuffer (

+  IN ESL_SOCKET * pSocket,

+  IN int Flags,

+  IN size_t BufferLength,

+  IN CONST UINT8 * pBuffer,

+  OUT size_t * pDataLength,

+  IN const struct sockaddr * pAddress,

+  IN socklen_t AddressLength

+  )

+{

+  ESL_PACKET * pPacket;

+  ESL_PACKET * pPreviousPacket;

+  ESL_PORT * pPort;

+  const struct sockaddr_in * pRemoteAddress;

+  ESL_UDP4_CONTEXT * pUdp4;

+  size_t * pTxBytes;

+  ESL_UDP4_TX_DATA * pTxData;

+  EFI_STATUS Status;

+  EFI_TPL TplPrevious;

+

+  DBG_ENTER ( );

+

+  //

+  //  Assume failure

+  //

+  Status = EFI_UNSUPPORTED;

+  pSocket->errno = ENOTCONN;

+  *pDataLength = 0;

+

+  //

+  //  Verify that the socket is connected

+  //

+  if ( SOCKET_STATE_CONNECTED == pSocket->State ) {

+    //

+    //  Verify that there is enough room to buffer another

+    //  transmit operation

+    //

+    pTxBytes = &pSocket->TxBytes;

+    if ( pSocket->MaxTxBuf > *pTxBytes ) {

+      //

+      //  Locate the port

+      //

+      pPort = pSocket->pPortList;

+      while ( NULL != pPort ) {

+        //

+        //  Determine the queue head

+        //

+        pUdp4 = &pPort->Context.Udp4;

+

+        //

+        //  Attempt to allocate the packet

+        //

+        Status = EslSocketPacketAllocate ( &pPacket,

+                                           sizeof ( pPacket->Op.Udp4Tx )

+                                           - sizeof ( pPacket->Op.Udp4Tx.Buffer )

+                                           + BufferLength,

+                                           0,

+                                           DEBUG_TX );

+        if ( !EFI_ERROR ( Status )) {

+          //

+          //  Initialize the transmit operation

+          //

+          pTxData = &pPacket->Op.Udp4Tx;

+          pTxData->TxData.GatewayAddress = NULL;

+          pTxData->TxData.UdpSessionData = NULL;

+          pTxData->TxData.DataLength = (UINT32) BufferLength;

+          pTxData->TxData.FragmentCount = 1;

+          pTxData->TxData.FragmentTable[0].FragmentLength = (UINT32) BufferLength;

+          pTxData->TxData.FragmentTable[0].FragmentBuffer = &pPacket->Op.Udp4Tx.Buffer[0];

+          pTxData->RetransmitCount = 0;

+

+          //

+          //  Set the remote system address if necessary

+          //

+          pTxData->TxData.UdpSessionData = NULL;

+          if ( NULL != pAddress ) {

+            pRemoteAddress = (const struct sockaddr_in *)pAddress;

+            pTxData->Session.SourceAddress.Addr[0] = pUdp4->ConfigData.StationAddress.Addr[0];

+            pTxData->Session.SourceAddress.Addr[1] = pUdp4->ConfigData.StationAddress.Addr[1];

+            pTxData->Session.SourceAddress.Addr[2] = pUdp4->ConfigData.StationAddress.Addr[2];

+            pTxData->Session.SourceAddress.Addr[3] = pUdp4->ConfigData.StationAddress.Addr[3];

+            pTxData->Session.SourcePort = 0;

+            pTxData->Session.DestinationAddress.Addr[0] = (UINT8)pRemoteAddress->sin_addr.s_addr;

+            pTxData->Session.DestinationAddress.Addr[1] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 8 );

+            pTxData->Session.DestinationAddress.Addr[2] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 16 );

+            pTxData->Session.DestinationAddress.Addr[3] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 24 );

+            pTxData->Session.DestinationPort = SwapBytes16 ( pRemoteAddress->sin_port );

+

+            //

+            //  Use the remote system address when sending this packet

+            //

+            pTxData->TxData.UdpSessionData = &pTxData->Session;

+          }

+

+          //

+          //  Copy the data into the buffer

+          //

+          CopyMem ( &pPacket->Op.Udp4Tx.Buffer[0],

+                    pBuffer,

+                    BufferLength );

+

+          //

+          //  Synchronize with the socket layer

+          //

+          RAISE_TPL ( TplPrevious, TPL_SOCKETS );

+

+          //

+          //  Display the request

+          //

+          DEBUG (( DEBUG_TX,

+                    "Send %d bytes from 0x%08x to %d.%d.%d.%d:%d\r\n",

+                    BufferLength,

+                    pBuffer,

+                    pTxData->Session.DestinationAddress.Addr[0],

+                    pTxData->Session.DestinationAddress.Addr[1],

+                    pTxData->Session.DestinationAddress.Addr[2],

+                    pTxData->Session.DestinationAddress.Addr[3],

+                    pTxData->Session.DestinationPort ));

+

+          //

+          //  Queue the data for transmission

+          //

+          pPacket->pNext = NULL;

+          pPreviousPacket = pSocket->pTxPacketListTail;

+          if ( NULL == pPreviousPacket ) {

+            pSocket->pTxPacketListHead = pPacket;

+          }

+          else {

+            pPreviousPacket->pNext = pPacket;

+          }

+          pSocket->pTxPacketListTail = pPacket;

+          DEBUG (( DEBUG_TX,

+                    "0x%08x: Packet on transmit list\r\n",

+                    pPacket ));

+

+          //

+          //  Account for the buffered data

+          //

+          *pTxBytes += BufferLength;

+          *pDataLength = BufferLength;

+

+          //

+          //  Start the transmit engine if it is idle

+          //

+          if ( NULL != pPort->pTxFree ) {

+            pPacket = pSocket->pTxPacketListHead;

+            EslSocketTxStart ( pPort,

+                               &pSocket->pTxPacketListHead,

+                               &pSocket->pTxPacketListTail,

+                               &pPort->pTxActive,

+                               &pPort->pTxFree );

+

+            //

+            //  Ignore any transmit error

+            //

+            if ( EFI_ERROR ( pSocket->TxError )) {

+              DEBUG (( DEBUG_TX,

+                       "0x%08x: Transmit error, Packet: 0x%08x, Status: %r\r\n",

+                       pPort,

+                       pPacket,

+                       pSocket->TxError ));

+            }

+            pSocket->TxError = EFI_SUCCESS;

+          }

+

+          //

+          //  Release the socket layer synchronization

+          //

+          RESTORE_TPL ( TplPrevious );

+        }

+        else {

+          //

+          //  Packet allocation failed

+          //

+          pSocket->errno = ENOMEM;

+          break;

+        }

+

+        //

+        //  Set the next port

+        //

+        pPort = pPort->pLinkSocket;

+      }

+    }

+    else {

+      //

+      //  Not enough buffer space available

+      //

+      pSocket->errno = EAGAIN;

+      Status = EFI_NOT_READY;

+    }

+  }

+

+  //

+  //  Return the operation status

+  //

+  DBG_EXIT_STATUS ( Status );

+  return Status;

+}

+

+

+/**

+  Process the transmit completion

+

+  This routine use ::EslSocketTxComplete to perform the transmit

+  completion processing for data packets.

+

+  This routine is called by the UDPv4 network layer when a data

+  transmit request completes.

+

+  @param [in] Event     The normal transmit completion event

+

+  @param [in] pIo       Address of an ::ESL_IO_MGMT structure

+

+**/

+VOID

+EslUdp4TxComplete (

+  IN EFI_EVENT Event,

+  IN ESL_IO_MGMT * pIo

+  )

+{

+  UINT32 LengthInBytes;

+  ESL_PORT * pPort;

+  ESL_PACKET * pPacket;

+  ESL_SOCKET * pSocket;

+  EFI_STATUS Status;

+  

+  DBG_ENTER ( );

+  

+  //

+  //  Locate the active transmit packet

+  //

+  pPacket = pIo->pPacket;

+  pPort = pIo->pPort;

+  pSocket = pPort->pSocket;

+

+  //

+  //  Get the transmit length and status

+  //

+  LengthInBytes = pPacket->Op.Udp4Tx.TxData.DataLength;

+  pSocket->TxBytes -= LengthInBytes;

+  Status = pIo->Token.Udp4Tx.Status;

+

+  //

+  //  Ignore the transmit error

+  //

+  if ( EFI_ERROR ( Status )) {

+    DEBUG (( DEBUG_TX,

+             "0x%08x: Transmit completion error, Packet: 0x%08x, Status: %r\r\n",

+             pPort,

+             pPacket,

+             Status ));

+    Status = EFI_SUCCESS;

+  }

+

+  //

+  //  Complete the transmit operation

+  //

+  EslSocketTxComplete ( pIo,

+                        LengthInBytes,

+                        Status,

+                        "UDP ",

+                        &pSocket->pTxPacketListHead,

+                        &pSocket->pTxPacketListTail,

+                        &pPort->pTxActive,

+                        &pPort->pTxFree );

+  DBG_EXIT ( );

+}

+

+

+/**

+  Verify the adapter's IP address

+

+  This support routine is called by EslSocketBindTest.

+

+  @param [in] pPort       Address of an ::ESL_PORT structure.

+  @param [in] pConfigData Address of the configuration data

+

+  @retval EFI_SUCCESS - The IP address is valid

+  @retval EFI_NOT_STARTED - The IP address is invalid

+

+ **/

+EFI_STATUS

+EslUdp4VerifyLocalIpAddress (

+  IN ESL_PORT * pPort,

+  IN EFI_UDP4_CONFIG_DATA * pConfigData

+  )

+{

+  UINTN DataSize;

+  EFI_IP4_IPCONFIG_DATA * pIpConfigData;

+  EFI_IP4_CONFIG_PROTOCOL * pIpConfigProtocol;

+  ESL_SERVICE * pService;

+  EFI_STATUS Status;

+

+  DBG_ENTER ( );

+

+  //

+  //  Use break instead of goto

+  //

+  pIpConfigData = NULL;

+  for ( ; ; ) {

+    //

+    //  Determine if the IP address is specified

+    //

+    DEBUG (( DEBUG_BIND,

+              "UseDefaultAddress: %s\r\n",

+              pConfigData->UseDefaultAddress ? L"TRUE" : L"FALSE" ));

+    DEBUG (( DEBUG_BIND,

+              "Requested IP address: %d.%d.%d.%d\r\n",

+              pConfigData->StationAddress.Addr [ 0 ],

+              pConfigData->StationAddress.Addr [ 1 ],

+              pConfigData->StationAddress.Addr [ 2 ],

+              pConfigData->StationAddress.Addr [ 3 ]));

+    if ( pConfigData->UseDefaultAddress

+      || (( 0 == pConfigData->StationAddress.Addr [ 0 ])

+      && ( 0 == pConfigData->StationAddress.Addr [ 1 ])

+      && ( 0 == pConfigData->StationAddress.Addr [ 2 ])

+      && ( 0 == pConfigData->StationAddress.Addr [ 3 ])))

+    {

+      Status = EFI_SUCCESS;

+      break;

+    }

+

+    //

+    //  Open the configuration protocol

+    //

+    pService = pPort->pService;

+    Status = gBS->OpenProtocol ( pService->Controller,

+                                 &gEfiIp4ConfigProtocolGuid,

+                                 (VOID **)&pIpConfigProtocol,

+                                 NULL,

+                                 NULL,

+                                 EFI_OPEN_PROTOCOL_GET_PROTOCOL );

+    if ( EFI_ERROR ( Status )) {

+      DEBUG (( DEBUG_ERROR,

+                "ERROR - IP Configuration Protocol not available, Status: %r\r\n",

+                Status ));

+      break;

+    }

+

+    //

+    //  Get the IP configuration data size

+    //

+    DataSize = 0;

+    Status = pIpConfigProtocol->GetData ( pIpConfigProtocol,

+                                          &DataSize,

+                                          NULL );

+    if ( EFI_BUFFER_TOO_SMALL != Status ) {

+      DEBUG (( DEBUG_ERROR,

+                "ERROR - Failed to get IP Configuration data size, Status: %r\r\n",

+                Status ));

+      break;

+    }

+

+    //

+    //  Allocate the configuration data buffer

+    //

+    pIpConfigData = AllocatePool ( DataSize );

+    if ( NULL == pIpConfigData ) {

+      DEBUG (( DEBUG_ERROR,

+                "ERROR - Not enough memory to allocate IP Configuration data!\r\n" ));

+      Status = EFI_OUT_OF_RESOURCES;

+      break;

+    }

+

+    //

+    //  Get the IP configuration

+    //

+    Status = pIpConfigProtocol->GetData ( pIpConfigProtocol,

+                                          &DataSize,

+                                          pIpConfigData );

+    if ( EFI_ERROR ( Status )) {

+      DEBUG (( DEBUG_ERROR,

+                "ERROR - Failed to return IP Configuration data, Status: %r\r\n",

+                Status ));

+      break;

+    }

+

+    //

+    //  Display the current configuration

+    //

+    DEBUG (( DEBUG_BIND,

+              "Actual adapter IP address: %d.%d.%d.%d\r\n",

+              pIpConfigData->StationAddress.Addr [ 0 ],

+              pIpConfigData->StationAddress.Addr [ 1 ],

+              pIpConfigData->StationAddress.Addr [ 2 ],

+              pIpConfigData->StationAddress.Addr [ 3 ]));

+

+    //

+    //  Assume the port is not configured

+    //

+    Status = EFI_SUCCESS;

+    if (( pConfigData->StationAddress.Addr [ 0 ] == pIpConfigData->StationAddress.Addr [ 0 ])

+      && ( pConfigData->StationAddress.Addr [ 1 ] == pIpConfigData->StationAddress.Addr [ 1 ])

+      && ( pConfigData->StationAddress.Addr [ 2 ] == pIpConfigData->StationAddress.Addr [ 2 ])

+      && ( pConfigData->StationAddress.Addr [ 3 ] == pIpConfigData->StationAddress.Addr [ 3 ])) {

+      break;

+    }

+

+    //

+    //  The IP address did not match

+    //

+    Status = EFI_NOT_STARTED;

+    break;

+  }

+

+  //

+  //  Free the buffer if necessary

+  //

+  if ( NULL != pIpConfigData ) {

+    FreePool ( pIpConfigData );

+  }

+

+  //

+  //  Return the IP address status

+  //

+  DBG_EXIT_STATUS ( Status );

+  return Status;

+}

+

+

+/**

+  Interface between the socket layer and the network specific

+  code that supports SOCK_DGRAM sockets over UDPv4.

+**/

+CONST ESL_PROTOCOL_API cEslUdp4Api = {

+  "UDPv4",

+  IPPROTO_UDP,

+  OFFSET_OF ( ESL_PORT, Context.Udp4.ConfigData ),

+  OFFSET_OF ( ESL_LAYER, pUdp4List ),

+  OFFSET_OF ( struct sockaddr_in, sin_zero ),

+  sizeof ( struct sockaddr_in ),

+  AF_INET,

+  sizeof (((ESL_PACKET *)0 )->Op.Udp4Rx ),

+  sizeof (((ESL_PACKET *)0 )->Op.Udp4Rx ),

+  OFFSET_OF ( ESL_IO_MGMT, Token.Udp4Rx.Packet.RxData ),

+  FALSE,

+  EADDRINUSE,

+  NULL,   //  Accept

+  NULL,   //  ConnectPoll

+  NULL,   //  ConnectStart

+  EslUdp4SocketIsConfigured,

+  EslUdp4LocalAddressGet,

+  EslUdp4LocalAddressSet,

+  NULL,   //  Listen

+  NULL,   //  OptionGet

+  NULL,   //  OptionSet

+  EslUdp4PacketFree,

+  EslUdp4PortAllocate,

+  NULL,   //  PortClose,

+  NULL,   //  PortCloseOp

+  TRUE,

+  EslUdp4Receive,

+  EslUdp4RemoteAddressGet,

+  EslUdp4RemoteAddressSet,

+  EslUdp4RxComplete,

+  NULL,   //  RxStart

+  EslUdp4TxBuffer,

+  EslUdp4TxComplete,

+  NULL,   //  TxOobComplete

+  (PFN_API_VERIFY_LOCAL_IP_ADDRESS)EslUdp4VerifyLocalIpAddress

+};