core: various fixes to autoconnect retry handling (rh #1029480)

This commit is contained in:
Dan Winship 2014-01-23 15:16:24 -05:00
commit 38ef82d015
14 changed files with 381 additions and 417 deletions

View file

@ -180,11 +180,6 @@ pan_connection_check_create (NMBluezDevice *self)
return;
}
if (!nm_connection_provider_has_connections_loaded (priv->provider)) {
/* do not try to create any connections until the connection provider is ready. */
return;
}
/* Only try once to create a connection. If it does not succeed, we do not try again. Also,
* if the connection gets deleted later, do not create another one for this device. */
priv->pan_connection_no_autocreate = TRUE;
@ -387,13 +382,14 @@ cp_connection_updated (NMConnectionProvider *provider,
}
static void
cp_connections_loaded (NMConnectionProvider *provider, NMBluezDevice *self)
load_connections (NMBluezDevice *self)
{
NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self);
const GSList *connections, *iter;
connections = nm_connection_provider_get_connections (provider);
connections = nm_connection_provider_get_connections (priv->provider);
for (iter = connections; iter; iter = g_slist_next (iter))
cp_connection_added (provider, NM_CONNECTION (iter->data), self);
cp_connection_added (priv->provider, NM_CONNECTION (iter->data), self);
}
/***********************************************************/
@ -832,7 +828,7 @@ get_properties_cb_4 (GObject *source_object, GAsyncResult *res, gpointer user_da
g_variant_unref (v_properties);
/* Check if any connections match this device */
cp_connections_loaded (priv->provider, self);
load_connections (self);
priv->initialized = TRUE;
g_signal_emit (self, signals[INITIALIZED], 0, TRUE);
@ -883,7 +879,7 @@ query_properties (NMBluezDevice *self)
}
/* Check if any connections match this device */
cp_connections_loaded (priv->provider, self);
load_connections (self);
break;
}
@ -970,11 +966,6 @@ nm_bluez_device_new (const char *path, NMConnectionProvider *provider, int bluez
G_CALLBACK (cp_connection_updated),
self);
g_signal_connect (priv->provider,
NM_CP_SIGNAL_CONNECTIONS_LOADED,
G_CALLBACK (cp_connections_loaded),
self);
g_bus_get (G_BUS_TYPE_SYSTEM,
NULL,
(GAsyncReadyCallback) on_bus_acquired,
@ -1027,7 +1018,6 @@ dispose (GObject *object)
g_signal_handlers_disconnect_by_func (priv->provider, cp_connection_added, self);
g_signal_handlers_disconnect_by_func (priv->provider, cp_connection_removed, self);
g_signal_handlers_disconnect_by_func (priv->provider, cp_connection_updated, self);
g_signal_handlers_disconnect_by_func (priv->provider, cp_connections_loaded, self);
g_slist_free_full (priv->connections, g_object_unref);
priv->connections = NULL;

View file

@ -137,6 +137,7 @@ enum {
PROP_AVAILABLE_CONNECTIONS,
PROP_PHYSICAL_PORT_ID,
PROP_IS_MASTER,
PROP_MASTER,
PROP_HW_ADDRESS,
PROP_HAS_PENDING_ACTION,
LAST_PROP
@ -351,7 +352,6 @@ static const char *reason_to_string (NMDeviceStateReason reason);
static void ip_check_gw_ping_cleanup (NMDevice *self);
static void cp_connection_added (NMConnectionProvider *cp, NMConnection *connection, gpointer user_data);
static void cp_connections_loaded (NMConnectionProvider *cp, NMConnection *connection, gpointer user_data);
static void cp_connection_removed (NMConnectionProvider *cp, NMConnection *connection, gpointer user_data);
static void cp_connection_updated (NMConnectionProvider *cp, NMConnection *connection, gpointer user_data);
@ -365,7 +365,7 @@ static void update_ip_config (NMDevice *self, gboolean initial);
static void device_ip_changed (NMPlatform *platform, int ifindex, gpointer platform_object, NMPlatformReason reason, gpointer user_data);
static void nm_device_slave_notify_enslave (NMDevice *dev, gboolean success);
static void nm_device_slave_notify_release (NMDevice *dev, gboolean master_failed);
static void nm_device_slave_notify_release (NMDevice *dev, NMDeviceStateReason reason);
static void addrconf6_start_with_link_ready (NMDevice *self);
@ -907,11 +907,6 @@ nm_device_set_connection_provider (NMDevice *device,
G_CALLBACK (cp_connection_added),
device);
priv->cp_loaded_id = g_signal_connect (priv->con_provider,
NM_CP_SIGNAL_CONNECTIONS_LOADED,
G_CALLBACK (cp_connections_loaded),
device);
priv->cp_removed_id = g_signal_connect (priv->con_provider,
NM_CP_SIGNAL_CONNECTION_REMOVED,
G_CALLBACK (cp_connection_removed),
@ -1012,7 +1007,6 @@ nm_device_enslave_slave (NMDevice *dev, NMDevice *slave, NMConnection *connectio
* nm_device_release_one_slave:
* @dev: the master device
* @slave: the slave device to release
* @master_failed: %TRUE if the release was unexpected, ie the master failed
*
* If @dev is capable of enslaving other devices (ie it's a bridge, bond, team,
* etc) then this function releases the previously enslaved @slave.
@ -1021,11 +1015,12 @@ nm_device_enslave_slave (NMDevice *dev, NMDevice *slave, NMConnection *connectio
* other devices, or if @slave was never enslaved.
*/
static gboolean
nm_device_release_one_slave (NMDevice *dev, NMDevice *slave, gboolean master_failed)
nm_device_release_one_slave (NMDevice *dev, NMDevice *slave)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (dev);
SlaveInfo *info;
gboolean success = FALSE;
NMDeviceStateReason reason;
g_return_val_if_fail (slave != NULL, FALSE);
g_return_val_if_fail (NM_DEVICE_GET_CLASS (dev)->release_slave != NULL, FALSE);
@ -1038,7 +1033,12 @@ nm_device_release_one_slave (NMDevice *dev, NMDevice *slave, gboolean master_fai
success = NM_DEVICE_GET_CLASS (dev)->release_slave (dev, slave);
g_warn_if_fail (success);
}
nm_device_slave_notify_release (info->slave, master_failed);
if (priv->state == NM_DEVICE_STATE_FAILED)
reason = NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED;
else
reason = priv->state_reason;
nm_device_slave_notify_release (info->slave, reason);
priv->slaves = g_slist_remove (priv->slaves, info);
free_slave_info (info);
@ -1268,7 +1268,7 @@ slave_state_changed (NMDevice *slave,
}
if (release) {
nm_device_release_one_slave (self, slave, FALSE);
nm_device_release_one_slave (self, slave);
/* Bridge/bond/team interfaces are left up until manually deactivated */
if (priv->slaves == NULL && priv->state == NM_DEVICE_STATE_ACTIVATED) {
nm_log_dbg (LOGD_DEVICE, "(%s): last slave removed; remaining activated",
@ -1410,17 +1410,38 @@ nm_device_is_master (NMDevice *dev)
/* release all slaves */
static void
nm_device_master_release_slaves (NMDevice *self, gboolean failed)
nm_device_master_release_slaves (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
while (priv->slaves) {
SlaveInfo *info = priv->slaves->data;
nm_device_release_one_slave (self, info->slave, failed);
nm_device_release_one_slave (self, info->slave);
}
}
/**
* nm_device_get_master:
* @dev: the device
*
* If @dev has been enslaved by another device, this returns that
* device. Otherwise it returns %NULL. (In particular, note that if
* @dev is in the process of activating as a slave, but has not yet
* been enslaved by its master, this will return %NULL.)
*
* Returns: (transfer none): @dev's master, or %NULL
*/
NMDevice *
nm_device_get_master (NMDevice *dev)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (dev);
if (priv->enslaved)
return priv->master;
else
return NULL;
}
/**
* nm_device_slave_notify_enslave:
@ -1447,6 +1468,7 @@ nm_device_slave_notify_enslave (NMDevice *dev, gboolean success)
nm_connection_get_id (connection));
priv->enslaved = TRUE;
g_object_notify (G_OBJECT (dev), NM_DEVICE_MASTER);
} else {
nm_log_warn (LOGD_DEVICE,
"Activation (%s) connection '%s' could not be enslaved",
@ -1464,42 +1486,44 @@ nm_device_slave_notify_enslave (NMDevice *dev, gboolean success)
/**
* nm_device_slave_notify_release:
* @dev: the slave device
* @master_failed: indicates whether the release was unexpected,
* ie the master device failed.
* @reason: the reason associated with the state change
*
* Notifies a slave that it has been released, and whether this was expected
* or not.
* Notifies a slave that it has been released, and why.
*/
static void
nm_device_slave_notify_release (NMDevice *dev, gboolean master_failed)
nm_device_slave_notify_release (NMDevice *dev, NMDeviceStateReason reason)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (dev);
NMConnection *connection = nm_device_get_connection (dev);
NMDeviceState new_state;
NMDeviceStateReason reason;
const char *master_status;
if ( priv->state > NM_DEVICE_STATE_DISCONNECTED
&& priv->state <= NM_DEVICE_STATE_ACTIVATED) {
if (master_failed) {
if (reason == NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED) {
new_state = NM_DEVICE_STATE_FAILED;
reason = NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED;
nm_log_warn (LOGD_DEVICE,
"Activation (%s) connection '%s' master failed",
nm_device_get_iface (dev),
nm_connection_get_id (connection));
master_status = "failed";
} else if (reason == NM_DEVICE_STATE_REASON_USER_REQUESTED) {
new_state = NM_DEVICE_STATE_DEACTIVATING;
master_status = "deactivated by user request";
} else {
new_state = NM_DEVICE_STATE_DISCONNECTED;
reason = NM_DEVICE_STATE_REASON_NONE;
nm_log_dbg (LOGD_DEVICE,
"Activation (%s) connection '%s' master deactivated",
nm_device_get_iface (dev),
nm_connection_get_id (connection));
master_status = "deactivated";
}
nm_log_dbg (LOGD_DEVICE,
"Activation (%s) connection '%s' master %s",
nm_device_get_iface (dev),
nm_connection_get_id (connection),
master_status);
nm_device_queue_state (dev, new_state, reason);
}
if (priv->enslaved) {
priv->enslaved = FALSE;
g_object_notify (G_OBJECT (dev), NM_DEVICE_MASTER);
}
}
/**
@ -4552,11 +4576,12 @@ nm_device_deactivate (NMDevice *self, NMDeviceStateReason reason)
NM_DEVICE_GET_CLASS (self)->deactivate (self);
/* master: release slaves */
nm_device_master_release_slaves (self, FALSE);
nm_device_master_release_slaves (self);
/* slave: mark no longer enslaved */
g_clear_object (&priv->master);
priv->enslaved = FALSE;
g_object_notify (G_OBJECT (self), NM_DEVICE_MASTER);
/* Tear down an existing activation request */
clear_act_request (self);
@ -4616,15 +4641,8 @@ disconnect_cb (NMDevice *device,
} else {
priv->autoconnect = FALSE;
/* Software devices are removed when manually disconnected and thus
* we need to track the autoconnect flag outside the device.
*/
nm_manager_prevent_device_auto_connect (nm_manager_get (),
nm_device_get_ip_iface (device),
TRUE);
nm_device_state_changed (device,
NM_DEVICE_STATE_DISCONNECTED,
NM_DEVICE_STATE_DEACTIVATING,
NM_DEVICE_STATE_REASON_USER_REQUESTED);
dbus_g_method_return (context);
}
@ -5642,6 +5660,9 @@ get_property (GObject *object, guint prop_id,
case PROP_IS_MASTER:
g_value_set_boolean (value, priv->is_master);
break;
case PROP_MASTER:
g_value_set_object (value, priv->master);
break;
case PROP_HW_ADDRESS:
if (priv->hw_addr_len)
g_value_take_string (value, nm_utils_hwaddr_ntoa_len (priv->hw_addr, priv->hw_addr_len));
@ -5919,6 +5940,14 @@ nm_device_class_init (NMDeviceClass *klass)
FALSE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property
(object_class, PROP_MASTER,
g_param_spec_object (NM_DEVICE_MASTER,
"Master",
"Master",
NM_TYPE_DEVICE,
G_PARAM_READABLE));
g_object_class_install_property
(object_class, PROP_HW_ADDRESS,
g_param_spec_string (NM_DEVICE_HW_ADDRESS,
@ -6310,6 +6339,9 @@ nm_device_state_changed (NMDevice *device,
nm_device_queue_state (device, NM_DEVICE_STATE_UNMANAGED, NM_DEVICE_STATE_REASON_NONE);
}
break;
case NM_DEVICE_STATE_DEACTIVATING:
nm_device_queue_state (device, NM_DEVICE_STATE_DISCONNECTED, reason);
break;
case NM_DEVICE_STATE_DISCONNECTED:
if (old_state > NM_DEVICE_STATE_DISCONNECTED && priv->default_unmanaged)
nm_device_queue_state (device, NM_DEVICE_STATE_UNMANAGED, NM_DEVICE_STATE_REASON_NONE);
@ -6327,7 +6359,7 @@ nm_device_state_changed (NMDevice *device,
connection ? nm_connection_get_id (connection) : "<unknown>");
/* Notify any slaves of the unexpected failure */
nm_device_master_release_slaves (device, TRUE);
nm_device_master_release_slaves (device);
/* If the connection doesn't yet have a timestamp, set it to zero so that
* we can distinguish between connections we've tried to activate and have
@ -7042,20 +7074,6 @@ cp_connection_added (NMConnectionProvider *cp, NMConnection *connection, gpointe
_signal_available_connections_changed (NM_DEVICE (user_data));
}
static void
cp_connections_loaded (NMConnectionProvider *cp, NMConnection *connection, gpointer user_data)
{
const GSList *connections, *iter;
gboolean added = FALSE;
connections = nm_connection_provider_get_connections (cp);
for (iter = connections; iter; iter = g_slist_next (iter))
added |= _try_add_available_connection (NM_DEVICE (user_data), NM_CONNECTION (iter->data));
if (added)
_signal_available_connections_changed (NM_DEVICE (user_data));
}
static void
cp_connection_removed (NMConnectionProvider *cp, NMConnection *connection, gpointer user_data)
{

View file

@ -66,6 +66,7 @@
#define NM_DEVICE_RFKILL_TYPE "rfkill-type" /* Internal only */
#define NM_DEVICE_IFINDEX "ifindex" /* Internal only */
#define NM_DEVICE_IS_MASTER "is-master" /* Internal only */
#define NM_DEVICE_MASTER "master" /* Internal only */
#define NM_DEVICE_HW_ADDRESS "hw-address" /* Internal only */
#define NM_DEVICE_HAS_PENDING_ACTION "has-pending-action" /* Internal only */
@ -239,6 +240,9 @@ gboolean nm_device_master_add_slave (NMDevice *dev, NMDevice *slave, gbo
GSList * nm_device_master_get_slaves (NMDevice *dev);
gboolean nm_device_is_master (NMDevice *dev);
/* Slave */
NMDevice * nm_device_get_master (NMDevice *dev);
NMActRequest * nm_device_get_act_request (NMDevice *dev);
NMConnection * nm_device_get_connection (NMDevice *dev);

View file

@ -44,7 +44,6 @@ typedef struct {
char *path;
char *specific_object;
NMDevice *device;
guint32 device_state_id;
char *pending_activation_id;
@ -92,7 +91,7 @@ enum {
};
static void check_master_ready (NMActiveConnection *self);
static void _device_cleanup (NMActiveConnectionPrivate *priv);
static void _device_cleanup (NMActiveConnection *self);
/****************************************************************/
@ -169,7 +168,7 @@ nm_active_connection_set_state (NMActiveConnection *self,
* emit property change notification so clients re-read the value,
* which will be NULL due to conditions in get_property().
*/
_device_cleanup (priv);
_device_cleanup (self);
g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_DEVICES);
}
}
@ -344,10 +343,8 @@ device_state_changed (NMDevice *device,
/* If the device used to be active, but now is disconnected/failed, we
* no longer care about its state.
*/
if (new_state <= NM_DEVICE_STATE_DISCONNECTED || new_state == NM_DEVICE_STATE_FAILED) {
g_signal_handler_disconnect (device, priv->device_state_id);
priv->device_state_id = 0;
}
if (new_state <= NM_DEVICE_STATE_DISCONNECTED || new_state == NM_DEVICE_STATE_FAILED)
g_signal_handlers_disconnect_by_func (device, G_CALLBACK (device_state_changed), self);
}
/* Let subclasses handle the state change */
@ -355,6 +352,31 @@ device_state_changed (NMDevice *device,
NM_ACTIVE_CONNECTION_GET_CLASS (self)->device_state_changed (self, device, new_state, old_state);
}
static void
device_master_changed (GObject *object,
GParamSpec *pspec,
gpointer user_data)
{
NMDevice *device = NM_DEVICE (object);
NMActiveConnection *self = NM_ACTIVE_CONNECTION (user_data);
NMActiveConnection *master;
NMActiveConnectionState master_state;
if (!nm_device_get_master (device))
return;
g_signal_handlers_disconnect_by_func (device, G_CALLBACK (device_master_changed), self);
master = nm_active_connection_get_master (self);
g_assert (master);
master_state = nm_active_connection_get_state (master);
if (master_state >= NM_ACTIVE_CONNECTION_STATE_DEACTIVATING) {
/* Master failed before attaching the slave */
if (NM_ACTIVE_CONNECTION_GET_CLASS (self)->master_failed)
NM_ACTIVE_CONNECTION_GET_CLASS (self)->master_failed (self);
}
}
gboolean
nm_active_connection_set_device (NMActiveConnection *self, NMDevice *device)
{
@ -374,10 +396,10 @@ nm_active_connection_set_device (NMActiveConnection *self, NMDevice *device)
priv->device = g_object_ref (device);
g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_INT_DEVICE);
priv->device_state_id = g_signal_connect (device,
"state-changed",
G_CALLBACK (device_state_changed),
self);
g_signal_connect (device, "state-changed",
G_CALLBACK (device_state_changed), self);
g_signal_connect (device, "notify::master",
G_CALLBACK (device_master_changed), self);
priv->pending_activation_id = g_strdup_printf ("activation::%p", (void *)self);
nm_device_add_pending_action (device, priv->pending_activation_id);
@ -457,7 +479,6 @@ master_state_cb (NMActiveConnection *master,
gpointer user_data)
{
NMActiveConnection *self = NM_ACTIVE_CONNECTION (user_data);
NMActiveConnectionState self_state = nm_active_connection_get_state (self);
NMActiveConnectionState master_state = nm_active_connection_get_state (master);
check_master_ready (self);
@ -465,15 +486,9 @@ master_state_cb (NMActiveConnection *master,
nm_log_dbg (LOGD_DEVICE, "(%p): master ActiveConnection [%p] state now '%s' (%d)",
self, master, state_to_string (master_state), master_state);
/* Master is deactivating, so this active connection must also deactivate */
if (self_state < NM_ACTIVE_CONNECTION_STATE_DEACTIVATING &&
master_state >= NM_ACTIVE_CONNECTION_STATE_DEACTIVATING) {
nm_log_dbg (LOGD_DEVICE, "(%p): master ActiveConnection [%p] '%s' failed",
self, master, nm_active_connection_get_name (master));
g_signal_handlers_disconnect_by_func (master,
(GCallback) master_state_cb,
self);
if (master_state == NM_ACTIVE_CONNECTION_STATE_DEACTIVATING &&
nm_active_connection_get_device (master) == NULL) {
/* Master failed without ever creating its device */
if (NM_ACTIVE_CONNECTION_GET_CLASS (self)->master_failed)
NM_ACTIVE_CONNECTION_GET_CLASS (self)->master_failed (self);
}
@ -761,24 +776,28 @@ get_property (GObject *object, guint prop_id,
}
static void
_device_cleanup (NMActiveConnectionPrivate *priv)
_device_cleanup (NMActiveConnection *self)
{
if (priv->device_state_id) {
g_assert (priv->device);
g_signal_handler_disconnect (priv->device, priv->device_state_id);
priv->device_state_id = 0;
NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
if (priv->device) {
g_signal_handlers_disconnect_by_func (priv->device, G_CALLBACK (device_state_changed), self);
g_signal_handlers_disconnect_by_func (priv->device, G_CALLBACK (device_master_changed), self);
}
if (priv->pending_activation_id) {
nm_device_remove_pending_action (priv->device, priv->pending_activation_id);
g_clear_pointer (&priv->pending_activation_id, g_free);
}
g_clear_object (&priv->device);
}
static void
dispose (GObject *object)
{
NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (object);
NMActiveConnection *self = NM_ACTIVE_CONNECTION (object);
NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
if (priv->chain) {
nm_auth_chain_unref (priv->chain);
@ -792,12 +811,12 @@ dispose (GObject *object)
g_clear_object (&priv->connection);
_device_cleanup (priv);
_device_cleanup (self);
if (priv->master) {
g_signal_handlers_disconnect_by_func (priv->master,
(GCallback) master_state_cb,
NM_ACTIVE_CONNECTION (object));
self);
}
g_clear_object (&priv->master);
g_clear_object (&priv->subject);

View file

@ -41,15 +41,6 @@ nm_connection_provider_get_connections (NMConnectionProvider *self)
return NULL;
}
gboolean
nm_connection_provider_has_connections_loaded (NMConnectionProvider *self)
{
g_return_val_if_fail (NM_IS_CONNECTION_PROVIDER (self), FALSE);
g_assert (NM_CONNECTION_PROVIDER_GET_INTERFACE (self)->has_connections_loaded);
return NM_CONNECTION_PROVIDER_GET_INTERFACE (self)->has_connections_loaded (self);
}
/**
* nm_connection_provider_add_connection:
* @self: the #NMConnectionProvider
@ -131,14 +122,6 @@ nm_connection_provider_init (gpointer g_iface)
NULL, NULL,
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE, 1, G_TYPE_OBJECT);
g_signal_new (NM_CP_SIGNAL_CONNECTIONS_LOADED,
iface_type,
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (NMConnectionProvider, connections_loaded),
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
}
GType

View file

@ -29,7 +29,6 @@ typedef struct _NMConnectionProvider NMConnectionProvider;
#define NM_CP_SIGNAL_CONNECTION_ADDED "cp-connection-added"
#define NM_CP_SIGNAL_CONNECTION_UPDATED "cp-connection-updated"
#define NM_CP_SIGNAL_CONNECTION_REMOVED "cp-connection-removed"
#define NM_CP_SIGNAL_CONNECTIONS_LOADED "cp-connections-loaded"
/**
@ -58,8 +57,6 @@ struct _NMConnectionProvider {
const GSList * (*get_connections) (NMConnectionProvider *self);
gboolean (*has_connections_loaded) (NMConnectionProvider *self);
NMConnection * (*add_connection) (NMConnectionProvider *self,
NMConnection *connection,
gboolean save_to_disk,
@ -75,7 +72,6 @@ struct _NMConnectionProvider {
void (*connection_removed) (NMConnectionProvider *self, NMConnection *connection);
void (*connections_loaded) (NMConnectionProvider *self);
};
GType nm_connection_provider_get_type (void);
@ -113,19 +109,6 @@ GSList *nm_connection_provider_get_best_connections (NMConnectionProvider *self,
*/
const GSList *nm_connection_provider_get_connections (NMConnectionProvider *self);
/**
* nm_connection_provider_has_connections_loaded:
* @self: the #NMConnectionProvider
*
* Returns: TRUE or FALSE indicating whether the connections of the provider are already
* loaded. If they are not yet loaded, the provider will not emit the signals
* NM_CP_SIGNAL_CONNECTION_ADDED, NM_CP_SIGNAL_CONNECTION_UPDATED and
* NM_CP_SIGNAL_CONNECTION_REMOVED until NM_CP_SIGNAL_CONNECTIONS_LOADED gets
* emited.
*/
gboolean nm_connection_provider_has_connections_loaded (NMConnectionProvider *self);
/**
* nm_connection_provider_add_connection:
* @self: the #NMConnectionProvider

View file

@ -249,9 +249,6 @@ typedef struct {
guint timestamp_update_id;
/* Track auto-activation for software devices */
GHashTable *noauto_sw_devices;
gboolean startup;
gboolean disposed;
} NMManagerPrivate;
@ -1214,21 +1211,11 @@ system_create_virtual_devices (NMManager *self)
connections = nm_settings_get_connections (priv->settings);
for (iter = connections; iter; iter = g_slist_next (iter)) {
NMConnection *connection = iter->data;
NMSettingConnection *s_con = nm_connection_get_setting_connection (connection);
g_assert (s_con);
if (connection_needs_virtual_device (connection)) {
char *iface = get_virtual_iface_name (self, connection, NULL);
/* We only create a virtual interface if the connection can autoconnect
* and the interface was not manually disconnected before.
*/
if ( nm_setting_connection_get_autoconnect (s_con)
&& iface
&& nm_manager_can_device_auto_connect (self, iface))
system_create_virtual_device (self, connection);
g_free (iface);
}
/* We only create a virtual interface if the connection can autoconnect */
if ( connection_needs_virtual_device (connection)
&& nm_settings_connection_can_autoconnect (NM_SETTINGS_CONNECTION (connection)))
system_create_virtual_device (self, connection);
}
g_slist_free (connections);
}
@ -2720,31 +2707,8 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError *
device = nm_active_connection_get_device (active);
if (!device) {
char *iface;
g_assert (connection_needs_virtual_device (connection));
iface = get_virtual_iface_name (self, connection, NULL);
g_assert (iface);
/* Create the software device. Only exception is when:
* - this is an auto-activation *and* the device denies auto-activation
* at this time (the device was manually disconnected/deleted before)
*/
if (!nm_manager_can_device_auto_connect (self, iface)) {
if (nm_active_connection_get_user_requested (active)) {
/* Manual activation - allow device auto-activation again */
nm_manager_prevent_device_auto_connect (self, iface, FALSE);
} else {
g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_AUTOCONNECT_NOT_ALLOWED,
"Automatic activation of '%s' not allowed for connection '%s'",
iface, nm_connection_get_id (connection));
g_free (iface);
return FALSE;
}
}
g_free (iface);
device = system_create_virtual_device (self, connection);
if (!device) {
g_set_error_literal (error,
@ -2978,6 +2942,22 @@ _new_active_connection (NMManager *self,
device);
}
static void
_internal_activation_failed (NMManager *self,
NMActiveConnection *active,
const char *error_desc)
{
nm_log_warn (LOGD_CORE, "Failed to activate '%s': %s",
nm_connection_get_id (nm_active_connection_get_connection (active)),
error_desc);
if (nm_active_connection_get_state (active) <= NM_ACTIVE_CONNECTION_STATE_ACTIVATED) {
nm_active_connection_set_state (active, NM_ACTIVE_CONNECTION_STATE_DEACTIVATING);
nm_active_connection_set_state (active, NM_ACTIVE_CONNECTION_STATE_DEACTIVATED);
}
active_connection_remove (self, active);
}
static void
_internal_activation_auth_done (NMActiveConnection *active,
gboolean success,
@ -2992,12 +2972,9 @@ _internal_activation_auth_done (NMActiveConnection *active,
if (_internal_activate_generic (self, active, &error))
return;
}
g_assert (error_desc || error);
active_connection_remove (self, active);
nm_log_warn (LOGD_CORE, "Failed to activate '%s': %s",
nm_connection_get_id (nm_active_connection_get_connection (active)),
error_desc ? error_desc : error->message);
g_assert (error_desc || error);
_internal_activation_failed (self, active, error_desc ? error_desc : error->message);
g_clear_error (&error);
}
@ -3166,8 +3143,8 @@ activation_auth_done (NMActiveConnection *active,
error_desc);
}
active_connection_remove (self, active);
dbus_g_method_return_error (context, error);
_internal_activation_failed (self, active, error->message);
g_error_free (error);
}
@ -3311,10 +3288,8 @@ activation_add_done (NMSettings *self,
error = local;
}
active_connection_remove (info->manager, info->active);
if (error)
dbus_g_method_return_error (context, error);
_internal_activation_failed (info->manager, info->active, error->message);
dbus_g_method_return_error (context, error);
g_clear_error (&local);
done:
@ -3489,9 +3464,8 @@ nm_manager_deactivate_connection (NMManager *manager,
"The VPN connection was not active.");
} else {
g_assert (NM_IS_ACT_REQUEST (active));
/* FIXME: use DEACTIVATING state */
nm_device_state_changed (nm_active_connection_get_device (active),
NM_DEVICE_STATE_DISCONNECTED,
NM_DEVICE_STATE_DEACTIVATING,
reason);
success = TRUE;
}
@ -3618,33 +3592,6 @@ done:
g_clear_error (&error);
}
/*
* Track (software) devices that cannot auto activate.
* It is needed especially for software devices, that can be removed and added
* again. So we can't simply use a flag inside the device.
*/
void
nm_manager_prevent_device_auto_connect (NMManager *manager, const char *ifname, gboolean prevent)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
if (prevent)
g_hash_table_add (priv->noauto_sw_devices, g_strdup (ifname));
else
g_hash_table_remove (priv->noauto_sw_devices, ifname);
}
gboolean
nm_manager_can_device_auto_connect (NMManager *manager, const char *ifname)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
if (!ifname)
return FALSE;
return !g_hash_table_contains (priv->noauto_sw_devices, ifname);
}
static void
do_sleep_wake (NMManager *self)
{
@ -4720,8 +4667,6 @@ dispose (GObject *object)
g_object_unref (priv->fw_monitor);
}
g_hash_table_unref (priv->noauto_sw_devices);
g_slist_free (priv->factories);
if (priv->timestamp_update_id) {
@ -5086,9 +5031,6 @@ nm_manager_init (NMManager *manager)
KERNEL_FIRMWARE_DIR);
}
/* Hash table storing software devices that should not auto activate */
priv->noauto_sw_devices = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
load_device_factories (manager);
/* Update timestamps in active connections */

View file

@ -128,12 +128,6 @@ gboolean nm_manager_deactivate_connection (NMManager *manager,
NMDeviceStateReason reason,
GError **error);
void nm_manager_prevent_device_auto_connect (NMManager *manager,
const char *ifname,
gboolean prevent);
gboolean nm_manager_can_device_auto_connect (NMManager *manager,
const char *ifname);
/* State handling */
NMState nm_manager_get_state (NMManager *manager);

View file

@ -89,12 +89,6 @@ enum {
PROP_ACTIVATING_IP6_DEVICE
};
#define RETRIES_TAG "autoconnect-retries"
#define RETRIES_DEFAULT 4
#define RESET_RETRIES_TIMESTAMP_TAG "reset-retries-timestamp-tag"
#define RESET_RETRIES_TIMER 300
#define FAILURE_REASON_TAG "failure-reason"
static void schedule_activate_all (NMPolicy *policy);
@ -927,20 +921,6 @@ check_activating_devices (NMPolicy *policy)
g_object_thaw_notify (object);
}
static void
set_connection_auto_retries (NMConnection *connection, guint retries)
{
/* add +1 so that the tag still exists if the # retries is 0 */
g_object_set_data (G_OBJECT (connection), RETRIES_TAG, GUINT_TO_POINTER (retries + 1));
}
static guint32
get_connection_auto_retries (NMConnection *connection)
{
/* subtract 1 to handle the +1 from set_connection_auto_retries() */
return GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (connection), RETRIES_TAG)) - 1;
}
typedef struct {
NMPolicy *policy;
NMDevice *device;
@ -989,28 +969,11 @@ auto_activate_device (gpointer user_data)
/* Remove connections that shouldn't be auto-activated */
while (iter) {
NMSettingsConnection *candidate = NM_SETTINGS_CONNECTION (iter->data);
gboolean remove_it = FALSE;
const char *permission;
/* Grab next item before we possibly delete the current item */
iter = g_slist_next (iter);
/* Ignore connections that were tried too many times or are not visible
* to any logged-in users. Also ignore shared wifi connections for
* which no user has the shared wifi permission.
*/
if ( get_connection_auto_retries (NM_CONNECTION (candidate)) == 0
|| nm_settings_connection_is_visible (candidate) == FALSE)
remove_it = TRUE;
else {
permission = nm_utils_get_shared_wifi_permission (NM_CONNECTION (candidate));
if (permission) {
if (nm_settings_connection_check_permission (candidate, permission) == FALSE)
remove_it = TRUE;
}
}
if (remove_it)
if (!nm_settings_connection_can_autoconnect (candidate))
connections = g_slist_remove (connections, candidate);
}
@ -1164,42 +1127,76 @@ hostname_changed (NMManager *manager, GParamSpec *pspec, gpointer user_data)
}
static void
reset_retries_all (NMSettings *settings, NMDevice *device)
{
GSList *connections, *iter;
GError *error = NULL;
connections = nm_settings_get_connections (settings);
for (iter = connections; iter; iter = g_slist_next (iter)) {
if (!device || nm_device_check_connection_compatible (device, iter->data, &error))
set_connection_auto_retries (NM_CONNECTION (iter->data), RETRIES_DEFAULT);
g_clear_error (&error);
}
g_slist_free (connections);
}
static void
reset_retries_for_failed_secrets (NMSettings *settings)
reset_autoconnect_all (NMPolicy *policy, NMDevice *device)
{
NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (policy);
GSList *connections, *iter;
connections = nm_settings_get_connections (settings);
for (iter = connections; iter; iter = g_slist_next (iter)) {
NMDeviceStateReason reason = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (iter->data), FAILURE_REASON_TAG));
if (device) {
nm_log_dbg (LOGD_DEVICE, "Re-enabling autoconnect for all connections on %s",
nm_device_get_iface (device));
} else
nm_log_dbg (LOGD_DEVICE, "Re-enabling autoconnect for all connections");
if (reason == NM_DEVICE_STATE_REASON_NO_SECRETS) {
set_connection_auto_retries (NM_CONNECTION (iter->data), RETRIES_DEFAULT);
g_object_set_data (G_OBJECT (iter->data), FAILURE_REASON_TAG, GUINT_TO_POINTER (0));
connections = nm_settings_get_connections (priv->settings);
for (iter = connections; iter; iter = g_slist_next (iter)) {
if (!device || nm_device_check_connection_compatible (device, iter->data, NULL)) {
nm_settings_connection_reset_autoconnect_retries (iter->data);
nm_settings_connection_set_autoconnect_blocked_reason (iter->data, NM_DEVICE_STATE_REASON_NONE);
}
}
g_slist_free (connections);
}
static void
reset_autoconnect_for_failed_secrets (NMPolicy *policy)
{
NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (policy);
GSList *connections, *iter;
nm_log_dbg (LOGD_DEVICE, "Re-enabling autoconnect for all connections with failed secrets");
connections = nm_settings_get_connections (priv->settings);
for (iter = connections; iter; iter = g_slist_next (iter)) {
NMSettingsConnection *connection = NM_SETTINGS_CONNECTION (iter->data);
if (nm_settings_connection_get_autoconnect_blocked_reason (connection) == NM_DEVICE_STATE_REASON_NO_SECRETS) {
nm_settings_connection_reset_autoconnect_retries (connection);
nm_settings_connection_set_autoconnect_blocked_reason (connection, NM_DEVICE_STATE_REASON_NONE);
}
}
g_slist_free (connections);
}
static void
block_autoconnect_for_device (NMPolicy *policy, NMDevice *device)
{
NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (policy);
GSList *connections, *iter;
nm_log_dbg (LOGD_DEVICE, "Blocking autoconnect for all connections on %s",
nm_device_get_iface (device));
/* NMDevice keeps its own autoconnect-able-ness state; we only need to
* explicitly block connections for software devices, where the NMDevice
* might be destroyed and recreated later.
*/
if (!nm_device_is_software (device))
return;
connections = nm_settings_get_connections (priv->settings);
for (iter = connections; iter; iter = g_slist_next (iter)) {
if (nm_device_check_connection_compatible (device, iter->data, NULL)) {
nm_settings_connection_set_autoconnect_blocked_reason (NM_SETTINGS_CONNECTION (iter->data),
NM_DEVICE_STATE_REASON_USER_REQUESTED);
}
}
}
static void
sleeping_changed (NMManager *manager, GParamSpec *pspec, gpointer user_data)
{
NMPolicy *policy = user_data;
NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (policy);
gboolean sleeping = FALSE, enabled = FALSE;
g_object_get (G_OBJECT (manager), NM_MANAGER_SLEEPING, &sleeping, NULL);
@ -1207,7 +1204,7 @@ sleeping_changed (NMManager *manager, GParamSpec *pspec, gpointer user_data)
/* Reset retries on all connections so they'll checked on wakeup */
if (sleeping || !enabled)
reset_retries_all (priv->settings, NULL);
reset_autoconnect_all (policy, NULL);
}
static void
@ -1253,26 +1250,27 @@ reset_connections_retries (gpointer user_data)
priv->reset_retries_id = 0;
min_stamp = now = time (NULL);
min_stamp = 0;
now = time (NULL);
connections = nm_settings_get_connections (priv->settings);
for (iter = connections; iter; iter = g_slist_next (iter)) {
con_stamp = GPOINTER_TO_SIZE (g_object_get_data (G_OBJECT (iter->data), RESET_RETRIES_TIMESTAMP_TAG));
NMSettingsConnection *connection = NM_SETTINGS_CONNECTION (iter->data);
con_stamp = nm_settings_connection_get_autoconnect_retry_time (connection);
if (con_stamp == 0)
continue;
if (con_stamp + RESET_RETRIES_TIMER <= now) {
set_connection_auto_retries (NM_CONNECTION (iter->data), RETRIES_DEFAULT);
g_object_set_data (G_OBJECT (iter->data), RESET_RETRIES_TIMESTAMP_TAG, GSIZE_TO_POINTER (0));
if (con_stamp < now) {
nm_settings_connection_reset_autoconnect_retries (connection);
changed = TRUE;
continue;
}
if (con_stamp < min_stamp)
} else if (min_stamp == 0 || min_stamp > con_stamp)
min_stamp = con_stamp;
}
g_slist_free (connections);
/* Schedule the handler again if there are some stamps left */
if (min_stamp != now)
priv->reset_retries_id = g_timeout_add_seconds (RESET_RETRIES_TIMER - (now - min_stamp), reset_connections_retries, policy);
if (min_stamp != 0)
priv->reset_retries_id = g_timeout_add_seconds (min_stamp - now, reset_connections_retries, policy);
/* If anything changed, try to activate the newly re-enabled connections */
if (changed)
@ -1284,8 +1282,7 @@ reset_connections_retries (gpointer user_data)
static void schedule_activate_all (NMPolicy *policy);
static void
activate_slave_connections (NMPolicy *policy, NMConnection *connection,
NMDevice *device)
activate_slave_connections (NMPolicy *policy, NMDevice *device)
{
NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (policy);
const char *master_device;
@ -1306,7 +1303,7 @@ activate_slave_connections (NMPolicy *policy, NMConnection *connection,
g_assert (s_slave_con);
if (!g_strcmp0 (nm_setting_connection_get_master (s_slave_con), master_device))
set_connection_auto_retries (slave, RETRIES_DEFAULT);
nm_settings_connection_reset_autoconnect_retries (NM_SETTINGS_CONNECTION (slave));
}
g_slist_free (connections);
@ -1393,15 +1390,12 @@ device_state_changed (NMDevice *device,
{
NMPolicy *policy = (NMPolicy *) user_data;
NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (policy);
NMConnection *connection = nm_device_get_connection (device);
NMSettingsConnection *connection = NM_SETTINGS_CONNECTION (nm_device_get_connection (device));
const char *ip_iface = nm_device_get_ip_iface (device);
NMIP4Config *ip4_config;
NMIP6Config *ip6_config;
NMSettingConnection *s_con;
if (connection)
g_object_set_data (G_OBJECT (connection), FAILURE_REASON_TAG, GUINT_TO_POINTER (0));
switch (new_state) {
case NM_DEVICE_STATE_FAILED:
/* Mark the connection invalid if it failed during activation so that
@ -1410,46 +1404,42 @@ device_state_changed (NMDevice *device,
if ( connection
&& old_state >= NM_DEVICE_STATE_PREPARE
&& old_state <= NM_DEVICE_STATE_ACTIVATED) {
guint32 tries = get_connection_auto_retries (connection);
guint32 tries = nm_settings_connection_get_autoconnect_retries (connection);
if (reason == NM_DEVICE_STATE_REASON_NO_SECRETS) {
/* If the connection couldn't get the secrets it needed (ex because
* the user canceled, or no secrets exist), there's no point in
* automatically retrying because it's just going to fail anyway.
*/
set_connection_auto_retries (connection, 0);
nm_log_dbg (LOGD_DEVICE, "Connection '%s' now blocked from autoconnect due to no secrets",
nm_connection_get_id (NM_CONNECTION (connection)));
/* Mark the connection as failed due to missing secrets so that we can reset
* RETRIES_TAG and automatically re-try when an secret agent registers.
*/
g_object_set_data (G_OBJECT (connection), FAILURE_REASON_TAG, GUINT_TO_POINTER (NM_DEVICE_STATE_REASON_NO_SECRETS));
nm_settings_connection_set_autoconnect_blocked_reason (connection, NM_DEVICE_STATE_REASON_NO_SECRETS);
} else if (tries > 0) {
/* Otherwise if it's a random failure, just decrease the number
* of automatic retries so that the connection gets tried again
* if it still has a retry count.
*/
set_connection_auto_retries (connection, tries - 1);
nm_log_dbg (LOGD_DEVICE, "Connection '%s' failed to autoconnect; %d tries left",
nm_connection_get_id (NM_CONNECTION (connection)), tries);
nm_settings_connection_set_autoconnect_retries (connection, tries - 1);
}
if (get_connection_auto_retries (connection) == 0) {
nm_log_info (LOGD_DEVICE, "Marking connection '%s' invalid.", nm_connection_get_id (connection));
if (nm_settings_connection_get_autoconnect_retries (connection) == 0) {
nm_log_info (LOGD_DEVICE, "Disabling autoconnect for connection '%s'.",
nm_connection_get_id (NM_CONNECTION (connection)));
/* Schedule a handler to reset retries count */
g_object_set_data (G_OBJECT (connection), RESET_RETRIES_TIMESTAMP_TAG, GSIZE_TO_POINTER ((gsize) time (NULL)));
if (!priv->reset_retries_id)
priv->reset_retries_id = g_timeout_add_seconds (RESET_RETRIES_TIMER, reset_connections_retries, policy);
if (!priv->reset_retries_id) {
time_t retry_time = nm_settings_connection_get_autoconnect_retry_time (connection);
g_warn_if_fail (retry_time != 0);
priv->reset_retries_id = g_timeout_add_seconds (MAX (0, retry_time - time (NULL)), reset_connections_retries, policy);
}
}
nm_connection_clear_secrets (connection);
nm_connection_clear_secrets (NM_CONNECTION (connection));
}
break;
case NM_DEVICE_STATE_ACTIVATED:
if (connection) {
/* Reset auto retries back to default since connection was successful */
set_connection_auto_retries (connection, RETRIES_DEFAULT);
nm_settings_connection_reset_autoconnect_retries (connection);
/* And clear secrets so they will always be requested from the
* settings service when the next connection is made.
*/
nm_connection_clear_secrets (connection);
nm_connection_clear_secrets (NM_CONNECTION (connection));
}
/* Add device's new IPv4 and IPv6 configs to DNS */
@ -1472,11 +1462,25 @@ device_state_changed (NMDevice *device,
if (old_state > NM_DEVICE_STATE_DISCONNECTED)
update_routing_and_dns (policy, FALSE);
break;
case NM_DEVICE_STATE_DEACTIVATING:
if (reason == NM_DEVICE_STATE_REASON_USER_REQUESTED) {
if (!nm_device_get_autoconnect (device)) {
/* The device was disconnected; block all connections on it */
block_autoconnect_for_device (policy, device);
} else {
/* The connection was deactivated, so block just this connection */
nm_log_dbg (LOGD_DEVICE, "Blocking autoconnect of connection '%s' by user request",
nm_connection_get_id (NM_CONNECTION (connection)));
nm_settings_connection_set_autoconnect_blocked_reason (connection, NM_DEVICE_STATE_REASON_USER_REQUESTED);
}
}
break;
case NM_DEVICE_STATE_DISCONNECTED:
/* Reset RETRIES_TAG when carrier on. If cable was unplugged
* and plugged again, we should try to reconnect */
/* Reset retry counts for a device's connections when carrier on; if cable
* was unplugged and plugged in again, we should try to reconnect.
*/
if (reason == NM_DEVICE_STATE_REASON_CARRIER && old_state == NM_DEVICE_STATE_UNAVAILABLE)
reset_retries_all (priv->settings, device);
reset_autoconnect_all (policy, device);
if (old_state > NM_DEVICE_STATE_DISCONNECTED)
update_routing_and_dns (policy, FALSE);
@ -1488,16 +1492,20 @@ device_state_changed (NMDevice *device,
case NM_DEVICE_STATE_PREPARE:
/* Reset auto-connect retries of all slaves and schedule them for
* activation. */
activate_slave_connections (policy, connection, device);
activate_slave_connections (policy, device);
break;
case NM_DEVICE_STATE_IP_CONFIG:
/* We must have secrets if we got here. */
nm_settings_connection_set_autoconnect_blocked_reason (connection, NM_DEVICE_STATE_REASON_NONE);
break;
case NM_DEVICE_STATE_SECONDARIES:
s_con = nm_connection_get_setting_connection (connection);
s_con = nm_connection_get_setting_connection (NM_CONNECTION (connection));
if (s_con && nm_setting_connection_get_num_secondaries (s_con) > 0) {
/* Make routes and DNS up-to-date before activating dependent connections */
update_routing_and_dns (policy, FALSE);
/* Activate secondary (VPN) connections */
if (!activate_secondary_connections (policy, connection, device))
if (!activate_secondary_connections (policy, NM_CONNECTION (connection), device))
nm_device_queue_state (device, NM_DEVICE_STATE_FAILED,
NM_DEVICE_STATE_REASON_SECONDARY_CONNECTION_FAILED);
} else
@ -1827,24 +1835,12 @@ schedule_activate_all (NMPolicy *policy)
static void
connection_added (NMSettings *settings,
NMConnection *connection,
NMSettingsConnection *connection,
gpointer user_data)
{
set_connection_auto_retries (connection, RETRIES_DEFAULT);
schedule_activate_all ((NMPolicy *) user_data);
}
NMPolicy *policy = NM_POLICY (user_data);
static void
connections_loaded (NMSettings *settings, gpointer user_data)
{
// FIXME: "connections-loaded" signal is emmitted *before* we connect to it
// in nm_policy_new(). So this function is never called. Currently we work around
// that by calling reset_retries_all() in nm_policy_new()
/* Initialize connections' auto-retries */
reset_retries_all (settings, NULL);
schedule_activate_all ((NMPolicy *) user_data);
schedule_activate_all (policy);
}
static void
@ -1957,11 +1953,11 @@ connection_updated (NMSettings *settings,
static void
connection_updated_by_user (NMSettings *settings,
NMConnection *connection,
NMSettingsConnection *connection,
gpointer user_data)
{
/* Reset auto retries back to default since connection was updated */
set_connection_auto_retries (connection, RETRIES_DEFAULT);
nm_settings_connection_reset_autoconnect_retries (connection);
}
static void
@ -2021,12 +2017,14 @@ secret_agent_registered (NMSettings *settings,
NMSecretAgent *agent,
gpointer user_data)
{
NMPolicy *policy = 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_retries_for_failed_secrets (settings);
schedule_activate_all ((NMPolicy *) user_data);
reset_autoconnect_for_failed_secrets (policy);
schedule_activate_all (policy);
}
static void
@ -2099,7 +2097,6 @@ nm_policy_new (NMManager *manager, NMSettings *settings)
_connect_manager_signal (policy, NM_MANAGER_ACTIVE_CONNECTION_ADDED, active_connection_added);
_connect_manager_signal (policy, NM_MANAGER_ACTIVE_CONNECTION_REMOVED, active_connection_removed);
_connect_settings_signal (policy, NM_SETTINGS_SIGNAL_CONNECTIONS_LOADED, connections_loaded);
_connect_settings_signal (policy, NM_SETTINGS_SIGNAL_CONNECTION_ADDED, connection_added);
_connect_settings_signal (policy, NM_SETTINGS_SIGNAL_CONNECTION_UPDATED, connection_updated);
_connect_settings_signal (policy, NM_SETTINGS_SIGNAL_CONNECTION_UPDATED_BY_USER, connection_updated_by_user);
@ -2108,9 +2105,6 @@ nm_policy_new (NMManager *manager, NMSettings *settings)
connection_visibility_changed);
_connect_settings_signal (policy, NM_SETTINGS_SIGNAL_AGENT_REGISTERED, secret_agent_registered);
/* Initialize connections' auto-retries */
reset_retries_all (priv->settings, NULL);
initialized = TRUE;
return policy;
}

View file

@ -124,6 +124,11 @@ typedef struct {
guint64 timestamp; /* Up-to-date timestamp of connection use */
gboolean timestamp_set;
GHashTable *seen_bssids; /* Up-to-date BSSIDs that's been seen for the connection */
int autoconnect_retries;
time_t autoconnect_retry_time;
NMDeviceStateReason autoconnect_blocked_reason;
} NMSettingsConnectionPrivate;
/**************************************************************/
@ -1899,6 +1904,78 @@ nm_settings_connection_read_and_fill_seen_bssids (NMSettingsConnection *connecti
}
}
#define AUTOCONNECT_RETRIES_DEFAULT 4
#define AUTOCONNECT_RESET_RETRIES_TIMER 300
int
nm_settings_connection_get_autoconnect_retries (NMSettingsConnection *connection)
{
return NM_SETTINGS_CONNECTION_GET_PRIVATE (connection)->autoconnect_retries;
}
void
nm_settings_connection_set_autoconnect_retries (NMSettingsConnection *connection,
int retries)
{
NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (connection);
priv->autoconnect_retries = retries;
if (retries)
priv->autoconnect_retry_time = 0;
else
priv->autoconnect_retry_time = time (NULL) + AUTOCONNECT_RESET_RETRIES_TIMER;
}
void
nm_settings_connection_reset_autoconnect_retries (NMSettingsConnection *connection)
{
nm_settings_connection_set_autoconnect_retries (connection, AUTOCONNECT_RETRIES_DEFAULT);
}
time_t
nm_settings_connection_get_autoconnect_retry_time (NMSettingsConnection *connection)
{
return NM_SETTINGS_CONNECTION_GET_PRIVATE (connection)->autoconnect_retry_time;
}
NMDeviceStateReason
nm_settings_connection_get_autoconnect_blocked_reason (NMSettingsConnection *connection)
{
return NM_SETTINGS_CONNECTION_GET_PRIVATE (connection)->autoconnect_blocked_reason;
}
void
nm_settings_connection_set_autoconnect_blocked_reason (NMSettingsConnection *connection,
NMDeviceStateReason reason)
{
NM_SETTINGS_CONNECTION_GET_PRIVATE (connection)->autoconnect_blocked_reason = reason;
}
gboolean
nm_settings_connection_can_autoconnect (NMSettingsConnection *connection)
{
NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (connection);
NMSettingConnection *s_con;
const char *permission;
if ( !priv->visible
|| priv->autoconnect_retries == 0
|| priv->autoconnect_blocked_reason != NM_DEVICE_STATE_REASON_NONE)
return FALSE;
s_con = nm_connection_get_setting_connection (NM_CONNECTION (connection));
if (!nm_setting_connection_get_autoconnect (s_con))
return FALSE;
permission = nm_utils_get_shared_wifi_permission (NM_CONNECTION (connection));
if (permission) {
if (nm_settings_connection_check_permission (connection, permission) == FALSE)
return FALSE;
}
return TRUE;
}
/**************************************************************/
static void
@ -1918,6 +1995,9 @@ nm_settings_connection_init (NMSettingsConnection *self)
priv->seen_bssids = g_hash_table_new_full (mac_hash, mac_equal, g_free, g_free);
priv->autoconnect_retries = AUTOCONNECT_RETRIES_DEFAULT;
priv->autoconnect_blocked_reason = NM_DEVICE_STATE_REASON_NONE;
g_signal_connect (self, NM_CONNECTION_SECRETS_CLEARED, G_CALLBACK (secrets_cleared_cb), NULL);
g_signal_connect (self, NM_CONNECTION_CHANGED, G_CALLBACK (changed_cb), GUINT_TO_POINTER (TRUE));
}

View file

@ -149,6 +149,19 @@ void nm_settings_connection_add_seen_bssid (NMSettingsConnection *connection,
void nm_settings_connection_read_and_fill_seen_bssids (NMSettingsConnection *connection);
int nm_settings_connection_get_autoconnect_retries (NMSettingsConnection *connection);
void nm_settings_connection_set_autoconnect_retries (NMSettingsConnection *connection,
int retries);
void nm_settings_connection_reset_autoconnect_retries (NMSettingsConnection *connection);
time_t nm_settings_connection_get_autoconnect_retry_time (NMSettingsConnection *connection);
NMDeviceStateReason nm_settings_connection_get_autoconnect_blocked_reason (NMSettingsConnection *connection);
void nm_settings_connection_set_autoconnect_blocked_reason (NMSettingsConnection *connection,
NMDeviceStateReason reason);
gboolean nm_settings_connection_can_autoconnect (NMSettingsConnection *connection);
G_END_DECLS
#endif /* NM_SETTINGS_CONNECTION_H */

View file

@ -152,7 +152,6 @@ enum {
CONNECTION_UPDATED_BY_USER,
CONNECTION_REMOVED,
CONNECTION_VISIBILITY_CHANGED,
CONNECTIONS_LOADED,
AGENT_REGISTERED,
NEW_CONNECTION, /* exported, not used internally */
@ -183,9 +182,6 @@ load_connections (NMSettings *self)
NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
GSList *iter;
if (priv->connections_loaded)
return;
for (iter = priv->plugins; iter; iter = g_slist_next (iter)) {
NMSystemConfigInterface *plugin = NM_SYSTEM_CONFIG_INTERFACE (iter->data);
GSList *plugin_connections;
@ -214,9 +210,6 @@ load_connections (NMSettings *self)
unmanaged_specs_changed (NULL, self);
unrecognized_specs_changed (NULL, self);
g_signal_emit (self, signals[CONNECTIONS_LOADED], 0);
g_signal_emit_by_name (self, NM_CP_SIGNAL_CONNECTIONS_LOADED);
}
void
@ -233,8 +226,6 @@ nm_settings_for_each_connection (NMSettings *self,
priv = NM_SETTINGS_GET_PRIVATE (self);
load_connections (self);
g_hash_table_iter_init (&iter, priv->connections);
while (g_hash_table_iter_next (&iter, NULL, &data))
for_each_func (self, NM_SETTINGS_CONNECTION (data), user_data);
@ -249,8 +240,6 @@ impl_settings_list_connections (NMSettings *self,
GHashTableIter iter;
gpointer key;
load_connections (self);
*connections = g_ptr_array_sized_new (g_hash_table_size (priv->connections) + 1);
g_hash_table_iter_init (&iter, priv->connections);
while (g_hash_table_iter_next (&iter, &key, NULL))
@ -270,8 +259,6 @@ nm_settings_get_connection_by_uuid (NMSettings *self, const char *uuid)
priv = NM_SETTINGS_GET_PRIVATE (self);
load_connections (self);
g_hash_table_iter_init (&iter, priv->connections);
while (g_hash_table_iter_next (&iter, NULL, (gpointer) &candidate)) {
if (g_strcmp0 (uuid, nm_connection_get_uuid (NM_CONNECTION (candidate))) == 0)
@ -361,8 +348,6 @@ nm_settings_get_connection_by_path (NMSettings *self, const char *path)
priv = NM_SETTINGS_GET_PRIVATE (self);
load_connections (self);
return (NMSettingsConnection *) g_hash_table_lookup (priv->connections, path);
}
@ -416,7 +401,6 @@ nm_settings_get_unmanaged_specs (NMSettings *self)
{
NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
load_connections (self);
return priv->unmanaged_specs;
}
@ -861,9 +845,7 @@ claim_connection (NMSettings *self,
g_object_ref (connection));
/* Only emit the individual connection-added signal after connections
* have been initially loaded. While getting the first list of connections
* we suppress it, then send the connections-loaded signal after we're all
* done to minimize processing.
* have been initially loaded.
*/
if (priv->connections_loaded) {
/* Internal added signal */
@ -1314,14 +1296,10 @@ impl_settings_reload_connections (NMSettings *self,
if (!ensure_root (priv->dbus_mgr, context))
return;
if (!priv->connections_loaded) {
load_connections (self);
} else {
for (iter = priv->plugins; iter; iter = g_slist_next (iter)) {
NMSystemConfigInterface *plugin = NM_SYSTEM_CONFIG_INTERFACE (iter->data);
for (iter = priv->plugins; iter; iter = g_slist_next (iter)) {
NMSystemConfigInterface *plugin = NM_SYSTEM_CONFIG_INTERFACE (iter->data);
nm_system_config_interface_reload_connections (plugin);
}
nm_system_config_interface_reload_connections (plugin);
}
dbus_g_method_return (context, TRUE);
@ -1770,14 +1748,6 @@ get_connections (NMConnectionProvider *provider)
return list;
}
static gboolean
has_connections_loaded (NMConnectionProvider *provider)
{
NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (provider);
return priv->connections_loaded;
}
static NMConnection *
cp_get_connection_by_uuid (NMConnectionProvider *provider, const char *uuid)
{
@ -1805,8 +1775,7 @@ nm_settings_new (GError **error)
return NULL;
}
unmanaged_specs_changed (NULL, self);
unrecognized_specs_changed (NULL, self);
load_connections (self);
nm_dbus_manager_register_object (priv->dbus_mgr, NM_DBUS_PATH_SETTINGS, self);
return self;
@ -1817,7 +1786,6 @@ connection_provider_init (NMConnectionProvider *cp_class)
{
cp_class->get_best_connections = get_best_connections;
cp_class->get_connections = get_connections;
cp_class->has_connections_loaded = has_connections_loaded;
cp_class->add_connection = _nm_connection_provider_add_connection;
cp_class->get_connection_by_uuid = cp_get_connection_by_uuid;
}
@ -1996,15 +1964,6 @@ nm_settings_class_init (NMSettingsClass *class)
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE, 1, G_TYPE_OBJECT);
signals[CONNECTIONS_LOADED] =
g_signal_new (NM_SETTINGS_SIGNAL_CONNECTIONS_LOADED,
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (NMSettingsClass, connections_loaded),
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
signals[AGENT_REGISTERED] =
g_signal_new (NM_SETTINGS_SIGNAL_AGENT_REGISTERED,
G_OBJECT_CLASS_TYPE (object_class),

View file

@ -49,7 +49,6 @@
#define NM_SETTINGS_SIGNAL_CONNECTION_UPDATED_BY_USER "connection-updated-by-user"
#define NM_SETTINGS_SIGNAL_CONNECTION_REMOVED "connection-removed"
#define NM_SETTINGS_SIGNAL_CONNECTION_VISIBILITY_CHANGED "connection-visibility-changed"
#define NM_SETTINGS_SIGNAL_CONNECTIONS_LOADED "connections-loaded"
#define NM_SETTINGS_SIGNAL_AGENT_REGISTERED "agent-registered"
typedef struct {
@ -70,8 +69,6 @@ typedef struct {
void (*connection_visibility_changed) (NMSettings *self, NMSettingsConnection *connection);
void (*connections_loaded) (NMSettings *self);
void (*agent_registered) (NMSettings *self, NMSecretAgent *agent);
} NMSettingsClass;

View file

@ -300,17 +300,6 @@ device_state_changed (NMActiveConnection *active,
}
}
static void
master_failed (NMActiveConnection *self)
{
NMVPNConnection *connection = NM_VPN_CONNECTION (self);
/* Master failure fails the VPN */
nm_vpn_connection_set_vpn_state (connection,
NM_VPN_CONNECTION_STATE_FAILED,
NM_VPN_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED);
}
static void
add_ip4_vpn_gateway_route (NMDevice *parent_device, guint32 vpn_gw)
{
@ -1828,7 +1817,6 @@ nm_vpn_connection_class_init (NMVPNConnectionClass *connection_class)
object_class->constructed = constructed;
object_class->dispose = dispose;
object_class->finalize = finalize;
active_class->master_failed = master_failed;
active_class->device_state_changed = device_state_changed;
g_object_class_override_property (object_class, PROP_MASTER, NM_ACTIVE_CONNECTION_MASTER);