From 9922f122fb500ae2b0dbdbde8bdec8755d3afdb7 Mon Sep 17 00:00:00 2001 From: gururaajar <83449026+gururaajar@users.noreply.github.com> Date: Tue, 21 Apr 2026 13:16:05 -0400 Subject: [PATCH 1/2] RDKEMW-16150: Let's get connected" displayed during Migration testing (#296) * RDKEMW-16150: Let's get connected" displayed during Migration testing Reason for Change: Deleting all the connections only in case of BOOT_MIGRATION so that networkmanager connecting to the eth0 connection can be avoided and we can create new "Wired Connection 1" to connect. Test Procedure: Migration Scenario Priority: P1 Risks: Medium Signed-off-by: Gururaaja ESR * RDKEMW-16150: Let's get connected" displayed during Migration testing Reason for Change: Deleting all the connections only in case of BOOT_MIGRATION so that networkmanager connecting to the eth0 connection can be avoided and we can create new "Wired Connection 1" to connect. Test Procedure: Migration Scenario Priority: P1 Risks: Medium Signed-off-by: Gururaaja ESR --------- Signed-off-by: Gururaaja ESR --- plugin/gnome/NetworkManagerGnomeProxy.cpp | 131 +++++++++++++++++++--- plugin/gnome/NetworkManagerGnomeWIFI.cpp | 60 ++++++++++ plugin/gnome/NetworkManagerGnomeWIFI.h | 1 + 3 files changed, 174 insertions(+), 18 deletions(-) diff --git a/plugin/gnome/NetworkManagerGnomeProxy.cpp b/plugin/gnome/NetworkManagerGnomeProxy.cpp index 85326d63..52cfb914 100644 --- a/plugin/gnome/NetworkManagerGnomeProxy.cpp +++ b/plugin/gnome/NetworkManagerGnomeProxy.cpp @@ -423,6 +423,7 @@ namespace WPEFramework return rc; } #endif + uint32_t NetworkManagerImplementation::SetInterfaceState(const string& interface/* @in */, const bool enabled /* @in */) { @@ -438,33 +439,127 @@ namespace WPEFramework return Core::ERROR_GENERAL; } - if(!wifi->setInterfaceState(interface, enabled)) + // For ethernet enable: run BOOT_MIGRATION cleanup first, then setInterfaceState + if(enabled && interface == nmUtils::ethIface()) { - NMLOG_ERROR("interface state change failed"); - return Core::ERROR_GENERAL; - } + // Check boot type and delete all ethernet NM connections if BOOT_MIGRATION + { + const char* bootFile = "/tmp/bootType"; + std::ifstream file(bootFile); - NMLOG_INFO("interface %s state: %s", interface.c_str(), enabled ? "enabled" : "disabled"); - // update the interface global cache state - if(interface == nmUtils::wlanIface() && _instance != NULL) - _instance->m_wlanEnabled.store(enabled); - else if(interface == nmUtils::ethIface() && _instance != NULL) - _instance->m_ethEnabled.store(enabled); + if(file.is_open()) + { + std::string line, bootTypeValue; + while(std::getline(file, line)) + { + const std::string key = "BOOT_TYPE="; + auto pos = line.find(key); + if(pos != std::string::npos) + { + bootTypeValue = line.substr(pos + key.size()); + break; + } + } + + if(bootTypeValue == "BOOT_MIGRATION") + { + NMLOG_INFO("BOOT_MIGRATION detected, deleting all wired NM connections"); + + // Bring down the ethernet interface before wiping its connections + // so NM doesn't immediately re-activate them during deletion. + NMDevice *ethDev = nm_client_get_device_by_iface(client, interface.c_str()); + if(ethDev) + { + GError *discError = nullptr; + if(!nm_device_disconnect(ethDev, nullptr, &discError)) + { + NMLOG_WARNING("Failed to disconnect %s before migration cleanup: %s", + interface.c_str(), + discError ? discError->message : "unknown error"); + if(discError) g_error_free(discError); + } + } + + const GPtrArray *connections = nm_client_get_connections(client); + if(connections && connections->len > 0) + { + /* Snapshot the list before iterating: nm_client_get_connections() + * returns an internal array that can be mutated as connections + * are removed, so we must not iterate it while deleting. */ + GPtrArray *snapshot = g_ptr_array_new_full(connections->len, g_object_unref); + for(guint i = 0; i < connections->len; ++i) + { + NMRemoteConnection *conn = NM_REMOTE_CONNECTION(connections->pdata[i]); + if(!conn) continue; + NMSettingConnection *sCon = nm_connection_get_setting_connection(NM_CONNECTION(conn)); + if(!sCon) continue; + const char *connType = nm_setting_connection_get_connection_type(sCon); + if(g_strcmp0(connType, NM_SETTING_WIRED_SETTING_NAME) != 0) + { + NMLOG_DEBUG("Skipping non-wired connection type: %s", connType ? connType : "null"); + continue; + } + g_ptr_array_add(snapshot, g_object_ref(conn)); + } + + for(guint i = 0; i < snapshot->len; ++i) + { + NMRemoteConnection *conn = NM_REMOTE_CONNECTION(snapshot->pdata[i]); + GError *error = nullptr; + if(!nm_remote_connection_delete(conn, nullptr, &error)) + { + const char *connId = nm_connection_get_id(NM_CONNECTION(conn)); + NMLOG_ERROR("Failed to delete connection %s: %s", + connId ? connId : "", + error ? error->message : "unknown error"); + if(error) g_error_free(error); + } + } + g_ptr_array_unref(snapshot); + } + } + } + } + + NMLOG_INFO("Adding minimal ethernet connection profile ..."); + wifi->addMinimalEthernetConnection(nmUtils::ethIface()); + + if(!wifi->setInterfaceState(interface, enabled)) + { + NMLOG_ERROR("interface state change failed"); + return Core::ERROR_GENERAL; + } + + NMLOG_INFO("interface %s state: %s", interface.c_str(), enabled ? "enabled" : "disabled"); + if(_instance != NULL) + _instance->m_ethEnabled.store(enabled); - if(enabled) - { sleep(1); // wait for 1 sec to change the device state + NMLOG_INFO("Activating connection 'Wired connection 1' ..."); + // default wired connection name is 'Wired connection 1' + wifi->activateKnownConnection(nmUtils::ethIface(), "Wired connection 1"); + } + else + { + if(!wifi->setInterfaceState(interface, enabled)) + { + NMLOG_ERROR("interface state change failed"); + return Core::ERROR_GENERAL; + } + + NMLOG_INFO("interface %s state: %s", interface.c_str(), enabled ? "enabled" : "disabled"); + // update the interface global cache state if(interface == nmUtils::wlanIface() && _instance != NULL) + _instance->m_wlanEnabled.store(enabled); + else if(interface == nmUtils::ethIface() && _instance != NULL) + _instance->m_ethEnabled.store(enabled); + + if(enabled && interface == nmUtils::wlanIface() && _instance != NULL) { + sleep(1); // wait for 1 sec to change the device state NMLOG_INFO("Activating connection '%s' ...", _instance->m_lastConnectedSSID.c_str()); wifi->activateKnownConnection(nmUtils::wlanIface(), _instance->m_lastConnectedSSID); } - else if(interface == nmUtils::ethIface()) - { - NMLOG_INFO("Activating connection 'Wired connection 1' ..."); - // default wired connection name is 'Wired connection 1' - wifi->activateKnownConnection(nmUtils::ethIface(), "Wired connection 1"); - } } return Core::ERROR_NONE; diff --git a/plugin/gnome/NetworkManagerGnomeWIFI.cpp b/plugin/gnome/NetworkManagerGnomeWIFI.cpp index b6583482..f862f946 100644 --- a/plugin/gnome/NetworkManagerGnomeWIFI.cpp +++ b/plugin/gnome/NetworkManagerGnomeWIFI.cpp @@ -621,6 +621,66 @@ namespace WPEFramework return connection; } + static void addMinimalEthernetConnectionCb(GObject *client, GAsyncResult *result, gpointer user_data) + { + GError *error = NULL; + wifiManager *_wifiManager = static_cast(user_data); + NMRemoteConnection *remoteConn = nm_client_add_connection2_finish(NM_CLIENT(client), result, NULL, &error); + if (error) { + if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { + NMLOG_DEBUG("addMinimalEthernetConnection operation was cancelled"); + g_error_free(error); + if (remoteConn) + g_object_unref(remoteConn); + if (_wifiManager->m_loop && g_main_loop_is_running(_wifiManager->m_loop)) { + g_main_loop_quit(_wifiManager->m_loop); + } + return; // do not alter m_isSuccess on cancellation + } + NMLOG_ERROR("addMinimalEthernetConnection error: %s", error->message); + _wifiManager->m_isSuccess = false; + g_error_free(error); + } + else if (!remoteConn) { + NMLOG_ERROR("addMinimalEthernetConnection failed"); + _wifiManager->m_isSuccess = false; + } + else { + NMLOG_INFO("addMinimalEthernetConnection success"); + _wifiManager->m_isSuccess = true; + g_object_unref(remoteConn); + } + g_main_loop_quit(_wifiManager->m_loop); + } + + bool wifiManager::addMinimalEthernetConnection(std::string iface) + { + if (!createClientNewConnection()) + return false; + + NMConnection *ethConn = createMinimalEthernetConnection(iface); + if (ethConn == NULL) + { + NMLOG_ERROR("Failed to create minimal ethernet connection"); + deleteClientConnection(); + return false; + } + + GVariant *connSettings = nm_connection_to_dbus(ethConn, NM_CONNECTION_SERIALIZE_ALL); + g_object_unref(ethConn); + + m_isSuccess = false; + nm_client_add_connection2(m_client, + connSettings, + NM_SETTINGS_ADD_CONNECTION2_FLAG_TO_DISK, + NULL, TRUE, m_cancellable, + addMinimalEthernetConnectionCb, this); + g_variant_unref(connSettings); + wait(m_loop); + deleteClientConnection(); + return m_isSuccess; + } + static bool connectionBuilder(const Exchange::INetworkManager::WiFiConnectTo& ssidinfo, NMConnection *m_connection, bool iswpsAP = false) { if(ssidinfo.ssid.empty() || ssidinfo.ssid.length() > 32) diff --git a/plugin/gnome/NetworkManagerGnomeWIFI.h b/plugin/gnome/NetworkManagerGnomeWIFI.h index ca4d1d95..42cb58e7 100644 --- a/plugin/gnome/NetworkManagerGnomeWIFI.h +++ b/plugin/gnome/NetworkManagerGnomeWIFI.h @@ -66,6 +66,7 @@ namespace WPEFramework bool setInterfaceState(std::string interface, bool enabled); bool setIpSettings(const string interface, const Exchange::INetworkManager::IPAddress &address); bool setPrimaryInterface(const string interface); + bool addMinimalEthernetConnection(std::string iface); private: NMDevice *getWifiDevice(); From 00f3e4ac3d54d809721951d837b1097bedd52349 Mon Sep 17 00:00:00 2001 From: gururaajar <83449026+gururaajar@users.noreply.github.com> Date: Wed, 29 Apr 2026 14:32:13 -0400 Subject: [PATCH 2/2] RDKEMW-17624: Fixed potential causes of plugin crash (#303) Reason for Change: Fixed potential causes of plugin crash Test Procedure: Monitor for networkmanager plugin crash Priority: P1 Risks: Medium Signed-off-by: Gururaaja ESR --- legacy/LegacyNetworkAPIs.cpp | 3 + legacy/LegacyWiFiManagerAPIs.cpp | 3 + plugin/NetworkManagerConnectivity.cpp | 120 +++++++++-------- plugin/NetworkManagerImplementation.cpp | 31 +++-- plugin/NetworkManagerImplementation.h | 25 +++- plugin/NetworkManagerJsonRpc.cpp | 6 + plugin/gnome/NetworkManagerGnomeProxy.cpp | 125 +++++++++++++----- plugin/gnome/NetworkManagerGnomeWIFI.cpp | 19 ++- .../gnome/gdbus/NetworkManagerGdbusProxy.cpp | 21 ++- plugin/rdk/NetworkManagerRDKProxy.cpp | 20 ++- tests/l2Test/libnm/l2_test_libnmproxy.cpp | 3 +- 11 files changed, 261 insertions(+), 115 deletions(-) diff --git a/legacy/LegacyNetworkAPIs.cpp b/legacy/LegacyNetworkAPIs.cpp index 7bf3b941..7bbca12f 100644 --- a/legacy/LegacyNetworkAPIs.cpp +++ b/legacy/LegacyNetworkAPIs.cpp @@ -772,6 +772,9 @@ const string CIDR_PREFIXES[CIDR_NETMASK_IP_LEN+1] = { } } endpointsIter = (Core::Service::Create(endpoints)); + if (endpointsIter == nullptr) { + returnJson(rc); + } auto _nwmgr = m_service->QueryInterfaceByCallsign(NETWORK_MANAGER_CALLSIGN); if (_nwmgr) diff --git a/legacy/LegacyWiFiManagerAPIs.cpp b/legacy/LegacyWiFiManagerAPIs.cpp index 12e91b0a..9132ed09 100644 --- a/legacy/LegacyWiFiManagerAPIs.cpp +++ b/legacy/LegacyWiFiManagerAPIs.cpp @@ -653,6 +653,9 @@ namespace WPEFramework } ssids = (Core::Service::Create(inputSSIDlist)); + if (ssids == nullptr) { + returnJson(rc); + } } auto _nwmgr = m_service->QueryInterfaceByCallsign(NETWORK_MANAGER_CALLSIGN); diff --git a/plugin/NetworkManagerConnectivity.cpp b/plugin/NetworkManagerConnectivity.cpp index 3d9b8892..93825d51 100644 --- a/plugin/NetworkManagerConnectivity.cpp +++ b/plugin/NetworkManagerConnectivity.cpp @@ -575,7 +575,7 @@ namespace WPEFramework NMCONNECTIVITY_CURL_HEAD_REQUEST, ipversionLocal, interface); if (interface.empty()) - interface = _instance->m_defaultInterface; + interface = _instance->getDefaultInterface(); return testInternet.getInternetState(); } @@ -634,7 +634,9 @@ namespace WPEFramework return false; } - if(_instance->m_defaultInterface.empty()) + string defaultIface = _instance->getDefaultInterface(); + + if(defaultIface.empty()) { NMLOG_WARNING("default interface not set"); return false; @@ -646,7 +648,7 @@ namespace WPEFramework m_cmCv.notify_one(); NMLOG_INFO("switching to initial check - eth %s - wlan %s - default interface %s", - _instance->m_ethConnected.load()? "up":"down", _instance->m_wlanConnected.load()? "up":"down", _instance->m_defaultInterface.c_str()); + _instance->m_ethConnected.load()? "up":"down", _instance->m_wlanConnected.load()? "up":"down", defaultIface.c_str()); return true; } @@ -658,7 +660,8 @@ namespace WPEFramework { NMLOG_INFO("notifying internet state %s", getInternetStateString(newInternetState)); Exchange::INetworkManager::InternetStatus newState = newInternetState; - _instance->ReportInternetStatusChange(oldState , newState, _instance->m_defaultInterface); + string defaultIface = _instance->getDefaultInterface(); + _instance->ReportInternetStatusChange(oldState, newState, defaultIface); m_InternetState = newInternetState; oldState = newState; // 'm_InternetState' not exactly previous state, it may change to unknow when interface changed } @@ -694,68 +697,73 @@ namespace WPEFramework m_notify = true; InitialRetryCount = 1; } - else if(_instance->m_defaultInterface.empty()) - { - NMLOG_WARNING("default interface not set"); - if (InitialRetryCount == 0) - m_notify = true; - InitialRetryCount = 1; - } - else if (m_switchToInitial) + else { - if (InitialRetryCount == 0) - m_notify = true; - NMLOG_INFO("Initial connectivity check - index:%d, current state:%s, interface:%s", InitialRetryCount, getInternetStateString(currentInternetState), _instance->m_defaultInterface.c_str()); - timeoutInSec = NMCONNECTIVITY_MONITOR_MIN_INTERVAL; - TestConnectivity testInternet(m_endpoint(), NMCONNECTIVITY_CURL_REQUEST_TIMEOUT_MS, - NMCONNECTIVITY_CURL_HEAD_REQUEST, 2, _instance->m_defaultInterface); - currentInternetState = testInternet.getInternetState(); + string defaultIface = _instance->getDefaultInterface(); - if (currentInternetState == INTERNET_NOT_AVAILABLE) { - NMLOG_DEBUG("interface connected but no internet"); - InitialRetryCount = 1; // continue same check for 5 sec - } - else { - if(currentInternetState == INTERNET_CAPTIVE_PORTAL) - m_captiveURI = testInternet.getCaptivePortal(); - - if (currentInternetState != m_InternetState) { - NMLOG_DEBUG("initial connectivity state change from %s to %s", getInternetStateString(m_InternetState), getInternetStateString(currentInternetState)); - m_InternetState = currentInternetState; - InitialRetryCount = 1; // reset retry count to get continuous 3 same state + if(defaultIface.empty()) + { + NMLOG_WARNING("default interface not set"); + if (InitialRetryCount == 0) m_notify = true; - } - InitialRetryCount++; + InitialRetryCount = 1; } - - if (InitialRetryCount > NM_CONNECTIVITY_MONITOR_RETRY_COUNT) { - m_switchToInitial = false; - m_notify = true; - NMLOG_INFO("switching to ideal ccm check interface: %s", _instance->m_defaultInterface.c_str()); - } - } - else - { - // ideal case check every 30 sec happenses when captive portal or limited internet - timeoutInSec = NMCONNECTIVITY_MONITOR_RETRY_INTERVAL; - InitialRetryCount = 0; - - if(m_InternetState != INTERNET_FULLY_CONNECTED) + else if (m_switchToInitial) { + if (InitialRetryCount == 0) + m_notify = true; + NMLOG_INFO("Initial connectivity check - index:%d, current state:%s, interface:%s", InitialRetryCount, getInternetStateString(currentInternetState), defaultIface.c_str()); + timeoutInSec = NMCONNECTIVITY_MONITOR_MIN_INTERVAL; TestConnectivity testInternet(m_endpoint(), NMCONNECTIVITY_CURL_REQUEST_TIMEOUT_MS, - NMCONNECTIVITY_CURL_HEAD_REQUEST, 2, _instance->m_defaultInterface); // check both IP versions + NMCONNECTIVITY_CURL_HEAD_REQUEST, 2, defaultIface); currentInternetState = testInternet.getInternetState(); - if (currentInternetState == INTERNET_CAPTIVE_PORTAL) // if captive portal found copy the URL - m_captiveURI = testInternet.getCaptivePortal(); + if (currentInternetState == INTERNET_NOT_AVAILABLE) { + NMLOG_DEBUG("interface connected but no internet"); + InitialRetryCount = 1; // continue same check for 5 sec + } + else { + if(currentInternetState == INTERNET_CAPTIVE_PORTAL) + m_captiveURI = testInternet.getCaptivePortal(); + + if (currentInternetState != m_InternetState) { + NMLOG_DEBUG("initial connectivity state change from %s to %s", getInternetStateString(m_InternetState), getInternetStateString(currentInternetState)); + m_InternetState = currentInternetState; + InitialRetryCount = 1; // reset retry count to get continuous 3 same state + m_notify = true; + } + InitialRetryCount++; + } - if (currentInternetState != m_InternetState) - { - NMLOG_INFO("ideal connectivity state change from %s to %s", getInternetStateString(m_InternetState), getInternetStateString(currentInternetState)); - m_switchToInitial = true; + if (InitialRetryCount > NM_CONNECTIVITY_MONITOR_RETRY_COUNT) { + m_switchToInitial = false; m_notify = true; - InitialRetryCount = 1; - timeoutInSec = NMCONNECTIVITY_MONITOR_MIN_INTERVAL; // retry in 5 sec + NMLOG_INFO("switching to ideal ccm check interface: %s", defaultIface.c_str()); + } + } + else + { + // ideal case check every 30 sec happenses when captive portal or limited internet + timeoutInSec = NMCONNECTIVITY_MONITOR_RETRY_INTERVAL; + InitialRetryCount = 0; + + if(m_InternetState != INTERNET_FULLY_CONNECTED) + { + TestConnectivity testInternet(m_endpoint(), NMCONNECTIVITY_CURL_REQUEST_TIMEOUT_MS, + NMCONNECTIVITY_CURL_HEAD_REQUEST, 2, defaultIface); // check both IP versions + currentInternetState = testInternet.getInternetState(); + + if (currentInternetState == INTERNET_CAPTIVE_PORTAL) // if captive portal found copy the URL + m_captiveURI = testInternet.getCaptivePortal(); + + if (currentInternetState != m_InternetState) + { + NMLOG_INFO("ideal connectivity state change from %s to %s", getInternetStateString(m_InternetState), getInternetStateString(currentInternetState)); + m_switchToInitial = true; + m_notify = true; + InitialRetryCount = 1; + timeoutInSec = NMCONNECTIVITY_MONITOR_MIN_INTERVAL; // retry in 5 sec + } } } } diff --git a/plugin/NetworkManagerImplementation.cpp b/plugin/NetworkManagerImplementation.cpp index cd616c54..daccd548 100644 --- a/plugin/NetworkManagerImplementation.cpp +++ b/plugin/NetworkManagerImplementation.cpp @@ -63,6 +63,7 @@ namespace WPEFramework NMLOG_INFO("NetworkManager Out-Of-Process Shutdown/Cleanup"); connectivityMonitor.stopConnectivityMonitor(); _instance = nullptr; + platform_deinit(); if(m_registrationThread.joinable()) { m_registrationThread.join(); @@ -240,6 +241,9 @@ namespace WPEFramework LOG_ENTRY_FUNCTION(); std::vector tmpEndpoints = connectivityMonitor.getConnectivityMonitorEndpoints(); endpoints = (Core::Service::Create(tmpEndpoints)); + if(endpoints == nullptr) { + return Core::ERROR_GENERAL; + } return Core::ERROR_NONE; } @@ -301,7 +305,7 @@ namespace WPEFramework ipversion = "IPv4"; if(interface.empty()) - interface = m_defaultInterface; + interface = getDefaultInterface(); return Core::ERROR_NONE; } @@ -327,7 +331,7 @@ namespace WPEFramework NMLOG_DEBUG("Primary interface: %s, eth0: [enabled=%d, connected=%d], wlan0: [enabled=%d, connected=%d]", interface.c_str(), m_ethEnabled.load(), m_ethConnected.load(), m_wlanEnabled.load(), m_wlanConnected.load()); - m_defaultInterface = interface; + setDefaultInterface(interface); return Core::ERROR_NONE; } @@ -354,7 +358,7 @@ namespace WPEFramework ipversion = "IPv4"; if (interface.empty()) - interface = m_defaultInterface; + interface = getDefaultInterface(); ipaddress = result.public_ip; return Core::ERROR_NONE; @@ -620,7 +624,9 @@ namespace WPEFramework using Implementation = RPC::IteratorType; security = Core::Service::Create(modeInfo); - + if (security == nullptr) { + return Core::ERROR_GENERAL; + } return Core::ERROR_NONE; } @@ -634,7 +640,7 @@ namespace WPEFramework m_ethIPv4Address = {}; m_ethIPv6Address = {}; m_ethConnected.store(false); - m_defaultInterface = "wlan0"; // If WiFi is connected, make it the default interface + setDefaultInterface("wlan0"); // If WiFi is connected, make it the default interface // As default interface is changed to wlan0, switch connectivity monitor to initial check connectivityMonitor.switchToInitialCheck(); } @@ -643,10 +649,11 @@ namespace WPEFramework m_wlanIPv4Address = {}; m_wlanIPv6Address = {}; m_wlanConnected.store(false); + bool triggerConnectivityCheck; if(m_ethConnected.load()) - m_defaultInterface = "eth0"; // If Ethernet is connected, make it the default interface - - if(m_defaultInterface == interface) + setDefaultInterface("eth0"); // If Ethernet is connected, make it the default interface + triggerConnectivityCheck = (getDefaultInterface() == interface); + if(triggerConnectivityCheck) { // When WiFi is disconnected while Ethernet is connected, we don't need to trigger connectivity monitor. // For WiFi-only state and WiFi disconnected, we should trigger connectivity monitor. @@ -731,12 +738,14 @@ namespace WPEFramework } // FIXME : Availability of ip address for a given interface does not mean that its the default interface. This hardcoding will work for RDKProxy but not for Gnome. + bool isDefaultIface; if (m_ethConnected.load() && m_wlanConnected.load()) - m_defaultInterface = "eth0"; + setDefaultInterface("eth0"); else - m_defaultInterface = interface; + setDefaultInterface(interface); + isDefaultIface = (getDefaultInterface() == interface); - if(m_defaultInterface == interface) { + if(isDefaultIface) { // As default interface is connected, switch connectivity monitor to initial check any way connectivityMonitor.switchToInitialCheck(); } diff --git a/plugin/NetworkManagerImplementation.h b/plugin/NetworkManagerImplementation.h index 565d7ee9..aad9ba4d 100644 --- a/plugin/NetworkManagerImplementation.h +++ b/plugin/NetworkManagerImplementation.h @@ -26,6 +26,7 @@ #include #include #include +#include using namespace std; @@ -34,6 +35,10 @@ using namespace std; #include "NetworkManagerConnectivity.h" #include "NetworkManagerStunClient.h" +/* Forward declarations to avoid pulling GLib/libnm headers into this header */ +typedef struct _NMClient NMClient; +typedef struct _GMainContext GMainContext; + /* * Receiver thermal noise + BW factor + assumed noise figure (NF) (dB) * for a 20MHz channel, @@ -272,6 +277,7 @@ namespace WPEFramework private: void platform_init(void); + void platform_deinit(void); void platform_logging(const NetworkManagerLogger::LogLevel& level); void getInitialConnectionState(void); void executeExternally(NetworkEvents event, const string commandToExecute, string& response); @@ -315,9 +321,26 @@ namespace WPEFramework std::atomic m_wlanConnected; std::atomic m_ethEnabled; std::atomic m_wlanEnabled; - string m_defaultInterface; std::string m_lastConnectedSSID; + NMClient *m_nmClient{nullptr}; /* proxy NMClient — bound to m_nmContext */ + GMainContext *m_nmContext{nullptr}; /* isolated context, not the global default */ mutable ConnectivityMonitor connectivityMonitor; + + string getDefaultInterface() const + { + std::lock_guard lock(m_defaultInterfaceMutex); + return m_defaultInterface; + } + + void setDefaultInterface(const string& iface) + { + std::lock_guard lock(m_defaultInterfaceMutex); + m_defaultInterface = iface; + } + + private: + string m_defaultInterface; + mutable std::mutex m_defaultInterfaceMutex; }; } } diff --git a/plugin/NetworkManagerJsonRpc.cpp b/plugin/NetworkManagerJsonRpc.cpp index b63a322c..2726f112 100644 --- a/plugin/NetworkManagerJsonRpc.cpp +++ b/plugin/NetworkManagerJsonRpc.cpp @@ -427,6 +427,9 @@ namespace WPEFramework } } endpointsIter = (Core::Service::Create(endpoints)); + if(endpointsIter == nullptr){ + returnJson(rc); + } if (_networkManager) rc = _networkManager->SetConnectivityTestEndpoints(endpointsIter); @@ -662,6 +665,9 @@ namespace WPEFramework } } ssids = (Core::Service::Create(ssidslist)); + if(ssids == nullptr){ + returnJson(rc); + } } if (_networkManager) diff --git a/plugin/gnome/NetworkManagerGnomeProxy.cpp b/plugin/gnome/NetworkManagerGnomeProxy.cpp index 52cfb914..8b833967 100644 --- a/plugin/gnome/NetworkManagerGnomeProxy.cpp +++ b/plugin/gnome/NetworkManagerGnomeProxy.cpp @@ -25,7 +25,6 @@ #include #define IN_IS_ADDR_LINKLOCAL(a) ((((uint32_t)ntohl(a)) & 0xffff0000U) == 0xa9fe0000U) -static NMClient *client = NULL; using namespace WPEFramework; using namespace WPEFramework::Plugin; using namespace std; @@ -197,7 +196,7 @@ namespace WPEFramework const GPtrArray *connections = NULL; NMConnection *connection = NULL; - if (client == nullptr) { + if (m_nmClient == nullptr) { NMLOG_ERROR("NMClient is NULL"); return Core::ERROR_GENERAL; } @@ -208,7 +207,7 @@ namespace WPEFramework return Core::ERROR_BAD_REQUEST; } - connections = nm_client_get_connections(client); + connections = nm_client_get_connections(m_nmClient); if (connections == NULL || connections->len == 0) { NMLOG_ERROR("Could not get nm connections"); @@ -251,6 +250,12 @@ namespace WPEFramework return Core::ERROR_NONE; } + void NetworkManagerImplementation::platform_deinit() + { + if(m_nmClient) { g_object_unref(m_nmClient); m_nmClient = nullptr; } + if(m_nmContext) { g_main_context_unref(m_nmContext); m_nmContext = nullptr; } + } + void NetworkManagerImplementation::platform_logging(const NetworkManagerLogger::LogLevel& level) { /* set networkmanager daemon log level based on current plugin log level */ @@ -265,24 +270,35 @@ namespace WPEFramework GError *error = NULL; // initialize the NMClient object - client = nm_client_new(NULL, &error); - if (client == NULL) { + // Create an isolated GMainContext so this m_nmClient's D-Bus socket is NOT a + // source on the global default context. The event thread runs the default + // context via g_main_loop_run(); without isolation it would own and mutate + // this m_nmClient's GObjects concurrently with the RPC thread. + m_nmContext = g_main_context_new(); + g_main_context_push_thread_default(m_nmContext); + m_nmClient = nm_client_new(NULL, &error); + g_main_context_pop_thread_default(m_nmContext); + if (m_nmClient == NULL) { if (error) { NMLOG_FATAL("Error initializing NMClient: %s", error->message); g_error_free(error); } + if (m_nmContext) { + g_main_context_unref(m_nmContext); + m_nmContext = nullptr; + } return; } nmUtils::getDeviceProperties(); // get interface name form '/etc/device.proprties' - modifyDefaultConnConfig(client); - NMDeviceState ethState = ifaceState(client, nmUtils::ethIface()); + modifyDefaultConnConfig(m_nmClient); + NMDeviceState ethState = ifaceState(m_nmClient, nmUtils::ethIface()); if(ethState > NM_DEVICE_STATE_DISCONNECTED && ethState < NM_DEVICE_STATE_DEACTIVATING) - m_defaultInterface = nmUtils::ethIface(); + setDefaultInterface(nmUtils::ethIface()); else - m_defaultInterface = nmUtils::wlanIface(); + setDefaultInterface(nmUtils::wlanIface()); - NMLOG_INFO("default interface is %s", m_defaultInterface.c_str()); + NMLOG_INFO("default interface is %s", getDefaultInterface().c_str()); // getInitialConnectionState function not called here, as event monitor will report the initial state nmEvent = GnomeNetworkManagerEvents::getInstance(); nmEvent->startNetworkMangerEventMonitor(); @@ -295,12 +311,17 @@ namespace WPEFramework std::vector interfaceList; std::string wifiname = nmUtils::wlanIface(), ethname = nmUtils::ethIface(); - if(client == nullptr) { - NMLOG_FATAL("client connection null:"); + if(m_nmClient == nullptr) { + NMLOG_FATAL("NMClient is null"); return Core::ERROR_GENERAL; } - GPtrArray *devices = const_cast(nm_client_get_devices(client)); + if (m_nmContext) { + for (int i = 0; i < 100 && g_main_context_iteration(m_nmContext, FALSE); ++i){ + // Intentional empty body: just flushing the event queue + } + } + GPtrArray *devices = const_cast(nm_client_get_devices(m_nmClient)); if (devices == NULL) { NMLOG_ERROR("Failed to get device list."); return Core::ERROR_GENERAL; @@ -351,6 +372,9 @@ namespace WPEFramework using Implementation = RPC::IteratorType; interfacesItr = Core::Service::Create(interfaceList); + if(interfacesItr == nullptr) { + return Core::ERROR_GENERAL; + } return rc; } #if 0 @@ -427,9 +451,9 @@ namespace WPEFramework uint32_t NetworkManagerImplementation::SetInterfaceState(const string& interface/* @in */, const bool enabled /* @in */) { - if(client == nullptr) + if(m_nmClient == nullptr) { - NMLOG_WARNING("client connection null:"); + NMLOG_WARNING("NMClient is null"); return Core::ERROR_RPC_CALL_FAILED; } @@ -467,7 +491,7 @@ namespace WPEFramework // Bring down the ethernet interface before wiping its connections // so NM doesn't immediately re-activate them during deletion. - NMDevice *ethDev = nm_client_get_device_by_iface(client, interface.c_str()); + NMDevice *ethDev = nm_client_get_device_by_iface(m_nmClient, interface.c_str()); if(ethDev) { GError *discError = nullptr; @@ -480,7 +504,7 @@ namespace WPEFramework } } - const GPtrArray *connections = nm_client_get_connections(client); + const GPtrArray *connections = nm_client_get_connections(m_nmClient); if(connections && connections->len > 0) { /* Snapshot the list before iterating: nm_client_get_connections() @@ -571,19 +595,26 @@ namespace WPEFramework bool isIfaceFound = false; std::string wifiname = nmUtils::wlanIface(), ethname = nmUtils::ethIface(); - if(client == nullptr) - { - NMLOG_WARNING("client connection null:"); - return Core::ERROR_RPC_CALL_FAILED; - } - if(interface.empty() || (wifiname != interface && ethname != interface)) { NMLOG_ERROR("interface: %s; not valied", interface.c_str()!=nullptr? interface.c_str():"empty"); return Core::ERROR_GENERAL; } - GPtrArray *devices = const_cast(nm_client_get_devices(client)); + if(m_nmClient == nullptr) + { + NMLOG_WARNING("NMClient is null"); + return Core::ERROR_RPC_CALL_FAILED; + } + + if (m_nmContext) { + for (int i = 0; i < 100 && g_main_context_iteration(m_nmContext, FALSE); ++i){ + // Intentional empty body: just flushing the event queue + } + } + + GPtrArray *devices = const_cast(nm_client_get_devices(m_nmClient)); + if (devices == NULL) { NMLOG_ERROR("Failed to get device list."); return Core::ERROR_GENERAL; @@ -655,12 +686,6 @@ namespace WPEFramework std::string wifiname = nmUtils::wlanIface(), ethname = nmUtils::ethIface(); - if(client == nullptr) - { - NMLOG_WARNING("client connection null:"); - return Core::ERROR_RPC_CALL_FAILED; - } - if(interface.empty()) { if(Core::ERROR_NONE != GetPrimaryInterface(interface)) @@ -722,7 +747,24 @@ namespace WPEFramework } } - device = nm_client_get_device_by_iface(client, interface.c_str()); + if(m_nmClient == nullptr) + { + NMLOG_WARNING("NMClient is null"); + return Core::ERROR_RPC_CALL_FAILED; + } + + /* Drain any pending D-Bus property-change events queued on m_nmContext + * before reading libnm GObject state. Because m_nmContext is isolated + * from the event thread, nobody else can run it — so this loop is + * single-threaded and safe. It ensures m_nmClient reflects the latest state + * from NetworkManager before we start iterating connections/addresses. */ + if (m_nmContext) { + for (int i = 0; i < 100 && g_main_context_iteration(m_nmContext, FALSE); ++i){ + // Intentional empty body: just flushing the event queue + } + } + + device = nm_client_get_device_by_iface(m_nmClient, interface.c_str()); if (device == NULL) { NMLOG_FATAL("libnm doesn't have device corresponding to %s", interface.c_str()); @@ -740,7 +782,7 @@ namespace WPEFramework // if(ipversion.empty()) // NMLOG_DEBUG("ipversion is empty default value IPv4"); - const GPtrArray *connections = nm_client_get_active_connections(client); + const GPtrArray *connections = nm_client_get_active_connections(m_nmClient); if(connections == NULL) { NMLOG_WARNING("no active connection; ip is not assigned to interface"); @@ -797,9 +839,14 @@ namespace WPEFramework { for (int i = 0; i < ipByte->len; i++) { + ipStr.clear(); ipAddr = static_cast(ipByte->pdata[i]); if(ipAddr) - ipStr = nm_ip_address_get_address(ipAddr); + { + const char* addr = nm_ip_address_get_address(ipAddr); + if(addr) + ipStr = addr; + } if(!ipStr.empty()) { // Skip link-local IPv4 addresses (169.254.x.x) @@ -809,7 +856,7 @@ namespace WPEFramework NMLOG_DEBUG("Skipping link-local IPv4 address: %s", ipStr.c_str()); continue; } - result.ipaddress = nm_ip_address_get_address(ipAddr); + result.ipaddress = ipStr; result.prefix = nm_ip_address_get_prefix(ipAddr); NMLOG_INFO("IPv4 addr: %s/%d", result.ipaddress.c_str(), result.prefix); } @@ -868,9 +915,14 @@ namespace WPEFramework { for (int i = 0; i < ipArray->len; i++) { + ipStr.clear(); ipAddr = static_cast(ipArray->pdata[i]); if(ipAddr) - ipStr = nm_ip_address_get_address(ipAddr); + { + const char* addr = nm_ip_address_get_address(ipAddr); + if(addr) + ipStr = addr; + } if(!ipStr.empty()) { if (ipStr.compare(0, 5, "fe80:") == 0 || ipStr.compare(0, 6, "fe80::") == 0) @@ -984,6 +1036,9 @@ namespace WPEFramework if (!ssidList.empty()) { ssids = Core::Service::Create(ssidList); + if(ssids == nullptr) { + return Core::ERROR_GENERAL; + } rc = Core::ERROR_NONE; } else diff --git a/plugin/gnome/NetworkManagerGnomeWIFI.cpp b/plugin/gnome/NetworkManagerGnomeWIFI.cpp index f862f946..cbef3553 100644 --- a/plugin/gnome/NetworkManagerGnomeWIFI.cpp +++ b/plugin/gnome/NetworkManagerGnomeWIFI.cpp @@ -1666,7 +1666,11 @@ namespace WPEFramework g_error_free(error); } else - NMLOG_ERROR("NetworkManager cleint create failed"); + NMLOG_ERROR("NetworkManager client create failed"); + g_main_context_pop_thread_default(wpsContext); + g_main_context_release(wpsContext); + g_main_context_unref(wpsContext); + wpsContext = NULL; break; } @@ -1674,6 +1678,10 @@ namespace WPEFramework if(wifidevice == NULL) { NMLOG_ERROR("Failed to get device list."); + g_main_context_pop_thread_default(wpsContext); + g_main_context_release(wpsContext); + g_main_context_unref(wpsContext); + wpsContext = NULL; break; } @@ -1713,6 +1721,10 @@ namespace WPEFramework if(ApList == NULL) { NMLOG_ERROR("Aplist Error !"); + g_main_context_pop_thread_default(wpsContext); + g_main_context_release(wpsContext); + g_main_context_unref(wpsContext); + wpsContext = NULL; break; } @@ -1805,6 +1817,11 @@ namespace WPEFramework { /* if wps action not triggerd do a scanning request */ nm_device_wifi_request_scan(NM_DEVICE_WIFI(wifidevice), NULL, &error); + if(error) { + NMLOG_WARNING("WiFi scan request failed: %s", error->message); + g_error_free(error); + error = NULL; + } } g_main_context_pop_thread_default(wpsContext); diff --git a/plugin/gnome/gdbus/NetworkManagerGdbusProxy.cpp b/plugin/gnome/gdbus/NetworkManagerGdbusProxy.cpp index 6e848836..73aa49d9 100644 --- a/plugin/gnome/gdbus/NetworkManagerGdbusProxy.cpp +++ b/plugin/gnome/gdbus/NetworkManagerGdbusProxy.cpp @@ -90,6 +90,11 @@ namespace WPEFramework nmUtils::setNetworkManagerlogLevelToTrace(); } + void NetworkManagerImplementation::platform_deinit() + { + return; + } + void NetworkManagerImplementation::platform_init() { ::_instance = this; @@ -104,14 +109,14 @@ namespace WPEFramework if(_nmGdbusClient->getDeviceInfo(GnomeUtils::getEthIfname(), ethDevInfo)) { if(ethDevInfo.state > NM_DEVICE_STATE_DISCONNECTED && ethDevInfo.state < NM_DEVICE_STATE_DEACTIVATING) - m_defaultInterface = GnomeUtils::getEthIfname(); + setDefaultInterface(GnomeUtils::getEthIfname()); else - m_defaultInterface = GnomeUtils::getWifiIfname(); + setDefaultInterface(GnomeUtils::getWifiIfname()); } else - m_defaultInterface = GnomeUtils::getWifiIfname(); + setDefaultInterface(GnomeUtils::getWifiIfname()); - NMLOG_INFO("default interface is %s", m_defaultInterface.c_str()); + NMLOG_INFO("default interface is %s", getDefaultInterface().c_str()); // Start event monitoring _nmGdbusEvents->startNetworkMangerEventMonitor(); @@ -136,6 +141,9 @@ namespace WPEFramework NMLOG_ERROR("GetAvailableInterfaces failed"); using Implementation = RPC::IteratorType; interfacesItr = Core::Service::Create(interfaceList); + if(interfacesItr == nullptr){ + return Core::ERROR_GENERAL; + } return rc; } @@ -148,7 +156,7 @@ namespace WPEFramework { if(_nmGdbusClient->getDefaultInterface(interface)) { - _instance->m_defaultInterface = interface; + _instance->setDefaultInterface(interface); return Core::ERROR_NONE; } else @@ -234,6 +242,9 @@ namespace WPEFramework if(_nmGdbusClient->getKnownSSIDs(ssidList) && !ssidList.empty()) { ssids = Core::Service::Create(ssidList); + if(ssids == nullptr) { + return Core::ERROR_GENERAL; + } rc = Core::ERROR_NONE; } else diff --git a/plugin/rdk/NetworkManagerRDKProxy.cpp b/plugin/rdk/NetworkManagerRDKProxy.cpp index f2a1e959..0623bdde 100644 --- a/plugin/rdk/NetworkManagerRDKProxy.cpp +++ b/plugin/rdk/NetworkManagerRDKProxy.cpp @@ -399,8 +399,8 @@ namespace WPEFramework if(iface.connected) { NMLOG_INFO("'%s' interface is connected", iface.name.c_str()); - if(m_defaultInterface != iface.name) - ReportActiveInterfaceChange(m_defaultInterface, iface.name); + if(getDefaultInterface() != iface.name) + ReportActiveInterfaceChange(getDefaultInterface(), iface.name); Exchange::INetworkManager::IPAddress addrv4; Exchange::INetworkManager::IPAddress addrv6; std::string ipversion = "IPv4"; @@ -444,6 +444,11 @@ namespace WPEFramework return Core::ERROR_NONE; } + void NetworkManagerImplementation::platform_deinit() + { + return; + } + void NetworkManagerImplementation::platform_init() { LOG_ENTRY_FUNCTION(); @@ -562,6 +567,9 @@ namespace WPEFramework } using Implementation = RPC::IteratorType; interfacesItr = Core::Service::Create(interfaceList); + if(interfacesItr == nullptr) { + return Core::ERROR_GENERAL; + } rc = Core::ERROR_NONE; } @@ -583,7 +591,8 @@ namespace WPEFramework if (IARM_RESULT_SUCCESS == IARM_Bus_Call(IARM_BUS_NM_SRV_MGR_NAME, IARM_BUS_NETSRVMGR_API_getDefaultInterface, (void*)&defaultRoute, sizeof(defaultRoute))) { NMLOG_INFO ("Call to %s for %s returned interface = %s, gateway = %s", IARM_BUS_NM_SRV_MGR_NAME, IARM_BUS_NETSRVMGR_API_getDefaultInterface, defaultRoute.interface, defaultRoute.gateway); - interface = m_defaultInterface = defaultRoute.interface; + interface = defaultRoute.interface; + setDefaultInterface(defaultRoute.interface); rc = Core::ERROR_NONE; } else @@ -699,7 +708,7 @@ namespace WPEFramework if(interface.empty()) { - interface = m_defaultInterface; + interface = getDefaultInterface(); } if(ipversion.empty()) { @@ -1037,6 +1046,9 @@ const string CIDR_PREFIXES[CIDR_NETMASK_IP_LEN+1] = { NMLOG_INFO ("GetKnownSSIDs Success"); ssids = Core::Service::Create(ssidList); + if(ssids == nullptr) { + return Core::ERROR_GENERAL; + } rc = Core::ERROR_NONE; } else diff --git a/tests/l2Test/libnm/l2_test_libnmproxy.cpp b/tests/l2Test/libnm/l2_test_libnmproxy.cpp index 9cb4de3c..4c131c24 100644 --- a/tests/l2Test/libnm/l2_test_libnmproxy.cpp +++ b/tests/l2Test/libnm/l2_test_libnmproxy.cpp @@ -770,7 +770,6 @@ TEST_F(NetworkManagerTest, GetIPSettings_ipv4_config_valid) .WillOnce(::testing::Return("192.168.1.0")); EXPECT_CALL(*p_libnmWrapsImplMock, nm_ip_address_get_address(::testing::_)) - .WillOnce(::testing::Return("192.168.1.2")) .WillOnce(::testing::Return("192.168.1.2")); EXPECT_CALL(*p_libnmWrapsImplMock, nm_ip_config_get_addresses(::testing::_)) @@ -1371,4 +1370,4 @@ TEST_F(NetworkManagerTest, SetIPSettings_static_wlan0_autoConffalse) g_object_unref(dummyActiveConn); g_object_unref(dummyRemoteConn); -} \ No newline at end of file +}