]> git.proxmox.com Git - mirror_edk2.git/blobdiff - AppPkg/Applications/Sockets/DataSource/DataSource.c
Add Socket Library applications.
[mirror_edk2.git] / AppPkg / Applications / Sockets / DataSource / DataSource.c
diff --git a/AppPkg/Applications/Sockets/DataSource/DataSource.c b/AppPkg/Applications/Sockets/DataSource/DataSource.c
new file mode 100644 (file)
index 0000000..d8f7f05
--- /dev/null
@@ -0,0 +1,1615 @@
+/** @file\r
+  Data source for network testing.\r
+\r
+  Copyright (c) 2011, Intel Corporation\r
+  All rights reserved. This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <errno.h>\r
+#include <Uefi.h>\r
+\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiLib.h>\r
+\r
+#include <netinet/in.h>\r
+\r
+#include <Protocol/ServiceBinding.h>\r
+#include <Protocol/Tcp4.h>\r
+\r
+#include <sys/EfiSysCall.h>\r
+#include <sys/poll.h>\r
+#include <sys/socket.h>\r
+\r
+\r
+#define RANGE_SWITCH                2048  ///<  Switch display ranges\r
+#define DATA_RATE_UPDATE_SHIFT      2     ///<  2n seconds between updates\r
+#define AVERAGE_SHIFT_COUNT ( 6 - DATA_RATE_UPDATE_SHIFT )  ///<  2n samples in average\r
+\r
+#define TPL_DATASOURCE      TPL_CALLBACK  ///<  Synchronization TPL\r
+\r
+#define PACKET_SIZE                 1448  ///<  Size of data packets\r
+#define DATA_BUFFER_SIZE    (( 65536 / PACKET_SIZE ) * PACKET_SIZE )  ///<  Buffer size in bytes\r
+\r
+\r
+//\r
+//  Socket Data\r
+//\r
+int Socket = -1;\r
+\r
+//\r
+//  TCP V4 Data\r
+//\r
+BOOLEAN bTcp4;                      ///<  TRUE if TCP4 is being used\r
+BOOLEAN bTcp4Connected;             ///<  TRUE if connected to remote system\r
+BOOLEAN bTcp4Connecting;            ///<  TRUE while connection in progress\r
+UINTN Tcp4Index;                    ///<  Index into handle array\r
+EFI_HANDLE Tcp4Controller;          ///<  Network controller handle\r
+EFI_HANDLE Tcp4Handle;              ///<  TCP4 port handle\r
+EFI_TCP4_PROTOCOL * pTcp4Protocol;  ///<  TCP4 protocol pointer\r
+EFI_SERVICE_BINDING_PROTOCOL * pTcp4Service;  ///<  TCP4 Service binding\r
+EFI_TCP4_CONFIG_DATA Tcp4ConfigData;///<  TCP4 configuration data\r
+EFI_TCP4_OPTION Tcp4Option;         ///<  TCP4 port options\r
+EFI_TCP4_CLOSE_TOKEN Tcp4CloseToken;///<  Close control\r
+EFI_TCP4_CONNECTION_TOKEN Tcp4ConnectToken; ///<  Connection control\r
+EFI_TCP4_LISTEN_TOKEN Tcp4ListenToken;      ///<  Listen control\r
+EFI_TCP4_IO_TOKEN Tcp4TxToken;      ///<  Normal data token\r
+\r
+//\r
+//  Timer Data\r
+//\r
+volatile BOOLEAN bTick;\r
+BOOLEAN bTimerRunning;\r
+EFI_EVENT pTimer;\r
+\r
+//\r
+//  Remote IP Address Data\r
+//\r
+struct sockaddr_in RemoteHostAddress;\r
+CHAR8 * pRemoteHost;\r
+\r
+//\r
+//  Traffic Data\r
+//\r
+UINT64 TotalBytesSent;\r
+UINT64 PreviousBytes;\r
+UINT64 AverageBytes;\r
+UINT64 Samples;\r
+UINT8 Buffer [ DATA_BUFFER_SIZE ];\r
+\r
+\r
+//\r
+//  Forward routine declarations\r
+//\r
+EFI_STATUS TimerStart ( UINTN Milliseconds );\r
+\r
+\r
+/**\r
+  Check for control C entered at console\r
+\r
+  @retval  EFI_SUCCESS  Control C not entered\r
+  @retval  EFI_ABORTED  Control C entered\r
+**/\r
+EFI_STATUS\r
+ControlCCheck (\r
+  )\r
+{\r
+  EFI_STATUS Status;\r
+\r
+  //\r
+  //  Assume no user intervention\r
+  //\r
+  Status = EFI_SUCCESS;\r
+\r
+  //\r
+  //  Display user stop request\r
+  //\r
+  if ( EFI_ERROR ( Status )) {\r
+    DEBUG (( DEBUG_INFO,\r
+              "User stop request!\r\n" ));\r
+  }\r
+\r
+  //\r
+  //  Return the check status\r
+  //\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Get a digit\r
+\r
+  @param [in] pDigit    The address of the next digit\r
+  @param [out] pValue   The address to receive the value\r
+\r
+  @returns  Returns the address of the separator\r
+\r
+**/\r
+CHAR8 *\r
+GetDigit (\r
+  CHAR8 * pDigit,\r
+  UINT32 * pValue\r
+  )\r
+{\r
+  UINT32 Value;\r
+\r
+  //\r
+  //  Walk the digits\r
+  //\r
+  Value = 0;\r
+  while (( '0' <= *pDigit ) && ( '9' >= *pDigit ))\r
+  {\r
+    //\r
+    //  Make room for the new least significant digit\r
+    //\r
+    Value *= 10;\r
+\r
+    //\r
+    //  Convert the digit from ASCII to binary\r
+    //\r
+    Value += *pDigit - '0';\r
+\r
+    //\r
+    //  Set the next digit\r
+    //\r
+    pDigit += 1;\r
+  }\r
+\r
+  //\r
+  //  Return the value\r
+  //\r
+  *pValue = Value;\r
+\r
+  //\r
+  //  Return the next separator\r
+  //\r
+  return pDigit;\r
+}\r
+\r
+\r
+/**\r
+  Get the IP address\r
+\r
+  @retval  EFI_SUCCESS  The IP address is valid\r
+  @retval  Other        Failure to convert the IP address\r
+**/\r
+EFI_STATUS\r
+IpAddress (\r
+  )\r
+{\r
+  CHAR8 * pSeparator;\r
+  INT32 RemoteAddress;\r
+  EFI_STATUS Status;\r
+  UINT32 Value1;\r
+  UINT32 Value2;\r
+  UINT32 Value3;\r
+  UINT32 Value4;\r
+\r
+  //\r
+  //  Assume failure\r
+  //\r
+  Status = EFI_INVALID_PARAMETER;\r
+\r
+  //\r
+  //  Convert the IP address from a string to a numeric value\r
+  //\r
+  pSeparator = GetDigit ( pRemoteHost, &Value1 );\r
+  if (( 255 >= Value1 ) && ( '.' == *pSeparator )) {\r
+    pSeparator = GetDigit ( ++pSeparator, &Value2 );\r
+    if (( 255 >= Value2 ) && ( '.' == *pSeparator )) {\r
+      pSeparator = GetDigit ( ++pSeparator, &Value3 );\r
+      if (( 255 >= Value3 ) && ( '.' == *pSeparator )) {\r
+        pSeparator = GetDigit ( ++pSeparator, &Value4 );\r
+        if (( 255 >= Value4 ) && ( 0 == *pSeparator )) {\r
+          RemoteAddress = Value1\r
+                        | ( Value2 << 8 )\r
+                        | ( Value3 << 16 )\r
+                        | ( Value4 << 24 );\r
+          RemoteHostAddress.sin_addr.s_addr = (UINT32) RemoteAddress;\r
+          Status = EFI_SUCCESS;\r
+          DEBUG (( DEBUG_INFO,\r
+                    "%d.%d.%d.%d: Remote host IP address\r\n",\r
+                    Value1,\r
+                    Value2,\r
+                    Value3,\r
+                    Value4 ));\r
+        }\r
+      }\r
+    }\r
+  }\r
+  if ( EFI_ERROR ( Status )) {\r
+    Print ( L"Invalid digit detected: %d\r\n", *pSeparator );\r
+  }\r
+\r
+  //\r
+  //  Return the operation status\r
+  //\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Close the socket\r
+\r
+  @retval  EFI_SUCCESS  The application is running normally\r
+  @retval  Other        The user stopped the application\r
+**/\r
+EFI_STATUS\r
+SocketClose (\r
+  )\r
+{\r
+  int CloseStatus;\r
+  EFI_STATUS Status;\r
+\r
+  //\r
+  //  Determine if the socket is open\r
+  //\r
+  Status = EFI_DEVICE_ERROR;\r
+  if ( -1 != Socket ) {\r
+    //\r
+    //  Attempt to close the socket\r
+    //\r
+    CloseStatus = close ( Socket );\r
+    if ( 0 == CloseStatus ) {\r
+      DEBUG (( DEBUG_INFO,\r
+                "0x%08x: Socket closed\r\n",\r
+                Socket ));\r
+      Socket = -1;\r
+      Status = EFI_SUCCESS;\r
+    }\r
+    else {\r
+      DEBUG (( DEBUG_ERROR,\r
+                "ERROR: Failed to close socket, errno: %d\r\n",\r
+                errno ));\r
+    }\r
+  }\r
+\r
+  //\r
+  //  Return the operation status\r
+  //\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Connect the socket\r
+\r
+  @retval  EFI_SUCCESS  The application is running normally\r
+  @retval  Other        The user stopped the application\r
+**/\r
+EFI_STATUS\r
+SocketConnect (\r
+  )\r
+{\r
+  int ConnectStatus;\r
+  UINT32 RemoteAddress;\r
+  EFI_STATUS Status;\r
+\r
+  //\r
+  //  Display the connecting message\r
+  //\r
+  RemoteAddress = RemoteHostAddress.sin_addr.s_addr;\r
+  Print ( L"Connecting to remote system %d.%d.%d.%d:%d\r\n",\r
+          RemoteAddress & 0xff,\r
+          ( RemoteAddress >> 8 ) & 0xff,\r
+          ( RemoteAddress >> 16 ) & 0xff,\r
+          ( RemoteAddress >> 24 ) & 0xff,\r
+          htons ( RemoteHostAddress.sin_port ));\r
+\r
+  //\r
+  //  Connect to the remote system\r
+  //\r
+  Status = EFI_SUCCESS;\r
+  do {\r
+    //\r
+    //  Check for user stop request\r
+    //\r
+    while ( ! bTick ) {\r
+      Status = ControlCCheck ( );\r
+      if ( EFI_ERROR ( Status )) {\r
+        break;\r
+      }\r
+    }\r
+    bTick = FALSE;\r
+    if ( EFI_ERROR ( Status )) {\r
+      break;\r
+    }\r
+\r
+    //\r
+    //  Connect to the remote system\r
+    //\r
+    ConnectStatus = connect ( Socket,\r
+                              (struct sockaddr *) &RemoteHostAddress,\r
+                              RemoteHostAddress.sin_len );\r
+    if ( -1 != ConnectStatus ) {\r
+      Print ( L"Connected to remote system %d.%d.%d.%d:%d\r\n",\r
+              RemoteAddress & 0xff,\r
+              ( RemoteAddress >> 8 ) & 0xff,\r
+              ( RemoteAddress >> 16 ) & 0xff,\r
+              ( RemoteAddress >> 24 ) & 0xff,\r
+              htons ( RemoteHostAddress.sin_port ));\r
+    }\r
+    else {\r
+      //\r
+      //  Close the socket and try again\r
+      //\r
+      if ( EAGAIN != errno ) {\r
+        Status = EFI_NOT_STARTED;\r
+        break;\r
+      }\r
+    }\r
+  } while ( -1 == ConnectStatus );\r
+\r
+  //\r
+  //  Return the operation status\r
+  //\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Create the socket\r
+\r
+  @retval  EFI_SUCCESS  The application is running normally\r
+  @retval  Other        The user stopped the application\r
+**/\r
+EFI_STATUS\r
+SocketNew (\r
+  )\r
+{\r
+  EFI_STATUS Status;\r
+\r
+  //\r
+  //  Loop creating the socket\r
+  //\r
+  DEBUG (( DEBUG_INFO,\r
+            "Creating the socket\r\n" ));\r
+  do {\r
+    //\r
+    //  Check for user stop request\r
+    //\r
+    Status = ControlCCheck ( );\r
+    if ( EFI_ERROR ( Status )) {\r
+      break;\r
+    }\r
+\r
+    //\r
+    //  Attempt to create the socket\r
+    //\r
+    Socket = socket ( AF_INET,\r
+                      SOCK_STREAM,\r
+                      IPPROTO_TCP );\r
+    if ( -1 != Socket ) {\r
+      DEBUG (( DEBUG_INFO,\r
+                "0x%08x: Socket created\r\n",\r
+                Socket ));\r
+      break;\r
+    }\r
+  } while ( -1 == Socket );\r
+\r
+  //\r
+  //  Return the operation status\r
+  //\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Send data over the socket\r
+\r
+  @retval  EFI_SUCCESS  The application is running normally\r
+  @retval  Other        The user stopped the application\r
+**/\r
+EFI_STATUS\r
+SocketSend (\r
+  )\r
+{\r
+  size_t BytesSent;\r
+  EFI_STATUS Status;\r
+  EFI_TPL TplPrevious;\r
+\r
+  //\r
+  //  Restart the timer\r
+  //\r
+  TimerStart ( 1000 << DATA_RATE_UPDATE_SHIFT );\r
+\r
+  //\r
+  //  Loop until the connection breaks or the user stops\r
+  //\r
+  do {\r
+    //\r
+    //  Check for user stop request\r
+    //\r
+    Status = ControlCCheck ( );\r
+    if ( EFI_ERROR ( Status )) {\r
+      break;\r
+    }\r
+\r
+    //\r
+    //  Send some bytes\r
+    //\r
+    BytesSent = write ( Socket, &Buffer[0], sizeof ( Buffer ));\r
+    if ( -1 == BytesSent ) {\r
+      DEBUG (( DEBUG_INFO,\r
+                "ERROR: send failed, errno: %d\r\n",\r
+                errno ));\r
+\r
+      //\r
+      //  Try again\r
+      //\r
+      Status = EFI_SUCCESS;\r
+\r
+//\r
+//  Exit now\r
+//\r
+Status = EFI_NOT_STARTED;\r
+      break;\r
+    }\r
+\r
+    //\r
+    //  Synchronize with the TimerCallback routine\r
+    //\r
+    TplPrevious = gBS->RaiseTPL ( TPL_DATASOURCE );\r
+\r
+    //\r
+    //  Account for the data sent\r
+    //\r
+    TotalBytesSent += BytesSent;\r
+\r
+    //\r
+    //  Release the TimerCallback routine synchronization\r
+    //\r
+    gBS->RestoreTPL ( TplPrevious );\r
+  } while ( !EFI_ERROR ( Status ));\r
+\r
+  //\r
+  //  Return the operation status\r
+  //\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Open the network connection and send the data.\r
+\r
+  @retval EFI_SUCCESS   Continue looping\r
+  @retval other         Stopped by user's Control-C input\r
+\r
+**/\r
+EFI_STATUS\r
+SocketOpen (\r
+  )\r
+{\r
+  EFI_STATUS Status;\r
+\r
+  //\r
+  //  Use do/while and break instead of goto\r
+  //\r
+  do\r
+  {\r
+    //\r
+    //  Wait for the network layer to initialize\r
+    //\r
+    Status = SocketNew ( );\r
+    if ( EFI_ERROR ( Status )) {\r
+      break;\r
+    }\r
+\r
+    //\r
+    //  Wait for the remote network application to start\r
+    //\r
+    Status = SocketConnect ( );\r
+    if ( EFI_NOT_STARTED == Status ) {\r
+      Status = SocketClose ( );\r
+      continue;\r
+    }\r
+    else if ( EFI_SUCCESS != Status ) {\r
+      //\r
+      //  Control-C\r
+      //\r
+      break;\r
+    }\r
+\r
+    //\r
+    //  Send data until the connection breaks\r
+    //\r
+    Status = SocketSend ( );\r
+    if ( EFI_ERROR ( Status )) {\r
+      break;\r
+    }\r
+  } while ( FALSE );\r
+\r
+  //\r
+  //  Return the operation status\r
+  //\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Close the TCP connection\r
+\r
+  @retval  EFI_SUCCESS  The application is running normally\r
+  @retval  Other        The user stopped the application\r
+**/\r
+EFI_STATUS\r
+Tcp4Close (\r
+  )\r
+{\r
+  UINTN Index;\r
+  UINT8 * pIpAddress;\r
+  EFI_STATUS Status;\r
+\r
+  //\r
+  //  Close the port\r
+  //\r
+  if ( bTcp4Connected ) {\r
+    Tcp4CloseToken.AbortOnClose = TRUE;\r
+    Status = pTcp4Protocol->Close ( pTcp4Protocol,\r
+                                    &Tcp4CloseToken );\r
+    if ( EFI_ERROR ( Status )) {\r
+      DEBUG (( DEBUG_ERROR,\r
+                "ERROR - Failed to start the TCP port close, Status: %r\r\n",\r
+                Status ));\r
+    }\r
+    else {\r
+      Status = gBS->WaitForEvent ( 1,\r
+                                   &Tcp4CloseToken.CompletionToken.Event,\r
+                                    &Index );\r
+      if ( EFI_ERROR ( Status )) {\r
+        DEBUG (( DEBUG_ERROR,\r
+                  "ERROR - Failed to wait for close event, Status: %r\r\n",\r
+                  Status ));\r
+      }\r
+      else {\r
+        Status = Tcp4CloseToken.CompletionToken.Status;\r
+        if ( EFI_ERROR ( Status )) {\r
+          DEBUG (( DEBUG_ERROR,\r
+                    "ERROR - Failed to close the TCP port, Status: %r\r\n",\r
+                    Status ));\r
+        }\r
+        else {\r
+          DEBUG (( DEBUG_INFO,\r
+                    "0x%08x: TCP port closed\r\n",\r
+                    pTcp4Protocol ));\r
+          bTcp4Connected = FALSE;\r
+\r
+          //\r
+          //  Display the port closed message\r
+          //\r
+          pIpAddress = (UINT8 *)&RemoteHostAddress.sin_addr.s_addr;\r
+          Print ( L"Closed connection to %d.%d.%d.%d:%d\r\n",\r
+                  pIpAddress[0],\r
+                  pIpAddress[1],\r
+                  pIpAddress[2],\r
+                  pIpAddress[3],\r
+                  htons ( RemoteHostAddress.sin_port ));\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+  //\r
+  //  Release the events\r
+  //\r
+  if ( NULL != Tcp4TxToken.CompletionToken.Event ) {\r
+    Status = gBS->CloseEvent ( Tcp4TxToken.CompletionToken.Event );\r
+    if ( !EFI_ERROR ( Status )) {\r
+      DEBUG (( DEBUG_INFO,\r
+                "0x%08x: TX event closed\r\n",\r
+                Tcp4TxToken.CompletionToken.Event ));\r
+      Tcp4TxToken.CompletionToken.Event = NULL;\r
+    }\r
+    else {\r
+      DEBUG (( DEBUG_ERROR,\r
+                "ERROR - Failed to close the Tcp4TxToken event, Status: %r\r\n",\r
+                Status ));\r
+    }\r
+  }\r
+\r
+  if ( NULL != Tcp4ListenToken.CompletionToken.Event ) {\r
+    Status = gBS->CloseEvent ( Tcp4ListenToken.CompletionToken.Event );\r
+    if ( !EFI_ERROR ( Status )) {\r
+      DEBUG (( DEBUG_INFO,\r
+                "0x%08x: Listen event closed\r\n",\r
+                Tcp4ListenToken.CompletionToken.Event ));\r
+      Tcp4ListenToken.CompletionToken.Event = NULL;\r
+    }\r
+    else {\r
+      DEBUG (( DEBUG_ERROR,\r
+                "ERROR - Failed to close the Tcp4ListenToken event, Status: %r\r\n",\r
+                Status ));\r
+    }\r
+  }\r
+\r
+  if ( NULL != Tcp4ConnectToken.CompletionToken.Event ) {\r
+    Status = gBS->CloseEvent ( Tcp4ConnectToken.CompletionToken.Event );\r
+    if ( !EFI_ERROR ( Status )) {\r
+      DEBUG (( DEBUG_INFO,\r
+                "0x%08x: Connect event closed\r\n",\r
+                Tcp4ConnectToken.CompletionToken.Event ));\r
+      Tcp4ConnectToken.CompletionToken.Event = NULL;\r
+    }\r
+    else {\r
+      DEBUG (( DEBUG_ERROR,\r
+                "ERROR - Failed to close the Tcp4ConnectToken event, Status: %r\r\n",\r
+                Status ));\r
+    }\r
+  }\r
+\r
+  if ( NULL != Tcp4CloseToken.CompletionToken.Event ) {\r
+    Status = gBS->CloseEvent ( Tcp4CloseToken.CompletionToken.Event );\r
+    if ( !EFI_ERROR ( Status )) {\r
+      DEBUG (( DEBUG_INFO,\r
+                "0x%08x: Close event closed\r\n",\r
+                Tcp4CloseToken.CompletionToken.Event ));\r
+      Tcp4CloseToken.CompletionToken.Event = NULL;\r
+    }\r
+    else {\r
+      DEBUG (( DEBUG_ERROR,\r
+                "ERROR - Failed to close the Tcp4CloseToken event, Status: %r\r\n",\r
+                Status ));\r
+    }\r
+  }\r
+\r
+  //\r
+  //  Close the TCP protocol\r
+  //\r
+  if ( NULL != pTcp4Protocol ) {\r
+    Status = gBS->CloseProtocol ( Tcp4Handle,\r
+                                  &gEfiTcp4ProtocolGuid,\r
+                                  gImageHandle,\r
+                                  NULL );\r
+    if ( EFI_ERROR ( Status )) {\r
+      DEBUG (( DEBUG_ERROR,\r
+                "ERROR - Failed to close the TCP protocol, Status: %r\r\n",\r
+                Status ));\r
+    }\r
+    else {\r
+      DEBUG (( DEBUG_INFO,\r
+                "0x%08x: TCP4 protocol closed\r\n",\r
+                pTcp4Protocol ));\r
+      pTcp4Protocol = NULL;\r
+    }\r
+  }\r
+\r
+  //\r
+  //  Done with the TCP service\r
+  //\r
+  if ( NULL != Tcp4Handle ) {\r
+    Status = pTcp4Service->DestroyChild ( pTcp4Service,\r
+                                          Tcp4Handle );\r
+    if ( EFI_ERROR ( Status )) {\r
+      DEBUG (( DEBUG_ERROR,\r
+                "ERROR - Failed to release TCP service handle, Status: %r\r\n",\r
+                Status ));\r
+    }\r
+    else {\r
+      DEBUG (( DEBUG_INFO,\r
+                "Ox%08x: TCP service closed\r\n",\r
+                Tcp4Handle ));\r
+      Tcp4Handle = NULL;\r
+    }\r
+  }\r
+\r
+  //\r
+  //  Close the service protocol\r
+  //\r
+  if ( NULL != pTcp4Service ) {\r
+    Status = gBS->CloseProtocol ( Tcp4Controller,\r
+                                  &gEfiTcp4ServiceBindingProtocolGuid,\r
+                                  gImageHandle,\r
+                                  NULL );\r
+    if ( !EFI_ERROR ( Status )) {\r
+      DEBUG (( DEBUG_INFO,\r
+                "0x%08x: Controller closed gEfiTcp4ServiceBindingProtocolGuid protocol\r\n",\r
+                Tcp4Controller ));\r
+      pTcp4Service = NULL;\r
+    }\r
+    else {\r
+      DEBUG (( DEBUG_ERROR,\r
+                "ERROR - Failed to close the gEfiTcp4ServiceBindingProtocolGuid protocol, Status: %r\r\n",\r
+                Status ));\r
+    }\r
+  }\r
+  Tcp4Controller = NULL;\r
+  bTcp4Connecting = TRUE;\r
+\r
+  //\r
+  //  Mark the connection as closed\r
+  //\r
+  Status = EFI_SUCCESS;\r
+\r
+  //\r
+  //  Return the operation status\r
+  //\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Locate TCP protocol\r
+\r
+  @retval EFI_SUCCESS   Protocol found\r
+  @retval other         Protocl not found\r
+**/\r
+EFI_STATUS\r
+Tcp4Locate (\r
+  )\r
+{\r
+  UINTN HandleCount;\r
+  EFI_HANDLE * pHandles;\r
+  UINT8 * pIpAddress;\r
+  EFI_STATUS Status;\r
+\r
+  //\r
+  //  Use do/while and break instead of goto\r
+  //\r
+  do {\r
+    //\r
+    //  Attempt to locate the next TCP adapter in the system\r
+    //\r
+    Status = gBS->LocateHandleBuffer ( ByProtocol,\r
+                                       &gEfiTcp4ServiceBindingProtocolGuid,\r
+                                       NULL,\r
+                                       &HandleCount,\r
+                                       &pHandles );\r
+    if ( EFI_ERROR ( Status )) {\r
+      DEBUG (( DEBUG_WARN,\r
+                "WARNING - No network controllers or TCP4 available, Status: %r\r\n",\r
+                Status ));\r
+      break;\r
+    }\r
+\r
+    //\r
+    //  Wrap the index if necessary\r
+    //\r
+    if ( HandleCount <= Tcp4Index ) {\r
+      Tcp4Index = 0;\r
+    \r
+      //\r
+      //  Wait for the next timer tick\r
+      //\r
+      do {\r
+      } while ( !bTick );\r
+      bTick = FALSE;\r
+    }\r
+\r
+    //\r
+    //  Display the connecting message\r
+    //\r
+    if ( bTcp4Connecting ) {\r
+      pIpAddress = (UINT8 *)&RemoteHostAddress.sin_addr.s_addr;\r
+      Print ( L"Connecting to %d.%d.%d.%d:%d\r\n",\r
+              pIpAddress[0],\r
+              pIpAddress[1],\r
+              pIpAddress[2],\r
+              pIpAddress[3],\r
+              htons ( RemoteHostAddress.sin_port ));\r
+      bTcp4Connecting = FALSE;\r
+    }\r
+    \r
+    //\r
+    //  Open the network controller's service protocol\r
+    //\r
+    Tcp4Controller = pHandles [ Tcp4Index++ ];\r
+    Status = gBS->OpenProtocol (\r
+                    Tcp4Controller,\r
+                    &gEfiTcp4ServiceBindingProtocolGuid,\r
+                    (VOID **) &pTcp4Service,\r
+                    gImageHandle,\r
+                    NULL,\r
+                    EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL );\r
+    if ( EFI_ERROR ( Status )) {\r
+      DEBUG (( DEBUG_ERROR,\r
+                "ERROR - Failed to open gEfiTcp4ServiceBindingProtocolGuid on controller 0x%08x\r\n",\r
+                Tcp4Controller ));\r
+      Tcp4Controller = NULL;\r
+      break;\r
+    }\r
+    DEBUG (( DEBUG_INFO,\r
+              "0x%08x: Controller opened gEfiTcp4ServiceBindingProtocolGuid protocol\r\n",\r
+              Tcp4Controller ));\r
+\r
+    //\r
+    //  Connect to the TCP service\r
+    //\r
+    Status = pTcp4Service->CreateChild ( pTcp4Service,\r
+                                         &Tcp4Handle );\r
+    if ( EFI_ERROR ( Status )) {\r
+      DEBUG (( DEBUG_ERROR,\r
+                "ERROR - Failed to open TCP service, Status: %r\r\n",\r
+                Status ));\r
+      Tcp4Handle = NULL;\r
+      break;\r
+    }\r
+    DEBUG (( DEBUG_INFO,\r
+              "Ox%08x: TCP service opened\r\n",\r
+              Tcp4Handle ));\r
+\r
+    //\r
+    //  Locate the TCP protcol\r
+    //\r
+    Status = gBS->OpenProtocol ( Tcp4Handle,\r
+                                 &gEfiTcp4ProtocolGuid,\r
+                                 (VOID **)&pTcp4Protocol,\r
+                                 gImageHandle,\r
+                                 NULL,\r
+                                 EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL );\r
+    if ( EFI_ERROR ( Status )) {\r
+      DEBUG (( DEBUG_ERROR,\r
+                "ERROR - Failed to open the TCP protocol, Status: %r\r\n",\r
+                Status ));\r
+      pTcp4Protocol = NULL;\r
+      break;\r
+    }\r
+    DEBUG (( DEBUG_INFO,\r
+              "0x%08x: TCP4 protocol opened\r\n",\r
+              pTcp4Protocol ));\r
+  }while ( FALSE );\r
+\r
+  //\r
+  //  Release the handle buffer\r
+  //\r
+  gBS->FreePool ( pHandles );\r
+\r
+  //\r
+  //  Return the operation status\r
+  //\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Send data over the TCP4 connection\r
+\r
+  @retval  EFI_SUCCESS  The application is running normally\r
+  @retval  Other        The user stopped the application\r
+**/\r
+EFI_STATUS\r
+Tcp4Send (\r
+  )\r
+{\r
+  UINTN Index;\r
+  EFI_TCP4_TRANSMIT_DATA Packet;\r
+  EFI_STATUS Status;\r
+  EFI_TPL TplPrevious;\r
+\r
+  //\r
+  //  Restart the timer\r
+  //\r
+  TimerStart ( 1000 << DATA_RATE_UPDATE_SHIFT );\r
+\r
+  //\r
+  //  Initialize the packet\r
+  //\r
+  Packet.DataLength = sizeof ( Buffer );\r
+  Packet.FragmentCount = 1;\r
+  Packet.Push = FALSE;\r
+  Packet.Urgent = FALSE;\r
+  Packet.FragmentTable[0].FragmentBuffer = &Buffer[0];\r
+  Packet.FragmentTable[0].FragmentLength = sizeof ( Buffer );\r
+  Tcp4TxToken.Packet.TxData = &Packet;\r
+\r
+  //\r
+  //  Loop until the connection breaks or the user stops\r
+  //\r
+  do {\r
+    //\r
+    //  Check for user stop request\r
+    //\r
+    Status = ControlCCheck ( );\r
+    if ( EFI_ERROR ( Status )) {\r
+      break;\r
+    }\r
+\r
+    //\r
+    //  Send some bytes\r
+    //\r
+    Status = pTcp4Protocol->Transmit ( pTcp4Protocol,\r
+                                       &Tcp4TxToken );\r
+    if ( EFI_ERROR ( Status )) {\r
+      DEBUG (( DEBUG_ERROR,\r
+                "ERROR - Failed to start the transmit, Status: %r\r\n",\r
+                Status ));\r
+\r
+      //\r
+      //  Try again\r
+      //\r
+      Status = EFI_SUCCESS;\r
+      break;\r
+    }\r
+\r
+    //\r
+    //  Wait for the transmit to complete\r
+    //\r
+    Status = gBS->WaitForEvent ( 1,\r
+                                 &Tcp4TxToken.CompletionToken.Event,\r
+                                 &Index );\r
+    if ( EFI_ERROR ( Status )) {\r
+      DEBUG (( DEBUG_ERROR,\r
+                "ERROR - Failed to wait for transmit completion, Status: %r\r\n",\r
+                Status ));\r
+\r
+      //\r
+      //  Try again\r
+      //\r
+      Status = EFI_SUCCESS;\r
+      break;\r
+    }\r
+\r
+    //\r
+    //  Get the transmit status\r
+    //\r
+    Status = Tcp4TxToken.CompletionToken.Status;\r
+    if ( EFI_ERROR ( Status )) {\r
+      DEBUG (( DEBUG_WARN,\r
+                "WARNING - Failed the transmission, Status: %r\r\n",\r
+                Status ));\r
+\r
+      //\r
+      //  Try again\r
+      //\r
+      Status = EFI_SUCCESS;\r
+\r
+//\r
+//  Exit now\r
+//\r
+Status = EFI_NOT_STARTED;\r
+      break;\r
+    }\r
+\r
+    //\r
+    //  Synchronize with the TimerCallback routine\r
+    //\r
+    TplPrevious = gBS->RaiseTPL ( TPL_DATASOURCE );\r
+\r
+    //\r
+    //  Account for the data sent\r
+    //\r
+    TotalBytesSent += Packet.DataLength;\r
+\r
+    //\r
+    //  Release the TimerCallback routine synchronization\r
+    //\r
+    gBS->RestoreTPL ( TplPrevious );\r
+  } while ( !EFI_ERROR ( Status ));\r
+\r
+  //\r
+  //  Return the operation status\r
+  //\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Open the network connection and send the data.\r
+\r
+  @retval EFI_SUCCESS   Continue looping\r
+  @retval other         Stopped by user's Control-C input\r
+\r
+**/\r
+EFI_STATUS\r
+Tcp4Open (\r
+  )\r
+{\r
+  UINTN Index;\r
+  UINT8 * pIpAddress;\r
+  EFI_STATUS Status;\r
+\r
+  //\r
+  //  Use do/while and break instead of goto\r
+  //\r
+  do {\r
+    //\r
+    //  Locate the TCP protocol\r
+    //\r
+    Status = Tcp4Locate ( );\r
+    if ( EFI_ERROR ( Status )) {\r
+      break;\r
+    }\r
+\r
+    //\r
+    //  Create the necessary events\r
+    //\r
+    Status = gBS->CreateEvent ( 0,\r
+                                TPL_CALLBACK,\r
+                                NULL,\r
+                                NULL,\r
+                                &Tcp4CloseToken.CompletionToken.Event );\r
+    if ( EFI_ERROR ( Status )) {\r
+      DEBUG (( DEBUG_ERROR,\r
+                "ERROR - Failed to create the close event, Status: %r\r\n",\r
+                Status ));\r
+      Tcp4CloseToken.CompletionToken.Event = NULL;\r
+      break;\r
+    }\r
+    DEBUG (( DEBUG_INFO,\r
+              "0x%08x: Close event open\r\n",\r
+              Tcp4CloseToken.CompletionToken.Event ));\r
+\r
+    Status = gBS->CreateEvent ( 0,\r
+                                TPL_CALLBACK,\r
+                                NULL,\r
+                                NULL,\r
+                                &Tcp4ConnectToken.CompletionToken.Event );\r
+    if ( EFI_ERROR ( Status )) {\r
+      DEBUG (( DEBUG_ERROR,\r
+                "ERROR - Failed to create the connect event, Status: %r\r\n",\r
+                Status ));\r
+      Tcp4ConnectToken.CompletionToken.Event = NULL;\r
+      break;\r
+    }\r
+    DEBUG (( DEBUG_INFO,\r
+              "0x%08x: Connect event open\r\n",\r
+              Tcp4ConnectToken.CompletionToken.Event ));\r
+\r
+    Status = gBS->CreateEvent ( 0,\r
+                                TPL_CALLBACK,\r
+                                NULL,\r
+                                NULL,\r
+                                &Tcp4ListenToken.CompletionToken.Event );\r
+    if ( EFI_ERROR ( Status )) {\r
+      DEBUG (( DEBUG_ERROR,\r
+                "ERROR - Failed to create the listen event, Status: %r\r\n",\r
+                Status ));\r
+      Tcp4ListenToken.CompletionToken.Event = NULL;\r
+      break;\r
+    }\r
+    DEBUG (( DEBUG_INFO,\r
+              "0x%08x: Listen event open\r\n",\r
+              Tcp4ListenToken.CompletionToken.Event ));\r
+\r
+    Status = gBS->CreateEvent ( 0,\r
+                                TPL_CALLBACK,\r
+                                NULL,\r
+                                NULL,\r
+                                &Tcp4TxToken.CompletionToken.Event );\r
+    if ( EFI_ERROR ( Status )) {\r
+      DEBUG (( DEBUG_ERROR,\r
+                "ERROR - Failed to create the TX event, Status: %r\r\n",\r
+                Status ));\r
+      Tcp4TxToken.CompletionToken.Event = NULL;\r
+      break;\r
+    }\r
+    DEBUG (( DEBUG_INFO,\r
+              "0x%08x: TX event open\r\n",\r
+              Tcp4TxToken.CompletionToken.Event ));\r
+\r
+    //\r
+    //  Configure the local TCP port\r
+    //\r
+    Tcp4ConfigData.TimeToLive = 255;\r
+    Tcp4ConfigData.TypeOfService = 0;\r
+    Tcp4ConfigData.ControlOption = NULL;\r
+    Tcp4ConfigData.AccessPoint.ActiveFlag = TRUE;\r
+    Tcp4ConfigData.AccessPoint.StationAddress.Addr[0] = 0;\r
+    Tcp4ConfigData.AccessPoint.StationAddress.Addr[1] = 0;\r
+    Tcp4ConfigData.AccessPoint.StationAddress.Addr[2] = 0;\r
+    Tcp4ConfigData.AccessPoint.StationAddress.Addr[3] = 0;\r
+    Tcp4ConfigData.AccessPoint.StationPort = 0;\r
+    Tcp4ConfigData.AccessPoint.RemoteAddress.Addr[0] = (UINT8)  RemoteHostAddress.sin_addr.s_addr;\r
+    Tcp4ConfigData.AccessPoint.RemoteAddress.Addr[1] = (UINT8)( RemoteHostAddress.sin_addr.s_addr >> 8 );\r
+    Tcp4ConfigData.AccessPoint.RemoteAddress.Addr[2] = (UINT8)( RemoteHostAddress.sin_addr.s_addr >> 16 );\r
+    Tcp4ConfigData.AccessPoint.RemoteAddress.Addr[3] = (UINT8)( RemoteHostAddress.sin_addr.s_addr >> 24 );\r
+    Tcp4ConfigData.AccessPoint.RemotePort = RemoteHostAddress.sin_port;\r
+    Tcp4ConfigData.AccessPoint.UseDefaultAddress = TRUE;\r
+    Tcp4ConfigData.AccessPoint.SubnetMask.Addr[0] = 0;\r
+    Tcp4ConfigData.AccessPoint.SubnetMask.Addr[1] = 0;\r
+    Tcp4ConfigData.AccessPoint.SubnetMask.Addr[2] = 0;\r
+    Tcp4ConfigData.AccessPoint.SubnetMask.Addr[3] = 0;\r
+    Status = pTcp4Protocol->Configure ( pTcp4Protocol,\r
+                                        &Tcp4ConfigData );\r
+    if ( EFI_ERROR ( Status )) {\r
+      DEBUG (( DEBUG_ERROR, \r
+                "ERROR - Failed to configure TCP port, Status: %r\r\n",\r
+                Status ));\r
+      break;\r
+    }\r
+    DEBUG (( DEBUG_INFO,\r
+              "0x%08x: TCP4 port configured\r\n",\r
+              pTcp4Protocol ));\r
+\r
+    //\r
+    //  Connect to the remote TCP port\r
+    //\r
+    Status = pTcp4Protocol->Connect ( pTcp4Protocol,\r
+                                      &Tcp4ConnectToken );\r
+    if ( EFI_ERROR ( Status )) {\r
+      DEBUG (( DEBUG_ERROR,\r
+                "ERROR - Failed to start the connection to the remote system, Status: %r\r\n",\r
+                Status ));\r
+      break;\r
+    }\r
+    Status = gBS->WaitForEvent ( 1,\r
+                                 &Tcp4ConnectToken.CompletionToken.Event,\r
+                                 &Index );\r
+    if ( EFI_ERROR ( Status )) {\r
+      DEBUG (( DEBUG_ERROR,\r
+                "ERROR - Failed to wait for the connection, Status: %r\r\n",\r
+                Status ));\r
+      break;\r
+    }\r
+    Status = Tcp4ConnectToken.CompletionToken.Status;\r
+    if ( EFI_ERROR ( Status )) {\r
+      DEBUG (( DEBUG_WARN,\r
+                "WARNING - Failed to connect to the remote system, Status: %r\r\n",\r
+                Status ));\r
+      break;\r
+    }\r
+    DEBUG (( DEBUG_INFO,\r
+              "0x%08x: TCP4 port connected\r\n",\r
+              pTcp4Protocol ));\r
+    bTcp4Connected = TRUE;\r
+\r
+    //\r
+    //  Display the connection\r
+    //\r
+    pIpAddress = (UINT8 *)&RemoteHostAddress.sin_addr.s_addr;\r
+    Print ( L"Connected to %d.%d.%d.%d:%d\r\n",\r
+            pIpAddress[0],\r
+            pIpAddress[1],\r
+            pIpAddress[2],\r
+            pIpAddress[3],\r
+            htons ( RemoteHostAddress.sin_port ));\r
+  } while ( 0 );\r
+\r
+  if ( EFI_ERROR ( Status )) {\r
+    //\r
+    //  Try again\r
+    //\r
+    Status = EFI_SUCCESS;\r
+  }\r
+  else {\r
+    //\r
+    //  Semd data until the connection breaks\r
+    //\r
+    Status = Tcp4Send ( );\r
+  }\r
+\r
+  //\r
+  //  Return the operation status\r
+  //\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Handle the timer callback\r
+\r
+  @param [in] Event     Event that caused this callback\r
+  @param [in] pContext  Context for this routine\r
+**/\r
+VOID\r
+TimerCallback (\r
+  IN EFI_EVENT Event,\r
+  IN VOID * pContext\r
+  )\r
+{\r
+  UINT64 BytesSent;\r
+  UINT64 DeltaBytes;\r
+  UINT32 Delta;\r
+  UINT64 Average;\r
+\r
+  //\r
+  //  Notify the other code of the timer tick\r
+  //\r
+  bTick = TRUE;\r
+\r
+  //\r
+  //  Update the average bytes per second\r
+  //\r
+  BytesSent = TotalBytesSent;\r
+  if ( 0 != BytesSent ) {\r
+    DeltaBytes = AverageBytes >> AVERAGE_SHIFT_COUNT;\r
+    AverageBytes -= DeltaBytes;\r
+    DeltaBytes = BytesSent - PreviousBytes;\r
+    PreviousBytes = BytesSent;\r
+    AverageBytes += DeltaBytes;\r
+\r
+    //\r
+    //  Separate the samples\r
+    //\r
+    if (( 2 << AVERAGE_SHIFT_COUNT ) == Samples ) {\r
+      Print ( L"---------- Stable average ----------\r\n" );\r
+    }\r
+    Samples += 1;\r
+\r
+    //\r
+    //  Display the data rate\r
+    //\r
+    Delta = (UINT32)( DeltaBytes >> DATA_RATE_UPDATE_SHIFT );\r
+    Average = AverageBytes >> ( AVERAGE_SHIFT_COUNT + DATA_RATE_UPDATE_SHIFT );\r
+    if ( Average < RANGE_SWITCH ) {\r
+      Print ( L"%d Bytes/sec, Ave: %d Bytes/Sec\r\n",\r
+              Delta,\r
+              (UINT32) Average );\r
+    }\r
+    else {\r
+      Average >>= 10;\r
+      if ( Average < RANGE_SWITCH ) {\r
+        Print ( L"%d Bytes/sec, Ave: %d KiBytes/Sec\r\n",\r
+                Delta,\r
+                (UINT32) Average );\r
+      }\r
+      else {\r
+        Average >>= 10;\r
+        if ( Average < RANGE_SWITCH ) {\r
+          Print ( L"%d Bytes/sec, Ave: %d MiBytes/Sec\r\n",\r
+                  Delta,\r
+                  (UINT32) Average );\r
+        }\r
+        else {\r
+          Average >>= 10;\r
+          if ( Average < RANGE_SWITCH ) {\r
+            Print ( L"%d Bytes/sec, Ave: %d GiBytes/Sec\r\n",\r
+                    Delta,\r
+                    (UINT32) Average );\r
+          }\r
+          else {\r
+            Average >>= 10;\r
+            if ( Average < RANGE_SWITCH ) {\r
+              Print ( L"%d Bytes/sec, Ave: %d TiBytes/Sec\r\n",\r
+                      Delta,\r
+                      Average );\r
+            }\r
+            else {\r
+              Average >>= 10;\r
+              Print ( L"%d Bytes/sec, Ave: %d PiBytes/Sec\r\n",\r
+                      Delta,\r
+                      (UINT32) Average );\r
+            }\r
+          }\r
+        }\r
+      }\r
+    }\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Create the timer\r
+\r
+  @retval  EFI_SUCCESS  The timer was successfully created\r
+  @retval  Other        Timer initialization failed\r
+**/\r
+EFI_STATUS\r
+TimerCreate (\r
+  )\r
+{\r
+  EFI_STATUS Status;\r
+\r
+  //\r
+  //  Create the timer\r
+  //\r
+  Status = gBS->CreateEvent ( EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
+                              TPL_DATASOURCE,\r
+                              TimerCallback,\r
+                              NULL,\r
+                              &pTimer );\r
+  if ( EFI_ERROR ( Status )) {\r
+    DEBUG (( DEBUG_ERROR,\r
+              "ERROR - Failed to allocate the timer event, Status: %r\r\n",\r
+              Status ));\r
+  }\r
+  else {\r
+    DEBUG (( DEBUG_INFO,\r
+              "0x%08x: Timer created\r\n",\r
+              pTimer ));\r
+  }\r
+\r
+  //\r
+  //  Return the operation status\r
+  //\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Stop the timer\r
+\r
+  @retval  EFI_SUCCESS  The timer was stopped successfully\r
+  @retval  Other        The timer failed to stop\r
+**/\r
+EFI_STATUS\r
+TimerStop (\r
+  )\r
+{\r
+  EFI_STATUS Status;\r
+\r
+  //\r
+  //  Assume success\r
+  //\r
+  Status = EFI_SUCCESS;\r
+\r
+  //\r
+  //  Determine if the timer is running\r
+  //\r
+  if ( bTimerRunning ) {\r
+    //\r
+    //  Stop the timer\r
+    //\r
+    Status = gBS->SetTimer ( pTimer,\r
+                             TimerCancel,\r
+                             0 );\r
+    if ( EFI_ERROR ( Status )) {\r
+      DEBUG (( DEBUG_ERROR,\r
+                "ERROR - Failed to stop the timer, Status: %r\r\n",\r
+                Status ));\r
+    }\r
+    else {\r
+      //\r
+      //  Timer timer is now stopped\r
+      //\r
+      bTimerRunning = FALSE;\r
+      DEBUG (( DEBUG_INFO,\r
+                "0x%08x: Timer stopped\r\n",\r
+                pTimer ));\r
+    }\r
+  }\r
+\r
+  //\r
+  //  Return the operation status\r
+  //\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Start the timer\r
+\r
+  @param [in] Milliseconds  The number of milliseconds between timer callbacks\r
+\r
+  @retval  EFI_SUCCESS  The timer was successfully created\r
+  @retval  Other        Timer initialization failed\r
+**/\r
+EFI_STATUS\r
+TimerStart (\r
+  UINTN Milliseconds\r
+  )\r
+{\r
+  EFI_STATUS Status;\r
+  UINT64 TimeDelay;\r
+\r
+  //\r
+  //  Stop the timer if necessary\r
+  //\r
+  Status = EFI_SUCCESS;\r
+  if ( bTimerRunning ) {\r
+    Status = TimerStop ( );\r
+  }\r
+  if ( !EFI_ERROR ( Status )) {\r
+    //\r
+    //  Compute the new delay\r
+    //\r
+    TimeDelay = Milliseconds;\r
+    TimeDelay *= 1000 * 10;\r
+\r
+    //\r
+    //  Start the timer\r
+    //\r
+    Status = gBS->SetTimer ( pTimer,\r
+                             TimerPeriodic,\r
+                             TimeDelay );\r
+    if ( EFI_ERROR ( Status )) {\r
+      DEBUG (( DEBUG_ERROR,\r
+                "ERROR - Failed to start the timer, Status: %r\r\n",\r
+                Status ));\r
+    }\r
+    else {\r
+      //\r
+      //  The timer is now running\r
+      //\r
+      bTimerRunning = TRUE;\r
+      DEBUG (( DEBUG_INFO,\r
+        "0x%08x: Timer running\r\n",\r
+        pTimer ));\r
+    }\r
+  }\r
+\r
+  //\r
+  //  Return the operation status\r
+  //\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Destroy the timer\r
+\r
+  @retval  EFI_SUCCESS  The timer was destroyed successfully\r
+  @retval  Other        Failed to destroy the timer\r
+**/\r
+EFI_STATUS\r
+TimerDestroy (\r
+  )\r
+{\r
+  EFI_STATUS Status;\r
+\r
+  //\r
+  //  Assume success\r
+  //\r
+  Status = EFI_SUCCESS;\r
+\r
+  //\r
+  //  Determine if the timer is running\r
+  //\r
+  if ( bTimerRunning ) {\r
+    //\r
+    //  Stop the timer\r
+    //\r
+    Status = TimerStop ( );\r
+  }\r
+  if (( !EFI_ERROR ( Status )) && ( NULL != pTimer )) {\r
+    //\r
+    //  Done with this timer\r
+    //\r
+    Status = gBS->CloseEvent ( pTimer );\r
+    if ( EFI_ERROR ( Status )) {\r
+      DEBUG (( DEBUG_ERROR,\r
+                "ERROR - Failed to free the timer event, Status: %r\r\n",\r
+                Status ));\r
+    }\r
+    else {\r
+      DEBUG (( DEBUG_INFO,\r
+                "0x%08x: Timer Destroyed\r\n",\r
+                pTimer ));\r
+      pTimer = NULL;\r
+    }\r
+  }\r
+\r
+  //\r
+  //  Return the operation status\r
+  //\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Send data to the DataSink program to test a network's bandwidth.\r
+\r
+  @param [in] Argc  The number of arguments\r
+  @param [in] Argv  The argument value array\r
+\r
+  @retval  0        The application exited normally.\r
+  @retval  Other    An error occurred.\r
+**/\r
+int\r
+main (\r
+  IN int Argc,\r
+  IN char **Argv\r
+  )\r
+{\r
+  EFI_STATUS (* pClose) ();\r
+  EFI_STATUS (* pOpen) ();\r
+  EFI_STATUS Status;\r
+\r
+  DEBUG (( DEBUG_INFO,\r
+            "DataSource starting\r\n" ));\r
+\r
+  //\r
+  //  Validate the command line\r
+  //\r
+  if ( 2 != Argc ) {\r
+    Print ( L"%s  <remote IP address>\r\n", Argv[0] );\r
+    return -1;\r
+  }\r
+\r
+bTcp4 = TRUE;\r
+\r
+  //\r
+  //  Determine the support routines\r
+  //\r
+  if ( bTcp4 ) {\r
+    pOpen = Tcp4Open;\r
+    pClose = Tcp4Close;\r
+    bTcp4Connecting = TRUE;\r
+  }\r
+  else {\r
+    pOpen = SocketOpen;\r
+    pClose = SocketClose;\r
+  }\r
+\r
+  //\r
+  //  Use for/break instead of goto\r
+  //\r
+  for ( ; ; )\r
+  {\r
+    //\r
+    //  No bytes sent so far\r
+    //\r
+    TotalBytesSent = 0;\r
+    AverageBytes = 0;\r
+    PreviousBytes = 0;\r
+    Samples = 0;\r
+\r
+    //\r
+    //  Get the port number\r
+    //\r
+    ZeroMem ( &RemoteHostAddress, sizeof ( RemoteHostAddress ));\r
+    RemoteHostAddress.sin_len = sizeof ( RemoteHostAddress );\r
+    RemoteHostAddress.sin_family = AF_INET;\r
+    RemoteHostAddress.sin_port = htons ( PcdGet16 ( DataSource_Port ));\r
+\r
+Print ( L"Argc: %d\r\n", Argc);\r
+Print ( L"Argv[0]: %a\r\n", Argv[0]);\r
+Print ( L"Argv[1]: %a\r\n", Argv[1]);\r
+\r
+    //\r
+    //  Get the IP address\r
+    //\r
+    pRemoteHost = Argv [1];\r
+    Status = IpAddress ( );\r
+    if ( EFI_ERROR ( Status )) {\r
+      break;\r
+    }\r
+\r
+    //\r
+    //  Create the timer\r
+    //\r
+    bTick = TRUE;\r
+    Status = TimerCreate ( );\r
+    if ( EFI_ERROR ( Status )) {\r
+      break;\r
+    }\r
+\r
+    //\r
+    //  Loop forever abusing the specified system\r
+    //\r
+    do {\r
+      //\r
+      //  Start a timer to perform connection polling and display updates\r
+      //\r
+      Status = TimerStart ( 2 * 1000 );\r
+      if ( EFI_ERROR ( Status )) {\r
+        break;\r
+      }\r
+\r
+      //\r
+      //  Open the network connection and send the data\r
+      //\r
+      Status = pOpen ( );\r
+      if ( EFI_ERROR ( Status )) {\r
+        break;\r
+      }\r
+\r
+      //\r
+      //  Done with the network connection\r
+      //\r
+      Status = pClose ( );\r
+    } while ( !EFI_ERROR ( Status ));\r
+\r
+    //\r
+    //  Close the network connection if necessary\r
+    //\r
+    pClose ( );\r
+\r
+    //\r
+    //  All done\r
+    //\r
+    break;\r
+  }\r
+\r
+  //\r
+  //  Stop the timer if necessary\r
+  //\r
+  TimerStop ( );\r
+  TimerDestroy ( );\r
+\r
+  //\r
+  //  Return the operation status\r
+  //\r
+  DEBUG (( DEBUG_INFO,\r
+            "DataSource exiting, Status: %r\r\n",\r
+            Status ));\r
+  return Status;\r
+}\r