diff options
author | Michael Biebl <biebl@debian.org> | 2015-07-14 19:38:58 +0200 |
---|---|---|
committer | Michael Biebl <biebl@debian.org> | 2015-07-14 19:38:58 +0200 |
commit | 50a58f0fabd8a34c1b6108a107e08abe3c1ccd24 (patch) | |
tree | 6790165f39daee79e2b6c6617483320613493367 /src/nm-manager.c | |
parent | f408e27bccfacf347605a8d98649975a68f38a17 (diff) |
Imported Upstream version 1.0.4upstream/1.0.4
Diffstat (limited to 'src/nm-manager.c')
-rw-r--r-- | src/nm-manager.c | 1053 |
1 files changed, 510 insertions, 543 deletions
diff --git a/src/nm-manager.c b/src/nm-manager.c index 0fa88d1d8..080cdb8b2 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -26,8 +26,6 @@ #include <errno.h> #include <string.h> #include <unistd.h> -#include <sys/types.h> -#include <sys/stat.h> #include <dbus/dbus-glib-lowlevel.h> #include <dbus/dbus-glib.h> #include <gio/gio.h> @@ -129,8 +127,6 @@ static NMActiveConnection *_new_active_connection (NMManager *self, static void policy_activating_device_changed (GObject *object, GParamSpec *pspec, gpointer user_data); -static NMDevice *find_device_by_ip_iface (NMManager *self, const gchar *iface); - static void rfkill_change (const char *desc, RfKillType rtype, gboolean enabled); static gboolean find_master (NMManager *self, @@ -161,25 +157,22 @@ typedef struct { char *state_file; GSList *active_connections; + GSList *authorizing_connections; guint ac_cleanup_id; NMActiveConnection *primary_connection; NMActiveConnection *activating_connection; GSList *devices; NMState state; + NMConfig *config; NMConnectivity *connectivity; - int ignore_link_added_cb; - NMPolicy *policy; NMDBusManager *dbus_mgr; gboolean prop_filter_added; NMRfkillManager *rfkill_mgr; - /* List of NMDeviceFactoryFunc pointers sorted in priority order */ - GSList *factories; - NMSettings *settings; char *hostname; @@ -285,7 +278,8 @@ active_connection_remove (NMManager *self, NMActiveConnection *active) g_object_unref (active); - if (connection) { + if ( connection + && nm_settings_has_connection (priv->settings, connection)) { nm_log_dbg (LOGD_DEVICE, "Assumed connection disconnected. Deleting generated connection '%s' (%s)", nm_connection_get_id (connection), nm_connection_get_uuid (connection)); nm_settings_connection_delete (NM_SETTINGS_CONNECTION (connection), NULL, NULL); @@ -463,20 +457,18 @@ active_connection_get_by_path (NMManager *manager, const char *path) /************************************************************************/ -static NMDevice * -nm_manager_get_device_by_udi (NMManager *manager, const char *udi) +static void +_config_changed_cb (NMConfig *config, NMConfigData *config_data, NMConfigChangeFlags changes, NMConfigData *old_data, NMManager *self) { - GSList *iter; - - g_return_val_if_fail (udi != NULL, NULL); - - for (iter = NM_MANAGER_GET_PRIVATE (manager)->devices; iter; iter = iter->next) { - if (!strcmp (nm_device_get_udi (NM_DEVICE (iter->data)), udi)) - return NM_DEVICE (iter->data); - } - return NULL; + g_object_set (NM_MANAGER_GET_PRIVATE (self)->connectivity, + NM_CONNECTIVITY_URI, nm_config_data_get_connectivity_uri (config_data), + NM_CONNECTIVITY_INTERVAL, nm_config_data_get_connectivity_interval (config_data), + NM_CONNECTIVITY_RESPONSE, nm_config_data_get_connectivity_response (config_data), + NULL); } +/************************************************************************/ + static NMDevice * nm_manager_get_device_by_path (NMManager *manager, const char *path) { @@ -506,6 +498,50 @@ nm_manager_get_device_by_ifindex (NMManager *manager, int ifindex) return NULL; } +static NMDevice * +find_device_by_hw_addr (NMManager *manager, const char *hwaddr) +{ + GSList *iter; + const char *device_addr; + + g_return_val_if_fail (hwaddr != NULL, NULL); + + if (nm_utils_hwaddr_valid (hwaddr, -1)) { + for (iter = NM_MANAGER_GET_PRIVATE (manager)->devices; iter; iter = iter->next) { + device_addr = nm_device_get_hw_address (NM_DEVICE (iter->data)); + if (device_addr && nm_utils_hwaddr_matches (hwaddr, -1, device_addr, -1)) + return NM_DEVICE (iter->data); + } + } + return NULL; +} + +static NMDevice * +find_device_by_ip_iface (NMManager *self, const gchar *iface) +{ + GSList *iter; + + g_return_val_if_fail (iface != NULL, NULL); + + for (iter = NM_MANAGER_GET_PRIVATE (self)->devices; iter; iter = g_slist_next (iter)) { + if (g_strcmp0 (nm_device_get_ip_iface (NM_DEVICE (iter->data)), iface) == 0) + return NM_DEVICE (iter->data); + } + return NULL; +} + +static NMDevice * +find_device_by_iface (NMManager *self, const gchar *iface) +{ + GSList *iter; + + for (iter = NM_MANAGER_GET_PRIVATE (self)->devices; iter; iter = g_slist_next (iter)) { + if (g_strcmp0 (nm_device_get_iface (NM_DEVICE (iter->data)), iface) == 0) + return NM_DEVICE (iter->data); + } + return NULL; +} + static gboolean manager_sleeping (NMManager *self) { @@ -834,109 +870,56 @@ nm_manager_get_state (NMManager *manager) return NM_MANAGER_GET_PRIVATE (manager)->state; } -/*******************************************************************/ -/* Settings stuff via NMSettings */ -/*******************************************************************/ +/***************************/ static NMDevice * -get_device_from_hwaddr (NMManager *self, const char *setting_mac) +find_parent_device_for_connection (NMManager *self, NMConnection *connection) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - const char *device_mac; + NMDeviceFactory *factory; + const char *parent_name = NULL; + NMConnection *parent_connection; + NMDevice *parent, *first_compatible = NULL; GSList *iter; - if (!setting_mac) + factory = nm_device_factory_manager_find_factory_for_connection (connection); + if (!factory) return NULL; - for (iter = priv->devices; iter; iter = g_slist_next (iter)) { - NMDevice *device = iter->data; - - device_mac = nm_device_get_hw_address (iter->data); - if (!device_mac) - continue; - if (nm_utils_hwaddr_matches (setting_mac, -1, device_mac, -1)) - return device; - } - return NULL; -} - -static NMDevice * -find_vlan_parent (NMManager *self, - NMConnection *connection) -{ - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - NMSettingVlan *s_vlan; - NMSettingWired *s_wired; - NMConnection *parent_connection; - const char *parent_iface; - NMDevice *parent = NULL; - const char *setting_mac; - GSList *iter; + parent_name = nm_device_factory_get_connection_parent (factory, connection); + if (!parent_name) + return NULL; - /* The 'parent' property could be given by an interface name, a - * connection UUID, or the MAC address of an NMSettingWired. - */ - s_vlan = nm_connection_get_setting_vlan (connection); - g_return_val_if_fail (s_vlan != NULL, NULL); - - s_wired = nm_connection_get_setting_wired (connection); - setting_mac = s_wired ? nm_setting_wired_get_mac_address (s_wired) : NULL; - - parent_iface = nm_setting_vlan_get_parent (s_vlan); - if (parent_iface) { - parent = find_device_by_ip_iface (self, parent_iface); - if (parent) - return parent; - - if (nm_utils_is_uuid (parent_iface)) { - /* Try as a connection UUID */ - parent_connection = (NMConnection *) nm_settings_get_connection_by_uuid (priv->settings, parent_iface); - if (parent_connection) { - /* Check if the parent connection is activated on some device already */ - for (iter = priv->devices; iter; iter = g_slist_next (iter)) { - NMActRequest *req; - NMConnection *candidate; - - req = nm_device_get_act_request (NM_DEVICE (iter->data)); - if (req) { - candidate = nm_active_connection_get_connection (NM_ACTIVE_CONNECTION (req)); - if (candidate == parent_connection) - return NM_DEVICE (iter->data); - } - } + /* Try as an interface name */ + parent = find_device_by_ip_iface (self, parent_name); + if (parent) + return parent; - /* Check the hardware address of the parent connection */ - return get_device_from_hwaddr (self, setting_mac); - } - return NULL; - } - } + /* Maybe a hardware address */ + parent = find_device_by_hw_addr (self, parent_name); + if (parent) + return parent; - /* Try the hardware address from the VLAN connection's hardware setting */ - return get_device_from_hwaddr (self, setting_mac); -} + /* Maybe a connection UUID */ + parent_connection = (NMConnection *) nm_settings_get_connection_by_uuid (priv->settings, parent_name); + if (!parent_connection) + return NULL; -static NMDevice * -find_infiniband_parent (NMManager *self, - NMConnection *connection) -{ - NMSettingInfiniband *s_infiniband; - const char *parent_iface; - NMDevice *parent = NULL; - const char *setting_mac; + /* Check if the parent connection is currently activated or is comaptible + * with some known device. + */ + for (iter = priv->devices; iter; iter = iter->next) { + NMDevice *candidate = iter->data; - s_infiniband = nm_connection_get_setting_infiniband (connection); - g_return_val_if_fail (s_infiniband != NULL, NULL); + if (nm_device_get_connection (candidate) == parent_connection) + return candidate; - parent_iface = nm_setting_infiniband_get_parent (s_infiniband); - if (parent_iface) { - parent = find_device_by_ip_iface (self, parent_iface); - if (parent) - return parent; + if ( !first_compatible + && nm_device_check_connection_compatible (candidate, parent_connection)) + first_compatible = candidate; } - setting_mac = nm_setting_infiniband_get_mac_address (s_infiniband); - return get_device_from_hwaddr (self, setting_mac); + return first_compatible; } /** @@ -944,86 +927,69 @@ find_infiniband_parent (NMManager *self, * @self: the #NMManager * @connection: the #NMConnection representing a virtual interface * @out_parent: on success, the parent device if any + * @error: an error if determining the virtual interface name failed * * Given @connection, returns the interface name that the connection - * would represent. If the interface name is not given by the connection, - * this may require constructing it based on information in the connection - * and existing network interfaces. + * would represent if it is a virtual connection. %NULL is returned and + * @error is set if the connection is not virtual, or if the name could + * not be determined. * * Returns: the expected interface name (caller takes ownership), or %NULL */ static char * get_virtual_iface_name (NMManager *self, NMConnection *connection, - NMDevice **out_parent) + NMDevice **out_parent, + GError **error) { + NMDeviceFactory *factory; + char *iface = NULL; NMDevice *parent = NULL; - const char *ifname; if (out_parent) *out_parent = NULL; - if (!nm_connection_is_virtual (connection)) + if (!nm_connection_is_virtual (connection)) { + g_set_error (error, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_FAILED, + "NetworkManager plugin for '%s' unavailable", + nm_connection_get_connection_type (connection)); return NULL; - - ifname = nm_connection_get_interface_name (connection); - - if (nm_connection_is_type (connection, NM_SETTING_VLAN_SETTING_NAME)) { - NMSettingVlan *s_vlan; - char *vname; - - s_vlan = nm_connection_get_setting_vlan (connection); - g_return_val_if_fail (s_vlan != NULL, NULL); - - parent = find_vlan_parent (self, connection); - if (!parent) - return NULL; - - if (!nm_device_supports_vlans (parent)) { - nm_log_warn (LOGD_DEVICE, "(%s): No support for VLANs on interface %s of type %s", - ifname ? ifname : nm_connection_get_id (connection), - nm_device_get_ip_iface (parent), - nm_device_get_type_desc (parent)); - return NULL; - } - - /* If the connection doesn't specify the interface name for the VLAN - * device, we create one for it using the VLAN ID and the parent - * interface's name. - */ - if (ifname) - vname = g_strdup (ifname); - else { - vname = nm_utils_new_vlan_name (nm_device_get_ip_iface (parent), - nm_setting_vlan_get_id (s_vlan)); - } - if (out_parent) - *out_parent = parent; - return vname; } - if (nm_connection_is_type (connection, NM_SETTING_INFINIBAND_SETTING_NAME)) { - NMSettingInfiniband *s_infiniband; - - parent = find_infiniband_parent (self, connection); - if (!parent) - return NULL; + factory = nm_device_factory_manager_find_factory_for_connection (connection); + if (!factory) { + nm_log_warn (LOGD_DEVICE, "(%s) NetworkManager plugin for '%s' unavailable", + nm_connection_get_id (connection), + nm_connection_get_connection_type (connection)); + g_set_error (error, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_FAILED, + "NetworkManager plugin for '%s' unavailable", + nm_connection_get_connection_type (connection)); + return NULL; + } - s_infiniband = nm_connection_get_setting_infiniband (connection); - if (out_parent) - *out_parent = parent; - return g_strdup (nm_setting_infiniband_get_virtual_interface_name (s_infiniband)); + parent = find_parent_device_for_connection (self, connection); + iface = nm_device_factory_get_virtual_iface_name (factory, + connection, + parent ? nm_device_get_ip_iface (parent) : NULL); + if (!iface) { + nm_log_warn (LOGD_DEVICE, "(%s) failed to determine virtual interface name", + nm_connection_get_id (connection)); + g_set_error_literal (error, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_UNKNOWN_DEVICE, + "failed to determine virtual interface name"); + return NULL; } - /* For any other virtual connection, NMSettingConnection:interface-name is - * the virtual device name. - */ - g_return_val_if_fail (ifname != NULL, NULL); - return g_strdup (ifname); + if (out_parent) + *out_parent = parent; + return iface; } -/***************************/ - /** * system_create_virtual_device: * @self: the #NMManager @@ -1039,7 +1005,7 @@ static NMDevice * system_create_virtual_device (NMManager *self, NMConnection *connection, GError **error) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - GError *local_err = NULL; + NMDeviceFactory *factory; GSList *iter; char *iface = NULL; NMDevice *device = NULL, *parent = NULL; @@ -1049,16 +1015,9 @@ system_create_virtual_device (NMManager *self, NMConnection *connection, GError g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); - iface = get_virtual_iface_name (self, connection, &parent); - if (!iface) { - nm_log_dbg (LOGD_DEVICE, "(%s) failed to determine virtual interface name", - nm_connection_get_id (connection)); - g_set_error_literal (error, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_FAILED, - "failed to determine virtual interface name"); + iface = get_virtual_iface_name (self, connection, &parent, error); + if (!iface) return NULL; - } /* Make sure we didn't create a device for this connection already */ for (iter = priv->devices; iter; iter = g_slist_next (iter)) { @@ -1076,32 +1035,25 @@ system_create_virtual_device (NMManager *self, NMConnection *connection, GError } } - /* Block notification of link added since we're creating the device - * explicitly here, otherwise adding the platform/kernel device would - * create it before this function can do the rest of the setup. - */ - priv->ignore_link_added_cb++; - - nm_owned = !nm_platform_link_exists (iface); - - for (iter = priv->factories; iter; iter = iter->next) { - device = nm_device_factory_create_virtual_device_for_connection (NM_DEVICE_FACTORY (iter->data), - connection, - parent, - &local_err); - if (device || local_err) { - if (device) - g_assert_no_error (local_err); - else { - nm_log_err (LOGD_DEVICE, "(%s) failed to create virtual device: %s", - nm_connection_get_id (connection), - local_err ? local_err->message : "(unknown error)"); - g_propagate_error (error, local_err); - } - break; - } + factory = nm_device_factory_manager_find_factory_for_connection (connection); + if (!factory) { + nm_log_err (LOGD_DEVICE, "(%s:%s) NetworkManager plugin for '%s' unavailable", + nm_connection_get_id (connection), iface, + nm_connection_get_connection_type (connection)); + g_set_error (error, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_FAILED, + "NetworkManager plugin for '%s' unavailable", + nm_connection_get_connection_type (connection)); + goto out; } + nm_owned = !nm_platform_link_get_by_ifname (NM_PLATFORM_GET, iface); + + device = nm_device_factory_create_virtual_device_for_connection (factory, + connection, + parent, + error); if (device) { if (nm_owned) nm_device_set_nm_owned (device); @@ -1112,20 +1064,8 @@ system_create_virtual_device (NMManager *self, NMConnection *connection, GError add_device (self, device, !nm_owned); g_object_unref (device); - } else { - if (error && !*error) - nm_log_err (LOGD_DEVICE, "(%s:%s) NetworkManager plugin for '%s' unavailable", - nm_connection_get_id (connection), iface, - nm_connection_get_connection_type (connection)); - g_set_error (error, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_FAILED, - "NetworkManager plugin for '%s' unavailable", - nm_connection_get_connection_type (connection)); } - priv->ignore_link_added_cb--; - out: g_free (iface); return device; @@ -1565,13 +1505,13 @@ get_existing_connection (NMManager *manager, NMDevice *device, gboolean *out_gen nm_device_capture_initial_config (device); if (ifindex) { - int master_ifindex = nm_platform_link_get_master (ifindex); + int master_ifindex = nm_platform_link_get_master (NM_PLATFORM_GET, ifindex); if (master_ifindex) { master = nm_manager_get_device_by_ifindex (manager, master_ifindex); if (!master) { nm_log_dbg (LOGD_DEVICE, "(%s): cannot generate connection for slave before its master (%s/%d)", - nm_device_get_iface (device), nm_platform_link_get_name (master_ifindex), master_ifindex); + nm_device_get_iface (device), nm_platform_link_get_name (NM_PLATFORM_GET, master_ifindex), master_ifindex); return NULL; } if (!nm_device_get_act_request (master)) { @@ -1694,10 +1634,7 @@ recheck_assume_connection (NMDevice *device, gpointer user_data) if (manager_sleeping (self)) return FALSE; - if (nm_device_get_unmanaged_flag (device, NM_UNMANAGED_USER) || - nm_device_get_unmanaged_flag (device, NM_UNMANAGED_INTERNAL) || - nm_device_get_unmanaged_flag (device, NM_UNMANAGED_EXTERNAL_DOWN) || - nm_device_get_unmanaged_flag (device, NM_UNMANAGED_PARENT)) + if (nm_device_get_unmanaged_flag (device, NM_UNMANAGED_ALL & ~NM_UNMANAGED_DEFAULT)) return FALSE; state = nm_device_get_state (device); @@ -1768,6 +1705,18 @@ device_ip_iface_changed (NMDevice *device, } } +static gboolean +notify_component_added (NMManager *self, GObject *component) +{ + GSList *iter; + + for (iter = NM_MANAGER_GET_PRIVATE (self)->devices; iter; iter = iter->next) { + if (nm_device_notify_component_added (NM_DEVICE (iter->data), component)) + return TRUE; + } + return FALSE; +} + /** * add_device: * @self: the #NMManager @@ -1788,9 +1737,13 @@ add_device (NMManager *self, NMDevice *device, gboolean try_assume) RfKillType rtype; GSList *iter, *remove = NULL; gboolean connection_assumed = FALSE; + int ifindex; /* No duplicates */ - if (nm_manager_get_device_by_udi (self, nm_device_get_udi (device))) + ifindex = nm_device_get_ifindex (device); + if (ifindex > 0 && nm_manager_get_device_by_ifindex (self, ifindex)) + return; + if (find_device_by_iface (self, nm_device_get_iface (device))) return; /* Remove existing devices owned by the new device; eg remove ethernet @@ -1852,8 +1805,12 @@ add_device (NMManager *self, NMDevice *device, gboolean try_assume) driver = nm_device_get_driver (device); if (!driver) driver = "unknown"; - nm_log_info (LOGD_HW, "(%s): new %s device (driver: '%s' ifindex: %d)", - iface, type_desc, driver, nm_device_get_ifindex (device)); + nm_log_info (LOGD_HW, "(%s): new %s device (carrier: %s, driver: '%s', ifindex: %d)", + iface, type_desc, + nm_device_has_capability (device, NM_DEVICE_CAP_CARRIER_DETECT) + ? (nm_device_has_carrier (device) ? "ON" : "OFF") + : "UNKNOWN", + driver, nm_device_get_ifindex (device)); unmanaged_specs = nm_settings_get_unmanaged_specs (priv->settings); user_unmanaged = nm_device_spec_match_list (device, unmanaged_specs); @@ -1881,27 +1838,14 @@ add_device (NMManager *self, NMDevice *device, gboolean try_assume) g_signal_emit (self, signals[DEVICE_ADDED], 0, device); g_object_notify (G_OBJECT (self), NM_MANAGER_DEVICES); + notify_component_added (self, G_OBJECT (device)); + /* New devices might be master interfaces for virtual interfaces; so we may * need to create new virtual interfaces now. */ system_create_virtual_devices (self); } -static NMDevice * -find_device_by_ip_iface (NMManager *self, const gchar *iface) -{ - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - GSList *iter; - - for (iter = priv->devices; iter; iter = g_slist_next (iter)) { - NMDevice *candidate = iter->data; - - if (g_strcmp0 (nm_device_get_ip_iface (candidate), iface) == 0) - return candidate; - } - return NULL; -} - /*******************************************************************/ static void @@ -1917,134 +1861,13 @@ factory_component_added_cb (NMDeviceFactory *factory, GObject *component, gpointer user_data) { - NMManager *self = NM_MANAGER (user_data); - GSList *iter; - - for (iter = NM_MANAGER_GET_PRIVATE (self)->devices; iter; iter = iter->next) { - if (nm_device_notify_component_added (NM_DEVICE (iter->data), component)) - return TRUE; - } - return FALSE; -} - -#define PLUGIN_PREFIX "libnm-device-plugin-" -#define PLUGIN_PATH_TAG "NMManager-plugin-path" - -struct read_device_factory_paths_data { - char *path; - struct stat st; -}; - -static gint -read_device_factory_paths_sort_fcn (gconstpointer a, gconstpointer b) -{ - const struct read_device_factory_paths_data *da = a; - const struct read_device_factory_paths_data *db = b; - time_t ta, tb; - - ta = MAX (da->st.st_mtime, da->st.st_ctime); - tb = MAX (db->st.st_mtime, db->st.st_ctime); - - if (ta < tb) - return 1; - if (ta > tb) - return -1; - return 0; + return notify_component_added (NM_MANAGER (user_data), component); } -static char** -read_device_factory_paths (void) -{ - GDir *dir; - GError *error = NULL; - const char *item; - GArray *paths; - char **result; - guint i; - - dir = g_dir_open (NMPLUGINDIR, 0, &error); - if (!dir) { - nm_log_warn (LOGD_HW, "device plugin: failed to open directory %s: %s", - NMPLUGINDIR, - (error && error->message) ? error->message : "(unknown)"); - g_clear_error (&error); - return NULL; - } - - paths = g_array_new (FALSE, FALSE, sizeof (struct read_device_factory_paths_data)); - - while ((item = g_dir_read_name (dir))) { - int errsv; - struct read_device_factory_paths_data data; - - if (!g_str_has_prefix (item, PLUGIN_PREFIX)) - continue; - if (g_str_has_suffix (item, ".la")) - continue; - - data.path = g_build_filename (NMPLUGINDIR, item, NULL); - - if (stat (data.path, &data.st) != 0) { - errsv = errno; - nm_log_warn (LOGD_HW, "device plugin: skip invalid file %s (error during stat: %s)", data.path, strerror (errsv)); - goto NEXT; - } - if (!S_ISREG (data.st.st_mode)) - goto NEXT; - if (data.st.st_uid != 0) { - nm_log_warn (LOGD_HW, "device plugin: skip invalid file %s (file must be owned by root)", data.path); - goto NEXT; - } - if (data.st.st_mode & (S_IWGRP | S_IWOTH | S_ISUID)) { - nm_log_warn (LOGD_HW, "device plugin: skip invalid file %s (invalid file permissions)", data.path); - goto NEXT; - } - - g_array_append_val (paths, data); - continue; -NEXT: - g_free (data.path); - } - g_dir_close (dir); - - /* sort filenames by modification time. */ - g_array_sort (paths, read_device_factory_paths_sort_fcn); - - result = g_new (char *, paths->len + 1); - for (i = 0; i < paths->len; i++) - result[i] = g_array_index (paths, struct read_device_factory_paths_data, i).path; - result[i] = NULL; - - g_array_free (paths, TRUE); - return result; -} - -static gboolean -_register_device_factory (NMManager *self, - NMDeviceFactory *factory, - gboolean duplicate_check, - const char *path, - GError **error) +static void +_register_device_factory (NMDeviceFactory *factory, gpointer user_data) { - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - NMDeviceType ftype; - GSList *iter; - - if (duplicate_check) { - /* Make sure we don't double-register factories */ - ftype = nm_device_factory_get_device_type (factory); - for (iter = priv->factories; iter; iter = iter->next) { - if (ftype == nm_device_factory_get_device_type (iter->data)) { - g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED, - "multiple plugins for same type (using '%s' instead of '%s')", - (char *) g_object_get_data (G_OBJECT (iter->data), PLUGIN_PATH_TAG), - path); - return FALSE; - } - } - } - - priv->factories = g_slist_append (priv->factories, factory); + NMManager *self = NM_MANAGER (user_data); g_signal_connect (factory, NM_DEVICE_FACTORY_DEVICE_ADDED, @@ -2054,80 +1877,6 @@ _register_device_factory (NMManager *self, NM_DEVICE_FACTORY_COMPONENT_ADDED, G_CALLBACK (factory_component_added_cb), self); - g_object_set_data_full (G_OBJECT (factory), PLUGIN_PATH_TAG, - g_strdup (path), g_free); - return TRUE; -} - -static void -load_device_factories (NMManager *self) -{ - NMDeviceFactory *factory; - const GSList *iter; - GError *error = NULL; - char **path, **paths; - - /* Register internal factories first */ - for (iter = nm_device_factory_get_internal_factory_types (); iter; iter = iter->next) { - GType ftype = (GType) GPOINTER_TO_SIZE (iter->data); - - factory = (NMDeviceFactory *) g_object_new (ftype, NULL); - g_assert (factory); - if (_register_device_factory (self, factory, FALSE, "internal", &error)) { - nm_log_dbg (LOGD_HW, "Loaded device plugin: %s", g_type_name (ftype)); - } else { - nm_log_warn (LOGD_HW, "Loading device plugin failed: %s", error->message); - g_object_unref (factory); - g_clear_error (&error); - } - } - - paths = read_device_factory_paths (); - if (!paths) - return; - - for (path = paths; *path; path++) { - GModule *plugin; - NMDeviceFactoryCreateFunc create_func; - const char *item; - - item = strrchr (*path, '/'); - g_assert (item); - - plugin = g_module_open (*path, G_MODULE_BIND_LOCAL); - - if (!plugin) { - nm_log_warn (LOGD_HW, "(%s): failed to load plugin: %s", item, g_module_error ()); - continue; - } - - if (!g_module_symbol (plugin, "nm_device_factory_create", (gpointer) &create_func)) { - nm_log_warn (LOGD_HW, "(%s): failed to find device factory creator: %s", item, g_module_error ()); - g_module_close (plugin); - continue; - } - - factory = create_func (&error); - if (!factory) { - nm_log_warn (LOGD_HW, "(%s): failed to initialize device factory: %s", - item, error ? error->message : "unknown"); - g_clear_error (&error); - g_module_close (plugin); - continue; - } - g_clear_error (&error); - - if (_register_device_factory (self, factory, TRUE, g_module_name (plugin), &error)) { - nm_log_info (LOGD_HW, "Loaded device plugin: %s", g_module_name (plugin)); - g_module_make_resident (plugin); - } else { - nm_log_warn (LOGD_HW, "Loading device plugin failed: %s", error->message); - g_object_unref (factory); - g_module_close (plugin); - g_clear_error (&error); - } - } - g_strfreev (paths); } /*******************************************************************/ @@ -2135,63 +1884,43 @@ load_device_factories (NMManager *self) static void platform_link_added (NMManager *self, int ifindex, - NMPlatformLink *plink, - NMPlatformReason reason) + NMPlatformLink *plink) { - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); + NMDeviceFactory *factory; NMDevice *device = NULL; - GSList *iter; GError *error = NULL; g_return_if_fail (ifindex > 0); - if (priv->ignore_link_added_cb > 0) - return; - if (nm_manager_get_device_by_ifindex (self, ifindex)) return; /* Try registered device factories */ - for (iter = priv->factories; iter; iter = iter->next) { - NMDeviceFactory *factory = NM_DEVICE_FACTORY (iter->data); - - device = nm_device_factory_new_link (factory, plink, &error); - if (device && NM_IS_DEVICE (device)) { - g_assert_no_error (error); - break; /* success! */ - } + factory = nm_device_factory_manager_find_factory_for_link_type (plink->type); + if (factory) { + gboolean ignore = FALSE; - if (error) { - nm_log_warn (LOGD_HW, "%s: factory failed to create device: (%d) %s", - plink->udi, - error ? error->code : -1, - error ? error->message : "(unknown)"); - g_clear_error (&error); + device = nm_device_factory_new_link (factory, plink, &ignore, &error); + if (!device) { + if (!ignore) { + nm_log_warn (LOGD_HW, "%s: factory failed to create device: %s", + plink->name, error->message); + g_clear_error (&error); + } return; } } - /* Ignore Bluetooth PAN interfaces; they are handled by their NMDeviceBt - * parent and don't get a separate interface. - */ - if (!strncmp (plink->name, "bnep", STRLEN ("bnep"))) - return; - if (device == NULL) { switch (plink->type) { - case NM_LINK_TYPE_WWAN_ETHERNET: - /* WWAN pseudo-ethernet interfaces are handled automatically by - * their NMDeviceModem and don't get a separate NMDevice object. - */ - break; - + case NM_LINK_TYPE_BNEP: case NM_LINK_TYPE_OLPC_MESH: case NM_LINK_TYPE_TEAM: case NM_LINK_TYPE_WIFI: case NM_LINK_TYPE_WIMAX: nm_log_info (LOGD_HW, "(%s): '%s' plugin not available; creating generic device", - plink->name, plink->type_name); + plink->name, nm_link_type_to_string (plink->type)); /* fall through */ default: device = nm_device_generic_new (plink); @@ -2205,30 +1934,76 @@ platform_link_added (NMManager *self, } } +typedef struct { + NMManager *self; + int ifindex; +} PlatformLinkCbData; + +static gboolean +_platform_link_cb_idle (PlatformLinkCbData *data) +{ + NMManager *self = data->self; + + if (self) { + const NMPlatformLink *l; + + l = nm_platform_link_get (NM_PLATFORM_GET, data->ifindex); + if (l) { + NMPlatformLink pllink; + + pllink = *l; /* make a copy of the link instance */ + platform_link_added (self, data->ifindex, &pllink); + } else { + NMDevice *device; + + device = nm_manager_get_device_by_ifindex (self, data->ifindex); + if (device) + remove_device (self, device, FALSE, TRUE); + } + g_object_remove_weak_pointer (G_OBJECT (self), (gpointer *) &data->self); + } + g_slice_free (PlatformLinkCbData, data); + return G_SOURCE_REMOVE; +} + static void platform_link_cb (NMPlatform *platform, + NMPObjectType obj_type, int ifindex, NMPlatformLink *plink, NMPlatformSignalChangeType change_type, NMPlatformReason reason, gpointer user_data) { + PlatformLinkCbData *data; + switch (change_type) { case NM_PLATFORM_SIGNAL_ADDED: - platform_link_added (NM_MANAGER (user_data), ifindex, plink, reason); - break; - case NM_PLATFORM_SIGNAL_REMOVED: { - NMManager *self = NM_MANAGER (user_data); - NMDevice *device; - - device = nm_manager_get_device_by_ifindex (self, ifindex); - if (device) - remove_device (self, device, FALSE, TRUE); + case NM_PLATFORM_SIGNAL_REMOVED: + data = g_slice_new (PlatformLinkCbData); + data->self = NM_MANAGER (user_data); + data->ifindex = ifindex; + g_object_add_weak_pointer (G_OBJECT (data->self), (gpointer *) &data->self); + g_idle_add ((GSourceFunc) _platform_link_cb_idle, data); break; - } - default: + default: break; - } + } +} + +static void +platform_query_devices (NMManager *self) +{ + GArray *links_array; + NMPlatformLink *links; + int i; + + links_array = nm_platform_link_get_all (NM_PLATFORM_GET); + links = (NMPlatformLink *) links_array->data; + for (i = 0; i < links_array->len; i++) + platform_link_added (self, links[i].ifindex, &links[i]); + + g_array_unref (links_array); } static void @@ -2248,6 +2023,40 @@ nm_manager_get_devices (NMManager *manager) return NM_MANAGER_GET_PRIVATE (manager)->devices; } +static NMDevice * +nm_manager_get_connection_device (NMManager *self, + NMConnection *connection) +{ + NMActiveConnection *ac = find_ac_for_connection (self, connection); + if (ac == NULL) + return NULL; + + return nm_active_connection_get_device (ac); +} + +static NMDevice * +nm_manager_get_best_device_for_connection (NMManager *self, + NMConnection *connection) +{ + const GSList *devices, *iter; + NMDevice *act_device = nm_manager_get_connection_device (self, connection); + + if (act_device) + return act_device; + + /* Pick the first device that's compatible with the connection. */ + devices = nm_manager_get_devices (self); + for (iter = devices; iter; iter = g_slist_next (iter)) { + NMDevice *device = NM_DEVICE (iter->data); + + if (nm_device_check_connection_available (device, connection, NM_DEVICE_CHECK_CON_AVAILABLE_NONE, NULL)) + return device; + } + + /* No luck. :( */ + return NULL; +} + static gboolean impl_manager_get_devices (NMManager *manager, GPtrArray **devices, GError **err) { @@ -2411,13 +2220,10 @@ find_master (NMManager *self, NMConnection *candidate = iter->data; char *vname; - if (nm_connection_is_virtual (candidate)) { - vname = get_virtual_iface_name (self, candidate, NULL); - if ( g_strcmp0 (master, vname) == 0 - && is_compatible_with_slave (candidate, connection)) - master_connection = candidate; - g_free (vname); - } + vname = get_virtual_iface_name (self, candidate, NULL, NULL); + if (g_strcmp0 (master, vname) == 0 && is_compatible_with_slave (candidate, connection)) + master_connection = candidate; + g_free (vname); } g_slist_free (connections); } @@ -2615,6 +2421,127 @@ ensure_master_active_connection (NMManager *self, return NULL; } +/** + * find_slaves: + * @manager: #NMManager object + * @connection: the master #NMConnection to find slave connections for + * @device: the master #NMDevice for the @connection + * + * Given an #NMConnection, attempts to find its slaves. If @connection is not + * master, or has not any slaves, this will return %NULL. + * + * Returns: list of slave connections for given master @connection, or %NULL + **/ +static GSList * +find_slaves (NMManager *manager, + NMConnection *connection, + NMDevice *device) +{ + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); + GSList *all_connections, *iter; + GSList *slaves = NULL; + NMSettingConnection *s_con; + const char *master; + + s_con = nm_connection_get_setting_connection (connection); + g_assert (s_con); + master = nm_setting_connection_get_master (s_con); + + if (master != NULL) + return NULL; /* connection is not master */ + + /* Search through all connections, not only inactive ones, because + * even if a slave was already active, it might be deactivated during + * master reactivation. + */ + all_connections = nm_settings_get_connections (priv->settings); + for (iter = all_connections; iter; iter = iter->next) { + NMConnection *master_connection = NULL; + NMDevice *master_device = NULL; + NMConnection *candidate = iter->data; + + find_master (manager, candidate, NULL, &master_connection, &master_device, NULL, NULL); + if ( (master_connection && master_connection == connection) + || (master_device && master_device == device)) { + slaves = g_slist_prepend (slaves, candidate); + } + } + g_slist_free (all_connections); + + return g_slist_reverse (slaves); +} + +static gboolean +should_connect_slaves (NMConnection *connection, NMDevice *device) +{ + NMSettingConnection *s_con; + NMSettingConnectionAutoconnectSlaves autoconnect_slaves; + gs_free char *value = NULL; + + s_con = nm_connection_get_setting_connection (connection); + g_assert (s_con); + + /* Check autoconnect-slaves property */ + autoconnect_slaves = nm_setting_connection_get_autoconnect_slaves (s_con); + if (autoconnect_slaves != NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES_DEFAULT) + goto out; + + /* Check configuration default for autoconnect-slaves property */ + value = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, + "connection.autoconnect-slaves", device); + if (value) + autoconnect_slaves = _nm_utils_ascii_str_to_int64 (value, 10, 0, 1, -1); + +out: + if (autoconnect_slaves == NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES_NO) + return FALSE; + if (autoconnect_slaves == NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES_YES) + return TRUE; + return FALSE; +} + +static gboolean +autoconnect_slaves (NMManager *manager, + NMConnection *master_connection, + NMDevice *master_device, + NMAuthSubject *subject) +{ + GError *local_err = NULL; + gboolean ret = FALSE; + + if (should_connect_slaves (master_connection, master_device)) { + GSList *slaves, *iter; + + iter = slaves = find_slaves (manager, master_connection, master_device); + ret = slaves != NULL; + + while (iter) { + NMConnection *slave_connection = iter->data; + + iter = iter->next; + nm_log_dbg (LOGD_CORE, "will activate slave connection '%s' (%s) as a dependency for master '%s' (%s)", + nm_connection_get_id (slave_connection), + nm_connection_get_uuid (slave_connection), + nm_connection_get_id (master_connection), + nm_connection_get_uuid (master_connection)); + + /* Schedule slave activation */ + nm_manager_activate_connection (manager, + slave_connection, + NULL, + nm_manager_get_best_device_for_connection (manager, slave_connection), + subject, + &local_err); + if (local_err) { + nm_log_warn (LOGD_CORE, "Slave connection activation failed: %s", local_err->message); + g_error_free (local_err); + } + } + g_slist_free (slaves); + } + return ret; +} + static gboolean _internal_activate_vpn (NMManager *self, NMActiveConnection *active, GError **error) { @@ -2635,7 +2562,7 @@ _internal_activate_vpn (NMManager *self, NMActiveConnection *active, GError **er static gboolean _internal_activate_device (NMManager *self, NMActiveConnection *active, GError **error) { - NMDevice *device, *master_device = NULL; + NMDevice *device, *existing, *master_device = NULL; NMConnection *connection; NMConnection *master_connection = NULL; NMActiveConnection *master_ac = NULL; @@ -2783,11 +2710,19 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError * } nm_active_connection_set_master (active, master_ac); - nm_log_dbg (LOGD_CORE, "Activation of '%s' depends on active connection %s", + nm_log_dbg (LOGD_CORE, "Activation of '%s' depends on active connection %p", nm_connection_get_id (connection), - nm_active_connection_get_path (master_ac)); + master_ac); } + /* Check slaves for master connection and possibly activate them */ + autoconnect_slaves (self, connection, device, nm_active_connection_get_subject (active)); + + /* Disconnect the connection if connected or queued on another device */ + existing = nm_manager_get_connection_device (self, connection); + if (existing) + nm_device_steal_connection (existing, connection); + /* Export the new ActiveConnection to clients and start it on the device */ nm_active_connection_export (active); g_object_notify (G_OBJECT (self), NM_MANAGER_ACTIVE_CONNECTIONS); @@ -2825,6 +2760,7 @@ _internal_activate_generic (NMManager *self, NMActiveConnection *active, GError * is exported, make sure the manager's activating-connection property * is up-to-date. */ + active_connection_add (self, active); policy_activating_device_changed (G_OBJECT (priv->policy), NULL, self); } @@ -2894,18 +2830,6 @@ _new_active_connection (NMManager *self, return NULL; } - if (existing_ac) { - NMDevice *existing_device = nm_active_connection_get_device (existing_ac); - - if (existing_device != device) { - g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_CONNECTION_ALREADY_ACTIVE, - "Connection '%s' is already active on %s", - nm_connection_get_id (connection), - nm_device_get_iface (existing_device)); - return NULL; - } - } - /* Normalize the specific object */ if (specific_object && g_strcmp0 (specific_object, "/") == 0) specific_object = NULL; @@ -2929,15 +2853,14 @@ _internal_activation_failed (NMManager *self, NMActiveConnection *active, const char *error_desc) { - nm_log_warn (LOGD_CORE, "Failed to activate '%s': %s", - nm_connection_get_id (nm_active_connection_get_connection (active)), - error_desc); + nm_log_dbg (LOGD_CORE, "Failed to activate '%s': %s", + nm_connection_get_id (nm_active_connection_get_connection (active)), + error_desc); if (nm_active_connection_get_state (active) <= NM_ACTIVE_CONNECTION_STATE_ACTIVATED) { nm_active_connection_set_state (active, NM_ACTIVE_CONNECTION_STATE_DEACTIVATING); nm_active_connection_set_state (active, NM_ACTIVE_CONNECTION_STATE_DEACTIVATED); } - active_connection_remove (self, active); } static void @@ -2948,8 +2871,11 @@ _internal_activation_auth_done (NMActiveConnection *active, gpointer user_data2) { NMManager *self = user_data1; + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); GError *error = NULL; + priv->authorizing_connections = g_slist_remove (priv->authorizing_connections, active); + if (success) { if (_internal_activate_generic (self, active, &error)) { g_object_unref (active); @@ -2989,8 +2915,10 @@ nm_manager_activate_connection (NMManager *self, NMAuthSubject *subject, GError **error) { + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); NMActiveConnection *active; char *error_desc = NULL; + GSList *iter; g_return_val_if_fail (self != NULL, NULL); g_return_val_if_fail (connection != NULL, NULL); @@ -3010,6 +2938,22 @@ nm_manager_activate_connection (NMManager *self, return NULL; } + /* Look for a active connection that's equivalent and is already pending authorization + * and eventual activation. This is used to de-duplicate concurrent activations which would + * otherwise race and cause the device to disconnect and reconnect repeatedly. + * In particular, this allows the master and multiple slaves to concurrently auto-activate + * while all the slaves would use the same active-connection. */ + for (iter = priv->authorizing_connections; iter; iter = g_slist_next (iter)) { + active = iter->data; + + if ( connection == nm_active_connection_get_connection (active) + && g_strcmp0 (nm_active_connection_get_specific_object (active), specific_object) == 0 + && nm_active_connection_get_device (active) == device + && nm_auth_subject_is_internal (nm_active_connection_get_subject (active)) + && nm_auth_subject_is_internal (subject)) + return active; + } + active = _new_active_connection (self, connection, specific_object, @@ -3017,8 +2961,8 @@ nm_manager_activate_connection (NMManager *self, subject, error); if (active) { + priv->authorizing_connections = g_slist_prepend (priv->authorizing_connections, active); nm_active_connection_authorize (active, _internal_activation_auth_done, self, NULL); - active_connection_add (self, active); } return active; } @@ -3064,6 +3008,18 @@ validate_activation_request (NMManager *self, goto error; } + /* Not implemented yet, we want to fail early */ + if ( nm_connection_get_setting_connection (connection) + && nm_connection_get_setting_ip6_config (connection) + && !strcmp (nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP6_CONFIG), + NM_SETTING_IP6_CONFIG_METHOD_SHARED)) { + g_set_error_literal (error, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_CONNECTION_NOT_AVAILABLE, + "Sharing IPv6 connections is not supported yet."); + return NULL; + } + /* Check whether it's a VPN or not */ if ( nm_connection_get_setting_vpn (connection) || nm_connection_is_type (connection, NM_SETTING_VPN_SETTING_NAME)) @@ -3083,7 +3039,10 @@ validate_activation_request (NMManager *self, "Device not found"); goto error; } - } else { + } else + device = nm_manager_get_best_device_for_connection (self, connection); + + if (!device) { gboolean is_software = nm_connection_is_virtual (connection); /* VPN and software-device connections don't need a device yet */ @@ -3091,22 +3050,17 @@ validate_activation_request (NMManager *self, g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE, - "This connection requires an existing device."); + "No suitable device found for this connection."); goto error; } if (is_software) { - /* Look for an existing device with the connection's interface name */ char *iface; - iface = get_virtual_iface_name (self, connection, NULL); - if (!iface) { - g_set_error_literal (error, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_UNKNOWN_DEVICE, - "Failed to determine connection's virtual interface name"); + /* Look for an existing device with the connection's interface name */ + iface = get_virtual_iface_name (self, connection, NULL, error); + if (!iface) goto error; - } device = find_device_by_ip_iface (self, iface); g_free (iface); @@ -3252,7 +3206,6 @@ impl_manager_activate_connection (NMManager *self, goto error; nm_active_connection_authorize (active, _activation_auth_done, self, context); - active_connection_add (self, active); g_clear_object (&subject); return; @@ -3330,8 +3283,6 @@ _add_and_activate_auth_done (NMActiveConnection *active, activation_add_done, info); } else { - active_connection_remove (self, active); - g_assert (error_desc); error = g_error_new_literal (NM_MANAGER_ERROR, NM_MANAGER_ERROR_PERMISSION_DENIED, @@ -3438,7 +3389,6 @@ impl_manager_add_and_activate_connection (NMManager *self, goto error; nm_active_connection_authorize (active, _add_and_activate_auth_done, self, context); - active_connection_add (self, active); g_object_unref (connection); g_object_unref (subject); return; @@ -3616,7 +3566,7 @@ done: static gboolean device_is_wake_on_lan (NMDevice *device) { - return nm_platform_link_get_wake_on_lan (nm_device_get_ip_ifindex (device)); + return nm_platform_link_get_wake_on_lan (NM_PLATFORM_GET, nm_device_get_ip_ifindex (device)); } static void @@ -4172,11 +4122,16 @@ impl_manager_check_connectivity (NMManager *manager, nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_NETWORK_CONTROL, TRUE); } +static void +start_factory (NMDeviceFactory *factory, gpointer user_data) +{ + nm_device_factory_start (factory); +} + void nm_manager_start (NMManager *self) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - GSList *iter; guint i; /* Set initial radio enabled/disabled state */ @@ -4208,10 +4163,9 @@ nm_manager_start (NMManager *self) system_hostname_changed_cb (priv->settings, NULL, self); /* Start device factories */ - for (iter = priv->factories; iter; iter = iter->next) - nm_device_factory_start (iter->data); + nm_device_factory_manager_for_each_factory (start_factory, NULL); - nm_platform_query_devices (); + platform_query_devices (self); /* * Connections added before the manager is started do not emit @@ -4270,12 +4224,9 @@ connectivity_changed (NMConnectivity *connectivity, gpointer user_data) { NMManager *self = NM_MANAGER (user_data); - NMConnectivityState state; - static const char *connectivity_states[] = { "UNKNOWN", "NONE", "PORTAL", "LIMITED", "FULL" }; - state = nm_connectivity_get_state (connectivity); nm_log_dbg (LOGD_CORE, "connectivity checking indicates %s", - connectivity_states[state]); + nm_connectivity_state_to_string (nm_connectivity_get_state (connectivity))); nm_manager_update_state (self); g_object_notify (G_OBJECT (self), NM_MANAGER_CONNECTIVITY); @@ -4718,6 +4669,7 @@ nm_manager_new (NMSettings *settings, NMManagerPrivate *priv; DBusGConnection *bus; DBusConnection *dbus_connection; + NMConfigData *config_data; g_assert (settings); @@ -4749,7 +4701,16 @@ nm_manager_new (NMSettings *settings, g_signal_connect (priv->policy, "notify::" NM_POLICY_ACTIVATING_IP6_DEVICE, G_CALLBACK (policy_activating_device_changed), singleton); - priv->connectivity = nm_connectivity_new (); + priv->config = g_object_ref (nm_config_get ()); + g_signal_connect (G_OBJECT (priv->config), + NM_CONFIG_SIGNAL_CONFIG_CHANGED, + G_CALLBACK (_config_changed_cb), + singleton); + + config_data = nm_config_get_data (priv->config); + priv->connectivity = nm_connectivity_new (nm_config_data_get_connectivity_uri (config_data), + nm_config_data_get_connectivity_interval (config_data), + nm_config_data_get_connectivity_response (config_data)); g_signal_connect (priv->connectivity, "notify::" NM_CONNECTIVITY_STATE, G_CALLBACK (connectivity_changed), singleton); @@ -4807,7 +4768,7 @@ nm_manager_new (NMSettings *settings, rfkill_change (priv->radio_states[RFKILL_TYPE_WLAN].desc, RFKILL_TYPE_WLAN, initial_wifi_enabled); rfkill_change (priv->radio_states[RFKILL_TYPE_WWAN].desc, RFKILL_TYPE_WWAN, initial_wwan_enabled); - load_device_factories (singleton); + nm_device_factory_manager_load_factories (_register_device_factory, singleton); return singleton; } @@ -5042,13 +5003,18 @@ set_property (GObject *object, guint prop_id, } static void +_deinit_device_factory (NMDeviceFactory *factory, gpointer user_data) +{ + g_signal_handlers_disconnect_matched (factory, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, NM_MANAGER (user_data)); +} + +static void dispose (GObject *object) { NMManager *manager = NM_MANAGER (object); NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); DBusGConnection *bus; DBusConnection *dbus_connection; - GSList *iter; g_slist_free_full (priv->auth_chains, (GDestroyNotify) nm_auth_chain_unref); priv->auth_chains = NULL; @@ -5070,7 +5036,14 @@ dispose (GObject *object) g_clear_object (&priv->primary_connection); g_clear_object (&priv->activating_connection); - g_clear_object (&priv->connectivity); + if (priv->config) { + g_signal_handlers_disconnect_by_func (priv->config, _config_changed_cb, manager); + g_clear_object (&priv->config); + } + if (priv->connectivity) { + g_signal_handlers_disconnect_by_func (priv->connectivity, connectivity_changed, manager); + g_clear_object (&priv->connectivity); + } g_free (priv->hostname); @@ -5113,14 +5086,8 @@ dispose (GObject *object) g_clear_object (&priv->fw_monitor); } - for (iter = priv->factories; iter; iter = iter->next) { - NMDeviceFactory *factory = iter->data; - - g_signal_handlers_disconnect_matched (factory, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, manager); - g_object_unref (factory); - } - g_clear_pointer (&priv->factories, g_slist_free); - + nm_device_factory_manager_for_each_factory (_deinit_device_factory, manager); + if (priv->timestamp_update_id) { g_source_remove (priv->timestamp_update_id); priv->timestamp_update_id = 0; |