mirror of https://github.com/acidanthera/audk.git
1751 lines
45 KiB
C
1751 lines
45 KiB
C
/** @file
|
|
Data source for network testing.
|
|
|
|
Copyright (c) 2011, 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,
|
|
htons ( 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 ],
|
|
htons ( 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,
|
|
htons ( 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 ],
|
|
htons ( pRemoteAddress6->sin6_port ));
|
|
}
|
|
}
|
|
else {
|
|
//
|
|
// Close the socket and try again
|
|
//
|
|
if ( EAGAIN != errno ) {
|
|
Status = EFI_NOT_STARTED;
|
|
break;
|
|
}
|
|
}
|
|
} while ( -1 == ConnectStatus );
|
|
|
|
//
|
|
// Return the operation 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 ));
|
|
|
|
//
|
|
// 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 ( );
|
|
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
|
|
//
|
|
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],
|
|
htons ( ((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],
|
|
htons ( ((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 = ((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],
|
|
htons ( ((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;
|
|
}
|