/**
 * nm_active_connection_set_master:
 * @self: the #NMActiveConnection
 * @master: if the activation depends on another device (ie, bond or bridge
 * master to which this device will be enslaved) pass the #NMActiveConnection
 * that this activation request is a child of
 *
 * Sets the master active connection of @self.
 */
void
nm_active_connection_set_master (NMActiveConnection *self, NMActiveConnection *master)
{
	NMActiveConnectionPrivate *priv;

	g_return_if_fail (NM_IS_ACTIVE_CONNECTION (self));
	g_return_if_fail (NM_IS_ACTIVE_CONNECTION (master));

	priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);

	/* Master is write-once, and must be set before exporting the object */
	g_return_if_fail (priv->master == NULL);
	g_return_if_fail (!nm_exported_object_is_exported (NM_EXPORTED_OBJECT (self)));
	if (priv->device) {
		/* Note, the master ActiveConnection may not yet have a device */
		g_return_if_fail (priv->device != nm_active_connection_get_device (master));
	}

	_LOGD ("set master %p, %s, state %s",
	       master,
	       nm_active_connection_get_settings_connection_id (master),
	       state_to_string (nm_active_connection_get_state (master)));

	priv->master = g_object_ref (master);
	g_signal_connect (priv->master,
	                  "notify::" NM_ACTIVE_CONNECTION_STATE,
	                  (GCallback) master_state_cb,
	                  self);

	check_master_ready (self);
}
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;
}
gboolean
nm_active_connection_get_user_requested (NMActiveConnection *self)
{
	g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), FALSE);

	return nm_auth_subject_is_unix_process (NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->subject);
}
NMDevice *
nm_active_connection_get_device (NMActiveConnection *self)
{
	g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), NULL);

	return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->device;
}
void
nm_active_connection_set_settings_connection (NMActiveConnection *self,
                                              NMSettingsConnection *connection)
{
	NMActiveConnectionPrivate *priv;

	g_return_if_fail (NM_IS_ACTIVE_CONNECTION (self));

	priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);

	g_return_if_fail (NM_IS_SETTINGS_CONNECTION (connection));
	g_return_if_fail (!priv->settings_connection);
	g_return_if_fail (!priv->applied_connection);

	/* Can't change connection after the ActiveConnection is exported over D-Bus.
	 *
	 * Later, we want to change the settings-connection of an activated connection.
	 * When doing that, this changes the assumption that the settings-connection
	 * never changes (once it's set). That has effects for NMVpnConnection and
	 * NMActivationRequest.
	 * For example, we'd have to cancel all pending seret requests. */
	g_return_if_fail (!nm_exported_object_is_exported (NM_EXPORTED_OBJECT (self)));

	_set_settings_connection (self, connection);
	priv->applied_connection = nm_simple_connection_new_clone (NM_CONNECTION (priv->settings_connection));
	nm_connection_clear_secrets (priv->applied_connection);
}
NMSettingsConnection *
_nm_active_connection_get_settings_connection (NMActiveConnection *self)
{
	g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), NULL);

	return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->settings_connection;
}
NMActiveConnection *
nm_active_connection_get_master (NMActiveConnection *self)
{
	g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), NULL);

	return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->master;
}
/**
 * nm_active_connection_get_master_ready:
 * @self: the #NMActiveConnection
 *
 * Returns: %TRUE if the connection has a master connection, and that
 * master connection is ready to accept slaves.  Otherwise %FALSE.
 */
gboolean
nm_active_connection_get_master_ready (NMActiveConnection *self)
{
	g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), FALSE);

	return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->master_ready;
}
guint64
nm_active_connection_version_id_get (NMActiveConnection *self)
{
	g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), 0);

	return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->version_id;
}
NMAuthSubject *
nm_active_connection_get_subject (NMActiveConnection *self)
{
	g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), NULL);

	return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->subject;
}
/**
 * nm_active_connection_get_scope:
 * @connection: a #NMActiveConnection
 *
 * Gets the scope of the active connection.
 *
 * Returns: the connection's scope
 **/
