Home | History | Annotate | Download | only in DataSource
      1 /** @file
      2   Data source for network testing.
      3 
      4   Copyright (c) 2011-2012, Intel Corporation
      5   All rights reserved. This program and the accompanying materials
      6   are licensed and made available under the terms and conditions of the BSD License
      7   which accompanies this distribution.  The full text of the license may be found at
      8   http://opensource.org/licenses/bsd-license.php
      9 
     10   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 #include <errno.h>
     16 #include <Uefi.h>
     17 
     18 #include <Library/BaseMemoryLib.h>
     19 #include <Library/DebugLib.h>
     20 #include <Library/PcdLib.h>
     21 #include <Library/UefiBootServicesTableLib.h>
     22 #include <Library/UefiLib.h>
     23 
     24 #include <netinet/in.h>
     25 
     26 #include <Protocol/ServiceBinding.h>
     27 #include <Protocol/Tcp4.h>
     28 
     29 #include <sys/EfiSysCall.h>
     30 #include <sys/poll.h>
     31 #include <sys/socket.h>
     32 
     33 #include <stdio.h>
     34 #include <string.h>
     35 
     36 
     37 #define DATA_SAMPLE_SHIFT           5       ///<  Shift for number of samples
     38 #define RANGE_SWITCH        ( 1024 * 1024 ) ///<  Switch display ranges
     39 #define DATA_RATE_UPDATE_SHIFT      2       ///<  2n seconds between updates
     40 #define AVERAGE_SHIFT_COUNT ( 6 - DATA_RATE_UPDATE_SHIFT )  ///<  2n samples in average
     41 #define DATA_SAMPLES        ( 1 << DATA_SAMPLE_SHIFT )      ///<  Number of samples
     42 
     43 #define TPL_DATASOURCE      TPL_CALLBACK  ///<  Synchronization TPL
     44 
     45 #define PACKET_SIZE                 1448  ///<  Size of data packets
     46 #define DATA_BUFFER_SIZE    (( 65536 / PACKET_SIZE ) * PACKET_SIZE )  ///<  Buffer size in bytes
     47 
     48 
     49 //
     50 //  Socket Data
     51 //
     52 int Socket = -1;
     53 
     54 //
     55 //  TCP V4 Data
     56 //
     57 BOOLEAN bTcp4;                      ///<  TRUE if TCP4 is being used
     58 BOOLEAN bTcp4Connected;             ///<  TRUE if connected to remote system
     59 BOOLEAN bTcp4Connecting;            ///<  TRUE while connection in progress
     60 UINTN Tcp4Index;                    ///<  Index into handle array
     61 EFI_HANDLE Tcp4Controller;          ///<  Network controller handle
     62 EFI_HANDLE Tcp4Handle;              ///<  TCP4 port handle
     63 EFI_TCP4_PROTOCOL * pTcp4Protocol;  ///<  TCP4 protocol pointer
     64 EFI_SERVICE_BINDING_PROTOCOL * pTcp4Service;  ///<  TCP4 Service binding
     65 EFI_TCP4_CONFIG_DATA Tcp4ConfigData;///<  TCP4 configuration data
     66 EFI_TCP4_OPTION Tcp4Option;         ///<  TCP4 port options
     67 EFI_TCP4_CLOSE_TOKEN Tcp4CloseToken;///<  Close control
     68 EFI_TCP4_CONNECTION_TOKEN Tcp4ConnectToken; ///<  Connection control
     69 EFI_TCP4_LISTEN_TOKEN Tcp4ListenToken;      ///<  Listen control
     70 EFI_TCP4_IO_TOKEN Tcp4TxToken;      ///<  Normal data token
     71 
     72 //
     73 //  Timer Data
     74 //
     75 volatile BOOLEAN bTick;
     76 BOOLEAN bTimerRunning;
     77 EFI_EVENT pTimer;
     78 
     79 //
     80 //  Remote IP Address Data
     81 //
     82 struct sockaddr_in6 RemoteHostAddress;
     83 CHAR8 * pRemoteHost;
     84 
     85 //
     86 //  Traffic Data
     87 //
     88 UINT64 TotalBytesSent;
     89 UINT32 In;
     90 UINT32 Samples;
     91 UINT64 BytesSent[ DATA_SAMPLES ];
     92 UINT8 Buffer[ DATA_BUFFER_SIZE ];
     93 
     94 
     95 //
     96 //  Forward routine declarations
     97 //
     98 EFI_STATUS TimerStart ( UINTN Milliseconds );
     99 
    100 
    101 /**
    102   Check for control C entered at console
    103 
    104   @retval  EFI_SUCCESS  Control C not entered
    105   @retval  EFI_ABORTED  Control C entered
    106 **/
    107 EFI_STATUS
    108 ControlCCheck (
    109   )
    110 {
    111   EFI_STATUS Status;
    112 
    113   //
    114   //  Assume no user intervention
    115   //
    116   Status = EFI_SUCCESS;
    117 
    118   //
    119   //  Display user stop request
    120   //
    121   if ( EFI_ERROR ( Status )) {
    122     DEBUG (( DEBUG_INFO,
    123               "User stop request!\r\n" ));
    124   }
    125 
    126   //
    127   //  Return the check status
    128   //
    129   return Status;
    130 }
    131 
    132 
    133 /**
    134   Get a digit
    135 
    136   @param [in] pDigit    The address of the next digit
    137   @param [out] pValue   The address to receive the value
    138 
    139   @return   Returns the address of the separator
    140 
    141 **/
    142 CHAR8 *
    143 GetDigit (
    144   CHAR8 * pDigit,
    145   UINT32 * pValue
    146   )
    147 {
    148   UINT32 Value;
    149 
    150   //
    151   //  Walk the digits
    152   //
    153   Value = 0;
    154   while (( '0' <= *pDigit ) && ( '9' >= *pDigit )) {
    155     //
    156     //  Make room for the new least significant digit
    157     //
    158     Value *= 10;
    159 
    160     //
    161     //  Convert the digit from ASCII to binary
    162     //
    163     Value += *pDigit - '0';
    164 
    165     //
    166     //  Set the next digit
    167     //
    168     pDigit += 1;
    169   }
    170 
    171   //
    172   //  Return the value
    173   //
    174   *pValue = Value;
    175 
    176   //
    177   //  Return the next separator
    178   //
    179   return pDigit;
    180 }
    181 
    182 
    183 /**
    184   Get the IP address
    185 
    186   @retval  EFI_SUCCESS  The IP address is valid
    187   @retval  Other        Failure to convert the IP address
    188 **/
    189 EFI_STATUS
    190 IpAddress (
    191   )
    192 {
    193   struct sockaddr_in * pRemoteAddress4;
    194   struct sockaddr_in6 * pRemoteAddress6;
    195   UINT32 RemoteAddress;
    196   EFI_STATUS Status;
    197   UINT32 Value1;
    198   UINT32 Value2;
    199   UINT32 Value3;
    200   UINT32 Value4;
    201   UINT32 Value5;
    202   UINT32 Value6;
    203   UINT32 Value7;
    204   UINT32 Value8;
    205 
    206   //
    207   //  Assume failure
    208   //
    209   Status = EFI_INVALID_PARAMETER;
    210 
    211   //
    212   //  Get the port number
    213   //
    214   ZeroMem ( &RemoteHostAddress, sizeof ( RemoteHostAddress ));
    215   RemoteHostAddress.sin6_port = htons ( PcdGet16 ( DataSource_Port ));
    216   pRemoteAddress4 = (struct sockaddr_in *)&RemoteHostAddress;
    217   pRemoteAddress6 = &RemoteHostAddress;
    218 
    219   //
    220   //  Convert the IP address from a string to a numeric value
    221   //
    222   if (( 4 == sscanf ( pRemoteHost,
    223                       "%d.%d.%d.%d",
    224                       &Value1,
    225                       &Value2,
    226                       &Value3,
    227                       &Value4 ))
    228       && ( 255 >= Value1 )
    229       && ( 255 >= Value2 )
    230       && ( 255 >= Value3 )
    231       && ( 255 >= Value4 )) {
    232     //
    233     //  Build the IPv4 address
    234     //
    235     pRemoteAddress4->sin_len = sizeof ( *pRemoteAddress4 );
    236     pRemoteAddress4->sin_family = AF_INET;
    237     RemoteAddress = Value1
    238                   | ( Value2 << 8 )
    239                   | ( Value3 << 16 )
    240                   | ( Value4 << 24 );
    241     pRemoteAddress4->sin_addr.s_addr = RemoteAddress;
    242     Status = EFI_SUCCESS;
    243 
    244     //
    245     //  Display the IP address
    246     //
    247     DEBUG (( DEBUG_INFO,
    248               "%d.%d.%d.%d: Remote host IP address\r\n",
    249               Value1,
    250               Value2,
    251               Value3,
    252               Value4 ));
    253   }
    254   else if (( 8 == sscanf ( pRemoteHost,
    255                            "%x:%x:%x:%x:%x:%x:%x:%x",
    256                            &Value1,
    257                            &Value2,
    258                            &Value3,
    259                            &Value4,
    260                            &Value5,
    261                            &Value6,
    262                            &Value7,
    263                            &Value8 ))
    264             && ( 0xffff >= Value1 )
    265             && ( 0xffff >= Value2 )
    266             && ( 0xffff >= Value3 )
    267             && ( 0xffff >= Value4 )
    268             && ( 0xffff >= Value5 )
    269             && ( 0xffff >= Value6 )
    270             && ( 0xffff >= Value7 )
    271             && ( 0xffff >= Value8 )) {
    272     //
    273     //  Build the IPv6 address
    274     //
    275     pRemoteAddress6->sin6_len = sizeof ( *pRemoteAddress6 );
    276     pRemoteAddress6->sin6_family = AF_INET6;
    277     pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 0 ] = (UINT8)( Value1 >> 8 );
    278     pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 1 ] = (UINT8)Value1;
    279     pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 2 ] = (UINT8)( Value2 >> 8 );
    280     pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 3 ] = (UINT8)Value2;
    281     pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 4 ] = (UINT8)( Value3 >> 8 );
    282     pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 5 ] = (UINT8)Value3;
    283     pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 6 ] = (UINT8)( Value4 >> 8 );
    284     pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 7 ] = (UINT8)Value4;
    285     pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 8 ] = (UINT8)( Value5 >> 8 );
    286     pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 9 ] = (UINT8)Value5;
    287     pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 10 ] = (UINT8)( Value6 >> 8 );
    288     pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 11 ] = (UINT8)Value6;
    289     pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 12 ] = (UINT8)( Value7 >> 8 );
    290     pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 13 ] = (UINT8)Value7;
    291     pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 14 ] = (UINT8)( Value8 >> 8 );
    292     pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 15 ] = (UINT8)Value8;
    293     Status = EFI_SUCCESS;
    294 
    295     //
    296     //  Display the IP address
    297     //
    298     DEBUG (( DEBUG_INFO,
    299               "[%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]: Remote host IP address\r\n",
    300               Value1,
    301               Value2,
    302               Value3,
    303               Value4,
    304               Value5,
    305               Value6,
    306               Value7,
    307               Value8 ));
    308   }
    309   else {
    310     Print ( L"ERROR - Invalid IP address!\r\n" );
    311   }
    312 
    313   //
    314   //  Return the operation status
    315   //
    316   return Status;
    317 }
    318 
    319 
    320 /**
    321   Close the socket
    322 
    323   @retval  EFI_SUCCESS  The application is running normally
    324   @retval  Other        The user stopped the application
    325 **/
    326 EFI_STATUS
    327 SocketClose (
    328   )
    329 {
    330   int CloseStatus;
    331   EFI_STATUS Status;
    332 
    333   //
    334   //  Determine if the socket is open
    335   //
    336   Status = EFI_DEVICE_ERROR;
    337   if ( -1 != Socket ) {
    338     //
    339     //  Attempt to close the socket
    340     //
    341     CloseStatus = close ( Socket );
    342     if ( 0 == CloseStatus ) {
    343       DEBUG (( DEBUG_INFO,
    344                 "0x%08x: Socket closed\r\n",
    345                 Socket ));
    346       Socket = -1;
    347       Status = EFI_SUCCESS;
    348     }
    349     else {
    350       DEBUG (( DEBUG_ERROR,
    351                 "ERROR: Failed to close socket, errno: %d\r\n",
    352                 errno ));
    353     }
    354   }
    355 
    356   //
    357   //  Return the operation status
    358   //
    359   return Status;
    360 }
    361 
    362 
    363 /**
    364   Connect the socket
    365 
    366   @retval  EFI_SUCCESS  The application is running normally
    367   @retval  Other        The user stopped the application
    368 **/
    369 EFI_STATUS
    370 SocketConnect (
    371   )
    372 {
    373   int ConnectStatus;
    374   struct sockaddr_in * pRemoteAddress4;
    375   struct sockaddr_in6 * pRemoteAddress6;
    376   EFI_STATUS Status;
    377 
    378   //
    379   //  Display the connecting message
    380   //
    381   pRemoteAddress4 = (struct sockaddr_in *)&RemoteHostAddress;
    382   pRemoteAddress6 = &RemoteHostAddress;
    383   if ( AF_INET == pRemoteAddress6->sin6_family ) {
    384     Print ( L"Connecting to remote system %d.%d.%d.%d:%d\r\n",
    385             pRemoteAddress4->sin_addr.s_addr & 0xff,
    386             ( pRemoteAddress4->sin_addr.s_addr >> 8 ) & 0xff,
    387             ( pRemoteAddress4->sin_addr.s_addr >> 16 ) & 0xff,
    388             ( pRemoteAddress4->sin_addr.s_addr >> 24 ) & 0xff,
    389             ntohs ( pRemoteAddress4->sin_port ));
    390   }
    391   else {
    392     Print ( L"Connecting to remote system [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d\r\n",
    393             pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 0 ],
    394             pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 1 ],
    395             pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 2 ],
    396             pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 3 ],
    397             pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 4 ],
    398             pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 5 ],
    399             pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 6 ],
    400             pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 7 ],
    401             pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 8 ],
    402             pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 9 ],
    403             pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 10 ],
    404             pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 11 ],
    405             pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 12 ],
    406             pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 13 ],
    407             pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 14 ],
    408             pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 15 ],
    409             ntohs ( pRemoteAddress6->sin6_port ));
    410   }
    411 
    412   //
    413   //  Connect to the remote system
    414   //
    415   Status = EFI_SUCCESS;
    416   do {
    417     //
    418     //  Check for user stop request
    419     //
    420     while ( !bTick ) {
    421       Status = ControlCCheck ( );
    422       if ( EFI_ERROR ( Status )) {
    423         break;
    424       }
    425     }
    426     bTick = FALSE;
    427     if ( EFI_ERROR ( Status )) {
    428       break;
    429     }
    430 
    431     //
    432     //  Connect to the remote system
    433     //
    434     ConnectStatus = connect ( Socket,
    435                               (struct sockaddr *)pRemoteAddress6,
    436                               pRemoteAddress6->sin6_len );
    437     if ( -1 != ConnectStatus ) {
    438       if ( AF_INET == pRemoteAddress6->sin6_family ) {
    439         Print ( L"Connected to remote system %d.%d.%d.%d:%d\r\n",
    440                 pRemoteAddress4->sin_addr.s_addr & 0xff,
    441                 ( pRemoteAddress4->sin_addr.s_addr >> 8 ) & 0xff,
    442                 ( pRemoteAddress4->sin_addr.s_addr >> 16 ) & 0xff,
    443                 ( pRemoteAddress4->sin_addr.s_addr >> 24 ) & 0xff,
    444                 ntohs ( pRemoteAddress4->sin_port ));
    445       }
    446       else {
    447         Print ( L"Connected to remote system [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d\r\n",
    448                 pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 0 ],
    449                 pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 1 ],
    450                 pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 2 ],
    451                 pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 3 ],
    452                 pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 4 ],
    453                 pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 5 ],
    454                 pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 6 ],
    455                 pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 7 ],
    456                 pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 8 ],
    457                 pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 9 ],
    458                 pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 10 ],
    459                 pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 11 ],
    460                 pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 12 ],
    461                 pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 13 ],
    462                 pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 14 ],
    463                 pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 15 ],
    464                 ntohs ( pRemoteAddress6->sin6_port ));
    465       }
    466 Print ( L"ConnectStatus: %d, Status: %r\r\n", ConnectStatus, Status );
    467     }
    468     else {
    469       //
    470       //  Close the socket and try again
    471       //
    472       if ( EAGAIN != errno ) {
    473         Status = EFI_NOT_STARTED;
    474         break;
    475       }
    476     }
    477   } while ( -1 == ConnectStatus );
    478 
    479   //
    480   //  Return the operation status
    481   //
    482 Print ( L"SocketConnect returning Status: %r\r\n", Status );
    483   return Status;
    484 }
    485 
    486 
    487 /**
    488   Create the socket
    489 
    490   @param [in] Family    Network family, AF_INET or AF_INET6
    491 
    492   @retval  EFI_SUCCESS  The application is running normally
    493   @retval  Other        The user stopped the application
    494 **/
    495 EFI_STATUS
    496 SocketNew (
    497   sa_family_t Family
    498   )
    499 {
    500   EFI_STATUS Status;
    501 
    502   //
    503   //  Loop creating the socket
    504   //
    505   DEBUG (( DEBUG_INFO,
    506             "Creating the socket\r\n" ));
    507   do {
    508     //
    509     //  Check for user stop request
    510     //
    511     Status = ControlCCheck ( );
    512     if ( EFI_ERROR ( Status )) {
    513       break;
    514     }
    515 
    516     //
    517     //  Attempt to create the socket
    518     //
    519     Socket = socket ( Family,
    520                       SOCK_STREAM,
    521                       IPPROTO_TCP );
    522     if ( -1 != Socket ) {
    523       DEBUG (( DEBUG_INFO,
    524                 "0x%08x: Socket created\r\n",
    525                 Socket ));
    526       break;
    527     }
    528   } while ( -1 == Socket );
    529 
    530   //
    531   //  Return the operation status
    532   //
    533   return Status;
    534 }
    535 
    536 
    537 /**
    538   Send data over the socket
    539 
    540   @retval  EFI_SUCCESS  The application is running normally
    541   @retval  Other        The user stopped the application
    542 **/
    543 EFI_STATUS
    544 SocketSend (
    545   )
    546 {
    547   size_t BytesSent;
    548   EFI_STATUS Status;
    549   EFI_TPL TplPrevious;
    550 
    551   //
    552   //  Restart the timer
    553   //
    554   TimerStart ( 1 * 1000 );
    555 
    556   //
    557   //  Loop until the connection breaks or the user stops
    558   //
    559   do {
    560     //
    561     //  Check for user stop request
    562     //
    563     Status = ControlCCheck ( );
    564     if ( EFI_ERROR ( Status )) {
    565       break;
    566     }
    567 
    568     //
    569     //  Send some bytes
    570     //
    571     BytesSent = write ( Socket, &Buffer[0], sizeof ( Buffer ));
    572     if ( -1 == BytesSent ) {
    573       DEBUG (( DEBUG_INFO,
    574                 "ERROR: send failed, errno: %d\r\n",
    575                 errno ));
    576 Print ( L"ERROR: send failed, errno: %d\r\n", errno );
    577 
    578       //
    579       //  Try again
    580       //
    581       Status = EFI_SUCCESS;
    582 
    583 //
    584 //  Exit now
    585 //
    586 Status = EFI_NOT_STARTED;
    587       break;
    588     }
    589 
    590     //
    591     //  Synchronize with the TimerCallback routine
    592     //
    593     TplPrevious = gBS->RaiseTPL ( TPL_DATASOURCE );
    594 
    595     //
    596     //  Account for the data sent
    597     //
    598     TotalBytesSent += BytesSent;
    599 
    600     //
    601     //  Release the TimerCallback routine synchronization
    602     //
    603     gBS->RestoreTPL ( TplPrevious );
    604   } while ( !EFI_ERROR ( Status ));
    605 
    606   //
    607   //  Return the operation status
    608   //
    609   return Status;
    610 }
    611 
    612 
    613 /**
    614   Open the network connection and send the data.
    615 
    616   @retval EFI_SUCCESS   Continue looping
    617   @retval other         Stopped by user's Control-C input
    618 
    619 **/
    620 EFI_STATUS
    621 SocketOpen (
    622   )
    623 {
    624   EFI_STATUS Status;
    625 
    626   //
    627   //  Use do/while and break instead of goto
    628   //
    629   do {
    630     //
    631     //  Wait for the network layer to initialize
    632     //
    633     Status = SocketNew ( RemoteHostAddress.sin6_family );
    634     if ( EFI_ERROR ( Status )) {
    635       break;
    636     }
    637 
    638     //
    639     //  Wait for the remote network application to start
    640     //
    641     Status = SocketConnect ( );
    642 Print ( L"Status: %r\r\n", Status );
    643     if ( EFI_NOT_STARTED == Status ) {
    644       Status = SocketClose ( );
    645       continue;
    646     }
    647     else if ( EFI_SUCCESS != Status ) {
    648       //
    649       //  Control-C
    650       //
    651       break;
    652     }
    653 
    654     //
    655     //  Send data until the connection breaks
    656     //
    657     Status = SocketSend ( );
    658     if ( EFI_ERROR ( Status )) {
    659       break;
    660     }
    661   } while ( FALSE );
    662 
    663   //
    664   //  Return the operation status
    665   //
    666 Print ( L"Returning Status: %r\r\n", Status );
    667   return Status;
    668 }
    669 
    670 
    671 /**
    672   Close the TCP connection
    673 
    674   @retval  EFI_SUCCESS  The application is running normally
    675   @retval  Other        The user stopped the application
    676 **/
    677 EFI_STATUS
    678 Tcp4Close (
    679   )
    680 {
    681   UINTN Index;
    682   UINT8 * pIpAddress;
    683   EFI_STATUS Status;
    684 
    685   //
    686   //  Close the port
    687   //
    688   if ( bTcp4Connected ) {
    689     Tcp4CloseToken.AbortOnClose = TRUE;
    690     Status = pTcp4Protocol->Close ( pTcp4Protocol,
    691                                     &Tcp4CloseToken );
    692     if ( EFI_ERROR ( Status )) {
    693       DEBUG (( DEBUG_ERROR,
    694                 "ERROR - Failed to start the TCP port close, Status: %r\r\n",
    695                 Status ));
    696     }
    697     else {
    698       Status = gBS->WaitForEvent ( 1,
    699                                    &Tcp4CloseToken.CompletionToken.Event,
    700                                     &Index );
    701       if ( EFI_ERROR ( Status )) {
    702         DEBUG (( DEBUG_ERROR,
    703                   "ERROR - Failed to wait for close event, Status: %r\r\n",
    704                   Status ));
    705       }
    706       else {
    707         Status = Tcp4CloseToken.CompletionToken.Status;
    708         if ( EFI_ERROR ( Status )) {
    709           DEBUG (( DEBUG_ERROR,
    710                     "ERROR - Failed to close the TCP port, Status: %r\r\n",
    711                     Status ));
    712         }
    713         else {
    714           DEBUG (( DEBUG_INFO,
    715                     "0x%08x: TCP port closed\r\n",
    716                     pTcp4Protocol ));
    717           bTcp4Connected = FALSE;
    718 
    719           //
    720           //  Display the port closed message
    721           //
    722           pIpAddress = (UINT8 *)&((struct sockaddr_in *)&RemoteHostAddress)->sin_addr.s_addr;
    723           Print ( L"Closed connection to %d.%d.%d.%d:%d\r\n",
    724                   pIpAddress[0],
    725                   pIpAddress[1],
    726                   pIpAddress[2],
    727                   pIpAddress[3],
    728                   ntohs ( ((struct sockaddr_in *)&RemoteHostAddress)->sin_port ));
    729         }
    730       }
    731     }
    732   }
    733 
    734   //
    735   //  Release the events
    736   //
    737   if ( NULL != Tcp4TxToken.CompletionToken.Event ) {
    738     Status = gBS->CloseEvent ( Tcp4TxToken.CompletionToken.Event );
    739     if ( !EFI_ERROR ( Status )) {
    740       DEBUG (( DEBUG_INFO,
    741                 "0x%08x: TX event closed\r\n",
    742                 Tcp4TxToken.CompletionToken.Event ));
    743       Tcp4TxToken.CompletionToken.Event = NULL;
    744     }
    745     else {
    746       DEBUG (( DEBUG_ERROR,
    747                 "ERROR - Failed to close the Tcp4TxToken event, Status: %r\r\n",
    748                 Status ));
    749     }
    750   }
    751 
    752   if ( NULL != Tcp4ListenToken.CompletionToken.Event ) {
    753     Status = gBS->CloseEvent ( Tcp4ListenToken.CompletionToken.Event );
    754     if ( !EFI_ERROR ( Status )) {
    755       DEBUG (( DEBUG_INFO,
    756                 "0x%08x: Listen event closed\r\n",
    757                 Tcp4ListenToken.CompletionToken.Event ));
    758       Tcp4ListenToken.CompletionToken.Event = NULL;
    759     }
    760     else {
    761       DEBUG (( DEBUG_ERROR,
    762                 "ERROR - Failed to close the Tcp4ListenToken event, Status: %r\r\n",
    763                 Status ));
    764     }
    765   }
    766 
    767   if ( NULL != Tcp4ConnectToken.CompletionToken.Event ) {
    768     Status = gBS->CloseEvent ( Tcp4ConnectToken.CompletionToken.Event );
    769     if ( !EFI_ERROR ( Status )) {
    770       DEBUG (( DEBUG_INFO,
    771                 "0x%08x: Connect event closed\r\n",
    772                 Tcp4ConnectToken.CompletionToken.Event ));
    773       Tcp4ConnectToken.CompletionToken.Event = NULL;
    774     }
    775     else {
    776       DEBUG (( DEBUG_ERROR,
    777                 "ERROR - Failed to close the Tcp4ConnectToken event, Status: %r\r\n",
    778                 Status ));
    779     }
    780   }
    781 
    782   if ( NULL != Tcp4CloseToken.CompletionToken.Event ) {
    783     Status = gBS->CloseEvent ( Tcp4CloseToken.CompletionToken.Event );
    784     if ( !EFI_ERROR ( Status )) {
    785       DEBUG (( DEBUG_INFO,
    786                 "0x%08x: Close event closed\r\n",
    787                 Tcp4CloseToken.CompletionToken.Event ));
    788       Tcp4CloseToken.CompletionToken.Event = NULL;
    789     }
    790     else {
    791       DEBUG (( DEBUG_ERROR,
    792                 "ERROR - Failed to close the Tcp4CloseToken event, Status: %r\r\n",
    793                 Status ));
    794     }
    795   }
    796 
    797   //
    798   //  Close the TCP protocol
    799   //
    800   if ( NULL != pTcp4Protocol ) {
    801     Status = gBS->CloseProtocol ( Tcp4Handle,
    802                                   &gEfiTcp4ProtocolGuid,
    803                                   gImageHandle,
    804                                   NULL );
    805     if ( EFI_ERROR ( Status )) {
    806       DEBUG (( DEBUG_ERROR,
    807                 "ERROR - Failed to close the TCP protocol, Status: %r\r\n",
    808                 Status ));
    809     }
    810     else {
    811       DEBUG (( DEBUG_INFO,
    812                 "0x%08x: TCP4 protocol closed\r\n",
    813                 pTcp4Protocol ));
    814       pTcp4Protocol = NULL;
    815     }
    816   }
    817 
    818   //
    819   //  Done with the TCP service
    820   //
    821   if ( NULL != Tcp4Handle ) {
    822     Status = pTcp4Service->DestroyChild ( pTcp4Service,
    823                                           Tcp4Handle );
    824     if ( EFI_ERROR ( Status )) {
    825       DEBUG (( DEBUG_ERROR,
    826                 "ERROR - Failed to release TCP service handle, Status: %r\r\n",
    827                 Status ));
    828     }
    829     else {
    830       DEBUG (( DEBUG_INFO,
    831                 "Ox%08x: TCP service closed\r\n",
    832                 Tcp4Handle ));
    833       Tcp4Handle = NULL;
    834     }
    835   }
    836 
    837   //
    838   //  Close the service protocol
    839   //
    840   if ( NULL != pTcp4Service ) {
    841     Status = gBS->CloseProtocol ( Tcp4Controller,
    842                                   &gEfiTcp4ServiceBindingProtocolGuid,
    843                                   gImageHandle,
    844                                   NULL );
    845     if ( !EFI_ERROR ( Status )) {
    846       DEBUG (( DEBUG_INFO,
    847                 "0x%08x: Controller closed gEfiTcp4ServiceBindingProtocolGuid protocol\r\n",
    848                 Tcp4Controller ));
    849       pTcp4Service = NULL;
    850     }
    851     else {
    852       DEBUG (( DEBUG_ERROR,
    853                 "ERROR - Failed to close the gEfiTcp4ServiceBindingProtocolGuid protocol, Status: %r\r\n",
    854                 Status ));
    855     }
    856   }
    857   Tcp4Controller = NULL;
    858   bTcp4Connecting = TRUE;
    859 
    860   //
    861   //  Mark the connection as closed
    862   //
    863   Status = EFI_SUCCESS;
    864 
    865   //
    866   //  Return the operation status
    867   //
    868   return Status;
    869 }
    870 
    871 
    872 /**
    873   Locate TCP protocol
    874 
    875   @retval EFI_SUCCESS   Protocol found
    876   @retval other         Protocl not found
    877 **/
    878 EFI_STATUS
    879 Tcp4Locate (
    880   )
    881 {
    882   UINTN HandleCount;
    883   EFI_HANDLE * pHandles;
    884   UINT8 * pIpAddress;
    885   EFI_STATUS Status;
    886 
    887   //
    888   //  Use do/while and break instead of goto
    889   //
    890   do {
    891     //
    892     //  Attempt to locate the next TCP adapter in the system
    893     //
    894     Status = gBS->LocateHandleBuffer ( ByProtocol,
    895                                        &gEfiTcp4ServiceBindingProtocolGuid,
    896                                        NULL,
    897                                        &HandleCount,
    898                                        &pHandles );
    899     if ( EFI_ERROR ( Status )) {
    900       DEBUG (( DEBUG_WARN,
    901                 "WARNING - No network controllers or TCP4 available, Status: %r\r\n",
    902                 Status ));
    903       break;
    904     }
    905 
    906     //
    907     //  Wrap the index if necessary
    908     //
    909     if ( HandleCount <= Tcp4Index ) {
    910       Tcp4Index = 0;
    911 
    912       //
    913       //  Wait for the next timer tick
    914       //
    915       do {
    916       } while ( !bTick );
    917       bTick = FALSE;
    918     }
    919 
    920     //
    921     //  Display the connecting message
    922     //
    923     if ( bTcp4Connecting ) {
    924       pIpAddress = (UINT8 *)&((struct sockaddr_in *)&RemoteHostAddress)->sin_addr.s_addr;
    925       Print ( L"Connecting to %d.%d.%d.%d:%d\r\n",
    926               pIpAddress[0],
    927               pIpAddress[1],
    928               pIpAddress[2],
    929               pIpAddress[3],
    930               ntohs ( ((struct sockaddr_in *)&RemoteHostAddress)->sin_port ));
    931       bTcp4Connecting = FALSE;
    932     }
    933 
    934     //
    935     //  Open the network controller's service protocol
    936     //
    937     Tcp4Controller = pHandles[ Tcp4Index++ ];
    938     Status = gBS->OpenProtocol (
    939                     Tcp4Controller,
    940                     &gEfiTcp4ServiceBindingProtocolGuid,
    941                     (VOID **) &pTcp4Service,
    942                     gImageHandle,
    943                     NULL,
    944                     EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL );
    945     if ( EFI_ERROR ( Status )) {
    946       DEBUG (( DEBUG_ERROR,
    947                 "ERROR - Failed to open gEfiTcp4ServiceBindingProtocolGuid on controller 0x%08x\r\n",
    948                 Tcp4Controller ));
    949       Tcp4Controller = NULL;
    950       break;
    951     }
    952     DEBUG (( DEBUG_INFO,
    953               "0x%08x: Controller opened gEfiTcp4ServiceBindingProtocolGuid protocol\r\n",
    954               Tcp4Controller ));
    955 
    956     //
    957     //  Connect to the TCP service
    958     //
    959     Status = pTcp4Service->CreateChild ( pTcp4Service,
    960                                          &Tcp4Handle );
    961     if ( EFI_ERROR ( Status )) {
    962       DEBUG (( DEBUG_ERROR,
    963                 "ERROR - Failed to open TCP service, Status: %r\r\n",
    964                 Status ));
    965       Tcp4Handle = NULL;
    966       break;
    967     }
    968     DEBUG (( DEBUG_INFO,
    969               "Ox%08x: TCP service opened\r\n",
    970               Tcp4Handle ));
    971 
    972     //
    973     //  Locate the TCP protcol
    974     //
    975     Status = gBS->OpenProtocol ( Tcp4Handle,
    976                                  &gEfiTcp4ProtocolGuid,
    977                                  (VOID **)&pTcp4Protocol,
    978                                  gImageHandle,
    979                                  NULL,
    980                                  EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL );
    981     if ( EFI_ERROR ( Status )) {
    982       DEBUG (( DEBUG_ERROR,
    983                 "ERROR - Failed to open the TCP protocol, Status: %r\r\n",
    984                 Status ));
    985       pTcp4Protocol = NULL;
    986       break;
    987     }
    988     DEBUG (( DEBUG_INFO,
    989               "0x%08x: TCP4 protocol opened\r\n",
    990               pTcp4Protocol ));
    991   }while ( FALSE );
    992 
    993   //
    994   //  Release the handle buffer
    995   //
    996   gBS->FreePool ( pHandles );
    997 
    998   //
    999   //  Return the operation status
   1000   //
   1001   return Status;
   1002 }
   1003 
   1004 
   1005 /**
   1006   Send data over the TCP4 connection
   1007 
   1008   @retval  EFI_SUCCESS  The application is running normally
   1009   @retval  Other        The user stopped the application
   1010 **/
   1011 EFI_STATUS
   1012 Tcp4Send (
   1013   )
   1014 {
   1015   UINTN Index;
   1016   EFI_TCP4_TRANSMIT_DATA Packet;
   1017   EFI_STATUS Status;
   1018   EFI_TPL TplPrevious;
   1019 
   1020   //
   1021   //  Restart the timer
   1022   //
   1023   TimerStart ( 1 * 1000 );
   1024 
   1025   //
   1026   //  Initialize the packet
   1027   //
   1028   Packet.DataLength = sizeof ( Buffer );
   1029   Packet.FragmentCount = 1;
   1030   Packet.Push = FALSE;
   1031   Packet.Urgent = FALSE;
   1032   Packet.FragmentTable[0].FragmentBuffer = &Buffer[0];
   1033   Packet.FragmentTable[0].FragmentLength = sizeof ( Buffer );
   1034   Tcp4TxToken.Packet.TxData = &Packet;
   1035 
   1036   //
   1037   //  Loop until the connection breaks or the user stops
   1038   //
   1039   do {
   1040     //
   1041     //  Check for user stop request
   1042     //
   1043     Status = ControlCCheck ( );
   1044     if ( EFI_ERROR ( Status )) {
   1045       break;
   1046     }
   1047 
   1048     //
   1049     //  Send some bytes
   1050     //
   1051     Status = pTcp4Protocol->Transmit ( pTcp4Protocol,
   1052                                        &Tcp4TxToken );
   1053     if ( EFI_ERROR ( Status )) {
   1054       DEBUG (( DEBUG_ERROR,
   1055                 "ERROR - Failed to start the transmit, Status: %r\r\n",
   1056                 Status ));
   1057 
   1058       //
   1059       //  Try again
   1060       //
   1061       Status = EFI_SUCCESS;
   1062       break;
   1063     }
   1064 
   1065     //
   1066     //  Wait for the transmit to complete
   1067     //
   1068     Status = gBS->WaitForEvent ( 1,
   1069                                  &Tcp4TxToken.CompletionToken.Event,
   1070                                  &Index );
   1071     if ( EFI_ERROR ( Status )) {
   1072       DEBUG (( DEBUG_ERROR,
   1073                 "ERROR - Failed to wait for transmit completion, Status: %r\r\n",
   1074                 Status ));
   1075 
   1076       //
   1077       //  Try again
   1078       //
   1079       Status = EFI_SUCCESS;
   1080       break;
   1081     }
   1082 
   1083     //
   1084     //  Get the transmit status
   1085     //
   1086     Status = Tcp4TxToken.CompletionToken.Status;
   1087     if ( EFI_ERROR ( Status )) {
   1088       DEBUG (( DEBUG_WARN,
   1089                 "WARNING - Failed the transmission, Status: %r\r\n",
   1090                 Status ));
   1091 
   1092       //
   1093       //  Try again
   1094       //
   1095       Status = EFI_SUCCESS;
   1096 
   1097 //
   1098 //  Exit now
   1099 //
   1100 Status = EFI_NOT_STARTED;
   1101       break;
   1102     }
   1103 
   1104     //
   1105     //  Synchronize with the TimerCallback routine
   1106     //
   1107     TplPrevious = gBS->RaiseTPL ( TPL_DATASOURCE );
   1108 
   1109     //
   1110     //  Account for the data sent
   1111     //
   1112     TotalBytesSent += Packet.DataLength;
   1113 
   1114     //
   1115     //  Release the TimerCallback routine synchronization
   1116     //
   1117     gBS->RestoreTPL ( TplPrevious );
   1118   } while ( !EFI_ERROR ( Status ));
   1119 
   1120   //
   1121   //  Return the operation status
   1122   //
   1123   return Status;
   1124 }
   1125 
   1126 
   1127 /**
   1128   Open the network connection and send the data.
   1129 
   1130   @retval EFI_SUCCESS   Continue looping
   1131   @retval other         Stopped by user's Control-C input
   1132 
   1133 **/
   1134 EFI_STATUS
   1135 Tcp4Open (
   1136   )
   1137 {
   1138   UINTN Index;
   1139   UINT8 * pIpAddress;
   1140   EFI_STATUS Status;
   1141 
   1142   //
   1143   //  Use do/while and break instead of goto
   1144   //
   1145   do {
   1146     //
   1147     //  Locate the TCP protocol
   1148     //
   1149     Status = Tcp4Locate ( );
   1150     if ( EFI_ERROR ( Status )) {
   1151       break;
   1152     }
   1153 
   1154     //
   1155     //  Create the necessary events
   1156     //
   1157     Status = gBS->CreateEvent ( 0,
   1158                                 TPL_CALLBACK,
   1159                                 NULL,
   1160                                 NULL,
   1161                                 &Tcp4CloseToken.CompletionToken.Event );
   1162     if ( EFI_ERROR ( Status )) {
   1163       DEBUG (( DEBUG_ERROR,
   1164                 "ERROR - Failed to create the close event, Status: %r\r\n",
   1165                 Status ));
   1166       Tcp4CloseToken.CompletionToken.Event = NULL;
   1167       break;
   1168     }
   1169     DEBUG (( DEBUG_INFO,
   1170               "0x%08x: Close event open\r\n",
   1171               Tcp4CloseToken.CompletionToken.Event ));
   1172 
   1173     Status = gBS->CreateEvent ( 0,
   1174                                 TPL_CALLBACK,
   1175                                 NULL,
   1176                                 NULL,
   1177                                 &Tcp4ConnectToken.CompletionToken.Event );
   1178     if ( EFI_ERROR ( Status )) {
   1179       DEBUG (( DEBUG_ERROR,
   1180                 "ERROR - Failed to create the connect event, Status: %r\r\n",
   1181                 Status ));
   1182       Tcp4ConnectToken.CompletionToken.Event = NULL;
   1183       break;
   1184     }
   1185     DEBUG (( DEBUG_INFO,
   1186               "0x%08x: Connect event open\r\n",
   1187               Tcp4ConnectToken.CompletionToken.Event ));
   1188 
   1189     Status = gBS->CreateEvent ( 0,
   1190                                 TPL_CALLBACK,
   1191                                 NULL,
   1192                                 NULL,
   1193                                 &Tcp4ListenToken.CompletionToken.Event );
   1194     if ( EFI_ERROR ( Status )) {
   1195       DEBUG (( DEBUG_ERROR,
   1196                 "ERROR - Failed to create the listen event, Status: %r\r\n",
   1197                 Status ));
   1198       Tcp4ListenToken.CompletionToken.Event = NULL;
   1199       break;
   1200     }
   1201     DEBUG (( DEBUG_INFO,
   1202               "0x%08x: Listen event open\r\n",
   1203               Tcp4ListenToken.CompletionToken.Event ));
   1204 
   1205     Status = gBS->CreateEvent ( 0,
   1206                                 TPL_CALLBACK,
   1207                                 NULL,
   1208                                 NULL,
   1209                                 &Tcp4TxToken.CompletionToken.Event );
   1210     if ( EFI_ERROR ( Status )) {
   1211       DEBUG (( DEBUG_ERROR,
   1212                 "ERROR - Failed to create the TX event, Status: %r\r\n",
   1213                 Status ));
   1214       Tcp4TxToken.CompletionToken.Event = NULL;
   1215       break;
   1216     }
   1217     DEBUG (( DEBUG_INFO,
   1218               "0x%08x: TX event open\r\n",
   1219               Tcp4TxToken.CompletionToken.Event ));
   1220 
   1221     //
   1222     //  Configure the local TCP port
   1223     //
   1224     Tcp4ConfigData.TimeToLive = 255;
   1225     Tcp4ConfigData.TypeOfService = 0;
   1226     Tcp4ConfigData.ControlOption = NULL;
   1227     Tcp4ConfigData.AccessPoint.ActiveFlag = TRUE;
   1228     Tcp4ConfigData.AccessPoint.StationAddress.Addr[0] = 0;
   1229     Tcp4ConfigData.AccessPoint.StationAddress.Addr[1] = 0;
   1230     Tcp4ConfigData.AccessPoint.StationAddress.Addr[2] = 0;
   1231     Tcp4ConfigData.AccessPoint.StationAddress.Addr[3] = 0;
   1232     Tcp4ConfigData.AccessPoint.StationPort = 0;
   1233     Tcp4ConfigData.AccessPoint.RemoteAddress.Addr[0] = (UINT8)  ((struct sockaddr_in *)&RemoteHostAddress)->sin_addr.s_addr;
   1234     Tcp4ConfigData.AccessPoint.RemoteAddress.Addr[1] = (UINT8)( ((struct sockaddr_in *)&RemoteHostAddress)->sin_addr.s_addr >> 8 );
   1235     Tcp4ConfigData.AccessPoint.RemoteAddress.Addr[2] = (UINT8)( ((struct sockaddr_in *)&RemoteHostAddress)->sin_addr.s_addr >> 16 );
   1236     Tcp4ConfigData.AccessPoint.RemoteAddress.Addr[3] = (UINT8)( ((struct sockaddr_in *)&RemoteHostAddress)->sin_addr.s_addr >> 24 );
   1237     Tcp4ConfigData.AccessPoint.RemotePort = ntohs (((struct sockaddr_in *)&RemoteHostAddress)->sin_port);
   1238     Tcp4ConfigData.AccessPoint.UseDefaultAddress = TRUE;
   1239     Tcp4ConfigData.AccessPoint.SubnetMask.Addr[0] = 0;
   1240     Tcp4ConfigData.AccessPoint.SubnetMask.Addr[1] = 0;
   1241     Tcp4ConfigData.AccessPoint.SubnetMask.Addr[2] = 0;
   1242     Tcp4ConfigData.AccessPoint.SubnetMask.Addr[3] = 0;
   1243     Status = pTcp4Protocol->Configure ( pTcp4Protocol,
   1244                                         &Tcp4ConfigData );
   1245     if ( EFI_ERROR ( Status )) {
   1246       DEBUG (( DEBUG_ERROR,
   1247                 "ERROR - Failed to configure TCP port, Status: %r\r\n",
   1248                 Status ));
   1249       break;
   1250     }
   1251     DEBUG (( DEBUG_INFO,
   1252               "0x%08x: TCP4 port configured\r\n",
   1253               pTcp4Protocol ));
   1254 
   1255     //
   1256     //  Connect to the remote TCP port
   1257     //
   1258     Status = pTcp4Protocol->Connect ( pTcp4Protocol,
   1259                                       &Tcp4ConnectToken );
   1260     if ( EFI_ERROR ( Status )) {
   1261       DEBUG (( DEBUG_ERROR,
   1262                 "ERROR - Failed to start the connection to the remote system, Status: %r\r\n",
   1263                 Status ));
   1264       break;
   1265     }
   1266     Status = gBS->WaitForEvent ( 1,
   1267                                  &Tcp4ConnectToken.CompletionToken.Event,
   1268                                  &Index );
   1269     if ( EFI_ERROR ( Status )) {
   1270       DEBUG (( DEBUG_ERROR,
   1271                 "ERROR - Failed to wait for the connection, Status: %r\r\n",
   1272                 Status ));
   1273       break;
   1274     }
   1275     Status = Tcp4ConnectToken.CompletionToken.Status;
   1276     if ( EFI_ERROR ( Status )) {
   1277       DEBUG (( DEBUG_WARN,
   1278                 "WARNING - Failed to connect to the remote system, Status: %r\r\n",
   1279                 Status ));
   1280       break;
   1281     }
   1282     DEBUG (( DEBUG_INFO,
   1283               "0x%08x: TCP4 port connected\r\n",
   1284               pTcp4Protocol ));
   1285     bTcp4Connected = TRUE;
   1286 
   1287     //
   1288     //  Display the connection
   1289     //
   1290     pIpAddress = (UINT8 *)&((struct sockaddr_in *)&RemoteHostAddress)->sin_addr.s_addr;
   1291     Print ( L"Connected to %d.%d.%d.%d:%d\r\n",
   1292             pIpAddress[0],
   1293             pIpAddress[1],
   1294             pIpAddress[2],
   1295             pIpAddress[3],
   1296             ntohs ( ((struct sockaddr_in *)&RemoteHostAddress)->sin_port ));
   1297   } while ( 0 );
   1298 
   1299   if ( EFI_ERROR ( Status )) {
   1300     //
   1301     //  Try again
   1302     //
   1303     Status = EFI_SUCCESS;
   1304   }
   1305   else {
   1306     //
   1307     //  Semd data until the connection breaks
   1308     //
   1309     Status = Tcp4Send ( );
   1310   }
   1311 
   1312   //
   1313   //  Return the operation status
   1314   //
   1315   return Status;
   1316 }
   1317 
   1318 
   1319 /**
   1320   Handle the timer callback
   1321 
   1322   @param [in] Event     Event that caused this callback
   1323   @param [in] pContext  Context for this routine
   1324 **/
   1325 VOID
   1326 EFIAPI
   1327 TimerCallback (
   1328   IN EFI_EVENT Event,
   1329   IN VOID * pContext
   1330   )
   1331 {
   1332   UINT32 Average;
   1333   UINT64 BitsPerSecond;
   1334   UINT32 Index;
   1335   UINT64 TotalBytes;
   1336 
   1337   //
   1338   //  Notify the other code of the timer tick
   1339   //
   1340   bTick = TRUE;
   1341 
   1342   //
   1343   //  Update the average bytes per second
   1344   //
   1345   if ( 0 != TotalBytesSent ) {
   1346     BytesSent[ In ] = TotalBytesSent;
   1347     TotalBytesSent = 0;
   1348     In += 1;
   1349     if ( DATA_SAMPLES <= In ) {
   1350       In = 0;
   1351     }
   1352 
   1353     //
   1354     //  Separate the samples
   1355     //
   1356     if ( DATA_SAMPLES == Samples ) {
   1357       Print ( L"---------- Stable average ----------\r\n" );
   1358     }
   1359     Samples += 1;
   1360 
   1361     //
   1362     //  Compute the data rate
   1363     //
   1364     TotalBytes = 0;
   1365     for ( Index = 0; DATA_SAMPLES > Index; Index++ ) {
   1366       TotalBytes += BytesSent[ Index ];
   1367     }
   1368     Average = (UINT32)RShiftU64 ( TotalBytes, DATA_SAMPLE_SHIFT );
   1369     BitsPerSecond = Average * 8;
   1370 
   1371     //
   1372     //  Display the data rate
   1373     //
   1374     if (( RANGE_SWITCH >> 10 ) > Average ) {
   1375       Print ( L"Ave: %d Bytes/Sec, %Ld Bits/sec\r\n",
   1376               Average,
   1377               BitsPerSecond );
   1378     }
   1379     else {
   1380       BitsPerSecond /= 1000;
   1381       if ( RANGE_SWITCH > Average ) {
   1382         Print ( L"Ave: %d.%03d KiBytes/Sec, %Ld KBits/sec\r\n",
   1383                 Average >> 10,
   1384                 (( Average & 0x3ff ) * 1000 ) >> 10,
   1385                 BitsPerSecond );
   1386       }
   1387       else {
   1388         BitsPerSecond /= 1000;
   1389         Average >>= 10;
   1390         if ( RANGE_SWITCH > Average ) {
   1391           Print ( L"Ave: %d.%03d MiBytes/Sec, %Ld MBits/sec\r\n",
   1392                   Average >> 10,
   1393                   (( Average & 0x3ff ) * 1000 ) >> 10,
   1394                   BitsPerSecond );
   1395         }
   1396         else {
   1397           BitsPerSecond /= 1000;
   1398           Average >>= 10;
   1399           if ( RANGE_SWITCH > Average ) {
   1400             Print ( L"Ave: %d.%03d GiBytes/Sec, %Ld GBits/sec\r\n",
   1401                     Average >> 10,
   1402                     (( Average & 0x3ff ) * 1000 ) >> 10,
   1403                     BitsPerSecond );
   1404           }
   1405           else {
   1406             BitsPerSecond /= 1000;
   1407             Average >>= 10;
   1408             if ( RANGE_SWITCH > Average ) {
   1409               Print ( L"Ave: %d.%03d TiBytes/Sec, %Ld TBits/sec\r\n",
   1410                       Average >> 10,
   1411                       (( Average & 0x3ff ) * 1000 ) >> 10,
   1412                       BitsPerSecond );
   1413             }
   1414             else {
   1415               BitsPerSecond /= 1000;
   1416               Average >>= 10;
   1417               Print ( L"Ave: %d.%03d PiBytes/Sec, %Ld PBits/sec\r\n",
   1418                       Average >> 10,
   1419                       (( Average & 0x3ff ) * 1000 ) >> 10,
   1420                       BitsPerSecond );
   1421             }
   1422           }
   1423         }
   1424       }
   1425     }
   1426   }
   1427 }
   1428 
   1429 
   1430 /**
   1431   Create the timer
   1432 
   1433   @retval  EFI_SUCCESS  The timer was successfully created
   1434   @retval  Other        Timer initialization failed
   1435 **/
   1436 EFI_STATUS
   1437 TimerCreate (
   1438   )
   1439 {
   1440   EFI_STATUS Status;
   1441 
   1442   //
   1443   //  Create the timer
   1444   //
   1445   Status = gBS->CreateEvent ( EVT_TIMER | EVT_NOTIFY_SIGNAL,
   1446                               TPL_DATASOURCE,
   1447                               TimerCallback,
   1448                               NULL,
   1449                               &pTimer );
   1450   if ( EFI_ERROR ( Status )) {
   1451     DEBUG (( DEBUG_ERROR,
   1452               "ERROR - Failed to allocate the timer event, Status: %r\r\n",
   1453               Status ));
   1454   }
   1455   else {
   1456     DEBUG (( DEBUG_INFO,
   1457               "0x%08x: Timer created\r\n",
   1458               pTimer ));
   1459   }
   1460 
   1461   //
   1462   //  Return the operation status
   1463   //
   1464   return Status;
   1465 }
   1466 
   1467 
   1468 /**
   1469   Stop the timer
   1470 
   1471   @retval  EFI_SUCCESS  The timer was stopped successfully
   1472   @retval  Other        The timer failed to stop
   1473 **/
   1474 EFI_STATUS
   1475 TimerStop (
   1476   )
   1477 {
   1478   EFI_STATUS Status;
   1479 
   1480   //
   1481   //  Assume success
   1482   //
   1483   Status = EFI_SUCCESS;
   1484 
   1485   //
   1486   //  Determine if the timer is running
   1487   //
   1488   if ( bTimerRunning ) {
   1489     //
   1490     //  Stop the timer
   1491     //
   1492     Status = gBS->SetTimer ( pTimer,
   1493                              TimerCancel,
   1494                              0 );
   1495     if ( EFI_ERROR ( Status )) {
   1496       DEBUG (( DEBUG_ERROR,
   1497                 "ERROR - Failed to stop the timer, Status: %r\r\n",
   1498                 Status ));
   1499     }
   1500     else {
   1501       //
   1502       //  Timer timer is now stopped
   1503       //
   1504       bTimerRunning = FALSE;
   1505       DEBUG (( DEBUG_INFO,
   1506                 "0x%08x: Timer stopped\r\n",
   1507                 pTimer ));
   1508     }
   1509   }
   1510 
   1511   //
   1512   //  Return the operation status
   1513   //
   1514   return Status;
   1515 }
   1516 
   1517 
   1518 /**
   1519   Start the timer
   1520 
   1521   @param [in] Milliseconds  The number of milliseconds between timer callbacks
   1522 
   1523   @retval  EFI_SUCCESS  The timer was successfully created
   1524   @retval  Other        Timer initialization failed
   1525 **/
   1526 EFI_STATUS
   1527 TimerStart (
   1528   UINTN Milliseconds
   1529   )
   1530 {
   1531   EFI_STATUS Status;
   1532   UINT64 TimeDelay;
   1533 
   1534   //
   1535   //  Stop the timer if necessary
   1536   //
   1537   Status = EFI_SUCCESS;
   1538   if ( bTimerRunning ) {
   1539     Status = TimerStop ( );
   1540   }
   1541   if ( !EFI_ERROR ( Status )) {
   1542     //
   1543     //  Compute the new delay
   1544     //
   1545     TimeDelay = Milliseconds;
   1546     TimeDelay *= 1000 * 10;
   1547 
   1548     //
   1549     //  Start the timer
   1550     //
   1551     Status = gBS->SetTimer ( pTimer,
   1552                              TimerPeriodic,
   1553                              TimeDelay );
   1554     if ( EFI_ERROR ( Status )) {
   1555       DEBUG (( DEBUG_ERROR,
   1556                 "ERROR - Failed to start the timer, Status: %r\r\n",
   1557                 Status ));
   1558     }
   1559     else {
   1560       //
   1561       //  The timer is now running
   1562       //
   1563       bTimerRunning = TRUE;
   1564       DEBUG (( DEBUG_INFO,
   1565         "0x%08x: Timer running\r\n",
   1566         pTimer ));
   1567     }
   1568   }
   1569 
   1570   //
   1571   //  Return the operation status
   1572   //
   1573   return Status;
   1574 }
   1575 
   1576 
   1577 /**
   1578   Destroy the timer
   1579 
   1580   @retval  EFI_SUCCESS  The timer was destroyed successfully
   1581   @retval  Other        Failed to destroy the timer
   1582 **/
   1583 EFI_STATUS
   1584 TimerDestroy (
   1585   )
   1586 {
   1587   EFI_STATUS Status;
   1588 
   1589   //
   1590   //  Assume success
   1591   //
   1592   Status = EFI_SUCCESS;
   1593 
   1594   //
   1595   //  Determine if the timer is running
   1596   //
   1597   if ( bTimerRunning ) {
   1598     //
   1599     //  Stop the timer
   1600     //
   1601     Status = TimerStop ( );
   1602   }
   1603   if (( !EFI_ERROR ( Status )) && ( NULL != pTimer )) {
   1604     //
   1605     //  Done with this timer
   1606     //
   1607     Status = gBS->CloseEvent ( pTimer );
   1608     if ( EFI_ERROR ( Status )) {
   1609       DEBUG (( DEBUG_ERROR,
   1610                 "ERROR - Failed to free the timer event, Status: %r\r\n",
   1611                 Status ));
   1612     }
   1613     else {
   1614       DEBUG (( DEBUG_INFO,
   1615                 "0x%08x: Timer Destroyed\r\n",
   1616                 pTimer ));
   1617       pTimer = NULL;
   1618     }
   1619   }
   1620 
   1621   //
   1622   //  Return the operation status
   1623   //
   1624   return Status;
   1625 }
   1626 
   1627 
   1628 /**
   1629   Send data to the DataSink program to test a network's bandwidth.
   1630 
   1631   @param [in] Argc  The number of arguments
   1632   @param [in] Argv  The argument value array
   1633 
   1634   @retval  0        The application exited normally.
   1635   @retval  Other    An error occurred.
   1636 **/
   1637 int
   1638 main (
   1639   IN int Argc,
   1640   IN char **Argv
   1641   )
   1642 {
   1643   EFI_STATUS (* pClose) ();
   1644   EFI_STATUS (* pOpen) ();
   1645   EFI_STATUS Status;
   1646 
   1647   DEBUG (( DEBUG_INFO,
   1648             "DataSource starting\r\n" ));
   1649 
   1650   //
   1651   //  Validate the command line
   1652   //
   1653   if ( 2 > Argc ) {
   1654     Print ( L"%s  <remote IP address> [Use TCP]\r\n", Argv[0] );
   1655     return -1;
   1656   }
   1657 
   1658   //
   1659   //  Determine if TCP should be used
   1660   //
   1661   bTcp4 = (BOOLEAN)( 2 < Argc );
   1662 
   1663   //
   1664   //  Determine the support routines
   1665   //
   1666   if ( bTcp4 ) {
   1667     pOpen = Tcp4Open;
   1668     pClose = Tcp4Close;
   1669     bTcp4Connecting = TRUE;
   1670   }
   1671   else {
   1672     pOpen = SocketOpen;
   1673     pClose = SocketClose;
   1674   }
   1675 
   1676   //
   1677   //  Use for/break instead of goto
   1678   //
   1679   for ( ; ; ) {
   1680     //
   1681     //  No bytes sent so far
   1682     //
   1683     TotalBytesSent = 0;
   1684     Samples = 0;
   1685     memset ( &BytesSent, 0, sizeof ( BytesSent ));
   1686 
   1687     //
   1688     //  Get the IP address
   1689     //
   1690     pRemoteHost = Argv[1];
   1691     Status = IpAddress ( );
   1692     if ( EFI_ERROR ( Status )) {
   1693       break;
   1694     }
   1695 
   1696     //
   1697     //  Create the timer
   1698     //
   1699     bTick = TRUE;
   1700     Status = TimerCreate ( );
   1701     if ( EFI_ERROR ( Status )) {
   1702       break;
   1703     }
   1704 
   1705     //
   1706     //  Loop forever abusing the specified system
   1707     //
   1708     do {
   1709       //
   1710       //  Start a timer to perform connection polling and display updates
   1711       //
   1712       Status = TimerStart ( 2 * 1000 );
   1713       if ( EFI_ERROR ( Status )) {
   1714         break;
   1715       }
   1716 
   1717       //
   1718       //  Open the network connection and send the data
   1719       //
   1720       Status = pOpen ( );
   1721       if ( EFI_ERROR ( Status )) {
   1722         break;
   1723       }
   1724 
   1725       //
   1726       //  Done with the network connection
   1727       //
   1728       Status = pClose ( );
   1729     } while ( !EFI_ERROR ( Status ));
   1730 
   1731     //
   1732     //  Close the network connection if necessary
   1733     //
   1734     pClose ( );
   1735 
   1736     //
   1737     //  All done
   1738     //
   1739     break;
   1740   }
   1741 
   1742   //
   1743   //  Stop the timer if necessary
   1744   //
   1745   TimerStop ( );
   1746   TimerDestroy ( );
   1747 
   1748   //
   1749   //  Return the operation status
   1750   //
   1751   DEBUG (( DEBUG_INFO,
   1752             "DataSource exiting, Status: %r\r\n",
   1753             Status ));
   1754   return Status;
   1755 }
   1756