Blame src/devices/wifi/nm-iwd-manager.c

Packit Service 87a54e
/* SPDX-License-Identifier: GPL-2.0-or-later */
Packit 5756e2
/*
Packit 5756e2
 * Copyright (C) 2017 Intel Corporation
Packit 5756e2
 */
Packit 5756e2
Packit 5756e2
#include "nm-default.h"
Packit 5756e2
Packit 5756e2
#include "nm-iwd-manager.h"
Packit 5756e2
Packit 5756e2
#include <net/if.h>
Packit 5756e2
Packit 5756e2
#include "nm-logging.h"
Packit 5756e2
#include "nm-core-internal.h"
Packit 5756e2
#include "nm-manager.h"
Packit 5756e2
#include "nm-device-iwd.h"
Packit 5756e2
#include "nm-wifi-utils.h"
Packit 5756e2
#include "nm-glib-aux/nm-random-utils.h"
Packit 5756e2
#include "settings/nm-settings.h"
Packit Service a1bd4f
#include "nm-std-aux/nm-dbus-compat.h"
Packit 5756e2
Packit 5756e2
/*****************************************************************************/
Packit 5756e2
Packit 5756e2
typedef struct {
Packit Service a1bd4f
    const char *         name;
Packit Service a1bd4f
    NMIwdNetworkSecurity security;
Packit Service a1bd4f
    char                 buf[0];
Packit 5756e2
} KnownNetworkId;
Packit 5756e2
Packit 5756e2
typedef struct {
Packit Service a1bd4f
    GDBusProxy *          known_network;
Packit Service a1bd4f
    NMSettingsConnection *mirror_connection;
Packit 5756e2
} KnownNetworkData;
Packit 5756e2
Packit 5756e2
typedef struct {
Packit Service a1bd4f
    NMManager *         manager;
Packit Service a1bd4f
    NMSettings *        settings;
Packit Service a1bd4f
    GCancellable *      cancellable;
Packit Service a1bd4f
    gboolean            running;
Packit Service a1bd4f
    GDBusObjectManager *object_manager;
Packit Service a1bd4f
    guint               agent_id;
Packit Service a1bd4f
    char *              agent_path;
Packit Service a1bd4f
    GHashTable *        known_networks;
Packit Service a1bd4f
    NMDeviceIwd *       last_agent_call_device;
Packit 5756e2
} NMIwdManagerPrivate;
Packit 5756e2
Packit 5756e2
struct _NMIwdManager {
Packit Service a1bd4f
    GObject             parent;
Packit Service a1bd4f
    NMIwdManagerPrivate _priv;
Packit 5756e2
};
Packit 5756e2
Packit 5756e2
struct _NMIwdManagerClass {
Packit Service a1bd4f
    GObjectClass parent;
Packit 5756e2
};
Packit 5756e2
Packit Service a1bd4f
G_DEFINE_TYPE(NMIwdManager, nm_iwd_manager, G_TYPE_OBJECT)
Packit 5756e2
Packit Service a1bd4f
#define NM_IWD_MANAGER_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMIwdManager, NM_IS_IWD_MANAGER)
Packit 5756e2
Packit 5756e2
/*****************************************************************************/
Packit 5756e2
Packit Service a1bd4f
#define _NMLOG_PREFIX_NAME "iwd-manager"
Packit Service a1bd4f
#define _NMLOG_DOMAIN      LOGD_WIFI
Packit Service a1bd4f
Packit Service a1bd4f
#define _NMLOG(level, ...)                                                 \
Packit Service a1bd4f
    G_STMT_START                                                           \
Packit Service a1bd4f
    {                                                                      \
Packit Service a1bd4f
        if (nm_logging_enabled(level, _NMLOG_DOMAIN)) {                    \
Packit Service a1bd4f
            char __prefix[32];                                             \
Packit Service a1bd4f
                                                                           \
Packit Service a1bd4f
            if (self)                                                      \
Packit Service a1bd4f
                g_snprintf(__prefix,                                       \
Packit Service a1bd4f
                           sizeof(__prefix),                               \
Packit Service a1bd4f
                           "%s[%p]",                                       \
Packit Service a1bd4f
                           ""_NMLOG_PREFIX_NAME                            \
Packit Service a1bd4f
                           "",                                             \
Packit Service a1bd4f
                           (self));                                        \
Packit Service a1bd4f
            else                                                           \
Packit Service a1bd4f
                g_strlcpy(__prefix, _NMLOG_PREFIX_NAME, sizeof(__prefix)); \
Packit Service a1bd4f
            _nm_log((level),                                               \
Packit Service a1bd4f
                    (_NMLOG_DOMAIN),                                       \
Packit Service a1bd4f
                    0,                                                     \
Packit Service a1bd4f
                    NULL,                                                  \
Packit Service a1bd4f
                    NULL,                                                  \
Packit Service a1bd4f
                    "%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__),             \
Packit Service a1bd4f
                    __prefix _NM_UTILS_MACRO_REST(__VA_ARGS__));           \
Packit Service a1bd4f
        }                                                                  \
Packit Service a1bd4f
    }                                                                      \
Packit Service a1bd4f
    G_STMT_END
Packit 5756e2
Packit 5756e2
/*****************************************************************************/
Packit 5756e2
Packit Service a1bd4f
static void mirror_connection_take_and_delete(NMSettingsConnection *sett_conn,
Packit Service a1bd4f
                                              KnownNetworkData *    data);
Packit 5756e2
Packit 5756e2
/*****************************************************************************/
Packit 5756e2
Packit 5756e2
static const char *
Packit Service a1bd4f
get_variant_string_or_null(GVariant *v)
Packit 5756e2
{
Packit Service a1bd4f
    if (!v)
Packit Service a1bd4f
        return NULL;
Packit 5756e2
Packit Service a1bd4f
    if (!g_variant_is_of_type(v, G_VARIANT_TYPE_STRING)
Packit Service a1bd4f
        && !g_variant_is_of_type(v, G_VARIANT_TYPE_OBJECT_PATH))
Packit Service a1bd4f
        return NULL;
Packit 5756e2
Packit Service a1bd4f
    return g_variant_get_string(v, NULL);
Packit 5756e2
}
Packit 5756e2
Packit 5756e2
static const char *
Packit Service a1bd4f
get_property_string_or_null(GDBusProxy *proxy, const char *property)
Packit 5756e2
{
Packit Service a1bd4f
    gs_unref_variant GVariant *value = NULL;
Packit 5756e2
Packit Service a1bd4f
    if (!proxy || !property)
Packit Service a1bd4f
        return NULL;
Packit 5756e2
Packit Service a1bd4f
    value = g_dbus_proxy_get_cached_property(proxy, property);
Packit 5756e2
Packit Service a1bd4f
    return get_variant_string_or_null(value);
Packit 5756e2
}
Packit 5756e2
Packit Service a1bd4f
static gboolean
Packit Service a1bd4f
get_property_bool(GDBusProxy *proxy, const char *property, gboolean default_val)
Packit 5756e2
{
Packit Service a1bd4f
    gs_unref_variant GVariant *value = NULL;
Packit 5756e2
Packit Service a1bd4f
    if (!proxy || !property)
Packit Service a1bd4f
        return default_val;
Packit 5756e2
Packit Service a1bd4f
    value = g_dbus_proxy_get_cached_property(proxy, property);
Packit Service a1bd4f
    if (!value || !g_variant_is_of_type(value, G_VARIANT_TYPE_BOOLEAN))
Packit Service a1bd4f
        return default_val;
Packit 5756e2
Packit Service a1bd4f
    return g_variant_get_boolean(value);
Packit Service a1bd4f
}
Packit 5756e2
Packit Service a1bd4f
static NMDeviceIwd *
Packit Service a1bd4f
get_device_from_network(NMIwdManager *self, GDBusProxy *network)
Packit Service a1bd4f
{
Packit Service a1bd4f
    NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self);
Packit Service a1bd4f
    const char *         ifname;
Packit Service a1bd4f
    const char *         device_path;
Packit Service a1bd4f
    NMDevice *           device;
Packit Service a1bd4f
    gs_unref_object GDBusInterface *device_obj = NULL;
Packit Service a1bd4f
Packit Service a1bd4f
    /* Try not to rely on the path of the Device being a prefix of the
Packit Service a1bd4f
     * Network's object path.
Packit Service a1bd4f
     */
Packit Service a1bd4f
Packit Service a1bd4f
    device_path = get_property_string_or_null(network, "Device");
Packit Service a1bd4f
    if (!device_path) {
Packit Service a1bd4f
        _LOGD("Device not cached for network at %s", g_dbus_proxy_get_object_path(network));
Packit Service a1bd4f
        return NULL;
Packit Service a1bd4f
    }
Packit Service a1bd4f
Packit Service a1bd4f
    device_obj = g_dbus_object_manager_get_interface(priv->object_manager,
Packit Service a1bd4f
                                                     device_path,
Packit Service a1bd4f
                                                     NM_IWD_DEVICE_INTERFACE);
Packit Service a1bd4f
Packit Service a1bd4f
    ifname = get_property_string_or_null(G_DBUS_PROXY(device_obj), "Name");
Packit Service a1bd4f
    if (!ifname) {
Packit Service a1bd4f
        _LOGD("Name not cached for device at %s", device_path);
Packit Service a1bd4f
        return NULL;
Packit Service a1bd4f
    }
Packit Service a1bd4f
Packit Service a1bd4f
    device = nm_manager_get_device(priv->manager, ifname, NM_DEVICE_TYPE_WIFI);
Packit Service a1bd4f
    if (!device || !NM_IS_DEVICE_IWD(device)) {
Packit Service a1bd4f
        _LOGD("NM device %s is not an IWD-managed device", ifname);
Packit Service a1bd4f
        return NULL;
Packit Service a1bd4f
    }
Packit Service a1bd4f
Packit Service a1bd4f
    return NM_DEVICE_IWD(device);
Packit 5756e2
}
Packit 5756e2
Packit 5756e2
static void
Packit Service a1bd4f
agent_dbus_method_cb(GDBusConnection *      connection,
Packit Service a1bd4f
                     const char *           sender,
Packit Service a1bd4f
                     const char *           object_path,
Packit Service a1bd4f
                     const char *           interface_name,
Packit Service a1bd4f
                     const char *           method_name,
Packit Service a1bd4f
                     GVariant *             parameters,
Packit Service a1bd4f
                     GDBusMethodInvocation *invocation,
Packit Service a1bd4f
                     gpointer               user_data)
Packit 5756e2
{
Packit Service a1bd4f
    NMIwdManager *       self = user_data;
Packit Service a1bd4f
    NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self);
Packit Service a1bd4f
    const char *         network_path;
Packit Service a1bd4f
    NMDeviceIwd *        device;
Packit Service a1bd4f
    gs_free char *       name_owner         = NULL;
