/** @file
  Data source for network testing.

  Copyright (c) 2011-2012, 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 <errno.h>
#include <Uefi.h>

#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
#include <Library/PcdLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiLib.h>

#include <netinet/in.h>

#include <sys/EfiSysCall.h>
#include <sys/poll.h>
#include <sys/socket.h>


#define DATA_SAMPLE_SHIFT           5       ///<  Shift for number of samples
#define MAX_CONNECTIONS       ( 1 + 16 )    ///<  Maximum number of client connections
#define RANGE_SWITCH        ( 1024 * 1024 ) ///<  Switch display ranges
#define DATA_RATE_UPDATE_SHIFT      2       ///<  2n seconds between updates
#define AVERAGE_SHIFT_COUNT ( 6 - DATA_RATE_UPDATE_SHIFT )  ///<  2n samples in average
#define DATA_SAMPLES        ( 1 << DATA_SAMPLE_SHIFT )      ///<  Number of samples

#define TPL_DATASINK        TPL_CALLBACK  ///<  Synchronization TPL

#define PACKET_SIZE                 1448  ///<  Size of data packets
#define DATA_BUFFER_SIZE    (( 65536 / PACKET_SIZE ) * PACKET_SIZE )  ///<  Buffer size in bytes

typedef struct _DT_PORT {
  UINT64 BytesTotal;
  struct sockaddr_in6 IpAddress;
  UINT32 In;
  UINT32 Samples;
  UINT64 BytesReceived[ DATA_SAMPLES ];
} DT_PORT;

volatile BOOLEAN bTick;
BOOLEAN bTimerRunning;
struct sockaddr_in6 LocalAddress;
EFI_EVENT pTimer;
int ListenSocket;
UINT8 Buffer[ DATA_BUFFER_SIZE ];
struct pollfd PollFd[ MAX_CONNECTIONS ];
DT_PORT Port[ MAX_CONNECTIONS ];
nfds_t MaxPort;


//
//  Forward routine declarations
//
EFI_STATUS TimerStart ( UINTN Milliseconds );


/**
  Check for control C entered at console

  @retval  EFI_SUCCESS  Control C not entered
  @retval  EFI_ABORTED  Control C entered
**/
EFI_STATUS
ControlCCheck (
  )
{
  EFI_STATUS Status;

  //
  //  Assume no user intervention
  //
  Status = EFI_SUCCESS;

  //
  //  Display user stop request
  //
  if ( EFI_ERROR ( Status )) {
    DEBUG (( DEBUG_INFO,
              "User stop request!\r\n" ));
  }

  //
  //  Return the check status
  //
  return Status;
}


/**
  Accept a socket connection

  @retval  EFI_SUCCESS      The application is running normally
  @retval  EFI_NOT_STARTED  Error with the listen socket
  @retval  Other            The user stopped the application
**/
EFI_STATUS
SocketAccept (
  )
{
  INT32 SocketStatus;
  EFI_STATUS Status;
  INTN Index;

  //
  //  Assume failure
  //
  Status = EFI_DEVICE_ERROR;

  //
  //  Bind to the local address
  //
  SocketStatus = bind ( ListenSocket,
                        (struct sockaddr *) &LocalAddress,
                        LocalAddress.sin6_len );
  if ( 0 == SocketStatus ) {
    //
    //  Start listening on the local socket
    //
    SocketStatus = listen ( ListenSocket, 5 );
    if ( 0 == SocketStatus ) {
      //
      //  Local socket in the listen state
      //
      Status = EFI_SUCCESS;

      //
      //  Allocate a port
      //
      Index = MaxPort++;
      PollFd[ Index ].fd = ListenSocket;
      PollFd[ Index ].events = POLLRDNORM | POLLHUP;
      PollFd[ Index ].revents = 0;
      ZeroMem ( &Port[ Index ], sizeof ( Port[ Index ]));
    }
  }

  //
  //  Return the operation status
  //
  return Status;
}


/**
  Close the socket

  @retval  EFI_SUCCESS  The application is running normally
  @retval  Other        The user stopped the application
**/
EFI_STATUS
SocketClose (
  )
{
  INT32 CloseStatus;
  EFI_STATUS Status;

  //
  //  Determine if the socket is open
  //
  Status = EFI_DEVICE_ERROR;
  if ( -1 != ListenSocket ) {
    //
    //  Attempt to close the socket
    //
    CloseStatus = close ( ListenSocket );
    if ( 0 == CloseStatus ) {
      DEBUG (( DEBUG_INFO,
                "0x%08x: Socket closed\r\n",
                ListenSocket ));
      ListenSocket = -1;
      Status = EFI_SUCCESS;
    }
    else {
      DEBUG (( DEBUG_ERROR,
                "ERROR: Failed to close socket, errno: %d\r\n",
                errno ));
    }
  }

  //
  //  Return the operation status
  //
  return Status;
}


