diff options
Diffstat (limited to 'src/supplicant/nm-supplicant-interface.c')
| -rw-r--r-- | src/supplicant/nm-supplicant-interface.c | 3475 |
1 files changed, 0 insertions, 3475 deletions
diff --git a/src/supplicant/nm-supplicant-interface.c b/src/supplicant/nm-supplicant-interface.c deleted file mode 100644 index 77254c7e..00000000 --- a/src/supplicant/nm-supplicant-interface.c +++ /dev/null @@ -1,3475 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * 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 "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; - 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 || priv->supp_state == NM_SUPPLICANT_INTERFACE_STATE_SCANNING); - - 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)) { - p_ap_flags = 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))) - || (!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; -} - -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, ¶meter); - - 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); -} |