/** @file Data source for network testing. Copyright (c) 2011-2012, Intel Corporation. All rights reserved. SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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 [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; }