Packit Service a1bd4f
    gs_unref_object GDBusInterface *network = NULL;
Packit Service a1bd4f
Packit Service a1bd4f
    /* Be paranoid and check the sender address */
Packit Service a1bd4f
    name_owner = g_dbus_object_manager_client_get_name_owner(
Packit Service a1bd4f
        G_DBUS_OBJECT_MANAGER_CLIENT(priv->object_manager));
Packit Service a1bd4f
    if (!nm_streq0(name_owner, sender))
Packit Service a1bd4f
        goto return_error;
Packit Service a1bd4f
Packit Service a1bd4f
    if (!strcmp(method_name, "Cancel")) {
Packit Service a1bd4f
        const char *reason = NULL;
Packit Service a1bd4f
Packit Service a1bd4f
        g_variant_get(parameters, "(&s)", &reason);
Packit Service a1bd4f
        _LOGD("agent-request: Cancel reason: %s", reason);
Packit Service a1bd4f
Packit Service a1bd4f
        if (!priv->last_agent_call_device)
Packit Service a1bd4f
            goto return_error;
Packit Service a1bd4f
Packit Service a1bd4f
        if (nm_device_iwd_agent_query(priv->last_agent_call_device, NULL)) {
Packit Service a1bd4f
            priv->last_agent_call_device = NULL;
Packit Service a1bd4f
            g_dbus_method_invocation_return_value(invocation, NULL);
Packit Service a1bd4f
            return;
Packit Service a1bd4f
        }
Packit Service a1bd4f
Packit Service a1bd4f
        priv->last_agent_call_device = NULL;
Packit Service a1bd4f
        goto return_error;
Packit Service a1bd4f
    }
Packit Service a1bd4f
Packit Service a1bd4f
    if (!strcmp(method_name, "RequestUserPassword"))
Packit Service a1bd4f
        g_variant_get(parameters, "(&os)", &network_path, NULL);
Packit Service a1bd4f
    else
Packit Service a1bd4f
        g_variant_get(parameters, "(&o)", &network_path);
Packit Service a1bd4f
Packit Service a1bd4f
    network = g_dbus_object_manager_get_interface(priv->object_manager,
Packit Service a1bd4f
                                                  network_path,
Packit Service a1bd4f
                                                  NM_IWD_NETWORK_INTERFACE);
Packit Service a1bd4f
    if (!network) {
Packit Service a1bd4f
        _LOGE("agent-request: unable to find the network object");
Packit Service a1bd4f
        goto return_error;
Packit Service a1bd4f
    }
Packit Service a1bd4f
Packit Service a1bd4f
    device = get_device_from_network(self, G_DBUS_PROXY(network));
Packit Service a1bd4f
    if (!device) {
Packit Service a1bd4f
        _LOGD("agent-request: device not found in IWD Agent request");
Packit Service a1bd4f
        goto return_error;
Packit Service a1bd4f
    }
Packit Service a1bd4f
Packit Service a1bd4f
    if (nm_device_iwd_agent_query(device, invocation)) {
Packit Service a1bd4f
        priv->last_agent_call_device = device;
Packit Service a1bd4f
        return;
Packit Service a1bd4f
    }
Packit Service a1bd4f
Packit Service a1bd4f
    _LOGD("agent-request: device %s did not handle the IWD Agent request",
Packit Service a1bd4f
          nm_device_get_iface(NM_DEVICE(device)));
Packit 5756e2
Packit Service a1bd4f
return_error:
Packit Service a1bd4f
    /* IWD doesn't look at the specific error */
Packit Service a1bd4f
    g_dbus_method_invocation_return_error_literal(invocation,
Packit Service a1bd4f
                                                  NM_DEVICE_ERROR,
Packit Service a1bd4f
                                                  NM_DEVICE_ERROR_INVALID_CONNECTION,
Packit Service a1bd4f
                                                  "Secrets not available for this connection");
Packit Service a1bd4f
}
Packit 5756e2
Packit Service a1bd4f
static const GDBusInterfaceInfo iwd_agent_iface_info = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT(
Packit Service a1bd4f
    "net.connman.iwd.Agent",
Packit Service a1bd4f
    .methods = NM_DEFINE_GDBUS_METHOD_INFOS(
Packit Service a1bd4f
        NM_DEFINE_GDBUS_METHOD_INFO(
Packit Service a1bd4f
            "RequestPassphrase",
Packit Service a1bd4f
            .in_args  = NM_DEFINE_GDBUS_ARG_INFOS(NM_DEFINE_GDBUS_ARG_INFO("network", "o"), ),
Packit Service a1bd4f
            .out_args = NM_DEFINE_GDBUS_ARG_INFOS(NM_DEFINE_GDBUS_ARG_INFO("passphrase", "s"), ), ),
Packit Service a1bd4f
        NM_DEFINE_GDBUS_METHOD_INFO(
Packit Service a1bd4f
            "RequestPrivateKeyPassphrase",
Packit Service a1bd4f
            .in_args  = NM_DEFINE_GDBUS_ARG_INFOS(NM_DEFINE_GDBUS_ARG_INFO("network", "o"), ),
Packit Service a1bd4f
            .out_args = NM_DEFINE_GDBUS_ARG_INFOS(NM_DEFINE_GDBUS_ARG_INFO("passphrase", "s"), ), ),
Packit Service a1bd4f
        NM_DEFINE_GDBUS_METHOD_INFO(
Packit Service a1bd4f
            "RequestUserNameAndPassword",
Packit Service a1bd4f
            .in_args  = NM_DEFINE_GDBUS_ARG_INFOS(NM_DEFINE_GDBUS_ARG_INFO("network", "o"), ),
Packit Service a1bd4f
            .out_args = NM_DEFINE_GDBUS_ARG_INFOS(NM_DEFINE_GDBUS_ARG_INFO("user", "s"),
Packit Service a1bd4f
                                                  NM_DEFINE_GDBUS_ARG_INFO("password", "s"), ), ),
Packit Service a1bd4f
        NM_DEFINE_GDBUS_METHOD_INFO(
Packit Service a1bd4f
            "RequestUserPassword",
Packit Service a1bd4f
            .in_args  = NM_DEFINE_GDBUS_ARG_INFOS(NM_DEFINE_GDBUS_ARG_INFO("network", "o"),
Packit Service a1bd4f
                                                 NM_DEFINE_GDBUS_ARG_INFO("user", "s"), ),
Packit Service a1bd4f
            .out_args = NM_DEFINE_GDBUS_ARG_INFOS(NM_DEFINE_GDBUS_ARG_INFO("password", "s"), ), ),
Packit Service a1bd4f
        NM_DEFINE_GDBUS_METHOD_INFO("Cancel",
Packit Service a1bd4f
                                    .in_args = NM_DEFINE_GDBUS_ARG_INFOS(
Packit Service a1bd4f
                                        NM_DEFINE_GDBUS_ARG_INFO("reason", "s"), ), ), ), );
Packit 5756e2
Packit Service a1bd4f
static guint
Packit Service a1bd4f
iwd_agent_export(GDBusConnection *connection, gpointer user_data, char **agent_path, GError **error)
Packit Service a1bd4f
{
Packit Service a1bd4f
    static const GDBusInterfaceVTable vtable = {
Packit Service a1bd4f
        .method_call = agent_dbus_method_cb,
Packit Service a1bd4f
    };
Packit Service a1bd4f
    char         path[50];
Packit Service a1bd4f
    unsigned int rnd;
Packit Service a1bd4f
    guint        id;
Packit Service a1bd4f
Packit Service a1bd4f
    nm_utils_random_bytes(&rnd, sizeof(rnd));
Packit Service a1bd4f
Packit Service a1bd4f
    nm_sprintf_buf(path, "/agent/%u", rnd);
Packit Service a1bd4f
Packit Service a1bd4f
    id =
Packit Service a1bd4f
        g_dbus_connection_register_object(connection,
Packit Service a1bd4f
                                          path,
Packit Service a1bd4f
                                          NM_UNCONST_PTR(GDBusInterfaceInfo, &iwd_agent_iface_info),
Packit Service a1bd4f
                                          &vtable,
Packit Service a1bd4f
                                          user_data,
Packit Service a1bd4f
                                          NULL,
Packit Service a1bd4f
                                          error);
Packit Service a1bd4f
Packit Service a1bd4f
    if (id)
Packit Service a1bd4f
        *agent_path = g_strdup(path);
Packit Service a1bd4f
    return id;
Packit Service a1bd4f
}
Packit 5756e2
Packit Service a1bd4f
static void
Packit Service a1bd4f
register_agent(NMIwdManager *self)
Packit Service a1bd4f
{
Packit Service a1bd4f
    NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self);
Packit Service a1bd4f
    GDBusInterface *     agent_manager;
Packit Service a1bd4f
Packit Service a1bd4f
    agent_manager = g_dbus_object_manager_get_interface(priv->object_manager,
Packit Service a1bd4f
                                                        "/net/connman/iwd", /* IWD 1.0+ */
Packit Service a1bd4f
                                                        NM_IWD_AGENT_MANAGER_INTERFACE);
Packit Service a1bd4f
    if (!agent_manager) {
Packit Service a1bd4f
        _LOGE("unable to register the IWD Agent: PSK/8021x Wi-Fi networks may not work");
Packit Service a1bd4f
        return;
Packit Service a1bd4f
    }
Packit Service a1bd4f
Packit Service a1bd4f
    /* Register our agent */
Packit Service a1bd4f
    g_dbus_proxy_call(G_DBUS_PROXY(agent_manager),
Packit Service a1bd4f
                      "RegisterAgent",
Packit Service a1bd4f
                      g_variant_new("(o)", priv->agent_path),
Packit Service a1bd4f
                      G_DBUS_CALL_FLAGS_NONE,
Packit Service a1bd4f
                      -1,
Packit Service a1bd4f
                      NULL,
Packit Service a1bd4f
                      NULL,
Packit Service a1bd4f
                      NULL);
Packit Service a1bd4f
Packit Service a1bd4f
    g_object_unref(agent_manager);