NMConnectionScope
nm_active_connection_get_scope (NMActiveConnection *connection)
{
	g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (connection), NM_CONNECTION_SCOPE_UNKNOWN);

	/* Make sure service_name and scope are up-to-date */
	nm_active_connection_get_service_name (connection);
	return NM_ACTIVE_CONNECTION_GET_PRIVATE (connection)->scope;
}
gboolean
nm_active_connection_set_device (NMActiveConnection *self, NMDevice *device)
{
	NMActiveConnectionPrivate *priv;
	gs_unref_object NMDevice *old_device = NULL;

	g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), FALSE);
	g_return_val_if_fail (!device || NM_IS_DEVICE (device), FALSE);

	priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
	if (device == priv->device)
		return TRUE;

	_LOGD ("set device %s%s%s [%p]",
	       NM_PRINT_FMT_QUOTED (device && nm_device_get_iface (device),
	                            "\"",
	                            nm_device_get_iface (device),
	                            "\"",
	                            device ? "(unknown)" : "(null)"),
	       device);

	old_device = priv->device ? g_object_ref (priv->device) : NULL;
	_device_cleanup (self);

	if (device) {
		/* Device obviously can't be its own master */
		g_return_val_if_fail (!priv->master || device != nm_active_connection_get_device (priv->master), FALSE);

		priv->device = g_object_ref (device);

		g_signal_connect (device, NM_DEVICE_STATE_CHANGED,
		                  G_CALLBACK (device_state_changed), self);
		g_signal_connect (device, "notify::master",
		                  G_CALLBACK (device_master_changed), self);
		g_signal_connect (device, "notify::" NM_DEVICE_METERED,
		                  G_CALLBACK (device_metered_changed), self);

		if (!priv->assumed) {
			priv->pending_activation_id = g_strdup_printf ("activation::%p", (void *)self);
			nm_device_add_pending_action (device, priv->pending_activation_id, TRUE);
		}
	} else {
		/* The ActiveConnection's device can only be cleared after the
		 * connection is activated.
		 */
		g_warn_if_fail (priv->state > NM_ACTIVE_CONNECTION_STATE_UNKNOWN);
		priv->device = NULL;
	}
	_notify (self, PROP_INT_DEVICE);

	g_signal_emit (self, signals[DEVICE_CHANGED], 0, priv->device, old_device);

	_notify (self, PROP_DEVICES);

	return TRUE;
}
static void
device_metered_changed (GObject *object,
                        GParamSpec *pspec,
                        gpointer user_data)
{
	NMActiveConnection *self = (NMActiveConnection *) user_data;
	NMDevice *device = NM_DEVICE (object);

	g_return_if_fail (NM_IS_ACTIVE_CONNECTION (self));
	g_signal_emit (self, signals[DEVICE_METERED_CHANGED], 0, nm_device_get_metered (device));
}
const char *
nm_active_connection_get_settings_connection_id (NMActiveConnection *self)
{
	NMSettingsConnection *con;

	g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), NULL);

	con = NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->settings_connection;
	return con
	       ? nm_connection_get_id (NM_CONNECTION (con))
	       : NULL;
}
guint64
nm_active_connection_version_id_bump (NMActiveConnection *self)
{
	NMActiveConnectionPrivate *priv;

	g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), 0);

	priv = NM_ACTIVE_CONNECTION_GET_PRIVATE  (self);
	priv->version_id = _version_id_new ();
	_LOGT ("new version-id %llu", (long long unsigned) priv->version_id);
	return priv->version_id;
}
void
nm_active_connection_set_default6 (NMActiveConnection *self, gboolean is_default6)
{
	NMActiveConnectionPrivate *priv;

	g_return_if_fail (NM_IS_ACTIVE_CONNECTION (self));

	priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
	if (priv->is_default6 == is_default6)
		return;

	priv->is_default6 = is_default6;
	g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_DEFAULT6);
}
NMConnection *
nm_active_connection_get_applied_connection (NMActiveConnection *self)
{
	NMConnection *con;

	g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), NULL);

	con = NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->applied_connection;

	/* Only call this function on an active-connection that is already
	 * fully set-up (i.e. that has a settings-connection). Other uses
	 * indicate a bug. */
	g_return_val_if_fail (con, NULL);
	return con;
}
void
nm_active_connection_clear_secrets (NMActiveConnection *self)
{
	NMActiveConnectionPrivate *priv;

	g_return_if_fail (NM_IS_ACTIVE_CONNECTION (self));

	priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);

	if (nm_settings_connection_has_unmodified_applied_connection (priv->settings_connection,
	                                                              priv->applied_connection,
	                                                              NM_SETTING_COMPARE_FLAG_NONE))
		nm_connection_clear_secrets ((NMConnection *) priv->settings_connection);
	nm_connection_clear_secrets (priv->applied_connection);
}
gboolean
nm_active_connection_has_unmodified_applied_connection (NMActiveConnection *self, NMSettingCompareFlags compare_flags)
{
	NMActiveConnectionPrivate *priv;

	g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), FALSE);

	priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);

	g_return_val_if_fail (priv->settings_connection, FALSE);

	return nm_settings_connection_has_unmodified_applied_connection (priv->settings_connection,
	                                                                 priv->applied_connection,
	                                                                 compare_flags);
}
/**
 * nm_active_connection_get_specific_object:
 * @connection: a #NMActiveConnection
 *
 * Gets the "specific object" used at the activation.
 *
 * Returns: the specific object's DBus path. This is the internal string used by the
 * connection, and must not be modified.
 **/