/**
  Create the socket

  @param [in] Family    Network family, AF_INET or AF_INET6

  @retval  EFI_SUCCESS  The application is running normally
  @retval  Other        The user stopped the application
**/
EFI_STATUS
SocketNew (
  sa_family_t Family
  )
{
  EFI_STATUS Status;

  //
  //  Get the port number
  //
  ZeroMem ( &LocalAddress, sizeof ( LocalAddress ));
  LocalAddress.sin6_len = sizeof ( LocalAddress );
  LocalAddress.sin6_family = Family;
  LocalAddress.sin6_port = htons ( PcdGet16 ( DataSource_Port ));
  
  //
  //  Loop creating the socket
  //
  DEBUG (( DEBUG_INFO,
            "Creating the socket\r\n" ));

  //
  //  Check for user stop request
  //
  Status = ControlCCheck ( );
  if ( !EFI_ERROR ( Status )) {
    //
    //  Attempt to create the socket
    //
    ListenSocket = socket ( LocalAddress.sin6_family,
                            SOCK_STREAM,
                            IPPROTO_TCP );
    if ( -1 != ListenSocket ) {
      DEBUG (( DEBUG_INFO,
                "0x%08x: Socket created\r\n",
                ListenSocket ));
    }
    else {
      Status = EFI_NOT_STARTED;
    }
  }

  //
  //  Return the operation status
  //
  return Status;
}


