diff --git a/CMakeLists.txt b/CMakeLists.txt index f774427b..50e77090 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,7 +54,13 @@ get_directory_property(SEVICES_DEFINES COMPILE_DEFINITIONS) option(ENABLE_LEGACY_PLUGINS "Enable Legacy Plugins" ON) option(USE_RDK_LOGGER "Enable RDK Logger for logging" OFF ) option(ENABLE_UNIT_TESTING "Enable unit tests" OFF) +option(USE_TELEMETRY "Enable Telemetry T2 support" OFF) +if (USE_TELEMETRY) + find_package(T2 REQUIRED) + add_compile_definitions(USE_TELEMETRY=1) + message("Telemetry support enabled") +endif(USE_TELEMETRY) add_subdirectory(interface) add_subdirectory(definition) @@ -70,4 +76,3 @@ if(ENABLE_UNIT_TESTING) add_subdirectory(tests/l1Test) add_subdirectory(tests/l2Test) endif(ENABLE_UNIT_TESTING) - diff --git a/plugin/CMakeLists.txt b/plugin/CMakeLists.txt index abfd9998..11904b9d 100644 --- a/plugin/CMakeLists.txt +++ b/plugin/CMakeLists.txt @@ -33,7 +33,9 @@ if (USE_RDK_LOGGER) include_directories(${RDKLOGGER_INCLUDE_DIRS}) endif (USE_RDK_LOGGER) - +if (USE_TELEMETRY) + include_directories(${T2_INCLUDE_DIRS}) +endif (USE_TELEMETRY) if(ENABLE_GNOME_NETWORKMANAGER) pkg_check_modules(GLIB REQUIRED glib-2.0) @@ -141,6 +143,11 @@ if (USE_RDK_LOGGER) target_link_libraries(${MODULE_IMPL_NAME} PRIVATE ${RDKLOGGER_LIBRARIES}) endif (USE_RDK_LOGGER) +if (USE_TELEMETRY) + target_link_libraries(${MODULE_NAME} PRIVATE ${T2_LIBRARIES}) + target_link_libraries(${MODULE_IMPL_NAME} PRIVATE ${T2_LIBRARIES}) +endif (USE_TELEMETRY) + install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/${STORAGE_DIRECTORY}/plugins) install(TARGETS ${MODULE_IMPL_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/${STORAGE_DIRECTORY}/plugins) diff --git a/plugin/NetworkManagerImplementation.cpp b/plugin/NetworkManagerImplementation.cpp index cd616c54..58374840 100644 --- a/plugin/NetworkManagerImplementation.cpp +++ b/plugin/NetworkManagerImplementation.cpp @@ -20,6 +20,12 @@ #include #include #include "NetworkManagerImplementation.h" + +#if USE_TELEMETRY +#include "NetworkManagerJsonEnum.h" +#include +#endif + using namespace WPEFramework; using namespace WPEFramework::Plugin; using namespace NetworkManagerLogger; @@ -56,6 +62,10 @@ namespace WPEFramework NetworkManagerLogger::Init(); NMLOG_INFO((_T("NWMgrPlugin Out-Of-Process Instantiation; SHA: " _T(EXPAND_AND_QUOTE(PLUGIN_BUILD_REFERENCE))))); m_processMonThread = std::thread(&NetworkManagerImplementation::processMonitor, this, NM_PROCESS_MONITOR_INTERVAL_SEC); + #if USE_TELEMETRY + // Initialize Telemetry T2 for NwMgrPlugin + t2_init("NwMgrPlugin"); + #endif } NetworkManagerImplementation::~NetworkManagerImplementation() @@ -357,6 +367,13 @@ namespace WPEFramework interface = m_defaultInterface; ipaddress = result.public_ip; +#if USE_TELEMETRY + if(ipversion == "IPv4") + { + NMLOG_INFO("NM_PUBLIC_IPV4 = %s", ipaddress.c_str()); + logTelemetry("NM_PUBLIC_IPV4", ipaddress); + } +#endif return Core::ERROR_NONE; } else @@ -710,6 +727,10 @@ namespace WPEFramework for (const auto callback : _notificationCallbacks) { callback->onActiveInterfaceChange(prevActiveInterface, currentActiveinterface); } +#if USE_TELEMETRY + NMLOG_INFO("NM_INTERFACE_STATUS = Active Interface changed"); + logTelemetry("NM_INTERFACE_STATUS", "Interface changed to " + currentActiveinterface); +#endif _notificationLock.Unlock(); } @@ -756,9 +777,24 @@ namespace WPEFramework { _notificationLock.Lock(); NMLOG_INFO("Posting onInternetStatusChange with current state as %u", (unsigned)currState); +#if USE_TELEMETRY + // Log error only when ethernet is down and there's no internet + if(currState == Exchange::INetworkManager::INTERNET_NOT_AVAILABLE && + !m_ethConnected.load() && + prevState != Exchange::INetworkManager::INTERNET_NOT_AVAILABLE) + { + NMLOG_INFO("NM_ETHERNET_FAILED = Ethernet is down, no internet"); + logTelemetry("NM_ETHERNET_FAILED", "Ethernet is down, no internet"); + } +#endif for (const auto callback : _notificationCallbacks) { callback->onInternetStatusChange(prevState, currState, interface); } +#if USE_TELEMETRY + string stateStr = Core::EnumerateType(currState).Data(); + NMLOG_INFO("NM_INTERNET_STATUS = %s", stateStr.c_str()); + logTelemetry("NM_INTERNET_STATUS", stateStr); +#endif _notificationLock.Unlock(); } @@ -1107,6 +1143,14 @@ namespace WPEFramework _notificationLock.Lock(); NMLOG_INFO("Posting onWiFiStateChange (%d)", state); +#if USE_TELEMETRY + string stateStr = Core::EnumerateType(state).Data(); + if(INetworkManager::WiFiState::WIFI_STATE_CONNECTED == state) + NMLOG_INFO("NM_WIFI_STATUS = %s", stateStr.c_str()); + else if(INetworkManager::WiFiState::WIFI_STATE_DISCONNECTED == state) + NMLOG_INFO("NM_WIFI_STATUS = %s", stateStr.c_str()); + logTelemetry("NM_WIFI_STATUS", stateStr); +#endif for (const auto callback : _notificationCallbacks) { callback->onWiFiStateChange(state); } @@ -1122,5 +1166,16 @@ namespace WPEFramework } _notificationLock.Unlock(); } + + void NetworkManagerImplementation::logTelemetry(const std::string& eventName, const std::string& message) + { +#if USE_TELEMETRY + T2ERROR t2error = t2_event_s(eventName.c_str(), const_cast(message.c_str())); + if (t2error != T2ERROR_SUCCESS) { + NMLOG_ERROR("t2_event_s(\"%s\", \"%s\") failed with error %d", + eventName.c_str(), message.c_str(), t2error); + } +#endif + } } } diff --git a/plugin/NetworkManagerImplementation.h b/plugin/NetworkManagerImplementation.h index 565d7ee9..3ccc8ae0 100644 --- a/plugin/NetworkManagerImplementation.h +++ b/plugin/NetworkManagerImplementation.h @@ -269,6 +269,7 @@ namespace WPEFramework void ReportAvailableSSIDs(const JsonArray &arrayofWiFiScanResults); void ReportWiFiStateChange(const Exchange::INetworkManager::WiFiState state); void ReportWiFiSignalQualityChange(const string ssid, const int strength, const int noise, const int snr, const Exchange::INetworkManager::WiFiSignalQuality quality); + void logTelemetry(const std::string& eventName, const std::string& message); private: void platform_init(void); diff --git a/plugin/gnome/NetworkManagerGnomeEvents.cpp b/plugin/gnome/NetworkManagerGnomeEvents.cpp index 90f9b03f..56174cb5 100644 --- a/plugin/gnome/NetworkManagerGnomeEvents.cpp +++ b/plugin/gnome/NetworkManagerGnomeEvents.cpp @@ -271,8 +271,35 @@ namespace WPEFramework } if (nm_ip_address_get_family(address) == AF_INET) { const char *ipAddress = nm_ip_address_get_address(address); - if(ipAddress != NULL) + if(ipAddress != NULL) { GnomeNetworkManagerEvents::onAddressChangeCb(iface, ipAddress, true, false); + // Get gateway MAC address for WiFi and Ethernet after IP is acquired + if(ifname == nmUtils::wlanIface() || ifname == nmUtils::ethIface()) { + static std::map gatewayMacCache; + NMClient *client = nm_object_get_client(NM_OBJECT(device)); + if (client != NULL) { + std::string gatewayMac = nmUtils::getGatewayMacAddress(client, ifname); + if (!gatewayMac.empty()) { + // Only log when MAC changes or is first time + if (gatewayMacCache[ifname] != gatewayMac) { + gatewayMacCache[ifname] = gatewayMac; +#if USE_TELEMETRY + if(ifname == nmUtils::wlanIface() + { + NMLOG_INFO("NM_WIFI_GW_MAC = %s", gatewayMac.c_str()); + _instance->logTelemetry("NM_WIFI_GW_MAC", gatewayMac); + } + else if(ifname == nmUtils::ethIface()) + { + NMLOG_INFO("NM_ETHERNET_GW_MAC = %s", gatewayMac.c_str()); + _instance->logTelemetry("NM_ETHERNET_GW_MAC", gatewayMac); + } +#endif + } + } + } + } + } } } } diff --git a/plugin/gnome/NetworkManagerGnomeUtils.cpp b/plugin/gnome/NetworkManagerGnomeUtils.cpp index d175b27a..394fedbb 100644 --- a/plugin/gnome/NetworkManagerGnomeUtils.cpp +++ b/plugin/gnome/NetworkManagerGnomeUtils.cpp @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include #include #include "Module.h" @@ -389,5 +391,100 @@ namespace WPEFramework return false; } + std::string nmUtils::resolveGatewayMac(const std::string& gatewayIp) + { + std::string mac = ""; + std::string arpFile = "/proc/net/arp"; + std::ifstream file(arpFile); + std::string line; + + if (!file.is_open()) { + NMLOG_ERROR("Failed to open %s", arpFile.c_str()); + return mac; + } + + // Skip header + std::getline(file, line); + + while (std::getline(file, line)) { + std::istringstream iss(line); + std::string ip, hwType, flags, hwAddr; + + if (iss >> ip >> hwType >> flags >> hwAddr) { + if (ip == gatewayIp && hwAddr != "00:00:00:00:00:00") { + mac = hwAddr; + NMLOG_INFO("Resolved gateway IP %s to MAC %s", gatewayIp.c_str(), mac.c_str()); + break; + } + } + } + + if (mac.empty()) { + NMLOG_WARNING("Could not resolve gateway IP %s to MAC address", gatewayIp.c_str()); + } + + return mac; + } + + std::string nmUtils::getGatewayMacAddress(NMClient* client, const std::string& interface) + { + std::string gatewayMac = ""; + + if (client == NULL) { + NMLOG_ERROR("NMClient is NULL"); + return gatewayMac; + } + + if (interface.empty()) { + NMLOG_ERROR("Interface name is empty"); + return gatewayMac; + } + + // Get all active connections and find the one for our interface + const GPtrArray *activeConnections = nm_client_get_active_connections(client); + if (!activeConnections) { + NMLOG_WARNING("No active connections found"); + return gatewayMac; + } + + for (guint i = 0; i < activeConnections->len; i++) { + NMActiveConnection *activeConn = NM_ACTIVE_CONNECTION(g_ptr_array_index(activeConnections, i)); + if (!activeConn) continue; + + // Get devices for this connection + const GPtrArray *devices = nm_active_connection_get_devices(activeConn); + if (!devices) continue; + + // Check if this connection belongs to our interface + for (guint j = 0; j < devices->len; j++) { + NMDevice *device = NM_DEVICE(g_ptr_array_index(devices, j)); + if (!device) continue; + + const char *ifname = nm_device_get_iface(device); + if (ifname && interface == ifname) { + // Found the connection for our interface + NMIPConfig *ip4Config = nm_active_connection_get_ip4_config(activeConn); + if (ip4Config) { + const char *gateway = nm_ip_config_get_gateway(ip4Config); + if (gateway) { + NMLOG_DEBUG("Found gateway IP for %s: %s", interface.c_str(), gateway); + // Use ARP to resolve gateway IP to MAC address + gatewayMac = resolveGatewayMac(gateway); + return gatewayMac; + } else { + NMLOG_WARNING("No gateway found for %s", interface.c_str()); + } + } else { + NMLOG_WARNING("No IPv4 configuration found for %s", interface.c_str()); + } + return gatewayMac; + } + } + } + + NMLOG_WARNING("No active connection found for interface %s", interface.c_str()); + return gatewayMac; + } + } // Plugin } // WPEFramework diff --git a/plugin/gnome/NetworkManagerGnomeUtils.h b/plugin/gnome/NetworkManagerGnomeUtils.h index b9632d2e..dbfb24b1 100644 --- a/plugin/gnome/NetworkManagerGnomeUtils.h +++ b/plugin/gnome/NetworkManagerGnomeUtils.h @@ -50,6 +50,8 @@ namespace WPEFramework static bool isInterfaceEnabled(const std::string& interface); static bool writePersistentHostname(const std::string& hostname); static bool readPersistentHostname(std::string& hostname); + static std::string resolveGatewayMac(const std::string& gatewayIp); + static std::string getGatewayMacAddress(NMClient* client, const std::string& interface); }; } } diff --git a/plugin/gnome/NetworkManagerGnomeWIFI.cpp b/plugin/gnome/NetworkManagerGnomeWIFI.cpp index b6583482..5dd09070 100644 --- a/plugin/gnome/NetworkManagerGnomeWIFI.cpp +++ b/plugin/gnome/NetworkManagerGnomeWIFI.cpp @@ -945,7 +945,6 @@ namespace WPEFramework std::string activeSSID{}; NMLOG_DEBUG("wifi connect ssid: %s, security %d persist %d", ssidInfoParam.ssid.c_str(), ssidInfoParam.security, ssidInfoParam.persist); - Exchange::INetworkManager::WiFiConnectTo ssidInfo = ssidInfoParam; m_isSuccess = false; if(!createClientNewConnection()) diff --git a/tools/plugincli/CMakeLists.txt b/tools/plugincli/CMakeLists.txt index e1f5fd62..56883676 100644 --- a/tools/plugincli/CMakeLists.txt +++ b/tools/plugincli/CMakeLists.txt @@ -85,7 +85,7 @@ if(ENABLE_GNOME_GDBUS) target_compile_options(${PLUGIN_GDBUS_CLI} PRIVATE ${COMMON_COMPILE_OPTIONS}) target_include_directories(${PLUGIN_GDBUS_CLI} PRIVATE ${COMMON_INCLUDES}) - target_link_libraries(${PLUGIN_GDBUS_CLI} PRIVATE ${COMMON_LIBS} uuid) + target_link_libraries(${PLUGIN_GDBUS_CLI} PRIVATE ${COMMON_LIBS} ${LIBNM_LIBRARIES} uuid) install(TARGETS ${PLUGIN_GDBUS_CLI} DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) diff --git a/tools/upnp/CMakeLists.txt b/tools/upnp/CMakeLists.txt index 1cfa40e8..788f0540 100644 --- a/tools/upnp/CMakeLists.txt +++ b/tools/upnp/CMakeLists.txt @@ -34,9 +34,7 @@ if (NOT GUPNP_FOUND) endif () if (USE_TELEMETRY) - find_package(T2 REQUIRED) - add_definitions(-DUSE_TELEMETRY) - include_directories(${TELEMETRY_INCLUDE_DIRS}) + include_directories(${T2_INCLUDE_DIRS}) endif (USE_TELEMETRY) add_definitions(-DENABLE_ROUTER_DISCOVERY_MAIN)