diff options
Diffstat (limited to 'src/core/devices/wifi/nm-wifi-p2p-peer.c')
| -rw-r--r-- | src/core/devices/wifi/nm-wifi-p2p-peer.c | 699 |
1 files changed, 699 insertions, 0 deletions
diff --git a/src/core/devices/wifi/nm-wifi-p2p-peer.c b/src/core/devices/wifi/nm-wifi-p2p-peer.c new file mode 100644 index 00000000..8488f32d --- /dev/null +++ b/src/core/devices/wifi/nm-wifi-p2p-peer.c @@ -0,0 +1,699 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2018 Red Hat, Inc. + */ + +#include "src/core/nm-default-daemon.h" + +#include "nm-wifi-p2p-peer.h" + +#include <stdlib.h> +#include <linux/if_ether.h> + +#include "NetworkManagerUtils.h" +#include "devices/nm-device.h" +#include "nm-core-internal.h" +#include "nm-dbus-manager.h" +#include "nm-glib-aux/nm-ref-string.h" +#include "nm-setting-wireless.h" +#include "nm-utils.h" +#include "nm-wifi-utils.h" +#include "platform/nm-platform.h" +#include "supplicant/nm-supplicant-types.h" + +/*****************************************************************************/ + +NM_GOBJECT_PROPERTIES_DEFINE(NMWifiP2PPeer, + PROP_NAME, + PROP_MANUFACTURER, + PROP_MODEL, + PROP_MODEL_NUMBER, + PROP_SERIAL, + PROP_WFD_IES, + PROP_HW_ADDRESS, + PROP_STRENGTH, + PROP_LAST_SEEN, + PROP_FLAGS, ); + +struct _NMWifiP2PPeerPrivate { + NMRefString *supplicant_path; /* D-Bus object path of this Peer from wpa_supplicant */ + + /* Scanned or cached values */ + char *name; + char *manufacturer; + char *model; + char *model_number; + char *serial; + + char *address; + + GBytes *wfd_ies; + + const char **groups; + + guint8 strength; + + NM80211ApFlags flags; /* General flags */ + + /* Non-scanned attributes */ + gint32 + last_seen; /* Timestamp when the Peer was seen lastly (obtained via nm_utils_get_monotonic_timestamp_sec()) */ +}; + +typedef struct _NMWifiP2PPeerPrivate NMWifiP2PPeerPrivate; + +struct _NMWifiP2PPeerClass { + NMDBusObjectClass parent; +}; + +G_DEFINE_TYPE(NMWifiP2PPeer, nm_wifi_p2p_peer, NM_TYPE_DBUS_OBJECT) + +#define NM_WIFI_P2P_PEER_GET_PRIVATE(self) \ + _NM_GET_PRIVATE_PTR(self, NMWifiP2PPeer, NM_IS_WIFI_P2P_PEER) + +/*****************************************************************************/ + +const char ** +nm_wifi_p2p_peers_get_paths(const CList *peers_lst_head) +{ + NMWifiP2PPeer *peer; + const char ** list; + const char * path; + gsize i, n; + + n = c_list_length(peers_lst_head); + list = g_new(const char *, n + 1); + + i = 0; + if (n > 0) { + c_list_for_each_entry (peer, peers_lst_head, peers_lst) { + nm_assert(i < n); + path = nm_dbus_object_get_path(NM_DBUS_OBJECT(peer)); + nm_assert(path); + + list[i++] = path; + } + nm_assert(i <= n); + } + list[i] = NULL; + return list; +} + +NMWifiP2PPeer * +nm_wifi_p2p_peers_find_first_compatible(const CList *peers_lst_head, NMConnection *connection) +{ + NMWifiP2PPeer *peer; + + g_return_val_if_fail(connection, NULL); + + c_list_for_each_entry (peer, peers_lst_head, peers_lst) { + if (nm_wifi_p2p_peer_check_compatible(peer, connection)) + return peer; + } + return NULL; +} + +NMWifiP2PPeer * +nm_wifi_p2p_peers_find_by_supplicant_path(const CList *peers_lst_head, const char *path) +{ + NMWifiP2PPeer *peer; + + g_return_val_if_fail(path != NULL, NULL); + + c_list_for_each_entry (peer, peers_lst_head, peers_lst) { + if (nm_streq0(path, nm_wifi_p2p_peer_get_supplicant_path(peer))) + return peer; + } + return NULL; +} + +/*****************************************************************************/ + +NMWifiP2PPeer * +nm_wifi_p2p_peer_lookup_for_device(NMDevice *device, const char *exported_path) +{ + NMWifiP2PPeer *peer; + + g_return_val_if_fail(NM_IS_DEVICE(device), NULL); + + peer = (NMWifiP2PPeer *) nm_dbus_manager_lookup_object( + nm_dbus_object_get_manager(NM_DBUS_OBJECT(device)), + exported_path); + if (!peer || !NM_IS_WIFI_P2P_PEER(peer) || peer->wifi_device != device) + return NULL; + + return peer; +} + +/*****************************************************************************/ + +const char * +nm_wifi_p2p_peer_get_supplicant_path(NMWifiP2PPeer *peer) +{ + g_return_val_if_fail(NM_IS_WIFI_P2P_PEER(peer), NULL); + + return nm_ref_string_get_str(NM_WIFI_P2P_PEER_GET_PRIVATE(peer)->supplicant_path); +} + +const char * +nm_wifi_p2p_peer_get_name(const NMWifiP2PPeer *peer) +{ + g_return_val_if_fail(NM_IS_WIFI_P2P_PEER(peer), NULL); + + return NM_WIFI_P2P_PEER_GET_PRIVATE(peer)->name; +} + +gboolean +nm_wifi_p2p_peer_set_name(NMWifiP2PPeer *peer, const char *str) +{ + NMWifiP2PPeerPrivate *priv = NM_WIFI_P2P_PEER_GET_PRIVATE(peer); + + if (!nm_utils_strdup_reset(&priv->name, str)) + return FALSE; + _notify(peer, PROP_NAME); + return TRUE; +} + +const char * +nm_wifi_p2p_peer_get_manufacturer(const NMWifiP2PPeer *peer) +{ + g_return_val_if_fail(NM_IS_WIFI_P2P_PEER(peer), NULL); + + return NM_WIFI_P2P_PEER_GET_PRIVATE(peer)->manufacturer; +} + +gboolean +nm_wifi_p2p_peer_set_manufacturer(NMWifiP2PPeer *peer, const char *str) +{ + NMWifiP2PPeerPrivate *priv = NM_WIFI_P2P_PEER_GET_PRIVATE(peer); + + if (!nm_utils_strdup_reset(&priv->manufacturer, str)) + return FALSE; + _notify(peer, PROP_MANUFACTURER); + return TRUE; +} + +const char * +nm_wifi_p2p_peer_get_model(const NMWifiP2PPeer *peer) +{ + g_return_val_if_fail(NM_IS_WIFI_P2P_PEER(peer), NULL); + + return NM_WIFI_P2P_PEER_GET_PRIVATE(peer)->model; +} + +gboolean +nm_wifi_p2p_peer_set_model(NMWifiP2PPeer *peer, const char *str) +{ + NMWifiP2PPeerPrivate *priv = NM_WIFI_P2P_PEER_GET_PRIVATE(peer); + + if (!nm_utils_strdup_reset(&priv->model, str)) + return FALSE; + _notify(peer, PROP_MODEL); + return TRUE; +} + +const char * +nm_wifi_p2p_peer_get_model_number(const NMWifiP2PPeer *peer) +{ + g_return_val_if_fail(NM_IS_WIFI_P2P_PEER(peer), NULL); + + return NM_WIFI_P2P_PEER_GET_PRIVATE(peer)->model_number; +} + +gboolean +nm_wifi_p2p_peer_set_model_number(NMWifiP2PPeer *peer, const char *str) +{ + NMWifiP2PPeerPrivate *priv = NM_WIFI_P2P_PEER_GET_PRIVATE(peer); + + if (!nm_utils_strdup_reset(&priv->model_number, str)) + return FALSE; + _notify(peer, PROP_MODEL_NUMBER); + return TRUE; +} + +const char * +nm_wifi_p2p_peer_get_serial(const NMWifiP2PPeer *peer) +{ + g_return_val_if_fail(NM_IS_WIFI_P2P_PEER(peer), NULL); + + return NM_WIFI_P2P_PEER_GET_PRIVATE(peer)->serial; +} + +gboolean +nm_wifi_p2p_peer_set_serial(NMWifiP2PPeer *peer, const char *str) +{ + NMWifiP2PPeerPrivate *priv = NM_WIFI_P2P_PEER_GET_PRIVATE(peer); + + if (!nm_utils_strdup_reset(&priv->serial, str)) + return FALSE; + _notify(peer, PROP_SERIAL); + return TRUE; +} + +GBytes * +nm_wifi_p2p_peer_get_wfd_ies(const NMWifiP2PPeer *peer) +{ + g_return_val_if_fail(NM_IS_WIFI_P2P_PEER(peer), NULL); + + return NM_WIFI_P2P_PEER_GET_PRIVATE(peer)->wfd_ies; +} + +gboolean +nm_wifi_p2p_peer_set_wfd_ies(NMWifiP2PPeer *peer, GBytes *wfd_ies) +{ + NMWifiP2PPeerPrivate *priv; + gs_unref_bytes GBytes *wfd_ies_old = NULL; + + g_return_val_if_fail(NM_IS_WIFI_P2P_PEER(peer), FALSE); + + priv = NM_WIFI_P2P_PEER_GET_PRIVATE(peer); + + if (nm_gbytes_equal0(priv->wfd_ies, wfd_ies)) + return FALSE; + + wfd_ies_old = g_steal_pointer(&priv->wfd_ies); + priv->wfd_ies = wfd_ies ? g_bytes_ref(wfd_ies) : NULL; + + _notify(peer, PROP_WFD_IES); + return TRUE; +} + +const char *const * +nm_wifi_p2p_peer_get_groups(const NMWifiP2PPeer *peer) +{ + g_return_val_if_fail(NM_IS_WIFI_P2P_PEER(peer), NULL); + + return NM_WIFI_P2P_PEER_GET_PRIVATE(peer)->groups; +} + +const char * +nm_wifi_p2p_peer_get_address(const NMWifiP2PPeer *peer) +{ + g_return_val_if_fail(NM_IS_WIFI_P2P_PEER(peer), NULL); + + return NM_WIFI_P2P_PEER_GET_PRIVATE(peer)->address; +} + +static gboolean +nm_wifi_p2p_peer_set_address_bin(NMWifiP2PPeer *peer, const guint8 addr[static ETH_ALEN]) +{ + NMWifiP2PPeerPrivate *priv = NM_WIFI_P2P_PEER_GET_PRIVATE(peer); + + if (priv->address && nm_utils_hwaddr_matches(addr, ETH_ALEN, priv->address, -1)) + return FALSE; + + g_free(priv->address); + priv->address = nm_utils_hwaddr_ntoa(addr, ETH_ALEN); + _notify(peer, PROP_HW_ADDRESS); + return TRUE; +} + +gboolean +nm_wifi_p2p_peer_set_address(NMWifiP2PPeer *peer, const char *addr) +{ + guint8 addr_buf[ETH_ALEN]; + + g_return_val_if_fail(NM_IS_WIFI_P2P_PEER(peer), FALSE); + + if (!addr || !nm_utils_hwaddr_aton(addr, addr_buf, sizeof(addr_buf))) + g_return_val_if_reached(FALSE); + + return nm_wifi_p2p_peer_set_address_bin(peer, addr_buf); +} + +gint8 +nm_wifi_p2p_peer_get_strength(NMWifiP2PPeer *peer) +{ + g_return_val_if_fail(NM_IS_WIFI_P2P_PEER(peer), 0); + + return NM_WIFI_P2P_PEER_GET_PRIVATE(peer)->strength; +} + +gboolean +nm_wifi_p2p_peer_set_strength(NMWifiP2PPeer *peer, const gint8 strength) +{ + NMWifiP2PPeerPrivate *priv = NM_WIFI_P2P_PEER_GET_PRIVATE(peer); + + if (priv->strength != strength) { + priv->strength = strength; + _notify(peer, PROP_STRENGTH); + return TRUE; + } + return FALSE; +} + +NM80211ApFlags +nm_wifi_p2p_peer_get_flags(const NMWifiP2PPeer *peer) +{ + g_return_val_if_fail(NM_IS_WIFI_P2P_PEER(peer), NM_802_11_AP_FLAGS_NONE); + + return NM_WIFI_P2P_PEER_GET_PRIVATE(peer)->flags; +} + +static gboolean +nm_wifi_p2p_peer_set_last_seen(NMWifiP2PPeer *peer, gint32 last_seen) +{ + NMWifiP2PPeerPrivate *priv; + + g_return_val_if_fail(NM_IS_WIFI_P2P_PEER(peer), FALSE); + + priv = NM_WIFI_P2P_PEER_GET_PRIVATE(peer); + + if (priv->last_seen != last_seen) { + priv->last_seen = last_seen; + _notify(peer, PROP_LAST_SEEN); + return TRUE; + } + return FALSE; +} + +/*****************************************************************************/ + +gboolean +nm_wifi_p2p_peer_update_from_properties(NMWifiP2PPeer *peer, const NMSupplicantPeerInfo *peer_info) +{ + NMWifiP2PPeerPrivate *priv; + gboolean changed = FALSE; + + g_return_val_if_fail(NM_IS_WIFI_P2P_PEER(peer), FALSE); + g_return_val_if_fail(peer_info, FALSE); + nm_assert(NM_IS_REF_STRING(peer_info->peer_path)); + + priv = NM_WIFI_P2P_PEER_GET_PRIVATE(peer); + + nm_assert(!priv->supplicant_path || priv->supplicant_path == peer_info->peer_path); + + g_object_freeze_notify(G_OBJECT(peer)); + + if (!priv->supplicant_path) { + priv->supplicant_path = nm_ref_string_ref(peer_info->peer_path); + changed = TRUE; + } + + changed |= nm_wifi_p2p_peer_set_strength(peer, peer_info->signal_percent); + changed |= nm_wifi_p2p_peer_set_name(peer, peer_info->device_name); + changed |= nm_wifi_p2p_peer_set_manufacturer(peer, peer_info->manufacturer); + changed |= nm_wifi_p2p_peer_set_model(peer, peer_info->model); + changed |= nm_wifi_p2p_peer_set_model_number(peer, peer_info->model_number); + changed |= nm_wifi_p2p_peer_set_serial(peer, peer_info->serial); + + if (peer_info->address_valid) + changed |= nm_wifi_p2p_peer_set_address_bin(peer, peer_info->address); + else { + /* we don't reset the address. */ + } + + changed |= nm_wifi_p2p_peer_set_wfd_ies(peer, peer_info->ies); + changed |= nm_wifi_p2p_peer_set_last_seen(peer, peer_info->last_seen_msec / 1000u); + + /* We currently only use the groups information internally to check if + * the peer is still joined. */ + if (!nm_utils_strv_equal(priv->groups, peer_info->groups)) { + g_free(priv->groups); + priv->groups = nm_utils_strv_dup_packed(peer_info->groups, -1); + changed |= TRUE; + } + + g_object_thaw_notify(G_OBJECT(peer)); + + return changed; +} + +const char * +nm_wifi_p2p_peer_to_string(const NMWifiP2PPeer *self, char *str_buf, gsize buf_len, gint32 now_s) +{ + const NMWifiP2PPeerPrivate *priv; + const char * supplicant_id = "-"; + const char * export_path; + + g_return_val_if_fail(NM_IS_WIFI_P2P_PEER(self), NULL); + + priv = NM_WIFI_P2P_PEER_GET_PRIVATE(self); + + if (priv->supplicant_path) + supplicant_id = strrchr(priv->supplicant_path->str, '/') ?: supplicant_id; + + export_path = nm_dbus_object_get_path(NM_DBUS_OBJECT(self)); + if (export_path) + export_path = strrchr(export_path, '/') ?: export_path; + else + export_path = "/"; + + g_snprintf(str_buf, + buf_len, + "%17s [n:%s, m:%s, mod:%s, mod_num:%s, ser:%s] %3us sup:%s [nm:%s]", + priv->address ?: "(none)", + priv->name, + priv->manufacturer, + priv->model, + priv->model_number, + priv->serial, + priv->last_seen > 0 ? ((now_s > 0 ? now_s : nm_utils_get_monotonic_timestamp_sec()) + - priv->last_seen) + : -1, + supplicant_id, + export_path); + + return str_buf; +} + +gboolean +nm_wifi_p2p_peer_check_compatible(NMWifiP2PPeer *self, NMConnection *connection) +{ + NMWifiP2PPeerPrivate *priv; + NMSettingWifiP2P * s_wifi_p2p; + const char * hwaddr; + + g_return_val_if_fail(NM_IS_WIFI_P2P_PEER(self), FALSE); + g_return_val_if_fail(NM_IS_CONNECTION(connection), FALSE); + + priv = NM_WIFI_P2P_PEER_GET_PRIVATE(self); + + s_wifi_p2p = + NM_SETTING_WIFI_P2P(nm_connection_get_setting(connection, NM_TYPE_SETTING_WIFI_P2P)); + if (s_wifi_p2p == NULL) + return FALSE; + + hwaddr = nm_setting_wifi_p2p_get_peer(s_wifi_p2p); + if (hwaddr && (!priv->address || !nm_utils_hwaddr_matches(hwaddr, -1, priv->address, -1))) + return FALSE; + + return TRUE; +} + +/*****************************************************************************/ + +static void +get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + NMWifiP2PPeer * self = NM_WIFI_P2P_PEER(object); + NMWifiP2PPeerPrivate *priv = NM_WIFI_P2P_PEER_GET_PRIVATE(self); + + switch (prop_id) { + case PROP_FLAGS: + g_value_set_uint(value, priv->flags); + break; + case PROP_NAME: + g_value_set_string(value, priv->name); + break; + case PROP_MANUFACTURER: + g_value_set_string(value, priv->manufacturer); + break; + case PROP_MODEL: + g_value_set_string(value, priv->model); + break; + case PROP_MODEL_NUMBER: + g_value_set_string(value, priv->model_number); + break; + case PROP_SERIAL: + g_value_set_string(value, priv->serial); + break; + case PROP_WFD_IES: + g_value_take_variant(value, nm_utils_gbytes_to_variant_ay(priv->wfd_ies)); + break; + case PROP_HW_ADDRESS: + g_value_set_string(value, priv->address); + break; + case PROP_STRENGTH: + g_value_set_uchar(value, priv->strength); + break; + case PROP_LAST_SEEN: + g_value_set_int(value, + priv->last_seen > 0 + ? (int) nm_utils_monotonic_timestamp_as_boottime(priv->last_seen, + NM_UTILS_NSEC_PER_SEC) + : -1); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +/*****************************************************************************/ + +static void +nm_wifi_p2p_peer_init(NMWifiP2PPeer *self) +{ + NMWifiP2PPeerPrivate *priv; + + priv = G_TYPE_INSTANCE_GET_PRIVATE(self, NM_TYPE_WIFI_P2P_PEER, NMWifiP2PPeerPrivate); + + self->_priv = priv; + + c_list_init(&self->peers_lst); + + priv->flags = NM_802_11_AP_FLAGS_NONE; + priv->last_seen = -1; +} + +NMWifiP2PPeer * +nm_wifi_p2p_peer_new_from_properties(const NMSupplicantPeerInfo *peer_info) +{ + NMWifiP2PPeer *peer; + + g_return_val_if_fail(peer_info, NULL); + + peer = g_object_new(NM_TYPE_WIFI_P2P_PEER, NULL); + nm_wifi_p2p_peer_update_from_properties(peer, peer_info); + return peer; +} + +static void +finalize(GObject *object) +{ + NMWifiP2PPeer * self = NM_WIFI_P2P_PEER(object); + NMWifiP2PPeerPrivate *priv = NM_WIFI_P2P_PEER_GET_PRIVATE(self); + + nm_assert(!self->wifi_device); + nm_assert(c_list_is_empty(&self->peers_lst)); + + nm_ref_string_unref(priv->supplicant_path); + g_free(priv->name); + g_free(priv->manufacturer); + g_free(priv->model); + g_free(priv->model_number); + g_free(priv->serial); + g_free(priv->address); + g_bytes_unref(priv->wfd_ies); + g_free(priv->groups); + + G_OBJECT_CLASS(nm_wifi_p2p_peer_parent_class)->finalize(object); +} + +static const NMDBusInterfaceInfoExtended interface_info_p2p_peer = { + .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( + NM_DBUS_INTERFACE_WIFI_P2P_PEER, + .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( + /* Before 1.24, we wrongly exposed a property "Groups" of type "as". Don't reuse that property name. */ + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Flags", "u", NM_WIFI_P2P_PEER_FLAGS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Name", "s", NM_WIFI_P2P_PEER_NAME), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Manufacturer", + "s", + NM_WIFI_P2P_PEER_MANUFACTURER), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Model", "s", NM_WIFI_P2P_PEER_MODEL), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("ModelNumber", + "s", + NM_WIFI_P2P_PEER_MODEL_NUMBER), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Serial", "s", NM_WIFI_P2P_PEER_SERIAL), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("WfdIEs", + "ay", + NM_WIFI_P2P_PEER_WFD_IES), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("HwAddress", + "s", + NM_WIFI_P2P_PEER_HW_ADDRESS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Strength", + "y", + NM_WIFI_P2P_PEER_STRENGTH), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("LastSeen", + "i", + NM_WIFI_P2P_PEER_LAST_SEEN), ), ), + .legacy_property_changed = FALSE, +}; + +static void +nm_wifi_p2p_peer_class_init(NMWifiP2PPeerClass *klass) +{ + GObjectClass * object_class = G_OBJECT_CLASS(klass); + NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(klass); + + g_type_class_add_private(object_class, sizeof(NMWifiP2PPeerPrivate)); + + dbus_object_class->export_path = NM_DBUS_EXPORT_PATH_NUMBERED(NM_DBUS_PATH_WIFI_P2P_PEER); + dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS(&interface_info_p2p_peer); + + object_class->get_property = get_property; + object_class->finalize = finalize; + + obj_properties[PROP_FLAGS] = g_param_spec_uint(NM_WIFI_P2P_PEER_FLAGS, + "", + "", + NM_802_11_AP_FLAGS_NONE, + NM_802_11_AP_FLAGS_PRIVACY, + NM_802_11_AP_FLAGS_NONE, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + obj_properties[PROP_NAME] = g_param_spec_string(NM_WIFI_P2P_PEER_NAME, + "", + "", + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + obj_properties[PROP_MANUFACTURER] = + g_param_spec_string(NM_WIFI_P2P_PEER_MANUFACTURER, + "", + "", + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + obj_properties[PROP_MODEL] = g_param_spec_string(NM_WIFI_P2P_PEER_MODEL, + "", + "", + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + obj_properties[PROP_MODEL_NUMBER] = + g_param_spec_string(NM_WIFI_P2P_PEER_MODEL_NUMBER, + "", + "", + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + obj_properties[PROP_SERIAL] = g_param_spec_string(NM_WIFI_P2P_PEER_SERIAL, + "", + "", + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + obj_properties[PROP_WFD_IES] = g_param_spec_variant(NM_WIFI_P2P_PEER_WFD_IES, + "", + "", + G_VARIANT_TYPE("ay"), + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + obj_properties[PROP_HW_ADDRESS] = + g_param_spec_string(NM_WIFI_P2P_PEER_HW_ADDRESS, + "", + "", + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + obj_properties[PROP_STRENGTH] = g_param_spec_uchar(NM_WIFI_P2P_PEER_STRENGTH, + "", + "", + 0, + G_MAXINT8, + 0, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + obj_properties[PROP_LAST_SEEN] = g_param_spec_int(NM_WIFI_P2P_PEER_LAST_SEEN, + "", + "", + -1, + G_MAXINT, + -1, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); +} |