/**
  Poll the socket for more work

  @retval  EFI_SUCCESS      The application is running normally
  @retval  EFI_NOT_STARTED  Listen socket error
  @retval  Other            The user stopped the application
**/
EFI_STATUS
SocketPoll (
  )
{
  BOOLEAN bRemoveSocket;
  BOOLEAN bListenError;
  size_t BytesReceived;
  int CloseStatus;
  nfds_t Entry;
  INTN EntryPrevious;
  int FdCount;
  nfds_t Index;
  socklen_t LengthInBytes;
  struct sockaddr_in * pPortIpAddress4;
  struct sockaddr_in6 * pPortIpAddress6;
  struct sockaddr_in * pRemoteAddress4;
  struct sockaddr_in6 * pRemoteAddress6;
  struct sockaddr_in6 RemoteAddress;
  int Socket;
  EFI_STATUS Status;
  EFI_TPL TplPrevious;

  //
  //  Check for control-C
  //
  pRemoteAddress4 = (struct sockaddr_in *)&RemoteAddress;
  pRemoteAddress6 = (struct sockaddr_in6 *)&RemoteAddress;
  bListenError = FALSE;
  Status = ControlCCheck ( );
  if ( !EFI_ERROR ( Status )) {
    //
    //  Poll the sockets
    //
    FdCount = poll ( &PollFd[0],
                     MaxPort,
                     0 );
    if ( -1 == FdCount ) {
      //
      //  Poll error
      //
      DEBUG (( DEBUG_ERROR,
                "ERROR - Poll error, errno: %d\r\n",
                errno ));
      Status = EFI_DEVICE_ERROR;
    }
    else {
      //
      //  Process the poll output
      //
      Index = 0;
      while ( FdCount ) {
        bRemoveSocket = FALSE;

        //
        //  Account for this descriptor
        //
        pPortIpAddress4 = (struct sockaddr_in *)&Port[ Index ].IpAddress;
        pPortIpAddress6 = (struct sockaddr_in6 *)&Port[ Index ].IpAddress;
        if ( 0 != PollFd[ Index ].revents ) {
          FdCount -= 1;
        }

        //
        //  Check for a broken connection
        //
        if ( 0 != ( PollFd[ Index ].revents & POLLHUP )) {
          bRemoveSocket = TRUE;
          if ( ListenSocket == PollFd[ Index ].fd ) {
            bListenError = TRUE;
            DEBUG (( DEBUG_ERROR,
                      "ERROR - Network closed on listen socket, errno: %d\r\n",
                      errno ));
          }
          else {
            if ( AF_INET == pPortIpAddress4->sin_family ) {
              DEBUG (( DEBUG_ERROR,
                        "ERROR - Network closed on socket %d.%d.%d.%d:%d, errno: %d\r\n",
                        pPortIpAddress4->sin_addr.s_addr & 0xff,
                        ( pPortIpAddress4->sin_addr.s_addr >> 8 ) & 0xff,
                        ( pPortIpAddress4->sin_addr.s_addr >> 16 ) & 0xff,
                        ( pPortIpAddress4->sin_addr.s_addr >> 24 ) & 0xff,
                        htons ( pPortIpAddress4->sin_port ),
                        errno ));
            }
            else {
              DEBUG (( DEBUG_ERROR,
                        "ERROR - Network closed on socket [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d, errno: %d\r\n",
                        pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 0 ],
                        pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 1 ],
                        pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 2 ],
                        pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 3 ],
                        pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 4 ],
                        pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 5 ],
                        pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 6 ],
                        pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 7 ],
                        pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 8 ],
                        pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 9 ],
                        pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 10 ],
                        pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 11 ],
                        pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 12 ],
                        pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 13 ],
                        pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 14 ],
                        pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 15 ],
                        htons ( pPortIpAddress6->sin6_port ),
                        errno ));
            }

            //
            //  Close the socket
            //
            CloseStatus = close ( PollFd[ Index ].fd );
            if ( 0 == CloseStatus ) {
              bRemoveSocket = TRUE;
              if ( AF_INET == pPortIpAddress4->sin_family ) {
                DEBUG (( DEBUG_INFO,
                          "0x%08x: Socket closed for %d.%d.%d.%d:%d\r\n",
                          PollFd[ Index ].fd,
                          pPortIpAddress4->sin_addr.s_addr & 0xff,
                          ( pPortIpAddress4->sin_addr.s_addr >> 8 ) & 0xff,
                          ( pPortIpAddress4->sin_addr.s_addr >> 16 ) & 0xff,
                          ( pPortIpAddress4->sin_addr.s_addr >> 24 ) & 0xff,
                          htons ( pPortIpAddress4->sin_port )));
              }
              else {
                DEBUG (( DEBUG_INFO,
                          "0x%08x: Socket closed for [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d\r\n",
                          PollFd[ Index ].fd,
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 0 ],
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 1 ],
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 2 ],
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 3 ],
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 4 ],
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 5 ],
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 6 ],
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 7 ],
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 8 ],
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 9 ],
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 10 ],
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 11 ],
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 12 ],
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 13 ],
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 14 ],
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 15 ],
                          htons ( pPortIpAddress6->sin6_port )));
              }
            }
            else {
              if ( AF_INET == pPortIpAddress4->sin_family ) {
                DEBUG (( DEBUG_ERROR,
                          "ERROR - Failed to close socket 0x%08x for %d.%d.%d.%d:%d, errno: %d\r\n",
                          PollFd[ Index ].fd,
                          pPortIpAddress4->sin_addr.s_addr & 0xff,
                          ( pPortIpAddress4->sin_addr.s_addr >> 8 ) & 0xff,
                          ( pPortIpAddress4->sin_addr.s_addr >> 16 ) & 0xff,
                          ( pPortIpAddress4->sin_addr.s_addr >> 24 ) & 0xff,
                          htons ( pPortIpAddress4->sin_port ),
                          errno ));
              }
              else {
                DEBUG (( DEBUG_ERROR,
                          "ERROR - Failed to close socket 0x%08x for [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d, errno: %d\r\n",
                          PollFd[ Index ].fd,
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 0 ],
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 1 ],
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 2 ],
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 3 ],
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 4 ],
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 5 ],
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 6 ],
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 7 ],
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 8 ],
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 9 ],
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 10 ],
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 11 ],
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 12 ],
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 13 ],
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 14 ],
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 15 ],
                          htons ( pPortIpAddress6->sin6_port ),
                          errno ));
              }
            }
          }
        }
        
        //
        //  Check for a connection or read data
        //
        if ( 0 != ( PollFd[ Index ].revents & POLLRDNORM )) {
          //
          //  Check for a connection
          //
          if ( ListenSocket == PollFd[ Index ].fd ) {
            //
            //  Another client connection was received
            //
            LengthInBytes = sizeof ( RemoteAddress );
            Socket = accept ( ListenSocket,
                              (struct sockaddr *) &RemoteAddress,
                              &LengthInBytes );
            if ( -1 == Socket ) {
              //
              //  Listen socket error
              //
              bListenError = TRUE;
              bRemoveSocket = TRUE;
              DEBUG (( DEBUG_ERROR,
                        "ERROR - Listen socket failure, errno: %d\r\n",
                        errno ));
            }
            else {
              //
              //  Determine if there is room for this connection
              //
              if (( MAX_CONNECTIONS <= MaxPort )
                || ((( MAX_CONNECTIONS - 1 ) == MaxPort ) && ( -1 == ListenSocket ))) {
                //
                //  Display the connection
                //
                if ( AF_INET == pRemoteAddress4->sin_family ) {
                  Print ( L"Rejecting connection to remote system %d.%d.%d.%d:%d\r\n",
                          pRemoteAddress4->sin_addr.s_addr & 0xff,
                          ( pRemoteAddress4->sin_addr.s_addr >> 8 ) & 0xff,
                          ( pRemoteAddress4->sin_addr.s_addr >> 16 ) & 0xff,
                          ( pRemoteAddress4->sin_addr.s_addr >> 24 ) & 0xff,
                          htons ( pRemoteAddress4->sin_port ));
                }
                else {
                  Print ( L"Rejecting connection to remote system [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d\r\n",
                          pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 0 ],
                          pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 1 ],
                          pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 2 ],
                          pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 3 ],
                          pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 4 ],
                          pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 5 ],
                          pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 6 ],
                          pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 7 ],
                          pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 8 ],
                          pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 9 ],
                          pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 10 ],
                          pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 11 ],
                          pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 12 ],
                          pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 13 ],
                          pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 14 ],
                          pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 15 ],
                          htons ( pRemoteAddress6->sin6_port ));
                }

                //
                //  No room for this connection
                //  Close the connection
                //
                CloseStatus = close ( Socket );
                if ( 0 == CloseStatus ) {
                  bRemoveSocket = TRUE;
                  if ( AF_INET == pRemoteAddress4->sin_family ) {
                    DEBUG (( DEBUG_INFO,
                              "0x%08x: Socket closed for %d.%d.%d.%d:%d\r\n",
                              PollFd[ Index ].fd,
                              pRemoteAddress4->sin_addr.s_addr & 0xff,
                              ( pRemoteAddress4->sin_addr.s_addr >> 8 ) & 0xff,
                              ( pRemoteAddress4->sin_addr.s_addr >> 16 ) & 0xff,
                              ( pRemoteAddress4->sin_addr.s_addr >> 24 ) & 0xff,
                              htons ( pRemoteAddress4->sin_port )));
                  }
                  else {
                    DEBUG (( DEBUG_INFO,
                              "0x%08x: Socket closed for [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d\r\n",
                              PollFd[ Index ].fd,
                              pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 0 ],
                              pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 1 ],
                              pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 2 ],
                              pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 3 ],
                              pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 4 ],
                              pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 5 ],
                              pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 6 ],
                              pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 7 ],
                              pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 8 ],
                              pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 9 ],
                              pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 10 ],
                              pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 11 ],
                              pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 12 ],
                              pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 13 ],
                              pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 14 ],
                              pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 15 ],
                              htons ( pRemoteAddress6->sin6_port )));
                  }
                }
                else {
                  DEBUG (( DEBUG_ERROR,
                            "ERROR - Failed to close socket 0x%08x, errno: %d\r\n",
                            PollFd[ Index ].fd,
                            errno ));
                }

                //
                //  Keep the application running
                //  No issue with the listen socket
                //
                Status = EFI_SUCCESS;
              }
              else {
                //
                //  Display the connection
                //
                if ( AF_INET == pRemoteAddress4->sin_family ) {
                  Print ( L"Connected to remote system %d.%d.%d.%d:%d\r\n",
                          pRemoteAddress4->sin_addr.s_addr & 0xff,
                          ( pRemoteAddress4->sin_addr.s_addr >> 8 ) & 0xff,
                          ( pRemoteAddress4->sin_addr.s_addr >> 16 ) & 0xff,
                          ( pRemoteAddress4->sin_addr.s_addr >> 24 ) & 0xff,
                          htons ( pRemoteAddress4->sin_port ));
                }
                else {
                  Print ( L"Connected to remote system [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d\r\n",
                          pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 0 ],
                          pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 1 ],
                          pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 2 ],
                          pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 3 ],
                          pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 4 ],
                          pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 5 ],
                          pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 6 ],
                          pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 7 ],
                          pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 8 ],
                          pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 9 ],
                          pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 10 ],
                          pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 11 ],
                          pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 12 ],
                          pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 13 ],
                          pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 14 ],
                          pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 15 ],
                          htons ( pRemoteAddress6->sin6_port ));
                }

                //
                //  Allocate the client connection
                //
                Index = MaxPort++;
                ZeroMem ( &Port[ Index ], sizeof ( Port[ Index ]));
                CopyMem ( pPortIpAddress6, pRemoteAddress6, sizeof ( *pRemoteAddress6 ));
                PollFd[ Index ].fd = Socket;
                PollFd[ Index ].events = POLLRDNORM | POLLHUP;
                PollFd[ Index ].revents = 0;
              }
            }
          }
          else {
            //
            //  Data received
            //
            BytesReceived = read ( PollFd[ Index ].fd,
                                   &Buffer,
                                   sizeof ( Buffer ));
            if ( 0 < BytesReceived ) {
              //
              //  Display the amount of data received
              //
              if ( AF_INET == pPortIpAddress4->sin_family ) {
                DEBUG (( DEBUG_INFO,
                          "0x%08x: Socket received 0x%08x bytes from %d.%d.%d.%d:%d\r\n",
                          PollFd[ Index ].fd,
                          BytesReceived,
                          pPortIpAddress4->sin_addr.s_addr & 0xff,
                          ( pPortIpAddress4->sin_addr.s_addr >> 8 ) & 0xff,
                          ( pPortIpAddress4->sin_addr.s_addr >> 16 ) & 0xff,
                          ( pPortIpAddress4->sin_addr.s_addr >> 24 ) & 0xff,
                          htons ( pPortIpAddress4->sin_port )));
              }
              else {
                DEBUG (( DEBUG_INFO,
                          "0x%08x: Socket received 0x%08x bytes from [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d\r\n",
                          PollFd[ Index ].fd,
                          BytesReceived,
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 0 ],
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 1 ],
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 2 ],
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 3 ],
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 4 ],
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 5 ],
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 6 ],
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 7 ],
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 8 ],
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 9 ],
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 10 ],
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 11 ],
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 12 ],
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 13 ],
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 14 ],
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 15 ],
                          htons ( pPortIpAddress6->sin6_port )));
              }

              //
              //  Synchronize with the TimerCallback routine
              //
              TplPrevious = gBS->RaiseTPL ( TPL_DATASINK );

              //
              //  Account for the data received
              //
              Port[ Index ].BytesTotal += BytesReceived;

              //
              //  Release the synchronization with the TimerCallback routine
              //
              gBS->RestoreTPL ( TplPrevious );
            }
            else if ( -1 == BytesReceived ) {
              //
              //  Close the socket
              //
              if ( AF_INET == pPortIpAddress4->sin_family ) {
                DEBUG (( DEBUG_INFO,
                          "ERROR - Receive failure for %d.%d.%d.%d:%d, errno: %d\r\n",
                          pPortIpAddress4->sin_addr.s_addr & 0xff,
                          ( pPortIpAddress4->sin_addr.s_addr >> 8 ) & 0xff,
                          ( pPortIpAddress4->sin_addr.s_addr >> 16 ) & 0xff,
                          ( pPortIpAddress4->sin_addr.s_addr >> 24 ) & 0xff,
                          htons ( pPortIpAddress4->sin_port ),
                          errno ));
              }
              else {
                DEBUG (( DEBUG_INFO,
                          "ERROR - Receive failure for [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d, errno: %d\r\n",
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 0 ],
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 1 ],
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 2 ],
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 3 ],
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 4 ],
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 5 ],
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 6 ],
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 7 ],
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 8 ],
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 9 ],
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 10 ],
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 11 ],
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 12 ],
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 13 ],
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 14 ],
                          pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 15 ],
                          htons ( pPortIpAddress6->sin6_port ),
                          errno ));
              }
              CloseStatus = close ( PollFd[ Index ].fd );
              if ( 0 == CloseStatus ) {
                bRemoveSocket = TRUE;
                if ( AF_INET == pPortIpAddress4->sin_family ) {
                  DEBUG (( DEBUG_INFO,
                            "0x%08x: Socket closed for %d.%d.%d.%d:%d\r\n",
                            PollFd[ Index ].fd,
                            pPortIpAddress4->sin_addr.s_addr & 0xff,
                            ( pPortIpAddress4->sin_addr.s_addr >> 8 ) & 0xff,
                            ( pPortIpAddress4->sin_addr.s_addr >> 16 ) & 0xff,
                            ( pPortIpAddress4->sin_addr.s_addr >> 24 ) & 0xff,
                            htons ( pPortIpAddress4->sin_port )));
                }
                else {
                  DEBUG (( DEBUG_INFO,
                            "0x%08x: Socket closed for [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d\r\n",
                            PollFd[ Index ].fd,
                            pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 0 ],
                            pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 1 ],
                            pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 2 ],
                            pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 3 ],
                            pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 4 ],
                            pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 5 ],
                            pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 6 ],
                            pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 7 ],
                            pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 8 ],
                            pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 9 ],
                            pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 10 ],
                            pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 11 ],
                            pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 12 ],
                            pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 13 ],
                            pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 14 ],
                            pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 15 ],
                            htons ( pPortIpAddress6->sin6_port )));
                }
              }
              else {
                if ( AF_INET == pPortIpAddress4->sin_family ) {
                  DEBUG (( DEBUG_ERROR,
                            "ERROR - Failed to close socket 0x%08x for %d.%d.%d.%d:%d, errno: %d\r\n",
                            PollFd[ Index ].fd,
                            pPortIpAddress4->sin_addr.s_addr & 0xff,
                            ( pPortIpAddress4->sin_addr.s_addr >> 8 ) & 0xff,
                            ( pPortIpAddress4->sin_addr.s_addr >> 16 ) & 0xff,
                            ( pPortIpAddress4->sin_addr.s_addr >> 24 ) & 0xff,
                            htons ( pPortIpAddress4->sin_port ),
                            errno ));
                }
                else {
                  DEBUG (( DEBUG_ERROR,
                            "ERROR - Failed to close socket 0x%08x for [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d, errno: %d\r\n",
                            PollFd[ Index ].fd,
                            pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 0 ],
                            pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 1 ],
                            pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 2 ],
                            pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 3 ],
                            pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 4 ],
                            pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 5 ],
                            pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 6 ],
                            pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 7 ],
                            pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 8 ],
                            pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 9 ],
                            pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 10 ],
                            pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 11 ],
                            pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 12 ],
                            pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 13 ],
                            pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 14 ],
                            pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 15 ],
                            htons ( pPortIpAddress6->sin6_port ),
                            errno ));
                }
              }
            }

            //
            //  Keep the application running
            //  No issue with the listen socket
            //
            Status = EFI_SUCCESS;
          }
        }

        //
        //  Remove the socket if necessary
        //
        if ( bRemoveSocket ) {
          DEBUG (( DEBUG_INFO,
                    "0x%08x: Socket removed from polling\r\n",
                    PollFd[ Index ].fd ));
          MaxPort -= 1;
          for ( Entry = Index + 1; MaxPort >= Entry; Entry++ ) {
            EntryPrevious = Entry;
            CopyMem ( &Port[ EntryPrevious ],
                      &Port[ Entry ],
                      sizeof ( Port[ Entry ]));
            PollFd[ EntryPrevious ].events = PollFd[ Entry ].events;
            PollFd[ EntryPrevious ].fd = PollFd[ Entry ].fd;
            PollFd[ EntryPrevious ].revents = PollFd[ Entry ].revents;
          }
          PollFd[ MaxPort ].fd = -1;
          Index -= 1;
        }

        //
        //  Account for this socket
        //
        Index += 1;
      }
    }
  }

  //
  //  Return the listen failure if necessary
  //
  if (( !EFI_ERROR ( Status )) && bListenError ) {
    Status = EFI_NOT_STARTED;
  }

  //
  //  Return the poll status
  //
  return Status;
}