Packit 5756e2
}
Packit 5756e2
Packit 5756e2
/*****************************************************************************/
Packit 5756e2
Packit 5756e2
static KnownNetworkId *
Packit Service a1bd4f
known_network_id_new(const char *name, NMIwdNetworkSecurity security)
Packit 5756e2
{
Packit Service a1bd4f
    KnownNetworkId *id;
Packit Service a1bd4f
    gsize           strsize = strlen(name) + 1;
Packit 5756e2
Packit Service a1bd4f
    id           = g_malloc(sizeof(KnownNetworkId) + strsize);
Packit Service a1bd4f
    id->name     = id->buf;
Packit Service a1bd4f
    id->security = security;
Packit Service a1bd4f
    memcpy(id->buf, name, strsize);
Packit 5756e2
Packit Service a1bd4f
    return id;
Packit 5756e2
}
Packit 5756e2
Packit 5756e2
static guint
Packit Service a1bd4f
known_network_id_hash(KnownNetworkId *id)
Packit 5756e2
{
Packit Service a1bd4f
    NMHashState h;
Packit 5756e2
Packit Service a1bd4f
    nm_hash_init(&h, 1947951703u);
Packit Service a1bd4f
    nm_hash_update_val(&h, id->security);
Packit Service a1bd4f
    nm_hash_update_str(&h, id->name);
Packit Service a1bd4f
    return nm_hash_complete(&h);
Packit 5756e2
}
Packit 5756e2
Packit 5756e2
static gboolean
Packit Service a1bd4f
known_network_id_equal(KnownNetworkId *a, KnownNetworkId *b)
Packit 5756e2
{
Packit Service a1bd4f
    return a->security == b->security && nm_streq(a->name, b->name);
Packit 5756e2
}
Packit 5756e2
Packit 5756e2
static void
Packit Service a1bd4f
known_network_data_free(KnownNetworkData *network)
Packit 5756e2
{
Packit Service a1bd4f
    if (!network)
Packit Service a1bd4f
        return;
Packit 5756e2
Packit Service a1bd4f
    g_object_unref(network->known_network);
Packit Service a1bd4f
    mirror_connection_take_and_delete(network->mirror_connection, network);
Packit Service a1bd4f
    g_slice_free(KnownNetworkData, network);
Packit 5756e2
}
Packit 5756e2
Packit 5756e2
/*****************************************************************************/
Packit 5756e2
Packit 5756e2
static void
Packit Service a1bd4f
set_device_dbus_object(NMIwdManager *self, GDBusProxy *proxy, GDBusObject *object)
Packit Service a1bd4f
{
Packit Service a1bd4f
    NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self);
Packit Service a1bd4f
    const char *         ifname;
Packit Service a1bd4f
    int                  ifindex;
Packit Service a1bd4f
    NMDevice *           device;
Packit Service a1bd4f
    int                  errsv;
Packit Service a1bd4f
Packit Service a1bd4f
    ifname = get_property_string_or_null(proxy, "Name");
Packit Service a1bd4f
    if (!ifname) {
Packit Service a1bd4f
        _LOGE("Name not cached for Device at %s", g_dbus_proxy_get_object_path(proxy));
Packit Service a1bd4f
        return;
Packit Service a1bd4f
    }
Packit Service a1bd4f
Packit Service a1bd4f
    ifindex = if_nametoindex(ifname);
Packit Service a1bd4f
Packit Service a1bd4f
    if (!ifindex) {
Packit Service a1bd4f
        errsv = errno;
Packit Service a1bd4f
        _LOGE("if_nametoindex failed for Name %s for Device at %s: %i",
Packit Service a1bd4f
              ifname,
Packit Service a1bd4f
              g_dbus_proxy_get_object_path(proxy),
Packit Service a1bd4f
              errsv);
Packit Service a1bd4f
        return;
Packit Service a1bd4f
    }
Packit Service a1bd4f
Packit Service a1bd4f
    device = nm_manager_get_device_by_ifindex(priv->manager, ifindex);
Packit Service a1bd4f
    if (!NM_IS_DEVICE_IWD(device)) {
Packit Service a1bd4f
        _LOGE("IWD device named %s is not a Wifi device", ifname);
Packit Service a1bd4f
        return;
Packit Service a1bd4f
    }
Packit Service a1bd4f
Packit Service a1bd4f
    nm_device_iwd_set_dbus_object(NM_DEVICE_IWD(device), object);
Packit 5756e2
}
Packit 5756e2
Packit 5756e2
static void
Packit Service a1bd4f
known_network_update_cb(GObject *source, GAsyncResult *res, gpointer user_data)
Packit 5756e2
{
Packit Service a1bd4f
    gs_unref_variant GVariant *variant = NULL;
Packit Service a1bd4f
    gs_free_error GError *error        = NULL;
Packit Service a1bd4f
Packit Service a1bd4f
    variant = g_dbus_proxy_call_finish(G_DBUS_PROXY(source), res, &error);
Packit Service a1bd4f
    if (!variant) {
Packit Service a1bd4f
        nm_log_warn(LOGD_WIFI,
Packit Service a1bd4f
                    "Updating %s on IWD known network %s failed: %s",
Packit Service a1bd4f
                    (const char *) user_data,
Packit Service a1bd4f
                    g_dbus_proxy_get_object_path(G_DBUS_PROXY(source)),
Packit Service a1bd4f
                    error->message);
Packit Service a1bd4f
    }
Packit 5756e2
}
Packit 5756e2
Packit 5756e2
static void
Packit Service a1bd4f
sett_conn_changed(NMSettingsConnection *sett_conn, guint update_reason, KnownNetworkData *data)
Packit Service a1bd4f
{
Packit Service a1bd4f
    NMSettingsConnectionIntFlags flags;
Packit Service a1bd4f
    NMConnection *               conn   = nm_settings_connection_get_connection(sett_conn);
Packit Service a1bd4f
    NMSettingConnection *        s_conn = nm_connection_get_setting_connection(conn);
Packit Service a1bd4f
    gboolean                     nm_autoconnectable = nm_setting_connection_get_autoconnect(s_conn);
Packit Service a1bd4f
    gboolean iwd_autoconnectable = get_property_bool(data->known_network, "AutoConnect", TRUE);
Packit Service a1bd4f
Packit Service a1bd4f
    nm_assert(sett_conn == data->mirror_connection);
Packit Service a1bd4f
Packit Service a1bd4f
    if (iwd_autoconnectable == nm_autoconnectable)
Packit Service a1bd4f
        return;
Packit Service a1bd4f
Packit Service a1bd4f
    /* If this is a generated connection it may be ourselves updating it */
Packit Service a1bd4f
    flags = nm_settings_connection_get_flags(data->mirror_connection);
Packit Service a1bd4f
    if (NM_FLAGS_HAS(flags, NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED))
Packit Service a1bd4f
        return;
Packit Service a1bd4f
Packit Service a1bd4f
    nm_log_dbg(LOGD_WIFI,
Packit Service a1bd4f
               "Updating AutoConnect on known network at %s based on connection %s",
Packit Service a1bd4f
               g_dbus_proxy_get_object_path(data->known_network),
Packit Service a1bd4f
               nm_settings_connection_get_id(data->mirror_connection));
Packit Service a1bd4f
    g_dbus_proxy_call(data->known_network,
Packit Service a1bd4f
                      DBUS_INTERFACE_PROPERTIES ".Set",
Packit Service a1bd4f
                      g_variant_new("(ssv)",
Packit Service a1bd4f
                                    NM_IWD_KNOWN_NETWORK_INTERFACE,
Packit Service a1bd4f
                                    "AutoConnect",
Packit Service a1bd4f
                                    g_variant_new_boolean(nm_autoconnectable)),
Packit Service a1bd4f
                      G_DBUS_CALL_FLAGS_NONE,
Packit Service a1bd4f
                      -1,
Packit Service a1bd4f
                      NULL,
Packit Service a1bd4f
                      known_network_update_cb,
Packit Service a1bd4f
                      "AutoConnect");
Packit 5756e2
}
Packit 5756e2
Packit Service a1bd4f
/* Look up an existing NMSettingsConnection for a network that has been
Packit Service a1bd4f
 * preprovisioned with an IWD config file or has been connected to before,
Packit Service a1bd4f
 * or create a new in-memory NMSettingsConnection object.  This will let
Packit Service a1bd4f
 * users control the few supported properties (mainly make it
Packit Service a1bd4f
 * IWD-autoconnectable or not), remove/forget the network, or, for a
Packit Service a1bd4f
 * WPA2-Enterprise type network it will inform the NM autoconnect mechanism
Packit Service a1bd4f
 * and the clients that this networks needs no additional EAP configuration
Packit Service a1bd4f
 * from the user.
Packit Service a1bd4f
 */
Packit Service a1bd4f
static NMSettingsConnection *
Packit Service a1bd4f
mirror_connection(NMIwdManager *        self,
Packit Service a1bd4f
                  const KnownNetworkId *id,
Packit Service a1bd4f
                  gboolean              create_new,
Packit Service a1bd4f
                  GDBusProxy *          known_network)
