static void
iface_check_ap_mode_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
{
	NMSupplicantInterface *self;
	NMSupplicantInterfacePrivate *priv;
	gs_unref_variant GVariant *variant = NULL;
	gs_free_error GError *error = NULL;
	const char *data;

	/* The ProbeRequest method only exists if AP mode has been enabled */
	variant = _nm_dbus_proxy_call_finish (proxy, result,
	                                      G_VARIANT_TYPE ("(s)"),
	                                      &error);
	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
		return;

	self = NM_SUPPLICANT_INTERFACE (user_data);
	priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);

	if (variant) {
		g_variant_get (variant, "(&s)", &data);
		if (strstr (data, "ProbeRequest"))
			priv->ap_support = AP_SUPPORT_YES;
	}

	iface_check_ready (self);
}
static void
iface_check_netreply_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
{
	NMSupplicantInterface *self;
	NMSupplicantInterfacePrivate *priv;
	gs_unref_variant GVariant *variant = NULL;
	gs_free_error GError *error = NULL;

	/* We know NetworkReply is supported if the NetworkReply method returned
	 * successfully (which is unexpected since we sent a bogus network
	 * object path) or if we got an "InvalidArgs" (which indicates NetworkReply
	 * is supported).  We know it's not supported if we get an
	 * "UnknownMethod" error.
	 */

	variant = g_dbus_proxy_call_finish (proxy, result, &error);
	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
		return;

	self = NM_SUPPLICANT_INTERFACE (user_data);
	priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);

	if (variant || _nm_dbus_error_has_name (error, "fi.w1.wpa_supplicant1.InvalidArgs"))
		priv->has_credreq = TRUE;

	nm_log_dbg (LOGD_SUPPLICANT, "Supplicant %s network credentials requests",
	            priv->has_credreq ? "supports" : "does not support");

	iface_check_ready (self);
}
Example #3
0
static void
nm_supplicant_interface_smgr_state_changed (NMSupplicantManager * smgr,
                                            guint32 new_state,
                                            guint32 old_state,
                                            gpointer user_data)
{
	NMSupplicantInterface * self = NM_SUPPLICANT_INTERFACE (user_data);

	switch (new_state) {
		case NM_SUPPLICANT_MANAGER_STATE_DOWN:
			/* The supplicant went away, likely the connection to it is also
			 * gone.  Therefore, this interface must move to the DOWN state
			 * and be disposed of.
			 */
			nm_supplicant_interface_set_state (self, NM_SUPPLICANT_INTERFACE_STATE_DOWN);
			break;
		case NM_SUPPLICANT_MANAGER_STATE_IDLE:
			/* Handle the supplicant now being available. */
			nm_supplicant_interface_handle_supplicant_manager_idle_state (self);
			break;
		default:
			nm_log_warn (LOGD_SUPPLICANT, "Unknown supplicant manager state!");
			break;
	}
}
static void
set_ap_scan_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
{
	NMSupplicantInterface *self;
	NMSupplicantInterfacePrivate *priv;
	gs_unref_variant GVariant *reply = NULL;
	gs_free_error GError *error = NULL;

	reply = g_dbus_proxy_call_finish (proxy, result, &error);
	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
		return;

	self = NM_SUPPLICANT_INTERFACE (user_data);
	priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);

	if (!reply) {
		g_dbus_error_strip_remote_error (error);
		nm_log_warn (LOGD_SUPPLICANT, "Couldn't send AP scan mode to the supplicant interface: %s.",
		             error->message);
		emit_error_helper (self, error);
		return;
	}

	nm_log_info (LOGD_SUPPLICANT, "Config: set interface ap_scan to %d",
	             nm_supplicant_config_get_ap_scan (priv->cfg));

	g_dbus_proxy_call (priv->iface_proxy,
	                   "AddNetwork",
	                   g_variant_new ("(@a{sv})", nm_supplicant_config_to_variant (priv->cfg)),
	                   G_DBUS_CALL_FLAGS_NONE,
	                   -1,
	                   priv->assoc_cancellable,
	                   (GAsyncReadyCallback) add_network_cb,
	                   self);
}
static void
interface_get_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
{
	NMSupplicantInterface *self;
	NMSupplicantInterfacePrivate *priv;
	gs_unref_variant GVariant *variant = NULL;
	gs_free_error GError *error = NULL;
	const char *path;

	variant = _nm_dbus_proxy_call_finish (proxy, result,
	                                      G_VARIANT_TYPE ("(o)"),
	                                      &error);
	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
		return;

	self = NM_SUPPLICANT_INTERFACE (user_data);
	priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);

	if (variant) {
		g_variant_get (variant, "(&o)", &path);
		interface_add_done (self, path);
	} else {
		g_dbus_error_strip_remote_error (error);
		nm_log_err (LOGD_SUPPLICANT, "(%s): error getting interface: %s", priv->dev, error->message);
		set_state (self, NM_SUPPLICANT_INTERFACE_STATE_DOWN);
	}
}
static void
dispose (GObject *object)
{
	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (object);

	if (priv->iface_proxy)
		g_signal_handlers_disconnect_by_data (priv->iface_proxy, NM_SUPPLICANT_INTERFACE (object));
	g_clear_object (&priv->iface_proxy);

	if (priv->init_cancellable)
		g_cancellable_cancel (priv->init_cancellable);
	g_clear_object (&priv->init_cancellable);

	if (priv->other_cancellable)
		g_cancellable_cancel (priv->other_cancellable);
	g_clear_object (&priv->other_cancellable);

	g_clear_object (&priv->wpas_proxy);
	g_clear_pointer (&priv->bss_proxies, (GDestroyNotify) g_hash_table_destroy);

	g_clear_pointer (&priv->net_path, g_free);
	g_clear_pointer (&priv->dev, g_free);
	g_clear_pointer (&priv->object_path, g_free);
	g_clear_pointer (&priv->current_bss, g_free);

	g_clear_object (&priv->cfg);

	/* Chain up to the parent class */
	G_OBJECT_CLASS (nm_supplicant_interface_parent_class)->dispose (object);
}
Example #7
0
static gboolean
request_scan_results (gpointer user_data)
{
	NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data);
	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
	NMSupplicantInfo *info;
	DBusGProxyCall *call;
	GTimeVal cur_time;

	priv->scan_results_timeout = 0;

	g_return_val_if_fail (priv->iface_proxy != NULL, FALSE);

	info = nm_supplicant_info_new (self, priv->iface_proxy, priv->other_pcalls);
	call = dbus_g_proxy_begin_call (priv->iface_proxy, "scanResults",
	                                scan_results_cb, 
	                                info,
	                                nm_supplicant_info_destroy,
	                                G_TYPE_INVALID);
	nm_supplicant_info_set_call (info, call);

	g_get_current_time (&cur_time);
	priv->last_scan = cur_time.tv_sec;
	return FALSE;
}
static void
on_wpas_proxy_acquired (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
{
	NMSupplicantInterface *self;
	NMSupplicantInterfacePrivate *priv;
	gs_free_error GError *error = NULL;
	GDBusProxy *wpas_proxy;
	GVariantBuilder props;

	wpas_proxy = g_dbus_proxy_new_for_bus_finish (result, &error);
	if (!wpas_proxy) {
		if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
			nm_log_warn (LOGD_SUPPLICANT, "Failed to acquire wpa_supplicant proxy: (%s)",
			             error ? error->message : "unknown");
			set_state (NM_SUPPLICANT_INTERFACE (user_data), NM_SUPPLICANT_INTERFACE_STATE_DOWN);
		}
		return;
	}

	self = NM_SUPPLICANT_INTERFACE (user_data);
	priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);

	priv->wpas_proxy = wpas_proxy;

	/* Try to add the interface to the supplicant.  If the supplicant isn't
	 * running, this will start it via D-Bus activation and return the response
	 * when the supplicant has started.
	 */

	g_variant_builder_init (&props, G_VARIANT_TYPE_VARDICT);
	g_variant_builder_add (&props, "{sv}",
	                       "Driver",
	                       g_variant_new_string (priv->is_wireless ? DEFAULT_WIFI_DRIVER : "wired"));
	g_variant_builder_add (&props, "{sv}",
	                       "Ifname",
	                       g_variant_new_string (priv->dev));

	g_dbus_proxy_call (priv->wpas_proxy,
	                   "CreateInterface",
	                   g_variant_new ("(a{sv})", &props),
	                   G_DBUS_CALL_FLAGS_NONE,
	                   -1,
	                   priv->init_cancellable,
	                   (GAsyncReadyCallback) interface_add_cb,
	                   self);
}
static void
wpas_iface_bss_added (DBusGProxy *proxy,
                      const char *object_path,
                      GHashTable *props,
                      gpointer user_data)
{
	g_signal_emit (NM_SUPPLICANT_INTERFACE (user_data), signals[NEW_BSS], 0, props);
}
static void
add_network_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
{
	NMSupplicantInterface *self;
	NMSupplicantInterfacePrivate *priv;
	gs_unref_variant GVariant *reply = NULL;
	gs_free_error GError *error = NULL;
	GHashTable *blobs;
	GHashTableIter iter;
	const char *blob_name;
	GByteArray *blob_data;

	reply = _nm_dbus_proxy_call_finish (proxy, result,
	                                    G_VARIANT_TYPE ("(o)"),
	                                    &error);
	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
		return;

	self = NM_SUPPLICANT_INTERFACE (user_data);
	priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);

	g_free (priv->net_path);
	priv->net_path = NULL;

	if (error) {
		g_dbus_error_strip_remote_error (error);
		nm_log_warn (LOGD_SUPPLICANT, "Adding network to supplicant failed: %s.", error->message);
		emit_error_helper (self, error);
		return;
	}

	g_variant_get (reply, "(o)", &priv->net_path);

	/* Send blobs first; otherwise jump to selecting the network */
	blobs = nm_supplicant_config_get_blobs (priv->cfg);
	priv->blobs_left = g_hash_table_size (blobs);

	g_hash_table_iter_init (&iter, blobs);
	while (g_hash_table_iter_next (&iter, (gpointer) &blob_name, (gpointer) &blob_data)) {
		g_dbus_proxy_call (priv->iface_proxy,
		                   "AddBlob",
		                   g_variant_new ("(s@ay)",
		                                  blob_name,
		                                  g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
		                                                             blob_data->data, blob_data->len, 1)),
		                   G_DBUS_CALL_FLAGS_NONE,
		                   -1,
		                   priv->assoc_cancellable,
		                   (GAsyncReadyCallback) add_blob_cb,
		                   self);
	}

	call_select_network (self);
}
static void
wpas_iface_bss_removed (GDBusProxy *proxy,
                        const char *path,
                        gpointer user_data)
{
	NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data);
	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);

	g_signal_emit (self, signals[BSS_REMOVED], 0, path);
	g_hash_table_remove (priv->bss_proxies, path);
}
static void
availability_changed (NMSupplicantManager *self, gboolean available)
{
	NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
	GList *ifaces, *iter;

	/* priv->ifaces may be modified if availability changes; can't use GHashTableIter */
	ifaces = g_hash_table_get_values (priv->ifaces);
	for (iter = ifaces; iter; iter = iter->next)
		nm_supplicant_interface_set_supplicant_available (NM_SUPPLICANT_INTERFACE (iter->data), available);
	g_list_free (ifaces);
}
static void
interface_add_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
{
	NMSupplicantInterface *self;
	NMSupplicantInterfacePrivate *priv;
	gs_free_error GError *error = NULL;
	gs_unref_variant GVariant *variant = NULL;
	const char *path;

	variant = _nm_dbus_proxy_call_finish (proxy, result,
	                                      G_VARIANT_TYPE ("(o)"),
	                                      &error);
	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
		return;

	self = NM_SUPPLICANT_INTERFACE (user_data);
	priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);

	if (variant) {
		g_variant_get (variant, "(&o)", &path);
		interface_add_done (self, path);
	} else if (_nm_dbus_error_has_name (error, WPAS_ERROR_EXISTS_ERROR)) {
		/* Interface already added, just get its object path */
		g_dbus_proxy_call (priv->wpas_proxy,
		                   "GetInterface",
		                   g_variant_new ("(s)", priv->dev),
		                   G_DBUS_CALL_FLAGS_NONE,
		                   -1,
		                   priv->init_cancellable,
		                   (GAsyncReadyCallback) interface_get_cb,
		                   self);
	} else if (   g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN)
	           || g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SPAWN_EXEC_FAILED)
	           || g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SPAWN_FORK_FAILED)
	           || g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SPAWN_FAILED)
	           || g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_TIMEOUT)
	           || g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_NO_REPLY)
	           || g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_TIMED_OUT)
	           || g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SPAWN_SERVICE_NOT_FOUND)) {
		/* Supplicant wasn't running and could not be launched via service
		 * activation.  Wait for it to start by moving back to the INIT
		 * state.
		 */
		g_dbus_error_strip_remote_error (error);
		nm_log_dbg (LOGD_SUPPLICANT, "(%s): failed to activate supplicant: %s",
		            priv->dev, error->message);
		set_state (self, NM_SUPPLICANT_INTERFACE_STATE_INIT);
	} else {
		g_dbus_error_strip_remote_error (error);
		nm_log_err (LOGD_SUPPLICANT, "(%s): error adding interface: %s", priv->dev, error->message);
		set_state (self, NM_SUPPLICANT_INTERFACE_STATE_DOWN);
	}
}
Example #14
0
static void
wpas_iface_handle_scanning (DBusGProxy *proxy,
                            gboolean scanning,
                            gpointer user_data)
{
	NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data);
	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);

	if (scanning != priv->scanning) {
		priv->scanning = scanning;
		g_object_notify (G_OBJECT (self), "scanning");
	}
}
static void
select_network_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
{
	gs_unref_variant GVariant *reply = NULL;
	gs_free_error GError *err = NULL;

	reply = g_dbus_proxy_call_finish (proxy, result, &err);
	if (!reply && !g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
		g_dbus_error_strip_remote_error (err);
		nm_log_warn (LOGD_SUPPLICANT, "Couldn't select network config: %s.", err->message);
		emit_error_helper (NM_SUPPLICANT_INTERFACE (user_data), err);
	}
}
static void
wpas_iface_network_request (GDBusProxy *proxy,
                            const char *path,
                            const char *field,
                            const char *message,
                            gpointer user_data)
{
	NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data);
	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);

	if (priv->has_credreq && priv->net_path && !g_strcmp0 (path, priv->net_path))
		g_signal_emit (self, signals[CREDENTIALS_REQUEST], 0, field, message);
}
static void
wpas_iface_scan_done (GDBusProxy *proxy,
                      gboolean success,
                      gpointer user_data)
{
	NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data);
	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);

	/* Cache last scan completed time */
	priv->last_scan = nm_utils_get_monotonic_timestamp_s ();

	g_signal_emit (self, signals[SCAN_DONE], 0, success);
}
static void
wpas_iface_bss_added (GDBusProxy *proxy,
                      const char *path,
                      GVariant *props,
                      gpointer user_data)
{
	NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data);
	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);

	if (priv->scanning)
		priv->last_scan = nm_utils_get_monotonic_timestamp_s ();

	handle_new_bss (self, path);
}
static void
wpas_iface_scan_done (DBusGProxy *proxy,
                      gboolean success,
                      gpointer user_data)
{
	NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data);
	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
	GTimeVal cur_time;

	/* Cache last scan completed time */
	g_get_current_time (&cur_time);
	priv->last_scan = cur_time.tv_sec;

	g_signal_emit (self, signals[SCAN_DONE], 0, success);
}
static void
bss_props_changed_cb (GDBusProxy *proxy,
                      GVariant *changed_properties,
                      char **invalidated_properties,
                      gpointer user_data)
{
	NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data);
	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);

	if (priv->scanning)
		priv->last_scan = nm_utils_get_monotonic_timestamp_s ();

	g_signal_emit (self, signals[BSS_UPDATED], 0,
	               g_dbus_proxy_get_object_path (proxy),
	               changed_properties);
}
static void
smgr_avail_cb (NMSupplicantManager *smgr,
               GParamSpec *pspec,
               gpointer user_data)
{
	NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data);
	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (user_data);

	if (nm_supplicant_manager_available (smgr)) {
		/* This can happen if the supplicant couldn't be activated but
		 * for some reason was started after the activation failure.
		 */
		if (priv->state == NM_SUPPLICANT_INTERFACE_STATE_INIT)
			interface_add (self, priv->is_wireless);
	} else {
		/* The supplicant stopped; so we must tear down the interface */
		set_state (self, NM_SUPPLICANT_INTERFACE_STATE_DOWN);
	}
}
static void
wpas_iface_properties_changed (DBusGProxy *proxy,
                               GHashTable *props,
                               gpointer user_data)
{
	NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data);
	GValue *value;

	value = g_hash_table_lookup (props, "Scanning");
	if (value && G_VALUE_HOLDS_BOOLEAN (value))
		set_scanning (self, g_value_get_boolean (value));

	value = g_hash_table_lookup (props, "State");
	if (value && G_VALUE_HOLDS_STRING (value))
		set_state_from_string (self, g_value_get_string (value));

	value = g_hash_table_lookup (props, "BSSs");
	if (value && G_VALUE_HOLDS (value, DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH))
		request_bss_properties (self, g_value_get_boxed (value));
}
static void
scan_request_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
{
	gs_unref_variant GVariant *reply = NULL;
	gs_free_error GError *error = NULL;

	reply = g_dbus_proxy_call_finish (proxy, result, &error);
	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
		return;

	if (error) {
		if (_nm_dbus_error_has_name (error, "fi.w1.wpa_supplicant1.Interface.ScanError"))
			nm_log_dbg (LOGD_SUPPLICANT, "Could not get scan request result: %s", error->message);
		else {
			g_dbus_error_strip_remote_error (error);
			nm_log_warn (LOGD_SUPPLICANT, "Could not get scan request result: %s", error->message);
		}
	}
	g_signal_emit (NM_SUPPLICANT_INTERFACE (user_data), signals[SCAN_DONE], 0, error ? FALSE : TRUE);
}
static void
on_bss_proxy_acquired (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
{
	NMSupplicantInterface *self;
	NMSupplicantInterfacePrivate *priv;
	gs_free_error GError *error = NULL;
	gs_strfreev char **properties = NULL;
	gs_unref_variant GVariant *props = NULL;
	GVariantBuilder builder;
	char **iter;

	if (!g_async_initable_init_finish (G_ASYNC_INITABLE (proxy), result, &error)) {
		if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
			nm_log_dbg (LOGD_SUPPLICANT, "Failed to acquire BSS proxy: (%s)", error->message);
			g_hash_table_remove (NM_SUPPLICANT_INTERFACE_GET_PRIVATE (user_data)->bss_proxies,
			                     g_dbus_proxy_get_object_path (proxy));
		}
		return;
	}

	self = NM_SUPPLICANT_INTERFACE (user_data);
	priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);

	g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));

	iter = properties = g_dbus_proxy_get_cached_property_names (proxy);
	while (iter && *iter) {
		GVariant *copy = g_dbus_proxy_get_cached_property (proxy, *iter);

		g_variant_builder_add (&builder, "{sv}", *iter++, copy);
		g_variant_unref (copy);
	}

	props = g_variant_builder_end (&builder);
	g_signal_emit (self, signals[NEW_BSS], 0,
	               g_dbus_proxy_get_object_path (proxy),
	               g_variant_ref_sink (props));
}
static void
add_blob_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
{
	NMSupplicantInterface *self;
	NMSupplicantInterfacePrivate *priv;
	gs_unref_variant GVariant *reply = NULL;
	gs_free_error GError *err = NULL;

	reply = g_dbus_proxy_call_finish (proxy, result, &err);
	if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED))
		return;

	self = NM_SUPPLICANT_INTERFACE (user_data);
	priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);

	priv->blobs_left--;
	if (reply)
		call_select_network (self);
	else {
		g_dbus_error_strip_remote_error (err);
		nm_log_warn (LOGD_SUPPLICANT, "Couldn't set network certificates: %s.", err->message);
		emit_error_helper (self, err);
	}
}
static void
on_iface_proxy_acquired (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
{
	NMSupplicantInterface *self;
	NMSupplicantInterfacePrivate *priv;
	gs_free_error GError *error = NULL;

	if (!g_async_initable_init_finish (G_ASYNC_INITABLE (proxy), result, &error)) {
		if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
			nm_log_warn (LOGD_SUPPLICANT, "Failed to acquire wpa_supplicant interface proxy: (%s)", error->message);
			set_state (NM_SUPPLICANT_INTERFACE (user_data), NM_SUPPLICANT_INTERFACE_STATE_DOWN);
		}
		return;
	}

	self = NM_SUPPLICANT_INTERFACE (user_data);
	priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);

	_nm_dbus_signal_connect (priv->iface_proxy, "ScanDone", G_VARIANT_TYPE ("(b)"),
	                         G_CALLBACK (wpas_iface_scan_done), self);
	_nm_dbus_signal_connect (priv->iface_proxy, "BSSAdded", G_VARIANT_TYPE ("(oa{sv})"),
	                         G_CALLBACK (wpas_iface_bss_added), self);
	_nm_dbus_signal_connect (priv->iface_proxy, "BSSRemoved", G_VARIANT_TYPE ("(o)"),
	                         G_CALLBACK (wpas_iface_bss_removed), self);
	_nm_dbus_signal_connect (priv->iface_proxy, "NetworkRequest", G_VARIANT_TYPE ("(oss)"),
	                         G_CALLBACK (wpas_iface_network_request), self);

	/* Scan result aging parameters */
	g_dbus_proxy_call (priv->iface_proxy,
	                   "org.freedesktop.DBus.Properties.Set",
	                   g_variant_new ("(ssv)",
	                                  WPAS_DBUS_IFACE_INTERFACE,
	                                  "BSSExpireAge",
	                                  g_variant_new_uint32 (250)),
	                   G_DBUS_CALL_FLAGS_NONE,
	                   -1,
	                   priv->init_cancellable,
	                   NULL,
	                   NULL);
	g_dbus_proxy_call (priv->iface_proxy,
	                   "org.freedesktop.DBus.Properties.Set",
	                   g_variant_new ("(ssv)",
	                                  WPAS_DBUS_IFACE_INTERFACE,
	                                  "BSSExpireCount",
	                                  g_variant_new_uint32 (2)),
	                   G_DBUS_CALL_FLAGS_NONE,
	                   -1,
	                   priv->init_cancellable,
	                   NULL,
	                   NULL);

	/* Check whether NetworkReply and AP mode are supported */
	priv->ready_count = 1;
	g_dbus_proxy_call (priv->iface_proxy,
	                   "NetworkReply",
	                   g_variant_new ("(oss)",
	                                  "/fff",
	                                  "foobar",
	                                  "foobar"),
	                   G_DBUS_CALL_FLAGS_NONE,
	                   -1,
	                   priv->init_cancellable,
	                   (GAsyncReadyCallback) iface_check_netreply_cb,
	                   self);

	if (priv->ap_support == AP_SUPPORT_UNKNOWN) {
		/* If the global supplicant capabilities property is not present, we can
		 * fall back to checking whether the ProbeRequest method is supported.  If
		 * neither of these works we have no way of determining if AP mode is
		 * supported or not.  hostap 1.0 and earlier don't support either of these.
		 */
		priv->ready_count++;
		g_dbus_proxy_call (priv->iface_proxy,
		                   DBUS_INTERFACE_INTROSPECTABLE ".Introspect",
		                   NULL,
		                   G_DBUS_CALL_FLAGS_NONE,
		                   -1,
		                   priv->init_cancellable,
		                   (GAsyncReadyCallback) iface_check_ap_mode_cb,
		                   self);
	}
}
static void
props_changed_cb (GDBusProxy *proxy,
                  GVariant *changed_properties,
                  GStrv invalidated_properties,
                  gpointer user_data)
{
	NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data);
	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
	const char *s, **array, **iter;
	gboolean b = FALSE;
	gint32 i32;
	GVariant *v;

	g_object_freeze_notify (G_OBJECT (self));

	if (g_variant_lookup (changed_properties, "Scanning", "b", &b))
		set_scanning (self, b);

	if (   g_variant_lookup (changed_properties, "State", "&s", &s)
	    && priv->state >= NM_SUPPLICANT_INTERFACE_STATE_READY) {
		/* Only transition to actual wpa_supplicant interface states (ie,
		 * anything > READY) after the NMSupplicantInterface has had a
		 * chance to initialize, which is signalled by entering the READY
		 * state.
		 */
		set_state_from_string (self, s);
	}

	if (g_variant_lookup (changed_properties, "BSSs", "^a&s", &array)) {
		iter = array;
		while (*iter)
			handle_new_bss (self, *iter++);
		g_free (array);
	}

	if (g_variant_lookup (changed_properties, "CurrentBSS", "&o", &s)) {
		if (strcmp (s, "/") == 0)
			s = NULL;
		if (g_strcmp0 (s, priv->current_bss) != 0) {
			g_free (priv->current_bss);
			priv->current_bss = g_strdup (s);
			g_object_notify (G_OBJECT (self), NM_SUPPLICANT_INTERFACE_CURRENT_BSS);
		}
	}

	v = g_variant_lookup_value (changed_properties, "Capabilities", G_VARIANT_TYPE_VARDICT);
	if (v) {
		parse_capabilities (self, v);
		g_variant_unref (v);
	}

	if (g_variant_lookup (changed_properties, "DisconnectReason", "i", &i32)) {
		/* Disconnect reason is currently only given for deauthentication events,
		 * not disassociation; currently they are IEEE 802.11 "reason codes",
		 * defined by (IEEE 802.11-2007, 7.3.1.7, Table 7-22).  Any locally caused
		 * deauthentication will be negative, while authentications caused by the
		 * AP will be positive.
		 */
		priv->disconnect_reason = i32;
		if (priv->disconnect_reason != 0) {
			nm_log_warn (LOGD_SUPPLICANT, "Connection disconnected (reason %d)",
				         priv->disconnect_reason);
		}
	}

	g_object_thaw_notify (G_OBJECT (self));
}