const char *
nm_active_connection_get_specific_object (NMActiveConnection *connection)
{
	NMActiveConnectionPrivate *priv;

	g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (connection), NULL);

	priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (connection);
	if (!priv->specific_object) {
		priv->specific_object = _nm_object_get_string_property (NM_OBJECT (connection),
		                                                       NM_DBUS_INTERFACE_ACTIVE_CONNECTION,
		                                                       DBUS_PROP_SPECIFIC_OBJECT);
	}

	return priv->specific_object;
}
/**
 * nm_active_connection_get_state:
 * @connection: a #NMActiveConnection
 *
 * Gets the active connection's state.
 *
 * Returns: the state
 **/
NMActiveConnectionState
nm_active_connection_get_state (NMActiveConnection *connection)
{
	NMActiveConnectionPrivate *priv;

	g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (connection), NM_ACTIVE_CONNECTION_STATE_UNKNOWN);

	priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (connection);
	if (!priv->state) {
		priv->state = _nm_object_get_uint_property (NM_OBJECT (connection),
		                                           NM_DBUS_INTERFACE_ACTIVE_CONNECTION,
		                                           DBUS_PROP_STATE);
	}

	return priv->state;
}
/**
 * nm_active_connection_get_default:
 * @connection: a #NMActiveConnection
 *
 * Whether the active connection is the default one (that is, is used for the default route
 * and DNS information).
 *
 * Returns: %TRUE if the active connection is the default one
 **/
gboolean
nm_active_connection_get_default (NMActiveConnection *connection)
{
	NMActiveConnectionPrivate *priv;

	g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (connection), FALSE);

	priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (connection);
	if (!priv->is_default) {
		priv->is_default = _nm_object_get_boolean_property (NM_OBJECT (connection),
		                                                   NM_DBUS_INTERFACE_ACTIVE_CONNECTION,
		                                                   DBUS_PROP_DEFAULT);
	}

	return priv->is_default;
}
void
nm_active_connection_set_default (NMActiveConnection *self, gboolean is_default)
{
	NMActiveConnectionPrivate *priv;

	g_return_if_fail (NM_IS_ACTIVE_CONNECTION (self));

	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);
}
/**
 * nm_active_connection_get_service_name:
 * @connection: a #NMActiveConnection
 *
 * Gets the service name of the active connection.
 *
 * Returns: the service name. This is the internal string used by the
 * connection, and must not be modified.
 **/
const char *
nm_active_connection_get_service_name (NMActiveConnection *connection)
{
	NMActiveConnectionPrivate *priv;

	g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (connection), NULL);

	priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (connection);
	if (!priv->service_name) {
		priv->service_name = _nm_object_get_string_property (NM_OBJECT (connection),
		                                                    NM_DBUS_INTERFACE_ACTIVE_CONNECTION,
		                                                    DBUS_PROP_SERVICE_NAME);
		priv->scope = get_scope_for_service_name (priv->service_name);
	}

	return priv->service_name;
}
/**
 * nm_active_connection_get_devices:
 * @connection: a #NMActiveConnection
 *
 * Gets the #NMDevice<!-- -->s used for the active connections.
 *
 * Returns: the #GPtrArray containing #NMDevice<!-- -->s.
 * This is the internal copy used by the connection, and must not be modified.
 **/
const GPtrArray *
nm_active_connection_get_devices (NMActiveConnection *connection)
{
	NMActiveConnectionPrivate *priv;
	GValue value = { 0, };

	g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (connection), NULL);

	priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (connection);
	if (priv->devices)
		return handle_ptr_array_return (priv->devices);

	if (!_nm_object_get_property (NM_OBJECT (connection),
	                             NM_DBUS_INTERFACE_ACTIVE_CONNECTION,
	                             DBUS_PROP_DEVICES,
	                             &value)) {
		return NULL;
	}

	demarshal_devices (NM_OBJECT (connection), NULL, &value, &priv->devices);
	g_value_unset (&value);

	return handle_ptr_array_return (priv->devices);
}