Home | History | Annotate | Download | only in EfiSocketLib
      1 /** @file
      2   Implement the UDP4 driver support for the socket layer.
      3 
      4   Copyright (c) 2011 - 2015, Intel Corporation
      5   All rights reserved. This program and the accompanying materials
      6   are licensed and made available under the terms and conditions of the BSD License
      7   which accompanies this distribution.  The full text of the license may be found at
      8   http://opensource.org/licenses/bsd-license.php
      9 
     10   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 #include "Socket.h"
     16 
     17 
     18 /**
     19   Get the local socket address
     20 
     21   This routine returns the IPv4 address and UDP port number associated
     22   with the local socket.
     23 
     24   This routine is called by ::EslSocketGetLocalAddress to determine the
     25   network address for the SOCK_DGRAM socket.
     26 
     27   @param [in] pPort       Address of an ::ESL_PORT structure.
     28 
     29   @param [out] pSockAddr  Network address to receive the local system address
     30 
     31 **/
     32 VOID
     33 EslUdp4LocalAddressGet (
     34   IN ESL_PORT * pPort,
     35   OUT struct sockaddr * pSockAddr
     36   )
     37 {
     38   struct sockaddr_in * pLocalAddress;
     39   ESL_UDP4_CONTEXT * pUdp4;
     40 
     41   DBG_ENTER ( );
     42 
     43   //
     44   //  Return the local address
     45   //
     46   pUdp4 = &pPort->Context.Udp4;
     47   pLocalAddress = (struct sockaddr_in *)pSockAddr;
     48   pLocalAddress->sin_family = AF_INET;
     49   pLocalAddress->sin_port = SwapBytes16 ( pUdp4->ConfigData.StationPort );
     50   CopyMem ( &pLocalAddress->sin_addr,
     51             &pUdp4->ConfigData.StationAddress.Addr[0],
     52             sizeof ( pLocalAddress->sin_addr ));
     53 
     54   DBG_EXIT ( );
     55 }
     56 
     57 
     58 /**
     59   Set the local port address.
     60 
     61   This routine sets the local port address.
     62 
     63   This support routine is called by ::EslSocketPortAllocate.
     64 
     65   @param [in] pPort       Address of an ESL_PORT structure
     66   @param [in] pSockAddr   Address of a sockaddr structure that contains the
     67                           connection point on the local machine.  An IPv4 address
     68                           of INADDR_ANY specifies that the connection is made to
     69                           all of the network stacks on the platform.  Specifying a
     70                           specific IPv4 address restricts the connection to the
     71                           network stack supporting that address.  Specifying zero
     72                           for the port causes the network layer to assign a port
     73                           number from the dynamic range.  Specifying a specific
     74                           port number causes the network layer to use that port.
     75 
     76   @param [in] bBindTest   TRUE = run bind testing
     77 
     78   @retval EFI_SUCCESS     The operation was successful
     79 
     80  **/
     81 EFI_STATUS
     82 EslUdp4LocalAddressSet (
     83   IN ESL_PORT * pPort,
     84   IN CONST struct sockaddr * pSockAddr,
     85   IN BOOLEAN bBindTest
     86   )
     87 {
     88   EFI_UDP4_CONFIG_DATA * pConfig;
     89   CONST struct sockaddr_in * pIpAddress;
     90   CONST UINT8 * pIpv4Address;
     91   EFI_STATUS Status;
     92 
     93   DBG_ENTER ( );
     94 
     95   //
     96   //  Validate the address
     97   //
     98   pIpAddress = (struct sockaddr_in *)pSockAddr;
     99   if ( INADDR_BROADCAST == pIpAddress->sin_addr.s_addr ) {
    100     //
    101     //  The local address must not be the broadcast address
    102     //
    103     Status = EFI_INVALID_PARAMETER;
    104     pPort->pSocket->errno = EADDRNOTAVAIL;
    105   }
    106   else {
    107     //
    108     //  Set the local address
    109     //
    110     pIpAddress = (struct sockaddr_in *)pSockAddr;
    111     pIpv4Address = (UINT8 *)&pIpAddress->sin_addr.s_addr;
    112     pConfig = &pPort->Context.Udp4.ConfigData;
    113     pConfig->StationAddress.Addr[0] = pIpv4Address[0];
    114     pConfig->StationAddress.Addr[1] = pIpv4Address[1];
    115     pConfig->StationAddress.Addr[2] = pIpv4Address[2];
    116     pConfig->StationAddress.Addr[3] = pIpv4Address[3];
    117 
    118     //
    119     //  Determine if the default address is used
    120     //
    121     pConfig->UseDefaultAddress = (BOOLEAN)( 0 == pIpAddress->sin_addr.s_addr );
    122 
    123     //
    124     //  Set the subnet mask
    125     //
    126     if ( pConfig->UseDefaultAddress ) {
    127       pConfig->SubnetMask.Addr[0] = 0;
    128       pConfig->SubnetMask.Addr[1] = 0;
    129       pConfig->SubnetMask.Addr[2] = 0;
    130       pConfig->SubnetMask.Addr[3] = 0;
    131     }
    132     else {
    133       pConfig->SubnetMask.Addr[0] = 0xff;
    134       pConfig->SubnetMask.Addr[1] = ( 128 <= pConfig->StationAddress.Addr[0]) ? 0xff : 0;
    135       pConfig->SubnetMask.Addr[2] = ( 192 <= pConfig->StationAddress.Addr[0]) ? 0xff : 0;
    136       pConfig->SubnetMask.Addr[3] = ( 224 <= pConfig->StationAddress.Addr[0]) ? 0xff : 0;
    137     }
    138 
    139     //
    140     //  Validate the IP address
    141     //
    142     pConfig->StationPort = 0;
    143     Status = bBindTest ? EslSocketBindTest ( pPort, EADDRNOTAVAIL )
    144                        : EFI_SUCCESS;
    145     if ( !EFI_ERROR ( Status )) {
    146       //
    147       //  Set the port number
    148       //
    149       pConfig->StationPort = SwapBytes16 ( pIpAddress->sin_port );
    150 
    151       //
    152       //  Display the local address
    153       //
    154       DEBUG (( DEBUG_BIND,
    155                 "0x%08x: Port, Local UDP4 Address: %d.%d.%d.%d:%d\r\n",
    156                 pPort,
    157                 pConfig->StationAddress.Addr[0],
    158                 pConfig->StationAddress.Addr[1],
    159                 pConfig->StationAddress.Addr[2],
    160                 pConfig->StationAddress.Addr[3],
    161                 pConfig->StationPort ));
    162     }
    163   }
    164 
    165   //
    166   //  Return the operation status
    167   //
    168   DBG_EXIT_STATUS ( Status );
    169   return Status;
    170 }
    171 
    172 
    173 /**
    174   Free a receive packet
    175 
    176   This routine performs the network specific operations necessary
    177   to free a receive packet.
    178 
    179   This routine is called by ::EslSocketPortCloseTxDone to free a
    180   receive packet.
    181 
    182   @param [in] pPacket         Address of an ::ESL_PACKET structure.
    183   @param [in, out] pRxBytes   Address of the count of RX bytes
    184 
    185 **/
    186 VOID
    187 EslUdp4PacketFree (
    188   IN ESL_PACKET * pPacket,
    189   IN OUT size_t * pRxBytes
    190   )
    191 {
    192   EFI_UDP4_RECEIVE_DATA * pRxData;
    193 
    194   DBG_ENTER ( );
    195 
    196   //
    197   //  Account for the receive bytes
    198   //
    199   pRxData = pPacket->Op.Udp4Rx.pRxData;
    200   *pRxBytes -= pRxData->DataLength;
    201 
    202   //
    203   //  Disconnect the buffer from the packet
    204   //
    205   pPacket->Op.Udp4Rx.pRxData = NULL;
    206 
    207   //
    208   //  Return the buffer to the UDP4 driver
    209   //
    210   gBS->SignalEvent ( pRxData->RecycleSignal );
    211   DBG_EXIT ( );
    212 }
    213 
    214 
    215 /**
    216   Initialize the network specific portions of an ::ESL_PORT structure.
    217 
    218   This routine initializes the network specific portions of an
    219   ::ESL_PORT structure for use by the socket.
    220 
    221   This support routine is called by ::EslSocketPortAllocate
    222   to connect the socket with the underlying network adapter
    223   running the UDPv4 protocol.
    224 
    225   @param [in] pPort       Address of an ESL_PORT structure
    226   @param [in] DebugFlags  Flags for debug messages
    227 
    228   @retval EFI_SUCCESS - Socket successfully created
    229 
    230  **/
    231 EFI_STATUS
    232 EslUdp4PortAllocate (
    233   IN ESL_PORT * pPort,
    234   IN UINTN DebugFlags
    235   )
    236 {
    237   EFI_UDP4_CONFIG_DATA * pConfig;
    238   ESL_SOCKET * pSocket;
    239   EFI_STATUS Status;
    240 
    241   DBG_ENTER ( );
    242 
    243   //
    244   //  Initialize the port
    245   //
    246   pSocket = pPort->pSocket;
    247   pSocket->TxPacketOffset = OFFSET_OF ( ESL_PACKET, Op.Udp4Tx.TxData );
    248   pSocket->TxTokenEventOffset = OFFSET_OF ( ESL_IO_MGMT, Token.Udp4Tx.Event );
    249   pSocket->TxTokenOffset = OFFSET_OF ( EFI_UDP4_COMPLETION_TOKEN, Packet.TxData );
    250 
    251   //
    252   //  Save the cancel, receive and transmit addresses
    253   //
    254   pPort->pfnConfigure = (PFN_NET_CONFIGURE)pPort->pProtocol.UDPv4->Configure;
    255   pPort->pfnRxCancel = (PFN_NET_IO_START)pPort->pProtocol.UDPv4->Cancel;
    256   pPort->pfnRxPoll = (PFN_NET_POLL)pPort->pProtocol.UDPv4->Poll;
    257   pPort->pfnRxStart = (PFN_NET_IO_START)pPort->pProtocol.UDPv4->Receive;
    258   pPort->pfnTxStart = (PFN_NET_IO_START)pPort->pProtocol.UDPv4->Transmit;
    259 
    260   //
    261   //  Set the configuration flags
    262   //
    263   pConfig = &pPort->Context.Udp4.ConfigData;
    264   pConfig->TimeToLive = 255;
    265   pConfig->AcceptAnyPort = FALSE;
    266   pConfig->AcceptBroadcast = FALSE;
    267   pConfig->AcceptPromiscuous = FALSE;
    268   pConfig->AllowDuplicatePort = TRUE;
    269   pConfig->DoNotFragment = FALSE;
    270   Status = EFI_SUCCESS;
    271 
    272   //
    273   //  Return the operation status
    274   //
    275   DBG_EXIT_STATUS ( Status );
    276   return Status;
    277 }
    278 
    279 
    280 /**
    281   Receive data from a network connection.
    282 
    283   This routine attempts to return buffered data to the caller.  The
    284   data is removed from the urgent queue if the message flag MSG_OOB
    285   is specified, otherwise data is removed from the normal queue.
    286   See the \ref ReceiveEngine section.
    287 
    288   This routine is called by ::EslSocketReceive to handle the network
    289   specific receive operation to support SOCK_DGRAM sockets.
    290 
    291   @param [in] pPort           Address of an ::ESL_PORT structure.
    292 
    293   @param [in] pPacket         Address of an ::ESL_PACKET structure.
    294 
    295   @param [in] pbConsumePacket Address of a BOOLEAN indicating if the packet is to be consumed
    296 
    297   @param [in] BufferLength    Length of the the buffer
    298 
    299   @param [in] pBuffer         Address of a buffer to receive the data.
    300 
    301   @param [in] pDataLength     Number of received data bytes in the buffer.
    302 
    303   @param [out] pAddress       Network address to receive the remote system address
    304 
    305   @param [out] pSkipBytes     Address to receive the number of bytes skipped
    306 
    307   @return   Returns the address of the next free byte in the buffer.
    308 
    309  **/
    310 UINT8 *
    311 EslUdp4Receive (
    312   IN ESL_PORT * pPort,
    313   IN ESL_PACKET * pPacket,
    314   IN BOOLEAN * pbConsumePacket,
    315   IN size_t BufferLength,
    316   IN UINT8 * pBuffer,
    317   OUT size_t * pDataLength,
    318   OUT struct sockaddr * pAddress,
    319   OUT size_t * pSkipBytes
    320   )
    321 {
    322   size_t DataBytes;
    323   struct sockaddr_in * pRemoteAddress;
    324   EFI_UDP4_RECEIVE_DATA * pRxData;
    325 
    326   DBG_ENTER ( );
    327 
    328   pRxData = pPacket->Op.Udp4Rx.pRxData;
    329   //
    330   //  Return the remote system address if requested
    331   //
    332   if ( NULL != pAddress ) {
    333     //
    334     //  Build the remote address
    335     //
    336     DEBUG (( DEBUG_RX,
    337               "Getting packet remote address: %d.%d.%d.%d:%d\r\n",
    338               pRxData->UdpSession.SourceAddress.Addr[0],
    339               pRxData->UdpSession.SourceAddress.Addr[1],
    340               pRxData->UdpSession.SourceAddress.Addr[2],
    341               pRxData->UdpSession.SourceAddress.Addr[3],
    342               pRxData->UdpSession.SourcePort ));
    343     pRemoteAddress = (struct sockaddr_in *)pAddress;
    344     CopyMem ( &pRemoteAddress->sin_addr,
    345               &pRxData->UdpSession.SourceAddress.Addr[0],
    346               sizeof ( pRemoteAddress->sin_addr ));
    347     pRemoteAddress->sin_port = SwapBytes16 ( pRxData->UdpSession.SourcePort );
    348   }
    349 
    350   //
    351   //  Copy the received data
    352   //
    353   pBuffer = EslSocketCopyFragmentedBuffer ( pRxData->FragmentCount,
    354                                             (EFI_IP4_FRAGMENT_DATA *)&pRxData->FragmentTable[0],
    355                                             BufferLength,
    356                                             pBuffer,
    357                                             &DataBytes );
    358 
    359   //
    360   //  Determine if the data is being read
    361   //
    362   if ( *pbConsumePacket ) {
    363     //
    364     //  Display for the bytes consumed
    365     //
    366     DEBUG (( DEBUG_RX,
    367               "0x%08x: Port account for 0x%08x bytes\r\n",
    368               pPort,
    369               DataBytes ));
    370 
    371     //
    372     //  Account for any discarded data
    373     //
    374     *pSkipBytes = pRxData->DataLength - DataBytes;
    375   }
    376 
    377   //
    378   //  Return the data length and the buffer address
    379   //
    380   *pDataLength = DataBytes;
    381   DBG_EXIT_HEX ( pBuffer );
    382   return pBuffer;
    383 }
    384 
    385 
    386 /**
    387   Get the remote socket address
    388 
    389   This routine returns the address of the remote connection point
    390   associated with the SOCK_DGRAM socket.
    391 
    392   This routine is called by ::EslSocketGetPeerAddress to detemine
    393   the UDPv4 address and port number associated with the network adapter.
    394 
    395   @param [in] pPort       Address of an ::ESL_PORT structure.
    396 
    397   @param [out] pAddress   Network address to receive the remote system address
    398 
    399 **/
    400 VOID
    401 EslUdp4RemoteAddressGet (
    402   IN ESL_PORT * pPort,
    403   OUT struct sockaddr * pAddress
    404   )
    405 {
    406   struct sockaddr_in * pRemoteAddress;
    407   ESL_UDP4_CONTEXT * pUdp4;
    408 
    409   DBG_ENTER ( );
    410 
    411   //
    412   //  Return the remote address
    413   //
    414   pUdp4 = &pPort->Context.Udp4;
    415   pRemoteAddress = (struct sockaddr_in *)pAddress;
    416   pRemoteAddress->sin_family = AF_INET;
    417   pRemoteAddress->sin_port = SwapBytes16 ( pUdp4->ConfigData.RemotePort );
    418   CopyMem ( &pRemoteAddress->sin_addr,
    419             &pUdp4->ConfigData.RemoteAddress.Addr[0],
    420             sizeof ( pRemoteAddress->sin_addr ));
    421 
    422   DBG_EXIT ( );
    423 }
    424 
    425 
    426 /**
    427   Set the remote address
    428 
    429   This routine sets the remote address in the port.
    430 
    431   This routine is called by ::EslSocketConnect to specify the
    432   remote network address.
    433 
    434   @param [in] pPort           Address of an ::ESL_PORT structure.
    435 
    436   @param [in] pSockAddr       Network address of the remote system.
    437 
    438   @param [in] SockAddrLength  Length in bytes of the network address.
    439 
    440   @retval EFI_SUCCESS     The operation was successful
    441 
    442  **/
    443 EFI_STATUS
    444 EslUdp4RemoteAddressSet (
    445   IN ESL_PORT * pPort,
    446   IN CONST struct sockaddr * pSockAddr,
    447   IN socklen_t SockAddrLength
    448   )
    449 {
    450   CONST struct sockaddr_in * pRemoteAddress;
    451   ESL_UDP4_CONTEXT * pUdp4;
    452   EFI_STATUS Status;
    453 
    454   DBG_ENTER ( );
    455 
    456   //
    457   //  Set the remote address
    458   //
    459   pUdp4 = &pPort->Context.Udp4;
    460   pRemoteAddress = (struct sockaddr_in *)pSockAddr;
    461   pUdp4->ConfigData.RemoteAddress.Addr[0] = (UINT8)( pRemoteAddress->sin_addr.s_addr );
    462   pUdp4->ConfigData.RemoteAddress.Addr[1] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 8 );
    463   pUdp4->ConfigData.RemoteAddress.Addr[2] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 16 );
    464   pUdp4->ConfigData.RemoteAddress.Addr[3] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 24 );
    465   pUdp4->ConfigData.RemotePort = SwapBytes16 ( pRemoteAddress->sin_port );
    466   pPort->pSocket->bAddressSet = TRUE;
    467   Status = EFI_SUCCESS;
    468 
    469   //
    470   //  Return the operation status
    471   //
    472   DBG_EXIT_STATUS ( Status );
    473   return Status;
    474 }
    475 
    476 
    477 /**
    478   Process the receive completion
    479 
    480   This routine keeps the UDPv4 driver's buffer and queues it in
    481   in FIFO order to the data queue.  The UDP4 driver's buffer will
    482   be returned by either ::EslUdp4Receive or ::EslSocketPortCloseTxDone.
    483   See the \ref ReceiveEngine section.
    484 
    485   This routine is called by the UDPv4 driver when data is
    486   received.
    487 
    488   @param [in] Event     The receive completion event
    489 
    490   @param [in] pIo       Address of an ::ESL_IO_MGMT structure
    491 
    492 **/
    493 VOID
    494 EslUdp4RxComplete (
    495   IN EFI_EVENT Event,
    496   IN ESL_IO_MGMT * pIo
    497   )
    498 {
    499   size_t LengthInBytes;
    500   ESL_PACKET * pPacket;
    501   EFI_UDP4_RECEIVE_DATA * pRxData;
    502   EFI_STATUS Status;
    503 
    504   DBG_ENTER ( );
    505 
    506   //
    507   //  Get the operation status.
    508   //
    509   Status = pIo->Token.Udp4Rx.Status;
    510 
    511   //
    512   //  Get the packet length
    513   //
    514   pRxData = pIo->Token.Udp4Rx.Packet.RxData;
    515   LengthInBytes = pRxData->DataLength;
    516 
    517   //
    518   //      +--------------------+   +-----------------------+
    519   //      | ESL_IO_MGMT        |   |      Data Buffer      |
    520   //      |                    |   |     (Driver owned)    |
    521   //      |    +---------------+   +-----------------------+
    522   //      |    | Token         |               ^
    523   //      |    |      Rx Event |               |
    524   //      |    |               |   +-----------------------+
    525   //      |    |        RxData --> | EFI_UDP4_RECEIVE_DATA |
    526   //      +----+---------------+   |     (Driver owned)    |
    527   //                               +-----------------------+
    528   //      +--------------------+               ^
    529   //      | ESL_PACKET         |               .
    530   //      |                    |               .
    531   //      |    +---------------+               .
    532   //      |    |       pRxData --> NULL  .......
    533   //      +----+---------------+
    534   //
    535   //
    536   //  Save the data in the packet
    537   //
    538   pPacket = pIo->pPacket;
    539   pPacket->Op.Udp4Rx.pRxData = pRxData;
    540 
    541   //
    542   //  Complete this request
    543   //
    544   EslSocketRxComplete ( pIo, Status, LengthInBytes, FALSE );
    545   DBG_EXIT ( );
    546 }
    547 
    548 
    549 /**
    550   Determine if the socket is configured.
    551 
    552   This routine uses the flag ESL_SOCKET::bConfigured to determine
    553   if the network layer's configuration routine has been called.
    554   This routine calls the bind and configuration routines if they
    555   were not already called.  After the port is configured, the
    556   \ref ReceiveEngine is started.
    557 
    558   This routine is called by EslSocketIsConfigured to verify
    559   that the socket is configured.
    560 
    561   @param [in] pSocket         Address of an ::ESL_SOCKET structure
    562 
    563   @retval EFI_SUCCESS - The port is connected
    564   @retval EFI_NOT_STARTED - The port is not connected
    565 
    566  **/
    567  EFI_STATUS
    568  EslUdp4SocketIsConfigured (
    569   IN ESL_SOCKET * pSocket
    570   )
    571 {
    572   EFI_UDP4_CONFIG_DATA * pConfigData;
    573   ESL_PORT * pPort;
    574   ESL_PORT * pNextPort;
    575   ESL_UDP4_CONTEXT * pUdp4;
    576   EFI_UDP4_PROTOCOL * pUdp4Protocol;
    577   EFI_STATUS Status;
    578   struct sockaddr_in LocalAddress;
    579 
    580   DBG_ENTER ( );
    581 
    582   //
    583   //  Assume success
    584   //
    585   Status = EFI_SUCCESS;
    586 
    587   //
    588   //  Configure the port if necessary
    589   //
    590   if ( !pSocket->bConfigured ) {
    591     //
    592     //  Fill in the port list if necessary
    593     //
    594     pSocket->errno = ENETDOWN;
    595     if ( NULL == pSocket->pPortList ) {
    596       LocalAddress.sin_len = sizeof ( LocalAddress );
    597       LocalAddress.sin_family = AF_INET;
    598       LocalAddress.sin_addr.s_addr = 0;
    599       LocalAddress.sin_port = 0;
    600       Status = EslSocketBind ( &pSocket->SocketProtocol,
    601                                (struct sockaddr *)&LocalAddress,
    602                                LocalAddress.sin_len,
    603                                &pSocket->errno );
    604     }
    605 
    606     //
    607     //  Walk the port list
    608     //
    609     pPort = pSocket->pPortList;
    610     while ( NULL != pPort ) {
    611       //
    612       //  Attempt to configure the port
    613       //
    614       pNextPort = pPort->pLinkSocket;
    615       pUdp4 = &pPort->Context.Udp4;
    616       pUdp4Protocol = pPort->pProtocol.UDPv4;
    617       pConfigData = &pUdp4->ConfigData;
    618       DEBUG (( DEBUG_TX,
    619                 "0x%08x: pPort Configuring for %d.%d.%d.%d:%d --> %d.%d.%d.%d:%d\r\n",
    620                 pPort,
    621                 pConfigData->StationAddress.Addr[0],
    622                 pConfigData->StationAddress.Addr[1],
    623                 pConfigData->StationAddress.Addr[2],
    624                 pConfigData->StationAddress.Addr[3],
    625                 pConfigData->StationPort,
    626                 pConfigData->RemoteAddress.Addr[0],
    627                 pConfigData->RemoteAddress.Addr[1],
    628                 pConfigData->RemoteAddress.Addr[2],
    629                 pConfigData->RemoteAddress.Addr[3],
    630                 pConfigData->RemotePort ));
    631       Status = pUdp4Protocol->Configure ( pUdp4Protocol,
    632                                           pConfigData );
    633       if ( !EFI_ERROR ( Status )) {
    634         //
    635         //  Update the configuration data
    636         //
    637         Status = pUdp4Protocol->GetModeData ( pUdp4Protocol,
    638                                               pConfigData,
    639                                               NULL,
    640                                               NULL,
    641                                               NULL );
    642       }
    643       if ( EFI_ERROR ( Status )) {
    644         if ( !pSocket->bConfigured ) {
    645           DEBUG (( DEBUG_LISTEN,
    646                     "ERROR - Failed to configure the Udp4 port, Status: %r\r\n",
    647                     Status ));
    648           switch ( Status ) {
    649           case EFI_ACCESS_DENIED:
    650             pSocket->errno = EACCES;
    651             break;
    652 
    653           default:
    654           case EFI_DEVICE_ERROR:
    655             pSocket->errno = EIO;
    656             break;
    657 
    658           case EFI_INVALID_PARAMETER:
    659             pSocket->errno = EADDRNOTAVAIL;
    660             break;
    661 
    662           case EFI_NO_MAPPING:
    663             pSocket->errno = EAFNOSUPPORT;
    664             break;
    665 
    666           case EFI_OUT_OF_RESOURCES:
    667             pSocket->errno = ENOBUFS;
    668             break;
    669 
    670           case EFI_UNSUPPORTED:
    671             pSocket->errno = EOPNOTSUPP;
    672             break;
    673           }
    674         }
    675       }
    676       else {
    677         DEBUG (( DEBUG_TX,
    678                   "0x%08x: pPort Configured for %d.%d.%d.%d:%d --> %d.%d.%d.%d:%d\r\n",
    679                   pPort,
    680                   pConfigData->StationAddress.Addr[0],
    681                   pConfigData->StationAddress.Addr[1],
    682                   pConfigData->StationAddress.Addr[2],
    683                   pConfigData->StationAddress.Addr[3],
    684                   pConfigData->StationPort,
    685                   pConfigData->RemoteAddress.Addr[0],
    686                   pConfigData->RemoteAddress.Addr[1],
    687                   pConfigData->RemoteAddress.Addr[2],
    688                   pConfigData->RemoteAddress.Addr[3],
    689                   pConfigData->RemotePort ));
    690         pPort->bConfigured = TRUE;
    691         pSocket->bConfigured = TRUE;
    692 
    693         //
    694         //  Start the first read on the port
    695         //
    696         EslSocketRxStart ( pPort );
    697 
    698         //
    699         //  The socket is connected
    700         //
    701         pSocket->State = SOCKET_STATE_CONNECTED;
    702         pSocket->errno = 0;
    703       }
    704 
    705       //
    706       //  Set the next port
    707       //
    708       pPort = pNextPort;
    709     }
    710   }
    711 
    712   //
    713   //  Determine the socket configuration status
    714   //
    715   Status = pSocket->bConfigured ? EFI_SUCCESS : EFI_NOT_STARTED;
    716 
    717   //
    718   //  Return the port connected state.
    719   //
    720   DBG_EXIT_STATUS ( Status );
    721   return Status;
    722 }
    723 
    724 
    725 /**
    726   Buffer data for transmission over a network connection.
    727 
    728   This routine buffers data for the transmit engine in the normal
    729   data queue.  When the \ref TransmitEngine has resources, this
    730   routine will start the transmission of the next buffer on the
    731   network connection.
    732 
    733   This routine is called by ::EslSocketTransmit to buffer
    734   data for transmission.  The data is copied into a local buffer
    735   freeing the application buffer for reuse upon return.  When
    736   necessary, this routine starts the transmit engine that
    737   performs the data transmission on the network connection.  The
    738   transmit engine transmits the data a packet at a time over the
    739   network connection.
    740 
    741   Transmission errors are returned during the next transmission or
    742   during the close operation.  Only buffering errors are returned
    743   during the current transmission attempt.
    744 
    745   @param [in] pSocket         Address of an ::ESL_SOCKET structure
    746 
    747   @param [in] Flags           Message control flags
    748 
    749   @param [in] BufferLength    Length of the the buffer
    750 
    751   @param [in] pBuffer         Address of a buffer to receive the data.
    752 
    753   @param [in] pDataLength     Number of received data bytes in the buffer.
    754 
    755   @param [in] pAddress        Network address of the remote system address
    756 
    757   @param [in] AddressLength   Length of the remote network address structure
    758 
    759   @retval EFI_SUCCESS - Socket data successfully buffered
    760 
    761 **/
    762 EFI_STATUS
    763 EslUdp4TxBuffer (
    764   IN ESL_SOCKET * pSocket,
    765   IN int Flags,
    766   IN size_t BufferLength,
    767   IN CONST UINT8 * pBuffer,
    768   OUT size_t * pDataLength,
    769   IN const struct sockaddr * pAddress,
    770   IN socklen_t AddressLength
    771   )
    772 {
    773   ESL_PACKET * pPacket;
    774   ESL_PACKET * pPreviousPacket;
    775   ESL_PORT * pPort;
    776   const struct sockaddr_in * pRemoteAddress;
    777   ESL_UDP4_CONTEXT * pUdp4;
    778   size_t * pTxBytes;
    779   ESL_UDP4_TX_DATA * pTxData;
    780   EFI_STATUS Status;
    781   EFI_TPL TplPrevious;
    782 
    783   DBG_ENTER ( );
    784 
    785   //
    786   //  Assume failure
    787   //
    788   Status = EFI_UNSUPPORTED;
    789   pSocket->errno = ENOTCONN;
    790   *pDataLength = 0;
    791 
    792   //
    793   //  Verify that the socket is connected
    794   //
    795   if ( SOCKET_STATE_CONNECTED == pSocket->State ) {
    796     //
    797     //  Verify that there is enough room to buffer another
    798     //  transmit operation
    799     //
    800     pTxBytes = &pSocket->TxBytes;
    801     if ( pSocket->MaxTxBuf > *pTxBytes ) {
    802       //
    803       //  Locate the port
    804       //
    805       pPort = pSocket->pPortList;
    806       while ( NULL != pPort ) {
    807         //
    808         //  Determine the queue head
    809         //
    810         pUdp4 = &pPort->Context.Udp4;
    811 
    812         //
    813         //  Attempt to allocate the packet
    814         //
    815         Status = EslSocketPacketAllocate ( &pPacket,
    816                                            sizeof ( pPacket->Op.Udp4Tx )
    817                                            - sizeof ( pPacket->Op.Udp4Tx.Buffer )
    818                                            + BufferLength,
    819                                            0,
    820                                            DEBUG_TX );
    821         if ( !EFI_ERROR ( Status )) {
    822           //
    823           //  Initialize the transmit operation
    824           //
    825           pTxData = &pPacket->Op.Udp4Tx;
    826           pTxData->TxData.GatewayAddress = NULL;
    827           pTxData->TxData.UdpSessionData = NULL;
    828           pTxData->TxData.DataLength = (UINT32) BufferLength;
    829           pTxData->TxData.FragmentCount = 1;
    830           pTxData->TxData.FragmentTable[0].FragmentLength = (UINT32) BufferLength;
    831           pTxData->TxData.FragmentTable[0].FragmentBuffer = &pPacket->Op.Udp4Tx.Buffer[0];
    832           pTxData->RetransmitCount = 0;
    833 
    834           //
    835           //  Set the remote system address if necessary
    836           //
    837           pTxData->TxData.UdpSessionData = NULL;
    838           if ( NULL != pAddress ) {
    839             pRemoteAddress = (const struct sockaddr_in *)pAddress;
    840             pTxData->Session.SourceAddress.Addr[0] = pUdp4->ConfigData.StationAddress.Addr[0];
    841             pTxData->Session.SourceAddress.Addr[1] = pUdp4->ConfigData.StationAddress.Addr[1];
    842             pTxData->Session.SourceAddress.Addr[2] = pUdp4->ConfigData.StationAddress.Addr[2];
    843             pTxData->Session.SourceAddress.Addr[3] = pUdp4->ConfigData.StationAddress.Addr[3];
    844             pTxData->Session.SourcePort = 0;
    845             pTxData->Session.DestinationAddress.Addr[0] = (UINT8)pRemoteAddress->sin_addr.s_addr;
    846             pTxData->Session.DestinationAddress.Addr[1] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 8 );
    847             pTxData->Session.DestinationAddress.Addr[2] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 16 );
    848             pTxData->Session.DestinationAddress.Addr[3] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 24 );
    849             pTxData->Session.DestinationPort = SwapBytes16 ( pRemoteAddress->sin_port );
    850 
    851             //
    852             //  Use the remote system address when sending this packet
    853             //
    854             pTxData->TxData.UdpSessionData = &pTxData->Session;
    855           }
    856 
    857           //
    858           //  Copy the data into the buffer
    859           //
    860           CopyMem ( &pPacket->Op.Udp4Tx.Buffer[0],
    861                     pBuffer,
    862                     BufferLength );
    863 
    864           //
    865           //  Synchronize with the socket layer
    866           //
    867           RAISE_TPL ( TplPrevious, TPL_SOCKETS );
    868 
    869           //
    870           //  Display the request
    871           //
    872           DEBUG (( DEBUG_TX,
    873                     "Send %d bytes from 0x%08x to %d.%d.%d.%d:%d\r\n",
    874                     BufferLength,
    875                     pBuffer,
    876                     pTxData->Session.DestinationAddress.Addr[0],
    877                     pTxData->Session.DestinationAddress.Addr[1],
    878                     pTxData->Session.DestinationAddress.Addr[2],
    879                     pTxData->Session.DestinationAddress.Addr[3],
    880                     pTxData->Session.DestinationPort ));
    881 
    882           //
    883           //  Queue the data for transmission
    884           //
    885           pPacket->pNext = NULL;
    886           pPreviousPacket = pSocket->pTxPacketListTail;
    887           if ( NULL == pPreviousPacket ) {
    888             pSocket->pTxPacketListHead = pPacket;
    889           }
    890           else {
    891             pPreviousPacket->pNext = pPacket;
    892           }
    893           pSocket->pTxPacketListTail = pPacket;
    894           DEBUG (( DEBUG_TX,
    895                     "0x%08x: Packet on transmit list\r\n",
    896                     pPacket ));
    897 
    898           //
    899           //  Account for the buffered data
    900           //
    901           *pTxBytes += BufferLength;
    902           *pDataLength = BufferLength;
    903 
    904           //
    905           //  Start the transmit engine if it is idle
    906           //
    907           if ( NULL != pPort->pTxFree ) {
    908             pPacket = pSocket->pTxPacketListHead;
    909             EslSocketTxStart ( pPort,
    910                                &pSocket->pTxPacketListHead,
    911                                &pSocket->pTxPacketListTail,
    912                                &pPort->pTxActive,
    913                                &pPort->pTxFree );
    914 
    915             //
    916             //  Ignore any transmit error
    917             //
    918             if ( EFI_ERROR ( pSocket->TxError )) {
    919               DEBUG (( DEBUG_TX,
    920                        "0x%08x: Transmit error, Packet: 0x%08x, Status: %r\r\n",
    921                        pPort,
    922                        pPacket,
    923                        pSocket->TxError ));
    924             }
    925             pSocket->TxError = EFI_SUCCESS;
    926           }
    927 
    928           //
    929           //  Release the socket layer synchronization
    930           //
    931           RESTORE_TPL ( TplPrevious );
    932         }
    933         else {
    934           //
    935           //  Packet allocation failed
    936           //
    937           pSocket->errno = ENOMEM;
    938           break;
    939         }
    940 
    941         //
    942         //  Set the next port
    943         //
    944         pPort = pPort->pLinkSocket;
    945       }
    946     }
    947     else {
    948       //
    949       //  Not enough buffer space available
    950       //
    951       pSocket->errno = EAGAIN;
    952       Status = EFI_NOT_READY;
    953     }
    954   }
    955 
    956   //
    957   //  Return the operation status
    958   //
    959   DBG_EXIT_STATUS ( Status );
    960   return Status;
    961 }
    962 
    963 
    964 /**
    965   Process the transmit completion
    966 
    967   This routine use ::EslSocketTxComplete to perform the transmit
    968   completion processing for data packets.
    969 
    970   This routine is called by the UDPv4 network layer when a data
    971   transmit request completes.
    972 
    973   @param [in] Event     The normal transmit completion event
    974 
    975   @param [in] pIo       Address of an ::ESL_IO_MGMT structure
    976 
    977 **/
    978 VOID
    979 EslUdp4TxComplete (
    980   IN EFI_EVENT Event,
    981   IN ESL_IO_MGMT * pIo
    982   )
    983 {
    984   UINT32 LengthInBytes;
    985   ESL_PORT * pPort;
    986   ESL_PACKET * pPacket;
    987   ESL_SOCKET * pSocket;
    988   EFI_STATUS Status;
    989 
    990   DBG_ENTER ( );
    991 
    992   //
    993   //  Locate the active transmit packet
    994   //
    995   pPacket = pIo->pPacket;
    996   pPort = pIo->pPort;
    997   pSocket = pPort->pSocket;
    998 
    999   //
   1000   //  Get the transmit length and status
   1001   //
   1002   LengthInBytes = pPacket->Op.Udp4Tx.TxData.DataLength;
   1003   pSocket->TxBytes -= LengthInBytes;
   1004   Status = pIo->Token.Udp4Tx.Status;
   1005 
   1006   //
   1007   //  Ignore the transmit error
   1008   //
   1009   if ( EFI_ERROR ( Status )) {
   1010     DEBUG (( DEBUG_TX,
   1011              "0x%08x: Transmit completion error, Packet: 0x%08x, Status: %r\r\n",
   1012              pPort,
   1013              pPacket,
   1014              Status ));
   1015     Status = EFI_SUCCESS;
   1016   }
   1017 
   1018   //
   1019   //  Complete the transmit operation
   1020   //
   1021   EslSocketTxComplete ( pIo,
   1022                         LengthInBytes,
   1023                         Status,
   1024                         "UDP ",
   1025                         &pSocket->pTxPacketListHead,
   1026                         &pSocket->pTxPacketListTail,
   1027                         &pPort->pTxActive,
   1028                         &pPort->pTxFree );
   1029   DBG_EXIT ( );
   1030 }
   1031 
   1032 
   1033 /**
   1034   Verify the adapter's IP address
   1035 
   1036   This support routine is called by EslSocketBindTest.
   1037 
   1038   @param [in] pPort       Address of an ::ESL_PORT structure.
   1039   @param [in] pConfigData Address of the configuration data
   1040 
   1041   @retval EFI_SUCCESS - The IP address is valid
   1042   @retval EFI_NOT_STARTED - The IP address is invalid
   1043 
   1044  **/
   1045 EFI_STATUS
   1046 EslUdp4VerifyLocalIpAddress (
   1047   IN ESL_PORT * pPort,
   1048   IN EFI_UDP4_CONFIG_DATA * pConfigData
   1049   )
   1050 {
   1051   UINTN DataSize;
   1052   EFI_IP4_CONFIG2_INTERFACE_INFO * pIfInfo;
   1053   EFI_IP4_CONFIG2_PROTOCOL * pIpConfig2Protocol;
   1054   ESL_SERVICE * pService;
   1055   EFI_STATUS Status;
   1056 
   1057   DBG_ENTER ( );
   1058 
   1059   //
   1060   //  Use break instead of goto
   1061   //
   1062   pIfInfo = NULL;
   1063   for ( ; ; ) {
   1064     //
   1065     //  Determine if the IP address is specified
   1066     //
   1067     DEBUG (( DEBUG_BIND,
   1068               "UseDefaultAddress: %s\r\n",
   1069               pConfigData->UseDefaultAddress ? L"TRUE" : L"FALSE" ));
   1070     DEBUG (( DEBUG_BIND,
   1071               "Requested IP address: %d.%d.%d.%d\r\n",
   1072               pConfigData->StationAddress.Addr [ 0 ],
   1073               pConfigData->StationAddress.Addr [ 1 ],
   1074               pConfigData->StationAddress.Addr [ 2 ],
   1075               pConfigData->StationAddress.Addr [ 3 ]));
   1076     if ( pConfigData->UseDefaultAddress
   1077       || (( 0 == pConfigData->StationAddress.Addr [ 0 ])
   1078       && ( 0 == pConfigData->StationAddress.Addr [ 1 ])
   1079       && ( 0 == pConfigData->StationAddress.Addr [ 2 ])
   1080       && ( 0 == pConfigData->StationAddress.Addr [ 3 ])))
   1081     {
   1082       Status = EFI_SUCCESS;
   1083       break;
   1084     }
   1085 
   1086     //
   1087     //  Open the configuration protocol
   1088     //
   1089     pService = pPort->pService;
   1090     Status = gBS->OpenProtocol (
   1091                     pService->Controller,
   1092                     &gEfiIp4Config2ProtocolGuid,
   1093                     (VOID **)&pIpConfig2Protocol,
   1094                     NULL,
   1095                     NULL,
   1096                     EFI_OPEN_PROTOCOL_GET_PROTOCOL
   1097                     );
   1098     if ( EFI_ERROR ( Status )) {
   1099       DEBUG (( DEBUG_ERROR,
   1100                 "ERROR - IP Configuration Protocol not available, Status: %r\r\n",
   1101                 Status ));
   1102       break;
   1103     }
   1104 
   1105     //
   1106     //  Get the interface information size
   1107     //
   1108     DataSize = 0;
   1109     Status = pIpConfig2Protocol->GetData (
   1110                                    pIpConfig2Protocol,
   1111                                    Ip4Config2DataTypeInterfaceInfo,
   1112                                    &DataSize,
   1113                                    NULL
   1114                                    );
   1115     if ( EFI_BUFFER_TOO_SMALL != Status ) {
   1116       DEBUG (( DEBUG_ERROR,
   1117                 "ERROR - Failed to get the interface information size, Status: %r\r\n",
   1118                 Status ));
   1119       break;
   1120     }
   1121 
   1122     //
   1123     //  Allocate the interface information buffer
   1124     //
   1125     pIfInfo = AllocatePool ( DataSize );
   1126     if ( NULL == pIfInfo ) {
   1127       DEBUG (( DEBUG_ERROR,
   1128                 "ERROR - Not enough memory to allocate the interface information buffer!\r\n" ));
   1129       Status = EFI_OUT_OF_RESOURCES;
   1130       break;
   1131     }
   1132 
   1133     //
   1134     // Get the interface info.
   1135     //
   1136     Status = pIpConfig2Protocol->GetData (
   1137                                   pIpConfig2Protocol,
   1138                                   Ip4Config2DataTypeInterfaceInfo,
   1139                                   &DataSize,
   1140                                   pIfInfo
   1141                                   );
   1142     if ( EFI_ERROR ( Status )) {
   1143       DEBUG (( DEBUG_ERROR,
   1144                 "ERROR - Failed to return the interface info, Status: %r\r\n",
   1145                 Status ));
   1146       break;
   1147     }
   1148 
   1149     //
   1150     //  Display the current configuration
   1151     //
   1152     DEBUG (( DEBUG_BIND,
   1153               "Actual adapter IP address: %d.%d.%d.%d\r\n",
   1154               pIfInfo->StationAddress.Addr [ 0 ],
   1155               pIfInfo->StationAddress.Addr [ 1 ],
   1156               pIfInfo->StationAddress.Addr [ 2 ],
   1157               pIfInfo->StationAddress.Addr [ 3 ]));
   1158 
   1159     //
   1160     //  Assume the port is not configured
   1161     //
   1162     Status = EFI_SUCCESS;
   1163     if (( pConfigData->StationAddress.Addr [ 0 ] == pIfInfo->StationAddress.Addr [ 0 ])
   1164       && ( pConfigData->StationAddress.Addr [ 1 ] == pIfInfo->StationAddress.Addr [ 1 ])
   1165       && ( pConfigData->StationAddress.Addr [ 2 ] == pIfInfo->StationAddress.Addr [ 2 ])
   1166       && ( pConfigData->StationAddress.Addr [ 3 ] == pIfInfo->StationAddress.Addr [ 3 ])) {
   1167       break;
   1168     }
   1169 
   1170     //
   1171     //  The IP address did not match
   1172     //
   1173     Status = EFI_NOT_STARTED;
   1174     break;
   1175   }
   1176 
   1177   //
   1178   //  Free the buffer if necessary
   1179   //
   1180   if ( NULL != pIfInfo ) {
   1181     FreePool ( pIfInfo );
   1182   }
   1183 
   1184   //
   1185   //  Return the IP address status
   1186   //
   1187   DBG_EXIT_STATUS ( Status );
   1188   return Status;
   1189 }
   1190 
   1191 
   1192 /**
   1193   Interface between the socket layer and the network specific
   1194   code that supports SOCK_DGRAM sockets over UDPv4.
   1195 **/
   1196 CONST ESL_PROTOCOL_API cEslUdp4Api = {
   1197   "UDPv4",
   1198   IPPROTO_UDP,
   1199   OFFSET_OF ( ESL_PORT, Context.Udp4.ConfigData ),
   1200   OFFSET_OF ( ESL_LAYER, pUdp4List ),
   1201   OFFSET_OF ( struct sockaddr_in, sin_zero ),
   1202   sizeof ( struct sockaddr_in ),
   1203   AF_INET,
   1204   sizeof (((ESL_PACKET *)0 )->Op.Udp4Rx ),
   1205   sizeof (((ESL_PACKET *)0 )->Op.Udp4Rx ),
   1206   OFFSET_OF ( ESL_IO_MGMT, Token.Udp4Rx.Packet.RxData ),
   1207   FALSE,
   1208   EADDRINUSE,
   1209   NULL,   //  Accept
   1210   NULL,   //  ConnectPoll
   1211   NULL,   //  ConnectStart
   1212   EslUdp4SocketIsConfigured,
   1213   EslUdp4LocalAddressGet,
   1214   EslUdp4LocalAddressSet,
   1215   NULL,   //  Listen
   1216   NULL,   //  OptionGet
   1217   NULL,   //  OptionSet
   1218   EslUdp4PacketFree,
   1219   EslUdp4PortAllocate,
   1220   NULL,   //  PortClose,
   1221   NULL,   //  PortCloseOp
   1222   TRUE,
   1223   EslUdp4Receive,
   1224   EslUdp4RemoteAddressGet,
   1225   EslUdp4RemoteAddressSet,
   1226   EslUdp4RxComplete,
   1227   NULL,   //  RxStart
   1228   EslUdp4TxBuffer,
   1229   EslUdp4TxComplete,
   1230   NULL,   //  TxOobComplete
   1231   (PFN_API_VERIFY_LOCAL_IP_ADDRESS)EslUdp4VerifyLocalIpAddress
   1232 };
   1233