about summary refs log tree commit diff
path: root/src/core/devices/wifi
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2022-02-14 19:24:33 +0100
committerMichael Biebl <biebl@debian.org>2022-02-14 19:24:33 +0100
commit95864d59ac5530f59fe277580cc13f44b6de5b64 (patch)
tree617239c0147c38efedf639d325cd56e8c7fb8be9 /src/core/devices/wifi
parent1628eda029ba4dede8d4d45572c6b60367882436 (diff)
parent2f94dba7385fd0e0ef19a06eb4a2fcf6c43d7946 (diff)
Update upstream source from tag 'upstream/1.35.91'
Update to upstream version '1.35.91'
with Debian dir d8c1bf4c615814324dba64d19fe27402339c67f5
Diffstat (limited to 'src/core/devices/wifi')
-rw-r--r--src/core/devices/wifi/meson.build1
-rw-r--r--src/core/devices/wifi/nm-device-iwd-p2p.c1262
-rw-r--r--src/core/devices/wifi/nm-device-iwd-p2p.h36
-rw-r--r--src/core/devices/wifi/nm-device-iwd.c462
-rw-r--r--src/core/devices/wifi/nm-device-iwd.h4
-rw-r--r--src/core/devices/wifi/nm-device-olpc-mesh.c46
-rw-r--r--src/core/devices/wifi/nm-device-wifi-p2p.c212
-rw-r--r--src/core/devices/wifi/nm-device-wifi.c559
-rw-r--r--src/core/devices/wifi/nm-device-wifi.h4
-rw-r--r--src/core/devices/wifi/nm-iwd-manager.c497
-rw-r--r--src/core/devices/wifi/nm-iwd-manager.h40
-rw-r--r--src/core/devices/wifi/nm-wifi-ap.c48
-rw-r--r--src/core/devices/wifi/nm-wifi-ap.h14
-rw-r--r--src/core/devices/wifi/nm-wifi-common.c44
-rw-r--r--src/core/devices/wifi/nm-wifi-factory.c77
-rw-r--r--src/core/devices/wifi/nm-wifi-p2p-peer.c128
-rw-r--r--src/core/devices/wifi/nm-wifi-p2p-peer.h21
-rw-r--r--src/core/devices/wifi/nm-wifi-utils.c256
-rw-r--r--src/core/devices/wifi/nm-wifi-utils.h25
-rw-r--r--src/core/devices/wifi/tests/test-devices-wifi.c122
20 files changed, 2827 insertions, 1031 deletions
diff --git a/src/core/devices/wifi/meson.build b/src/core/devices/wifi/meson.build
index 85553c53..715bc0c9 100644
--- a/src/core/devices/wifi/meson.build
+++ b/src/core/devices/wifi/meson.build
@@ -4,6 +4,7 @@ iwd_sources = files()
 if enable_iwd
   iwd_sources += files(
     'nm-device-iwd.c',
+    'nm-device-iwd-p2p.c',
     'nm-iwd-manager.c',
   )
 endif