/**
  Handle the timer callback

  @param [in] Event     Event that caused this callback
  @param [in] pContext  Context for this routine
**/
VOID
EFIAPI
TimerCallback (
  IN EFI_EVENT Event,
  IN VOID * pContext
  )
{
  UINT32 Average;
  UINT64 BitsPerSecond;
  UINT64 BytesReceived;
  UINT32 Count;
  nfds_t Index;
  UINT64 TotalBytes;

  //
  //  Notify the other code of the timer tick
  //
  bTick = TRUE;

  //
  //  Walk the list of ports
  //
  for ( Index = 0; MaxPort > Index; Index++ ) {
    //
    //  Determine if any data was received
    //
    BytesReceived = Port[ Index ].BytesTotal;
    if (( ListenSocket != PollFd[ Index ].fd )
      && ( 0 != BytesReceived )) {
      //
      //  Update the received data samples
      //
      Port[ Index ].BytesTotal = 0;
      Port[ Index ].BytesReceived [ Port[ Index ].In ] = BytesReceived;
      Port[ Index ].In += 1;
      if ( DATA_SAMPLES <= Port[ Index ].In ) {
        Port[ Index ].In = 0;
      }
      
      //
      //  Separate the samples
      //
      if ( DATA_SAMPLES == Port[ Index ].Samples ) {
        Print ( L"---------- Stable average ----------\r\n" );
      }
      Port[ Index ].Samples += 1;

      //
      //  Compute the data rate
      //
      TotalBytes = 0;
      for ( Count = 0; DATA_SAMPLES > Count; Count++ )
      {
          TotalBytes += Port[ Index ].BytesReceived[ Count ];
      }
      Average = (UINT32)RShiftU64 ( TotalBytes, DATA_SAMPLE_SHIFT );
      BitsPerSecond = Average * 8;

      //
      //  Display the data rate
      //
      if (( RANGE_SWITCH >> 10 ) > Average ) {
        Print ( L"Ave: %d Bytes/Sec, %Ld Bits/sec\r\n",
                Average,
                BitsPerSecond );
      }
      else {
        BitsPerSecond /= 1000;
        if ( RANGE_SWITCH > Average ) {
          Print ( L"Ave: %d.%03d KiBytes/Sec, %Ld KBits/sec\r\n",
                  Average >> 10,
                  (( Average & 0x3ff ) * 1000 ) >> 10,
                  BitsPerSecond );
        }
        else {
          BitsPerSecond /= 1000;
          Average >>= 10;
          if ( RANGE_SWITCH > Average ) {
            Print ( L"Ave: %d.%03d MiBytes/Sec, %Ld MBits/sec\r\n",
                    Average >> 10,
                    (( Average & 0x3ff ) * 1000 ) >> 10,
                    BitsPerSecond );
          }
          else {
            BitsPerSecond /= 1000;
            Average >>= 10;
            if ( RANGE_SWITCH > Average ) {
              Print ( L"Ave: %d.%03d GiBytes/Sec, %Ld GBits/sec\r\n",
                      Average >> 10,
                      (( Average & 0x3ff ) * 1000 ) >> 10,
                      BitsPerSecond );
            }
            else {
              BitsPerSecond /= 1000;
              Average >>= 10;
              if ( RANGE_SWITCH > Average ) {
                Print ( L"Ave: %d.%03d TiBytes/Sec, %Ld TBits/sec\r\n",
                        Average >> 10,
                        (( Average & 0x3ff ) * 1000 ) >> 10,
                        BitsPerSecond );
              }
              else {
                BitsPerSecond /= 1000;
                Average >>= 10;
                Print ( L"Ave: %d.%03d PiBytes/Sec, %Ld PBits/sec\r\n",
                        Average >> 10,
                        (( Average & 0x3ff ) * 1000 ) >> 10,
                        BitsPerSecond );
              }
            }
          }
        }
      }
    }
  }
}


