core: merge branch 'th/user-block-autoconnect-rh1401515'

Related: https://bugzilla.redhat.com/show_bug.cgi?id=1401515
https://bugzilla.gnome.org/show_bug.cgi?id=790571
This commit is contained in:
Thomas Haller 2017-11-27 15:50:38 +01:00
commit 2c3dccfd28
20 changed files with 719 additions and 632 deletions

View file

@ -12446,7 +12446,7 @@ _cleanup_generic_post (NMDevice *self, CleanupType cleanup_type)
nm_assert (priv->needs_ip6_subnet == FALSE);
if (priv->act_request) {
nm_active_connection_set_default (NM_ACTIVE_CONNECTION (priv->act_request), FALSE);
nm_active_connection_set_default (NM_ACTIVE_CONNECTION (priv->act_request), AF_INET, FALSE);
priv->master_ready_handled = FALSE;
nm_clear_g_signal_handler (priv->act_request, &priv->master_ready_id);

View file

@ -1428,8 +1428,8 @@ build_hidden_probe_list (NMDeviceWifi *self)
connections = nm_settings_get_connections_clone (nm_device_get_settings ((NMDevice *) self),
&len,
hidden_filter_func,
NULL);
hidden_filter_func, NULL,
NULL, NULL);
if (!connections[0])
return NULL;

View file

