summaryrefslogtreecommitdiff
path: root/StdLib/EfiSocketLib/Udp4.c
diff options
context:
space:
mode:
Diffstat (limited to 'StdLib/EfiSocketLib/Udp4.c')
-rw-r--r--StdLib/EfiSocketLib/Udp4.c2408
1 files changed, 2408 insertions, 0 deletions
diff --git a/StdLib/EfiSocketLib/Udp4.c b/StdLib/EfiSocketLib/Udp4.c
new file mode 100644
index 0000000000..95fc66517a
--- /dev/null
+++ b/StdLib/EfiSocketLib/Udp4.c
@@ -0,0 +1,2408 @@
+/** @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"
+
+
+/**
+ Bind a name to a socket.
+
+ The ::UdpBind4 routine connects a name to a UDP4 stack on the local machine.
+
+ The configure call to the UDP4 driver occurs on the first poll, recv, recvfrom,
+ send or sentto call. Until then, all changes are made in the local UDP context
+ structure.
+
+ @param [in] pSocket Address of the socket 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] SockAddrLen Specifies the length in bytes of the sockaddr structure.
+
+ @retval EFI_SUCCESS - Socket successfully created
+
+ **/
+EFI_STATUS
+EslUdpBind4 (
+ IN DT_SOCKET * pSocket,
+ IN const struct sockaddr * pSockAddr,
+ IN socklen_t SockAddrLength
+ )
+{
+ EFI_HANDLE ChildHandle;
+ DT_LAYER * pLayer;
+ DT_PORT * pPort;
+ DT_SERVICE * pService;
+ CONST struct sockaddr_in * pIp4Address;
+ EFI_SERVICE_BINDING_PROTOCOL * pUdp4Service;
+ EFI_STATUS Status;
+ EFI_STATUS TempStatus;
+
+ DBG_ENTER ( );
+
+ //
+ // Verify the socket layer synchronization
+ //
+ VERIFY_TPL ( TPL_SOCKETS );
+
+ //
+ // Assume success
+ //
+ pSocket->errno = 0;
+ Status = EFI_SUCCESS;
+
+ //
+ // Validate the address length
+ //
+ pIp4Address = (CONST struct sockaddr_in *) pSockAddr;
+ if ( SockAddrLength >= ( sizeof ( *pIp4Address )
+ - sizeof ( pIp4Address->sin_zero ))) {
+
+ //
+ // Walk the list of services
+ //
+ pLayer = &mEslLayer;
+ pService = pLayer->pUdp4List;
+ while ( NULL != pService ) {
+
+ //
+ // Create the UDP port
+ //
+ pUdp4Service = pService->pInterface;
+ ChildHandle = NULL;
+ Status = pUdp4Service->CreateChild ( pUdp4Service,
+ &ChildHandle );
+ if ( !EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_BIND | DEBUG_POOL,
+ "0x%08x: Udp4 port handle created\r\n",
+ ChildHandle ));
+
+ //
+ // Open the port
+ //
+ Status = EslUdpPortAllocate4 ( pSocket,
+ pService,
+ ChildHandle,
+ (UINT8 *) &pIp4Address->sin_addr.s_addr,
+ SwapBytes16 ( pIp4Address->sin_port ),
+ DEBUG_BIND,
+ &pPort );
+ }
+ else {
+ DEBUG (( DEBUG_BIND | DEBUG_POOL,
+ "ERROR - Failed to open Udp4 port handle, Status: %r\r\n",
+ Status ));
+ ChildHandle = NULL;
+ }
+
+ //
+ // Close the port if necessary
+ //
+ if (( EFI_ERROR ( Status )) && ( NULL != ChildHandle )) {
+ TempStatus = pUdp4Service->DestroyChild ( pUdp4Service,
+ ChildHandle );
+ if ( !EFI_ERROR ( TempStatus )) {
+ DEBUG (( DEBUG_BIND | DEBUG_POOL,
+ "0x%08x: Udp4 port handle destroyed\r\n",
+ ChildHandle ));
+ }
+ else {
+ DEBUG (( DEBUG_ERROR | DEBUG_BIND | DEBUG_POOL,
+ "ERROR - Failed to destroy the Udp4 port handle 0x%08x, Status: %r\r\n",
+ ChildHandle,
+ TempStatus ));
+ ASSERT ( EFI_SUCCESS == TempStatus );
+ }
+ }
+
+ //
+ // Set the next service
+ //
+ pService = pService->pNext;
+ }
+
+ //
+ // Verify that at least one network connection was found
+ //
+ if ( NULL == pSocket->pPortList ) {
+ DEBUG (( DEBUG_BIND | DEBUG_POOL | DEBUG_INIT,
+ "Socket address %d.%d.%d.%d (0x%08x) is not available!\r\n",
+ ( pIp4Address->sin_addr.s_addr >> 24 ) & 0xff,
+ ( pIp4Address->sin_addr.s_addr >> 16 ) & 0xff,
+ ( pIp4Address->sin_addr.s_addr >> 8 ) & 0xff,
+ pIp4Address->sin_addr.s_addr & 0xff,
+ pIp4Address->sin_addr.s_addr ));
+ pSocket->errno = EADDRNOTAVAIL;
+ Status = EFI_INVALID_PARAMETER;
+ }
+ }
+ else {
+ DEBUG (( DEBUG_BIND,
+ "ERROR - Invalid Udp4 address length: %d\r\n",
+ SockAddrLength ));
+ Status = EFI_INVALID_PARAMETER;
+ pSocket->errno = EINVAL;
+ }
+
+ //
+ // Return the operation status
+ //
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+
+/**
+ Initialize the UDP4 service.
+
+ This routine initializes the UDP4 service after its service binding
+ protocol was located on a controller.
+
+ @param [in] pService DT_SERVICE structure address
+
+ @retval EFI_SUCCESS The service was properly initialized
+ @retval other A failure occurred during the service initialization
+
+**/
+EFI_STATUS
+EFIAPI
+EslUdpInitialize4 (
+ IN DT_SERVICE * pService
+ )
+{
+ DT_LAYER * pLayer;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Identify the service
+ //
+ pService->NetworkType = NETWORK_TYPE_UDP4;
+
+ //
+ // Connect this service to the service list
+ //
+ pLayer = &mEslLayer;
+ pService->pNext = pLayer->pUdp4List;
+ pLayer->pUdp4List = pService;
+
+ //
+ // Assume the list is empty
+ //
+ Status = EFI_SUCCESS;
+
+ //
+ // Return the initialization status
+ //
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+
+/**
+ Allocate and initialize a DT_PORT structure.
+
+ @param [in] pSocket Address of the socket structure.
+ @param [in] pService Address of the DT_SERVICE structure.
+ @param [in] ChildHandle Udp4 child handle
+ @param [in] pIpAddress Buffer containing IP4 network address of the local host
+ @param [in] PortNumber Udp4 port number
+ @param [in] DebugFlags Flags for debug messages
+ @param [out] ppPort Buffer to receive new DT_PORT structure address
+
+ @retval EFI_SUCCESS - Socket successfully created
+
+ **/
+EFI_STATUS
+EslUdpPortAllocate4 (
+ IN DT_SOCKET * pSocket,
+ IN DT_SERVICE * pService,
+ IN EFI_HANDLE ChildHandle,
+ IN CONST UINT8 * pIpAddress,
+ IN UINT16 PortNumber,
+ IN UINTN DebugFlags,
+ OUT DT_PORT ** ppPort
+ )
+{
+ UINTN LengthInBytes;
+ EFI_UDP4_CONFIG_DATA * pConfig;
+ DT_LAYER * pLayer;
+ DT_PORT * pPort;
+ DT_UDP4_CONTEXT * pUdp4;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Use for/break instead of goto
+ for ( ; ; ) {
+ //
+ // Allocate a port structure
+ //
+ pLayer = &mEslLayer;
+ LengthInBytes = sizeof ( *pPort );
+ Status = gBS->AllocatePool ( EfiRuntimeServicesData,
+ LengthInBytes,
+ (VOID **)&pPort );
+ if ( EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_ERROR | DebugFlags | DEBUG_POOL | DEBUG_INIT,
+ "ERROR - Failed to allocate the port structure, Status: %r\r\n",
+ Status ));
+ pSocket->errno = ENOMEM;
+ pPort = NULL;
+ break;
+ }
+ DEBUG (( DebugFlags | DEBUG_POOL | DEBUG_INIT,
+ "0x%08x: Allocate pPort, %d bytes\r\n",
+ pPort,
+ LengthInBytes ));
+
+ //
+ // Initialize the port
+ //
+ ZeroMem ( pPort, LengthInBytes );
+ pPort->Signature = PORT_SIGNATURE;
+ pPort->pService = pService;
+ pPort->pSocket = pSocket;
+ pPort->pfnCloseStart = EslUdpPortCloseStart4;
+ pPort->DebugFlags = DebugFlags;
+
+ //
+ // Allocate the receive event
+ //
+ pUdp4 = &pPort->Context.Udp4;
+ Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL,
+ TPL_SOCKETS,
+ (EFI_EVENT_NOTIFY)EslUdpRxComplete4,
+ pPort,
+ &pUdp4->RxToken.Event);
+ if ( EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_ERROR | DebugFlags,
+ "ERROR - Failed to create the receive event, Status: %r\r\n",
+ Status ));
+ pSocket->errno = ENOMEM;
+ break;
+ }
+ DEBUG (( DEBUG_RX | DEBUG_POOL,
+ "0x%08x: Created receive event\r\n",
+ pUdp4->RxToken.Event ));
+
+ //
+ // Allocate the transmit event
+ //
+ Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL,
+ TPL_SOCKETS,
+ (EFI_EVENT_NOTIFY)EslUdpTxComplete4,
+ pPort,
+ &pUdp4->TxToken.Event);
+ if ( EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_ERROR | DebugFlags,
+ "ERROR - Failed to create the transmit event, Status: %r\r\n",
+ Status ));
+ pSocket->errno = ENOMEM;
+ break;
+ }
+ DEBUG (( DEBUG_CLOSE | DEBUG_POOL,
+ "0x%08x: Created transmit event\r\n",
+ pUdp4->TxToken.Event ));
+
+ //
+ // Open the port protocol
+ //
+ Status = gBS->OpenProtocol (
+ ChildHandle,
+ &gEfiUdp4ProtocolGuid,
+ (VOID **) &pUdp4->pProtocol,
+ pLayer->ImageHandle,
+ NULL,
+ EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL );
+ if ( EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_ERROR | DebugFlags,
+ "ERROR - Failed to open gEfiUdp4ProtocolGuid on controller 0x%08x\r\n",
+ pUdp4->Handle ));
+ pSocket->errno = EEXIST;
+ break;
+ }
+ DEBUG (( DebugFlags,
+ "0x%08x: gEfiUdp4ProtocolGuid opened on controller 0x%08x\r\n",
+ pUdp4->pProtocol,
+ ChildHandle ));
+
+ //
+ // Set the port address
+ //
+ pUdp4->Handle = ChildHandle;
+ pConfig = &pPort->Context.Udp4.ConfigData;
+ pConfig->StationPort = PortNumber;
+ if (( 0 == pIpAddress[0])
+ && ( 0 == pIpAddress[1])
+ && ( 0 == pIpAddress[2])
+ && ( 0 == pIpAddress[3])) {
+ pConfig->UseDefaultAddress = TRUE;
+ }
+ else {
+ pConfig->StationAddress.Addr[0] = pIpAddress[0];
+ pConfig->StationAddress.Addr[1] = pIpAddress[1];
+ pConfig->StationAddress.Addr[2] = pIpAddress[2];
+ pConfig->StationAddress.Addr[3] = pIpAddress[3];
+ pConfig->SubnetMask.Addr[0] = 0xff;
+ pConfig->SubnetMask.Addr[1] = 0xff;
+ pConfig->SubnetMask.Addr[2] = 0xff;
+ pConfig->SubnetMask.Addr[3] = 0xff;
+ }
+ pConfig->TimeToLive = 255;
+ pConfig->AcceptAnyPort = FALSE;
+ pConfig->AcceptBroadcast = FALSE;
+ pConfig->AcceptPromiscuous = FALSE;
+ pConfig->AllowDuplicatePort = TRUE;
+ pConfig->DoNotFragment = TRUE;
+
+ //
+ // Verify the socket layer synchronization
+ //
+ VERIFY_TPL ( TPL_SOCKETS );
+
+ //
+ // 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 )) && ( NULL != pPort )) {
+ //
+ // Close the port
+ //
+ EslUdpPortClose4 ( pPort );
+ }
+ //
+ // Return the operation status
+ //
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+
+/**
+ Close a UDP4 port.
+
+ This routine releases the resources allocated by
+ ::UdpPortAllocate4().
+
+ @param [in] pPort Address of the port structure.
+
+ @retval EFI_SUCCESS The port is closed
+ @retval other Port close error
+
+**/
+EFI_STATUS
+EslUdpPortClose4 (
+ IN DT_PORT * pPort
+ )
+{
+ UINTN DebugFlags;
+ DT_LAYER * pLayer;
+ DT_PACKET * pPacket;
+ DT_PORT * pPreviousPort;
+ DT_SERVICE * pService;
+ DT_SOCKET * pSocket;
+ EFI_SERVICE_BINDING_PROTOCOL * pUdp4Service;
+ DT_UDP4_CONTEXT * pUdp4;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Verify the socket layer synchronization
+ //
+ VERIFY_TPL ( TPL_SOCKETS );
+
+ //
+ // Assume success
+ //
+ Status = EFI_SUCCESS;
+ pSocket = pPort->pSocket;
+ pSocket->errno = 0;
+
+ //
+ // Locate the port in the socket list
+ //
+ pLayer = &mEslLayer;
+ DebugFlags = pPort->DebugFlags;
+ 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
+ //
+ pService = pPort->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 receive queue
+ //
+ ASSERT ( NULL == pSocket->pRxPacketListHead );
+ ASSERT ( NULL == pSocket->pRxPacketListTail );
+ ASSERT ( 0 == pSocket->RxBytes );
+
+ //
+ // Empty the receive free queue
+ //
+ while ( NULL != pSocket->pRxFree ) {
+ pPacket = pSocket->pRxFree;
+ pSocket->pRxFree = pPacket->pNext;
+ EslSocketPacketFree ( pPacket, DEBUG_RX );
+ }
+
+ //
+ // Done with the receive event
+ //
+ pUdp4 = &pPort->Context.Udp4;
+ if ( NULL != pUdp4->RxToken.Event ) {
+ Status = gBS->CloseEvent ( pUdp4->RxToken.Event );
+ if ( !EFI_ERROR ( Status )) {
+ DEBUG (( DebugFlags | DEBUG_POOL,
+ "0x%08x: Closed receive event\r\n",
+ pUdp4->RxToken.Event ));
+ }
+ else {
+ DEBUG (( DEBUG_ERROR | DebugFlags,
+ "ERROR - Failed to close the receive event, Status: %r\r\n",
+ Status ));
+ ASSERT ( EFI_SUCCESS == Status );
+ }
+ }
+
+ //
+ // Done with the transmit event
+ //
+ if ( NULL != pUdp4->TxToken.Event ) {
+ Status = gBS->CloseEvent ( pUdp4->TxToken.Event );
+ if ( !EFI_ERROR ( Status )) {
+ DEBUG (( DebugFlags | DEBUG_POOL,
+ "0x%08x: Closed normal transmit event\r\n",
+ pUdp4->TxToken.Event ));
+ }
+ else {
+ DEBUG (( DEBUG_ERROR | DebugFlags,
+ "ERROR - Failed to close the normal transmit event, Status: %r\r\n",
+ Status ));
+ ASSERT ( EFI_SUCCESS == Status );
+ }
+ }
+
+ //
+ // Done with the UDP protocol
+ //
+ pUdp4Service = pService->pInterface;
+ if ( NULL != pUdp4->pProtocol ) {
+ Status = gBS->CloseProtocol ( pUdp4->Handle,
+ &gEfiUdp4ProtocolGuid,
+ pLayer->ImageHandle,
+ NULL );
+ if ( !EFI_ERROR ( Status )) {
+ DEBUG (( DebugFlags,
+ "0x%08x: gEfiUdp4ProtocolGuid closed on controller 0x%08x\r\n",
+ pUdp4->pProtocol,
+ pUdp4->Handle ));
+ }
+ else {
+ DEBUG (( DEBUG_ERROR | DebugFlags,
+ "ERROR - Failed to close gEfiUdp4ProtocolGuid opened on controller 0x%08x, Status: %r\r\n",
+ pUdp4->Handle,
+ Status ));
+ ASSERT ( EFI_SUCCESS == Status );
+ }
+ }
+
+ //
+ // Done with the UDP port
+ //
+ if ( NULL != pUdp4->Handle ) {
+ Status = pUdp4Service->DestroyChild ( pUdp4Service,
+ pUdp4->Handle );
+ if ( !EFI_ERROR ( Status )) {
+ DEBUG (( DebugFlags | DEBUG_POOL,
+ "0x%08x: Udp4 port handle destroyed\r\n",
+ pUdp4->Handle ));
+ }
+ else {
+ DEBUG (( DEBUG_ERROR | DebugFlags | DEBUG_POOL,
+ "ERROR - Failed to destroy the Udp4 port handle, Status: %r\r\n",
+ 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;
+}
+
+
+/**
+ Start the close operation on a UDP4 port, state 1.
+
+ Closing a port goes through the following states:
+ 1. Port close starting - Mark the port as closing and wait for transmission to complete
+ 2. Port TX close done - Transmissions complete, close the port and abort the receives
+ 3. Port RX close done - Receive operations complete, close the port
+ 4. Port closed - Release the port resources
+
+ @param [in] pPort Address of the 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
+EslUdpPortCloseStart4 (
+ IN DT_PORT * pPort,
+ IN BOOLEAN bCloseNow,
+ IN UINTN DebugFlags
+ )
+{
+ DT_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 = EslUdpPortCloseTxDone4 ( pPort );
+ }
+
+ //
+ // Return the operation status
+ //
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+
+/**
+ Port close state 3
+
+ Continue the close operation after the receive is complete.
+
+ @param [in] pPort Address of the 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
+EslUdpPortCloseRxDone4 (
+ IN DT_PORT * pPort
+ )
+{
+ PORT_STATE PortState;
+ DT_SOCKET * pSocket;
+ DT_UDP4_CONTEXT * pUdp4;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Verify the socket layer synchronization
+ //
+ VERIFY_TPL ( TPL_SOCKETS );
+
+ //
+ // Verify that the port is closing
+ //
+ Status = EFI_ALREADY_STARTED;
+ pSocket = pPort->pSocket;
+ pSocket->errno = EALREADY;
+ PortState = pPort->State;
+ if (( PORT_STATE_CLOSE_TX_DONE == PortState )
+ || ( PORT_STATE_CLOSE_DONE == PortState )) {
+ //
+ // Determine if the receive operation is pending
+ //
+ Status = EFI_NOT_READY;
+ pSocket->errno = EAGAIN;
+ pUdp4 = &pPort->Context.Udp4;
+ if ( NULL == pUdp4->pReceivePending ) {
+ //
+ // 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 ));
+
+ //
+ // The close operation has completed
+ // Release the port resources
+ //
+ Status = EslUdpPortClose4 ( pPort );
+ }
+ else {
+ DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
+ "0x%08x: Port Close: Receive still pending!\r\n",
+ pPort ));
+ }
+ }
+
+ //
+ // Return the operation status
+ //
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+
+/**
+ Port close state 2
+
+ Continue the close operation after the transmission is complete.
+
+ @param [in] pPort Address of the 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
+EslUdpPortCloseTxDone4 (
+ IN DT_PORT * pPort
+ )
+{
+ DT_PACKET * pPacket;
+ DT_SOCKET * pSocket;
+ DT_UDP4_CONTEXT * pUdp4;
+ EFI_UDP4_PROTOCOL * pUdp4Protocol;
+ 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 )
+ || ( 0 == pSocket->TxBytes )) {
+ //
+ // Start the close operation on the port
+ //
+ pUdp4 = &pPort->Context.Udp4;
+ pUdp4Protocol = pUdp4->pProtocol;
+ if ( !pUdp4->bConfigured ) {
+ //
+ // Skip the close operation since the port is not
+ // configured
+ //
+ // 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 ));
+ Status = EFI_SUCCESS;
+ }
+ else {
+ //
+ // 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 ));
+
+ //
+ // Empty the receive queue
+ //
+ while ( NULL != pSocket->pRxPacketListHead ) {
+ pPacket = pSocket->pRxPacketListHead;
+ pSocket->pRxPacketListHead = pPacket->pNext;
+ pSocket->RxBytes -= pPacket->Op.Udp4Rx.pRxData->DataLength;
+
+ //
+ // Return the buffer to the UDP4 driver
+ //
+ gBS->SignalEvent ( pPacket->Op.Udp4Rx.pRxData->RecycleSignal );
+
+ //
+ // Done with this packet
+ //
+ EslSocketPacketFree ( pPacket, DEBUG_RX );
+ }
+ pSocket->pRxPacketListTail = NULL;
+ ASSERT ( 0 == pSocket->RxBytes );
+
+ //
+ // Reset the port, cancel the outstanding receive
+ //
+ Status = pUdp4Protocol->Configure ( pUdp4Protocol,
+ NULL );
+ if ( !EFI_ERROR ( Status )) {
+ DEBUG (( pPort->DebugFlags | DEBUG_CLOSE | DEBUG_INFO,
+ "0x%08x: Port reset\r\n",
+ pPort ));
+
+ //
+ // Free the receive packet
+ //
+ Status = gBS->CheckEvent ( pUdp4->RxToken.Event );
+ if ( EFI_SUCCESS != Status ) {
+ EslSocketPacketFree ( pUdp4->pReceivePending, DEBUG_CLOSE );
+ pUdp4->pReceivePending = NULL;
+ Status = EFI_SUCCESS;
+ }
+ }
+ else {
+ DEBUG (( DEBUG_ERROR | pPort->DebugFlags | DEBUG_CLOSE | DEBUG_INFO,
+ "ERROR - Port 0x%08x reset failed, Status: %r\r\n",
+ pPort,
+ Status ));
+ ASSERT ( EFI_SUCCESS == Status );
+ }
+ }
+
+ //
+ // Determine if the receive operation is pending
+ //
+ if ( !EFI_ERROR ( Status )) {
+ Status = EslUdpPortCloseRxDone4 ( pPort );
+ }
+ }
+ else {
+ //
+ // Transmissions are still active, exit
+ //
+ DEBUG (( DEBUG_CLOSE | DEBUG_INFO,
+ "0x%08x: Port Close: Transmits are still pending!\r\n",
+ pPort ));
+ Status = EFI_NOT_READY;
+ pSocket->errno = EAGAIN;
+ }
+ }
+
+ //
+ // Return the operation status
+ //
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+
+/**
+ Connect to a remote system via the network.
+
+ The ::UdpConnectStart4= routine sets the remote address for the connection.
+
+ @param [in] pSocket Address of the socket structure.
+
+ @param [in] pSockAddr Network address of the remote system.
+
+ @param [in] SockAddrLength Length in bytes of the network address.
+
+ @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
+EslUdpConnect4 (
+ IN DT_SOCKET * pSocket,
+ IN const struct sockaddr * pSockAddr,
+ IN socklen_t SockAddrLength
+ )
+{
+ struct sockaddr_in LocalAddress;
+ DT_PORT * pPort;
+ struct sockaddr_in * pRemoteAddress;
+ DT_UDP4_CONTEXT * pUdp4;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Assume failure
+ //
+ Status = EFI_NETWORK_UNREACHABLE;
+ pSocket->errno = ENETUNREACH;
+
+ //
+ // Get the address
+ //
+ pRemoteAddress = (struct sockaddr_in *)pSockAddr;
+
+ //
+ // Validate the address length
+ //
+ if ( SockAddrLength >= ( sizeof ( *pRemoteAddress )
+ - sizeof ( pRemoteAddress->sin_zero ))) {
+ //
+ // Determine if BIND was already called
+ //
+ if ( NULL == pSocket->pPortList ) {
+ //
+ // Allow any local port
+ //
+ ZeroMem ( &LocalAddress, sizeof ( LocalAddress ));
+ LocalAddress.sin_len = sizeof ( LocalAddress );
+ LocalAddress.sin_family = AF_INET;
+ Status = EslSocketBind ( &pSocket->SocketProtocol,
+ (struct sockaddr *)&LocalAddress,
+ LocalAddress.sin_len,
+ &pSocket->errno );
+ }
+
+ //
+ // Walk the list of ports
+ //
+ pPort = pSocket->pPortList;
+ while ( NULL != pPort ) {
+ //
+ // Set the remote address
+ //
+ pUdp4 = &pPort->Context.Udp4;
+ 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 );
+
+ //
+ // At least one path exists
+ //
+ Status = EFI_SUCCESS;
+ pSocket->errno = 0;
+
+ //
+ // Set the next port
+ //
+ pPort = pPort->pLinkSocket;
+ }
+ }
+ else {
+ DEBUG (( DEBUG_CONNECT,
+ "ERROR - Invalid UDP4 address length: %d\r\n",
+ SockAddrLength ));
+ Status = EFI_INVALID_PARAMETER;
+ pSocket->errno = EINVAL;
+ }
+
+ //
+ // Return the connect status
+ //
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+
+/**
+ Get the local socket address
+
+ @param [in] pSocket Address of the socket structure.
+
+ @param [out] pAddress Network address to receive the local system address
+
+ @param [in,out] pAddressLength Length of the local network address structure
+
+ @retval EFI_SUCCESS - Address available
+ @retval Other - Failed to get the address
+
+**/
+EFI_STATUS
+EslUdpGetLocalAddress4 (
+ IN DT_SOCKET * pSocket,
+ OUT struct sockaddr * pAddress,
+ IN OUT socklen_t * pAddressLength
+ )
+{
+ socklen_t LengthInBytes;
+ DT_PORT * pPort;
+ struct sockaddr_in * pLocalAddress;
+ DT_UDP4_CONTEXT * pUdp4;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Verify the socket layer synchronization
+ //
+ VERIFY_TPL ( TPL_SOCKETS );
+
+ //
+ // Verify that there is just a single connection
+ //
+ pPort = pSocket->pPortList;
+ if (( NULL != pPort ) && ( NULL == pPort->pLinkSocket )) {
+ //
+ // Verify the address length
+ //
+ LengthInBytes = sizeof ( struct sockaddr_in );
+ if ( LengthInBytes <= * pAddressLength ) {
+ //
+ // Return the local address
+ //
+ pUdp4 = &pPort->Context.Udp4;
+ pLocalAddress = (struct sockaddr_in *)pAddress;
+ ZeroMem ( pLocalAddress, LengthInBytes );
+ pLocalAddress->sin_family = AF_INET;
+ pLocalAddress->sin_len = (uint8_t)LengthInBytes;
+ pLocalAddress->sin_port = SwapBytes16 ( pUdp4->ConfigData.StationPort );
+ CopyMem ( &pLocalAddress->sin_addr,
+ &pUdp4->ConfigData.StationAddress.Addr[0],
+ sizeof ( pLocalAddress->sin_addr ));
+ pSocket->errno = 0;
+ Status = EFI_SUCCESS;
+ }
+ else {
+ pSocket->errno = EINVAL;
+ Status = EFI_INVALID_PARAMETER;
+ }
+ }
+ else {
+ pSocket->errno = ENOTCONN;
+ Status = EFI_NOT_STARTED;
+ }
+
+ //
+ // Return the operation status
+ //
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+
+/**
+ Get the remote socket address
+
+ @param [in] pSocket Address of the socket structure.
+
+ @param [out] pAddress Network address to receive the remote system address
+
+ @param [in,out] pAddressLength Length of the remote network address structure
+
+ @retval EFI_SUCCESS - Address available
+ @retval Other - Failed to get the address
+
+**/
+EFI_STATUS
+EslUdpGetRemoteAddress4 (
+ IN DT_SOCKET * pSocket,
+ OUT struct sockaddr * pAddress,
+ IN OUT socklen_t * pAddressLength
+ )
+{
+ socklen_t LengthInBytes;
+ DT_PORT * pPort;
+ struct sockaddr_in * pRemoteAddress;
+ DT_UDP4_CONTEXT * pUdp4;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Verify the socket layer synchronization
+ //
+ VERIFY_TPL ( TPL_SOCKETS );
+
+ //
+ // Verify that there is just a single connection
+ //
+ pPort = pSocket->pPortList;
+ if (( NULL != pPort ) && ( NULL == pPort->pLinkSocket )) {
+ //
+ // Verify the address length
+ //
+ LengthInBytes = sizeof ( struct sockaddr_in );
+ if ( LengthInBytes <= * pAddressLength ) {
+ //
+ // Return the local address
+ //
+ pUdp4 = &pPort->Context.Udp4;
+ pRemoteAddress = (struct sockaddr_in *)pAddress;
+ ZeroMem ( pRemoteAddress, LengthInBytes );
+ pRemoteAddress->sin_family = AF_INET;
+ pRemoteAddress->sin_len = (uint8_t)LengthInBytes;
+ pRemoteAddress->sin_port = SwapBytes16 ( pUdp4->ConfigData.RemotePort );
+ CopyMem ( &pRemoteAddress->sin_addr,
+ &pUdp4->ConfigData.RemoteAddress.Addr[0],
+ sizeof ( pRemoteAddress->sin_addr ));
+ pSocket->errno = 0;
+ Status = EFI_SUCCESS;
+ }
+ else {
+ pSocket->errno = EINVAL;
+ Status = EFI_INVALID_PARAMETER;
+ }
+ }
+ else {
+ pSocket->errno = ENOTCONN;
+ Status = EFI_NOT_STARTED;
+ }
+
+ //
+ // Return the operation status
+ //
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+
+/**
+ Receive data from a network connection.
+
+ To minimize the number of buffer copies, the ::UdpRxComplete4
+ routine queues the UDP4 driver's buffer to a list of datagrams
+ waiting to be received. The socket driver holds on to the
+ buffers from the UDP4 driver until the application layer requests
+ the data or the socket is closed.
+
+ The application calls this routine in the socket layer to
+ receive datagrams from one or more remote systems. This routine
+ removes the next available datagram from the list of datagrams
+ and copies the data from the UDP4 driver's buffer into the
+ application's buffer. The UDP4 driver's buffer is then returned.
+
+ @param [in] pSocket Address of a DT_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 [out] pAddress Network address to receive the remote system address
+
+ @param [in,out] pAddressLength Length of the remote network address structure
+
+ @retval EFI_SUCCESS - Socket data successfully received
+
+**/
+EFI_STATUS
+EslUdpReceive4 (
+ IN DT_SOCKET * pSocket,
+ IN INT32 Flags,
+ IN size_t BufferLength,
+ IN UINT8 * pBuffer,
+ OUT size_t * pDataLength,
+ OUT struct sockaddr * pAddress,
+ IN OUT socklen_t * pAddressLength
+ )
+{
+ socklen_t AddressLength;
+ size_t BytesToCopy;
+ size_t DataBytes;
+ UINT32 Fragment;
+ in_addr_t IpAddress;
+ size_t LengthInBytes;
+ UINT8 * pData;
+ DT_PACKET * pPacket;
+ DT_PORT * pPort;
+ struct sockaddr_in * pRemoteAddress;
+ EFI_UDP4_RECEIVE_DATA * pRxData;
+ DT_UDP4_CONTEXT * pUdp4;
+ struct sockaddr_in RemoteAddress;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Assume failure
+ //
+ Status = EFI_UNSUPPORTED;
+ pSocket->errno = ENOTCONN;
+
+ //
+ // Verify that the socket is connected
+ //
+ if (( SOCKET_STATE_CONNECTED == pSocket->State )
+ || ( PORT_STATE_RX_ERROR == pSocket->State )) {
+ //
+ // Locate the port
+ //
+ pPort = pSocket->pPortList;
+ if ( NULL != pPort ) {
+ //
+ // Determine if there is any data on the queue
+ //
+ pUdp4 = &pPort->Context.Udp4;
+ pPacket = pSocket->pRxPacketListHead;
+ if ( NULL != pPacket ) {
+ //
+ // Validate the return address parameters
+ //
+ pRxData = pPacket->Op.Udp4Rx.pRxData;
+ if (( NULL == pAddress ) || ( NULL != pAddressLength )) {
+ //
+ // Return the remote system address if requested
+ //
+ if ( NULL != pAddress ) {
+ //
+ // Build the remote address
+ //
+ DEBUG (( DEBUG_RX,
+ "Getting packet source 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 ));
+ ZeroMem ( &RemoteAddress, sizeof ( RemoteAddress ));
+ RemoteAddress.sin_len = sizeof ( RemoteAddress );
+ RemoteAddress.sin_family = AF_INET;
+ IpAddress = pRxData->UdpSession.SourceAddress.Addr[3];
+ IpAddress <<= 8;
+ IpAddress |= pRxData->UdpSession.SourceAddress.Addr[2];
+ IpAddress <<= 8;
+ IpAddress |= pRxData->UdpSession.SourceAddress.Addr[1];
+ IpAddress <<= 8;
+ IpAddress |= pRxData->UdpSession.SourceAddress.Addr[0];
+ RemoteAddress.sin_addr.s_addr = IpAddress;
+ RemoteAddress.sin_port = SwapBytes16 ( pRxData->UdpSession.SourcePort );
+
+ //
+ // Copy the address
+ //
+ pRemoteAddress = (struct sockaddr_in *)pAddress;
+ AddressLength = sizeof ( *pRemoteAddress );
+ if ( AddressLength > *pAddressLength ) {
+ AddressLength = *pAddressLength;
+ }
+ CopyMem ( pRemoteAddress,
+ &RemoteAddress,
+ AddressLength );
+
+ //
+ // Update the address length
+ //
+ *pAddressLength = AddressLength;
+ }
+
+ //
+ // Reduce the buffer length if necessary
+ //
+ DataBytes = pRxData->DataLength;
+ if ( DataBytes < BufferLength ) {
+ BufferLength = DataBytes;
+ }
+
+ //
+ // Copy the received data
+ //
+ LengthInBytes = 0;
+ Fragment = 0;
+ do {
+ //
+ // Determine the amount of received data
+ //
+ pData = pRxData->FragmentTable[Fragment].FragmentBuffer;
+ BytesToCopy = pRxData->FragmentTable[Fragment].FragmentLength;
+ if (( BufferLength - LengthInBytes ) < BytesToCopy ) {
+ BytesToCopy = BufferLength - LengthInBytes;
+ }
+ LengthInBytes += BytesToCopy;
+
+ //
+ // Move the data into the buffer
+ //
+ DEBUG (( DEBUG_RX,
+ "0x%08x: Port copy packet 0x%08x data into 0x%08x, 0x%08x bytes\r\n",
+ pPort,
+ pPacket,
+ pBuffer,
+ BytesToCopy ));
+ CopyMem ( pBuffer, pData, BytesToCopy );
+ } while ( BufferLength > LengthInBytes );
+
+ //
+ // Determine if the data is being read
+ //
+ if ( 0 == ( Flags & MSG_PEEK )) {
+ //
+ // Display for the bytes consumed
+ //
+ DEBUG (( DEBUG_RX,
+ "0x%08x: Port account for 0x%08x bytes\r\n",
+ pPort,
+ BufferLength ));
+
+ //
+ // All done with this packet
+ // Account for any discarded data
+ //
+ pSocket->RxBytes -= DataBytes;
+ if ( 0 != ( DataBytes - BufferLength )) {
+ DEBUG (( DEBUG_RX,
+ "0x%08x: Port, packet read, skipping over 0x%08x bytes\r\n",
+ pPort,
+ DataBytes - BufferLength ));
+ }
+
+ //
+ // Remove this packet from the queue
+ //
+ pSocket->pRxPacketListHead = pPacket->pNext;
+ if ( NULL == pSocket->pRxPacketListHead ) {
+ pSocket->pRxPacketListTail = NULL;
+ }
+
+ //
+ // Return this packet to the UDP4 driver
+ //
+ gBS->SignalEvent ( pRxData->RecycleSignal );
+
+ //
+ // 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 this receive operation if necessary
+ //
+ if (( NULL == pUdp4->pReceivePending )
+ && ( MAX_RX_DATA > pSocket->RxBytes )) {
+ EslUdpRxStart4 ( pPort );
+ }
+ }
+
+ //
+ // Return the data length
+ //
+ *pDataLength = LengthInBytes;
+
+ //
+ // Successful operation
+ //
+ Status = EFI_SUCCESS;
+ pSocket->errno = 0;
+ }
+ else {
+ //
+ // Bad return address pointer and length
+ //
+ Status = EFI_INVALID_PARAMETER;
+ pSocket->errno = EINVAL;
+ }
+ }
+ else {
+ //
+ // The queue is empty
+ // Determine if it is time to return the receive error
+ //
+ if ( EFI_ERROR ( pSocket->RxError )) {
+ Status = pSocket->RxError;
+ switch ( Status ) {
+ default:
+ pSocket->errno = EIO;
+ 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;
+ }
+ pSocket->RxError = EFI_SUCCESS;
+ }
+ else {
+ Status = EFI_NOT_READY;
+ pSocket->errno = EAGAIN;
+ }
+ }
+ }
+ }
+
+ //
+ // Return the operation status
+ //
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+
+/**
+ Cancel the receive operations
+
+ @param [in] pSocket Address of a DT_SOCKET structure
+
+ @retval EFI_SUCCESS - The cancel was successful
+
+ **/
+EFI_STATUS
+EslUdpRxCancel4 (
+ IN DT_SOCKET * pSocket
+ )
+{
+ DT_PACKET * pPacket;
+ DT_PORT * pPort;
+ DT_UDP4_CONTEXT * pUdp4;
+ EFI_UDP4_PROTOCOL * pUdp4Protocol;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Assume failure
+ //
+ Status = EFI_NOT_FOUND;
+
+ //
+ // Locate the port
+ //
+ pPort = pSocket->pPortList;
+ if ( NULL != pPort ) {
+ //
+ // Determine if a receive is pending
+ //
+ pUdp4 = &pPort->Context.Udp4;
+ pPacket = pUdp4->pReceivePending;
+ if ( NULL != pPacket ) {
+ //
+ // Attempt to cancel the receive operation
+ //
+ pUdp4Protocol = pUdp4->pProtocol;
+ Status = pUdp4Protocol->Cancel ( pUdp4Protocol,
+ &pUdp4->RxToken );
+ if ( EFI_NOT_FOUND == Status ) {
+ //
+ // The receive is complete
+ //
+ Status = EFI_SUCCESS;
+ }
+ }
+ }
+
+ //
+ // Return the operation status
+ //
+ DBG_EXIT_STATUS ( Status );
+ return Status;
+}
+
+
+/**
+ Process the receive completion
+
+ Keep the UDP4 driver's buffer and append it to the list of
+ datagrams for the application to receive. The UDP4 driver's
+ buffer will be returned by either ::UdpReceive4 or
+ ::UdpPortCloseTxDone4.
+
+ @param Event The receive completion event
+
+ @param pPort The DT_PORT structure address
+
+**/
+VOID
+EslUdpRxComplete4 (
+ IN EFI_EVENT Event,
+ IN DT_PORT * pPort
+ )
+{
+ size_t LengthInBytes;
+ DT_PACKET * pPacket;
+ DT_PACKET * pPrevious;
+ EFI_UDP4_RECEIVE_DATA * pRxData;
+ DT_SOCKET * pSocket;
+ DT_UDP4_CONTEXT * pUdp4;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Mark this receive complete
+ //
+ pUdp4 = &pPort->Context.Udp4;
+ pPacket = pUdp4->pReceivePending;
+ pUdp4->pReceivePending = NULL;
+
+ //
+ // Determine if this receive was successful
+ //
+ pSocket = pPort->pSocket;
+ Status = pUdp4->RxToken.Status;
+ if (( !EFI_ERROR ( Status )) && ( !pSocket->bRxDisable )) {
+ pRxData = pUdp4->RxToken.Packet.RxData;
+ if ( PORT_STATE_CLOSE_STARTED >= pPort->State ) {
+ //
+ // Save the data in the packet
+ //
+ pPacket->Op.Udp4Rx.pRxData = pRxData;
+
+ //
+ // Queue this packet
+ //
+ pPrevious = pSocket->pRxPacketListTail;
+ if ( NULL == pPrevious ) {
+ pSocket->pRxPacketListHead = pPacket;
+ }
+ else {
+ pPrevious->pNext = pPacket;
+ }
+ pSocket->pRxPacketListTail = pPacket;
+
+ //
+ // Account for the normal data
+ //
+ LengthInBytes = pRxData->DataLength;
+ pSocket->RxBytes += LengthInBytes;
+
+ //
+ // Log the received data
+ //
+ DEBUG (( DEBUG_RX | DEBUG_INFO,
+ "Received packet from: %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 ));
+ DEBUG (( DEBUG_RX | DEBUG_INFO,
+ "Received packet sent to: %d.%d.%d.%d:%d\r\n",
+ pRxData->UdpSession.DestinationAddress.Addr[0],
+ pRxData->UdpSession.DestinationAddress.Addr[1],
+ pRxData->UdpSession.DestinationAddress.Addr[2],
+ pRxData->UdpSession.DestinationAddress.Addr[3],
+ pRxData->UdpSession.DestinationPort ));
+ DEBUG (( DEBUG_RX | DEBUG_INFO,
+ "0x%08x: Packet queued on port 0x%08x with 0x%08x bytes of data\r\n",
+ pPacket,
+ pPort,
+ LengthInBytes ));
+
+ //
+ // Attempt to restart this receive operation
+ //
+ if ( pSocket->MaxRxBuf > pSocket->RxBytes ) {
+ EslUdpRxStart4 ( pPort );
+ }
+ else {
+ DEBUG (( DEBUG_RX,
+ "0x%08x: Port RX suspended, 0x%08x bytes queued\r\n",
+ pPort,
+ pSocket->RxBytes ));
+ }
+ }
+ else {
+ //
+ // The port is being closed
+ // Return the buffer to the UDP4 driver
+ //
+ gBS->SignalEvent ( pRxData->RecycleSignal );
+
+ //
+ // Free the packet
+ //
+ EslSocketPacketFree ( pPacket, DEBUG_RX );
+ }
+ }
+ else
+ {
+ DEBUG (( DEBUG_RX | DEBUG_INFO,
+ "ERROR - Receiving packet 0x%08x, on port 0x%08x, Status:%r\r\n",
+ pPacket,
+ pPort,
+ Status ));
+
+ //
+ // 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 ) {
+ EslUdpPortCloseRxDone4 ( pPort );
+ }
+ else {
+ if ( EFI_ERROR ( Status )) {
+ pPort->State = PORT_STATE_RX_ERROR;
+ }
+ }
+ }
+
+ DBG_EXIT ( );
+}
+
+
+/**
+ Start a receive operation
+
+ @param [in] pPort Address of the DT_PORT structure.
+
+ **/
+VOID
+EslUdpRxStart4 (
+ IN DT_PORT * pPort
+ )
+{
+ DT_PACKET * pPacket;
+ DT_SOCKET * pSocket;
+ DT_UDP4_CONTEXT * pUdp4;
+ EFI_UDP4_PROTOCOL * pUdp4Protocol;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Determine if a receive is already pending
+ //
+ Status = EFI_SUCCESS;
+ pPacket = NULL;
+ pSocket = pPort->pSocket;
+ pUdp4 = &pPort->Context.Udp4;
+ if ( !EFI_ERROR ( pPort->pSocket->RxError )) {
+ if (( NULL == pUdp4->pReceivePending )
+ && ( PORT_STATE_CLOSE_STARTED > pPort->State )) {
+ //
+ // 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,
+ sizeof ( pPacket->Op.Udp4Rx ),
+ 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 ));
+ }
+ }
+
+ //
+ // Determine if a packet is available
+ //
+ if ( NULL != pPacket ) {
+ //
+ // Initialize the buffer for receive
+ //
+ pPacket->pNext = NULL;
+ pPacket->Op.Udp4Rx.pRxData = NULL;
+ pUdp4->RxToken.Packet.RxData = NULL;
+ pUdp4->pReceivePending = pPacket;
+
+ //
+ // Start the receive on the packet
+ //
+ pUdp4Protocol = pUdp4->pProtocol;
+ Status = pUdp4Protocol->Receive ( pUdp4Protocol,
+ &pUdp4->RxToken );
+ if ( !EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_RX | DEBUG_INFO,
+ "0x%08x: Packet receive pending on port 0x%08x\r\n",
+ pPacket,
+ pPort ));
+ }
+ 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
+ //
+ pUdp4->pReceivePending = NULL;
+ pPacket->pNext = pSocket->pRxFree;
+ pSocket->pRxFree = pPacket;
+ }
+ }
+ }
+ }
+
+ DBG_EXIT ( );
+}
+
+
+/**
+ Shutdown the UDP4 service.
+
+ This routine undoes the work performed by ::UdpInitialize4.
+
+ @param [in] pService DT_SERVICE structure address
+
+**/
+VOID
+EFIAPI
+EslUdpShutdown4 (
+ IN DT_SERVICE * pService
+ )
+{
+ DT_LAYER * pLayer;
+ DT_PORT * pPort;
+ DT_SERVICE * pPreviousService;
+
+ DBG_ENTER ( );
+
+ //
+ // Verify the socket layer synchronization
+ //
+ VERIFY_TPL ( TPL_SOCKETS );
+
+ //
+ // Walk the list of ports
+ //
+ do {
+ pPort = pService->pPortList;
+ if ( NULL != pPort ) {
+ //
+ // Remove the port from the port list
+ //
+ pService->pPortList = pPort->pLinkService;
+
+ //
+ // Close the port
+ // TODO: Fix this
+ //
+// pPort->pfnClosePort ( pPort, 0 );
+ }
+ } while ( NULL != pPort );
+
+ //
+ // Remove the service from the service list
+ //
+ pLayer = &mEslLayer;
+ pPreviousService = pLayer->pUdp4List;
+ if ( pService == pPreviousService ) {
+ //
+ // Remove the service from the beginning of the list
+ //
+ pLayer->pUdp4List = pService->pNext;
+ }
+ else {
+ //
+ // Remove the service from the middle of the list
+ //
+ while ( NULL != pPreviousService ) {
+ if ( pService == pPreviousService->pNext ) {
+ pPreviousService->pNext = pService->pNext;
+ break;
+ }
+ }
+ }
+
+ DBG_EXIT ( );
+}
+
+
+/**
+ Determine if the sockedt is configured.
+
+
+ @param [in] pSocket Address of a DT_SOCKET structure
+
+ @retval EFI_SUCCESS - The port is connected
+ @retval EFI_NOT_STARTED - The port is not connected
+
+ **/
+ EFI_STATUS
+ EslUdpSocketIsConfigured4 (
+ IN DT_SOCKET * pSocket
+ )
+{
+ DT_PORT * pPort;
+ DT_PORT * pNextPort;
+ DT_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
+ //
+ 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 = EslUdpBind4 ( pSocket,
+ (struct sockaddr *)&LocalAddress,
+ LocalAddress.sin_len );
+ }
+
+ //
+ // Walk the port list
+ //
+ pPort = pSocket->pPortList;
+ while ( NULL != pPort ) {
+ //
+ // Attempt to configure the port
+ //
+ pNextPort = pPort->pLinkSocket;
+ pUdp4 = &pPort->Context.Udp4;
+ pUdp4Protocol = pUdp4->pProtocol;
+ Status = pUdp4Protocol->Configure ( pUdp4Protocol,
+ &pUdp4->ConfigData );
+ if ( EFI_ERROR ( Status )) {
+ 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_LISTEN,
+ "0x%08x: Port configured\r\n",
+ pPort ));
+ pUdp4->bConfigured = TRUE;
+
+ //
+ // Start the first read on the port
+ //
+ EslUdpRxStart4 ( pPort );
+
+ //
+ // The socket is connected
+ //
+ pSocket->State = SOCKET_STATE_CONNECTED;
+ }
+
+ //
+ // Set the next port
+ //
+ pPort = pNextPort;
+ }
+
+ //
+ // Determine the configuration status
+ //
+ if ( NULL != pSocket->pPortList ) {
+ pSocket->bConfigured = TRUE;
+ }
+ }
+
+ //
+ // Determine the socket configuration status
+ //
+ if ( !EFI_ERROR ( 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 is called by the socket layer API 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 will start 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 a DT_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
+EslUdpTxBuffer4 (
+ IN DT_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
+ )
+{
+ DT_PACKET * pPacket;
+ DT_PACKET * pPreviousPacket;
+ DT_PACKET ** ppPacket;
+ DT_PORT * pPort;
+ const struct sockaddr_in * pRemoteAddress;
+ DT_UDP4_CONTEXT * pUdp4;
+ EFI_UDP4_COMPLETION_TOKEN * pToken;
+ size_t * pTxBytes;
+ DT_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 ) {
+ //
+ // Locate the port
+ //
+ pPort = pSocket->pPortList;
+ if ( NULL != pPort ) {
+ //
+ // Determine the queue head
+ //
+ pUdp4 = &pPort->Context.Udp4;
+ ppPacket = &pUdp4->pTxPacket;
+ pToken = &pUdp4->TxToken;
+ pTxBytes = &pSocket->TxBytes;
+
+ //
+ // Verify that there is enough room to buffer another
+ // transmit operation
+ //
+ if ( pSocket->MaxTxBuf > *pTxBytes ) {
+ //
+ // Attempt to allocate the packet
+ //
+ Status = EslSocketPacketAllocate ( &pPacket,
+ sizeof ( pPacket->Op.Udp4Tx )
+ - sizeof ( pPacket->Op.Udp4Tx.Buffer )
+ + BufferLength,
+ 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];
+
+ //
+ // Set the remote system address if necessary
+ //
+ if ( NULL != pAddress ) {
+ pRemoteAddress = (const struct sockaddr_in *)pAddress;
+ pTxData->Session.SourceAddress.Addr[0] = 0;
+ pTxData->Session.SourceAddress.Addr[1] = 0;
+ pTxData->Session.SourceAddress.Addr[2] = 0;
+ pTxData->Session.SourceAddress.Addr[3] = 0;
+ 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 );
+
+ //
+ // Stop transmission after an error
+ //
+ if ( !EFI_ERROR ( pSocket->TxError )) {
+ //
+ // Display the request
+ //
+ DEBUG (( DEBUG_TX,
+ "Send %d %s bytes from 0x%08x\r\n",
+ BufferLength,
+ pBuffer ));
+
+ //
+ // 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 == pUdp4->pTxPacket ) {
+ EslUdpTxStart4 ( pSocket->pPortList );
+ }
+ }
+ else {
+ //
+ // Previous transmit error
+ // Stop transmission
+ //
+ Status = pSocket->TxError;
+ pSocket->errno = EIO;
+
+ //
+ // Free the packet
+ //
+ EslSocketPacketFree ( pPacket, DEBUG_TX );
+ }
+
+ //
+ // Release the socket layer synchronization
+ //
+ RESTORE_TPL ( TplPrevious );
+ }
+ else {
+ //
+ // Packet allocation failed
+ //
+ pSocket->errno = ENOMEM;
+ }
+ }
+ 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
+
+ @param Event The normal transmit completion event
+
+ @param pPort The DT_PORT structure address
+
+**/
+VOID
+EslUdpTxComplete4 (
+ IN EFI_EVENT Event,
+ IN DT_PORT * pPort
+ )
+{
+ UINT32 LengthInBytes;
+ DT_PACKET * pCurrentPacket;
+ DT_PACKET * pNextPacket;
+ DT_PACKET * pPacket;
+ DT_SOCKET * pSocket;
+ DT_UDP4_CONTEXT * pUdp4;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Locate the active transmit packet
+ //
+ pSocket = pPort->pSocket;
+ pUdp4 = &pPort->Context.Udp4;
+ pPacket = pUdp4->pTxPacket;
+
+ //
+ // Mark this packet as complete
+ //
+ pUdp4->pTxPacket = NULL;
+ LengthInBytes = pPacket->Op.Udp4Tx.TxData.DataLength;
+ pSocket->TxBytes -= LengthInBytes;
+
+ //
+ // Save any transmit error
+ //
+ Status = pUdp4->TxToken.Status;
+ if ( EFI_ERROR ( Status )) {
+ if ( !EFI_ERROR ( pSocket->TxError )) {
+ pSocket->TxError = Status;
+ }
+ DEBUG (( DEBUG_TX | DEBUG_INFO,
+ "ERROR - Transmit failure for packet 0x%08x, Status: %r\r\n",
+ pPacket,
+ Status ));
+
+ //
+ // Empty the normal transmit list
+ //
+ pCurrentPacket = pPacket;
+ pNextPacket = pSocket->pTxPacketListHead;
+ while ( NULL != pNextPacket ) {
+ pPacket = pNextPacket;
+ pNextPacket = pPacket->pNext;
+ EslSocketPacketFree ( pPacket, DEBUG_TX );
+ }
+ pSocket->pTxPacketListHead = NULL;
+ pSocket->pTxPacketListTail = NULL;
+ pPacket = pCurrentPacket;
+ }
+ else
+ {
+ DEBUG (( DEBUG_TX | DEBUG_INFO,
+ "0x%08x: Packet transmitted %d bytes successfully\r\n",
+ pPacket,
+ LengthInBytes ));
+
+ //
+ // Verify the transmit engine is still running
+ //
+ if ( !pPort->bCloseNow ) {
+ //
+ // Start the next packet transmission
+ //
+ EslUdpTxStart4 ( pPort );
+ }
+ }
+
+ //
+ // Release this packet
+ //
+ EslSocketPacketFree ( pPacket, DEBUG_TX );
+
+ //
+ // Finish the close operation if necessary
+ //
+ if (( PORT_STATE_CLOSE_STARTED <= pPort->State )
+ && ( NULL == pSocket->pTxPacketListHead )
+ && ( NULL == pUdp4->pTxPacket )) {
+ //
+ // Indicate that the transmit is complete
+ //
+ EslUdpPortCloseTxDone4 ( pPort );
+ }
+ DBG_EXIT ( );
+}
+
+
+/**
+ Transmit data using a network connection.
+
+ @param [in] pPort Address of a DT_PORT structure
+
+ **/
+VOID
+EslUdpTxStart4 (
+ IN DT_PORT * pPort
+ )
+{
+ DT_PACKET * pNextPacket;
+ DT_PACKET * pPacket;
+ DT_SOCKET * pSocket;
+ DT_UDP4_CONTEXT * pUdp4;
+ EFI_UDP4_PROTOCOL * pUdp4Protocol;
+ EFI_STATUS Status;
+
+ DBG_ENTER ( );
+
+ //
+ // Assume success
+ //
+ Status = EFI_SUCCESS;
+
+ //
+ // Get the packet from the queue head
+ //
+ pSocket = pPort->pSocket;
+ pPacket = pSocket->pTxPacketListHead;
+ if ( NULL != pPacket ) {
+ //
+ // Remove the packet from the queue
+ //
+ pNextPacket = pPacket->pNext;
+ pSocket->pTxPacketListHead = pNextPacket;
+ if ( NULL == pNextPacket ) {
+ pSocket->pTxPacketListTail = NULL;
+ }
+
+ //
+ // Set the packet as active
+ //
+ pUdp4 = &pPort->Context.Udp4;
+ pUdp4->pTxPacket = pPacket;
+
+ //
+ // Start the transmit operation
+ //
+ pUdp4Protocol = pUdp4->pProtocol;
+ pUdp4->TxToken.Packet.TxData = &pPacket->Op.Udp4Tx.TxData;
+ Status = pUdp4Protocol->Transmit ( pUdp4Protocol, &pUdp4->TxToken );
+ if ( EFI_ERROR ( Status )) {
+ pSocket = pPort->pSocket;
+ if ( EFI_SUCCESS == pSocket->TxError ) {
+ pSocket->TxError = Status;
+ }
+ }
+ }
+
+ DBG_EXIT ( );
+}
+