diff --git a/src/core/devices/wifi/nm-device-iwd-p2p.c b/src/core/devices/wifi/nm-device-iwd-p2p.c
new file mode 100644
index 00000000..01774b12
--- /dev/null
+++ b/src/core/devices/wifi/nm-device-iwd-p2p.c
@@ -0,0 +1,1262 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2021 Intel Corporation
+ */
+
+#include "src/core/nm-default-daemon.h"
+
+#include "nm-device-iwd-p2p.h"
+
+#include "NetworkManagerUtils.h"
+#include "devices/nm-device-private.h"
+#include "nm-act-request.h"
+#include "libnm-core-aux-intern/nm-libnm-core-utils.h"
+#include "libnm-core-intern/nm-core-internal.h"
+#include "libnm-std-aux/nm-dbus-compat.h"
+#include "nm-setting-wifi-p2p.h"
+#include "nm-utils.h"
+#include "nm-wifi-p2p-peer.h"
+#include "nm-iwd-manager.h"
+#include "settings/nm-settings.h"
+
+#define _NMLOG_DEVICE_TYPE NMDeviceIwdP2P
+#include "devices/nm-device-logging.h"
+
+/*****************************************************************************/
+
+NM_GOBJECT_PROPERTIES_DEFINE(NMDeviceIwdP2P, PROP_PEERS, );
+
+typedef struct {
+    GDBusObject *dbus_obj;
+    GDBusProxy  *dbus_p2p_proxy;
+    GDBusProxy  *dbus_peer_proxy;
+    CList        peers_lst_head;
+
+    GSource *find_peer_timeout_source;
+    GSource *peer_dump_source;
+
+    GCancellable *find_cancellable;
+    GCancellable *connect_cancellable;
+
+    bool enabled : 1;
+
+    bool stage2_ready : 1;
+
+    bool wfd_registered : 1;
+} NMDeviceIwdP2PPrivate;
+
+struct _NMDeviceIwdP2P {
+    NMDevice              parent;
+    NMDeviceIwdP2PPrivate _priv;
+};
+
+struct _NMDeviceIwdP2PClass {
+    NMDeviceClass parent;
+};
+
+G_DEFINE_TYPE(NMDeviceIwdP2P, nm_device_iwd_p2p, NM_TYPE_DEVICE)
+
+#define NM_DEVICE_IWD_P2P_GET_PRIVATE(self) \
+    _NM_GET_PRIVATE(self, NMDeviceIwdP2P, NM_IS_DEVICE_IWD_P2P, NMDevice)
+
+/*****************************************************************************/
+
+static const NMDBusInterfaceInfoExtended interface_info_device_wifi_p2p;
+static const GDBusSignalInfo             nm_signal_info_wifi_p2p_peer_added;
+static const GDBusSignalInfo             nm_signal_info_wifi_p2p_peer_removed;
+static gboolean                          iwd_discovery_timeout_cb(gpointer user_data);
+
+/*****************************************************************************/
+
+static void
+_peer_dump(NMDeviceIwdP2P      *self,
+           NMLogLevel           log_level,
+           const NMWifiP2PPeer *peer,
+           const char          *prefix,
+           gint32               now_s)
+{
+    char buf[1024];
+
+    _NMLOG(log_level,
+           LOGD_WIFI_SCAN,
+           "wifi-peer: %-7s %s",
+           prefix,
+           nm_wifi_p2p_peer_to_string(peer, buf, sizeof(buf), now_s));
+}
+
+static gboolean
+peer_list_dump(gpointer user_data)
+{
+    NMDeviceIwdP2P        *self = NM_DEVICE_IWD_P2P(user_data);
+    NMDeviceIwdP2PPrivate *priv = NM_DEVICE_IWD_P2P_GET_PRIVATE(self);
+
+    nm_clear_g_source_inst(&priv->peer_dump_source);
+
+    if (_LOGD_ENABLED(LOGD_WIFI_SCAN)) {
+        NMWifiP2PPeer *peer;
+        gint32         now_s = nm_utils_get_monotonic_timestamp_sec();
+
+        _LOGD(LOGD_WIFI_SCAN, "P2P Peers: [now:%u]", now_s);
+        c_list_for_each_entry (peer, &priv->peers_lst_head, peers_lst)
+            _peer_dump(self, LOGL_DEBUG, peer, "dump", now_s);
+    }
+
+    return G_SOURCE_REMOVE;
+}
+
+static void
+schedule_peer_list_dump(NMDeviceIwdP2P *self)
+{
+    NMDeviceIwdP2PPrivate *priv = NM_DEVICE_IWD_P2P_GET_PRIVATE(self);
+
+    if (!priv->peer_dump_source && _LOGD_ENABLED(LOGD_WIFI_SCAN)) {
+        priv->peer_dump_source = nm_g_timeout_add_seconds_source(1, peer_list_dump, self);
+    }
+}
+
+/*****************************************************************************/
+
+static gboolean
+is_available(NMDevice *device, NMDeviceCheckDevAvailableFlags flags)
+{
+    NMDeviceIwdP2P        *self = NM_DEVICE_IWD_P2P(device);
+    NMDeviceIwdP2PPrivate *priv = NM_DEVICE_IWD_P2P_GET_PRIVATE(self);
+
+    return priv->enabled;
+}
+
+static gboolean
+check_connection_compatible(NMDevice *device, NMConnection *connection, GError **error)
+{
+    NMSettingWifiP2P  *s_wifi_p2p;
+    GBytes            *wfd_ies;
+    NMSettingIPConfig *s_ip;
+
+    if (!NM_DEVICE_CLASS(nm_device_iwd_p2p_parent_class)
+             ->check_connection_compatible(device, connection, error))
+        return FALSE;
+
+    s_wifi_p2p =
+        NM_SETTING_WIFI_P2P(nm_connection_get_setting(connection, NM_TYPE_SETTING_WIFI_P2P));
+
+    /* Any of the existing values other than DISABLED is ok */
+    if (nm_setting_wifi_p2p_get_wps_method(s_wifi_p2p)
+        == NM_SETTING_WIRELESS_SECURITY_WPS_METHOD_DISABLED) {
+        nm_utils_error_set_literal(error,
+                                   NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE,
+                                   "No WPS method enabled");
+        return FALSE;
+    }
+
+    wfd_ies = nm_setting_wifi_p2p_get_wfd_ies(s_wifi_p2p);
+    if (wfd_ies && !nm_wifi_utils_parse_wfd_ies(wfd_ies, NULL)) {
+        nm_utils_error_set_literal(error,
+                                   NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE,
+                                   "Can't parse connection WFD IEs");
+        return FALSE;
+    }
+
+    s_ip = NM_SETTING_IP_CONFIG(nm_connection_get_setting_ip4_config(connection));
+    if (s_ip
+        && !NM_IN_STRSET(nm_setting_ip_config_get_method(s_ip),
+                         NULL,
+                         NM_SETTING_IP4_CONFIG_METHOD_AUTO)) {
+        nm_utils_error_set_literal(error,
+                                   NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE,
+                                   "P2P implies 'auto' IPv4 config method");
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+static gboolean
+check_connection_available(NMDevice                      *device,
+                           NMConnection                  *connection,
+                           NMDeviceCheckConAvailableFlags flags,
+                           const char                    *specific_object,
+                           GError                       **error)
+{
+    NMDeviceIwdP2P        *self = NM_DEVICE_IWD_P2P(device);
+    NMDeviceIwdP2PPrivate *priv = NM_DEVICE_IWD_P2P_GET_PRIVATE(self);
+    NMSettingWifiP2P      *s_wifi_p2p;
+    GBytes                *wfd_ies;
+    NMWifiP2PPeer         *peer;
+
+    if (specific_object) {
+        peer = nm_wifi_p2p_peer_lookup_for_device(NM_DEVICE(self), specific_object);
+        if (!peer) {
+            g_set_error(error,
+                        NM_UTILS_ERROR,
+                        NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY,
+                        "The P2P peer %s is unknown",
+                        specific_object);
+            return FALSE;
+        }
+
+        if (!nm_wifi_p2p_peer_check_compatible(peer, connection, FALSE)) {
+            nm_utils_error_set_literal(error,
+                                       NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY,
+                                       "Requested P2P peer is not compatible with profile");
+            return FALSE;
+        }
+    } else {
+        peer = nm_wifi_p2p_peers_find_first_compatible(&priv->peers_lst_head, connection, FALSE);
+        if (!peer) {
+            nm_utils_error_set_literal(error,
+                                       NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY,
+                                       "No compatible P2P peer found");
+            return FALSE;
+        }
+    }
+
+    s_wifi_p2p =
+        NM_SETTING_WIFI_P2P(nm_connection_get_setting(connection, NM_TYPE_SETTING_WIFI_P2P));
+    wfd_ies = nm_setting_wifi_p2p_get_wfd_ies(s_wifi_p2p);
+    if (wfd_ies) {
+        NMIwdWfdInfo wfd_info = {};
+
+        if (!nm_wifi_utils_parse_wfd_ies(wfd_ies, &wfd_info)) {
+            nm_utils_error_set_literal(error,
+                                       NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE,
+                                       "Can't parse connection WFD IEs");
+            return FALSE;
+        }
+
+        if (!nm_iwd_manager_check_wfd_info_compatible(nm_iwd_manager_get(), &wfd_info)) {
+            nm_utils_error_set_literal(error,
+                                       NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY,
+                                       "An incompatible WFD connection is active");
+            return FALSE;
+        }
+    }
+
+    return TRUE;
+}
+
+static gboolean
+complete_connection(NMDevice            *device,
+                    NMConnection        *connection,
+                    const char          *specific_object,
+                    NMConnection *const *existing_connections,
+                    GError             **error)
+{
+    NMDeviceIwdP2P   *self         = NM_DEVICE_IWD_P2P(device);
+    gs_free char     *setting_name = NULL;
+    NMSettingWifiP2P *s_wifi_p2p;
+    NMWifiP2PPeer    *peer;
+    const char       *setting_peer;
+
+    s_wifi_p2p =
+        NM_SETTING_WIFI_P2P(nm_connection_get_setting(connection, NM_TYPE_SETTING_WIFI_P2P));
+
+    if (!specific_object) {
+        /* If not given a specific object, we need at minimum a peer address */
+        if (!s_wifi_p2p) {
+            g_set_error(error,
+                        NM_DEVICE_ERROR,
+                        NM_DEVICE_ERROR_INVALID_CONNECTION,
+                        "A '%s' setting is required if no Peer path was given",
+                        NM_SETTING_WIFI_P2P_SETTING_NAME);
+            return FALSE;
+        }
+
+        setting_peer = nm_setting_wifi_p2p_get_peer(s_wifi_p2p);
+        if (!setting_peer) {
+            g_set_error(error,
+                        NM_DEVICE_ERROR,
+                        NM_DEVICE_ERROR_INVALID_CONNECTION,
+                        "A '%s' setting with a valid Peer is required if no Peer path was given",
+                        NM_SETTING_WIFI_P2P_SETTING_NAME);
+            return FALSE;
+        }
+    } else {
+        peer = nm_wifi_p2p_peer_lookup_for_device(NM_DEVICE(self), specific_object);
+        if (!peer) {
+            g_set_error(error,
+                        NM_DEVICE_ERROR,
+                        NM_DEVICE_ERROR_SPECIFIC_OBJECT_NOT_FOUND,
+                        "The P2P peer %s is unknown",
+                        specific_object);
+            return FALSE;
+        }
+
+        setting_peer = nm_wifi_p2p_peer_get_address(peer);
+        g_return_val_if_fail(setting_peer, FALSE);
+    }
+
+    /* Add a Wi-Fi P2P setting if one doesn't exist yet */
+    s_wifi_p2p = _nm_connection_ensure_setting(connection, NM_TYPE_SETTING_WIFI_P2P);
+
+    g_object_set(G_OBJECT(s_wifi_p2p), NM_SETTING_WIFI_P2P_PEER, setting_peer, NULL);
+
+    setting_name = g_strdup_printf("Wi-Fi P2P Peer %s", setting_peer);
+    nm_utils_complete_generic(nm_device_get_platform(device),
+                              connection,
+                              NM_SETTING_WIFI_P2P_SETTING_NAME,
+                              existing_connections,
+                              setting_name,
+                              setting_name,
+                              NULL,
+                              NULL,
+                              TRUE);
+
+    return TRUE;
+}
+
+static gboolean
+get_enabled(NMDevice *device)
+{
+    return NM_DEVICE_IWD_P2P_GET_PRIVATE(device)->enabled;
+}
+
+static void
+set_enabled_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+    NMDeviceIwdP2P            *self    = user_data;
+    gs_unref_variant GVariant *variant = NULL;
+    gs_free_error GError      *error   = NULL;
+
+    variant = g_dbus_proxy_call_finish(G_DBUS_PROXY(source), res, &error);
+    if (!variant) {
+        _LOGE(LOGD_DEVICE | LOGD_WIFI, ".Set failed: %s", error->message);
+        return;
+    }
+    _LOGD(LOGD_DEVICE | LOGD_WIFI, ".Set OK!");
+}
+
+static void
+set_enabled(NMDevice *device, gboolean enabled)
+{
+    NMDeviceIwdP2P        *self = NM_DEVICE_IWD_P2P(device);
+    NMDeviceIwdP2PPrivate *priv = NM_DEVICE_IWD_P2P_GET_PRIVATE(self);
+
+    enabled = !!enabled;
+
+    if (priv->enabled == enabled)
+        return;
+
+    _LOGD(LOGD_WIFI, "device will be %s", enabled ? "enabled" : "disabled");
+
+    g_dbus_proxy_call(
+        priv->dbus_p2p_proxy,
+        DBUS_INTERFACE_PROPERTIES ".Set",
+        g_variant_new("(ssv)", NM_IWD_P2P_INTERFACE, "Enabled", g_variant_new("b", enabled)),
+        G_DBUS_CALL_FLAGS_NONE,
+        2000,
+        NULL,
+        set_enabled_cb,
+        self);
+}
+
+static void
+p2p_properties_changed_cb(GDBusProxy *proxy,
+                          GVariant   *changed_properties,
+                          GStrv       invalidate_properties,
+                          gpointer    user_data)
+{
+    NMDeviceIwdP2P        *self   = user_data;
+    NMDeviceIwdP2PPrivate *priv   = NM_DEVICE_IWD_P2P_GET_PRIVATE(self);
+    NMDevice              *device = NM_DEVICE(self);
+    gboolean               new_bool;
+
+    if (g_variant_lookup(changed_properties, "Enabled", "b", &new_bool)
+        && new_bool != priv->enabled) {
+        priv->enabled = new_bool;
+
+        _LOGD(LOGD_WIFI, "device now %s", priv->enabled ? "enabled" : "disabled");
+
+        if (priv->enabled) {
+            NMDeviceState state = nm_device_get_state(device);
+
+            if (state != NM_DEVICE_STATE_UNAVAILABLE)
+                _LOGW(LOGD_CORE, "not in expected unavailable state!");
+
+            nm_device_queue_recheck_available(device,
+                                              NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE,
+                                              NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED);
+        } else {
+            nm_device_state_changed(device,
+                                    NM_DEVICE_STATE_UNAVAILABLE,
+                                    NM_DEVICE_STATE_REASON_NONE);
+        }
+    }
+}
+
+static void
+iwd_request_discovery_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+    NMDeviceIwdP2P            *self    = user_data;
+    NMDeviceIwdP2PPrivate     *priv    = NM_DEVICE_IWD_P2P_GET_PRIVATE(self);
+    gs_unref_variant GVariant *variant = NULL;
+    gs_free_error GError      *error   = NULL;
+
+    variant = g_dbus_proxy_call_finish(G_DBUS_PROXY(source), res, &error);
+    if (!variant) {
+        NMDevice *device = NM_DEVICE(self);
+
+        _LOGE(LOGD_DEVICE | LOGD_WIFI,
+              "%s(wifi-p2p) IWD p2p.Device.RequestDiscovery failed: %s",
+              nm_device_is_activating(device) ? "Activation: " : "",
+              error->message);
+
+        if (nm_utils_error_is_cancelled(error) && !nm_device_is_activating(device))
+            return;
+
+        nm_clear_g_cancellable(&priv->find_cancellable);
+        nm_device_state_changed(device,
+                                NM_DEVICE_STATE_FAILED,
+                                NM_DEVICE_STATE_REASON_PEER_NOT_FOUND);
+        return;
+    }
+
+    nm_clear_g_cancellable(&priv->find_cancellable);
+    _LOGI(LOGD_DEVICE | LOGD_WIFI,
+          "%s(wifi-p2p) Target peer discovery running",
+          nm_device_is_activating(NM_DEVICE(self)) ? "Activation: " : "");
+}
+
+static void
+iwd_request_discovery(NMDeviceIwdP2P *self, unsigned timeout)
+{
+    NMDeviceIwdP2PPrivate *priv      = NM_DEVICE_IWD_P2P_GET_PRIVATE(self);
+    bool                   requested = priv->find_peer_timeout_source != NULL;
+
+    nm_clear_g_source_inst(&priv->find_peer_timeout_source);
+    priv->find_peer_timeout_source =
+        nm_g_timeout_add_seconds_source(timeout, iwd_discovery_timeout_cb, self);
+
+    if (!requested) {
+        priv->find_cancellable = g_cancellable_new();
+
+        g_dbus_proxy_call(priv->dbus_p2p_proxy,
+                          "RequestDiscovery",
+                          NULL,
+                          G_DBUS_CALL_FLAGS_NONE,
+                          G_MAXINT,
+                          priv->find_cancellable,
+                          iwd_request_discovery_cb,
+                          self);
+    }
+}
+
+static void
+iwd_release_discovery(NMDeviceIwdP2P *self)
+{
+    NMDeviceIwdP2PPrivate *priv = NM_DEVICE_IWD_P2P_GET_PRIVATE(self);
+
+    nm_clear_g_source_inst(&priv->find_peer_timeout_source);
+    nm_clear_g_cancellable(&priv->find_cancellable);
+
+    g_dbus_proxy_call(priv->dbus_p2p_proxy,
+                      "ReleaseDiscovery",
+                      NULL,
+                      G_DBUS_CALL_FLAGS_NONE,
+                      G_MAXINT,
+                      NULL,
+                      NULL,
+                      self);
+}
+
+/*
+ * Called when IWD has been unable to find the peer we want to connect to within the
+ * 10s time limit or when a D-bus Find() ends.
+ */
+static gboolean
+iwd_discovery_timeout_cb(gpointer user_data)
+{
+    NMDeviceIwdP2P        *self   = NM_DEVICE_IWD_P2P(user_data);
+    NMDeviceIwdP2PPrivate *priv   = NM_DEVICE_IWD_P2P_GET_PRIVATE(self);
+    NMDevice              *device = NM_DEVICE(self);
+
+    nm_clear_g_source_inst(&priv->find_peer_timeout_source);
+
+    iwd_release_discovery(self);
+
+    if (nm_device_is_activating(device)) {
+        _LOGW(LOGD_DEVICE | LOGD_WIFI,
+              "Activation: (wifi-p2p) Could not find peer, failing activation");
+        nm_device_state_changed(device,
+                                NM_DEVICE_STATE_FAILED,
+                                NM_DEVICE_STATE_REASON_PEER_NOT_FOUND);
+    } else {
+        _LOGD(LOGD_DEVICE | LOGD_WIFI, "(wifi-p2p) Find timeout");
+    }
+
+    return G_SOURCE_REMOVE;
+}
+
+static void
+cleanup_connect_attempt(NMDeviceIwdP2P *self)
+{
+    NMDeviceIwdP2PPrivate *priv = NM_DEVICE_IWD_P2P_GET_PRIVATE(self);
+
+    if (priv->find_peer_timeout_source)
+        iwd_release_discovery(self);
+
+    if (priv->wfd_registered) {
+        nm_iwd_manager_unregister_wfd(nm_iwd_manager_get());
+        priv->wfd_registered = FALSE;
+    }
+
+    if (!priv->dbus_peer_proxy)
+        return;
+
+    if (nm_device_is_activating(NM_DEVICE(self)))
+        nm_device_set_ip_iface(NM_DEVICE(self), NULL);
+
+    priv->stage2_ready = FALSE;
+    g_signal_handlers_disconnect_by_data(priv->dbus_peer_proxy, self);
+    g_clear_object(&priv->dbus_peer_proxy);
+    nm_clear_g_cancellable(&priv->connect_cancellable);
+}
+
+static void
+peer_properties_changed_cb(GDBusProxy *proxy,
+                           GVariant   *changed_properties,
+                           GStrv       invalidate_properties,
+                           gpointer    user_data)
+{
+    NMDeviceIwdP2P *self  = user_data;
+    NMDeviceState   state = nm_device_get_state(NM_DEVICE(self));
+    gboolean        new_bool;
+    const char     *new_str;
+
+    if (g_variant_lookup(changed_properties, "Connected", "b", &new_bool) && !new_bool
+        && state >= NM_DEVICE_STATE_CONFIG && state <= NM_DEVICE_STATE_DEACTIVATING) {
+        cleanup_connect_attempt(self);
+        nm_device_state_changed(NM_DEVICE(self),
+                                NM_DEVICE_STATE_DISCONNECTED,
+                                NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT);
+    }
+
+    if (g_variant_lookup(changed_properties, "ConnectedInterface", "&s", &new_str)
+        && state >= NM_DEVICE_STATE_CONFIG && state <= NM_DEVICE_STATE_IP_CONFIG) {
+        nm_device_set_ip_iface(NM_DEVICE(self), new_str);
+    }
+}
+
+static NMActStageReturn
+act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason)
+{
+    NMDeviceIwdP2P        *self = NM_DEVICE_IWD_P2P(device);
+    NMDeviceIwdP2PPrivate *priv = NM_DEVICE_IWD_P2P_GET_PRIVATE(self);
+    NMConnection          *connection;
+    NMSettingWifiP2P      *s_wifi_p2p;
+    NMWifiP2PPeer         *peer;
+    GBytes                *wfd_ies;
+
+    if (!priv->enabled) {
+        NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED);
+        return NM_ACT_STAGE_RETURN_FAILURE;
+    }
+
+    connection = nm_device_get_applied_connection(NM_DEVICE(self));
+    g_return_val_if_fail(connection, NM_ACT_STAGE_RETURN_FAILURE);
+
+    s_wifi_p2p =
+        NM_SETTING_WIFI_P2P(nm_connection_get_setting(connection, NM_TYPE_SETTING_WIFI_P2P));
+    g_return_val_if_fail(s_wifi_p2p, NM_ACT_STAGE_RETURN_FAILURE);
+
+    /* Set the WFD IEs before connecting and before peer discovery if that is needed,
+     * usually the WFD IEs need to actually be sent in the Probe frames before we can
+     * receive the peers' WFD IEs and decide whether the peer is compatible with the
+     * requested WFD parameters.  In the current setup we only get the WFD IEs from
+     * the connection settings so during a normal find the client will not be getting
+     * any WFD information about the peers and has to decide to connect based on the
+     * name and device type (category + subcategory) -- assuming that the peers even
+     * bother to reply to probes without WFD IEs.  We'll then need to redo the find
+     * here in PREPARE because IWD wants to see that the parameters in the peer's
+     * WFD IEs match those in our WFD IEs.  The normal use case for IWD is that the
+     * WFD client registers its WFD parameters as soon as it starts and they remain
+     * registered during the find and then during the connect.  */
+    wfd_ies = nm_setting_wifi_p2p_get_wfd_ies(s_wifi_p2p);
+    if (wfd_ies) {
+        NMIwdWfdInfo wfd_info = {};
+
+        if (!nm_wifi_utils_parse_wfd_ies(wfd_ies, &wfd_info)) {
+            _LOGE(LOGD_DEVICE | LOGD_WIFI, "Activation: (wifi-p2p) Can't parse connection WFD IEs");
+            NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_CONFIG_FAILED);
+            return NM_ACT_STAGE_RETURN_FAILURE;
+        }
+
+        if (!nm_iwd_manager_check_wfd_info_compatible(nm_iwd_manager_get(), &wfd_info)) {
+            _LOGE(LOGD_DEVICE | LOGD_WIFI,
+                  "Activation: (wifi-p2p) An incompatible WFD connection is active");
+            NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_CONFIG_FAILED);
+            return NM_ACT_STAGE_RETURN_FAILURE;
+        }
+
+        if (!nm_iwd_manager_register_wfd(nm_iwd_manager_get(), &wfd_info)) {
+            _LOGE(LOGD_DEVICE | LOGD_WIFI, "Activation: (wifi-p2p) Can't register WFD service");
+            NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_CONFIG_FAILED);
+            return NM_ACT_STAGE_RETURN_FAILURE;
+        }
+
+        priv->wfd_registered = TRUE;
+    }
+
+    peer = nm_wifi_p2p_peers_find_first_compatible(&priv->peers_lst_head, connection, TRUE);
+    if (!peer) {
+        iwd_request_discovery(self, 10);
+        return NM_ACT_STAGE_RETURN_POSTPONE;
+    } else if (priv->find_peer_timeout_source) {
+        iwd_release_discovery(self);
+    }
+
+    return NM_ACT_STAGE_RETURN_SUCCESS;
+}
+
+static void
+iwd_wsc_connect_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+    NMDeviceIwdP2P            *self    = user_data;
+    NMDeviceIwdP2PPrivate     *priv    = NM_DEVICE_IWD_P2P_GET_PRIVATE(self);
+    gs_unref_variant GVariant *variant = NULL;
+    gs_free_error GError      *error   = NULL;
+    NMDevice                  *device  = NM_DEVICE(self);
+
+    variant = g_dbus_proxy_call_finish(G_DBUS_PROXY(source), res, &error);
+    if (!variant) {
+        _LOGE(LOGD_DEVICE | LOGD_WIFI,
+              "Activation: (wifi-p2p) IWD SimpleConfiguration.PushButton/StartPin() failed: %s",
+              error->message);
+
+        if (nm_utils_error_is_cancelled(error) && !nm_device_is_activating(device))
+            return;
+
+        nm_clear_g_cancellable(&priv->connect_cancellable);
+        nm_device_state_changed(device,
+                                NM_DEVICE_STATE_FAILED,
+                                NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED);
+        return;
+    }
+
+    nm_clear_g_cancellable(&priv->connect_cancellable);
+    _LOGI(LOGD_DEVICE | LOGD_WIFI, "Activation: (wifi-p2p) IWD connection successful");
+
+    g_signal_connect(priv->dbus_peer_proxy,
+                     "g-properties-changed",
+                     G_CALLBACK(peer_properties_changed_cb),
+                     self);
+
+    priv->stage2_ready = TRUE;
+
+    nm_device_activate_schedule_stage2_device_config(device, FALSE);
+}
+
+static NMActStageReturn
+act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason)
+{
+    NMDeviceIwdP2P             *self = NM_DEVICE_IWD_P2P(device);
+    NMDeviceIwdP2PPrivate      *priv = NM_DEVICE_IWD_P2P_GET_PRIVATE(self);
+    NMConnection               *connection;
+    NMSettingWifiP2P           *s_wifi_p2p;
+    NMWifiP2PPeer              *peer;
+    gs_unref_object GDBusProxy *peer_proxy = NULL;
+    gs_unref_object GDBusProxy *wsc_proxy  = NULL;
+
+    if (priv->stage2_ready)
+        return NM_ACT_STAGE_RETURN_SUCCESS;
+
+    if (!priv->dbus_p2p_proxy) {
+        cleanup_connect_attempt(self);
+        NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED);
+        return NM_ACT_STAGE_RETURN_FAILURE;
+    }
+
+    if (nm_clear_g_source_inst(&priv->find_peer_timeout_source))
+        nm_assert_not_reached();
+
+    connection = nm_device_get_applied_connection(device);
+    g_return_val_if_fail(connection, NM_ACT_STAGE_RETURN_FAILURE);
+    nm_assert(
+        NM_IS_SETTING_WIFI_P2P(nm_connection_get_setting(connection, NM_TYPE_SETTING_WIFI_P2P)));
+
+    /* The prepare stage ensures that the peer has been found */
+    peer = nm_wifi_p2p_peers_find_first_compatible(&priv->peers_lst_head, connection, TRUE);
+    if (!peer) {
+        cleanup_connect_attempt(self);
+        NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_PEER_NOT_FOUND);
+        return NM_ACT_STAGE_RETURN_FAILURE;
+    }
+
+    s_wifi_p2p =
+        NM_SETTING_WIFI_P2P(nm_connection_get_setting(connection, NM_TYPE_SETTING_WIFI_P2P));
+    if (nm_setting_wifi_p2p_get_wps_method(s_wifi_p2p)
+        == NM_SETTING_WIRELESS_SECURITY_WPS_METHOD_PIN) {
+        /* TODO: check we have the pin secret, if so use StartPin(pin) otherwise request pin,
+         * move to NEED_AUTH and return postpone */
+        cleanup_connect_attempt(self);
+        NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED);
+        return NM_ACT_STAGE_RETURN_FAILURE;
+    }
+
+    peer_proxy = nm_iwd_manager_get_dbus_interface(nm_iwd_manager_get(),
+                                                   nm_wifi_p2p_peer_get_supplicant_path(peer),
+                                                   NM_IWD_P2P_PEER_INTERFACE);
+    wsc_proxy  = nm_iwd_manager_get_dbus_interface(nm_iwd_manager_get(),
+                                                  nm_wifi_p2p_peer_get_supplicant_path(peer),
+                                                  NM_IWD_WSC_INTERFACE);
+
+    if (!wsc_proxy || !peer_proxy) {
+        cleanup_connect_attempt(self);
+        NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_PEER_NOT_FOUND);
+        return NM_ACT_STAGE_RETURN_FAILURE;
+    }
+
+    g_dbus_proxy_call(wsc_proxy,
+                      "PushButton",
+                      NULL,
+                      G_DBUS_CALL_FLAGS_NONE,
+                      G_MAXINT,
+                      priv->connect_cancellable,
+                      iwd_wsc_connect_cb,
+                      self);
+
+    priv->dbus_peer_proxy = g_steal_pointer(&peer_proxy);
+    return NM_ACT_STAGE_RETURN_POSTPONE;
+}
+
+/*****************************************************************************/
+
+static void
+emit_signal_p2p_peer_add_remove(NMDeviceIwdP2P *device,
+                                NMWifiP2PPeer  *peer,
+                                gboolean        is_added /* or else is_removed */)
+{
+    nm_dbus_object_emit_signal(NM_DBUS_OBJECT(device),
+                               &interface_info_device_wifi_p2p,
+                               is_added ? &nm_signal_info_wifi_p2p_peer_added
+                                        : &nm_signal_info_wifi_p2p_peer_removed,
+                               "(o)",
+                               nm_dbus_object_get_path(NM_DBUS_OBJECT(peer)));
+}
+
+static void
+act_check_new_peer_compatible(NMDeviceIwdP2P *self, NMWifiP2PPeer *peer)
+{
+    NMDevice     *device = NM_DEVICE(self);
+    NMConnection *connection;
+
+    connection = nm_device_get_applied_connection(device);
+    nm_assert(NM_IS_CONNECTION(connection));
+
+    if (nm_wifi_p2p_peer_check_compatible(peer, connection, TRUE)) {
+        /* A peer for the connection was found, cancel the timeout and go to configure state. */
+        iwd_release_discovery(self);
+        nm_device_activate_schedule_stage2_device_config(device, FALSE);
+    }
+}
+
+static void
+peer_add_remove(NMDeviceIwdP2P *self,
+                gboolean        is_adding, /* or else removing */
+                NMWifiP2PPeer  *peer,
+                gboolean        recheck_available_connections)
+{
+    NMDevice              *device = NM_DEVICE(self);
+    NMDeviceIwdP2PPrivate *priv   = NM_DEVICE_IWD_P2P_GET_PRIVATE(self);
+
+    if (is_adding) {
+        g_object_ref(peer);
+        peer->wifi_device = device;
+        c_list_link_tail(&priv->peers_lst_head, &peer->peers_lst);
+        nm_dbus_object_export(NM_DBUS_OBJECT(peer));
+        _peer_dump(self, LOGL_DEBUG, peer, "added", 0);
+
+        emit_signal_p2p_peer_add_remove(self, peer, TRUE);
+    } else {
+        peer->wifi_device = NULL;
+        c_list_unlink(&peer->peers_lst);
+        _peer_dump(self, LOGL_DEBUG, peer, "removed", 0);
+    }
+
+    _notify(self, PROP_PEERS);
+
+    if (!is_adding) {
+        emit_signal_p2p_peer_add_remove(self, peer, FALSE);
+        nm_dbus_object_clear_and_unexport(&peer);
+    }
+
+    if (is_adding) {
+        /* If we are in prepare state, then we are currently running a find
+         * to search for the requested peer. */
+        if (priv->find_peer_timeout_source
+            && nm_device_get_state(device) == NM_DEVICE_STATE_PREPARE)
+            act_check_new_peer_compatible(self, peer);
+
+        /* TODO: We may want to re-check auto-activation here */
+    }
+}
+
+static void
+iwd_peer_interface_added_cb(GDBusObject *peer_obj, GDBusInterface *interface, gpointer user_data)
+{
+    NMDeviceIwdP2P        *self = user_data;
+    NMDeviceIwdP2PPrivate *priv = NM_DEVICE_IWD_P2P_GET_PRIVATE(self);
+    const char            *iface_name;
+    NMWifiP2PPeer         *peer;
+
+    g_return_if_fail(G_IS_DBUS_PROXY(interface));
+
+    iface_name = g_dbus_proxy_get_interface_name(G_DBUS_PROXY(interface));
+    if (!nm_streq(iface_name, NM_IWD_P2P_WFD_INTERFACE))
+        return;
+
+    peer = nm_wifi_p2p_peers_find_by_supplicant_path(&priv->peers_lst_head,
+                                                     g_dbus_object_get_object_path(peer_obj));
+    if (!peer)
+        return;
+
+    nm_wifi_p2p_peer_update_from_iwd_object(peer, peer_obj);
+
+    /* If we are in prepare state, then we are currently running a find
+     * to search for the requested peer. */
+    if (priv->find_peer_timeout_source)
+        act_check_new_peer_compatible(self, peer);
+}
+
+static void
+iwd_peer_interface_removed_cb(GDBusObject *peer_obj, GDBusInterface *interface, gpointer user_data)
+{
+    NMDeviceIwdP2P        *self = user_data;
+    NMDeviceIwdP2PPrivate *priv = NM_DEVICE_IWD_P2P_GET_PRIVATE(self);
+    const char            *iface_name;
+    NMWifiP2PPeer         *peer;
+
+    g_return_if_fail(G_IS_DBUS_PROXY(interface));
+
+    iface_name = g_dbus_proxy_get_interface_name(G_DBUS_PROXY(interface));
+    if (!nm_streq(iface_name, NM_IWD_P2P_WFD_INTERFACE))
+        return;
+
+    peer = nm_wifi_p2p_peers_find_by_supplicant_path(&priv->peers_lst_head,
+                                                     g_dbus_object_get_object_path(peer_obj));
+    if (!peer)
+        return;
+
+    nm_wifi_p2p_peer_set_wfd_ies(peer, NULL);
+}
+
+void
+nm_device_iwd_p2p_peer_add_remove(NMDeviceIwdP2P *self, GDBusObject *peer_obj, bool add)
+{
+    NMDeviceIwdP2PPrivate *priv = NM_DEVICE_IWD_P2P_GET_PRIVATE(self);
+    NMWifiP2PPeer         *found_peer;
+
+    found_peer = nm_wifi_p2p_peers_find_by_supplicant_path(&priv->peers_lst_head,
+                                                           g_dbus_object_get_object_path(peer_obj));
+
+    if (found_peer && !add) {
+        if (priv->dbus_peer_proxy
+            && !nm_streq(g_dbus_object_get_object_path(peer_obj),
+                         g_dbus_proxy_get_object_path(priv->dbus_peer_proxy))) {
+            cleanup_connect_attempt(self);
+            nm_device_state_changed(NM_DEVICE(self),
+                                    NM_DEVICE_STATE_DISCONNECTED,
+                                    NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT);
+        }
+
+        peer_add_remove(self, FALSE, found_peer, TRUE);
+        g_signal_handlers_disconnect_by_data(peer_obj, self);
+    }
+
+    if (!found_peer && add) {
+        gs_unref_object NMWifiP2PPeer *peer = nm_wifi_p2p_peer_new_from_iwd_object(peer_obj);
+
+        if (!peer) {
+            _LOGD(LOGD_DEVICE | LOGD_WIFI,
+                  "Can't interpret IWD Peer properties at %s",
+                  g_dbus_object_get_object_path(peer_obj));
+            return;
+        }
+
+        peer_add_remove(self, TRUE, peer, TRUE);
+
+        /* None of the D-Bus properties that we use on this interface emit PropertiesChanges
+         * signals, only the WFD properties do.  We do listen to changes to "Connected"
+         * but only while we're connecting/connected to a given peer.
+         */
+        g_signal_connect(peer_obj,
+                         "interface-added",
+                         G_CALLBACK(iwd_peer_interface_added_cb),
+                         self);
+        g_signal_connect(peer_obj,
+                         "interface-removed",
+                         G_CALLBACK(iwd_peer_interface_removed_cb),
+                         self);
+
+        /* TODO: every now and then call p2p.Device.GetPeers() and update the signal strength
+         * values for all peers we got through ObjectManager events.
+         */
+    }
+
+    schedule_peer_list_dump(self);
+}
+
+/*****************************************************************************/
+
+static void
+deactivate(NMDevice *device)
+{
+    NMDeviceIwdP2P        *self = NM_DEVICE_IWD_P2P(device);
+    NMDeviceIwdP2PPrivate *priv = NM_DEVICE_IWD_P2P_GET_PRIVATE(self);
+
+    if (priv->find_peer_timeout_source)
+        iwd_release_discovery(self);
+
+    if (priv->dbus_peer_proxy) {
+        g_dbus_proxy_call(priv->dbus_peer_proxy,
+                          "Disconnect",
+                          NULL,
+                          G_DBUS_CALL_FLAGS_NONE,
+                          G_MAXINT,
+                          NULL,
+                          NULL,
+                          self);
+
+        cleanup_connect_attempt(self);
+    }
+}
+
+static guint32
+get_configured_mtu(NMDevice *device, NMDeviceMtuSource *out_source, gboolean *out_force)
+{
+    *out_source = NM_DEVICE_MTU_SOURCE_NONE;
+    return 0;
+}
+
+static gboolean
+unmanaged_on_quit(NMDevice *self)
+{
+    return TRUE;
+}
+
+static void
+device_state_changed(NMDevice           *device,
+                     NMDeviceState       new_state,
+                     NMDeviceState       old_state,
+                     NMDeviceStateReason reason)
+{
+    NMDeviceIwdP2P        *self = NM_DEVICE_IWD_P2P(device);
+    NMDeviceIwdP2PPrivate *priv = NM_DEVICE_IWD_P2P_GET_PRIVATE(self);
+
+    switch (new_state) {
+    case NM_DEVICE_STATE_UNMANAGED:
+        break;
+    case NM_DEVICE_STATE_UNAVAILABLE:
+        if (priv->enabled) {
+            nm_device_queue_recheck_available(device,
+                                              NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE,
+                                              NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED);
+        }
+        break;
+    case NM_DEVICE_STATE_IP_CONFIG:
+        /* TODO: start periodic RSSI and bitrate updates? */
+        break;
+    default:
+        break;
+    }
+}
+
+static void
+impl_device_iwd_p2p_start_find(NMDBusObject                      *obj,
+                               const NMDBusInterfaceInfoExtended *interface_info,
+                               const NMDBusMethodInfoExtended    *method_info,
+                               GDBusConnection                   *connection,
+                               const char                        *sender,
+                               GDBusMethodInvocation             *invocation,
+                               GVariant                          *parameters)
+{
+    NMDeviceIwdP2P            *self    = NM_DEVICE_IWD_P2P(obj);
+    NMDeviceIwdP2PPrivate     *priv    = NM_DEVICE_IWD_P2P_GET_PRIVATE(self);
+    gs_unref_variant GVariant *options = NULL;
+    const char                *opts_key;
+    GVariant                  *opts_val;
+    GVariantIter               iter;
+    gint32                     timeout = 30;
+
+    g_variant_get(parameters, "(@a{sv})", &options);
+
+    g_variant_iter_init(&iter, options);
+    while (g_variant_iter_next(&iter, "{&sv}", &opts_key, &opts_val)) {
+        _nm_unused gs_unref_variant GVariant *opts_val_free = opts_val;
+
+        if (nm_streq(opts_key, "timeout")) {
+            if (!g_variant_is_of_type(opts_val, G_VARIANT_TYPE_INT32)) {
+                g_dbus_method_invocation_return_error_literal(
+                    invocation,
+                    NM_DEVICE_ERROR,
+                    NM_DEVICE_ERROR_INVALID_ARGUMENT,
+                    "\"timeout\" must be an integer \"i\"");
+                return;
+            }
+
+            timeout = g_variant_get_int32(opts_val);
+            if (timeout <= 0 || timeout > 600) {
+                g_dbus_method_invocation_return_error_literal(
+                    invocation,
+                    NM_DEVICE_ERROR,
+                    NM_DEVICE_ERROR_NOT_ALLOWED,
+                    "The timeout for a find operation needs to be in the range of 1-600s.");
+                return;
+            }
+
+            continue;
+        }
+
+        g_dbus_method_invocation_return_error(invocation,
+                                              NM_DEVICE_ERROR,
+                                              NM_DEVICE_ERROR_INVALID_ARGUMENT,
+                                              "Unsupported options key \"%s\"",
+                                              opts_key);
+        return;
+    }
+
+    if (!priv->enabled || nm_device_is_activating(NM_DEVICE(self))) {
+        g_dbus_method_invocation_return_error_literal(invocation,
+                                                      NM_DEVICE_ERROR,
+                                                      NM_DEVICE_ERROR_NOT_ACTIVE,
+                                                      "P2P device not enabled or busy.");
+        return;
+    }
+
+    iwd_request_discovery(self, timeout);
+    g_dbus_method_invocation_return_value(invocation, NULL);
+}
+
+static void
+impl_device_iwd_p2p_stop_find(NMDBusObject                      *obj,
+                              const NMDBusInterfaceInfoExtended *interface_info,
+                              const NMDBusMethodInfoExtended    *method_info,
+                              GDBusConnection                   *connection,
+                              const char                        *sender,
+                              GDBusMethodInvocation             *invocation,
+                              GVariant                          *parameters)
+{
+    NMDeviceIwdP2P        *self = NM_DEVICE_IWD_P2P(obj);
+    NMDeviceIwdP2PPrivate *priv = NM_DEVICE_IWD_P2P_GET_PRIVATE(self);
+
+    if (!priv->find_peer_timeout_source || nm_device_is_activating(NM_DEVICE(self))) {
+        g_dbus_method_invocation_return_error_literal(invocation,
+                                                      NM_DEVICE_ERROR,
+                                                      NM_DEVICE_ERROR_NOT_ACTIVE,
+                                                      "Find phase is not active.");
+        return;
+    }
+
+    iwd_release_discovery(self);
+    g_dbus_method_invocation_return_value(invocation, NULL);
+}
+
+/*****************************************************************************/
+
+static bool
+nm_device_iwd_p2p_set_dbus_obj(NMDeviceIwdP2P *self, GDBusObject *obj)
+{
+    NMDeviceIwdP2PPrivate     *priv;
+    gs_unref_variant GVariant *enabled_value = NULL;
+
+    g_return_val_if_fail(NM_IS_DEVICE_IWD_P2P(self), FALSE);
+
+    priv = NM_DEVICE_IWD_P2P_GET_PRIVATE(self);
+
+    if (priv->dbus_obj == obj)
+        goto done;
+
+    if (priv->dbus_obj) {
+        cleanup_connect_attempt(self);
+        g_signal_handlers_disconnect_by_data(priv->dbus_p2p_proxy, self);
+        g_clear_object(&priv->dbus_p2p_proxy);
+        g_clear_object(&priv->dbus_obj);
+        priv->enabled = FALSE;
+    }
+
+    if (!obj)
+        goto done;
+
+    priv->dbus_p2p_proxy = G_DBUS_PROXY(g_dbus_object_get_interface(obj, NM_IWD_P2P_INTERFACE));
+    if (!priv->dbus_p2p_proxy)
+        return FALSE;
+
+    enabled_value = g_dbus_proxy_get_cached_property(priv->dbus_p2p_proxy, "Enabled");
+    if (!enabled_value || !g_variant_is_of_type(enabled_value, G_VARIANT_TYPE_BOOLEAN))
+        return FALSE;
+
+    priv->dbus_obj = g_object_ref(obj);
+
+    g_signal_connect(priv->dbus_p2p_proxy,
+                     "g-properties-changed",
+                     G_CALLBACK(p2p_properties_changed_cb),
+                     self);
+
+    priv->enabled = g_variant_get_boolean(enabled_value);
+    _LOGD(LOGD_WIFI, "iniital state is %s", priv->enabled ? "enabled" : "disabled");
+
+done:
+    nm_device_queue_recheck_available(NM_DEVICE(self),
+                                      NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE,
+                                      NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED);
+    return TRUE;
+}
+
+void
+nm_device_iwd_p2p_remove(NMDeviceIwdP2P *self)
+{
+    g_signal_emit_by_name(self, NM_DEVICE_REMOVED);
+}
+
+/*****************************************************************************/
+
+static const char *
+get_type_description(NMDevice *device)
+{
+    return "wifi-p2p";
+}
+
+/*****************************************************************************/
+
+static const GDBusSignalInfo nm_signal_info_wifi_p2p_peer_added = NM_DEFINE_GDBUS_SIGNAL_INFO_INIT(
+    "PeerAdded",
+    .args = NM_DEFINE_GDBUS_ARG_INFOS(NM_DEFINE_GDBUS_ARG_INFO("peer", "o"), ), );
+
+static const GDBusSignalInfo nm_signal_info_wifi_p2p_peer_removed =
+    NM_DEFINE_GDBUS_SIGNAL_INFO_INIT(
+        "PeerRemoved",
+        .args = NM_DEFINE_GDBUS_ARG_INFOS(NM_DEFINE_GDBUS_ARG_INFO("peer", "o"), ), );
+
+static const NMDBusInterfaceInfoExtended interface_info_device_wifi_p2p = {
+    .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT(
+        NM_DBUS_INTERFACE_DEVICE_WIFI_P2P,
+        .methods = NM_DEFINE_GDBUS_METHOD_INFOS(
+            NM_DEFINE_DBUS_METHOD_INFO_EXTENDED(
+                NM_DEFINE_GDBUS_METHOD_INFO_INIT(
+                    "StartFind",
+                    .in_args = NM_DEFINE_GDBUS_ARG_INFOS(
+                        NM_DEFINE_GDBUS_ARG_INFO("options", "a{sv}"), ), ),
+                .handle = impl_device_iwd_p2p_start_find, ),
+            NM_DEFINE_DBUS_METHOD_INFO_EXTENDED(NM_DEFINE_GDBUS_METHOD_INFO_INIT("StopFind", ),
+                                                .handle = impl_device_iwd_p2p_stop_find, ), ),
+        .signals    = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_wifi_p2p_peer_added,
+                                                &nm_signal_info_wifi_p2p_peer_removed, ),
+        .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS(
+            NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("HwAddress", "s", NM_DEVICE_HW_ADDRESS),
+            NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Peers",
+                                                           "ao",
+                                                           NM_DEVICE_IWD_P2P_PEERS), ), ),
+};
+
+/*****************************************************************************/
+
+static void
+get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+    NMDeviceIwdP2P        *self = NM_DEVICE_IWD_P2P(object);
+    NMDeviceIwdP2PPrivate *priv = NM_DEVICE_IWD_P2P_GET_PRIVATE(self);
+    const char           **list;
+
+    switch (prop_id) {
+    case PROP_PEERS:
+        list = nm_wifi_p2p_peers_get_paths(&priv->peers_lst_head);
+        g_value_take_boxed(value, nm_strv_make_deep_copied(list));
+        break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+        break;
+    }
+}
+
+/*****************************************************************************/
+
+static void
+nm_device_iwd_p2p_init(NMDeviceIwdP2P *self)
+{
+    NMDeviceIwdP2PPrivate *priv = NM_DEVICE_IWD_P2P_GET_PRIVATE(self);
+
+    c_list_init(&priv->peers_lst_head);
+}
+
+NMDeviceIwdP2P *
+nm_device_iwd_p2p_new(GDBusObject *dbus_obj)
+{
+    gs_unref_object NMDeviceIwdP2P *self = NULL;
+
+    g_return_val_if_fail(!dbus_obj || G_IS_DBUS_OBJECT(dbus_obj), NULL);
+
+    /* cfg80211 P2P-Device virtual interfaces don't map to netdev-type interfaces.
+     * Provide a false unique interface name only to avoid triggering assertions
+     * in NMManager and for that name to appear in debug messages.  */
+    self = g_object_new(NM_TYPE_DEVICE_IWD_P2P,
+                        NM_DEVICE_IFACE,
+                        g_dbus_object_get_object_path(dbus_obj),
+                        NM_DEVICE_TYPE_DESC,
+                        "802.11 Wi-Fi P2P",
+                        NM_DEVICE_DEVICE_TYPE,
+                        NM_DEVICE_TYPE_WIFI_P2P,
+                        NM_DEVICE_LINK_TYPE,
+                        NM_LINK_TYPE_WIFI,
+                        NM_DEVICE_RFKILL_TYPE,
+                        RFKILL_TYPE_WLAN,
+                        NULL);
+
+    if (!self || !nm_device_iwd_p2p_set_dbus_obj(self, dbus_obj))
+        return NULL;
+
+    return nm_steal_pointer(&self);
+}
+
+static void
+dispose(GObject *object)
+{
+    NMDeviceIwdP2P        *self = NM_DEVICE_IWD_P2P(object);
+    NMDeviceIwdP2PPrivate *priv = NM_DEVICE_IWD_P2P_GET_PRIVATE(object);
+
+    nm_clear_g_source_inst(&priv->peer_dump_source);
+
+    nm_device_iwd_p2p_set_dbus_obj(self, NULL);
+
+    G_OBJECT_CLASS(nm_device_iwd_p2p_parent_class)->dispose(object);
+}
+
+static void
+nm_device_iwd_p2p_class_init(NMDeviceIwdP2PClass *klass)
+{
+    GObjectClass      *object_class      = G_OBJECT_CLASS(klass);
+    NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(klass);
+    NMDeviceClass     *device_class      = NM_DEVICE_CLASS(klass);
+
+    object_class->get_property = get_property;
+    object_class->dispose      = dispose;
+
+    dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS(&interface_info_device_wifi_p2p);
+
+    device_class->connection_type_supported        = NM_SETTING_WIFI_P2P_SETTING_NAME;
+    device_class->connection_type_check_compatible = NM_SETTING_WIFI_P2P_SETTING_NAME;
+    device_class->link_types           = NM_DEVICE_DEFINE_LINK_TYPES(NM_LINK_TYPE_WIFI_P2P);
+    device_class->get_type_description = get_type_description;
+
+    device_class->is_available                = is_available;
+    device_class->check_connection_compatible = check_connection_compatible;
+    device_class->check_connection_available  = check_connection_available;
+    device_class->complete_connection         = complete_connection;
+    device_class->get_enabled                 = get_enabled;
+    device_class->set_enabled                 = set_enabled;
+
+    device_class->act_stage1_prepare = act_stage1_prepare;
+    device_class->act_stage2_config  = act_stage2_config;
+    device_class->get_configured_mtu = get_configured_mtu;
+
+    device_class->deactivate        = deactivate;
+    device_class->unmanaged_on_quit = unmanaged_on_quit;
+
+    device_class->state_changed = device_state_changed;
+
+    obj_properties[PROP_PEERS] = g_param_spec_boxed(NM_DEVICE_IWD_P2P_PEERS,
+                                                    "",
+                                                    "",
+                                                    G_TYPE_STRV,
+                                                    G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+    g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties);
+}
diff --git a/src/core/devices/wifi/nm-device-iwd-p2p.h b/src/core/devices/wifi/nm-device-iwd-p2p.h
new file mode 100644
index 00000000..9ce353c0
--- /dev/null
+++ b/src/core/devices/wifi/nm-device-iwd-p2p.h
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2021 Intel Corporation
+ */
+
+#ifndef __NM_DEVICE_IWD_P2P_H__
+#define __NM_DEVICE_IWD_P2P_H__
+
+#include "devices/nm-device.h"
+#include "nm-device-wifi-p2p.h"
+
+#define NM_TYPE_DEVICE_IWD_P2P (nm_device_iwd_p2p_get_type())
+#define NM_DEVICE_IWD_P2P(obj) \
+    (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_IWD_P2P, NMDeviceIwdP2P))
+#define NM_DEVICE_IWD_P2P_CLASS(klass) \
+    (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_IWD_P2P, NMDeviceIwdP2PClass))
+#define NM_IS_DEVICE_IWD_P2P(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_IWD_P2P))
+#define NM_IS_DEVICE_IWD_P2P_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DEVICE_IWD_P2P))
+#define NM_DEVICE_IWD_P2P_GET_CLASS(obj) \
+    (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DEVICE_IWD_P2P, NMDeviceIwdP2PClass))
+
+#define NM_DEVICE_IWD_P2P_PEERS  NM_DEVICE_WIFI_P2P_PEERS
+#define NM_DEVICE_IWD_P2P_GROUPS NM_DEVICE_WIFI_P2P_GROUPS
+
+typedef struct _NMDeviceIwdP2P      NMDeviceIwdP2P;
+typedef struct _NMDeviceIwdP2PClass NMDeviceIwdP2PClass;
+
+GType nm_device_iwd_p2p_get_type(void);
+
+NMDeviceIwdP2P *nm_device_iwd_p2p_new(GDBusObject *object);
+
+void nm_device_iwd_p2p_remove(NMDeviceIwdP2P *p2p);
+
+void nm_device_iwd_p2p_peer_add_remove(NMDeviceIwdP2P *p2p, GDBusObject *peer_obj, bool add);
+
+#endif /* __NM_DEVICE_IWD_P2P_H__ */
diff --git a/src/core/devices/wifi/nm-device-iwd.c b/src/core/devices/wifi/nm-device-iwd.c
index 27a3188b..7543d9da 100644
--- a/src/core/devices/wifi/nm-device-iwd.c
+++ b/src/core/devices/wifi/nm-device-iwd.c
@@ -48,14 +48,14 @@ NM_GOBJECT_PROPERTIES_DEFINE(NMDeviceIwd,
                              PROP_LAST_SCAN, );
 
 typedef struct {
-    GDBusObject *                 dbus_obj;
-    GDBusProxy *                  dbus_device_proxy;
-    GDBusProxy *                  dbus_station_proxy;
-    GDBusProxy *                  dbus_ap_proxy;
-    GDBusProxy *                  dbus_adhoc_proxy;
+    GDBusObject                  *dbus_obj;
+    GDBusProxy                   *dbus_device_proxy;
+    GDBusProxy                   *dbus_station_proxy;
+    GDBusProxy                   *dbus_ap_proxy;
+    GDBusProxy                   *dbus_adhoc_proxy;
     CList                         aps_lst_head;
-    NMWifiAP *                    current_ap;
-    GCancellable *                cancellable;
+    NMWifiAP                     *current_ap;
+    GCancellable                 *cancellable;
     _NMDeviceWifiCapabilities     capabilities;
     NMActRequestGetSecretsCallId *wifi_secrets_id;
     guint                         periodic_scan_id;
@@ -74,8 +74,8 @@ typedef struct {
     uint32_t                      ap_id;
     guint32                       rate;
     NMEtherAddr                   current_ap_bssid;
-    GDBusMethodInvocation *       pending_agent_request;
-    NMActiveConnection *          assumed_ac;
+    GDBusMethodInvocation        *pending_agent_request;
+    NMActiveConnection           *assumed_ac;
     guint                         assumed_ac_timeout;
 } NMDeviceIwdPrivate;
 
@@ -120,7 +120,7 @@ _ap_dump(NMDeviceIwd *self, NMLogLevel log_level, const NMWifiAP *ap, const char
 static void
 ap_add_remove(NMDeviceIwd *self,
               gboolean     is_adding, /* or else is removing */
-              NMWifiAP *   ap,
+              NMWifiAP    *ap,
               gboolean     recheck_available_connections)
 {
     NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self);
@@ -156,7 +156,7 @@ static void
 set_current_ap(NMDeviceIwd *self, NMWifiAP *new_ap, gboolean recheck_available_connections)
 {
     NMDeviceIwdPrivate *priv;
-    NMWifiAP *          old_ap;
+    NMWifiAP           *old_ap;
 
     g_return_if_fail(NM_IS_DEVICE_IWD(self));
 
@@ -186,7 +186,7 @@ static void
 remove_all_aps(NMDeviceIwd *self)
 {
     NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self);
-    NMWifiAP *          ap, *ap_safe;
+    NMWifiAP           *ap, *ap_safe;
 
     if (c_list_is_empty(&priv->aps_lst_head))
         return;
@@ -219,20 +219,20 @@ ap_security_flags_from_network_type(const char *type)
 
 static NMWifiAP *
 ap_from_network(NMDeviceIwd *self,
-                GDBusProxy * network,
+                GDBusProxy  *network,
                 NMRefString *bss_path,
                 gint64       last_seen_msec,
                 int16_t      signal)
 {
-    NMDeviceIwdPrivate *priv              = NM_DEVICE_IWD_GET_PRIVATE(self);
+    NMDeviceIwdPrivate        *priv       = NM_DEVICE_IWD_GET_PRIVATE(self);
     gs_unref_variant GVariant *name_value = NULL;
     gs_unref_variant GVariant *type_value = NULL;
-    const char *               name;
-    const char *               type;
+    const char                *name;
+    const char                *type;
     uint32_t                   ap_id;
-    gs_unref_bytes GBytes *ssid = NULL;
-    NMWifiAP *             ap;
-    NMSupplicantBssInfo    bss_info;
+    gs_unref_bytes GBytes     *ssid = NULL;
+    NMWifiAP                  *ap;
+    NMSupplicantBssInfo        bss_info;
 
     g_return_val_if_fail(network, NULL);
 
@@ -284,14 +284,14 @@ ap_from_network(NMDeviceIwd *self,
 
 static void
 insert_ap_from_network(NMDeviceIwd *self,
-                       GHashTable * aps,
-                       const char * path,
+                       GHashTable  *aps,
+                       const char  *path,
                        gint64       last_seen_msec,
                        int16_t      signal)
 {
-    gs_unref_object GDBusProxy *network_proxy = NULL;
-    nm_auto_ref_string NMRefString *bss_path  = nm_ref_string_new(path);
-    NMWifiAP *                      ap;
+    gs_unref_object GDBusProxy     *network_proxy = NULL;
+    nm_auto_ref_string NMRefString *bss_path      = nm_ref_string_new(path);
+    NMWifiAP                       *ap;
 
     if (g_hash_table_lookup(aps, bss_path)) {
         _LOGD(LOGD_WIFI, "Duplicate network at %s", path);
@@ -311,16 +311,16 @@ insert_ap_from_network(NMDeviceIwd *self,
 static void
 get_ordered_networks_cb(GObject *source, GAsyncResult *res, gpointer user_data)
 {
-    NMDeviceIwd *       self = user_data;
-    NMDeviceIwdPrivate *priv;
-    gs_free_error GError *error        = NULL;
-    gs_unref_variant GVariant *variant = NULL;
-    GVariantIter *             networks;
-    const char *               path;
-    int16_t                    signal;
-    NMWifiAP *                 ap, *ap_safe, *new_ap;
-    gboolean                   changed;
-    GHashTableIter             ap_iter;
+    NMDeviceIwd                   *self = user_data;
+    NMDeviceIwdPrivate            *priv;
+    gs_free_error GError          *error   = NULL;
+    gs_unref_variant GVariant     *variant = NULL;
+    GVariantIter                  *networks;
+    const char                    *path;
+    int16_t                        signal;
+    NMWifiAP                      *ap, *ap_safe, *new_ap;
+    gboolean                       changed;
+    GHashTableIter                 ap_iter;
     gs_unref_hashtable GHashTable *new_aps = NULL;
     gint64                         last_seen_msec;
 
@@ -421,7 +421,7 @@ periodic_update(NMDeviceIwd *self)
     int                 percent;
     NMEtherAddr         bssid;
     gboolean            ap_changed = FALSE;
-    NMPlatform *        platform;
+    NMPlatform         *platform;
 
     ifindex = nm_device_get_ifindex(NM_DEVICE(self));
     if (ifindex <= 0)
@@ -528,8 +528,8 @@ cleanup_association_attempt(NMDeviceIwd *self, gboolean disconnect)
 }
 
 static void
-reset_mode(NMDeviceIwd *       self,
-           GCancellable *      cancellable,
+reset_mode(NMDeviceIwd        *self,
+           GCancellable       *cancellable,
            GAsyncReadyCallback callback,
            gpointer            user_data)
 {
@@ -575,7 +575,7 @@ get_variant_state(GVariant *v)
 static void
 deactivate(NMDevice *device)
 {
-    NMDeviceIwd *       self = NM_DEVICE_IWD(device);
+    NMDeviceIwd        *self = NM_DEVICE_IWD(device);
     NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self);
 
     if (!priv->dbus_obj)
@@ -608,8 +608,8 @@ disconnect_cb(GObject *source, GAsyncResult *res, gpointer user_data)
     gs_unref_object NMDeviceIwd *self = NULL;
     NMDeviceDeactivateCallback   callback;
     gpointer                     callback_user_data;
-    gs_unref_variant GVariant *variant = NULL;
-    gs_free_error GError *error        = NULL;
+    gs_unref_variant GVariant   *variant = NULL;
+    gs_free_error GError        *error   = NULL;
 
     nm_utils_user_data_unpack(user_data, &self, &callback, &callback_user_data);
 
@@ -623,7 +623,7 @@ disconnect_cb_on_idle(gpointer user_data, GCancellable *cancellable)
     gs_unref_object NMDeviceIwd *self = NULL;
     NMDeviceDeactivateCallback   callback;
     gpointer                     callback_user_data;
-    gs_free_error GError *cancelled_error = NULL;
+    gs_free_error GError        *cancelled_error = NULL;
 
     nm_utils_user_data_unpack(user_data, &self, &callback, &callback_user_data);
 
@@ -632,12 +632,12 @@ disconnect_cb_on_idle(gpointer user_data, GCancellable *cancellable)
 }
 
 static void
-deactivate_async(NMDevice *                 device,
-                 GCancellable *             cancellable,
+deactivate_async(NMDevice                  *device,
+                 GCancellable              *cancellable,
                  NMDeviceDeactivateCallback callback,
                  gpointer                   callback_user_data)
 {
-    NMDeviceIwd *       self = NM_DEVICE_IWD(device);
+    NMDeviceIwd        *self = NM_DEVICE_IWD(device);
     NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self);
     gpointer            user_data;
 
@@ -676,7 +676,7 @@ static gboolean
 is_connection_known_network(NMConnection *connection)
 {
     NMIwdNetworkSecurity security;
-    gs_free char *       ssid = NULL;
+    gs_free char        *ssid = NULL;
 
     if (!nm_wifi_connection_get_iwd_ssid_and_security(connection, &ssid, &security))
         return FALSE;
@@ -688,7 +688,7 @@ static gboolean
 is_ap_known_network(NMWifiAP *ap)
 {
     gs_unref_object GDBusProxy *network_proxy = NULL;
-    gs_unref_variant GVariant *known_network  = NULL;
+    gs_unref_variant GVariant  *known_network = NULL;
 
     network_proxy =
         nm_iwd_manager_get_dbus_interface(nm_iwd_manager_get(),
@@ -704,17 +704,17 @@ is_ap_known_network(NMWifiAP *ap)
 static gboolean
 check_connection_compatible(NMDevice *device, NMConnection *connection, GError **error)
 {
-    NMDeviceIwd *        self = NM_DEVICE_IWD(device);
-    NMDeviceIwdPrivate * priv = NM_DEVICE_IWD_GET_PRIVATE(self);
-    NMSettingWireless *  s_wireless;
-    const char *         mac;
-    const char *const *  mac_blacklist;
+    NMDeviceIwd         *self = NM_DEVICE_IWD(device);
+    NMDeviceIwdPrivate  *priv = NM_DEVICE_IWD_GET_PRIVATE(self);
+    NMSettingWireless   *s_wireless;
+    const char          *mac;
+    const char *const   *mac_blacklist;
     int                  i;
-    const char *         perm_hw_addr;
-    const char *         mode;
+    const char          *perm_hw_addr;
+    const char          *mode;
     NMIwdNetworkSecurity security;
-    GBytes *             ssid;
-    const guint8 *       ssid_bytes;
+    GBytes              *ssid;
+    const guint8        *ssid_bytes;
     gsize                ssid_len;
 
     if (!NM_DEVICE_CLASS(nm_device_iwd_parent_class)
@@ -860,17 +860,17 @@ check_connection_compatible(NMDevice *device, NMConnection *connection, GError *
 }
 
 static gboolean
-check_connection_available(NMDevice *                     device,
-                           NMConnection *                 connection,
+check_connection_available(NMDevice                      *device,
+                           NMConnection                  *connection,
                            NMDeviceCheckConAvailableFlags flags,
-                           const char *                   specific_object,
-                           GError **                      error)
-{
-    NMDeviceIwd *        self = NM_DEVICE_IWD(device);
-    NMDeviceIwdPrivate * priv = NM_DEVICE_IWD_GET_PRIVATE(self);
-    NMSettingWireless *  s_wifi;
-    const char *         mode;
-    NMWifiAP *           ap = NULL;
+                           const char                    *specific_object,
+                           GError                       **error)
+{
+    NMDeviceIwd         *self = NM_DEVICE_IWD(device);
+    NMDeviceIwdPrivate  *priv = NM_DEVICE_IWD_GET_PRIVATE(self);
+    NMSettingWireless   *s_wifi;
+    const char          *mode;
+    NMWifiAP            *ap = NULL;
     NMIwdNetworkSecurity security;
 
     s_wifi = nm_connection_get_setting_wireless(connection);
@@ -952,20 +952,20 @@ iwd_ssid_to_str(const GBytes *ssid)
 }
 
 static gboolean
-complete_connection(NMDevice *           device,
-                    NMConnection *       connection,
-                    const char *         specific_object,
+complete_connection(NMDevice            *device,
+                    NMConnection        *connection,
+                    const char          *specific_object,
                     NMConnection *const *existing_connections,
-                    GError **            error)
+                    GError             **error)
 {
-    NMDeviceIwd *       self = NM_DEVICE_IWD(device);
+    NMDeviceIwd        *self = NM_DEVICE_IWD(device);
     NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self);
-    NMSettingWireless * s_wifi;
-    gs_free char *      ssid_utf8 = NULL;
-    NMWifiAP *          ap;
-    GBytes *            ssid   = NULL;
+    NMSettingWireless  *s_wifi;
+    gs_free char       *ssid_utf8 = NULL;
+    NMWifiAP           *ap;
+    GBytes             *ssid   = NULL;
     gboolean            hidden = FALSE;
-    const char *        mode;
+    const char         *mode;
 
     s_wifi = _nm_connection_ensure_setting(connection, NM_TYPE_SETTING_WIRELESS);
 
@@ -1059,7 +1059,7 @@ complete_connection(NMDevice *           device,
 static gboolean
 is_available(NMDevice *device, NMDeviceCheckDevAvailableFlags flags)
 {
-    NMDeviceIwd *       self  = NM_DEVICE_IWD(device);
+    NMDeviceIwd        *self  = NM_DEVICE_IWD(device);
     NMDeviceIwdPrivate *priv  = NM_DEVICE_IWD_GET_PRIVATE(self);
     NMDeviceState       state = nm_device_get_state(device);
 
@@ -1088,12 +1088,12 @@ get_autoconnect_allowed(NMDevice *device)
 static gboolean
 can_auto_connect(NMDevice *device, NMSettingsConnection *sett_conn, char **specific_object)
 {
-    NMDeviceIwd *       self = NM_DEVICE_IWD(device);
+    NMDeviceIwd        *self = NM_DEVICE_IWD(device);
     NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self);
-    NMConnection *      connection;
-    NMSettingWireless * s_wifi;
-    NMWifiAP *          ap;
-    const char *        mode;
+    NMConnection       *connection;
+    NMSettingWireless  *s_wifi;
+    NMWifiAP           *ap;
+    const char         *mode;
     guint64             timestamp = 0;
 
     nm_assert(!specific_object || !*specific_object);
@@ -1141,10 +1141,10 @@ _nm_device_iwd_get_aps(NMDeviceIwd *self)
 static void
 scan_cb(GObject *source, GAsyncResult *res, gpointer user_data)
 {
-    NMDeviceIwd *       self = user_data;
-    NMDeviceIwdPrivate *priv;
+    NMDeviceIwd               *self = user_data;
+    NMDeviceIwdPrivate        *priv;
     gs_unref_variant GVariant *variant = NULL;
-    gs_free_error GError *error        = NULL;
+    gs_free_error GError      *error   = NULL;
 
     variant = g_dbus_proxy_call_finish(G_DBUS_PROXY(source), res, &error);
     if (!variant && nm_utils_error_is_cancelled(error))
@@ -1165,14 +1165,14 @@ scan_cb(GObject *source, GAsyncResult *res, gpointer user_data)
 }
 
 static void
-dbus_request_scan_cb(NMDevice *             device,
+dbus_request_scan_cb(NMDevice              *device,
                      GDBusMethodInvocation *context,
-                     NMAuthSubject *        subject,
-                     GError *               error,
+                     NMAuthSubject         *subject,
+                     GError                *error,
                      gpointer               user_data)
 {
-    NMDeviceIwd *       self = NM_DEVICE_IWD(device);
-    NMDeviceIwdPrivate *priv;
+    NMDeviceIwd               *self = NM_DEVICE_IWD(device);
+    NMDeviceIwdPrivate        *priv;
     gs_unref_variant GVariant *scan_options = user_data;
 
     if (error) {
@@ -1229,7 +1229,7 @@ void
 _nm_device_iwd_request_scan(NMDeviceIwd *self, GVariant *options, GDBusMethodInvocation *invocation)
 {
     NMDeviceIwdPrivate *priv   = NM_DEVICE_IWD_GET_PRIVATE(self);
-    NMDevice *          device = NM_DEVICE(self);
+    NMDevice           *device = NM_DEVICE(self);
 
     if (!priv->can_scan) {
         g_dbus_method_invocation_return_error_literal(invocation,
@@ -1283,7 +1283,7 @@ static const char *
 get_agent_request_network_path(GDBusMethodInvocation *invocation)
 {
     const char *method_name  = g_dbus_method_invocation_get_method_name(invocation);
-    GVariant *  params       = g_dbus_method_invocation_get_parameters(invocation);
+    GVariant   *params       = g_dbus_method_invocation_get_parameters(invocation);
     const char *network_path = NULL;
 
     if (nm_streq(method_name, "RequestPassphrase"))
@@ -1308,17 +1308,17 @@ get_agent_request_network_path(GDBusMethodInvocation *invocation)
  * Return TRUE in either case, return FALSE if an error is detected.
  */
 static gboolean
-try_reply_agent_request(NMDeviceIwd *          self,
-                        NMConnection *         connection,
+try_reply_agent_request(NMDeviceIwd           *self,
+                        NMConnection          *connection,
                         GDBusMethodInvocation *invocation,
                         gboolean               allow_existing,
-                        const char **          setting_name,
-                        const char **          setting_key,
-                        gboolean *             replied)
+                        const char           **setting_name,
+                        const char           **setting_key,
+                        gboolean              *replied)
 {
-    const char *               method_name = g_dbus_method_invocation_get_method_name(invocation);
+    const char                *method_name = g_dbus_method_invocation_get_method_name(invocation);
     NMSettingWirelessSecurity *s_wireless_sec;
-    NMSetting8021x *           s_8021x;
+    NMSetting8021x            *s_8021x;
 
     s_wireless_sec = nm_connection_get_setting_wireless_security(connection);
     s_8021x        = nm_connection_get_setting_802_1x(connection);
@@ -1418,7 +1418,7 @@ try_reply_agent_request(NMDeviceIwd *          self,
 static gboolean
 assumed_ac_timeout_cb(gpointer user_data)
 {
-    NMDeviceIwd *       self = user_data;
+    NMDeviceIwd        *self = user_data;
     NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self);
 
     nm_assert(priv->assumed_ac);
@@ -1434,30 +1434,30 @@ assumed_ac_timeout_cb(gpointer user_data)
     return G_SOURCE_REMOVE;
 }
 
-static void wifi_secrets_get_one(NMDeviceIwd *                self,
-                                 const char *                 setting_name,
+static void wifi_secrets_get_one(NMDeviceIwd                 *self,
+                                 const char                  *setting_name,
                                  NMSecretAgentGetSecretsFlags flags,
-                                 const char *                 setting_key,
-                                 GDBusMethodInvocation *      invocation);
+                                 const char                  *setting_key,
+                                 GDBusMethodInvocation       *invocation);
 
 static void
-wifi_secrets_cb(NMActRequest *                req,
+wifi_secrets_cb(NMActRequest                 *req,
                 NMActRequestGetSecretsCallId *call_id,
-                NMSettingsConnection *        s_connection,
-                GError *                      error,
+                NMSettingsConnection         *s_connection,
+                GError                       *error,
                 gpointer                      user_data)
 {
-    NMDeviceIwd *                self;
-    NMDeviceIwdPrivate *         priv;
-    NMDevice *                   device;
-    GDBusMethodInvocation *      invocation;
-    const char *                 setting_name;
-    const char *                 setting_key;
+    NMDeviceIwd                 *self;
+    NMDeviceIwdPrivate          *priv;
+    NMDevice                    *device;
+    GDBusMethodInvocation       *invocation;
+    const char                  *setting_name;
+    const char                  *setting_key;
     gboolean                     replied;
     NMSecretAgentGetSecretsFlags get_secret_flags =
         NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION;
     NMIwdNetworkSecurity security;
-    NMConnection *       connection;
+    NMConnection        *connection;
 
     nm_utils_user_data_unpack(user_data, &self, &invocation);
 
@@ -1550,14 +1550,14 @@ secrets_error:
 }
 
 static void
-wifi_secrets_get_one(NMDeviceIwd *                self,
-                     const char *                 setting_name,
+wifi_secrets_get_one(NMDeviceIwd                 *self,
+                     const char                  *setting_name,
                      NMSecretAgentGetSecretsFlags flags,
-                     const char *                 setting_key,
-                     GDBusMethodInvocation *      invocation)
+                     const char                  *setting_key,
+                     GDBusMethodInvocation       *invocation)
 {
     NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self);
-    NMActRequest *      req;
+    NMActRequest       *req;
 
     wifi_secrets_cancel(self);
 
@@ -1576,16 +1576,16 @@ wifi_secrets_get_one(NMDeviceIwd *                self,
 static void
 network_connect_cb(GObject *source, GAsyncResult *res, gpointer user_data)
 {
-    NMDeviceIwd *       self           = user_data;
-    NMDevice *          device         = NM_DEVICE(self);
-    NMDeviceIwdPrivate *priv           = NM_DEVICE_IWD_GET_PRIVATE(self);
+    NMDeviceIwd               *self    = user_data;
+    NMDevice                  *device  = NM_DEVICE(self);
+    NMDeviceIwdPrivate        *priv    = NM_DEVICE_IWD_GET_PRIVATE(self);
     gs_unref_variant GVariant *variant = NULL;
-    gs_free_error GError *error        = NULL;
-    NMConnection *        connection;
-    gs_free char *        ssid   = NULL;
-    NMDeviceStateReason   reason = NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED;
-    GVariant *            value;
-    gboolean              disconnect;
+    gs_free_error GError      *error   = NULL;
+    NMConnection              *connection;
+    gs_free char              *ssid   = NULL;
+    NMDeviceStateReason        reason = NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED;
+    GVariant                  *value;
+    gboolean                   disconnect;
 
     disconnect = !priv->iwd_autoconnect
                  || nm_device_autoconnect_blocked_get(device, NM_DEVICE_AUTOCONNECT_BLOCKED_ALL);
@@ -1642,7 +1642,7 @@ network_connect_cb(GObject *source, GAsyncResult *res, gpointer user_data)
     _LOGI(LOGD_DEVICE | LOGD_WIFI,
           "Activation: (wifi) Stage 2 of 5 (Device Configure) successful.  Connected to '%s'.",
           ssid);
-    nm_device_activate_schedule_stage3_ip_config_start(device);
+    nm_device_activate_schedule_stage3_ip_config(device, FALSE);
 
     return;
 
@@ -1667,10 +1667,10 @@ failed:
 static void
 act_failed_cb(GObject *source, GAsyncResult *res, gpointer user_data)
 {
-    NMDeviceIwd *    self              = user_data;
-    NMDevice *       device            = NM_DEVICE(self);
+    NMDeviceIwd               *self    = user_data;
+    NMDevice                  *device  = NM_DEVICE(self);
     gs_unref_variant GVariant *variant = NULL;
-    gs_free_error GError *error        = NULL;
+    gs_free_error GError      *error   = NULL;
 
     variant = g_dbus_proxy_call_finish(G_DBUS_PROXY(source), res, &error);
     if (!variant && nm_utils_error_is_cancelled(error))
@@ -1689,12 +1689,12 @@ act_failed_cb(GObject *source, GAsyncResult *res, gpointer user_data)
 static void
 act_start_cb(GObject *source, GAsyncResult *res, gpointer user_data)
 {
-    NMDeviceIwd *       self           = user_data;
-    NMDeviceIwdPrivate *priv           = NM_DEVICE_IWD_GET_PRIVATE(self);
-    NMDevice *          device         = NM_DEVICE(self);
+    NMDeviceIwd               *self    = user_data;
+    NMDeviceIwdPrivate        *priv    = NM_DEVICE_IWD_GET_PRIVATE(self);
+    NMDevice                  *device  = NM_DEVICE(self);
     gs_unref_variant GVariant *variant = NULL;
-    gs_free_error GError *error        = NULL;
-    gs_free char *        ssid         = NULL;
+    gs_free_error GError      *error   = NULL;
+    gs_free char              *ssid    = NULL;
 
     variant = g_dbus_proxy_call_finish(G_DBUS_PROXY(source), res, &error);
     if (!variant) {
@@ -1721,7 +1721,7 @@ act_start_cb(GObject *source, GAsyncResult *res, gpointer user_data)
     _LOGI(LOGD_DEVICE | LOGD_WIFI,
           "Activation: (wifi) Stage 2 of 5 (Device Configure) successful.  Started '%s'.",
           ssid);
-    nm_device_activate_schedule_stage3_ip_config_start(device);
+    nm_device_activate_schedule_stage3_ip_config(device, FALSE);
 
     return;
 
@@ -1736,12 +1736,12 @@ error:
 static void
 act_check_interface(NMDeviceIwd *self)
 {
-    NMDeviceIwdPrivate * priv   = NM_DEVICE_IWD_GET_PRIVATE(self);
-    NMDevice *           device = NM_DEVICE(self);
-    NMSettingWireless *  s_wireless;
-    GDBusProxy *         proxy = NULL;
-    gs_free char *       ssid  = NULL;
-    const char *         mode;
+    NMDeviceIwdPrivate  *priv   = NM_DEVICE_IWD_GET_PRIVATE(self);
+    NMDevice            *device = NM_DEVICE(self);
+    NMSettingWireless   *s_wireless;
+    GDBusProxy          *proxy = NULL;
+    gs_free char        *ssid  = NULL;
+    const char          *mode;
     NMIwdNetworkSecurity security;
 
     if (!priv->act_mode_switch)
@@ -1780,7 +1780,7 @@ act_check_interface(NMDeviceIwd *self)
                           self);
     } else if (security == NM_IWD_NETWORK_SECURITY_PSK) {
         NMSettingWirelessSecurity *s_wireless_sec;
-        const char *               psk;
+        const char                *psk;
 
         s_wireless_sec = (NMSettingWirelessSecurity *) nm_device_get_applied_setting(
             device,
@@ -1813,11 +1813,11 @@ failed:
 static void
 act_set_mode_cb(GObject *source, GAsyncResult *res, gpointer user_data)
 {
-    NMDeviceIwd *       self           = user_data;
-    NMDeviceIwdPrivate *priv           = NM_DEVICE_IWD_GET_PRIVATE(self);
-    NMDevice *          device         = NM_DEVICE(self);
+    NMDeviceIwd               *self    = user_data;
+    NMDeviceIwdPrivate        *priv    = NM_DEVICE_IWD_GET_PRIVATE(self);
+    NMDevice                  *device  = NM_DEVICE(self);
     gs_unref_variant GVariant *variant = NULL;
-    gs_free_error GError *error        = NULL;
+    gs_free_error GError      *error   = NULL;
 
     variant = g_dbus_proxy_call_finish(G_DBUS_PROXY(source), res, &error);
     if (!variant) {
@@ -1848,10 +1848,10 @@ static void
 act_set_mode(NMDeviceIwd *self)
 {
     NMDeviceIwdPrivate *priv   = NM_DEVICE_IWD_GET_PRIVATE(self);
-    NMDevice *          device = NM_DEVICE(self);
-    const char *        iwd_mode;
-    const char *        mode;
-    NMSettingWireless * s_wireless;
+    NMDevice           *device = NM_DEVICE(self);
+    const char         *iwd_mode;
+    const char         *mode;
+    NMSettingWireless  *s_wireless;
 
     s_wireless =
         (NMSettingWireless *) nm_device_get_applied_setting(device, NM_TYPE_SETTING_WIRELESS);
@@ -1880,15 +1880,15 @@ act_set_mode(NMDeviceIwd *self)
 }
 
 static void
-act_psk_cb(NMActRequest *                req,
+act_psk_cb(NMActRequest                 *req,
            NMActRequestGetSecretsCallId *call_id,
-           NMSettingsConnection *        s_connection,
-           GError *                      error,
+           NMSettingsConnection         *s_connection,
+           GError                       *error,
            gpointer                      user_data)
 {
-    NMDeviceIwd *       self = user_data;
+    NMDeviceIwd        *self = user_data;
     NMDeviceIwdPrivate *priv;
-    NMDevice *          device;
+    NMDevice           *device;
 
     if (nm_utils_error_is_cancelled(error))
         return;
@@ -1944,7 +1944,7 @@ static NMWifiAP *
 find_ap_by_supplicant_path(NMDeviceIwd *self, const NMRefString *path)
 {
     NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self);
-    NMWifiAP *          tmp;
+    NMWifiAP           *tmp;
 
     c_list_for_each_entry (tmp, &priv->aps_lst_head, aps_lst)
         if (nm_wifi_ap_get_supplicant_path(tmp) == path)
@@ -1956,7 +1956,7 @@ find_ap_by_supplicant_path(NMDeviceIwd *self, const NMRefString *path)
 static void
 assumed_connection_state_changed(NMActiveConnection *active, GParamSpec *pspec, NMDeviceIwd *self)
 {
-    NMSettingsConnection *  sett_conn = nm_active_connection_get_settings_connection(active);
+    NMSettingsConnection   *sett_conn = nm_active_connection_get_settings_connection(active);
     NMActiveConnectionState state     = nm_active_connection_get_state(active);
 
     /* Delete the temporary connection created for an external IWD connection
@@ -1983,10 +1983,10 @@ assumed_connection_state_changed(NMActiveConnection *active, GParamSpec *pspec,
 
 static void
 assumed_connection_state_changed_before_managed(NMActiveConnection *active,
-                                                GParamSpec *        pspec,
-                                                NMDeviceIwd *       self)
+                                                GParamSpec         *pspec,
+                                                NMDeviceIwd        *self)
 {
-    NMDeviceIwdPrivate *    priv  = NM_DEVICE_IWD_GET_PRIVATE(self);
+    NMDeviceIwdPrivate     *priv  = NM_DEVICE_IWD_GET_PRIVATE(self);
     NMActiveConnectionState state = nm_active_connection_get_state(active);
     gboolean                disconnect;
 
@@ -2020,11 +2020,11 @@ assumed_connection_state_changed_before_managed(NMActiveConnection *active,
 static void
 assume_connection(NMDeviceIwd *self, NMWifiAP *ap)
 {
-    NMDeviceIwdPrivate *  priv = NM_DEVICE_IWD_GET_PRIVATE(self);
-    NMSettingsConnection *sett_conn;
+    NMDeviceIwdPrivate            *priv = NM_DEVICE_IWD_GET_PRIVATE(self);
+    NMSettingsConnection          *sett_conn;
     gs_unref_object NMAuthSubject *subject = NULL;
-    NMActiveConnection *           ac;
-    gs_free_error GError *error = NULL;
+    NMActiveConnection            *ac;
+    gs_free_error GError          *error = NULL;
 
     /* We can use the .update_connection / nm_device_emit_recheck_assume
      * API but we can also pass an assumed/external activation type
@@ -2104,7 +2104,7 @@ static void
 assumed_connection_progress_to_ip_config(NMDeviceIwd *self, gboolean was_postponed)
 {
     NMDeviceIwdPrivate *priv      = NM_DEVICE_IWD_GET_PRIVATE(self);
-    NMDevice *          device    = NM_DEVICE(self);
+    NMDevice           *device    = NM_DEVICE(self);
     NMDeviceState       dev_state = nm_device_get_state(device);
 
     wifi_secrets_cancel(self);
@@ -2127,17 +2127,17 @@ assumed_connection_progress_to_ip_config(NMDeviceIwd *self, gboolean was_postpon
      * that stage2 is done.
      */
     if (was_postponed)
-        nm_device_activate_schedule_stage3_ip_config_start(NM_DEVICE(self));
+        nm_device_activate_schedule_stage3_ip_config(NM_DEVICE(self), FALSE);
 }
 
 static void
 initial_check_assume(NMDeviceIwd *self)
 {
-    NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self);
-    const char *        network_path_str;
+    NMDeviceIwdPrivate             *priv = NM_DEVICE_IWD_GET_PRIVATE(self);
+    const char                     *network_path_str;
     nm_auto_ref_string NMRefString *network_path = NULL;
-    NMWifiAP *                      ap           = NULL;
-    gs_unref_variant GVariant *state_value =
+    NMWifiAP                       *ap           = NULL;
+    gs_unref_variant GVariant      *state_value =
         g_dbus_proxy_get_cached_property(priv->dbus_station_proxy, "State");
     gs_unref_variant GVariant *cn_value =
         g_dbus_proxy_get_cached_property(priv->dbus_station_proxy, "ConnectedNetwork");
@@ -2174,15 +2174,15 @@ initial_check_assume(NMDeviceIwd *self)
 static NMActStageReturn
 act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason)
 {
-    NMDeviceIwd *       self          = NM_DEVICE_IWD(device);
-    NMDeviceIwdPrivate *priv          = NM_DEVICE_IWD_GET_PRIVATE(self);
-    NMWifiAP *          ap            = NULL;
+    NMDeviceIwd              *self    = NM_DEVICE_IWD(device);
+    NMDeviceIwdPrivate       *priv    = NM_DEVICE_IWD_GET_PRIVATE(self);
+    NMWifiAP                 *ap      = NULL;
     gs_unref_object NMWifiAP *ap_fake = NULL;
-    NMActRequest *            req;
-    NMConnection *            connection;
-    NMSettingWireless *       s_wireless;
-    const char *              mode;
-    const char *              ap_path;
+    NMActRequest             *req;
+    NMConnection             *connection;
+    NMSettingWireless        *s_wireless;
+    const char               *mode;
+    const char               *ap_path;
 
     req = nm_device_get_act_request(device);
     g_return_val_if_fail(req, NM_ACT_STAGE_RETURN_FAILURE);
@@ -2246,12 +2246,12 @@ add_new:
 static NMActStageReturn
 act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason)
 {
-    NMDeviceIwd *       self = NM_DEVICE_IWD(device);
+    NMDeviceIwd        *self = NM_DEVICE_IWD(device);
     NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self);
-    NMActRequest *      req;
-    NMConnection *      connection;
-    NMSettingWireless * s_wireless;
-    const char *        mode;
+    NMActRequest       *req;
+    NMConnection       *connection;
+    NMSettingWireless  *s_wireless;
+    const char         *mode;
 
     req        = nm_device_get_act_request(device);
     connection = nm_act_request_get_applied_connection(req);
@@ -2262,8 +2262,8 @@ act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason)
 
     if (NM_IN_STRSET(mode, NULL, NM_SETTING_WIRELESS_MODE_INFRA)) {
         gs_unref_object GDBusProxy *network_proxy = NULL;
-        NMWifiAP *                  ap            = priv->current_ap;
-        NMSettingWirelessSecurity * s_wireless_sec;
+        NMWifiAP                   *ap            = priv->current_ap;
+        NMSettingWirelessSecurity  *s_wireless_sec;
 
         if (!ap) {
             NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED);
@@ -2432,7 +2432,7 @@ get_configured_mtu(NMDevice *device, NMDeviceMtuSource *out_source, gboolean *ou
 static gboolean
 periodic_scan_timeout_cb(gpointer user_data)
 {
-    NMDeviceIwd *       self = user_data;
+    NMDeviceIwd        *self = user_data;
     NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self);
 
     priv->periodic_scan_id = 0;
@@ -2503,15 +2503,15 @@ set_can_scan(NMDeviceIwd *self, gboolean can_scan)
 }
 
 static void
-device_state_changed(NMDevice *          device,
+device_state_changed(NMDevice           *device,
                      NMDeviceState       new_state,
                      NMDeviceState       old_state,
                      NMDeviceStateReason reason)
 {
-    NMDeviceIwd *       self = NM_DEVICE_IWD(device);
+    NMDeviceIwd        *self = NM_DEVICE_IWD(device);
     NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self);
-    NMSettingWireless * s_wireless;
-    const char *        mode;
+    NMSettingWireless  *s_wireless;
+    const char         *mode;
 
     switch (new_state) {
     case NM_DEVICE_STATE_UNMANAGED:
@@ -2559,7 +2559,7 @@ get_enabled(NMDevice *device)
 static void
 set_enabled(NMDevice *device, gboolean enabled)
 {
-    NMDeviceIwd *       self = NM_DEVICE_IWD(device);
+    NMDeviceIwd        *self = NM_DEVICE_IWD(device);
     NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self);
     NMDeviceState       state;
 
@@ -2596,12 +2596,12 @@ set_enabled(NMDevice *device, gboolean enabled)
 }
 
 static gboolean
-can_reapply_change(NMDevice *  device,
+can_reapply_change(NMDevice   *device,
                    const char *setting_name,
-                   NMSetting * s_old,
-                   NMSetting * s_new,
+                   NMSetting  *s_old,
+                   NMSetting  *s_new,
                    GHashTable *diffs,
-                   GError **   error)
+                   GError    **error)
 {
     NMDeviceClass *device_class;
 
@@ -2624,9 +2624,9 @@ can_reapply_change(NMDevice *  device,
 static void
 get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
 {
-    NMDeviceIwd *       self = NM_DEVICE_IWD(object);
+    NMDeviceIwd        *self = NM_DEVICE_IWD(object);
     NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self);
-    const char **       list;
+    const char        **list;
 
     switch (prop_id) {
     case PROP_MODE:
@@ -2673,18 +2673,18 @@ static void
 state_changed(NMDeviceIwd *self, const char *new_state)
 {
     NMDeviceIwdPrivate *priv           = NM_DEVICE_IWD_GET_PRIVATE(self);
-    NMDevice *          device         = NM_DEVICE(self);
+    NMDevice           *device         = NM_DEVICE(self);
     NMDeviceState       dev_state      = nm_device_get_state(device);
     gboolean            nm_connection  = priv->current_ap || priv->assumed_ac;
     gboolean            iwd_connection = FALSE;
-    NMWifiAP *          ap             = NULL;
+    NMWifiAP           *ap             = NULL;
     gboolean            can_connect    = priv->nm_autoconnect;
 
     _LOGI(LOGD_DEVICE | LOGD_WIFI, "new IWD device state is %s", new_state);
 
     if (NM_IN_STRSET(new_state, "connecting", "connected", "roaming")) {
-        gs_unref_variant GVariant *value = NULL;
-        const char *               network_path_str;
+        gs_unref_variant GVariant      *value = NULL;
+        const char                     *network_path_str;
         nm_auto_ref_string NMRefString *network_path = NULL;
 
         value = g_dbus_proxy_get_cached_property(priv->dbus_station_proxy, "ConnectedNetwork");
@@ -2855,12 +2855,12 @@ scanning_changed(NMDeviceIwd *self, gboolean new_scanning)
 
 static void
 station_properties_changed(GDBusProxy *proxy,
-                           GVariant *  changed_properties,
+                           GVariant   *changed_properties,
                            GStrv       invalidate_properties,
                            gpointer    user_data)
 {
     NMDeviceIwd *self = user_data;
-    const char * new_str;
+    const char  *new_str;
     gboolean     new_bool;
 
     if (g_variant_lookup(changed_properties, "State", "&s", &new_str))
@@ -2872,7 +2872,7 @@ station_properties_changed(GDBusProxy *proxy,
 
 static void
 ap_adhoc_properties_changed(GDBusProxy *proxy,
-                            GVariant *  changed_properties,
+                            GVariant   *changed_properties,
                             GStrv       invalidate_properties,
                             gpointer    user_data)
 {
@@ -2889,7 +2889,7 @@ static void
 powered_changed(NMDeviceIwd *self, gboolean new_powered)
 {
     NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self);
-    GDBusInterface *    interface;
+    GDBusInterface     *interface;
 
     nm_device_queue_recheck_available(NM_DEVICE(self),
                                       NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE,
@@ -3004,7 +3004,7 @@ powered_changed(NMDeviceIwd *self, gboolean new_powered)
 
 static void
 device_properties_changed(GDBusProxy *proxy,
-                          GVariant *  changed_properties,
+                          GVariant   *changed_properties,
                           GStrv       invalidate_properties,
                           gpointer    user_data)
 {
@@ -3016,11 +3016,11 @@ device_properties_changed(GDBusProxy *proxy,
 }
 
 static void
-config_changed(NMConfig *          config,
-               NMConfigData *      config_data,
+config_changed(NMConfig           *config,
+               NMConfigData       *config_data,
                NMConfigChangeFlags changes,
-               NMConfigData *      old_data,
-               NMDeviceIwd *       self)
+               NMConfigData       *old_data,
+               NMDeviceIwd        *self)
 {
     NMDeviceIwdPrivate *priv       = NM_DEVICE_IWD_GET_PRIVATE(self);
     gboolean            old_iwd_ac = priv->iwd_autoconnect;
@@ -3048,12 +3048,12 @@ config_changed(NMConfig *          config,
 void
 nm_device_iwd_set_dbus_object(NMDeviceIwd *self, GDBusObject *object)
 {
-    NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self);
-    GDBusInterface *    interface;
-    gs_unref_variant GVariant *value          = NULL;
+    NMDeviceIwdPrivate         *priv = NM_DEVICE_IWD_GET_PRIVATE(self);
+    GDBusInterface             *interface;
+    gs_unref_variant GVariant  *value         = NULL;
     gs_unref_object GDBusProxy *adapter_proxy = NULL;
-    GVariantIter *              iter;
-    const char *                mode;
+    GVariantIter               *iter;
+    const char                 *mode;
     gboolean                    powered;
     _NMDeviceWifiCapabilities   capabilities;
 
@@ -3159,18 +3159,18 @@ error:
 gboolean
 nm_device_iwd_agent_query(NMDeviceIwd *self, GDBusMethodInvocation *invocation)
 {
-    NMDevice *                   device = NM_DEVICE(self);
-    NMDeviceIwdPrivate *         priv   = NM_DEVICE_IWD_GET_PRIVATE(self);
+    NMDevice                    *device = NM_DEVICE(self);
+    NMDeviceIwdPrivate          *priv   = NM_DEVICE_IWD_GET_PRIVATE(self);
     NMDeviceState                state  = nm_device_get_state(device);
-    const char *                 setting_name;
-    const char *                 setting_key;
+    const char                  *setting_name;
+    const char                  *setting_key;
     gboolean                     replied;
-    NMWifiAP *                   ap;
+    NMWifiAP                    *ap;
     gboolean                     allow_existing = FALSE;
     NMSecretAgentGetSecretsFlags get_secret_flags =
         NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION;
-    NMIwdNetworkSecurity security;
-    NMConnection *       connection;
+    NMIwdNetworkSecurity            security;
+    NMConnection                   *connection;
     nm_auto_ref_string NMRefString *network_path = NULL;
 
     if (!invocation) {
@@ -3324,9 +3324,9 @@ nm_device_iwd_agent_query(NMDeviceIwd *self, GDBusMethodInvocation *invocation)
 void
 nm_device_iwd_network_add_remove(NMDeviceIwd *self, GDBusProxy *network, bool add)
 {
-    NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self);
-    NMWifiAP *          ap   = NULL;
-    bool                recheck;
+    NMDeviceIwdPrivate             *priv = NM_DEVICE_IWD_GET_PRIVATE(self);
+    NMWifiAP                       *ap   = NULL;
+    bool                            recheck;
     nm_auto_ref_string NMRefString *bss_path = NULL;
 
     bss_path = nm_ref_string_new(g_dbus_proxy_get_object_path(network));
@@ -3371,7 +3371,7 @@ nm_device_iwd_network_add_remove(NMDeviceIwd *self, GDBusProxy *network, bool ad
 static void
 autoconnect_changed(NMDevice *device, GParamSpec *pspec, NMDeviceIwd *self)
 {
-    NMDeviceIwdPrivate *priv         = NM_DEVICE_IWD_GET_PRIVATE(self);
+    NMDeviceIwdPrivate        *priv  = NM_DEVICE_IWD_GET_PRIVATE(self);
     gs_unref_variant GVariant *value = NULL;
 
     /* Note IWD normally remains in "disconnected" during a secret request
@@ -3434,7 +3434,7 @@ nm_device_iwd_new(const char *iface)
 static void
 dispose(GObject *object)
 {
-    NMDeviceIwd *       self = NM_DEVICE_IWD(object);
+    NMDeviceIwd        *self = NM_DEVICE_IWD(object);
     NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self);
 
     nm_clear_g_cancellable(&priv->cancellable);
@@ -3450,9 +3450,9 @@ dispose(GObject *object)
 static void
 nm_device_iwd_class_init(NMDeviceIwdClass *klass)
 {
-    GObjectClass *     object_class      = G_OBJECT_CLASS(klass);
+    GObjectClass      *object_class      = G_OBJECT_CLASS(klass);
     NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(klass);
-    NMDeviceClass *    device_class      = NM_DEVICE_CLASS(klass);
+    NMDeviceClass     *device_class      = NM_DEVICE_CLASS(klass);
 
     object_class->get_property = get_property;
     object_class->dispose      = dispose;
diff --git a/src/core/devices/wifi/nm-device-iwd.h b/src/core/devices/wifi/nm-device-iwd.h
index ce94c9ea..bb136bf6 100644
--- a/src/core/devices/wifi/nm-device-iwd.h
+++ b/src/core/devices/wifi/nm-device-iwd.h
@@ -40,8 +40,8 @@ gboolean nm_device_iwd_agent_query(NMDeviceIwd *device, GDBusMethodInvocation *i
 
 const CList *_nm_device_iwd_get_aps(NMDeviceIwd *self);
 
-void _nm_device_iwd_request_scan(NMDeviceIwd *          self,
-                                 GVariant *             options,
+void _nm_device_iwd_request_scan(NMDeviceIwd           *self,
+                                 GVariant              *options,
                                  GDBusMethodInvocation *invocation);
 
 void nm_device_iwd_network_add_remove(NMDeviceIwd *device, GDBusProxy *network, bool add);
diff --git a/src/core/devices/wifi/nm-device-olpc-mesh.c b/src/core/devices/wifi/nm-device-olpc-mesh.c
index d829f9ae..fd851ebc 100644
--- a/src/core/devices/wifi/nm-device-olpc-mesh.c
+++ b/src/core/devices/wifi/nm-device-olpc-mesh.c
@@ -39,7 +39,7 @@
 NM_GOBJECT_PROPERTIES_DEFINE(NMDeviceOlpcMesh, PROP_COMPANION, PROP_ACTIVE_CHANNEL, );
 
 typedef struct {
-    NMDevice * companion;
+    NMDevice  *companion;
     NMManager *manager;
     bool       stage1_waiting : 1;
 } NMDeviceOlpcMeshPrivate;
@@ -63,7 +63,7 @@ G_DEFINE_TYPE(NMDeviceOlpcMesh, nm_device_olpc_mesh, NM_TYPE_DEVICE)
 static gboolean
 get_autoconnect_allowed(NMDevice *device)
 {
-    NMDeviceOlpcMesh *       self = NM_DEVICE_OLPC_MESH(device);
+    NMDeviceOlpcMesh        *self = NM_DEVICE_OLPC_MESH(device);
     NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE(self);
 
     /* We can't even connect if we don't have a companion yet. */
@@ -81,11 +81,11 @@ get_autoconnect_allowed(NMDevice *device)
 #define DEFAULT_SSID "olpc-mesh"
 
 static gboolean
-complete_connection(NMDevice *           device,
-                    NMConnection *       connection,
-                    const char *         specific_object,
+complete_connection(NMDevice            *device,
+                    NMConnection        *connection,
+                    const char          *specific_object,
                     NMConnection *const *existing_connections,
-                    GError **            error)
+                    GError             **error)
 {
     NMSettingOlpcMesh *s_mesh;
 
@@ -133,7 +133,7 @@ get_dhcp_anycast_address(NMDevice *device)
 static NMActStageReturn
 act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason)
 {
-    NMDeviceOlpcMesh *       self = NM_DEVICE_OLPC_MESH(device);
+    NMDeviceOlpcMesh        *self = NM_DEVICE_OLPC_MESH(device);
     NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE(self);
 
     /* disconnect companion device, if it is connected */
@@ -183,9 +183,9 @@ _mesh_set_channel(NMDeviceOlpcMesh *self, guint32 channel)
 static NMActStageReturn
 act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason)
 {
-    NMDeviceOlpcMesh * self = NM_DEVICE_OLPC_MESH(device);
+    NMDeviceOlpcMesh  *self = NM_DEVICE_OLPC_MESH(device);
     NMSettingOlpcMesh *s_mesh;
-    GBytes *           ssid;
+    GBytes            *ssid;
     gboolean           success;
 
     s_mesh = nm_device_get_applied_setting(device, NM_TYPE_SETTING_OLPC_MESH);
@@ -243,7 +243,7 @@ companion_cleanup(NMDeviceOlpcMesh *self)
 static void
 companion_notify_cb(NMDeviceWifi *companion, GParamSpec *pspec, gpointer user_data)
 {
-    NMDeviceOlpcMesh *       self = NM_DEVICE_OLPC_MESH(user_data);
+    NMDeviceOlpcMesh        *self = NM_DEVICE_OLPC_MESH(user_data);
     NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE(self);
 
     nm_assert(NM_IS_DEVICE_WIFI(companion));
@@ -260,7 +260,7 @@ companion_notify_cb(NMDeviceWifi *companion, GParamSpec *pspec, gpointer user_da
 
 /* disconnect from mesh if someone starts using the companion */
 static void
-companion_state_changed_cb(NMDeviceWifi *      companion,
+companion_state_changed_cb(NMDeviceWifi       *companion,
                            NMDeviceState       state,
                            NMDeviceState       old_state,
                            NMDeviceStateReason reason,
@@ -299,7 +299,7 @@ static gboolean
 check_companion(NMDeviceOlpcMesh *self, NMDevice *other)
 {
     NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE(self);
-    const char *             my_addr, *their_addr;
+    const char              *my_addr, *their_addr;
 
     if (!NM_IS_DEVICE_WIFI(other))
         return FALSE;
@@ -337,7 +337,7 @@ check_companion(NMDeviceOlpcMesh *self, NMDevice *other)
 static void
 device_added_cb(NMManager *manager, NMDevice *other, gpointer user_data)
 {
-    NMDeviceOlpcMesh *       self = NM_DEVICE_OLPC_MESH(user_data);
+    NMDeviceOlpcMesh        *self = NM_DEVICE_OLPC_MESH(user_data);
     NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE(self);
 
     if (!priv->companion && check_companion(self, other)) {
@@ -363,8 +363,8 @@ static void
 find_companion(NMDeviceOlpcMesh *self)
 {
     NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE(self);
-    const CList *            tmp_lst;
-    NMDevice *               candidate;
+    const CList             *tmp_lst;
+    NMDevice                *candidate;
 
     if (priv->companion)
         return;
@@ -386,12 +386,12 @@ find_companion(NMDeviceOlpcMesh *self)
 }
 
 static void
-state_changed(NMDevice *          device,
+state_changed(NMDevice           *device,
               NMDeviceState       new_state,
               NMDeviceState       old_state,
               NMDeviceStateReason reason)
 {
-    NMDeviceOlpcMesh *       self = NM_DEVICE_OLPC_MESH(device);
+    NMDeviceOlpcMesh        *self = NM_DEVICE_OLPC_MESH(device);
     NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE(self);
 
     if (new_state == NM_DEVICE_STATE_UNAVAILABLE)
@@ -422,8 +422,8 @@ get_dhcp_timeout_for_device(NMDevice *device, int addr_family)
 static void
 get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
 {
-    NMDeviceOlpcMesh *       self   = NM_DEVICE_OLPC_MESH(object);
-    NMDevice *               device = NM_DEVICE(self);
+    NMDeviceOlpcMesh        *self   = NM_DEVICE_OLPC_MESH(object);
+    NMDevice                *device = NM_DEVICE(self);
     NMDeviceOlpcMeshPrivate *priv   = NM_DEVICE_OLPC_MESH_GET_PRIVATE(self);
 
     switch (prop_id) {
@@ -450,7 +450,7 @@ nm_device_olpc_mesh_init(NMDeviceOlpcMesh *self)
 static void
 constructed(GObject *object)
 {
-    NMDeviceOlpcMesh *       self = NM_DEVICE_OLPC_MESH(object);
+    NMDeviceOlpcMesh        *self = NM_DEVICE_OLPC_MESH(object);
     NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE(self);
 
     G_OBJECT_CLASS(nm_device_olpc_mesh_parent_class)->constructed(object);
@@ -479,7 +479,7 @@ nm_device_olpc_mesh_new(const char *iface)
 static void
 dispose(GObject *object)
 {
-    NMDeviceOlpcMesh *       self = NM_DEVICE_OLPC_MESH(object);
+    NMDeviceOlpcMesh        *self = NM_DEVICE_OLPC_MESH(object);
     NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE(self);
 
     companion_cleanup(self);
@@ -510,9 +510,9 @@ static const NMDBusInterfaceInfoExtended interface_info_device_olpc_mesh = {
 static void
 nm_device_olpc_mesh_class_init(NMDeviceOlpcMeshClass *klass)
 {
-    GObjectClass *     object_class      = G_OBJECT_CLASS(klass);
+    GObjectClass      *object_class      = G_OBJECT_CLASS(klass);
     NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(klass);
-    NMDeviceClass *    device_class      = NM_DEVICE_CLASS(klass);
+    NMDeviceClass     *device_class      = NM_DEVICE_CLASS(klass);
 
     object_class->constructed  = constructed;
     object_class->get_property = get_property;
diff --git a/src/core/devices/wifi/nm-device-wifi-p2p.c b/src/core/devices/wifi/nm-device-wifi-p2p.c
index 67202a67..dfbf8978 100644
--- a/src/core/devices/wifi/nm-device-wifi-p2p.c
+++ b/src/core/devices/wifi/nm-device-wifi-p2p.c
@@ -14,18 +14,18 @@
 
 #include "NetworkManagerUtils.h"
 #include "devices/nm-device-private.h"
-#include "nm-act-request.h"
 #include "libnm-core-aux-intern/nm-libnm-core-utils.h"
 #include "libnm-core-intern/nm-core-internal.h"
 #include "libnm-glib-aux/nm-ref-string.h"
-#include "nm-ip4-config.h"
+#include "libnm-platform/nm-platform.h"
+#include "libnm-platform/nmp-object.h"
+#include "nm-act-request.h"
+#include "nm-l3-config-data.h"
 #include "nm-manager.h"
 #include "nm-manager.h"
 #include "nm-setting-wifi-p2p.h"
 #include "nm-utils.h"
 #include "nm-wifi-p2p-peer.h"
-#include "libnm-platform/nm-platform.h"
-#include "libnm-platform/nmp-object.h"
 #include "settings/nm-settings.h"
 
 #define _NMLOG_DEVICE_TYPE NMDeviceWifiP2P
@@ -82,10 +82,10 @@ static void supplicant_interfaces_release(NMDeviceWifiP2P *self, gboolean set_is
 /*****************************************************************************/
 
 static void
-_peer_dump(NMDeviceWifiP2P *    self,
+_peer_dump(NMDeviceWifiP2P     *self,
            NMLogLevel           log_level,
            const NMWifiP2PPeer *peer,
-           const char *         prefix,
+           const char          *prefix,
            gint32               now_s)
 {
     char buf[1024];
@@ -100,7 +100,7 @@ _peer_dump(NMDeviceWifiP2P *    self,
 static gboolean
 peer_list_dump(gpointer user_data)
 {
-    NMDeviceWifiP2P *       self = NM_DEVICE_WIFI_P2P(user_data);
+    NMDeviceWifiP2P        *self = NM_DEVICE_WIFI_P2P(user_data);
     NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE(self);
 
     priv->peer_dump_id = 0;
@@ -153,10 +153,10 @@ static gboolean
 check_connection_peer_joined(NMDeviceWifiP2P *device)
 {
     NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE(device);
-    NMConnection *          conn = nm_device_get_applied_connection(NM_DEVICE(device));
-    NMWifiP2PPeer *         peer;
-    const char *            group;
-    const char *const *     groups;
+    NMConnection           *conn = nm_device_get_applied_connection(NM_DEVICE(device));
+    NMWifiP2PPeer          *peer;
+    const char             *group;
+    const char *const      *groups;
 
     if (!conn || !priv->group_iface)
         return FALSE;
@@ -168,7 +168,7 @@ check_connection_peer_joined(NMDeviceWifiP2P *device)
         return FALSE;
 
     /* NOTE: We currently only support connections to a specific peer */
-    peer = nm_wifi_p2p_peers_find_first_compatible(&priv->peers_lst_head, conn);
+    peer = nm_wifi_p2p_peers_find_first_compatible(&priv->peers_lst_head, conn, FALSE);
     if (!peer)
         return FALSE;
 
@@ -182,8 +182,8 @@ check_connection_peer_joined(NMDeviceWifiP2P *device)
 static gboolean
 disconnect_on_connection_peer_missing_cb(gpointer user_data)
 {
-    NMDevice *              device = NM_DEVICE(user_data);
-    NMDeviceWifiP2P *       self   = NM_DEVICE_WIFI_P2P(device);
+    NMDevice               *device = NM_DEVICE(user_data);
+    NMDeviceWifiP2P        *self   = NM_DEVICE_WIFI_P2P(device);
     NMDeviceWifiP2PPrivate *priv   = NM_DEVICE_WIFI_P2P_GET_PRIVATE(self);
 
     _LOGW(LOGD_WIFI, "Peer requested in connection is missing for too long, failing connection.");
@@ -222,8 +222,8 @@ update_disconnect_on_connection_peer_missing(NMDeviceWifiP2P *self)
 static gboolean
 is_available(NMDevice *device, NMDeviceCheckDevAvailableFlags flags)
 {
-    NMDeviceWifiP2P *          self = NM_DEVICE_WIFI_P2P(device);
-    NMDeviceWifiP2PPrivate *   priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE(self);
+    NMDeviceWifiP2P           *self = NM_DEVICE_WIFI_P2P(device);
+    NMDeviceWifiP2PPrivate    *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE(self);
     NMSupplicantInterfaceState supplicant_state;
 
     if (!priv->mgmt_iface)
@@ -251,17 +251,17 @@ check_connection_compatible(NMDevice *device, NMConnection *connection, GError *
 }
 
 static gboolean
-complete_connection(NMDevice *           device,
-                    NMConnection *       connection,
-                    const char *         specific_object,
+complete_connection(NMDevice            *device,
+                    NMConnection        *connection,
+                    const char          *specific_object,
                     NMConnection *const *existing_connections,
-                    GError **            error)
+                    GError             **error)
 {
-    NMDeviceWifiP2P * self         = NM_DEVICE_WIFI_P2P(device);
-    gs_free char *    setting_name = NULL;
+    NMDeviceWifiP2P  *self         = NM_DEVICE_WIFI_P2P(device);
+    gs_free char     *setting_name = NULL;
     NMSettingWifiP2P *s_wifi_p2p;
-    NMWifiP2PPeer *   peer;
-    const char *      setting_peer;
+    NMWifiP2PPeer    *peer;
+    const char       *setting_peer;
 
     s_wifi_p2p =
         NM_SETTING_WIFI_P2P(nm_connection_get_setting(connection, NM_TYPE_SETTING_WIFI_P2P));
@@ -329,8 +329,8 @@ complete_connection(NMDevice *           device,
 static gboolean
 supplicant_find_timeout_cb(gpointer user_data)
 {
-    NMDevice *              device = NM_DEVICE(user_data);
-    NMDeviceWifiP2P *       self   = NM_DEVICE_WIFI_P2P(user_data);
+    NMDevice               *device = NM_DEVICE(user_data);
+    NMDeviceWifiP2P        *self   = NM_DEVICE_WIFI_P2P(user_data);
     NMDeviceWifiP2PPrivate *priv   = NM_DEVICE_WIFI_P2P_GET_PRIVATE(self);
 
     priv->find_peer_timeout_id = 0;
@@ -351,11 +351,11 @@ supplicant_find_timeout_cb(gpointer user_data)
 static NMActStageReturn
 act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason)
 {
-    NMDeviceWifiP2P *       self = NM_DEVICE_WIFI_P2P(device);
+    NMDeviceWifiP2P        *self = NM_DEVICE_WIFI_P2P(device);
     NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE(self);
-    NMConnection *          connection;
-    NMSettingWifiP2P *      s_wifi_p2p;
-    NMWifiP2PPeer *         peer;
+    NMConnection           *connection;
+    NMSettingWifiP2P       *s_wifi_p2p;
+    NMWifiP2PPeer          *peer;
 
     if (!priv->mgmt_iface) {
         NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED);
@@ -369,7 +369,7 @@ act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason)
         NM_SETTING_WIFI_P2P(nm_connection_get_setting(connection, NM_TYPE_SETTING_WIFI_P2P));
     g_return_val_if_fail(s_wifi_p2p, NM_ACT_STAGE_RETURN_FAILURE);
 
-    peer = nm_wifi_p2p_peers_find_first_compatible(&priv->peers_lst_head, connection);
+    peer = nm_wifi_p2p_peers_find_first_compatible(&priv->peers_lst_head, connection, FALSE);
     if (!peer) {
         /* Set up a timeout on the find attempt and run a find for the same period of time */
         if (priv->find_peer_timeout_id == 0) {
@@ -393,8 +393,8 @@ act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason)
 static gboolean
 supplicant_connection_timeout_cb(gpointer user_data)
 {
-    NMDevice *              device = NM_DEVICE(user_data);
-    NMDeviceWifiP2P *       self   = NM_DEVICE_WIFI_P2P(user_data);
+    NMDevice               *device = NM_DEVICE(user_data);
+    NMDeviceWifiP2P        *self   = NM_DEVICE_WIFI_P2P(user_data);
     NMDeviceWifiP2PPrivate *priv   = NM_DEVICE_WIFI_P2P_GET_PRIVATE(self);
 
     priv->sup_timeout_id = 0;
@@ -415,12 +415,12 @@ supplicant_connection_timeout_cb(gpointer user_data)
 static NMActStageReturn
 act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason)
 {
-    NMDeviceWifiP2P *       self = NM_DEVICE_WIFI_P2P(device);
+    NMDeviceWifiP2P        *self = NM_DEVICE_WIFI_P2P(device);
     NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE(self);
-    NMConnection *          connection;
-    NMSettingWifiP2P *      s_wifi_p2p;
-    NMWifiP2PPeer *         peer;
-    GBytes *                wfd_ies;
+    NMConnection           *connection;
+    NMSettingWifiP2P       *s_wifi_p2p;
+    NMWifiP2PPeer          *peer;
+    GBytes                 *wfd_ies;
 
     if (nm_clear_g_source(&priv->find_peer_timeout_id))
         nm_assert_not_reached();
@@ -436,7 +436,7 @@ act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason)
         NM_IS_SETTING_WIFI_P2P(nm_connection_get_setting(connection, NM_TYPE_SETTING_WIFI_P2P)));
 
     /* The prepare stage ensures that the peer has been found */
-    peer = nm_wifi_p2p_peers_find_first_compatible(&priv->peers_lst_head, connection);
+    peer = nm_wifi_p2p_peers_find_first_compatible(&priv->peers_lst_head, connection, FALSE);
     if (!peer) {
         NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_PEER_NOT_FOUND);
         return NM_ACT_STAGE_RETURN_FAILURE;
@@ -469,7 +469,7 @@ act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason)
 
 static void
 emit_signal_p2p_peer_add_remove(NMDeviceWifiP2P *device,
-                                NMWifiP2PPeer *  peer,
+                                NMWifiP2PPeer   *peer,
                                 gboolean         is_added /* or else is_removed */)
 {
     nm_dbus_object_emit_signal(NM_DBUS_OBJECT(device),
@@ -483,10 +483,10 @@ emit_signal_p2p_peer_add_remove(NMDeviceWifiP2P *device,
 static void
 peer_add_remove(NMDeviceWifiP2P *self,
                 gboolean         is_adding, /* or else removing */
-                NMWifiP2PPeer *  peer,
+                NMWifiP2PPeer   *peer,
                 gboolean         recheck_available_connections)
 {
-    NMDevice *              device = NM_DEVICE(self);
+    NMDevice               *device = NM_DEVICE(self);
     NMDeviceWifiP2PPrivate *priv   = NM_DEVICE_WIFI_P2P_GET_PRIVATE(self);
 
     if (is_adding) {
@@ -521,7 +521,8 @@ peer_add_remove(NMDeviceWifiP2P *self,
             connection = nm_device_get_applied_connection(device);
             nm_assert(NM_IS_CONNECTION(connection));
 
-            peer = nm_wifi_p2p_peers_find_first_compatible(&priv->peers_lst_head, connection);
+            peer =
+                nm_wifi_p2p_peers_find_first_compatible(&priv->peers_lst_head, connection, FALSE);
             if (peer) {
                 /* A peer for the connection was found, cancel the timeout and go to configure state. */
                 nm_clear_g_source(&priv->find_peer_timeout_id);
@@ -539,7 +540,7 @@ static void
 remove_all_peers(NMDeviceWifiP2P *self)
 {
     NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE(self);
-    NMWifiP2PPeer *         peer;
+    NMWifiP2PPeer          *peer;
 
     if (c_list_is_empty(&priv->peers_lst_head))
         return;
@@ -552,46 +553,44 @@ remove_all_peers(NMDeviceWifiP2P *self)
 
 /*****************************************************************************/
 
-static NMActStageReturn
-act_stage3_ip_config_start(NMDevice *           device,
-                           int                  addr_family,
-                           gpointer *           out_config,
-                           NMDeviceStateReason *out_failure_reason)
+static void
+act_stage3_ip_config(NMDevice *device, int addr_family)
 {
-    NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE(device);
+    NMDeviceWifiP2PPrivate *priv    = NM_DEVICE_WIFI_P2P_GET_PRIVATE(device);
+    const int               IS_IPv4 = NM_IS_IPv4(addr_family);
     gboolean                indicate_addressing_running;
-    NMConnection *          connection;
-    const char *            method;
+    NMConnection           *connection;
+    const char             *method;
 
     connection = nm_device_get_applied_connection(device);
 
     method = nm_utils_get_ip_config_method(connection, addr_family);
 
     /* We may have an address assigned by the group owner */
-    if (NM_IN_STRSET(method, NM_SETTING_IP4_CONFIG_METHOD_AUTO) && priv->group_iface
+    if (IS_IPv4 && NM_IN_STRSET(method, NM_SETTING_IP4_CONFIG_METHOD_AUTO) && priv->group_iface
         && !nm_supplicant_interface_get_p2p_group_owner(priv->group_iface)) {
         in_addr_t addr;
         guint8    plen;
 
         if (nm_supplicant_interface_get_p2p_assigned_addr(priv->group_iface, &addr, &plen)) {
-            NMPlatformIP4Address address = {
-                .addr_source = NM_IP_CONFIG_SOURCE_DHCP,
+            nm_auto_unref_l3cd_init NML3ConfigData *l3cd    = NULL;
+            NMPlatformIP4Address                    address = {
+                                   .addr_source = NM_IP_CONFIG_SOURCE_DHCP,
             };
-            gs_unref_object NMIP4Config *ip4_config = NULL;
 
             nm_platform_ip4_address_set_addr(&address, addr, plen);
 
-            ip4_config = nm_device_ip4_config_new(device);
-            nm_ip4_config_add_address(ip4_config, &address);
+            l3cd = nm_device_create_l3_config_data(device, NM_IP_CONFIG_SOURCE_DHCP);
+            nm_l3_config_data_add_address_4(l3cd, &address);
 
-            nm_device_set_dev2_ip_config(device, AF_INET, NM_IP_CONFIG(ip4_config));
+            nm_device_devip_set_state(device, AF_INET, NM_DEVICE_IP_STATE_READY, l3cd);
 
             /* This just disables the addressing indicator. */
             method = NM_SETTING_IP4_CONFIG_METHOD_DISABLED;
         }
     }
 
-    if (addr_family == AF_INET)
+    if (IS_IPv4)
         indicate_addressing_running = NM_IN_STRSET(method, NM_SETTING_IP4_CONFIG_METHOD_AUTO);
     else {
         indicate_addressing_running = NM_IN_STRSET(method,
@@ -603,15 +602,12 @@ act_stage3_ip_config_start(NMDevice *           device,
         nm_platform_wifi_indicate_addressing_running(nm_device_get_platform(device),
                                                      nm_device_get_ip_ifindex(device),
                                                      TRUE);
-
-    return NM_DEVICE_CLASS(nm_device_wifi_p2p_parent_class)
-        ->act_stage3_ip_config_start(device, addr_family, out_config, out_failure_reason);
 }
 
 static void
 deactivate(NMDevice *device)
 {
-    NMDeviceWifiP2P *       self    = NM_DEVICE_WIFI_P2P(device);
+    NMDeviceWifiP2P        *self    = NM_DEVICE_WIFI_P2P(device);
     int                     ifindex = nm_device_get_ip_ifindex(device);
     NMDeviceWifiP2PPrivate *priv    = NM_DEVICE_WIFI_P2P_GET_PRIVATE(self);
 
@@ -642,7 +638,7 @@ get_configured_mtu(NMDevice *device, NMDeviceMtuSource *out_source, gboolean *ou
 static const char *
 get_auto_ip_config_method(NMDevice *device, int addr_family)
 {
-    NMDeviceWifiP2P *       self = NM_DEVICE_WIFI_P2P(device);
+    NMDeviceWifiP2P        *self = NM_DEVICE_WIFI_P2P(device);
     NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE(self);
 
     if (addr_family == AF_INET && priv->group_iface
@@ -675,8 +671,8 @@ supplicant_iface_state_cb(NMSupplicantInterface *iface,
                           int                    disconnect_reason,
                           gpointer               user_data)
 {
-    NMDeviceWifiP2P *          self      = NM_DEVICE_WIFI_P2P(user_data);
-    NMDevice *                 device    = NM_DEVICE(self);
+    NMDeviceWifiP2P           *self      = NM_DEVICE_WIFI_P2P(user_data);
+    NMDevice                  *device    = NM_DEVICE(self);
     NMSupplicantInterfaceState new_state = new_state_i;
     NMSupplicantInterfaceState old_state = old_state_i;
 
@@ -704,12 +700,12 @@ supplicant_iface_state_cb(NMSupplicantInterface *iface,
 
 static void
 supplicant_iface_peer_changed_cb(NMSupplicantInterface *iface,
-                                 NMSupplicantPeerInfo * peer_info,
+                                 NMSupplicantPeerInfo  *peer_info,
                                  gboolean               is_present,
-                                 NMDeviceWifiP2P *      self)
+                                 NMDeviceWifiP2P       *self)
 {
     NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE(self);
-    NMWifiP2PPeer *         found_peer;
+    NMWifiP2PPeer          *found_peer;
 
     found_peer =
         nm_wifi_p2p_peers_find_by_supplicant_path(&priv->peers_lst_head, peer_info->peer_path->str);
@@ -757,7 +753,7 @@ check_group_iface_ready(NMDeviceWifiP2P *self)
     nm_clear_g_source(&priv->sup_timeout_id);
     update_disconnect_on_connection_peer_missing(self);
 
-    nm_device_activate_schedule_stage3_ip_config_start(NM_DEVICE(self));
+    nm_device_activate_schedule_stage3_ip_config(NM_DEVICE(self), FALSE);
 }
 
 static void
@@ -786,7 +782,7 @@ supplicant_group_iface_state_cb(NMSupplicantInterface *iface,
                                 int                    disconnect_reason,
                                 gpointer               user_data)
 {
-    NMDeviceWifiP2P *          self      = NM_DEVICE_WIFI_P2P(user_data);
+    NMDeviceWifiP2P           *self      = NM_DEVICE_WIFI_P2P(user_data);
     NMSupplicantInterfaceState new_state = new_state_i;
     NMSupplicantInterfaceState old_state = old_state_i;
 
@@ -812,8 +808,8 @@ supplicant_group_iface_state_cb(NMSupplicantInterface *iface,
 
 static void
 supplicant_group_iface_group_finished_cb(NMSupplicantInterface *iface,
-                                         const char *           iface_path,
-                                         void *                 user_data)
+                                         const char            *iface_path,
+                                         void                  *user_data)
 {
     NMDeviceWifiP2P *self = NM_DEVICE_WIFI_P2P(user_data);
 
@@ -826,8 +822,8 @@ supplicant_group_iface_group_finished_cb(NMSupplicantInterface *iface,
 
 static void
 supplicant_iface_group_joined_updated_cb(NMSupplicantInterface *iface,
-                                         GParamSpec *           pspec,
-                                         void *                 user_data)
+                                         GParamSpec            *pspec,
+                                         void                  *user_data)
 {
     NMDeviceWifiP2P *self = NM_DEVICE_WIFI_P2P(user_data);
 
@@ -837,9 +833,9 @@ supplicant_iface_group_joined_updated_cb(NMSupplicantInterface *iface,
 static void
 supplicant_iface_group_started_cb(NMSupplicantInterface *iface,
                                   NMSupplicantInterface *group_iface,
-                                  NMDeviceWifiP2P *      self)
+                                  NMDeviceWifiP2P       *self)
 {
-    NMDeviceWifiP2PPrivate *   priv;
+    NMDeviceWifiP2PPrivate    *priv;
     NMSupplicantInterfaceState state;
 
     g_return_if_fail(self);
@@ -923,12 +919,12 @@ supplicant_interfaces_release(NMDeviceWifiP2P *self, gboolean set_is_waiting)
 }
 
 static void
-device_state_changed(NMDevice *          device,
+device_state_changed(NMDevice           *device,
                      NMDeviceState       new_state,
                      NMDeviceState       old_state,
                      NMDeviceStateReason reason)
 {
-    NMDeviceWifiP2P *       self = NM_DEVICE_WIFI_P2P(device);
+    NMDeviceWifiP2P        *self = NM_DEVICE_WIFI_P2P(device);
     NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE(self);
 
     update_disconnect_on_connection_peer_missing(self);
@@ -984,19 +980,19 @@ device_state_changed(NMDevice *          device,
 }
 
 static void
-impl_device_wifi_p2p_start_find(NMDBusObject *                     obj,
+impl_device_wifi_p2p_start_find(NMDBusObject                      *obj,
                                 const NMDBusInterfaceInfoExtended *interface_info,
-                                const NMDBusMethodInfoExtended *   method_info,
-                                GDBusConnection *                  connection,
-                                const char *                       sender,
-                                GDBusMethodInvocation *            invocation,
-                                GVariant *                         parameters)
+                                const NMDBusMethodInfoExtended    *method_info,
+                                GDBusConnection                   *connection,
+                                const char                        *sender,
+                                GDBusMethodInvocation             *invocation,
+                                GVariant                          *parameters)
 {
-    NMDeviceWifiP2P *       self       = NM_DEVICE_WIFI_P2P(obj);
-    NMDeviceWifiP2PPrivate *priv       = NM_DEVICE_WIFI_P2P_GET_PRIVATE(self);
+    NMDeviceWifiP2P           *self    = NM_DEVICE_WIFI_P2P(obj);
+    NMDeviceWifiP2PPrivate    *priv    = NM_DEVICE_WIFI_P2P_GET_PRIVATE(self);
     gs_unref_variant GVariant *options = NULL;
-    const char *               opts_key;
-    GVariant *                 opts_val;
+    const char                *opts_key;
+    GVariant                  *opts_val;
     GVariantIter               iter;
     gint32                     timeout = 30;
 
@@ -1052,15 +1048,15 @@ impl_device_wifi_p2p_start_find(NMDBusObject *                     obj,
 }
 
 static void
-impl_device_wifi_p2p_stop_find(NMDBusObject *                     obj,
+impl_device_wifi_p2p_stop_find(NMDBusObject                      *obj,
                                const NMDBusInterfaceInfoExtended *interface_info,
-                               const NMDBusMethodInfoExtended *   method_info,
-                               GDBusConnection *                  connection,
-                               const char *                       sender,
-                               GDBusMethodInvocation *            invocation,
-                               GVariant *                         parameters)
+                               const NMDBusMethodInfoExtended    *method_info,
+                               GDBusConnection                   *connection,
+                               const char                        *sender,
+                               GDBusMethodInvocation             *invocation,
+                               GVariant                          *parameters)
 {
-    NMDeviceWifiP2P *       self = NM_DEVICE_WIFI_P2P(obj);
+    NMDeviceWifiP2P        *self = NM_DEVICE_WIFI_P2P(obj);
     NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE(self);
 
     if (!priv->mgmt_iface) {
@@ -1184,9 +1180,9 @@ static const NMDBusInterfaceInfoExtended interface_info_device_wifi_p2p = {
 static void
 get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
 {
-    NMDeviceWifiP2P *       self = NM_DEVICE_WIFI_P2P(object);
+    NMDeviceWifiP2P        *self = NM_DEVICE_WIFI_P2P(object);
     NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE(self);
-    const char **           list;
+    const char            **list;
 
     switch (prop_id) {
     case PROP_PEERS:
@@ -1241,7 +1237,7 @@ nm_device_wifi_p2p_new(const char *iface)
 static void
 dispose(GObject *object)
 {
-    NMDeviceWifiP2P *       self = NM_DEVICE_WIFI_P2P(object);
+    NMDeviceWifiP2P        *self = NM_DEVICE_WIFI_P2P(object);
     NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE(object);
 
     g_clear_object(&priv->sup_mgr);
@@ -1254,7 +1250,7 @@ dispose(GObject *object)
 static void
 finalize(GObject *object)
 {
-    NMDeviceWifiP2P *       peer = NM_DEVICE_WIFI_P2P(object);
+    NMDeviceWifiP2P        *peer = NM_DEVICE_WIFI_P2P(object);
     NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE(peer);
 
     nm_assert(c_list_is_empty(&priv->peers_lst_head));
@@ -1265,9 +1261,9 @@ finalize(GObject *object)
 static void
 nm_device_wifi_p2p_class_init(NMDeviceWifiP2PClass *klass)
 {
-    GObjectClass *     object_class      = G_OBJECT_CLASS(klass);
+    GObjectClass      *object_class      = G_OBJECT_CLASS(klass);
     NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(klass);
-    NMDeviceClass *    device_class      = NM_DEVICE_CLASS(klass);
+    NMDeviceClass     *device_class      = NM_DEVICE_CLASS(klass);
 
     object_class->constructed  = constructed;
     object_class->get_property = get_property;
@@ -1286,11 +1282,11 @@ nm_device_wifi_p2p_class_init(NMDeviceWifiP2PClass *klass)
     device_class->check_connection_compatible = check_connection_compatible;
     device_class->complete_connection         = complete_connection;
 
-    device_class->act_stage1_prepare         = act_stage1_prepare;
-    device_class->act_stage2_config          = act_stage2_config;
-    device_class->get_configured_mtu         = get_configured_mtu;
-    device_class->get_auto_ip_config_method  = get_auto_ip_config_method;
-    device_class->act_stage3_ip_config_start = act_stage3_ip_config_start;
+    device_class->act_stage1_prepare        = act_stage1_prepare;
+    device_class->act_stage2_config         = act_stage2_config;
+    device_class->get_configured_mtu        = get_configured_mtu;
+    device_class->get_auto_ip_config_method = get_auto_ip_config_method;
+    device_class->act_stage3_ip_config      = act_stage3_ip_config;
 
     device_class->deactivate        = deactivate;
     device_class->unmanaged_on_quit = unmanaged_on_quit;
diff --git a/src/core/devices/wifi/nm-device-wifi.c b/src/core/devices/wifi/nm-device-wifi.c
index 82896c77..010cee08 100644
--- a/src/core/devices/wifi/nm-device-wifi.c
+++ b/src/core/devices/wifi/nm-device-wifi.c
@@ -32,7 +32,6 @@
 #include "nm-setting-wireless-security.h"
 #include "nm-setting-8021x.h"
 #include "nm-setting-ip4-config.h"
-#include "nm-ip4-config.h"
 #include "nm-setting-ip6-config.h"
 #include "libnm-platform/nm-platform.h"
 #include "nm-auth-utils.h"
@@ -95,9 +94,9 @@ typedef struct {
 
     NMActRequestGetSecretsCallId *wifi_secrets_id;
 
-    NMSupplicantManager *        sup_mgr;
+    NMSupplicantManager         *sup_mgr;
     NMSupplMgrCreateIfaceHandle *sup_create_handle;
-    NMSupplicantInterface *      sup_iface;
+    NMSupplicantInterface       *sup_iface;
 
     gint64 scan_last_complete_msec;
     gint64 scan_periodic_next_msec;
@@ -136,6 +135,8 @@ typedef struct {
     bool ssid_found : 1;
     bool hidden_probe_scan_warn : 1;
 
+    bool addressing_running_indicated : 1;
+
 } NMDeviceWifiPrivate;
 
 struct _NMDeviceWifi {
@@ -160,7 +161,7 @@ static void supplicant_iface_state_down(NMDeviceWifi *self);
 
 static void cleanup_association_attempt(NMDeviceWifi *self, gboolean disconnect);
 
-static void supplicant_iface_state(NMDeviceWifi *             self,
+static void supplicant_iface_state(NMDeviceWifi              *self,
                                    NMSupplicantInterfaceState new_state,
                                    NMSupplicantInterfaceState old_state,
                                    int                        disconnect_reason,
@@ -173,27 +174,27 @@ static void supplicant_iface_state_cb(NMSupplicantInterface *iface,
                                       gpointer               user_data);
 
 static void supplicant_iface_bss_changed_cb(NMSupplicantInterface *iface,
-                                            NMSupplicantBssInfo *  bss_info,
+                                            NMSupplicantBssInfo   *bss_info,
                                             gboolean               is_present,
-                                            NMDeviceWifi *         self);
+                                            NMDeviceWifi          *self);
 
 static void supplicant_iface_wps_credentials_cb(NMSupplicantInterface *iface,
-                                                GVariant *             credentials,
-                                                NMDeviceWifi *         self);
+                                                GVariant              *credentials,
+                                                NMDeviceWifi          *self);
 
 static void supplicant_iface_notify_current_bss(NMSupplicantInterface *iface,
-                                                GParamSpec *           pspec,
-                                                NMDeviceWifi *         self);
+                                                GParamSpec            *pspec,
+                                                NMDeviceWifi          *self);
 
 static void supplicant_iface_notify_p2p_available(NMSupplicantInterface *iface,
-                                                  GParamSpec *           pspec,
-                                                  NMDeviceWifi *         self);
+                                                  GParamSpec            *pspec,
+                                                  NMDeviceWifi          *self);
 
 static void periodic_update(NMDeviceWifi *self);
 
 static void ap_add_remove(NMDeviceWifi *self,
                           gboolean      is_adding,
-                          NMWifiAP *    ap,
+                          NMWifiAP     *ap,
                           gboolean      recheck_available_connections);
 
 static void _hw_addr_set_scanning(NMDeviceWifi *self, gboolean do_reset);
@@ -290,7 +291,7 @@ static GPtrArray *
 _scan_request_ssids_fetch(NMDeviceWifiPrivate *priv, gint64 now_msec)
 {
     ScanRequestSsidData *srs_data;
-    GPtrArray *          ssids;
+    GPtrArray           *ssids;
     guint                len;
 
     _scan_request_ssids_remove_all(priv, now_msec, G_MAXUINT);
@@ -331,7 +332,7 @@ _scan_request_ssids_track(NMDeviceWifiPrivate *priv, const GPtrArray *ssids)
     c_list_splice(&old_lst_head, &priv->scan_request_ssids_lst_head);
 
     for (i = 0; i < ssids->len; i++) {
-        GBytes *             ssid = ssids->pdata[i];
+        GBytes              *ssid = ssids->pdata[i];
         ScanRequestSsidData *d;
 
         G_STATIC_ASSERT_EXPR(G_STRUCT_OFFSET(ScanRequestSsidData, ssid) == 0);
@@ -364,7 +365,7 @@ nm_device_wifi_scanning_prohibited_track(NMDeviceWifi *self,
                                          gboolean      temporarily_prohibited)
 {
     NMDeviceWifiPrivate *priv;
-    NMCListElem *        elem;
+    NMCListElem         *elem;
 
     g_return_if_fail(NM_IS_DEVICE_WIFI(self));
     nm_assert(tag);
@@ -394,10 +395,26 @@ nm_device_wifi_scanning_prohibited_track(NMDeviceWifi *self,
 /*****************************************************************************/
 
 static void
-_ap_dump(NMDeviceWifi *  self,
+_indicate_addressing_running_reset(NMDeviceWifi *self)
+{
+    NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self);
+
+    if (!priv->addressing_running_indicated)
+        return;
+
+    priv->addressing_running_indicated = FALSE;
+    nm_platform_wifi_indicate_addressing_running(nm_device_get_platform(NM_DEVICE(self)),
+                                                 nm_device_get_ifindex(NM_DEVICE(self)),
+                                                 FALSE);
+}
+
+/*****************************************************************************/
+
+static void
+_ap_dump(NMDeviceWifi   *self,
          NMLogLevel      log_level,
          const NMWifiAP *ap,
-         const char *    prefix,
+         const char     *prefix,
          gint64          now_msec)
 {
     char buf[1024];
@@ -530,8 +547,8 @@ _scan_notify_allowed(NMDeviceWifi *self, NMTernary do_kickoff)
 
 static void
 supplicant_iface_notify_scanning_cb(NMSupplicantInterface *iface,
-                                    GParamSpec *           pspec,
-                                    NMDeviceWifi *         self)
+                                    GParamSpec            *pspec,
+                                    NMDeviceWifi          *self)
 {
     _scan_notify_is_scanning(self);
 }
@@ -549,13 +566,13 @@ unmanaged_on_quit(NMDevice *self)
 }
 
 static void
-supplicant_interface_acquire_cb(NMSupplicantManager *        supplicant_manager,
+supplicant_interface_acquire_cb(NMSupplicantManager         *supplicant_manager,
                                 NMSupplMgrCreateIfaceHandle *handle,
-                                NMSupplicantInterface *      iface,
-                                GError *                     error,
+                                NMSupplicantInterface       *iface,
+                                GError                      *error,
                                 gpointer                     user_data)
 {
-    NMDeviceWifi *       self = user_data;
+    NMDeviceWifi        *self = user_data;
     NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self);
 
     if (nm_utils_error_is_cancelled(error))
@@ -694,7 +711,7 @@ static void
 set_current_ap(NMDeviceWifi *self, NMWifiAP *new_ap, gboolean recheck_available_connections)
 {
     NMDeviceWifiPrivate *priv;
-    NMWifiAP *           old_ap;
+    NMWifiAP            *old_ap;
 
     g_return_if_fail(NM_IS_DEVICE_WIFI(self));
 
@@ -790,7 +807,7 @@ periodic_update_cb(gpointer user_data)
 static void
 ap_add_remove(NMDeviceWifi *self,
               gboolean      is_adding, /* or else removing */
-              NMWifiAP *    ap,
+              NMWifiAP     *ap,
               gboolean      recheck_available_connections)
 {
     NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self);
@@ -831,7 +848,7 @@ static void
 remove_all_aps(NMDeviceWifi *self)
 {
     NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self);
-    NMWifiAP *           ap;
+    NMWifiAP            *ap;
 
     if (c_list_is_empty(&priv->aps_lst_head))
         return;
@@ -847,7 +864,7 @@ remove_all_aps(NMDeviceWifi *self)
 static gboolean
 wake_on_wlan_restore(NMDeviceWifi *self)
 {
-    NMDeviceWifiPrivate *        priv = NM_DEVICE_WIFI_GET_PRIVATE(self);
+    NMDeviceWifiPrivate         *priv = NM_DEVICE_WIFI_GET_PRIVATE(self);
     _NMSettingWirelessWakeOnWLan w;
 
     w = priv->wowlan_restore;
@@ -879,7 +896,7 @@ disconnect_cb_on_idle(gpointer user_data, GCancellable *cancellable)
     gs_unref_object NMDeviceWifi *self = NULL;
     NMDeviceDeactivateCallback    callback;
     gpointer                      callback_user_data;
-    gs_free_error GError *cancelled_error = NULL;
+    gs_free_error GError         *cancelled_error = NULL;
 
     nm_utils_user_data_unpack(user_data, &self, &callback, &callback_user_data);
 
@@ -888,12 +905,12 @@ disconnect_cb_on_idle(gpointer user_data, GCancellable *cancellable)
 }
 
 static void
-deactivate_async(NMDevice *                 device,
-                 GCancellable *             cancellable,
+deactivate_async(NMDevice                  *device,
+                 GCancellable              *cancellable,
                  NMDeviceDeactivateCallback callback,
                  gpointer                   callback_user_data)
 {
-    NMDeviceWifi *       self = NM_DEVICE_WIFI(device);
+    NMDeviceWifi        *self = NM_DEVICE_WIFI(device);
     NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self);
     gpointer             user_data;
 
@@ -917,7 +934,7 @@ deactivate_async(NMDevice *                 device,
 static void
 deactivate(NMDevice *device)
 {
-    NMDeviceWifi *       self    = NM_DEVICE_WIFI(device);
+    NMDeviceWifi        *self    = NM_DEVICE_WIFI(device);
     NMDeviceWifiPrivate *priv    = NM_DEVICE_WIFI_GET_PRIVATE(self);
     int                  ifindex = nm_device_get_ifindex(device);
 
@@ -932,8 +949,7 @@ deactivate(NMDevice *device)
     if (!wake_on_wlan_restore(self))
         _LOGW(LOGD_DEVICE | LOGD_WIFI, "Cannot unconfigure WoWLAN.");
 
-    /* Clear any critical protocol notification in the Wi-Fi stack */
-    nm_platform_wifi_indicate_addressing_running(nm_device_get_platform(device), ifindex, FALSE);
+    _indicate_addressing_running_reset(self);
 
     /* Ensure we're in infrastructure mode after deactivation; some devices
      * (usually older ones) don't scan well in adhoc mode.
@@ -962,14 +978,14 @@ deactivate_reset_hw_addr(NMDevice *device)
 static gboolean
 check_connection_compatible(NMDevice *device, NMConnection *connection, GError **error)
 {
-    NMDeviceWifi *       self = NM_DEVICE_WIFI(device);
+    NMDeviceWifi        *self = NM_DEVICE_WIFI(device);
     NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self);
-    NMSettingWireless *  s_wireless;
-    const char *         mac;
-    const char *const *  mac_blacklist;
+    NMSettingWireless   *s_wireless;
+    const char          *mac;
+    const char *const   *mac_blacklist;
     int                  i;
-    const char *         mode;
-    const char *         perm_hw_addr;
+    const char          *mode;
+    const char          *perm_hw_addr;
 
     if (!NM_DEVICE_CLASS(nm_device_wifi_parent_class)
              ->check_connection_compatible(device, connection, error))
@@ -1062,16 +1078,16 @@ check_connection_compatible(NMDevice *device, NMConnection *connection, GError *
 }
 
 static gboolean
-check_connection_available(NMDevice *                     device,
-                           NMConnection *                 connection,
+check_connection_available(NMDevice                      *device,
+                           NMConnection                  *connection,
                            NMDeviceCheckConAvailableFlags flags,
-                           const char *                   specific_object,
-                           GError **                      error)
+                           const char                    *specific_object,
+                           GError                       **error)
 {
-    NMDeviceWifi *       self = NM_DEVICE_WIFI(device);
+    NMDeviceWifi        *self = NM_DEVICE_WIFI(device);
     NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self);
-    NMSettingWireless *  s_wifi;
-    const char *         mode;
+    NMSettingWireless   *s_wifi;
+    const char          *mode;
 
     s_wifi = nm_connection_get_setting_wireless(connection);
     g_return_val_if_fail(s_wifi, FALSE);
@@ -1130,21 +1146,21 @@ check_connection_available(NMDevice *                     device,
 }
 
 static gboolean
-complete_connection(NMDevice *           device,
-                    NMConnection *       connection,
-                    const char *         specific_object,
+complete_connection(NMDevice            *device,
+                    NMConnection        *connection,
+                    const char          *specific_object,
                     NMConnection *const *existing_connections,
-                    GError **            error)
+                    GError             **error)
 {
-    NMDeviceWifi *       self = NM_DEVICE_WIFI(device);
+    NMDeviceWifi        *self = NM_DEVICE_WIFI(device);
     NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self);
-    NMSettingWireless *  s_wifi;
-    gs_free char *       ssid_utf8 = NULL;
-    NMWifiAP *           ap;
-    GBytes *             ssid         = NULL;
-    GBytes *             setting_ssid = NULL;
+    NMSettingWireless   *s_wifi;
+    gs_free char        *ssid_utf8 = NULL;
+    NMWifiAP            *ap;
+    GBytes              *ssid         = NULL;
+    GBytes              *setting_ssid = NULL;
     gboolean             hidden       = FALSE;
-    const char *         mode;
+    const char          *mode;
 
     s_wifi = nm_connection_get_setting_wireless(connection);
 
@@ -1265,8 +1281,8 @@ complete_connection(NMDevice *           device,
 static gboolean
 is_available(NMDevice *device, NMDeviceCheckDevAvailableFlags flags)
 {
-    NMDeviceWifi *             self = NM_DEVICE_WIFI(device);
-    NMDeviceWifiPrivate *      priv = NM_DEVICE_WIFI_GET_PRIVATE(self);
+    NMDeviceWifi              *self = NM_DEVICE_WIFI(device);
+    NMDeviceWifiPrivate       *priv = NM_DEVICE_WIFI_GET_PRIVATE(self);
     NMSupplicantInterfaceState supplicant_state;
 
     if (!priv->enabled)
@@ -1292,12 +1308,12 @@ get_autoconnect_allowed(NMDevice *device)
 static gboolean
 can_auto_connect(NMDevice *device, NMSettingsConnection *sett_conn, char **specific_object)
 {
-    NMDeviceWifi *       self = NM_DEVICE_WIFI(device);
+    NMDeviceWifi        *self = NM_DEVICE_WIFI(device);
     NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self);
-    NMConnection *       connection;
-    NMSettingWireless *  s_wifi;
-    NMWifiAP *           ap;
-    const char *         method6, *mode;
+    NMConnection        *connection;
+    NMSettingWireless   *s_wifi;
+    NMWifiAP            *ap;
+    const char          *method6, *mode;
     gboolean             auto4, auto6;
 
     nm_assert(!specific_object || !*specific_object);
@@ -1345,7 +1361,7 @@ _nm_device_wifi_get_aps(NMDeviceWifi *self)
 static void
 _hw_addr_set_scanning(NMDeviceWifi *self, gboolean do_reset)
 {
-    NMDevice *           device = (NMDevice *) self;
+    NMDevice            *device = (NMDevice *) self;
     NMDeviceWifiPrivate *priv;
     guint32              now;
     gboolean             randomize;
@@ -1381,7 +1397,7 @@ _hw_addr_set_scanning(NMDeviceWifi *self, gboolean do_reset)
 
     if (now >= priv->hw_addr_scan_expire) {
         gs_free char *hw_addr_scan = NULL;
-        const char *  generate_mac_address_mask;
+        const char   *generate_mac_address_mask;
 
         /* the random MAC address for scanning expires after a while.
          *
@@ -1428,7 +1444,7 @@ ssids_options_to_ptrarray(GVariant *value, GError **error)
         for (i = 0; i < num_ssids; i++) {
             gs_unref_variant GVariant *v = NULL;
             gsize                      len;
-            const guint8 *             bytes;
+            const guint8              *bytes;
 
             v     = g_variant_get_child_value(value, i);
             bytes = g_variant_get_fixed_array(v, &len, sizeof(guint8));
@@ -1455,14 +1471,14 @@ nmtst_ssids_options_to_ptrarray(GVariant *value, GError **error)
 }
 
 static void
-dbus_request_scan_cb(NMDevice *             device,
+dbus_request_scan_cb(NMDevice              *device,
                      GDBusMethodInvocation *context,
-                     NMAuthSubject *        subject,
-                     GError *               error,
+                     NMAuthSubject         *subject,
+                     GError                *error,
                      gpointer               user_data)
 {
-    NMDeviceWifi *       self          = NM_DEVICE_WIFI(device);
-    NMDeviceWifiPrivate *priv          = NM_DEVICE_WIFI_GET_PRIVATE(self);
+    NMDeviceWifi                *self  = NM_DEVICE_WIFI(device);
+    NMDeviceWifiPrivate         *priv  = NM_DEVICE_WIFI_GET_PRIVATE(self);
     gs_unref_ptrarray GPtrArray *ssids = user_data;
 
     if (error) {
@@ -1477,13 +1493,13 @@ dbus_request_scan_cb(NMDevice *             device,
 }
 
 void
-_nm_device_wifi_request_scan(NMDeviceWifi *         self,
-                             GVariant *             options,
+_nm_device_wifi_request_scan(NMDeviceWifi          *self,
+                             GVariant              *options,
                              GDBusMethodInvocation *invocation)
 {
-    NMDeviceWifiPrivate *priv          = NM_DEVICE_WIFI_GET_PRIVATE(self);
-    NMDevice *           device        = NM_DEVICE(self);
-    gs_unref_ptrarray GPtrArray *ssids = NULL;
+    NMDeviceWifiPrivate         *priv   = NM_DEVICE_WIFI_GET_PRIVATE(self);
+    NMDevice                    *device = NM_DEVICE(self);
+    gs_unref_ptrarray GPtrArray *ssids  = NULL;
 
     if (options) {
         gs_unref_variant GVariant *val = g_variant_lookup_value(options, "ssids", NULL);
@@ -1529,7 +1545,7 @@ _nm_device_wifi_request_scan(NMDeviceWifi *         self,
 static gboolean
 hidden_filter_func(NMSettings *settings, NMSettingsConnection *set_con, gpointer user_data)
 {
-    NMConnection *     connection = nm_settings_connection_get_connection(set_con);
+    NMConnection      *connection = nm_settings_connection_get_connection(set_con);
     NMSettingWireless *s_wifi;
 
     if (!nm_connection_is_type(connection, NM_SETTING_WIRELESS_SETTING_NAME))
@@ -1545,12 +1561,12 @@ hidden_filter_func(NMSettings *settings, NMSettingsConnection *set_con, gpointer
 static GPtrArray *
 _scan_request_ssids_build_hidden(NMDeviceWifi *self,
                                  gint64        now_msec,
-                                 gboolean *    out_has_hidden_profiles)
+                                 gboolean     *out_has_hidden_profiles)
 {
     NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self);
-    guint   max_scan_ssids    = nm_supplicant_interface_get_max_scan_ssids(priv->sup_iface);
+    guint max_scan_ssids      = nm_supplicant_interface_get_max_scan_ssids(priv->sup_iface);
     gs_free NMSettingsConnection **connections  = NULL;
-    gs_unref_ptrarray GPtrArray *ssids          = NULL;
+    gs_unref_ptrarray GPtrArray   *ssids        = NULL;
     gs_unref_hashtable GHashTable *unique_ssids = NULL;
     guint                          connections_len;
     guint                          n_hidden;
@@ -1608,7 +1624,7 @@ _scan_request_ssids_build_hidden(NMDeviceWifi *self,
     n_hidden = 0;
     for (i = 0; i < connections_len; i++) {
         NMSettingWireless *s_wifi;
-        GBytes *           ssid;
+        GBytes            *ssid;
 
         if (ssids->len >= max_scan_ssids)
             break;
@@ -1637,7 +1653,7 @@ _scan_request_ssids_build_hidden(NMDeviceWifi *self,
 static gboolean
 _scan_request_delay_cb(gpointer user_data)
 {
-    NMDeviceWifi *       self = user_data;
+    NMDeviceWifi        *self = user_data;
     NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self);
 
     nm_clear_g_source_inst(&priv->scan_request_delay_source);
@@ -1650,10 +1666,10 @@ _scan_request_delay_cb(gpointer user_data)
 
 static void
 _scan_supplicant_request_scan_cb(NMSupplicantInterface *supp_iface,
-                                 GCancellable *         cancellable,
+                                 GCancellable          *cancellable,
                                  gpointer               user_data)
 {
-    NMDeviceWifi *       self;
+    NMDeviceWifi        *self;
     NMDeviceWifiPrivate *priv;
 
     if (g_cancellable_is_cancelled(cancellable))
@@ -1680,7 +1696,7 @@ _scan_supplicant_request_scan_cb(NMSupplicantInterface *supp_iface,
 static gboolean
 _scan_kickoff_timeout_cb(gpointer user_data)
 {
-    NMDeviceWifi *       self = user_data;
+    NMDeviceWifi        *self = user_data;
     NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self);
 
     priv->scan_kickoff_timeout_id = 0;
@@ -1691,7 +1707,7 @@ _scan_kickoff_timeout_cb(gpointer user_data)
 static void
 _scan_kickoff(NMDeviceWifi *self)
 {
-    NMDeviceWifiPrivate *priv               = NM_DEVICE_WIFI_GET_PRIVATE(self);
+    NMDeviceWifiPrivate         *priv       = NM_DEVICE_WIFI_GET_PRIVATE(self);
     gs_unref_ptrarray GPtrArray *ssids      = NULL;
     gboolean                     is_explict = FALSE;
     NMDeviceState                device_state;
@@ -1866,7 +1882,7 @@ _scan_kickoff(NMDeviceWifi *self)
 static gboolean
 ap_list_dump(gpointer user_data)
 {
-    NMDeviceWifi *       self = NM_DEVICE_WIFI(user_data);
+    NMDeviceWifi        *self = NM_DEVICE_WIFI(user_data);
     NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self);
 
     priv->ap_dump_id = 0;
@@ -1904,7 +1920,7 @@ schedule_ap_list_dump(NMDeviceWifi *self)
 static void
 try_fill_ssid_for_hidden_ap(NMDeviceWifi *self, NMWifiAP *ap)
 {
-    const char *                 bssid;
+    const char                  *bssid;
     NMSettingsConnection *const *connections;
     guint                        i;
 
@@ -1918,7 +1934,7 @@ try_fill_ssid_for_hidden_ap(NMDeviceWifi *self, NMWifiAP *ap)
     connections = nm_settings_get_connections(nm_device_get_settings((NMDevice *) self), NULL);
     for (i = 0; connections[i]; i++) {
         NMSettingsConnection *sett_conn = connections[i];
-        NMSettingWireless *   s_wifi;
+        NMSettingWireless    *s_wifi;
 
         if (!nm_settings_connection_has_seen_bssid(sett_conn, bssid))
             continue;
@@ -1934,13 +1950,13 @@ try_fill_ssid_for_hidden_ap(NMDeviceWifi *self, NMWifiAP *ap)
 
 static void
 supplicant_iface_bss_changed_cb(NMSupplicantInterface *iface,
-                                NMSupplicantBssInfo *  bss_info,
+                                NMSupplicantBssInfo   *bss_info,
                                 gboolean               is_present,
-                                NMDeviceWifi *         self)
+                                NMDeviceWifi          *self)
 {
     NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self);
-    NMWifiAP *           found_ap;
-    GBytes *             ssid;
+    NMWifiAP            *found_ap;
+    GBytes              *ssid;
 
     found_ap = g_hash_table_lookup(priv->aps_idx_by_supplicant_path, bss_info->bss_path);
 
@@ -2033,14 +2049,14 @@ cleanup_supplicant_failures(NMDeviceWifi *self)
 }
 
 static void
-wifi_secrets_cb(NMActRequest *                req,
+wifi_secrets_cb(NMActRequest                 *req,
                 NMActRequestGetSecretsCallId *call_id,
-                NMSettingsConnection *        connection,
-                GError *                      error,
+                NMSettingsConnection         *connection,
+                GError                       *error,
                 gpointer                      user_data)
 {
-    NMDevice *           device = user_data;
-    NMDeviceWifi *       self   = user_data;
+    NMDevice            *device = user_data;
+    NMDeviceWifi        *self   = user_data;
     NMDeviceWifiPrivate *priv;
 
     g_return_if_fail(NM_IS_DEVICE_WIFI(self));
@@ -2107,15 +2123,15 @@ wifi_secrets_cancel(NMDeviceWifi *self)
 
 static void
 supplicant_iface_wps_credentials_cb(NMSupplicantInterface *iface,
-                                    GVariant *             credentials,
-                                    NMDeviceWifi *         self)
+                                    GVariant              *credentials,
+                                    NMDeviceWifi          *self)
 {
-    NMActRequest *   req;
+    NMActRequest              *req;
     gs_unref_variant GVariant *val_key = NULL;
     gs_unref_variant GVariant *secrets = NULL;
-    gs_free_error GError *error        = NULL;
-    const char *          array;
-    gsize                 psk_len = 0;
+    gs_free_error GError      *error   = NULL;
+    const char                *array;
+    gsize                      psk_len = 0;
 
     if (nm_device_get_state(NM_DEVICE(self)) != NM_DEVICE_STATE_NEED_AUTH) {
         _LOGI(LOGD_DEVICE | LOGD_WIFI, "WPS: The connection can't be updated with credentials");
@@ -2168,7 +2184,7 @@ supplicant_iface_wps_credentials_cb(NMSupplicantInterface *iface,
 static gboolean
 wps_timeout_cb(gpointer user_data)
 {
-    NMDeviceWifi *       self = NM_DEVICE_WIFI(user_data);
+    NMDeviceWifi        *self = NM_DEVICE_WIFI(user_data);
     NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self);
 
     priv->wps_timeout_id = 0;
@@ -2183,12 +2199,12 @@ wps_timeout_cb(gpointer user_data)
 }
 
 static void
-wifi_secrets_get_secrets(NMDeviceWifi *               self,
-                         const char *                 setting_name,
+wifi_secrets_get_secrets(NMDeviceWifi                *self,
+                         const char                  *setting_name,
                          NMSecretAgentGetSecretsFlags flags)
 {
     NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self);
-    NMActRequest *       req;
+    NMActRequest        *req;
 
     wifi_secrets_cancel(self);
 
@@ -2209,8 +2225,8 @@ wifi_secrets_get_secrets(NMDeviceWifi *               self,
 static gboolean
 link_timeout_cb(gpointer user_data)
 {
-    NMDevice *           device = NM_DEVICE(user_data);
-    NMDeviceWifi *       self   = NM_DEVICE_WIFI(device);
+    NMDevice            *device = NM_DEVICE(user_data);
+    NMDeviceWifi        *self   = NM_DEVICE_WIFI(device);
     NMDeviceWifiPrivate *priv   = NM_DEVICE_WIFI_GET_PRIVATE(self);
 
     _LOGW(LOGD_WIFI, "link timed out.");
@@ -2234,14 +2250,14 @@ link_timeout_cb(gpointer user_data)
 }
 
 static gboolean
-need_new_8021x_secrets(NMDeviceWifi *             self,
+need_new_8021x_secrets(NMDeviceWifi              *self,
                        NMSupplicantInterfaceState old_state,
-                       const char **              setting_name)
+                       const char               **setting_name)
 {
-    NMSetting8021x *           s_8021x;
+    NMSetting8021x            *s_8021x;
     NMSettingWirelessSecurity *s_wsec;
     NMSettingSecretFlags       secret_flags = NM_SETTING_SECRET_FLAG_NONE;
-    NMConnection *             connection;
+    NMConnection              *connection;
 
     g_return_val_if_fail(setting_name, FALSE);
 
@@ -2289,14 +2305,14 @@ need_new_8021x_secrets(NMDeviceWifi *             self,
 }
 
 static gboolean
-need_new_wpa_psk(NMDeviceWifi *             self,
+need_new_wpa_psk(NMDeviceWifi              *self,
                  NMSupplicantInterfaceState old_state,
                  int                        disconnect_reason,
-                 const char **              setting_name)
+                 const char               **setting_name)
 {
     NMSettingWirelessSecurity *s_wsec;
-    NMConnection *             connection;
-    const char *               key_mgmt = NULL;
+    NMConnection              *connection;
+    const char                *key_mgmt = NULL;
 
     g_return_val_if_fail(setting_name, FALSE);
 
@@ -2331,14 +2347,14 @@ need_new_wpa_psk(NMDeviceWifi *             self,
 }
 
 static gboolean
-handle_8021x_or_psk_auth_fail(NMDeviceWifi *             self,
+handle_8021x_or_psk_auth_fail(NMDeviceWifi              *self,
                               NMSupplicantInterfaceState new_state,
                               NMSupplicantInterfaceState old_state,
                               int                        disconnect_reason)
 {
-    NMDevice *    device = NM_DEVICE(self);
+    NMDevice     *device = NM_DEVICE(self);
     NMActRequest *req;
-    const char *  setting_name = NULL;
+    const char   *setting_name = NULL;
     gboolean      handled      = FALSE;
 
     g_return_val_if_fail(new_state == NM_SUPPLICANT_INTERFACE_STATE_DISCONNECTED, FALSE);
@@ -2370,8 +2386,8 @@ handle_8021x_or_psk_auth_fail(NMDeviceWifi *             self,
 static gboolean
 reacquire_interface_cb(gpointer user_data)
 {
-    NMDevice *           device = NM_DEVICE(user_data);
-    NMDeviceWifi *       self   = NM_DEVICE_WIFI(device);
+    NMDevice            *device = NM_DEVICE(user_data);
+    NMDeviceWifi        *self   = NM_DEVICE_WIFI(device);
     NMDeviceWifiPrivate *priv   = NM_DEVICE_WIFI_GET_PRIVATE(self);
 
     priv->reacquire_iface_id = 0;
@@ -2389,7 +2405,7 @@ static void
 supplicant_iface_state_down(NMDeviceWifi *self)
 {
     NMDeviceWifiPrivate *priv   = NM_DEVICE_WIFI_GET_PRIVATE(self);
-    NMDevice *           device = NM_DEVICE(self);
+    NMDevice            *device = NM_DEVICE(self);
 
     nm_device_queue_recheck_available(device,
                                       NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE,
@@ -2409,14 +2425,14 @@ supplicant_iface_state_down(NMDeviceWifi *self)
 }
 
 static void
-supplicant_iface_state(NMDeviceWifi *             self,
+supplicant_iface_state(NMDeviceWifi              *self,
                        NMSupplicantInterfaceState new_state,
                        NMSupplicantInterfaceState old_state,
                        int                        disconnect_reason,
                        gboolean                   is_real_signal)
 {
     NMDeviceWifiPrivate *priv   = NM_DEVICE_WIFI_GET_PRIVATE(self);
-    NMDevice *           device = NM_DEVICE(self);
+    NMDevice            *device = NM_DEVICE(self);
     NMDeviceState        devstate;
     gboolean             scanning;
     gboolean             scan_changed;
@@ -2463,8 +2479,8 @@ supplicant_iface_state(NMDeviceWifi *             self,
          */
         if (devstate == NM_DEVICE_STATE_CONFIG) {
             NMSettingWireless *s_wifi;
-            GBytes *           ssid;
-            gs_free char *     ssid_str = NULL;
+            GBytes            *ssid;
+            gs_free char      *ssid_str = NULL;
 
             s_wifi = nm_device_get_applied_setting(NM_DEVICE(self), NM_TYPE_SETTING_WIRELESS);
 
@@ -2478,7 +2494,7 @@ supplicant_iface_state(NMDeviceWifi *             self,
                   priv->mode == _NM_802_11_MODE_AP ? "Started Wi-Fi Hotspot"
                                                    : "Connected to wireless network",
                   (ssid_str = _nm_utils_ssid_to_string_gbytes(ssid)));
-            nm_device_activate_schedule_stage3_ip_config_start(device);
+            nm_device_activate_schedule_stage3_ip_config(device, FALSE);
         } else if (devstate == NM_DEVICE_STATE_ACTIVATED)
             periodic_update(self);
         break;
@@ -2540,7 +2556,7 @@ static void
 supplicant_iface_assoc_cb(NMSupplicantInterface *iface, GError *error, gpointer user_data)
 {
     NMDeviceWifi *self   = NM_DEVICE_WIFI(user_data);
-    NMDevice *    device = NM_DEVICE(self);
+    NMDevice     *device = NM_DEVICE(self);
 
     if (error && !nm_utils_error_is_cancelled_or_disposing(error)
         && nm_device_is_activating(device)) {
@@ -2553,23 +2569,23 @@ supplicant_iface_assoc_cb(NMSupplicantInterface *iface, GError *error, gpointer
 
 static void
 supplicant_iface_notify_current_bss(NMSupplicantInterface *iface,
-                                    GParamSpec *           pspec,
-                                    NMDeviceWifi *         self)
+                                    GParamSpec            *pspec,
+                                    NMDeviceWifi          *self)
 {
     NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self);
-    NMRefString *        current_bss;
-    NMWifiAP *           new_ap = NULL;
-    NMActRequest *       req;
+    NMRefString         *current_bss;
+    NMWifiAP            *new_ap = NULL;
+    NMActRequest        *req;
 
     current_bss = nm_supplicant_interface_get_current_bss(iface);
     if (current_bss)
         new_ap = g_hash_table_lookup(priv->aps_idx_by_supplicant_path, current_bss);
 
     if (new_ap != priv->current_ap) {
-        const char *  new_bssid  = NULL;
-        GBytes *      new_ssid   = NULL;
-        const char *  old_bssid  = NULL;
-        GBytes *      old_ssid   = NULL;
+        const char   *new_bssid  = NULL;
+        GBytes       *new_ssid   = NULL;
+        const char   *old_bssid  = NULL;
+        GBytes       *old_ssid   = NULL;
         gs_free char *new_ssid_s = NULL;
         gs_free char *old_ssid_s = NULL;
 
@@ -2666,8 +2682,8 @@ recheck_p2p_availability(NMDeviceWifi *self)
 
 static void
 supplicant_iface_notify_p2p_available(NMSupplicantInterface *iface,
-                                      GParamSpec *           pspec,
-                                      NMDeviceWifi *         self)
+                                      GParamSpec            *pspec,
+                                      NMDeviceWifi          *self)
 {
     if (nm_supplicant_interface_get_state(iface) > NM_SUPPLICANT_INTERFACE_STATE_STARTING)
         recheck_p2p_availability(self);
@@ -2676,14 +2692,14 @@ supplicant_iface_notify_p2p_available(NMSupplicantInterface *iface,
 static gboolean
 handle_auth_or_fail(NMDeviceWifi *self, NMActRequest *req, gboolean new_secrets)
 {
-    NMDeviceWifiPrivate *              priv = NM_DEVICE_WIFI_GET_PRIVATE(self);
-    const char *                       setting_name;
-    NMConnection *                     applied_connection;
-    NMSettingWirelessSecurity *        s_wsec;
-    const char *                       bssid = NULL;
+    NMDeviceWifiPrivate               *priv = NM_DEVICE_WIFI_GET_PRIVATE(self);
+    const char                        *setting_name;
+    NMConnection                      *applied_connection;
+    NMSettingWirelessSecurity         *s_wsec;
+    const char                        *bssid = NULL;
     NM80211ApFlags                     ap_flags;
     NMSettingWirelessSecurityWpsMethod wps_method;
-    const char *                       type;
+    const char                        *type;
     NMSecretAgentGetSecretsFlags       get_secret_flags =
         NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION;
 
@@ -2761,11 +2777,11 @@ handle_auth_or_fail(NMDeviceWifi *self, NMActRequest *req, gboolean new_secrets)
 static gboolean
 supplicant_connection_timeout_cb(gpointer user_data)
 {
-    NMDevice *           device = NM_DEVICE(user_data);
-    NMDeviceWifi *       self   = NM_DEVICE_WIFI(user_data);
+    NMDevice            *device = NM_DEVICE(user_data);
+    NMDeviceWifi        *self   = NM_DEVICE_WIFI(user_data);
     NMDeviceWifiPrivate *priv   = NM_DEVICE_WIFI_GET_PRIVATE(self);
-    NMActRequest *       req;
-    NMConnection *       connection;
+    NMActRequest        *req;
+    NMConnection        *connection;
 
     cleanup_association_attempt(self, TRUE);
 
@@ -2841,12 +2857,12 @@ static NMSupplicantConfig *
 build_supplicant_config(NMDeviceWifi *self,
                         NMConnection *connection,
                         guint32       fixed_freq,
-                        GError **     error)
+                        GError      **error)
 {
-    NMDeviceWifiPrivate *         priv   = NM_DEVICE_WIFI_GET_PRIVATE(self);
-    NMSupplicantConfig *          config = NULL;
-    NMSettingWireless *           s_wireless;
-    NMSettingWirelessSecurity *   s_wireless_sec;
+    NMDeviceWifiPrivate          *priv   = NM_DEVICE_WIFI_GET_PRIVATE(self);
+    NMSupplicantConfig           *config = NULL;
+    NMSettingWireless            *s_wireless;
+    NMSettingWirelessSecurity    *s_wireless_sec;
     NMSettingWirelessSecurityPmf  pmf;
     NMSettingWirelessSecurityFils fils;
     NMTernary                     ap_isolation;
@@ -2889,7 +2905,7 @@ build_supplicant_config(NMDeviceWifi *self,
     s_wireless_sec = nm_connection_get_setting_wireless_security(connection);
     if (s_wireless_sec) {
         NMSetting8021x *s_8021x;
-        const char *    con_uuid = nm_connection_get_uuid(connection);
+        const char     *con_uuid = nm_connection_get_uuid(connection);
         guint32         mtu      = nm_platform_link_get_mtu(nm_device_get_platform(NM_DEVICE(self)),
                                                nm_device_get_ifindex(NM_DEVICE(self)));
 
@@ -2950,10 +2966,10 @@ error:
 static gboolean
 wake_on_wlan_enable(NMDeviceWifi *self)
 {
-    NMDeviceWifiPrivate *        priv = NM_DEVICE_WIFI_GET_PRIVATE(self);
+    NMDeviceWifiPrivate         *priv = NM_DEVICE_WIFI_GET_PRIVATE(self);
     NMSettingWirelessWakeOnWLan  wowl;
     _NMSettingWirelessWakeOnWLan wowl2;
-    NMSettingWireless *          s_wireless;
+    NMSettingWireless           *s_wireless;
 
     s_wireless = nm_device_get_applied_setting(NM_DEVICE(self), NM_TYPE_SETTING_WIRELESS);
     if (s_wireless) {
@@ -3004,15 +3020,15 @@ found:
 static NMActStageReturn
 act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason)
 {
-    NMDeviceWifi *       self         = NM_DEVICE_WIFI(device);
-    NMDeviceWifiPrivate *priv         = NM_DEVICE_WIFI_GET_PRIVATE(self);
-    NMWifiAP *           ap           = NULL;
+    NMDeviceWifi             *self    = NM_DEVICE_WIFI(device);
+    NMDeviceWifiPrivate      *priv    = NM_DEVICE_WIFI_GET_PRIVATE(self);
+    NMWifiAP                 *ap      = NULL;
     gs_unref_object NMWifiAP *ap_fake = NULL;
-    NMActRequest *            req;
-    NMConnection *            connection;
-    NMSettingWireless *       s_wireless;
-    const char *              mode;
-    const char *              ap_path;
+    NMActRequest             *req;
+    NMConnection             *connection;
+    NMSettingWireless        *s_wireless;
+    const char               *mode;
+    const char               *ap_path;
 
     req = nm_device_get_act_request(NM_DEVICE(self));
     g_return_val_if_fail(req, NM_ACT_STAGE_RETURN_FAILURE);
@@ -3087,8 +3103,8 @@ act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason)
 static void
 ensure_hotspot_frequency(NMDeviceWifi *self, NMSettingWireless *s_wifi, NMWifiAP *ap)
 {
-    NMDevice *    device     = NM_DEVICE(self);
-    const char *  band       = nm_setting_wireless_get_band(s_wifi);
+    NMDevice     *device     = NM_DEVICE(self);
+    const char   *band       = nm_setting_wireless_get_band(s_wifi);
     const guint32 a_freqs[]  = {5180, 5200, 5220, 5745, 5765, 5785, 5805, 0};
     const guint32 bg_freqs[] = {2412, 2437, 2462, 2472, 0};
     guint32       freq       = 0;
@@ -3117,8 +3133,8 @@ ensure_hotspot_frequency(NMDeviceWifi *self, NMSettingWireless *s_wifi, NMWifiAP
 static void
 set_powersave(NMDevice *device)
 {
-    NMDeviceWifi *             self = NM_DEVICE_WIFI(device);
-    NMSettingWireless *        s_wireless;
+    NMDeviceWifi              *self = NM_DEVICE_WIFI(device);
+    NMSettingWireless         *s_wireless;
     NMSettingWirelessPowersave val;
 
     s_wireless = nm_device_get_applied_setting(device, NM_TYPE_SETTING_WIRELESS);
@@ -3148,20 +3164,20 @@ set_powersave(NMDevice *device)
 static NMActStageReturn
 act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason)
 {
-    NMDeviceWifi *       self                  = NM_DEVICE_WIFI(device);
-    NMDeviceWifiPrivate *priv                  = NM_DEVICE_WIFI_GET_PRIVATE(self);
+    NMDeviceWifi                       *self   = NM_DEVICE_WIFI(device);
+    NMDeviceWifiPrivate                *priv   = NM_DEVICE_WIFI_GET_PRIVATE(self);
     gs_unref_object NMSupplicantConfig *config = NULL;
     _NM80211Mode                        ap_mode;
-    NMActRequest *                      req;
-    NMWifiAP *                          ap;
-    NMConnection *                      connection;
-    const char *                        setting_name;
-    NMSettingWireless *                 s_wireless;
-    GError *                            error = NULL;
+    NMActRequest                       *req;
+    NMWifiAP                           *ap;
+    NMConnection                       *connection;
+    const char                         *setting_name;
+    NMSettingWireless                  *s_wireless;
+    GError                             *error = NULL;
     guint                               timeout;
-    NMActRequest *                      request;
-    NMActiveConnection *                master_ac;
-    NMDevice *                          master;
+    NMActRequest                       *request;
+    NMActiveConnection                 *master_ac;
+    NMDevice                           *master;
 
     nm_clear_g_source(&priv->sup_timeout_id);
     nm_clear_g_source(&priv->link_timeout_id);
@@ -3263,20 +3279,24 @@ out_fail:
     return NM_ACT_STAGE_RETURN_FAILURE;
 }
 
-static NMActStageReturn
-act_stage3_ip_config_start(NMDevice *           device,
-                           int                  addr_family,
-                           gpointer *           out_config,
-                           NMDeviceStateReason *out_failure_reason)
+static void
+act_stage3_ip_config(NMDevice *device, int addr_family)
 {
-    gboolean      indicate_addressing_running;
-    NMConnection *connection;
-    const char *  method;
+    NMDeviceWifi        *self = NM_DEVICE_WIFI(device);
+    NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self);
+    const char          *method;
+    gboolean             indicate_addressing_running;
+
+    if (priv->addressing_running_indicated)
+        return;
 
-    connection = nm_device_get_applied_connection(device);
+    /* we always set the flag, even if we don't indicate it below. The reason
+     * is that we always want to *clear* the flag after we are done (as we don't
+     * know whether it isn't already set on the interface).  */
+    priv->addressing_running_indicated = TRUE;
 
-    method = nm_utils_get_ip_config_method(connection, addr_family);
-    if (addr_family == AF_INET)
+    method = nm_utils_get_ip_config_method(nm_device_get_applied_connection(device), addr_family);
+    if (NM_IS_IPv4(addr_family))
         indicate_addressing_running = NM_IN_STRSET(method, NM_SETTING_IP4_CONFIG_METHOD_AUTO);
     else {
         indicate_addressing_running = NM_IN_STRSET(method,
@@ -3284,13 +3304,11 @@ act_stage3_ip_config_start(NMDevice *           device,
                                                    NM_SETTING_IP6_CONFIG_METHOD_DHCP);
     }
 
-    if (indicate_addressing_running)
+    if (indicate_addressing_running) {
         nm_platform_wifi_indicate_addressing_running(nm_device_get_platform(device),
                                                      nm_device_get_ip_ifindex(device),
                                                      TRUE);
-
-    return NM_DEVICE_CLASS(nm_device_wifi_parent_class)
-        ->act_stage3_ip_config_start(device, addr_family, out_config, out_failure_reason);
+    }
 }
 
 static guint32
@@ -3301,90 +3319,18 @@ get_configured_mtu(NMDevice *device, NMDeviceMtuSource *out_source, gboolean *ou
                                                         out_source);
 }
 
-static gboolean
-is_static_wep(NMConnection *connection)
-{
-    NMSettingWirelessSecurity *s_wsec;
-    const char *               str;
-
-    g_return_val_if_fail(connection != NULL, FALSE);
-
-    s_wsec = nm_connection_get_setting_wireless_security(connection);
-    if (!s_wsec)
-        return FALSE;
-
-    str = nm_setting_wireless_security_get_key_mgmt(s_wsec);
-    if (g_strcmp0(str, "none") != 0)
-        return FALSE;
-
-    str = nm_setting_wireless_security_get_auth_alg(s_wsec);
-    if (g_strcmp0(str, "leap") == 0)
-        return FALSE;
-
-    return TRUE;
-}
-
-static NMActStageReturn
-act_stage4_ip_config_timeout(NMDevice *           device,
-                             int                  addr_family,
-                             NMDeviceStateReason *out_failure_reason)
-{
-    NMDeviceWifi *       self = NM_DEVICE_WIFI(device);
-    NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self);
-    NMConnection *       connection;
-    NMSettingIPConfig *  s_ip;
-    gboolean             may_fail;
-
-    connection = nm_device_get_applied_connection(device);
-    s_ip       = nm_connection_get_setting_ip_config(connection, addr_family);
-    may_fail   = nm_setting_ip_config_get_may_fail(s_ip);
-
-    if (priv->mode == _NM_802_11_MODE_AP)
-        goto call_parent;
-
-    if (may_fail || !is_static_wep(connection)) {
-        /* Not static WEP or failure allowed; let superclass handle it */
-        goto call_parent;
-    }
-
-    /* If IP configuration times out and it's a static WEP connection, that
-     * usually means the WEP key is wrong.  WEP's Open System auth mode has
-     * no provision for figuring out if the WEP key is wrong, so you just have
-     * to wait for DHCP to fail to figure it out.  For all other Wi-Fi security
-     * types (open, WPA, 802.1x, etc) if the secrets/certs were wrong the
-     * connection would have failed before IP configuration.
-     *
-     * Activation failed, we must have bad encryption key */
-    _LOGW(LOGD_DEVICE | LOGD_WIFI,
-          "Activation: (wifi) could not get IP configuration for connection '%s'.",
-          nm_connection_get_id(connection));
-
-    if (!handle_auth_or_fail(self, NULL, TRUE)) {
-        NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_NO_SECRETS);
-        return NM_ACT_STAGE_RETURN_FAILURE;
-    }
-
-    _LOGI(LOGD_DEVICE | LOGD_WIFI, "Activation: (wifi) asking for new secrets");
-    return NM_ACT_STAGE_RETURN_POSTPONE;
-
-call_parent:
-    return NM_DEVICE_CLASS(nm_device_wifi_parent_class)
-        ->act_stage4_ip_config_timeout(device, addr_family, out_failure_reason);
-}
-
 static void
 activation_success_handler(NMDevice *device)
 {
-    NMDeviceWifi *       self    = NM_DEVICE_WIFI(device);
+    NMDeviceWifi        *self    = NM_DEVICE_WIFI(device);
     NMDeviceWifiPrivate *priv    = NM_DEVICE_WIFI_GET_PRIVATE(self);
     int                  ifindex = nm_device_get_ifindex(device);
-    NMActRequest *       req;
+    NMActRequest        *req;
 
     req = nm_device_get_act_request(device);
     g_assert(req);
 
-    /* Clear any critical protocol notification in the wifi stack */
-    nm_platform_wifi_indicate_addressing_running(nm_device_get_platform(device), ifindex, FALSE);
+    _indicate_addressing_running_reset(self);
 
     /* There should always be a current AP, either a fake one because we haven't
      * seen a scan result for the activated AP yet, or a real one from the
@@ -3439,12 +3385,12 @@ activation_success_handler(NMDevice *device)
 }
 
 static void
-device_state_changed(NMDevice *          device,
+device_state_changed(NMDevice           *device,
                      NMDeviceState       new_state,
                      NMDeviceState       old_state,
                      NMDeviceStateReason reason)
 {
-    NMDeviceWifi *       self      = NM_DEVICE_WIFI(device);
+    NMDeviceWifi        *self      = NM_DEVICE_WIFI(device);
     NMDeviceWifiPrivate *priv      = NM_DEVICE_WIFI_GET_PRIVATE(self);
     gboolean             clear_aps = FALSE;
 
@@ -3484,19 +3430,13 @@ device_state_changed(NMDevice *          device,
             nm_supplicant_interface_disconnect(priv->sup_iface);
         break;
     case NM_DEVICE_STATE_IP_CHECK:
-        /* Clear any critical protocol notification in the wifi stack */
-        nm_platform_wifi_indicate_addressing_running(nm_device_get_platform(device),
-                                                     nm_device_get_ifindex(device),
-                                                     FALSE);
+        _indicate_addressing_running_reset(self);
         break;
     case NM_DEVICE_STATE_ACTIVATED:
         activation_success_handler(device);
         break;
     case NM_DEVICE_STATE_FAILED:
-        /* Clear any critical protocol notification in the wifi stack */
-        nm_platform_wifi_indicate_addressing_running(nm_device_get_platform(device),
-                                                     nm_device_get_ifindex(device),
-                                                     FALSE);
+        _indicate_addressing_running_reset(self);
         break;
     case NM_DEVICE_STATE_DISCONNECTED:
         break;
@@ -3519,7 +3459,7 @@ get_enabled(NMDevice *device)
 static void
 set_enabled(NMDevice *device, gboolean enabled)
 {
-    NMDeviceWifi *       self = NM_DEVICE_WIFI(device);
+    NMDeviceWifi        *self = NM_DEVICE_WIFI(device);
     NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self);
     NMDeviceState        state;
 
@@ -3573,19 +3513,19 @@ set_enabled(NMDevice *device, gboolean enabled)
 static gboolean
 get_guessed_metered(NMDevice *device)
 {
-    NMDeviceWifi *       self = NM_DEVICE_WIFI(device);
+    NMDeviceWifi        *self = NM_DEVICE_WIFI(device);
     NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self);
 
     return priv->current_ap && nm_wifi_ap_get_metered(priv->current_ap);
 }
 
 static gboolean
-can_reapply_change(NMDevice *  device,
+can_reapply_change(NMDevice   *device,
                    const char *setting_name,
-                   NMSetting * s_old,
-                   NMSetting * s_new,
+                   NMSetting  *s_old,
+                   NMSetting  *s_new,
                    GHashTable *diffs,
-                   GError **   error)
+                   GError    **error)
 {
     NMDeviceClass *device_class;
 
@@ -3623,9 +3563,9 @@ reapply_connection(NMDevice *device, NMConnection *con_old, NMConnection *con_ne
 static void
 get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
 {
-    NMDeviceWifi *       self = NM_DEVICE_WIFI(object);
+    NMDeviceWifi        *self = NM_DEVICE_WIFI(object);
     NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self);
-    const char **        list;
+    const char         **list;
 
     switch (prop_id) {
     case PROP_MODE:
@@ -3664,7 +3604,7 @@ get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
 static void
 set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
 {
-    NMDeviceWifi *       device = NM_DEVICE_WIFI(object);
+    NMDeviceWifi        *device = NM_DEVICE_WIFI(object);
     NMDeviceWifiPrivate *priv   = NM_DEVICE_WIFI_GET_PRIVATE(device);
 
     switch (prop_id) {
@@ -3699,7 +3639,7 @@ nm_device_wifi_init(NMDeviceWifi *self)
 static void
 constructed(GObject *object)
 {
-    NMDeviceWifi *       self = NM_DEVICE_WIFI(object);
+    NMDeviceWifi        *self = NM_DEVICE_WIFI(object);
     NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self);
 
     G_OBJECT_CLASS(nm_device_wifi_parent_class)->constructed(object);
@@ -3733,7 +3673,7 @@ nm_device_wifi_new(const char *iface, _NMDeviceWifiCapabilities capabilities)
 static void
 dispose(GObject *object)
 {
-    NMDeviceWifi *       self = NM_DEVICE_WIFI(object);
+    NMDeviceWifi        *self = NM_DEVICE_WIFI(object);
     NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self);
 
     nm_assert(c_list_is_empty(&priv->scanning_prohibited_lst_head));
@@ -3762,7 +3702,7 @@ dispose(GObject *object)
 static void
 finalize(GObject *object)
 {
-    NMDeviceWifi *       self = NM_DEVICE_WIFI(object);
+    NMDeviceWifi        *self = NM_DEVICE_WIFI(object);
     NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self);
 
     nm_assert(c_list_is_empty(&priv->aps_lst_head));
@@ -3776,9 +3716,9 @@ finalize(GObject *object)
 static void
 nm_device_wifi_class_init(NMDeviceWifiClass *klass)
 {
-    GObjectClass *     object_class      = G_OBJECT_CLASS(klass);
+    GObjectClass      *object_class      = G_OBJECT_CLASS(klass);
     NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(klass);
-    NMDeviceClass *    device_class      = NM_DEVICE_CLASS(klass);
+    NMDeviceClass     *device_class      = NM_DEVICE_CLASS(klass);
 
     object_class->constructed  = constructed;
     object_class->get_property = get_property;
@@ -3803,17 +3743,16 @@ nm_device_wifi_class_init(NMDeviceWifiClass *klass)
     device_class->get_guessed_metered         = get_guessed_metered;
     device_class->set_enabled                 = set_enabled;
 
-    device_class->act_stage1_prepare           = act_stage1_prepare;
-    device_class->act_stage2_config            = act_stage2_config;
-    device_class->get_configured_mtu           = get_configured_mtu;
-    device_class->act_stage3_ip_config_start   = act_stage3_ip_config_start;
-    device_class->act_stage4_ip_config_timeout = act_stage4_ip_config_timeout;
-    device_class->deactivate_async             = deactivate_async;
-    device_class->deactivate                   = deactivate;
-    device_class->deactivate_reset_hw_addr     = deactivate_reset_hw_addr;
-    device_class->unmanaged_on_quit            = unmanaged_on_quit;
-    device_class->can_reapply_change           = can_reapply_change;
-    device_class->reapply_connection           = reapply_connection;
+    device_class->act_stage1_prepare       = act_stage1_prepare;
+    device_class->act_stage2_config        = act_stage2_config;
+    device_class->get_configured_mtu       = get_configured_mtu;
+    device_class->act_stage3_ip_config     = act_stage3_ip_config;
+    device_class->deactivate_async         = deactivate_async;
+    device_class->deactivate               = deactivate;
+    device_class->deactivate_reset_hw_addr = deactivate_reset_hw_addr;
+    device_class->unmanaged_on_quit        = unmanaged_on_quit;
+    device_class->can_reapply_change       = can_reapply_change;
+    device_class->reapply_connection       = reapply_connection;
 
     device_class->state_changed = device_state_changed;
 
diff --git a/src/core/devices/wifi/nm-device-wifi.h b/src/core/devices/wifi/nm-device-wifi.h
index c7ff1a14..3a85192e 100644
--- a/src/core/devices/wifi/nm-device-wifi.h
+++ b/src/core/devices/wifi/nm-device-wifi.h
@@ -37,8 +37,8 @@ NMDevice *nm_device_wifi_new(const char *iface, _NMDeviceWifiCapabilities capabi
 
 const CList *_nm_device_wifi_get_aps(NMDeviceWifi *self);
 
-void _nm_device_wifi_request_scan(NMDeviceWifi *         self,
-                                  GVariant *             options,
+void _nm_device_wifi_request_scan(NMDeviceWifi          *self,
+                                  GVariant              *options,
                                   GDBusMethodInvocation *invocation);
 
 GPtrArray *nmtst_ssids_options_to_ptrarray(GVariant *value, GError **error);
diff --git a/src/core/devices/wifi/nm-iwd-manager.c b/src/core/devices/wifi/nm-iwd-manager.c
index 56386c57..5563ebf8 100644
--- a/src/core/devices/wifi/nm-iwd-manager.c
+++ b/src/core/devices/wifi/nm-iwd-manager.c
@@ -15,6 +15,7 @@
 #include "libnm-core-intern/nm-core-internal.h"
 #include "nm-manager.h"
 #include "nm-device-iwd.h"
+#include "nm-device-iwd-p2p.h"
 #include "nm-wifi-utils.h"
 #include "libnm-glib-aux/nm-uuid.h"
 #include "libnm-glib-aux/nm-random-utils.h"
@@ -25,30 +26,42 @@
 
 /*****************************************************************************/
 
+enum {
+    P2P_DEVICE_ADDED,
+
+    LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
 typedef struct {
-    const char *         name;
+    const char          *name;
     NMIwdNetworkSecurity security;
     char                 buf[0];
 } KnownNetworkId;
 
 typedef struct {
-    GDBusProxy *          known_network;
+    GDBusProxy           *known_network;
     NMSettingsConnection *mirror_connection;
     const KnownNetworkId *id;
 } KnownNetworkData;
 
 typedef struct {
-    NMManager *         manager;
-    NMSettings *        settings;
-    GCancellable *      cancellable;
+    NMManager          *manager;
+    NMSettings         *settings;
+    GCancellable       *cancellable;
     gboolean            running;
     GDBusObjectManager *object_manager;
     guint               agent_id;
-    char *              agent_path;
-    GHashTable *        known_networks;
-    NMDeviceIwd *       last_agent_call_device;
-    char *              last_state_dir;
-    char *              warned_state_dir;
+    char               *agent_path;
+    GHashTable         *known_networks;
+    NMDeviceIwd        *last_agent_call_device;
+    char               *last_state_dir;
+    char               *warned_state_dir;
+    bool                netconfig_enabled;
+    GHashTable         *p2p_devices;
+    NMIwdWfdInfo        wfd_info;
+    guint               wfd_use_count;
 } NMIwdManagerPrivate;
 
 struct _NMIwdManager {
@@ -98,7 +111,7 @@ G_DEFINE_TYPE(NMIwdManager, nm_iwd_manager, G_TYPE_OBJECT)
 /*****************************************************************************/
 
 static void mirror_connection_take_and_delete(NMSettingsConnection *sett_conn,
-                                              KnownNetworkData *    data);
+                                              KnownNetworkData     *data);
 
 /*****************************************************************************/
 
@@ -146,10 +159,10 @@ get_property_bool(GDBusProxy *proxy, const char *property, gboolean default_val)
 static NMDeviceIwd *
 get_device_from_network(NMIwdManager *self, GDBusProxy *network)
 {
-    NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self);
-    const char *         ifname;
-    const char *         device_path;
-    NMDevice *           device;
+    NMIwdManagerPrivate            *priv = NM_IWD_MANAGER_GET_PRIVATE(self);
+    const char                     *ifname;
+    const char                     *device_path;
+    NMDevice                       *device;
     gs_unref_object GDBusInterface *device_obj = NULL;
 
     /* Try not to rely on the path of the Device being a prefix of the
@@ -182,21 +195,21 @@ get_device_from_network(NMIwdManager *self, GDBusProxy *network)
 }
 
 static void
-agent_dbus_method_cb(GDBusConnection *      connection,
-                     const char *           sender,
-                     const char *           object_path,
-                     const char *           interface_name,
-                     const char *           method_name,
-                     GVariant *             parameters,
+agent_dbus_method_cb(GDBusConnection       *connection,
+                     const char            *sender,
+                     const char            *object_path,
+                     const char            *interface_name,
+                     const char            *method_name,
+                     GVariant              *parameters,
                      GDBusMethodInvocation *invocation,
                      gpointer               user_data)
 {
-    NMIwdManager *       self = user_data;
-    NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self);
-    const char *         network_path;
-    NMDeviceIwd *        device;
-    gs_free char *       name_owner         = NULL;
-    gs_unref_object GDBusInterface *network = NULL;
+    NMIwdManager                   *self = user_data;
+    NMIwdManagerPrivate            *priv = NM_IWD_MANAGER_GET_PRIVATE(self);
+    const char                     *network_path;
+    NMDeviceIwd                    *device;
+    gs_free char                   *name_owner = NULL;
+    gs_unref_object GDBusInterface *network    = NULL;
 
     /* Be paranoid and check the sender address */
     name_owner = g_dbus_object_manager_client_get_name_owner(
@@ -315,7 +328,7 @@ static void
 register_agent(NMIwdManager *self)
 {
     NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self);
-    GDBusInterface *     agent_manager;
+    GDBusInterface      *agent_manager;
 
     agent_manager = g_dbus_object_manager_get_interface(priv->object_manager,
                                                         "/net/connman/iwd", /* IWD 1.0+ */
@@ -388,9 +401,9 @@ static void
 set_device_dbus_object(NMIwdManager *self, GDBusProxy *proxy, GDBusObject *object)
 {
     NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self);
-    const char *         ifname;
+    const char          *ifname;
     int                  ifindex;
-    NMDevice *           device;
+    NMDevice            *device;
     int                  errsv;
 
     ifname = get_property_string_or_null(proxy, "Name");
@@ -420,10 +433,70 @@ set_device_dbus_object(NMIwdManager *self, GDBusProxy *proxy, GDBusObject *objec
 }
 
 static void
+add_p2p_device(NMIwdManager *self, GDBusProxy *proxy, GDBusObject *object)
+{
+    NMIwdManagerPrivate            *priv = NM_IWD_MANAGER_GET_PRIVATE(self);
+    const char                     *path = g_dbus_object_get_object_path(object);
+    NMDeviceIwdP2P                 *p2p;
+    gs_unref_object GDBusInterface *wiphy = NULL;
+    const char                     *phy_name;
+
+    if (g_hash_table_contains(priv->p2p_devices, path))
+        return;
+
+    wiphy = g_dbus_object_get_interface(object, NM_IWD_WIPHY_INTERFACE);
+    if (!wiphy)
+        return;
+
+    phy_name = get_property_string_or_null(G_DBUS_PROXY(wiphy), "Name");
+    if (!phy_name) {
+        _LOGE("Name not cached for phy at %s", path);
+        return;
+    }
+
+    p2p = nm_device_iwd_p2p_new(object);
+    if (!p2p) {
+        _LOGE("Can't create NMDeviceIwdP2P for phy at %s", path);
+        return;
+    }
+
+    g_hash_table_insert(priv->p2p_devices, g_strdup(path), p2p);
+    g_signal_emit(self, signals[P2P_DEVICE_ADDED], 0, p2p, phy_name);
+
+    /* There should be no peer objects before the device object appeared so don't
+     * try to look for them and notify the new device.  */
+}
+
+static void
+remove_p2p_device(NMIwdManager *self, GDBusProxy *proxy, GDBusObject *object)
+{
+    NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self);
+    const char          *path = g_dbus_object_get_object_path(object);
+    NMDeviceIwdP2P      *p2p  = g_hash_table_lookup(priv->p2p_devices, path);
+
+    if (!p2p)
+        return;
+
+    g_hash_table_remove(priv->p2p_devices, path);
+}
+
+static NMDeviceIwdP2P *
+get_p2p_device_from_peer(NMIwdManager *self, GDBusProxy *proxy)
+{
+    NMIwdManagerPrivate *priv        = NM_IWD_MANAGER_GET_PRIVATE(self);
+    const char          *device_path = get_property_string_or_null(proxy, "Device");
+
+    if (!device_path)
+        return NULL;
+
+    return g_hash_table_lookup(priv->p2p_devices, device_path);
+}
+
+static void
 known_network_update_cb(GObject *source, GAsyncResult *res, gpointer user_data)
 {
     gs_unref_variant GVariant *variant = NULL;
-    gs_free_error GError *error        = NULL;
+    gs_free_error GError      *error   = NULL;
 
     variant = g_dbus_proxy_call_finish(G_DBUS_PROXY(source), res, &error);
     if (!variant) {
@@ -436,13 +509,13 @@ known_network_update_cb(GObject *source, GAsyncResult *res, gpointer user_data)
 }
 
 static gboolean
-iwd_config_write(GKeyFile *             config,
-                 const char *           filepath,
+iwd_config_write(GKeyFile              *config,
+                 const char            *filepath,
                  const struct timespec *mtime,
-                 GError **              error)
+                 GError               **error)
 {
     gsize           length;
-    gs_free char *  data     = g_key_file_to_data(config, &length, NULL);
+    gs_free char   *data     = g_key_file_to_data(config, &length, NULL);
     struct timespec times[2] = {{.tv_nsec = UTIME_OMIT}, *mtime};
 
     /* Atomically write or replace the file with the right permission bits
@@ -458,7 +531,7 @@ static const char *
 get_config_path(NMIwdManager *self)
 {
     NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self);
-    const char *         path;
+    const char          *path;
 
     path = nm_config_data_get_iwd_config_path(NM_CONFIG_GET_DATA);
     if (path && path[0] == '\0') {
@@ -489,26 +562,26 @@ get_config_path(NMIwdManager *self)
 }
 
 static void
-sett_conn_changed(NMSettingsConnection *  sett_conn,
+sett_conn_changed(NMSettingsConnection   *sett_conn,
                   guint                   update_reason,
                   const KnownNetworkData *data)
 {
-    NMSettingsConnectionIntFlags flags;
-    NMConnection *               conn          = nm_settings_connection_get_connection(sett_conn);
-    NMSettingConnection *        s_conn        = nm_connection_get_setting_connection(conn);
-    NMSettingWireless *          s_wifi        = nm_connection_get_setting_wireless(conn);
+    NMSettingsConnectionIntFlags    flags;
+    NMConnection                   *conn       = nm_settings_connection_get_connection(sett_conn);
+    NMSettingConnection            *s_conn     = nm_connection_get_setting_connection(conn);
+    NMSettingWireless              *s_wifi     = nm_connection_get_setting_wireless(conn);
     nm_auto_unref_keyfile GKeyFile *iwd_config = NULL;
-    const char *                    iwd_dir;
-    gs_free char *                  filename  = NULL;
-    gs_free char *                  full_path = NULL;
-    gs_free_error GError *error               = NULL;
-    NMIwdNetworkSecurity  security;
-    GBytes *              ssid;
-    const guint8 *        ssid_data;
-    gsize                 ssid_len;
-    gboolean              removed;
-    GStatBuf              statbuf;
-    gboolean              have_mtime;
+    const char                     *iwd_dir;
+    gs_free char                   *filename  = NULL;
+    gs_free char                   *full_path = NULL;
+    gs_free_error GError           *error     = NULL;
+    NMIwdNetworkSecurity            security;
+    GBytes                         *ssid;
+    const guint8                   *ssid_data;
+    gsize                           ssid_len;
+    gboolean                        removed;
+    GStatBuf                        statbuf;
+    gboolean                        have_mtime;
 
     nm_assert(sett_conn == data->mirror_connection);
 
@@ -660,24 +733,24 @@ sett_conn_changed(NMSettingsConnection *  sett_conn,
  * from the user.
  */
 static NMSettingsConnection *
-mirror_connection(NMIwdManager *        self,
+mirror_connection(NMIwdManager         *self,
                   const KnownNetworkId *id,
                   gboolean              create_new,
-                  GDBusProxy *          known_network)
+                  GDBusProxy           *known_network)
 {
-    NMIwdManagerPrivate *        priv = NM_IWD_MANAGER_GET_PRIVATE(self);
-    NMSettingsConnection *const *iter;
+    NMIwdManagerPrivate          *priv = NM_IWD_MANAGER_GET_PRIVATE(self);
+    NMSettingsConnection *const  *iter;
     gs_unref_object NMConnection *connection          = NULL;
-    NMSettingsConnection *        settings_connection = NULL;
+    NMSettingsConnection         *settings_connection = NULL;
     char                          uuid[37];
-    NMSetting *                   setting;
-    gs_free_error GError *error            = NULL;
-    gs_unref_bytes GBytes *new_ssid        = NULL;
-    gsize                  ssid_len        = strlen(id->name);
-    gboolean               autoconnectable = TRUE;
-    gboolean               hidden          = FALSE;
-    gboolean               exact_match     = TRUE;
-    const char *           key_mgmt        = NULL;
+    NMSetting                    *setting;
+    gs_free_error GError         *error           = NULL;
+    gs_unref_bytes GBytes        *new_ssid        = NULL;
+    gsize                         ssid_len        = strlen(id->name);
+    gboolean                      autoconnectable = TRUE;
+    gboolean                      hidden          = FALSE;
+    gboolean                      exact_match     = TRUE;
+    const char                   *key_mgmt        = NULL;
 
     if (known_network) {
         autoconnectable = get_property_bool(known_network, "AutoConnect", TRUE);
@@ -686,10 +759,10 @@ mirror_connection(NMIwdManager *        self,
 
     for (iter = nm_settings_get_connections(priv->settings, NULL); *iter; iter++) {
         NMSettingsConnection *sett_conn = *iter;
-        NMConnection *        conn      = nm_settings_connection_get_connection(sett_conn);
+        NMConnection         *conn      = nm_settings_connection_get_connection(sett_conn);
         NMIwdNetworkSecurity  security;
-        NMSettingWireless *   s_wifi;
-        const guint8 *        ssid_bytes;
+        NMSettingWireless    *s_wifi;
+        const guint8         *ssid_bytes;
         gsize                 ssid_len2;
 
         if (!nm_wifi_connection_get_iwd_ssid_and_security(conn, NULL, &security))
@@ -770,7 +843,7 @@ mirror_connection(NMIwdManager *        self,
         if (NM_FLAGS_HAS(flags, NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED)) {
             NMConnection *tmp_conn = nm_settings_connection_get_connection(settings_connection);
             NMSettingConnection *s_conn = nm_connection_get_setting_connection(tmp_conn);
-            NMSettingWireless *  s_wifi = nm_connection_get_setting_wireless(tmp_conn);
+            NMSettingWireless   *s_wifi = nm_connection_get_setting_wireless(tmp_conn);
 
             g_object_set(G_OBJECT(s_conn),
                          NM_SETTING_CONNECTION_AUTOCONNECT,
@@ -912,14 +985,14 @@ mirror_connection_take_and_delete(NMSettingsConnection *sett_conn, KnownNetworkD
 
 static void
 interface_added(GDBusObjectManager *object_manager,
-                GDBusObject *       object,
-                GDBusInterface *    interface,
+                GDBusObject        *object,
+                GDBusInterface     *interface,
                 gpointer            user_data)
 {
-    NMIwdManager *       self = user_data;
+    NMIwdManager        *self = user_data;
     NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self);
-    GDBusProxy *         proxy;
-    const char *         iface_name;
+    GDBusProxy          *proxy;
+    const char          *iface_name;
 
     if (!priv->running)
         return;
@@ -935,11 +1008,11 @@ interface_added(GDBusObjectManager *object_manager,
     }
 
     if (nm_streq(iface_name, NM_IWD_KNOWN_NETWORK_INTERFACE)) {
-        KnownNetworkId *      id;
-        KnownNetworkId *      orig_id;
-        KnownNetworkData *    data;
+        KnownNetworkId       *id;
+        KnownNetworkId       *orig_id;
+        KnownNetworkData     *data;
         NMIwdNetworkSecurity  security;
-        const char *          type_str, *name;
+        const char           *type_str, *name;
         NMSettingsConnection *sett_conn = NULL;
 
         type_str = get_property_string_or_null(proxy, "Type");
@@ -998,18 +1071,34 @@ interface_added(GDBusObjectManager *object_manager,
 
         return;
     }
+
+    if (nm_streq(iface_name, NM_IWD_P2P_INTERFACE)) {
+        add_p2p_device(self, proxy, object);
+        return;
+    }
+
+    if (nm_streq(iface_name, NM_IWD_P2P_PEER_INTERFACE)) {
+        NMDeviceIwdP2P *p2p = get_p2p_device_from_peer(self, proxy);
+
+        /* This is more conveniently done with a direct call than a signal because
+         * this way we only notify the interested NMDeviceIwdP2P.  */
+        if (p2p)
+            nm_device_iwd_p2p_peer_add_remove(p2p, object, TRUE);
+
+        return;
+    }
 }
 
 static void
 interface_removed(GDBusObjectManager *object_manager,
-                  GDBusObject *       object,
-                  GDBusInterface *    interface,
+                  GDBusObject        *object,
+                  GDBusInterface     *interface,
                   gpointer            user_data)
 {
-    NMIwdManager *       self = user_data;
+    NMIwdManager        *self = user_data;
     NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self);
-    GDBusProxy *         proxy;
-    const char *         iface_name;
+    GDBusProxy          *proxy;
+    const char          *iface_name;
 
     g_return_if_fail(G_IS_DBUS_PROXY(interface));
 
@@ -1023,7 +1112,7 @@ interface_removed(GDBusObjectManager *object_manager,
 
     if (nm_streq(iface_name, NM_IWD_KNOWN_NETWORK_INTERFACE)) {
         KnownNetworkId id;
-        const char *   type_str;
+        const char    *type_str;
 
         type_str = get_property_string_or_null(proxy, "Type");
         id.name  = get_property_string_or_null(proxy, "Name");
@@ -1051,6 +1140,20 @@ interface_removed(GDBusObjectManager *object_manager,
 
         return;
     }
+
+    if (nm_streq(iface_name, NM_IWD_P2P_INTERFACE)) {
+        remove_p2p_device(self, proxy, object);
+        return;
+    }
+
+    if (nm_streq(iface_name, NM_IWD_P2P_PEER_INTERFACE)) {
+        NMDeviceIwdP2P *p2p = get_p2p_device_from_peer(self, proxy);
+
+        if (p2p)
+            nm_device_iwd_p2p_peer_add_remove(p2p, object, FALSE);
+
+        return;
+    }
 }
 
 static void
@@ -1088,19 +1191,19 @@ object_removed(GDBusObjectManager *object_manager, GDBusObject *object, gpointer
 static void
 connection_removed(NMSettings *settings, NMSettingsConnection *sett_conn, gpointer user_data)
 {
-    NMIwdManager *        self = user_data;
-    NMIwdManagerPrivate * priv = NM_IWD_MANAGER_GET_PRIVATE(self);
-    NMConnection *        conn = nm_settings_connection_get_connection(sett_conn);
-    NMSettingWireless *   s_wireless;
-    KnownNetworkData *    data;
+    NMIwdManager         *self = user_data;
+    NMIwdManagerPrivate  *priv = NM_IWD_MANAGER_GET_PRIVATE(self);
+    NMConnection         *conn = nm_settings_connection_get_connection(sett_conn);
+    NMSettingWireless    *s_wireless;
+    KnownNetworkData     *data;
     KnownNetworkId        id;
     char                  ssid_buf[33];
-    const guint8 *        ssid_bytes;
+    const guint8         *ssid_bytes;
     gsize                 ssid_len;
     NMSettingsConnection *new_mirror_conn;
-    const char *          iwd_dir;
-    gs_free char *        filename  = NULL;
-    gs_free char *        full_path = NULL;
+    const char           *iwd_dir;
+    gs_free char         *filename  = NULL;
+    gs_free char         *full_path = NULL;
 
     if (!nm_wifi_connection_get_iwd_ssid_and_security(conn, NULL, &id.security))
         return;
@@ -1170,13 +1273,13 @@ try_delete_file:
 static void
 connection_added(NMSettings *settings, NMSettingsConnection *sett_conn, gpointer user_data)
 {
-    NMIwdManager *       self   = user_data;
-    NMConnection *       conn   = nm_settings_connection_get_connection(sett_conn);
-    NMSettingConnection *s_conn = nm_connection_get_setting_connection(conn);
-    const char *         iwd_dir;
-    gs_free char *       filename              = NULL;
-    gs_free char *       full_path             = NULL;
-    gs_free_error GError *error                = NULL;
+    NMIwdManager                   *self   = user_data;
+    NMConnection                   *conn   = nm_settings_connection_get_connection(sett_conn);
+    NMSettingConnection            *s_conn = nm_connection_get_setting_connection(conn);
+    const char                     *iwd_dir;
+    gs_free char                   *filename   = NULL;
+    gs_free char                   *full_path  = NULL;
+    gs_free_error GError           *error      = NULL;
     nm_auto_unref_keyfile GKeyFile *iwd_config = NULL;
     NMSettingsConnectionIntFlags    flags;
 
@@ -1259,7 +1362,7 @@ release_object_manager(NMIwdManager *self)
     g_signal_handlers_disconnect_by_data(priv->object_manager, self);
 
     if (priv->agent_id) {
-        GDBusConnection *         agent_connection;
+        GDBusConnection          *agent_connection;
         GDBusObjectManagerClient *omc = G_DBUS_OBJECT_MANAGER_CLIENT(priv->object_manager);
 
         agent_connection = g_dbus_object_manager_client_get_connection(omc);
@@ -1281,9 +1384,9 @@ static void prepare_object_manager(NMIwdManager *self);
 static void
 name_owner_changed(GObject *object, GParamSpec *pspec, gpointer user_data)
 {
-    NMIwdManager *       self           = user_data;
+    NMIwdManager        *self           = user_data;
     NMIwdManagerPrivate *priv           = NM_IWD_MANAGER_GET_PRIVATE(self);
-    GDBusObjectManager * object_manager = G_DBUS_OBJECT_MANAGER(object);
+    GDBusObjectManager  *object_manager = G_DBUS_OBJECT_MANAGER(object);
 
     nm_assert(object_manager == priv->object_manager);
 
@@ -1292,7 +1395,7 @@ name_owner_changed(GObject *object, GParamSpec *pspec, gpointer user_data)
         prepare_object_manager(self);
     } else {
         const CList *tmp_lst;
-        NMDevice *   device;
+        NMDevice    *device;
 
         if (!priv->running)
             return;
@@ -1310,9 +1413,9 @@ name_owner_changed(GObject *object, GParamSpec *pspec, gpointer user_data)
 static void
 device_added(NMManager *manager, NMDevice *device, gpointer user_data)
 {
-    NMIwdManager *       self = user_data;
+    NMIwdManager        *self = user_data;
     NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self);
-    GList *              objects, *iter;
+    GList               *objects, *iter;
 
     if (!NM_IS_DEVICE_IWD(device))
         return;
@@ -1331,7 +1434,7 @@ device_added(NMManager *manager, NMDevice *device, gpointer user_data)
     objects = g_dbus_object_manager_get_objects(priv->object_manager);
 
     for (iter = objects; iter; iter = iter->next) {
-        GDBusObject *   object                    = G_DBUS_OBJECT(iter->data);
+        GDBusObject                    *object    = G_DBUS_OBJECT(iter->data);
         gs_unref_object GDBusInterface *interface = NULL;
 
         interface = g_dbus_object_get_interface(object, NM_IWD_NETWORK_INTERFACE);
@@ -1343,9 +1446,9 @@ device_added(NMManager *manager, NMDevice *device, gpointer user_data)
     }
 
     for (iter = objects; iter; iter = iter->next) {
-        GDBusObject *   object                    = G_DBUS_OBJECT(iter->data);
+        GDBusObject                    *object    = G_DBUS_OBJECT(iter->data);
         gs_unref_object GDBusInterface *interface = NULL;
-        const char *                    obj_ifname;
+        const char                     *obj_ifname;
 
         interface  = g_dbus_object_get_interface(object, NM_IWD_DEVICE_INTERFACE);
         obj_ifname = get_property_string_or_null((GDBusProxy *) interface, "Name");
@@ -1363,7 +1466,7 @@ device_added(NMManager *manager, NMDevice *device, gpointer user_data)
 static void
 device_removed(NMManager *manager, NMDevice *device, gpointer user_data)
 {
-    NMIwdManager *       self = user_data;
+    NMIwdManager        *self = user_data;
     NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self);
 
     if (!NM_IS_DEVICE_IWD(device))
@@ -1431,13 +1534,13 @@ object_compare_interfaces(gconstpointer a, gconstpointer b)
 static void
 get_daemon_info_cb(GObject *source, GAsyncResult *res, gpointer user_data)
 {
-    NMIwdManager *       self = user_data;
-    NMIwdManagerPrivate *priv;
+    NMIwdManager              *self = user_data;
+    NMIwdManagerPrivate       *priv;
     gs_unref_variant GVariant *properties = NULL;
-    gs_free_error GError *error           = NULL;
-    GVariantIter *        properties_iter;
-    const char *          key;
-    GVariant *            value;
+    gs_free_error GError      *error      = NULL;
+    GVariantIter              *properties_iter;
+    const char                *key;
+    GVariant                  *value;
 
     properties = g_dbus_proxy_call_finish(G_DBUS_PROXY(source), res, &error);
     if (!properties) {
@@ -1469,6 +1572,15 @@ get_daemon_info_cb(GObject *source, GAsyncResult *res, gpointer user_data)
 
             nm_clear_g_free(&priv->last_state_dir);
             priv->last_state_dir = g_variant_dup_string(value, NULL);
+        } else if (nm_streq(key, "NetworkConfigurationEnabled")) {
+            if (!g_variant_is_of_type(value, G_VARIANT_TYPE_BOOLEAN)) {
+                _LOGE("Daemon.GetInfo property %s is typed '%s' instead of 'b'",
+                      key,
+                      g_variant_get_type_string(value));
+                goto next;
+            }
+
+            priv->netconfig_enabled = g_variant_get_boolean(value);
         }
 
 next:
@@ -1481,11 +1593,11 @@ next:
 static void
 got_object_manager(GObject *object, GAsyncResult *result, gpointer user_data)
 {
-    NMIwdManager *       self  = user_data;
+    NMIwdManager        *self  = user_data;
     NMIwdManagerPrivate *priv  = NM_IWD_MANAGER_GET_PRIVATE(self);
-    GError *             error = NULL;
-    GDBusObjectManager * object_manager;
-    GDBusConnection *    connection;
+    GError              *error = NULL;
+    GDBusObjectManager  *object_manager;
+    GDBusConnection     *connection;
 
     object_manager = g_dbus_object_manager_client_new_for_bus_finish(result, &error);
     if (object_manager == NULL) {
@@ -1515,7 +1627,7 @@ got_object_manager(GObject *object, GAsyncResult *result, gpointer user_data)
     }
 
     if (_om_has_name_owner(object_manager)) {
-        GList *         objects, *iter;
+        GList                          *objects, *iter;
         gs_unref_object GDBusInterface *daemon = NULL;
 
         priv->running = true;
@@ -1543,6 +1655,8 @@ got_object_manager(GObject *object, GAsyncResult *result, gpointer user_data)
         if (priv->agent_id)
             register_agent(self);
 
+        priv->netconfig_enabled = false; /* Assume false until GetInfo() results come in */
+
         daemon = g_dbus_object_manager_get_interface(object_manager,
                                                      "/net/connman/iwd", /* IWD 1.15+ */
                                                      NM_IWD_DAEMON_INTERFACE);
@@ -1587,11 +1701,11 @@ nm_iwd_manager_is_known_network(NMIwdManager *self, const char *name, NMIwdNetwo
 NMSettingsConnection *
 nm_iwd_manager_get_ap_mirror_connection(NMIwdManager *self, NMWifiAP *ap)
 {
-    NMIwdManagerPrivate *  priv = NM_IWD_MANAGER_GET_PRIVATE(self);
-    KnownNetworkData *     data;
+    NMIwdManagerPrivate   *priv = NM_IWD_MANAGER_GET_PRIVATE(self);
+    KnownNetworkData      *data;
     char                   name_buf[33];
     KnownNetworkId         kn_id = {name_buf, NM_IWD_NETWORK_SECURITY_OPEN};
-    const guint8 *         ssid_bytes;
+    const guint8          *ssid_bytes;
     gsize                  ssid_len;
     NM80211ApFlags         flags     = nm_wifi_ap_get_flags(ap);
     NM80211ApSecurityFlags sec_flags = nm_wifi_ap_get_wpa_flags(ap) | nm_wifi_ap_get_rsn_flags(ap);
@@ -1629,7 +1743,7 @@ GDBusProxy *
 nm_iwd_manager_get_dbus_interface(NMIwdManager *self, const char *path, const char *name)
 {
     NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self);
-    GDBusInterface *     interface;
+    GDBusInterface      *interface;
 
     if (!priv->object_manager)
         return NULL;
@@ -1639,6 +1753,121 @@ nm_iwd_manager_get_dbus_interface(NMIwdManager *self, const char *path, const ch
     return interface ? G_DBUS_PROXY(interface) : NULL;
 }
 
+gboolean
+nm_iwd_manager_get_netconfig_enabled(NMIwdManager *self)
+{
+    NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self);
+
+    return priv->netconfig_enabled;
+}
+
+/* IWD's net.connman.iwd.p2p.ServiceManager.RegisterDisplayService() is global so
+ * two local Wi-Fi P2P devices can't be connected to (or even scanning for) WFD
+ * peers using different WFD IE contents, e.g. one as a sink and one as a source.
+ * If one device is connected to a peer without a WFD service, another can try
+ * to establish a WFD connection to a peer since this won't disturb the first
+ * connection.  Similarly if one device is connected to a peer with WFD, another
+ * can make a connection to a non-WFD peer (if that exists...) because a non-WFD
+ * peer will simply ignore the WFD IEs, but it cannot connect to or search for a
+ * peer that's WFD capable without passing our own WFD IEs, i.e. if the new
+ * NMSettingsConnection has no WFD IEs and we're already in a WFD connection on
+ * another device, we can't activate that new connection.  We expose methods
+ * for the NMDeviceIwdP2P's to register/unregister the service and one to check
+ * if there's already an incompatible connection active.
+ */
+gboolean
+nm_iwd_manager_check_wfd_info_compatible(NMIwdManager *self, const NMIwdWfdInfo *wfd_info)
+{
+    NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self);
+
+    if (priv->wfd_use_count == 0)
+        return TRUE;
+
+    return nm_wifi_utils_wfd_info_eq(&priv->wfd_info, wfd_info);
+}
+
+gboolean
+nm_iwd_manager_register_wfd(NMIwdManager *self, const NMIwdWfdInfo *wfd_info)
+{
+    NMIwdManagerPrivate            *priv            = NM_IWD_MANAGER_GET_PRIVATE(self);
+    gs_unref_object GDBusInterface *service_manager = NULL;
+    GVariantBuilder                 builder;
+
+    nm_assert(nm_iwd_manager_check_wfd_info_compatible(self, wfd_info));
+
+    if (!priv->object_manager)
+        return FALSE;
+
+    service_manager = g_dbus_object_manager_get_interface(priv->object_manager,
+                                                          "/net/connman/iwd",
+                                                          NM_IWD_P2P_SERVICE_MANAGER_INTERFACE);
+    if (!service_manager) {
+        _LOGE("IWD P2P service manager not found");
+        return FALSE;
+    }
+
+    g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT);
+    g_variant_builder_add(&builder, "{sv}", "Source", g_variant_new_boolean(wfd_info->source));
+    g_variant_builder_add(&builder, "{sv}", "Sink", g_variant_new_boolean(wfd_info->sink));
+
+    if (wfd_info->source)
+        g_variant_builder_add(&builder, "{sv}", "Port", g_variant_new_uint16(wfd_info->port));
+
+    if (wfd_info->sink && wfd_info->has_audio)
+        g_variant_builder_add(&builder, "{sv}", "HasAudio", g_variant_new_boolean(TRUE));
+
+    if (wfd_info->has_uibc)
+        g_variant_builder_add(&builder, "{sv}", "HasUIBC", g_variant_new_boolean(TRUE));
+
+    if (wfd_info->has_cp)
+        g_variant_builder_add(&builder,
+                              "{sv}",
+                              "HasContentProtection",
+                              g_variant_new_boolean(TRUE));
+
+    g_dbus_proxy_call(G_DBUS_PROXY(service_manager),
+                      "RegisterDisplayService",
+                      g_variant_new("(a{sv})", &builder),
+                      G_DBUS_CALL_FLAGS_NONE,
+                      -1,
+                      NULL,
+                      NULL,
+                      NULL);
+
+    memcpy(&priv->wfd_info, wfd_info, sizeof(priv->wfd_info));
+    priv->wfd_use_count++;
+    return TRUE;
+}
+
+void
+nm_iwd_manager_unregister_wfd(NMIwdManager *self)
+{
+    NMIwdManagerPrivate            *priv            = NM_IWD_MANAGER_GET_PRIVATE(self);
+    gs_unref_object GDBusInterface *service_manager = NULL;
+
+    nm_assert(priv->wfd_use_count > 0);
+
+    priv->wfd_use_count--;
+
+    if (!priv->object_manager)
+        return;
+
+    service_manager = g_dbus_object_manager_get_interface(priv->object_manager,
+                                                          "/net/connman/iwd",
+                                                          NM_IWD_P2P_SERVICE_MANAGER_INTERFACE);
+    if (!service_manager)
+        return;
+
+    g_dbus_proxy_call(G_DBUS_PROXY(service_manager),
+                      "UnregisterDisplayService",
+                      g_variant_new("()"),
+                      G_DBUS_CALL_FLAGS_NONE,
+                      -1,
+                      NULL,
+                      NULL,
+                      NULL);
+}
+
 /*****************************************************************************/
 
 NM_DEFINE_SINGLETON_GETTER(NMIwdManager, nm_iwd_manager_get, NM_TYPE_IWD_MANAGER);
@@ -1685,13 +1914,15 @@ nm_iwd_manager_init(NMIwdManager *self)
                                                  g_free,
                                                  (GDestroyNotify) known_network_data_free);
 
+    priv->p2p_devices = g_hash_table_new_full(nm_str_hash, g_str_equal, g_free, g_object_unref);
+
     prepare_object_manager(self);
 }
 
 static void
 dispose(GObject *object)
 {
-    NMIwdManager *       self = (NMIwdManager *) object;
+    NMIwdManager        *self = (NMIwdManager *) object;
     NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self);
 
     release_object_manager(self);
@@ -1718,6 +1949,8 @@ dispose(GObject *object)
     nm_clear_g_free(&priv->last_state_dir);
     nm_clear_g_free(&priv->warned_state_dir);
 
+    g_hash_table_unref(nm_steal_pointer(&priv->p2p_devices));
+
     G_OBJECT_CLASS(nm_iwd_manager_parent_class)->dispose(object);
 }
 
@@ -1727,4 +1960,16 @@ nm_iwd_manager_class_init(NMIwdManagerClass *klass)
     GObjectClass *object_class = G_OBJECT_CLASS(klass);
 
     object_class->dispose = dispose;
+
+    signals[P2P_DEVICE_ADDED] = g_signal_new(NM_IWD_MANAGER_P2P_DEVICE_ADDED,
+                                             G_OBJECT_CLASS_TYPE(object_class),
+                                             G_SIGNAL_RUN_LAST,
+                                             0,
+                                             NULL,
+                                             NULL,
+                                             NULL,
+                                             G_TYPE_NONE,
+                                             2,
+                                             NM_TYPE_DEVICE,
+                                             G_TYPE_STRING);
 }
diff --git a/src/core/devices/wifi/nm-iwd-manager.h b/src/core/devices/wifi/nm-iwd-manager.h
index e794e661..02cd6bba 100644
--- a/src/core/devices/wifi/nm-iwd-manager.h
+++ b/src/core/devices/wifi/nm-iwd-manager.h
@@ -13,18 +13,22 @@
 #define NM_IWD_BUS_TYPE G_BUS_TYPE_SYSTEM
 #define NM_IWD_SERVICE  "net.connman.iwd"
 
-#define NM_IWD_DAEMON_INTERFACE        "net.connman.iwd.Daemon"
-#define NM_IWD_AGENT_MANAGER_INTERFACE "net.connman.iwd.AgentManager"
-#define NM_IWD_WIPHY_INTERFACE         "net.connman.iwd.Adapter"
-#define NM_IWD_DEVICE_INTERFACE        "net.connman.iwd.Device"
-#define NM_IWD_NETWORK_INTERFACE       "net.connman.iwd.Network"
-#define NM_IWD_AGENT_INTERFACE         "net.connman.iwd.Agent"
-#define NM_IWD_WSC_INTERFACE           "net.connman.iwd.WiFiSimpleConfiguration"
-#define NM_IWD_KNOWN_NETWORK_INTERFACE "net.connman.iwd.KnownNetwork"
-#define NM_IWD_SIGNAL_AGENT_INTERFACE  "net.connman.iwd.SignalLevelAgent"
-#define NM_IWD_AP_INTERFACE            "net.connman.iwd.AccessPoint"
-#define NM_IWD_ADHOC_INTERFACE         "net.connman.iwd.AdHoc"
-#define NM_IWD_STATION_INTERFACE       "net.connman.iwd.Station"
+#define NM_IWD_DAEMON_INTERFACE              "net.connman.iwd.Daemon"
+#define NM_IWD_AGENT_MANAGER_INTERFACE       "net.connman.iwd.AgentManager"
+#define NM_IWD_WIPHY_INTERFACE               "net.connman.iwd.Adapter"
+#define NM_IWD_DEVICE_INTERFACE              "net.connman.iwd.Device"
+#define NM_IWD_NETWORK_INTERFACE             "net.connman.iwd.Network"
+#define NM_IWD_AGENT_INTERFACE               "net.connman.iwd.Agent"
+#define NM_IWD_WSC_INTERFACE                 "net.connman.iwd.SimpleConfiguration"
+#define NM_IWD_KNOWN_NETWORK_INTERFACE       "net.connman.iwd.KnownNetwork"
+#define NM_IWD_SIGNAL_AGENT_INTERFACE        "net.connman.iwd.SignalLevelAgent"
+#define NM_IWD_AP_INTERFACE                  "net.connman.iwd.AccessPoint"
+#define NM_IWD_ADHOC_INTERFACE               "net.connman.iwd.AdHoc"
+#define NM_IWD_STATION_INTERFACE             "net.connman.iwd.Station"
+#define NM_IWD_P2P_INTERFACE                 "net.connman.iwd.p2p.Device"
+#define NM_IWD_P2P_PEER_INTERFACE            "net.connman.iwd.p2p.Peer"
+#define NM_IWD_P2P_SERVICE_MANAGER_INTERFACE "net.connman.iwd.p2p.ServiceManager"
+#define NM_IWD_P2P_WFD_INTERFACE             "net.connman.iwd.p2p.Display"
 
 #define NM_TYPE_IWD_MANAGER (nm_iwd_manager_get_type())
 #define NM_IWD_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_IWD_MANAGER, NMIwdManager))
@@ -35,6 +39,8 @@
 #define NM_IWD_MANAGER_GET_CLASS(obj) \
     (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_IWD_MANAGER, NMIwdManagerClass))
 
+#define NM_IWD_MANAGER_P2P_DEVICE_ADDED "p2p-device-added"
+
 typedef struct _NMIwdManager      NMIwdManager;
 typedef struct _NMIwdManagerClass NMIwdManagerClass;
 
@@ -42,8 +48,8 @@ GType nm_iwd_manager_get_type(void);
 
 NMIwdManager *nm_iwd_manager_get(void);
 
-gboolean nm_iwd_manager_is_known_network(NMIwdManager *       self,
-                                         const char *         name,
+gboolean nm_iwd_manager_is_known_network(NMIwdManager        *self,
+                                         const char          *name,
                                          NMIwdNetworkSecurity security);
 
 NMSettingsConnection *nm_iwd_manager_get_ap_mirror_connection(NMIwdManager *self, NMWifiAP *ap);
@@ -51,4 +57,10 @@ NMSettingsConnection *nm_iwd_manager_get_ap_mirror_connection(NMIwdManager *self
 GDBusProxy *
 nm_iwd_manager_get_dbus_interface(NMIwdManager *self, const char *path, const char *name);
 
+gboolean nm_iwd_manager_get_netconfig_enabled(NMIwdManager *self);
+
+gboolean nm_iwd_manager_check_wfd_info_compatible(NMIwdManager *self, const NMIwdWfdInfo *wfd_info);
+gboolean nm_iwd_manager_register_wfd(NMIwdManager *self, const NMIwdWfdInfo *wfd_info);
+void     nm_iwd_manager_unregister_wfd(NMIwdManager *self);
+
 #endif /* __NETWORKMANAGER_IWD_MANAGER_H__ */
diff --git a/src/core/devices/wifi/nm-wifi-ap.c b/src/core/devices/wifi/nm-wifi-ap.c
index 72a60885..ac0b748a 100644
--- a/src/core/devices/wifi/nm-wifi-ap.c
+++ b/src/core/devices/wifi/nm-wifi-ap.c
@@ -41,8 +41,8 @@ NM_GOBJECT_PROPERTIES_DEFINE(NMWifiAP,
 
 struct _NMWifiAPPrivate {
     /* Scanned or cached values */
-    GBytes *     ssid;
-    char *       address;
+    GBytes      *ssid;
+    char        *address;
     _NM80211Mode mode;
     guint8       strength;
     guint32      freq;        /* Frequency in MHz; ie 2412 (== 2.412 GHz) */
@@ -430,7 +430,7 @@ has_proto(NMSettingWirelessSecurity *sec, const char *proto)
 static void
 add_pair_ciphers(NMWifiAP *ap, NMSettingWirelessSecurity *sec)
 {
-    NMWifiAPPrivate *      priv  = NM_WIFI_AP_GET_PRIVATE(ap);
+    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;
@@ -458,7 +458,7 @@ add_pair_ciphers(NMWifiAP *ap, NMSettingWirelessSecurity *sec)
 static void
 add_group_ciphers(NMWifiAP *ap, NMSettingWirelessSecurity *sec)
 {
-    NMWifiAPPrivate *      priv  = NM_WIFI_AP_GET_PRIVATE(ap);
+    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;
@@ -491,10 +491,10 @@ 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;
+    const char            *supplicant_id = "-";
+    const char            *export_path;
     guint32                chan;
-    gs_free char *         ssid_to_free = NULL;
+    gs_free char          *ssid_to_free = NULL;
     char                   str_buf_ts[100];
 
     g_return_val_if_fail(NM_IS_WIFI_AP(self), NULL);
@@ -558,13 +558,13 @@ freq_to_band(guint32 freq)
 gboolean
 nm_wifi_ap_check_compatible(NMWifiAP *self, NMConnection *connection)
 {
-    NMWifiAPPrivate *          priv;
-    NMSettingWireless *        s_wireless;
+    NMWifiAPPrivate           *priv;
+    NMSettingWireless         *s_wireless;
     NMSettingWirelessSecurity *s_wireless_sec;
-    GBytes *                   ssid;
-    const char *               mode;
-    const char *               band;
-    const char *               bssid;
+    GBytes                    *ssid;
+    const char                *mode;
+    const char                *band;
+    const char                *bssid;
     guint32                    channel;
 
     g_return_val_if_fail(NM_IS_WIFI_AP(self), FALSE);
@@ -629,10 +629,10 @@ nm_wifi_ap_check_compatible(NMWifiAP *self, NMConnection *connection)
 }
 
 gboolean
-nm_wifi_ap_complete_connection(NMWifiAP *    self,
+nm_wifi_ap_complete_connection(NMWifiAP     *self,
                                NMConnection *connection,
                                gboolean      lock_bssid,
-                               GError **     error)
+                               GError      **error)
 {
     NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE(self);
 
@@ -655,7 +655,7 @@ nm_wifi_ap_complete_connection(NMWifiAP *    self,
 static void
 get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
 {
-    NMWifiAP *       self = NM_WIFI_AP(object);
+    NMWifiAP        *self = NM_WIFI_AP(object);
     NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE(self);
 
     switch (prop_id) {
@@ -734,11 +734,11 @@ nm_wifi_ap_new_from_properties(const NMSupplicantBssInfo *bss_info)
 NMWifiAP *
 nm_wifi_ap_new_fake_from_connection(NMConnection *connection)
 {
-    NMWifiAP *                 ap;
-    NMWifiAPPrivate *          priv;
-    NMSettingWireless *        s_wireless;
+    NMWifiAP                  *ap;
+    NMWifiAPPrivate           *priv;
+    NMSettingWireless         *s_wireless;
     NMSettingWirelessSecurity *s_wireless_sec;
-    const char *               mode, *band, *key_mgmt;
+    const char                *mode, *band, *key_mgmt;
     guint32                    channel;
     NM80211ApSecurityFlags     flags;
     gboolean                   psk = FALSE, eap = FALSE, adhoc = FALSE;
@@ -845,7 +845,7 @@ error:
 static void
 finalize(GObject *object)
 {
-    NMWifiAP *       self = NM_WIFI_AP(object);
+    NMWifiAP        *self = NM_WIFI_AP(object);
     NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE(self);
 
     nm_assert(!self->wifi_device);
@@ -890,7 +890,7 @@ nm_wifi_ap_class_init(NMWifiAPClass *ap_class)
      | 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);
+    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));
@@ -987,10 +987,10 @@ nm_wifi_ap_class_init(NMWifiAPClass *ap_class)
 const char **
 nm_wifi_aps_get_paths(const CList *aps_lst_head, gboolean include_without_ssid)
 {
-    NMWifiAP *   ap;
+    NMWifiAP    *ap;
     gsize        i, n;
     const char **list;
-    const char * path;
+    const char  *path;
 
     n    = c_list_length(aps_lst_head);
     list = g_new(const char *, n + 1);
diff --git a/src/core/devices/wifi/nm-wifi-ap.h b/src/core/devices/wifi/nm-wifi-ap.h
index bffd28a8..c0422900 100644
--- a/src/core/devices/wifi/nm-wifi-ap.h
+++ b/src/core/devices/wifi/nm-wifi-ap.h
@@ -32,9 +32,9 @@
 
 typedef struct {
     NMDBusObject             parent;
-    NMDevice *               wifi_device;
+    NMDevice                *wifi_device;
     CList                    aps_lst;
-    NMRefString *            _supplicant_path;
+    NMRefString             *_supplicant_path;
     struct _NMWifiAPPrivate *_priv;
 } NMWifiAP;
 
@@ -47,15 +47,15 @@ GType nm_wifi_ap_get_type(void);
 NMWifiAP *nm_wifi_ap_new_from_properties(const struct _NMSupplicantBssInfo *bss_info);
 NMWifiAP *nm_wifi_ap_new_fake_from_connection(NMConnection *connection);
 
-gboolean nm_wifi_ap_update_from_properties(NMWifiAP *                         ap,
+gboolean nm_wifi_ap_update_from_properties(NMWifiAP                          *ap,
                                            const struct _NMSupplicantBssInfo *bss_info);
 
 gboolean nm_wifi_ap_check_compatible(NMWifiAP *self, NMConnection *connection);
 
-gboolean nm_wifi_ap_complete_connection(NMWifiAP *    self,
+gboolean nm_wifi_ap_complete_connection(NMWifiAP     *self,
                                         NMConnection *connection,
                                         gboolean      lock_bssid,
-                                        GError **     error);
+                                        GError      **error);
 
 static inline NMRefString *
 nm_wifi_ap_get_supplicant_path(NMWifiAP *ap)
@@ -65,9 +65,9 @@ nm_wifi_ap_get_supplicant_path(NMWifiAP *ap)
     return ap->_supplicant_path;
 }
 
-GBytes *               nm_wifi_ap_get_ssid(const NMWifiAP *ap);
+GBytes                *nm_wifi_ap_get_ssid(const NMWifiAP *ap);
 gboolean               nm_wifi_ap_set_ssid(NMWifiAP *ap, GBytes *ssid);
-const char *           nm_wifi_ap_get_address(const NMWifiAP *ap);
+const char            *nm_wifi_ap_get_address(const NMWifiAP *ap);
 gboolean               nm_wifi_ap_set_address(NMWifiAP *ap, const char *addr);
 gboolean               nm_wifi_ap_set_address_bin(NMWifiAP *ap, const NMEtherAddr *addr);
 _NM80211Mode           nm_wifi_ap_get_mode(NMWifiAP *ap);
diff --git a/src/core/devices/wifi/nm-wifi-common.c b/src/core/devices/wifi/nm-wifi-common.c
index d029ce7f..681d9cb5 100644
--- a/src/core/devices/wifi/nm-wifi-common.c
+++ b/src/core/devices/wifi/nm-wifi-common.c
@@ -56,17 +56,17 @@ _dispatch_request_scan(NMDevice *device, GVariant *options, GDBusMethodInvocatio
 }
 
 static void
-impl_device_wifi_get_access_points(NMDBusObject *                     obj,
+impl_device_wifi_get_access_points(NMDBusObject                      *obj,
                                    const NMDBusInterfaceInfoExtended *interface_info,
-                                   const NMDBusMethodInfoExtended *   method_info,
-                                   GDBusConnection *                  connection,
-                                   const char *                       sender,
-                                   GDBusMethodInvocation *            invocation,
-                                   GVariant *                         parameters)
+                                   const NMDBusMethodInfoExtended    *method_info,
+                                   GDBusConnection                   *connection,
+                                   const char                        *sender,
+                                   GDBusMethodInvocation             *invocation,
+                                   GVariant                          *parameters)
 {
     gs_free const char **list = NULL;
-    GVariant *           v;
-    const CList *        all_aps;
+    GVariant            *v;
+    const CList         *all_aps;
 
     /* NOTE: this handler is called both for NMDevicwWifi and NMDeviceIwd. */
 
@@ -77,17 +77,17 @@ impl_device_wifi_get_access_points(NMDBusObject *                     obj,
 }
 
 static void
-impl_device_wifi_get_all_access_points(NMDBusObject *                     obj,
+impl_device_wifi_get_all_access_points(NMDBusObject                      *obj,
                                        const NMDBusInterfaceInfoExtended *interface_info,
-                                       const NMDBusMethodInfoExtended *   method_info,
-                                       GDBusConnection *                  connection,
-                                       const char *                       sender,
-                                       GDBusMethodInvocation *            invocation,
-                                       GVariant *                         parameters)
+                                       const NMDBusMethodInfoExtended    *method_info,
+                                       GDBusConnection                   *connection,
+                                       const char                        *sender,
+                                       GDBusMethodInvocation             *invocation,
+                                       GVariant                          *parameters)
 {
     gs_free const char **list = NULL;
-    GVariant *           v;
-    const CList *        all_aps;
+    GVariant            *v;
+    const CList         *all_aps;
 
     /* NOTE: this handler is called both for NMDevicwWifi and NMDeviceIwd. */
 
@@ -98,13 +98,13 @@ impl_device_wifi_get_all_access_points(NMDBusObject *                     obj,
 }
 
 static void
-impl_device_wifi_request_scan(NMDBusObject *                     obj,
+impl_device_wifi_request_scan(NMDBusObject                      *obj,
                               const NMDBusInterfaceInfoExtended *interface_info,
-                              const NMDBusMethodInfoExtended *   method_info,
-                              GDBusConnection *                  connection,
-                              const char *                       sender,
-                              GDBusMethodInvocation *            invocation,
-                              GVariant *                         parameters)
+                              const NMDBusMethodInfoExtended    *method_info,
+                              GDBusConnection                   *connection,
+                              const char                        *sender,
+                              GDBusMethodInvocation             *invocation,
+                              GVariant                          *parameters)
 {
     gs_unref_variant GVariant *options = NULL;
 
diff --git a/src/core/devices/wifi/nm-wifi-factory.c b/src/core/devices/wifi/nm-wifi-factory.c
index d2269c74..5e354c6b 100644
--- a/src/core/devices/wifi/nm-wifi-factory.c
+++ b/src/core/devices/wifi/nm-wifi-factory.c
@@ -14,6 +14,8 @@
 #include "nm-device-wifi-p2p.h"
 #include "nm-device-olpc-mesh.h"
 #include "nm-device-iwd.h"
+#include "nm-device-iwd-p2p.h"
+#include "nm-iwd-manager.h"
 #include "settings/nm-settings-connection.h"
 #include "libnm-platform/nm-platform.h"
 #include "nm-config.h"
@@ -50,7 +52,7 @@ NM_DEVICE_FACTORY_DECLARE_TYPES(
                                                 NM_SETTING_OLPC_MESH_SETTING_NAME))
 
 G_MODULE_EXPORT NMDeviceFactory *
-                nm_device_factory_create(GError **error)
+nm_device_factory_create(GError **error)
 {
     return g_object_new(NM_TYPE_WIFI_FACTORY, NULL);
 }
@@ -67,15 +69,29 @@ p2p_device_created(NMDeviceWifi *device, NMDeviceWifiP2P *p2p_device, NMDeviceFa
     g_signal_emit_by_name(self, NM_DEVICE_FACTORY_DEVICE_ADDED, p2p_device);
 }
 
+#if WITH_IWD
+static void
+iwd_p2p_device_added(NMIwdManager    *iwd,
+                     NMDeviceIwdP2P  *p2p_device,
+                     const char      *phy_name,
+                     NMDeviceFactory *self)
+{
+    nm_log_info(LOGD_PLATFORM | LOGD_WIFI, "Wi-Fi P2P device added on %s", phy_name);
+
+    g_signal_emit_by_name(self, NM_DEVICE_FACTORY_DEVICE_ADDED, p2p_device);
+}
+#endif
+
 static NMDevice *
-create_device(NMDeviceFactory *     factory,
-              const char *          iface,
+create_device(NMDeviceFactory      *factory,
+              const char           *iface,
               const NMPlatformLink *plink,
-              NMConnection *        connection,
-              gboolean *            out_ignore)
+              NMConnection         *connection,
+              gboolean             *out_ignore)
 {
     gs_free char *backend_free = NULL;
-    const char *  backend;
+    const char   *backend;
+    _NM80211Mode  mode;
 
     g_return_val_if_fail(iface != NULL, NULL);
     g_return_val_if_fail(plink != NULL, NULL);
@@ -85,6 +101,20 @@ create_device(NMDeviceFactory *     factory,
     if (plink->type != NM_LINK_TYPE_WIFI)
         return nm_device_olpc_mesh_new(iface);
 
+    /* Ignore monitor-mode and other unhandled interface types.
+     * FIXME: keep TYPE_MONITOR devices in UNAVAILABLE state and manage
+     * them if/when they change to a handled type.
+     */
+    mode = nm_platform_wifi_get_mode(NM_PLATFORM_GET, plink->ifindex);
+    if (!NM_IN_SET(mode,
+                   _NM_802_11_MODE_INFRA,
+                   _NM_802_11_MODE_ADHOC,
+                   _NM_802_11_MODE_AP,
+                   _NM_802_11_MODE_MESH)) {
+        *out_ignore = TRUE;
+        return NULL;
+    }
+
     backend = nm_config_data_get_device_config_by_pllink(NM_CONFIG_GET_DATA,
                                                          NM_CONFIG_KEYFILE_KEY_DEVICE_WIFI_BACKEND,
                                                          plink,
@@ -92,15 +122,17 @@ create_device(NMDeviceFactory *     factory,
                                                          NULL);
     backend = nm_strstrip_avoid_copy_a(300, backend, &backend_free);
 
+    if (!backend)
+        backend = "" NM_CONFIG_DEFAULT_WIFI_BACKEND;
+
     nm_log_dbg(LOGD_PLATFORM | LOGD_WIFI,
                "(%s) config: backend is %s%s%s%s",
                iface,
                NM_PRINT_FMT_QUOTE_STRING(backend),
                WITH_IWD ? " (iwd support enabled)" : "");
-    if (!backend || !g_ascii_strcasecmp(backend, "wpa_supplicant")) {
-        NMDevice *                device;
+    if (!g_ascii_strcasecmp(backend, "wpa_supplicant")) {
+        NMDevice                 *device;
         _NMDeviceWifiCapabilities capabilities;
-        _NM80211Mode              mode;
 
         if (!nm_platform_wifi_get_capabilities(NM_PLATFORM_GET, plink->ifindex, &capabilities)) {
             nm_log_warn(LOGD_PLATFORM | LOGD_WIFI,
@@ -110,16 +142,6 @@ create_device(NMDeviceFactory *     factory,
             return NULL;
         }
 
-        /* Ignore monitor-mode and other unhandled interface types.
-         * FIXME: keep TYPE_MONITOR devices in UNAVAILABLE state and manage
-         * them if/when they change to a handled type.
-         */
-        mode = nm_platform_wifi_get_mode(NM_PLATFORM_GET, plink->ifindex);
-        if (mode == _NM_802_11_MODE_UNKNOWN) {
-            *out_ignore = TRUE;
-            return NULL;
-        }
-
         device = nm_device_wifi_new(iface, capabilities);
 
         g_signal_connect_object(device,
@@ -131,8 +153,23 @@ create_device(NMDeviceFactory *     factory,
         return device;
     }
 #if WITH_IWD
-    else if (!g_ascii_strcasecmp(backend, "iwd"))
+    else if (!g_ascii_strcasecmp(backend, "iwd")) {
+        NMIwdManager *iwd = nm_iwd_manager_get();
+
+        if (!g_signal_handler_find(iwd,
+                                   G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA,
+                                   0,
+                                   0,
+                                   NULL,
+                                   G_CALLBACK(iwd_p2p_device_added),
+                                   factory))
+            g_signal_connect(iwd,
+                             NM_IWD_MANAGER_P2P_DEVICE_ADDED,
+                             G_CALLBACK(iwd_p2p_device_added),
+                             factory);
+
         return nm_device_iwd_new(iface);
+    }
 #endif
 
     nm_log_warn(LOGD_PLATFORM | LOGD_WIFI,
diff --git a/src/core/devices/wifi/nm-wifi-p2p-peer.c b/src/core/devices/wifi/nm-wifi-p2p-peer.c
index ac13952d..0a174270 100644
--- a/src/core/devices/wifi/nm-wifi-p2p-peer.c
+++ b/src/core/devices/wifi/nm-wifi-p2p-peer.c
@@ -18,6 +18,7 @@
 #include "nm-setting-wireless.h"
 #include "nm-utils.h"
 #include "nm-wifi-utils.h"
+#include "nm-iwd-manager.h"
 #include "libnm-platform/nm-platform.h"
 #include "supplicant/nm-supplicant-types.h"
 
@@ -77,8 +78,8 @@ const char **
 nm_wifi_p2p_peers_get_paths(const CList *peers_lst_head)
 {
     NMWifiP2PPeer *peer;
-    const char **  list;
-    const char *   path;
+    const char   **list;
+    const char    *path;
     gsize          i, n;
 
     n    = c_list_length(peers_lst_head);
@@ -100,14 +101,16 @@ nm_wifi_p2p_peers_get_paths(const CList *peers_lst_head)
 }
 
 NMWifiP2PPeer *
-nm_wifi_p2p_peers_find_first_compatible(const CList *peers_lst_head, NMConnection *connection)
+nm_wifi_p2p_peers_find_first_compatible(const CList  *peers_lst_head,
+                                        NMConnection *connection,
+                                        gboolean      check_wfd)
 {
     NMWifiP2PPeer *peer;
 
     g_return_val_if_fail(connection, NULL);
 
     c_list_for_each_entry (peer, peers_lst_head, peers_lst) {
-        if (nm_wifi_p2p_peer_check_compatible(peer, connection))
+        if (nm_wifi_p2p_peer_check_compatible(peer, connection, check_wfd))
             return peer;
     }
     return NULL;
@@ -261,7 +264,7 @@ nm_wifi_p2p_peer_get_wfd_ies(const NMWifiP2PPeer *peer)
 gboolean
 nm_wifi_p2p_peer_set_wfd_ies(NMWifiP2PPeer *peer, GBytes *wfd_ies)
 {
-    NMWifiP2PPeerPrivate *priv;
+    NMWifiP2PPeerPrivate  *priv;
     gs_unref_bytes GBytes *wfd_ies_old = NULL;
 
     g_return_val_if_fail(NM_IS_WIFI_P2P_PEER(peer), FALSE);
@@ -419,12 +422,96 @@ nm_wifi_p2p_peer_update_from_properties(NMWifiP2PPeer *peer, const NMSupplicantP
     return changed;
 }
 
+gboolean
+nm_wifi_p2p_peer_update_from_iwd_object(NMWifiP2PPeer *peer, GDBusObject *obj)
+{
+    NMWifiP2PPeerPrivate           *priv;
+    gboolean                        changed    = FALSE;
+    nm_auto_ref_string NMRefString *peer_path  = NULL;
+    gs_unref_object GDBusProxy     *peer_proxy = NULL;
+    gs_unref_object GDBusProxy     *wfd_proxy  = NULL;
+    GVariant                       *value;
+    gs_unref_bytes GBytes          *wfd_ies = NULL;
+
+    g_return_val_if_fail(NM_IS_WIFI_P2P_PEER(peer), FALSE);
+
+    peer_proxy = G_DBUS_PROXY(g_dbus_object_get_interface(obj, NM_IWD_P2P_PEER_INTERFACE));
+    wfd_proxy  = G_DBUS_PROXY(g_dbus_object_get_interface(obj, NM_IWD_P2P_WFD_INTERFACE));
+    g_return_val_if_fail(peer_proxy, FALSE);
+
+    peer_path = nm_ref_string_new(g_dbus_object_get_object_path(obj));
+    priv      = NM_WIFI_P2P_PEER_GET_PRIVATE(peer);
+    nm_assert(!priv->supplicant_path || priv->supplicant_path == peer_path);
+
+    g_object_freeze_notify(G_OBJECT(peer));
+
+    if (!priv->supplicant_path) {
+        priv->supplicant_path = g_steal_pointer(&peer_path);
+        changed               = TRUE;
+    }
+
+    value = g_dbus_proxy_get_cached_property(peer_proxy, "Name");
+    if (value && g_variant_is_of_type(value, G_VARIANT_TYPE_STRING))
+        changed |= nm_wifi_p2p_peer_set_name(peer, g_variant_get_string(value, NULL));
+    else
+        changed |= nm_wifi_p2p_peer_set_name(peer, "");
+    nm_g_variant_unref(value);
+
+    value = g_dbus_proxy_get_cached_property(peer_proxy, "Address");
+    if (value && g_variant_is_of_type(value, G_VARIANT_TYPE_STRING))
+        changed |= nm_wifi_p2p_peer_set_address(peer, g_variant_get_string(value, NULL));
+    nm_g_variant_unref(value);
+
+    if (wfd_proxy) {
+        NMIwdWfdInfo wfd = {};
+
+        value      = g_dbus_proxy_get_cached_property(wfd_proxy, "Source");
+        wfd.source = value && g_variant_is_of_type(value, G_VARIANT_TYPE_BOOLEAN)
+                     && g_variant_get_boolean(value);
+        nm_g_variant_unref(value);
+
+        value    = g_dbus_proxy_get_cached_property(wfd_proxy, "Sink");
+        wfd.sink = value && g_variant_is_of_type(value, G_VARIANT_TYPE_BOOLEAN)
+                   && g_variant_get_boolean(value);
+        nm_g_variant_unref(value);
+
+        value    = g_dbus_proxy_get_cached_property(wfd_proxy, "Port");
+        wfd.port = (value && g_variant_is_of_type(value, G_VARIANT_TYPE_UINT16))
+                       ? g_variant_get_uint16(value)
+                       : 0;
+        nm_g_variant_unref(value);
+
+        value         = g_dbus_proxy_get_cached_property(wfd_proxy, "HasAudio");
+        wfd.has_audio = value && g_variant_is_of_type(value, G_VARIANT_TYPE_BOOLEAN)
+                        && g_variant_get_boolean(value);
+        nm_g_variant_unref(value);
+
+        value        = g_dbus_proxy_get_cached_property(wfd_proxy, "HasUIBC");
+        wfd.has_uibc = value && g_variant_is_of_type(value, G_VARIANT_TYPE_BOOLEAN)
+                       && g_variant_get_boolean(value);
+        nm_g_variant_unref(value);
+
+        value      = g_dbus_proxy_get_cached_property(wfd_proxy, "HasContentProtection");
+        wfd.has_cp = value && g_variant_is_of_type(value, G_VARIANT_TYPE_BOOLEAN)
+                     && g_variant_get_boolean(value);
+        nm_g_variant_unref(value);
+
+        wfd_ies = nm_wifi_utils_build_wfd_ies(&wfd);
+    }
+
+    changed |= nm_wifi_p2p_peer_set_wfd_ies(peer, wfd_ies);
+
+    g_object_thaw_notify(G_OBJECT(peer));
+
+    return changed;
+}
+
 const char *
 nm_wifi_p2p_peer_to_string(const NMWifiP2PPeer *self, char *str_buf, gsize buf_len, gint32 now_s)
 {
     const NMWifiP2PPeerPrivate *priv;
-    const char *                supplicant_id = "-";
-    const char *                export_path;
+    const char                 *supplicant_id = "-";
+    const char                 *export_path;
 
     g_return_val_if_fail(NM_IS_WIFI_P2P_PEER(self), NULL);
 
@@ -458,11 +545,11 @@ nm_wifi_p2p_peer_to_string(const NMWifiP2PPeer *self, char *str_buf, gsize buf_l
 }
 
 gboolean
-nm_wifi_p2p_peer_check_compatible(NMWifiP2PPeer *self, NMConnection *connection)
+nm_wifi_p2p_peer_check_compatible(NMWifiP2PPeer *self, NMConnection *connection, gboolean check_wfd)
 {
     NMWifiP2PPeerPrivate *priv;
-    NMSettingWifiP2P *    s_wifi_p2p;
-    const char *          hwaddr;
+    NMSettingWifiP2P     *s_wifi_p2p;
+    const char           *hwaddr;
 
     g_return_val_if_fail(NM_IS_WIFI_P2P_PEER(self), FALSE);
     g_return_val_if_fail(NM_IS_CONNECTION(connection), FALSE);
@@ -478,6 +565,10 @@ nm_wifi_p2p_peer_check_compatible(NMWifiP2PPeer *self, NMConnection *connection)
     if (hwaddr && (!priv->address || !nm_utils_hwaddr_matches(hwaddr, -1, priv->address, -1)))
         return FALSE;
 
+    if (check_wfd && nm_setting_wifi_p2p_get_wfd_ies(s_wifi_p2p)
+        && !nm_wifi_p2p_peer_get_wfd_ies(self))
+        return FALSE;
+
     return TRUE;
 }
 
@@ -486,7 +577,7 @@ nm_wifi_p2p_peer_check_compatible(NMWifiP2PPeer *self, NMConnection *connection)
 static void
 get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
 {
-    NMWifiP2PPeer *       self = NM_WIFI_P2P_PEER(object);
+    NMWifiP2PPeer        *self = NM_WIFI_P2P_PEER(object);
     NMWifiP2PPeerPrivate *priv = NM_WIFI_P2P_PEER_GET_PRIVATE(self);
 
     switch (prop_id) {
@@ -559,10 +650,21 @@ nm_wifi_p2p_peer_new_from_properties(const NMSupplicantPeerInfo *peer_info)
     return peer;
 }
 
+NMWifiP2PPeer *
+nm_wifi_p2p_peer_new_from_iwd_object(GDBusObject *obj)
+{
+    NMWifiP2PPeer *peer;
+
+    /* TODO: Set the flags here */
+    peer = g_object_new(NM_TYPE_WIFI_P2P_PEER, NULL);
+    nm_wifi_p2p_peer_update_from_iwd_object(peer, obj);
+    return peer;
+}
+
 static void
 finalize(GObject *object)
 {
-    NMWifiP2PPeer *       self = NM_WIFI_P2P_PEER(object);
+    NMWifiP2PPeer        *self = NM_WIFI_P2P_PEER(object);
     NMWifiP2PPeerPrivate *priv = NM_WIFI_P2P_PEER_GET_PRIVATE(self);
 
     nm_assert(!self->wifi_device);
@@ -613,7 +715,7 @@ static const NMDBusInterfaceInfoExtended interface_info_p2p_peer = {
 static void
 nm_wifi_p2p_peer_class_init(NMWifiP2PPeerClass *klass)
 {
-    GObjectClass *     object_class      = G_OBJECT_CLASS(klass);
+    GObjectClass      *object_class      = G_OBJECT_CLASS(klass);
     NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(klass);
 
     g_type_class_add_private(object_class, sizeof(NMWifiP2PPeerPrivate));
diff --git a/src/core/devices/wifi/nm-wifi-p2p-peer.h b/src/core/devices/wifi/nm-wifi-p2p-peer.h
index ee4bfb53..5124d1de 100644
--- a/src/core/devices/wifi/nm-wifi-p2p-peer.h
+++ b/src/core/devices/wifi/nm-wifi-p2p-peer.h
@@ -33,7 +33,7 @@
 
 typedef struct {
     NMDBusObject                  parent;
-    NMDevice *                    wifi_device;
+    NMDevice                     *wifi_device;
     CList                         peers_lst;
     struct _NMWifiP2PPeerPrivate *_priv;
 } NMWifiP2PPeer;
@@ -45,11 +45,15 @@ struct _NMSupplicantPeerInfo;
 GType nm_wifi_p2p_peer_get_type(void);
 
 NMWifiP2PPeer *nm_wifi_p2p_peer_new_from_properties(const struct _NMSupplicantPeerInfo *peer_info);
+NMWifiP2PPeer *nm_wifi_p2p_peer_new_from_iwd_object(GDBusObject *obj);
 
-gboolean nm_wifi_p2p_peer_update_from_properties(NMWifiP2PPeer *                     peer,
+gboolean nm_wifi_p2p_peer_update_from_properties(NMWifiP2PPeer                      *peer,
                                                  const struct _NMSupplicantPeerInfo *peer_info);
+gboolean nm_wifi_p2p_peer_update_from_iwd_object(NMWifiP2PPeer *peer, GDBusObject *obj);
 
-gboolean nm_wifi_p2p_peer_check_compatible(NMWifiP2PPeer *self, NMConnection *connection);
+gboolean nm_wifi_p2p_peer_check_compatible(NMWifiP2PPeer *self,
+                                           NMConnection  *connection,
+                                           gboolean       check_wfd);
 
 const char *nm_wifi_p2p_peer_get_supplicant_path(NMWifiP2PPeer *peer);
 
@@ -64,12 +68,12 @@ gboolean    nm_wifi_p2p_peer_set_model_number(NMWifiP2PPeer *peer, const char *n
 const char *nm_wifi_p2p_peer_get_serial(const NMWifiP2PPeer *peer);
 gboolean    nm_wifi_p2p_peer_set_serial(NMWifiP2PPeer *peer, const char *serial);
 
-GBytes * nm_wifi_p2p_peer_get_wfd_ies(const NMWifiP2PPeer *peer);
+GBytes  *nm_wifi_p2p_peer_get_wfd_ies(const NMWifiP2PPeer *peer);
 gboolean nm_wifi_p2p_peer_set_wfd_ies(NMWifiP2PPeer *peer, GBytes *bytes);
 
 const char *const *nm_wifi_p2p_peer_get_groups(const NMWifiP2PPeer *peer);
 
-const char *   nm_wifi_p2p_peer_get_address(const NMWifiP2PPeer *peer);
+const char    *nm_wifi_p2p_peer_get_address(const NMWifiP2PPeer *peer);
 gboolean       nm_wifi_p2p_peer_set_address(NMWifiP2PPeer *peer, const char *addr);
 gint8          nm_wifi_p2p_peer_get_strength(NMWifiP2PPeer *peer);
 gboolean       nm_wifi_p2p_peer_set_strength(NMWifiP2PPeer *peer, gint8 strength);
@@ -80,11 +84,12 @@ nm_wifi_p2p_peer_to_string(const NMWifiP2PPeer *self, char *str_buf, gsize buf_l
 
 const char **nm_wifi_p2p_peers_get_paths(const CList *peers_lst_head);
 
-NMWifiP2PPeer *nm_wifi_p2p_peers_find_first_compatible(const CList * peers_lst_head,
-                                                       NMConnection *connection);
+NMWifiP2PPeer *nm_wifi_p2p_peers_find_first_compatible(const CList  *peers_lst_head,
+                                                       NMConnection *connection,
+                                                       gboolean      check_wfd);
 
 NMWifiP2PPeer *nm_wifi_p2p_peers_find_by_supplicant_path(const CList *peers_lst_head,
-                                                         const char * path);
+                                                         const char  *path);
 
 NMWifiP2PPeer *nm_wifi_p2p_peer_lookup_for_device(NMDevice *device, const char *exported_path);
 
diff --git a/src/core/devices/wifi/nm-wifi-utils.c b/src/core/devices/wifi/nm-wifi-utils.c
index 4939e786..1a8204b0 100644
--- a/src/core/devices/wifi/nm-wifi-utils.c
+++ b/src/core/devices/wifi/nm-wifi-utils.c
@@ -41,9 +41,9 @@ verify_no_wep(NMSettingWirelessSecurity *s_wsec, const char *tag, GError **error
 
 static gboolean
 verify_leap(NMSettingWirelessSecurity *s_wsec,
-            NMSetting8021x *           s_8021x,
+            NMSetting8021x            *s_8021x,
             gboolean                   adhoc,
-            GError **                  error)
+            GError                   **error)
 {
     const char *key_mgmt, *auth_alg, *leap_username;
 
@@ -224,9 +224,9 @@ verify_no_wpa(NMSettingWirelessSecurity *s_wsec, const char *tag, GError **error
 
 static gboolean
 verify_dynamic_wep(NMSettingWirelessSecurity *s_wsec,
-                   NMSetting8021x *           s_8021x,
+                   NMSetting8021x            *s_8021x,
                    gboolean                   adhoc,
-                   GError **                  error)
+                   GError                   **error)
 {
     const char *key_mgmt, *auth_alg, *leap_username;
 
@@ -303,11 +303,11 @@ verify_dynamic_wep(NMSettingWirelessSecurity *s_wsec,
 
 static gboolean
 verify_wpa_psk(NMSettingWirelessSecurity *s_wsec,
-               NMSetting8021x *           s_8021x,
+               NMSetting8021x            *s_8021x,
                gboolean                   adhoc,
                guint32                    wpa_flags,
                guint32                    rsn_flags,
-               GError **                  error)
+               GError                   **error)
 {
     const char *key_mgmt, *auth_alg;
 
@@ -400,10 +400,10 @@ verify_wpa_psk(NMSettingWirelessSecurity *s_wsec,
 
 static gboolean
 verify_wpa_eap(NMSettingWirelessSecurity *s_wsec,
-               NMSetting8021x *           s_8021x,
+               NMSetting8021x            *s_8021x,
                guint32                    wpa_flags,
                guint32                    rsn_flags,
-               GError **                  error)
+               GError                   **error)
 {
     const char *key_mgmt, *auth_alg;
     gboolean    is_wpa_eap = FALSE;
@@ -465,9 +465,9 @@ verify_wpa_eap(NMSettingWirelessSecurity *s_wsec,
 
 static gboolean
 verify_adhoc(NMSettingWirelessSecurity *s_wsec,
-             NMSetting8021x *           s_8021x,
+             NMSetting8021x            *s_8021x,
              gboolean                   adhoc,
-             GError **                  error)
+             GError                   **error)
 {
     const char *key_mgmt = NULL, *leap_username = NULL, *auth_alg = NULL;
 
@@ -529,8 +529,8 @@ verify_adhoc(NMSettingWirelessSecurity *s_wsec,
 }
 
 gboolean
-nm_wifi_utils_complete_connection(GBytes *      ap_ssid,
-                                  const char *  bssid,
+nm_wifi_utils_complete_connection(GBytes       *ap_ssid,
+                                  const char   *bssid,
                                   _NM80211Mode  ap_mode,
                                   guint32       ap_freq,
                                   guint32       ap_flags,
@@ -538,13 +538,13 @@ nm_wifi_utils_complete_connection(GBytes *      ap_ssid,
                                   guint32       ap_rsn_flags,
                                   NMConnection *connection,
                                   gboolean      lock_bssid,
-                                  GError **     error)
+                                  GError      **error)
 {
-    NMSettingWireless *        s_wifi;
+    NMSettingWireless         *s_wifi;
     NMSettingWirelessSecurity *s_wsec;
-    NMSetting8021x *           s_8021x;
-    GBytes *                   ssid;
-    const char *               mode, *key_mgmt, *auth_alg, *leap_username;
+    NMSetting8021x            *s_8021x;
+    GBytes                    *ssid;
+    const char                *mode, *key_mgmt, *auth_alg, *leap_username;
     gboolean                   adhoc = FALSE;
     gboolean                   mesh  = FALSE;
 
@@ -892,20 +892,20 @@ nm_wifi_utils_is_manf_default_ssid(GBytes *ssid)
 
 /* To be used for connections where the SSID has been validated before */
 gboolean
-nm_wifi_connection_get_iwd_ssid_and_security(NMConnection *        connection,
-                                             char **               ssid,
+nm_wifi_connection_get_iwd_ssid_and_security(NMConnection         *connection,
+                                             char                **ssid,
                                              NMIwdNetworkSecurity *security)
 {
-    NMSettingWireless *        s_wireless;
+    NMSettingWireless         *s_wireless;
     NMSettingWirelessSecurity *s_wireless_sec;
-    const char *               key_mgmt = NULL;
+    const char                *key_mgmt = NULL;
 
     s_wireless = nm_connection_get_setting_wireless(connection);
     if (!s_wireless)
         return FALSE;
 
     if (ssid) {
-        GBytes *    bytes = nm_setting_wireless_get_ssid(s_wireless);
+        GBytes     *bytes = nm_setting_wireless_get_ssid(s_wireless);
         gsize       ssid_len;
         const char *ssid_str = (const char *) g_bytes_get_data(bytes, &ssid_len);
 
@@ -947,7 +947,7 @@ nm_wifi_connection_get_iwd_ssid_and_security(NMConnection *        connection,
  * @ssid_len can be -1 instead of actual SSID length.
  */
 char *
-nm_wifi_utils_get_iwd_config_filename(const char *         ssid,
+nm_wifi_utils_get_iwd_config_filename(const char          *ssid,
                                       gssize               ssid_len,
                                       NMIwdNetworkSecurity security)
 {
@@ -995,10 +995,10 @@ static gboolean
 psk_setting_to_iwd_config(GKeyFile *file, NMSettingWirelessSecurity *s_wsec, GError **error)
 {
     NMSettingSecretFlags psk_flags = nm_setting_wireless_security_get_psk_flags(s_wsec);
-    const char *         psk       = nm_setting_wireless_security_get_psk(s_wsec);
+    const char          *psk       = nm_setting_wireless_security_get_psk(s_wsec);
     gsize                psk_len;
     guint8               buffer[32];
-    const char *         key_mgmt = nm_setting_wireless_security_get_key_mgmt(s_wsec);
+    const char          *key_mgmt = nm_setting_wireless_security_get_key_mgmt(s_wsec);
 
     if (!psk || NM_FLAGS_ANY(psk_flags, SECRETS_DONT_STORE_FLAGS)) {
         if (NM_FLAGS_ANY(psk_flags, SECRETS_DONT_STORE_FLAGS)) {
@@ -1029,11 +1029,11 @@ psk_setting_to_iwd_config(GKeyFile *file, NMSettingWirelessSecurity *s_wsec, GEr
 }
 
 static gboolean
-eap_certs_to_iwd_config(GKeyFile *      file,
+eap_certs_to_iwd_config(GKeyFile       *file,
                         NMSetting8021x *s_8021x,
                         bool            phase2,
-                        char *          iwd_prefix,
-                        GError **       error)
+                        char           *iwd_prefix,
+                        GError        **error)
 {
     NMSetting8021xCKScheme ca_cert_scheme =
         phase2 ? nm_setting_802_1x_get_phase2_ca_cert_scheme(s_8021x)
@@ -1043,13 +1043,13 @@ eap_certs_to_iwd_config(GKeyFile *      file,
                : nm_setting_802_1x_get_client_cert_scheme(s_8021x);
     NMSetting8021xCKScheme key_scheme;
     NMSettingSecretFlags   key_password_flags;
-    const char *           ca_path = phase2 ? nm_setting_802_1x_get_phase2_ca_path(s_8021x)
+    const char            *ca_path = phase2 ? nm_setting_802_1x_get_phase2_ca_path(s_8021x)
                                             : nm_setting_802_1x_get_ca_path(s_8021x);
-    const char *           cert_path;
-    const char *           key_path = NULL;
-    const char *           key_password;
-    const char *           domain_suffix_match;
-    const char *           domain_match;
+    const char            *cert_path;
+    const char            *key_path = NULL;
+    const char            *key_password;
+    const char            *domain_suffix_match;
+    const char            *domain_match;
     char                   setting_buf[128];
 
     /* TODO: should check that all certificates and the key are RSA */
@@ -1220,7 +1220,7 @@ private_key_done:
                                  : nm_setting_802_1x_get_domain_match(s_8021x);
 
     if (domain_suffix_match || domain_match) {
-        GString *   s = g_string_sized_new(128);
+        GString    *s = g_string_sized_new(128);
         const char *ptr;
         const char *end;
 
@@ -1287,13 +1287,13 @@ eap_optional_identity_to_iwd_config(GKeyFile *file, const char *iwd_prefix, cons
 }
 
 static gboolean
-eap_optional_password_to_iwd_config(GKeyFile *      file,
-                                    const char *    iwd_prefix,
+eap_optional_password_to_iwd_config(GKeyFile       *file,
+                                    const char     *iwd_prefix,
                                     NMSetting8021x *s_8021x,
-                                    GError **       error)
+                                    GError        **error)
 {
     char                 setting_buf[128];
-    const char *         password = nm_setting_802_1x_get_password(s_8021x);
+    const char          *password = nm_setting_802_1x_get_password(s_8021x);
     NMSettingSecretFlags flags    = nm_setting_802_1x_get_password_flags(s_8021x);
 
     if (!password && nm_setting_802_1x_get_password_raw(s_8021x)) {
@@ -1347,12 +1347,12 @@ eap_phase1_identity_to_iwd_config(GKeyFile *file, const char *iwd_prefix, NMSett
 }
 
 static gboolean
-eap_method_config_to_iwd_config(GKeyFile *      file,
+eap_method_config_to_iwd_config(GKeyFile       *file,
                                 NMSetting8021x *s_8021x,
                                 gboolean        phase2,
-                                const char *    method,
-                                const char *    iwd_prefix,
-                                GError **       error)
+                                const char     *method,
+                                const char     *iwd_prefix,
+                                GError        **error)
 {
     char prefix_buf[128];
 
@@ -1677,18 +1677,18 @@ ip6_config_to_iwd_config(GKeyFile *file, NMSettingIPConfig *s_ip, GError **error
 
 GKeyFile *
 nm_wifi_utils_connection_to_iwd_config(NMConnection *connection,
-                                       char **       out_filename,
-                                       GError **     error)
+                                       char        **out_filename,
+                                       GError      **error)
 {
-    NMSettingConnection * s_conn = nm_connection_get_setting_connection(connection);
-    NMSettingWireless *   s_wifi = nm_connection_get_setting_wireless(connection);
-    GBytes *              ssid;
-    const guint8 *        ssid_data;
-    gsize                 ssid_len;
-    NMIwdNetworkSecurity  security;
-    const char *          cloned_mac_addr;
-    gs_free char *        comment        = NULL;
-    nm_auto_unref_keyfile GKeyFile *file = NULL;
+    NMSettingConnection            *s_conn = nm_connection_get_setting_connection(connection);
+    NMSettingWireless              *s_wifi = nm_connection_get_setting_wireless(connection);
+    GBytes                         *ssid;
+    const guint8                   *ssid_data;
+    gsize                           ssid_len;
+    NMIwdNetworkSecurity            security;
+    const char                     *cloned_mac_addr;
+    gs_free char                   *comment = NULL;
+    nm_auto_unref_keyfile GKeyFile *file    = NULL;
 
     if (!s_conn || !s_wifi
         || !nm_streq(nm_setting_connection_get_connection_type(s_conn),
@@ -1800,3 +1800,151 @@ nm_wifi_utils_connection_to_iwd_config(NMConnection *connection,
 
     return g_steal_pointer(&file);
 }
+
+/* Wi-Fi Display Technical Specification v2.1.0 Table 27 */
+enum wfd_subelem_type {
+    WFD_SUBELEM_WFD_DEVICE_INFORMATION   = 0,
+    WFD_SUBELEM_ASSOCIATED_BSSID         = 1,
+    WFD_SUBELEM_COUPLED_SINK_INFORMATION = 6,
+    WFD_SUBELEM_EXTENDED_CAPABILITY      = 7,
+    WFD_SUBELEM_LOCAL_IP_ADDRESS         = 8,
+    WFD_SUBELEM_SESION_INFORMATION       = 9,
+    WFD_SUBELEM_ALTERNATIVE_MAC_ADDRESS  = 10,
+    WFD_SUBELEM_R2_DEVICE_INFORMATION    = 11,
+};
+
+bool
+nm_wifi_utils_parse_wfd_ies(GBytes *ies, NMIwdWfdInfo *out_wfd)
+{
+    size_t         len;
+    const uint8_t *data         = g_bytes_get_data(ies, &len);
+    const uint8_t *dev_info     = NULL;
+    uint16_t       dev_info_len = 0;
+    uint16_t       dev_info_flags;
+    const uint8_t *ext_capability     = NULL;
+    uint16_t       ext_capability_len = 0;
+
+    /* The single WFD IEs array provided by the client is supposed to be sent to
+     * the peer in the different frame types that may include the WFD IE: Probe
+     * Request/Response, Beacon, (Re)Association Request/Response, GO
+     * Negotiation Request/Response/Confirm and Provision Discovery
+     * Request/Response.
+     *
+     * It's going to be a subset of the elements allowed in all those frames.
+     * Validate that it contains at least a valid WFD Device Information (with
+     * the Session Available bit true) and that the sequence of subelements is
+     * valid.
+     */
+    while (len) {
+        uint8_t  subelem_id;
+        uint16_t subelem_len;
+
+        /* Does the subelement header fit */
+        if (len < 3)
+            return FALSE;
+
+        subelem_id  = data[0];
+        subelem_len = (data[1] << 8) | data[2];
+        data += 3;
+        len -= 3;
+
+        if (subelem_len > len)
+            return FALSE;
+
+        if (subelem_id == WFD_SUBELEM_WFD_DEVICE_INFORMATION) {
+            /* Is there a duplicate WFD Device Information */
+            if (dev_info)
+                return FALSE;
+
+            dev_info     = data;
+            dev_info_len = subelem_len;
+        }
+
+        if (subelem_id == WFD_SUBELEM_EXTENDED_CAPABILITY) {
+            /* Is there a duplicate WFD Extended Capability */
+            if (ext_capability)
+                return FALSE;
+
+            ext_capability     = data;
+            ext_capability_len = subelem_len;
+        }
+
+        data += subelem_len;
+        len -= subelem_len;
+    }
+
+    if (!dev_info || dev_info_len != 6)
+        return FALSE;
+
+    dev_info_flags = (dev_info[0] << 8) | dev_info[1];
+
+    /* Secondary sink not supported */
+    if ((dev_info_flags & 3) == 2)
+        return FALSE;
+
+    /* Must be available for WFD Session */
+    if (((dev_info_flags >> 4) & 3) != 1)
+        return FALSE;
+
+    /* TDLS persistent group re-invocation not supported */
+    if ((dev_info_flags >> 13) & 1)
+        return FALSE;
+
+    /* All other flags indicate support but not a requirement for something
+     * so not preserving them in the IEs IWD eventually sends doesn't break
+     * basic functionality.
+     */
+
+    if (ext_capability && ext_capability_len != 2)
+        return FALSE;
+
+    if (!out_wfd)
+        return TRUE;
+
+    out_wfd->source = NM_IN_SET(dev_info_flags & 3, 0, 3);
+    out_wfd->sink   = NM_IN_SET(dev_info_flags & 3, 1, 3);
+    out_wfd->port   = (dev_info[2] << 8) | dev_info[3];
+    out_wfd->has_audio =
+        out_wfd->sink ? ((dev_info_flags >> 10) & 1) == 0 : (((dev_info_flags >> 11) & 1) == 1);
+    out_wfd->has_uibc = ext_capability && (ext_capability[1] & 1) == 1;
+    out_wfd->has_cp   = ((dev_info_flags >> 8) & 1) == 1;
+    return TRUE;
+}
+
+GBytes *
+nm_wifi_utils_build_wfd_ies(const NMIwdWfdInfo *wfd)
+{
+    uint8_t  data[64];
+    uint8_t *ptr = data;
+
+    *ptr++ = WFD_SUBELEM_WFD_DEVICE_INFORMATION;
+    *ptr++ = 0; /* WFD Subelement length */
+    *ptr++ = 6;
+    *ptr++ = 0;                                               /* WFD Device Information bitmap: */
+    *ptr++ = (wfd->source ? (wfd->sink ? 3 : 0) : 1) | 0x10 | /* WFD Session Available */
+             (wfd->has_cp ? 0x100 : 0) | (wfd->has_audio ? 0 : 0x400);
+    *ptr++ = wfd->port >> 8;
+    *ptr++ = wfd->port & 255;
+    *ptr++ = 0; /* WFD Device Maximum throughput */
+    *ptr++ = 10;
+
+    if (wfd->has_uibc) {
+        *ptr++ = WFD_SUBELEM_EXTENDED_CAPABILITY;
+        *ptr++ = 0; /* WFD Subelement length */
+        *ptr++ = 2;
+        *ptr++ = 0x00; /* WFD Extended Capability Bitmap: */
+        *ptr++ = 0x10; /* UIBC Support */
+    }
+
+    return g_bytes_new(data, ptr - data);
+}
+
+bool
+nm_wifi_utils_wfd_info_eq(const NMIwdWfdInfo *a, const NMIwdWfdInfo *b)
+{
+    if (!a || !b)
+        return a == b;
+
+    return a->source == b->source && a->sink == b->sink && a->port == b->port
+           && a->has_audio == b->has_audio && a->has_uibc == b->has_uibc && a->has_cp == b->has_cp;
+}
diff --git a/src/core/devices/wifi/nm-wifi-utils.h b/src/core/devices/wifi/nm-wifi-utils.h
index 2664c03e..1d46a900 100644
--- a/src/core/devices/wifi/nm-wifi-utils.h
+++ b/src/core/devices/wifi/nm-wifi-utils.h
@@ -20,8 +20,17 @@ typedef enum {
     NM_IWD_NETWORK_SECURITY_8021X,
 } NMIwdNetworkSecurity;
 
-gboolean nm_wifi_utils_complete_connection(GBytes *      ssid,
-                                           const char *  bssid,
+typedef struct {
+    bool     source;
+    bool     sink;
+    uint16_t port;
+    bool     has_audio;
+    bool     has_uibc;
+    bool     has_cp;
+} NMIwdWfdInfo;
+
+gboolean nm_wifi_utils_complete_connection(GBytes       *ssid,
+                                           const char   *bssid,
                                            _NM80211Mode  mode,
                                            guint32       ap_freq,
                                            guint32       flags,
@@ -29,18 +38,22 @@ gboolean nm_wifi_utils_complete_connection(GBytes *      ssid,
                                            guint32       rsn_flags,
                                            NMConnection *connection,
                                            gboolean      lock_bssid,
-                                           GError **     error);
+                                           GError      **error);
 
 gboolean nm_wifi_utils_is_manf_default_ssid(GBytes *ssid);
 
-gboolean nm_wifi_connection_get_iwd_ssid_and_security(NMConnection *        connection,
-                                                      char **               ssid,
+gboolean nm_wifi_connection_get_iwd_ssid_and_security(NMConnection         *connection,
+                                                      char                **ssid,
                                                       NMIwdNetworkSecurity *security);
-char *   nm_wifi_utils_get_iwd_config_filename(const char *         ssid,
+char    *nm_wifi_utils_get_iwd_config_filename(const char          *ssid,
                                                gssize               ssid_len,
                                                NMIwdNetworkSecurity security);
 
 GKeyFile *
 nm_wifi_utils_connection_to_iwd_config(NMConnection *conn, char **out_filename, GError **error);
 
+bool    nm_wifi_utils_parse_wfd_ies(GBytes *ies, NMIwdWfdInfo *out_wfd);
+GBytes *nm_wifi_utils_build_wfd_ies(const NMIwdWfdInfo *wfd);
+bool    nm_wifi_utils_wfd_info_eq(const NMIwdWfdInfo *a, const NMIwdWfdInfo *b);
+
 #endif /* __NM_WIFI_UTILS_H__ */
diff --git a/src/core/devices/wifi/tests/test-devices-wifi.c b/src/core/devices/wifi/tests/test-devices-wifi.c
index 5d1167cf..69d365e3 100644
--- a/src/core/devices/wifi/tests/test-devices-wifi.c
+++ b/src/core/devices/wifi/tests/test-devices-wifi.c
@@ -47,18 +47,18 @@
     }
 
 static gboolean
-complete_connection(const char *  ssid,
-                    const char *  bssid,
+complete_connection(const char   *ssid,
+                    const char   *bssid,
                     _NM80211Mode  mode,
                     guint32       flags,
                     guint32       wpa_flags,
                     guint32       rsn_flags,
                     gboolean      lock_bssid,
                     NMConnection *src,
-                    GError **     error)
+                    GError      **error)
 {
     gs_unref_bytes GBytes *ssid_b = NULL;
-    NMSettingWireless *    s_wifi;
+    NMSettingWireless     *s_wifi;
 
     /* Add a wifi setting if one doesn't exist */
     s_wifi = nm_connection_get_setting_wireless(src);
@@ -91,8 +91,8 @@ static void
 set_items(NMSetting *setting, const KeyData *items)
 {
     const KeyData *item;
-    GParamSpec *   pspec;
-    GBytes *       tmp;
+    GParamSpec    *pspec;
+    GBytes        *tmp;
 
     for (item = items; item && item->key; item++) {
         g_assert(item->key);
@@ -199,9 +199,9 @@ fill_8021x(NMConnection *connection, const KeyData items[])
 static NMConnection *
 create_basic(const char *ssid, const char *bssid, _NM80211Mode mode)
 {
-    NMConnection *     connection;
+    NMConnection      *connection;
     NMSettingWireless *s_wifi = NULL;
-    GBytes *           tmp;
+    GBytes            *tmp;
 
     connection = nm_simple_connection_new();
 
@@ -233,10 +233,10 @@ static void
 test_lock_bssid(void)
 {
     NMConnection *src, *expected;
-    const char *  bssid = "01:02:03:04:05:06";
-    const char *  ssid  = "blahblah";
+    const char   *bssid = "01:02:03:04:05:06";
+    const char   *ssid  = "blahblah";
     gboolean      success;
-    GError *      error = NULL;
+    GError       *error = NULL;
 
     src      = nm_simple_connection_new();
     success  = complete_connection(ssid,
@@ -261,10 +261,10 @@ static void
 test_open_ap_empty_connection(void)
 {
     NMConnection *src, *expected;
-    const char *  bssid = "01:02:03:04:05:06";
-    const char *  ssid  = "blahblah";
+    const char   *bssid = "01:02:03:04:05:06";
+    const char   *ssid  = "blahblah";
     gboolean      success;
-    GError *      error = NULL;
+    GError       *error = NULL;
 
     /* Test that an empty source connection is correctly filled with the
      * SSID and Infra modes of the given AP details.
@@ -293,11 +293,11 @@ static void
 test_open_ap_leap_connection_1(gconstpointer add_wifi)
 {
     NMConnection *src;
-    const char *  bssid      = "01:02:03:04:05:06";
+    const char   *bssid      = "01:02:03:04:05:06";
     const KeyData src_wsec[] = {{NM_SETTING_WIRELESS_SECURITY_LEAP_USERNAME, "Bill Smith", 0},
                                 {NULL}};
     gboolean      success;
-    GError *      error = NULL;
+    GError       *error = NULL;
 
     /* Test that a basic connection filled with a LEAP username is
      * rejected when completion is attempted with an open AP.  LEAP requires
@@ -330,10 +330,10 @@ static void
 test_open_ap_leap_connection_2(void)
 {
     NMConnection *src;
-    const char *  bssid      = "01:02:03:04:05:06";
+    const char   *bssid      = "01:02:03:04:05:06";
     const KeyData src_wsec[] = {{NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "ieee8021x", 0}, {NULL}};
     gboolean      success;
-    GError *      error = NULL;
+    GError       *error = NULL;
 
     /* Test that a basic connection specifying IEEE8021x security (ie, Dynamic
      * WEP or LEAP) is rejected when completion is attempted with an open AP.
@@ -364,14 +364,14 @@ static void
 test_open_ap_wep_connection(gconstpointer add_wifi)
 {
     NMConnection *src;
-    const char *  bssid      = "01:02:03:04:05:06";
+    const char   *bssid      = "01:02:03:04:05:06";
     const KeyData src_wsec[] = {
         {NM_SETTING_WIRELESS_SECURITY_WEP_KEY0, "11111111111111111111111111", 0},
         {NM_SETTING_WIRELESS_SECURITY_WEP_TX_KEYIDX, NULL, 0},
         {NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open", 0},
         {NULL}};
     gboolean success;
-    GError * error = NULL;
+    GError  *error = NULL;
 
     /* Test that a static WEP connection is rejected when completion is
      * attempted with an open AP.
@@ -399,8 +399,8 @@ test_open_ap_wep_connection(gconstpointer add_wifi)
 /*****************************************************************************/
 
 static void
-test_ap_wpa_psk_connection_base(const char *  key_mgmt,
-                                const char *  auth_alg,
+test_ap_wpa_psk_connection_base(const char   *key_mgmt,
+                                const char   *auth_alg,
                                 guint32       flags,
                                 guint32       wpa_flags,
                                 guint32       rsn_flags,
@@ -409,8 +409,8 @@ test_ap_wpa_psk_connection_base(const char *  key_mgmt,
                                 NMConnection *expected)
 {
     NMConnection *src;
-    const char *  ssid        = "blahblah";
-    const char *  bssid       = "01:02:03:04:05:06";
+    const char   *ssid        = "blahblah";
+    const char   *bssid       = "01:02:03:04:05:06";
     const KeyData exp_wifi[]  = {{NM_SETTING_WIRELESS_SSID, ssid, 0},
                                 {NM_SETTING_WIRELESS_MODE, "infrastructure", 0},
                                 {NULL}};
@@ -419,7 +419,7 @@ test_ap_wpa_psk_connection_base(const char *  key_mgmt,
                                  {NM_SETTING_WIRELESS_SECURITY_PSK, "asdfasdfasdfasdfasdfafs", 0},
                                  {NULL}};
     gboolean      success;
-    GError *      error = NULL;
+    GError       *error = NULL;
 
     src = nm_simple_connection_new();
     if (add_wifi)
@@ -538,13 +538,13 @@ test_ap_wpa_eap_connection_base(const char *key_mgmt,
                                 guint       error_code)
 {
     NMConnection *src;
-    const char *  bssid       = "01:02:03:04:05:06";
+    const char   *bssid       = "01:02:03:04:05:06";
     const KeyData src_empty[] = {{NULL}};
     const KeyData src_wsec[]  = {{NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, key_mgmt, 0},
                                 {NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, auth_alg, 0},
                                 {NULL}};
     gboolean      success;
-    GError *      error = NULL;
+    GError       *error = NULL;
 
     src = nm_simple_connection_new();
     if (add_wifi)
@@ -738,11 +738,11 @@ static void
 test_priv_ap_empty_connection(void)
 {
     NMConnection *src, *expected;
-    const char *  bssid      = "01:02:03:04:05:06";
-    const char *  ssid       = "blahblah";
+    const char   *bssid      = "01:02:03:04:05:06";
+    const char   *ssid       = "blahblah";
     const KeyData exp_wsec[] = {{NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "none", 0}, {NULL}};
     gboolean      success;
-    GError *      error = NULL;
+    GError       *error = NULL;
 
     /* Test that an empty connection is completed to a valid Static WEP
      * connection when completed with an AP with the Privacy bit set.
@@ -774,9 +774,9 @@ static void
 test_priv_ap_leap_connection_1(gconstpointer add_wifi)
 {
     NMConnection *src, *expected;
-    const char *  ssid          = "blahblah";
-    const char *  bssid         = "01:02:03:04:05:06";
-    const char *  leap_username = "Bill Smith";
+    const char   *ssid          = "blahblah";
+    const char   *bssid         = "01:02:03:04:05:06";
+    const char   *leap_username = "Bill Smith";
     const KeyData src_wsec[]    = {{NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "ieee8021x", 0},
                                 {NM_SETTING_WIRELESS_SECURITY_LEAP_USERNAME, leap_username, 0},
                                 {NULL}};
@@ -785,7 +785,7 @@ test_priv_ap_leap_connection_1(gconstpointer add_wifi)
                                 {NM_SETTING_WIRELESS_SECURITY_LEAP_USERNAME, leap_username, 0},
                                 {NULL}};
     gboolean      success;
-    GError *      error = NULL;
+    GError       *error = NULL;
 
     /* Test that an minimal LEAP connection specifying only key management and
      * the LEAP username is completed to a full LEAP connection when completed
@@ -823,12 +823,12 @@ static void
 test_priv_ap_leap_connection_2(void)
 {
     NMConnection *src;
-    const char *  bssid      = "01:02:03:04:05:06";
+    const char   *bssid      = "01:02:03:04:05:06";
     const KeyData src_wsec[] = {{NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "ieee8021x", 0},
                                 {NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "leap", 0},
                                 {NULL}};
     gboolean      success;
-    GError *      error = NULL;
+    GError       *error = NULL;
 
     /* Test that an minimal LEAP connection specifying only key management and
      * the LEAP auth alg is completed to a full LEAP connection when completed
@@ -859,8 +859,8 @@ static void
 test_priv_ap_dynamic_wep_1(void)
 {
     NMConnection *src, *expected;
-    const char *  ssid         = "blahblah";
-    const char *  bssid        = "01:02:03:04:05:06";
+    const char   *ssid         = "blahblah";
+    const char   *bssid        = "01:02:03:04:05:06";
     const KeyData src_wsec[]   = {{NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "ieee8021x", 0},
                                 {NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open", 0},
                                 {NULL}};
@@ -872,7 +872,7 @@ test_priv_ap_dynamic_wep_1(void)
                                 {NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open", 0},
                                 {NULL}};
     gboolean      success;
-    GError *      error = NULL;
+    GError       *error = NULL;
 
     /* Test that an minimal Dynamic WEP connection specifying key management,
      * the auth algorithm, and valid 802.1x setting is completed to a valid
@@ -909,8 +909,8 @@ static void
 test_priv_ap_dynamic_wep_2(void)
 {
     NMConnection *src, *expected;
-    const char *  ssid         = "blahblah";
-    const char *  bssid        = "01:02:03:04:05:06";
+    const char   *ssid         = "blahblah";
+    const char   *bssid        = "01:02:03:04:05:06";
     const KeyData src_wsec[]   = {{NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open", 0}, {NULL}};
     const KeyData both_8021x[] = {{NM_SETTING_802_1X_EAP, "peap", 0},
                                   {NM_SETTING_802_1X_IDENTITY, "Bill Smith", 0},
@@ -920,7 +920,7 @@ test_priv_ap_dynamic_wep_2(void)
                                 {NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open", 0},
                                 {NULL}};
     gboolean      success;
-    GError *      error = NULL;
+    GError       *error = NULL;
 
     /* Test that an minimal Dynamic WEP connection specifying only the auth
      * algorithm and a valid 802.1x setting is completed to a valid Dynamic
@@ -957,14 +957,14 @@ static void
 test_priv_ap_dynamic_wep_3(void)
 {
     NMConnection *src;
-    const char *  bssid       = "01:02:03:04:05:06";
+    const char   *bssid       = "01:02:03:04:05:06";
     const KeyData src_wsec[]  = {{NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "shared", 0}, {NULL}};
     const KeyData src_8021x[] = {{NM_SETTING_802_1X_EAP, "peap", 0},
                                  {NM_SETTING_802_1X_IDENTITY, "Bill Smith", 0},
                                  {NM_SETTING_802_1X_PHASE2_AUTH, "mschapv2", 0},
                                  {NULL}};
     gboolean      success;
-    GError *      error = NULL;
+    GError       *error = NULL;
 
     /* Ensure that a basic connection specifying 'shared' auth and an 802.1x
      * setting is rejected, as 802.1x is incompatible with 'shared' auth.
@@ -1086,13 +1086,13 @@ test_wpa_ap_empty_connection(gconstpointer data)
 {
     guint         idx = GPOINTER_TO_UINT(data);
     NMConnection *src, *expected;
-    const char *  bssid      = "01:02:03:04:05:06";
-    const char *  ssid       = "blahblah";
+    const char   *bssid      = "01:02:03:04:05:06";
+    const char   *ssid       = "blahblah";
     const KeyData exp_wsec[] = {{NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-psk", 0},
                                 {NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open", 0},
                                 {NULL}};
     gboolean      success;
-    GError *      error = NULL;
+    GError       *error = NULL;
 
     /* Test that a basic WPA-PSK connection specifying just key management and
      * the auth algorithm is completed successfully when given an AP with WPA
@@ -1126,14 +1126,14 @@ test_wpa_ap_leap_connection_1(gconstpointer data)
 {
     guint         idx = GPOINTER_TO_UINT(data);
     NMConnection *src;
-    const char *  ssid          = "blahblah";
-    const char *  bssid         = "01:02:03:04:05:06";
-    const char *  leap_username = "Bill Smith";
+    const char   *ssid          = "blahblah";
+    const char   *bssid         = "01:02:03:04:05:06";
+    const char   *leap_username = "Bill Smith";
     const KeyData src_wsec[]    = {{NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "ieee8021x", 0},
                                 {NM_SETTING_WIRELESS_SECURITY_LEAP_USERNAME, leap_username, 0},
                                 {NULL}};
     gboolean      success;
-    GError *      error = NULL;
+    GError       *error = NULL;
 
     /* Test that completion of a LEAP connection with a WPA-enabled AP is
      * rejected since WPA APs (usually) do not support LEAP.
@@ -1164,12 +1164,12 @@ test_wpa_ap_leap_connection_2(gconstpointer data)
 {
     guint         idx = GPOINTER_TO_UINT(data);
     NMConnection *src;
-    const char *  bssid      = "01:02:03:04:05:06";
+    const char   *bssid      = "01:02:03:04:05:06";
     const KeyData src_wsec[] = {{NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "ieee8021x", 0},
                                 {NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "leap", 0},
                                 {NULL}};
     gboolean      success;
-    GError *      error = NULL;
+    GError       *error = NULL;
 
     /* Test that completion of a LEAP connection with a WPA-enabled AP is
      * rejected since WPA APs (usually) do not support LEAP.
@@ -1200,10 +1200,10 @@ test_wpa_ap_dynamic_wep_connection(gconstpointer data)
 {
     guint         idx = GPOINTER_TO_UINT(data);
     NMConnection *src;
-    const char *  bssid      = "01:02:03:04:05:06";
+    const char   *bssid      = "01:02:03:04:05:06";
     const KeyData src_wsec[] = {{NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "ieee8021x", 0}, {NULL}};
     gboolean      success;
-    GError *      error = NULL;
+    GError       *error = NULL;
 
     /* Test that completion of a Dynamic WEP connection with a WPA-enabled AP is
      * rejected since WPA APs (usually) do not support Dynamic WEP.
@@ -1409,12 +1409,12 @@ test_strength_all(void)
 static void
 do_test_ssids_options_to_ptrarray(const char *const *ssids)
 {
-    GVariantBuilder  builder;
-    gs_unref_variant GVariant *variant     = NULL;
+    GVariantBuilder              builder;
+    gs_unref_variant GVariant   *variant   = NULL;
     gs_unref_ptrarray GPtrArray *ssids_arr = NULL;
-    gs_free_error GError *error            = NULL;
-    gsize                 len;
-    gsize                 i;
+    gs_free_error GError        *error     = NULL;
+    gsize                        len;
+    gsize                        i;
 
     g_assert(ssids);
 
@@ -1443,7 +1443,7 @@ do_test_ssids_options_to_ptrarray(const char *const *ssids)
     g_assert_cmpint(len, ==, ssids_arr->len);
     for (i = 0; i < len; i++) {
         const char *ssid  = ssids[i];
-        GBytes *    bytes = ssids_arr->pdata[i];
+        GBytes     *bytes = ssids_arr->pdata[i];
 
         g_assert(nm_g_bytes_equal_mem(bytes, ssid, strlen(ssid)));
     }