Commit fec407b3 authored by Dan Williams's avatar Dan Williams

system-settings: resurrect auto-wired-default behavior

Dropped due to time during the udev conversion.
parent c07409af
......@@ -405,7 +405,7 @@ main (int argc, char *argv[])
goto done;
}
manager = nm_manager_get (plugins, &error);
manager = nm_manager_get (config, plugins, &error);
if (manager == NULL) {
nm_error ("Failed to initialize the network manager: %s",
error && error->message ? error->message : "(unknown)");
......
......@@ -126,6 +126,8 @@ typedef struct {
} PendingConnectionInfo;
typedef struct {
char *config_file;
GSList *devices;
NMState state;
......@@ -348,11 +350,14 @@ manager_device_state_changed (NMDevice *device,
static GSList *
remove_one_device (NMManager *manager, GSList *list, NMDevice *device)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
if (nm_device_get_managed (device))
nm_device_set_managed (device, FALSE, NM_DEVICE_STATE_REASON_REMOVED);
g_signal_handlers_disconnect_by_func (device, manager_device_state_changed, manager);
nm_sysconfig_settings_device_removed (priv->sys_settings, device);
g_signal_emit (manager, signals[DEVICE_REMOVED], 0, device);
g_object_unref (device);
......@@ -1179,6 +1184,7 @@ add_device (NMManager *self, NMDevice *device)
if (!priv->sleeping && !nm_device_interface_spec_match_list (NM_DEVICE_INTERFACE (device), unmanaged_specs))
nm_device_set_managed (device, TRUE, NM_DEVICE_STATE_REASON_NOW_MANAGED);
nm_sysconfig_settings_device_added (priv->sys_settings, device);
g_signal_emit (self, signals[DEVICE_ADDED], 0, device);
}
......@@ -1260,7 +1266,7 @@ static void
bluez_manager_resync_devices (NMManager *self)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
GSList *iter, *gone = NULL, *keep = NULL;;
GSList *iter, *gone = NULL, *keep = NULL;
/* Remove devices from the device list that don't have a corresponding connection */
for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
......@@ -1279,11 +1285,18 @@ bluez_manager_resync_devices (NMManager *self)
} else
keep = g_slist_prepend (keep, candidate);
}
g_slist_free (priv->devices);
priv->devices = keep;
while (g_slist_length (gone))
gone = remove_one_device (self, gone, NM_DEVICE (gone->data));
/* Only touch the device list if anything actually changed */
if (g_slist_length (gone)) {
g_slist_free (priv->devices);
priv->devices = keep;
while (g_slist_length (gone))
gone = remove_one_device (self, gone, NM_DEVICE (gone->data));
} else {
g_slist_free (keep);
g_slist_free (gone);
}
/* Now look for devices without connections */
nm_bluez_manager_query_devices (priv->bluez_mgr);
......@@ -2408,7 +2421,7 @@ nm_manager_start (NMManager *self)
}
NMManager *
nm_manager_get (const char *plugins, GError **error)
nm_manager_get (const char *config_file, const char *plugins, GError **error)
{
static NMManager *singleton = NULL;
NMManagerPrivate *priv;
......@@ -2421,12 +2434,14 @@ nm_manager_get (const char *plugins, GError **error)
priv = NM_MANAGER_GET_PRIVATE (singleton);
priv->sys_settings = nm_sysconfig_settings_new (plugins, error);
priv->sys_settings = nm_sysconfig_settings_new (config_file, plugins, error);
if (!priv->sys_settings) {
g_object_unref (singleton);
return NULL;
}
priv->config_file = g_strdup (config_file);
g_signal_connect (priv->sys_settings, "notify::" NM_SYSCONFIG_SETTINGS_UNMANAGED_SPECS,
G_CALLBACK (system_unmanaged_devices_changed_cb), singleton);
g_signal_connect (priv->sys_settings, "notify::" NM_SYSCONFIG_SETTINGS_HOSTNAME,
......@@ -2493,9 +2508,11 @@ dispose (GObject *object)
free_get_secrets_info (info);
}
g_message ("%s: priv->devices %p (length %d)", __func__, priv->devices, g_slist_length (priv->devices));
while (g_slist_length (priv->devices)) {
NMDevice *device = NM_DEVICE (priv->devices->data);
g_message ("%s: candidate %p", __func__, device);
priv->devices = remove_one_device (manager, priv->devices, device);
}
......@@ -2509,6 +2526,7 @@ dispose (GObject *object)
priv->system_connections = NULL;
g_free (priv->hostname);
g_free (priv->config_file);
if (priv->sys_settings) {
g_object_unref (priv->sys_settings);
......
......@@ -73,7 +73,7 @@ typedef struct {
GType nm_manager_get_type (void);
NMManager *nm_manager_get (const char *plugins, GError **error);
NMManager *nm_manager_get (const char *config_file, const char *plugins, GError **error);
void nm_manager_start (NMManager *manager);
......
......@@ -38,7 +38,7 @@ G_DEFINE_TYPE (NMDefaultWiredConnection, nm_default_wired_connection, NM_TYPE_SY
#define NM_DEFAULT_WIRED_CONNECTION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEFAULT_WIRED_CONNECTION, NMDefaultWiredConnectionPrivate))
typedef struct {
char *iface;
NMDevice *device;
GByteArray *mac;
gboolean read_only;
} NMDefaultWiredConnectionPrivate;
......@@ -46,7 +46,7 @@ typedef struct {
enum {
PROP_0,
PROP_MAC,
PROP_IFACE,
PROP_DEVICE,
PROP_READ_ONLY,
LAST_PROP
};
......@@ -62,21 +62,29 @@ static guint signals[LAST_SIGNAL] = { 0 };
NMDefaultWiredConnection *
nm_default_wired_connection_new (const GByteArray *mac,
const char *iface,
NMDevice *device,
gboolean read_only)
{
g_return_val_if_fail (mac != NULL, NULL);
g_return_val_if_fail (mac->len == ETH_ALEN, NULL);
g_return_val_if_fail (iface != NULL, NULL);
g_return_val_if_fail (NM_IS_DEVICE (device), NULL);
return g_object_new (NM_TYPE_DEFAULT_WIRED_CONNECTION,
NM_DEFAULT_WIRED_CONNECTION_MAC, mac,
NM_DEFAULT_WIRED_CONNECTION_IFACE, iface,
NM_DEFAULT_WIRED_CONNECTION_DEVICE, device,
NM_DEFAULT_WIRED_CONNECTION_READ_ONLY, read_only,
NULL);
}
NMDevice *
nm_default_wired_connection_get_device (NMDefaultWiredConnection *wired)
{
g_return_val_if_fail (NM_IS_DEFAULT_WIRED_CONNECTION (wired), NULL);
return NM_DEFAULT_WIRED_CONNECTION_GET_PRIVATE (wired)->device;
}
static GByteArray *
dup_wired_mac (NMExportedConnection *exported)
{
......@@ -179,7 +187,7 @@ constructor (GType type,
s_con = NM_SETTING_CONNECTION (nm_setting_connection_new ());
id = g_strdup_printf (_("Auto %s"), priv->iface);
id = g_strdup_printf (_("Auto %s"), nm_device_get_iface (priv->device));
uuid = nm_utils_uuid_generate ();
g_object_set (s_con,
......@@ -211,7 +219,7 @@ finalize (GObject *object)
{
NMDefaultWiredConnectionPrivate *priv = NM_DEFAULT_WIRED_CONNECTION_GET_PRIVATE (object);
g_free (priv->iface);
g_object_unref (priv->device);
g_byte_array_free (priv->mac, TRUE);
G_OBJECT_CLASS (nm_default_wired_connection_parent_class)->finalize (object);
......@@ -227,8 +235,8 @@ get_property (GObject *object, guint prop_id,
case PROP_MAC:
g_value_set_pointer (value, priv->mac);
break;
case PROP_IFACE:
g_value_set_string (value, priv->iface);
case PROP_DEVICE:
g_value_set_object (value, priv->device);
break;
case PROP_READ_ONLY:
g_value_set_boolean (value, priv->read_only);
......@@ -260,9 +268,10 @@ set_property (GObject *object, guint prop_id,
g_byte_array_append (priv->mac, array->data, ETH_ALEN);
}
break;
case PROP_IFACE:
g_free (priv->iface);
priv->iface = g_value_dup_string (value);
case PROP_DEVICE:
if (priv->device)
g_object_unref (priv->device);
priv->device = g_value_dup_object (value);
break;
case PROP_READ_ONLY:
priv->read_only = g_value_get_boolean (value);
......@@ -313,11 +322,11 @@ nm_default_wired_connection_class_init (NMDefaultWiredConnectionClass *klass)
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property
(object_class, PROP_IFACE,
g_param_spec_string (NM_DEFAULT_WIRED_CONNECTION_IFACE,
"Iface",
"Interface",
NULL,
(object_class, PROP_DEVICE,
g_param_spec_object (NM_DEFAULT_WIRED_CONNECTION_DEVICE,
"Device",
"Device",
NM_TYPE_DEVICE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property
......
......@@ -24,6 +24,7 @@
#include <nm-settings.h>
#include "nm-sysconfig-connection.h"
#include "nm-device.h"
G_BEGIN_DECLS
......@@ -35,7 +36,7 @@ G_BEGIN_DECLS
#define NM_DEFAULT_WIRED_CONNECTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEFAULT_WIRED_CONNECTION, NMDefaultWiredConnectionClass))
#define NM_DEFAULT_WIRED_CONNECTION_MAC "mac"
#define NM_DEFAULT_WIRED_CONNECTION_IFACE "iface"
#define NM_DEFAULT_WIRED_CONNECTION_DEVICE "device"
#define NM_DEFAULT_WIRED_CONNECTION_READ_ONLY "read-only"
typedef struct {
......@@ -49,9 +50,11 @@ typedef struct {
GType nm_default_wired_connection_get_type (void);
NMDefaultWiredConnection *nm_default_wired_connection_new (const GByteArray *mac,
const char *iface,
NMDevice *device,
gboolean read_only);
NMDevice *nm_default_wired_connection_get_device (NMDefaultWiredConnection *wired);
G_END_DECLS
#endif /* NM_DEFAULT_WIRED_CONNECTION_H */
......@@ -26,12 +26,17 @@
#include <unistd.h>
#include <string.h>
#include <gmodule.h>
#include <net/ethernet.h>
#include <netinet/ether.h>
#include <NetworkManager.h>
#include <nm-connection.h>
#include <dbus/dbus.h>
#include <nm-setting-connection.h>
#include <nm-setting-wired.h>
#include <nm-setting-pppoe.h>
#include "../nm-device-ethernet.h"
#include "nm-dbus-glib-types.h"
#include "nm-sysconfig-settings.h"
#include "nm-sysconfig-connection.h"
......@@ -39,7 +44,9 @@
#include "nm-polkit-helpers.h"
#include "nm-system-config-error.h"
#include "nm-utils.h"
#include "nm-default-wired-connection.h"
#define CONFIG_KEY_NO_AUTO_DEFAULT "no-auto-default"
/* LINKER CRACKROCK */
#define EXPORT(sym) void * __export_##sym = &sym;
......@@ -67,6 +74,7 @@ static void unmanaged_devices_changed (NMSystemConfigInterface *config, gpointer
typedef struct {
NMDBusManager *dbus_mgr;
PolKitContext *pol_ctx;
char *config_file;
GSList *plugins;
gboolean connections_loaded;
......@@ -221,6 +229,7 @@ finalize (GObject *object)
g_object_unref (priv->dbus_mgr);
g_free (priv->orig_hostname);
g_free (priv->config_file);
G_OBJECT_CLASS (nm_sysconfig_settings_parent_class)->finalize (object);
}
......@@ -816,8 +825,312 @@ impl_settings_save_hostname (NMSysconfigSettings *self,
}
}
static gboolean
have_connection_for_device (NMSysconfigSettings *self, GByteArray *mac)
{
GSList *list, *iter;
NMSettingConnection *s_con;
NMSettingWired *s_wired;
const GByteArray *setting_mac;
gboolean ret = FALSE;
g_return_val_if_fail (NM_IS_SYSCONFIG_SETTINGS (self), FALSE);
g_return_val_if_fail (mac != NULL, FALSE);
/* Find a wired connection locked to the given MAC address, if any */
list = nm_settings_list_connections (NM_SETTINGS (self));
for (iter = list; iter; iter = g_slist_next (iter)) {
NMExportedConnection *exported = NM_EXPORTED_CONNECTION (iter->data);
NMConnection *connection;
const char *connection_type;
connection = nm_exported_connection_get_connection (exported);
if (!connection)
continue;
s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
connection_type = nm_setting_connection_get_connection_type (s_con);
if ( strcmp (connection_type, NM_SETTING_WIRED_SETTING_NAME)
&& strcmp (connection_type, NM_SETTING_PPPOE_SETTING_NAME))
continue;
s_wired = (NMSettingWired *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED);
/* No wired setting; therefore the PPPoE connection applies to any device */
if (!s_wired && !strcmp (connection_type, NM_SETTING_PPPOE_SETTING_NAME)) {
ret = TRUE;
break;
}
setting_mac = nm_setting_wired_get_mac_address (s_wired);
if (setting_mac) {
/* A connection mac-locked to this device */
if (!memcmp (setting_mac->data, mac->data, ETH_ALEN)) {
ret = TRUE;
break;
}
} else {
/* A connection that applies to any wired device */
ret = TRUE;
break;
}
}
g_slist_free (list);
return ret;
}
/* Search through the list of blacklisted MAC addresses in the config file. */
static gboolean
is_mac_auto_wired_blacklisted (NMSysconfigSettings *self, const GByteArray *mac)
{
NMSysconfigSettingsPrivate *priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (self);
GKeyFile *config;
char **list, **iter;
gboolean found = FALSE;
g_return_val_if_fail (mac != NULL, FALSE);
if (!priv->config_file)
return FALSE;
config = g_key_file_new ();
if (!config) {
g_warning ("%s: not enough memory to load config file.", __func__);
return FALSE;
}
g_key_file_set_list_separator (config, ',');
if (!g_key_file_load_from_file (config, priv->config_file, G_KEY_FILE_NONE, NULL))
goto out;
list = g_key_file_get_string_list (config, "main", CONFIG_KEY_NO_AUTO_DEFAULT, NULL, NULL);
for (iter = list; iter && *iter; iter++) {
struct ether_addr *candidate;
candidate = ether_aton (*iter);
if (candidate && !memcmp (mac->data, candidate->ether_addr_octet, ETH_ALEN)) {
found = TRUE;
break;
}
}
if (list)
g_strfreev (list);
out:
g_key_file_free (config);
return found;
}
#define DEFAULT_WIRED_TAG "default-wired"
static void
default_wired_deleted (NMDefaultWiredConnection *wired,
const GByteArray *mac,
NMSysconfigSettings *self)
{
NMSysconfigSettingsPrivate *priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (self);
NMConnection *wrapped;
NMSettingConnection *s_con;
char *tmp;
GKeyFile *config;
char **list, **iter, **updated;
gboolean found = FALSE;
gsize len = 0;
char *data;
/* If there was no config file specified, there's nothing to do */
if (!priv->config_file)
goto cleanup;
/* When the default wired connection is removed (either deleted or saved
* to a new persistent connection by a plugin), write the MAC address of
* the wired device to the config file and don't create a new default wired
* connection for that device again.
*/
wrapped = nm_exported_connection_get_connection (NM_EXPORTED_CONNECTION (wired));
g_assert (wrapped);
s_con = (NMSettingConnection *) nm_connection_get_setting (wrapped, NM_TYPE_SETTING_CONNECTION);
g_assert (s_con);
/* Ignore removals of read-only connections, since they couldn't have
* been removed by the user.
*/
if (nm_setting_connection_get_read_only (s_con))
goto cleanup;
config = g_key_file_new ();
if (!config)
goto cleanup;
g_key_file_set_list_separator (config, ',');
g_key_file_load_from_file (config, priv->config_file, G_KEY_FILE_KEEP_COMMENTS, NULL);
list = g_key_file_get_string_list (config, "main", CONFIG_KEY_NO_AUTO_DEFAULT, &len, NULL);
/* Traverse entire list to get count of # items */
for (iter = list; iter && *iter; iter++) {
struct ether_addr *candidate;
candidate = ether_aton (*iter);
if (candidate && !memcmp (mac->data, candidate->ether_addr_octet, ETH_ALEN))
found = TRUE;
}
/* Add this device's MAC to the list */
if (!found) {
tmp = g_strdup_printf ("%02x:%02x:%02x:%02x:%02x:%02x",
mac->data[0], mac->data[1], mac->data[2],
mac->data[3], mac->data[4], mac->data[5]);
updated = g_malloc0 (sizeof (char*) * (len + 2));
if (list && len)
memcpy (updated, list, len);
updated[len] = tmp;
g_key_file_set_string_list (config,
"main", CONFIG_KEY_NO_AUTO_DEFAULT,
(const char **) updated,
len + 1);
/* g_free() not g_strfreev() since 'updated' isn't a deep-copy */
g_free (updated);
g_free (tmp);
data = g_key_file_to_data (config, &len, NULL);
if (data) {
g_file_set_contents (priv->config_file, data, len, NULL);
g_free (data);
}
}
if (list)
g_strfreev (list);
g_key_file_free (config);
cleanup:
g_object_set_data (G_OBJECT (nm_default_wired_connection_get_device (wired)),
DEFAULT_WIRED_TAG,
NULL);
}
static void
default_wired_try_update (NMDefaultWiredConnection *wired,
GHashTable *new_settings,
NMSysconfigSettings *self)
{
GError *error = NULL;
NMConnection *wrapped;
NMSettingConnection *s_con;
const char *id;
/* Try to move this default wired conneciton to a plugin so that it has
* persistent storage.
*/
wrapped = nm_exported_connection_get_connection (NM_EXPORTED_CONNECTION (wired));
g_assert (wrapped);
s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (wrapped, NM_TYPE_SETTING_CONNECTION));
g_assert (s_con);
id = nm_setting_connection_get_id (s_con);
g_assert (id);
nm_sysconfig_settings_remove_connection (self, NM_EXPORTED_CONNECTION (wired), FALSE);
if (nm_sysconfig_settings_add_new_connection (self, new_settings, &error)) {
g_object_set_data (G_OBJECT (nm_default_wired_connection_get_device (wired)),
DEFAULT_WIRED_TAG,
NULL);
g_message ("Saved default wired connection '%s' to persistent storage", id);
return;
}
g_warning ("%s: couldn't save default wired connection '%s': %d / %s",
__func__, id, error ? error->code : -1,
(error && error->message) ? error->message : "(unknown)");
g_clear_error (&error);
/* If there was an error, don't destroy the default wired connection,
* but add it back to the system settings service. Connection is already
* exported on the bus, don't export it again, thus do_export == FALSE.
*/
nm_sysconfig_settings_add_connection (self, NM_EXPORTED_CONNECTION (wired), FALSE);
}
void
nm_sysconfig_settings_device_added (NMSysconfigSettings *self, NMDevice *device)
{
GByteArray *mac = NULL;
struct ether_addr tmp;
NMDefaultWiredConnection *connection;
NMSettingConnection *s_con;
NMConnection *wrapped;
gboolean read_only = TRUE;
const char *id;
if (nm_device_get_device_type (device) != NM_DEVICE_TYPE_ETHERNET)
return;
/* If the device isn't managed or it already has a default wired connection,
* ignore it.
*/
if ( !nm_device_get_managed (device)
|| g_object_get_data (G_OBJECT (device), DEFAULT_WIRED_TAG))
return;
nm_device_ethernet_get_address (NM_DEVICE_ETHERNET (device), &tmp);
mac = g_byte_array_sized_new (ETH_ALEN);
g_byte_array_append (mac, tmp.ether_addr_octet, ETH_ALEN);
if ( have_connection_for_device (self, mac)
|| is_mac_auto_wired_blacklisted (self, mac))
goto ignore;
if (nm_sysconfig_settings_get_plugin (self, NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_CONNECTIONS))
read_only = FALSE;
connection = nm_default_wired_connection_new (mac, device, read_only);
if (!connection)
goto ignore;
wrapped = nm_exported_connection_get_connection (NM_EXPORTED_CONNECTION (connection));
g_assert (wrapped);
s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (wrapped, NM_TYPE_SETTING_CONNECTION));
g_assert (s_con);
id = nm_setting_connection_get_id (s_con);
g_assert (id);
g_message ("Added default wired connection '%s' for %s", id, nm_device_get_udi (device));
g_signal_connect (connection, "try-update", (GCallback) default_wired_try_update, self);
g_signal_connect (connection, "deleted", (GCallback) default_wired_deleted, self);
nm_sysconfig_settings_add_connection (self, NM_EXPORTED_CONNECTION (connection), TRUE);
g_object_unref (connection);
g_object_set_data (G_OBJECT (device), DEFAULT_WIRED_TAG, connection);
ignore:
g_byte_array_free (mac, TRUE);
}
void
nm_sysconfig_settings_device_removed (NMSysconfigSettings *self, NMDevice *device)
{
NMExportedConnection *exported;
if (nm_device_get_device_type (device) != NM_DEVICE_TYPE_ETHERNET)
return;
exported = (NMExportedConnection *) g_object_get_data (G_OBJECT (device), DEFAULT_WIRED_TAG);
if (exported)
nm_sysconfig_settings_remove_connection (self, exported, TRUE);
}
NMSysconfigSettings *