Packit 5756e2
{
Packit Service a1bd4f
    NMIwdManagerPrivate *        priv = NM_IWD_MANAGER_GET_PRIVATE(self);
Packit Service a1bd4f
    NMSettingsConnection *const *iter;
Packit Service a1bd4f
    gs_unref_object NMConnection *connection          = NULL;
Packit Service a1bd4f
    NMSettingsConnection *        settings_connection = NULL;
Packit Service a1bd4f
    char                          uuid[37];
Packit Service a1bd4f
    NMSetting *                   setting;
Packit Service a1bd4f
    gs_free_error GError *error            = NULL;
Packit Service a1bd4f
    gs_unref_bytes GBytes *new_ssid        = NULL;
Packit Service a1bd4f
    gsize                  ssid_len        = strlen(id->name);
Packit Service a1bd4f
    gboolean               autoconnectable = TRUE;
Packit Service a1bd4f
    gboolean               hidden          = FALSE;
Packit Service a1bd4f
    gboolean               exact_match     = TRUE;
Packit Service a1bd4f
    const char *           key_mgmt        = NULL;
Packit Service a1bd4f
Packit Service a1bd4f
    if (known_network) {
Packit Service a1bd4f
        autoconnectable = get_property_bool(known_network, "AutoConnect", TRUE);
Packit Service a1bd4f
        hidden          = get_property_bool(known_network, "Hidden", FALSE);
Packit Service a1bd4f
    }
Packit Service a1bd4f
Packit Service a1bd4f
    for (iter = nm_settings_get_connections(priv->settings, NULL); *iter; iter++) {
Packit Service a1bd4f
        NMSettingsConnection *sett_conn = *iter;
Packit Service a1bd4f
        NMConnection *        conn      = nm_settings_connection_get_connection(sett_conn);
Packit Service a1bd4f
        NMIwdNetworkSecurity  security;
Packit Service a1bd4f
        NMSettingWireless *   s_wifi;
Packit Service a1bd4f
        const guint8 *        ssid_bytes;
Packit Service a1bd4f
        gsize                 ssid_len2;
Packit Service a1bd4f
Packit Service a1bd4f
        if (!nm_wifi_connection_get_iwd_ssid_and_security(conn, NULL, &security))
Packit Service a1bd4f
            continue;
Packit Service a1bd4f
Packit Service a1bd4f
        if (security != id->security)
Packit Service a1bd4f
            continue;
Packit Service a1bd4f
Packit Service a1bd4f
        s_wifi = nm_connection_get_setting_wireless(conn);
Packit Service a1bd4f
        if (!s_wifi)
Packit Service a1bd4f
            continue;
Packit Service a1bd4f
Packit Service a1bd4f
        /* The SSID must be UTF-8 if it matches since id->name is known to be
Packit Service a1bd4f
         * valid UTF-8, so just memcmp them.
Packit Service a1bd4f
         */
Packit Service a1bd4f
        ssid_bytes = g_bytes_get_data(nm_setting_wireless_get_ssid(s_wifi), &ssid_len2);
Packit Service a1bd4f
        if (!ssid_bytes || ssid_len2 != ssid_len || memcmp(ssid_bytes, id->name, ssid_len))
Packit Service a1bd4f
            continue;
Packit Service a1bd4f
Packit Service a1bd4f
        exact_match = TRUE;
Packit Service a1bd4f
Packit Service a1bd4f
        if (known_network) {
Packit Service a1bd4f
            NMSettingConnection *s_conn = nm_connection_get_setting_connection(conn);
Packit Service a1bd4f
Packit Service a1bd4f
            if (nm_setting_connection_get_autoconnect(s_conn) != autoconnectable
Packit Service a1bd4f
                || nm_setting_wireless_get_hidden(s_wifi) != hidden)
Packit Service a1bd4f
                exact_match = FALSE;
Packit Service a1bd4f
        }
Packit Service a1bd4f
Packit Service a1bd4f
        switch (id->security) {
Packit Service a1bd4f
        case NM_IWD_NETWORK_SECURITY_WEP:
Packit Service a1bd4f
        case NM_IWD_NETWORK_SECURITY_NONE:
Packit Service a1bd4f
        case NM_IWD_NETWORK_SECURITY_PSK:
Packit Service a1bd4f
            break;
Packit Service a1bd4f
        case NM_IWD_NETWORK_SECURITY_8021X:
Packit Service a1bd4f
        {
Packit Service a1bd4f
            NMSetting8021x *s_8021x  = nm_connection_get_setting_802_1x(conn);
Packit Service a1bd4f
            gboolean        external = FALSE;
Packit Service a1bd4f
            guint           i;
Packit Service a1bd4f
Packit Service a1bd4f
            for (i = 0; i < nm_setting_802_1x_get_num_eap_methods(s_8021x); i++) {
Packit Service a1bd4f
                if (nm_streq(nm_setting_802_1x_get_eap_method(s_8021x, i), "external")) {
Packit Service a1bd4f
                    external = TRUE;
Packit Service a1bd4f
                    break;
Packit Service a1bd4f
                }
Packit Service a1bd4f
            }
Packit Service a1bd4f
Packit Service a1bd4f
            /* Prefer returning connections with EAP method "external" */
Packit Service a1bd4f
            if (!external)
Packit Service a1bd4f
                exact_match = FALSE;
Packit Service a1bd4f
        }
Packit Service a1bd4f
        }
Packit Service a1bd4f
Packit Service a1bd4f
        if (!settings_connection || exact_match)
Packit Service a1bd4f
            settings_connection = sett_conn;
Packit Service a1bd4f
Packit Service a1bd4f
        if (exact_match)
Packit Service a1bd4f
            break;
Packit Service a1bd4f
    }
Packit Service a1bd4f
Packit Service a1bd4f
    if (settings_connection && known_network && !exact_match) {
Packit Service a1bd4f
        NMSettingsConnectionIntFlags flags = nm_settings_connection_get_flags(settings_connection);
Packit Service a1bd4f
Packit Service a1bd4f
        /* If we found a connection and it's generated (likely by ourselves)
Packit Service a1bd4f
         * it may have been created on a request by
Packit Service a1bd4f
         * nm_iwd_manager_get_ap_mirror_connection() when no Known Network
Packit Service a1bd4f
         * was available so we didn't have access to its properties other
Packit Service a1bd4f
         * than Name and Security.  Copy their values to the generated
Packit Service a1bd4f
         * NMConnection.
Packit Service a1bd4f
         * TODO: avoid notify signals triggering our own watch.
Packit Service a1bd4f
         *
Packit Service a1bd4f
         * If on the other hand this is a user-created NMConnection we
Packit Service a1bd4f
         * should try to copy the properties from it to IWD's Known Network
Packit Service a1bd4f
         * using the Properties DBus interface in case the user created an
Packit Service a1bd4f
         * NM connection before IWD appeared on the bus, or before IWD
Packit Service a1bd4f
         * created its Known Network object.
Packit Service a1bd4f
         */
Packit Service a1bd4f
        if (NM_FLAGS_HAS(flags, NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED)) {
Packit Service a1bd4f
            NMConnection *tmp_conn = nm_settings_connection_get_connection(settings_connection);
Packit Service a1bd4f
            NMSettingConnection *s_conn = nm_connection_get_setting_connection(tmp_conn);
Packit Service a1bd4f
            NMSettingWireless *  s_wifi = nm_connection_get_setting_wireless(tmp_conn);
Packit Service a1bd4f
Packit Service a1bd4f
            g_object_set(G_OBJECT(s_conn),
Packit Service a1bd4f
                         NM_SETTING_CONNECTION_AUTOCONNECT,
Packit Service a1bd4f
                         autoconnectable,
Packit Service a1bd4f
                         NULL);
Packit Service a1bd4f
            g_object_set(G_OBJECT(s_wifi), NM_SETTING_WIRELESS_HIDDEN, hidden, NULL);
Packit Service a1bd4f
        } else {
Packit Service a1bd4f
            KnownNetworkData data = {known_network, settings_connection};
Packit Service a1bd4f
            sett_conn_changed(settings_connection, 0, &data);
Packit Service a1bd4f
        }
Packit Service a1bd4f
    }
Packit Service a1bd4f
Packit Service a1bd4f
    if (settings_connection && known_network) {
Packit Service a1bd4f
        /* Reset NM_SETTINGS_CONNECTION_INT_FLAGS_EXTERNAL now that the
Packit Service a1bd4f
         * connection is going to be referenced by a known network, we don't
Packit Service a1bd4f
         * want it to be deleted when activation fails anymore.
Packit Service a1bd4f
         */
Packit Service a1bd4f
        nm_settings_connection_set_flags_full(settings_connection,
Packit Service a1bd4f
                                              NM_SETTINGS_CONNECTION_INT_FLAGS_EXTERNAL,
Packit Service a1bd4f
                                              0);
Packit Service a1bd4f
    }
Packit Service a1bd4f
Packit Service a1bd4f
    /* If we already have an NMSettingsConnection matching this
Packit Service a1bd4f
     * KnownNetwork, whether it's saved or an in-memory connection
Packit Service a1bd4f
     * potentially created by ourselves then we have nothing left to
Packit Service a1bd4f
     * do here.
Packit Service a1bd4f
     */
Packit Service a1bd4f
    if (settings_connection || !create_new)
Packit Service a1bd4f
        return settings_connection;
Packit Service a1bd4f
Packit Service a1bd4f
    connection = nm_simple_connection_new();
Packit Service a1bd4f
Packit Service a1bd4f
    setting = NM_SETTING(g_object_new(NM_TYPE_SETTING_CONNECTION,
Packit Service a1bd4f
                                      NM_SETTING_CONNECTION_TYPE,
Packit Service a1bd4f
                                      NM_SETTING_WIRELESS_SETTING_NAME,
Packit Service a1bd4f
                                      NM_SETTING_CONNECTION_ID,
Packit Service a1bd4f
                                      id->name,
Packit Service a1bd4f
                                      NM_SETTING_CONNECTION_UUID,
Packit Service a1bd4f
                                      nm_utils_uuid_generate_buf(uuid),
Packit Service a1bd4f
                                      NM_SETTING_CONNECTION_AUTOCONNECT,
Packit Service a1bd4f
                                      autoconnectable,
Packit Service a1bd4f
                                      NULL));
Packit Service a1bd4f
    nm_connection_add_setting(connection, setting);
Packit Service a1bd4f
Packit Service a1bd4f
    new_ssid = g_bytes_new(id->name, ssid_len);
Packit Service a1bd4f
    setting  = NM_SETTING(g_object_new(NM_TYPE_SETTING_WIRELESS,
Packit Service a1bd4f
                                      NM_SETTING_WIRELESS_SSID,
Packit Service a1bd4f
                                      new_ssid,
Packit Service a1bd4f
                                      NM_SETTING_WIRELESS_MODE,
Packit Service a1bd4f
                                      NM_SETTING_WIRELESS_MODE_INFRA,
Packit Service a1bd4f
                                      NM_SETTING_WIRELESS_HIDDEN,
Packit Service a1bd4f
                                      hidden,
Packit Service a1bd4f
                                      NULL));
Packit Service a1bd4f
    nm_connection_add_setting(connection, setting);
Packit Service a1bd4f
Packit Service a1bd4f
    switch (id->security) {
Packit Service a1bd4f
    case NM_IWD_NETWORK_SECURITY_WEP:
Packit Service a1bd4f
        key_mgmt = "none";
Packit Service a1bd4f
        break;
Packit Service a1bd4f
    case NM_IWD_NETWORK_SECURITY_NONE:
Packit Service a1bd4f
        key_mgmt = NULL;
Packit Service a1bd4f
        break;
Packit Service a1bd4f
    case NM_IWD_NETWORK_SECURITY_PSK:
Packit Service a1bd4f
        key_mgmt = "wpa-psk";
Packit Service a1bd4f
        break;
Packit Service a1bd4f
    case NM_IWD_NETWORK_SECURITY_8021X:
Packit Service a1bd4f
        key_mgmt = "wpa-eap";
Packit Service a1bd4f
        break;
Packit Service a1bd4f
    }
Packit Service a1bd4f
Packit Service a1bd4f
    if (key_mgmt) {
Packit Service a1bd4f
        setting = NM_SETTING(g_object_new(NM_TYPE_SETTING_WIRELESS_SECURITY,
Packit Service a1bd4f
                                          NM_SETTING_WIRELESS_SECURITY_AUTH_ALG,
Packit Service a1bd4f
                                          "open",
Packit Service a1bd4f
                                          NM_SETTING_WIRELESS_SECURITY_KEY_MGMT,
Packit Service a1bd4f
                                          key_mgmt,
Packit Service a1bd4f
                                          NULL));
Packit Service a1bd4f
        nm_connection_add_setting(connection, setting);
Packit Service a1bd4f
    }
Packit Service a1bd4f
Packit Service a1bd4f
    if (id->security == NM_IWD_NETWORK_SECURITY_8021X) {
Packit Service a1bd4f
        /* "password" and "private-key-password" may be requested by the IWD agent
Packit Service a1bd4f
         * from NM and IWD will implement a specific secret cache policy so by
Packit Service a1bd4f
         * default respect that policy and don't save copies of those secrets in
Packit Service a1bd4f
         * NM settings.  The saved values can not be used anyway because of our
Packit Service a1bd4f
         * use of NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW.
Packit Service a1bd4f
         */
Packit Service a1bd4f
        setting = NM_SETTING(g_object_new(NM_TYPE_SETTING_802_1X,
Packit Service a1bd4f
                                          NM_SETTING_802_1X_PASSWORD_FLAGS,
Packit Service a1bd4f
                                          NM_SETTING_SECRET_FLAG_NOT_SAVED,
Packit Service a1bd4f
                                          NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD_FLAGS,
Packit Service a1bd4f
                                          NM_SETTING_SECRET_FLAG_NOT_SAVED,
Packit Service a1bd4f
                                          NULL));
Packit Service a1bd4f
        nm_setting_802_1x_add_eap_method(NM_SETTING_802_1X(setting), "external");
Packit Service a1bd4f
        nm_connection_add_setting(connection, setting);
Packit Service a1bd4f
    }
Packit Service a1bd4f
Packit Service a1bd4f
    if (!nm_connection_normalize(connection, NULL, NULL, NULL))
Packit Service a1bd4f
        return NULL;
Packit Service a1bd4f
Packit Service a1bd4f
    if (!nm_settings_add_connection(
Packit Service a1bd4f
            priv->settings,
Packit Service a1bd4f
            connection,
Packit Service a1bd4f
            NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_ONLY,
Packit Service a1bd4f
            NM_SETTINGS_CONNECTION_ADD_REASON_NONE,
Packit Service a1bd4f
            NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED
Packit Service a1bd4f
                | (known_network ? 0 : NM_SETTINGS_CONNECTION_INT_FLAGS_EXTERNAL),
Packit Service a1bd4f
            &settings_connection,
Packit Service a1bd4f
            &error)) {
Packit Service a1bd4f
        _LOGW("failed to add a mirror NMConnection for IWD's Known Network '%s': %s",
Packit Service a1bd4f
              id->name,
Packit Service a1bd4f
              error->message);
Packit Service a1bd4f
        return NULL;
Packit Service a1bd4f
    }
Packit Service a1bd4f
Packit Service a1bd4f
    return settings_connection;
Packit Service a1bd4f
}
Packit 5756e2
Packit Service a1bd4f
static void
Packit Service a1bd4f
mirror_connection_take_and_delete(NMSettingsConnection *sett_conn, KnownNetworkData *data)
Packit Service a1bd4f
{
Packit Service a1bd4f
    NMSettingsConnectionIntFlags flags;
Packit 5756e2
Packit Service a1bd4f
    if (!sett_conn)
Packit Service a1bd4f
        return;
Packit 5756e2
Packit Service a1bd4f
    flags = nm_settings_connection_get_flags(sett_conn);
Packit 5756e2
Packit Service a1bd4f
    /* If connection has not been saved since we created it
Packit Service a1bd4f
     * in interface_added it too can be removed now. */
Packit Service a1bd4f
    if (NM_FLAGS_HAS(flags, NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED))
Packit Service a1bd4f
        nm_settings_connection_delete(sett_conn, FALSE);
Packit 5756e2
Packit Service a1bd4f
    g_signal_handlers_disconnect_by_data(sett_conn, data);
Packit Service a1bd4f
    g_object_unref(sett_conn);
Packit 5756e2
}
Packit 5756e2
Packit 5756e2
static void
Packit Service a1bd4f
interface_added(GDBusObjectManager *object_manager,
Packit Service a1bd4f
                GDBusObject *       object,
Packit Service a1bd4f
                GDBusInterface *    interface,
Packit Service a1bd4f
                gpointer            user_data)