/**
  Create the timer

  @retval  EFI_SUCCESS  The timer was successfully created
  @retval  Other        Timer initialization failed
**/
EFI_STATUS
TimerCreate (
  )
{
  EFI_STATUS Status;

  //
  //  Create the timer
  //
  Status = gBS->CreateEvent ( EVT_TIMER | EVT_NOTIFY_SIGNAL,
                              TPL_DATASINK,
                              TimerCallback,
                              NULL,
                              &pTimer );
  if ( EFI_ERROR ( Status )) {
    DEBUG (( DEBUG_ERROR,
              "ERROR - Failed to allocate the timer event, Status: %r\r\n",
              Status ));
  }
  else {
    DEBUG (( DEBUG_INFO,
              "0x%08x: Timer created\r\n",
              pTimer ));
  }

  //
  //  Return the operation status
  //
  return Status;
}


/**
  Stop the timer

  @retval  EFI_SUCCESS  The timer was stopped successfully
  @retval  Other        The timer failed to stop
**/
EFI_STATUS
TimerStop (
  )
{
  EFI_STATUS Status;

  //
  //  Assume success
  //
  Status = EFI_SUCCESS;

  //
  //  Determine if the timer is running
  //
  if ( bTimerRunning ) {
    //
    //  Stop the timer
    //
    Status = gBS->SetTimer ( pTimer,
                             TimerCancel,
                             0 );
    if ( EFI_ERROR ( Status )) {
      DEBUG (( DEBUG_ERROR,
                "ERROR - Failed to stop the timer, Status: %r\r\n",
                Status ));
    }
    else {
      //
      //  Timer timer is now stopped
      //
      bTimerRunning = FALSE;
      DEBUG (( DEBUG_INFO,
                "0x%08x: Timer stopped\r\n",
                pTimer ));
    }
  }

  //
  //  Return the operation status
  //
  return Status;
}


