summaryrefslogtreecommitdiff
path: root/src/supplicant/nm-supplicant-interface.c
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2021-02-03 15:25:56 +0100
committerThomas Haller <thaller@redhat.com>2021-02-04 09:45:55 +0100
commitac1a9e03e4d6674e1e60529b47b325a8f62e67b3 (patch)
treeef0445da3fd804e6cc5ee1e9c48a352dd348df1f /src/supplicant/nm-supplicant-interface.c
parent97ed143e04e74323a59a0f24a965d36341233670 (diff)
all: move "src/" directory to "src/core/"
Currently "src/" mostly contains the source code of the daemon. I say mostly, because that is not true, there are also the device, settings, wwan, ppp plugins, the initrd generator, the pppd and dhcp helper, and probably more. Also we have source code under libnm-core/, libnm/, clients/, and shared/ directories. That is all confusing. We should have one "src" directory, that contains subdirectories. Those subdirectories should contain individual parts (libraries or applications), that possibly have dependencies on other subdirectories. There should be a flat hierarchy of directories under src/, which contains individual modules. As the name "src/" is already taken, that prevents any sensible restructuring of the code. As a first step, move "src/" to "src/core/". This gives space to reorganize the code better by moving individual components into "src/". For inspiration, look at systemd's "src/" directory. https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/743
Diffstat (limited to 'src/supplicant/nm-supplicant-interface.c')
-rw-r--r--src/supplicant/nm-supplicant-interface.c3522
1 files changed, 0 insertions, 3522 deletions
diff --git a/src/supplicant/nm-supplicant-interface.c b/src/supplicant/nm-supplicant-interface.c
deleted file mode 100644
index ec278c31fc..0000000000
--- a/src/supplicant/nm-supplicant-interface.c
+++ /dev/null
@@ -1,3522 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * Copyright (C) 2006 - 2017 Red Hat, Inc.
- * Copyright (C) 2006 - 2008 Novell, Inc.
- */
-
-#include "nm-default.h"
-
-#include "nm-supplicant-interface.h"
-
-#include <stdio.h>
-#include <linux/if_ether.h>
-
-#include "NetworkManagerUtils.h"
-#include "nm-core-internal.h"
-#include "nm-glib-aux/nm-c-list.h"
-#include "nm-glib-aux/nm-ref-string.h"
-#include "nm-std-aux/nm-dbus-compat.h"
-#include "nm-supplicant-config.h"
-#include "nm-supplicant-manager.h"
-#include "shared/nm-glib-aux/nm-dbus-aux.h"
-
-#define DBUS_TIMEOUT_MSEC 20000
-
-/*****************************************************************************/
-
-typedef struct {
- NMSupplicantInterface *self;
- char * type;
- char * bssid;
- char * pin;
- guint signal_id;
- GCancellable * cancellable;
- bool needs_cancelling : 1;
- bool is_cancelling : 1;
-} WpsData;
-
-struct _AddNetworkData;
-
-typedef struct {
- NMSupplicantInterface * self;
- NMSupplicantConfig * cfg;
- GCancellable * cancellable;
- NMSupplicantInterfaceAssocCb callback;
- gpointer user_data;
- guint fail_on_idle_id;
- guint blobs_left;
- guint calls_left;
- struct _AddNetworkData * add_network_data;
-} AssocData;
-
-typedef struct _AddNetworkData {
- /* the assoc_data at the time when doing the call. */
- AssocData * assoc_data;
- NMRefString *name_owner;
- NMRefString *object_path;
- GObject * shutdown_wait_obj;
-} AddNetworkData;
-
-enum {
- STATE, /* change in the interface's state */
- BSS_CHANGED, /* a new BSS appeared, was updated, or was removed. */
- PEER_CHANGED, /* a new Peer appeared, was updated, or was removed */
- WPS_CREDENTIALS, /* WPS credentials received */
- GROUP_STARTED, /* a new Group (interface) was created */
- GROUP_FINISHED, /* a Group (interface) has been finished */
- LAST_SIGNAL
-};
-
-static guint signals[LAST_SIGNAL] = {0};
-
-NM_GOBJECT_PROPERTIES_DEFINE(NMSupplicantInterface,
- PROP_SUPPLICANT_MANAGER,
- PROP_DBUS_OBJECT_PATH,
- PROP_IFINDEX,
- PROP_P2P_GROUP_JOINED,
- PROP_P2P_GROUP_PATH,
- PROP_P2P_GROUP_OWNER,
- PROP_SCANNING,
- PROP_CURRENT_BSS,
- PROP_DRIVER,
- PROP_P2P_AVAILABLE,
- PROP_AUTH_STATE, );
-
-typedef struct _NMSupplicantInterfacePrivate {
- NMSupplicantManager *supplicant_manager;
-
- GDBusConnection *dbus_connection;
- NMRefString * name_owner;
- NMRefString * object_path;
-
- char *ifname;
-
- GCancellable *main_cancellable;
-
- NMRefString *p2p_group_path;
-
- GCancellable *p2p_group_properties_cancellable;
-
- WpsData *wps_data;
-
- AssocData *assoc_data;
-
- char *net_path;
-
- char *driver;
-
- GHashTable *bss_idx;
- CList bss_lst_head;
- CList bss_initializing_lst_head;
-
- NMRefString *current_bss;
-
- GHashTable *peer_idx;
- CList peer_lst_head;
- CList peer_initializing_lst_head;
-
- gint64 last_scan_msec;
-
- NMSupplicantAuthState auth_state;
-
- NMSupplicantDriver requested_driver;
- NMSupplCapMask global_capabilities;
- NMSupplCapMask iface_capabilities;
-
- guint properties_changed_id;
- guint signal_id;
- guint bss_properties_changed_id;
- guint peer_properties_changed_id;
- guint p2p_group_properties_changed_id;
-
- int ifindex;
-
- int starting_pending_count;
-
- guint32 max_scan_ssids;
-
- gint32 disconnect_reason;
-
- NMSupplicantInterfaceState state;
- NMSupplicantInterfaceState supp_state;
-
- bool scanning_property : 1;
- bool scanning_cached : 1;
-
- bool p2p_capable_property : 1;
- bool p2p_capable_cached : 1;
-
- bool p2p_group_owner_property : 1;
- bool p2p_group_owner_cached : 1;
-
- bool p2p_group_joined_cached : 1;
-
- bool is_ready_main : 1;
- bool is_ready_p2p_device : 1;
-
- bool prop_scan_active : 1;
- bool prop_scan_ssid : 1;
-
- bool ap_isolate_supported : 1;
- bool ap_isolate_needs_reset : 1;
-} NMSupplicantInterfacePrivate;
-
-struct _NMSupplicantInterfaceClass {
- GObjectClass parent;
-};
-
-G_DEFINE_TYPE(NMSupplicantInterface, nm_supplicant_interface, G_TYPE_OBJECT)
-
-#define NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self) \
- _NM_GET_PRIVATE_PTR(self, NMSupplicantInterface, NM_IS_SUPPLICANT_INTERFACE)
-
-/*****************************************************************************/
-
-static const char *
-_log_pretty_object_path(NMSupplicantInterfacePrivate *priv)
-{
- const char *s;
-
- nm_assert(priv);
- nm_assert(NM_IS_REF_STRING(priv->object_path));
-
- s = priv->object_path->str;
- if (NM_STR_HAS_PREFIX(s, "/fi/w1/wpa_supplicant1/Interfaces/")) {
- s += NM_STRLEN("/fi/w1/wpa_supplicant1/Interfaces/");
- if (s[0] && s[0] != '/')
- return s;
- }
- return priv->object_path->str;
-}
-
-#define _NMLOG_DOMAIN LOGD_SUPPLICANT
-#define _NMLOG_PREFIX_NAME "sup-iface"
-#define _NMLOG(level, ...) \
- G_STMT_START \
- { \
- NMSupplicantInterface * _self = (self); \
- NMSupplicantInterfacePrivate *_priv = \
- _self ? NM_SUPPLICANT_INTERFACE_GET_PRIVATE(_self) : NULL; \
- char _sbuf[255]; \
- const char *_ifname = _priv ? _priv->ifname : NULL; \
- \
- nm_log((level), \
- _NMLOG_DOMAIN, \
- _ifname, \
- NULL, \
- "%s%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
- _NMLOG_PREFIX_NAME, \
- (_self ? nm_sprintf_buf(_sbuf, \
- "[" NM_HASH_OBFUSCATE_PTR_FMT ",%s,%s]", \
- NM_HASH_OBFUSCATE_PTR(_self), \
- _log_pretty_object_path(_priv), \
- _ifname ?: "???") \
- : "") _NM_UTILS_MACRO_REST(__VA_ARGS__)); \
- } \
- G_STMT_END
-
-/*****************************************************************************/
-
-static void _starting_check_ready(NMSupplicantInterface *self);
-
-static void assoc_return(NMSupplicantInterface *self, GError *error, const char *message);
-
-/*****************************************************************************/
-
-NM_UTILS_LOOKUP_STR_DEFINE(
- nm_supplicant_interface_state_to_string,
- NMSupplicantInterfaceState,
- NM_UTILS_LOOKUP_DEFAULT_WARN("internal-unknown"),
- NM_UTILS_LOOKUP_STR_ITEM(NM_SUPPLICANT_INTERFACE_STATE_INVALID, "internal-invalid"),
- NM_UTILS_LOOKUP_STR_ITEM(NM_SUPPLICANT_INTERFACE_STATE_STARTING, "internal-starting"),
-
- NM_UTILS_LOOKUP_STR_ITEM(NM_SUPPLICANT_INTERFACE_STATE_4WAY_HANDSHAKE, "4way_handshake"),
- NM_UTILS_LOOKUP_STR_ITEM(NM_SUPPLICANT_INTERFACE_STATE_ASSOCIATED, "associated"),
- NM_UTILS_LOOKUP_STR_ITEM(NM_SUPPLICANT_INTERFACE_STATE_ASSOCIATING, "associating"),
- NM_UTILS_LOOKUP_STR_ITEM(NM_SUPPLICANT_INTERFACE_STATE_AUTHENTICATING, "authenticating"),
- NM_UTILS_LOOKUP_STR_ITEM(NM_SUPPLICANT_INTERFACE_STATE_COMPLETED, "completed"),
- NM_UTILS_LOOKUP_STR_ITEM(NM_SUPPLICANT_INTERFACE_STATE_DISCONNECTED, "disconnected"),
- NM_UTILS_LOOKUP_STR_ITEM(NM_SUPPLICANT_INTERFACE_STATE_GROUP_HANDSHAKE, "group_handshake"),
- NM_UTILS_LOOKUP_STR_ITEM(NM_SUPPLICANT_INTERFACE_STATE_INACTIVE, "inactive"),
- NM_UTILS_LOOKUP_STR_ITEM(NM_SUPPLICANT_INTERFACE_STATE_DISABLED, "interface_disabled"),
- NM_UTILS_LOOKUP_STR_ITEM(NM_SUPPLICANT_INTERFACE_STATE_SCANNING, "scanning"),
-
- NM_UTILS_LOOKUP_STR_ITEM(NM_SUPPLICANT_INTERFACE_STATE_DOWN, "internal-down"), );
-
-static NM_UTILS_STRING_TABLE_LOOKUP_DEFINE(
- wpas_state_string_to_enum,
- NMSupplicantInterfaceState,
- { nm_assert(name); },
- { return NM_SUPPLICANT_INTERFACE_STATE_INVALID; },
- {"4way_handshake", NM_SUPPLICANT_INTERFACE_STATE_4WAY_HANDSHAKE},
- {"associated", NM_SUPPLICANT_INTERFACE_STATE_ASSOCIATED},
- {"associating", NM_SUPPLICANT_INTERFACE_STATE_ASSOCIATING},
- {"authenticating", NM_SUPPLICANT_INTERFACE_STATE_AUTHENTICATING},
- {"completed", NM_SUPPLICANT_INTERFACE_STATE_COMPLETED},
- {"disconnected", NM_SUPPLICANT_INTERFACE_STATE_DISCONNECTED},
- {"group_handshake", NM_SUPPLICANT_INTERFACE_STATE_GROUP_HANDSHAKE},
- {"inactive", NM_SUPPLICANT_INTERFACE_STATE_INACTIVE},
- {"interface_disabled", NM_SUPPLICANT_INTERFACE_STATE_DISABLED},
- {"scanning", NM_SUPPLICANT_INTERFACE_STATE_SCANNING}, );
-
-/*****************************************************************************/
-
-static NM80211ApSecurityFlags
-security_from_vardict(GVariant *security)
-{
- NM80211ApSecurityFlags flags = NM_802_11_AP_SEC_NONE;
- const char ** array;
- const char * tmp;
-
- nm_assert(g_variant_is_of_type(security, G_VARIANT_TYPE_VARDICT));
-
- if (g_variant_lookup(security, "KeyMgmt", "^a&s", &array)) {
- if (g_strv_contains(array, "wpa-psk") || g_strv_contains(array, "wpa-ft-psk"))
- flags |= NM_802_11_AP_SEC_KEY_MGMT_PSK;
- if (g_strv_contains(array, "wpa-eap") || g_strv_contains(array, "wpa-ft-eap")
- || g_strv_contains(array, "wpa-fils-sha256")
- || g_strv_contains(array, "wpa-fils-sha384"))
- flags |= NM_802_11_AP_SEC_KEY_MGMT_802_1X;
- if (g_strv_contains(array, "sae"))
- flags |= NM_802_11_AP_SEC_KEY_MGMT_SAE;
- if (g_strv_contains(array, "owe"))
- flags |= NM_802_11_AP_SEC_KEY_MGMT_OWE;
- if (g_strv_contains(array, "wpa-eap-suite-b-192"))
- flags |= NM_802_11_AP_SEC_KEY_MGMT_EAP_SUITE_B_192;
- g_free(array);
- }
-
- if (g_variant_lookup(security, "Pairwise", "^a&s", &array)) {
- if (g_strv_contains(array, "tkip"))
- flags |= NM_802_11_AP_SEC_PAIR_TKIP;
- if (g_strv_contains(array, "ccmp"))
- flags |= NM_802_11_AP_SEC_PAIR_CCMP;
- g_free(array);
- }
-
- if (g_variant_lookup(security, "Group", "&s", &tmp)) {
- if (nm_streq(tmp, "wep40"))
- flags |= NM_802_11_AP_SEC_GROUP_WEP40;
- else if (nm_streq(tmp, "wep104"))
- flags |= NM_802_11_AP_SEC_GROUP_WEP104;
- else if (nm_streq(tmp, "tkip"))
- flags |= NM_802_11_AP_SEC_GROUP_TKIP;
- else if (nm_streq(tmp, "ccmp"))
- flags |= NM_802_11_AP_SEC_GROUP_CCMP;
- }
-
- return flags;
-}
-
-/*****************************************************************************/
-
-/* Various conditions prevent _starting_check_ready() from completing. For example,
- * bss_initializing_lst_head, peer_initializing_lst_head and p2p_group_properties_cancellable.
- * At some places, these conditions might toggle, and it would seems we would have
- * to call _starting_check_ready() at that point, to ensure we don't miss a state
- * change that we are ready. However, these places are deep in the call stack and
- * not suitable to perform this state change. Instead, the callers *MUST* have
- * added their own starting_pending_count to delay _starting_check_ready().
- *
- * Assert that is the case. */
-#define nm_assert_starting_has_pending_count(v) nm_assert((v) > 0)
-
-/*****************************************************************************/
-
-static void
-_dbus_connection_call(NMSupplicantInterface *self,
- const char * interface_name,
- const char * method_name,
- GVariant * parameters,
- const GVariantType * reply_type,
- GDBusCallFlags flags,
- int timeout_msec,
- GCancellable * cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self);
-
- g_dbus_connection_call(priv->dbus_connection,
- priv->name_owner->str,
- priv->object_path->str,
- interface_name,
- method_name,
- parameters,
- reply_type,
- flags,
- timeout_msec,
- cancellable,
- callback,
- user_data);
-}
-
-static void
-_dbus_connection_call_simple_cb(GObject *source, GAsyncResult *result, gpointer user_data)
-{
- NMSupplicantInterface *self;
- gs_unref_variant GVariant *res = NULL;
- gs_free_error GError *error = NULL;
- const char * log_reason;
- gs_free char * remote_error = NULL;
-
- nm_utils_user_data_unpack(user_data, &self, &log_reason);
-
- res = g_dbus_connection_call_finish(G_DBUS_CONNECTION(source), result, &error);
- if (nm_utils_error_is_cancelled(error))
- return;
-
- if (res) {
- _LOGT("call-%s: success", log_reason);
- return;
- }
-
- remote_error = g_dbus_error_get_remote_error(error);
- if (!nm_streq0(remote_error, "fi.w1.wpa_supplicant1.NotConnected")) {
- g_dbus_error_strip_remote_error(error);
- _LOGW("call-%s: failed with %s", log_reason, error->message);
- return;
- }
-
- _LOGT("call-%s: failed with %s", log_reason, error->message);
-}
-
-static void
-_dbus_connection_call_simple(NMSupplicantInterface *self,
- const char * interface_name,
- const char * method_name,
- GVariant * parameters,
- const GVariantType * reply_type,
- const char * log_reason)
-{
- NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self);
-
- _dbus_connection_call(self,
- interface_name,
- method_name,
- parameters,
- reply_type,
- G_DBUS_CALL_FLAGS_NONE,
- DBUS_TIMEOUT_MSEC,
- priv->main_cancellable,
- _dbus_connection_call_simple_cb,
- nm_utils_user_data_pack(self, log_reason));
-}
-
-/*****************************************************************************/
-
-static void
-_emit_signal_state(NMSupplicantInterface * self,
- NMSupplicantInterfaceState new_state,
- NMSupplicantInterfaceState old_state,
- gint32 disconnect_reason)
-{
- g_signal_emit(self,
- signals[STATE],
- 0,
- (int) new_state,
- (int) old_state,
- (int) disconnect_reason);
-}
-
-/*****************************************************************************/
-
-static void
-_remove_network(NMSupplicantInterface *self)
-{
- NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self);
- gs_free char * net_path = NULL;
-
- if (!priv->net_path)
- return;
-
- net_path = g_steal_pointer(&priv->net_path);
- _dbus_connection_call_simple(self,
- NM_WPAS_DBUS_IFACE_INTERFACE,
- "RemoveNetwork",
- g_variant_new("(o)", net_path),
- G_VARIANT_TYPE("()"),
- "remove-network");
-
- if (priv->ap_isolate_supported && priv->ap_isolate_needs_reset) {
- _dbus_connection_call_simple(self,
- DBUS_INTERFACE_PROPERTIES,
- "Set",
- g_variant_new("(ssv)",
- NM_WPAS_DBUS_IFACE_INTERFACE,
- "ApIsolate",
- g_variant_new_string("0")),
- G_VARIANT_TYPE("()"),
- "reset-ap-isolation");
- }
- priv->ap_isolate_needs_reset = FALSE;
-}
-
-/*****************************************************************************/
-
-static void
-_notify_maybe_scanning(NMSupplicantInterface *self)
-{
- NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self);
- gboolean scanning;
-
- scanning = nm_supplicant_interface_state_is_operational(priv->state) && priv->scanning_property;
-
- if (priv->scanning_cached == scanning)
- return;
-
- if (!scanning && !c_list_is_empty(&priv->bss_initializing_lst_head)) {
- /* we would change state to indicate we no longer scan. However,
- * we still have BSS instances to be initialized. Delay the
- * state change further. */
- return;
- }
-
- _LOGT("scanning: %s", scanning ? "yes" : "no");
-
- if (!scanning)
- priv->last_scan_msec = nm_utils_get_monotonic_timestamp_msec();
- else {
- /* while we are scanning, we set the timestamp to -1. */
- priv->last_scan_msec = -1;
- }
- priv->scanning_cached = scanning;
- _notify(self, PROP_SCANNING);
-}
-
-static void
-_notify_maybe_p2p_available(NMSupplicantInterface *self)
-{
- NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self);
- gboolean value;
-
- value = priv->is_ready_p2p_device && priv->p2p_capable_property;
-
- if (priv->p2p_capable_cached == value)
- return;
-
- priv->p2p_capable_cached = value;
- _notify(self, PROP_P2P_AVAILABLE);
-}
-
-static void
-_notify_maybe_p2p_group(NMSupplicantInterface *self)
-{
- NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self);
- gboolean value_joined;
- gboolean value_owner;
- gboolean joined_changed;
- gboolean owner_changed;
-
- value_joined = priv->p2p_group_path && !priv->p2p_group_properties_cancellable;
- value_owner = value_joined && priv->p2p_group_owner_property;
-
- if ((joined_changed = (priv->p2p_group_joined_cached != value_joined)))
- priv->p2p_group_joined_cached = value_joined;
-
- if ((owner_changed = (priv->p2p_group_owner_cached != value_owner)))
- priv->p2p_group_owner_cached = value_owner;
-
- if (joined_changed)
- _notify(self, PROP_P2P_GROUP_JOINED);
- if (owner_changed)
- _notify(self, PROP_P2P_GROUP_OWNER);
-}
-
-/*****************************************************************************/
-
-static void
-_bss_info_destroy(NMSupplicantBssInfo *bss_info)
-{
- c_list_unlink_stale(&bss_info->_bss_lst);
- nm_clear_g_cancellable(&bss_info->_init_cancellable);
- g_bytes_unref(bss_info->ssid);
- nm_ref_string_unref(bss_info->bss_path);
- nm_g_slice_free(bss_info);
-}
-
-static void
-_bss_info_changed_emit(NMSupplicantInterface *self,
- NMSupplicantBssInfo * bss_info,
- gboolean is_present)
-{
- _LOGT("BSS %s %s", bss_info->bss_path->str, is_present ? "updated" : "deleted");
- g_signal_emit(self, signals[BSS_CHANGED], 0, bss_info, is_present);
-}
-
-static void
-_bss_info_properties_changed(NMSupplicantInterface *self,
- NMSupplicantBssInfo * bss_info,
- GVariant * properties,
- gboolean initial)
-{
- gboolean v_b;
- GVariant * v_v;
- const char * v_s;
- gint16 v_i16;
- guint16 v_u16;
- guint32 v_u32;
- NM80211ApFlags p_ap_flags;
- NM80211Mode p_mode;
- guint8 p_signal_percent;
- const guint8 * arr_data;
- gsize arr_len;
- guint32 p_max_rate;
- gboolean p_max_rate_has;
- gint64 now_msec = 0;
-
- if (nm_g_variant_lookup(properties, "Age", "u", &v_u32)) {
- bss_info->last_seen_msec =
- nm_utils_get_monotonic_timestamp_msec_cached(&now_msec) - (((gint64) v_u32) * 1000);
- } else if (initial) {
- /* Unknown Age. Assume we just received it. */
- bss_info->last_seen_msec = nm_utils_get_monotonic_timestamp_msec_cached(&now_msec);
- }
-
- p_ap_flags = bss_info->ap_flags;
- if (nm_g_variant_lookup(properties, "Privacy", "b", &v_b))
- p_ap_flags = NM_FLAGS_ASSIGN(p_ap_flags, NM_802_11_AP_FLAGS_PRIVACY, v_b);
- else {
- nm_assert(!initial || !NM_FLAGS_HAS(p_ap_flags, NM_802_11_AP_FLAGS_PRIVACY));
- }
- v_v = nm_g_variant_lookup_value(properties, "WPS", G_VARIANT_TYPE_VARDICT);
- if (v_v || initial) {
- NM80211ApFlags f = NM_802_11_AP_FLAGS_NONE;
-
- if (v_v) {
- if (g_variant_lookup(v_v, "Type", "&s", &v_s)) {
- f = NM_802_11_AP_FLAGS_WPS;
- if (nm_streq(v_s, "pcb"))
- f |= NM_802_11_AP_FLAGS_WPS_PBC;
- else if (nm_streq(v_s, "pin"))
- f |= NM_802_11_AP_FLAGS_WPS_PIN;
- }
- g_variant_unref(v_v);
- }
- p_ap_flags = NM_FLAGS_ASSIGN_MASK(p_ap_flags,
- NM_802_11_AP_FLAGS_WPS | NM_802_11_AP_FLAGS_WPS_PBC
- | NM_802_11_AP_FLAGS_WPS_PIN,
- f);
- }
- if (bss_info->ap_flags != p_ap_flags) {
- bss_info->ap_flags = p_ap_flags;
- nm_assert(bss_info->ap_flags == p_ap_flags);
- }
-
- if (nm_g_variant_lookup(properties, "Mode", "&s", &v_s)) {
- if (nm_streq(v_s, "infrastructure"))
- p_mode = NM_802_11_MODE_INFRA;
- else if (nm_streq(v_s, "ad-hoc"))
- p_mode = NM_802_11_MODE_ADHOC;
- else if (nm_streq(v_s, "mesh"))
- p_mode = NM_802_11_MODE_MESH;
- else
- p_mode = NM_802_11_MODE_UNKNOWN;
- } else if (initial)
- p_mode = NM_802_11_MODE_UNKNOWN;
- else
- p_mode = bss_info->mode;
- if (bss_info->mode != p_mode) {
- bss_info->mode = p_mode;
- nm_assert(bss_info->mode == p_mode);
- }
-
- if (nm_g_variant_lookup(properties, "Signal", "n", &v_i16))
- p_signal_percent = nm_wifi_utils_level_to_quality(v_i16);
- else if (initial)
- p_signal_percent = 0;
- else
- p_signal_percent = bss_info->signal_percent;
- bss_info->signal_percent = p_signal_percent;
-
- if (nm_g_variant_lookup(properties, "Frequency", "q", &v_u16))
- bss_info->frequency = v_u16;
-
- v_v = nm_g_variant_lookup_value(properties, "SSID", G_VARIANT_TYPE_BYTESTRING);
- if (v_v) {
- arr_data = g_variant_get_fixed_array(v_v, &arr_len, 1);
- arr_len = MIN(32, arr_len);
-
- /* Stupid ieee80211 layer uses <hidden> */
- if (arr_data && arr_len
- && !(NM_IN_SET(arr_len, 8, 9) && memcmp(arr_data, "<hidden>", arr_len) == 0)
- && !nm_utils_is_empty_ssid(arr_data, arr_len)) {
- /* good */
- } else
- arr_len = 0;
-
- if (!nm_utils_gbytes_equal_mem(bss_info->ssid, arr_data, arr_len)) {
- _nm_unused gs_unref_bytes GBytes *old_free = g_steal_pointer(&bss_info->ssid);
-
- bss_info->ssid = (arr_len == 0) ? NULL : g_bytes_new(arr_data, arr_len);
- }
-
- g_variant_unref(v_v);
- } else {
- nm_assert(!initial || !bss_info->ssid);
- }
-
- v_v = nm_g_variant_lookup_value(properties, "BSSID", G_VARIANT_TYPE_BYTESTRING);
- if (v_v) {
- arr_data = g_variant_get_fixed_array(v_v, &arr_len, 1);
- if (arr_len == ETH_ALEN && memcmp(arr_data, &nm_ether_addr_zero, ETH_ALEN) != 0
- && memcmp(arr_data, (char[ETH_ALEN]){0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, ETH_ALEN)
- != 0) {
- /* pass */
- } else
- arr_len = 0;
-
- if (arr_len != 0) {
- nm_assert(arr_len == sizeof(bss_info->bssid));
- bss_info->bssid_valid = TRUE;
- memcpy(&bss_info->bssid, arr_data, sizeof(bss_info->bssid));
- } else if (bss_info->bssid_valid) {
- bss_info->bssid_valid = FALSE;
- memset(&bss_info->bssid, 0, sizeof(bss_info->bssid));
- }
- g_variant_unref(v_v);
- } else {
- nm_assert(!initial || !bss_info->bssid_valid);
- }
- nm_assert((!!bss_info->bssid_valid)
- == (!nm_utils_memeqzero(&bss_info->bssid, sizeof(bss_info->bssid))));
-
- p_max_rate_has = FALSE;
- p_max_rate = 0;
- v_v = nm_g_variant_lookup_value(properties, "Rates", G_VARIANT_TYPE("au"));
- if (v_v) {
- const guint32 *rates = g_variant_get_fixed_array(v_v, &arr_len, sizeof(guint32));
- gsize i;
-
- for (i = 0; i < arr_len; i++)
- p_max_rate = NM_MAX(p_max_rate, rates[i]);
- p_max_rate_has = TRUE;
- g_variant_unref(v_v);
- }
-
- v_v = nm_g_variant_lookup_value(properties, "WPA", G_VARIANT_TYPE_VARDICT);
- if (v_v) {
- bss_info->wpa_flags = security_from_vardict(v_v);
- g_variant_unref(v_v);
- }
-
- v_v = nm_g_variant_lookup_value(properties, "RSN", G_VARIANT_TYPE_VARDICT);
- if (v_v) {
- bss_info->rsn_flags = security_from_vardict(v_v);
- g_variant_unref(v_v);
- }
-
- v_v = nm_g_variant_lookup_value(properties, "IEs", G_VARIANT_TYPE_BYTESTRING);
- if (v_v) {
- gboolean p_owe_transition_mode;
- gboolean p_metered;
- guint32 rate;
-
- arr_data = g_variant_get_fixed_array(v_v, &arr_len, 1);
- nm_wifi_utils_parse_ies(arr_data, arr_len, &rate, &p_metered, &p_owe_transition_mode);
- p_max_rate = NM_MAX(p_max_rate, rate);
- p_max_rate_has = TRUE;
- g_variant_unref(v_v);
-
- if (p_owe_transition_mode)
- bss_info->rsn_flags |= NM_802_11_AP_SEC_KEY_MGMT_OWE_TM;
- else
- bss_info->rsn_flags &= ~NM_802_11_AP_SEC_KEY_MGMT_OWE_TM;
-
- bss_info->metered = p_metered;
- }
-
- if (p_max_rate_has)
- bss_info->max_rate = p_max_rate / 1000u;
-
- _bss_info_changed_emit(self, bss_info, TRUE);
-}
-
-static void
-_bss_info_get_all_cb(GVariant *result, GError *error, gpointer user_data)
-{
- NMSupplicantBssInfo * bss_info;
- NMSupplicantInterface * self;
- NMSupplicantInterfacePrivate *priv;
- gs_unref_variant GVariant *properties = NULL;
-
- if (nm_utils_error_is_cancelled(error))
- return;
-
- bss_info = user_data;
- self = bss_info->_self;
- priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self);
-
- g_clear_object(&bss_info->_init_cancellable);
- nm_c_list_move_tail(&priv->bss_lst_head, &bss_info->_bss_lst);
-
- if (result)
- g_variant_get(result, "(@a{sv})", &properties);
-
- _bss_info_properties_changed(self, bss_info, properties, TRUE);
-
- _starting_check_ready(self);
-
- _notify_maybe_scanning(self);
-}
-
-static void
-_bss_info_add(NMSupplicantInterface *self, const char *object_path)
-{
- NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self);
- nm_auto_ref_string NMRefString *bss_path = NULL;
- NMSupplicantBssInfo * bss_info;
-
- bss_path = nm_ref_string_new(nm_dbus_path_not_empty(object_path));
- if (!bss_path)
- return;
-
- bss_info = g_hash_table_lookup(priv->bss_idx, &bss_path);
- if (bss_info) {
- bss_info->_bss_dirty = FALSE;
- return;
- }
-
- bss_info = g_slice_new(NMSupplicantBssInfo);
- *bss_info = (NMSupplicantBssInfo){
- ._self = self,
- .bss_path = g_steal_pointer(&bss_path),
- ._init_cancellable = g_cancellable_new(),
- };
- c_list_link_tail(&priv->bss_initializing_lst_head, &bss_info->_bss_lst);
- g_hash_table_add(priv->bss_idx, bss_info);
-
- nm_dbus_connection_call_get_all(priv->dbus_connection,
- priv->name_owner->str,
- bss_info->bss_path->str,
- NM_WPAS_DBUS_IFACE_BSS,
- 5000,
- bss_info->_init_cancellable,
- _bss_info_get_all_cb,
- bss_info);
-}
-
-static gboolean
-_bss_info_remove(NMSupplicantInterface *self, NMRefString **p_bss_path)
-{
- NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self);
- NMSupplicantBssInfo * bss_info;
- gpointer unused_but_required;
-
- if (!g_hash_table_steal_extended(priv->bss_idx,
- p_bss_path,
- (gpointer *) &bss_info,
- &unused_but_required))
- return FALSE;
-
- c_list_unlink(&bss_info->_bss_lst);
- if (!bss_info->_init_cancellable)
- _bss_info_changed_emit(self, bss_info, FALSE);
- _bss_info_destroy(bss_info);
-
- nm_assert_starting_has_pending_count(priv->starting_pending_count);
-
- return TRUE;
-}
-
-/*****************************************************************************/
-
-static void
-_peer_info_destroy(NMSupplicantPeerInfo *peer_info)
-{
- c_list_unlink(&peer_info->_peer_lst);
- nm_clear_g_cancellable(&peer_info->_init_cancellable);
-
- g_free(peer_info->device_name);
- g_free(peer_info->manufacturer);
- g_free(peer_info->model);
- g_free(peer_info->model_number);
- g_free(peer_info->serial);
- g_free(peer_info->groups);
- g_bytes_unref(peer_info->ies);
-
- nm_ref_string_unref(peer_info->peer_path);
-
- nm_g_slice_free(peer_info);
-}
-
-static void
-_peer_info_changed_emit(NMSupplicantInterface *self,
- NMSupplicantPeerInfo * peer_info,
- gboolean is_present)
-{
- g_signal_emit(self, signals[PEER_CHANGED], 0, peer_info, is_present);
-}
-
-static void
-_peer_info_properties_changed(NMSupplicantInterface *self,
- NMSupplicantPeerInfo * peer_info,
- GVariant * properties,
- gboolean initial)
-{
- GVariant * v_v;
- const char * v_s;
- const char ** v_strv;
- gint32 v_i32;
- const guint8 *arr_data;
- gsize arr_len;
-
- peer_info->last_seen_msec = nm_utils_get_monotonic_timestamp_msec();
-
- if (nm_g_variant_lookup(properties, "level", "i", &v_i32))
- peer_info->signal_percent = nm_wifi_utils_level_to_quality(v_i32);
-
- if (nm_g_variant_lookup(properties, "DeviceName", "&s", &v_s))
- nm_utils_strdup_reset(&peer_info->device_name, v_s);
-
- if (nm_g_variant_lookup(properties, "Manufacturer", "&s", &v_s))
- nm_utils_strdup_reset(&peer_info->manufacturer, v_s);
-
- if (nm_g_variant_lookup(properties, "Model", "&s", &v_s))
- nm_utils_strdup_reset(&peer_info->model, v_s);
-
- if (nm_g_variant_lookup(properties, "ModelNumber", "&s", &v_s))
- nm_utils_strdup_reset(&peer_info->model_number, v_s);
-
- if (nm_g_variant_lookup(properties, "Serial", "&s", &v_s))
- nm_utils_strdup_reset(&peer_info->serial, v_s);
-
- if (nm_g_variant_lookup(properties, "Groups", "^a&o", &v_strv)) {
- g_free(peer_info->groups);
- peer_info->groups = nm_utils_strv_dup_packed(v_strv, -1);
-
- g_free(v_strv);
- }
-
- v_v = nm_g_variant_lookup_value(properties, "DeviceAddress", G_VARIANT_TYPE_BYTESTRING);
- if (v_v) {
- arr_data = g_variant_get_fixed_array(v_v, &arr_len, 1);
- if (arr_len == ETH_ALEN && memcmp(arr_data, &nm_ether_addr_zero, ETH_ALEN) != 0
- && memcmp(arr_data, (char[ETH_ALEN]){0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, ETH_ALEN)
- != 0) {
- /* pass */
- } else
- arr_len = 0;
-
- if (arr_len != 0) {
- nm_assert(arr_len == sizeof(peer_info->address));
- peer_info->address_valid = TRUE;
- memcpy(peer_info->address, arr_data, sizeof(peer_info->address));
- } else if (peer_info->address_valid) {
- peer_info->address_valid = FALSE;
- memset(peer_info->address, 0, sizeof(peer_info->address));
- }
- g_variant_unref(v_v);
- } else {
- nm_assert(!initial || !peer_info->address_valid);
- }
- nm_assert((peer_info->address_valid
- && !nm_utils_memeqzero(peer_info->address, sizeof(peer_info->address)))
- || (!peer_info->address_valid
- && nm_utils_memeqzero(peer_info->address, sizeof(peer_info->address))));
-
- /* The IEs property contains the WFD R1 subelements */
- v_v = nm_g_variant_lookup_value(properties, "IEs", G_VARIANT_TYPE_BYTESTRING);
- if (v_v) {
- arr_data = g_variant_get_fixed_array(v_v, &arr_len, 1);
- if (!nm_utils_gbytes_equal_mem(peer_info->ies, arr_data, arr_len)) {
- _nm_unused gs_unref_bytes GBytes *old_free = g_steal_pointer(&peer_info->ies);
-
- peer_info->ies = g_bytes_new(arr_data, arr_len);
- } else if (arr_len == 0 && !peer_info->ies)
- peer_info->ies = g_bytes_new(NULL, 0);
- g_variant_unref(v_v);
- }
-
- _peer_info_changed_emit(self, peer_info, TRUE);
-}
-
-static void
-_peer_info_get_all_cb(GVariant *result, GError *error, gpointer user_data)
-{
- NMSupplicantPeerInfo * peer_info;
- NMSupplicantInterface * self;
- NMSupplicantInterfacePrivate *priv;
- gs_unref_variant GVariant *properties = NULL;
-
- if (nm_utils_error_is_cancelled(error))
- return;
-
- peer_info = user_data;
- self = peer_info->_self;
- priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self);
-
- g_clear_object(&peer_info->_init_cancellable);
- nm_c_list_move_tail(&priv->peer_lst_head, &peer_info->_peer_lst);
-
- if (result)
- g_variant_get(result, "(@a{sv})", &properties);
-
- _peer_info_properties_changed(self, peer_info, properties, TRUE);
-
- _starting_check_ready(self);
-}
-
-static void
-_peer_info_add(NMSupplicantInterface *self, const char *object_path)
-{
- NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self);
- nm_auto_ref_string NMRefString *peer_path = NULL;
- NMSupplicantPeerInfo * peer_info;
-
- peer_path = nm_ref_string_new(nm_dbus_path_not_empty(object_path));
- if (!peer_path)
- return;
-
- peer_info = g_hash_table_lookup(priv->peer_idx, &peer_path);
-
- if (peer_info) {
- peer_info->_peer_dirty = FALSE;
- return;
- }
-
- peer_info = g_slice_new(NMSupplicantPeerInfo);
- *peer_info = (NMSupplicantPeerInfo){
- ._self = self,
- .peer_path = g_steal_pointer(&peer_path),
- ._init_cancellable = g_cancellable_new(),
- };
- c_list_link_tail(&priv->peer_initializing_lst_head, &peer_info->_peer_lst);
- g_hash_table_add(priv->peer_idx, peer_info);
-
- nm_dbus_connection_call_get_all(priv->dbus_connection,
- priv->name_owner->str,
- peer_info->peer_path->str,
- NM_WPAS_DBUS_IFACE_PEER,
- 5000,
- peer_info->_init_cancellable,
- _peer_info_get_all_cb,
- peer_info);
-}
-
-static gboolean
-_peer_info_remove(NMSupplicantInterface *self, NMRefString **p_peer_path)
-{
- NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self);
- NMSupplicantPeerInfo * peer_info;
- gpointer unused_but_required;
-
- if (!g_hash_table_steal_extended(priv->peer_idx,
- p_peer_path,
- (gpointer *) &peer_info,
- &unused_but_required))
- return FALSE;
-
- c_list_unlink(&peer_info->_peer_lst);
- if (!peer_info->_init_cancellable)
- _peer_info_changed_emit(self, peer_info, FALSE);
- _peer_info_destroy(peer_info);
-
- nm_assert_starting_has_pending_count(priv->starting_pending_count);
-
- return TRUE;
-}
-
-/*****************************************************************************/
-
-static void
-set_state_down(NMSupplicantInterface *self,
- gboolean force_remove_from_supplicant,
- const char * reason)
-{
- _nm_unused gs_unref_object NMSupplicantInterface *self_keep_alive = g_object_ref(self);
- NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self);
- NMSupplicantBssInfo * bss_info;
- NMSupplicantPeerInfo * peer_info;
- NMSupplicantInterfaceState old_state;
-
- nm_assert(priv->state != NM_SUPPLICANT_INTERFACE_STATE_DOWN);
- nm_assert(!c_list_is_empty(&self->supp_lst));
-
- _LOGD("remove interface \"%s\" on %s (%s)%s",
- priv->object_path->str,
- priv->name_owner->str,
- reason,
- force_remove_from_supplicant ? " (remove in wpa_supplicant)" : "");
-
- old_state = priv->state;
-
- priv->state = NM_SUPPLICANT_INTERFACE_STATE_DOWN;
-
- _nm_supplicant_manager_unregister_interface(priv->supplicant_manager, self);
-
- nm_assert(c_list_is_empty(&self->supp_lst));
-
- if (force_remove_from_supplicant) {
- _nm_supplicant_manager_dbus_call_remove_interface(priv->supplicant_manager,
- priv->name_owner->str,
- priv->object_path->str);
- }
-
- _emit_signal_state(self, priv->state, old_state, 0);
-
- nm_clear_g_dbus_connection_signal(priv->dbus_connection, &priv->properties_changed_id);
- nm_clear_g_dbus_connection_signal(priv->dbus_connection, &priv->signal_id);
- nm_clear_g_dbus_connection_signal(priv->dbus_connection, &priv->bss_properties_changed_id);
- nm_clear_g_dbus_connection_signal(priv->dbus_connection, &priv->peer_properties_changed_id);
- nm_clear_g_dbus_connection_signal(priv->dbus_connection,
- &priv->p2p_group_properties_changed_id);
-
- nm_supplicant_interface_cancel_wps(self);
-
- if (priv->assoc_data) {
- gs_free_error GError *error = NULL;
-
- nm_utils_error_set_cancelled(&error, TRUE, "NMSupplicantInterface");
- assoc_return(self, error, "cancelled because supplicant interface is going down");
- }
-
- while (
- (bss_info =
- c_list_first_entry(&priv->bss_initializing_lst_head, NMSupplicantBssInfo, _bss_lst))) {
- g_hash_table_remove(priv->bss_idx, bss_info);
- _bss_info_destroy(bss_info);
- }
- while ((bss_info = c_list_first_entry(&priv->bss_lst_head, NMSupplicantBssInfo, _bss_lst))) {
- g_hash_table_remove(priv->bss_idx, bss_info);
- _bss_info_destroy(bss_info);
- }
- nm_assert(g_hash_table_size(priv->bss_idx) == 0);
-
- while ((peer_info = c_list_first_entry(&priv->peer_initializing_lst_head,
- NMSupplicantPeerInfo,
- _peer_lst))) {
- g_hash_table_remove(priv->peer_idx, peer_info);
- _peer_info_destroy(peer_info);
- }
- while (
- (peer_info = c_list_first_entry(&priv->peer_lst_head, NMSupplicantPeerInfo, _peer_lst))) {
- g_hash_table_remove(priv->peer_idx, peer_info);
- _peer_info_destroy(peer_info);
- }
- nm_assert(g_hash_table_size(priv->peer_idx) == 0);
-
- nm_clear_g_cancellable(&priv->main_cancellable);
- nm_clear_g_cancellable(&priv->p2p_group_properties_cancellable);
-
- nm_clear_pointer(&priv->p2p_group_path, nm_ref_string_unref);
-
- _remove_network(self);
-
- nm_clear_pointer(&priv->current_bss, nm_ref_string_unref);
-
- _notify_maybe_scanning(self);
-}
-
-static void
-set_state(NMSupplicantInterface *self, NMSupplicantInterfaceState new_state)
-{
- NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self);
- NMSupplicantInterfaceState old_state = priv->state;
-
- nm_assert(new_state > NM_SUPPLICANT_INTERFACE_STATE_STARTING);
- nm_assert(new_state < NM_SUPPLICANT_INTERFACE_STATE_DOWN);
- nm_assert(nm_supplicant_interface_state_is_operational(new_state));
-
- nm_assert(priv->state >= NM_SUPPLICANT_INTERFACE_STATE_STARTING);
- nm_assert(priv->state < NM_SUPPLICANT_INTERFACE_STATE_DOWN);
-
- if (new_state == priv->state)
- return;
-
- _LOGT("state: set state \"%s\" (was \"%s\")",
- nm_supplicant_interface_state_to_string(new_state),
- nm_supplicant_interface_state_to_string(priv->state));
-
- priv->state = new_state;
-
- _emit_signal_state(
- self,
- priv->state,
- old_state,
- priv->state != NM_SUPPLICANT_INTERFACE_STATE_DISCONNECTED ? 0u : priv->disconnect_reason);
-}
-
-NMRefString *
-nm_supplicant_interface_get_current_bss(NMSupplicantInterface *self)
-{
- g_return_val_if_fail(self != NULL, FALSE);
-
- return NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self)->current_bss;
-}
-
-gboolean
-nm_supplicant_interface_get_scanning(NMSupplicantInterface *self)
-{
- g_return_val_if_fail(NM_IS_SUPPLICANT_INTERFACE(self), FALSE);
-
- return NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self)->scanning_cached;
-}
-
-gint64
-nm_supplicant_interface_get_last_scan(NMSupplicantInterface *self)
-{
- g_return_val_if_fail(NM_IS_SUPPLICANT_INTERFACE(self), FALSE);
-
- return NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self)->last_scan_msec;
-}
-
-#define MATCH_PROPERTY(p, n, v, t) (!strcmp(p, n) && g_variant_is_of_type(v, t))
-
-static void
-parse_capabilities(NMSupplicantInterface *self, GVariant *capabilities)
-{
- NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self);
- const gboolean old_prop_scan_active = priv->prop_scan_active;
- const gboolean old_prop_scan_ssid = priv->prop_scan_ssid;
- const guint32 old_max_scan_ssids = priv->max_scan_ssids;
- gboolean have_ft = FALSE;
- gint32 max_scan_ssids;
- const char ** array;
-
- nm_assert(capabilities && g_variant_is_of_type(capabilities, G_VARIANT_TYPE_VARDICT));
-
- if (g_variant_lookup(capabilities, "KeyMgmt", "^a&s", &array)) {
- have_ft = g_strv_contains(array, "wpa-ft-psk");
- g_free(array);
- }
-
- priv->iface_capabilities = NM_SUPPL_CAP_MASK_SET(priv->iface_capabilities,
- NM_SUPPL_CAP_TYPE_FT,
- have_ft ? NM_TERNARY_TRUE : NM_TERNARY_FALSE);
-
- if (g_variant_lookup(capabilities, "Modes", "^a&s", &array)) {
- /* Setting p2p_capable might toggle _prop_p2p_available_get(). However,
- * we don't need to check for a property changed notification, because
- * the caller did g_object_freeze_notify() and will perform the check. */
- priv->p2p_capable_property = g_strv_contains(array, "p2p");
- g_free(array);
- }
-
- if (g_variant_lookup(capabilities, "Scan", "^a&s", &array)) {
- const char **a;
-
- priv->prop_scan_active = FALSE;
- priv->prop_scan_ssid = FALSE;
- for (a = array; *a; a++) {
- if (nm_streq(*a, "active"))
- priv->prop_scan_active = TRUE;
- else if (nm_streq(*a, "ssid"))
- priv->prop_scan_ssid = TRUE;
- }
- g_free(array);
- }
-
- if (g_variant_lookup(capabilities, "MaxScanSSID", "i", &max_scan_ssids)) {
- const gint32 WPAS_MAX_SCAN_SSIDS = 16;
-
- /* Even if supplicant claims that 20 SSIDs are supported, the Scan request
- * still only accepts WPAS_MAX_SCAN_SSIDS SSIDs. Otherwise, the D-Bus
- * request will be rejected with "fi.w1.wpa_supplicant1.InvalidArgs"
- * Body: ('Did not receive correct message arguments.', 'Too many ssids specified. Specify at most four')
- * */
- priv->max_scan_ssids = CLAMP(max_scan_ssids, 0, WPAS_MAX_SCAN_SSIDS);
- }
-
- if (old_max_scan_ssids != priv->max_scan_ssids || old_prop_scan_active != priv->prop_scan_active
- || old_prop_scan_ssid != priv->prop_scan_ssid) {
- _LOGD("supports %u scan SSIDs (scan: %cactive %cssid)",
- (guint32) priv->max_scan_ssids,
- priv->prop_scan_active ? '+' : '-',
- priv->prop_scan_ssid ? '+' : '-');
- }
-}
-
-static void
-_starting_check_ready(NMSupplicantInterface *self)
-{
- NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self);
-
- if (priv->state != NM_SUPPLICANT_INTERFACE_STATE_STARTING)
- return;
-
- if (priv->starting_pending_count > 0)
- return;
-
- if (!c_list_is_empty(&priv->bss_initializing_lst_head))
- return;
-
- if (!c_list_is_empty(&priv->peer_initializing_lst_head))
- return;
-
- if (priv->p2p_group_properties_cancellable)
- return;
-
- nm_assert(priv->state == NM_SUPPLICANT_INTERFACE_STATE_STARTING);
-
- if (!nm_supplicant_interface_state_is_operational(priv->supp_state)) {
- _LOGW("Supplicant state is unknown during initialization. Destroy the interface");
- set_state_down(self, TRUE, "failure to get valid interface state");
- return;
- }
-
- set_state(self, priv->supp_state);
-}
-
-static NMTernary
-_get_capability(NMSupplicantInterfacePrivate *priv, NMSupplCapType type)
-{
- NMTernary value;
- NMTernary iface_value;
-
- switch (type) {
- case NM_SUPPL_CAP_TYPE_AP:
- iface_value = NM_SUPPL_CAP_MASK_GET(priv->iface_capabilities, type);
- value = NM_SUPPL_CAP_MASK_GET(priv->global_capabilities, type);
- value = MAX(iface_value, value);
- break;
- case NM_SUPPL_CAP_TYPE_FT:
- value = NM_SUPPL_CAP_MASK_GET(priv->global_capabilities, type);
- if (value != NM_TERNARY_FALSE) {
- iface_value = NM_SUPPL_CAP_MASK_GET(priv->iface_capabilities, type);
- if (iface_value != NM_TERNARY_DEFAULT)
- value = iface_value;
- }
- break;
- default:
- nm_assert(NM_SUPPL_CAP_MASK_GET(priv->iface_capabilities, type) == NM_TERNARY_DEFAULT);
- value = NM_SUPPL_CAP_MASK_GET(priv->global_capabilities, type);
- break;
- }
- return value;
-}
-
-NMTernary
-nm_supplicant_interface_get_capability(NMSupplicantInterface *self, NMSupplCapType type)
-{
- return _get_capability(NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self), type);
-}
-
-NMSupplCapMask
-nm_supplicant_interface_get_capabilities(NMSupplicantInterface *self)
-{
- NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self);
- NMSupplCapMask caps;
-
- caps = priv->global_capabilities;
- caps = NM_SUPPL_CAP_MASK_SET(caps,
- NM_SUPPL_CAP_TYPE_AP,
- _get_capability(priv, NM_SUPPL_CAP_TYPE_AP));
- caps = NM_SUPPL_CAP_MASK_SET(caps,
- NM_SUPPL_CAP_TYPE_FT,
- _get_capability(priv, NM_SUPPL_CAP_TYPE_FT));
-
- nm_assert(!NM_FLAGS_ANY(priv->iface_capabilities,
- ~(NM_SUPPL_CAP_MASK_T_AP_MASK | NM_SUPPL_CAP_MASK_T_FT_MASK)));
-
-#if NM_MORE_ASSERTS > 10
- {
- NMSupplCapType type;
-
- for (type = 0; type < _NM_SUPPL_CAP_TYPE_NUM; type++)
- nm_assert(NM_SUPPL_CAP_MASK_GET(caps, type) == _get_capability(priv, type));
- }
-#endif
-
- return caps;
-}
-
-static void
-set_bridge_cb(GVariant *ret, GError *error, gpointer user_data)
-{
- NMSupplicantInterface *self;
- NMLogLevel level;
- gs_free const char * bridge = NULL;
-
- nm_utils_user_data_unpack(user_data, &self, &bridge);
-
- if (nm_utils_error_is_cancelled(error))
- return;
-
- /* The supplicant supports writing the bridge property since
- * version 2.10. Before that version, trying to set the property
- * results in a InvalidArgs error. Don't log a warning unless we
- * are trying to set a non-NULL bridge. */
- if (!error)
- level = LOGL_DEBUG;
- else if (bridge == NULL && g_error_matches(error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS)) {
- level = LOGL_DEBUG;
- } else
- level = LOGL_WARN;
-
- _NMLOG(level,
- "set bridge %s%s%s result: %s",
- NM_PRINT_FMT_QUOTE_STRING(bridge),
- error ? error->message : "success");
-}
-
-void
-nm_supplicant_interface_set_bridge(NMSupplicantInterface *self, const char *bridge)
-{
- NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self);
-
- _LOGT("set bridge %s%s%s", NM_PRINT_FMT_QUOTE_STRING(bridge));
-
- nm_dbus_connection_call_set(priv->dbus_connection,
- priv->name_owner->str,
- priv->object_path->str,
- NM_WPAS_DBUS_IFACE_INTERFACE,
- "BridgeIfname",
- g_variant_new_string(bridge ?: ""),
- DBUS_TIMEOUT_MSEC,
- priv->main_cancellable,
- set_bridge_cb,
- nm_utils_user_data_pack(self, g_strdup(bridge)));
-}
-
-void
-nm_supplicant_interface_set_global_capabilities(NMSupplicantInterface *self, NMSupplCapMask value)
-{
- NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self);
-
- priv->global_capabilities = value;
-}
-
-NMSupplicantAuthState
-nm_supplicant_interface_get_auth_state(NMSupplicantInterface *self)
-{
- return NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self)->auth_state;
-}
-
-/*****************************************************************************/
-
-static void
-_p2p_group_properties_changed(NMSupplicantInterface *self, GVariant *properties)
-{
- NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self);
- const char * s;
-
- if (!properties)
- priv->p2p_group_owner_property = FALSE;
- else if (g_variant_lookup(properties, "Role", "&s", &s))
- priv->p2p_group_owner_property = nm_streq(s, "GO");
-
- _notify_maybe_p2p_group(self);
-}
-
-static void
-_p2p_group_properties_changed_cb(GDBusConnection *connection,
- const char * sender_name,
- const char * object_path,
- const char * signal_interface_name,
- const char * signal_name,
- GVariant * parameters,
- gpointer user_data)
-{
- NMSupplicantInterface * self = NM_SUPPLICANT_INTERFACE(user_data);
- NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self);
- gs_unref_variant GVariant *changed_properties = NULL;
-
- if (priv->p2p_group_properties_cancellable)
- return;
- if (!g_variant_is_of_type(parameters, G_VARIANT_TYPE("(sa{sv}as)")))
- return;
-
- g_variant_get(parameters, "(&s@a{sv}^a&s)", NULL, &changed_properties, NULL);
-
- _p2p_group_properties_changed(self, changed_properties);
-}
-
-static void
-_p2p_group_properties_get_all_cb(GVariant *result, GError *error, gpointer user_data)
-{
- NMSupplicantInterface * self;
- NMSupplicantInterfacePrivate *priv;
- gs_unref_variant GVariant *properties = NULL;
-
- if (nm_utils_error_is_cancelled(error))
- return;
-
- self = NM_SUPPLICANT_INTERFACE(user_data);
- priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self);
-
- g_object_freeze_notify(G_OBJECT(self));
-
- nm_clear_g_cancellable(&priv->p2p_group_properties_cancellable);
-
- if (result)
- g_variant_get(result, "(@a{sv})", &properties);
-
- _p2p_group_properties_changed(self, properties);
-
- _starting_check_ready(self);
-
- _notify_maybe_p2p_group(self);
-
- g_object_thaw_notify(G_OBJECT(self));
-}
-
-static void
-_p2p_group_set_path(NMSupplicantInterface *self, const char *path)
-{
- NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self);
- nm_auto_ref_string NMRefString *group_path = NULL;
-
- group_path = nm_ref_string_new(nm_dbus_path_not_empty(path));
-
- if (priv->p2p_group_path == group_path)
- return;
-
- nm_clear_g_dbus_connection_signal(priv->dbus_connection,
- &priv->p2p_group_properties_changed_id);
- nm_clear_g_cancellable(&priv->p2p_group_properties_cancellable);
-
- nm_ref_string_unref(priv->p2p_group_path);
- priv->p2p_group_path = g_steal_pointer(&group_path);
-
- if (priv->p2p_group_path) {
- priv->p2p_group_properties_cancellable = g_cancellable_new();
- priv->p2p_group_properties_changed_id =
- nm_dbus_connection_signal_subscribe_properties_changed(priv->dbus_connection,
- priv->name_owner->str,
- priv->p2p_group_path->str,
- NM_WPAS_DBUS_IFACE_GROUP,
- _p2p_group_properties_changed_cb,
- self,
- NULL);
- nm_dbus_connection_call_get_all(priv->dbus_connection,
- priv->name_owner->str,
- priv->p2p_group_path->str,
- NM_WPAS_DBUS_IFACE_GROUP,
- 5000,
- priv->p2p_group_properties_cancellable,
- _p2p_group_properties_get_all_cb,
- self);
- }
-
- _notify(self, PROP_P2P_GROUP_PATH);
- _notify_maybe_p2p_group(self);
-
- nm_assert_starting_has_pending_count(priv->starting_pending_count);
-}
-
-/*****************************************************************************/
-
-static void
-_wps_data_free(WpsData *wps_data, GDBusConnection *dbus_connection)
-{
- nm_clear_g_dbus_connection_signal(dbus_connection, &wps_data->signal_id);
- nm_clear_g_cancellable(&wps_data->cancellable);
- g_free(wps_data->type);
- g_free(wps_data->pin);
- g_free(wps_data->bssid);
- nm_g_slice_free(wps_data);
-}
-
-static void
-_wps_credentials_changed_cb(GDBusConnection *connection,
- const char * sender_name,
- const char * object_path,
- const char * signal_interface_name,
- const char * signal_name,
- GVariant * parameters,
- gpointer user_data)
-{
- NMSupplicantInterface *self = user_data;
- gs_unref_variant GVariant *props = NULL;
-
- if (!g_variant_is_of_type(parameters, G_VARIANT_TYPE("(a{sv})")))
- return;
-
- g_variant_get(parameters, "(@a{sv})", &props);
-
- _LOGT("wps: new credentials");
- g_signal_emit(self, signals[WPS_CREDENTIALS], 0, props);
-}
-
-static void
-_wps_handle_start_cb(GObject *source, GAsyncResult *result, gpointer user_data)
-{
- NMSupplicantInterface *self;
- WpsData * wps_data;
- gs_unref_variant GVariant *res = NULL;
- gs_free_error GError *error = NULL;
-
- res = g_dbus_connection_call_finish(G_DBUS_CONNECTION(source), result, &error);
- if (nm_utils_error_is_cancelled(error))
- return;
-
- wps_data = user_data;
- self = wps_data->self;
-
- if (res)
- _LOGT("wps: started with success");
- else
- _LOGW("wps: start failed with %s", error->message);
-
- g_clear_object(&wps_data->cancellable);
- nm_clear_g_free(&wps_data->type);
- nm_clear_g_free(&wps_data->pin);
- nm_clear_g_free(&wps_data->bssid);
-}
-
-static void
-_wps_handle_set_pc_cb(GVariant *res, GError *error, gpointer user_data)
-{
- NMSupplicantInterface * self;
- NMSupplicantInterfacePrivate *priv;
- WpsData * wps_data;
- GVariantBuilder start_args;
- guint8 bssid_buf[ETH_ALEN];
-
- if (nm_utils_error_is_cancelled(error))
- return;
-
- wps_data = user_data;
- self = wps_data->self;
- priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self);
-
- if (res)
- _LOGT("wps: ProcessCredentials successfully set, starting...");
- else
- _LOGW("wps: ProcessCredentials failed to set (%s), starting...", error->message);
-
- wps_data->signal_id = g_dbus_connection_signal_subscribe(priv->dbus_connection,
- priv->name_owner->str,
- NM_WPAS_DBUS_IFACE_INTERFACE_WPS,
- "Credentials",
- priv->object_path->str,
- NULL,
- G_DBUS_SIGNAL_FLAGS_NONE,
- _wps_credentials_changed_cb,
- self,
- NULL);
-
- g_variant_builder_init(&start_args, G_VARIANT_TYPE_VARDICT);
- g_variant_builder_add(&start_args, "{sv}", "Role", g_variant_new_string("enrollee"));
- g_variant_builder_add(&start_args, "{sv}", "Type", g_variant_new_string(wps_data->type));
- if (wps_data->pin)
- g_variant_builder_add(&start_args, "{sv}", "Pin", g_variant_new_string(wps_data->pin));
- if (wps_data->bssid) {
- /* The BSSID is in fact not mandatory. If it is not set the supplicant would
- * enroll with any BSS in range. */
- if (!nm_utils_hwaddr_aton(wps_data->bssid, bssid_buf, sizeof(bssid_buf)))
- nm_assert_not_reached();
- g_variant_builder_add(
- &start_args,
- "{sv}",
- "Bssid",
- g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, bssid_buf, ETH_ALEN, sizeof(guint8)));
- }
-
- wps_data->needs_cancelling = TRUE;
- if (!wps_data->cancellable)
- wps_data->cancellable = g_cancellable_new();
-
- _dbus_connection_call(self,
- NM_WPAS_DBUS_IFACE_INTERFACE_WPS,
- "Start",
- g_variant_new("(a{sv})", &start_args),
- G_VARIANT_TYPE("(a{sv})"),
- G_DBUS_CALL_FLAGS_NONE,
- 5000,
- wps_data->cancellable,
- _wps_handle_start_cb,
- wps_data);
-}
-
-static void
-_wps_call_set_pc(NMSupplicantInterface *self, WpsData *wps_data)
-{
- NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self);
-
- if (!wps_data->cancellable)
- wps_data->cancellable = g_cancellable_new();
-
- nm_dbus_connection_call_set(priv->dbus_connection,
- priv->name_owner->str,
- priv->object_path->str,
- NM_WPAS_DBUS_IFACE_INTERFACE_WPS,
- "ProcessCredentials",
- g_variant_new_boolean(TRUE),
- 5000,
- wps_data->cancellable,
- _wps_handle_set_pc_cb,
- wps_data);
-}
-
-static void
-_wps_handle_cancel_cb(GObject *source, GAsyncResult *result, gpointer user_data)
-{
- GDBusConnection * dbus_connection = G_DBUS_CONNECTION(source);
- NMSupplicantInterface * self;
- NMSupplicantInterfacePrivate *priv;
- WpsData * wps_data;
- gs_unref_variant GVariant *res = NULL;
- gs_free_error GError *error = NULL;
-
- res = g_dbus_connection_call_finish(dbus_connection, result, &error);
- nm_assert(!nm_utils_error_is_cancelled(error));
-
- wps_data = user_data;
- self = wps_data->self;
-
- if (!self) {
- _wps_data_free(wps_data, dbus_connection);
- if (res)
- _LOGT("wps: cancel completed successfully, after supplicant interface is gone");
- else
- _LOGW("wps: cancel failed (%s), after supplicant interface is gone", error->message);
- return;
- }
-
- priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self);
-
- wps_data->is_cancelling = FALSE;
-
- if (!wps_data->type) {
- priv->wps_data = NULL;
- _wps_data_free(wps_data, dbus_connection);
- if (res)
- _LOGT("wps: cancel completed successfully");
- else
- _LOGW("wps: cancel failed (%s)", error->message);
- return;
- }
-
- if (res)
- _LOGT("wps: cancel completed successfully, setting ProcessCredentials now...");
- else
- _LOGW("wps: cancel failed (%s), setting ProcessCredentials now...", error->message);
-
- _wps_call_set_pc(self, wps_data);
-}
-
-static void
-_wps_start(NMSupplicantInterface *self, const char *type, const char *bssid, const char *pin)
-{
- NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self);
- WpsData * wps_data;
-
- if (type)
- _LOGI("wps: type %s start...", type);
-
- wps_data = priv->wps_data;
-
- if (!wps_data) {
- if (!type)
- return;
-
- if (priv->state == NM_SUPPLICANT_INTERFACE_STATE_DOWN) {
- _LOGD("wps: interface is down. Cannot start with WPS");
- return;
- }
-
- wps_data = g_slice_new(WpsData);
- *wps_data = (WpsData){
- .self = self,
- .type = g_strdup(type),
- .bssid = g_strdup(bssid),
- .pin = g_strdup(pin),
- };
- priv->wps_data = wps_data;
- } else {
- g_free(wps_data->type);
- g_free(wps_data->bssid);
- g_free(wps_data->pin);
- wps_data->type = g_strdup(type);
- wps_data->bssid = g_strdup(bssid);
- wps_data->pin = g_strdup(pin);
- }
-
- if (wps_data->is_cancelling) {
- /* we wait for cancellation to complete. */
- return;
- }
-
- if (!type || wps_data->needs_cancelling) {
- _LOGT("wps: cancel %senrollment...", wps_data->needs_cancelling ? "previous " : "");
-
- wps_data->is_cancelling = TRUE;
- wps_data->needs_cancelling = FALSE;
- nm_clear_g_cancellable(&wps_data->cancellable);
- nm_clear_g_dbus_connection_signal(priv->dbus_connection, &wps_data->signal_id);
-
- _dbus_connection_call(self,
- NM_WPAS_DBUS_IFACE_INTERFACE_WPS,
- "Cancel",
- NULL,
- G_VARIANT_TYPE("()"),
- G_DBUS_CALL_FLAGS_NONE,
- 5000,
- NULL,
- _wps_handle_cancel_cb,
- wps_data);
- return;
- }
-
- _LOGT("wps: setting ProcessCredentials...");
- _wps_call_set_pc(self, wps_data);
-}
-
-void
-nm_supplicant_interface_enroll_wps(NMSupplicantInterface *self,
- const char * type,
- const char * bssid,
- const char * pin)
-{
- _wps_start(self, type, bssid, pin);
-}
-
-void
-nm_supplicant_interface_cancel_wps(NMSupplicantInterface *self)
-{
- _wps_start(self, NULL, NULL, NULL);
-}
-
-/*****************************************************************************/
-
-static void
-iface_introspect_cb(GObject *source, GAsyncResult *result, gpointer user_data)
-{
- NMSupplicantInterface * self;
- NMSupplicantInterfacePrivate *priv;
- gs_unref_variant GVariant *res = NULL;
- gs_free_error GError *error = NULL;
- const char * data;
- NMTernary value;
-
- res = g_dbus_connection_call_finish(G_DBUS_CONNECTION(source), result, &error);
- if (nm_utils_error_is_cancelled(error))
- return;
-
- self = NM_SUPPLICANT_INTERFACE(user_data);
- priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self);
-
- nm_assert(NM_SUPPL_CAP_MASK_GET(priv->global_capabilities, NM_SUPPL_CAP_TYPE_AP)
- == NM_TERNARY_DEFAULT);
-
- value = NM_TERNARY_DEFAULT;
- if (res) {
- g_variant_get(res, "(&s)", &data);
-
- /* The ProbeRequest method only exists if AP mode has been enabled */
- value = strstr(data, "ProbeRequest") ? NM_TERNARY_TRUE : NM_TERNARY_FALSE;
- }
-
- priv->iface_capabilities =
- NM_SUPPL_CAP_MASK_SET(priv->iface_capabilities, NM_SUPPL_CAP_TYPE_AP, value);
-
- priv->starting_pending_count--;
- _starting_check_ready(self);
-}
-
-static void
-_properties_changed_main(NMSupplicantInterface *self, GVariant *properties)
-{
- NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self);
- const char ** v_strv;
- const char * v_s;
- gboolean v_b;
- gint32 v_i32;
- GVariant * v_v;
- gboolean do_log_driver_info = FALSE;
- gboolean do_set_state = FALSE;
- gboolean do_notify_current_bss = FALSE;
-
- nm_assert(properties || g_variant_is_of_type(properties, G_VARIANT_TYPE("a{sv}")));
-
- v_v = g_variant_lookup_value(properties, "Capabilities", G_VARIANT_TYPE_VARDICT);
- if (v_v) {
- parse_capabilities(self, v_v);
- g_variant_unref(v_v);
- }
-
- if (nm_g_variant_lookup(properties, "Scanning", "b", &v_b)) {
- if (priv->scanning_property != (!!v_b)) {
- _LOGT("scanning: %s (plain property)", v_b ? "yes" : "no");
- priv->scanning_property = v_b;
- }
- }
-
- if (nm_g_variant_lookup(properties, "Ifname", "&s", &v_s)) {
- if (nm_utils_strdup_reset(&priv->ifname, v_s))
- do_log_driver_info = TRUE;
- }
- if (nm_g_variant_lookup(properties, "Driver", "&s", &v_s)) {
- if (nm_utils_strdup_reset(&priv->driver, v_s))
- do_log_driver_info = TRUE;
- }
-
- if (nm_g_variant_lookup(properties, "DisconnectReason", "i", &v_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 = v_i32;
- }
-
- if (nm_g_variant_lookup(properties, "State", "&s", &v_s)) {
- NMSupplicantInterfaceState state;
-
- state = wpas_state_string_to_enum(v_s);
- if (state == NM_SUPPLICANT_INTERFACE_STATE_INVALID)
- _LOGT("state: ignore unknown supplicant state '%s' (is %s, plain property)",
- v_s,
- nm_supplicant_interface_state_to_string(priv->supp_state));
- else if (priv->supp_state != state) {
- _LOGT("state: %s (was %s, plain property)",
- nm_supplicant_interface_state_to_string(state),
- nm_supplicant_interface_state_to_string(priv->supp_state));
- priv->supp_state = state;
- if (priv->state > NM_SUPPLICANT_INTERFACE_STATE_STARTING) {
- /* Only transition to actual wpa_supplicant interface states (ie,
- * anything > STARTING) after the NMSupplicantInterface has had a
- * chance to initialize, which is signalled by entering the STARTING
- * state.
- */
- do_set_state = TRUE;
- }
- }
- }
-
- if (nm_g_variant_lookup(properties, "CurrentBSS", "&o", &v_s)) {
- v_s = nm_dbus_path_not_empty(v_s);
- if (!nm_ref_string_equals_str(priv->current_bss, v_s)) {
- nm_ref_string_unref(priv->current_bss);
- priv->current_bss = nm_ref_string_new(v_s);
- do_notify_current_bss = TRUE;
- }
- }
-
- if (nm_g_variant_lookup(properties, "ApIsolate", "&s", &v_s))
- priv->ap_isolate_supported = TRUE;
-
- if (do_log_driver_info) {
- _LOGD("supplicant interface for ifindex=%d, ifname=%s%s%s, driver=%s%s%s (requested %s)",
- priv->ifindex,
- NM_PRINT_FMT_QUOTE_STRING(priv->ifname),
- NM_PRINT_FMT_QUOTE_STRING(priv->driver),
- nm_supplicant_driver_to_string(priv->requested_driver));
- }
-
- if (nm_g_variant_lookup(properties, "BSSs", "^a&o", &v_strv)) {
- NMSupplicantBssInfo *bss_info;
- NMSupplicantBssInfo *bss_info_safe;
- const char ** iter;
-
- c_list_for_each_entry (bss_info, &priv->bss_lst_head, _bss_lst)
- bss_info->_bss_dirty = TRUE;
- c_list_for_each_entry (bss_info, &priv->bss_initializing_lst_head, _bss_lst)
- bss_info->_bss_dirty = TRUE;
-
- for (iter = v_strv; *iter; iter++)
- _bss_info_add(self, *iter);
-
- g_free(v_strv);
-
- c_list_for_each_entry_safe (bss_info,
- bss_info_safe,
- &priv->bss_initializing_lst_head,
- _bss_lst) {
- if (bss_info->_bss_dirty)
- _bss_info_remove(self, &bss_info->bss_path);
- }
- c_list_for_each_entry_safe (bss_info, bss_info_safe, &priv->bss_lst_head, _bss_lst) {
- if (bss_info->_bss_dirty)
- _bss_info_remove(self, &bss_info->bss_path);
- }
- }
-
- if (do_notify_current_bss)
- _notify(self, PROP_CURRENT_BSS);
-
- if (do_set_state)
- set_state(self, priv->supp_state);
-
- _notify_maybe_scanning(self);
-}
-
-static void
-_properties_changed_p2p_device(NMSupplicantInterface *self, GVariant *properties)
-{
- NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self);
- const char ** v_strv;
- const char * v_s;
-
- nm_assert(!properties || g_variant_is_of_type(properties, G_VARIANT_TYPE("a{sv}")));
-
- if (nm_g_variant_lookup(properties, "Peers", "^a&o", &v_strv)) {
- NMSupplicantPeerInfo *peer_info;
- NMSupplicantPeerInfo *peer_info_safe;
- const char *const * iter;
-
- c_list_for_each_entry (peer_info, &priv->peer_lst_head, _peer_lst)
- peer_info->_peer_dirty = TRUE;
- c_list_for_each_entry (peer_info, &priv->peer_initializing_lst_head, _peer_lst)
- peer_info->_peer_dirty = TRUE;
-
- for (iter = v_strv; *iter; iter++)
- _peer_info_add(self, *iter);
-
- g_free(v_strv);
-
- c_list_for_each_entry_safe (peer_info,
- peer_info_safe,
- &priv->peer_initializing_lst_head,
- _peer_lst) {
- if (peer_info->_peer_dirty)
- _peer_info_remove(self, &peer_info->peer_path);
- }
- c_list_for_each_entry_safe (peer_info, peer_info_safe, &priv->peer_lst_head, _peer_lst) {
- if (peer_info->_peer_dirty)
- _peer_info_remove(self, &peer_info->peer_path);
- }
- }
-
- if (nm_g_variant_lookup(properties, "Group", "&o", &v_s))
- _p2p_group_set_path(self, v_s);
-}
-
-/*****************************************************************************/
-
-static void
-assoc_return(NMSupplicantInterface *self, GError *error, const char *message)
-{
- NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self);
- AssocData * assoc_data;
-
- assoc_data = g_steal_pointer(&priv->assoc_data);
- if (!assoc_data)
- return;
-
- if (error) {
- g_dbus_error_strip_remote_error(error);
- _LOGW("assoc[" NM_HASH_OBFUSCATE_PTR_FMT "]: %s: %s",
- NM_HASH_OBFUSCATE_PTR(assoc_data),
- message,
- error->message);
- } else {
- _LOGD("assoc[" NM_HASH_OBFUSCATE_PTR_FMT "]: association request successful",
- NM_HASH_OBFUSCATE_PTR(assoc_data));
- }
-
- if (assoc_data->add_network_data) {
- /* signal that this request already completed */
- assoc_data->add_network_data->assoc_data = NULL;
- }
-
- nm_clear_g_source(&assoc_data->fail_on_idle_id);
- nm_clear_g_cancellable(&assoc_data->cancellable);
-
- if (assoc_data->callback)
- assoc_data->callback(self, error, assoc_data->user_data);
-
- g_object_unref(assoc_data->cfg);
- g_slice_free(AssocData, assoc_data);
-}
-
-void
-nm_supplicant_interface_disconnect(NMSupplicantInterface *self)
-{
- NMSupplicantInterfacePrivate *priv;
-
- g_return_if_fail(NM_IS_SUPPLICANT_INTERFACE(self));
-
- priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self);
-
- /* Disconnect from the current AP */
- if ((priv->state >= NM_SUPPLICANT_INTERFACE_STATE_SCANNING)
- && (priv->state <= NM_SUPPLICANT_INTERFACE_STATE_COMPLETED)) {
- _dbus_connection_call_simple(self,
- NM_WPAS_DBUS_IFACE_INTERFACE,
- "Disconnect",
- NULL,
- G_VARIANT_TYPE("()"),
- "disconnect");
- }
-
- _remove_network(self);
-
- /* Cancel any WPS enrollment, if any */
- nm_supplicant_interface_cancel_wps(self);
-
- /* Cancel all pending calls related to a prior connection attempt */
- if (priv->assoc_data) {
- gs_free_error GError *error = NULL;
-
- nm_utils_error_set_cancelled(&error, FALSE, "NMSupplicantInterface");
- assoc_return(self, error, "abort due to disconnect");
- }
-}
-
-static void
-disconnect_cb(GObject *source, GAsyncResult *result, gpointer user_data)
-{
- gs_unref_object NMSupplicantInterface *self = NULL;
- gs_unref_variant GVariant *res = NULL;
- gs_free_error GError * error = NULL;
- NMSupplicantInterfaceDisconnectCb callback;
- gpointer callback_user_data;
-
- nm_utils_user_data_unpack(user_data, &self, &callback, &callback_user_data);
-
- res = g_dbus_connection_call_finish(G_DBUS_CONNECTION(source), result, &error);
-
- if (!res && !strstr(error->message, "fi.w1.wpa_supplicant1.NotConnected")) {
- /* an already disconnected interface is not an error*/
- g_clear_error(&error);
- }
-
- callback(self, error, callback_user_data);
-}
-
-void
-nm_supplicant_interface_disconnect_async(NMSupplicantInterface * self,
- GCancellable * cancellable,
- NMSupplicantInterfaceDisconnectCb callback,
- gpointer user_data)
-{
- g_return_if_fail(NM_IS_SUPPLICANT_INTERFACE(self));
- g_return_if_fail(callback);
-
- _dbus_connection_call(self,
- NM_WPAS_DBUS_IFACE_INTERFACE,
- "Disconnect",
- NULL,
- G_VARIANT_TYPE("()"),
- G_DBUS_CALL_FLAGS_NONE,
- DBUS_TIMEOUT_MSEC,
- cancellable,
- disconnect_cb,
- nm_utils_user_data_pack(g_object_ref(self), callback, user_data));
-}
-
-static void
-assoc_select_network_cb(GObject *source, GAsyncResult *result, gpointer user_data)
-{
- NMSupplicantInterface *self;
- gs_unref_variant GVariant *res = NULL;
- gs_free_error GError *error = NULL;
-
- res = g_dbus_connection_call_finish(G_DBUS_CONNECTION(source), result, &error);
- if (nm_utils_error_is_cancelled(error))
- return;
-
- self = NM_SUPPLICANT_INTERFACE(user_data);
- if (error)
- assoc_return(self, error, "failure to select network config");
- else
- assoc_return(self, NULL, NULL);
-}
-
-static void
-assoc_call_select_network(NMSupplicantInterface *self)
-{
- NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self);
-
- _dbus_connection_call(self,
- NM_WPAS_DBUS_IFACE_INTERFACE,
- "SelectNetwork",
- g_variant_new("(o)", priv->net_path),
- G_VARIANT_TYPE("()"),
- G_DBUS_CALL_FLAGS_NONE,
- DBUS_TIMEOUT_MSEC,
- priv->assoc_data->cancellable,
- assoc_select_network_cb,
- self);
-}
-
-static void
-assoc_add_blob_cb(GObject *source, GAsyncResult *result, gpointer user_data)
-{
- NMSupplicantInterface * self;
- NMSupplicantInterfacePrivate *priv;
- gs_unref_variant GVariant *res = NULL;
- gs_free_error GError *error = NULL;
-
- res = g_dbus_connection_call_finish(G_DBUS_CONNECTION(source), result, &error);
- if (nm_utils_error_is_cancelled(error))
- return;
-
- self = NM_SUPPLICANT_INTERFACE(user_data);
- priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self);
-
- if (error) {
- assoc_return(self, error, "failure to set network certificates");
- return;
- }
-
- priv->assoc_data->blobs_left--;
- _LOGT("assoc[" NM_HASH_OBFUSCATE_PTR_FMT "]: blob added (%u left)",
- NM_HASH_OBFUSCATE_PTR(priv->assoc_data),
- priv->assoc_data->blobs_left);
- if (priv->assoc_data->blobs_left == 0)
- assoc_call_select_network(self);
-}
-
-static void
-assoc_add_network_cb(GObject *source, GAsyncResult *result, gpointer user_data)
-{
- AddNetworkData * add_network_data = user_data;
- AssocData * assoc_data;
- NMSupplicantInterface * self;
- NMSupplicantInterfacePrivate *priv;
- gs_unref_variant GVariant *res = NULL;
- gs_free_error GError *error = NULL;
- GHashTable * blobs;
- GHashTableIter iter;
- const char * blob_name;
- GBytes * blob_data;
- nm_auto_ref_string NMRefString *name_owner = NULL;
- nm_auto_ref_string NMRefString *object_path = NULL;
-
- g_clear_object(&add_network_data->shutdown_wait_obj);
-
- assoc_data = add_network_data->assoc_data;
- if (assoc_data)
- assoc_data->add_network_data = NULL;
- name_owner = g_steal_pointer(&add_network_data->name_owner);
- object_path = g_steal_pointer(&add_network_data->object_path);
- nm_g_slice_free(add_network_data);
-
- res = g_dbus_connection_call_finish(G_DBUS_CONNECTION(source), result, &error);
-
- if (!assoc_data) {
- if (!error) {
- const char *net_path;
-
- /* the assoc-request was already cancelled, but the AddNetwork request succeeded.
- * Cleanup the created network.
- *
- * This cleanup action does not work when NetworkManager is about to exit
- * and leaves the mainloop. During program shutdown, we may orphan networks. */
- g_variant_get(res, "(&o)", &net_path);
- g_dbus_connection_call(G_DBUS_CONNECTION(source),
- name_owner->str,
- object_path->str,
- NM_WPAS_DBUS_IFACE_INTERFACE,
- "RemoveNetwork",
- g_variant_new("(o)", net_path),
- G_VARIANT_TYPE("()"),
- G_DBUS_CALL_FLAGS_NONE,
- DBUS_TIMEOUT_MSEC,
- NULL,
- NULL,
- NULL);
- }
- return;
- }
-
- self = NM_SUPPLICANT_INTERFACE(assoc_data->self);
- priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self);
-
- if (error) {
- assoc_return(self, error, "failure to add network");
- return;
- }
-
- nm_assert(!priv->net_path);
- g_variant_get(res, "(o)", &priv->net_path);
-
- /* Send blobs first; otherwise jump to selecting the network */
- blobs = nm_supplicant_config_get_blobs(priv->assoc_data->cfg);
- priv->assoc_data->blobs_left = blobs ? g_hash_table_size(blobs) : 0u;
-
- _LOGT("assoc[" NM_HASH_OBFUSCATE_PTR_FMT "]: network added (%s) (%u blobs left)",
- NM_HASH_OBFUSCATE_PTR(priv->assoc_data),
- priv->net_path,
- priv->assoc_data->blobs_left);
-
- if (priv->assoc_data->blobs_left == 0) {
- assoc_call_select_network(self);
- return;
- }
-
- g_hash_table_iter_init(&iter, blobs);
- while (g_hash_table_iter_next(&iter, (gpointer) &blob_name, (gpointer) &blob_data)) {
- _dbus_connection_call(
- self,
- NM_WPAS_DBUS_IFACE_INTERFACE,
- "AddBlob",
- g_variant_new("(s@ay)", blob_name, nm_utils_gbytes_to_variant_ay(blob_data)),
- G_VARIANT_TYPE("()"),
- G_DBUS_CALL_FLAGS_NONE,
- DBUS_TIMEOUT_MSEC,
- priv->assoc_data->cancellable,
- assoc_add_blob_cb,
- self);
- }
-}
-
-static void
-add_network(NMSupplicantInterface *self)
-{
- NMSupplicantInterfacePrivate *priv;
- AddNetworkData * add_network_data;
-
- priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self);
-
- /* the association does not keep @self alive. We want to be able to remove
- * the network again, even if @self is already gone. Hence, track the data
- * separately.
- *
- * For that we also have a shutdown_wait_obj so that on exit we still wait
- * to handle the response. */
- add_network_data = g_slice_new(AddNetworkData);
- *add_network_data = (AddNetworkData){
- .assoc_data = priv->assoc_data,
- .name_owner = nm_ref_string_ref(priv->name_owner),
- .object_path = nm_ref_string_ref(priv->object_path),
- .shutdown_wait_obj = g_object_new(G_TYPE_OBJECT, NULL),
- };
- nm_shutdown_wait_obj_register_object(add_network_data->shutdown_wait_obj,
- "supplicant-add-network");
- priv->assoc_data->add_network_data = add_network_data;
-
- _dbus_connection_call(
- self,
- NM_WPAS_DBUS_IFACE_INTERFACE,
- "AddNetwork",
- g_variant_new("(@a{sv})", nm_supplicant_config_to_variant(priv->assoc_data->cfg)),
- G_VARIANT_TYPE("(o)"),
- G_DBUS_CALL_FLAGS_NONE,
- DBUS_TIMEOUT_MSEC,
- NULL,
- assoc_add_network_cb,
- add_network_data);
-}
-
-static void
-assoc_set_ap_isolation(GVariant *ret, GError *error, gpointer user_data)
-{
- NMSupplicantInterface * self;
- NMSupplicantInterfacePrivate *priv;
- gboolean value;
-
- if (nm_utils_error_is_cancelled(error))
- return;
-
- self = NM_SUPPLICANT_INTERFACE(user_data);
- priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self);
-
- if (error) {
- assoc_return(self, error, "failure to set AP isolation");
- return;
- }
-
- value = nm_supplicant_config_get_ap_isolation(priv->assoc_data->cfg);
- _LOGT("assoc[" NM_HASH_OBFUSCATE_PTR_FMT "]: interface AP isolation set to %d",
- NM_HASH_OBFUSCATE_PTR(priv->assoc_data),
- value);
-
- priv->ap_isolate_needs_reset = value;
-
- nm_assert(priv->assoc_data->calls_left > 0);
- if (--priv->assoc_data->calls_left == 0)
- add_network(self);
-}
-
-static void
-assoc_set_ap_scan_cb(GVariant *ret, GError *error, gpointer user_data)
-{
- NMSupplicantInterface * self;
- NMSupplicantInterfacePrivate *priv;
-
- if (nm_utils_error_is_cancelled(error))
- return;
-
- self = NM_SUPPLICANT_INTERFACE(user_data);
- priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self);
-
- if (error) {
- assoc_return(self, error, "failure to set AP scan mode");
- return;
- }
-
- _LOGT("assoc[" NM_HASH_OBFUSCATE_PTR_FMT "]: interface ap_scan set to %d",
- NM_HASH_OBFUSCATE_PTR(priv->assoc_data),
- nm_supplicant_config_get_ap_scan(priv->assoc_data->cfg));
-
- nm_assert(priv->assoc_data->calls_left > 0);
- if (--priv->assoc_data->calls_left == 0)
- add_network(self);
-}
-
-static gboolean
-assoc_fail_on_idle_cb(gpointer user_data)
-{
- NMSupplicantInterface * self = user_data;
- NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self);
- gs_free_error GError *error = NULL;
-
- priv->assoc_data->fail_on_idle_id = 0;
- g_set_error(&error,
- NM_SUPPLICANT_ERROR,
- NM_SUPPLICANT_ERROR_CONFIG,
- "EAP-FAST is not supported by the supplicant");
- assoc_return(self, error, "failure due to missing supplicant support");
- return G_SOURCE_REMOVE;
-}
-
-/**
- * nm_supplicant_interface_assoc:
- * @self: the supplicant interface instance
- * @cfg: the configuration with the data for the association
- * @callback: callback invoked when the association completes or fails.
- * @user_data: data for the callback.
- *
- * Calls AddNetwork and SelectNetwork to start associating according to @cfg.
- *
- * The callback is invoked exactly once (always) and always asynchronously.
- * The pending association can be aborted via nm_supplicant_interface_disconnect()
- * or by destroying @self. In that case, the @callback is invoked synchronously with
- * an error reason indicating cancellation/disposing (see nm_utils_error_is_cancelled()).
- */
-void
-nm_supplicant_interface_assoc(NMSupplicantInterface * self,
- NMSupplicantConfig * cfg,
- NMSupplicantInterfaceAssocCb callback,
- gpointer user_data)
-{
- NMSupplicantInterfacePrivate *priv;
- AssocData * assoc_data;
- gboolean ap_isolation;
-
- g_return_if_fail(NM_IS_SUPPLICANT_INTERFACE(self));
- g_return_if_fail(NM_IS_SUPPLICANT_CONFIG(cfg));
-
- priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self);
-
- nm_supplicant_interface_disconnect(self);
-
- assoc_data = g_slice_new(AssocData);
- *assoc_data = (AssocData){
- .self = self,
- .cfg = g_object_ref(cfg),
- .callback = callback,
- .user_data = user_data,
- };
-
- priv->assoc_data = assoc_data;
-
- _LOGD("assoc[" NM_HASH_OBFUSCATE_PTR_FMT "]: starting association...",
- NM_HASH_OBFUSCATE_PTR(assoc_data));
-
- if (_get_capability(priv, NM_SUPPL_CAP_TYPE_FAST) == NM_TERNARY_FALSE
- && nm_supplicant_config_fast_required(cfg)) {
- /* Make sure the supplicant supports EAP-FAST before trying to send
- * it an EAP-FAST configuration.
- */
- assoc_data->fail_on_idle_id = g_idle_add(assoc_fail_on_idle_cb, self);
- return;
- }
-
- assoc_data->cancellable = g_cancellable_new();
- assoc_data->calls_left++;
- nm_dbus_connection_call_set(
- priv->dbus_connection,
- priv->name_owner->str,
- priv->object_path->str,
- NM_WPAS_DBUS_IFACE_INTERFACE,
- "ApScan",
- g_variant_new_uint32(nm_supplicant_config_get_ap_scan(priv->assoc_data->cfg)),
- DBUS_TIMEOUT_MSEC,
- assoc_data->cancellable,
- assoc_set_ap_scan_cb,
- self);
-
- ap_isolation = nm_supplicant_config_get_ap_isolation(priv->assoc_data->cfg);
- if (!priv->ap_isolate_supported) {
- if (ap_isolation) {
- _LOGW("assoc[" NM_HASH_OBFUSCATE_PTR_FMT
- "]: requested AP isolation but the supplicant doesn't support it",
- NM_HASH_OBFUSCATE_PTR(assoc_data));
- }
- } else {
- assoc_data->calls_left++;
- /* It would be smarter to change the property only when necessary.
- * However, wpa_supplicant doesn't send the PropertiesChanged
- * signal for ApIsolate, and so to know the current value we would
- * need first a Get call. It seems simpler to just set the value
- * we want. */
- nm_dbus_connection_call_set(priv->dbus_connection,
- priv->name_owner->str,
- priv->object_path->str,
- NM_WPAS_DBUS_IFACE_INTERFACE,
- "ApIsolate",
- g_variant_new_string(ap_isolation ? "1" : "0"),
- DBUS_TIMEOUT_MSEC,
- assoc_data->cancellable,
- assoc_set_ap_isolation,
- self);
- }
-}
-
-/*****************************************************************************/
-
-typedef struct {
- NMSupplicantInterface * self;
- GCancellable * cancellable;
- NMSupplicantInterfaceRequestScanCallback callback;
- gpointer user_data;
-} ScanRequestData;
-
-static void
-scan_request_cb(GObject *source, GAsyncResult *result, gpointer user_data)
-{
- gs_unref_object NMSupplicantInterface *self_keep_alive = NULL;
- NMSupplicantInterface * self;
- gs_unref_variant GVariant *res = NULL;
- gs_free_error GError *error = NULL;
- ScanRequestData * data = user_data;
- gboolean cancelled = FALSE;
-
- res = g_dbus_connection_call_finish(G_DBUS_CONNECTION(source), result, &error);
- if (nm_utils_error_is_cancelled(error)) {
- if (!data->callback) {
- /* the self instance was not kept alive. We also must not touch it. Return. */
- nm_g_object_unref(data->cancellable);
- nm_g_slice_free(data);
- return;
- }
- cancelled = TRUE;
- }
-
- self = data->self;
- if (data->callback) {
- /* the self instance was kept alive. Balance the reference count. */
- self_keep_alive = self;
- }
-
- /* we don't propagate the error/success. That is, because either answer is not
- * reliable. What is important to us is whether the request completed, and
- * the current nm_supplicant_interface_get_scanning() state. */
- if (cancelled)
- _LOGD("request-scan: request cancelled");
- else {
- if (error) {
- if (_nm_dbus_error_has_name(error, "fi.w1.wpa_supplicant1.Interface.ScanError"))
- _LOGD("request-scan: could not get scan request result: %s", error->message);
- else {
- g_dbus_error_strip_remote_error(error);
- _LOGW("request-scan: could not get scan request result: %s", error->message);
- }
- } else
- _LOGT("request-scan: request scanning success");
- }
-
- if (data->callback)
- data->callback(self, data->cancellable, data->user_data);
-
- nm_g_object_unref(data->cancellable);
- nm_g_slice_free(data);
-}
-
-void
-nm_supplicant_interface_request_scan(NMSupplicantInterface * self,
- GBytes *const * ssids,
- guint ssids_len,
- GCancellable * cancellable,
- NMSupplicantInterfaceRequestScanCallback callback,
- gpointer user_data)
-{
- NMSupplicantInterfacePrivate *priv;
- GVariantBuilder builder;
- ScanRequestData * data;
- guint i;
-
- g_return_if_fail(NM_IS_SUPPLICANT_INTERFACE(self));
-
- nm_assert((!cancellable && !callback) || (G_IS_CANCELLABLE(cancellable) && callback));
-
- priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self);
-
- _LOGT("request-scan: request scanning (%u ssids)...", ssids_len);
-
- g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT);
- g_variant_builder_add(&builder, "{sv}", "Type", g_variant_new_string("active"));
- g_variant_builder_add(&builder, "{sv}", "AllowRoam", g_variant_new_boolean(FALSE));
- if (ssids_len > 0) {
- GVariantBuilder ssids_builder;
-
- g_variant_builder_init(&ssids_builder, G_VARIANT_TYPE_BYTESTRING_ARRAY);
- for (i = 0; i < ssids_len; i++) {
- nm_assert(ssids[i]);
- g_variant_builder_add(&ssids_builder, "@ay", nm_utils_gbytes_to_variant_ay(ssids[i]));
- }
- g_variant_builder_add(&builder, "{sv}", "SSIDs", g_variant_builder_end(&ssids_builder));
- }
-
- data = g_slice_new(ScanRequestData);
- *data = (ScanRequestData){
- .self = self,
- .callback = callback,
- .user_data = user_data,
- .cancellable = nm_g_object_ref(cancellable),
- };
-
- if (callback) {
- /* A callback was provided. This keeps @self alive. The caller
- * must provide a cancellable as the caller must never leave an asynchronous
- * operation pending indefinitely. */
- nm_assert(G_IS_CANCELLABLE(cancellable));
- g_object_ref(self);
- } else {
- /* We don't keep @self alive, and we don't accept a cancellable either. */
- nm_assert(!cancellable);
- cancellable = priv->main_cancellable;
- }
-
- _dbus_connection_call(self,
- NM_WPAS_DBUS_IFACE_INTERFACE,
- "Scan",
- g_variant_new("(a{sv})", &builder),
- G_VARIANT_TYPE("()"),
- G_DBUS_CALL_FLAGS_NONE,
- DBUS_TIMEOUT_MSEC,
- cancellable,
- scan_request_cb,
- data);
-}
-
-/*****************************************************************************/
-
-NMSupplicantInterfaceState
-nm_supplicant_interface_get_state(NMSupplicantInterface *self)
-{
- g_return_val_if_fail(NM_IS_SUPPLICANT_INTERFACE(self), NM_SUPPLICANT_INTERFACE_STATE_DOWN);
-
- return NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self)->state;
-}
-
-void
-_nm_supplicant_interface_set_state_down(NMSupplicantInterface *self,
- gboolean force_remove_from_supplicant,
- const char * reason)
-{
- set_state_down(self, force_remove_from_supplicant, reason);
-}
-
-NMRefString *
-nm_supplicant_interface_get_name_owner(NMSupplicantInterface *self)
-{
- g_return_val_if_fail(NM_IS_SUPPLICANT_INTERFACE(self), NULL);
-
- return NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self)->name_owner;
-}
-
-NMRefString *
-nm_supplicant_interface_get_object_path(NMSupplicantInterface *self)
-{
- g_return_val_if_fail(NM_IS_SUPPLICANT_INTERFACE(self), NULL);
-
- return NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self)->object_path;
-}
-
-const char *
-nm_supplicant_interface_get_ifname(NMSupplicantInterface *self)
-{
- g_return_val_if_fail(NM_IS_SUPPLICANT_INTERFACE(self), NULL);
-
- return NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self)->ifname;
-}
-
-guint
-nm_supplicant_interface_get_max_scan_ssids(NMSupplicantInterface *self)
-{
- NMSupplicantInterfacePrivate *priv;
-
- g_return_val_if_fail(NM_IS_SUPPLICANT_INTERFACE(self), 0);
-
- priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self);
- return priv->prop_scan_active && priv->prop_scan_ssid ? priv->max_scan_ssids : 0u;
-}
-
-/*****************************************************************************/
-
-void
-nm_supplicant_interface_p2p_start_find(NMSupplicantInterface *self, guint timeout)
-{
- GVariantBuilder builder;
-
- g_return_if_fail(NM_IS_SUPPLICANT_INTERFACE(self));
- g_return_if_fail(timeout > 0 && timeout <= 600);
-
- g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT);
- g_variant_builder_add(&builder, "{sv}", "Timeout", g_variant_new_int32(timeout));
-
- _dbus_connection_call_simple(self,
- NM_WPAS_DBUS_IFACE_INTERFACE_P2P_DEVICE,
- "Find",
- g_variant_new("(a{sv})", &builder),
- G_VARIANT_TYPE("()"),
- "p2p-find");
-}
-
-void
-nm_supplicant_interface_p2p_stop_find(NMSupplicantInterface *self)
-{
- g_return_if_fail(NM_IS_SUPPLICANT_INTERFACE(self));
-
- _dbus_connection_call_simple(self,
- NM_WPAS_DBUS_IFACE_INTERFACE_P2P_DEVICE,
- "StopFind",
- NULL,
- G_VARIANT_TYPE("()"),
- "p2p-stop-find");
-}
-
-/*****************************************************************************/
-
-void
-nm_supplicant_interface_p2p_connect(NMSupplicantInterface *self,
- const char * peer,
- const char * wps_method,
- const char * wps_pin)
-{
- GVariantBuilder builder;
-
- g_return_if_fail(NM_IS_SUPPLICANT_INTERFACE(self));
-
- g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT);
-
- g_variant_builder_add(&builder, "{sv}", "wps_method", g_variant_new_string(wps_method));
- if (wps_pin)
- g_variant_builder_add(&builder, "{sv}", "pin", g_variant_new_string(wps_pin));
- g_variant_builder_add(&builder, "{sv}", "peer", g_variant_new_object_path(peer));
- g_variant_builder_add(&builder, "{sv}", "join", g_variant_new_boolean(FALSE));
- g_variant_builder_add(&builder, "{sv}", "persistent", g_variant_new_boolean(FALSE));
- g_variant_builder_add(&builder, "{sv}", "go_intent", g_variant_new_int32(7));
-
- _dbus_connection_call_simple(self,
- NM_WPAS_DBUS_IFACE_INTERFACE_P2P_DEVICE,
- "Connect",
- g_variant_new("(a{sv})", &builder),
- G_VARIANT_TYPE("(s)"),
- "p2p-connect");
-}
-
-void
-nm_supplicant_interface_p2p_cancel_connect(NMSupplicantInterface *self)
-{
- g_return_if_fail(NM_IS_SUPPLICANT_INTERFACE(self));
-
- _dbus_connection_call_simple(self,
- NM_WPAS_DBUS_IFACE_INTERFACE_P2P_DEVICE,
- "Cancel",
- NULL,
- G_VARIANT_TYPE("()"),
- "p2p-cancel");
-}
-
-void
-nm_supplicant_interface_p2p_disconnect(NMSupplicantInterface *self)
-{
- g_return_if_fail(NM_IS_SUPPLICANT_INTERFACE(self));
-
- _dbus_connection_call_simple(self,
- NM_WPAS_DBUS_IFACE_INTERFACE_P2P_DEVICE,
- "Disconnect",
- NULL,
- G_VARIANT_TYPE("()"),
- "p2p-disconnect");
-}
-
-/*****************************************************************************/
-
-static void
-_properties_changed(NMSupplicantInterface *self,
- const char * interface_name,
- GVariant * properties,
- gboolean initial)
-{
- NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self);
- gboolean is_main;
-
- nm_assert(!properties || g_variant_is_of_type(properties, G_VARIANT_TYPE("a{sv}")));
-
- if (initial)
- priv->starting_pending_count--;
-
- if ((initial || priv->is_ready_main) && nm_streq(interface_name, NM_WPAS_DBUS_IFACE_INTERFACE))
- is_main = TRUE;
- else if ((initial || priv->is_ready_p2p_device)
- && nm_streq(interface_name, NM_WPAS_DBUS_IFACE_INTERFACE_P2P_DEVICE)) {
- nm_assert(_get_capability(priv, NM_SUPPL_CAP_TYPE_P2P) == NM_TERNARY_TRUE);
- is_main = FALSE;
- } else
- return;
-
- g_object_freeze_notify(G_OBJECT(self));
-
- priv->starting_pending_count++;
-
- if (is_main) {
- priv->is_ready_main = TRUE;
- _properties_changed_main(self, properties);
- } else {
- priv->is_ready_p2p_device = TRUE;
- _properties_changed_p2p_device(self, properties);
- }
-
- priv->starting_pending_count--;
- _starting_check_ready(self);
-
- _notify_maybe_scanning(self);
- _notify_maybe_p2p_available(self);
-
- g_object_thaw_notify(G_OBJECT(self));
-}
-
-static void
-_properties_changed_cb(GDBusConnection *connection,
- const char * sender_name,
- const char * object_path,
- const char * signal_interface_name,
- const char * signal_name,
- GVariant * parameters,
- gpointer user_data)
-{
- NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE(user_data);
- const char * interface_name;
- gs_unref_variant GVariant *changed_properties = NULL;
-
- if (!g_variant_is_of_type(parameters, G_VARIANT_TYPE("(sa{sv}as)")))
- return;
-
- g_variant_get(parameters, "(&s@a{sv}^a&s)", &interface_name, &changed_properties, NULL);
- _properties_changed(self, interface_name, changed_properties, FALSE);
-}
-
-static void
-_bss_properties_changed_cb(GDBusConnection *connection,
- const char * sender_name,
- const char * object_path,
- const char * signal_interface_name,
- const char * signal_name,
- GVariant * parameters,
- gpointer user_data)
-{
- NMSupplicantInterface * self = NM_SUPPLICANT_INTERFACE(user_data);
- NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self);
- nm_auto_ref_string NMRefString *bss_path = NULL;
- gs_unref_variant GVariant *changed_properties = NULL;
- NMSupplicantBssInfo * bss_info;
-
- if (!g_variant_is_of_type(parameters, G_VARIANT_TYPE("(sa{sv}as)")))
- return;
-
- bss_path = nm_ref_string_new(object_path);
-
- bss_info = g_hash_table_lookup(priv->bss_idx, &bss_path);
- if (!bss_info)
- return;
- if (bss_info->_init_cancellable)
- return;
-
- g_variant_get(parameters, "(&s@a{sv}^a&s)", NULL, &changed_properties, NULL);
- _bss_info_properties_changed(self, bss_info, changed_properties, FALSE);
-}
-
-static void
-_peer_properties_changed_cb(GDBusConnection *connection,
- const char * sender_name,
- const char * object_path,
- const char * signal_interface_name,
- const char * signal_name,
- GVariant * parameters,
- gpointer user_data)
-{
- NMSupplicantInterface * self = NM_SUPPLICANT_INTERFACE(user_data);
- NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self);
- nm_auto_ref_string NMRefString *peer_path = NULL;
- gs_unref_variant GVariant *changed_properties = NULL;
- NMSupplicantPeerInfo * peer_info;
-
- if (!g_variant_is_of_type(parameters, G_VARIANT_TYPE("(sa{sv}as)")))
- return;
-
- peer_path = nm_ref_string_new(object_path);
-
- peer_info = g_hash_table_lookup(priv->peer_idx, &peer_path);
- if (!peer_info)
- return;
- if (peer_info->_init_cancellable)
- return;
-
- g_variant_get(parameters, "(&s@a{sv}^a&s)", NULL, &changed_properties, NULL);
- _peer_info_properties_changed(self, peer_info, changed_properties, FALSE);
-}
-
-static void
-_get_all_main_cb(GVariant *result, GError *error, gpointer user_data)
-{
- gs_unref_variant GVariant *properties = NULL;
-
- if (nm_utils_error_is_cancelled(error))
- return;
-
- if (result)
- g_variant_get(result, "(@a{sv})", &properties);
- _properties_changed(user_data, NM_WPAS_DBUS_IFACE_INTERFACE, properties, TRUE);
-}
-
-static void
-_get_all_p2p_device_cb(GVariant *result, GError *error, gpointer user_data)
-{
- gs_unref_variant GVariant *properties = NULL;
-
- if (nm_utils_error_is_cancelled(error))
- return;
-
- if (result)
- g_variant_get(result, "(@a{sv})", &properties);
- _properties_changed(user_data, NM_WPAS_DBUS_IFACE_INTERFACE_P2P_DEVICE, properties, TRUE);
-}
-
-static void
-_signal_handle(NMSupplicantInterface *self,
- const char * signal_interface_name,
- const char * signal_name,
- GVariant * parameters)
-{
- NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self);
- const char * path;
-
- if (nm_streq(signal_interface_name, NM_WPAS_DBUS_IFACE_INTERFACE)) {
- if (!priv->is_ready_main)
- return;
-
- if (nm_streq(signal_name, "BSSAdded")) {
- if (!g_variant_is_of_type(parameters, G_VARIANT_TYPE("(oa{sv})")))
- return;
-
- g_variant_get(parameters, "(&oa{sv})", &path, NULL);
- _bss_info_add(self, path);
- return;
- }
-
- if (nm_streq(signal_name, "BSSRemoved")) {
- nm_auto_ref_string NMRefString *bss_path = NULL;
-
- if (!g_variant_is_of_type(parameters, G_VARIANT_TYPE("(o)")))
- return;
-
- g_variant_get(parameters, "(&o)", &path);
- bss_path = nm_ref_string_new(path);
- _bss_info_remove(self, &bss_path);
- return;
- }
-
- if (nm_streq(signal_name, "EAP")) {
- NMSupplicantAuthState auth_state = NM_SUPPLICANT_AUTH_STATE_UNKNOWN;
- const char * status;
- const char * parameter;
-
- if (g_variant_is_of_type(parameters, G_VARIANT_TYPE("(ss)")))
- return;
-
- g_variant_get(parameters, "(&s&s)", &status, &parameter);
-
- if (nm_streq(status, "started"))
- auth_state = NM_SUPPLICANT_AUTH_STATE_STARTED;
- else if (nm_streq(status, "completion")) {
- if (nm_streq(parameter, "success"))
- auth_state = NM_SUPPLICANT_AUTH_STATE_SUCCESS;
- else if (nm_streq(parameter, "failure"))
- auth_state = NM_SUPPLICANT_AUTH_STATE_FAILURE;
- }
-
- /* the state eventually reaches one of started, success or failure
- * so ignore any other intermediate (unknown) state change. */
- if (auth_state != NM_SUPPLICANT_AUTH_STATE_UNKNOWN && auth_state != priv->auth_state) {
- priv->auth_state = auth_state;
- _notify(self, PROP_AUTH_STATE);
- }
- return;
- }
-
- return;
- }
-
- if (nm_streq(signal_interface_name, NM_WPAS_DBUS_IFACE_INTERFACE_P2P_DEVICE)) {
- if (!priv->is_ready_p2p_device)
- return;
-
- if (nm_streq(signal_name, "DeviceFound")) {
- if (g_variant_is_of_type(parameters, G_VARIANT_TYPE("(o)"))) {
- g_variant_get(parameters, "(&o)", &path);
- _peer_info_add(self, path);
- }
- return;
- }
-
- if (nm_streq(signal_name, "DeviceLost")) {
- if (g_variant_is_of_type(parameters, G_VARIANT_TYPE("(o)"))) {
- nm_auto_ref_string NMRefString *peer_path = NULL;
-
- g_variant_get(parameters, "(&o)", &path);
- peer_path = nm_ref_string_new(path);
- _peer_info_remove(self, &peer_path);
- }
- return;
- }
-
- if (nm_streq(signal_name, "GroupStarted")) {
- if (g_variant_is_of_type(parameters, G_VARIANT_TYPE("(a{sv})"))) {
- gs_unref_variant GVariant *args = NULL;
- gs_unref_object NMSupplicantInterface *iface = NULL;
- const char * group_path;
- const char * iface_path;
-
- g_variant_get(parameters, "(@a{sv})", &args);
- if (!g_variant_lookup(args, "group_object", "&o", &group_path))
- return;
- if (!g_variant_lookup(args, "interface_object", "&o", &iface_path))
- return;
-
- if (nm_streq(iface_path, priv->object_path->str)) {
- _LOGW("P2P: GroupStarted on existing interface");
- iface = g_object_ref(self);
- } else {
- iface =
- nm_supplicant_manager_create_interface_from_path(priv->supplicant_manager,
- iface_path);
- if (iface == NULL) {
- _LOGW("P2P: Group interface already exists in GroupStarted handler, "
- "aborting further processing.");
- return;
- }
- }
-
- /* Signal existence of the (new) interface. */
- g_signal_emit(self, signals[GROUP_STARTED], 0, iface);
- }
- return;
- }
-
- if (nm_streq(signal_name, "GroupFinished")) {
- if (g_variant_is_of_type(parameters, G_VARIANT_TYPE("(a{sv})"))) {
- gs_unref_variant GVariant *args = NULL;
- const char * iface_path;
-
- g_variant_get(parameters, "(@a{sv})", &args);
-
- /* TODO: Group finished is called on the management interface!
- * This means the signal consumer will currently need to assume which
- * interface is finishing or it needs to match the object paths.
- */
- if (!g_variant_lookup(args, "interface_object", "&o", &iface_path))
- return;
-
- _LOGD("P2P: GroupFinished signal on interface %s for interface %s",
- priv->object_path->str,
- iface_path);
-
- /* Signal group finish interface (on management interface). */
- g_signal_emit(self, signals[GROUP_FINISHED], 0, iface_path);
- }
- return;
- }
-
- return;
- }
-}
-
-static void
-_signal_cb(GDBusConnection *connection,
- const char * sender_name,
- const char * object_path,
- const char * signal_interface_name,
- const char * signal_name,
- GVariant * parameters,
- gpointer user_data)
-{
- NMSupplicantInterface * self = user_data;
- NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self);
-
- priv->starting_pending_count++;
- _signal_handle(self, signal_interface_name, signal_name, parameters);
- priv->starting_pending_count--;
- _starting_check_ready(self);
-
- _notify_maybe_scanning(self);
-}
-
-/*****************************************************************************/
-
-gboolean
-nm_supplicant_interface_get_p2p_available(NMSupplicantInterface *self)
-{
- return NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self)->p2p_capable_cached;
-}
-
-gboolean
-nm_supplicant_interface_get_p2p_group_joined(NMSupplicantInterface *self)
-{
- return NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self)->p2p_group_joined_cached;
-}
-
-const char *
-nm_supplicant_interface_get_p2p_group_path(NMSupplicantInterface *self)
-{
- return nm_ref_string_get_str(NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self)->p2p_group_path);
-}
-
-gboolean
-nm_supplicant_interface_get_p2p_group_owner(NMSupplicantInterface *self)
-{
- return NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self)->p2p_group_owner_cached;
-}
-
-/*****************************************************************************/
-
-static void
-get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
-{
- NMSupplicantInterface * self = NM_SUPPLICANT_INTERFACE(object);
- NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self);
-
- switch (prop_id) {
- case PROP_SCANNING:
- g_value_set_boolean(value, nm_supplicant_interface_get_scanning(self));
- break;
- case PROP_CURRENT_BSS:
- g_value_set_string(value,
- nm_ref_string_get_str(nm_supplicant_interface_get_current_bss(self)));
- break;
- case PROP_P2P_GROUP_JOINED:
- g_value_set_boolean(value, nm_supplicant_interface_get_p2p_group_joined(self));
- break;
- case PROP_P2P_GROUP_PATH:
- g_value_set_string(value, nm_supplicant_interface_get_p2p_group_path(self));
- break;
- case PROP_P2P_GROUP_OWNER:
- g_value_set_boolean(value, nm_supplicant_interface_get_p2p_group_owner(self));
- break;
- case PROP_P2P_AVAILABLE:
- g_value_set_boolean(value, nm_supplicant_interface_get_p2p_available(self));
- break;
- case PROP_AUTH_STATE:
- g_value_set_uint(value, priv->auth_state);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
- break;
- }
-}
-
-static void
-set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
-{
- NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE(object);
-
- switch (prop_id) {
- case PROP_SUPPLICANT_MANAGER:
- /* construct-only */
- priv->supplicant_manager = g_object_ref(g_value_get_pointer(value));
- nm_assert(NM_IS_SUPPLICANT_MANAGER(priv->supplicant_manager));
-
- priv->dbus_connection =
- g_object_ref(nm_supplicant_manager_get_dbus_connection(priv->supplicant_manager));
- nm_assert(G_IS_DBUS_CONNECTION(priv->dbus_connection));
-
- priv->name_owner =
- nm_ref_string_ref(nm_supplicant_manager_get_dbus_name_owner(priv->supplicant_manager));
- nm_assert(NM_IS_REF_STRING(priv->name_owner));
-
- priv->global_capabilities =
- nm_supplicant_manager_get_global_capabilities(priv->supplicant_manager);
- break;
- case PROP_DBUS_OBJECT_PATH:
- /* construct-only */
- priv->object_path = nm_ref_string_ref(g_value_get_pointer(value));
- nm_assert(NM_IS_REF_STRING(priv->object_path));
- break;
- case PROP_IFINDEX:
- /* construct-only */
- priv->ifindex = g_value_get_int(value);
- break;
- case PROP_DRIVER:
- /* construct-only */
- priv->requested_driver = g_value_get_uint(value);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
- break;
- }
-}
-
-/*****************************************************************************/
-
-static void
-nm_supplicant_interface_init(NMSupplicantInterface *self)
-{
- NMSupplicantInterfacePrivate *priv;
-
- priv = G_TYPE_INSTANCE_GET_PRIVATE(self,
- NM_TYPE_SUPPLICANT_INTERFACE,
- NMSupplicantInterfacePrivate);
-
- self->_priv = priv;
-
- nm_assert(priv->global_capabilities == NM_SUPPL_CAP_MASK_NONE);
- nm_assert(priv->iface_capabilities == NM_SUPPL_CAP_MASK_NONE);
-
- priv->state = NM_SUPPLICANT_INTERFACE_STATE_STARTING;
- priv->supp_state = NM_SUPPLICANT_INTERFACE_STATE_INVALID;
- priv->last_scan_msec = -1;
-
- c_list_init(&self->supp_lst);
-
- G_STATIC_ASSERT_EXPR(G_STRUCT_OFFSET(NMSupplicantBssInfo, bss_path) == 0);
- priv->bss_idx = g_hash_table_new(nm_pdirect_hash, nm_pdirect_equal);
-
- c_list_init(&priv->bss_lst_head);
- c_list_init(&priv->bss_initializing_lst_head);
-
- G_STATIC_ASSERT_EXPR(G_STRUCT_OFFSET(NMSupplicantPeerInfo, peer_path) == 0);
- priv->peer_idx = g_hash_table_new(nm_pdirect_hash, nm_pdirect_equal);
-
- c_list_init(&priv->peer_lst_head);
- c_list_init(&priv->peer_initializing_lst_head);
-
- priv->main_cancellable = g_cancellable_new();
-}
-
-static void
-constructed(GObject *object)
-{
- NMSupplicantInterface * self = NM_SUPPLICANT_INTERFACE(object);
- NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self);
-
- G_OBJECT_CLASS(nm_supplicant_interface_parent_class)->constructed(object);
-
- _LOGD("new supplicant interface %s on %s", priv->object_path->str, priv->name_owner->str);
-
- priv->properties_changed_id =
- nm_dbus_connection_signal_subscribe_properties_changed(priv->dbus_connection,
- priv->name_owner->str,
- priv->object_path->str,
- NULL,
- _properties_changed_cb,
- self,
- NULL);
-
- priv->bss_properties_changed_id =
- nm_dbus_connection_signal_subscribe_properties_changed(priv->dbus_connection,
- priv->name_owner->str,
- NULL,
- NM_WPAS_DBUS_IFACE_BSS,
- _bss_properties_changed_cb,
- self,
- NULL);
-
- priv->signal_id = g_dbus_connection_signal_subscribe(priv->dbus_connection,
- priv->name_owner->str,
- NULL,
- NULL,
- priv->object_path->str,
- NULL,
- G_DBUS_SIGNAL_FLAGS_NONE,
- _signal_cb,
- self,
- NULL);
-
- /* Scan result aging parameters */
- nm_dbus_connection_call_set(priv->dbus_connection,
- priv->name_owner->str,
- priv->object_path->str,
- NM_WPAS_DBUS_IFACE_INTERFACE,
- "BSSExpireAge",
- g_variant_new_uint32(250),
- DBUS_TIMEOUT_MSEC,
- NULL,
- NULL,
- NULL);
- nm_dbus_connection_call_set(priv->dbus_connection,
- priv->name_owner->str,
- priv->object_path->str,
- NM_WPAS_DBUS_IFACE_INTERFACE,
- "BSSExpireCount",
- g_variant_new_uint32(2),
- DBUS_TIMEOUT_MSEC,
- NULL,
- NULL,
- NULL);
-
- if (_get_capability(priv, NM_SUPPL_CAP_TYPE_PMF) == NM_TERNARY_TRUE) {
- /* Initialize global PMF setting to 'optional' */
- nm_dbus_connection_call_set(priv->dbus_connection,
- priv->name_owner->str,
- priv->object_path->str,
- NM_WPAS_DBUS_IFACE_INTERFACE,
- "Pmf",
- g_variant_new_string("1"),
- DBUS_TIMEOUT_MSEC,
- NULL,
- NULL,
- NULL);
- }
-
- if (_get_capability(priv, NM_SUPPL_CAP_TYPE_AP) == NM_TERNARY_DEFAULT) {
- /* 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->starting_pending_count++;
- _dbus_connection_call(self,
- DBUS_INTERFACE_INTROSPECTABLE,
- "Introspect",
- NULL,
- G_VARIANT_TYPE("(s)"),
- G_DBUS_CALL_FLAGS_NONE,
- 5000,
- priv->main_cancellable,
- iface_introspect_cb,
- self);
- }
-
- priv->starting_pending_count++;
- nm_dbus_connection_call_get_all(priv->dbus_connection,
- priv->name_owner->str,
- priv->object_path->str,
- NM_WPAS_DBUS_IFACE_INTERFACE,
- 5000,
- priv->main_cancellable,
- _get_all_main_cb,
- self);
-
- if (_get_capability(priv, NM_SUPPL_CAP_TYPE_P2P) == NM_TERNARY_TRUE) {
- priv->peer_properties_changed_id =
- nm_dbus_connection_signal_subscribe_properties_changed(priv->dbus_connection,
- priv->name_owner->str,
- NULL,
- NM_WPAS_DBUS_IFACE_PEER,
- _peer_properties_changed_cb,
- self,
- NULL);
-
- priv->starting_pending_count++;
- nm_dbus_connection_call_get_all(priv->dbus_connection,
- priv->name_owner->str,
- priv->object_path->str,
- NM_WPAS_DBUS_IFACE_INTERFACE_P2P_DEVICE,
- 5000,
- priv->main_cancellable,
- _get_all_p2p_device_cb,
- self);
- }
-}
-
-NMSupplicantInterface *
-nm_supplicant_interface_new(NMSupplicantManager *supplicant_manager,
- NMRefString * object_path,
- int ifindex,
- NMSupplicantDriver driver)
-{
- nm_assert(NM_IS_SUPPLICANT_MANAGER(supplicant_manager));
-
- return g_object_new(NM_TYPE_SUPPLICANT_INTERFACE,
- NM_SUPPLICANT_INTERFACE_SUPPLICANT_MANAGER,
- supplicant_manager,
- NM_SUPPLICANT_INTERFACE_DBUS_OBJECT_PATH,
- object_path,
- NM_SUPPLICANT_INTERFACE_IFINDEX,
- ifindex,
- NM_SUPPLICANT_INTERFACE_DRIVER,
- (guint) driver,
- NULL);
-}
-
-static void
-dispose(GObject *object)
-{
- NMSupplicantInterface * self = NM_SUPPLICANT_INTERFACE(object);
- NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self);
-
- if (priv->state != NM_SUPPLICANT_INTERFACE_STATE_DOWN)
- set_state_down(self, TRUE, "NMSupplicantInterface is disposing");
-
- nm_assert(c_list_is_empty(&self->supp_lst));
-
- if (priv->wps_data) {
- /* we shut down, but an asynchronous Cancel request is pending.
- * We don't want to cancel it, so mark wps-data that @self is gone.
- * This way, _wps_handle_cancel_cb() knows it must no longer touch
- * @self */
- priv->wps_data->self = NULL;
- priv->wps_data = NULL;
- }
-
- nm_assert(!priv->assoc_data);
-
- nm_clear_pointer(&priv->bss_idx, g_hash_table_destroy);
- nm_clear_pointer(&priv->peer_idx, g_hash_table_destroy);
-
- nm_clear_pointer(&priv->current_bss, nm_ref_string_unref);
-
- G_OBJECT_CLASS(nm_supplicant_interface_parent_class)->dispose(object);
-
- nm_clear_pointer(&priv->object_path, nm_ref_string_unref);
- nm_clear_pointer(&priv->name_owner, nm_ref_string_unref);
- g_clear_object(&priv->supplicant_manager);
- g_clear_object(&priv->dbus_connection);
- nm_clear_g_free(&priv->ifname);
- nm_clear_g_free(&priv->driver);
- nm_assert(!priv->net_path);
-}
-
-static void
-nm_supplicant_interface_class_init(NMSupplicantInterfaceClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS(klass);
-
- g_type_class_add_private(object_class, sizeof(NMSupplicantInterfacePrivate));
-
- object_class->constructed = constructed;
- object_class->dispose = dispose;
- object_class->set_property = set_property;
- object_class->get_property = get_property;
-
- obj_properties[PROP_SUPPLICANT_MANAGER] =
- g_param_spec_pointer(NM_SUPPLICANT_INTERFACE_SUPPLICANT_MANAGER,
- "",
- "",
- G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
- obj_properties[PROP_DBUS_OBJECT_PATH] =
- g_param_spec_pointer(NM_SUPPLICANT_INTERFACE_DBUS_OBJECT_PATH,
- "",
- "",
- G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
- obj_properties[PROP_IFINDEX] =
- g_param_spec_int(NM_SUPPLICANT_INTERFACE_IFINDEX,
- "",
- "",
- 0,
- G_MAXINT,
- 0,
- G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
- obj_properties[PROP_DRIVER] =
- g_param_spec_uint(NM_SUPPLICANT_INTERFACE_DRIVER,
- "",
- "",
- 0,
- G_MAXUINT,
- NM_SUPPLICANT_DRIVER_WIRELESS,
- G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
-
- obj_properties[PROP_SCANNING] = g_param_spec_boolean(NM_SUPPLICANT_INTERFACE_SCANNING,
- "",
- "",
- FALSE,
- G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
- obj_properties[PROP_CURRENT_BSS] =
- g_param_spec_string(NM_SUPPLICANT_INTERFACE_CURRENT_BSS,
- "",
- "",
- NULL,
- G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
- obj_properties[PROP_P2P_GROUP_JOINED] =
- g_param_spec_boolean(NM_SUPPLICANT_INTERFACE_P2P_GROUP_JOINED,
- "",
- "",
- FALSE,
- G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
- obj_properties[PROP_P2P_GROUP_PATH] =
- g_param_spec_string(NM_SUPPLICANT_INTERFACE_P2P_GROUP_PATH,
- "",
- "",
- NULL,
- G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
- obj_properties[PROP_P2P_GROUP_OWNER] =
- g_param_spec_boolean(NM_SUPPLICANT_INTERFACE_P2P_GROUP_OWNER,
- "",
- "",
- FALSE,
- G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
- obj_properties[PROP_P2P_AVAILABLE] =
- g_param_spec_boolean(NM_SUPPLICANT_INTERFACE_P2P_AVAILABLE,
- "",
- "",
- FALSE,
- G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
- obj_properties[PROP_AUTH_STATE] = g_param_spec_uint(NM_SUPPLICANT_INTERFACE_AUTH_STATE,
- "",
- "",
- NM_SUPPLICANT_AUTH_STATE_UNKNOWN,
- _NM_SUPPLICANT_AUTH_STATE_NUM - 1,
- NM_SUPPLICANT_AUTH_STATE_UNKNOWN,
- G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
-
- g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties);
-
- signals[STATE] = g_signal_new(NM_SUPPLICANT_INTERFACE_STATE,
- G_OBJECT_CLASS_TYPE(object_class),
- G_SIGNAL_RUN_LAST,
- 0,
- NULL,
- NULL,
- NULL,
- G_TYPE_NONE,
- 3,
- G_TYPE_INT,
- G_TYPE_INT,
- G_TYPE_INT);
-
- signals[BSS_CHANGED] = g_signal_new(NM_SUPPLICANT_INTERFACE_BSS_CHANGED,
- G_OBJECT_CLASS_TYPE(object_class),
- G_SIGNAL_RUN_LAST,
- 0,
- NULL,
- NULL,
- NULL,
- G_TYPE_NONE,
- 2,
- G_TYPE_POINTER,
- G_TYPE_BOOLEAN);
-
- signals[PEER_CHANGED] = g_signal_new(NM_SUPPLICANT_INTERFACE_PEER_CHANGED,
- G_OBJECT_CLASS_TYPE(object_class),
- G_SIGNAL_RUN_LAST,
- 0,
- NULL,
- NULL,
- NULL,
- G_TYPE_NONE,
- 2,
- G_TYPE_POINTER,
- G_TYPE_BOOLEAN);
-
- signals[WPS_CREDENTIALS] = g_signal_new(NM_SUPPLICANT_INTERFACE_WPS_CREDENTIALS,
- G_OBJECT_CLASS_TYPE(object_class),
- G_SIGNAL_RUN_LAST,
- 0,
- NULL,
- NULL,
- NULL,
- G_TYPE_NONE,
- 1,
- G_TYPE_VARIANT);
-
- signals[GROUP_STARTED] = g_signal_new(NM_SUPPLICANT_INTERFACE_GROUP_STARTED,
- G_OBJECT_CLASS_TYPE(object_class),
- G_SIGNAL_RUN_LAST,
- 0,
- NULL,
- NULL,
- NULL,
- G_TYPE_NONE,
- 1,
- NM_TYPE_SUPPLICANT_INTERFACE);
-
- signals[GROUP_FINISHED] = g_signal_new(NM_SUPPLICANT_INTERFACE_GROUP_FINISHED,
- G_OBJECT_CLASS_TYPE(object_class),
- G_SIGNAL_RUN_LAST,
- 0,
- NULL,
- NULL,
- NULL,
- G_TYPE_NONE,
- 1,
- G_TYPE_STRING);
-}