Packit 5756e2
{
Packit Service a1bd4f
    NMIwdManager *       self = user_data;
Packit Service a1bd4f
    NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self);
Packit Service a1bd4f
    GDBusProxy *         proxy;
Packit Service a1bd4f
    const char *         iface_name;
Packit Service a1bd4f
Packit Service a1bd4f
    if (!priv->running)
Packit Service a1bd4f
        return;
Packit Service a1bd4f
Packit Service a1bd4f
    g_return_if_fail(G_IS_DBUS_PROXY(interface));
Packit Service a1bd4f
Packit Service a1bd4f
    proxy      = G_DBUS_PROXY(interface);
Packit Service a1bd4f
    iface_name = g_dbus_proxy_get_interface_name(proxy);
Packit Service a1bd4f
Packit Service a1bd4f
    if (nm_streq(iface_name, NM_IWD_DEVICE_INTERFACE)) {
Packit Service a1bd4f
        set_device_dbus_object(self, proxy, object);
Packit Service a1bd4f
        return;
Packit Service a1bd4f
    }
Packit Service a1bd4f
Packit Service a1bd4f
    if (nm_streq(iface_name, NM_IWD_KNOWN_NETWORK_INTERFACE)) {
Packit Service a1bd4f
        KnownNetworkId *      id;
Packit Service a1bd4f
        KnownNetworkId *      orig_id;
Packit Service a1bd4f
        KnownNetworkData *    data;
Packit Service a1bd4f
        NMIwdNetworkSecurity  security;
Packit Service a1bd4f
        const char *          type_str, *name;
Packit Service a1bd4f
        NMSettingsConnection *sett_conn = NULL;
Packit Service a1bd4f
Packit Service a1bd4f
        type_str = get_property_string_or_null(proxy, "Type");
Packit Service a1bd4f
        name     = get_property_string_or_null(proxy, "Name");
Packit Service a1bd4f
        if (!type_str || !name)
Packit Service a1bd4f
            return;
Packit Service a1bd4f
Packit Service a1bd4f
        if (nm_streq(type_str, "open"))
Packit Service a1bd4f
            security = NM_IWD_NETWORK_SECURITY_NONE;
Packit Service a1bd4f
        else if (nm_streq(type_str, "psk"))
Packit Service a1bd4f
            security = NM_IWD_NETWORK_SECURITY_PSK;
Packit Service a1bd4f
        else if (nm_streq(type_str, "8021x"))
Packit Service a1bd4f
            security = NM_IWD_NETWORK_SECURITY_8021X;
Packit Service a1bd4f
        else
Packit Service a1bd4f
            return;
Packit Service a1bd4f
Packit Service a1bd4f
        id = known_network_id_new(name, security);
Packit Service a1bd4f
Packit Service a1bd4f
        if (g_hash_table_lookup_extended(priv->known_networks,
Packit Service a1bd4f
                                         id,
Packit Service a1bd4f
                                         (void **) &orig_id,
Packit Service a1bd4f
                                         (void **) &data)) {
Packit Service a1bd4f
            _LOGW("DBus error: KnownNetwork already exists ('%s', %s)", name, type_str);
Packit Service a1bd4f
            nm_g_object_ref_set(&data->known_network, proxy);
Packit Service a1bd4f
            g_free(id);
Packit Service a1bd4f
            id = orig_id;
Packit Service a1bd4f
        } else {
Packit Service a1bd4f
            data                = g_slice_new0(KnownNetworkData);
Packit Service a1bd4f
            data->known_network = g_object_ref(proxy);
Packit Service a1bd4f
            g_hash_table_insert(priv->known_networks, id, data);
Packit Service a1bd4f
        }
Packit Service a1bd4f
Packit Service a1bd4f
        sett_conn = mirror_connection(self, id, TRUE, proxy);
Packit Service a1bd4f
Packit Service a1bd4f
        if (sett_conn && sett_conn != data->mirror_connection) {
Packit Service a1bd4f
            NMSettingsConnection *sett_conn_old = data->mirror_connection;
Packit Service a1bd4f
Packit Service a1bd4f
            data->mirror_connection = nm_g_object_ref(sett_conn);
Packit Service a1bd4f
            mirror_connection_take_and_delete(sett_conn_old, data);
Packit Service a1bd4f
Packit Service a1bd4f
            g_signal_connect(sett_conn,
Packit Service a1bd4f
                             NM_SETTINGS_CONNECTION_UPDATED_INTERNAL,
Packit Service a1bd4f
                             G_CALLBACK(sett_conn_changed),
Packit Service a1bd4f
                             data);
Packit Service a1bd4f
        }
Packit Service a1bd4f
Packit Service a1bd4f
        return;
Packit Service a1bd4f
    }
Packit Service a1bd4f
Packit Service a1bd4f
    if (nm_streq(iface_name, NM_IWD_NETWORK_INTERFACE)) {
Packit Service a1bd4f
        NMDeviceIwd *device = get_device_from_network(self, proxy);
Packit Service a1bd4f
Packit Service a1bd4f
        if (device)
Packit Service a1bd4f
            nm_device_iwd_network_add_remove(device, proxy, TRUE);
Packit Service a1bd4f
Packit Service a1bd4f
        return;
Packit Service a1bd4f
    }
Packit 5756e2
}
Packit 5756e2
Packit 5756e2
static void
Packit Service a1bd4f
interface_removed(GDBusObjectManager *object_manager,
Packit Service a1bd4f
                  GDBusObject *       object,
Packit Service a1bd4f
                  GDBusInterface *    interface,
Packit Service a1bd4f
                  gpointer            user_data)
Packit 5756e2
{
Packit Service a1bd4f
    NMIwdManager *       self = user_data;
Packit Service a1bd4f
    NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self);
Packit Service a1bd4f
    GDBusProxy *         proxy;
Packit Service a1bd4f
    const char *         iface_name;
Packit Service a1bd4f
Packit Service a1bd4f
    g_return_if_fail(G_IS_DBUS_PROXY(interface));
Packit Service a1bd4f
Packit Service a1bd4f
    proxy      = G_DBUS_PROXY(interface);
Packit Service a1bd4f
    iface_name = g_dbus_proxy_get_interface_name(proxy);
Packit Service a1bd4f
Packit Service a1bd4f
    if (nm_streq(iface_name, NM_IWD_DEVICE_INTERFACE)) {
Packit Service a1bd4f
        set_device_dbus_object(self, proxy, NULL);
Packit Service a1bd4f
        return;
Packit Service a1bd4f
    }