/**
  Start the timer

  @param [in] Milliseconds  The number of milliseconds between timer callbacks

  @retval  EFI_SUCCESS  The timer was successfully created
  @retval  Other        Timer initialization failed
**/
EFI_STATUS
TimerStart (
  UINTN Milliseconds
  )
{
  EFI_STATUS Status;
  UINT64 TimeDelay;

  //
  //  Stop the timer if necessary
  //
  Status = EFI_SUCCESS;
  if ( bTimerRunning ) {
    Status = TimerStop ( );
  }
  if ( !EFI_ERROR ( Status )) {
    //
    //  Compute the new delay
    //
    TimeDelay = Milliseconds;
    TimeDelay *= 1000 * 10;

    //
    //  Start the timer
    //
    Status = gBS->SetTimer ( pTimer,
                             TimerPeriodic,
                             TimeDelay );
    if ( EFI_ERROR ( Status )) {
      DEBUG (( DEBUG_ERROR,
                "ERROR - Failed to start the timer, Status: %r\r\n",
                Status ));
    }
    else {
      //
      //  The timer is now running
      //
      bTimerRunning = TRUE;
      DEBUG (( DEBUG_INFO,
        "0x%08x: Timer running\r\n",
        pTimer ));
    }
  }

  //
  //  Return the operation status
  //
  return Status;
}


