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 5dd09070..4a87d6da 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();