Packit Service a1bd4f
Packit Service a1bd4f
    if (nm_streq(iface_name, NM_IWD_KNOWN_NETWORK_INTERFACE)) {
Packit Service a1bd4f
        KnownNetworkId id;
Packit Service a1bd4f
        const char *   type_str;
Packit Service a1bd4f
Packit Service a1bd4f
        type_str = get_property_string_or_null(proxy, "Type");
Packit Service a1bd4f
        id.name  = get_property_string_or_null(proxy, "Name");
Packit Service a1bd4f
        if (!type_str || !id.name)
Packit Service a1bd4f
            return;
Packit Service a1bd4f
Packit Service a1bd4f
        if (nm_streq(type_str, "open"))
Packit Service a1bd4f
            id.security = NM_IWD_NETWORK_SECURITY_NONE;
Packit Service a1bd4f
        else if (nm_streq(type_str, "psk"))
Packit Service a1bd4f
            id.security = NM_IWD_NETWORK_SECURITY_PSK;
Packit Service a1bd4f
        else if (nm_streq(type_str, "8021x"))
Packit Service a1bd4f
            id.security = NM_IWD_NETWORK_SECURITY_8021X;
Packit Service a1bd4f
        else
Packit Service a1bd4f
            return;
Packit Service a1bd4f
Packit Service a1bd4f
        g_hash_table_remove(priv->known_networks, &id;;
Packit Service a1bd4f
        return;
Packit Service a1bd4f
    }
Packit Service a1bd4f
Packit Service a1bd4f
    if (nm_streq(iface_name, NM_IWD_NETWORK_INTERFACE)) {
Packit Service a1bd4f
        NMDeviceIwd *device = get_device_from_network(self, proxy);
Packit Service a1bd4f
Packit Service a1bd4f
        if (device)
Packit Service a1bd4f
            nm_device_iwd_network_add_remove(device, proxy, FALSE);
Packit Service a1bd4f
Packit Service a1bd4f
        return;
Packit Service a1bd4f
    }
Packit 5756e2
}
Packit 5756e2
Packit 5756e2
static void
Packit Service a1bd4f
object_added(GDBusObjectManager *object_manager, GDBusObject *object, gpointer user_data)
Packit 5756e2
{
Packit Service a1bd4f
    GList *interfaces, *iter;
Packit 5756e2
Packit Service a1bd4f
    interfaces = g_dbus_object_get_interfaces(object);
Packit 5756e2
Packit Service a1bd4f
    for (iter = interfaces; iter; iter = iter->next) {
Packit Service a1bd4f
        GDBusInterface *interface = G_DBUS_INTERFACE(iter->data);
Packit 5756e2
Packit Service a1bd4f
        interface_added(NULL, object, interface, user_data);
Packit Service a1bd4f
    }
Packit 5756e2
Packit Service a1bd4f
    g_list_free_full(interfaces, g_object_unref);
Packit 5756e2
}
Packit 5756e2
Packit 5756e2
static void
Packit Service a1bd4f
object_removed(GDBusObjectManager *object_manager, GDBusObject *object, gpointer user_data)
Packit 5756e2
{
Packit Service a1bd4f
    GList *interfaces, *iter;
Packit 5756e2
Packit Service a1bd4f
    interfaces = g_dbus_object_get_interfaces(object);
Packit 5756e2
Packit Service a1bd4f
    for (iter = interfaces; iter; iter = iter->next) {
Packit Service a1bd4f
        GDBusInterface *interface = G_DBUS_INTERFACE(iter->data);
Packit 5756e2
Packit Service a1bd4f
        interface_removed(NULL, object, interface, user_data);
Packit Service a1bd4f
    }
Packit 5756e2
Packit Service a1bd4f
    g_list_free_full(interfaces, g_object_unref);
Packit 5756e2
}
Packit 5756e2
Packit 5756e2
static void
Packit Service a1bd4f
connection_removed(NMSettings *settings, NMSettingsConnection *sett_conn, gpointer user_data)
Packit 5756e2
{
Packit Service a1bd4f
    NMIwdManager *        self = user_data;
Packit Service a1bd4f
    NMIwdManagerPrivate * priv = NM_IWD_MANAGER_GET_PRIVATE(self);
Packit Service a1bd4f
    NMConnection *        conn = nm_settings_connection_get_connection(sett_conn);
Packit Service a1bd4f
    NMSettingWireless *   s_wireless;
Packit Service a1bd4f
    KnownNetworkData *    data;
Packit Service a1bd4f
    KnownNetworkId        id;
Packit Service a1bd4f
    char                  ssid_buf[33];
Packit Service a1bd4f
    const guint8 *        ssid_bytes;
Packit Service a1bd4f
    gsize                 ssid_len;
Packit Service a1bd4f
    NMSettingsConnection *new_mirror_conn;
Packit Service a1bd4f
Packit Service a1bd4f
    if (!nm_wifi_connection_get_iwd_ssid_and_security(conn, NULL, &id.security))
Packit Service a1bd4f
        return;
Packit Service a1bd4f
Packit Service a1bd4f
    s_wireless = nm_connection_get_setting_wireless(conn);
Packit Service a1bd4f
    if (!s_wireless)
Packit Service a1bd4f
        return;
Packit Service a1bd4f
Packit Service a1bd4f
    ssid_bytes = g_bytes_get_data(nm_setting_wireless_get_ssid(s_wireless), &ssid_len);
Packit Service a1bd4f
    if (!ssid_bytes || ssid_len > 32 || memchr(ssid_bytes, 0, ssid_len))
Packit Service a1bd4f
        return;
Packit Service a1bd4f
Packit Service a1bd4f
    memcpy(ssid_buf, ssid_bytes, ssid_len);
Packit Service a1bd4f
    ssid_buf[ssid_len] = '\0';
Packit Service a1bd4f
    id.name            = ssid_buf;
Packit Service a1bd4f
    data               = g_hash_table_lookup(priv->known_networks, &id;;
Packit Service a1bd4f
    if (!data)
Packit Service a1bd4f
        return;
Packit Service a1bd4f
Packit Service a1bd4f
    if (data->mirror_connection != sett_conn)
Packit Service a1bd4f
        return;
Packit Service a1bd4f
Packit Service a1bd4f
    g_clear_object(&data->mirror_connection);
Packit Service a1bd4f
Packit Service a1bd4f
    /* Don't call Forget on the Known Network until there's no longer *any*
Packit Service a1bd4f
     * matching NMSettingsConnection (debatable)
Packit Service a1bd4f
     */
Packit Service a1bd4f
    new_mirror_conn = mirror_connection(self, &id, FALSE, NULL);
Packit Service a1bd4f
    if (new_mirror_conn) {
Packit Service a1bd4f
        data->mirror_connection = g_object_ref(new_mirror_conn);
Packit Service a1bd4f
        return;
Packit Service a1bd4f
    }
Packit Service a1bd4f
Packit Service a1bd4f
    if (!priv->running)
Packit Service a1bd4f
        return;
Packit Service a1bd4f
Packit Service a1bd4f
    g_dbus_proxy_call(data->known_network,
Packit Service a1bd4f
                      "Forget",
Packit Service a1bd4f
                      NULL,
Packit Service a1bd4f
                      G_DBUS_CALL_FLAGS_NONE,
Packit Service a1bd4f
                      -1,
Packit Service a1bd4f
                      NULL,
Packit Service a1bd4f
                      NULL,
Packit Service a1bd4f
                      NULL);
Packit Service a1bd4f
}
Packit 5756e2
Packit Service a1bd4f
static gboolean
Packit Service a1bd4f
_om_has_name_owner(GDBusObjectManager *object_manager)
Packit Service a1bd4f
{
Packit Service a1bd4f
    gs_free char *name_owner = NULL;
Packit 5756e2
Packit Service a1bd4f
    nm_assert(G_IS_DBUS_OBJECT_MANAGER_CLIENT(object_manager));
Packit 5756e2
Packit Service a1bd4f
    name_owner =
Packit Service a1bd4f
        g_dbus_object_manager_client_get_name_owner(G_DBUS_OBJECT_MANAGER_CLIENT(object_manager));
Packit Service a1bd4f
    return !!name_owner;
Packit 5756e2
}
Packit 5756e2
Packit 5756e2
static void
Packit Service a1bd4f
release_object_manager(NMIwdManager *self)
Packit 5756e2
{
Packit Service a1bd4f
    NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self);
Packit 5756e2
Packit Service a1bd4f
    if (!priv->object_manager)
Packit Service a1bd4f
        return;
Packit 5756e2
Packit Service a1bd4f
    g_signal_handlers_disconnect_by_data(priv->object_manager, self);
Packit 5756e2
Packit Service a1bd4f
    if (priv->agent_id) {
Packit Service a1bd4f
        GDBusConnection *         agent_connection;
Packit Service a1bd4f
        GDBusObjectManagerClient *omc = G_DBUS_OBJECT_MANAGER_CLIENT(priv->object_manager);
Packit 5756e2
Packit Service a1bd4f
        agent_connection = g_dbus_object_manager_client_get_connection(omc);
Packit 5756e2
Packit Service a1bd4f
        /* We're is called when we're shutting down (i.e. our DBus connection
Packit Service a1bd4f
         * is being closed, and IWD will detect this) or IWD was stopped so
Packit Service a1bd4f
         * in either case calling UnregisterAgent will not do anything.
Packit Service a1bd4f
         */
Packit Service a1bd4f
        g_dbus_connection_unregister_object(agent_connection, priv->agent_id);
Packit Service a1bd4f
        priv->agent_id = 0;
Packit Service a1bd4f
        nm_clear_g_free(&priv->agent_path);
Packit Service a1bd4f
    }
Packit 5756e2
Packit Service a1bd4f
    g_clear_object(&priv->object_manager);
Packit Service a1bd4f
}
Packit 5756e2
Packit Service a1bd4f
static void prepare_object_manager(NMIwdManager *self);
Packit 5756e2
Packit Service a1bd4f
static void
Packit Service a1bd4f
name_owner_changed(GObject *object, GParamSpec *pspec, gpointer user_data)
Packit Service a1bd4f
{
Packit Service a1bd4f
    NMIwdManager *       self           = user_data;
Packit Service a1bd4f
    NMIwdManagerPrivate *priv           = NM_IWD_MANAGER_GET_PRIVATE(self);
Packit Service a1bd4f
    GDBusObjectManager * object_manager = G_DBUS_OBJECT_MANAGER(object);
Packit Service a1bd4f
Packit Service a1bd4f
    nm_assert(object_manager == priv->object_manager);
Packit Service a1bd4f
Packit Service a1bd4f
    if (_om_has_name_owner(object_manager)) {
Packit Service a1bd4f
        release_object_manager(self);
Packit Service a1bd4f
        prepare_object_manager(self);
Packit Service a1bd4f
    } else {
Packit Service a1bd4f
        const CList *tmp_lst;
Packit Service a1bd4f
        NMDevice *   device;
Packit Service a1bd4f
Packit Service a1bd4f
        if (!priv->running)
Packit Service a1bd4f
            return;
Packit Service a1bd4f
Packit Service a1bd4f
        priv->running = false;
Packit Service a1bd4f
Packit Service a1bd4f
        nm_manager_for_each_device (priv->manager, device, tmp_lst) {
Packit Service a1bd4f
            if (NM_IS_DEVICE_IWD(device)) {
Packit Service a1bd4f
                nm_device_iwd_set_dbus_object(NM_DEVICE_IWD(device), NULL);
Packit Service a1bd4f
            }
Packit Service a1bd4f
        }
Packit Service a1bd4f
    }
Packit Service a1bd4f
}
Packit 5756e2
Packit Service a1bd4f
static void
Packit Service a1bd4f
device_added(NMManager *manager, NMDevice *device, gpointer user_data)
Packit Service a1bd4f
{
Packit Service a1bd4f
    NMIwdManager *       self = user_data;
Packit Service a1bd4f
    NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self);