@ -96,7 +96,7 @@ struct _NMActRequestGetSecretsCallId {
NMActRequest *self;
NMActRequestSecretsFunc callback;
gpointer callback_data;
NMSettingsConnectionCallId call_id;
NMSettingsConnectionCallId *call_id;
bool has_ref;
};
@ -113,7 +113,7 @@ _get_secrets_call_id_free (NMActRequestGetSecretsCallId *call_id)
static void
get_secrets_cb (NMSettingsConnection *connection,
NMSettingsConnectionCallId call_id_s,
NMSettingsConnectionCallId *call_id_s,
const char *agent_username,
const char *setting_name,
GError *error,
@ -172,7 +172,7 @@ nm_act_request_get_secrets (NMActRequest *self,
{
NMActRequestPrivate *priv;
NMActRequestGetSecretsCallId *call_id;
NMSettingsConnectionCallId call_id_s;
NMSettingsConnectionCallId *call_id_s;
NMSettingsConnection *settings_connection;
NMConnection *applied_connection;
const char *hints[2] = { hint, NULL };
@ -454,10 +454,8 @@ device_state_changed (NMActiveConnection *active,
}
if ( ac_state == NM_ACTIVE_CONNECTION_STATE_DEACTIVATED
|| ac_state == NM_ACTIVE_CONNECTION_STATE_UNKNOWN) {
nm_active_connection_set_default (active, FALSE);
nm_active_connection_set_default6 (active, FALSE);
}
|| ac_state == NM_ACTIVE_CONNECTION_STATE_UNKNOWN)
nm_active_connection_set_default (active, AF_UNSPEC, FALSE);
nm_active_connection_set_state (active, ac_state, ac_state_reason);
}

View file

@ -494,53 +494,46 @@ nm_active_connection_set_specific_object (NMActiveConnection *self,
}
void
nm_active_connection_set_default (NMActiveConnection *self, gboolean is_default)
nm_active_connection_set_default (NMActiveConnection *self,
int addr_family,
gboolean is_default)
{
NMActiveConnectionPrivate *priv;
g_return_if_fail (NM_IS_ACTIVE_CONNECTION (self));
nm_assert (NM_IN_SET (addr_family, AF_UNSPEC, AF_INET, AF_INET6));
is_default = !!is_default;
priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
if (priv->is_default == is_default)
return;
priv->is_default = is_default;
_notify (self, PROP_DEFAULT);
if (NM_IN_SET (addr_family, AF_UNSPEC, AF_INET)) {
if (priv->is_default != is_default) {
priv->is_default = is_default;
_notify (self, PROP_DEFAULT);
}
}
if (NM_IN_SET (addr_family, AF_UNSPEC, AF_INET6)) {
if (priv->is_default6 != is_default) {
priv->is_default6 = is_default;
_notify (self, PROP_DEFAULT6);
}
}
}
gboolean
nm_active_connection_get_default (NMActiveConnection *self)
{
g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), FALSE);
return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->is_default;
}
void
nm_active_connection_set_default6 (NMActiveConnection *self, gboolean is_default6)
nm_active_connection_get_default (NMActiveConnection *self, int addr_family)
{
NMActiveConnectionPrivate *priv;
g_return_if_fail (NM_IS_ACTIVE_CONNECTION (self));
is_default6 = !!is_default6;
g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), FALSE);
nm_assert (NM_IN_SET (addr_family, AF_UNSPEC, AF_INET, AF_INET6));
priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
if (priv->is_default6 == is_default6)
return;
priv->is_default6 = is_default6;
_notify (self, PROP_DEFAULT6);
}
gboolean
nm_active_connection_get_default6 (NMActiveConnection *self)
{
g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), FALSE);
return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->is_default6;
switch (addr_family) {
case AF_INET: return priv->is_default;
case AF_INET6: return priv->is_default6;
default: return priv->is_default || priv->is_default6;
}
}
NMAuthSubject *
@ -1263,10 +1256,10 @@ set_property (GObject *object, guint prop_id,
priv->specific_object = g_strdup (tmp);
break;
case PROP_DEFAULT:
priv->is_default = !!g_value_get_boolean (value);
priv->is_default = g_value_get_boolean (value);
break;
case PROP_DEFAULT6:
priv->is_default6 = !!g_value_get_boolean (value);
priv->is_default6 = g_value_get_boolean (value);
break;
case PROP_VPN:
priv->vpn = g_value_get_boolean (value);
@ -1289,6 +1282,8 @@ nm_active_connection_init (NMActiveConnection *self)
priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NM_TYPE_ACTIVE_CONNECTION, NMActiveConnectionPrivate);
self->_priv = priv;
c_list_init (&self->active_connections_lst);
_LOGT ("creating");
priv->activation_type = NM_ACTIVATION_TYPE_MANAGED;
@ -1331,6 +1326,8 @@ dispose (GObject *object)
NMActiveConnection *self = NM_ACTIVE_CONNECTION (object);
NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
nm_assert (!c_list_is_linked (&self->active_connections_lst));
_LOGD ("disposing");
if (priv->chain) {

View file

@ -24,6 +24,8 @@
#include "nm-exported-object.h"
#include "nm-connection.h"
#include "nm-utils/c-list.h"
#define NM_TYPE_ACTIVE_CONNECTION (nm_active_connection_get_type ())
#define NM_ACTIVE_CONNECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_ACTIVE_CONNECTION, NMActiveConnection))
#define NM_ACTIVE_CONNECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_ACTIVE_CONNECTION, NMActiveConnectionClass))
@ -71,6 +73,10 @@ struct _NMActiveConnectionPrivate;
struct _NMActiveConnection {
NMExportedObject parent;
struct _NMActiveConnectionPrivate *_priv;
/* active connection can be tracked in a list by NMManager. This is
* the list node. */
CList active_connections_lst;
};
typedef struct {
@ -131,14 +137,10 @@ void nm_active_connection_set_specific_object (NMActiveConnection *self
const char *specific_object);
void nm_active_connection_set_default (NMActiveConnection *self,
int addr_family,
gboolean is_default);
gboolean nm_active_connection_get_default (NMActiveConnection *self);
void nm_active_connection_set_default6 (NMActiveConnection *self,
gboolean is_default6);
gboolean nm_active_connection_get_default6 (NMActiveConnection *self);
gboolean nm_active_connection_get_default (NMActiveConnection *self, int addr_family);
NMActiveConnectionState nm_active_connection_get_state (NMActiveConnection *self);

View file

@ -125,10 +125,10 @@ find_settings_connection (NMCheckpoint *self,
gboolean *need_activation)
{
NMCheckpointPrivate *priv = NM_CHECKPOINT_GET_PRIVATE (self);
const GSList *active_connections, *iter;
NMActiveConnection *active = NULL;
NMActiveConnection *active;
NMSettingsConnection *connection;
const char *uuid, *ac_uuid;
const CList *tmp_clist;
*need_activation = FALSE;
*need_update = FALSE;
@ -149,9 +149,7 @@ find_settings_connection (NMCheckpoint *self,
}
/* ... is active, ... */
active_connections = nm_manager_get_active_connections (priv->manager);
for (iter = active_connections; iter; iter = g_slist_next (iter)) {
active = iter->data;
nm_manager_for_each_active_connection (priv->manager, active, tmp_clist) {
ac_uuid = nm_settings_connection_get_uuid (nm_active_connection_get_settings_connection (active));
if (nm_streq (uuid, ac_uuid)) {
_LOGT ("rollback: connection %s is active", uuid);
@ -159,7 +157,7 @@ find_settings_connection (NMCheckpoint *self,
}
}
if (!iter) {
if (!active) {
_LOGT ("rollback: connection %s is not active", uuid);
*need_activation = TRUE;
return connection;
@ -335,7 +333,9 @@ next_dev:
guint i;
g_return_val_if_fail (priv->connection_uuids, NULL);
list = nm_settings_get_connections_sorted (nm_settings_get (), NULL);
list = nm_settings_get_connections_clone (nm_settings_get (), NULL,
NULL, NULL,
nm_settings_connection_cmp_autoconnect_priority_p_with_data, NULL);
for (i = 0; list[i]; i++) {
con = list[i];

View file

@ -95,6 +95,8 @@ typedef struct {
guint interval;
} connectivity;
int autoconnect_retries_default;
struct {
char **arr;
GSList *specs;
@ -275,6 +277,14 @@ nm_config_data_get_connectivity_response (const NMConfigData *self)
return NM_CONFIG_DATA_GET_PRIVATE (self)->connectivity.response;
}
int
nm_config_data_get_autoconnect_retries_default (const NMConfigData *self)
{
g_return_val_if_fail (self, FALSE);
return NM_CONFIG_DATA_GET_PRIVATE (self)->autoconnect_retries_default;
}
const char *const*
nm_config_data_get_no_auto_default (const NMConfigData *self)
{
@ -1527,7 +1537,7 @@ constructed (GObject *object)
{
NMConfigData *self = NM_CONFIG_DATA (object);
NMConfigDataPrivate *priv = NM_CONFIG_DATA_GET_PRIVATE (self);
char *interval;
char *str;
priv->keyfile = _merge_keyfiles (priv->keyfile_user, priv->keyfile_intern);
@ -1538,13 +1548,15 @@ constructed (GObject *object)
priv->connectivity.uri = nm_strstrip (g_key_file_get_string (priv->keyfile, NM_CONFIG_KEYFILE_GROUP_CONNECTIVITY, "uri", NULL));
priv->connectivity.response = g_key_file_get_string (priv->keyfile, NM_CONFIG_KEYFILE_GROUP_CONNECTIVITY, "response", NULL);
str = nm_config_keyfile_get_value (priv->keyfile, NM_CONFIG_KEYFILE_GROUP_MAIN, NM_CONFIG_KEYFILE_KEY_MAIN_AUTOCONNECT_RETRIES_DEFAULT, NM_CONFIG_GET_VALUE_NONE);
priv->autoconnect_retries_default = _nm_utils_ascii_str_to_int64 (str, 10, 0, G_MAXINT32, 4);
g_free (str);
/* On missing config value, fallback to 300. On invalid value, disable connectivity checking by setting
* the interval to zero. */
interval = g_key_file_get_string (priv->keyfile, NM_CONFIG_KEYFILE_GROUP_CONNECTIVITY, "interval", NULL);
priv->connectivity.interval = interval
? _nm_utils_ascii_str_to_int64 (interval, 10, 0, G_MAXUINT, 0)
: NM_CONFIG_DEFAULT_CONNECTIVITY_INTERVAL;
g_free (interval);
str = g_key_file_get_string (priv->keyfile, NM_CONFIG_KEYFILE_GROUP_CONNECTIVITY, "interval", NULL);
priv->connectivity.interval = _nm_utils_ascii_str_to_int64 (str, 10, 0, G_MAXUINT, NM_CONFIG_DEFAULT_CONNECTIVITY_INTERVAL);
g_free (str);
priv->dns_mode = nm_strstrip (g_key_file_get_string (priv->keyfile, NM_CONFIG_KEYFILE_GROUP_MAIN, "dns", NULL));
priv->rc_manager = nm_strstrip (g_key_file_get_string (priv->keyfile, NM_CONFIG_KEYFILE_GROUP_MAIN, "rc-manager", NULL));

View file

@ -165,6 +165,8 @@ const char *nm_config_data_get_connectivity_uri (const NMConfigData *config_data
guint nm_config_data_get_connectivity_interval (const NMConfigData *config_data);
const char *nm_config_data_get_connectivity_response (const NMConfigData *config_data);
int nm_config_data_get_autoconnect_retries_default (const NMConfigData *config_data);
const char *const*nm_config_data_get_no_auto_default (const NMConfigData *config_data);
gboolean nm_config_data_get_no_auto_default_for_device (const NMConfigData *self, NMDevice *device);

View file

@ -60,6 +60,7 @@
#define NM_CONFIG_KEYFILE_GROUP_IFNET "ifnet"
#define NM_CONFIG_KEYFILE_KEY_MAIN_AUTH_POLKIT "auth-polkit"
#define NM_CONFIG_KEYFILE_KEY_MAIN_AUTOCONNECT_RETRIES_DEFAULT "autoconnect-retries-default"
#define NM_CONFIG_KEYFILE_KEY_MAIN_DHCP "dhcp"
#define NM_CONFIG_KEYFILE_KEY_MAIN_DEBUG "debug"
#define NM_CONFIG_KEYFILE_KEY_MAIN_HOSTNAME_MODE "hostname-mode"

View file

@ -114,7 +114,7 @@ typedef struct {
GArray *capabilities;
GSList *active_connections;
CList active_connections_lst_head;
GSList *authorizing_connections;
guint ac_cleanup_id;
NMActiveConnection *primary_connection;
@ -314,39 +314,38 @@ static gboolean
active_connection_remove (NMManager *self, NMActiveConnection *active)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
gboolean notify = nm_exported_object_is_exported (NM_EXPORTED_OBJECT (active));
GSList *found;
NMSettingsConnection *connection;
gboolean notify;
/* FIXME: switch to a GList for faster removal */
found = g_slist_find (priv->active_connections, active);
if (found) {
NMSettingsConnection *connection;
nm_assert (NM_IS_ACTIVE_CONNECTION (active));
nm_assert (c_list_contains (&priv->active_connections_lst_head, &active->active_connections_lst));
priv->active_connections = g_slist_remove (priv->active_connections, active);
g_signal_emit (self, signals[ACTIVE_CONNECTION_REMOVED], 0, active);
g_signal_handlers_disconnect_by_func (active, active_connection_state_changed, self);
g_signal_handlers_disconnect_by_func (active, active_connection_default_changed, self);
g_signal_handlers_disconnect_by_func (active, active_connection_parent_active, self);
notify = nm_exported_object_is_exported (NM_EXPORTED_OBJECT (active));
if ( (connection = nm_active_connection_get_settings_connection (active))
&& nm_settings_connection_get_volatile (connection))
g_object_ref (connection);
else
connection = NULL;
c_list_unlink_init (&active->active_connections_lst);
g_signal_emit (self, signals[ACTIVE_CONNECTION_REMOVED], 0, active);
g_signal_handlers_disconnect_by_func (active, active_connection_state_changed, self);
g_signal_handlers_disconnect_by_func (active, active_connection_default_changed, self);
g_signal_handlers_disconnect_by_func (active, active_connection_parent_active, self);
nm_exported_object_clear_and_unexport (&active);
if ( (connection = nm_active_connection_get_settings_connection (active))
&& nm_settings_connection_get_volatile (connection))
g_object_ref (connection);
else
connection = NULL;
if (connection) {
if (nm_settings_has_connection (priv->settings, connection)) {
_LOGD (LOGD_DEVICE, "assumed connection disconnected. Deleting generated connection '%s' (%s)",
nm_settings_connection_get_id (connection), nm_settings_connection_get_uuid (connection));
nm_settings_connection_delete (connection, NULL);
}
g_object_unref (connection);
nm_exported_object_clear_and_unexport (&active);
if (connection) {
if (nm_settings_has_connection (priv->settings, connection)) {
_LOGD (LOGD_DEVICE, "assumed connection disconnected. Deleting generated connection '%s' (%s)",
nm_settings_connection_get_id (connection), nm_settings_connection_get_uuid (connection));
nm_settings_connection_delete (connection, NULL);
}
g_object_unref (connection);
}
return found && notify;
return notify;
}
static gboolean
@ -354,16 +353,12 @@ _active_connection_cleanup (gpointer user_data)
{
NMManager *self = NM_MANAGER (user_data);
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
GSList *iter;
NMActiveConnection *ac, *ac_safe;
priv->ac_cleanup_id = 0;
g_object_freeze_notify (G_OBJECT (self));
iter = priv->active_connections;
while (iter) {
NMActiveConnection *ac = iter->data;
iter = iter->next;
c_list_for_each_entry_safe (ac, ac_safe, &priv->active_connections_lst_head, active_connections_lst) {
if (nm_active_connection_get_state (ac) == NM_ACTIVE_CONNECTION_STATE_DEACTIVATED) {
if (active_connection_remove (self, ac))
_notify (self, PROP_ACTIVE_CONNECTIONS);
@ -421,10 +416,11 @@ active_connection_add (NMManager *self, NMActiveConnection *active)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
g_return_if_fail (g_slist_find (priv->active_connections, active) == FALSE);
nm_assert (NM_IS_ACTIVE_CONNECTION (active));
nm_assert (!c_list_is_linked (&active->active_connections_lst));
priv->active_connections = g_slist_prepend (priv->active_connections,
g_object_ref (active));
c_list_link_front (&priv->active_connections_lst_head, &active->active_connections_lst);
g_object_ref (active);
g_signal_connect (active,
"notify::" NM_ACTIVE_CONNECTION_STATE,
@ -446,10 +442,10 @@ active_connection_add (NMManager *self, NMActiveConnection *active)
_notify (self, PROP_ACTIVE_CONNECTIONS);
}
const GSList *
const CList *
nm_manager_get_active_connections (NMManager *manager)
{
return NM_MANAGER_GET_PRIVATE (manager)->active_connections;
return &NM_MANAGER_GET_PRIVATE (manager)->active_connections_lst_head;
}
static NMActiveConnection *
@ -458,16 +454,12 @@ active_connection_find_first (NMManager *self,
const char *uuid,
NMActiveConnectionState max_state)
{
NMManagerPrivate *priv;
GSList *iter;
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
NMActiveConnection *ac;
g_return_val_if_fail (NM_IS_MANAGER (self), NULL);
g_return_val_if_fail (!settings_connection || NM_IS_SETTINGS_CONNECTION (settings_connection), NULL);
nm_assert (!settings_connection || NM_IS_SETTINGS_CONNECTION (settings_connection));
priv = NM_MANAGER_GET_PRIVATE (self);
for (iter = priv->active_connections; iter; iter = iter->next) {
NMActiveConnection *ac = iter->data;
c_list_for_each_entry (ac, &priv->active_connections_lst_head, active_connections_lst) {
NMSettingsConnection *con;
con = nm_active_connection_get_settings_connection (ac);
@ -511,42 +503,29 @@ _get_activatable_connections_filter (NMSettings *settings,
return !active_connection_find_first (user_data, connection, NULL, NM_ACTIVE_CONNECTION_STATE_DEACTIVATING);
}
/* Filter out connections that are already active.
* nm_settings_get_connections_sorted() returns sorted list. We need to preserve the
* order so that we didn't change auto-activation order (recent timestamps
* are first).
* Caller is responsible for freeing the returned list with g_slist_free().
*/
NMSettingsConnection **
nm_manager_get_activatable_connections (NMManager *manager, guint *out_len, gboolean sort)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
NMSettingsConnection **connections;
guint len;
connections = nm_settings_get_connections_clone (priv->settings, &len,
_get_activatable_connections_filter,
manager);
if (sort && len > 1)
g_qsort_with_data (connections, len, sizeof (connections[0]), nm_settings_connection_cmp_autoconnect_priority_p_with_data, NULL);
NM_SET_OUT (out_len, len);
return connections;
return nm_settings_get_connections_clone (priv->settings, out_len,
_get_activatable_connections_filter,
manager,
sort ? nm_settings_connection_cmp_autoconnect_priority_p_with_data : NULL,
NULL);
}
static NMActiveConnection *
active_connection_get_by_path (NMManager *manager, const char *path)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
GSList *iter;
NMActiveConnection *ac;
g_return_val_if_fail (manager != NULL, NULL);
g_return_val_if_fail (path != NULL, NULL);
nm_assert (path);
for (iter = priv->active_connections; iter; iter = g_slist_next (iter)) {
NMActiveConnection *candidate = iter->data;
if (g_strcmp0 (path, nm_exported_object_get_path (NM_EXPORTED_OBJECT (candidate))) == 0)
return candidate;
c_list_for_each_entry (ac, &priv->active_connections_lst_head, active_connections_lst) {
if (nm_streq0 (path, nm_exported_object_get_path (NM_EXPORTED_OBJECT (ac))))
return ac;
}
return NULL;
}
@ -828,16 +807,14 @@ find_best_device_state (NMManager *manager)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
NMState best_state = NM_STATE_DISCONNECTED;
GSList *iter;
NMActiveConnection *ac;
for (iter = priv->active_connections; iter; iter = iter->next) {
NMActiveConnection *ac = NM_ACTIVE_CONNECTION (iter->data);
c_list_for_each_entry (ac, &priv->active_connections_lst_head, active_connections_lst) {
NMActiveConnectionState ac_state = nm_active_connection_get_state (ac);
switch (ac_state) {
case NM_ACTIVE_CONNECTION_STATE_ACTIVATED:
if ( nm_active_connection_get_default (ac)
|| nm_active_connection_get_default6 (ac)) {
if (nm_active_connection_get_default (ac, AF_UNSPEC)) {
if (priv->connectivity_state == NM_CONNECTIVITY_FULL)
return NM_STATE_CONNECTED_GLOBAL;
@ -1392,7 +1369,9 @@ system_create_virtual_device (NMManager *self, NMConnection *connection)
}
/* Create backing resources if the device has any autoconnect connections */
connections = nm_settings_get_connections_sorted (priv->settings, NULL);
connections = nm_settings_get_connections_clone (priv->settings, NULL,
NULL, NULL,
nm_settings_connection_cmp_autoconnect_priority_p_with_data, NULL);
for (i = 0; connections[i]; i++) {
NMConnection *candidate = NM_CONNECTION (connections[i]);
NMSettingConnection *s_con;
@ -1436,7 +1415,9 @@ retry_connections_for_parent_device (NMManager *self, NMDevice *device)
g_return_if_fail (device);
connections = nm_settings_get_connections_sorted (priv->settings, NULL);
connections = nm_settings_get_connections_clone (priv->settings, NULL,
NULL, NULL,
nm_settings_connection_cmp_autoconnect_priority_p_with_data, NULL);
for (i = 0; connections[i]; i++) {
NMConnection *candidate = NM_CONNECTION (connections[i]);
gs_free_error GError *error = NULL;
@ -3022,7 +3003,9 @@ find_slaves (NMManager *manager,
* even if a slave was already active, it might be deactivated during
* master reactivation.
*/
all_connections = nm_settings_get_connections_sorted (priv->settings, &n_all_connections);
all_connections = nm_settings_get_connections_clone (priv->settings, &n_all_connections,
NULL, NULL,
nm_settings_connection_cmp_autoconnect_priority_p_with_data, NULL);
for (i = 0; i < n_all_connections; i++) {
NMSettingsConnection *master_connection = NULL;
NMDevice *master_device = NULL, *slave_device;
@ -3628,11 +3611,11 @@ _internal_activation_auth_done (NMActiveConnection *active,
gpointer user_data1,
gpointer user_data2)
{
_nm_unused gs_unref_object NMActiveConnection *active_to_free = active;
NMManager *self = user_data1;
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
NMActiveConnection *candidate;
GError *error = NULL;
GSList *iter;
NMActiveConnection *ac;
gs_free_error GError *error = NULL;
priv->authorizing_connections = g_slist_remove (priv->authorizing_connections, active);
@ -3641,12 +3624,12 @@ _internal_activation_auth_done (NMActiveConnection *active,
* detect a duplicate if the existing active connection is undergoing
* authorization in impl_manager_activate_connection().
*/
if (success && nm_auth_subject_is_internal (nm_active_connection_get_subject (active))) {
for (iter = priv->active_connections; iter; iter = iter->next) {
candidate = iter->data;
if ( nm_active_connection_get_device (candidate) == nm_active_connection_get_device (active)
&& nm_active_connection_get_settings_connection (candidate) == nm_active_connection_get_settings_connection (active)
&& NM_IN_SET (nm_active_connection_get_state (candidate),
if ( success
&& nm_auth_subject_is_internal (nm_active_connection_get_subject (active))) {
c_list_for_each_entry (ac, &priv->active_connections_lst_head, active_connections_lst) {
if ( nm_active_connection_get_device (ac) == nm_active_connection_get_device (active)
&& nm_active_connection_get_settings_connection (ac) == nm_active_connection_get_settings_connection (active)
&& NM_IN_SET (nm_active_connection_get_state (ac),
NM_ACTIVE_CONNECTION_STATE_ACTIVATING,
NM_ACTIVE_CONNECTION_STATE_ACTIVATED)) {
g_set_error (&error,
@ -3661,16 +3644,12 @@ _internal_activation_auth_done (NMActiveConnection *active,
}
if (success) {
if (_internal_activate_generic (self, active, &error)) {
g_object_unref (active);
if (_internal_activate_generic (self, active, &error))
return;
}
}
g_assert (error_desc || error);
nm_assert (error_desc || error);
_internal_activation_failed (self, active, error_desc ? error_desc : error->message);
g_object_unref (active);
g_clear_error (&error);
}
/**
@ -4167,7 +4146,9 @@ impl_manager_add_and_activate_connection (NMManager *self,
gs_free NMSettingsConnection **connections = NULL;
guint i, len;
connections = nm_settings_get_connections_sorted (priv->settings, &len);
connections = nm_settings_get_connections_clone (priv->settings, &len,
NULL, NULL,
nm_settings_connection_cmp_autoconnect_priority_p_with_data, NULL);
all_connections = NULL;
for (i = len; i > 0; ) {
i--;
@ -5226,7 +5207,9 @@ nm_manager_start (NMManager *self, GError **error)
* connection-added signals thus devices have to be created manually.
*/
_LOGD (LOGD_CORE, "creating virtual devices...");
connections = nm_settings_get_connections_sorted (priv->settings, NULL);
connections = nm_settings_get_connections_clone (priv->settings, NULL,
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]));
@ -5990,19 +5973,15 @@ periodic_update_active_connection_timestamps (gpointer user_data)
{
NMManager *manager = NM_MANAGER (user_data);
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
GSList *iter;
for (iter = priv->active_connections; iter; iter = g_slist_next (iter)) {
NMActiveConnection *ac = iter->data;
NMSettingsConnection *connection;
NMActiveConnection *ac;
c_list_for_each_entry (ac, &priv->active_connections_lst_head, active_connections_lst) {
if (nm_active_connection_get_state (ac) == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) {
connection = nm_active_connection_get_settings_connection (ac);
nm_settings_connection_update_timestamp (connection, (guint64) time (NULL), FALSE);
nm_settings_connection_update_timestamp (nm_active_connection_get_settings_connection (ac),
(guint64) time (NULL), FALSE);
}
}
return TRUE;
return G_SOURCE_CONTINUE;
}
static void
@ -6164,6 +6143,7 @@ nm_manager_init (NMManager *self)
GFile *file;
c_list_init (&priv->link_cb_lst);
c_list_init (&priv->active_connections_lst_head);
priv->platform = g_object_ref (NM_PLATFORM_GET);
@ -6252,6 +6232,10 @@ get_property (GObject *object, guint prop_id,
const NMGlobalDnsConfig *dns_config;
const char *type;
char **strv;
const char *path;
NMActiveConnection *ac;
GPtrArray *ptrarr;
gboolean vbool;
switch (prop_id) {
case PROP_VERSION:
@ -6291,7 +6275,14 @@ get_property (GObject *object, guint prop_id,
g_value_set_boolean (value, FALSE);
break;
case PROP_ACTIVE_CONNECTIONS:
nm_utils_g_value_set_object_path_array (value, priv->active_connections, NULL, NULL);
ptrarr = g_ptr_array_new ();
c_list_for_each_entry (ac, &priv->active_connections_lst_head, active_connections_lst) {
path = nm_exported_object_get_path (NM_EXPORTED_OBJECT (ac));
if (path)
g_ptr_array_add (ptrarr, g_strdup (path));
}
g_ptr_array_add (ptrarr, NULL);
g_value_take_boxed (value, g_ptr_array_free (ptrarr, FALSE));
break;
case PROP_CONNECTIVITY:
g_value_set_uint (value, priv->connectivity_state);
@ -6302,15 +6293,11 @@ get_property (GObject *object, guint prop_id,
break;
case PROP_CONNECTIVITY_CHECK_ENABLED:
#if WITH_CONCHECK
{
NMConnectivity *connectivity;
connectivity = nm_connectivity_get ();
g_value_set_boolean (value, nm_connectivity_check_enabled (connectivity));
}
vbool = nm_connectivity_check_enabled (nm_connectivity_get ());
#else
g_value_set_boolean (value, FALSE);
vbool = FALSE;
#endif
g_value_set_boolean (value, FALSE);
break;
case PROP_PRIMARY_CONNECTION:
nm_utils_g_value_set_object_path (value, priv->primary_connection);
@ -6415,6 +6402,7 @@ dispose (GObject *object)
NMManager *self = NM_MANAGER (object);
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
CList *iter, *iter_safe;
NMActiveConnection *ac, *ac_safe;
g_signal_handlers_disconnect_by_func (priv->platform,
G_CALLBACK (platform_link_cb),
@ -6448,9 +6436,9 @@ dispose (GObject *object)
nm_clear_g_source (&priv->ac_cleanup_id);
while (priv->active_connections)
active_connection_remove (self, NM_ACTIVE_CONNECTION (priv->active_connections->data));
g_clear_pointer (&priv->active_connections, g_slist_free);
c_list_for_each_entry_safe (ac, ac_safe, &priv->active_connections_lst_head, active_connections_lst)
active_connection_remove (self, ac);
nm_assert (c_list_is_empty (&priv->active_connections_lst_head));
g_clear_object (&priv->primary_connection);
g_clear_object (&priv->activating_connection);

View file

@ -24,6 +24,7 @@
#include "nm-exported-object.h"
#include "settings/nm-settings-connection.h"
#include "nm-utils/c-list.h"
#define NM_TYPE_MANAGER (nm_manager_get_type ())
#define NM_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_MANAGER, NMManager))
@ -85,7 +86,19 @@ gboolean nm_manager_start (NMManager *manager,
GError **error);
void nm_manager_stop (NMManager *manager);
NMState nm_manager_get_state (NMManager *manager);
const GSList *nm_manager_get_active_connections (NMManager *manager);
const CList * nm_manager_get_active_connections (NMManager *manager);
#define nm_manager_for_each_active_connection(manager, iter, tmp_list) \
for (tmp_list = nm_manager_get_active_connections (manager), \
iter = c_list_entry (tmp_list->next, NMActiveConnection, active_connections_lst); \
({ \
gboolean _has_next = (&iter->active_connections_lst != tmp_list); \
\
if (!_has_next) \
iter = NULL; \
_has_next; \
}); \
iter = c_list_entry (iter->active_connections_lst.next, NMActiveConnection, active_connections_lst))
NMSettingsConnection **nm_manager_get_activatable_connections (NMManager *manager,
guint *out_len,

View file

@ -44,6 +44,7 @@
#include "nm-manager.h"
#include "settings/nm-settings.h"
#include "settings/nm-settings-connection.h"
#include "settings/nm-agent-manager.h"
#include "nm-dhcp4-config.h"
#include "nm-dhcp6-config.h"
#include "nm-config.h"
@ -65,7 +66,9 @@ typedef struct {
NMManager *manager;
NMNetns *netns;
NMFirewallManager *firewall_manager;
GSList *pending_activation_checks;
CList pending_activation_checks;
NMAgentManager *agent_mgr;
GHashTable *devices;
GHashTable *pending_active_connections;
@ -312,8 +315,9 @@ device_ip6_prefix_delegated (NMDevice *device,
NMPolicyPrivate *priv = user_data;
NMPolicy *self = _PRIV_TO_SELF (priv);
IP6PrefixDelegation *delegation = NULL;
const GSList *connections, *iter;
guint i;
const CList *tmp_list;
NMActiveConnection *ac;
_LOGI (LOGD_IP6, "ipv6-pd: received a prefix %s/%d from %s",
nm_utils_inet6_ntop (&prefix->address, NULL),
@ -344,10 +348,10 @@ device_ip6_prefix_delegated (NMDevice *device,
* so traversing it from the beginning makes it likely for newly
* activated connections that have no subnet assigned to be served
* first. That is a simple yet fair policy, which is good. */
connections = nm_manager_get_active_connections (priv->manager);
for (iter = connections; iter; iter = g_slist_next (iter)) {
NMDevice *to_device = nm_active_connection_get_device (iter->data);
nm_manager_for_each_active_connection (priv->manager, ac, tmp_list) {
NMDevice *to_device;
to_device = nm_active_connection_get_device (ac);
if (nm_device_needs_ip6_subnet (to_device))
ip6_subnet_from_delegation (delegation, to_device);
}
@ -818,25 +822,25 @@ update_system_hostname (NMPolicy *self, const char *msg)
static void
update_default_ac (NMPolicy *self,
NMActiveConnection *best,
void (*set_active_func)(NMActiveConnection*, gboolean))
int addr_family,
NMActiveConnection *best)
{
NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self);
const GSList *connections, *iter;
const CList *tmp_list;
NMActiveConnection *ac;
/* Clear the 'default[6]' flag on all active connections that aren't the new
* default active connection. We'll set the new default after; this ensures
* we don't ever have two marked 'default[6]' simultaneously.
*/
connections = nm_manager_get_active_connections (priv->manager);
for (iter = connections; iter; iter = g_slist_next (iter)) {
if (NM_ACTIVE_CONNECTION (iter->data) != best)
set_active_func (NM_ACTIVE_CONNECTION (iter->data), FALSE);
nm_manager_for_each_active_connection (priv->manager, ac, tmp_list) {
if (ac != best)
nm_active_connection_set_default (ac, addr_family, FALSE);
}
/* Mark new default active connection */
if (best)
set_active_func (best, TRUE);
nm_active_connection_set_default (best, addr_family, TRUE);
}
static gpointer
@ -850,19 +854,19 @@ get_best_ip_config (NMPolicy *self,
NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self);
NMDevice *device;
gpointer conf;
const GSList *iter;
const CList *tmp_list;
NMActiveConnection *ac;
nm_assert (NM_IN_SET (addr_family, AF_INET, AF_INET6));
for (iter = nm_manager_get_active_connections (priv->manager); iter; iter = iter->next) {
NMActiveConnection *active = NM_ACTIVE_CONNECTION (iter->data);
nm_manager_for_each_active_connection (priv->manager, ac, tmp_list) {
NMVpnConnection *candidate;
NMVpnConnectionState vpn_state;
if (!NM_IS_VPN_CONNECTION (active))
if (!NM_IS_VPN_CONNECTION (ac))
continue;
candidate = NM_VPN_CONNECTION (active);
candidate = NM_VPN_CONNECTION (ac);
vpn_state = nm_vpn_connection_get_vpn_state (candidate);
if (vpn_state != NM_VPN_CONNECTION_STATE_ACTIVATED)
@ -887,7 +891,7 @@ get_best_ip_config (NMPolicy *self,
* best metric. */
NM_SET_OUT (out_device, NULL);
NM_SET_OUT (out_vpn, candidate);
NM_SET_OUT (out_ac, active);
NM_SET_OUT (out_ac, ac);
NM_SET_OUT (out_ip_iface, nm_vpn_connection_get_ip_iface (candidate, TRUE));
return conf;
}
@ -926,6 +930,8 @@ update_ip4_routing (NMPolicy *self, gboolean force_update)
NMVpnConnection *vpn = NULL;
NMActiveConnection *best_ac = NULL;
const char *ip_iface = NULL;
const CList *tmp_list;
NMActiveConnection *ac;
/* Note that we might have an IPv4 VPN tunneled over an IPv6-only device,
* so we can get (vpn != NULL && best == NULL).
@ -945,23 +951,18 @@ update_ip4_routing (NMPolicy *self, gboolean force_update)
return;
if (best) {
const GSList *connections, *iter;
connections = nm_manager_get_active_connections (priv->manager);
for (iter = connections; iter; iter = g_slist_next (iter)) {
NMActiveConnection *active = iter->data;
if ( NM_IS_VPN_CONNECTION (active)
&& nm_vpn_connection_get_ip4_config (NM_VPN_CONNECTION (active))
&& !nm_active_connection_get_device (active))
nm_active_connection_set_device (active, best);
nm_manager_for_each_active_connection (priv->manager, ac, tmp_list) {
if ( NM_IS_VPN_CONNECTION (ac)
&& nm_vpn_connection_get_ip4_config (NM_VPN_CONNECTION (ac))
&& !nm_active_connection_get_device (ac))
nm_active_connection_set_device (ac, best);
}
}
if (vpn)
best = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (vpn));
update_default_ac (self, best_ac, nm_active_connection_set_default);
update_default_ac (self, AF_INET, best_ac);
if (!nm_g_object_ref_set (&priv->default_device4, best))
return;
@ -977,12 +978,12 @@ static void
update_ip6_dns_delegation (NMPolicy *self)
{
NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self);
const GSList *connections, *iter;
connections = nm_manager_get_active_connections (priv->manager);
for (iter = connections; iter; iter = g_slist_next (iter)) {
NMDevice *device = nm_active_connection_get_device (iter->data);
NMDevice *device;
NMActiveConnection *ac;
const CList *tmp_list;
nm_manager_for_each_active_connection (priv->manager, ac, tmp_list) {
device = nm_active_connection_get_device (ac);
if (device && nm_device_needs_ip6_subnet (device))
nm_device_copy_ip6_dns_config (device, priv->default_device6);
}
@ -992,13 +993,13 @@ static void
update_ip6_prefix_delegation (NMPolicy *self)
{
NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self);
const GSList *connections, *iter;
NMDevice *device;
NMActiveConnection *ac;
const CList *tmp_list;
/* There's new default IPv6 connection, try to get a prefix for everyone. */
connections = nm_manager_get_active_connections (priv->manager);
for (iter = connections; iter; iter = g_slist_next (iter)) {
NMDevice *device = nm_active_connection_get_device (iter->data);
nm_manager_for_each_active_connection (priv->manager, ac, tmp_list) {
device = nm_active_connection_get_device (ac);
if (device && nm_device_needs_ip6_subnet (device))
ip6_subnet_from_device (self, priv->default_device6, device);
}
@ -1012,6 +1013,8 @@ update_ip6_routing (NMPolicy *self, gboolean force_update)
NMVpnConnection *vpn = NULL;
NMActiveConnection *best_ac = NULL;
const char *ip_iface = NULL;
NMActiveConnection *ac;
const CList *tmp_list;
/* Note that we might have an IPv6 VPN tunneled over an IPv4-only device,
* so we can get (vpn != NULL && best == NULL).
@ -1031,23 +1034,18 @@ update_ip6_routing (NMPolicy *self, gboolean force_update)
return;
if (best) {
const GSList *connections, *iter;
connections = nm_manager_get_active_connections (priv->manager);
for (iter = connections; iter; iter = g_slist_next (iter)) {
NMActiveConnection *active = iter->data;
if ( NM_IS_VPN_CONNECTION (active)
&& nm_vpn_connection_get_ip6_config (NM_VPN_CONNECTION (active))
&& !nm_active_connection_get_device (active))
nm_active_connection_set_device (active, best);
nm_manager_for_each_active_connection (priv->manager, ac, tmp_list) {
if ( NM_IS_VPN_CONNECTION (ac)
&& nm_vpn_connection_get_ip6_config (NM_VPN_CONNECTION (ac))
&& !nm_active_connection_get_device (ac))
nm_active_connection_set_device (ac, best);
}
}
if (vpn)
best = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (vpn));
update_default_ac (self, best_ac, nm_active_connection_set_default6);
update_default_ac (self, AF_INET6, best_ac);
if (!nm_g_object_ref_set (&priv->default_device6, best))
return;
@ -1132,6 +1130,7 @@ check_activating_devices (NMPolicy *self)
}
typedef struct {
CList pending_lst;
NMPolicy *policy;
NMDevice *device;
guint autoactivate_id;
@ -1140,14 +1139,10 @@ typedef struct {
static void
activate_data_free (ActivateData *data)
{
NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (data->policy);
nm_device_remove_pending_action (data->device, NM_PENDING_ACTION_AUTOACTIVATE, TRUE);
priv->pending_activation_checks = g_slist_remove (priv->pending_activation_checks, data);
c_list_unlink (&data->pending_lst);
nm_clear_g_source (&data->autoactivate_id);
g_object_unref (data->device);
g_slice_free (ActivateData, data);
}
@ -1178,7 +1173,7 @@ pending_ac_state_changed (NMActiveConnection *ac, guint state, guint reason, NMP
* loop.
*/
con = nm_active_connection_get_settings_connection (ac);
nm_settings_connection_autoconnect_blocked_reason_set (con, NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED);
nm_settings_connection_autoconnect_blocked_reason_set (con, NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED, TRUE);
schedule_activate_check (self, nm_active_connection_get_device (ac));
/* Cleanup */
@ -1199,7 +1194,7 @@ auto_activate_device (NMPolicy *self,
gs_free char *specific_object = NULL;
gs_free NMSettingsConnection **connections = NULL;
guint i, len;
GError *error = NULL;
gs_free_error GError *error = NULL;
NMAuthSubject *subject;
NMActiveConnection *ac;
@ -1230,8 +1225,7 @@ auto_activate_device (NMPolicy *self,
const char *permission;
if ( !nm_settings_connection_is_visible (candidate)
|| nm_settings_connection_autoconnect_retries_get (candidate) == 0
|| nm_settings_connection_autoconnect_blocked_reason_get (candidate) != NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NONE)
|| nm_settings_connection_autoconnect_is_blocked (candidate))
continue;
s_con = nm_connection_get_setting_connection (NM_CONNECTION (candidate));
@ -1264,13 +1258,12 @@ auto_activate_device (NMPolicy *self,
NM_ACTIVATION_TYPE_MANAGED,
&error);
if (!ac) {
_LOGI (LOGD_DEVICE, "connection '%s' auto-activation failed: (%d) %s",
_LOGI (LOGD_DEVICE, "connection '%s' auto-activation failed: %s",
nm_settings_connection_get_id (best_connection),
error->code,
error->message);
g_error_free (error);
nm_settings_connection_autoconnect_blocked_reason_set (best_connection,
NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED);
NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED,
TRUE);
schedule_activate_check (self, device);
return;
}
@ -1304,13 +1297,14 @@ auto_activate_device_cb (gpointer user_data)
}
static ActivateData *
find_pending_activation (GSList *list, NMDevice *device)
find_pending_activation (NMPolicy *self, NMDevice *device)
{
GSList *iter;
NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self);
ActivateData *data;
for (iter = list; iter; iter = g_slist_next (iter)) {
if (((ActivateData *) iter->data)->device == device)
return iter->data;
c_list_for_each_entry (data, &priv->pending_activation_checks, pending_lst) {
if (data->device == device)
return data;
}
return NULL;
}
@ -1408,48 +1402,56 @@ hostname_changed (NMHostnameManager *hostname_manager, GParamSpec *pspec, gpoint
update_system_hostname (self, "hostname changed");
}
static void
reset_autoconnect_all (NMPolicy *self, NMDevice *device)
static gboolean
reset_autoconnect_all (NMPolicy *self,
NMDevice *device, /* if present, only reset connections compatible with @device */
gboolean only_no_secrets)
{
NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self);
gs_free NMSettingsConnection **connections = NULL;
NMSettingsConnection *const*connections = NULL;
guint i;
gboolean changed;
if (device) {
_LOGD (LOGD_DEVICE, "re-enabling autoconnect for all connections on %s",
nm_device_get_iface (device));
} else
_LOGD (LOGD_DEVICE, "re-enabling autoconnect for all connections");
_LOGD (LOGD_DEVICE, "re-enabling autoconnect for all connections%s%s%s",
device ? " on " : "",
device ? nm_device_get_iface (device) : "",
only_no_secrets ? " (only clear no-secrets flag)" : "");
connections = nm_settings_get_connections_sorted (priv->settings, NULL);
connections = nm_settings_get_connections (priv->settings, NULL);
for (i = 0; connections[i]; i++) {
NMSettingsConnection *connection = connections[i];
if (!device || nm_device_check_connection_compatible (device, NM_CONNECTION (connection))) {
if ( device
&& !nm_device_check_connection_compatible (device, NM_CONNECTION (connection)))
continue;
if (only_no_secrets) {
/* we only reset the no-secrets blocked flag. */
if (nm_settings_connection_autoconnect_blocked_reason_set (connection,
NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NO_SECRETS,
FALSE)) {
/* maybe the connection is still blocked afterwards for other reasons
* and in the larger picture nothing changed. But it's too complicated
* to find out exactly. Just assume, something changed to be sure. */
if (!nm_settings_connection_autoconnect_is_blocked (connection))
changed = TRUE;
}
} else {
/* we reset the tries-count and any blocked-reason */
if (nm_settings_connection_autoconnect_retries_get (connection) == 0)
changed = TRUE;
nm_settings_connection_autoconnect_retries_reset (connection);
nm_settings_connection_autoconnect_blocked_reason_set (connection, NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NONE);
}
}
}
static void
reset_autoconnect_for_failed_secrets (NMPolicy *self)
{
NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self);
gs_free NMSettingsConnection **connections = NULL;
guint i;
_LOGD (LOGD_DEVICE, "re-enabling autoconnect for all connections with failed secrets");
connections = nm_settings_get_connections_sorted (priv->settings, NULL);
for (i = 0; connections[i]; i++) {
NMSettingsConnection *connection = connections[i];
if (nm_settings_connection_autoconnect_blocked_reason_get (connection) == NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NO_SECRETS) {
nm_settings_connection_autoconnect_retries_reset (connection);
nm_settings_connection_autoconnect_blocked_reason_set (connection, NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NONE);
if (nm_settings_connection_autoconnect_blocked_reason_set (connection,
NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_ALL
& ~NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_USER_REQUEST,
FALSE)) {
if (!nm_settings_connection_autoconnect_is_blocked (connection))
changed = TRUE;
}
}
}
return changed;
}
static void
@ -1463,8 +1465,10 @@ sleeping_changed (NMManager *manager, GParamSpec *pspec, gpointer user_data)
g_object_get (G_OBJECT (manager), NM_MANAGER_NETWORKING_ENABLED, &enabled, NULL);
/* Reset retries on all connections so they'll checked on wakeup */
if (sleeping || !enabled)
reset_autoconnect_all (self, NULL);
if (sleeping || !enabled) {
if (reset_autoconnect_all (self, NULL, FALSE))
schedule_activate_all (self);
}
}
static void
@ -1472,7 +1476,8 @@ schedule_activate_check (NMPolicy *self, NMDevice *device)
{
NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self);
ActivateData *data;
const GSList *active_connections, *iter;
NMActiveConnection *ac;
const CList *tmp_list;
if (nm_manager_get_state (priv->manager) == NM_STATE_ASLEEP)
return;
@ -1480,12 +1485,11 @@ schedule_activate_check (NMPolicy *self, NMDevice *device)
if (!nm_device_autoconnect_allowed (device))
return;
if (find_pending_activation (priv->pending_activation_checks, device))
if (find_pending_activation (self, device))
return;
active_connections = nm_manager_get_active_connections (priv->manager);
for (iter = active_connections; iter; iter = iter->next) {
if (nm_active_connection_get_device (NM_ACTIVE_CONNECTION (iter->data)) == device)
nm_manager_for_each_active_connection (priv->manager, ac, tmp_list) {
if (nm_active_connection_get_device (ac) == device)
return;
}
@ -1495,18 +1499,7 @@ schedule_activate_check (NMPolicy *self, NMDevice *device)
data->policy = self;
data->device = g_object_ref (device);
data->autoactivate_id = g_idle_add (auto_activate_device_cb, data);
priv->pending_activation_checks = g_slist_append (priv->pending_activation_checks, data);
}
static void
clear_pending_activate_check (NMPolicy *self, NMDevice *device)
{
NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self);
ActivateData *data;
data = find_pending_activation (priv->pending_activation_checks, device);
if (data && data->autoactivate_id)
activate_data_free (data);
c_list_link_tail (&priv->pending_activation_checks, &data->pending_lst);
}
static gboolean
@ -1514,7 +1507,7 @@ reset_connections_retries (gpointer user_data)
{
NMPolicy *self = (NMPolicy *) user_data;
NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self);
gs_free NMSettingsConnection **connections = NULL;
NMSettingsConnection *const*connections = NULL;
guint i;
gint32 con_stamp, min_stamp, now;
gboolean changed = FALSE;
@ -1523,11 +1516,11 @@ reset_connections_retries (gpointer user_data)
min_stamp = 0;
now = nm_utils_get_monotonic_timestamp_s ();
connections = nm_settings_get_connections_sorted (priv->settings, NULL);
connections = nm_settings_get_connections (priv->settings, NULL);
for (i = 0; connections[i]; i++) {
NMSettingsConnection *connection = connections[i];
con_stamp = nm_settings_connection_autoconnect_blocked_until_get (connection);
con_stamp = nm_settings_connection_autoconnect_retries_blocked_until (connection);
if (con_stamp == 0)
continue;
@ -1549,6 +1542,29 @@ reset_connections_retries (gpointer user_data)
return FALSE;
}
static void
_connection_autoconnect_retries_set (NMPolicy *self,
NMSettingsConnection *connection,
int tries)
{
NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self);
nm_assert (NM_IS_SETTINGS_CONNECTION (connection));
nm_assert (tries >= 0);
nm_settings_connection_autoconnect_retries_set (connection, tries);
if (tries == 0) {
/* Schedule a handler to reset retries count */
if (!priv->reset_retries_id) {
gint32 retry_time = nm_settings_connection_autoconnect_retries_blocked_until (connection);
g_warn_if_fail (retry_time != 0);
priv->reset_retries_id = g_timeout_add_seconds (MAX (0, retry_time - nm_utils_get_monotonic_timestamp_s ()), reset_connections_retries, self);
}
}
}
static void
activate_slave_connections (NMPolicy *self, NMDevice *device)
{
@ -1557,7 +1573,8 @@ activate_slave_connections (NMPolicy *self, NMDevice *device)
guint i;
NMActRequest *req;
gboolean internal_activation = FALSE;
gs_free NMSettingsConnection **connections = NULL;
NMSettingsConnection *const*connections;
gboolean changed;
master_device = nm_device_get_iface (device);
g_assert (master_device);
@ -1581,38 +1598,37 @@ activate_slave_connections (NMPolicy *self, NMDevice *device)
internal_activation = subject && nm_auth_subject_is_internal (subject);
}
connections = nm_settings_get_connections_sorted (priv->settings, NULL);
changed = FALSE;
connections = nm_settings_get_connections (priv->settings, NULL);
for (i = 0; connections[i]; i++) {
NMConnection *slave;
NMSettingsConnection *connection = connections[i];
NMSettingConnection *s_slave_con;
const char *slave_master;
slave = NM_CONNECTION (connections[i]);
s_slave_con = nm_connection_get_setting_connection (slave);
g_assert (s_slave_con);
s_slave_con = nm_connection_get_setting_connection (NM_CONNECTION (connection));
slave_master = nm_setting_connection_get_master (s_slave_con);
if (!slave_master)
continue;
if (!NM_IN_STRSET (slave_master, master_device,
master_uuid_applied,
master_uuid_settings))
continue;
if ( nm_streq0 (slave_master, master_device)
|| nm_streq0 (slave_master, master_uuid_applied)
|| nm_streq0 (slave_master, master_uuid_settings)) {
NMSettingsConnection *settings = NM_SETTINGS_CONNECTION (slave);
NMSettingsAutoconnectBlockedReason reason;
if (!internal_activation)
nm_settings_connection_autoconnect_retries_reset (settings);
reason = nm_settings_connection_autoconnect_blocked_reason_get (settings);
if (reason == NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED) {
reason = NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NONE;
nm_settings_connection_autoconnect_blocked_reason_set (settings, reason);
}
if (!internal_activation) {
if (nm_settings_connection_autoconnect_retries_get (connection) == 0)
changed = TRUE;
nm_settings_connection_autoconnect_retries_reset (connection);
}
if (nm_settings_connection_autoconnect_blocked_reason_set (connection,
NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED,
FALSE)) {
if (!nm_settings_connection_autoconnect_is_blocked (connection))
changed = TRUE;
}
}
schedule_activate_all (self);
if (changed)
schedule_activate_all (self);
}
static gboolean
@ -1718,7 +1734,8 @@ device_state_changed (NMDevice *device,
*/
if (connection) {
nm_settings_connection_autoconnect_blocked_reason_set (connection,
NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED);
NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED,
TRUE);
}
break;
default:
@ -1733,36 +1750,40 @@ device_state_changed (NMDevice *device,
if ( connection
&& old_state >= NM_DEVICE_STATE_PREPARE
&& old_state <= NM_DEVICE_STATE_ACTIVATED) {
gboolean block_no_secrets = FALSE;
int tries;
guint64 con_v;
tries = nm_settings_connection_autoconnect_retries_get (connection);
if (nm_device_state_reason_check (reason) == NM_DEVICE_STATE_REASON_NO_SECRETS) {
/* we want to block the connection from auto-connect if it failed due to no-secrets.
* However, if a secret-agent registered, since the connection made the last
* secret-request, we do not block it. The new secret-agent might not yet
* been consulted, and it may be able to provide the secrets.
*
* We detect this by using a version-id of the agent-manager, which increments
* whenever new agents register. */
con_v = nm_settings_connection_get_last_secret_agent_version_id (connection);
if ( con_v == 0
|| con_v != nm_agent_manager_get_agent_version_id (priv->agent_mgr))
block_no_secrets = TRUE;
}
if (block_no_secrets) {
_LOGD (LOGD_DEVICE, "connection '%s' now blocked from autoconnect due to no secrets",
nm_settings_connection_get_id (connection));
nm_settings_connection_autoconnect_blocked_reason_set (connection, NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NO_SECRETS);
} else if (tries != 0) {
nm_settings_connection_autoconnect_blocked_reason_set (connection, NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NO_SECRETS, TRUE);
} else {
tries = nm_settings_connection_autoconnect_retries_get (connection);
if (tries > 0) {
_LOGD (LOGD_DEVICE, "connection '%s' failed to autoconnect; %d tries left",
nm_settings_connection_get_id (connection), tries);
nm_settings_connection_autoconnect_retries_set (connection, --tries);
} else {
nm_settings_connection_get_id (connection), tries - 1);
_connection_autoconnect_retries_set (self, connection, tries - 1);
} else if (tries != 0) {
_LOGD (LOGD_DEVICE, "connection '%s' failed to autoconnect; infinite tries left",
nm_settings_connection_get_id (connection));
}
}
if (nm_settings_connection_autoconnect_retries_get (connection) == 0) {
_LOGI (LOGD_DEVICE, "disabling autoconnect for connection '%s'.",
nm_settings_connection_get_id (connection));
/* Schedule a handler to reset retries count */
if (!priv->reset_retries_id) {
gint32 retry_time = nm_settings_connection_autoconnect_blocked_until_get (connection);
g_warn_if_fail (retry_time != 0);
priv->reset_retries_id = g_timeout_add_seconds (MAX (0, retry_time - nm_utils_get_monotonic_timestamp_s ()), reset_connections_retries, self);
}
}
nm_connection_clear_secrets (NM_CONNECTION (connection));
}
break;
@ -1799,22 +1820,25 @@ device_state_changed (NMDevice *device,
update_routing_and_dns (self, FALSE);
break;
case NM_DEVICE_STATE_DEACTIVATING:
if (NM_IN_SET (nm_device_state_reason_check (reason),
NM_DEVICE_STATE_REASON_USER_REQUESTED,
NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED)) {
if (connection) {
NMSettingsAutoconnectBlockedReason blocked_reason;
if (connection) {
NMSettingsAutoconnectBlockedReason blocked_reason = NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NONE;
/* The connection was deactivated, so block just this connection */
switch (nm_device_state_reason_check (reason)) {
case NM_DEVICE_STATE_REASON_USER_REQUESTED:
blocked_reason = NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_USER_REQUEST;
break;
case NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED:
blocked_reason = NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED;
break;
default:
break;
}
if (blocked_reason != NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NONE) {
_LOGD (LOGD_DEVICE, "blocking autoconnect of connection '%s': %s",
nm_settings_connection_get_id (connection),
NM_UTILS_LOOKUP_STR (nm_device_state_reason_to_str,
nm_device_state_reason_check (reason)));
if (nm_device_state_reason_check (reason) == NM_DEVICE_STATE_REASON_USER_REQUESTED)
blocked_reason = NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_USER_REQUEST;
else
blocked_reason = NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED;
nm_settings_connection_autoconnect_blocked_reason_set (connection, blocked_reason);
nm_settings_connection_autoconnect_blocked_reason_set (connection, blocked_reason, TRUE);
}
}
ip6_remove_device_prefix_delegations (self, device);
@ -1825,7 +1849,7 @@ device_state_changed (NMDevice *device,
*/
if ( nm_device_state_reason_check (reason) == NM_DEVICE_STATE_REASON_CARRIER
&& old_state == NM_DEVICE_STATE_UNAVAILABLE)
reset_autoconnect_all (self, device);
reset_autoconnect_all (self, device, FALSE);
if (old_state > NM_DEVICE_STATE_DISCONNECTED)
update_routing_and_dns (self, FALSE);
@ -1851,7 +1875,7 @@ device_state_changed (NMDevice *device,
case NM_DEVICE_STATE_IP_CONFIG:
/* We must have secrets if we got here. */
if (connection)
nm_settings_connection_autoconnect_blocked_reason_set (connection, NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NONE);
nm_settings_connection_autoconnect_blocked_reason_set (connection, NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_ALL, FALSE);
break;
case NM_DEVICE_STATE_SECONDARIES:
if (connection)
@ -2014,13 +2038,16 @@ device_removed (NMManager *manager, NMDevice *device, gpointer user_data)
{
NMPolicyPrivate *priv = user_data;
NMPolicy *self = _PRIV_TO_SELF (priv);
ActivateData *data;
/* XXX is this needed? The delegations are cleaned up
* on transition to deactivated too. */
ip6_remove_device_prefix_delegations (self, device);
/* Clear any idle callbacks for this device */
clear_pending_activate_check (self, device);
data = find_pending_activation (self, device);
if (data && data->autoactivate_id)
activate_data_free (data);
if (g_hash_table_remove (priv->devices, device))
devices_list_unregister (self, device);
@ -2310,19 +2337,21 @@ connection_updated (NMSettings *settings,
}
static void
_deactivate_if_active (NMManager *manager, NMSettingsConnection *connection)
_deactivate_if_active (NMPolicy *self, NMSettingsConnection *connection)
{
const GSList *active, *iter;
NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self);
NMActiveConnection *ac;
const CList *tmp_list;
GError *error = NULL;
active = nm_manager_get_active_connections (manager);
for (iter = active; iter; iter = g_slist_next (iter)) {
NMActiveConnection *ac = iter->data;
nm_assert (NM_IS_SETTINGS_CONNECTION (connection));
nm_manager_for_each_active_connection (priv->manager, ac, tmp_list) {
NMActiveConnectionState state = nm_active_connection_get_state (ac);
GError *error = NULL;
if (nm_active_connection_get_settings_connection (ac) == connection &&
(state <= NM_ACTIVE_CONNECTION_STATE_ACTIVATED)) {
if (!nm_manager_deactivate_connection (manager,
if ( nm_active_connection_get_settings_connection (ac) == connection
&& (state <= NM_ACTIVE_CONNECTION_STATE_ACTIVATED)) {
if (!nm_manager_deactivate_connection (priv->manager,
ac,
NM_DEVICE_STATE_REASON_CONNECTION_REMOVED,
&error)) {
@ -2341,9 +2370,7 @@ connection_removed (NMSettings *settings,
NMSettingsConnection *connection,
gpointer user_data)
{
NMPolicyPrivate *priv = user_data;
_deactivate_if_active (priv->manager, connection);
_deactivate_if_active (user_data, connection);
}
static void
@ -2357,7 +2384,7 @@ connection_visibility_changed (NMSettings *settings,
if (nm_settings_connection_is_visible (connection))
schedule_activate_all (self);
else
_deactivate_if_active (priv->manager, connection);
_deactivate_if_active (self, connection);
}
static void
@ -2365,15 +2392,14 @@ secret_agent_registered (NMSettings *settings,
NMSecretAgent *agent,
gpointer user_data)
{
NMPolicyPrivate *priv = user_data;
NMPolicy *self = _PRIV_TO_SELF (priv);
NMPolicy *self = NM_POLICY (user_data);
/* The registered secret agent may provide some missing secrets. Thus we
* reset retries count here and schedule activation, so that the
* connections failed due to missing secrets may re-try auto-connection.
*/
reset_autoconnect_for_failed_secrets (self);
schedule_activate_all (self);
if (reset_autoconnect_all (self, NULL, TRUE))
schedule_activate_all (self);
}
NMDevice *
@ -2469,6 +2495,8 @@ nm_policy_init (NMPolicy *self)
NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self);
const char *hostname_mode;
c_list_init (&priv->pending_activation_checks);
priv->netns = g_object_ref (nm_netns_get ());
priv->hostname_manager = g_object_ref (nm_hostname_manager_get ());
@ -2509,6 +2537,8 @@ constructed (GObject *object)
_LOGT (LOGD_DNS, "hostname-original: set to %s%s%s",
NM_PRINT_FMT_QUOTE_STRING (priv->orig_hostname));
priv->agent_mgr = g_object_ref (nm_agent_manager_get ());
priv->firewall_manager = g_object_ref (nm_firewall_manager_get ());
g_signal_connect (priv->firewall_manager, NM_FIREWALL_MANAGER_STATE_CHANGED,
G_CALLBACK (firewall_state_changed), self);
@ -2533,7 +2563,8 @@ constructed (GObject *object)
g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_UPDATED, (GCallback) connection_updated, priv);
g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_REMOVED, (GCallback) connection_removed, priv);
g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_VISIBILITY_CHANGED, (GCallback) connection_visibility_changed, priv);
g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_AGENT_REGISTERED, (GCallback) secret_agent_registered, priv);
g_signal_connect (priv->agent_mgr, NM_AGENT_MANAGER_AGENT_REGISTERED, G_CALLBACK (secret_agent_registered), self);
G_OBJECT_CLASS (nm_policy_parent_class)->constructed (object);
@ -2557,9 +2588,9 @@ dispose (GObject *object)
{
NMPolicy *self = NM_POLICY (object);
NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self);
const GSList *connections;
GHashTableIter h_iter;
NMDevice *device;
ActivateData *data, *data_safe;
nm_clear_g_cancellable (&priv->lookup.cancellable);
g_clear_object (&priv->lookup.addr);
@ -2571,8 +2602,8 @@ dispose (GObject *object)
nm_clear_g_object (&priv->activating_device6);
g_clear_pointer (&priv->pending_active_connections, g_hash_table_unref);
while (priv->pending_activation_checks)
activate_data_free (priv->pending_activation_checks->data);
c_list_for_each_entry_safe (data, data_safe, &priv->pending_activation_checks, pending_lst)
activate_data_free (data);
g_slist_free_full (priv->pending_secondaries, (GDestroyNotify) pending_secondary_data_free);
priv->pending_secondaries = NULL;
@ -2582,6 +2613,11 @@ dispose (GObject *object)
g_clear_object (&priv->firewall_manager);
}
if (priv->agent_mgr) {
g_signal_handlers_disconnect_by_func (priv->agent_mgr, secret_agent_registered, self);
g_clear_object (&priv->agent_mgr);
}
if (priv->dns_manager) {
nm_clear_g_signal_handler (priv->dns_manager, &priv->config_changed_id);
g_clear_object (&priv->dns_manager);
@ -2597,8 +2633,7 @@ dispose (GObject *object)
* will have called active_connection_removed() and thus we don't need
* to clean anything up. Assert that this is TRUE.
*/
connections = nm_manager_get_active_connections (priv->manager);
g_assert (connections == NULL);
nm_assert (c_list_is_empty (nm_manager_get_active_connections (priv->manager)));
nm_clear_g_source (&priv->reset_retries_id);
nm_clear_g_source (&priv->schedule_activate_all_id);

View file

@ -62,6 +62,8 @@ typedef struct {
GHashTable *agents;
CList requests;
guint64 agent_version_id;
} NMAgentManagerPrivate;
struct _NMAgentManager {
@ -137,6 +139,16 @@ static gboolean _con_get_try_complete_early (Request *req);
/*****************************************************************************/
guint64
nm_agent_manager_get_agent_version_id (NMAgentManager *self)
{
g_return_val_if_fail (NM_IS_AGENT_MANAGER (self), 0);
return NM_AGENT_MANAGER_GET_PRIVATE (self)->agent_version_id;
}
/*****************************************************************************/
typedef enum {
REQUEST_TYPE_INVALID,
REQUEST_TYPE_CON_GET,
@ -336,6 +348,7 @@ agent_register_permissions_done (NMAuthChain *chain,
if (result == NM_AUTH_CALL_RESULT_YES)
nm_secret_agent_add_permission (agent, NM_AUTH_PERMISSION_WIFI_SHARE_OPEN, TRUE);
priv->agent_version_id += 1;
sender = nm_secret_agent_get_dbus_owner (agent);
g_hash_table_insert (priv->agents, g_strdup (sender), agent);
_LOGD (agent, "agent registered");
@ -1558,6 +1571,7 @@ nm_agent_manager_init (NMAgentManager *self)
{
NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self);
priv->agent_version_id = 1;
c_list_init (&priv->requests);
priv->agents = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, g_object_unref);
}
@ -1627,7 +1641,7 @@ nm_agent_manager_class_init (NMAgentManagerClass *agent_manager_class)
object_class->dispose = dispose;
signals[AGENT_REGISTERED] =
g_signal_new ("agent-registered",
g_signal_new (NM_AGENT_MANAGER_AGENT_REGISTERED,
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
0,

View file

@ -33,6 +33,8 @@
#define NM_IS_AGENT_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_AGENT_MANAGER))
#define NM_AGENT_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_AGENT_MANAGER, NMAgentManagerClass))
#define NM_AGENT_MANAGER_AGENT_REGISTERED "agent-registered"
typedef struct _NMAgentManagerCallId *NMAgentManagerCallId;
typedef struct _NMAgentManagerClass NMAgentManagerClass;
@ -41,6 +43,8 @@ GType nm_agent_manager_get_type (void);
NMAgentManager *nm_agent_manager_get (void);
guint64 nm_agent_manager_get_agent_version_id (NMAgentManager *self);
/* If no agent fulfilled the secrets request, agent_dbus_owner will be NULL */
typedef void (*NMAgentSecretsResultFunc) (NMAgentManager *manager,
NMAgentManagerCallId call_id,

View file

@ -50,16 +50,13 @@ typedef struct {
char *owner_username;
char *dbus_owner;
NMSecretAgentCapabilities capabilities;
GSList *permissions;
NMDBusSecretAgent *proxy;
NMBusManager *bus_mgr;
GDBusConnection *connection;
gboolean connection_is_private;
gulong on_disconnected_id;
CList requests;
gulong on_disconnected_id;
bool connection_is_private:1;
} NMSecretAgentPrivate;
struct _NMSecretAgent {

View file

@ -25,6 +25,8 @@
#include <string.h>
#include "nm-utils/c-list.h"
#include "nm-common-macros.h"
#include "nm-config.h"
#include "nm-config-data.h"
@ -42,9 +44,8 @@
#define SETTINGS_TIMESTAMPS_FILE NMSTATEDIR "/timestamps"
#define SETTINGS_SEEN_BSSIDS_FILE NMSTATEDIR "/seen-bssids"
#define AUTOCONNECT_RETRIES_UNSET -2
#define AUTOCONNECT_RETRIES_FOREVER -1
#define AUTOCONNECT_RETRIES_DEFAULT 4
#define AUTOCONNECT_RETRIES_UNSET -2
#define AUTOCONNECT_RETRIES_FOREVER -1
#define AUTOCONNECT_RESET_RETRIES_TIMER 300
/*****************************************************************************/
@ -84,11 +85,11 @@ typedef struct _NMSettingsConnectionPrivate {
bool timestamp_set:1;
NMSettingsAutoconnectBlockedReason autoconnect_blocked_reason:3;
NMSettingsAutoconnectBlockedReason autoconnect_blocked_reason:4;
GSList *pending_auths; /* List of pending authentication requests */
GSList *get_secret_requests; /* in-progress secrets requests */
CList call_ids_lst_head; /* in-progress secrets requests */
/* Caches secrets from on-disk connections; were they not cached any
* call to nm_connection_clear_secrets() wipes them out and we'd have
@ -105,13 +106,17 @@ typedef struct _NMSettingsConnectionPrivate {
*/
NMConnection *agent_secrets;
guint64 timestamp; /* Up-to-date timestamp of connection use */
char *filename;
GHashTable *seen_bssids; /* Up-to-date BSSIDs that's been seen for the connection */
int autoconnect_retries;
gint32 autoconnect_blocked_until;
guint64 timestamp; /* Up-to-date timestamp of connection use */
guint64 last_secret_agent_version_id;
int autoconnect_retries;
gint32 autoconnect_retries_blocked_until;
char *filename;
} NMSettingsConnectionPrivate;
G_DEFINE_TYPE_WITH_CODE (NMSettingsConnection, nm_settings_connection, NM_TYPE_EXPORTED_OBJECT,
@ -170,6 +175,16 @@ nm_settings_connection_has_unmodified_applied_connection (NMSettingsConnection *
/*****************************************************************************/
guint64
nm_settings_connection_get_last_secret_agent_version_id (NMSettingsConnection *self)
{
g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (self), 0);
return NM_SETTINGS_CONNECTION_GET_PRIVATE (self)->last_secret_agent_version_id;
}
/*****************************************************************************/
/* Return TRUE to keep, FALSE to drop */
typedef gboolean (*ForEachSecretFunc) (NMSettingSecretFlags flags,
gpointer user_data);
@ -795,18 +810,19 @@ nm_settings_connection_delete (NMSettingsConnection *self,
typedef enum {
GET_SECRETS_INFO_TYPE_REQ,
GET_SECRETS_INFO_TYPE_IDLE,
} GetSecretsInfoType;
CALL_ID_TYPE_REQ,
CALL_ID_TYPE_IDLE,
} CallIdType;
struct _NMSettingsConnectionCallId {
NMSettingsConnection *self;
CList call_ids_lst;
gboolean had_applied_connection;
NMConnection *applied_connection;
NMSettingsConnectionSecretsFunc callback;
gpointer callback_data;
GetSecretsInfoType type;
CallIdType type;
union {
struct {
NMAgentManagerCallId id;
@ -818,59 +834,36 @@ struct _NMSettingsConnectionCallId {
} t;
};
typedef struct _NMSettingsConnectionCallId GetSecretsInfo;
static GetSecretsInfo *
_get_secrets_info_new (NMSettingsConnection *self,
NMConnection *applied_connection,
NMSettingsConnectionSecretsFunc callback,
gpointer callback_data)
{
GetSecretsInfo *info;
info = g_slice_new0 (GetSecretsInfo);
info->self = self;
if (applied_connection) {
info->had_applied_connection = TRUE;
info->applied_connection = applied_connection;
g_object_add_weak_pointer (G_OBJECT (applied_connection), (gpointer *) &info->applied_connection);
}
info->callback = callback;
info->callback_data = callback_data;
return info;
}
static void
_get_secrets_info_callback (GetSecretsInfo *info,
_get_secrets_info_callback (NMSettingsConnectionCallId *call_id,
const char *agent_username,
const char *setting_name,
GError *error)
{
if (info->callback) {
info->callback (info->self,
info,
agent_username,
setting_name,
error,
info->callback_data);
if (call_id->callback) {
call_id->callback (call_id->self,
call_id,
agent_username,
setting_name,
error,
call_id->callback_data);
}
}
static void
_get_secrets_info_free (GetSecretsInfo *info)
_get_secrets_info_free (NMSettingsConnectionCallId *call_id)
{
g_return_if_fail (info && info->self);
g_return_if_fail (call_id && call_id->self);
nm_assert (!c_list_is_linked (&call_id->call_ids_lst));
if (info->applied_connection)
g_object_remove_weak_pointer (G_OBJECT (info->applied_connection), (gpointer *) &info->applied_connection);
if (call_id->applied_connection)
g_object_remove_weak_pointer (G_OBJECT (call_id->applied_connection), (gpointer *) &call_id->applied_connection);
if (info->type == GET_SECRETS_INFO_TYPE_IDLE)
g_clear_error (&info->t.idle.error);
if (call_id->type == CALL_ID_TYPE_IDLE)
g_clear_error (&call_id->t.idle.error);
memset (info, 0, sizeof (*info));
g_slice_free (GetSecretsInfo, info);
memset (call_id, 0, sizeof (*call_id));
g_slice_free (NMSettingsConnectionCallId, call_id);
}
static gboolean
@ -907,7 +900,7 @@ secret_is_system_owned (NMSettingSecretFlags flags,
static void
get_cmp_flags (NMSettingsConnection *self, /* only needed for logging */
GetSecretsInfo *info, /* only needed for logging */
NMSettingsConnectionCallId *call_id, /* only needed for logging */
NMConnection *connection,
const char *agent_dbus_owner,
gboolean agent_has_modify,
@ -930,7 +923,7 @@ get_cmp_flags (NMSettingsConnection *self, /* only needed for logging */
if (is_self) {
_LOGD ("(%s:%p) secrets returned from agent %s",
setting_name,
info,
call_id,
agent_dbus_owner);
}
@ -949,7 +942,7 @@ get_cmp_flags (NMSettingsConnection *self, /* only needed for logging */
if (is_self) {
_LOGD ("(%s:%p) interaction forbidden but agent %s returned system secrets",
setting_name,
info,
call_id,
agent_dbus_owner);
}
@ -961,7 +954,7 @@ get_cmp_flags (NMSettingsConnection *self, /* only needed for logging */
if (is_self) {
_LOGD ("(%s:%p) agent failed to authenticate but provided system secrets",
setting_name,
info);
call_id);
}
cmp_flags->required |= NM_SETTING_SECRET_FLAG_AGENT_OWNED;
@ -971,7 +964,7 @@ get_cmp_flags (NMSettingsConnection *self, /* only needed for logging */
if (is_self) {
_LOGD ("(%s:%p) existing secrets returned",
setting_name,
info);
call_id);
}
}
@ -1023,7 +1016,7 @@ get_secrets_done_cb (NMAgentManager *manager,
GError *error,
gpointer user_data)
{
GetSecretsInfo *info = user_data;
NMSettingsConnectionCallId *call_id = user_data;
NMSettingsConnection *self;
NMSettingsConnectionPrivate *priv;
NMConnection *applied_connection;
@ -1035,36 +1028,36 @@ get_secrets_done_cb (NMAgentManager *manager,
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
return;
self = info->self;
self = call_id->self;
g_return_if_fail (NM_IS_SETTINGS_CONNECTION (self));
priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self);
g_return_if_fail (g_slist_find (priv->get_secret_requests, info));
nm_assert (c_list_contains (&priv->call_ids_lst_head, &call_id->call_ids_lst));
priv->get_secret_requests = g_slist_remove (priv->get_secret_requests, info);
c_list_unlink_init (&call_id->call_ids_lst);
if (error) {
_LOGD ("(%s:%p) secrets request error: %s",
setting_name, info, error->message);
setting_name, call_id, error->message);
_get_secrets_info_callback (info, NULL, setting_name, error);
_get_secrets_info_callback (call_id, NULL, setting_name, error);
goto out;
}
if ( info->had_applied_connection
&& !info->applied_connection) {
if ( call_id->had_applied_connection
&& !call_id->applied_connection) {
g_set_error_literal (&local, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_SETTING_NOT_FOUND,
"Applied connection deleted since requesting secrets");
_get_secrets_info_callback (info, NULL, setting_name, local);
_get_secrets_info_callback (call_id, NULL, setting_name, local);
goto out;
}
if ( info->had_applied_connection
&& !nm_settings_connection_has_unmodified_applied_connection (self, info->applied_connection, NM_SETTING_COMPARE_FLAG_NONE)) {
if ( call_id->had_applied_connection
&& !nm_settings_connection_has_unmodified_applied_connection (self, call_id->applied_connection, NM_SETTING_COMPARE_FLAG_NONE)) {
g_set_error_literal (&local, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
"The connection was modified since activation");
_get_secrets_info_callback (info, NULL, setting_name, local);
_get_secrets_info_callback (call_id, NULL, setting_name, local);
goto out;
}
@ -1072,12 +1065,12 @@ get_secrets_done_cb (NMAgentManager *manager,
g_set_error (&local, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_SETTING_NOT_FOUND,
"Connection didn't have requested setting '%s'.",
setting_name);
_get_secrets_info_callback (info, NULL, setting_name, local);
_get_secrets_info_callback (call_id, NULL, setting_name, local);
goto out;
}
get_cmp_flags (self,
info,
call_id,
NM_CONNECTION (self),
agent_dbus_owner,
agent_has_modify,
@ -1089,7 +1082,7 @@ get_secrets_done_cb (NMAgentManager *manager,
_LOGD ("(%s:%p) secrets request completed",
setting_name,
info);
call_id);
dict = nm_connection_to_dbus (priv->system_secrets, NM_CONNECTION_SERIALIZE_ONLY_SECRETS);
@ -1119,7 +1112,7 @@ get_secrets_done_cb (NMAgentManager *manager,
if (agent_had_system) {
_LOGD ("(%s:%p) saving new secrets to backing storage",
setting_name,
info);
call_id);
nm_settings_connection_commit_changes (self,
NULL,
@ -1128,27 +1121,27 @@ get_secrets_done_cb (NMAgentManager *manager,
} else {
_LOGD ("(%s:%p) new agent secrets processed",
setting_name,
info);
call_id);
}
} else {
_LOGD ("(%s:%p) failed to update with agent secrets: %s",
setting_name,
info,
call_id,
local->message);
}
g_variant_unref (filtered_secrets);
} else {
_LOGD ("(%s:%p) failed to update with existing secrets: %s",
setting_name,
info,
call_id,
local->message);
}
applied_connection = info->applied_connection;
applied_connection = call_id->applied_connection;
if (applied_connection) {
get_cmp_flags (self,
info,
call_id,
applied_connection,
agent_dbus_owner,
agent_has_modify,
@ -1169,31 +1162,31 @@ get_secrets_done_cb (NMAgentManager *manager,
}
}
_get_secrets_info_callback (info, agent_username, setting_name, local);
_get_secrets_info_callback (call_id, agent_username, setting_name, local);
g_clear_error (&local);
if (dict)
g_variant_unref (dict);
out:
_get_secrets_info_free (info);
_get_secrets_info_free (call_id);
}
static gboolean
get_secrets_idle_cb (GetSecretsInfo *info)
get_secrets_idle_cb (NMSettingsConnectionCallId *call_id)
{
NMSettingsConnectionPrivate *priv;
g_return_val_if_fail (info && NM_IS_SETTINGS_CONNECTION (info->self), G_SOURCE_REMOVE);
g_return_val_if_fail (call_id && NM_IS_SETTINGS_CONNECTION (call_id->self), G_SOURCE_REMOVE);
priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (info->self);
priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (call_id->self);
g_return_val_if_fail (g_slist_find (priv->get_secret_requests, info), G_SOURCE_REMOVE);
nm_assert (c_list_contains (&priv->call_ids_lst_head, &call_id->call_ids_lst));
priv->get_secret_requests = g_slist_remove (priv->get_secret_requests, info);
c_list_unlink_init (&call_id->call_ids_lst);
_get_secrets_info_callback (info, NULL, NULL, info->t.idle.error);
_get_secrets_info_callback (call_id, NULL, NULL, call_id->t.idle.error);
_get_secrets_info_free (info);
_get_secrets_info_free (call_id);
return G_SOURCE_REMOVE;
}
@ -1222,7 +1215,7 @@ get_secrets_idle_cb (GetSecretsInfo *info)
*
* Returns: a call ID which may be used to cancel the ongoing secrets request.
**/
NMSettingsConnectionCallId
NMSettingsConnectionCallId *
nm_settings_connection_get_secrets (NMSettingsConnection *self,
NMConnection *applied_connection,
NMAuthSubject *subject,
@ -1236,7 +1229,7 @@ nm_settings_connection_get_secrets (NMSettingsConnection *self,
GVariant *existing_secrets;
NMAgentManagerCallId call_id_a;
gs_free char *joined_hints = NULL;
GetSecretsInfo *info;
NMSettingsConnectionCallId *call_id;
GError *local = NULL;
g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (self), NULL);
@ -1244,12 +1237,16 @@ nm_settings_connection_get_secrets (NMSettingsConnection *self,
|| ( NM_IS_CONNECTION (applied_connection)
&& (((NMConnection *) self) != applied_connection)), NULL);
info = _get_secrets_info_new (self,
applied_connection,
callback,
callback_data);
priv->get_secret_requests = g_slist_append (priv->get_secret_requests, info);
call_id = g_slice_new0 (NMSettingsConnectionCallId);
call_id->self = self;
if (applied_connection) {
call_id->had_applied_connection = TRUE;
call_id->applied_connection = applied_connection;
g_object_add_weak_pointer (G_OBJECT (applied_connection), (gpointer *) &call_id->applied_connection);
}
call_id->callback = callback;
call_id->callback_data = callback_data;
c_list_link_tail (&priv->call_ids_lst_head, &call_id->call_ids_lst);
/* Use priv->secrets to work around the fact that nm_connection_clear_secrets()
* will clear secrets on this object's settings.
@ -1278,6 +1275,14 @@ nm_settings_connection_get_secrets (NMSettingsConnection *self,
existing_secrets = nm_connection_to_dbus (priv->system_secrets, NM_CONNECTION_SERIALIZE_ONLY_SECRETS);
if (existing_secrets)
g_variant_ref_sink (existing_secrets);
/* we remember the current version-id of the secret-agents. The version-id is strictly increasing,
* as new agents register the number. We know hence, that this request was made against a certain
* set of secret-agents.
* If after making this request a new secret-agent registeres, the version-id increases.
* Then we know that the this request probably did not yet include the latest secret-agent. */
priv->last_secret_agent_version_id = nm_agent_manager_get_agent_version_id (priv->agent_mgr);
call_id_a = nm_agent_manager_get_secrets (priv->agent_mgr,
nm_connection_get_path (NM_CONNECTION (self)),
NM_CONNECTION (self),
@ -1287,7 +1292,7 @@ nm_settings_connection_get_secrets (NMSettingsConnection *self,
flags,
hints,
get_secrets_done_cb,
info);
call_id);
g_assert (call_id_a);
if (existing_secrets)
g_variant_unref (existing_secrets);
@ -1299,45 +1304,44 @@ nm_settings_connection_get_secrets (NMSettingsConnection *self,
(hints && hints[0]) ? (joined_hints = g_strjoinv (",", (char **) hints)) : "(none)");
if (call_id_a) {
info->type = GET_SECRETS_INFO_TYPE_REQ;
info->t.req.id = call_id_a;
call_id->type = CALL_ID_TYPE_REQ;
call_id->t.req.id = call_id_a;
} else {
schedule_dummy:
info->type = GET_SECRETS_INFO_TYPE_IDLE;
g_propagate_error (&info->t.idle.error, local);
info->t.idle.id = g_idle_add ((GSourceFunc) get_secrets_idle_cb, info);
call_id->type = CALL_ID_TYPE_IDLE;
g_propagate_error (&call_id->t.idle.error, local);
call_id->t.idle.id = g_idle_add ((GSourceFunc) get_secrets_idle_cb, call_id);
}
return info;
return call_id;
}
static void
_get_secrets_cancel (NMSettingsConnection *self,
GetSecretsInfo *info,
NMSettingsConnectionCallId *call_id,
gboolean is_disposing)
{
NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self);
gs_free_error GError *error = NULL;
if (!g_slist_find (priv->get_secret_requests, info))
g_return_if_reached ();
nm_assert (c_list_contains (&priv->call_ids_lst_head, &call_id->call_ids_lst));
priv->get_secret_requests = g_slist_remove (priv->get_secret_requests, info);
c_list_unlink_init (&call_id->call_ids_lst);
if (info->type == GET_SECRETS_INFO_TYPE_REQ)
nm_agent_manager_cancel_secrets (priv->agent_mgr, info->t.req.id);
if (call_id->type == CALL_ID_TYPE_REQ)
nm_agent_manager_cancel_secrets (priv->agent_mgr, call_id->t.req.id);
else
g_source_remove (info->t.idle.id);
g_source_remove (call_id->t.idle.id);
nm_utils_error_set_cancelled (&error, is_disposing, "NMSettingsConnection");
_get_secrets_info_callback (info, NULL, NULL, error);
_get_secrets_info_callback (call_id, NULL, NULL, error);
_get_secrets_info_free (info);
_get_secrets_info_free (call_id);
}
void
nm_settings_connection_cancel_secrets (NMSettingsConnection *self,
NMSettingsConnectionCallId call_id)
NMSettingsConnectionCallId *call_id)
{
_LOGD ("(%p) secrets canceled", call_id);
@ -1656,8 +1660,7 @@ update_complete (NMSettingsConnection *self,
g_clear_object (&info->agent_mgr);
g_clear_object (&info->new_settings);
g_free (info->audit_args);
memset (info, 0, sizeof (*info));
g_free (info);
g_slice_free (UpdateInfo, info);
}
static void
@ -1832,7 +1835,7 @@ settings_connection_update_helper (NMSettingsConnection *self,
goto error;
}
info = g_malloc0 (sizeof (*info));
info = g_slice_new0 (UpdateInfo);
info->context = context;
info->agent_mgr = g_object_ref (priv->agent_mgr);
info->subject = subject;
@ -1951,7 +1954,7 @@ out_err:
static void
dbus_get_agent_secrets_cb (NMSettingsConnection *self,
NMSettingsConnectionCallId call_id,
NMSettingsConnectionCallId *call_id,
const char *agent_username,
const char *setting_name,
GError *error,
@ -2533,6 +2536,54 @@ nm_settings_connection_read_and_fill_seen_bssids (NMSettingsConnection *self)
/*****************************************************************************/
static int
_autoconnect_retries_initial (NMSettingsConnection *self)
{
NMSettingConnection *s_con;
int retries = -1;
s_con = nm_connection_get_setting_connection ((NMConnection *) self);
if (s_con)
retries = nm_setting_connection_get_autoconnect_retries (s_con);
/* -1 means 'default' */
if (retries == -1)
retries = nm_config_data_get_autoconnect_retries_default (NM_CONFIG_GET_DATA);
/* 0 means 'forever', which is translated to a retry count of -1 */
if (retries == 0)
retries = AUTOCONNECT_RETRIES_FOREVER;
nm_assert (retries == AUTOCONNECT_RETRIES_FOREVER || retries >= 0);
return retries;
}
static void
_autoconnect_retries_set (NMSettingsConnection *self,
int retries,
gboolean is_reset)
{
NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self);
g_return_if_fail (retries == AUTOCONNECT_RETRIES_FOREVER || retries >= 0);
if (priv->autoconnect_retries != retries) {
_LOGT ("autoconnect: retries set %d%s", retries,
is_reset ? " (reset)" : "");
priv->autoconnect_retries = retries;
}
if (retries)
priv->autoconnect_retries_blocked_until = 0;
else {
/* XXX: the blocked time must be identical for all connections, otherwise
* the tracking of resetting the retry count in NMPolicy needs adjustment
* in _connection_autoconnect_retries_set() (as it would need to re-evaluate
* the next-timeout everytime a connection gets blocked). */
priv->autoconnect_retries_blocked_until = nm_utils_get_monotonic_timestamp_s () + AUTOCONNECT_RESET_RETRIES_TIMER;
}
}
/**
* nm_settings_connection_autoconnect_retries_get:
* @self: the settings connection
@ -2547,30 +2598,10 @@ nm_settings_connection_autoconnect_retries_get (NMSettingsConnection *self)
NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self);
if (G_UNLIKELY (priv->autoconnect_retries == AUTOCONNECT_RETRIES_UNSET)) {
NMSettingConnection *s_con;
int retries = -1;
s_con = nm_connection_get_setting_connection ((NMConnection *) self);
if (s_con)
retries = nm_setting_connection_get_autoconnect_retries (s_con);
/* -1 means 'default' */
if (retries == -1) {
retries = nm_config_data_get_value_int64 (NM_CONFIG_GET_DATA,
NM_CONFIG_KEYFILE_GROUP_MAIN,
"autoconnect-retries-default",
10, 0, G_MAXINT32,
AUTOCONNECT_RETRIES_DEFAULT);
}
/* 0 means 'forever', which is translated to a retry count of -1 */
if (retries == 0)
retries = AUTOCONNECT_RETRIES_FOREVER;
_LOGT ("autoconnect-retries: init %d", retries);
priv->autoconnect_retries = retries;
_autoconnect_retries_set (self,
_autoconnect_retries_initial (self),
TRUE);
}
return priv->autoconnect_retries;
}
@ -2578,51 +2609,71 @@ void
nm_settings_connection_autoconnect_retries_set (NMSettingsConnection *self,
int retries)
{
NMSettingsConnectionPrivate *priv;
g_return_if_fail (NM_IS_SETTINGS_CONNECTION (self));
nm_assert (retries == AUTOCONNECT_RETRIES_UNSET || retries >= 0);
g_return_if_fail (retries >= 0);
priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self);
if (priv->autoconnect_retries != retries) {
_LOGT ("autoconnect-retries: set %d", retries);
priv->autoconnect_retries = retries;
}
if (retries)
priv->autoconnect_blocked_until = 0;
else
priv->autoconnect_blocked_until = nm_utils_get_monotonic_timestamp_s () + AUTOCONNECT_RESET_RETRIES_TIMER;
_autoconnect_retries_set (self, retries, FALSE);
}
void
nm_settings_connection_autoconnect_retries_reset (NMSettingsConnection *self)
{
nm_settings_connection_autoconnect_retries_set (self, AUTOCONNECT_RETRIES_UNSET);
g_return_if_fail (NM_IS_SETTINGS_CONNECTION (self));
_autoconnect_retries_set (self,
_autoconnect_retries_initial (self),
TRUE);
}
gint32
nm_settings_connection_autoconnect_blocked_until_get (NMSettingsConnection *self)
nm_settings_connection_autoconnect_retries_blocked_until (NMSettingsConnection *self)
{
return NM_SETTINGS_CONNECTION_GET_PRIVATE (self)->autoconnect_blocked_until;
return NM_SETTINGS_CONNECTION_GET_PRIVATE (self)->autoconnect_retries_blocked_until;
}
NM_UTILS_FLAGS2STR_DEFINE_STATIC (_autoconnect_blocked_reason_to_string, NMSettingsAutoconnectBlockedReason,
NM_UTILS_FLAGS2STR (NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NONE, "none"),
NM_UTILS_FLAGS2STR (NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_USER_REQUEST, "user-request"),
NM_UTILS_FLAGS2STR (NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED, "failed"),
NM_UTILS_FLAGS2STR (NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NO_SECRETS, "no-secrets"),
);
NMSettingsAutoconnectBlockedReason
nm_settings_connection_autoconnect_blocked_reason_get (NMSettingsConnection *self)
nm_settings_connection_autoconnect_blocked_reason_get (NMSettingsConnection *self, NMSettingsAutoconnectBlockedReason mask)
{
return NM_SETTINGS_CONNECTION_GET_PRIVATE (self)->autoconnect_blocked_reason;
return NM_SETTINGS_CONNECTION_GET_PRIVATE (self)->autoconnect_blocked_reason & (mask ?: NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_ALL);
}
void
nm_settings_connection_autoconnect_blocked_reason_set (NMSettingsConnection *self,
NMSettingsAutoconnectBlockedReason reason)
gboolean
nm_settings_connection_autoconnect_blocked_reason_set_full (NMSettingsConnection *self,
NMSettingsAutoconnectBlockedReason mask,
NMSettingsAutoconnectBlockedReason value)
{
g_return_if_fail (NM_IN_SET (reason,
NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NONE,
NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_USER_REQUEST,
NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED,
NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NO_SECRETS));
NM_SETTINGS_CONNECTION_GET_PRIVATE (self)->autoconnect_blocked_reason = reason;
NMSettingsAutoconnectBlockedReason v;
NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self);
char buf[100];
nm_assert (mask);
nm_assert (!NM_FLAGS_ANY (value, ~mask));
v = priv->autoconnect_blocked_reason;
v = (v & ~mask) | (value & mask);
if (priv->autoconnect_blocked_reason == v)
return FALSE;
_LOGT ("autoconnect: blocked reason: %s", _autoconnect_blocked_reason_to_string (v, buf, sizeof (buf)));
priv->autoconnect_blocked_reason = v;
return TRUE;
}
gboolean
nm_settings_connection_autoconnect_is_blocked (NMSettingsConnection *self)
{
NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self);
return !priv->autoconnect_blocked_reason
&& priv->autoconnect_retries != 0;
}
/*****************************************************************************/
@ -2771,17 +2822,14 @@ dispose (GObject *object)
{
NMSettingsConnection *self = NM_SETTINGS_CONNECTION (object);
NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self);
NMSettingsConnectionCallId *call_id, *call_id_safe;
_LOGD ("disposing");
/* Cancel in-progress secrets requests */
if (priv->agent_mgr) {
while (priv->get_secret_requests) {
GetSecretsInfo *info = priv->get_secret_requests->data;
_get_secrets_cancel (self, info, TRUE);
g_return_if_fail (!priv->get_secret_requests || (info != priv->get_secret_requests->data));
}
c_list_for_each_entry_safe (call_id, call_id_safe, &priv->call_ids_lst_head, call_ids_lst)
_get_secrets_cancel (self, call_id, TRUE);
}
/* Disconnect handlers.

View file

@ -84,13 +84,18 @@ typedef enum { /*< skip >*/
typedef enum {
NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NONE = 0,
NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_USER_REQUEST = 1,
NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED = 2,
NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NO_SECRETS = 3,
NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_USER_REQUEST = (1LL << 0),
NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED = (1LL << 1),
NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NO_SECRETS = (1LL << 2),
NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_ALL = ( NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_USER_REQUEST
| NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED
| NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NO_SECRETS),
} NMSettingsAutoconnectBlockedReason;
struct _NMSettingsConnectionCallId;
typedef struct _NMSettingsConnectionCallId *NMSettingsConnectionCallId;
typedef struct _NMSettingsConnectionCallId NMSettingsConnectionCallId;
typedef struct _NMSettingsConnectionClass NMSettingsConnectionClass;
@ -120,6 +125,8 @@ struct _NMSettingsConnectionClass {
GType nm_settings_connection_get_type (void);
guint64 nm_settings_connection_get_last_secret_agent_version_id (NMSettingsConnection *self);
gboolean nm_settings_connection_has_unmodified_applied_connection (NMSettingsConnection *self,
NMConnection *applied_connection,
NMSettingCompareFlags compare_flage);
@ -150,7 +157,7 @@ gboolean nm_settings_connection_delete (NMSettingsConnection *self,
GError **error);
typedef void (*NMSettingsConnectionSecretsFunc) (NMSettingsConnection *self,
NMSettingsConnectionCallId call_id,
NMSettingsConnectionCallId *call_id,
const char *agent_username,
const char *setting_name,
GError *error,
@ -162,17 +169,17 @@ gboolean nm_settings_connection_new_secrets (NMSettingsConnection *self,
GVariant *secrets,
GError **error);
NMSettingsConnectionCallId nm_settings_connection_get_secrets (NMSettingsConnection *self,
NMConnection *applied_connection,
NMAuthSubject *subject,
const char *setting_name,
NMSecretAgentGetSecretsFlags flags,
const char *const*hints,
NMSettingsConnectionSecretsFunc callback,
gpointer callback_data);
NMSettingsConnectionCallId *nm_settings_connection_get_secrets (NMSettingsConnection *self,
NMConnection *applied_connection,
NMAuthSubject *subject,
const char *setting_name,
NMSecretAgentGetSecretsFlags flags,
const char *const*hints,
NMSettingsConnectionSecretsFunc callback,
gpointer callback_data);
void nm_settings_connection_cancel_secrets (NMSettingsConnection *self,
NMSettingsConnectionCallId call_id);
NMSettingsConnectionCallId *call_id);
gboolean nm_settings_connection_is_visible (NMSettingsConnection *self);
@ -218,11 +225,23 @@ void nm_settings_connection_autoconnect_retries_set (NMSettingsConnection *self,
int retries);
void nm_settings_connection_autoconnect_retries_reset (NMSettingsConnection *self);
gint32 nm_settings_connection_autoconnect_blocked_until_get (NMSettingsConnection *self);
gint32 nm_settings_connection_autoconnect_retries_blocked_until (NMSettingsConnection *self);
NMSettingsAutoconnectBlockedReason nm_settings_connection_autoconnect_blocked_reason_get (NMSettingsConnection *self);
void nm_settings_connection_autoconnect_blocked_reason_set (NMSettingsConnection *self,
NMSettingsAutoconnectBlockedReason reason);
NMSettingsAutoconnectBlockedReason nm_settings_connection_autoconnect_blocked_reason_get (NMSettingsConnection *self,
NMSettingsAutoconnectBlockedReason mask);
gboolean nm_settings_connection_autoconnect_blocked_reason_set_full (NMSettingsConnection *self,
NMSettingsAutoconnectBlockedReason mask,
NMSettingsAutoconnectBlockedReason value);
static inline gboolean
nm_settings_connection_autoconnect_blocked_reason_set (NMSettingsConnection *self,
NMSettingsAutoconnectBlockedReason mask,
gboolean set)
{
return nm_settings_connection_autoconnect_blocked_reason_set_full (self, mask, set ? mask : NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NONE);
}
gboolean nm_settings_connection_autoconnect_is_blocked (NMSettingsConnection *self);
gboolean nm_settings_connection_get_nm_generated (NMSettingsConnection *self);
gboolean nm_settings_connection_get_volatile (NMSettingsConnection *self);

View file

@ -128,7 +128,6 @@ enum {
CONNECTION_UPDATED,
CONNECTION_REMOVED,
CONNECTION_VISIBILITY_CHANGED,
AGENT_REGISTERED,
NEW_CONNECTION, /* exported, not used internally */
LAST_SIGNAL
};
@ -431,6 +430,9 @@ nm_settings_get_connections (NMSettings *self, guint *out_len)
* @out_len: (allow-none): optional output argument
* @func: caller-supplied function for filtering connections
* @func_data: caller-supplied data passed to @func
* @sort_compare_func: (allow-none): optional function pointer for
* sorting the returned list.
* @sort_data: user data for @sort_compare_func.
*
* Returns: (transfer container) (element-type NMSettingsConnection):
* an NULL terminated array of #NMSettingsConnection objects that were
@ -443,7 +445,9 @@ NMSettingsConnection **
nm_settings_get_connections_clone (NMSettings *self,
guint *out_len,
NMSettingsConnectionFilterFunc func,
gpointer func_data)
gpointer func_data,
GCompareDataFunc sort_compare_func,
gpointer sort_data)
{
NMSettingsConnection *const*list_cached;
NMSettingsConnection **list;
@ -471,31 +475,15 @@ nm_settings_get_connections_clone (NMSettings *self,
} else
memcpy (list, list_cached, sizeof (list[0]) * ((gsize) len + 1));
if ( len > 1
&& sort_compare_func) {
g_qsort_with_data (list, len, sizeof (NMSettingsConnection *),
sort_compare_func, sort_data);
}
NM_SET_OUT (out_len, len);
return list;
}
/* Returns a list of NMSettingsConnections.
* The list is sorted in the order suitable for auto-connecting, i.e.
* first go connections with autoconnect=yes and most recent timestamp.
* Caller must free the list with g_free(), but not the list items.
*/
NMSettingsConnection **
nm_settings_get_connections_sorted (NMSettings *self, guint *out_len)
{
NMSettingsConnection **connections;
guint len;
g_return_val_if_fail (NM_IS_SETTINGS (self), NULL);
connections = nm_settings_get_connections_clone (self, &len, NULL, NULL);
if (len > 1)
g_qsort_with_data (connections, len, sizeof (NMSettingsConnection *), nm_settings_connection_cmp_autoconnect_priority_p_with_data, NULL);
NM_SET_OUT (out_len, len);
return connections;
}
NMSettingsConnection *
nm_settings_get_connection_by_path (NMSettings *self, const char *path)
{
@ -889,18 +877,6 @@ connection_removed (NMSettingsConnection *connection, gpointer user_data)
g_object_unref (connection);
}
static void
secret_agent_registered (NMAgentManager *agent_mgr,
NMSecretAgent *agent,
gpointer user_data)
{
/* Re-emit for listeners like NMPolicy */
g_signal_emit (NM_SETTINGS (user_data),
signals[AGENT_REGISTERED],
0,
agent);
}
#define NM_DBUS_SERVICE_OPENCONNECT "org.freedesktop.NetworkManager.openconnect"
#define NM_OPENCONNECT_KEY_GATEWAY "gateway"
#define NM_OPENCONNECT_KEY_COOKIE "cookie"
@ -1899,16 +1875,8 @@ nm_settings_init (NMSettings *self)
priv->connections = g_hash_table_new_full (nm_str_hash, g_str_equal, NULL, g_object_unref);
/* Hold a reference to the agent manager so it stays alive; the only
* other holders are NMSettingsConnection objects which are often
* transient, and we don't want the agent manager to get destroyed and
* recreated often.
*/
priv->agent_mgr = g_object_ref (nm_agent_manager_get ());
priv->config = g_object_ref (nm_config_get ());
g_signal_connect (priv->agent_mgr, "agent-registered", G_CALLBACK (secret_agent_registered), self);
}
NMSettings *
@ -2033,15 +2001,6 @@ nm_settings_class_init (NMSettingsClass *class)
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE, 1, NM_TYPE_SETTINGS_CONNECTION);
signals[AGENT_REGISTERED] =
g_signal_new (NM_SETTINGS_SIGNAL_AGENT_REGISTERED,
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
0, NULL, NULL,
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE, 1, NM_TYPE_SECRET_AGENT);
signals[NEW_CONNECTION] =
g_signal_new ("new-connection",
G_OBJECT_CLASS_TYPE (object_class),

View file

@ -47,7 +47,6 @@
#define NM_SETTINGS_SIGNAL_CONNECTION_UPDATED "connection-updated"
#define NM_SETTINGS_SIGNAL_CONNECTION_REMOVED "connection-removed"
#define NM_SETTINGS_SIGNAL_CONNECTION_VISIBILITY_CHANGED "connection-visibility-changed"
#define NM_SETTINGS_SIGNAL_AGENT_REGISTERED "agent-registered"
/**
* NMConnectionFilterFunc:
@ -100,10 +99,9 @@ NMSettingsConnection *const* nm_settings_get_connections (NMSettings *settings,
NMSettingsConnection **nm_settings_get_connections_clone (NMSettings *self,
guint *out_len,
NMSettingsConnectionFilterFunc func,
gpointer func_data);
NMSettingsConnection **nm_settings_get_connections_sorted (NMSettings *self,
guint *out_len);
gpointer func_data,
GCompareDataFunc sort_compare_func,
gpointer sort_data);
NMSettingsConnection *nm_settings_add_connection (NMSettings *settings,
NMConnection *connection,

View file

@ -103,7 +103,7 @@ typedef struct {
gboolean service_can_persist;
gboolean connection_can_persist;
NMSettingsConnectionCallId secrets_id;
NMSettingsConnectionCallId *secrets_id;
SecretsReq secrets_idx;
char *username;
@ -2571,7 +2571,7 @@ plugin_new_secrets_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_da
static void
get_secrets_cb (NMSettingsConnection *connection,
NMSettingsConnectionCallId call_id,
NMSettingsConnectionCallId *call_id,
const char *agent_username,
const char *setting_name,
GError *error,