diff options
| author | Michael Biebl <biebl@debian.org> | 2018-09-08 17:44:06 +0200 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2018-09-08 17:44:06 +0200 |
| commit | 8f7a3cbbdd0c0a48277c341dd3a8ec8743ae9735 (patch) | |
| tree | 4353551fcb59cc822c3cadf2f4888f70601e8fbf /src/nm-manager.c | |
| parent | caf1db9d6fbc056cc6c76a24574890f6c7895f3d (diff) | |
New upstream version 1.13.90 upstream/1.13.90
Diffstat (limited to 'src/nm-manager.c')
| -rw-r--r-- | src/nm-manager.c | 875 |
1 files changed, 543 insertions, 332 deletions
diff --git a/src/nm-manager.c b/src/nm-manager.c index 289dcf83..f8be6d37 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -310,7 +310,8 @@ static void _emit_device_added_removed (NMManager *self, static NMActiveConnection *_new_active_connection (NMManager *self, gboolean is_vpn, - NMConnection *connection, + NMSettingsConnection *sett_conn, + NMConnection *incompl_conn, NMConnection *applied, const char *specific_object, NMDevice *device, @@ -319,7 +320,7 @@ static NMActiveConnection *_new_active_connection (NMManager *self, NMActivationReason activation_reason, GError **error); -static void policy_activating_device_changed (GObject *object, GParamSpec *pspec, gpointer user_data); +static void policy_activating_ac_changed (GObject *object, GParamSpec *pspec, gpointer user_data); static gboolean find_master (NMManager *self, NMConnection *connection, @@ -331,7 +332,8 @@ static gboolean find_master (NMManager *self, static void nm_manager_update_state (NMManager *manager); -static void connection_changed (NMManager *self, NMConnection *connection); +static void connection_changed (NMManager *self, + NMSettingsConnection *sett_conn); static void device_sleep_cb (NMDevice *device, GParamSpec *pspec, NMManager *self); @@ -353,7 +355,7 @@ static void active_connection_parent_active (NMActiveConnection *active, NMManager *self); static NMActiveConnection *active_connection_find (NMManager *self, - NMSettingsConnection *settings_connection, + NMSettingsConnection *sett_conn, const char *uuid, NMActiveConnectionState max_state, GPtrArray **out_all_matching); @@ -947,7 +949,7 @@ nm_manager_get_active_connections (NMManager *manager) static NMActiveConnection * active_connection_find (NMManager *self, - NMSettingsConnection *settings_connection, + NMSettingsConnection *sett_conn, const char *uuid, NMActiveConnectionState max_state /* candidates in state @max_state will be found */, GPtrArray **out_all_matching) @@ -957,16 +959,18 @@ active_connection_find (NMManager *self, NMActiveConnection *best_ac = NULL; GPtrArray *all = NULL; - nm_assert (!settings_connection || NM_IS_SETTINGS_CONNECTION (settings_connection)); + nm_assert (!sett_conn || NM_IS_SETTINGS_CONNECTION (sett_conn)); nm_assert (!out_all_matching || !*out_all_matching); c_list_for_each_entry (ac, &priv->active_connections_lst_head, active_connections_lst) { - NMSettingsConnection *con; + NMSettingsConnection *ac_conn; - con = nm_active_connection_get_settings_connection (ac); - if (settings_connection && con != settings_connection) + ac_conn = nm_active_connection_get_settings_connection (ac); + if ( sett_conn + && sett_conn != ac_conn) continue; - if (uuid && !nm_streq0 (uuid, nm_connection_get_uuid (NM_CONNECTION (con)))) + if ( uuid + && !nm_streq0 (uuid, nm_settings_connection_get_uuid (ac_conn))) continue; if (nm_active_connection_get_state (ac) > max_state) continue; @@ -1005,47 +1009,73 @@ active_connection_find (NMManager *self, static NMActiveConnection * active_connection_find_by_connection (NMManager *self, + NMSettingsConnection *sett_conn, NMConnection *connection, NMActiveConnectionState max_state, GPtrArray **out_all_matching) { - gboolean is_settings_connection; - nm_assert (NM_IS_MANAGER (self)); - nm_assert (NM_IS_CONNECTION (connection)); + nm_assert (!sett_conn || NM_IS_SETTINGS_CONNECTION (sett_conn)); + nm_assert (!connection || NM_IS_CONNECTION (connection)); + nm_assert (sett_conn || connection); + nm_assert (!connection || !sett_conn || connection == nm_settings_connection_get_connection (sett_conn)); - is_settings_connection = NM_IS_SETTINGS_CONNECTION (connection); /* Depending on whether connection is a settings connection, * either lookup by object-identity of @connection, or compare the UUID */ return active_connection_find (self, - is_settings_connection ? NM_SETTINGS_CONNECTION (connection) : NULL, - is_settings_connection ? NULL : nm_connection_get_uuid (connection), + sett_conn, + sett_conn ? NULL : nm_connection_get_uuid (connection), max_state, out_all_matching); } +typedef struct { + NMManager *self; + gboolean for_auto_activation; +} GetActivatableConnectionsFilterData; + static gboolean _get_activatable_connections_filter (NMSettings *settings, - NMSettingsConnection *connection, + NMSettingsConnection *sett_conn, gpointer user_data) { - if (NM_FLAGS_HAS (nm_settings_connection_get_flags (connection), + const GetActivatableConnectionsFilterData *d = user_data; + NMConnectionMultiConnect multi_connect; + + if (NM_FLAGS_HAS (nm_settings_connection_get_flags (sett_conn), NM_SETTINGS_CONNECTION_INT_FLAGS_VOLATILE)) return FALSE; + multi_connect = _nm_connection_get_multi_connect (nm_settings_connection_get_connection (sett_conn)); + if ( multi_connect == NM_CONNECTION_MULTI_CONNECT_MULTIPLE + || ( multi_connect == NM_CONNECTION_MULTI_CONNECT_MANUAL_MULTIPLE + && !d->for_auto_activation)) + return TRUE; + /* the connection is activatable, if it has no active-connections that are in state * activated, activating, or waiting to be activated. */ - return !active_connection_find (user_data, connection, NULL, NM_ACTIVE_CONNECTION_STATE_ACTIVATED, NULL); + return !active_connection_find (d->self, + sett_conn, + NULL, + NM_ACTIVE_CONNECTION_STATE_ACTIVATED, + NULL); } NMSettingsConnection ** -nm_manager_get_activatable_connections (NMManager *manager, guint *out_len, gboolean sort) +nm_manager_get_activatable_connections (NMManager *manager, + gboolean for_auto_activation, + gboolean sort, + guint *out_len) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); + const GetActivatableConnectionsFilterData d = { + .self = manager, + .for_auto_activation = for_auto_activation, + }; return nm_settings_get_connections_clone (priv->settings, out_len, _get_activatable_connections_filter, - manager, + (gpointer) &d, sort ? nm_settings_connection_cmp_autoconnect_priority_p_with_data : NULL, NULL); } @@ -1056,8 +1086,8 @@ active_connection_get_by_path (NMManager *self, const char *path) NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); NMActiveConnection *ac; - ac = (NMActiveConnection *) nm_dbus_manager_lookup_object (nm_dbus_object_get_manager (NM_DBUS_OBJECT (self)), - path); + ac = nm_dbus_manager_lookup_object (nm_dbus_object_get_manager (NM_DBUS_OBJECT (self)), + path); if ( !ac || !NM_IS_ACTIVE_CONNECTION (ac) || c_list_is_empty (&ac->active_connections_lst)) @@ -1193,8 +1223,8 @@ nm_manager_get_device_by_path (NMManager *self, const char *path) g_return_val_if_fail (path, NULL); - device = (NMDevice *) nm_dbus_manager_lookup_object (nm_dbus_object_get_manager (NM_DBUS_OBJECT (self)), - path); + device = nm_dbus_manager_lookup_object (nm_dbus_object_get_manager (NM_DBUS_OBJECT (self)), + path); if ( !device || !NM_IS_DEVICE (device) || c_list_is_empty (&device->devices_lst)) @@ -1244,7 +1274,7 @@ find_device_by_permanent_hw_addr (NMManager *self, const char *hwaddr) } static NMDevice * -find_device_by_ip_iface (NMManager *self, const gchar *iface) +find_device_by_ip_iface (NMManager *self, const char *iface) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); NMDevice *device; @@ -1290,7 +1320,7 @@ find_device_by_iface (NMManager *self, if (strcmp (nm_device_get_iface (candidate), iface)) continue; - if (connection && !nm_device_check_connection_compatible (candidate, connection)) + if (connection && !nm_device_check_connection_compatible (candidate, connection, NULL)) continue; if (slave) { if (!nm_device_is_master (candidate)) @@ -1459,20 +1489,23 @@ manager_device_state_changed (NMDevice *device, && new_state > NM_DEVICE_STATE_UNMANAGED) retry_connections_for_parent_device (self, device); - switch (new_state) { - case NM_DEVICE_STATE_UNMANAGED: - case NM_DEVICE_STATE_UNAVAILABLE: - case NM_DEVICE_STATE_DISCONNECTED: - case NM_DEVICE_STATE_PREPARE: - case NM_DEVICE_STATE_FAILED: + if (NM_IN_SET (new_state, + NM_DEVICE_STATE_UNMANAGED, + NM_DEVICE_STATE_UNAVAILABLE, + NM_DEVICE_STATE_DISCONNECTED, + NM_DEVICE_STATE_PREPARE, + NM_DEVICE_STATE_FAILED)) _notify (self, PROP_ACTIVE_CONNECTIONS); - break; - default: - break; - } - if ( new_state == NM_DEVICE_STATE_UNAVAILABLE - || new_state == NM_DEVICE_STATE_DISCONNECTED) + if (NM_IN_SET (new_state, + NM_DEVICE_STATE_UNMANAGED, + NM_DEVICE_STATE_DISCONNECTED, + NM_DEVICE_STATE_ACTIVATED)) + nm_manager_write_device_state (self, device); + + if (NM_IN_SET (new_state, + NM_DEVICE_STATE_UNAVAILABLE, + NM_DEVICE_STATE_DISCONNECTED)) nm_settings_device_added (priv->settings, device); } @@ -1707,7 +1740,9 @@ find_parent_device_for_connection (NMManager *self, NMConnection *connection, NM return candidate; if ( !first_compatible - && nm_device_check_connection_compatible (candidate, NM_CONNECTION (parent_connection))) + && nm_device_check_connection_compatible (candidate, + nm_settings_connection_get_connection (parent_connection), + NULL)) first_compatible = candidate; } @@ -1801,13 +1836,13 @@ const char * nm_manager_iface_for_uuid (NMManager *self, const char *uuid) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - NMSettingsConnection *connection; + NMSettingsConnection *sett_conn; - connection = nm_settings_get_connection_by_uuid (priv->settings, uuid); - if (!connection) + sett_conn = nm_settings_get_connection_by_uuid (priv->settings, uuid); + if (!sett_conn) return NULL; - return nm_connection_get_interface_name (NM_CONNECTION (connection)); + return nm_connection_get_interface_name (nm_settings_connection_get_connection (sett_conn)); } NMDevice * @@ -1877,7 +1912,7 @@ system_create_virtual_device (NMManager *self, NMConnection *connection) /* See if there's a device that is already compatible with this connection */ c_list_for_each_entry (dev_candidate, &priv->devices_lst_head, devices_lst) { - if (nm_device_check_connection_compatible (dev_candidate, connection)) { + if (nm_device_check_connection_compatible (dev_candidate, connection, NULL)) { if (nm_device_is_real (dev_candidate)) { _LOG3D (LOGD_DEVICE, connection, "already created virtual interface name %s", iface); @@ -1930,10 +1965,10 @@ system_create_virtual_device (NMManager *self, NMConnection *connection) NULL, NULL, nm_settings_connection_cmp_autoconnect_priority_p_with_data, NULL); for (i = 0; connections[i]; i++) { - NMConnection *candidate = NM_CONNECTION (connections[i]); + NMConnection *candidate = nm_settings_connection_get_connection (connections[i]); NMSettingConnection *s_con; - if (!nm_device_check_connection_compatible (device, candidate)) + if (!nm_device_check_connection_compatible (device, candidate, NULL)) continue; s_con = nm_connection_get_setting_connection (candidate); @@ -1976,18 +2011,19 @@ retry_connections_for_parent_device (NMManager *self, NMDevice *device) NULL, NULL, nm_settings_connection_cmp_autoconnect_priority_p_with_data, NULL); for (i = 0; connections[i]; i++) { - NMConnection *candidate = NM_CONNECTION (connections[i]); + NMSettingsConnection *sett_conn = connections[i]; + NMConnection *connection = nm_settings_connection_get_connection (sett_conn); gs_free_error GError *error = NULL; gs_free char *ifname = NULL; NMDevice *parent; - parent = find_parent_device_for_connection (self, candidate, NULL); + parent = find_parent_device_for_connection (self, connection, NULL); if (parent == device) { /* Only try to activate devices that don't already exist */ - ifname = nm_manager_get_connection_iface (self, candidate, &parent, &error); + ifname = nm_manager_get_connection_iface (self, connection, &parent, &error); if (ifname) { if (!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, ifname)) - connection_changed (self, candidate); + connection_changed (self, sett_conn); } } } @@ -1995,9 +2031,10 @@ retry_connections_for_parent_device (NMManager *self, NMDevice *device) static void connection_changed (NMManager *self, - NMConnection *connection) + NMSettingsConnection *sett_conn) { NMDevice *device; + NMConnection *connection = nm_settings_connection_get_connection (sett_conn); if (!nm_connection_is_virtual (connection)) return; @@ -2014,20 +2051,20 @@ connection_changed (NMManager *self, static void connection_added_cb (NMSettings *settings, - NMConnection *connection, + NMSettingsConnection *sett_conn, NMManager *self) { - connection_changed (self, connection); + connection_changed (self, sett_conn); } static void connection_updated_cb (NMSettings *settings, - NMConnection *connection, + NMSettingsConnection *sett_conn, gboolean by_user, NMManager *self) { if (by_user) - connection_changed (self, connection); + connection_changed (self, sett_conn); } /*****************************************************************************/ @@ -2370,6 +2407,20 @@ done: g_clear_error (&error); } +static gboolean +new_activation_allowed_for_connection (NMManager *self, + NMSettingsConnection *connection) +{ + if (NM_IN_SET (_nm_connection_get_multi_connect (nm_settings_connection_get_connection (connection)), + NM_CONNECTION_MULTI_CONNECT_MANUAL_MULTIPLE, + NM_CONNECTION_MULTI_CONNECT_MULTIPLE)) + return TRUE; + + return !active_connection_find (self, connection, NULL, + NM_ACTIVE_CONNECTION_STATE_ACTIVATED, + NULL); +} + /** * get_existing_connection: * @manager: #NMManager instance @@ -2386,12 +2437,12 @@ get_existing_connection (NMManager *self, { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); gs_unref_object NMConnection *connection = NULL; - NMSettingsConnection *added = NULL; + NMSettingsConnection *added; GError *error = NULL; gs_free_error GError *gen_error = NULL; NMDevice *master = NULL; int ifindex = nm_device_get_ifindex (device); - NMSettingsConnection *matched; + NMSettingsConnection *matched = NULL; NMSettingsConnection *connection_checked = NULL; gboolean assume_state_guess_assume = FALSE; const char *assume_state_connection_uuid = NULL; @@ -2457,28 +2508,25 @@ get_existing_connection (NMManager *self, */ if ( assume_state_connection_uuid && (connection_checked = nm_settings_get_connection_by_uuid (priv->settings, assume_state_connection_uuid)) - && !active_connection_find (self, connection_checked, NULL, - NM_ACTIVE_CONNECTION_STATE_ACTIVATED, - NULL) - && nm_device_check_connection_compatible (device, NM_CONNECTION (connection_checked))) { + && new_activation_allowed_for_connection (self, connection_checked) + && nm_device_check_connection_compatible (device, + nm_settings_connection_get_connection (connection_checked), + NULL)) { if (connection) { - NMConnection *const connections[] = { - NM_CONNECTION (connection_checked), - NULL, - }; - - matched = NM_SETTINGS_CONNECTION (nm_utils_match_connection (connections, - connection, - TRUE, - nm_device_has_carrier (device), - nm_device_get_route_metric (device, AF_INET), - nm_device_get_route_metric (device, AF_INET6), - NULL, NULL)); + NMConnection *con = nm_settings_connection_get_connection (connection_checked); + + if (nm_utils_match_connection ((NMConnection *[]) { con, NULL }, + connection, + TRUE, + nm_device_has_carrier (device), + nm_device_get_route_metric (device, AF_INET), + nm_device_get_route_metric (device, AF_INET6), + NULL, NULL)) + matched = connection_checked; } else matched = connection_checked; - } else - matched = NULL; + } if (!matched && only_by_uuid) { _LOG2D (LOGD_DEVICE, device, "assume: cannot generate connection: %s", @@ -2487,32 +2535,51 @@ get_existing_connection (NMManager *self, } if (!matched && assume_state_guess_assume) { - gs_free NMSettingsConnection **connections = NULL; + gs_free NMSettingsConnection **sett_conns = NULL; guint len, i, j; /* the state file doesn't indicate a connection UUID to assume. Search the * persistent connections for a matching candidate. */ - connections = nm_manager_get_activatable_connections (self, &len, FALSE); + sett_conns = nm_manager_get_activatable_connections (self, FALSE, FALSE, &len); if (len > 0) { for (i = 0, j = 0; i < len; i++) { - NMConnection *con = NM_CONNECTION (connections[i]); + NMSettingsConnection *sett_conn = sett_conns[i]; - if ( con != NM_CONNECTION (connection_checked) - && nm_device_check_connection_compatible (device, con)) - connections[j++] = connections[i]; + if ( sett_conn != connection_checked + && nm_device_check_connection_compatible (device, + nm_settings_connection_get_connection (sett_conn), + NULL)) + sett_conns[j++] = sett_conn; } - connections[j] = NULL; + sett_conns[j] = NULL; len = j; - g_qsort_with_data (connections, len, sizeof (connections[0]), - nm_settings_connection_cmp_timestamp_p_with_data, NULL); - - matched = NM_SETTINGS_CONNECTION (nm_utils_match_connection ((NMConnection *const*) connections, - connection, - FALSE, - nm_device_has_carrier (device), - nm_device_get_route_metric (device, AF_INET), - nm_device_get_route_metric (device, AF_INET6), - NULL, NULL)); + if (len > 0) { + gs_free NMConnection **conns = NULL; + NMConnection *con; + + g_qsort_with_data (sett_conns, len, sizeof (sett_conns[0]), + nm_settings_connection_cmp_timestamp_p_with_data, NULL); + + conns = nm_settings_connections_array_to_connections (sett_conns, len); + + con = nm_utils_match_connection (conns, + connection, + FALSE, + nm_device_has_carrier (device), + nm_device_get_route_metric (device, AF_INET), + nm_device_get_route_metric (device, AF_INET6), + NULL, + NULL); + if (con) { + for (i = 0; i < len; i++) { + if (conns[i] == con) { + matched = sett_conns[i]; + break; + } + } + nm_assert (matched); + } + } } } @@ -2541,7 +2608,7 @@ get_existing_connection (NMManager *self, return NULL; } - nm_settings_connection_set_flags (NM_SETTINGS_CONNECTION (added), + nm_settings_connection_set_flags (added, NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED | NM_SETTINGS_CONNECTION_INT_FLAGS_VOLATILE, TRUE); @@ -2553,7 +2620,7 @@ static gboolean recheck_assume_connection (NMManager *self, NMDevice *device) { - NMSettingsConnection *connection; + NMSettingsConnection *sett_conn; gboolean was_unmanaged = FALSE; gboolean generated = FALSE; NMDeviceState state; @@ -2575,9 +2642,9 @@ recheck_assume_connection (NMManager *self, return FALSE; } - connection = get_existing_connection (self, device, &generated); + sett_conn = get_existing_connection (self, device, &generated); /* log no reason. get_existing_connection() already does it. */ - if (!connection) + if (!sett_conn) return FALSE; nm_device_sys_iface_state_set (device, @@ -2609,7 +2676,8 @@ recheck_assume_connection (NMManager *self, subject = nm_auth_subject_new_internal (); active = _new_active_connection (self, FALSE, - NM_CONNECTION (connection), + sett_conn, + NULL, NULL, NULL, device, @@ -2620,7 +2688,7 @@ recheck_assume_connection (NMManager *self, if (!active) { _LOGW (LOGD_DEVICE, "assume: assumed connection %s failed to activate: %s", - nm_dbus_object_get_path (NM_DBUS_OBJECT (connection)), + nm_dbus_object_get_path (NM_DBUS_OBJECT (sett_conn)), error->message); g_error_free (error); @@ -2632,7 +2700,7 @@ recheck_assume_connection (NMManager *self, if (generated) { _LOG2D (LOGD_DEVICE, device, "assume: deleting generated connection after assuming failed"); - nm_settings_connection_delete (connection, NULL); + nm_settings_connection_delete (sett_conn, NULL); } else { if (nm_device_sys_iface_state_get (device) == NM_DEVICE_SYS_IFACE_STATE_ASSUME) nm_device_sys_iface_state_set (device, NM_DEVICE_SYS_IFACE_STATE_EXTERNAL); @@ -2642,7 +2710,14 @@ recheck_assume_connection (NMManager *self, /* If the device is a slave or VLAN, find the master ActiveConnection */ master_ac = NULL; - if (find_master (self, NM_CONNECTION (connection), device, NULL, NULL, &master_ac, NULL) && master_ac) + if ( find_master (self, + nm_settings_connection_get_connection (sett_conn), + device, + NULL, + NULL, + &master_ac, + NULL) + && master_ac) nm_active_connection_set_master (active, master_ac); active_connection_add (self, active); @@ -3008,10 +3083,21 @@ platform_link_added (NMManager *self, continue; if (nm_device_is_real (candidate)) { - /* Ignore the link added event since there's already a realized - * device with the link's name. + /* There's already a realized device with the link's name + * and a different ifindex. */ - nm_device_update_from_platform_link (candidate, plink); + if (nm_device_get_ifindex (candidate) <= 0) + nm_device_update_from_platform_link (candidate, plink); + else { + /* The ifindex of a device can't be changed after + * initialization because it is used as a key by + * the dns-manager. + */ + _LOGD (LOGD_DEVICE, "(%s): removing old device %p after ifindex change from %d to %d", + plink->name, candidate, nm_device_get_ifindex (candidate), ifindex); + remove_device (self, candidate, FALSE, TRUE); + goto add; + } return; } else if (nm_device_realize_start (candidate, plink, @@ -3031,6 +3117,7 @@ platform_link_added (NMManager *self, /* Try next unrealized device */ } +add: /* Try registered device factories */ factory = nm_device_factory_manager_find_factory_for_link_type (plink->type); if (factory) { @@ -3234,9 +3321,11 @@ nm_manager_get_devices (NMManager *manager) static NMDevice * nm_manager_get_best_device_for_connection (NMManager *self, + NMSettingsConnection *sett_conn, NMConnection *connection, gboolean for_user_request, - GHashTable *unavailable_devices) + GHashTable *unavailable_devices, + GError **error) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); NMActiveConnectionState ac_state; @@ -3245,16 +3334,25 @@ nm_manager_get_best_device_for_connection (NMManager *self, NMDevice *device; NMDeviceCheckConAvailableFlags flags; gs_unref_ptrarray GPtrArray *all_ac_arr = NULL; + gs_free_error GError *local_best = NULL; + + nm_assert (!sett_conn || NM_IS_SETTINGS_CONNECTION (sett_conn)); + nm_assert (!connection || NM_IS_CONNECTION (connection)); + nm_assert (sett_conn || connection); + nm_assert (!connection || !sett_conn || connection == nm_settings_connection_get_connection (sett_conn)); + + if (!connection) + connection = nm_settings_connection_get_connection (sett_conn); flags = for_user_request ? NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST : NM_DEVICE_CHECK_CON_AVAILABLE_NONE; - ac = active_connection_find_by_connection (self, connection, NM_ACTIVE_CONNECTION_STATE_DEACTIVATING, &all_ac_arr); + ac = active_connection_find_by_connection (self, sett_conn, connection, NM_ACTIVE_CONNECTION_STATE_DEACTIVATING, &all_ac_arr); if (ac) { ac_device = nm_active_connection_get_device (ac); if ( ac_device && ( (unavailable_devices && g_hash_table_contains (unavailable_devices, ac_device)) - || !nm_device_check_connection_available (ac_device, connection, flags, NULL))) + || !nm_device_check_connection_available (ac_device, connection, flags, NULL, NULL))) ac_device = NULL; if (all_ac_arr) { @@ -3271,7 +3369,7 @@ nm_manager_get_best_device_for_connection (NMManager *self, if ( !ac_device2 || (unavailable_devices && g_hash_table_contains (unavailable_devices, ac_device2)) - || !nm_device_check_connection_available (ac_device2, connection, flags, NULL)) + || !nm_device_check_connection_available (ac_device2, connection, flags, NULL, NULL)) continue; ac_state2 = nm_active_connection_get_state (ac2); @@ -3319,15 +3417,53 @@ found_better: /* Pick the first device that's compatible with the connection. */ c_list_for_each_entry (device, &priv->devices_lst_head, devices_lst) { + GError *local = NULL; - if (unavailable_devices && g_hash_table_contains (unavailable_devices, device)) + if ( unavailable_devices + && g_hash_table_contains (unavailable_devices, device)) continue; - if (nm_device_check_connection_available (device, connection, flags, NULL)) + if (nm_device_check_connection_available (device, + connection, + flags, + NULL, + error ? &local : NULL)) return device; + + if (error) { + gboolean reset_error; + + if (!local_best) + reset_error = TRUE; + else if (local_best->domain != NM_UTILS_ERROR) + reset_error = (local->domain == NM_UTILS_ERROR); + else { + reset_error = ( local->domain == NM_UTILS_ERROR + && local_best->code < local->code); + } + + if (reset_error) { + g_clear_error (&local_best); + g_set_error (&local_best, + local->domain, + local->code, + "device %s not available because %s", + nm_device_get_iface (device), + local->message); + } + g_error_free (local); + } } - /* No luck. :( */ + if (error) { + if (local_best) + g_propagate_error (error, g_steal_pointer (&local_best)); + else { + nm_utils_error_set_literal (error, + NM_UTILS_ERROR_UNKNOWN, + "no suitable device found"); + } + } return NULL; } @@ -3496,7 +3632,7 @@ find_master (NMManager *self, NMSettingConnection *s_con; const char *master; NMDevice *master_device = NULL; - NMSettingsConnection *master_connection = NULL; + NMSettingsConnection *master_connection; s_con = nm_connection_get_setting_connection (connection); g_assert (s_con); @@ -3515,7 +3651,9 @@ find_master (NMManager *self, } master_connection = nm_device_get_settings_connection (master_device); - if (master_connection && !is_compatible_with_slave (NM_CONNECTION (master_connection), connection)) { + if ( master_connection + && !is_compatible_with_slave (nm_settings_connection_get_connection (master_connection), + connection)) { g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_DEPENDENCY_FAILED, "The active connection on %s is not compatible", nm_device_get_iface (master_device)); @@ -3615,7 +3753,9 @@ ensure_master_active_connection (NMManager *self, * be already activated on the device, eg returned from find_master(). */ g_assert (!master_connection || master_connection == device_connection); - if (device_connection && !is_compatible_with_slave (NM_CONNECTION (device_connection), connection)) { + if ( device_connection + && !is_compatible_with_slave (nm_settings_connection_get_connection (device_connection), + connection)) { g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_DEPENDENCY_FAILED, "The active connection %s is not compatible", nm_connection_get_id (connection)); @@ -3640,17 +3780,22 @@ ensure_master_active_connection (NMManager *self, g_assert (master_connection == NULL); /* Find a compatible connection and activate this device using it */ - connections = nm_manager_get_activatable_connections (self, NULL, TRUE); + connections = nm_manager_get_activatable_connections (self, FALSE, TRUE, NULL); for (i = 0; connections[i]; i++) { NMSettingsConnection *candidate = connections[i]; + NMConnection *cand_conn = nm_settings_connection_get_connection (candidate); /* Ensure eg bond/team slave and the candidate master is a * bond/team master */ - if (!is_compatible_with_slave (NM_CONNECTION (candidate), connection)) + if (!is_compatible_with_slave (cand_conn, connection)) continue; - if (nm_device_check_connection_available (master_device, NM_CONNECTION (candidate), NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST, NULL)) { + if (nm_device_check_connection_available (master_device, + cand_conn, + NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST, + NULL, + NULL)) { master_ac = nm_manager_activate_connection (self, candidate, NULL, @@ -3686,7 +3831,11 @@ ensure_master_active_connection (NMManager *self, continue; } - if (!nm_device_check_connection_available (candidate, NM_CONNECTION (master_connection), NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST, NULL)) + if (!nm_device_check_connection_available (candidate, + nm_settings_connection_get_connection (master_connection), + NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST, + NULL, + NULL)) continue; if (!nm_device_is_software (candidate)) { @@ -3725,18 +3874,18 @@ typedef struct { /** * find_slaves: * @manager: #NMManager object - * @connection: the master #NMSettingsConnection to find slave connections for - * @device: the master #NMDevice for the @connection + * @sett_conn: the master #NMSettingsConnection to find slave connections for + * @device: the master #NMDevice for the @sett_conn * @out_n_slaves: on return, the number of slaves found * - * Given an #NMSettingsConnection, attempts to find its slaves. If @connection is not + * Given an #NMSettingsConnection, attempts to find its slaves. If @sett_conn is not * master, or has not any slaves, this will return %NULL. * - * Returns: an array of #SlaveConnectionInfo for given master @connection, or %NULL + * Returns: an array of #SlaveConnectionInfo for given master @sett_conn, or %NULL **/ static SlaveConnectionInfo * find_slaves (NMManager *manager, - NMSettingsConnection *connection, + NMSettingsConnection *sett_conn, NMDevice *device, guint *out_n_slaves) { @@ -3751,7 +3900,7 @@ find_slaves (NMManager *manager, nm_assert (out_n_slaves); - s_con = nm_connection_get_setting_connection (NM_CONNECTION (connection)); + s_con = nm_connection_get_setting_connection (nm_settings_connection_get_connection (sett_conn)); g_return_val_if_fail (s_con, NULL); devices = g_hash_table_new (nm_direct_hash, NULL); @@ -3766,15 +3915,23 @@ find_slaves (NMManager *manager, for (i = 0; i < n_all_connections; i++) { NMSettingsConnection *master_connection = NULL; NMDevice *master_device = NULL, *slave_device; - NMConnection *candidate = NM_CONNECTION (all_connections[i]); - - find_master (manager, candidate, NULL, &master_connection, &master_device, NULL, NULL); - if ( (master_connection && master_connection == connection) + NMSettingsConnection *candidate = all_connections[i]; + + find_master (manager, + nm_settings_connection_get_connection (candidate), + NULL, + &master_connection, + &master_device, + NULL, + NULL); + if ( (master_connection && master_connection == sett_conn) || (master_device && master_device == device)) { slave_device = nm_manager_get_best_device_for_connection (manager, candidate, + NULL, FALSE, - devices); + devices, + NULL); if (!slaves) { /* what we allocate is quite likely much too large. Don't bother, it is only @@ -3783,7 +3940,7 @@ find_slaves (NMManager *manager, } nm_assert (n_slaves < n_all_connections); - slaves[n_slaves].connection = NM_SETTINGS_CONNECTION (candidate), + slaves[n_slaves].connection = candidate, slaves[n_slaves].device = slave_device, n_slaves++; @@ -3802,32 +3959,29 @@ static gboolean should_connect_slaves (NMConnection *connection, NMDevice *device) { NMSettingConnection *s_con; - NMSettingConnectionAutoconnectSlaves autoconnect_slaves; - gs_free char *value = NULL; + NMSettingConnectionAutoconnectSlaves val; 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) + val = nm_setting_connection_get_autoconnect_slaves (s_con); + if (val != 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); + val = nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, + "connection.autoconnect-slaves", + device, + 0, 1, -1); out: - if (autoconnect_slaves == NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES_NO) + if (val == NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES_NO) return FALSE; - if (autoconnect_slaves == NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES_YES) + if (val == NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES_YES) return TRUE; return FALSE; } -static gint +static int compare_slaves (gconstpointer a, gconstpointer b, gpointer sort_by_name) { const SlaveConnectionInfo *a_info = a; @@ -3855,7 +4009,8 @@ autoconnect_slaves (NMManager *self, { GError *local_err = NULL; - if (should_connect_slaves (NM_CONNECTION (master_connection), master_device)) { + if (should_connect_slaves (nm_settings_connection_get_connection (master_connection), + master_device)) { gs_free SlaveConnectionInfo *slaves = NULL; guint i, n_slaves = 0; @@ -3996,7 +4151,7 @@ active_connection_parent_active (NMActiveConnection *active, { NMDevice *device = nm_active_connection_get_device (active); GError *error = NULL; - NMSettingsConnection *connection; + NMSettingsConnection *sett_conn; NMDevice *parent; g_signal_handlers_disconnect_by_func (active, @@ -4012,10 +4167,13 @@ active_connection_parent_active (NMActiveConnection *active, return; } - connection = nm_active_connection_get_settings_connection (active); + sett_conn = nm_active_connection_get_settings_connection (active); parent = nm_active_connection_get_device (parent_ac); - if (!nm_device_create_and_realize (device, (NMConnection *) connection, parent, &error)) { + if (!nm_device_create_and_realize (device, + nm_settings_connection_get_connection (sett_conn), + parent, + &error)) { _LOGW (LOGD_CORE, "Could not realize device '%s': %s", nm_device_get_iface (device), error->message); nm_active_connection_set_state_fail (active, @@ -4033,11 +4191,13 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError * { NMDevice *device, *master_device = NULL; NMConnection *applied; - NMSettingsConnection *connection; + NMSettingsConnection *sett_conn; NMSettingsConnection *master_connection = NULL; NMConnection *existing_connection = NULL; NMActiveConnection *master_ac = NULL; NMAuthSubject *subject; + GError *local = NULL; + NMConnectionMultiConnect multi_connect; g_return_val_if_fail (NM_IS_MANAGER (self), FALSE); g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (active), FALSE); @@ -4048,8 +4208,8 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError * device = nm_active_connection_get_device (active); g_return_val_if_fail (device != NULL, FALSE); - connection = nm_active_connection_get_settings_connection (active); - nm_assert (connection); + sett_conn = nm_active_connection_get_settings_connection (active); + nm_assert (sett_conn); applied = nm_active_connection_get_applied_connection (active); @@ -4071,10 +4231,13 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError * } /* Final connection must be available on device */ - if (!nm_device_check_connection_available (device, applied, NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST, NULL)) { + if (!nm_device_check_connection_available (device, applied, NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST, NULL, &local)) { g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_CONNECTION, - "Connection '%s' is not available on the device %s at this time.", - nm_settings_connection_get_id (connection), nm_device_get_iface (device)); + "Connection '%s' is not available on device %s because %s", + nm_settings_connection_get_id (sett_conn), + nm_device_get_iface (device), + local->message); + g_error_free (local); return FALSE; } @@ -4085,7 +4248,9 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError * if (!nm_device_is_real (device)) { NMDevice *parent; - parent = find_parent_device_for_connection (self, (NMConnection *) connection, NULL); + parent = find_parent_device_for_connection (self, + nm_settings_connection_get_connection (sett_conn), + NULL); if (parent && !nm_device_is_real (parent)) { NMSettingsConnection *parent_con; @@ -4097,7 +4262,11 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError * return FALSE; } - parent_ac = nm_manager_activate_connection (self, parent_con, NULL, NULL, parent, + parent_ac = nm_manager_activate_connection (self, + parent_con, + NULL, + NULL, + parent, subject, NM_ACTIVATION_TYPE_MANAGED, nm_active_connection_get_activation_reason (active), @@ -4115,7 +4284,10 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError * nm_active_connection_set_parent (active, parent_ac); } else { /* We can realize now; no need to wait for a parent device. */ - if (!nm_device_create_and_realize (device, (NMConnection *) connection, parent, error)) { + if (!nm_device_create_and_realize (device, + nm_settings_connection_get_connection (sett_conn), + parent, + error)) { g_prefix_error (error, "%s failed to create resources: ", nm_device_get_iface (device)); return FALSE; } @@ -4123,11 +4295,15 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError * } /* Try to find the master connection/device if the connection has a dependency */ - if (!find_master (self, applied, device, - &master_connection, &master_device, &master_ac, + if (!find_master (self, + applied, + device, + &master_connection, + &master_device, + &master_ac, error)) { g_prefix_error (error, "Can not find a master for %s: ", - nm_settings_connection_get_id (connection)); + nm_settings_connection_get_id (sett_conn)); return FALSE; } @@ -4137,21 +4313,23 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError * if (master_connection || master_device) { if (master_connection) { _LOGD (LOGD_CORE, "Activation of '%s' requires master connection '%s'", - nm_settings_connection_get_id (connection), + nm_settings_connection_get_id (sett_conn), nm_settings_connection_get_id (master_connection)); } if (master_device) { _LOGD (LOGD_CORE, "Activation of '%s' requires master device '%s'", - nm_settings_connection_get_id (connection), + nm_settings_connection_get_id (sett_conn), nm_device_get_ip_iface (master_device)); } /* Ensure eg bond slave and the candidate master is a bond master */ - if (master_connection && !is_compatible_with_slave (NM_CONNECTION (master_connection), applied)) { + if ( master_connection + && !is_compatible_with_slave (nm_settings_connection_get_connection (master_connection), + applied)) { g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_DEPENDENCY_FAILED, "The master connection '%s' is not compatible with '%s'", nm_settings_connection_get_id (master_connection), - nm_settings_connection_get_id (connection)); + nm_settings_connection_get_id (sett_conn)); return FALSE; } @@ -4170,7 +4348,7 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError * nm_device_get_ip_iface (device)); } else { g_prefix_error (error, "Master connection '%s' can't be activated: ", - nm_settings_connection_get_id (connection)); + nm_settings_connection_get_id (sett_conn)); } return FALSE; } @@ -4187,22 +4365,30 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError * nm_active_connection_set_master (active, master_ac); _LOGD (LOGD_CORE, "Activation of '%s' depends on active connection %p %s", - nm_settings_connection_get_id (connection), + nm_settings_connection_get_id (sett_conn), master_ac, nm_dbus_object_get_path (NM_DBUS_OBJECT (master_ac)) ?: ""); } /* Check slaves for master connection and possibly activate them */ - autoconnect_slaves (self, connection, device, nm_active_connection_get_subject (active)); - - { + autoconnect_slaves (self, sett_conn, device, nm_active_connection_get_subject (active)); + + multi_connect = _nm_connection_get_multi_connect (nm_settings_connection_get_connection (sett_conn)); + if ( multi_connect == NM_CONNECTION_MULTI_CONNECT_MULTIPLE + || ( multi_connect == NM_CONNECTION_MULTI_CONNECT_MANUAL_MULTIPLE + && NM_IN_SET (nm_active_connection_get_activation_reason (active), + NM_ACTIVATION_REASON_ASSUME, + NM_ACTIVATION_REASON_AUTOCONNECT_SLAVES, + NM_ACTIVATION_REASON_USER_REQUEST))) { + /* the profile can be activated multiple times. Proceed. */ + } else { gs_unref_ptrarray GPtrArray *all_ac_arr = NULL; NMActiveConnection *ac; guint i, n_all; /* Disconnect the connection if already connected or queued for activation. * The connection cannot be active multiple times (at the same time). */ - ac = active_connection_find (self, connection, NULL, NM_ACTIVE_CONNECTION_STATE_ACTIVATED, + ac = active_connection_find (self, sett_conn, NULL, NM_ACTIVE_CONNECTION_STATE_ACTIVATED, &all_ac_arr); if (ac) { n_all = all_ac_arr ? all_ac_arr->len : ((guint) 1); @@ -4265,7 +4451,7 @@ _internal_activate_generic (NMManager *self, NMActiveConnection *active, GError * is exported, make sure the manager's activating-connection property * is up-to-date. */ - policy_activating_device_changed (G_OBJECT (priv->policy), NULL, self); + policy_activating_ac_changed (G_OBJECT (priv->policy), NULL, self); } return success; @@ -4274,7 +4460,8 @@ _internal_activate_generic (NMManager *self, NMActiveConnection *active, GError static NMActiveConnection * _new_active_connection (NMManager *self, gboolean is_vpn, - NMConnection *connection, + NMSettingsConnection *sett_conn, + NMConnection *incompl_conn, NMConnection *applied, const char *specific_object, NMDevice *device, @@ -4284,18 +4471,19 @@ _new_active_connection (NMManager *self, GError **error) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - NMSettingsConnection *settings_connection = NULL; NMDevice *parent_device; - g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); - g_return_val_if_fail (NM_IS_AUTH_SUBJECT (subject), NULL); - - nm_assert (is_vpn == _connection_is_vpn (connection)); + nm_assert (!sett_conn || NM_IS_SETTINGS_CONNECTION (sett_conn)); + nm_assert (!incompl_conn || NM_IS_CONNECTION (incompl_conn)); + nm_assert ((!incompl_conn) ^ (!sett_conn)); + nm_assert (NM_IS_AUTH_SUBJECT (subject)); + nm_assert (is_vpn == _connection_is_vpn (sett_conn + ? nm_settings_connection_get_connection (sett_conn) + : incompl_conn)); nm_assert (is_vpn || NM_IS_DEVICE (device)); nm_assert (!nm_streq0 (specific_object, "/")); - - if (NM_IS_SETTINGS_CONNECTION (connection)) - settings_connection = (NMSettingsConnection *) connection; + nm_assert (!applied || NM_IS_CONNECTION (applied)); + nm_assert (!is_vpn || !applied); if (is_vpn) { NMActiveConnection *parent; @@ -4303,21 +4491,20 @@ _new_active_connection (NMManager *self, /* FIXME: for VPN connections, we don't allow re-activating an * already active connection. It's a bug, and should be fixed together * when reworking VPN handling. */ - if (active_connection_find_by_connection (self, connection, NM_ACTIVE_CONNECTION_STATE_ACTIVATED, NULL)) { + if (active_connection_find_by_connection (self, + sett_conn, + incompl_conn, + NM_ACTIVE_CONNECTION_STATE_ACTIVATED, + NULL)) { g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_CONNECTION_ALREADY_ACTIVE, "Connection '%s' is already active", - nm_connection_get_id (connection)); + sett_conn ? nm_settings_connection_get_id (sett_conn) : nm_connection_get_id (incompl_conn)); return NULL; } - /* FIXME: apparently, activation here only works if @connection is - * a settings-connection. Which is not the case during AddAndActivatate. - * Probably, AddAndActivate is broken for VPN. */ if (activation_type != NM_ACTIVATION_TYPE_MANAGED) g_return_val_if_reached (NULL); - g_return_val_if_fail (!settings_connection || NM_IS_SETTINGS_CONNECTION (settings_connection), NULL); - if (specific_object) { /* Find the specific connection the client requested we use */ parent = active_connection_get_by_path (self, specific_object); @@ -4348,14 +4535,14 @@ _new_active_connection (NMManager *self, return NULL; } - return (NMActiveConnection *) nm_vpn_connection_new (settings_connection, + return (NMActiveConnection *) nm_vpn_connection_new (sett_conn, parent_device, nm_dbus_object_get_path (NM_DBUS_OBJECT (parent)), activation_reason, subject); } - return (NMActiveConnection *) nm_act_request_new (settings_connection, + return (NMActiveConnection *) nm_act_request_new (sett_conn, applied, specific_object, subject, @@ -4416,17 +4603,17 @@ fail: /** * nm_manager_activate_connection(): * @self: the #NMManager - * @connection: the #NMSettingsConnection to activate on @device + * @sett_conn: the #NMSettingsConnection to activate on @device * @applied: (allow-none): the applied connection to activate on @device * @specific_object: the specific object path, if any, for the activation - * @device: the #NMDevice to activate @connection on. Can be %NULL for VPNs. + * @device: the #NMDevice to activate @sett_conn on. Can be %NULL for VPNs. * @subject: the subject which requested activation * @activation_type: whether to assume the connection. That is, take over gracefully, * non-destructible. * @activation_reason: the reason for activation * @error: return location for an error * - * Begins a new internally-initiated activation of @connection on @device. + * Begins a new internally-initiated activation of @sett_conn on @device. * @subject should be the subject of the activation that triggered this * one, or if this is an autoconnect request, a new internal subject. * The returned #NMActiveConnection is owned by the Manager and should be @@ -4434,11 +4621,11 @@ fail: * is supplied, it shall not be modified by the caller afterwards. * * Returns: (transfer none): the new #NMActiveConnection that tracks - * activation of @connection on @device + * activation of @sett_conn on @device */ NMActiveConnection * nm_manager_activate_connection (NMManager *self, - NMSettingsConnection *connection, + NMSettingsConnection *sett_conn, NMConnection *applied, const char *specific_object, NMDevice *device, @@ -4453,15 +4640,15 @@ nm_manager_activate_connection (NMManager *self, gboolean is_vpn; g_return_val_if_fail (NM_IS_MANAGER (self), NULL); - g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (connection), NULL); - is_vpn = _connection_is_vpn (NM_CONNECTION (connection)); + g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (sett_conn), NULL); + is_vpn = _connection_is_vpn (nm_settings_connection_get_connection (sett_conn)); g_return_val_if_fail (is_vpn || NM_IS_DEVICE (device), NULL); g_return_val_if_fail (!error || !*error, NULL); nm_assert (!nm_streq0 (specific_object, "/")); priv = NM_MANAGER_GET_PRIVATE (self); - if (!nm_auth_is_subject_in_acl_set_error (NM_CONNECTION (connection), + if (!nm_auth_is_subject_in_acl_set_error (nm_settings_connection_get_connection (sett_conn), subject, NM_MANAGER_ERROR, NM_MANAGER_ERROR_PERMISSION_DENIED, @@ -4479,7 +4666,7 @@ nm_manager_activate_connection (NMManager *self, continue; active = async_op_data->ac_auth.active; - if ( connection == nm_active_connection_get_settings_connection (active) + if ( sett_conn == nm_active_connection_get_settings_connection (active) && nm_streq0 (nm_active_connection_get_specific_object (active), specific_object) && (!device || nm_active_connection_get_device (active) == device) && nm_auth_subject_is_internal (nm_active_connection_get_subject (active)) @@ -4490,7 +4677,8 @@ nm_manager_activate_connection (NMManager *self, active = _new_active_connection (self, is_vpn, - NM_CONNECTION (connection), + sett_conn, + NULL, applied, specific_object, device, @@ -4513,7 +4701,9 @@ nm_manager_activate_connection (NMManager *self, * validate_activation_request: * @self: the #NMManager * @context: the D-Bus context of the requestor - * @connection: the partial or complete #NMConnection to be activated + * @sett_conn: the #NMSettingsConnection to be activated, or %NULL if there + * is only a partial activation. + * @connection: the partial #NMConnection to be activated (if @sett_conn is unspecified) * @device_path: the object path of the device to be activated, or NULL * @out_device: on successful reutrn, the #NMDevice to be activated with @connection * The caller may pass in a device which shortcuts the lookup by path. @@ -4532,6 +4722,7 @@ nm_manager_activate_connection (NMManager *self, static NMAuthSubject * validate_activation_request (NMManager *self, GDBusMethodInvocation *context, + NMSettingsConnection *sett_conn, NMConnection *connection, const char *device_path, NMDevice **out_device, @@ -4542,10 +4733,16 @@ validate_activation_request (NMManager *self, gboolean is_vpn = FALSE; gs_unref_object NMAuthSubject *subject = NULL; - nm_assert (NM_IS_CONNECTION (connection)); + nm_assert (!sett_conn || NM_IS_SETTINGS_CONNECTION (sett_conn)); + nm_assert (!connection || NM_IS_CONNECTION (connection)); + nm_assert (sett_conn || connection); + nm_assert (!connection || !sett_conn || connection == nm_settings_connection_get_connection (sett_conn)); nm_assert (out_device); nm_assert (out_is_vpn); + if (!connection) + connection = nm_settings_connection_get_connection (sett_conn); + /* Validate the caller */ subject = nm_auth_subject_new_unix_process_from_context (context); if (!subject) { @@ -4581,17 +4778,20 @@ validate_activation_request (NMManager *self, return NULL; } } else if (!is_vpn) { - device = nm_manager_get_best_device_for_connection (self, connection, TRUE, NULL); + gs_free_error GError *local = NULL; + + device = nm_manager_get_best_device_for_connection (self, sett_conn, connection, TRUE, NULL, &local); if (!device) { gs_free char *iface = NULL; /* VPN and software-device connections don't need a device yet, * but non-virtual connections do ... */ if (!nm_connection_is_virtual (connection)) { - g_set_error_literal (error, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_UNKNOWN_DEVICE, - "No suitable device found for this connection."); + g_set_error (error, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_UNKNOWN_DEVICE, + "No suitable device found for this connection (%s).", + local->message); return NULL; } @@ -4677,7 +4877,7 @@ impl_manager_activate_connection (NMDBusObject *obj, NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); gs_unref_object NMActiveConnection *active = NULL; gs_unref_object NMAuthSubject *subject = NULL; - NMSettingsConnection *connection = NULL; + NMSettingsConnection *sett_conn = NULL; NMDevice *device = NULL; gboolean is_vpn = FALSE; GError *error = NULL; @@ -4697,8 +4897,8 @@ impl_manager_activate_connection (NMDBusObject *obj, * (since this is an explicit request, not an auto-activation request). */ if (connection_path) { - connection = nm_settings_get_connection_by_path (priv->settings, connection_path); - if (!connection) { + sett_conn = nm_settings_get_connection_by_path (priv->settings, connection_path); + if (!sett_conn) { error = g_error_new_literal (NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_CONNECTION, "Connection could not be found."); @@ -4718,14 +4918,15 @@ impl_manager_activate_connection (NMDBusObject *obj, goto error; } - connection = nm_device_get_best_connection (device, specific_object_path, &error); - if (!connection) + sett_conn = nm_device_get_best_connection (device, specific_object_path, &error); + if (!sett_conn) goto error; } subject = validate_activation_request (self, invocation, - NM_CONNECTION (connection), + sett_conn, + NULL, device_path, &device, &is_vpn, @@ -4735,7 +4936,8 @@ impl_manager_activate_connection (NMDBusObject *obj, active = _new_active_connection (self, is_vpn, - NM_CONNECTION (connection), + sett_conn, + NULL, NULL, specific_object_path, device, @@ -4759,8 +4961,8 @@ impl_manager_activate_connection (NMDBusObject *obj, return; error: - if (connection) { - nm_audit_log_connection_op (NM_AUDIT_OP_CONN_ACTIVATE, connection, FALSE, NULL, + if (sett_conn) { + nm_audit_log_connection_op (NM_AUDIT_OP_CONN_ACTIVATE, sett_conn, FALSE, NULL, subject, error->message); } g_dbus_method_invocation_take_error (invocation, error); @@ -4875,7 +5077,7 @@ impl_manager_add_and_activate_connection (NMDBusObject *obj, { NMManager *self = NM_MANAGER (obj); NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - gs_unref_object NMConnection *connection = NULL; + gs_unref_object NMConnection *incompl_conn = NULL; NMActiveConnection *active = NULL; gs_unref_object NMAuthSubject *subject = NULL; GError *error = NULL; @@ -4884,6 +5086,7 @@ impl_manager_add_and_activate_connection (NMDBusObject *obj, gs_unref_variant GVariant *settings = NULL; const char *device_path; const char *specific_object_path; + gs_free NMConnection **conns = NULL; g_variant_get (parameters, "(@a{sa{sv}}&o&o)", &settings, &device_path, &specific_object_path); @@ -4897,13 +5100,14 @@ impl_manager_add_and_activate_connection (NMDBusObject *obj, * specific data being in the connection till then (especially in * validate_activation_request()). */ - connection = nm_simple_connection_new (); + incompl_conn = nm_simple_connection_new (); if (settings && g_variant_n_children (settings)) - _nm_connection_replace_settings (connection, settings, NM_SETTING_PARSE_FLAGS_STRICT, NULL); + _nm_connection_replace_settings (incompl_conn, settings, NM_SETTING_PARSE_FLAGS_STRICT, NULL); subject = validate_activation_request (self, invocation, - connection, + NULL, + incompl_conn, device_path, &device, &is_vpn, @@ -4913,7 +5117,7 @@ impl_manager_add_and_activate_connection (NMDBusObject *obj, if (is_vpn) { /* Try to fill the VPN's connection setting and name at least */ - if (!nm_connection_get_setting_vpn (connection)) { + if (!nm_connection_get_setting_vpn (incompl_conn)) { error = g_error_new_literal (NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_MISSING_SETTING, "VPN connections require a 'vpn' setting"); @@ -4921,27 +5125,31 @@ impl_manager_add_and_activate_connection (NMDBusObject *obj, goto error; } + conns = nm_settings_connections_array_to_connections (nm_settings_get_connections (priv->settings, NULL), -1); + nm_utils_complete_generic (priv->platform, - connection, + incompl_conn, NM_SETTING_VPN_SETTING_NAME, - (NMConnection *const*) nm_settings_get_connections (priv->settings, NULL), + conns, NULL, _("VPN connection"), NULL, FALSE); /* No IPv6 by default for now */ } else { + conns = nm_settings_connections_array_to_connections (nm_settings_get_connections (priv->settings, NULL), -1); /* Let each device subclass complete the connection */ if (!nm_device_complete_connection (device, - connection, + incompl_conn, specific_object_path, - (NMConnection *const*) nm_settings_get_connections (priv->settings, NULL), + conns, &error)) goto error; } active = _new_active_connection (self, is_vpn, - connection, + NULL, + incompl_conn, NULL, specific_object_path, device, @@ -4952,15 +5160,16 @@ impl_manager_add_and_activate_connection (NMDBusObject *obj, if (!active) goto error; - nm_active_connection_authorize (active, connection, + nm_active_connection_authorize (active, + incompl_conn, _async_op_complete_ac_auth_cb, _async_op_data_new_ac_auth_add_and_activate (self, active, invocation, - connection)); + incompl_conn)); /* we passed the pointers on to _async_op_data_new_ac_auth_add_and_activate() */ - g_steal_pointer (&connection); + g_steal_pointer (&incompl_conn); g_steal_pointer (&active); return; @@ -5077,7 +5286,7 @@ impl_manager_deactivate_connection (NMDBusObject *obj, NMManager *self = NM_MANAGER (obj); NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); NMActiveConnection *ac; - NMSettingsConnection *connection = NULL; + NMSettingsConnection *sett_conn = NULL; GError *error = NULL; NMAuthSubject *subject = NULL; NMAuthChain *chain; @@ -5088,9 +5297,9 @@ impl_manager_deactivate_connection (NMDBusObject *obj, /* Find the connection by its object path */ ac = active_connection_get_by_path (self, active_path); if (ac) - connection = nm_active_connection_get_settings_connection (ac); + sett_conn = nm_active_connection_get_settings_connection (ac); - if (!connection) { + if (!sett_conn) { error = g_error_new_literal (NM_MANAGER_ERROR, NM_MANAGER_ERROR_CONNECTION_NOT_ACTIVE, "The connection was not active."); @@ -5106,7 +5315,7 @@ impl_manager_deactivate_connection (NMDBusObject *obj, goto done; } - if (!nm_auth_is_subject_in_acl_set_error (NM_CONNECTION (connection), + if (!nm_auth_is_subject_in_acl_set_error (nm_settings_connection_get_connection (sett_conn), subject, NM_MANAGER_ERROR, NM_MANAGER_ERROR_PERMISSION_DENIED, @@ -5128,8 +5337,9 @@ impl_manager_deactivate_connection (NMDBusObject *obj, done: if (error) { - if (connection) { - nm_audit_log_connection_op (NM_AUDIT_OP_CONN_DEACTIVATE, connection, FALSE, NULL, + if (sett_conn) { + nm_audit_log_connection_op (NM_AUDIT_OP_CONN_DEACTIVATE, + sett_conn, FALSE, NULL, subject, error->message); } g_dbus_method_invocation_take_error (invocation, error); @@ -5878,66 +6088,76 @@ start_factory (NMDeviceFactory *factory, gpointer user_data) nm_device_factory_start (factory); } -void -nm_manager_write_device_state (NMManager *self) +gboolean +nm_manager_write_device_state (NMManager *self, NMDevice *device) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - NMDevice *device; - gs_unref_hashtable GHashTable *seen_ifindexes = NULL; - gint nm_owned; + int ifindex; + gboolean managed; + NMConfigDeviceStateManagedType managed_type; + const char *uuid = NULL; + const char *perm_hw_addr_fake = NULL; + gboolean perm_hw_addr_is_fake; + guint32 route_metric_default_aspired; + guint32 route_metric_default_effective; + int nm_owned; + + ifindex = nm_device_get_ip_ifindex (device); + if (ifindex <= 0) + return FALSE; + if (ifindex == 1) { + /* ignore loopback */ + return FALSE; + } - seen_ifindexes = g_hash_table_new (nm_direct_hash, NULL); + if (!nm_platform_link_get (priv->platform, ifindex)) + return FALSE; - c_list_for_each_entry (device, &priv->devices_lst_head, devices_lst) { - int ifindex; - gboolean managed; - NMConfigDeviceStateManagedType managed_type; - NMConnection *settings_connection; - const char *uuid = NULL; - const char *perm_hw_addr_fake = NULL; - gboolean perm_hw_addr_is_fake; - guint32 route_metric_default_aspired; - guint32 route_metric_default_effective; - - ifindex = nm_device_get_ip_ifindex (device); - if (ifindex <= 0) - continue; - if (ifindex == 1) { - /* ignore loopback */ - continue; - } + managed = nm_device_get_managed (device, FALSE); + if (managed) { + NMSettingsConnection *sett_conn; - if (!nm_platform_link_get (priv->platform, ifindex)) - continue; + sett_conn = nm_device_get_settings_connection (device); + if (sett_conn) + uuid = nm_settings_connection_get_uuid (sett_conn); + managed_type = NM_CONFIG_DEVICE_STATE_MANAGED_TYPE_MANAGED; + } else if (nm_device_get_unmanaged_flags (device, NM_UNMANAGED_USER_EXPLICIT)) + managed_type = NM_CONFIG_DEVICE_STATE_MANAGED_TYPE_UNMANAGED; + else + managed_type = NM_CONFIG_DEVICE_STATE_MANAGED_TYPE_UNKNOWN; - managed = nm_device_get_managed (device, FALSE); - if (managed) { - settings_connection = NM_CONNECTION (nm_device_get_settings_connection (device)); - if (settings_connection) - uuid = nm_connection_get_uuid (settings_connection); - managed_type = NM_CONFIG_DEVICE_STATE_MANAGED_TYPE_MANAGED; - } else if (nm_device_get_unmanaged_flags (device, NM_UNMANAGED_USER_EXPLICIT)) - managed_type = NM_CONFIG_DEVICE_STATE_MANAGED_TYPE_UNMANAGED; - else - managed_type = NM_CONFIG_DEVICE_STATE_MANAGED_TYPE_UNKNOWN; + perm_hw_addr_fake = nm_device_get_permanent_hw_address_full (device, FALSE, &perm_hw_addr_is_fake); + if (perm_hw_addr_fake && !perm_hw_addr_is_fake) + perm_hw_addr_fake = NULL; + + nm_owned = nm_device_is_software (device) ? nm_device_is_nm_owned (device) : -1; + + route_metric_default_effective = _device_route_metric_get (self, ifindex, NM_DEVICE_TYPE_UNKNOWN, + TRUE, &route_metric_default_aspired); - perm_hw_addr_fake = nm_device_get_permanent_hw_address_full (device, FALSE, &perm_hw_addr_is_fake); - if (perm_hw_addr_fake && !perm_hw_addr_is_fake) - perm_hw_addr_fake = NULL; + return nm_config_device_state_write (ifindex, + managed_type, + perm_hw_addr_fake, + uuid, + nm_owned, + route_metric_default_aspired, + route_metric_default_effective); +} - nm_owned = nm_device_is_software (device) ? nm_device_is_nm_owned (device) : -1; +void +nm_manager_write_device_state_all (NMManager *self) +{ + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); + gs_unref_hashtable GHashTable *seen_ifindexes = NULL; + NMDevice *device; - route_metric_default_effective = _device_route_metric_get (self, ifindex, NM_DEVICE_TYPE_UNKNOWN, - TRUE, &route_metric_default_aspired); + seen_ifindexes = g_hash_table_new (nm_direct_hash, NULL); - if (nm_config_device_state_write (ifindex, - managed_type, - perm_hw_addr_fake, - uuid, - nm_owned, - route_metric_default_aspired, - route_metric_default_effective)) - g_hash_table_add (seen_ifindexes, GINT_TO_POINTER (ifindex)); + c_list_for_each_entry (device, &priv->devices_lst_head, devices_lst) { + if (nm_manager_write_device_state (self, device)) { + g_hash_table_add (seen_ifindexes, + GINT_TO_POINTER (nm_device_get_ip_ifindex (device))); + } } nm_config_device_state_prune_unseen (seen_ifindexes); @@ -6017,7 +6237,7 @@ nm_manager_start (NMManager *self, GError **error) NULL, NULL, nm_settings_connection_cmp_autoconnect_priority_p_with_data, NULL); for (i = 0; connections[i]; i++) - connection_changed (self, NM_CONNECTION (connections[i])); + connection_changed (self, connections[i]); nm_clear_g_source (&priv->devices_inited_id); priv->devices_inited_id = g_idle_add_full (G_PRIORITY_LOW + 10, devices_inited_cb, self, NULL); @@ -6117,25 +6337,19 @@ connection_metered_changed (GObject *object, } static void -policy_default_device_changed (GObject *object, GParamSpec *pspec, gpointer user_data) +policy_default_ac_changed (GObject *object, GParamSpec *pspec, gpointer user_data) { NMManager *self = NM_MANAGER (user_data); NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - NMDevice *best; NMActiveConnection *ac; /* Note: this assumes that it's not possible for the IP4 default * route to be going over the default-ip6-device. If that changes, * we need something more complicated here. */ - best = nm_policy_get_default_ip4_device (priv->policy); - if (!best) - best = nm_policy_get_default_ip6_device (priv->policy); - - if (best) - ac = NM_ACTIVE_CONNECTION (nm_device_get_act_request (best)); - else - ac = NULL; + ac = nm_policy_get_default_ip4_ac (priv->policy); + if (!ac) + ac = nm_policy_get_default_ip6_ac (priv->policy); if (ac != priv->primary_connection) { if (priv->primary_connection) { @@ -6148,10 +6362,12 @@ policy_default_device_changed (GObject *object, GParamSpec *pspec, gpointer user priv->primary_connection = ac ? g_object_ref (ac) : NULL; if (priv->primary_connection) { - g_signal_connect (priv->primary_connection, NM_ACTIVE_CONNECTION_DEVICE_METERED_CHANGED, + g_signal_connect (priv->primary_connection, + NM_ACTIVE_CONNECTION_DEVICE_METERED_CHANGED, G_CALLBACK (connection_metered_changed), self); } - _LOGD (LOGD_CORE, "PrimaryConnection now %s", ac ? nm_active_connection_get_settings_connection_id (ac) : "(none)"); + _LOGD (LOGD_CORE, "PrimaryConnection now %s", + ac ? nm_active_connection_get_settings_connection_id (ac) : "(none)"); _notify (self, PROP_PRIMARY_CONNECTION); _notify (self, PROP_PRIMARY_CONNECTION_TYPE); nm_manager_update_metered (self); @@ -6159,34 +6375,29 @@ policy_default_device_changed (GObject *object, GParamSpec *pspec, gpointer user } static void -policy_activating_device_changed (GObject *object, GParamSpec *pspec, gpointer user_data) +policy_activating_ac_changed (GObject *object, GParamSpec *pspec, gpointer user_data) { NMManager *self = NM_MANAGER (user_data); NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - NMDevice *activating, *best; - NMActiveConnection *ac; + NMActiveConnection *activating, *best; - /* We only look at activating-ip6-device if activating-ip4-device - * AND default-ip4-device are NULL; if default-ip4-device is - * non-NULL, then activating-ip6-device is irrelevant, since while - * that device might become the new default-ip6-device, it can't - * become primary-connection while default-ip4-device is set to + /* We only look at activating-ip6-ac if activating-ip4-ac + * AND default-ip4-ac are NULL; if default-ip4-ac is + * non-NULL, then activating-ip6-ac is irrelevant, since while + * that AC might become the new default-ip6-ac, it can't + * become primary-connection while default-ip4-ac is set to * something else. */ - activating = nm_policy_get_activating_ip4_device (priv->policy); - best = nm_policy_get_default_ip4_device (priv->policy); + activating = nm_policy_get_activating_ip4_ac (priv->policy); + best = nm_policy_get_default_ip4_ac (priv->policy); if (!activating && !best) - activating = nm_policy_get_activating_ip6_device (priv->policy); + activating = nm_policy_get_activating_ip6_ac (priv->policy); - if (activating) - ac = NM_ACTIVE_CONNECTION (nm_device_get_act_request (activating)); - else - ac = NULL; - - if (ac != priv->activating_connection) { - g_clear_object (&priv->activating_connection); - priv->activating_connection = ac ? g_object_ref (ac) : NULL; - _LOGD (LOGD_CORE, "ActivatingConnection now %s", ac ? nm_active_connection_get_settings_connection_id (ac) : "(none)"); + if (nm_g_object_ref_set (&priv->activating_connection, activating)) { + _LOGD (LOGD_CORE, "ActivatingConnection now %s", + activating + ? nm_active_connection_get_settings_connection_id (activating) + : "(none)"); _notify (self, PROP_ACTIVATING_CONNECTION); } } @@ -6691,12 +6902,12 @@ nm_manager_set_capability (NMManager *self, priv = NM_MANAGER_GET_PRIVATE (self); - idx = _nm_utils_array_find_binary_search (&g_array_index (priv->capabilities, guint32, 0), - sizeof (guint32), - priv->capabilities->len, - &cap_i, - nm_cmp_uint32_p_with_data, - NULL); + idx = nm_utils_array_find_binary_search (&g_array_index (priv->capabilities, guint32, 0), + sizeof (guint32), + priv->capabilities->len, + &cap_i, + nm_cmp_uint32_p_with_data, + NULL); if (idx >= 0) return; @@ -6777,14 +6988,14 @@ constructed (GObject *object) */ priv->policy = nm_policy_new (self, priv->settings); - g_signal_connect (priv->policy, "notify::" NM_POLICY_DEFAULT_IP4_DEVICE, - G_CALLBACK (policy_default_device_changed), self); - g_signal_connect (priv->policy, "notify::" NM_POLICY_DEFAULT_IP6_DEVICE, - G_CALLBACK (policy_default_device_changed), self); - g_signal_connect (priv->policy, "notify::" NM_POLICY_ACTIVATING_IP4_DEVICE, - G_CALLBACK (policy_activating_device_changed), self); - g_signal_connect (priv->policy, "notify::" NM_POLICY_ACTIVATING_IP6_DEVICE, - G_CALLBACK (policy_activating_device_changed), self); + g_signal_connect (priv->policy, "notify::" NM_POLICY_DEFAULT_IP4_AC, + G_CALLBACK (policy_default_ac_changed), self); + g_signal_connect (priv->policy, "notify::" NM_POLICY_DEFAULT_IP6_AC, + G_CALLBACK (policy_default_ac_changed), self); + g_signal_connect (priv->policy, "notify::" NM_POLICY_ACTIVATING_IP4_AC, + G_CALLBACK (policy_activating_ac_changed), self); + g_signal_connect (priv->policy, "notify::" NM_POLICY_ACTIVATING_IP6_AC, + G_CALLBACK (policy_activating_ac_changed), self); priv->config = g_object_ref (nm_config_get ()); g_signal_connect (G_OBJECT (priv->config), @@ -7122,8 +7333,8 @@ dispose (GObject *object) } if (priv->policy) { - g_signal_handlers_disconnect_by_func (priv->policy, policy_default_device_changed, self); - g_signal_handlers_disconnect_by_func (priv->policy, policy_activating_device_changed, self); + g_signal_handlers_disconnect_by_func (priv->policy, policy_default_ac_changed, self); + g_signal_handlers_disconnect_by_func (priv->policy, policy_activating_ac_changed, self); g_clear_object (&priv->policy); } |