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
ControlCCheck()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 *
GetDigit(CHAR8 * pDigit,UINT32 * pValue)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
IpAddress()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
SocketClose()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
SocketConnect()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
SocketNew(sa_family_t Family)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
SocketSend()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
SocketOpen()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
Tcp4Close()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
Tcp4Locate()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
Tcp4Send()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
Tcp4Open()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
TimerCallback(IN EFI_EVENT Event,IN VOID * pContext)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
TimerCreate()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
TimerStop()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
TimerStart(UINTN Milliseconds)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
TimerDestroy()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
main(IN int Argc,IN char ** Argv)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