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