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//
52int Socket = -1;
53
54//
55//  TCP V4 Data
56//
57BOOLEAN bTcp4;                      ///<  TRUE if TCP4 is being used
58BOOLEAN bTcp4Connected;             ///<  TRUE if connected to remote system
59BOOLEAN bTcp4Connecting;            ///<  TRUE while connection in progress
60UINTN Tcp4Index;                    ///<  Index into handle array
61EFI_HANDLE Tcp4Controller;          ///<  Network controller handle
62EFI_HANDLE Tcp4Handle;              ///<  TCP4 port handle
63EFI_TCP4_PROTOCOL * pTcp4Protocol;  ///<  TCP4 protocol pointer
64EFI_SERVICE_BINDING_PROTOCOL * pTcp4Service;  ///<  TCP4 Service binding
65EFI_TCP4_CONFIG_DATA Tcp4ConfigData;///<  TCP4 configuration data
66EFI_TCP4_OPTION Tcp4Option;         ///<  TCP4 port options
67EFI_TCP4_CLOSE_TOKEN Tcp4CloseToken;///<  Close control
68EFI_TCP4_CONNECTION_TOKEN Tcp4ConnectToken; ///<  Connection control
69EFI_TCP4_LISTEN_TOKEN Tcp4ListenToken;      ///<  Listen control
70EFI_TCP4_IO_TOKEN Tcp4TxToken;      ///<  Normal data token
71
72//
73//  Timer Data
74//
75volatile BOOLEAN bTick;
76BOOLEAN bTimerRunning;
77EFI_EVENT pTimer;
78
79//
80//  Remote IP Address Data
81//
82struct sockaddr_in6 RemoteHostAddress;
83CHAR8 * pRemoteHost;
84
85//
86//  Traffic Data
87//
88UINT64 TotalBytesSent;
89UINT32 In;
90UINT32 Samples;
91UINT64 BytesSent[ DATA_SAMPLES ];
92UINT8 Buffer[ DATA_BUFFER_SIZE ];
93
94
95//
96//  Forward routine declarations
97//
98EFI_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**/
107EFI_STATUS
108ControlCCheck (
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**/
142CHAR8 *
143GetDigit (
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**/
189EFI_STATUS
190IpAddress (
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**/
326EFI_STATUS
327SocketClose (
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**/
369EFI_STATUS
370SocketConnect (
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      }
466Print ( 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  //
482Print ( 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**/
495EFI_STATUS
496SocketNew (
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**/
543EFI_STATUS
544SocketSend (
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 ));
576Print ( 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//
586Status = 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**/
620EFI_STATUS
621SocketOpen (
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 ( );
642Print ( 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  //
666Print ( 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**/
677EFI_STATUS
678Tcp4Close (
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**/
878EFI_STATUS
879Tcp4Locate (
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**/
1011EFI_STATUS
1012Tcp4Send (
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//
1100Status = 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**/
1134EFI_STATUS
1135Tcp4Open (
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**/
1325VOID
1326EFIAPI
1327TimerCallback (
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**/
1436EFI_STATUS
1437TimerCreate (
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**/
1474EFI_STATUS
1475TimerStop (
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**/
1526EFI_STATUS
1527TimerStart (
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**/
1583EFI_STATUS
1584TimerDestroy (
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**/
1637int
1638main (
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