diff options
| author | Michael Biebl <biebl@debian.org> | 2018-10-20 01:30:31 +0200 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2018-10-20 01:30:31 +0200 |
| commit | 6518e361171f64bcaaa4bf868139362ed95cc2e0 (patch) | |
| tree | d2d5b53faf80646a40ec2c0c7f2a42b3959612f5 /src/nm-manager.c | |
| parent | e126f3e804c35480c4f075777430419d6ece23da (diff) | |
New upstream version 1.14.2 upstream/1.14.2
Diffstat (limited to 'src/nm-manager.c')
| -rw-r--r-- | src/nm-manager.c | 1000 |
1 files changed, 667 insertions, 333 deletions
diff --git a/src/nm-manager.c b/src/nm-manager.c index ad906169..7598995d 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); } @@ -1599,7 +1632,7 @@ remove_device (NMManager *self, nm_device_sys_iface_state_set (device, NM_DEVICE_SYS_IFACE_STATE_REMOVED); nm_device_set_unmanaged_by_flags (device, NM_UNMANAGED_PLATFORM_INIT, TRUE, NM_DEVICE_STATE_REASON_REMOVED); } - } else if (quitting && nm_config_get_configure_and_quit (priv->config)) { + } else if (quitting && nm_config_get_configure_and_quit (priv->config) == NM_CONFIG_CONFIGURE_AND_QUIT_ENABLED) { nm_device_spawn_iface_helper (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); @@ -3244,29 +3319,133 @@ nm_manager_get_devices (NMManager *manager) return &NM_MANAGER_GET_PRIVATE (manager)->devices_lst_head; } +typedef enum { + DEVICE_ACTIVATION_PRIO_NONE, + DEVICE_ACTIVATION_PRIO_UNMANAGED, + DEVICE_ACTIVATION_PRIO_UNAVAILABLE, + DEVICE_ACTIVATION_PRIO_DEACTIVATING, + DEVICE_ACTIVATION_PRIO_ACTIVATING, + DEVICE_ACTIVATION_PRIO_ACTIVATED, + DEVICE_ACTIVATION_PRIO_DISCONNECTED, + + _DEVICE_ACTIVATION_PRIO_BEST = DEVICE_ACTIVATION_PRIO_DISCONNECTED, +} DeviceActivationPrio; + +static DeviceActivationPrio +_device_get_activation_prio (NMDevice *device) +{ + if (!nm_device_get_managed (device, TRUE)) + return DEVICE_ACTIVATION_PRIO_NONE; + + switch (nm_device_get_state (device)) { + case NM_DEVICE_STATE_DISCONNECTED: + return DEVICE_ACTIVATION_PRIO_DISCONNECTED; + case NM_DEVICE_STATE_ACTIVATED: + return DEVICE_ACTIVATION_PRIO_ACTIVATED; + case NM_DEVICE_STATE_PREPARE: + case NM_DEVICE_STATE_CONFIG: + case NM_DEVICE_STATE_NEED_AUTH: + case NM_DEVICE_STATE_IP_CONFIG: + case NM_DEVICE_STATE_IP_CHECK: + case NM_DEVICE_STATE_SECONDARIES: + return DEVICE_ACTIVATION_PRIO_ACTIVATING; + case NM_DEVICE_STATE_DEACTIVATING: + case NM_DEVICE_STATE_FAILED: + return DEVICE_ACTIVATION_PRIO_DEACTIVATING; + case NM_DEVICE_STATE_UNAVAILABLE: + return DEVICE_ACTIVATION_PRIO_UNAVAILABLE; + case NM_DEVICE_STATE_UNKNOWN: + case NM_DEVICE_STATE_UNMANAGED: + return DEVICE_ACTIVATION_PRIO_UNMANAGED; + } + + g_return_val_if_reached (DEVICE_ACTIVATION_PRIO_UNAVAILABLE); +} + 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; NMActiveConnection *ac; NMDevice *ac_device; NMDevice *device; + struct { + NMDevice *device; + DeviceActivationPrio prio; + } best = { + .device = NULL, + .prio = DEVICE_ACTIVATION_PRIO_NONE, + }; NMDeviceCheckConAvailableFlags flags; gs_unref_ptrarray GPtrArray *all_ac_arr = NULL; + gs_free_error GError *local_best = NULL; + NMConnectionMultiConnect multi_connect; + + 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); + + multi_connect = _nm_connection_get_multi_connect (connection); - flags = for_user_request ? NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST : NM_DEVICE_CHECK_CON_AVAILABLE_NONE; + if (!for_user_request) + flags = NM_DEVICE_CHECK_CON_AVAILABLE_NONE; + else { + /* if the profile is multi-connect=single, we also consider devices which + * are marked as unmanaged. And explicit user-request shows sufficent user + * intent to make the device managed. + * That is also, because we expect that such profile is suitably tied + * to the intended device. So when an unmanaged device matches, the user's + * intent is clear. + * + * For multi-connect != single devices that is different. The profile + * is not restricted to a particular device. + * For that reason, plain `nmcli connection up "$MULIT_PROFILE"` seems + * less suitable for multi-connect profiles, because the target device is + * left unspecified. Anyway, if a user issues + * + * $ nmcli device set "$DEVICE" managed no + * $ nmcli connection up "$MULIT_PROFILE" + * + * then it is reasonable for multi-connect profiles to not consider + * the device a suitable candidate. + * + * This may be seen inconsistent, but I think that it makes a lot of + * sense. Also note that "connection.multi-connect" work quite differently + * in aspects like activation. E.g. `nmcli connection up` of multi-connect + * "single" profile, will deactivate the profile if it is active already. + * That is different from multi-connect profiles, where it will aim to + * activate the profile one more time on an hitherto disconnected device. + */ + if (multi_connect == NM_CONNECTION_MULTI_CONNECT_SINGLE) + flags = NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST; + else + flags = NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST & ~_NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_OVERRULE_UNMANAGED; + } - ac = active_connection_find_by_connection (self, connection, NM_ACTIVE_CONNECTION_STATE_DEACTIVATING, &all_ac_arr); - if (ac) { + if ( multi_connect == NM_CONNECTION_MULTI_CONNECT_SINGLE + && (ac = active_connection_find_by_connection (self, sett_conn, connection, NM_ACTIVE_CONNECTION_STATE_DEACTIVATING, &all_ac_arr))) { + /* if we have a profile which may activate on only one device (multi-connect single), then + * we prefer the device on which the profile is already active. It means to reactivate + * the profile on the same device. + * + * If the profile can be activated on multiple devices, we don't do this. In fact, the + * check below for the DeviceActivationPrio will prefer devices which are not already + * activated (with this or another) profile. */ 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) { @@ -3283,7 +3462,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); @@ -3331,15 +3510,87 @@ 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; + DeviceActivationPrio prio; - 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)) - return device; + /* determine the priority of this device. Currently this priority is independent + * of the profile (connection) and the device's details (aside the state). + * + * Maybe nm_device_check_connection_available() should instead return a priority, + * as it has more information available. + * + * For example, if you have multiple Wi-Fi devices, currently a user-request would + * also select the device if the AP is not visible. Optimally, if one of the two + * devices sees the AP and the other one doesn't, the former would be preferred. + * For that, the priority would need to be determined by nm_device_check_connection_available(). */ + prio = _device_get_activation_prio (device); + if ( prio <= best.prio + && best.device) { + /* we already have a matching device with a better priority. This candidate + * cannot be better. Skip the check. + * + * Also note, that below we collect the best error message @local_best. + * Since we already have best.device, the error message does not matter + * either, and we can skip nm_device_check_connection_available() altogether. */ + continue; + } + + if (nm_device_check_connection_available (device, + connection, + flags, + NULL, + error ? &local : NULL)) { + if (prio == _DEVICE_ACTIVATION_PRIO_BEST) { + /* this device already has the best priority. It cannot get better + * and finish the search. */ + return device; + } + best.prio = prio; + best.device = device; + continue; + } + + 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 (best.device) + return best.device; + + 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; } @@ -3508,7 +3759,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); @@ -3527,7 +3778,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)); @@ -3627,7 +3880,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)); @@ -3652,17 +3907,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, @@ -3698,7 +3958,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)) { @@ -3737,18 +4001,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) { @@ -3763,7 +4027,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); @@ -3778,15 +4042,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 @@ -3795,7 +4067,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++; @@ -3814,32 +4086,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; @@ -3867,7 +4136,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; @@ -4008,7 +4278,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, @@ -4024,10 +4294,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, @@ -4045,11 +4318,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); @@ -4060,8 +4335,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); @@ -4083,10 +4358,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; } @@ -4097,7 +4375,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; @@ -4109,7 +4389,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), @@ -4127,7 +4411,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; } @@ -4135,11 +4422,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; } @@ -4149,21 +4440,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; } @@ -4182,7 +4475,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; } @@ -4199,22 +4492,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); @@ -4277,7 +4578,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; @@ -4286,7 +4587,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, @@ -4296,18 +4598,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; @@ -4315,21 +4618,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); @@ -4360,14 +4662,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, @@ -4428,17 +4730,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 @@ -4446,11 +4748,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, @@ -4465,15 +4767,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, @@ -4491,7 +4793,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)) @@ -4502,7 +4804,8 @@ nm_manager_activate_connection (NMManager *self, active = _new_active_connection (self, is_vpn, - NM_CONNECTION (connection), + sett_conn, + NULL, applied, specific_object, device, @@ -4525,7 +4828,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. @@ -4544,6 +4849,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, @@ -4554,10 +4860,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) { @@ -4593,17 +4905,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; } @@ -4689,7 +5004,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; @@ -4709,8 +5024,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."); @@ -4730,14 +5045,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, @@ -4747,7 +5063,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, @@ -4771,8 +5088,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); @@ -4887,7 +5204,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; @@ -4896,6 +5213,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); @@ -4909,13 +5227,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, @@ -4925,7 +5244,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"); @@ -4933,27 +5252,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, @@ -4964,15 +5287,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; @@ -5089,7 +5413,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; @@ -5100,9 +5424,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."); @@ -5118,7 +5442,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, @@ -5140,8 +5464,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); @@ -5890,66 +6215,84 @@ 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; + NMDhcp4Config *dhcp4_config; + const char *root_path = NULL; + + 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 = NULL; + + if (nm_device_get_state (device) <= NM_DEVICE_STATE_ACTIVATED) + 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; - if (!nm_platform_link_get (priv->platform, ifindex)) - continue; + 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; - 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; + 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); + + dhcp4_config = nm_device_get_dhcp4_config (device); + if (dhcp4_config) + root_path = nm_dhcp4_config_get_option (dhcp4_config, "root_path"); - 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, + root_path); +} - 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); @@ -6029,7 +6372,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); @@ -6129,25 +6472,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) { @@ -6160,10 +6497,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); @@ -6171,34 +6510,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); } } @@ -6703,12 +7037,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; @@ -6789,14 +7123,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), @@ -7134,8 +7468,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); } |