Packit Service a1bd4f
    GList *              objects, *iter;
Packit Service a1bd4f
Packit Service a1bd4f
    if (!NM_IS_DEVICE_IWD(device))
Packit Service a1bd4f
        return;
Packit Service a1bd4f
Packit Service a1bd4f
    if (!priv->running)
Packit Service a1bd4f
        return;
Packit Service a1bd4f
Packit Service a1bd4f
    /* Here we handle a potential scenario where IWD's DBus objects for the
Packit Service a1bd4f
     * new device popped up before the NMDevice.  The
Packit Service a1bd4f
     * interface_added/object_added signals have been received already and
Packit Service a1bd4f
     * the handlers couldn't do much because the NMDevice wasn't there yet
Packit Service a1bd4f
     * so now we go over the Network and Device interfaces again.  In this
Packit Service a1bd4f
     * exact order for "object path" property consistency -- see reasoning
Packit Service a1bd4f
     * in object_compare_interfaces.
Packit Service a1bd4f
     */
Packit Service a1bd4f
    objects = g_dbus_object_manager_get_objects(priv->object_manager);
Packit Service a1bd4f
Packit Service a1bd4f
    for (iter = objects; iter; iter = iter->next) {
Packit Service a1bd4f
        GDBusObject *   object                    = G_DBUS_OBJECT(iter->data);
Packit Service a1bd4f
        gs_unref_object GDBusInterface *interface = NULL;
Packit Service a1bd4f
Packit Service a1bd4f
        interface = g_dbus_object_get_interface(object, NM_IWD_NETWORK_INTERFACE);
Packit Service a1bd4f
        if (!interface)
Packit Service a1bd4f
            continue;
Packit Service a1bd4f
Packit Service a1bd4f
        if (NM_DEVICE_IWD(device) == get_device_from_network(self, (GDBusProxy *) interface))
Packit Service a1bd4f
            nm_device_iwd_network_add_remove(NM_DEVICE_IWD(device), (GDBusProxy *) interface, TRUE);
Packit Service a1bd4f
    }
Packit Service a1bd4f
Packit Service a1bd4f
    for (iter = objects; iter; iter = iter->next) {
Packit Service a1bd4f
        GDBusObject *   object                    = G_DBUS_OBJECT(iter->data);
Packit Service a1bd4f
        gs_unref_object GDBusInterface *interface = NULL;
Packit Service a1bd4f
        const char *                    obj_ifname;
Packit Service a1bd4f
Packit Service a1bd4f
        interface  = g_dbus_object_get_interface(object, NM_IWD_DEVICE_INTERFACE);
Packit Service a1bd4f
        obj_ifname = get_property_string_or_null((GDBusProxy *) interface, "Name");
Packit Service a1bd4f
Packit Service a1bd4f
        if (!obj_ifname || strcmp(nm_device_get_iface(device), obj_ifname))
Packit Service a1bd4f
            continue;
Packit Service a1bd4f
Packit Service a1bd4f
        nm_device_iwd_set_dbus_object(NM_DEVICE_IWD(device), object);
Packit Service a1bd4f
        break;
Packit Service a1bd4f
    }
Packit Service a1bd4f
Packit Service a1bd4f
    g_list_free_full(objects, g_object_unref);
Packit Service a1bd4f
}
Packit 5756e2
Packit Service a1bd4f
static void
Packit Service a1bd4f
device_removed(NMManager *manager, NMDevice *device, gpointer user_data)
Packit Service a1bd4f
{
Packit Service a1bd4f
    NMIwdManager *       self = user_data;
Packit Service a1bd4f
    NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self);
Packit 5756e2
Packit Service a1bd4f
    if (!NM_IS_DEVICE_IWD(device))
Packit Service a1bd4f
        return;
Packit 5756e2
Packit Service a1bd4f
    if (priv->last_agent_call_device == NM_DEVICE_IWD(device))
Packit Service a1bd4f
        priv->last_agent_call_device = NULL;
Packit Service a1bd4f
}
Packit 5756e2
Packit Service a1bd4f
/* This is used to sort the list of objects returned by GetManagedObjects()
Packit Service a1bd4f
 * based on the DBus interfaces available on these objects in such a way that
Packit Service a1bd4f
 * the interface_added calls happen in the right order.  The order is defined
Packit Service a1bd4f
 * by how some DBus interfaces point to interfaces on other objects using
Packit Service a1bd4f
 * DBus properties of the type "object path" ("o" signature).  This creates
Packit Service a1bd4f
 * "dependencies" between objects.
Packit Service a1bd4f
 *
Packit Service a1bd4f
 * When NM and IWD are running, the InterfacesAdded signals should come in
Packit Service a1bd4f
 * an order that ensures consistency of those object paths.  For example
Packit Service a1bd4f
 * when a Network interface is added with a KnownNetwork property, or that
Packit Service a1bd4f
 * property is assigned a new value, the KnownNetwork object pointed to by
Packit Service a1bd4f
 * it will have been added in an earlier InterfacesAdded signal.  Similarly
Packit Service a1bd4f
 * Station.ConnectedNetwork and Station.GetOrdereNetworks() only point to
Packit Service a1bd4f
 * existing Network objects.  (There may be circular dependencies but during
Packit Service a1bd4f
 * initialization we only need a subset of those properties that doesn't
Packit Service a1bd4f
 * have this problem.)
Packit Service a1bd4f
 *
Packit Service a1bd4f
 * But GetManagedObjects doesn't guarantee this kind of consistency so we
Packit Service a1bd4f
 * order the returned object list ourselves to simplify the job of
Packit Service a1bd4f
 * interface_added().  Objects that don't have any interfaces listed in
Packit Service a1bd4f
 * interface_order are moved to the end of the list.
Packit Service a1bd4f
 */
Packit Service a1bd4f
static int
Packit Service a1bd4f
object_compare_interfaces(gconstpointer a, gconstpointer b)
Packit Service a1bd4f
{
Packit Service a1bd4f
    static const char *interface_order[] = {
Packit Service a1bd4f
        NM_IWD_KNOWN_NETWORK_INTERFACE,
Packit Service a1bd4f
        NM_IWD_NETWORK_INTERFACE,
Packit Service a1bd4f
        NM_IWD_DEVICE_INTERFACE,
Packit Service a1bd4f
    };
Packit Service a1bd4f
    int   rank_a = G_N_ELEMENTS(interface_order);
Packit Service a1bd4f
    int   rank_b = G_N_ELEMENTS(interface_order);
Packit Service a1bd4f
    guint pos;
Packit Service a1bd4f
Packit Service a1bd4f
    for (pos = 0; interface_order[pos]; pos++) {
Packit Service a1bd4f
        GDBusInterface *iface_a;
Packit Service a1bd4f
        GDBusInterface *iface_b;
Packit Service a1bd4f
Packit Service a1bd4f
        if (rank_a == G_N_ELEMENTS(interface_order)
Packit Service a1bd4f
            && (iface_a = g_dbus_object_get_interface(G_DBUS_OBJECT(a), interface_order[pos]))) {
Packit Service a1bd4f
            rank_a = pos;
Packit Service a1bd4f
            g_object_unref(iface_a);
Packit Service a1bd4f
        }
Packit Service a1bd4f
Packit Service a1bd4f
        if (rank_b == G_N_ELEMENTS(interface_order)
Packit Service a1bd4f
            && (iface_b = g_dbus_object_get_interface(G_DBUS_OBJECT(b), interface_order[pos]))) {
Packit Service a1bd4f
            rank_b = pos;
Packit Service a1bd4f
            g_object_unref(iface_b);
Packit Service a1bd4f
        }
Packit Service a1bd4f
    }
Packit Service a1bd4f
Packit Service a1bd4f
    return rank_a - rank_b;
Packit 5756e2
}
Packit 5756e2
Packit 5756e2
static void
Packit Service a1bd4f
got_object_manager(GObject *object, GAsyncResult *result, gpointer user_data)
Packit 5756e2
{
Packit Service a1bd4f
    NMIwdManager *       self  = user_data;
Packit Service a1bd4f
    NMIwdManagerPrivate *priv  = NM_IWD_MANAGER_GET_PRIVATE(self);
Packit Service a1bd4f
    GError *             error = NULL;
Packit Service a1bd4f
    GDBusObjectManager * object_manager;
Packit Service a1bd4f
    GDBusConnection *    connection;
Packit Service a1bd4f
Packit Service a1bd4f
    object_manager = g_dbus_object_manager_client_new_for_bus_finish(result, &error);
Packit Service a1bd4f
    if (object_manager == NULL) {
Packit Service a1bd4f
        _LOGE("failed to acquire IWD Object Manager: Wi-Fi will not be available (%s)",
Packit Service a1bd4f
              error->message);
Packit Service a1bd4f
        g_clear_error(&error);
Packit Service a1bd4f
        return;
Packit Service a1bd4f
    }
Packit Service a1bd4f
Packit Service a1bd4f
    priv->object_manager = object_manager;
Packit Service a1bd4f
Packit Service a1bd4f
    g_signal_connect(priv->object_manager,
Packit Service a1bd4f
                     "notify::name-owner",
Packit Service a1bd4f
                     G_CALLBACK(name_owner_changed),
Packit Service a1bd4f
                     self);
Packit Service a1bd4f
Packit Service a1bd4f
    nm_assert(G_IS_DBUS_OBJECT_MANAGER_CLIENT(object_manager));
Packit Service a1bd4f
Packit Service a1bd4f
    connection =
Packit Service a1bd4f
        g_dbus_object_manager_client_get_connection(G_DBUS_OBJECT_MANAGER_CLIENT(object_manager));
Packit Service a1bd4f
Packit Service a1bd4f
    priv->agent_id = iwd_agent_export(connection, self, &priv->agent_path, &error);
Packit Service a1bd4f
    if (!priv->agent_id) {
Packit Service a1bd4f
        _LOGE("failed to export the IWD Agent: PSK/8021x Wi-Fi networks may not work: %s",
Packit Service a1bd4f
              error->message);
Packit Service a1bd4f
        g_clear_error(&error);
Packit Service a1bd4f
    }
Packit Service a1bd4f
Packit Service a1bd4f
    if (_om_has_name_owner(object_manager)) {
Packit Service a1bd4f
        GList *objects, *iter;
Packit Service a1bd4f
Packit Service a1bd4f
        priv->running = true;
Packit Service a1bd4f
Packit Service a1bd4f
        g_signal_connect(priv->object_manager,
Packit Service a1bd4f
                         "interface-added",
Packit Service a1bd4f
                         G_CALLBACK(interface_added),
Packit Service a1bd4f
                         self);
Packit Service a1bd4f
        g_signal_connect(priv->object_manager,
Packit Service a1bd4f
                         "interface-removed",
Packit Service a1bd4f
                         G_CALLBACK(interface_removed),
Packit Service a1bd4f
                         self);
Packit Service a1bd4f
        g_signal_connect(priv->object_manager, "object-added", G_CALLBACK(object_added), self);
Packit Service a1bd4f
        g_signal_connect(priv->object_manager, "object-removed", G_CALLBACK(object_removed), self);
Packit Service a1bd4f
Packit Service a1bd4f
        g_hash_table_remove_all(priv->known_networks);
Packit Service a1bd4f
Packit Service a1bd4f
        objects = g_dbus_object_manager_get_objects(object_manager);
Packit Service a1bd4f
        objects = g_list_sort(objects, object_compare_interfaces);
Packit Service a1bd4f
        for (iter = objects; iter; iter = iter->next)
Packit Service a1bd4f
            object_added(NULL, G_DBUS_OBJECT(iter->data), self);
Packit Service a1bd4f
Packit Service a1bd4f
        g_list_free_full(objects, g_object_unref);
Packit Service a1bd4f
Packit Service a1bd4f
        if (priv->agent_id)
Packit Service a1bd4f
            register_agent(self);
Packit Service a1bd4f
    }
Packit Service a1bd4f
}
Packit 5756e2
Packit Service a1bd4f
static void
Packit Service a1bd4f
prepare_object_manager(NMIwdManager *self)
Packit Service a1bd4f
{
Packit Service a1bd4f
    NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self);
