/** @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; | |
} |