/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (C) 2004 - 2017 Red Hat, Inc. * Copyright (C) 2006 - 2008 Novell, Inc. */ #include "src/core/nm-default-daemon.h" #include "nm-wifi-ap.h" #include #include #include "NetworkManagerUtils.h" #include "devices/nm-device.h" #include "libnm-core-intern/nm-core-internal.h" #include "nm-dbus-manager.h" #include "libnm-glib-aux/nm-ref-string.h" #include "nm-setting-wireless.h" #include "nm-utils.h" #include "nm-wifi-utils.h" #include "libnm-platform/nm-platform.h" #include "supplicant/nm-supplicant-interface.h" #define PROTO_WPA "wpa" #define PROTO_RSN "rsn" /*****************************************************************************/ NM_GOBJECT_PROPERTIES_DEFINE(NMWifiAP, PROP_FLAGS, PROP_WPA_FLAGS, PROP_RSN_FLAGS, PROP_SSID, PROP_FREQUENCY, PROP_HW_ADDRESS, PROP_MODE, PROP_MAX_BITRATE, PROP_STRENGTH, PROP_LAST_SEEN, ); struct _NMWifiAPPrivate { /* Scanned or cached values */ GBytes *ssid; char *address; _NM80211Mode mode; guint8 strength; guint32 freq; /* Frequency in MHz; ie 2412 (== 2.412 GHz) */ guint32 max_bitrate; /* Maximum bitrate of the AP in Kbit/s (ie 54000 Kb/s == 54Mbit/s) */ gint64 last_seen_msec; /* Timestamp when the AP was seen lastly (in nm_utils_get_monotonic_timestamp_*() scale). * Note that this value might be negative! */ NM80211ApFlags flags; /* General flags */ NM80211ApSecurityFlags wpa_flags; /* WPA-related flags */ NM80211ApSecurityFlags rsn_flags; /* RSN (WPA2) -related flags */ bool metered : 1; /* Non-scanned attributes */ bool fake : 1; /* Whether or not the AP is from a scan */ bool hotspot : 1; /* Whether the AP is a local device's hotspot network */ }; typedef struct _NMWifiAPPrivate NMWifiAPPrivate; struct _NMWifiAPClass { NMDBusObjectClass parent; }; G_DEFINE_TYPE(NMWifiAP, nm_wifi_ap, NM_TYPE_DBUS_OBJECT) #define NM_WIFI_AP_GET_PRIVATE(self) _NM_GET_PRIVATE_PTR(self, NMWifiAP, NM_IS_WIFI_AP) /*****************************************************************************/ GBytes * nm_wifi_ap_get_ssid(const NMWifiAP *ap) { g_return_val_if_fail(NM_IS_WIFI_AP(ap), NULL); return NM_WIFI_AP_GET_PRIVATE(ap)->ssid; } gboolean nm_wifi_ap_set_ssid(NMWifiAP *ap, GBytes *ssid) { NMWifiAPPrivate *priv; gsize l; g_return_val_if_fail(NM_IS_WIFI_AP(ap), FALSE); if (!ssid) { /* we don't clear the SSID, once we have it. We can only update * it by a better value. */ return FALSE; } l = g_bytes_get_size(ssid); if (l == 0 || l > NM_IW_ESSID_MAX_SIZE) g_return_val_if_reached(FALSE); priv = NM_WIFI_AP_GET_PRIVATE(ap); if (ssid == priv->ssid) return FALSE; if (priv->ssid && g_bytes_equal(ssid, priv->ssid)) return FALSE; g_bytes_ref(ssid); nm_clear_pointer(&priv->ssid, g_bytes_unref); priv->ssid = ssid; _notify(ap, PROP_SSID); return TRUE; } static gboolean nm_wifi_ap_set_flags(NMWifiAP *ap, NM80211ApFlags flags) { NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE(ap); if (priv->flags != flags) { priv->flags = flags; _notify(ap, PROP_FLAGS); return TRUE; } return FALSE; } static gboolean nm_wifi_ap_set_wpa_flags(NMWifiAP *ap, NM80211ApSecurityFlags flags) { NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE(ap); if (priv->wpa_flags != flags) { priv->wpa_flags = flags; _notify(ap, PROP_WPA_FLAGS); return TRUE; } return FALSE; } static gboolean nm_wifi_ap_set_rsn_flags(NMWifiAP *ap, NM80211ApSecurityFlags flags) { NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE(ap); if (priv->rsn_flags != flags) { priv->rsn_flags = flags; _notify(ap, PROP_RSN_FLAGS); return TRUE; } return FALSE; } const char * nm_wifi_ap_get_address(const NMWifiAP *ap) { g_return_val_if_fail(NM_IS_WIFI_AP(ap), NULL); return NM_WIFI_AP_GET_PRIVATE(ap)->address; } gboolean nm_wifi_ap_set_address_bin(NMWifiAP *ap, const NMEtherAddr *addr) { NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE(ap); nm_assert(addr); if (!priv->address || !nm_utils_hwaddr_matches(addr, ETH_ALEN, priv->address, -1)) { g_free(priv->address); priv->address = nm_utils_hwaddr_ntoa(addr, ETH_ALEN); _notify(ap, PROP_HW_ADDRESS); return TRUE; } return FALSE; } gboolean nm_wifi_ap_set_address(NMWifiAP *ap, const char *addr) { NMEtherAddr addr_buf; g_return_val_if_fail(NM_IS_WIFI_AP(ap), FALSE); if (!addr || !nm_utils_hwaddr_aton(addr, &addr_buf, sizeof(addr_buf))) g_return_val_if_reached(FALSE); return nm_wifi_ap_set_address_bin(ap, &addr_buf); } _NM80211Mode nm_wifi_ap_get_mode(NMWifiAP *ap) { g_return_val_if_fail(NM_IS_WIFI_AP(ap), _NM_802_11_MODE_UNKNOWN); return NM_WIFI_AP_GET_PRIVATE(ap)->mode; } static gboolean nm_wifi_ap_set_mode(NMWifiAP *ap, _NM80211Mode mode) { NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE(ap); nm_assert(NM_IN_SET(mode, _NM_802_11_MODE_UNKNOWN, _NM_802_11_MODE_ADHOC, _NM_802_11_MODE_INFRA, _NM_802_11_MODE_MESH)); if (priv->mode != mode) { priv->mode = mode; _notify(ap, PROP_MODE); return TRUE; } return FALSE; } gboolean nm_wifi_ap_is_hotspot(NMWifiAP *ap) { g_return_val_if_fail(NM_IS_WIFI_AP(ap), FALSE); return NM_WIFI_AP_GET_PRIVATE(ap)->hotspot; } gint8 nm_wifi_ap_get_strength(NMWifiAP *ap) { g_return_val_if_fail(NM_IS_WIFI_AP(ap), 0); return NM_WIFI_AP_GET_PRIVATE(ap)->strength; } gboolean nm_wifi_ap_set_strength(NMWifiAP *ap, gint8 strength) { NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE(ap); if (priv->strength != strength) { priv->strength = strength; _notify(ap, PROP_STRENGTH); return TRUE; } return FALSE; } guint32 nm_wifi_ap_get_freq(NMWifiAP *ap) { g_return_val_if_fail(NM_IS_WIFI_AP(ap), 0); return NM_WIFI_AP_GET_PRIVATE(ap)->freq; } gboolean nm_wifi_ap_set_freq(NMWifiAP *ap, guint32 freq) { NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE(ap); if (priv->freq != freq) { priv->freq = freq; _notify(ap, PROP_FREQUENCY); return TRUE; } return FALSE; } guint32 nm_wifi_ap_get_max_bitrate(NMWifiAP *ap) { g_return_val_if_fail(NM_IS_WIFI_AP(ap), 0); g_return_val_if_fail(nm_dbus_object_is_exported(NM_DBUS_OBJECT(ap)), 0); return NM_WIFI_AP_GET_PRIVATE(ap)->max_bitrate; } gboolean nm_wifi_ap_set_max_bitrate(NMWifiAP *ap, guint32 bitrate) { NMWifiAPPrivate *priv; g_return_val_if_fail(NM_IS_WIFI_AP(ap), FALSE); priv = NM_WIFI_AP_GET_PRIVATE(ap); if (priv->max_bitrate != bitrate) { priv->max_bitrate = bitrate; _notify(ap, PROP_MAX_BITRATE); return TRUE; } return FALSE; } gboolean nm_wifi_ap_get_fake(const NMWifiAP *ap) { g_return_val_if_fail(NM_IS_WIFI_AP(ap), FALSE); return NM_WIFI_AP_GET_PRIVATE(ap)->fake; } gboolean nm_wifi_ap_set_fake(NMWifiAP *ap, gboolean fake) { NMWifiAPPrivate *priv; g_return_val_if_fail(NM_IS_WIFI_AP(ap), FALSE); priv = NM_WIFI_AP_GET_PRIVATE(ap); if (priv->fake != !!fake) { priv->fake = fake; return TRUE; } return FALSE; } NM80211ApFlags nm_wifi_ap_get_flags(const NMWifiAP *ap) { g_return_val_if_fail(NM_IS_WIFI_AP(ap), NM_802_11_AP_FLAGS_NONE); return NM_WIFI_AP_GET_PRIVATE(ap)->flags; } static gboolean nm_wifi_ap_set_last_seen(NMWifiAP *ap, gint32 last_seen_msec) { NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE(ap); if (priv->last_seen_msec != last_seen_msec) { priv->last_seen_msec = last_seen_msec; _notify(ap, PROP_LAST_SEEN); return TRUE; } return FALSE; } gboolean nm_wifi_ap_get_metered(const NMWifiAP *self) { return NM_WIFI_AP_GET_PRIVATE(self)->metered; } NM80211ApSecurityFlags nm_wifi_ap_get_wpa_flags(const NMWifiAP *self) { return NM_WIFI_AP_GET_PRIVATE(self)->wpa_flags; } NM80211ApSecurityFlags nm_wifi_ap_get_rsn_flags(const NMWifiAP *self) { return NM_WIFI_AP_GET_PRIVATE(self)->rsn_flags; } /*****************************************************************************/ gboolean nm_wifi_ap_update_from_properties(NMWifiAP *ap, const NMSupplicantBssInfo *bss_info) { NMWifiAPPrivate *priv; gboolean changed = FALSE; g_return_val_if_fail(NM_IS_WIFI_AP(ap), FALSE); g_return_val_if_fail(bss_info, FALSE); nm_assert(NM_IS_REF_STRING(bss_info->bss_path)); priv = NM_WIFI_AP_GET_PRIVATE(ap); nm_assert(!ap->_supplicant_path || ap->_supplicant_path == bss_info->bss_path); g_object_freeze_notify(G_OBJECT(ap)); if (!ap->_supplicant_path) { ap->_supplicant_path = nm_ref_string_ref(bss_info->bss_path); changed = TRUE; } changed |= nm_wifi_ap_set_flags(ap, bss_info->ap_flags); changed |= nm_wifi_ap_set_mode(ap, bss_info->mode); changed |= nm_wifi_ap_set_strength(ap, bss_info->signal_percent); changed |= nm_wifi_ap_set_freq(ap, bss_info->frequency); changed |= nm_wifi_ap_set_ssid(ap, bss_info->ssid); if (bss_info->bssid_valid) changed |= nm_wifi_ap_set_address_bin(ap, &bss_info->bssid); else { /* we don't actually clear the value. */ } changed |= nm_wifi_ap_set_max_bitrate(ap, bss_info->max_rate); if (priv->metered != bss_info->metered) { priv->metered = bss_info->metered; changed = TRUE; } changed |= nm_wifi_ap_set_wpa_flags(ap, bss_info->wpa_flags); changed |= nm_wifi_ap_set_rsn_flags(ap, bss_info->rsn_flags); changed |= nm_wifi_ap_set_last_seen(ap, bss_info->last_seen_msec); changed |= nm_wifi_ap_set_fake(ap, FALSE); g_object_thaw_notify(G_OBJECT(ap)); return changed; } static gboolean has_proto(NMSettingWirelessSecurity *sec, const char *proto) { guint32 num_protos = nm_setting_wireless_security_get_num_protos(sec); guint32 i; if (num_protos == 0) return TRUE; /* interpret no protos as "all" */ for (i = 0; i < num_protos; i++) { if (!strcmp(nm_setting_wireless_security_get_proto(sec, i), proto)) return TRUE; } return FALSE; } static void add_pair_ciphers(NMWifiAP *ap, NMSettingWirelessSecurity *sec) { NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE(ap); guint32 num = nm_setting_wireless_security_get_num_pairwise(sec); NM80211ApSecurityFlags flags = NM_802_11_AP_SEC_NONE; guint32 i; /* If no ciphers are specified, that means "all" WPA ciphers */ if (num == 0) { flags |= NM_802_11_AP_SEC_PAIR_TKIP | NM_802_11_AP_SEC_PAIR_CCMP; } else { for (i = 0; i < num; i++) { const char *cipher = nm_setting_wireless_security_get_pairwise(sec, i); if (!strcmp(cipher, "tkip")) flags |= NM_802_11_AP_SEC_PAIR_TKIP; else if (!strcmp(cipher, "ccmp")) flags |= NM_802_11_AP_SEC_PAIR_CCMP; } } if (has_proto(sec, PROTO_WPA)) nm_wifi_ap_set_wpa_flags(ap, priv->wpa_flags | flags); if (has_proto(sec, PROTO_RSN)) nm_wifi_ap_set_rsn_flags(ap, priv->rsn_flags | flags); } static void add_group_ciphers(NMWifiAP *ap, NMSettingWirelessSecurity *sec) { NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE(ap); guint32 num = nm_setting_wireless_security_get_num_groups(sec); NM80211ApSecurityFlags flags = NM_802_11_AP_SEC_NONE; guint32 i; /* If no ciphers are specified, that means "all" WPA ciphers */ if (num == 0) { flags |= NM_802_11_AP_SEC_GROUP_TKIP | NM_802_11_AP_SEC_GROUP_CCMP; } else { for (i = 0; i < num; i++) { const char *cipher = nm_setting_wireless_security_get_group(sec, i); if (!strcmp(cipher, "wep40")) flags |= NM_802_11_AP_SEC_GROUP_WEP40; else if (!strcmp(cipher, "wep104")) flags |= NM_802_11_AP_SEC_GROUP_WEP104; else if (!strcmp(cipher, "tkip")) flags |= NM_802_11_AP_SEC_GROUP_TKIP; else if (!strcmp(cipher, "ccmp")) flags |= NM_802_11_AP_SEC_GROUP_CCMP; } } if (has_proto(sec, PROTO_WPA)) nm_wifi_ap_set_wpa_flags(ap, priv->wpa_flags | flags); if (has_proto(sec, PROTO_RSN)) nm_wifi_ap_set_rsn_flags(ap, priv->rsn_flags | flags); } const char * nm_wifi_ap_to_string(const NMWifiAP *self, char *str_buf, gulong buf_len, gint64 now_msec) { const NMWifiAPPrivate *priv; const char *supplicant_id = "-"; const char *export_path; guint32 chan; gs_free char *ssid_to_free = NULL; char str_buf_ts[100]; g_return_val_if_fail(NM_IS_WIFI_AP(self), NULL); priv = NM_WIFI_AP_GET_PRIVATE(self); chan = nm_utils_wifi_freq_to_channel(priv->freq); if (self->_supplicant_path) supplicant_id = strrchr(self->_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 = "/"; nm_utils_get_monotonic_timestamp_msec_cached(&now_msec); g_snprintf( str_buf, buf_len, "%17s %-35s [ %c %3u %3u%% %c%c %c%c W:%04X R:%04X ] %s sup:%s [nm:%s]", priv->address ?: "(none)", (ssid_to_free = _nm_utils_ssid_to_string_gbytes(priv->ssid)), (priv->mode == _NM_802_11_MODE_ADHOC ? '*' : (priv->hotspot ? '#' : (priv->fake ? 'f' : (priv->mode == _NM_802_11_MODE_MESH ? 'm' : 'a')))), chan, priv->strength, priv->flags & NM_802_11_AP_FLAGS_PRIVACY ? 'P' : '_', priv->metered ? 'M' : '_', priv->flags & NM_802_11_AP_FLAGS_WPS ? 'W' : '_', priv->flags & NM_802_11_AP_FLAGS_WPS_PIN ? 'p' : (priv->flags & NM_802_11_AP_FLAGS_WPS_PBC ? '#' : '_'), priv->wpa_flags & 0xFFFF, priv->rsn_flags & 0xFFFF, priv->last_seen_msec != G_MININT64 ? nm_sprintf_buf(str_buf_ts, "%3u.%03us", (guint) ((now_msec - priv->last_seen_msec) / 1000), (guint) ((now_msec - priv->last_seen_msec) % 1000)) : " ", supplicant_id, export_path); return str_buf; } static guint freq_to_band(guint32 freq) { if (freq >= 4915 && freq <= 5825) return 5; else if (freq >= 2412 && freq <= 2484) return 2; return 0; } gboolean nm_wifi_ap_check_compatible(NMWifiAP *self, NMConnection *connection) { NMWifiAPPrivate *priv; NMSettingWireless *s_wireless; NMSettingWirelessSecurity *s_wireless_sec; GBytes *ssid; const char *mode; const char *band; const char *bssid; guint32 channel; g_return_val_if_fail(NM_IS_WIFI_AP(self), FALSE); g_return_val_if_fail(NM_IS_CONNECTION(connection), FALSE); priv = NM_WIFI_AP_GET_PRIVATE(self); s_wireless = nm_connection_get_setting_wireless(connection); if (s_wireless == NULL) return FALSE; ssid = nm_setting_wireless_get_ssid(s_wireless); if (ssid != priv->ssid) { if (!ssid || !priv->ssid) return FALSE; if (!g_bytes_equal(ssid, priv->ssid)) return FALSE; } bssid = nm_setting_wireless_get_bssid(s_wireless); if (bssid && (!priv->address || !nm_utils_hwaddr_matches(bssid, -1, priv->address, -1))) return FALSE; mode = nm_setting_wireless_get_mode(s_wireless); if (mode) { if (!strcmp(mode, "infrastructure") && (priv->mode != _NM_802_11_MODE_INFRA)) return FALSE; if (!strcmp(mode, "adhoc") && (priv->mode != _NM_802_11_MODE_ADHOC)) return FALSE; if (!strcmp(mode, "ap") && (priv->mode != _NM_802_11_MODE_INFRA || priv->hotspot != TRUE)) return FALSE; if (!strcmp(mode, "mesh") && (priv->mode != _NM_802_11_MODE_MESH)) return FALSE; } band = nm_setting_wireless_get_band(s_wireless); if (band) { guint ap_band = freq_to_band(priv->freq); if (!strcmp(band, "a") && ap_band != 5) return FALSE; else if (!strcmp(band, "bg") && ap_band != 2) return FALSE; } channel = nm_setting_wireless_get_channel(s_wireless); if (channel) { guint32 ap_chan = nm_utils_wifi_freq_to_channel(priv->freq); if (channel != ap_chan) return FALSE; } s_wireless_sec = nm_connection_get_setting_wireless_security(connection); return nm_setting_wireless_ap_security_compatible(s_wireless, s_wireless_sec, priv->flags, priv->wpa_flags, priv->rsn_flags, NM_802_11_MODE_CAST(priv->mode)); } gboolean nm_wifi_ap_complete_connection(NMWifiAP *self, NMConnection *connection, gboolean lock_bssid, GError **error) { NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE(self); g_return_val_if_fail(connection != NULL, FALSE); return nm_wifi_utils_complete_connection(priv->ssid, priv->address, priv->mode, priv->freq, priv->flags, priv->wpa_flags, priv->rsn_flags, connection, lock_bssid, error); } /*****************************************************************************/ static void get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { NMWifiAP *self = NM_WIFI_AP(object); NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE(self); switch (prop_id) { case PROP_FLAGS: g_value_set_uint(value, priv->flags); break; case PROP_WPA_FLAGS: g_value_set_uint(value, priv->wpa_flags); break; case PROP_RSN_FLAGS: g_value_set_uint(value, priv->rsn_flags); break; case PROP_SSID: g_value_take_variant(value, nm_g_bytes_to_variant_ay(priv->ssid)); break; case PROP_FREQUENCY: g_value_set_uint(value, priv->freq); break; case PROP_HW_ADDRESS: g_value_set_string(value, priv->address); break; case PROP_MODE: g_value_set_uint(value, priv->mode); break; case PROP_MAX_BITRATE: g_value_set_uint(value, priv->max_bitrate); break; case PROP_STRENGTH: g_value_set_uchar(value, priv->strength); break; case PROP_LAST_SEEN: g_value_set_int(value, priv->last_seen_msec != G_MININT64 ? (int) NM_MAX( nm_utils_monotonic_timestamp_as_boottime(priv->last_seen_msec, NM_UTILS_NSEC_PER_MSEC) / 1000, 1) : -1); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); break; } } /*****************************************************************************/ static void nm_wifi_ap_init(NMWifiAP *self) { NMWifiAPPrivate *priv; priv = G_TYPE_INSTANCE_GET_PRIVATE(self, NM_TYPE_WIFI_AP, NMWifiAPPrivate); self->_priv = priv; c_list_init(&self->aps_lst); priv->mode = _NM_802_11_MODE_INFRA; priv->flags = NM_802_11_AP_FLAGS_NONE; priv->wpa_flags = NM_802_11_AP_SEC_NONE; priv->rsn_flags = NM_802_11_AP_SEC_NONE; priv->last_seen_msec = G_MININT64; } NMWifiAP * nm_wifi_ap_new_from_properties(const NMSupplicantBssInfo *bss_info) { NMWifiAP *ap; ap = g_object_new(NM_TYPE_WIFI_AP, NULL); nm_wifi_ap_update_from_properties(ap, bss_info); return ap; } NMWifiAP * nm_wifi_ap_new_fake_from_connection(NMConnection *connection) { NMWifiAP *ap; NMWifiAPPrivate *priv; NMSettingWireless *s_wireless; NMSettingWirelessSecurity *s_wireless_sec; const char *mode, *band, *key_mgmt; guint32 channel; NM80211ApSecurityFlags flags; gboolean psk = FALSE, eap = FALSE, adhoc = FALSE; g_return_val_if_fail(connection != NULL, NULL); s_wireless = nm_connection_get_setting_wireless(connection); g_return_val_if_fail(s_wireless != NULL, NULL); ap = g_object_new(NM_TYPE_WIFI_AP, NULL); priv = NM_WIFI_AP_GET_PRIVATE(ap); priv->fake = TRUE; nm_wifi_ap_set_ssid(ap, nm_setting_wireless_get_ssid(s_wireless)); // FIXME: bssid too? mode = nm_setting_wireless_get_mode(s_wireless); if (mode) { if (!strcmp(mode, "infrastructure")) nm_wifi_ap_set_mode(ap, _NM_802_11_MODE_INFRA); else if (!strcmp(mode, "adhoc")) { nm_wifi_ap_set_mode(ap, _NM_802_11_MODE_ADHOC); adhoc = TRUE; } else if (!strcmp(mode, "mesh")) nm_wifi_ap_set_mode(ap, _NM_802_11_MODE_MESH); else if (!strcmp(mode, "ap")) { nm_wifi_ap_set_mode(ap, _NM_802_11_MODE_INFRA); NM_WIFI_AP_GET_PRIVATE(ap)->hotspot = TRUE; } else goto error; } else { nm_wifi_ap_set_mode(ap, _NM_802_11_MODE_INFRA); } band = nm_setting_wireless_get_band(s_wireless); channel = nm_setting_wireless_get_channel(s_wireless); if (band && channel) { guint32 freq = nm_utils_wifi_channel_to_freq(channel, band); if (freq == 0) goto error; nm_wifi_ap_set_freq(ap, freq); } s_wireless_sec = nm_connection_get_setting_wireless_security(connection); /* Assume presence of a security setting means the AP is encrypted */ if (!s_wireless_sec) goto done; key_mgmt = nm_setting_wireless_security_get_key_mgmt(s_wireless_sec); /* Everything below here uses encryption */ nm_wifi_ap_set_flags(ap, priv->flags | NM_802_11_AP_FLAGS_PRIVACY); /* Static & Dynamic WEP */ if (!strcmp(key_mgmt, "none") || !strcmp(key_mgmt, "ieee8021x")) goto done; psk = nm_streq(key_mgmt, "wpa-psk"); eap = nm_streq(key_mgmt, "wpa-eap") || nm_streq(key_mgmt, "wpa-eap-suite-b-192"); if (!adhoc && (psk || eap)) { if (has_proto(s_wireless_sec, PROTO_WPA)) { flags = priv->wpa_flags | (eap ? NM_802_11_AP_SEC_KEY_MGMT_802_1X : NM_802_11_AP_SEC_KEY_MGMT_PSK); nm_wifi_ap_set_wpa_flags(ap, flags); } if (has_proto(s_wireless_sec, PROTO_RSN)) { flags = priv->rsn_flags | (eap ? NM_802_11_AP_SEC_KEY_MGMT_802_1X : NM_802_11_AP_SEC_KEY_MGMT_PSK); nm_wifi_ap_set_rsn_flags(ap, flags); } add_pair_ciphers(ap, s_wireless_sec); add_group_ciphers(ap, s_wireless_sec); } else if (adhoc && psk) { /* Ad-Hoc has special requirements: proto=RSN, pairwise=CCMP and * group=CCMP. */ flags = priv->wpa_flags | NM_802_11_AP_SEC_KEY_MGMT_PSK; /* Clear ciphers; only CCMP is supported */ flags &= ~(NM_802_11_AP_SEC_PAIR_WEP40 | NM_802_11_AP_SEC_PAIR_WEP104 | NM_802_11_AP_SEC_PAIR_TKIP | NM_802_11_AP_SEC_GROUP_WEP40 | NM_802_11_AP_SEC_GROUP_WEP104 | NM_802_11_AP_SEC_GROUP_TKIP); flags |= NM_802_11_AP_SEC_PAIR_CCMP; flags |= NM_802_11_AP_SEC_GROUP_CCMP; nm_wifi_ap_set_rsn_flags(ap, flags); /* Don't use Ad-Hoc WPA (WPA-none) anymore */ nm_wifi_ap_set_wpa_flags(ap, NM_802_11_AP_SEC_NONE); } done: return ap; error: g_object_unref(ap); return NULL; } static void finalize(GObject *object) { NMWifiAP *self = NM_WIFI_AP(object); NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE(self); nm_assert(!self->wifi_device); nm_assert(c_list_is_empty(&self->aps_lst)); nm_ref_string_unref(self->_supplicant_path); if (priv->ssid) g_bytes_unref(priv->ssid); g_free(priv->address); G_OBJECT_CLASS(nm_wifi_ap_parent_class)->finalize(object); } static const NMDBusInterfaceInfoExtended interface_info_access_point = { .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( NM_DBUS_INTERFACE_ACCESS_POINT, .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Flags", "u", NM_WIFI_AP_FLAGS), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("WpaFlags", "u", NM_WIFI_AP_WPA_FLAGS), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("RsnFlags", "u", NM_WIFI_AP_RSN_FLAGS), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Ssid", "ay", NM_WIFI_AP_SSID), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Frequency", "u", NM_WIFI_AP_FREQUENCY), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("HwAddress", "s", NM_WIFI_AP_HW_ADDRESS), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Mode", "u", NM_WIFI_AP_MODE), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("MaxBitrate", "u", NM_WIFI_AP_MAX_BITRATE), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Strength", "y", NM_WIFI_AP_STRENGTH), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("LastSeen", "i", NM_WIFI_AP_LAST_SEEN), ), ), }; static void nm_wifi_ap_class_init(NMWifiAPClass *ap_class) { #define ALL_SEC_FLAGS \ (NM_802_11_AP_SEC_NONE | NM_802_11_AP_SEC_PAIR_WEP40 | NM_802_11_AP_SEC_PAIR_WEP104 \ | NM_802_11_AP_SEC_PAIR_TKIP | NM_802_11_AP_SEC_PAIR_CCMP | NM_802_11_AP_SEC_GROUP_WEP40 \ | NM_802_11_AP_SEC_GROUP_WEP104 | NM_802_11_AP_SEC_GROUP_TKIP | NM_802_11_AP_SEC_GROUP_CCMP \ | NM_802_11_AP_SEC_KEY_MGMT_PSK | NM_802_11_AP_SEC_KEY_MGMT_802_1X \ | NM_802_11_AP_SEC_KEY_MGMT_SAE | NM_802_11_AP_SEC_KEY_MGMT_OWE \ | NM_802_11_AP_SEC_KEY_MGMT_OWE_TM | NM_802_11_AP_SEC_KEY_MGMT_EAP_SUITE_B_192) GObjectClass *object_class = G_OBJECT_CLASS(ap_class); NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(ap_class); g_type_class_add_private(object_class, sizeof(NMWifiAPPrivate)); dbus_object_class->export_path = NM_DBUS_EXPORT_PATH_NUMBERED(NM_DBUS_PATH_ACCESS_POINT); dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS(&interface_info_access_point); object_class->get_property = get_property; object_class->finalize = finalize; obj_properties[PROP_FLAGS] = g_param_spec_uint(NM_WIFI_AP_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_WPA_FLAGS] = g_param_spec_uint(NM_WIFI_AP_WPA_FLAGS, "", "", NM_802_11_AP_SEC_NONE, ALL_SEC_FLAGS, NM_802_11_AP_SEC_NONE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); obj_properties[PROP_RSN_FLAGS] = g_param_spec_uint(NM_WIFI_AP_RSN_FLAGS, "", "", NM_802_11_AP_SEC_NONE, ALL_SEC_FLAGS, NM_802_11_AP_SEC_NONE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); obj_properties[PROP_SSID] = g_param_spec_variant(NM_WIFI_AP_SSID, "", "", G_VARIANT_TYPE("ay"), NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); obj_properties[PROP_FREQUENCY] = g_param_spec_uint(NM_WIFI_AP_FREQUENCY, "", "", 0, 10000, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); obj_properties[PROP_HW_ADDRESS] = g_param_spec_string(NM_WIFI_AP_HW_ADDRESS, "", "", NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); obj_properties[PROP_MODE] = g_param_spec_uint(NM_WIFI_AP_MODE, "", "", _NM_802_11_MODE_ADHOC, _NM_802_11_MODE_INFRA, _NM_802_11_MODE_INFRA, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); obj_properties[PROP_MAX_BITRATE] = g_param_spec_uint(NM_WIFI_AP_MAX_BITRATE, "", "", 0, G_MAXUINT16, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); obj_properties[PROP_STRENGTH] = g_param_spec_uchar(NM_WIFI_AP_STRENGTH, "", "", 0, G_MAXINT8, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); obj_properties[PROP_LAST_SEEN] = g_param_spec_int(NM_WIFI_AP_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); } /*****************************************************************************/ const char ** nm_wifi_aps_get_paths(const CList *aps_lst_head, gboolean include_without_ssid) { NMWifiAP *ap; gsize i, n; const char **list; const char *path; n = c_list_length(aps_lst_head); list = g_new(const char *, n + 1); i = 0; if (n > 0) { c_list_for_each_entry (ap, aps_lst_head, aps_lst) { nm_assert(i < n); if (!include_without_ssid && !nm_wifi_ap_get_ssid(ap)) continue; path = nm_dbus_object_get_path(NM_DBUS_OBJECT(ap)); nm_assert(path); list[i++] = path; } nm_assert(i <= n); nm_assert(!include_without_ssid || i == n); } list[i] = NULL; return list; } NMWifiAP * nm_wifi_aps_find_first_compatible(const CList *aps_lst_head, NMConnection *connection) { NMWifiAP *ap; g_return_val_if_fail(connection, NULL); c_list_for_each_entry (ap, aps_lst_head, aps_lst) { if (nm_wifi_ap_check_compatible(ap, connection)) return ap; } return NULL; } /*****************************************************************************/ NMWifiAP * nm_wifi_ap_lookup_for_device(NMDevice *device, const char *exported_path) { NMWifiAP *ap; g_return_val_if_fail(NM_IS_DEVICE(device), NULL); ap = nm_dbus_manager_lookup_object_with_type(nm_dbus_object_get_manager(NM_DBUS_OBJECT(device)), NM_TYPE_WIFI_AP, exported_path); if (!ap || ap->wifi_device != device) return NULL; return ap; }