/**
  Destroy the timer

  @retval  EFI_SUCCESS  The timer was destroyed successfully
  @retval  Other        Failed to destroy the timer
**/
EFI_STATUS
TimerDestroy (
  )
{
  EFI_STATUS Status;

  //
  //  Assume success
  //
  Status = EFI_SUCCESS;

  //
  //  Determine if the timer is running
  //
  if ( bTimerRunning ) {
    //
    //  Stop the timer
    //
    Status = TimerStop ( );
  }
  if (( !EFI_ERROR ( Status )) && ( NULL != pTimer )) {
    //
    //  Done with this timer
    //
    Status = gBS->CloseEvent ( pTimer );
    if ( EFI_ERROR ( Status )) {
      DEBUG (( DEBUG_ERROR,
                "ERROR - Failed to free the timer event, Status: %r\r\n",
                Status ));
    }
    else {
      DEBUG (( DEBUG_INFO,
                "0x%08x: Timer Destroyed\r\n",
                pTimer ));
      pTimer = NULL;
    }
  }

  //
  //  Return the operation status
  //
  return Status;
}


/**
  Receive data from the DataSource program to test a network's bandwidth.

  @param [in] Argc  The number of arguments
  @param [in] Argv  The argument value array

  @retval  0        The application exited normally.
  @retval  Other    An error occurred.
**/
int
main (
  IN int Argc,
  IN char **Argv
  )
{
  sa_family_t Family;
  EFI_STATUS Status;

  DEBUG (( DEBUG_INFO,
            "DataSink starting\r\n" ));

  //
  //  Determine the family to use
  //
  Family = ( 1 < Argc ) ? AF_INET6 : AF_INET;

  //
  //  Use for/break instead of goto
  //
  for ( ; ; ) {
    //
    //  Create the timer
    //
    bTick = TRUE;
    Status = TimerCreate ( );
    if ( EFI_ERROR ( Status )) {
      break;
    }

    //
    //  Start a timer to perform network polling and display updates
    //
    Status = TimerStart ( 1 * 1000 );
    if ( EFI_ERROR ( Status )) {
      break;
    }

    //
    //  Loop forever waiting for abuse
    //
    do {
      ListenSocket = -1;
      do {
        //
        //  Complete any client operations
        //
        Status = SocketPoll ( );
        if ( EFI_ERROR ( Status )) {
          //
          //  Control-C
          //
          break;
        }
      
        //
        //  Wait for a while
        //
      } while ( !bTick );
      if ( EFI_ERROR ( Status )) {
        //
        //  Control-C
        //
        break;
      }
      
      //
      //  Wait for the network layer to initialize
      //
      Status = SocketNew ( Family );
      if ( EFI_ERROR ( Status )) {
        continue;
      }

      //
      //  Wait for the remote network application to start
      //
      Status = SocketAccept ( );
      if ( EFI_NOT_STARTED == Status ) {
        Status = SocketClose ( );
        continue;
      }
      else if ( EFI_SUCCESS != Status ) {
        //
        //  Control-C
        //
        break;
      }

      //
      //  Receive data until the connection breaks
      //
      do {
        Status = SocketPoll ( );
      } while ( !EFI_ERROR ( Status ));

      //
      //  Done with the socket
      //
      Status = SocketClose ( );
    } while ( !EFI_ERROR ( Status ));

    //
    //  Close the socket if necessary
    //
    SocketClose ( );

    //
    //  All done
    //
    break;
  }

  //
  //  Stop the timer if necessary
  //
  TimerStop ( );
  TimerDestroy ( );

  //
  //  Return the operation status
  //
  DEBUG (( DEBUG_INFO,
            "DataSink exiting, Status: %r\r\n",
            Status ));
  return Status;
}
