Skip to content
131 changes: 113 additions & 18 deletions plugin/gnome/NetworkManagerGnomeProxy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,7 @@ namespace WPEFramework
return rc;
}
#endif

uint32_t NetworkManagerImplementation::SetInterfaceState(const string& interface/* @in */, const bool enabled /* @in */)
{

Expand All @@ -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 : "<unknown>",
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;
Expand Down
60 changes: 60 additions & 0 deletions plugin/gnome/NetworkManagerGnomeWIFI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<wifiManager*>(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)
Expand Down
1 change: 1 addition & 0 deletions plugin/gnome/NetworkManagerGnomeWIFI.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down
Loading