Packit Service a1bd4f
Packit Service a1bd4f
    g_dbus_object_manager_client_new_for_bus(NM_IWD_BUS_TYPE,
Packit Service a1bd4f
                                             G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
Packit Service a1bd4f
                                             NM_IWD_SERVICE,
Packit Service a1bd4f
                                             "/",
Packit Service a1bd4f
                                             NULL,
Packit Service a1bd4f
                                             NULL,
Packit Service a1bd4f
                                             NULL,
Packit Service a1bd4f
                                             priv->cancellable,
Packit Service a1bd4f
                                             got_object_manager,
Packit Service a1bd4f
                                             self);
Packit 5756e2
}
Packit 5756e2
Packit 5756e2
gboolean
Packit Service a1bd4f
nm_iwd_manager_is_known_network(NMIwdManager *self, const char *name, NMIwdNetworkSecurity security)
Packit 5756e2
{
Packit Service a1bd4f
    NMIwdManagerPrivate *priv  = NM_IWD_MANAGER_GET_PRIVATE(self);
Packit Service a1bd4f
    KnownNetworkId       kn_id = {name, security};
Packit 5756e2
Packit Service a1bd4f
    return g_hash_table_contains(priv->known_networks, &kn_id);
Packit Service a1bd4f
}
Packit Service a1bd4f
Packit Service a1bd4f
NMSettingsConnection *
Packit Service a1bd4f
nm_iwd_manager_get_ap_mirror_connection(NMIwdManager *self, NMWifiAP *ap)
Packit Service a1bd4f
{
Packit Service a1bd4f
    NMIwdManagerPrivate *  priv = NM_IWD_MANAGER_GET_PRIVATE(self);
Packit Service a1bd4f
    KnownNetworkData *     data;
Packit Service a1bd4f
    char                   name_buf[33];
Packit Service a1bd4f
    KnownNetworkId         kn_id = {name_buf, NM_IWD_NETWORK_SECURITY_NONE};
Packit Service a1bd4f
    const guint8 *         ssid_bytes;
Packit Service a1bd4f
    gsize                  ssid_len;
Packit Service a1bd4f
    NM80211ApFlags         flags     = nm_wifi_ap_get_flags(ap);
Packit Service a1bd4f
    NM80211ApSecurityFlags sec_flags = nm_wifi_ap_get_wpa_flags(ap) | nm_wifi_ap_get_rsn_flags(ap);
Packit Service a1bd4f
Packit Service a1bd4f
    ssid_bytes = g_bytes_get_data(nm_wifi_ap_get_ssid(ap), &ssid_len);
Packit Service a1bd4f
    ssid_len   = MIN(ssid_len, 32);
Packit Service a1bd4f
    memcpy(name_buf, ssid_bytes, ssid_len);
Packit Service a1bd4f
    name_buf[ssid_len] = '\0';
Packit Service a1bd4f
Packit Service a1bd4f
    if (flags & NM_802_11_AP_FLAGS_PRIVACY)
Packit Service a1bd4f
        kn_id.security = NM_IWD_NETWORK_SECURITY_WEP;
Packit Service a1bd4f
Packit Service a1bd4f
    if (sec_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK)
Packit Service a1bd4f
        kn_id.security = NM_IWD_NETWORK_SECURITY_PSK;
Packit Service a1bd4f
    else if (sec_flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X)
Packit Service a1bd4f
        kn_id.security = NM_IWD_NETWORK_SECURITY_8021X;
Packit Service a1bd4f
Packit Service a1bd4f
    /* Right now it's easier for us to do a name+security lookup than to use
Packit Service a1bd4f
     * the Network.KnownNetwork property to look up by path.
Packit Service a1bd4f
     */
Packit Service a1bd4f
    data = g_hash_table_lookup(priv->known_networks, &kn_id);
Packit Service a1bd4f
    if (data)
Packit Service a1bd4f
        return data->mirror_connection;
Packit Service a1bd4f
Packit Service a1bd4f
    /* We have no KnownNetwork for this AP, we're probably connecting to it for
Packit Service a1bd4f
     * the first time.  This is not a usual/supported scenario so we don't need
Packit Service a1bd4f
     * to bother too much about creating a great mirror connection, we don't
Packit Service a1bd4f
     * even have any more information than the Name & Type properties on the
Packit Service a1bd4f
     * Network interface.  This *should* never happen for an 8021x type network.
Packit Service a1bd4f
     */
Packit Service a1bd4f
    return mirror_connection(self, &kn_id, TRUE, NULL);
Packit 5756e2
}
Packit 5756e2
Packit 5756e2
GDBusProxy *
Packit Service a1bd4f
nm_iwd_manager_get_dbus_interface(NMIwdManager *self, const char *path, const char *name)
Packit 5756e2
{
Packit Service a1bd4f
    NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self);
Packit Service a1bd4f
    GDBusInterface *     interface;
Packit 5756e2
Packit Service a1bd4f
    if (!priv->object_manager)
Packit Service a1bd4f
        return NULL;
Packit 5756e2
Packit Service a1bd4f
    interface = g_dbus_object_manager_get_interface(priv->object_manager, path, name);
Packit 5756e2
Packit Service a1bd4f
    return interface ? G_DBUS_PROXY(interface) : NULL;
Packit 5756e2
}
Packit 5756e2
Packit 5756e2
/*****************************************************************************/
Packit 5756e2
Packit Service a1bd4f
NM_DEFINE_SINGLETON_GETTER(NMIwdManager, nm_iwd_manager_get, NM_TYPE_IWD_MANAGER);
Packit 5756e2
Packit 5756e2
static void
Packit Service a1bd4f
nm_iwd_manager_init(NMIwdManager *self)
Packit 5756e2
{
Packit Service a1bd4f
    NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self);
Packit 5756e2
Packit Service a1bd4f
    priv->manager = g_object_ref(NM_MANAGER_GET);
Packit Service a1bd4f
    g_signal_connect(priv->manager, NM_MANAGER_DEVICE_ADDED, G_CALLBACK(device_added), self);
Packit Service a1bd4f
    g_signal_connect(priv->manager, NM_MANAGER_DEVICE_REMOVED, G_CALLBACK(device_removed), self);
Packit 5756e2
Packit Service a1bd4f
    priv->settings = g_object_ref(NM_SETTINGS_GET);
Packit Service a1bd4f
    g_signal_connect(priv->settings,
Packit Service a1bd4f
                     NM_SETTINGS_SIGNAL_CONNECTION_REMOVED,
Packit Service a1bd4f
                     G_CALLBACK(connection_removed),
Packit Service a1bd4f
                     self);
Packit 5756e2
Packit Service a1bd4f
    priv->cancellable = g_cancellable_new();
Packit 5756e2
Packit Service a1bd4f
    priv->known_networks = g_hash_table_new_full((GHashFunc) known_network_id_hash,
Packit Service a1bd4f
                                                 (GEqualFunc) known_network_id_equal,
Packit Service a1bd4f
                                                 g_free,
Packit Service a1bd4f
                                                 (GDestroyNotify) known_network_data_free);
Packit 5756e2
Packit Service a1bd4f
    prepare_object_manager(self);
Packit 5756e2
}
Packit 5756e2
Packit 5756e2
static void
Packit Service a1bd4f
dispose(GObject *object)
Packit 5756e2
{
Packit Service a1bd4f
    NMIwdManager *       self = (NMIwdManager *) object;
Packit Service a1bd4f
    NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self);
Packit Service a1bd4f
Packit Service a1bd4f
    release_object_manager(self);
Packit 5756e2
Packit Service a1bd4f
    nm_clear_g_cancellable(&priv->cancellable);
Packit 5756e2
Packit Service a1bd4f
    if (priv->settings) {
Packit Service a1bd4f
        g_signal_handlers_disconnect_by_data(priv->settings, self);
Packit Service a1bd4f
        g_clear_object(&priv->settings);
Packit Service a1bd4f
    }
Packit 5756e2
Packit Service a1bd4f
    /* This may trigger mirror connection removals so it happens
Packit Service a1bd4f
     * after the g_signal_handlers_disconnect_by_data above.
Packit Service a1bd4f
     */
Packit Service a1bd4f
    nm_clear_pointer(&priv->known_networks, g_hash_table_destroy);
Packit 5756e2
Packit Service a1bd4f
    if (priv->manager) {
Packit Service a1bd4f
        g_signal_handlers_disconnect_by_data(priv->manager, self);
Packit Service a1bd4f
        g_clear_object(&priv->manager);
Packit Service a1bd4f
    }
Packit 5756e2
Packit Service a1bd4f
    priv->last_agent_call_device = NULL;
Packit 5756e2
Packit Service a1bd4f
    G_OBJECT_CLASS(nm_iwd_manager_parent_class)->dispose(object);
Packit 5756e2
}
Packit 5756e2
Packit 5756e2
static void
Packit Service a1bd4f
nm_iwd_manager_class_init(NMIwdManagerClass *klass)
Packit 5756e2
{
Packit Service a1bd4f
    GObjectClass *object_class = G_OBJECT_CLASS(klass);
Packit 5756e2
Packit Service a1bd4f
    object_class->dispose = dispose;
Packit 5756e2
}