summary refs log tree commit diff
path: root/src/platform
diff options
context:
space:
mode:
Diffstat (limited to 'src/platform')
-rw-r--r--src/platform/linux/nl802154.h452
-rw-r--r--src/platform/nm-fake-platform.c14
-rw-r--r--src/platform/nm-linux-platform.c1628
-rw-r--r--src/platform/nm-netlink.c360
-rw-r--r--src/platform/nm-netlink.h68
-rw-r--r--src/platform/nm-platform-utils.c737
-rw-r--r--src/platform/nm-platform-utils.h56
-rw-r--r--src/platform/nm-platform.c521
-rw-r--r--src/platform/nm-platform.h106
-rw-r--r--src/platform/nmp-object.c351
-rw-r--r--src/platform/nmp-object.h51
-rw-r--r--src/platform/tests/test-cleanup.c2
-rw-r--r--src/platform/tests/test-common.c65
-rw-r--r--src/platform/tests/test-common.h6
-rw-r--r--src/platform/tests/test-general.c4
-rw-r--r--src/platform/tests/test-link.c243
-rw-r--r--src/platform/wifi/nm-wifi-utils.c240
-rw-r--r--src/platform/wifi/nm-wifi-utils.h84
-rw-r--r--src/platform/wifi/wifi-utils-nl80211.c (renamed from src/platform/wifi/nm-wifi-utils-nl80211.c)252
-rw-r--r--src/platform/wifi/wifi-utils-nl80211.h (renamed from src/platform/wifi/nm-wifi-utils-nl80211.h)15
-rw-r--r--src/platform/wifi/wifi-utils-private.h (renamed from src/platform/wifi/nm-wifi-utils-private.h)48
-rw-r--r--src/platform/wifi/wifi-utils-wext.c (renamed from src/platform/wifi/nm-wifi-utils-wext.c)139
-rw-r--r--src/platform/wifi/wifi-utils-wext.h (renamed from src/platform/wifi/nm-wifi-utils-wext.h)17
-rw-r--r--src/platform/wifi/wifi-utils.c231
-rw-r--r--src/platform/wifi/wifi-utils.h79
-rw-r--r--src/platform/wpan/nm-wpan-utils.c286
-rw-r--r--src/platform/wpan/nm-wpan-utils.h47
27 files changed, 1375 insertions, 4727 deletions
diff --git a/src/platform/linux/nl802154.h b/src/platform/linux/nl802154.h
deleted file mode 100644
index ddcee128..00000000
--- a/src/platform/linux/nl802154.h
+++ /dev/null
@@ -1,452 +0,0 @@
-#ifndef __NL802154_H
-#define __NL802154_H
-/*
- * 802.15.4 netlink interface public header
- *
- * Copyright 2014 Alexander Aring <aar@pengutronix.de>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- */
-
-#define NL802154_GENL_NAME "nl802154"
-
-enum nl802154_commands {
-/* don't change the order or add anything between, this is ABI! */
-/* currently we don't shipping this file via uapi, ignore the above one */
-	NL802154_CMD_UNSPEC,
-
-	NL802154_CMD_GET_WPAN_PHY,		/* can dump */
-	NL802154_CMD_SET_WPAN_PHY,
-	NL802154_CMD_NEW_WPAN_PHY,
-	NL802154_CMD_DEL_WPAN_PHY,
-
-	NL802154_CMD_GET_INTERFACE,		/* can dump */
-	NL802154_CMD_SET_INTERFACE,
-	NL802154_CMD_NEW_INTERFACE,
-	NL802154_CMD_DEL_INTERFACE,
-
-	NL802154_CMD_SET_CHANNEL,
-
-	NL802154_CMD_SET_PAN_ID,
-	NL802154_CMD_SET_SHORT_ADDR,
-
-	NL802154_CMD_SET_TX_POWER,
-	NL802154_CMD_SET_CCA_MODE,
-	NL802154_CMD_SET_CCA_ED_LEVEL,
-
-	NL802154_CMD_SET_MAX_FRAME_RETRIES,
-
-	NL802154_CMD_SET_BACKOFF_EXPONENT,
-	NL802154_CMD_SET_MAX_CSMA_BACKOFFS,
-
-	NL802154_CMD_SET_LBT_MODE,
-
-	NL802154_CMD_SET_ACKREQ_DEFAULT,
-
-	NL802154_CMD_SET_WPAN_PHY_NETNS,
-
-	/* add new commands above here */
-
-#ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
-	NL802154_CMD_SET_SEC_PARAMS,
-	NL802154_CMD_GET_SEC_KEY,		/* can dump */
-	NL802154_CMD_NEW_SEC_KEY,
-	NL802154_CMD_DEL_SEC_KEY,
-	NL802154_CMD_GET_SEC_DEV,		/* can dump */
-	NL802154_CMD_NEW_SEC_DEV,
-	NL802154_CMD_DEL_SEC_DEV,
-	NL802154_CMD_GET_SEC_DEVKEY,		/* can dump */
-	NL802154_CMD_NEW_SEC_DEVKEY,
-	NL802154_CMD_DEL_SEC_DEVKEY,
-	NL802154_CMD_GET_SEC_LEVEL,		/* can dump */
-	NL802154_CMD_NEW_SEC_LEVEL,
-	NL802154_CMD_DEL_SEC_LEVEL,
-#endif /* CONFIG_IEEE802154_NL802154_EXPERIMENTAL */
-
-	/* used to define NL802154_CMD_MAX below */
-	__NL802154_CMD_AFTER_LAST,
-	NL802154_CMD_MAX = __NL802154_CMD_AFTER_LAST - 1
-};
-
-enum nl802154_attrs {
-/* don't change the order or add anything between, this is ABI! */
-/* currently we don't shipping this file via uapi, ignore the above one */
-	NL802154_ATTR_UNSPEC,
-
-	NL802154_ATTR_WPAN_PHY,
-	NL802154_ATTR_WPAN_PHY_NAME,
-
-	NL802154_ATTR_IFINDEX,
-	NL802154_ATTR_IFNAME,
-	NL802154_ATTR_IFTYPE,
-
-	NL802154_ATTR_WPAN_DEV,
-
-	NL802154_ATTR_PAGE,
-	NL802154_ATTR_CHANNEL,
-
-	NL802154_ATTR_PAN_ID,
-	NL802154_ATTR_SHORT_ADDR,
-
-	NL802154_ATTR_TX_POWER,
-
-	NL802154_ATTR_CCA_MODE,
-	NL802154_ATTR_CCA_OPT,
-	NL802154_ATTR_CCA_ED_LEVEL,
-
-	NL802154_ATTR_MAX_FRAME_RETRIES,
-
-	NL802154_ATTR_MAX_BE,
-	NL802154_ATTR_MIN_BE,
-	NL802154_ATTR_MAX_CSMA_BACKOFFS,
-
-	NL802154_ATTR_LBT_MODE,
-
-	NL802154_ATTR_GENERATION,
-
-	NL802154_ATTR_CHANNELS_SUPPORTED,
-	NL802154_ATTR_SUPPORTED_CHANNEL,
-
-	NL802154_ATTR_EXTENDED_ADDR,
-
-	NL802154_ATTR_WPAN_PHY_CAPS,
-
-	NL802154_ATTR_SUPPORTED_COMMANDS,
-
-	NL802154_ATTR_ACKREQ_DEFAULT,
-
-	NL802154_ATTR_PAD,
-
-	NL802154_ATTR_PID,
-	NL802154_ATTR_NETNS_FD,
-
-	/* add attributes here, update the policy in nl802154.c */
-
-#ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
-	NL802154_ATTR_SEC_ENABLED,
-	NL802154_ATTR_SEC_OUT_LEVEL,
-	NL802154_ATTR_SEC_OUT_KEY_ID,
-	NL802154_ATTR_SEC_FRAME_COUNTER,
-
-	NL802154_ATTR_SEC_LEVEL,
-	NL802154_ATTR_SEC_DEVICE,
-	NL802154_ATTR_SEC_DEVKEY,
-	NL802154_ATTR_SEC_KEY,
-#endif /* CONFIG_IEEE802154_NL802154_EXPERIMENTAL */
-
-	__NL802154_ATTR_AFTER_LAST,
-	NL802154_ATTR_MAX = __NL802154_ATTR_AFTER_LAST - 1
-};
-
-enum nl802154_iftype {
-	/* for backwards compatibility TODO */
-	NL802154_IFTYPE_UNSPEC = -1,
-
-	NL802154_IFTYPE_NODE,
-	NL802154_IFTYPE_MONITOR,
-	NL802154_IFTYPE_COORD,
-
-	/* keep last */
-	NUM_NL802154_IFTYPES,
-	NL802154_IFTYPE_MAX = NUM_NL802154_IFTYPES - 1
-};
-
-/**
- * enum nl802154_wpan_phy_capability_attr - wpan phy capability attributes
- *
- * @__NL802154_CAP_ATTR_INVALID: attribute number 0 is reserved
- * @NL802154_CAP_ATTR_CHANNELS: a nested attribute for nl802154_channel_attr
- * @NL802154_CAP_ATTR_TX_POWERS: a nested attribute for
- *	nl802154_wpan_phy_tx_power
- * @NL802154_CAP_ATTR_MIN_CCA_ED_LEVEL: minimum value for cca_ed_level
- * @NL802154_CAP_ATTR_MAX_CCA_ED_LEVEL: maxmimum value for cca_ed_level
- * @NL802154_CAP_ATTR_CCA_MODES: nl802154_cca_modes flags
- * @NL802154_CAP_ATTR_CCA_OPTS: nl802154_cca_opts flags
- * @NL802154_CAP_ATTR_MIN_MINBE: minimum of minbe value
- * @NL802154_CAP_ATTR_MAX_MINBE: maximum of minbe value
- * @NL802154_CAP_ATTR_MIN_MAXBE: minimum of maxbe value
- * @NL802154_CAP_ATTR_MAX_MINBE: maximum of maxbe value
- * @NL802154_CAP_ATTR_MIN_CSMA_BACKOFFS: minimum of csma backoff value
- * @NL802154_CAP_ATTR_MAX_CSMA_BACKOFFS: maximum of csma backoffs value
- * @NL802154_CAP_ATTR_MIN_FRAME_RETRIES: minimum of frame retries value
- * @NL802154_CAP_ATTR_MAX_FRAME_RETRIES: maximum of frame retries value
- * @NL802154_CAP_ATTR_IFTYPES: nl802154_iftype flags
- * @NL802154_CAP_ATTR_LBT: nl802154_supported_bool_states flags
- * @NL802154_CAP_ATTR_MAX: highest cap attribute currently defined
- * @__NL802154_CAP_ATTR_AFTER_LAST: internal use
- */
-enum nl802154_wpan_phy_capability_attr {
-	__NL802154_CAP_ATTR_INVALID,
-
-	NL802154_CAP_ATTR_IFTYPES,
-
-	NL802154_CAP_ATTR_CHANNELS,
-	NL802154_CAP_ATTR_TX_POWERS,
-
-	NL802154_CAP_ATTR_CCA_ED_LEVELS,
-	NL802154_CAP_ATTR_CCA_MODES,
-	NL802154_CAP_ATTR_CCA_OPTS,
-
-	NL802154_CAP_ATTR_MIN_MINBE,
-	NL802154_CAP_ATTR_MAX_MINBE,
-
-	NL802154_CAP_ATTR_MIN_MAXBE,
-	NL802154_CAP_ATTR_MAX_MAXBE,
-
-	NL802154_CAP_ATTR_MIN_CSMA_BACKOFFS,
-	NL802154_CAP_ATTR_MAX_CSMA_BACKOFFS,
-
-	NL802154_CAP_ATTR_MIN_FRAME_RETRIES,
-	NL802154_CAP_ATTR_MAX_FRAME_RETRIES,
-
-	NL802154_CAP_ATTR_LBT,
-
-	/* keep last */
-	__NL802154_CAP_ATTR_AFTER_LAST,
-	NL802154_CAP_ATTR_MAX = __NL802154_CAP_ATTR_AFTER_LAST - 1
-};
-
-/**
- * enum nl802154_cca_modes - cca modes
- *
- * @__NL802154_CCA_INVALID: cca mode number 0 is reserved
- * @NL802154_CCA_ENERGY: Energy above threshold
- * @NL802154_CCA_CARRIER: Carrier sense only
- * @NL802154_CCA_ENERGY_CARRIER: Carrier sense with energy above threshold
- * @NL802154_CCA_ALOHA: CCA shall always report an idle medium
- * @NL802154_CCA_UWB_SHR: UWB preamble sense based on the SHR of a frame
- * @NL802154_CCA_UWB_MULTIPLEXED: UWB preamble sense based on the packet with
- *	the multiplexed preamble
- * @__NL802154_CCA_ATTR_AFTER_LAST: Internal
- * @NL802154_CCA_ATTR_MAX: Maximum CCA attribute number
- */
-enum nl802154_cca_modes {
-	__NL802154_CCA_INVALID,
-	NL802154_CCA_ENERGY,
-	NL802154_CCA_CARRIER,
-	NL802154_CCA_ENERGY_CARRIER,
-	NL802154_CCA_ALOHA,
-	NL802154_CCA_UWB_SHR,
-	NL802154_CCA_UWB_MULTIPLEXED,
-
-	/* keep last */
-	__NL802154_CCA_ATTR_AFTER_LAST,
-	NL802154_CCA_ATTR_MAX = __NL802154_CCA_ATTR_AFTER_LAST - 1
-};
-
-/**
- * enum nl802154_cca_opts - additional options for cca modes
- *
- * @NL802154_CCA_OPT_ENERGY_CARRIER_OR: NL802154_CCA_ENERGY_CARRIER with OR
- * @NL802154_CCA_OPT_ENERGY_CARRIER_AND: NL802154_CCA_ENERGY_CARRIER with AND
- */
-enum nl802154_cca_opts {
-	NL802154_CCA_OPT_ENERGY_CARRIER_AND,
-	NL802154_CCA_OPT_ENERGY_CARRIER_OR,
-
-	/* keep last */
-	__NL802154_CCA_OPT_ATTR_AFTER_LAST,
-	NL802154_CCA_OPT_ATTR_MAX = __NL802154_CCA_OPT_ATTR_AFTER_LAST - 1
-};
-
-/**
- * enum nl802154_supported_bool_states - bool states for bool capability entry
- *
- * @NL802154_SUPPORTED_BOOL_FALSE: indicates to set false
- * @NL802154_SUPPORTED_BOOL_TRUE: indicates to set true
- * @__NL802154_SUPPORTED_BOOL_INVALD: reserved
- * @NL802154_SUPPORTED_BOOL_BOTH: indicates to set true and false
- * @__NL802154_SUPPORTED_BOOL_AFTER_LAST: Internal
- * @NL802154_SUPPORTED_BOOL_MAX: highest value for bool states
- */
-enum nl802154_supported_bool_states {
-	NL802154_SUPPORTED_BOOL_FALSE,
-	NL802154_SUPPORTED_BOOL_TRUE,
-	/* to handle them in a mask */
-	__NL802154_SUPPORTED_BOOL_INVALD,
-	NL802154_SUPPORTED_BOOL_BOTH,
-
-	/* keep last */
-	__NL802154_SUPPORTED_BOOL_AFTER_LAST,
-	NL802154_SUPPORTED_BOOL_MAX = __NL802154_SUPPORTED_BOOL_AFTER_LAST - 1
-};
-
-#ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
-
-enum nl802154_dev_addr_modes {
-	NL802154_DEV_ADDR_NONE,
-	__NL802154_DEV_ADDR_INVALID,
-	NL802154_DEV_ADDR_SHORT,
-	NL802154_DEV_ADDR_EXTENDED,
-
-	/* keep last */
-	__NL802154_DEV_ADDR_AFTER_LAST,
-	NL802154_DEV_ADDR_MAX = __NL802154_DEV_ADDR_AFTER_LAST - 1
-};
-
-enum nl802154_dev_addr_attrs {
-	NL802154_DEV_ADDR_ATTR_UNSPEC,
-
-	NL802154_DEV_ADDR_ATTR_PAN_ID,
-	NL802154_DEV_ADDR_ATTR_MODE,
-	NL802154_DEV_ADDR_ATTR_SHORT,
-	NL802154_DEV_ADDR_ATTR_EXTENDED,
-	NL802154_DEV_ADDR_ATTR_PAD,
-
-	/* keep last */
-	__NL802154_DEV_ADDR_ATTR_AFTER_LAST,
-	NL802154_DEV_ADDR_ATTR_MAX = __NL802154_DEV_ADDR_ATTR_AFTER_LAST - 1
-};
-
-enum nl802154_key_id_modes {
-	NL802154_KEY_ID_MODE_IMPLICIT,
-	NL802154_KEY_ID_MODE_INDEX,
-	NL802154_KEY_ID_MODE_INDEX_SHORT,
-	NL802154_KEY_ID_MODE_INDEX_EXTENDED,
-
-	/* keep last */
-	__NL802154_KEY_ID_MODE_AFTER_LAST,
-	NL802154_KEY_ID_MODE_MAX = __NL802154_KEY_ID_MODE_AFTER_LAST - 1
-};
-
-enum nl802154_key_id_attrs {
-	NL802154_KEY_ID_ATTR_UNSPEC,
-
-	NL802154_KEY_ID_ATTR_MODE,
-	NL802154_KEY_ID_ATTR_INDEX,
-	NL802154_KEY_ID_ATTR_IMPLICIT,
-	NL802154_KEY_ID_ATTR_SOURCE_SHORT,
-	NL802154_KEY_ID_ATTR_SOURCE_EXTENDED,
-	NL802154_KEY_ID_ATTR_PAD,
-
-	/* keep last */
-	__NL802154_KEY_ID_ATTR_AFTER_LAST,
-	NL802154_KEY_ID_ATTR_MAX = __NL802154_KEY_ID_ATTR_AFTER_LAST - 1
-};
-
-enum nl802154_seclevels {
-	NL802154_SECLEVEL_NONE,
-	NL802154_SECLEVEL_MIC32,
-	NL802154_SECLEVEL_MIC64,
-	NL802154_SECLEVEL_MIC128,
-	NL802154_SECLEVEL_ENC,
-	NL802154_SECLEVEL_ENC_MIC32,
-	NL802154_SECLEVEL_ENC_MIC64,
-	NL802154_SECLEVEL_ENC_MIC128,
-
-	/* keep last */
-	__NL802154_SECLEVEL_AFTER_LAST,
-	NL802154_SECLEVEL_MAX = __NL802154_SECLEVEL_AFTER_LAST - 1
-};
-
-enum nl802154_frames {
-	NL802154_FRAME_BEACON,
-	NL802154_FRAME_DATA,
-	NL802154_FRAME_ACK,
-	NL802154_FRAME_CMD,
-
-	/* keep last */
-	__NL802154_FRAME_AFTER_LAST,
-	NL802154_FRAME_MAX = __NL802154_FRAME_AFTER_LAST - 1
-};
-
-enum nl802154_cmd_frames {
-	__NL802154_CMD_FRAME_INVALID,
-	NL802154_CMD_FRAME_ASSOC_REQUEST,
-	NL802154_CMD_FRAME_ASSOC_RESPONSE,
-	NL802154_CMD_FRAME_DISASSOC_NOTIFY,
-	NL802154_CMD_FRAME_DATA_REQUEST,
-	NL802154_CMD_FRAME_PAN_ID_CONFLICT_NOTIFY,
-	NL802154_CMD_FRAME_ORPHAN_NOTIFY,
-	NL802154_CMD_FRAME_BEACON_REQUEST,
-	NL802154_CMD_FRAME_COORD_REALIGNMENT,
-	NL802154_CMD_FRAME_GTS_REQUEST,
-
-	/* keep last */
-	__NL802154_CMD_FRAME_AFTER_LAST,
-	NL802154_CMD_FRAME_MAX = __NL802154_CMD_FRAME_AFTER_LAST - 1
-};
-
-enum nl802154_seclevel_attrs {
-	NL802154_SECLEVEL_ATTR_UNSPEC,
-
-	NL802154_SECLEVEL_ATTR_LEVELS,
-	NL802154_SECLEVEL_ATTR_FRAME,
-	NL802154_SECLEVEL_ATTR_CMD_FRAME,
-	NL802154_SECLEVEL_ATTR_DEV_OVERRIDE,
-
-	/* keep last */
-	__NL802154_SECLEVEL_ATTR_AFTER_LAST,
-	NL802154_SECLEVEL_ATTR_MAX = __NL802154_SECLEVEL_ATTR_AFTER_LAST - 1
-};
-
-/* TODO what is this? couldn't find in mib */
-enum {
-	NL802154_DEVKEY_IGNORE,
-	NL802154_DEVKEY_RESTRICT,
-	NL802154_DEVKEY_RECORD,
-
-	/* keep last */
-	__NL802154_DEVKEY_AFTER_LAST,
-	NL802154_DEVKEY_MAX = __NL802154_DEVKEY_AFTER_LAST - 1
-};
-
-enum nl802154_dev {
-	NL802154_DEV_ATTR_UNSPEC,
-
-	NL802154_DEV_ATTR_FRAME_COUNTER,
-	NL802154_DEV_ATTR_PAN_ID,
-	NL802154_DEV_ATTR_SHORT_ADDR,
-	NL802154_DEV_ATTR_EXTENDED_ADDR,
-	NL802154_DEV_ATTR_SECLEVEL_EXEMPT,
-	NL802154_DEV_ATTR_KEY_MODE,
-	NL802154_DEV_ATTR_PAD,
-
-	/* keep last */
-	__NL802154_DEV_ATTR_AFTER_LAST,
-	NL802154_DEV_ATTR_MAX = __NL802154_DEV_ATTR_AFTER_LAST - 1
-};
-
-enum nl802154_devkey {
-	NL802154_DEVKEY_ATTR_UNSPEC,
-
-	NL802154_DEVKEY_ATTR_FRAME_COUNTER,
-	NL802154_DEVKEY_ATTR_EXTENDED_ADDR,
-	NL802154_DEVKEY_ATTR_ID,
-	NL802154_DEVKEY_ATTR_PAD,
-
-	/* keep last */
-	__NL802154_DEVKEY_ATTR_AFTER_LAST,
-	NL802154_DEVKEY_ATTR_MAX = __NL802154_DEVKEY_ATTR_AFTER_LAST - 1
-};
-
-enum nl802154_key {
-	NL802154_KEY_ATTR_UNSPEC,
-
-	NL802154_KEY_ATTR_ID,
-	NL802154_KEY_ATTR_USAGE_FRAMES,
-	NL802154_KEY_ATTR_USAGE_CMDS,
-	NL802154_KEY_ATTR_BYTES,
-
-	/* keep last */
-	__NL802154_KEY_ATTR_AFTER_LAST,
-	NL802154_KEY_ATTR_MAX = __NL802154_KEY_ATTR_AFTER_LAST - 1
-};
-
-#define NL802154_KEY_SIZE		16
-#define NL802154_CMD_FRAME_NR_IDS	256
-
-#endif /* CONFIG_IEEE802154_NL802154_EXPERIMENTAL */
-
-#endif /* __NL802154_H */
diff --git a/src/platform/nm-fake-platform.c b/src/platform/nm-fake-platform.c
index 82f9e2fb..f8f4627e 100644
--- a/src/platform/nm-fake-platform.c
+++ b/src/platform/nm-fake-platform.c
@@ -602,6 +602,12 @@ link_set_mtu (NMPlatform *platform, int ifindex, guint32 mtu)
 	return NM_PLATFORM_ERROR_SUCCESS;
 }
 
+static gboolean
+link_set_sriov_num_vfs (NMPlatform *platform, int ifindex, guint num_vfs)
+{
+	return TRUE;
+}
+
 static const char *
 link_get_udi (NMPlatform *platform, int ifindex)
 {
@@ -887,6 +893,12 @@ wifi_get_bssid (NMPlatform *platform, int ifindex, guint8 *bssid)
 	return FALSE;
 }
 
+static GByteArray *
+wifi_get_ssid (NMPlatform *platform, int ifindex)
+{
+	return NULL;
+}
+
 static guint32
 wifi_get_frequency (NMPlatform *platform, int ifindex)
 {
@@ -1410,6 +1422,7 @@ nm_fake_platform_class_init (NMFakePlatformClass *klass)
 
 	platform_class->link_set_address = link_set_address;
 	platform_class->link_set_mtu = link_set_mtu;
+	platform_class->link_set_sriov_num_vfs = link_set_sriov_num_vfs;
 
 	platform_class->link_get_driver_info = link_get_driver_info;
 
@@ -1429,6 +1442,7 @@ nm_fake_platform_class_init (NMFakePlatformClass *klass)
 
 	platform_class->wifi_get_capabilities = wifi_get_capabilities;
 	platform_class->wifi_get_bssid = wifi_get_bssid;
+	platform_class->wifi_get_ssid = wifi_get_ssid;
 	platform_class->wifi_get_frequency = wifi_get_frequency;
 	platform_class->wifi_get_quality = wifi_get_quality;
 	platform_class->wifi_get_rate = wifi_get_rate;
diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c
index e73d5d8c..9bd662a1 100644
--- a/src/platform/nm-linux-platform.c
+++ b/src/platform/nm-linux-platform.c
@@ -15,7 +15,7 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * Copyright (C) 2012 - 2018 Red Hat, Inc.
+ * Copyright (C) 2012 - 2017 Red Hat, Inc.
  */
 #include "nm-default.h"
 
@@ -44,18 +44,15 @@
 #include "nm-core-internal.h"
 #include "nm-setting-vlan.h"
 
-#include "nm-utils/nm-secret-utils.h"
 #include "nm-netlink.h"
 #include "nm-core-utils.h"
 #include "nmp-object.h"
 #include "nmp-netns.h"
 #include "nm-platform-utils.h"
 #include "nm-platform-private.h"
-#include "wifi/nm-wifi-utils.h"
-#include "wifi/nm-wifi-utils-wext.h"
-#include "wpan/nm-wpan-utils.h"
+#include "wifi/wifi-utils.h"
+#include "wifi/wifi-utils-wext.h"
 #include "nm-utils/unaligned.h"
-#include "nm-utils/nm-io-utils.h"
 #include "nm-utils/nm-udev-utils.h"
 
 /*****************************************************************************/
@@ -157,13 +154,6 @@ G_STATIC_ASSERT (RTA_MAX == (__RTA_MAX - 1));
 
 /*****************************************************************************/
 
-/* Appeared in in kernel prior to 3.13 dated 19 January, 2014 */
-#ifndef ARPHRD_6LOWPAN
-#define ARPHRD_6LOWPAN 825
-#endif
-
-/*****************************************************************************/
-
 #define IFLA_MACSEC_UNSPEC              0
 #define IFLA_MACSEC_SCI                 1
 #define IFLA_MACSEC_PORT                2
@@ -183,79 +173,63 @@ G_STATIC_ASSERT (RTA_MAX == (__RTA_MAX - 1));
 
 /*****************************************************************************/
 
-#define WG_CMD_GET_DEVICE 0
-#define WG_CMD_SET_DEVICE 1
-
-#define WGDEVICE_A_UNSPEC                      0
-#define WGDEVICE_A_IFINDEX                     1
-#define WGDEVICE_A_IFNAME                      2
-#define WGDEVICE_A_PRIVATE_KEY                 3
-#define WGDEVICE_A_PUBLIC_KEY                  4
-#define WGDEVICE_A_FLAGS                       5
-#define WGDEVICE_A_LISTEN_PORT                 6
-#define WGDEVICE_A_FWMARK                      7
-#define WGDEVICE_A_PEERS                       8
-#define WGDEVICE_A_MAX                         8
-
-#define WGPEER_A_UNSPEC                        0
-#define WGPEER_A_PUBLIC_KEY                    1
-#define WGPEER_A_PRESHARED_KEY                 2
-#define WGPEER_A_FLAGS                         3
-#define WGPEER_A_ENDPOINT                      4
-#define WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL 5
-#define WGPEER_A_LAST_HANDSHAKE_TIME           6
-#define WGPEER_A_RX_BYTES                      7
-#define WGPEER_A_TX_BYTES                      8
-#define WGPEER_A_ALLOWEDIPS                    9
-#define WGPEER_A_MAX                           9
-
-#define WGALLOWEDIP_A_UNSPEC                   0
-#define WGALLOWEDIP_A_FAMILY                   1
-#define WGALLOWEDIP_A_IPADDR                   2
-#define WGALLOWEDIP_A_CIDR_MASK                3
-#define WGALLOWEDIP_A_MAX                      3
+#define _NMLOG_PREFIX_NAME                "platform-linux"
+#define _NMLOG_DOMAIN                     LOGD_PLATFORM
+#define _NMLOG2_DOMAIN                    LOGD_PLATFORM
+#define _NMLOG(level, ...)                _LOG     (       level, _NMLOG_DOMAIN,  platform, __VA_ARGS__)
+#define _NMLOG_err(errsv, level, ...)     _LOG_err (errsv, level, _NMLOG_DOMAIN,  platform, __VA_ARGS__)
+#define _NMLOG2(level, ...)               _LOG     (       level, _NMLOG2_DOMAIN, NULL,     __VA_ARGS__)
+#define _NMLOG2_err(errsv, level, ...)    _LOG_err (errsv, level, _NMLOG2_DOMAIN, NULL,     __VA_ARGS__)
 
-/*****************************************************************************/
+#define _LOG_print(__level, __domain, __errsv, self, ...) \
+    G_STMT_START { \
+        char __prefix[32]; \
+        const char *__p_prefix = _NMLOG_PREFIX_NAME; \
+        NMPlatform *const __self = (self); \
+        \
+        if (__self && nm_platform_get_log_with_ptr (__self)) { \
+            g_snprintf (__prefix, sizeof (__prefix), "%s[%p]", _NMLOG_PREFIX_NAME, __self); \
+            __p_prefix = __prefix; \
+        } \
+        _nm_log (__level, __domain, __errsv, NULL, NULL, \
+                 "%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \
+                 __p_prefix _NM_UTILS_MACRO_REST (__VA_ARGS__)); \
+    } G_STMT_END
 
-/* Redefine VF enums and structures that are not available on older kernels. */
-
-#define IFLA_VF_UNSPEC                 0
-#define IFLA_VF_MAC                    1
-#define IFLA_VF_VLAN                   2
-#define IFLA_VF_TX_RATE                3
-#define IFLA_VF_SPOOFCHK               4
-#define IFLA_VF_LINK_STATE             5
-#define IFLA_VF_RATE                   6
-#define IFLA_VF_RSS_QUERY_EN           7
-#define IFLA_VF_STATS                  8
-#define IFLA_VF_TRUST                  9
-#define IFLA_VF_IB_NODE_GUID           10
-#define IFLA_VF_IB_PORT_GUID           11
-#define IFLA_VF_VLAN_LIST              12
-
-#define IFLA_VF_VLAN_INFO_UNSPEC       0
-#define IFLA_VF_VLAN_INFO              1
-
-/* valid for TRUST, SPOOFCHK, LINK_STATE, RSS_QUERY_EN */
-struct _ifla_vf_setting {
-	guint32 vf;
-	guint32 setting;
-};
+#define _LOG(level, domain, self, ...) \
+    G_STMT_START { \
+        const NMLogLevel __level = (level); \
+        const NMLogDomain __domain = (domain); \
+        \
+        if (nm_logging_enabled (__level, __domain)) { \
+            _LOG_print (__level, __domain, 0, self, __VA_ARGS__); \
+        } \
+    } G_STMT_END
 
-struct _ifla_vf_rate {
-	guint32 vf;
-	guint32 min_tx_rate;
-	guint32 max_tx_rate;
-};
+#define _LOG_err(errsv, level, domain, self, ...) \
+    G_STMT_START { \
+        const NMLogLevel __level = (level); \
+        const NMLogDomain __domain = (domain); \
+        \
+        if (nm_logging_enabled (__level, __domain)) { \
+            int __errsv = (errsv); \
+            \
+            /* The %m format specifier (GNU extension) would alread allow you to specify the error
+             * message conveniently (and nm_log would get that right too). But we don't want to depend
+             * on that, so instead append the message at the end.
+             * Currently users are expected not to use %m in the format string. */ \
+            _LOG_print (__level, __domain, __errsv, self, \
+                        _NM_UTILS_MACRO_FIRST (__VA_ARGS__) ": %s (%d)" \
+                        _NM_UTILS_MACRO_REST (__VA_ARGS__), \
+                        g_strerror (__errsv), __errsv); \
+        } \
+    } G_STMT_END
 
-struct _ifla_vf_vlan_info {
-	guint32 vf;
-	guint32 vlan; /* 0 - 4095, 0 disables VLAN filter */
-	guint32 qos;
-	guint16 vlan_proto; /* VLAN protocol, either 802.1Q or 802.1ad */
-};
+#define LOG_FMT_IP_TUNNEL "adding %s '%s' parent %u local %s remote %s"
 
-/*****************************************************************************/
+/******************************************************************
+ * Forward declarations and enums
+ ******************************************************************/
 
 typedef enum {
 	INFINIBAND_ACTION_CREATE_CHILD,
@@ -333,133 +307,6 @@ typedef enum {
 	WAIT_FOR_NL_RESPONSE_RESULT_FAILED_SETNS,
 } WaitForNlResponseResult;
 
-typedef enum {
-	DELAYED_ACTION_RESPONSE_TYPE_VOID                       = 0,
-	DELAYED_ACTION_RESPONSE_TYPE_REFRESH_ALL_IN_PROGRESS    = 1,
-	DELAYED_ACTION_RESPONSE_TYPE_ROUTE_GET                  = 2,
-} DelayedActionWaitForNlResponseType;
-
-typedef struct {
-	guint32 seq_number;
-	WaitForNlResponseResult seq_result;
-	DelayedActionWaitForNlResponseType response_type;
-	gint64 timeout_abs_ns;
-	WaitForNlResponseResult *out_seq_result;
-	char **out_errmsg;
-	union {
-		int *out_refresh_all_in_progress;
-		NMPObject **out_route_get;
-		gpointer out_data;
-	} response;
-} DelayedActionWaitForNlResponseData;
-
-/*****************************************************************************/
-
-typedef struct {
-	struct nl_sock *genl;
-
-	struct nl_sock *nlh;
-	guint32 nlh_seq_next;
-#if NM_MORE_LOGGING
-	guint32 nlh_seq_last_handled;
-#endif
-	guint32 nlh_seq_last_seen;
-	GIOChannel *event_channel;
-	guint event_id;
-
-	bool pruning[_DELAYED_ACTION_IDX_REFRESH_ALL_NUM];
-
-	bool sysctl_get_warned;
-	GHashTable *sysctl_get_prev_values;
-
-	NMUdevClient *udev_client;
-
-	struct {
-		/* which delayed actions are scheduled, as marked in @flags.
-		 * Some types have additional arguments in the fields below. */
-		DelayedActionType flags;
-
-		/* counter that a refresh all action is in progress, separated
-		 * by type. */
-		int refresh_all_in_progress[_DELAYED_ACTION_IDX_REFRESH_ALL_NUM];
-
-		GPtrArray *list_master_connected;
-		GPtrArray *list_refresh_link;
-		GArray *list_wait_for_nl_response;
-
-		int is_handling;
-	} delayed_action;
-} NMLinuxPlatformPrivate;
-
-struct _NMLinuxPlatform {
-	NMPlatform parent;
-	NMLinuxPlatformPrivate _priv;
-};
-
-struct _NMLinuxPlatformClass {
-	NMPlatformClass parent;
-};
-
-G_DEFINE_TYPE (NMLinuxPlatform, nm_linux_platform, NM_TYPE_PLATFORM)
-
-#define NM_LINUX_PLATFORM_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMLinuxPlatform, NM_IS_LINUX_PLATFORM, NMPlatform)
-
-/*****************************************************************************/
-
-#define _NMLOG_PREFIX_NAME                "platform-linux"
-#define _NMLOG_DOMAIN                     LOGD_PLATFORM
-#define _NMLOG2_DOMAIN                    LOGD_PLATFORM
-#define _NMLOG(level, ...)                _LOG     (       level, _NMLOG_DOMAIN,  platform, __VA_ARGS__)
-#define _NMLOG_err(errsv, level, ...)     _LOG_err (errsv, level, _NMLOG_DOMAIN,  platform, __VA_ARGS__)
-#define _NMLOG2(level, ...)               _LOG     (       level, _NMLOG2_DOMAIN, NULL,     __VA_ARGS__)
-#define _NMLOG2_err(errsv, level, ...)    _LOG_err (errsv, level, _NMLOG2_DOMAIN, NULL,     __VA_ARGS__)
-
-#define _LOG_print(__level, __domain, __errsv, self, ...) \
-    G_STMT_START { \
-        char __prefix[32]; \
-        const char *__p_prefix = _NMLOG_PREFIX_NAME; \
-        NMPlatform *const __self = (self); \
-        \
-        if (__self && nm_platform_get_log_with_ptr (__self)) { \
-            g_snprintf (__prefix, sizeof (__prefix), "%s[%p]", _NMLOG_PREFIX_NAME, __self); \
-            __p_prefix = __prefix; \
-        } \
-        _nm_log (__level, __domain, __errsv, NULL, NULL, \
-                 "%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \
-                 __p_prefix _NM_UTILS_MACRO_REST (__VA_ARGS__)); \
-    } G_STMT_END
-
-#define _LOG(level, domain, self, ...) \
-    G_STMT_START { \
-        const NMLogLevel __level = (level); \
-        const NMLogDomain __domain = (domain); \
-        \
-        if (nm_logging_enabled (__level, __domain)) { \
-            _LOG_print (__level, __domain, 0, self, __VA_ARGS__); \
-        } \
-    } G_STMT_END
-
-#define _LOG_err(errsv, level, domain, self, ...) \
-    G_STMT_START { \
-        const NMLogLevel __level = (level); \
-        const NMLogDomain __domain = (domain); \
-        \
-        if (nm_logging_enabled (__level, __domain)) { \
-            int __errsv = (errsv); \
-            \
-            /* The %m format specifier (GNU extension) would alread allow you to specify the error
-             * message conveniently (and nm_log would get that right too). But we don't want to depend
-             * on that, so instead append the message at the end.
-             * Currently users are expected not to use %m in the format string. */ \
-            _LOG_print (__level, __domain, __errsv, self, \
-                        _NM_UTILS_MACRO_FIRST (__VA_ARGS__) ": %s (%d)" \
-                        _NM_UTILS_MACRO_REST (__VA_ARGS__), \
-                        g_strerror (__errsv), __errsv); \
-        } \
-    } G_STMT_END
-
-/*****************************************************************************/
-
 static void delayed_action_schedule (NMPlatform *platform, DelayedActionType action_type, gpointer user_data);
 static gboolean delayed_action_handle_all (NMPlatform *platform, gboolean read_netlink);
 static void do_request_link_no_delayed_actions (NMPlatform *platform, int ifindex, const char *name);
@@ -470,7 +317,6 @@ static void cache_on_change (NMPlatform *platform,
                              const NMPObject *obj_new);
 static void cache_prune_all (NMPlatform *platform);
 static gboolean event_handler_read_netlink (NMPlatform *platform, gboolean wait_for_acks);
-static struct nl_sock *_genl_sock (NMLinuxPlatform *platform);
 
 /*****************************************************************************/
 
@@ -687,8 +533,6 @@ static const LinkDesc linktypes[] = {
 	{ NM_LINK_TYPE_WIFI,          "wifi",        NULL,          "wlan" },
 	{ NM_LINK_TYPE_WWAN_NET,      "wwan",        NULL,          "wwan" },
 	{ NM_LINK_TYPE_WIMAX,         "wimax",       "wimax",       "wimax" },
-	{ NM_LINK_TYPE_WPAN,          "wpan",        NULL,          NULL },
-	{ NM_LINK_TYPE_6LOWPAN,       "6lowpan",     NULL,          NULL },
 
 	{ NM_LINK_TYPE_BNEP,          "bluetooth",   NULL,          "bluetooth" },
 	{ NM_LINK_TYPE_DUMMY,         "dummy",       "dummy",       NULL },
@@ -696,8 +540,6 @@ static const LinkDesc linktypes[] = {
 	{ NM_LINK_TYPE_GRETAP,        "gretap",      "gretap",      NULL },
 	{ NM_LINK_TYPE_IFB,           "ifb",         "ifb",         NULL },
 	{ NM_LINK_TYPE_IP6TNL,        "ip6tnl",      "ip6tnl",      NULL },
-	{ NM_LINK_TYPE_IP6GRE,        "ip6gre",      "ip6gre",      NULL },
-	{ NM_LINK_TYPE_IP6GRETAP,     "ip6gretap",   "ip6gretap",   NULL },
 	{ NM_LINK_TYPE_IPIP,          "ipip",        "ipip",        NULL },
 	{ NM_LINK_TYPE_LOOPBACK,      "loopback",    NULL,          NULL },
 	{ NM_LINK_TYPE_MACSEC,        "macsec",      "macsec",      NULL },
@@ -710,7 +552,6 @@ static const LinkDesc linktypes[] = {
 	{ NM_LINK_TYPE_VETH,          "veth",        "veth",        NULL },
 	{ NM_LINK_TYPE_VLAN,          "vlan",        "vlan",        "vlan" },
 	{ NM_LINK_TYPE_VXLAN,         "vxlan",       "vxlan",       "vxlan" },
-	{ NM_LINK_TYPE_WIREGUARD,     "wireguard",   "wireguard",   "wireguard" },
 
 	{ NM_LINK_TYPE_BRIDGE,        "bridge",      "bridge",      "bridge" },
 	{ NM_LINK_TYPE_BOND,          "bond",        "bond",        "bond" },
@@ -884,21 +725,19 @@ _addrtime_get_lifetimes (guint32 timestamp,
 /*****************************************************************************/
 
 static const NMPObject *
-_lookup_cached_link (const NMPCache *cache,
-                     int ifindex,
-                     gboolean *completed_from_cache,
-                     const NMPObject **link_cached)
+_lookup_cached_link (const NMPCache *cache, int ifindex, gboolean *completed_from_cache, const NMPObject **link_cached)
 {
 	const NMPObject *obj;
 
 	nm_assert (completed_from_cache && link_cached);
 
 	if (!*completed_from_cache) {
-		obj = ifindex > 0 && cache
-		      ? nmp_cache_lookup_link (cache, ifindex)
-		      : NULL;
+		obj = ifindex > 0 && cache ? nmp_cache_lookup_link (cache, ifindex) : NULL;
 
-		*link_cached = obj;
+		if (obj && obj->_link.netlink.is_in_netlink)
+			*link_cached = obj;
+		else
+			*link_cached = NULL;
 		*completed_from_cache = TRUE;
 	}
 	return *link_cached;
@@ -916,9 +755,7 @@ _linktype_read_devtype (int dirfd)
 
 	nm_assert (dirfd >= 0);
 
-	if (nm_utils_file_get_contents (dirfd, "uevent", 1*1024*1024,
-	                                NM_UTILS_FILE_GET_CONTENTS_FLAG_NONE,
-	                                &contents, NULL, NULL) < 0)
+	if (nm_utils_file_get_contents (dirfd, "uevent", 1*1024*1024, &contents, NULL, NULL) < 0)
 		return NULL;
 	for (cont = contents; cont; cont = end) {
 		end = strpbrk (cont, "\r\n");
@@ -969,7 +806,6 @@ _linktype_get_type (NMPlatform *platform,
 		 * when moving interfce to other netns). Thus here there is a tiny potential
 		 * of messing stuff up. */
 		if (   obj
-		    && obj->_link.netlink.is_in_netlink
 		    && !NM_IN_SET (obj->link.type, NM_LINK_TYPE_UNKNOWN, NM_LINK_TYPE_NONE)
 		    && nm_streq (ifname, obj->link.name)
 		    && (   !kind
@@ -1005,10 +841,6 @@ _linktype_get_type (NMPlatform *platform,
 		return NM_LINK_TYPE_IP6TNL;
 	else if (arptype == ARPHRD_PPP)
 		return NM_LINK_TYPE_PPP;
-	else if (arptype == ARPHRD_IEEE802154)
-		return NM_LINK_TYPE_WPAN;
-	else if (arptype == ARPHRD_6LOWPAN)
-		return NM_LINK_TYPE_6LOWPAN;
 
 	{
 		NMPUtilsEthtoolDriverInfo driver_info;
@@ -1053,7 +885,7 @@ _linktype_get_type (NMPlatform *platform,
 			}
 
 			/* Fallback for drivers that don't call SET_NETDEV_DEVTYPE() */
-			if (nm_wifi_utils_is_wifi (dirfd, ifname_verified))
+			if (wifi_utils_is_wifi (dirfd, ifname_verified))
 				return NM_LINK_TYPE_WIFI;
 		}
 
@@ -1121,21 +953,18 @@ _nl_addattr_l (struct nlmsghdr *n,
  * NMPObject/netlink functions
  ******************************************************************/
 
-#define _check_addr_or_return_val(tb, attr, addr_len, ret_val) \
+#define _check_addr_or_errout(tb, attr, addr_len) \
 	({ \
 	    const struct nlattr *__t = (tb)[(attr)]; \
 		\
 	    if (__t) { \
 			if (nla_len (__t) != (addr_len)) { \
-				return ret_val; \
+				goto errout; \
 			} \
 		} \
 		!!__t; \
 	})
 
-#define _check_addr_or_return_null(tb, attr, addr_len) \
-	_check_addr_or_return_val (tb, attr, addr_len, NULL)
-
 /*****************************************************************************/
 
 /* Copied and heavily modified from libnl3's inet6_parse_protinfo(). */
@@ -1162,19 +991,20 @@ _parse_af_inet6 (NMPlatform *platform,
 	gboolean token_valid = FALSE;
 	gboolean addr_gen_mode_valid = FALSE;
 	guint8 i6_addr_gen_mode_inv = 0;
+	gboolean success = FALSE;
 
 	err = nla_parse_nested (tb, IFLA_INET6_MAX, attr, policy);
 	if (err < 0)
-		return FALSE;
+		goto errout;
 
 	if (tb[IFLA_INET6_CONF] && nla_len(tb[IFLA_INET6_CONF]) % 4)
-		return FALSE;
+		goto errout;
 	if (tb[IFLA_INET6_STATS] && nla_len(tb[IFLA_INET6_STATS]) % 8)
-		return FALSE;
+		goto errout;
 	if (tb[IFLA_INET6_ICMP6STATS] && nla_len(tb[IFLA_INET6_ICMP6STATS]) % 8)
-		return FALSE;
+		goto errout;
 
-	if (_check_addr_or_return_val (tb, IFLA_INET6_TOKEN, sizeof (struct in6_addr), FALSE)) {
+	if (_check_addr_or_errout (tb, IFLA_INET6_TOKEN, sizeof (struct in6_addr))) {
 		nla_memcpy (&i6_token, tb[IFLA_INET6_TOKEN], sizeof (struct in6_addr));
 		token_valid = TRUE;
 	}
@@ -1190,11 +1020,12 @@ _parse_af_inet6 (NMPlatform *platform,
 		if (i6_addr_gen_mode_inv == 0) {
 			/* an inverse addrgenmode of zero is unexpected. We need to reserve zero
 			 * to signal "unset". */
-			return FALSE;
+			goto errout;
 		}
 		addr_gen_mode_valid = TRUE;
 	}
 
+	success = TRUE;
 	if (token_valid) {
 		*out_token_valid = token_valid;
 		nm_utils_ipv6_interface_identifier_get_from_addr (out_token, &i6_token);
@@ -1203,7 +1034,8 @@ _parse_af_inet6 (NMPlatform *platform,
 		*out_addr_gen_mode_valid = addr_gen_mode_valid;
 		*out_addr_gen_mode_inv = i6_addr_gen_mode_inv;
 	}
-	return TRUE;
+errout:
+	return success;
 }
 
 /*****************************************************************************/
@@ -1227,23 +1059,15 @@ _parse_lnk_gre (const char *kind, struct nlattr *info_data)
 	int err;
 	NMPObject *obj;
 	NMPlatformLnkGre *props;
-	gboolean is_tap;
-
-	if (!info_data || !kind)
-		return NULL;
 
-	if (nm_streq (kind, "gretap"))
-		is_tap = TRUE;
-	else if (nm_streq (kind, "gre"))
-		is_tap = FALSE;
-	else
+	if (!info_data || g_strcmp0 (kind, "gre"))
 		return NULL;
 
 	err = nla_parse_nested (tb, IFLA_GRE_MAX, info_data, policy);
 	if (err < 0)
 		return NULL;
 
-	obj = nmp_object_new (is_tap ? NMP_OBJECT_TYPE_LNK_GRETAP : NMP_OBJECT_TYPE_LNK_GRE, NULL);
+	obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_GRE, NULL);
 	props = &obj->lnk_gre;
 
 	props->parent_ifindex = tb[IFLA_GRE_LINK] ? nla_get_u32 (tb[IFLA_GRE_LINK]) : 0;
@@ -1256,7 +1080,6 @@ _parse_lnk_gre (const char *kind, struct nlattr *info_data)
 	props->tos = tb[IFLA_GRE_TOS] ? nla_get_u8 (tb[IFLA_GRE_TOS]) : 0;
 	props->ttl = tb[IFLA_GRE_TTL] ? nla_get_u8 (tb[IFLA_GRE_TTL]) : 0;
 	props->path_mtu_discovery = !tb[IFLA_GRE_PMTUDISC] || !!nla_get_u8 (tb[IFLA_GRE_PMTUDISC]);
-	props->is_tap = is_tap;
 
 	return obj;
 }
@@ -1377,79 +1200,6 @@ _parse_lnk_ip6tnl (const char *kind, struct nlattr *info_data)
 	return obj;
 }
 
-static NMPObject *
-_parse_lnk_ip6gre (const char *kind, struct nlattr *info_data)
-{
-	static const struct nla_policy policy[IFLA_GRE_MAX + 1] = {
-		[IFLA_GRE_LINK]        = { .type = NLA_U32 },
-		[IFLA_GRE_IFLAGS]      = { .type = NLA_U16 },
-		[IFLA_GRE_OFLAGS]      = { .type = NLA_U16 },
-		[IFLA_GRE_IKEY]        = { .type = NLA_U32 },
-		[IFLA_GRE_OKEY]        = { .type = NLA_U32 },
-		[IFLA_GRE_LOCAL]       = { .type = NLA_UNSPEC,
-		                             .minlen = sizeof (struct in6_addr)},
-		[IFLA_GRE_REMOTE]      = { .type = NLA_UNSPEC,
-		                             .minlen = sizeof (struct in6_addr)},
-		[IFLA_GRE_TTL]         = { .type = NLA_U8 },
-		[IFLA_GRE_ENCAP_LIMIT] = { .type = NLA_U8 },
-		[IFLA_GRE_FLOWINFO]    = { .type = NLA_U32 },
-		[IFLA_GRE_FLAGS]       = { .type = NLA_U32 },
-	};
-	struct nlattr *tb[IFLA_GRE_MAX + 1];
-	int err;
-	NMPObject *obj;
-	NMPlatformLnkIp6Tnl *props;
-	guint32 flowinfo;
-	gboolean is_tap;
-
-	if (!info_data || !kind)
-		return NULL;
-
-	if (nm_streq (kind, "ip6gre"))
-		is_tap = FALSE;
-	else if (nm_streq (kind, "ip6gretap"))
-		is_tap = TRUE;
-	else
-		return NULL;
-
-	err = nla_parse_nested (tb, IFLA_GRE_MAX, info_data, policy);
-	if (err < 0)
-		return NULL;
-
-	obj = nmp_object_new (is_tap ? NMP_OBJECT_TYPE_LNK_IP6GRETAP : NMP_OBJECT_TYPE_LNK_IP6GRE, NULL);
-	props = &obj->lnk_ip6tnl;
-	props->is_gre = TRUE;
-	props->is_tap = is_tap;
-
-	if (tb[IFLA_GRE_LINK])
-		props->parent_ifindex = nla_get_u32 (tb[IFLA_GRE_LINK]);
-	if (tb[IFLA_GRE_IFLAGS])
-		props->input_flags = ntohs (nla_get_u16 (tb[IFLA_GRE_IFLAGS]));
-	if (tb[IFLA_GRE_OFLAGS])
-		props->output_flags = ntohs (nla_get_u16 (tb[IFLA_GRE_OFLAGS]));
-	if (tb[IFLA_GRE_IKEY])
-		props->input_key = ntohl (nla_get_u32 (tb[IFLA_GRE_IKEY]));
-	if (tb[IFLA_GRE_OKEY])
-		props->output_key = ntohl (nla_get_u32 (tb[IFLA_GRE_OKEY]));
-	if (tb[IFLA_GRE_LOCAL])
-		memcpy (&props->local, nla_data (tb[IFLA_GRE_LOCAL]), sizeof (props->local));
-	if (tb[IFLA_GRE_REMOTE])
-		memcpy (&props->remote, nla_data (tb[IFLA_GRE_REMOTE]), sizeof (props->remote));
-	if (tb[IFLA_GRE_TTL])
-		props->ttl = nla_get_u8 (tb[IFLA_GRE_TTL]);
-	if (tb[IFLA_GRE_ENCAP_LIMIT])
-		props->encap_limit = nla_get_u8 (tb[IFLA_GRE_ENCAP_LIMIT]);
-	if (tb[IFLA_GRE_FLOWINFO]) {
-		flowinfo = ntohl (nla_get_u32 (tb[IFLA_GRE_FLOWINFO]));
-		props->flow_label = flowinfo & IP6_FLOWINFO_FLOWLABEL_MASK;
-		props->tclass = (flowinfo & IP6_FLOWINFO_TCLASS_MASK) >> IP6_FLOWINFO_TCLASS_SHIFT;
-	}
-	if (tb[IFLA_GRE_FLAGS])
-		props->flags = nla_get_u32 (tb[IFLA_GRE_FLAGS]);
-
-	return obj;
-}
-
 /*****************************************************************************/
 
 static NMPObject *
@@ -1913,378 +1663,6 @@ _parse_lnk_vxlan (const char *kind, struct nlattr *info_data)
 
 /*****************************************************************************/
 
-static gboolean
-_wireguard_update_from_allowed_ips_nla (NMPWireGuardAllowedIP *allowed_ip,
-                                        struct nlattr *nlattr)
-{
-	static const struct nla_policy policy[WGALLOWEDIP_A_MAX + 1] = {
-		[WGALLOWEDIP_A_FAMILY]    = { .type = NLA_U16 },
-		[WGALLOWEDIP_A_IPADDR]    = { .minlen = sizeof (struct in_addr) },
-		[WGALLOWEDIP_A_CIDR_MASK] = { .type = NLA_U8 },
-	};
-	struct nlattr *tb[WGALLOWEDIP_A_MAX + 1];
-	int family;
-	int addr_len;
-
-	if (nla_parse_nested (tb, WGALLOWEDIP_A_MAX, nlattr, policy) < 0)
-		return FALSE;
-
-	if (!tb[WGALLOWEDIP_A_FAMILY])
-		return FALSE;
-
-	family = nla_get_u16 (tb[WGALLOWEDIP_A_FAMILY]);
-	if (family == AF_INET)
-		addr_len = sizeof (in_addr_t);
-	else if (family == AF_INET6)
-		addr_len = sizeof (struct in6_addr);
-	else
-		return FALSE;
-
-	_check_addr_or_return_val (tb, WGALLOWEDIP_A_IPADDR, addr_len, FALSE);
-
-	memset (allowed_ip, 0, sizeof (NMPWireGuardAllowedIP));
-
-	allowed_ip->family = family;
-	nm_assert ((int) allowed_ip->family == family);
-
-	if (tb[WGALLOWEDIP_A_IPADDR])
-		nla_memcpy (&allowed_ip->addr, tb[WGALLOWEDIP_A_IPADDR], addr_len);
-	if (tb[WGALLOWEDIP_A_CIDR_MASK])
-		allowed_ip->mask = nla_get_u8 (tb[WGALLOWEDIP_A_CIDR_MASK]);
-
-	return TRUE;
-}
-
-typedef struct {
-	CList lst;
-	NMPWireGuardPeer data;
-} WireGuardPeerConstruct;
-
-static gboolean
-_wireguard_update_from_peers_nla (CList *peers,
-                                  GArray **p_allowed_ips,
-                                  struct nlattr *peer_attr)
-{
-	static const struct nla_policy policy[WGPEER_A_MAX + 1] = {
-		[WGPEER_A_PUBLIC_KEY]                    = { .minlen = NMP_WIREGUARD_PUBLIC_KEY_LEN },
-		[WGPEER_A_PRESHARED_KEY]                 = { },
-		[WGPEER_A_FLAGS]                         = { .type = NLA_U32 },
-		[WGPEER_A_ENDPOINT]                      = { },
-		[WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL] = { .type = NLA_U16 },
-		[WGPEER_A_LAST_HANDSHAKE_TIME]           = { },
-		[WGPEER_A_RX_BYTES]                      = { .type = NLA_U64 },
-		[WGPEER_A_TX_BYTES]                      = { .type = NLA_U64 },
-		[WGPEER_A_ALLOWEDIPS]                    = { .type = NLA_NESTED },
-	};
-	WireGuardPeerConstruct *peer_c;
-	struct nlattr *tb[WGPEER_A_MAX + 1];
-
-	if (nla_parse_nested (tb, WGPEER_A_MAX, peer_attr, policy) < 0)
-		return FALSE;
-
-	if (!tb[WGPEER_A_PUBLIC_KEY])
-		return FALSE;
-
-	/* a peer with the same public key as last peer is just a continuation for extra AllowedIPs */
-	peer_c = c_list_last_entry (peers, WireGuardPeerConstruct, lst);
-	if (   peer_c
-	    && !memcmp (nla_data (tb[WGPEER_A_PUBLIC_KEY]), peer_c->data.public_key, NMP_WIREGUARD_PUBLIC_KEY_LEN)) {
-		G_STATIC_ASSERT_EXPR (NMP_WIREGUARD_PUBLIC_KEY_LEN == sizeof (peer_c->data.public_key));
-		/* this message is a continuation of the previous peer.
-		 * Only parse WGPEER_A_ALLOWEDIPS below. */
-	}
-	else {
-		/* otherwise, start a new peer */
-		peer_c = g_slice_new0 (WireGuardPeerConstruct);
-		c_list_link_tail (peers, &peer_c->lst);
-
-		nla_memcpy (&peer_c->data.public_key, tb[WGPEER_A_PUBLIC_KEY], sizeof (peer_c->data.public_key));
-
-		if (tb[WGPEER_A_PRESHARED_KEY]) {
-			nla_memcpy (&peer_c->data.preshared_key, tb[WGPEER_A_PRESHARED_KEY], sizeof (peer_c->data.preshared_key));
-			/* FIXME(netlink-bzero-secret) */
-			nm_explicit_bzero (nla_data (tb[WGPEER_A_PRESHARED_KEY]),
-			                   nla_len (tb[WGPEER_A_PRESHARED_KEY]));
-		}
-		if (tb[WGPEER_A_ENDPOINT]) {
-			const struct sockaddr *addr = nla_data (tb[WGPEER_A_ENDPOINT]);
-			unsigned short family;
-
-			G_STATIC_ASSERT (sizeof (addr->sa_family) == sizeof (family));
-			memcpy (&family, &addr->sa_family, sizeof (addr->sa_family));
-
-			if (   family == AF_INET
-			    && nla_len (tb[WGPEER_A_ENDPOINT]) == sizeof (struct sockaddr_in)) {
-				const struct sockaddr_in *addr4 = (const struct sockaddr_in *) addr;
-
-				peer_c->data.endpoint_family = AF_INET;
-				peer_c->data.endpoint_port = unaligned_read_be16 (&addr4->sin_port);
-				peer_c->data.endpoint_addr.addr4 = unaligned_read_ne32 (&addr4->sin_addr.s_addr);
-				memcpy (&peer_c->data.endpoint_addr.addr4, &addr4->sin_addr.s_addr, 4);
-			} else if (   family == AF_INET6
-			           && nla_len (tb[WGPEER_A_ENDPOINT]) == sizeof (struct sockaddr_in6)) {
-				const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *) addr;
-
-				peer_c->data.endpoint_family = AF_INET6;
-				peer_c->data.endpoint_port = unaligned_read_be16 (&addr6->sin6_port);
-				memcpy (&peer_c->data.endpoint_addr.addr6, &addr6->sin6_addr, 16);
-			}
-		}
-		if (tb[WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL])
-			peer_c->data.persistent_keepalive_interval = nla_get_u64 (tb[WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL]);
-		if (tb[WGPEER_A_LAST_HANDSHAKE_TIME])
-			nla_memcpy (&peer_c->data.last_handshake_time, tb[WGPEER_A_LAST_HANDSHAKE_TIME], sizeof (peer_c->data.last_handshake_time));
-		if (tb[WGPEER_A_RX_BYTES])
-			peer_c->data.rx_bytes = nla_get_u64 (tb[WGPEER_A_RX_BYTES]);
-		if (tb[WGPEER_A_TX_BYTES])
-			peer_c->data.tx_bytes = nla_get_u64 (tb[WGPEER_A_TX_BYTES]);
-	}
-
-	if (tb[WGPEER_A_ALLOWEDIPS]) {
-		struct nlattr *attr;
-		int rem;
-		GArray *allowed_ips = *p_allowed_ips;
-
-		nla_for_each_nested (attr, tb[WGPEER_A_ALLOWEDIPS], rem) {
-			if (!allowed_ips) {
-				allowed_ips = g_array_new (FALSE, FALSE, sizeof (NMPWireGuardAllowedIP));
-				*p_allowed_ips = allowed_ips;
-				g_array_set_size (allowed_ips, 1);
-			} else
-				g_array_set_size (allowed_ips, allowed_ips->len + 1);
-
-			if (!_wireguard_update_from_allowed_ips_nla (&g_array_index (allowed_ips,
-			                                                             NMPWireGuardAllowedIP,
-			                                                             allowed_ips->len - 1),
-			                                            attr)) {
-				/* we ignore the error of parsing one allowed-ip. */
-				g_array_set_size (allowed_ips, allowed_ips->len - 1);
-				continue;
-			}
-
-			if (!peer_c->data._construct_idx_end)
-				peer_c->data._construct_idx_start = allowed_ips->len - 1;
-			peer_c->data._construct_idx_end = allowed_ips->len;
-		}
-	}
-
-	return TRUE;
-}
-
-typedef struct {
-	const int ifindex;
-	NMPObject *obj;
-	CList peers;
-	GArray *allowed_ips;
-} WireGuardParseData;
-
-static int
-_wireguard_get_device_cb (struct nl_msg *msg, void *arg)
-{
-	static const struct nla_policy policy[WGDEVICE_A_MAX + 1] = {
-		[WGDEVICE_A_IFINDEX]     = { .type = NLA_U32 },
-		[WGDEVICE_A_IFNAME]      = { .type = NLA_NUL_STRING, .maxlen = IFNAMSIZ },
-		[WGDEVICE_A_PRIVATE_KEY] = { },
-		[WGDEVICE_A_PUBLIC_KEY]  = { },
-		[WGDEVICE_A_FLAGS]       = { .type = NLA_U32 },
-		[WGDEVICE_A_LISTEN_PORT] = { .type = NLA_U16 },
-		[WGDEVICE_A_FWMARK]      = { .type = NLA_U32 },
-		[WGDEVICE_A_PEERS]       = { .type = NLA_NESTED },
-	};
-	WireGuardParseData *parse_data = arg;
-	struct nlattr *tb[WGDEVICE_A_MAX + 1];
-	int nlerr;
-
-	nlerr = genlmsg_parse (nlmsg_hdr (msg), 0, tb, WGDEVICE_A_MAX, policy);
-	if (nlerr < 0)
-		return NL_SKIP;
-
-	if (tb[WGDEVICE_A_IFINDEX]) {
-		int ifindex;
-
-		ifindex = (int) nla_get_u32 (tb[WGDEVICE_A_IFINDEX]);
-		if (   ifindex <= 0
-		    || parse_data->ifindex != ifindex)
-			return NL_SKIP;
-	} else {
-		if (!parse_data->obj)
-			return NL_SKIP;
-	}
-
-	if (parse_data->obj) {
-		/* we already have an object instance. This means the netlink message
-		 * is a continuation, only providing more WGDEVICE_A_PEERS data below. */
-	} else {
-		NMPObject *obj;
-		NMPlatformLnkWireGuard *props;
-
-		obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_WIREGUARD, NULL);
-		props = &obj->lnk_wireguard;
-
-		if (tb[WGDEVICE_A_PRIVATE_KEY]) {
-			nla_memcpy (props->private_key, tb[WGDEVICE_A_PRIVATE_KEY], sizeof (props->private_key));
-			/* FIXME(netlink-bzero-secret): extend netlink library to wipe memory. For now,
-			 * just hack it here (yes, this does not cover all places where the
-			 * private key was copied). */
-			nm_explicit_bzero (nla_data (tb[WGDEVICE_A_PRIVATE_KEY]),
-			                   nla_len (tb[WGDEVICE_A_PRIVATE_KEY]));
-		}
-		if (tb[WGDEVICE_A_PUBLIC_KEY])
-			nla_memcpy (props->public_key, tb[WGDEVICE_A_PUBLIC_KEY], sizeof (props->public_key));
-		if (tb[WGDEVICE_A_LISTEN_PORT])
-			props->listen_port = nla_get_u16 (tb[WGDEVICE_A_LISTEN_PORT]);
-		if (tb[WGDEVICE_A_FWMARK])
-			props->fwmark = nla_get_u32 (tb[WGDEVICE_A_FWMARK]);
-
-		parse_data->obj = obj;
-	}
-
-	if (tb[WGDEVICE_A_PEERS]) {
-		struct nlattr *attr;
-		int rem;
-
-		nla_for_each_nested (attr, tb[WGDEVICE_A_PEERS], rem) {
-			if (!_wireguard_update_from_peers_nla (&parse_data->peers, &parse_data->allowed_ips, attr)) {
-				/* we ignore the error of parsing one peer.
-				 * _wireguard_update_from_peers_nla() leaves the @peers array in the
-				 * desired state. */
-			}
-		}
-	}
-
-	return NL_OK;
-}
-
-static const NMPObject *
-_wireguard_read_info (NMPlatform *platform /* used only as logging context */,
-                     struct nl_sock *genl,
-                     int wireguard_family_id,
-                     int ifindex)
-{
-	nm_auto_nlmsg struct nl_msg *msg = NULL;
-	NMPObject *obj = NULL;
-	WireGuardPeerConstruct *peer_c;
-	WireGuardPeerConstruct *peer_c_safe;
-	gs_unref_array GArray *allowed_ips = NULL;
-	WireGuardParseData parse_data = {
-		.ifindex = ifindex,
-	};
-	guint i;
-
-	nm_assert (genl);
-	nm_assert (wireguard_family_id >= 0);
-	nm_assert (ifindex > 0);
-
-	msg = nlmsg_alloc ();
-
-	if (!genlmsg_put (msg,
-	                  NL_AUTO_PORT,
-	                  NL_AUTO_SEQ,
-	                  wireguard_family_id,
-	                  0,
-	                  NLM_F_DUMP,
-	                  WG_CMD_GET_DEVICE,
-	                  1))
-		return NULL;
-
-	NLA_PUT_U32 (msg, WGDEVICE_A_IFINDEX, (guint32) ifindex);
-
-	if (nl_send_auto (genl, msg) < 0)
-		return NULL;
-
-	c_list_init (&parse_data.peers);
-
-	/* we ignore errors, and return whatever we could successfully
-	 * parse. */
-	nl_recvmsgs (genl,
-	             &((const struct nl_cb) {
-	                 .valid_cb = _wireguard_get_device_cb,
-	                 .valid_arg = (gpointer) &parse_data,
-	             }));
-
-	/* unpack: transfer ownership */
-	obj = parse_data.obj;
-	allowed_ips = parse_data.allowed_ips;
-
-	if (!obj) {
-		while ((peer_c = c_list_first_entry (&parse_data.peers, WireGuardPeerConstruct, lst))) {
-			c_list_unlink_stale (&peer_c->lst);
-			nm_explicit_bzero (&peer_c->data.preshared_key, sizeof (peer_c->data.preshared_key));
-			g_slice_free (WireGuardPeerConstruct, peer_c);
-		}
-		return NULL;
-	}
-
-	/* we receive peers/allowed-ips possibly in separate netlink messages. Hence, while
-	 * parsing the dump, we don't know upfront how many peers/allowed-ips we will receive.
-	 *
-	 * We solve that, by collecting all peers with a CList. It's done this way,
-	 * because a GArray would require growing the array, but we want to bzero()
-	 * the preshared-key of each peer while reallocating. The CList apprach avoids
-	 * that.
-	 *
-	 * For allowed-ips, we instead track one GArray, which are all appended
-	 * there. The realloc/resize of the GArray is fine there. However,
-	 * while we build the GArray, we don't yet have the final pointers.
-	 * Hence, while constructing, we track the indexes with peer->_construct_idx_*
-	 * fields. These indexes must be convered to actual pointers blow.
-	 *
-	 * This is all done during parsing. In the final NMPObjectLnkWireGuard we
-	 * don't want the CList anymore and repackage the NMPObject tightly. The
-	 * reason is, that NMPObject instances are immutable and long-living. Spend
-	 * a bit effort below during construction to obtain a most suitable representation
-	 * in this regard. */
-	obj->_lnk_wireguard.peers_len = c_list_length (&parse_data.peers);
-	obj->_lnk_wireguard.peers = obj->_lnk_wireguard.peers_len > 0
-	                            ? g_new (NMPWireGuardPeer, obj->_lnk_wireguard.peers_len)
-	                            : NULL;
-
-	/* duplicate allowed_ips instead of using the pointer. The GArray possibly has more
-	 * space allocated then we need, and we want to get rid of this excess buffer.
-	 * Note that NMPObject instance is possibly put into the cache and long-living. */
-	obj->_lnk_wireguard._allowed_ips_buf_len = allowed_ips ? allowed_ips->len : 0u;
-	obj->_lnk_wireguard._allowed_ips_buf = obj->_lnk_wireguard._allowed_ips_buf_len > 0
-	                                       ? (NMPWireGuardAllowedIP *) nm_memdup (allowed_ips->data,
-	                                                                              sizeof (NMPWireGuardAllowedIP) * allowed_ips->len)
-	                                       : NULL;
-
-	i = 0;
-	c_list_for_each_entry_safe (peer_c, peer_c_safe, &parse_data.peers, lst) {
-		NMPWireGuardPeer *peer = (NMPWireGuardPeer *) &obj->_lnk_wireguard.peers[i++];
-
-		*peer = peer_c->data;
-
-		c_list_unlink_stale (&peer_c->lst);
-		nm_explicit_bzero (&peer_c->data.preshared_key, sizeof (peer_c->data.preshared_key));
-		g_slice_free (WireGuardPeerConstruct, peer_c);
-
-		if (peer->_construct_idx_end != 0) {
-			guint len;
-
-			nm_assert (obj->_lnk_wireguard._allowed_ips_buf);
-			nm_assert (peer->_construct_idx_end > peer->_construct_idx_start);
-			nm_assert (peer->_construct_idx_start < obj->_lnk_wireguard._allowed_ips_buf_len);
-			nm_assert (peer->_construct_idx_end <= obj->_lnk_wireguard._allowed_ips_buf_len);
-
-			len = peer->_construct_idx_end - peer->_construct_idx_start;
-			peer->allowed_ips = &obj->_lnk_wireguard._allowed_ips_buf[peer->_construct_idx_start];
-			peer->allowed_ips_len = len;
-		} else {
-			nm_assert (!peer->_construct_idx_start);
-			nm_assert (!peer->_construct_idx_end);
-			peer->allowed_ips = NULL;
-			peer->allowed_ips_len = 0;
-		}
-	}
-
-	return obj;
-
-nla_put_failure:
-	g_return_val_if_reached (NULL);
-}
-
-/*****************************************************************************/
-
 /* Copied and heavily modified from libnl3's link_msg_parser(). */
 static NMPObject *
 _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr *nlh, gboolean id_only)
@@ -2329,39 +1707,37 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr
 	const char *nl_info_kind = NULL;
 	int err;
 	nm_auto_nmpobj NMPObject *obj = NULL;
+	NMPObject *obj_result = NULL;
 	gboolean completed_from_cache_val = FALSE;
 	gboolean *completed_from_cache = cache ? &completed_from_cache_val : NULL;
 	const NMPObject *link_cached = NULL;
-	const NMPObject *lnk_data = NULL;
+	NMPObject *lnk_data = NULL;
 	gboolean address_complete_from_cache = TRUE;
 	gboolean lnk_data_complete_from_cache = TRUE;
-	gboolean need_ext_data = FALSE;
 	gboolean af_inet6_token_valid = FALSE;
 	gboolean af_inet6_addr_gen_mode_valid = FALSE;
 
 	if (!nlmsg_valid_hdr (nlh, sizeof (*ifi)))
 		return NULL;
-	ifi = nlmsg_data (nlh);
+	ifi = nlmsg_data(nlh);
 
 	if (ifi->ifi_family != AF_UNSPEC)
 		return NULL;
-	if (ifi->ifi_index <= 0)
-		return NULL;
 
 	obj = nmp_object_new_link (ifi->ifi_index);
 
 	if (id_only)
-		return g_steal_pointer (&obj);
+		goto id_only_handled;
 
 	err = nlmsg_parse (nlh, sizeof (*ifi), tb, IFLA_MAX, policy);
 	if (err < 0)
-		return NULL;
+		goto errout;
 
 	if (!tb[IFLA_IFNAME])
-		return NULL;
+		goto errout;
 	nla_strlcpy(obj->link.name, tb[IFLA_IFNAME], IFNAMSIZ);
 	if (!obj->link.name[0])
-		return NULL;
+		goto errout;
 
 	if (!tb[IFLA_MTU]) {
 		/* Kernel has two places that send RTM_GETLINK messages:
@@ -2376,14 +1752,14 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr
 		 * To some extent this is a hack and correct approach is to
 		 * merge objects per-field.
 		 */
-		return NULL;
+		goto errout;
 	}
 	obj->link.mtu = nla_get_u32 (tb[IFLA_MTU]);
 
 	if (tb[IFLA_LINKINFO]) {
 		err = nla_parse_nested (li, IFLA_INFO_MAX, tb[IFLA_LINKINFO], policy_link_info);
 		if (err < 0)
-			return NULL;
+			goto errout;
 
 		if (li[IFLA_INFO_KIND])
 			nl_info_kind = nla_get_string (li[IFLA_INFO_KIND]);
@@ -2462,7 +1838,6 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr
 
 	switch (obj->link.type) {
 	case NM_LINK_TYPE_GRE:
-	case NM_LINK_TYPE_GRETAP:
 		lnk_data = _parse_lnk_gre (nl_info_kind, nl_info_data);
 		break;
 	case NM_LINK_TYPE_INFINIBAND:
@@ -2471,10 +1846,6 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr
 	case NM_LINK_TYPE_IP6TNL:
 		lnk_data = _parse_lnk_ip6tnl (nl_info_kind, nl_info_data);
 		break;
-	case NM_LINK_TYPE_IP6GRE:
-	case NM_LINK_TYPE_IP6GRETAP:
-		lnk_data = _parse_lnk_ip6gre (nl_info_kind, nl_info_data);
-		break;
 	case NM_LINK_TYPE_IPIP:
 		lnk_data = _parse_lnk_ipip (nl_info_kind, nl_info_data);
 		break;
@@ -2497,15 +1868,6 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr
 	case NM_LINK_TYPE_VXLAN:
 		lnk_data = _parse_lnk_vxlan (nl_info_kind, nl_info_data);
 		break;
-	case NM_LINK_TYPE_WIFI:
-	case NM_LINK_TYPE_OLPC_MESH:
-	case NM_LINK_TYPE_WPAN:
-		need_ext_data = TRUE;
-		lnk_data_complete_from_cache = FALSE;
-		break;
-	case NM_LINK_TYPE_WIREGUARD:
-		lnk_data_complete_from_cache = TRUE;
-		break;
 	default:
 		lnk_data_complete_from_cache = FALSE;
 		break;
@@ -2513,14 +1875,12 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr
 
 	if (   completed_from_cache
 	    && (   lnk_data_complete_from_cache
-	        || need_ext_data
 	        || address_complete_from_cache
 	        || !af_inet6_token_valid
 	        || !af_inet6_addr_gen_mode_valid
 	        || !tb[IFLA_STATS64])) {
 		_lookup_cached_link (cache, obj->link.ifindex, completed_from_cache, &link_cached);
-		if (   link_cached
-		    && link_cached->_link.netlink.is_in_netlink) {
+		if (link_cached) {
 			if (   lnk_data_complete_from_cache
 			    && link_cached->link.type == obj->link.type
 			    && link_cached->_link.netlink.lnk
@@ -2533,16 +1893,8 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr
 				 * Also, sometimes the info-data is missing for updates. In this case
 				 * we want to keep the previously received lnk_data. */
 				nmp_object_unref (lnk_data);
-				lnk_data = nmp_object_ref (link_cached->_link.netlink.lnk);
+				lnk_data = (NMPObject *) nmp_object_ref (link_cached->_link.netlink.lnk);
 			}
-
-			if (   need_ext_data
-			    && link_cached->link.type == obj->link.type
-			    && link_cached->_link.ext_data) {
-				/* Prefer reuse of existing ext_data object */
-				obj->_link.ext_data = g_object_ref (link_cached->_link.ext_data);
-			}
-
 			if (address_complete_from_cache)
 				obj->link.addr = link_cached->link.addr;
 			if (!af_inet6_token_valid)
@@ -2560,71 +1912,12 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr
 
 	obj->_link.netlink.lnk = lnk_data;
 
-	if (   need_ext_data
-	    && obj->_link.ext_data == NULL) {
-		switch (obj->link.type) {
-		case NM_LINK_TYPE_WIFI:
-			obj->_link.ext_data = (GObject *) nm_wifi_utils_new (ifi->ifi_index,
-			                                                     _genl_sock (NM_LINUX_PLATFORM (platform)),
-			                                                     TRUE);
-			break;
-		case NM_LINK_TYPE_OLPC_MESH:
-#if HAVE_WEXT
-			/* The kernel driver now uses nl80211, but we force use of WEXT because
-			 * the cfg80211 interactions are not quite ready to support access to
-			 * mesh control through nl80211 just yet.
-			 */
-			obj->_link.ext_data = (GObject *) nm_wifi_utils_wext_new (ifi->ifi_index, FALSE);
-#endif
-			break;
-		case NM_LINK_TYPE_WPAN:
-			obj->_link.ext_data = (GObject *) nm_wpan_utils_new (ifi->ifi_index,
-			                                                     _genl_sock (NM_LINUX_PLATFORM (platform)),
-			                                                     TRUE);
-			break;
-		default:
-			g_assert_not_reached ();
-		}
-	}
-
-	if (obj->link.type == NM_LINK_TYPE_WIREGUARD) {
-		const NMPObject *lnk_data_new = NULL;
-		struct nl_sock *genl = NM_LINUX_PLATFORM_GET_PRIVATE (platform)->genl;
-
-		/* The WireGuard kernel module does not yet send link update
-		 * notifications, so we don't actually update the cache. For
-		 * now, always refetch link data here. */
-
-		_lookup_cached_link (cache, obj->link.ifindex, completed_from_cache, &link_cached);
-		if (   link_cached
-		    && link_cached->_link.netlink.is_in_netlink
-		    && link_cached->link.type == NM_LINK_TYPE_WIREGUARD)
-			obj->_link.wireguard_family_id = link_cached->_link.wireguard_family_id;
-		else
-			obj->_link.wireguard_family_id = -1;
-
-		if (obj->_link.wireguard_family_id < 0)
-			obj->_link.wireguard_family_id = genl_ctrl_resolve (genl, "wireguard");
-
-		if (obj->_link.wireguard_family_id >= 0) {
-			lnk_data_new = _wireguard_read_info (platform,
-			                                     genl,
-			                                     obj->_link.wireguard_family_id,
-			                                     obj->link.ifindex);
-		}
-
-		if (   lnk_data_new
-		    && obj->_link.netlink.lnk
-		    && nmp_object_equal (obj->_link.netlink.lnk, lnk_data_new))
-			nmp_object_unref (lnk_data_new);
-		else {
-			nmp_object_unref (obj->_link.netlink.lnk);
-			obj->_link.netlink.lnk = lnk_data_new;
-		}
-	}
-
 	obj->_link.netlink.is_in_netlink = TRUE;
-	return g_steal_pointer (&obj);
+id_only_handled:
+	obj_result = obj;
+	obj = NULL;
+errout:
+	return obj_result;
 }
 
 /* Copied and heavily modified from libnl3's addr_msg_parser(). */
@@ -2641,6 +1934,7 @@ _new_from_nl_addr (struct nlmsghdr *nlh, gboolean id_only)
 	int err;
 	gboolean is_v4;
 	nm_auto_nmpobj NMPObject *obj = NULL;
+	NMPObject *obj_result = NULL;
 	int addr_len;
 	guint32 lifetime, preferred, timestamp;
 
@@ -2649,19 +1943,19 @@ _new_from_nl_addr (struct nlmsghdr *nlh, gboolean id_only)
 	ifa = nlmsg_data(nlh);
 
 	if (!NM_IN_SET (ifa->ifa_family, AF_INET, AF_INET6))
-		return NULL;
+		goto errout;
 	is_v4 = ifa->ifa_family == AF_INET;
 
 	err = nlmsg_parse (nlh, sizeof(*ifa), tb, IFA_MAX, policy);
 	if (err < 0)
-		return NULL;
+		goto errout;
 
 	addr_len = is_v4
 	           ? sizeof (in_addr_t)
 	           : sizeof (struct in6_addr);
 
 	if (ifa->ifa_prefixlen > (is_v4 ? 32 : 128))
-		return NULL;
+		goto errout;
 
 	/*****************************************************************/
 
@@ -2670,8 +1964,8 @@ _new_from_nl_addr (struct nlmsghdr *nlh, gboolean id_only)
 	obj->ip_address.ifindex = ifa->ifa_index;
 	obj->ip_address.plen = ifa->ifa_prefixlen;
 
-	_check_addr_or_return_null (tb, IFA_ADDRESS, addr_len);
-	_check_addr_or_return_null (tb, IFA_LOCAL, addr_len);
+	_check_addr_or_errout (tb, IFA_ADDRESS, addr_len);
+	_check_addr_or_errout (tb, IFA_LOCAL, addr_len);
 	if (is_v4) {
 		/* For IPv4, kernel omits IFA_LOCAL/IFA_ADDRESS if (and only if) they
 		 * are effectively 0.0.0.0 (all-zero). */
@@ -2735,7 +2029,10 @@ _new_from_nl_addr (struct nlmsghdr *nlh, gboolean id_only)
 	                         &obj->ip_address.lifetime,
 	                         &obj->ip_address.preferred);
 
-	return g_steal_pointer (&obj);
+	obj_result = obj;
+	obj = NULL;
+errout:
+	return obj_result;
 }
 
 /* Copied and heavily modified from libnl3's rtnl_route_parse() and parse_multipath(). */
@@ -2758,6 +2055,7 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only)
 	int err;
 	gboolean is_v4;
 	nm_auto_nmpobj NMPObject *obj = NULL;
+	NMPObject *obj_result = NULL;
 	int addr_len;
 	struct {
 		gboolean is_present;
@@ -2776,14 +2074,14 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only)
 	 *****************************************************************/
 
 	if (!NM_IN_SET (rtm->rtm_family, AF_INET, AF_INET6))
-		return NULL;
+		goto errout;
 
 	if (rtm->rtm_type != RTN_UNICAST)
-		return NULL;
+		goto errout;
 
 	err = nlmsg_parse (nlh, sizeof (struct rtmsg), tb, RTA_MAX, policy);
 	if (err < 0)
-		return NULL;
+		goto errout;
 
 	/*****************************************************************/
 
@@ -2793,7 +2091,7 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only)
 	           : sizeof (struct in6_addr);
 
 	if (rtm->rtm_dst_len > (is_v4 ? 32 : 128))
-		return NULL;
+		goto errout;
 
 	/*****************************************************************
 	 * parse nexthops. Only handle routes with one nh.
@@ -2809,7 +2107,7 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only)
 
 			if (nh.is_present) {
 				/* we don't support multipath routes. */
-				return NULL;
+				goto errout;
 			}
 			nh.is_present = TRUE;
 
@@ -2823,9 +2121,9 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only)
 				                 rtnh->rtnh_len - sizeof (*rtnh),
 				                 policy);
 				if (err < 0)
-					return NULL;
+					goto errout;
 
-				if (_check_addr_or_return_null (ntb, RTA_GATEWAY, addr_len))
+				if (_check_addr_or_errout (ntb, RTA_GATEWAY, addr_len))
 					memcpy (&nh.gateway, nla_data (ntb[RTA_GATEWAY]), addr_len);
 			}
 
@@ -2842,7 +2140,7 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only)
 
 		if (tb[RTA_OIF])
 			ifindex = nla_get_u32 (tb[RTA_OIF]);
-		if (_check_addr_or_return_null (tb, RTA_GATEWAY, addr_len))
+		if (_check_addr_or_errout (tb, RTA_GATEWAY, addr_len))
 			memcpy (&gateway, nla_data (tb[RTA_GATEWAY]), addr_len);
 
 		if (!nh.is_present) {
@@ -2856,10 +2154,10 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only)
 			 * verify that it is a duplicate and ignore old-style nexthop. */
 			if (   nh.ifindex != ifindex
 			    || memcmp (&nh.gateway, &gateway, addr_len) != 0)
-				return NULL;
+				goto errout;
 		}
 	} else if (!nh.is_present)
-		return NULL;
+		goto errout;
 
 	/*****************************************************************/
 
@@ -2878,7 +2176,7 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only)
 
 		err = nla_parse_nested (mtb, RTAX_MAX, tb[RTA_METRICS], rtax_policy);
 		if (err < 0)
-			return NULL;
+			goto errout;
 
 		if (mtb[RTAX_LOCK])
 			lock = nla_get_u32 (mtb[RTAX_LOCK]);
@@ -2906,7 +2204,7 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only)
 
 	obj->ip_route.ifindex = nh.ifindex;
 
-	if (_check_addr_or_return_null (tb, RTA_DST, addr_len))
+	if (_check_addr_or_errout (tb, RTA_DST, addr_len))
 		memcpy (obj->ip_route.network_ptr, nla_data (tb[RTA_DST]), addr_len);
 
 	obj->ip_route.plen = rtm->rtm_dst_len;
@@ -2922,7 +2220,7 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only)
 	if (is_v4)
 		obj->ip4_route.scope_inv = nm_platform_route_scope_inv (rtm->rtm_scope);
 
-	if (_check_addr_or_return_null (tb, RTA_PREFSRC, addr_len)) {
+	if (_check_addr_or_errout (tb, RTA_PREFSRC, addr_len)) {
 		if (is_v4)
 			memcpy (&obj->ip4_route.pref_src, nla_data (tb[RTA_PREFSRC]), addr_len);
 		else
@@ -2933,7 +2231,7 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only)
 		obj->ip4_route.tos = rtm->rtm_tos;
 	else {
 		if (tb[RTA_SRC]) {
-			_check_addr_or_return_null (tb, RTA_SRC, addr_len);
+			_check_addr_or_errout (tb, RTA_SRC, addr_len);
 			memcpy (&obj->ip6_route.src, nla_data (tb[RTA_SRC]), addr_len);
 		}
 		obj->ip6_route.src_plen = rtm->rtm_src_len;
@@ -2963,7 +2261,10 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only)
 	obj->ip_route.r_rtm_flags = rtm->rtm_flags;
 	obj->ip_route.rt_source = nmp_utils_ip_config_source_from_rtprot (rtm->rtm_protocol);
 
-	return g_steal_pointer (&obj);
+	obj_result = obj;
+	obj = NULL;
+errout:
+	return obj_result;
 }
 
 static NMPObject *
@@ -3640,16 +2941,103 @@ nla_put_failure:
 	g_return_val_if_reached (NULL);
 }
 
-/*****************************************************************************/
+/******************************************************************
+ * NMPlatform types and functions
+ ******************************************************************/
+
+typedef enum {
+	DELAYED_ACTION_RESPONSE_TYPE_VOID                       = 0,
+	DELAYED_ACTION_RESPONSE_TYPE_REFRESH_ALL_IN_PROGRESS    = 1,
+	DELAYED_ACTION_RESPONSE_TYPE_ROUTE_GET                  = 2,
+} DelayedActionWaitForNlResponseType;
+
+typedef struct {
+	guint32 seq_number;
+	WaitForNlResponseResult seq_result;
+	DelayedActionWaitForNlResponseType response_type;
+	gint64 timeout_abs_ns;
+	WaitForNlResponseResult *out_seq_result;
+	char **out_errmsg;
+	union {
+		gint *out_refresh_all_in_progess;
+		NMPObject **out_route_get;
+		gpointer out_data;
+	} response;
+} DelayedActionWaitForNlResponseData;
+
+typedef struct {
+	struct nl_sock *nlh;
+	guint32 nlh_seq_next;
+#ifdef NM_MORE_LOGGING
+	guint32 nlh_seq_last_handled;
+#endif
+	guint32 nlh_seq_last_seen;
+	GIOChannel *event_channel;
+	guint event_id;
+
+	bool pruning[_DELAYED_ACTION_IDX_REFRESH_ALL_NUM];
+
+	bool sysctl_get_warned;
+	GHashTable *sysctl_get_prev_values;
+
+	NMUdevClient *udev_client;
+
+	struct {
+		/* which delayed actions are scheduled, as marked in @flags.
+		 * Some types have additional arguments in the fields below. */
+		DelayedActionType flags;
+
+		/* counter that a refresh all action is in progress, separated
+		 * by type. */
+		gint refresh_all_in_progess[_DELAYED_ACTION_IDX_REFRESH_ALL_NUM];
+
+		GPtrArray *list_master_connected;
+		GPtrArray *list_refresh_link;
+		GArray *list_wait_for_nl_response;
+
+		gint is_handling;
+	} delayed_action;
+
+	GHashTable *wifi_data;
+} NMLinuxPlatformPrivate;
+
+struct _NMLinuxPlatform {
+	NMPlatform parent;
+	NMLinuxPlatformPrivate _priv;
+};
+
+struct _NMLinuxPlatformClass {
+	NMPlatformClass parent;
+};
 
-static struct nl_sock *
-_genl_sock (NMLinuxPlatform *platform)
+G_DEFINE_TYPE (NMLinuxPlatform, nm_linux_platform, NM_TYPE_PLATFORM)
+
+#define NM_LINUX_PLATFORM_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMLinuxPlatform, NM_IS_LINUX_PLATFORM, NMPlatform)
+
+NMPlatform *
+nm_linux_platform_new (gboolean log_with_ptr, gboolean netns_support)
 {
-	NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
+	gboolean use_udev = FALSE;
+
+	if (   nmp_netns_is_initial ()
+	    && access ("/sys", W_OK) == 0)
+		use_udev = TRUE;
 
-	return priv->genl;
+	return g_object_new (NM_TYPE_LINUX_PLATFORM,
+	                     NM_PLATFORM_LOG_WITH_PTR, log_with_ptr,
+	                     NM_PLATFORM_USE_UDEV, use_udev,
+	                     NM_PLATFORM_NETNS_SUPPORT, netns_support,
+	                     NULL);
+}
+
+void
+nm_linux_platform_setup (void)
+{
+	nm_platform_setup (nm_linux_platform_new (FALSE, FALSE));
 }
 
+/*****************************************************************************/
+
 #define ASSERT_SYSCTL_ARGS(pathid, dirfd, path) \
 	G_STMT_START { \
 		const char *const _pathid = (pathid); \
@@ -3676,9 +3064,7 @@ _log_dbg_sysctl_set_impl (NMPlatform *platform, const char *pathid, int dirfd, c
 	char *contents;
 	gs_free char *value_escaped = g_strescape (value, NULL);
 
-	if (nm_utils_file_get_contents (dirfd, path, 1*1024*1024,
-	                                NM_UTILS_FILE_GET_CONTENTS_FLAG_NONE,
-	                                &contents, NULL, &error) < 0) {
+	if (nm_utils_file_get_contents (dirfd, path, 1*1024*1024, &contents, NULL, &error) < 0) {
 		_LOGD ("sysctl: setting '%s' to '%s' (current value cannot be read: %s)", pathid, value_escaped, error->message);
 		g_clear_error (&error);
 		return;
@@ -3895,9 +3281,7 @@ sysctl_get (NMPlatform *platform, const char *pathid, int dirfd, const char *pat
 		pathid = path;
 	}
 
-	if (nm_utils_file_get_contents (dirfd, path, 1*1024*1024,
-	                                NM_UTILS_FILE_GET_CONTENTS_FLAG_NONE,
-	                                &contents, NULL, &error) < 0) {
+	if (nm_utils_file_get_contents (dirfd, path, 1*1024*1024, &contents, NULL, &error) < 0) {
 		/* We assume FAILED means EOPNOTSUP */
 		if (   g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT)
 		    || g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NODEV)
@@ -4068,7 +3452,7 @@ delayed_action_refresh_all_in_progress (NMPlatform *platform, DelayedActionType
 	if (NM_FLAGS_ANY (priv->delayed_action.flags, action_type))
 		return TRUE;
 
-	if (priv->delayed_action.refresh_all_in_progress[delayed_action_refresh_all_to_idx (action_type)] > 0)
+	if (priv->delayed_action.refresh_all_in_progess[delayed_action_refresh_all_to_idx (action_type)] > 0)
 		return TRUE;
 
 	return FALSE;
@@ -4098,10 +3482,10 @@ delayed_action_wait_for_nl_response_complete (NMPlatform *platform,
 	case DELAYED_ACTION_RESPONSE_TYPE_VOID:
 		break;
 	case DELAYED_ACTION_RESPONSE_TYPE_REFRESH_ALL_IN_PROGRESS:
-		if (data->response.out_refresh_all_in_progress) {
-			nm_assert (*data->response.out_refresh_all_in_progress > 0);
-			*data->response.out_refresh_all_in_progress -= 1;
-			data->response.out_refresh_all_in_progress = NULL;
+		if (data->response.out_refresh_all_in_progess) {
+			nm_assert (*data->response.out_refresh_all_in_progess > 0);
+			*data->response.out_refresh_all_in_progess -= 1;
+			data->response.out_refresh_all_in_progess = NULL;
 		}
 		break;
 	case DELAYED_ACTION_RESPONSE_TYPE_ROUTE_GET:
@@ -4126,7 +3510,7 @@ delayed_action_wait_for_nl_response_complete_check (NMPlatform *platform,
 	guint i;
 	guint32 next_seq_number = 0;
 	gint64 next_timeout_abs_ns = 0;
-	int now_ns = 0;
+	gint now_ns = 0;
 
 	for (i = 0; i < priv->delayed_action.list_wait_for_nl_response->len; ) {
 		const DelayedActionWaitForNlResponseData *data = &g_array_index (priv->delayed_action.list_wait_for_nl_response, DelayedActionWaitForNlResponseData, i);
@@ -4548,10 +3932,7 @@ cache_on_change (NMPlatform *platform,
 
 			if (   !obj_new->_link.netlink.lnk
 			    && NM_IN_SET (obj_new->link.type, NM_LINK_TYPE_GRE,
-			                                      NM_LINK_TYPE_GRETAP,
 			                                      NM_LINK_TYPE_IP6TNL,
-			                                      NM_LINK_TYPE_IP6GRE,
-			                                      NM_LINK_TYPE_IP6GRETAP,
 			                                      NM_LINK_TYPE_INFINIBAND,
 			                                      NM_LINK_TYPE_MACVLAN,
 			                                      NM_LINK_TYPE_MACVLAN,
@@ -4824,11 +4205,11 @@ do_request_all_no_delayed_actions (NMPlatform *platform, DelayedActionType actio
 		const NMPClass *klass = nmp_class_from_type (obj_type);
 		nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
 		int nle;
-		int *out_refresh_all_in_progress;
+		gint *out_refresh_all_in_progess;
 
-		out_refresh_all_in_progress = &priv->delayed_action.refresh_all_in_progress[delayed_action_refresh_all_to_idx (iflags)];
-		nm_assert (*out_refresh_all_in_progress >= 0);
-		*out_refresh_all_in_progress += 1;
+		out_refresh_all_in_progess = &priv->delayed_action.refresh_all_in_progess[delayed_action_refresh_all_to_idx (iflags)];
+		nm_assert (*out_refresh_all_in_progess >= 0);
+		*out_refresh_all_in_progess += 1;
 
 		/* clear any delayed action that request a refresh of this object type. */
 		priv->delayed_action.flags &= ~iflags;
@@ -4862,9 +4243,9 @@ do_request_all_no_delayed_actions (NMPlatform *platform, DelayedActionType actio
 		if (nle < 0)
 			continue;
 
-		if (_nl_send_nlmsg (platform, nlmsg, NULL, NULL, DELAYED_ACTION_RESPONSE_TYPE_REFRESH_ALL_IN_PROGRESS, out_refresh_all_in_progress) < 0) {
-			nm_assert (*out_refresh_all_in_progress > 0);
-			*out_refresh_all_in_progress -= 1;
+		if (_nl_send_nlmsg (platform, nlmsg, NULL, NULL, DELAYED_ACTION_RESPONSE_TYPE_REFRESH_ALL_IN_PROGRESS, out_refresh_all_in_progess) < 0) {
+			nm_assert (*out_refresh_all_in_progess > 0);
+			*out_refresh_all_in_progess -= 1;
 		}
 	}
 }
@@ -4893,10 +4274,10 @@ event_seq_check_refresh_all (NMPlatform *platform, guint32 seq_number)
 			data = &g_array_index (priv->delayed_action.list_wait_for_nl_response, DelayedActionWaitForNlResponseData, i);
 
 			if (   data->response_type == DELAYED_ACTION_RESPONSE_TYPE_REFRESH_ALL_IN_PROGRESS
-			    && data->response.out_refresh_all_in_progress
+			    && data->response.out_refresh_all_in_progess
 			    && data->seq_number == priv->nlh_seq_last_seen) {
-				*data->response.out_refresh_all_in_progress -= 1;
-				data->response.out_refresh_all_in_progress = NULL;
+				*data->response.out_refresh_all_in_progess -= 1;
+				data->response.out_refresh_all_in_progess = NULL;
 				break;
 			}
 		}
@@ -4937,7 +4318,7 @@ event_seq_check (NMPlatform *platform, guint32 seq_number, WaitForNlResponseResu
 		}
 	}
 
-#if NM_MORE_LOGGING
+#ifdef NM_MORE_LOGGING
 	if (seq_number != priv->nlh_seq_last_handled)
 		_LOGt ("netlink: recvmsg: unwaited sequence number %u", seq_number);
 	priv->nlh_seq_last_handled = seq_number;
@@ -5360,9 +4741,6 @@ retry:
 	} else if (NM_IN_SET (-((int) seq_result), ENODEV)) {
 		log_level = LOGL_DEBUG;
 		result = NM_PLATFORM_ERROR_NOT_FOUND;
-	} else if (-((int) seq_result) == EAFNOSUPPORT) {
-		log_level = LOGL_DEBUG;
-		result = NM_PLATFORM_ERROR_OPNOTSUPP;
 	} else {
 		log_level = LOGL_WARN;
 		result = NM_PLATFORM_ERROR_UNSPECIFIED;
@@ -5463,6 +4841,8 @@ link_set_netns (NMPlatform *platform,
 {
 	nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
 
+	_LOGD ("link: move link %d to network namespace with fd %d", ifindex, netns_fd);
+
 	nlmsg = _nl_msg_new_link (RTM_NEWLINK,
 	                          0,
 	                          ifindex,
@@ -5651,6 +5031,7 @@ static NMPlatformError
 link_set_address (NMPlatform *platform, int ifindex, gconstpointer address, size_t length)
 {
 	nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
+	gs_free char *mac = NULL;
 	const ChangeLinkData d = {
 		.set_address = {
 			.address = address,
@@ -5661,6 +5042,10 @@ link_set_address (NMPlatform *platform, int ifindex, gconstpointer address, size
 	if (!address || !length)
 		g_return_val_if_reached (NM_PLATFORM_ERROR_BUG);
 
+	_LOGD ("link: change %d: address: %s (%lu bytes)", ifindex,
+	       (mac = nm_utils_hwaddr_ntoa (address, length)),
+	       (unsigned long) length);
+
 	nlmsg = _nl_msg_new_link (RTM_NEWLINK,
 	                          0,
 	                          ifindex,
@@ -5682,6 +5067,8 @@ link_set_name (NMPlatform *platform, int ifindex, const char *name)
 {
 	nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
 
+	_LOGD ("link: change %d: name: %s", ifindex, name);
+
 	nlmsg = _nl_msg_new_link (RTM_NEWLINK,
 	                          0,
 	                          ifindex,
@@ -5717,6 +5104,8 @@ link_set_mtu (NMPlatform *platform, int ifindex, guint32 mtu)
 {
 	nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
 
+	_LOGD ("link: change %d: mtu: %u", ifindex, (unsigned) mtu);
+
 	nlmsg = _nl_msg_new_link (RTM_NEWLINK,
 	                          0,
 	                          ifindex,
@@ -5734,18 +5123,16 @@ nla_put_failure:
 }
 
 static gboolean
-link_set_sriov_params (NMPlatform *platform,
-                       int ifindex,
-                       guint num_vfs,
-                       int autoprobe)
+link_set_sriov_num_vfs (NMPlatform *platform, int ifindex, guint num_vfs)
 {
 	nm_auto_pop_netns NMPNetns *netns = NULL;
 	nm_auto_close int dirfd = -1;
-	gboolean current_autoprobe;
-	guint total, current_num;
+	int total, current;
 	char ifname[IFNAMSIZ];
 	char buf[64];
 
+	_LOGD ("link: change %d: num VFs: %u", ifindex, num_vfs);
+
 	if (!nm_platform_netns_push (platform, &netns))
 		return FALSE;
 
@@ -5753,69 +5140,46 @@ link_set_sriov_params (NMPlatform *platform,
 	if (!dirfd)
 		return FALSE;
 
-	total = nm_platform_sysctl_get_int_checked (platform,
-	                                            NMP_SYSCTL_PATHID_NETDIR (dirfd,
-	                                                                      ifname,
-	                                                                      "device/sriov_totalvfs"),
-	                                            10, 0, G_MAXUINT, 0);
-	if (errno)
+	total = nm_platform_sysctl_get_int32 (platform,
+	                                      NMP_SYSCTL_PATHID_NETDIR (dirfd,
+	                                                                ifname,
+	                                                                "device/sriov_totalvfs"),
+	                                      -1);
+	if (total < 1)
 		return FALSE;
 	if (num_vfs > total) {
 		_LOGW ("link: %d only supports %u VFs (requested %u)", ifindex, total, num_vfs);
 		num_vfs = total;
 	}
 
-	/*
-	 * Take special care when setting new values:
-	 *  - don't touch anything if the right values are already set
-	 *  - to change the number of VFs or autoprobe we need to destroy existing VFs
-	 *  - the autoprobe setting is irrelevant when numvfs is zero
-	 */
-	current_num = nm_platform_sysctl_get_int_checked (platform,
-	                                                  NMP_SYSCTL_PATHID_NETDIR (dirfd,
-	                                                                            ifname,
-	                                                                            "device/sriov_numvfs"),
-	                                                  10, 0, G_MAXUINT, 0);
-	current_autoprobe = nm_platform_sysctl_get_int_checked (platform,
-	                                                        NMP_SYSCTL_PATHID_NETDIR (dirfd,
-	                                                                                  ifname,
-	                                                                                  "device/sriov_drivers_autoprobe"),
-	                                                        10, 0, G_MAXUINT, 0);
-	if (   current_num == num_vfs
-	    && (autoprobe == -1 || current_autoprobe == autoprobe))
+	current = nm_platform_sysctl_get_int32 (platform,
+	                                        NMP_SYSCTL_PATHID_NETDIR (dirfd,
+	                                                                  ifname,
+	                                                                  "device/sriov_numvfs"),
+	                                        -1);
+	if (current == num_vfs)
 		return TRUE;
 
-	if (current_num != 0) {
-		/* We need to destroy all other VFs before changing any value */
+	if (current != 0) {
+		/* We need to destroy all other VFs before changing the value */
 		if (!nm_platform_sysctl_set (NM_PLATFORM_GET,
 		                             NMP_SYSCTL_PATHID_NETDIR (dirfd,
 		                                                       ifname,
 		                                                      "device/sriov_numvfs"),
 		                             "0")) {
-			_LOGW ("link: couldn't reset SR-IOV num_vfs: %s", strerror (errno));
+			_LOGW ("link: couldn't set SR-IOV num_vfs to %d: %s", 0, strerror (errno));
 			return FALSE;
 		}
+		if (num_vfs == 0)
+			return TRUE;
 	}
 
-	if (num_vfs == 0)
-		return TRUE;
-
-	if (   autoprobe >= 0
-	    && current_autoprobe != autoprobe
-	    && !nm_platform_sysctl_set (NM_PLATFORM_GET,
-	                                NMP_SYSCTL_PATHID_NETDIR (dirfd,
-	                                                          ifname,
-	                                                          "device/sriov_drivers_autoprobe"),
-	                                nm_sprintf_buf (buf, "%d", autoprobe))) {
-		_LOGW ("link: couldn't set SR-IOV drivers-autoprobe to %d: %s", autoprobe, strerror (errno));
-		return FALSE;
-	}
-
+	/* Finally, set the desired value */
 	if (!nm_platform_sysctl_set (NM_PLATFORM_GET,
 	                             NMP_SYSCTL_PATHID_NETDIR (dirfd,
 	                                                       ifname,
 	                                                       "device/sriov_numvfs"),
-	                             nm_sprintf_buf (buf, "%u", num_vfs))) {
+	                             nm_sprintf_buf (buf, "%d", num_vfs))) {
 		_LOGW ("link: couldn't set SR-IOV num_vfs to %d: %s", num_vfs, strerror (errno));
 		return FALSE;
 	}
@@ -5823,101 +5187,6 @@ link_set_sriov_params (NMPlatform *platform,
 	return TRUE;
 }
 
-static gboolean
-link_set_sriov_vfs (NMPlatform *platform, int ifindex, const NMPlatformVF *const *vfs)
-{
-	nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
-	struct nlattr *list, *info, *vlan_list;
-	guint i;
-
-	nlmsg = _nl_msg_new_link (RTM_NEWLINK,
-	                          0,
-	                          ifindex,
-	                          NULL,
-	                          0,
-	                          0);
-	if (!nlmsg)
-		g_return_val_if_reached (NM_PLATFORM_ERROR_UNSPECIFIED);
-
-	if (!(list = nla_nest_start (nlmsg, IFLA_VFINFO_LIST)))
-		goto nla_put_failure;
-
-	for (i = 0; vfs[i]; i++) {
-		const NMPlatformVF *vf = vfs[i];
-
-		if (!(info = nla_nest_start (nlmsg, IFLA_VF_INFO)))
-			goto nla_put_failure;
-
-		if (vf->spoofchk >= 0) {
-			struct _ifla_vf_setting ivs = { 0 };
-
-			ivs.vf = vf->index;
-			ivs.setting = vf->spoofchk;
-			NLA_PUT (nlmsg, IFLA_VF_SPOOFCHK, sizeof (ivs), &ivs);
-		}
-
-		if (vf->trust >= 0) {
-			struct _ifla_vf_setting ivs = { 0 };
-
-			ivs.vf = vf->index;
-			ivs.setting = vf->trust;
-			NLA_PUT (nlmsg, IFLA_VF_TRUST, sizeof (ivs), &ivs);
-		}
-
-		if (vf->mac.len) {
-			struct ifla_vf_mac ivm = { 0 };
-
-			ivm.vf = vf->index;
-			memcpy (ivm.mac, vf->mac.data, vf->mac.len);
-			NLA_PUT (nlmsg, IFLA_VF_MAC, sizeof (ivm), &ivm);
-		}
-
-		if (vf->min_tx_rate || vf->max_tx_rate) {
-			struct _ifla_vf_rate ivr = { 0 };
-
-			ivr.vf = vf->index;
-			ivr.min_tx_rate = vf->min_tx_rate;
-			ivr.max_tx_rate = vf->max_tx_rate;
-			NLA_PUT (nlmsg, IFLA_VF_RATE, sizeof (ivr), &ivr);
-		}
-
-		/* Kernel only supports one VLAN per VF now. If this
-		 * changes in the future, we need to figure out how to
-		 * clear existing VLANs and set new ones in one message
-		 * with the new API.*/
-		if (vf->num_vlans > 1) {
-			_LOGW ("multiple VLANs per VF are not supported at the moment");
-			return FALSE;
-		} else {
-			struct _ifla_vf_vlan_info ivvi = { 0 };
-
-			if (!(vlan_list = nla_nest_start (nlmsg, IFLA_VF_VLAN_LIST)))
-				goto nla_put_failure;
-
-			ivvi.vf = vf->index;
-			if (vf->num_vlans == 1) {
-				ivvi.vlan = vf->vlans[0].id;
-				ivvi.qos = vf->vlans[0].qos;
-				ivvi.vlan_proto = htons (vf->vlans[0].proto_ad ? ETH_P_8021AD : ETH_P_8021Q);
-			} else {
-				/* Clear existing VLAN */
-				ivvi.vlan = 0;
-				ivvi.qos = 0;
-				ivvi.vlan_proto = htons (ETH_P_8021Q);
-			}
-
-			NLA_PUT (nlmsg, IFLA_VF_VLAN_INFO, sizeof (ivvi), &ivvi);
-			nla_nest_end (nlmsg, vlan_list);
-		}
-		nla_nest_end (nlmsg, info);
-	}
-	nla_nest_end (nlmsg, list);
-
-	return do_change_link (platform, CHANGE_LINK_TYPE_UNSPEC, ifindex, nlmsg, NULL) == NM_PLATFORM_ERROR_SUCCESS;
-nla_put_failure:
-	g_return_val_if_reached (FALSE);
-}
-
 static char *
 link_get_physical_port_id (NMPlatform *platform, int ifindex)
 {
@@ -5944,7 +5213,7 @@ link_get_dev_id (NMPlatform *platform, int ifindex)
 	                                           16, 0, G_MAXUINT16, 0);
 }
 
-static gboolean
+static int
 vlan_add (NMPlatform *platform,
           const char *name,
           int parent,
@@ -5960,6 +5229,10 @@ vlan_add (NMPlatform *platform,
 	G_STATIC_ASSERT (NM_VLAN_FLAG_MVRP == (guint32) VLAN_FLAG_MVRP);
 
 	vlan_flags &= (guint32) NM_VLAN_FLAGS_ALL;
+
+	_LOGD ("link: add vlan '%s', parent %d, vlan id %d, flags %X",
+	       name, parent, vlan_id, (unsigned) vlan_flags);
+
 	nlmsg = _nl_msg_new_link (RTM_NEWLINK,
 	                          NLM_F_CREATE | NLM_F_EXCL,
 	                          0,
@@ -5986,7 +5259,7 @@ nla_put_failure:
 	g_return_val_if_reached (FALSE);
 }
 
-static gboolean
+static int
 link_gre_add (NMPlatform *platform,
               const char *name,
               const NMPlatformLnkGre *props,
@@ -5995,6 +5268,14 @@ link_gre_add (NMPlatform *platform,
 	nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
 	struct nlattr *info;
 	struct nlattr *data;
+	char buffer[INET_ADDRSTRLEN];
+
+	_LOGD (LOG_FMT_IP_TUNNEL,
+	       "gre",
+	       name,
+	       props->parent_ifindex,
+	       nm_utils_inet4_ntop (props->local, NULL),
+	       nm_utils_inet4_ntop (props->remote, buffer));
 
 	nlmsg = _nl_msg_new_link (RTM_NEWLINK,
 	                          NLM_F_CREATE | NLM_F_EXCL,
@@ -6008,7 +5289,7 @@ link_gre_add (NMPlatform *platform,
 	if (!(info = nla_nest_start (nlmsg, IFLA_LINKINFO)))
 		goto nla_put_failure;
 
-	NLA_PUT_STRING (nlmsg, IFLA_INFO_KIND, props->is_tap ? "gretap" : "gre");
+	NLA_PUT_STRING (nlmsg, IFLA_INFO_KIND, "gre");
 
 	if (!(data = nla_nest_start (nlmsg, IFLA_INFO_DATA)))
 		goto nla_put_failure;
@@ -6022,20 +5303,18 @@ link_gre_add (NMPlatform *platform,
 	NLA_PUT_U8 (nlmsg, IFLA_GRE_PMTUDISC, !!props->path_mtu_discovery);
 	NLA_PUT_U32 (nlmsg, IFLA_GRE_IKEY, htonl (props->input_key));
 	NLA_PUT_U32 (nlmsg, IFLA_GRE_OKEY, htonl (props->output_key));
-	NLA_PUT_U16 (nlmsg, IFLA_GRE_IFLAGS, htons (props->input_flags));
-	NLA_PUT_U16 (nlmsg, IFLA_GRE_OFLAGS, htons (props->output_flags));
+	NLA_PUT_U32 (nlmsg, IFLA_GRE_IFLAGS, htons (props->input_flags));
+	NLA_PUT_U32 (nlmsg, IFLA_GRE_OFLAGS, htons (props->output_flags));
 
 	nla_nest_end (nlmsg, data);
 	nla_nest_end (nlmsg, info);
 
-	return do_add_link_with_lookup (platform,
-	                                props->is_tap ? NM_LINK_TYPE_GRETAP : NM_LINK_TYPE_GRE,
-	                                name, nlmsg, out_link);
+	return do_add_link_with_lookup (platform, NM_LINK_TYPE_GRE, name, nlmsg, out_link);
 nla_put_failure:
 	g_return_val_if_reached (FALSE);
 }
 
-static gboolean
+static int
 link_ip6tnl_add (NMPlatform *platform,
                  const char *name,
                  const NMPlatformLnkIp6Tnl *props,
@@ -6044,9 +5323,15 @@ link_ip6tnl_add (NMPlatform *platform,
 	nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
 	struct nlattr *info;
 	struct nlattr *data;
+	char buffer[INET_ADDRSTRLEN];
 	guint32 flowinfo;
 
-	g_return_val_if_fail (!props->is_gre, FALSE);
+	_LOGD (LOG_FMT_IP_TUNNEL,
+	       "ip6tnl",
+	       name,
+	       props->parent_ifindex,
+	       nm_utils_inet6_ntop (&props->local, NULL),
+	       nm_utils_inet6_ntop (&props->remote, buffer));
 
 	nlmsg = _nl_msg_new_link (RTM_NEWLINK,
 	                          NLM_F_CREATE | NLM_F_EXCL,
@@ -6091,69 +5376,7 @@ nla_put_failure:
 	g_return_val_if_reached (FALSE);
 }
 
-static gboolean
-link_ip6gre_add (NMPlatform *platform,
-                 const char *name,
-                 const NMPlatformLnkIp6Tnl *props,
-                 const NMPlatformLink **out_link)
-{
-	nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
-	struct nlattr *info;
-	struct nlattr *data;
-	guint32 flowinfo;
-
-	g_return_val_if_fail (props->is_gre, FALSE);
-
-	nlmsg = _nl_msg_new_link (RTM_NEWLINK,
-	                          NLM_F_CREATE | NLM_F_EXCL,
-	                          0,
-	                          name,
-	                          0,
-	                          0);
-	if (!nlmsg)
-		return FALSE;
-
-	if (!(info = nla_nest_start (nlmsg, IFLA_LINKINFO)))
-		goto nla_put_failure;
-
-	NLA_PUT_STRING (nlmsg, IFLA_INFO_KIND, props->is_tap ? "ip6gretap" : "ip6gre");
-
-	if (!(data = nla_nest_start (nlmsg, IFLA_INFO_DATA)))
-		goto nla_put_failure;
-
-	if (props->parent_ifindex)
-		NLA_PUT_U32 (nlmsg, IFLA_GRE_LINK, props->parent_ifindex);
-
-	NLA_PUT_U32 (nlmsg, IFLA_GRE_IKEY, htonl (props->input_key));
-	NLA_PUT_U32 (nlmsg, IFLA_GRE_OKEY, htonl (props->output_key));
-	NLA_PUT_U16 (nlmsg, IFLA_GRE_IFLAGS, htons (props->input_flags));
-	NLA_PUT_U16 (nlmsg, IFLA_GRE_OFLAGS, htons (props->output_flags));
-
-	if (memcmp (&props->local, &in6addr_any, sizeof (in6addr_any)))
-		NLA_PUT (nlmsg, IFLA_GRE_LOCAL, sizeof (props->local), &props->local);
-	if (memcmp (&props->remote, &in6addr_any, sizeof (in6addr_any)))
-		NLA_PUT (nlmsg, IFLA_GRE_REMOTE, sizeof (props->remote), &props->remote);
-
-	NLA_PUT_U8 (nlmsg, IFLA_GRE_TTL, props->ttl);
-	NLA_PUT_U8 (nlmsg, IFLA_GRE_ENCAP_LIMIT, props->encap_limit);
-
-	flowinfo = props->flow_label & IP6_FLOWINFO_FLOWLABEL_MASK;
-	flowinfo |=   (props->tclass << IP6_FLOWINFO_TCLASS_SHIFT)
-	            & IP6_FLOWINFO_TCLASS_MASK;
-	NLA_PUT_U32 (nlmsg, IFLA_GRE_FLOWINFO, htonl (flowinfo));
-	NLA_PUT_U32 (nlmsg, IFLA_GRE_FLAGS, props->flags);
-
-	nla_nest_end (nlmsg, data);
-	nla_nest_end (nlmsg, info);
-
-	return do_add_link_with_lookup (platform,
-	                                props->is_tap ? NM_LINK_TYPE_IP6GRETAP : NM_LINK_TYPE_IP6GRE,
-	                                name, nlmsg, out_link);
-nla_put_failure:
-	g_return_val_if_reached (FALSE);
-}
-
-static gboolean
+static int
 link_ipip_add (NMPlatform *platform,
                const char *name,
                const NMPlatformLnkIpIp *props,
@@ -6162,6 +5385,14 @@ link_ipip_add (NMPlatform *platform,
 	nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
 	struct nlattr *info;
 	struct nlattr *data;
+	char buffer[INET_ADDRSTRLEN];
+
+	_LOGD (LOG_FMT_IP_TUNNEL,
+	       "ipip",
+	       name,
+	       props->parent_ifindex,
+	       nm_utils_inet4_ntop (props->local, NULL),
+	       nm_utils_inet4_ntop (props->remote, buffer));
 
 	nlmsg = _nl_msg_new_link (RTM_NEWLINK,
 	                          NLM_F_CREATE | NLM_F_EXCL,
@@ -6196,7 +5427,7 @@ nla_put_failure:
 	g_return_val_if_reached (FALSE);
 }
 
-static gboolean
+static int
 link_macsec_add (NMPlatform *platform,
                  const char *name,
                  int parent,
@@ -6207,6 +5438,11 @@ link_macsec_add (NMPlatform *platform,
 	struct nlattr *info;
 	struct nlattr *data;
 
+	_LOGD ("adding macsec '%s' parent %u sci %llx",
+	       name,
+	       parent,
+	       (unsigned long long) props->sci);
+
 	nlmsg = _nl_msg_new_link (RTM_NEWLINK,
 	                          NLM_F_CREATE | NLM_F_EXCL,
 	                          0,
@@ -6253,7 +5489,7 @@ nla_put_failure:
 	g_return_val_if_reached (FALSE);
 }
 
-static gboolean
+static int
 link_macvlan_add (NMPlatform *platform,
                   const char *name,
                   int parent,
@@ -6264,6 +5500,12 @@ link_macvlan_add (NMPlatform *platform,
 	struct nlattr *info;
 	struct nlattr *data;
 
+	_LOGD ("adding %s '%s' parent %u mode %u",
+	       props->tap ? "macvtap" : "macvlan",
+	       name,
+	       parent,
+	       props->mode);
+
 	nlmsg = _nl_msg_new_link (RTM_NEWLINK,
 	                          NLM_F_CREATE | NLM_F_EXCL,
 	                          0,
@@ -6296,7 +5538,7 @@ nla_put_failure:
 	g_return_val_if_reached (FALSE);
 }
 
-static gboolean
+static int
 link_sit_add (NMPlatform *platform,
               const char *name,
               const NMPlatformLnkSit *props,
@@ -6305,6 +5547,14 @@ link_sit_add (NMPlatform *platform,
 	nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
 	struct nlattr *info;
 	struct nlattr *data;
+	char buffer[INET_ADDRSTRLEN];
+
+	_LOGD (LOG_FMT_IP_TUNNEL,
+	       "sit",
+	       name,
+	       props->parent_ifindex,
+	       nm_utils_inet4_ntop (props->local, NULL),
+	       nm_utils_inet4_ntop (props->remote, buffer));
 
 	nlmsg = _nl_msg_new_link (RTM_NEWLINK,
 	                          NLM_F_CREATE | NLM_F_EXCL,
@@ -6408,6 +5658,9 @@ link_vxlan_add (NMPlatform *platform,
 
 	g_return_val_if_fail (props, FALSE);
 
+	_LOGD ("link: add vxlan '%s', parent %d, vxlan id %d",
+	       name, props->parent_ifindex, props->id);
+
 	nlmsg = _nl_msg_new_link (RTM_NEWLINK,
 	                          NLM_F_CREATE | NLM_F_EXCL,
 	                          0,
@@ -6465,41 +5718,6 @@ nla_put_failure:
 	g_return_val_if_reached (FALSE);
 }
 
-static gboolean
-link_6lowpan_add (NMPlatform *platform,
-                  const char *name,
-                  int parent,
-                  const NMPlatformLink **out_link)
-{
-	nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
-	struct nlattr *info;
-
-	nlmsg = _nl_msg_new_link (RTM_NEWLINK,
-	                          NLM_F_CREATE | NLM_F_EXCL,
-	                          0,
-	                          name,
-	                          0,
-	                          0);
-	if (!nlmsg)
-		return FALSE;
-
-	NLA_PUT_U32 (nlmsg, IFLA_LINK, parent);
-
-	if (!(info = nla_nest_start (nlmsg, IFLA_LINKINFO)))
-		goto nla_put_failure;
-
-	NLA_PUT_STRING (nlmsg, IFLA_INFO_KIND, "lowpan");
-
-	nla_nest_end (nlmsg, info);
-
-	return do_add_link_with_lookup (platform,
-	                                NM_LINK_TYPE_6LOWPAN,
-	                                name, nlmsg, out_link);
-nla_put_failure:
-	g_return_val_if_reached (FALSE);
-}
-
-
 static void
 _vlan_change_vlan_qos_mapping_create (gboolean is_ingress_map,
                                       gboolean reset_all,
@@ -6594,6 +5812,9 @@ link_vlan_change (NMPlatform *platform,
 	guint new_n_egress_map = 0;
 	gs_free NMVlanQosMapping *new_ingress_map = NULL;
 	gs_free NMVlanQosMapping *new_egress_map = NULL;
+	char s_flags[64];
+	char s_ingress[256];
+	char s_egress[256];
 
 	obj_cache = nmp_cache_lookup_link (nm_platform_get_cache (platform), ifindex);
 	if (   !obj_cache
@@ -6624,6 +5845,26 @@ link_vlan_change (NMPlatform *platform,
 	                                      &new_egress_map,
 	                                      &new_n_egress_map);
 
+	_LOGD ("link: change %d: vlan:%s%s%s",
+	       ifindex,
+	       flags_mask
+	           ? nm_sprintf_buf (s_flags, " flags 0x%x/0x%x", (unsigned) flags_set, (unsigned) flags_mask)
+	           : "",
+	       new_n_ingress_map
+	           ? nm_platform_vlan_qos_mapping_to_string (" ingress-qos-map",
+	                                                     new_ingress_map,
+	                                                     new_n_ingress_map,
+	                                                     s_ingress,
+	                                                     sizeof (s_ingress))
+	           : "",
+	       new_n_egress_map
+	           ? nm_platform_vlan_qos_mapping_to_string (" egress-qos-map",
+	                                                     new_egress_map,
+	                                                     new_n_egress_map,
+	                                                     s_egress,
+	                                                     sizeof (s_egress))
+	           : "");
+
 	nlmsg = _nl_msg_new_link (RTM_NEWLINK,
 	                          0,
 	                          ifindex,
@@ -6650,6 +5891,8 @@ link_enslave (NMPlatform *platform, int master, int slave)
 	nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
 	int ifindex = slave;
 
+	_LOGD ("link: change %d: enslave: master %d", slave, master);
+
 	nlmsg = _nl_msg_new_link (RTM_NEWLINK,
 	                          0,
 	                          ifindex,
@@ -6737,26 +5980,43 @@ infiniband_partition_delete (NMPlatform *platform, int parent, int p_key)
 
 /*****************************************************************************/
 
-static GObject *
-get_ext_data (NMPlatform *platform, int ifindex)
+static WifiData *
+wifi_get_wifi_data (NMPlatform *platform, int ifindex)
 {
-	const NMPObject *obj;
+	NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
+	const NMPlatformLink *pllink;
+	WifiData *wifi_data;
+
+	wifi_data = g_hash_table_lookup (priv->wifi_data, GINT_TO_POINTER (ifindex));
+	pllink = nm_platform_link_get (platform, ifindex);
+
+	if (!wifi_data) {
+		if (pllink) {
+			if (pllink->type == NM_LINK_TYPE_WIFI)
+				wifi_data = wifi_utils_init (ifindex, TRUE);
+			else if (pllink->type == NM_LINK_TYPE_OLPC_MESH) {
+				/* The kernel driver now uses nl80211, but we force use of WEXT because
+				 * the cfg80211 interactions are not quite ready to support access to
+				 * mesh control through nl80211 just yet.
+				 */
+#if HAVE_WEXT
+				wifi_data = wifi_wext_init (ifindex, FALSE);
+#endif
+			}
 
-	obj = nmp_cache_lookup_link (nm_platform_get_cache (platform), ifindex);
-	if (!obj)
-		return NULL;
+			if (wifi_data)
+				g_hash_table_insert (priv->wifi_data, GINT_TO_POINTER (ifindex), wifi_data);
+		}
+	}
 
-	return obj->_link.ext_data;
+	return wifi_data;
 }
-
-/*****************************************************************************/
-
 #define WIFI_GET_WIFI_DATA_NETNS(wifi_data, platform, ifindex, retval) \
 	nm_auto_pop_netns NMPNetns *netns = NULL; \
-	NMWifiUtils *wifi_data; \
+	WifiData *wifi_data; \
 	if (!nm_platform_netns_push (platform, &netns)) \
 		return retval; \
-	wifi_data = NM_WIFI_UTILS (get_ext_data (platform, ifindex)); \
+	wifi_data = wifi_get_wifi_data (platform, ifindex); \
 	if (!wifi_data) \
 		return retval;
 
@@ -6765,7 +6025,7 @@ wifi_get_capabilities (NMPlatform *platform, int ifindex, NMDeviceWifiCapabiliti
 {
 	WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, FALSE);
 	if (caps)
-		*caps = nm_wifi_utils_get_caps (wifi_data);
+		*caps = wifi_utils_get_caps (wifi_data);
 	return TRUE;
 }
 
@@ -6773,70 +6033,63 @@ static gboolean
 wifi_get_bssid (NMPlatform *platform, int ifindex, guint8 *bssid)
 {
 	WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, FALSE);
-	return nm_wifi_utils_get_bssid (wifi_data, bssid);
+	return wifi_utils_get_bssid (wifi_data, bssid);
 }
 
 static guint32
 wifi_get_frequency (NMPlatform *platform, int ifindex)
 {
 	WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, 0);
-	return nm_wifi_utils_get_freq (wifi_data);
+	return wifi_utils_get_freq (wifi_data);
 }
 
 static gboolean
 wifi_get_quality (NMPlatform *platform, int ifindex)
 {
 	WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, FALSE);
-	return nm_wifi_utils_get_qual (wifi_data);
+	return wifi_utils_get_qual (wifi_data);
 }
 
 static guint32
 wifi_get_rate (NMPlatform *platform, int ifindex)
 {
 	WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, FALSE);
-	return nm_wifi_utils_get_rate (wifi_data);
+	return wifi_utils_get_rate (wifi_data);
 }
 
 static NM80211Mode
 wifi_get_mode (NMPlatform *platform, int ifindex)
 {
 	WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, NM_802_11_MODE_UNKNOWN);
-	return nm_wifi_utils_get_mode (wifi_data);
+	return wifi_utils_get_mode (wifi_data);
 }
 
 static void
 wifi_set_mode (NMPlatform *platform, int ifindex, NM80211Mode mode)
 {
 	WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, );
-	nm_wifi_utils_set_mode (wifi_data, mode);
+	wifi_utils_set_mode (wifi_data, mode);
 }
 
 static void
 wifi_set_powersave (NMPlatform *platform, int ifindex, guint32 powersave)
 {
 	WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, );
-	nm_wifi_utils_set_powersave (wifi_data, powersave);
+	wifi_utils_set_powersave (wifi_data, powersave);
 }
 
 static guint32
 wifi_find_frequency (NMPlatform *platform, int ifindex, const guint32 *freqs)
 {
 	WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, 0);
-	return nm_wifi_utils_find_freq (wifi_data, freqs);
+	return wifi_utils_find_freq (wifi_data, freqs);
 }
 
 static void
 wifi_indicate_addressing_running (NMPlatform *platform, int ifindex, gboolean running)
 {
 	WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, );
-	nm_wifi_utils_indicate_addressing_running (wifi_data, running);
-}
-
-static NMSettingWirelessWakeOnWLan
-wifi_get_wake_on_wlan (NMPlatform *platform, int ifindex)
-{
-	WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, FALSE);
-	return nm_wifi_utils_get_wake_on_wlan (wifi_data);
+	wifi_utils_indicate_addressing_running (wifi_data, running);
 }
 
 static gboolean
@@ -6844,7 +6097,7 @@ wifi_set_wake_on_wlan (NMPlatform *platform, int ifindex,
                        NMSettingWirelessWakeOnWLan wowl)
 {
 	WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, FALSE);
-	return nm_wifi_utils_set_wake_on_wlan (wifi_data, wowl);
+	return wifi_utils_set_wake_on_wlan (wifi_data, wowl);
 }
 
 /*****************************************************************************/
@@ -6895,56 +6148,21 @@ static guint32
 mesh_get_channel (NMPlatform *platform, int ifindex)
 {
 	WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, 0);
-	return nm_wifi_utils_get_mesh_channel (wifi_data);
+	return wifi_utils_get_mesh_channel (wifi_data);
 }
 
 static gboolean
 mesh_set_channel (NMPlatform *platform, int ifindex, guint32 channel)
 {
 	WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, FALSE);
-	return nm_wifi_utils_set_mesh_channel (wifi_data, channel);
+	return wifi_utils_set_mesh_channel (wifi_data, channel);
 }
 
 static gboolean
 mesh_set_ssid (NMPlatform *platform, int ifindex, const guint8 *ssid, gsize len)
 {
 	WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, FALSE);
-	return nm_wifi_utils_set_mesh_ssid (wifi_data, ssid, len);
-}
-
-/*****************************************************************************/
-
-#define WPAN_GET_WPAN_DATA(wpan_data, platform, ifindex, retval) \
-	NMWpanUtils *wpan_data = NM_WPAN_UTILS (get_ext_data (platform, ifindex)); \
-	if (!wpan_data) \
-		return retval;
-
-static guint16
-wpan_get_pan_id (NMPlatform *platform, int ifindex)
-{
-	WPAN_GET_WPAN_DATA (wpan_data, platform, ifindex, G_MAXINT16);
-	return nm_wpan_utils_get_pan_id (wpan_data);
-}
-
-static gboolean
-wpan_set_pan_id (NMPlatform *platform, int ifindex, guint16 pan_id)
-{
-	WPAN_GET_WPAN_DATA (wpan_data, platform, ifindex, FALSE);
-	return nm_wpan_utils_set_pan_id (wpan_data, pan_id);
-}
-
-static guint16
-wpan_get_short_addr (NMPlatform *platform, int ifindex)
-{
-	WPAN_GET_WPAN_DATA (wpan_data, platform, ifindex, G_MAXINT16);
-	return nm_wpan_utils_get_short_addr (wpan_data);
-}
-
-static gboolean
-wpan_set_short_addr (NMPlatform *platform, int ifindex, guint16 short_addr)
-{
-	WPAN_GET_WPAN_DATA (wpan_data, platform, ifindex, FALSE);
-	return nm_wpan_utils_set_short_addr (wpan_data, short_addr);
+	return wifi_utils_set_mesh_ssid (wifi_data, ssid, len);
 }
 
 /*****************************************************************************/
@@ -6961,12 +6179,12 @@ link_get_wake_on_lan (NMPlatform *platform, int ifindex)
 	if (type == NM_LINK_TYPE_ETHERNET)
 		return nmp_utils_ethtool_get_wake_on_lan (ifindex);
 	else if (type == NM_LINK_TYPE_WIFI) {
-		NMWifiUtils *wifi_data = NM_WIFI_UTILS (get_ext_data (platform, ifindex));
+		WifiData *wifi_data = wifi_get_wifi_data (platform, ifindex);
 
 		if (!wifi_data)
 			return FALSE;
 
-		return nm_wifi_utils_get_wake_on_wlan (wifi_data) != NM_SETTING_WIRELESS_WAKE_ON_WLAN_NONE;
+		return wifi_utils_get_wowlan (wifi_data);
 	} else
 		return FALSE;
 }
@@ -7780,14 +6998,6 @@ handle_udev_event (NMUdevClient *udev_client,
 
 /*****************************************************************************/
 
-void
-nm_linux_platform_setup (void)
-{
-	nm_platform_setup (nm_linux_platform_new (FALSE, FALSE));
-}
-
-/*****************************************************************************/
-
 static void
 nm_linux_platform_init (NMLinuxPlatform *self)
 {
@@ -7796,6 +7006,7 @@ nm_linux_platform_init (NMLinuxPlatform *self)
 	priv->delayed_action.list_master_connected = g_ptr_array_new ();
 	priv->delayed_action.list_refresh_link = g_ptr_array_new ();
 	priv->delayed_action.list_wait_for_nl_response = g_array_new (FALSE, TRUE, sizeof (DelayedActionWaitForNlResponseData));
+	priv->wifi_data = g_hash_table_new_full (nm_direct_hash, NULL, NULL, (GDestroyNotify) wifi_utils_unref);
 }
 
 static void
@@ -7825,18 +7036,6 @@ constructed (GObject *_object)
 	                                   nmp_netns_get_current () == nmp_netns_get_initial () ? "/main" : "")),
 	       nm_platform_get_use_udev (platform) ? "use" : "no");
 
-
-	priv->genl = nl_socket_alloc ();
-	g_assert (priv->genl);
-
-	nle = nl_connect (priv->genl, NETLINK_GENERIC);
-	if (nle) {
-		_LOGE ("unable to connect the generic netlink socket \"%s\" (%d)",
-		       nl_geterror (nle), -nle);
-		nl_socket_free (priv->genl);
-		priv->genl = NULL;
-	}
-
 	priv->nlh = nl_socket_alloc ();
 	g_assert (priv->nlh);
 
@@ -7928,22 +7127,6 @@ constructed (GObject *_object)
 	}
 }
 
-NMPlatform *
-nm_linux_platform_new (gboolean log_with_ptr, gboolean netns_support)
-{
-	gboolean use_udev = FALSE;
-
-	if (   nmp_netns_is_initial ()
-	    && access ("/sys", W_OK) == 0)
-		use_udev = TRUE;
-
-	return g_object_new (NM_TYPE_LINUX_PLATFORM,
-	                     NM_PLATFORM_LOG_WITH_PTR, log_with_ptr,
-	                     NM_PLATFORM_USE_UDEV, use_udev,
-	                     NM_PLATFORM_NETNS_SUPPORT, netns_support,
-	                     NULL);
-}
-
 static void
 dispose (GObject *object)
 {
@@ -7971,12 +7154,12 @@ finalize (GObject *object)
 	g_ptr_array_unref (priv->delayed_action.list_refresh_link);
 	g_array_unref (priv->delayed_action.list_wait_for_nl_response);
 
-	nl_socket_free (priv->genl);
-
 	g_source_remove (priv->event_id);
 	g_io_channel_unref (priv->event_channel);
 	nl_socket_free (priv->nlh);
 
+	g_hash_table_unref (priv->wifi_data);
+
 	if (priv->sysctl_get_prev_values) {
 		sysctl_clear_cache_list = g_slist_remove (sysctl_clear_cache_list, object);
 		g_hash_table_destroy (priv->sysctl_get_prev_values);
@@ -8022,8 +7205,7 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass)
 	platform_class->link_get_permanent_address = link_get_permanent_address;
 	platform_class->link_set_mtu = link_set_mtu;
 	platform_class->link_set_name = link_set_name;
-	platform_class->link_set_sriov_params = link_set_sriov_params;
-	platform_class->link_set_sriov_vfs = link_set_sriov_vfs;
+	platform_class->link_set_sriov_num_vfs = link_set_sriov_num_vfs;
 
 	platform_class->link_get_physical_port_id = link_get_physical_port_id;
 	platform_class->link_get_dev_id = link_get_dev_id;
@@ -8056,27 +7238,19 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass)
 	platform_class->wifi_set_powersave = wifi_set_powersave;
 	platform_class->wifi_find_frequency = wifi_find_frequency;
 	platform_class->wifi_indicate_addressing_running = wifi_indicate_addressing_running;
-	platform_class->wifi_get_wake_on_wlan = wifi_get_wake_on_wlan;
 	platform_class->wifi_set_wake_on_wlan = wifi_set_wake_on_wlan;
 
 	platform_class->mesh_get_channel = mesh_get_channel;
 	platform_class->mesh_set_channel = mesh_set_channel;
 	platform_class->mesh_set_ssid = mesh_set_ssid;
 
-	platform_class->wpan_get_pan_id = wpan_get_pan_id;
-	platform_class->wpan_set_pan_id = wpan_set_pan_id;
-	platform_class->wpan_get_short_addr = wpan_get_short_addr;
-	platform_class->wpan_set_short_addr = wpan_set_short_addr;
-
 	platform_class->link_gre_add = link_gre_add;
 	platform_class->link_ip6tnl_add = link_ip6tnl_add;
-	platform_class->link_ip6gre_add = link_ip6gre_add;
 	platform_class->link_macsec_add = link_macsec_add;
 	platform_class->link_macvlan_add = link_macvlan_add;
 	platform_class->link_ipip_add = link_ipip_add;
 	platform_class->link_sit_add = link_sit_add;
 	platform_class->link_tun_add = link_tun_add;
-	platform_class->link_6lowpan_add = link_6lowpan_add;
 
 	platform_class->object_delete = object_delete;
 	platform_class->ip4_address_add = ip4_address_add;
diff --git a/src/platform/nm-netlink.c b/src/platform/nm-netlink.c
index 3e2ad911..4cb19780 100644
--- a/src/platform/nm-netlink.c
+++ b/src/platform/nm-netlink.c
@@ -52,6 +52,7 @@ struct nl_msg {
 	struct ucred            nm_creds;
 	struct nlmsghdr *       nm_nlh;
 	size_t                  nm_size;
+	int                     nm_refcnt;
 };
 
 struct nl_sock {
@@ -83,18 +84,18 @@ NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_geterror, int,
 )
 
 const char *
-nl_geterror (int nlerr)
+nl_geterror (int err)
 {
 	const char *s;
 
-	nlerr = nl_errno (nlerr);
+	err = nl_errno (err);
 
-	if (nlerr >= _NLE_BASE) {
-		s = _geterror (nlerr);
+	if (err >= _NLE_BASE) {
+		s = _geterror (err);
 		if (s)
 			return s;
 	}
-	return g_strerror (nlerr);
+	return g_strerror (err);
 }
 
 /*****************************************************************************/
@@ -251,13 +252,27 @@ nlmsg_reserve (struct nl_msg *n, size_t len, int pad)
 	n->nm_nlh->nlmsg_len += tlen;
 
 	if (tlen > len)
-		memset (buf + len, 0, tlen - len);
+		memset(buf + len, 0, tlen - len);
 
 	return buf;
 }
 
 /*****************************************************************************/
 
+static int
+ get_default_page_size (void)
+{
+	static int val = 0;
+	int v;
+
+	if (G_UNLIKELY (val == 0)) {
+		v = getpagesize ();
+		g_assert (v > 0);
+		val = v;
+	}
+	return val;
+}
+
 struct nlattr *
 nla_reserve (struct nl_msg *msg, int attrtype, int attrlen)
 {
@@ -267,38 +282,22 @@ nla_reserve (struct nl_msg *msg, int attrtype, int attrlen)
 	if (attrlen < 0)
 		return NULL;
 
-	tlen = NLMSG_ALIGN (msg->nm_nlh->nlmsg_len) + nla_total_size (attrlen);
+	tlen = NLMSG_ALIGN(msg->nm_nlh->nlmsg_len) + nla_total_size(attrlen);
 
 	if (tlen > msg->nm_size)
 		return NULL;
 
-	nla = (struct nlattr *) nlmsg_tail (msg->nm_nlh);
+	nla = (struct nlattr *) nlmsg_tail(msg->nm_nlh);
 	nla->nla_type = attrtype;
-	nla->nla_len = nla_attr_size (attrlen);
+	nla->nla_len = nla_attr_size(attrlen);
 
 	if (attrlen)
-		memset ((unsigned char *) nla + nla->nla_len, 0, nla_padlen (attrlen));
+		memset((unsigned char *) nla + nla->nla_len, 0, nla_padlen(attrlen));
 	msg->nm_nlh->nlmsg_len = tlen;
 
 	return nla;
 }
 
-/*****************************************************************************/
-
-static int
-get_default_page_size (void)
-{
-	static int val = 0;
-	int v;
-
-	if (G_UNLIKELY (val == 0)) {
-		v = getpagesize ();
-		g_assert (v > 0);
-		val = v;
-	}
-	return val;
-}
-
 struct nl_msg *
 nlmsg_alloc_size (size_t len)
 {
@@ -309,6 +308,7 @@ nlmsg_alloc_size (size_t len)
 
 	nm = g_slice_new0 (struct nl_msg);
 
+	nm->nm_refcnt = 1;
 	nm->nm_protocol = -1;
 	nm->nm_size = len;
 	nm->nm_nlh = g_malloc0 (len);
@@ -331,40 +331,48 @@ nlmsg_alloc (void)
 	return nlmsg_alloc_size (get_default_page_size ());
 }
 
+/**
+ * Allocate a new netlink message with maximum payload size specified.
+ */
 struct nl_msg *
-nlmsg_alloc_convert (struct nlmsghdr *hdr)
+nlmsg_alloc_inherit (struct nlmsghdr *hdr)
 {
 	struct nl_msg *nm;
 
-	nm = nlmsg_alloc_size (NLMSG_ALIGN (hdr->nlmsg_len));
-	memcpy (nm->nm_nlh, hdr, hdr->nlmsg_len);
+	nm = nlmsg_alloc ();
+	if (hdr) {
+		struct nlmsghdr *new = nm->nm_nlh;
+
+		new->nlmsg_type = hdr->nlmsg_type;
+		new->nlmsg_flags = hdr->nlmsg_flags;
+		new->nlmsg_seq = hdr->nlmsg_seq;
+		new->nlmsg_pid = hdr->nlmsg_pid;
+	}
+
 	return nm;
 }
 
 struct nl_msg *
-nlmsg_alloc_simple (int nlmsgtype, int flags)
+nlmsg_alloc_convert (struct nlmsghdr *hdr)
 {
 	struct nl_msg *nm;
-	struct nlmsghdr *new;
 
-	nm = nlmsg_alloc ();
-	new = nm->nm_nlh;
-	new->nlmsg_type = nlmsgtype;
-	new->nlmsg_flags = flags;
+	nm = nlmsg_alloc_size (NLMSG_ALIGN (hdr->nlmsg_len));
+	memcpy(nm->nm_nlh, hdr, hdr->nlmsg_len);
 	return nm;
 }
 
-void nlmsg_free (struct nl_msg *msg)
+struct nl_msg *
+nlmsg_alloc_simple (int nlmsgtype, int flags)
 {
-	if (!msg)
-		return;
+	struct nlmsghdr nlh = {
+		.nlmsg_type = nlmsgtype,
+		.nlmsg_flags = flags,
+	};
 
-	g_free (msg->nm_nlh);
-	g_slice_free (struct nl_msg, msg);
+	return nlmsg_alloc_inherit (&nlh);
 }
 
-/*****************************************************************************/
-
 int
 nlmsg_append (struct nl_msg *n, void *data, size_t len, int pad)
 {
@@ -374,21 +382,19 @@ nlmsg_append (struct nl_msg *n, void *data, size_t len, int pad)
 	if (tmp == NULL)
 		return -ENOMEM;
 
-	memcpy (tmp, data, len);
+	memcpy(tmp, data, len);
 	return 0;
 }
 
-/*****************************************************************************/
-
 int
 nlmsg_parse (struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[],
              int maxtype, const struct nla_policy *policy)
 {
-	if (!nlmsg_valid_hdr (nlh, hdrlen))
+	if (!nlmsg_valid_hdr(nlh, hdrlen))
 		return -NLE_MSG_TOOSHORT;
 
-	return nla_parse (tb, maxtype, nlmsg_attrdata (nlh, hdrlen),
-	                  nlmsg_attrlen (nlh, hdrlen), policy);
+	return nla_parse (tb, maxtype, nlmsg_attrdata(nlh, hdrlen),
+	                  nlmsg_attrlen(nlh, hdrlen), policy);
 }
 
 struct nlmsghdr *
@@ -406,8 +412,8 @@ nlmsg_put (struct nl_msg *n, uint32_t pid, uint32_t seq,
 	nlh->nlmsg_pid = pid;
 	nlh->nlmsg_seq = seq;
 
-	if (   payload > 0
-	    && nlmsg_reserve (n, payload, NLMSG_ALIGNTO) == NULL)
+	if (payload > 0 &&
+	    nlmsg_reserve(n, payload, NLMSG_ALIGNTO) == NULL)
 		return NULL;
 
 	return nlh;
@@ -418,8 +424,8 @@ nla_get_u64 (const struct nlattr *nla)
 {
 	uint64_t tmp = 0;
 
-	if (nla && nla_len (nla) >= sizeof (tmp))
-		memcpy (&tmp, nla_data (nla), sizeof (tmp));
+	if (nla && nla_len(nla) >= sizeof (tmp))
+		memcpy(&tmp, nla_data(nla), sizeof (tmp));
 
 	return tmp;
 }
@@ -427,8 +433,8 @@ nla_get_u64 (const struct nlattr *nla)
 size_t
 nla_strlcpy (char *dst, const struct nlattr *nla, size_t dstsize)
 {
-	size_t srclen = nla_len (nla);
-	const char *src = nla_data (nla);
+	size_t srclen = nla_len(nla);
+	const char *src = nla_data(nla);
 
 	if (srclen > 0 && src[srclen - 1] == '\0')
 		srclen--;
@@ -436,8 +442,8 @@ nla_strlcpy (char *dst, const struct nlattr *nla, size_t dstsize)
 	if (dstsize > 0) {
 		size_t len = (srclen >= dstsize) ? dstsize - 1 : srclen;
 
-		memset (dst, 0, dstsize);
-		memcpy (dst, src, len);
+		memset(dst, 0, dstsize);
+		memcpy(dst, src, len);
 	}
 
 	return srclen;
@@ -452,7 +458,7 @@ nla_memcpy (void *dest, const struct nlattr *src, int count)
 		return 0;
 
 	minlen = NM_MIN (count, (int) nla_len (src));
-	memcpy (dest, nla_data (src), minlen);
+	memcpy(dest, nla_data(src), minlen);
 
 	return minlen;
 }
@@ -462,7 +468,7 @@ nla_put (struct nl_msg *msg, int attrtype, int datalen, const void *data)
 {
 	struct nlattr *nla;
 
-	nla = nla_reserve (msg, attrtype, datalen);
+	nla = nla_reserve(msg, attrtype, datalen);
 	if (!nla) {
 		if (datalen < 0)
 			g_return_val_if_reached (-NLE_BUG);
@@ -471,7 +477,7 @@ nla_put (struct nl_msg *msg, int attrtype, int datalen, const void *data)
 	}
 
 	if (datalen > 0)
-		memcpy (nla_data (nla), data, datalen);
+		memcpy (nla_data(nla), data, datalen);
 
 	return 0;
 }
@@ -495,21 +501,21 @@ nla_nest_cancel (struct nl_msg *msg, const struct nlattr *attr)
 {
 	ssize_t len;
 
-	len = (char *) nlmsg_tail (msg->nm_nlh) - (char *) attr;
+	len = (char *) nlmsg_tail(msg->nm_nlh) - (char *) attr;
 	if (len < 0)
 		g_return_if_reached ();
 	else if (len > 0) {
 		msg->nm_nlh->nlmsg_len -= len;
-		memset (nlmsg_tail (msg->nm_nlh), 0, len);
+		memset(nlmsg_tail(msg->nm_nlh), 0, len);
 	}
 }
 
 struct nlattr *
 nla_nest_start (struct nl_msg *msg, int attrtype)
 {
-	struct nlattr *start = (struct nlattr *) nlmsg_tail (msg->nm_nlh);
+	struct nlattr *start = (struct nlattr *) nlmsg_tail(msg->nm_nlh);
 
-	if (nla_put (msg, attrtype, 0, NULL) < 0)
+	if (nla_put(msg, attrtype, 0, NULL) < 0)
 		return NULL;
 
 	return start;
@@ -520,7 +526,7 @@ _nest_end (struct nl_msg *msg, struct nlattr *start, int keep_empty)
 {
 	size_t pad, len;
 
-	len = (char *) nlmsg_tail (msg->nm_nlh) - (char *) start;
+	len = (char *) nlmsg_tail(msg->nm_nlh) - (char *) start;
 
 	if (   len > USHRT_MAX
 	    || (!keep_empty && len == NLA_HDRLEN)) {
@@ -528,7 +534,7 @@ _nest_end (struct nl_msg *msg, struct nlattr *start, int keep_empty)
 		 * Max nlattr size exceeded or empty nested attribute, trim the
 		 * attribute header again
 		 */
-		nla_nest_cancel (msg, start);
+		nla_nest_cancel(msg, start);
 
 		/* Return error only if nlattr size was exceeded */
 		return (len == NLA_HDRLEN) ? 0 : -NLE_ATTRSIZE;
@@ -536,7 +542,7 @@ _nest_end (struct nl_msg *msg, struct nlattr *start, int keep_empty)
 
 	start->nla_len = len;
 
-	pad = NLMSG_ALIGN (msg->nm_nlh->nlmsg_len) - msg->nm_nlh->nlmsg_len;
+	pad = NLMSG_ALIGN(msg->nm_nlh->nlmsg_len) - msg->nm_nlh->nlmsg_len;
 	if (pad > 0) {
 		/*
 		 * Data inside attribute does not end at a alignment boundry.
@@ -544,7 +550,7 @@ _nest_end (struct nl_msg *msg, struct nlattr *start, int keep_empty)
 		 * the message. nlmsg_reserve() may never fail in this situation,
 		 * the allocate message buffer must be a multiple of NLMSG_ALIGNTO.
 		 */
-		if (!nlmsg_reserve (msg, pad, 0))
+		if (!nlmsg_reserve(msg, pad, 0))
 			g_return_val_if_reached (-NLE_BUG);
 	}
 
@@ -572,7 +578,7 @@ validate_nla (const struct nlattr *nla, int maxtype,
 {
 	const struct nla_policy *pt;
 	unsigned int minlen = 0;
-	int type = nla_type (nla);
+	int type = nla_type(nla);
 
 	if (type < 0 || type > maxtype)
 		return 0;
@@ -587,15 +593,15 @@ validate_nla (const struct nlattr *nla, int maxtype,
 	else if (pt->type != NLA_UNSPEC)
 		minlen = nla_attr_minlen[pt->type];
 
-	if (nla_len (nla) < minlen)
+	if (nla_len(nla) < minlen)
 		return -NLE_UNSPEC;
 
-	if (pt->maxlen && nla_len (nla) > pt->maxlen)
+	if (pt->maxlen && nla_len(nla) > pt->maxlen)
 		return -NLE_UNSPEC;
 
 	if (pt->type == NLA_STRING) {
-		const char *data = nla_data (nla);
-		if (data[nla_len (nla) - 1] != '\0')
+		const char *data = nla_data(nla);
+		if (data[nla_len(nla) - 1] != '\0')
 			return -NLE_UNSPEC;
 	}
 
@@ -607,32 +613,48 @@ nla_parse (struct nlattr *tb[], int maxtype, struct nlattr *head, int len,
            const struct nla_policy *policy)
 {
 	struct nlattr *nla;
-	int rem, nlerr;
+	int rem, err;
 
-	memset (tb, 0, sizeof (struct nlattr *) * (maxtype + 1));
+	memset(tb, 0, sizeof (struct nlattr *) * (maxtype + 1));
 
-	nla_for_each_attr (nla, head, len, rem) {
-		int type = nla_type (nla);
+	nla_for_each_attr(nla, head, len, rem) {
+		int type = nla_type(nla);
 
 		if (type > maxtype)
 			continue;
 
 		if (policy) {
-			nlerr = validate_nla (nla, maxtype, policy);
-			if (nlerr < 0)
+			err = validate_nla(nla, maxtype, policy);
+			if (err < 0)
 				goto errout;
 		}
 
 		tb[type] = nla;
 	}
 
-	nlerr = 0;
+	err = 0;
 errout:
-	return nlerr;
+	return err;
 }
 
 /*****************************************************************************/
 
+void nlmsg_free (struct nl_msg *msg)
+{
+	if (!msg)
+		return;
+
+	if (msg->nm_refcnt < 1)
+		g_return_if_reached ();
+
+	msg->nm_refcnt--;
+
+	if (msg->nm_refcnt <= 0) {
+		g_free (msg->nm_nlh);
+		g_slice_free (struct nl_msg, msg);
+	}
+}
+
 int
 nlmsg_get_proto (struct nl_msg *msg)
 {
@@ -791,7 +813,7 @@ int
 genl_ctrl_resolve (struct nl_sock *sk, const char *name)
 {
 	nm_auto_nlmsg struct nl_msg *msg = NULL;
-	int nlerr;
+	int result = -ENOMEM;
 	gint32 response_data = -1;
 	const struct nl_cb cb = {
 		.valid_cb = _genl_parse_getfamily,
@@ -802,29 +824,31 @@ genl_ctrl_resolve (struct nl_sock *sk, const char *name)
 
 	if (!genlmsg_put (msg, NL_AUTO_PORT, NL_AUTO_SEQ, GENL_ID_CTRL,
 	                  0, 0, CTRL_CMD_GETFAMILY, 1))
-		return -ENOMEM;
+		goto out;
 
-	nlerr = nla_put_string (msg, CTRL_ATTR_FAMILY_NAME, name);
-	if (nlerr < 0)
-		return nlerr;
+	if (nla_put_string (msg, CTRL_ATTR_FAMILY_NAME, name) < 0)
+		goto out;
 
-	nlerr = nl_send_auto (sk, msg);
-	if (nlerr < 0)
-		return nlerr;
+	result = nl_send_auto (sk, msg);
+	if (result < 0)
+		goto out;
 
-	nlerr = nl_recvmsgs (sk, &cb);
-	if (nlerr < 0)
-		return nlerr;
+	result = nl_recvmsgs (sk, &cb);
+	if (result < 0)
+		goto out;
 
 	/* If search was successful, request may be ACKed after data */
-	nlerr = nl_wait_for_ack (sk, NULL);
-	if (nlerr < 0)
-		return nlerr;
+	result = nl_wait_for_ack (sk, NULL);
+	if (result < 0)
+		goto out;
 
-	if (response_data < 0)
-		return -NLE_UNSPEC;
+	if (response_data > 0)
+		result = response_data;
+	else
+		result = -ENOENT;
 
-	return response_data;
+out:
+	return result;
 }
 
 /*****************************************************************************/
@@ -839,7 +863,7 @@ nl_socket_alloc (void)
 	sk->s_fd = -1;
 	sk->s_local.nl_family = AF_NETLINK;
 	sk->s_peer.nl_family = AF_NETLINK;
-	sk->s_seq_expect = sk->s_seq_next = time (NULL);
+	sk->s_seq_expect = sk->s_seq_next = time(NULL);
 
 	return sk;
 }
@@ -914,7 +938,7 @@ nl_socket_set_nonblocking (const struct nl_sock *sk)
 	if (sk->s_fd == -1)
 		return -NLE_BAD_SOCK;
 
-	if (fcntl (sk->s_fd, F_SETFL, O_NONBLOCK) < 0)
+	if (fcntl(sk->s_fd, F_SETFL, O_NONBLOCK) < 0)
 		return -nl_syserr2nlerr (errno);
 
 	return 0;
@@ -958,27 +982,25 @@ nl_socket_add_memberships (struct nl_sock *sk, int group, ...)
 	if (sk->s_fd == -1)
 		return -NLE_BAD_SOCK;
 
-	va_start (ap, group);
+	va_start(ap, group);
 
 	while (group != 0) {
 		if (group < 0) {
-			va_end (ap);
+			va_end(ap);
 			g_return_val_if_reached (-NLE_BUG);
 		}
 
 		err = setsockopt (sk->s_fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP,
 		                  &group, sizeof (group));
 		if (err < 0) {
-			int errsv = errno;
-
-			va_end (ap);
-			return -nl_syserr2nlerr (errsv);
+			va_end(ap);
+			return -nl_syserr2nlerr (errno);
 		}
 
-		group = va_arg (ap, int);
+		group = va_arg(ap, int);
 	}
 
-	va_end (ap);
+	va_end(ap);
 
 	return 0;
 }
@@ -1008,7 +1030,7 @@ void nl_socket_disable_msg_peek (struct nl_sock *sk)
 int
 nl_connect (struct nl_sock *sk, int protocol)
 {
-	int err, nlerr;
+	int err;
 	socklen_t addrlen;
 	struct sockaddr_nl local = { 0 };
 
@@ -1017,12 +1039,12 @@ nl_connect (struct nl_sock *sk, int protocol)
 
 	sk->s_fd = socket (AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, protocol);
 	if (sk->s_fd < 0) {
-		nlerr = -nl_syserr2nlerr (errno);
+		err = -nl_syserr2nlerr (errno);
 		goto errout;
 	}
 
-	nlerr = nl_socket_set_buffer_size (sk, 0, 0);
-	if (nlerr < 0)
+	err = nl_socket_set_buffer_size(sk, 0, 0);
+	if (err < 0)
 		goto errout;
 
 	nm_assert (sk->s_local.nl_pid == 0);
@@ -1030,7 +1052,7 @@ nl_connect (struct nl_sock *sk, int protocol)
 	err = bind (sk->s_fd, (struct sockaddr*) &sk->s_local,
 	            sizeof (sk->s_local));
 	if (err != 0) {
-		nlerr = -nl_syserr2nlerr (errno);
+		err = -nl_syserr2nlerr (errno);
 		goto errout;
 	}
 
@@ -1038,17 +1060,17 @@ nl_connect (struct nl_sock *sk, int protocol)
 	err = getsockname (sk->s_fd, (struct sockaddr *) &local,
 	                   &addrlen);
 	if (err < 0) {
-		nlerr = -nl_syserr2nlerr (errno);
+		err = -nl_syserr2nlerr (errno);
 		goto errout;
 	}
 
 	if (addrlen != sizeof (local)) {
-		nlerr = -NLE_UNSPEC;
+		err = -NLE_UNSPEC;
 		goto errout;
 	}
 
 	if (local.nl_family != AF_NETLINK) {
-		nlerr = -NLE_UNSPEC;
+		err = -NLE_UNSPEC;
 		goto errout;
 	}
 
@@ -1059,10 +1081,10 @@ nl_connect (struct nl_sock *sk, int protocol)
 
 errout:
 	if (sk->s_fd != -1) {
-		close (sk->s_fd);
+		close(sk->s_fd);
 		sk->s_fd = -1;
 	}
-	return nlerr;
+	return err;
 }
 
 /*****************************************************************************/
@@ -1078,7 +1100,7 @@ _cb_init (struct nl_cb *dst, const struct nl_cb *src)
 		memset (dst, 0, sizeof (*dst));
 }
 
-static int ack_wait_handler (struct nl_msg *msg, void *arg)
+static int ack_wait_handler(struct nl_msg *msg, void *arg)
 {
 	return NL_STOP;
 }
@@ -1099,22 +1121,16 @@ do { \
 	const struct nl_cb *_cb = (cb); \
 	\
 	if (_cb->type##_cb) { \
-		/* the returned value here must be either a negative
-		 * netlink error number, or one of NL_SKIP, NL_STOP, NL_OK. */ \
-		nlerr = _cb->type##_cb ((msg), _cb->type##_arg); \
-		switch (nlerr) { \
+		err = _cb->type##_cb ((msg), _cb->type##_arg); \
+		switch (err) { \
 		case NL_OK: \
-			nlerr = 0; \
+			err = 0; \
 			break; \
 		case NL_SKIP: \
 			goto skip; \
 		case NL_STOP: \
 			goto stop; \
 		default: \
-			if (nlerr >= 0) { \
-				nm_assert_not_reached (); \
-				nlerr = -NLE_BUG; \
-			} \
 			goto out; \
 		} \
 	} \
@@ -1123,7 +1139,7 @@ do { \
 int
 nl_recvmsgs (struct nl_sock *sk, const struct nl_cb *cb)
 {
-	int n, nlerr = 0, multipart = 0, interrupted = 0, nrecv = 0;
+	int n, err = 0, multipart = 0, interrupted = 0, nrecv = 0;
 	gs_free unsigned char *buf = NULL;
 	struct nlmsghdr *hdr;
 	struct sockaddr_nl nla = { 0 };
@@ -1148,9 +1164,9 @@ continue_reading:
 		nrecv++;
 
 		/* Only do sequence checking if auto-ack mode is enabled */
-		if (! (sk->s_flags & NL_NO_AUTO_ACK)) {
+		if (!(sk->s_flags & NL_NO_AUTO_ACK)) {
 			if (hdr->nlmsg_seq != sk->s_seq_expect) {
-				nlerr = -NLE_SEQ_MISMATCH;
+				err = -NLE_SEQ_MISMATCH;
 				goto out;
 			}
 		}
@@ -1182,7 +1198,7 @@ continue_reading:
 		 * this action by skipping this packet. */
 		if (hdr->nlmsg_type == NLMSG_DONE) {
 			multipart = 0;
-			NL_CB_CALL (cb, finish, msg);
+			NL_CB_CALL(cb, finish, msg);
 		}
 
 		/* Message to be ignored, the default action is to
@@ -1196,53 +1212,50 @@ continue_reading:
 		 * quit parsing. The user may overrule this action by retuning
 		 * NL_SKIP or NL_PROCEED (dangerous) */
 		else if (hdr->nlmsg_type == NLMSG_OVERRUN) {
-			nlerr = -NLE_MSG_OVERFLOW;
+			err = -NLE_MSG_OVERFLOW;
 			goto out;
 		}
 
 		/* Message carries a nlmsgerr */
 		else if (hdr->nlmsg_type == NLMSG_ERROR) {
-			struct nlmsgerr *e = nlmsg_data (hdr);
+			struct nlmsgerr *e = nlmsg_data(hdr);
 
-			if (hdr->nlmsg_len < nlmsg_size (sizeof (*e))) {
+			if (hdr->nlmsg_len < nlmsg_size(sizeof (*e))) {
 				/* Truncated error message, the default action
 				 * is to stop parsing. The user may overrule
 				 * this action by returning NL_SKIP or
 				 * NL_PROCEED (dangerous) */
-				nlerr = -NLE_MSG_TRUNC;
+				err = -NLE_MSG_TRUNC;
 				goto out;
 			}
 			if (e->error) {
 				/* Error message reported back from kernel. */
 				if (cb->err_cb) {
-					/* the returned value here must be either a negative
-					 * netlink error number, or one of NL_SKIP, NL_STOP, NL_OK. */
-					nlerr = cb->err_cb (&nla, e,
-					                    cb->err_arg);
-					if (nlerr < 0)
+					err = cb->err_cb (&nla, e,
+					                  cb->err_arg);
+					if (err < 0)
 						goto out;
-					else if (nlerr == NL_SKIP)
+					else if (err == NL_SKIP)
 						goto skip;
-					else if (nlerr == NL_STOP) {
-						nlerr = -nl_syserr2nlerr (e->error);
+					else if (err == NL_STOP) {
+						err = -e->error;
 						goto out;
 					}
-					nm_assert (nlerr == NL_OK);
 				} else {
-					nlerr = -nl_syserr2nlerr (e->error);
+					err = -e->error;
 					goto out;
 				}
 			} else
-				NL_CB_CALL (cb, ack, msg);
+				NL_CB_CALL(cb, ack, msg);
 		} else {
 			/* Valid message (not checking for MULTIPART bit to
 			 * get along with broken kernels. NL_SKIP has no
 			 * effect on this.  */
-			NL_CB_CALL (cb, valid, msg);
+			NL_CB_CALL(cb, valid, msg);
 		}
 skip:
-		nlerr = 0;
-		hdr = nlmsg_next (hdr, &n);
+		err = 0;
+		hdr = nlmsg_next(hdr, &n);
 	}
 
 	if (multipart) {
@@ -1254,14 +1267,13 @@ skip:
 	}
 
 stop:
-	nlerr = 0;
+	err = 0;
 
 out:
 	if (interrupted)
-		nlerr = -NLE_DUMP_INTR;
+		err = -NLE_DUMP_INTR;
 
-	nm_assert (nlerr <= 0);
-	return nlerr ?: nrecv;
+	return err ?: nrecv;
 }
 
 int
@@ -1274,7 +1286,7 @@ nl_sendmsg (struct nl_sock *sk, struct nl_msg *msg, struct msghdr *hdr)
 
 	nlmsg_set_src (msg, &sk->s_local);
 
-	ret = sendmsg (sk->s_fd, hdr, 0);
+	ret = sendmsg(sk->s_fd, hdr, 0);
 	if (ret < 0)
 		return -nl_syserr2nlerr (errno);
 
@@ -1292,31 +1304,31 @@ nl_send_iovec (struct nl_sock *sk, struct nl_msg *msg, struct iovec *iov, unsign
 		.msg_iov = iov,
 		.msg_iovlen = iovlen,
 	};
-	char buf[CMSG_SPACE (sizeof (struct ucred))];
+	char buf[CMSG_SPACE(sizeof (struct ucred))];
 
 	/* Overwrite destination if specified in the message itself, defaults
 	 * to the peer address of the socket.
 	 */
-	dst = nlmsg_get_dst (msg);
+	dst = nlmsg_get_dst(msg);
 	if (dst->nl_family == AF_NETLINK)
 		hdr.msg_name = dst;
 
 	/* Add credentials if present. */
-	creds = nlmsg_get_creds (msg);
+	creds = nlmsg_get_creds(msg);
 	if (creds != NULL) {
 		struct cmsghdr *cmsg;
 
 		hdr.msg_control = buf;
 		hdr.msg_controllen = sizeof (buf);
 
-		cmsg = CMSG_FIRSTHDR (&hdr);
+		cmsg = CMSG_FIRSTHDR(&hdr);
 		cmsg->cmsg_level = SOL_SOCKET;
 		cmsg->cmsg_type = SCM_CREDENTIALS;
-		cmsg->cmsg_len = CMSG_LEN (sizeof (struct ucred));
-		memcpy (CMSG_DATA (cmsg), creds, sizeof (struct ucred));
+		cmsg->cmsg_len = CMSG_LEN(sizeof (struct ucred));
+		memcpy(CMSG_DATA(cmsg), creds, sizeof (struct ucred));
 	}
 
-	return nl_sendmsg (sk, msg, &hdr);
+	return nl_sendmsg(sk, msg, &hdr);
 }
 
 void
@@ -1324,9 +1336,9 @@ nl_complete_msg (struct nl_sock *sk, struct nl_msg *msg)
 {
 	struct nlmsghdr *nlh;
 
-	nlh = nlmsg_hdr (msg);
+	nlh = nlmsg_hdr(msg);
 	if (nlh->nlmsg_pid == NL_AUTO_PORT)
-		nlh->nlmsg_pid = nl_socket_get_local_port (sk);
+		nlh->nlmsg_pid = nl_socket_get_local_port(sk);
 
 	if (nlh->nlmsg_seq == NL_AUTO_SEQ)
 		nlh->nlmsg_seq = sk->s_seq_next++;
@@ -1344,18 +1356,18 @@ int
 nl_send (struct nl_sock *sk, struct nl_msg *msg)
 {
 	struct iovec iov = {
-		.iov_base = (void *) nlmsg_hdr (msg),
-		.iov_len = nlmsg_hdr (msg)->nlmsg_len,
+		.iov_base = (void *) nlmsg_hdr(msg),
+		.iov_len = nlmsg_hdr(msg)->nlmsg_len,
 	};
 
-	return nl_send_iovec (sk, msg, &iov, 1);
+	return nl_send_iovec(sk, msg, &iov, 1);
 }
 
-int nl_send_auto (struct nl_sock *sk, struct nl_msg *msg)
+int nl_send_auto(struct nl_sock *sk, struct nl_msg *msg)
 {
-	nl_complete_msg (sk, msg);
+	nl_complete_msg(sk, msg);
 
-	return nl_send (sk, msg);
+	return nl_send(sk, msg);
 }
 
 int
@@ -1385,9 +1397,9 @@ nl_recv (struct nl_sock *sk, struct sockaddr_nl *nla,
 		flags |= MSG_PEEK | MSG_TRUNC;
 
 	if (page_size == 0)
-		page_size = getpagesize () * 4;
+		page_size = getpagesize() * 4;
 
-	iov.iov_len = sk->s_bufsize ?: page_size;
+	iov.iov_len = sk->s_bufsize ? : page_size;
 	iov.iov_base = g_malloc (iov.iov_len);
 
 	if (   creds
@@ -1397,7 +1409,7 @@ nl_recv (struct nl_sock *sk, struct sockaddr_nl *nla,
 	}
 
 retry:
-	n = recvmsg (sk->s_fd, &msg, flags);
+	n = recvmsg(sk->s_fd, &msg, flags);
 	if (!n) {
 		retval = 0;
 		goto abort;
@@ -1453,12 +1465,12 @@ retry:
 	if (creds && (sk->s_flags & NL_SOCK_PASSCRED)) {
 		struct cmsghdr *cmsg;
 
-		for (cmsg = CMSG_FIRSTHDR (&msg); cmsg; cmsg = CMSG_NXTHDR (&msg, cmsg)) {
+		for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
 			if (cmsg->cmsg_level != SOL_SOCKET)
 				continue;
 			if (cmsg->cmsg_type != SCM_CREDENTIALS)
 				continue;
-			tmpcreds = nm_memdup (CMSG_DATA (cmsg), sizeof (*tmpcreds));
+			tmpcreds = g_memdup (CMSG_DATA(cmsg), sizeof (*tmpcreds));
 			break;
 		}
 	}
diff --git a/src/platform/nm-netlink.h b/src/platform/nm-netlink.h
index 1fccddb9..185269ba 100644
--- a/src/platform/nm-netlink.h
+++ b/src/platform/nm-netlink.h
@@ -52,48 +52,32 @@
 #endif
 
 static inline int
-nl_errno (int nlerr)
+nl_errno (int err)
 {
-	/* Normalizes an netlink error to be positive. Various API returns negative
-	 * error codes, and this function converts the negative value to its
-	 * positive.
+	/* the error codes from our netlink implementation are plain errno
+	 * extended with our own error in a particular range starting from
+	 * _NLE_BASE.
 	 *
-	 * It's very similar to nm_errno(), but not exactly. The difference is that
-	 * nm_errno() is for plain errno, while nl_errno() is for netlink error numbers.
-	 * Yes, netlink error number are ~almost~ the same as errno, except that a particular
-	 * range (_NLE_BASE, _NLE_BASE_END) is reserved. The difference between the two
-	 * functions is only how G_MININT is mapped.
-	 *
-	 * See also nl_syserr2nlerr() below. */
-	return nlerr >= 0
-	       ? nlerr
-	       : ((nlerr == G_MININT) ? NLE_BUG : -nlerr);
+	 * However, often we encode errors as negative values. This function
+	 * normalizes the error and returns its positive value. */
+	return err >= 0
+	       ? err
+	       : ((err == G_MININT) ? NLE_BUG : -errno);
 }
 
 static inline int
-nl_syserr2nlerr (int errsv)
+nl_syserr2nlerr (int err)
 {
-	/* this maps a native errno to a (always non-negative) netlink error number.
-	 *
-	 * Note that netlink error numbers are embedded into the range of regular
-	 * errno. The only difference is, that netlink error numbers reserve a
-	 * range (_NLE_BASE, _NLE_BASE_END) for their own purpose.
-	 *
-	 * That means, converting an errno to netlink error number means in
-	 * most cases just returning itself (negative values are normalized
-	 * to be positive). Only values G_MININT and [_NLE_BASE, _NLE_BASE_END]
-	 * are coerced to the special value NLE_NATIVE_ERRNO, as they cannot
-	 * otherwise be represented in netlink error number domain. */
-	if (errsv == G_MININT)
+	if (err == G_MININT)
 		return NLE_NATIVE_ERRNO;
-	if (errsv < 0)
-		errsv = -errsv;
-	return (errsv >= _NLE_BASE && errsv < _NLE_BASE_END)
+	if (err < 0)
+		err = -err;
+	return (err >= _NLE_BASE && err < _NLE_BASE_END)
 	       ? NLE_NATIVE_ERRNO
-	       : errsv;
+	       : err;
 }
 
-const char *nl_geterror (int nlerr);
+const char *nl_geterror (int err);
 
 /*****************************************************************************/
 
@@ -193,12 +177,6 @@ nla_get_u8 (const struct nlattr *nla)
 }
 
 static inline uint8_t
-nla_get_s8 (const struct nlattr *nla)
-{
-	return *(const int8_t *) nla_data (nla);
-}
-
-static inline uint8_t
 nla_get_u8_cond (/*const*/ struct nlattr *const*tb, int attr, uint8_t default_val)
 {
 	nm_assert (tb);
@@ -219,12 +197,6 @@ nla_get_u32(const struct nlattr *nla)
 	return *(const uint32_t *) nla_data (nla);
 }
 
-static inline int32_t
-nla_get_s32(const struct nlattr *nla)
-{
-	return *(const int32_t *) nla_data (nla);
-}
-
 uint64_t nla_get_u64 (const struct nlattr *nla);
 
 static inline char *
@@ -260,18 +232,12 @@ nla_put_string (struct nl_msg *msg, int attrtype, const char *str)
 #define NLA_PUT_U8(msg, attrtype, value) \
 	NLA_PUT_TYPE(msg, uint8_t, attrtype, value)
 
-#define NLA_PUT_S8(msg, attrtype, value) \
-	NLA_PUT_TYPE(msg, int8_t, attrtype, value)
-
 #define NLA_PUT_U16(msg, attrtype, value) \
 	NLA_PUT_TYPE(msg, uint16_t, attrtype, value)
 
 #define NLA_PUT_U32(msg, attrtype, value) \
 	NLA_PUT_TYPE(msg, uint32_t, attrtype, value)
 
-#define NLA_PUT_S32(msg, attrtype, value) \
-	NLA_PUT_TYPE(msg, int32_t, attrtype, value)
-
 #define NLA_PUT_U64(msg, attrtype, value) \
 	NLA_PUT_TYPE(msg, uint64_t, attrtype, value)
 
@@ -330,6 +296,8 @@ struct nl_msg *nlmsg_alloc (void);
 
 struct nl_msg *nlmsg_alloc_size (size_t max);
 
+struct nl_msg *nlmsg_alloc_inherit (struct nlmsghdr *hdr);
+
 struct nl_msg *nlmsg_alloc_convert (struct nlmsghdr *hdr);
 
 struct nl_msg *nlmsg_alloc_simple (int nlmsgtype, int flags);
diff --git a/src/platform/nm-platform-utils.c b/src/platform/nm-platform-utils.c
index 216b1547..0d224443 100644
--- a/src/platform/nm-platform-utils.c
+++ b/src/platform/nm-platform-utils.c
@@ -36,15 +36,12 @@
 
 #include "nm-utils.h"
 #include "nm-setting-wired.h"
-#include "nm-ethtool-utils.h"
 
 #include "nm-core-utils.h"
 
-#define ONOFF(bool_val) ((bool_val) ? "on" : "off")
-
-/******************************************************************************
+/******************************************************************
  * utils
- *****************************************************************************/
+ ******************************************************************/
 
 extern char *if_indextoname (unsigned __ifindex, char *__ifname);
 unsigned if_nametoindex (const char *__ifname);
@@ -66,45 +63,9 @@ nmp_utils_if_nametoindex (const char *ifname)
 	return if_nametoindex (ifname);
 }
 
-/*****************************************************************************/
-
-typedef struct {
-	int fd;
-	int ifindex;
-	char ifname[IFNAMSIZ];
-} SocketHandle;
-
-static int
-socket_handle_init (SocketHandle *shandle, int ifindex)
-{
-	if (!nmp_utils_if_indextoname (ifindex, shandle->ifname)) {
-		shandle->ifindex = 0;
-		return -ENODEV;
-	}
-
-	shandle->fd = socket (PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
-	if (shandle->fd < 0) {
-		shandle->ifindex = 0;
-		return -errno;
-	}
-
-	shandle->ifindex = ifindex;
-	return 0;
-}
-
-static void
-socket_handle_destroy (SocketHandle *shandle)
-{
-	if (shandle->ifindex) {
-		shandle->ifindex = 0;
-		nm_close (shandle->fd);
-	}
-}
-#define nm_auto_socket_handle nm_auto(socket_handle_destroy)
-
-/******************************************************************************
+/******************************************************************
  * ethtool
- *****************************************************************************/
+ ******************************************************************/
 
 NM_UTILS_ENUM2STR_DEFINE_STATIC (_ethtool_cmd_to_string, guint32,
 	NM_UTILS_ENUM2STR (ETHTOOL_GDRVINFO,   "ETHTOOL_GDRVINFO"),
@@ -116,7 +77,6 @@ NM_UTILS_ENUM2STR_DEFINE_STATIC (_ethtool_cmd_to_string, guint32,
 	NM_UTILS_ENUM2STR (ETHTOOL_GSTATS,     "ETHTOOL_GSTATS"),
 	NM_UTILS_ENUM2STR (ETHTOOL_GSTRINGS,   "ETHTOOL_GSTRINGS"),
 	NM_UTILS_ENUM2STR (ETHTOOL_GWOL,       "ETHTOOL_GWOL"),
-	NM_UTILS_ENUM2STR (ETHTOOL_SFEATURES,  "ETHTOOL_SFEATURES"),
 	NM_UTILS_ENUM2STR (ETHTOOL_SSET,       "ETHTOOL_SSET"),
 	NM_UTILS_ENUM2STR (ETHTOOL_SWOL,       "ETHTOOL_SWOL"),
 );
@@ -127,8 +87,6 @@ _ethtool_data_to_string (gconstpointer edata, char *buf, gsize len)
 	return _ethtool_cmd_to_string (*((guint32 *) edata), buf, len);
 }
 
-/*****************************************************************************/
-
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
 #define ethtool_cmd_speed(pedata) ((pedata)->speed)
 
@@ -136,553 +94,117 @@ _ethtool_data_to_string (gconstpointer edata, char *buf, gsize len)
 	G_STMT_START { (pedata)->speed = (guint16) (speed); } G_STMT_END
 #endif
 
-static int
-ethtool_call_handle (SocketHandle *shandle, gpointer edata)
+static gboolean
+ethtool_get (int ifindex, gpointer edata)
 {
-	struct ifreq ifr = {
-		.ifr_data = edata,
-	};
+	char ifname[IFNAMSIZ];
 	char sbuf[50];
-	int errsv;
-
-	nm_assert (shandle);
-	nm_assert (shandle->ifindex);
-	nm_assert (shandle->ifname[0]);
-	nm_assert (strlen (shandle->ifname) < IFNAMSIZ);
-	nm_assert (edata);
-
-	memcpy (ifr.ifr_name, shandle->ifname, IFNAMSIZ);
-	if (ioctl (shandle->fd, SIOCETHTOOL, &ifr) < 0) {
-		errsv = errno;
-		nm_log_trace (LOGD_PLATFORM, "ethtool[%d]: %s, %s: failed: %s",
-		              shandle->ifindex,
-		              _ethtool_data_to_string (edata, sbuf, sizeof (sbuf)),
-		              shandle->ifname,
-		              strerror (errsv));
-		return -errsv;
-	}
 
-	nm_log_trace (LOGD_PLATFORM, "ethtool[%d]: %s, %s: success",
-	              shandle->ifindex,
-	              _ethtool_data_to_string (edata, sbuf, sizeof (sbuf)),
-	              shandle->ifname);
-	return 0;
-}
+	nm_assert (ifindex > 0);
 
-static int
-ethtool_call_ifindex (int ifindex, gpointer edata)
-{
-	nm_auto_socket_handle SocketHandle shandle = { };
-	int r;
-	char sbuf[50];
-
-	nm_assert (edata);
+	/* ethtool ioctl API uses the ifname to refer to an interface. That is racy
+	 * as interfaces can be renamed *sigh*.
+	 *
+	 * Note that we anyway have to verify whether the interface exists, before
+	 * calling ioctl for a non-existing ifname. This is to prevent autoloading
+	 * of kernel modules *sigh*.
+	 * Thus, as we anyway verify the existence of ifname before doing the call,
+	 * go one step further and lookup the ifname everytime anew.
+	 *
+	 * This does not solve the renaming race, but it minimizes the time for
+	 * the race to happen as much as possible. */
 
-	if ((r = socket_handle_init (&shandle, ifindex)) < 0) {
-		nm_log_trace (LOGD_PLATFORM, "ethtool[%d]: %s: failed creating ethtool socket: %s",
+	if (!nmp_utils_if_indextoname (ifindex, ifname)) {
+		nm_log_trace (LOGD_PLATFORM, "ethtool[%d]: %s: request fails resolving ifindex: %s",
 		              ifindex,
 		              _ethtool_data_to_string (edata, sbuf, sizeof (sbuf)),
-		              g_strerror (-r));
-		return r;
-	}
-
-	return ethtool_call_handle (&shandle, edata);
-}
-
-/*****************************************************************************/
-
-static struct ethtool_gstrings *
-ethtool_get_stringset (SocketHandle *shandle, int stringset_id)
-{
-	struct {
-		struct ethtool_sset_info info;
-		guint32 sentinel;
-	} sset_info = { };
-	gs_free struct ethtool_gstrings *gstrings = NULL;
-	guint32 i, len;
-
-	sset_info.info.cmd = ETHTOOL_GSSET_INFO;
-	sset_info.info.reserved = 0;
-	sset_info.info.sset_mask = (1ULL << stringset_id);
-
-	if (ethtool_call_handle (shandle, &sset_info) < 0)
-		return NULL;
-	if (!sset_info.info.sset_mask)
-		return NULL;
-
-	len = sset_info.info.data[0];
-
-	gstrings = g_malloc0 (sizeof (*gstrings) + (len * ETH_GSTRING_LEN));
-	gstrings->cmd = ETHTOOL_GSTRINGS;
-	gstrings->string_set = stringset_id;
-	gstrings->len = len;
-	if (gstrings->len > 0) {
-		if (ethtool_call_handle (shandle, gstrings) < 0)
-			return NULL;
-		for (i = 0; i < gstrings->len; i++) {
-			/* ensure NUL terminated */
-			gstrings->data[i * ETH_GSTRING_LEN + (ETH_GSTRING_LEN - 1)] = '\0';
-		}
-	}
-
-	return g_steal_pointer (&gstrings);
-}
-
-static int
-ethtool_gstrings_find (const struct ethtool_gstrings *gstrings, const char *needle)
-{
-	guint32 i;
-
-	/* ethtool_get_stringset() always ensures NUL terminated strings at ETH_GSTRING_LEN.
-	 * that means, we cannot possibly request longer names. */
-	nm_assert (needle && strlen (needle) < ETH_GSTRING_LEN);
-
-	for (i = 0; i < gstrings->len; i++) {
-		if (nm_streq ((char *) &gstrings->data[i * ETH_GSTRING_LEN], needle))
-			return i;
-	}
-	return -1;
-}
-
-static int
-ethtool_get_stringset_index (SocketHandle *shandle, int stringset_id, const char *needle)
-{
-	gs_free struct ethtool_gstrings *gstrings = NULL;
-
-	/* ethtool_get_stringset() always ensures NUL terminated strings at ETH_GSTRING_LEN.
-	 * that means, we cannot possibly request longer names. */
-	nm_assert (needle && strlen (needle) < ETH_GSTRING_LEN);
-
-	gstrings = ethtool_get_stringset (shandle, stringset_id);
-	if (gstrings)
-		return ethtool_gstrings_find (gstrings, needle);
-	return -1;
-}
-
-/*****************************************************************************/
-
-static const NMEthtoolFeatureInfo _ethtool_feature_infos[_NM_ETHTOOL_ID_FEATURE_NUM] = {
-#define ETHT_FEAT(eid, ...) \
-	{ \
-		.ethtool_id = eid, \
-		.n_kernel_names = NM_NARG (__VA_ARGS__), \
-		.kernel_names = ((const char *const[]) { __VA_ARGS__ }), \
-	}
-
-	/* the order does only matter for one thing: if it happens that more than one NMEthtoolID
-	 * reference the same kernel-name, then the one that is mentioned *later* will win in
-	 * case these NMEthtoolIDs are set. That mostly only makes sense for ethtool-ids which
-	 * refer to multiple features ("feature-tso"), while also having more specific ids
-	 * ("feature-tx-tcp-segmentation"). */
-
-	/* names from ethtool utility, which are aliases for multiple features. */
-	ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_SG,                           "tx-scatter-gather",
-	                                                               "tx-scatter-gather-fraglist"),
-	ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_TSO,                          "tx-tcp-segmentation",
-	                                                               "tx-tcp-ecn-segmentation",
-	                                                               "tx-tcp-mangleid-segmentation",
-	                                                               "tx-tcp6-segmentation"),
-	ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_TX,                           "tx-checksum-ipv4",
-	                                                               "tx-checksum-ip-generic",
-	                                                               "tx-checksum-ipv6",
-	                                                               "tx-checksum-fcoe-crc",
-	                                                               "tx-checksum-sctp"),
-
-	/* names from ethtool utility, which are aliases for one feature. */
-	ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_GRO,                          "rx-gro"),
-	ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_GSO,                          "tx-generic-segmentation"),
-	ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_LRO,                          "rx-lro"),
-	ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_NTUPLE,                       "rx-ntuple-filter"),
-	ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_RX,                           "rx-checksum"),
-	ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_RXHASH,                       "rx-hashing"),
-	ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_RXVLAN,                       "rx-vlan-hw-parse"),
-	ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_TXVLAN,                       "tx-vlan-hw-insert"),
-
-	/* names of features, as known by kernel. */
-	ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_ESP_HW_OFFLOAD,               "esp-hw-offload"),
-	ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_ESP_TX_CSUM_HW_OFFLOAD,       "esp-tx-csum-hw-offload"),
-	ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_FCOE_MTU,                     "fcoe-mtu"),
-	ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_HIGHDMA,                      "highdma"),
-	ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_HW_TC_OFFLOAD,                "hw-tc-offload"),
-	ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_L2_FWD_OFFLOAD,               "l2-fwd-offload"),
-	ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_LOOPBACK,                     "loopback"),
-	ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_RX_ALL,                       "rx-all"),
-	ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_RX_FCS,                       "rx-fcs"),
-	ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_RX_GRO_HW,                    "rx-gro-hw"),
-	ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_RX_UDP_TUNNEL_PORT_OFFLOAD,   "rx-udp_tunnel-port-offload"),
-	ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_RX_VLAN_FILTER,               "rx-vlan-filter"),
-	ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_RX_VLAN_STAG_FILTER,          "rx-vlan-stag-filter"),
-	ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_RX_VLAN_STAG_HW_PARSE,        "rx-vlan-stag-hw-parse"),
-	ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_TLS_HW_RECORD,                "tls-hw-record"),
-	ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_TLS_HW_TX_OFFLOAD,            "tls-hw-tx-offload"),
-	ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_TX_CHECKSUM_FCOE_CRC,         "tx-checksum-fcoe-crc"),
-	ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_TX_CHECKSUM_IPV4,             "tx-checksum-ipv4"),
-	ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_TX_CHECKSUM_IPV6,             "tx-checksum-ipv6"),
-	ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_TX_CHECKSUM_IP_GENERIC,       "tx-checksum-ip-generic"),
-	ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_TX_CHECKSUM_SCTP,             "tx-checksum-sctp"),
-	ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_TX_ESP_SEGMENTATION,          "tx-esp-segmentation"),
-	ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_TX_FCOE_SEGMENTATION,         "tx-fcoe-segmentation"),
-	ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_TX_GRE_CSUM_SEGMENTATION,     "tx-gre-csum-segmentation"),
-	ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_TX_GRE_SEGMENTATION,          "tx-gre-segmentation"),
-	ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_TX_GSO_PARTIAL,               "tx-gso-partial"),
-	ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_TX_GSO_ROBUST,                "tx-gso-robust"),
-	ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_TX_IPXIP4_SEGMENTATION,       "tx-ipxip4-segmentation"),
-	ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_TX_IPXIP6_SEGMENTATION,       "tx-ipxip6-segmentation"),
-	ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_TX_NOCACHE_COPY,              "tx-nocache-copy"),
-	ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_TX_SCATTER_GATHER,            "tx-scatter-gather"),
-	ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_TX_SCATTER_GATHER_FRAGLIST,   "tx-scatter-gather-fraglist"),
-	ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_TX_SCTP_SEGMENTATION,         "tx-sctp-segmentation"),
-	ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_TX_TCP6_SEGMENTATION,         "tx-tcp6-segmentation"),
-	ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_TX_TCP_ECN_SEGMENTATION,      "tx-tcp-ecn-segmentation"),
-	ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_TX_TCP_MANGLEID_SEGMENTATION, "tx-tcp-mangleid-segmentation"),
-	ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_TX_TCP_SEGMENTATION,          "tx-tcp-segmentation"),
-	ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_TX_UDP_SEGMENTATION,          "tx-udp-segmentation"),
-	ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_TX_UDP_TNL_CSUM_SEGMENTATION, "tx-udp_tnl-csum-segmentation"),
-	ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_TX_UDP_TNL_SEGMENTATION,      "tx-udp_tnl-segmentation"),
-	ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_TX_VLAN_STAG_HW_INSERT,       "tx-vlan-stag-hw-insert"),
-};
-
-/* the number of kernel features that we handle. It essentially is the sum of all
- * kernel_names. So, all ethtool-ids that reference exactly one kernel-name
- * (_NM_ETHTOOL_ID_FEATURE_NUM) + some extra, for ethtool-ids that are aliases
- * for multiple kernel-names. */
-#define N_ETHTOOL_KERNEL_FEATURES (((guint) _NM_ETHTOOL_ID_FEATURE_NUM) + 8u)
-
-static void
-_ASSERT_ethtool_feature_infos (void)
-{
-#if NM_MORE_ASSERTS > 10
-	guint i, k, n;
-	bool found[_NM_ETHTOOL_ID_FEATURE_NUM] = { };
-
-	G_STATIC_ASSERT_EXPR (G_N_ELEMENTS (_ethtool_feature_infos) == _NM_ETHTOOL_ID_FEATURE_NUM);
-
-	n = 0;
-	for (i = 0; i < G_N_ELEMENTS (_ethtool_feature_infos); i++) {
-		NMEthtoolFeatureState kstate;
-		const NMEthtoolFeatureInfo *inf = &_ethtool_feature_infos[i];
-
-		g_assert (inf->ethtool_id >= _NM_ETHTOOL_ID_FEATURE_FIRST);
-		g_assert (inf->ethtool_id <= _NM_ETHTOOL_ID_FEATURE_LAST);
-		g_assert (inf->n_kernel_names > 0);
-
-		for (k = 0; k < i; k++)
-			g_assert (inf->ethtool_id != _ethtool_feature_infos[k].ethtool_id);
-
-		g_assert (!found[inf->ethtool_id - _NM_ETHTOOL_ID_FEATURE_FIRST]);
-		found[inf->ethtool_id - _NM_ETHTOOL_ID_FEATURE_FIRST] = TRUE;
-
-		kstate.idx_kernel_name = inf->n_kernel_names - 1;
-		g_assert ((guint) kstate.idx_kernel_name == (guint) (inf->n_kernel_names - 1));
-
-		n += inf->n_kernel_names;
-		for (k = 0; k < inf->n_kernel_names; k++) {
-			g_assert (nm_utils_strv_find_first ((char **) inf->kernel_names,
-			                                    k,
-			                                    inf->kernel_names[k]) < 0);
-		}
-	}
-
-	for (i = 0; i < _NM_ETHTOOL_ID_FEATURE_NUM; i++)
-		g_assert (found[i]);
-
-	g_assert (n == N_ETHTOOL_KERNEL_FEATURES);
-#endif
-}
-
-static NMEthtoolFeatureStates *
-ethtool_get_features (SocketHandle *shandle)
-{
-	gs_free NMEthtoolFeatureStates *states = NULL;
-	gs_free struct ethtool_gstrings *ss_features = NULL;
-
-	_ASSERT_ethtool_feature_infos ();
-
-	ss_features = ethtool_get_stringset (shandle, ETH_SS_FEATURES);
-	if (!ss_features)
-		return NULL;
-
-	if (ss_features->len > 0) {
-		gs_free struct ethtool_gfeatures *gfeatures = NULL;
-		guint idx;
-		const NMEthtoolFeatureState *states_list0 = NULL;
-		const NMEthtoolFeatureState *const*states_plist0 = NULL;
-		guint states_plist_n = 0;
-
-		gfeatures = g_malloc0 (  sizeof (struct ethtool_gfeatures)
-		                       + (NM_DIV_ROUND_UP (ss_features->len, 32u) * sizeof(gfeatures->features[0])));
-
-		gfeatures->cmd = ETHTOOL_GFEATURES;
-		gfeatures->size = NM_DIV_ROUND_UP (ss_features->len, 32u);
-		if (ethtool_call_handle (shandle, gfeatures) < 0)
-			return NULL;
-
-		for (idx = 0; idx < G_N_ELEMENTS (_ethtool_feature_infos); idx++) {
-			const NMEthtoolFeatureInfo *info = &_ethtool_feature_infos[idx];
-			guint idx_kernel_name;
-
-			for (idx_kernel_name = 0; idx_kernel_name < info->n_kernel_names; idx_kernel_name++) {
-				NMEthtoolFeatureState *kstate;
-				const char *kernel_name = info->kernel_names[idx_kernel_name];
-				int i_feature;
-				guint i_block;
-				guint32 i_flag;
-
-				i_feature = ethtool_gstrings_find (ss_features, kernel_name);
-				if (i_feature < 0)
-					continue;
-
-				i_block = ((guint) i_feature) / 32u;
-				i_flag = (guint32) (1u << (((guint) i_feature) % 32u));
-
-				if (!states) {
-					states = g_malloc0 (sizeof (NMEthtoolFeatureStates)
-					                    + (N_ETHTOOL_KERNEL_FEATURES * sizeof (NMEthtoolFeatureState))
-					                    + ((N_ETHTOOL_KERNEL_FEATURES + G_N_ELEMENTS (_ethtool_feature_infos)) * sizeof (NMEthtoolFeatureState *)));
-					states_list0 = &states->states_list[0];
-					states_plist0 = (gpointer) &states_list0[N_ETHTOOL_KERNEL_FEATURES];
-					states->n_ss_features = ss_features->len;
-				}
-
-				nm_assert (states->n_states < N_ETHTOOL_KERNEL_FEATURES);
-				kstate = (NMEthtoolFeatureState *) &states_list0[states->n_states];
-				states->n_states++;
-
-				kstate->info = info;
-				kstate->idx_ss_features = i_feature;
-				kstate->idx_kernel_name = idx_kernel_name;
-				kstate->available     = !!(gfeatures->features[i_block].available     & i_flag);
-				kstate->requested     = !!(gfeatures->features[i_block].requested     & i_flag);
-				kstate->active        = !!(gfeatures->features[i_block].active        & i_flag);
-				kstate->never_changed = !!(gfeatures->features[i_block].never_changed & i_flag);
-
-				nm_assert (states_plist_n < N_ETHTOOL_KERNEL_FEATURES + G_N_ELEMENTS (_ethtool_feature_infos));
-
-				if (!states->states_indexed[info->ethtool_id - _NM_ETHTOOL_ID_FEATURE_FIRST])
-					states->states_indexed[info->ethtool_id - _NM_ETHTOOL_ID_FEATURE_FIRST] = &states_plist0[states_plist_n];
-				((const NMEthtoolFeatureState **) states_plist0)[states_plist_n] = kstate;
-				states_plist_n++;
-			}
-
-			if (states && states->states_indexed[info->ethtool_id - _NM_ETHTOOL_ID_FEATURE_FIRST]) {
-				nm_assert (states_plist_n < N_ETHTOOL_KERNEL_FEATURES + G_N_ELEMENTS (_ethtool_feature_infos));
-				nm_assert (!states_plist0[states_plist_n]);
-				states_plist_n++;
-			}
-		}
-	}
-
-	return g_steal_pointer (&states);
-}
-
-NMEthtoolFeatureStates *
-nmp_utils_ethtool_get_features (int ifindex)
-{
-	nm_auto_socket_handle SocketHandle shandle = { };
-	NMEthtoolFeatureStates *features;
-	int r;
-
-	g_return_val_if_fail (ifindex > 0, 0);
-
-	if ((r = socket_handle_init (&shandle, ifindex)) < 0) {
-		nm_log_trace (LOGD_PLATFORM, "ethtool[%d]: %s: failed creating ethtool socket: %s",
-		              ifindex,
-		              "get-features",
-		              g_strerror (-r));
+		              g_strerror (errno));
 		return FALSE;
 	}
 
-	features = ethtool_get_features (&shandle);
+	{
+		nm_auto_close int fd = -1;
+		struct ifreq ifr = {
+			.ifr_data = edata,
+		};
 
-	if (!features) {
-		nm_log_trace (LOGD_PLATFORM, "ethtool[%d]: %s: failure getting features",
-		              ifindex,
-		              "get-features");
-		return NULL;
-	}
-
-	nm_log_trace (LOGD_PLATFORM, "ethtool[%d]: %s: retrieved kernel features",
-	              ifindex,
-	              "get-features");
-	return features;
-}
-
-static const char *
-_ethtool_feature_state_to_string (char *buf, gsize buf_size, const NMEthtoolFeatureState *s, const char *prefix)
-{
-	int l;
-
-	l = g_snprintf (buf, buf_size,
-	                "%s %s%s",
-	                prefix ?: "",
-	                ONOFF (s->active),
-	                (!s->available || s->never_changed)
-	                  ? ", [fixed]"
-	                  : ((s->requested != s->active)
-	                       ? (s->requested ? ", [requested on]" : ", [requested off]")
-	                       : ""));
-	nm_assert (l < buf_size);
-	return buf;
-}
+		memcpy (ifr.ifr_name, ifname, sizeof (ifname));
 
-gboolean
-nmp_utils_ethtool_set_features (int ifindex,
-                                const NMEthtoolFeatureStates *features,
-                                const NMTernary *requested /* indexed by NMEthtoolID - _NM_ETHTOOL_ID_FEATURE_FIRST */,
-                                gboolean do_set /* or reset */)
-{
-	nm_auto_socket_handle SocketHandle shandle = { };
-	gs_free struct ethtool_sfeatures *sfeatures = NULL;
-	int r;
-	guint i, j;
-	struct {
-		const NMEthtoolFeatureState *f_state;
-		NMTernary requested;
-	} set_states[N_ETHTOOL_KERNEL_FEATURES];
-	guint set_states_n = 0;
-	gboolean success = TRUE;
-
-	g_return_val_if_fail (ifindex > 0, 0);
-	g_return_val_if_fail (features, 0);
-	g_return_val_if_fail (requested, 0);
-
-	nm_assert (features->n_states <= N_ETHTOOL_KERNEL_FEATURES);
-
-	for (i = 0; i < _NM_ETHTOOL_ID_FEATURE_NUM; i++) {
-		const NMEthtoolFeatureState *const*states_indexed;
-
-		if (requested[i] == NM_TERNARY_DEFAULT)
-			continue;
-
-		if (!(states_indexed = features->states_indexed[i])) {
-			if (do_set) {
-				nm_log_trace (LOGD_PLATFORM, "ethtool[%d]: %s: set feature %s: skip (not found)",
-				              ifindex,
-				              "set-features",
-				              nm_ethtool_data[i + _NM_ETHTOOL_ID_FEATURE_FIRST]->optname);
-				success = FALSE;
-			}
-			continue;
+		fd = socket (PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+		if (fd < 0) {
+			nm_log_trace (LOGD_PLATFORM, "ethtool[%d]: %s, %s: failed creating socket for ioctl: %s",
+			              ifindex,
+			              _ethtool_data_to_string (edata, sbuf, sizeof (sbuf)),
+			              ifname,
+			              g_strerror (errno));
+			return FALSE;
 		}
 
-		for (j = 0; states_indexed[j]; j++) {
-			const NMEthtoolFeatureState *s = states_indexed[j];
-			char sbuf[255];
-
-			if (set_states_n >= G_N_ELEMENTS (set_states))
-				g_return_val_if_reached (FALSE);
-
-			if (s->never_changed) {
-				nm_log_trace (LOGD_PLATFORM, "ethtool[%d]: %s: %s feature %s (%s): %s, %s (skip feature marked as never changed)",
-				              ifindex,
-				              "set-features",
-				              do_set ? "set" : "reset",
-				              nm_ethtool_data[i + _NM_ETHTOOL_ID_FEATURE_FIRST]->optname,
-				              s->info->kernel_names[s->idx_kernel_name],
-				              ONOFF (do_set ? requested[i] == NM_TERNARY_TRUE : s->active),
-				              _ethtool_feature_state_to_string (sbuf, sizeof (sbuf), s, do_set ? " currently:" : " before:"));
-				continue;
-			}
-
-			nm_log_trace (LOGD_PLATFORM, "ethtool[%d]: %s: %s feature %s (%s): %s, %s",
+		if (ioctl (fd, SIOCETHTOOL, &ifr) < 0) {
+			nm_log_trace (LOGD_PLATFORM, "ethtool[%d]: %s, %s: failed: %s",
 			              ifindex,
-			              "set-features",
-			              do_set ? "set" : "reset",
-			              nm_ethtool_data[i + _NM_ETHTOOL_ID_FEATURE_FIRST]->optname,
-			              s->info->kernel_names[s->idx_kernel_name],
-			              ONOFF (do_set ? requested[i] == NM_TERNARY_TRUE : s->active),
-			              _ethtool_feature_state_to_string (sbuf, sizeof (sbuf), s, do_set ? " currently:" : " before:"));
-
-			if (   do_set
-			    && (!s->available || s->never_changed)
-			    && (s->active != (requested[i] == NM_TERNARY_TRUE))) {
-				/* we request to change a flag which kernel reported as fixed.
-				 * While the ethtool operation will silently succeed, mark the request
-				 * as failure. */
-				success = FALSE;
-			}
-
-			set_states[set_states_n].f_state = s;
-			set_states[set_states_n].requested = requested[i];
-			set_states_n++;
+			              _ethtool_data_to_string (edata, sbuf, sizeof (sbuf)),
+			              ifname,
+			              strerror (errno));
+			return FALSE;
 		}
-	}
 
-	if (set_states_n == 0) {
-		nm_log_trace (LOGD_PLATFORM, "ethtool[%d]: %s: no feature requested",
+		nm_log_trace (LOGD_PLATFORM, "ethtool[%d]: %s, %s: success",
 		              ifindex,
-		              "set-features");
+		              _ethtool_data_to_string (edata, sbuf, sizeof (sbuf)),
+		              ifname);
 		return TRUE;
 	}
+}
 
-	if ((r = socket_handle_init (&shandle, ifindex)) < 0) {
-		nm_log_trace (LOGD_PLATFORM, "ethtool[%d]: %s: failed creating ethtool socket: %s",
-		              ifindex,
-		              "set-features",
-		              g_strerror (-r));
-		return FALSE;
-	}
+static int
+ethtool_get_stringset_index (int ifindex, int stringset_id, const char *string)
+{
+	gs_free struct ethtool_sset_info *info = NULL;
+	gs_free struct ethtool_gstrings *strings = NULL;
+	guint32 len, i;
 
-	sfeatures = g_malloc0 (sizeof (struct ethtool_sfeatures)
-	                       + (NM_DIV_ROUND_UP (features->n_ss_features, 32U) * sizeof(sfeatures->features[0])));
-	sfeatures->cmd = ETHTOOL_SFEATURES;
-	sfeatures->size = NM_DIV_ROUND_UP (features->n_ss_features, 32U);
+	g_return_val_if_fail (ifindex > 0, -1);
 
-	for (i = 0; i < set_states_n; i++) {
-		const NMEthtoolFeatureState *s = set_states[i].f_state;
-		guint i_block;
-		guint32 i_flag;
-		gboolean is_requested;
+	info = g_malloc0 (sizeof (*info) + sizeof (guint32));
+	info->cmd = ETHTOOL_GSSET_INFO;
+	info->reserved = 0;
+	info->sset_mask = 1ULL << stringset_id;
 
-		i_block = s->idx_ss_features / 32u;
-		i_flag = (guint32) (1u << (s->idx_ss_features % 32u));
+	if (!ethtool_get (ifindex, info))
+		return -1;
+	if (!info->sset_mask)
+		return -1;
 
-		sfeatures->features[i_block].valid |= i_flag;
+	len = info->data[0];
 
-		if (do_set)
-			is_requested = (set_states[i].requested == NM_TERNARY_TRUE);
-		else
-			is_requested = s->active;
+	strings = g_malloc0 (sizeof (*strings) + len * ETH_GSTRING_LEN);
+	strings->cmd = ETHTOOL_GSTRINGS;
+	strings->string_set = stringset_id;
+	strings->len = len;
+	if (!ethtool_get (ifindex, strings))
+		return -1;
 
-		if (is_requested)
-			sfeatures->features[i_block].requested |= i_flag;
-		else
-			sfeatures->features[i_block].requested &= ~i_flag;
-	}
-
-	if ((r = ethtool_call_handle (&shandle, sfeatures)) < 0) {
-		success = FALSE;
-		nm_log_trace (LOGD_PLATFORM, "ethtool[%d]: %s: failure setting features (%s)",
-		              ifindex,
-		              "set-features",
-		              g_strerror (-r));
-		return FALSE;
+	for (i = 0; i < len; i++) {
+		if (!strcmp ((char *) &strings->data[i * ETH_GSTRING_LEN], string))
+			return i;
 	}
 
-	nm_log_trace (LOGD_PLATFORM, "ethtool[%d]: %s: %s",
-	              ifindex,
-	              "set-features",
-	              success
-	                ? "successfully setting features"
-	                : "at least some of the features were not successfuly set");
-	return success;
+	return -1;
 }
 
-/*****************************************************************************/
-
 gboolean
 nmp_utils_ethtool_get_driver_info (int ifindex,
                                    NMPUtilsEthtoolDriverInfo *data)
 {
 	struct ethtool_drvinfo *drvinfo;
-
-	G_STATIC_ASSERT_EXPR (sizeof (*data) == sizeof (*drvinfo));
-	G_STATIC_ASSERT_EXPR (offsetof (NMPUtilsEthtoolDriverInfo, driver)     == offsetof (struct ethtool_drvinfo, driver));
-	G_STATIC_ASSERT_EXPR (offsetof (NMPUtilsEthtoolDriverInfo, version)    == offsetof (struct ethtool_drvinfo, version));
-	G_STATIC_ASSERT_EXPR (offsetof (NMPUtilsEthtoolDriverInfo, fw_version) == offsetof (struct ethtool_drvinfo, fw_version));
-	G_STATIC_ASSERT_EXPR (sizeof (data->driver)     == sizeof (drvinfo->driver));
-	G_STATIC_ASSERT_EXPR (sizeof (data->version)    == sizeof (drvinfo->version));
-	G_STATIC_ASSERT_EXPR (sizeof (data->fw_version) == sizeof (drvinfo->fw_version));
+	G_STATIC_ASSERT (sizeof (*data) == sizeof (*drvinfo));
+	G_STATIC_ASSERT (offsetof (NMPUtilsEthtoolDriverInfo, driver)     == offsetof (struct ethtool_drvinfo, driver));
+	G_STATIC_ASSERT (offsetof (NMPUtilsEthtoolDriverInfo, version)    == offsetof (struct ethtool_drvinfo, version));
+	G_STATIC_ASSERT (offsetof (NMPUtilsEthtoolDriverInfo, fw_version) == offsetof (struct ethtool_drvinfo, fw_version));
+	G_STATIC_ASSERT (sizeof (data->driver)     == sizeof (drvinfo->driver));
+	G_STATIC_ASSERT (sizeof (data->version)    == sizeof (drvinfo->version));
+	G_STATIC_ASSERT (sizeof (data->fw_version) == sizeof (drvinfo->fw_version));
 
 	g_return_val_if_fail (ifindex > 0, FALSE);
 	g_return_val_if_fail (data, FALSE);
@@ -691,7 +213,7 @@ nmp_utils_ethtool_get_driver_info (int ifindex,
 
 	memset (drvinfo, 0, sizeof (*drvinfo));
 	drvinfo->cmd = ETHTOOL_GDRVINFO;
-	return ethtool_call_ifindex (ifindex, drvinfo) >= 0;
+	return ethtool_get (ifindex, drvinfo);
 }
 
 gboolean
@@ -711,7 +233,7 @@ nmp_utils_ethtool_get_permanent_address (int ifindex,
 	edata.e.cmd = ETHTOOL_GPERMADDR;
 	edata.e.size = NM_UTILS_HWADDR_LEN_MAX;
 
-	if (ethtool_call_ifindex (ifindex, &edata.e) < 0)
+	if (!ethtool_get (ifindex, &edata.e))
 		return FALSE;
 
 	if (edata.e.size > NM_UTILS_HWADDR_LEN_MAX)
@@ -730,8 +252,8 @@ nmp_utils_ethtool_get_permanent_address (int ifindex,
 		}
 		return FALSE;
 	}
-
 not_all_0or1:
+
 	memcpy (buf, edata.e.data, edata.e.size);
 	*length = edata.e.size;
 	return TRUE;
@@ -748,30 +270,20 @@ nmp_utils_ethtool_supports_carrier_detect (int ifindex)
 	 * assume the device supports carrier-detect, otherwise we assume it
 	 * doesn't.
 	 */
-	return ethtool_call_ifindex (ifindex, &edata) >= 0;
+	return ethtool_get (ifindex, &edata);
 }
 
 gboolean
 nmp_utils_ethtool_supports_vlans (int ifindex)
 {
-	nm_auto_socket_handle SocketHandle shandle = { };
-	int r;
 	gs_free struct ethtool_gfeatures *features = NULL;
 	int idx, block, bit, size;
 
 	g_return_val_if_fail (ifindex > 0, FALSE);
 
-	if ((r = socket_handle_init (&shandle, ifindex)) < 0) {
-		nm_log_trace (LOGD_PLATFORM, "ethtool[%d]: %s: failed creating ethtool socket: %s",
-		              ifindex,
-		              "support-vlans",
-		              g_strerror (-r));
-		return FALSE;
-	}
-
-	idx = ethtool_get_stringset_index (&shandle, ETH_SS_FEATURES, "vlan-challenged");
-	if (idx < 0) {
-		nm_log_dbg (LOGD_PLATFORM, "ethtool[%d]: vlan-challenged ethtool feature does not exist?", ifindex);
+	idx = ethtool_get_stringset_index (ifindex, ETH_SS_FEATURES, "vlan-challenged");
+	if (idx == -1) {
+		nm_log_dbg (LOGD_PLATFORM, "ethtool: vlan-challenged ethtool feature does not exist for %d?", ifindex);
 		return FALSE;
 	}
 
@@ -783,7 +295,7 @@ nmp_utils_ethtool_supports_vlans (int ifindex)
 	features->cmd = ETHTOOL_GFEATURES;
 	features->size = size;
 
-	if (ethtool_call_handle (&shandle, features) < 0)
+	if (!ethtool_get (ifindex, features))
 		return FALSE;
 
 	return !(features->features[block].active & (1 << bit));
@@ -792,32 +304,21 @@ nmp_utils_ethtool_supports_vlans (int ifindex)
 int
 nmp_utils_ethtool_get_peer_ifindex (int ifindex)
 {
-	nm_auto_socket_handle SocketHandle shandle = { };
-	int r;
-
 	gs_free struct ethtool_stats *stats = NULL;
 	int peer_ifindex_stat;
 
 	g_return_val_if_fail (ifindex > 0, 0);
 
-	if ((r = socket_handle_init (&shandle, ifindex)) < 0) {
-		nm_log_trace (LOGD_PLATFORM, "ethtool[%d]: %s: failed creating ethtool socket: %s",
-		              ifindex,
-		              "get-peer-ifindex",
-		              g_strerror (-r));
-		return FALSE;
-	}
-
-	peer_ifindex_stat = ethtool_get_stringset_index (&shandle, ETH_SS_STATS, "peer_ifindex");
-	if (peer_ifindex_stat < 0) {
-		nm_log_dbg (LOGD_PLATFORM, "ethtool[%d]: peer_ifindex stat does not exist?", ifindex);
+	peer_ifindex_stat = ethtool_get_stringset_index (ifindex, ETH_SS_STATS, "peer_ifindex");
+	if (peer_ifindex_stat == -1) {
+		nm_log_dbg (LOGD_PLATFORM, "ethtool: peer_ifindex stat for %d does not exist?", ifindex);
 		return FALSE;
 	}
 
 	stats = g_malloc0 (sizeof (*stats) + (peer_ifindex_stat + 1) * sizeof (guint64));
 	stats->cmd = ETHTOOL_GSTATS;
 	stats->n_stats = peer_ifindex_stat + 1;
-	if (ethtool_call_ifindex (ifindex, stats) < 0)
+	if (!ethtool_get (ifindex, stats))
 		return 0;
 
 	return stats->data[peer_ifindex_stat];
@@ -832,7 +333,7 @@ nmp_utils_ethtool_get_wake_on_lan (int ifindex)
 
 	memset (&wol, 0, sizeof (wol));
 	wol.cmd = ETHTOOL_GWOL;
-	if (ethtool_call_ifindex (ifindex, &wol) < 0)
+	if (!ethtool_get (ifindex, &wol))
 		return FALSE;
 
 	return wol.wolopts != 0;
@@ -850,7 +351,7 @@ nmp_utils_ethtool_get_link_settings (int ifindex,
 
 	g_return_val_if_fail (ifindex > 0, FALSE);
 
-	if (ethtool_call_ifindex (ifindex, &edata) < 0)
+	if (!ethtool_get (ifindex, &edata))
 		return FALSE;
 
 	if (out_autoneg)
@@ -932,13 +433,9 @@ nmp_utils_ethtool_set_link_settings (int ifindex,
 	                      || (!speed && duplex == NM_PLATFORM_LINK_DUPLEX_UNKNOWN), FALSE);
 
 	/* retrieve first current settings */
-	if (ethtool_call_ifindex (ifindex, &edata) < 0)
+	if (!ethtool_get (ifindex, &edata))
 		return FALSE;
 
-	/* FIXME: try first new ETHTOOL_GLINKSETTINGS/SLINKSETTINGS API
-	 * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=3f1ac7a700d039c61d8d8b99f28d605d489a60cf
-	 */
-
 	/* then change the needed ones */
 	edata.cmd = ETHTOOL_SSET;
 	if (autoneg) {
@@ -988,7 +485,7 @@ nmp_utils_ethtool_set_link_settings (int ifindex,
 		}
 	}
 
-	return ethtool_call_ifindex (ifindex, &edata) >= 0;
+	return ethtool_get (ifindex, &edata);
 }
 
 gboolean
@@ -1003,8 +500,8 @@ nmp_utils_ethtool_set_wake_on_lan (int ifindex,
 	if (wol == NM_SETTING_WIRED_WAKE_ON_LAN_IGNORE)
 		return TRUE;
 
-	nm_log_dbg (LOGD_PLATFORM, "ethtool[%d]: setting Wake-on-LAN options 0x%x, password '%s'",
-	            ifindex, (unsigned) wol, wol_password);
+	nm_log_dbg (LOGD_PLATFORM, "setting Wake-on-LAN options 0x%x, password '%s'",
+	            (unsigned) wol, wol_password);
 
 	wol_info.cmd = ETHTOOL_SWOL;
 	wol_info.wolopts = 0;
@@ -1024,41 +521,45 @@ nmp_utils_ethtool_set_wake_on_lan (int ifindex,
 
 	if (wol_password) {
 		if (!nm_utils_hwaddr_aton (wol_password, wol_info.sopass, ETH_ALEN)) {
-			nm_log_dbg (LOGD_PLATFORM, "ethtool[%d]: couldn't parse Wake-on-LAN password '%s'", ifindex, wol_password);
+			nm_log_dbg (LOGD_PLATFORM, "couldn't parse Wake-on-LAN password '%s'", wol_password);
 			return FALSE;
 		}
 		wol_info.wolopts |= WAKE_MAGICSECURE;
 	}
 
-	return ethtool_call_ifindex (ifindex, &wol_info) >= 0;
+	return ethtool_get (ifindex, &wol_info);
 }
 
-/******************************************************************************
+/******************************************************************
  * mii
- *****************************************************************************/
+ ******************************************************************/
 
 gboolean
 nmp_utils_mii_supports_carrier_detect (int ifindex)
 {
-	nm_auto_socket_handle SocketHandle shandle = { };
-	int r;
+	char ifname[IFNAMSIZ];
+	nm_auto_close int fd = -1;
 	struct ifreq ifr;
 	struct mii_ioctl_data *mii;
 
 	g_return_val_if_fail (ifindex > 0, FALSE);
 
-	if ((r = socket_handle_init (&shandle, ifindex)) < 0) {
-		nm_log_trace (LOGD_PLATFORM, "mii[%d]: carrier-detect no: failed creating ethtool socket: %s",
-		              ifindex,
-		              g_strerror (-r));
+	if (!nmp_utils_if_indextoname (ifindex, ifname)) {
+		nm_log_trace (LOGD_PLATFORM, "mii[%d]: carrier-detect no: request fails resolving ifindex: %s", ifindex, g_strerror (errno));
+		return FALSE;
+	}
+
+	fd = socket (PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+	if (fd < 0) {
+		nm_log_trace (LOGD_PLATFORM, "mii[%d,%s]: carrier-detect no: couldn't open control socket: %s", ifindex, ifname, g_strerror (errno));
 		return FALSE;
 	}
 
 	memset (&ifr, 0, sizeof (struct ifreq));
-	memcpy (ifr.ifr_name, shandle.ifname, IFNAMSIZ);
+	memcpy (ifr.ifr_name, ifname, IFNAMSIZ);
 
-	if (ioctl (shandle.fd, SIOCGMIIPHY, &ifr) < 0) {
-		nm_log_trace (LOGD_PLATFORM, "mii[%d,%s]: carrier-detect no: SIOCGMIIPHY failed: %s", ifindex, shandle.ifname, strerror (errno));
+	if (ioctl (fd, SIOCGMIIPHY, &ifr) < 0) {
+		nm_log_trace (LOGD_PLATFORM, "mii[%d,%s]: carrier-detect no: SIOCGMIIPHY failed: %s", ifindex, ifname, strerror (errno));
 		return FALSE;
 	}
 
@@ -1066,18 +567,18 @@ nmp_utils_mii_supports_carrier_detect (int ifindex)
 	mii = (struct mii_ioctl_data *) &ifr.ifr_ifru;
 	mii->reg_num = MII_BMSR;
 
-	if (ioctl (shandle.fd, SIOCGMIIREG, &ifr) != 0) {
-		nm_log_trace (LOGD_PLATFORM, "mii[%d,%s]: carrier-detect no: SIOCGMIIREG failed: %s", ifindex, shandle.ifname, strerror (errno));
+	if (ioctl (fd, SIOCGMIIREG, &ifr) != 0) {
+		nm_log_trace (LOGD_PLATFORM, "mii[%d,%s]: carrier-detect no: SIOCGMIIREG failed: %s", ifindex, ifname, strerror (errno));
 		return FALSE;
 	}
 
-	nm_log_trace (LOGD_PLATFORM, "mii[%d,%s]: carrier-detect yes: SIOCGMIIREG result 0x%X", ifindex, shandle.ifname, mii->val_out);
+	nm_log_trace (LOGD_PLATFORM, "mii[%d,%s]: carrier-detect yes: SIOCGMIIREG result 0x%X", ifindex, ifname, mii->val_out);
 	return TRUE;
 }
 
-/******************************************************************************
+/******************************************************************
  * udev
- *****************************************************************************/
+ ******************************************************************/
 
 const char *
 nmp_utils_udev_get_driver (struct udev_device *udevice)
diff --git a/src/platform/nm-platform-utils.h b/src/platform/nm-platform-utils.h
index bad77aee..97f5630a 100644
--- a/src/platform/nm-platform-utils.h
+++ b/src/platform/nm-platform-utils.h
@@ -23,9 +23,6 @@
 
 #include "nm-platform.h"
 #include "nm-setting-wired.h"
-#include "nm-ethtool-utils.h"
-
-/*****************************************************************************/
 
 const char *nmp_utils_ethtool_get_driver (int ifindex);
 gboolean nmp_utils_ethtool_supports_carrier_detect (int ifindex);
@@ -38,10 +35,6 @@ gboolean nmp_utils_ethtool_set_wake_on_lan (int ifindex, NMSettingWiredWakeOnLan
 gboolean nmp_utils_ethtool_get_link_settings (int ifindex, gboolean *out_autoneg, guint32 *out_speed, NMPlatformLinkDuplexType *out_duplex);
 gboolean nmp_utils_ethtool_set_link_settings (int ifindex, gboolean autoneg, guint32 speed, NMPlatformLinkDuplexType duplex);
 
-gboolean  nmp_utils_ethtool_get_permanent_address (int ifindex,
-                                                   guint8 *buf,
-                                                   size_t *length);
-
 typedef struct {
 	/* We don't want to include <linux/ethtool.h> in header files,
 	 * thus create a ABI compatible version of struct ethtool_drvinfo.*/
@@ -62,52 +55,9 @@ typedef struct {
 gboolean nmp_utils_ethtool_get_driver_info (int ifindex,
                                             NMPUtilsEthtoolDriverInfo *data);
 
-typedef struct {
-	NMEthtoolID ethtool_id;
-
-	guint8 n_kernel_names;
-
-	/* one NMEthtoolID refers to one or more kernel_names. The reason for supporting this complexity
-	 * (where one NMSettingEthtool option refers to multiple kernel features)  is to follow what
-	 * ethtool does, where "tx" is an alias for multiple features. */
-	const char *const*kernel_names;
-} NMEthtoolFeatureInfo;
-
-typedef struct {
-	const NMEthtoolFeatureInfo *info;
-
-	guint idx_ss_features;
-
-	/* one NMEthtoolFeatureInfo references one or more kernel_names. This is the index
-	 * of the matching info->kernel_names */
-	guint8 idx_kernel_name;
-
-	bool available:1;
-	bool requested:1;
-	bool active:1;
-	bool never_changed:1;
-} NMEthtoolFeatureState;
-
-struct _NMEthtoolFeatureStates {
-	guint n_states;
-
-	guint n_ss_features;
-
-	/* indexed by NMEthtoolID - _NM_ETHTOOL_ID_FEATURE_FIRST */
-	const NMEthtoolFeatureState *const*states_indexed[_NM_ETHTOOL_ID_FEATURE_NUM];
-
-	/* the same content, here as a list of n_states entries. */
-	const NMEthtoolFeatureState states_list[];
-};
-
-NMEthtoolFeatureStates *nmp_utils_ethtool_get_features (int ifindex);
-
-gboolean nmp_utils_ethtool_set_features (int ifindex,
-                                         const NMEthtoolFeatureStates *features,
-                                         const NMTernary *requested /* indexed by NMEthtoolID - _NM_ETHTOOL_ID_FEATURE_FIRST */,
-                                         gboolean do_set /* or reset */);
-
-/*****************************************************************************/
+gboolean  nmp_utils_ethtool_get_permanent_address (int ifindex,
+                                                   guint8 *buf,
+                                                   size_t *length);
 
 gboolean nmp_utils_mii_supports_carrier_detect (int ifindex);
 
diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c
index 7ddcf41a..f75019e8 100644
--- a/src/platform/nm-platform.c
+++ b/src/platform/nm-platform.c
@@ -15,7 +15,7 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * Copyright (C) 2012 - 2018 Red Hat, Inc.
+ * Copyright (C) 2012 - 2017 Red Hat, Inc.
  */
 
 #include "nm-default.h"
@@ -27,8 +27,6 @@
 #include <unistd.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
-#include <sys/socket.h>
-#include <netdb.h>
 #include <string.h>
 #include <linux/ip.h>
 #include <linux/if_tun.h>
@@ -76,6 +74,8 @@ G_STATIC_ASSERT (G_STRUCT_OFFSET (NMPlatformIPRoute, network_ptr) == G_STRUCT_OF
         } \
     } G_STMT_END
 
+#define LOG_FMT_IP_TUNNEL "adding %s '%s' parent %u local %s remote %s"
+
 /*****************************************************************************/
 
 static guint signals[_NM_PLATFORM_SIGNAL_ID_LAST] = { 0 };
@@ -807,7 +807,6 @@ _nm_platform_link_get_by_address_match_link (const NMPObject *obj, struct _nm_pl
  **/
 const NMPlatformLink *
 nm_platform_link_get_by_address (NMPlatform *self,
-                                 NMLinkType link_type,
                                  gconstpointer address,
                                  size_t length)
 {
@@ -828,7 +827,7 @@ nm_platform_link_get_by_address (NMPlatform *self,
 		g_return_val_if_reached (NULL);
 
 	obj = nmp_cache_lookup_link_full (nm_platform_get_cache (self),
-	                                  0, NULL, TRUE, link_type,
+	                                  0, NULL, TRUE, NM_LINK_TYPE_NONE,
 	                                  (NMPObjectMatchFn) _nm_platform_link_get_by_address_match_link, &d);
 	return NMP_OBJECT_CAST_LINK (obj);
 }
@@ -902,7 +901,7 @@ nm_platform_link_add (NMPlatform *self,
 	if (plerr != NM_PLATFORM_ERROR_SUCCESS)
 		return plerr;
 
-	_LOGD ("link: adding link '%s': %s (%d)"
+	_LOGD ("link: adding link '%s' of type '%s' (%d)"
 	       "%s%s" /* address */
 	       "%s%s" /* veth peer */
 	       "",
@@ -986,7 +985,7 @@ nm_platform_link_set_netns (NMPlatform *self, int ifindex, int netns_fd)
 	if (!pllink)
 		return FALSE;
 
-	_LOGD ("link: move link %d to network namespace with fd %d", ifindex, netns_fd);
+	_LOGD ("link: ifindex %d changing network namespace to %d", ifindex, netns_fd);
 	return klass->link_set_netns (self, ifindex, netns_fd);
 }
 
@@ -1355,18 +1354,15 @@ nm_platform_link_set_user_ipv6ll_enabled (NMPlatform *self, int ifindex, gboolea
 NMPlatformError
 nm_platform_link_set_address (NMPlatform *self, int ifindex, gconstpointer address, size_t length)
 {
-	gs_free char *mac = NULL;
-
 	_CHECK_SELF (self, klass, NM_PLATFORM_ERROR_BUG);
 
 	g_return_val_if_fail (ifindex > 0, NM_PLATFORM_ERROR_BUG);
 	g_return_val_if_fail (address, NM_PLATFORM_ERROR_BUG);
 	g_return_val_if_fail (length > 0, NM_PLATFORM_ERROR_BUG);
 
-	_LOGD ("link: setting %s (%d) hardware address to %s",
+	_LOGD ("link: setting %s (%d) hardware address",
 	       nm_strquote_a (20, nm_platform_link_get_name (self, ifindex)),
-	       ifindex,
-	       (mac = nm_utils_hwaddr_ntoa (address, length)));
+	       ifindex);
 	return klass->link_set_address (self, ifindex, address, length);
 }
 
@@ -1463,52 +1459,18 @@ nm_platform_link_supports_sriov (NMPlatform *self, int ifindex)
 	return klass->link_supports_sriov (self, ifindex);
 }
 
-/**
- * nm_platform_link_set_sriov_params:
- * @self: platform instance
- * @ifindex: the index of the interface to change
- * @num_vfs: the number of VFs to create
- * @autoprobe: -1 to keep the current autoprobe-drivers value,
- *   or {0,1} to set a new value
- */
 gboolean
-nm_platform_link_set_sriov_params (NMPlatform *self,
-                                   int ifindex,
-                                   guint num_vfs,
-                                   int autoprobe)
+nm_platform_link_set_sriov_num_vfs (NMPlatform *self, int ifindex, guint num_vfs)
 {
 	_CHECK_SELF (self, klass, FALSE);
 
 	g_return_val_if_fail (ifindex > 0, FALSE);
-	g_return_val_if_fail (NM_IN_SET (autoprobe, -1, 0, 1), FALSE);
 
-	_LOGD ("link: setting %u total VFs and autoprobe %d for %s (%d)",
+	_LOGD ("link: setting %u VFs for %s (%d)",
 	       num_vfs,
-	       autoprobe,
 	       nm_strquote_a (25, nm_platform_link_get_name (self, ifindex)),
 	       ifindex);
-	return klass->link_set_sriov_params (self, ifindex, num_vfs, autoprobe);
-}
-
-gboolean
-nm_platform_link_set_sriov_vfs (NMPlatform *self, int ifindex, const NMPlatformVF *const *vfs)
-{
-	guint i;
-	_CHECK_SELF (self, klass, FALSE);
-
-	g_return_val_if_fail (ifindex > 0, FALSE);
-
-	_LOGD ("link: setting VFs for \"%s\" (%d):",
-	       nm_platform_link_get_name (self, ifindex),
-	       ifindex);
-
-	for (i = 0; vfs[i]; i++) {
-		const NMPlatformVF *vf = vfs[i];
-
-		_LOGD ("link:   VF %s", nm_platform_vf_to_string (vf, NULL, 0));
-	}
-
-	return klass->link_set_sriov_vfs (self, ifindex, vfs);
+	return klass->link_set_sriov_num_vfs (self, ifindex, num_vfs);
 }
 
 /**
@@ -1890,12 +1852,6 @@ nm_platform_link_get_lnk_gre (NMPlatform *self, int ifindex, const NMPlatformLin
 	return _link_get_lnk (self, ifindex, NM_LINK_TYPE_GRE, out_link);
 }
 
-const NMPlatformLnkGre *
-nm_platform_link_get_lnk_gretap (NMPlatform *self, int ifindex, const NMPlatformLink **out_link)
-{
-	return _link_get_lnk (self, ifindex, NM_LINK_TYPE_GRETAP, out_link);
-}
-
 const NMPlatformLnkInfiniband *
 nm_platform_link_get_lnk_infiniband (NMPlatform *self, int ifindex, const NMPlatformLink **out_link)
 {
@@ -1908,18 +1864,6 @@ nm_platform_link_get_lnk_ip6tnl (NMPlatform *self, int ifindex, const NMPlatform
 	return _link_get_lnk (self, ifindex, NM_LINK_TYPE_IP6TNL, out_link);
 }
 
-const NMPlatformLnkIp6Tnl *
-nm_platform_link_get_lnk_ip6gre (NMPlatform *self, int ifindex, const NMPlatformLink **out_link)
-{
-	return _link_get_lnk (self, ifindex, NM_LINK_TYPE_IP6GRE, out_link);
-}
-
-const NMPlatformLnkIp6Tnl *
-nm_platform_link_get_lnk_ip6gretap (NMPlatform *self, int ifindex, const NMPlatformLink **out_link)
-{
-	return _link_get_lnk (self, ifindex, NM_LINK_TYPE_IP6GRETAP, out_link);
-}
-
 const NMPlatformLnkIpIp *
 nm_platform_link_get_lnk_ipip (NMPlatform *self, int ifindex, const NMPlatformLink **out_link)
 {
@@ -1968,12 +1912,6 @@ nm_platform_link_get_lnk_vxlan (NMPlatform *self, int ifindex, const NMPlatformL
 	return _link_get_lnk (self, ifindex, NM_LINK_TYPE_VXLAN, out_link);
 }
 
-const NMPlatformLnkWireGuard *
-nm_platform_link_get_lnk_wireguard (NMPlatform *self, int ifindex, const NMPlatformLink **out_link)
-{
-	return _link_get_lnk (self, ifindex, NM_LINK_TYPE_WIREGUARD, out_link);
-}
-
 /*****************************************************************************/
 
 /**
@@ -2058,9 +1996,8 @@ nm_platform_link_vlan_add (NMPlatform *self,
 	if (plerr != NM_PLATFORM_ERROR_SUCCESS)
 		return plerr;
 
-	_LOGD ("link: adding link '%s': vlan parent %d vlanid %d vlanflags %x",
+	_LOGD ("link: adding vlan '%s' parent %d vlanid %d vlanflags %x",
 	       name, parent, vlanid, vlanflags);
-
 	if (!klass->vlan_add (self, name, parent, vlanid, vlanflags, out_link))
 		return NM_PLATFORM_ERROR_UNSPECIFIED;
 	return NM_PLATFORM_ERROR_SUCCESS;
@@ -2091,9 +2028,8 @@ nm_platform_link_vxlan_add (NMPlatform *self,
 	if (plerr != NM_PLATFORM_ERROR_SUCCESS)
 		return plerr;
 
-	_LOGD ("link: adding link '%s': %s",
-	       name, nm_platform_lnk_vxlan_to_string (props, NULL, 0));
-
+	_LOGD ("link: adding vxlan '%s' parent %d id %d",
+	       name, props->parent_ifindex, props->id);
 	if (!klass->link_vxlan_add (self, name, props, out_link))
 		return NM_PLATFORM_ERROR_UNSPECIFIED;
 	return NM_PLATFORM_ERROR_SUCCESS;
@@ -2144,78 +2080,13 @@ nm_platform_link_tun_add (NMPlatform *self,
 	if (plerr != NM_PLATFORM_ERROR_SUCCESS)
 		return plerr;
 
-	_LOGD ("link: adding link '%s': %s",
+	_LOGD ("link: adding tun '%s' %s",
 	       name, nm_platform_lnk_tun_to_string (props, b, sizeof (b)));
-
 	if (!klass->link_tun_add (self, name, props, out_link, out_fd))
 		return NM_PLATFORM_ERROR_UNSPECIFIED;
 	return NM_PLATFORM_ERROR_SUCCESS;
 }
 
-/**
- * nm_platform_6lowpan_add:
- * @self: platform instance
- * @parent: parent link
- * @name: name of the new interface
- * @out_link: on success, the link object
- *
- * Create a 6LoWPAN interface.
- */
-NMPlatformError
-nm_platform_link_6lowpan_add (NMPlatform *self,
-                              const char *name,
-                              int parent,
-                              const NMPlatformLink **out_link)
-{
-	NMPlatformError plerr;
-
-	_CHECK_SELF (self, klass, NM_PLATFORM_ERROR_BUG);
-
-	g_return_val_if_fail (name, NM_PLATFORM_ERROR_BUG);
-
-	plerr = _link_add_check_existing (self, name, NM_LINK_TYPE_6LOWPAN, out_link);
-	if (plerr != NM_PLATFORM_ERROR_SUCCESS)
-		return plerr;
-
-	_LOGD ("adding link '%s': 6lowpan parent %u", name, parent);
-
-	if (!klass->link_6lowpan_add (self, name, parent, out_link))
-		return NM_PLATFORM_ERROR_UNSPECIFIED;
-	return NM_PLATFORM_ERROR_SUCCESS;
-}
-
-gboolean
-nm_platform_link_6lowpan_get_properties (NMPlatform *self, int ifindex, int *out_parent)
-{
-	const NMPlatformLink *plink;
-	_CHECK_SELF (self, klass, FALSE);
-
-	plink = nm_platform_link_get (self, ifindex);
-
-	if (!plink)
-		return FALSE;
-	if (plink->type != NM_LINK_TYPE_6LOWPAN)
-		return FALSE;
-
-	if (plink->parent != 0) {
-		NM_SET_OUT (out_parent, plink->parent);
-		return TRUE;
-	}
-
-	/* As of 4.16 kernel does not expose the peer_ifindex as IFA_LINK.
-	 * Find the WPAN device with the same MAC address. */
-	if (out_parent) {
-		const NMPlatformLink *parent_plink;
-
-		parent_plink = nm_platform_link_get_by_address (self, NM_LINK_TYPE_WPAN,
-		                                                plink->addr.data,
-		                                                plink->addr.len);
-		NM_SET_OUT (out_parent, parent_plink ? parent_plink->ifindex : -1);
-	}
-
-	return TRUE;
-}
-
 /*****************************************************************************/
 
 static gboolean
@@ -2439,18 +2310,23 @@ nm_platform_link_gre_add (NMPlatform *self,
                           const NMPlatformLink **out_link)
 {
 	NMPlatformError plerr;
+	char buffer[INET_ADDRSTRLEN];
 
 	_CHECK_SELF (self, klass, NM_PLATFORM_ERROR_BUG);
 
 	g_return_val_if_fail (props, NM_PLATFORM_ERROR_BUG);
 	g_return_val_if_fail (name, NM_PLATFORM_ERROR_BUG);
 
-	plerr = _link_add_check_existing (self, name, props->is_tap ? NM_LINK_TYPE_GRETAP : NM_LINK_TYPE_GRE, out_link);
+	plerr = _link_add_check_existing (self, name, NM_LINK_TYPE_GRE, out_link);
 	if (plerr != NM_PLATFORM_ERROR_SUCCESS)
 		return plerr;
 
-	_LOGD ("adding link '%s': %s",
-	       name, nm_platform_lnk_gre_to_string (props, NULL, 0));
+	_LOGD (LOG_FMT_IP_TUNNEL,
+	       "gre",
+	       name,
+	       props->parent_ifindex,
+	       nm_utils_inet4_ntop (props->local, NULL),
+	       nm_utils_inet4_ntop (props->remote, buffer));
 
 	if (!klass->link_gre_add (self, name, props, out_link))
 		return NM_PLATFORM_ERROR_UNSPECIFIED;
@@ -2496,9 +2372,6 @@ _infiniband_add_add_or_delete (NMPlatform *self,
 		if (!klass->infiniband_partition_add (self, parent, p_key, out_link))
 			return NM_PLATFORM_ERROR_UNSPECIFIED;
 	} else {
-		_LOGD ("link: deleting infiniband partition %s for parent '%s' (%d), key %d",
-		       name, parent_link->name, parent, p_key);
-
 		if (!klass->infiniband_partition_delete (self, parent, p_key))
 			return NM_PLATFORM_ERROR_UNSPECIFIED;
 	}
@@ -2599,19 +2472,23 @@ nm_platform_link_ip6tnl_add (NMPlatform *self,
                              const NMPlatformLink **out_link)
 {
 	NMPlatformError plerr;
+	char buffer[INET6_ADDRSTRLEN];
 
 	_CHECK_SELF (self, klass, NM_PLATFORM_ERROR_BUG);
 
 	g_return_val_if_fail (props, NM_PLATFORM_ERROR_BUG);
 	g_return_val_if_fail (name, NM_PLATFORM_ERROR_BUG);
-	g_return_val_if_fail (!props->is_gre, NM_PLATFORM_ERROR_BUG);
 
 	plerr = _link_add_check_existing (self, name, NM_LINK_TYPE_IP6TNL, out_link);
 	if (plerr != NM_PLATFORM_ERROR_SUCCESS)
 		return plerr;
 
-	_LOGD ("adding link '%s': %s",
-	       name, nm_platform_lnk_ip6tnl_to_string (props, NULL, 0));
+	_LOGD (LOG_FMT_IP_TUNNEL,
+	       "ip6tnl",
+	       name,
+	       props->parent_ifindex,
+	       nm_utils_inet6_ntop (&props->local, NULL),
+	       nm_utils_inet6_ntop (&props->remote, buffer));
 
 	if (!klass->link_ip6tnl_add (self, name, props, out_link))
 		return NM_PLATFORM_ERROR_UNSPECIFIED;
@@ -2619,46 +2496,6 @@ nm_platform_link_ip6tnl_add (NMPlatform *self,
 }
 
 /**
- * nm_platform_ip6gre_add:
- * @self: platform instance
- * @name: name of the new interface
- * @props: interface properties
- * @out_link: on success, the link object
- *
- * Create an IPv6 GRE/GRETAP tunnel.
- */
-NMPlatformError
-nm_platform_link_ip6gre_add (NMPlatform *self,
-                             const char *name,
-                             const NMPlatformLnkIp6Tnl *props,
-                             const NMPlatformLink **out_link)
-{
-	NMPlatformError plerr;
-
-	_CHECK_SELF (self, klass, NM_PLATFORM_ERROR_BUG);
-
-	g_return_val_if_fail (props, NM_PLATFORM_ERROR_BUG);
-	g_return_val_if_fail (name, NM_PLATFORM_ERROR_BUG);
-	g_return_val_if_fail (props->is_gre, NM_PLATFORM_ERROR_BUG);
-
-	plerr = _link_add_check_existing (self,
-	                                  name,
-	                                  props->is_tap
-	                                      ? NM_LINK_TYPE_IP6GRETAP
-	                                      : NM_LINK_TYPE_IP6GRE,
-	                                  out_link);
-	if (plerr != NM_PLATFORM_ERROR_SUCCESS)
-		return plerr;
-
-	_LOGD ("adding link '%s': %s",
-	       name, nm_platform_lnk_ip6tnl_to_string (props, NULL, 0));
-
-	if (!klass->link_ip6gre_add (self, name, props, out_link))
-		return NM_PLATFORM_ERROR_UNSPECIFIED;
-	return NM_PLATFORM_ERROR_SUCCESS;
-}
-
-/**
  * nm_platform_ipip_add:
  * @self: platform instance
  * @name: name of the new interface
@@ -2674,6 +2511,7 @@ nm_platform_link_ipip_add (NMPlatform *self,
                            const NMPlatformLink **out_link)
 {
 	NMPlatformError plerr;
+	char buffer[INET_ADDRSTRLEN];
 
 	_CHECK_SELF (self, klass, NM_PLATFORM_ERROR_BUG);
 
@@ -2684,8 +2522,12 @@ nm_platform_link_ipip_add (NMPlatform *self,
 	if (plerr != NM_PLATFORM_ERROR_SUCCESS)
 		return plerr;
 
-	_LOGD ("adding link '%s': %s",
-	       name, nm_platform_lnk_ipip_to_string (props, NULL, 0));
+	_LOGD (LOG_FMT_IP_TUNNEL,
+	       "ipip",
+	       name,
+		   props->parent_ifindex,
+	       nm_utils_inet4_ntop (props->local, NULL),
+	       nm_utils_inet4_ntop (props->remote, buffer));
 
 	if (!klass->link_ipip_add (self, name, props, out_link))
 		return NM_PLATFORM_ERROR_UNSPECIFIED;
@@ -2696,7 +2538,6 @@ nm_platform_link_ipip_add (NMPlatform *self,
  * nm_platform_macsec_add:
  * @self: platform instance
  * @name: name of the new interface
- * @parent: parent link
  * @props: interface properties
  * @out_link: on success, the link object
  *
@@ -2720,8 +2561,10 @@ nm_platform_link_macsec_add (NMPlatform *self,
 	if (plerr != NM_PLATFORM_ERROR_SUCCESS)
 		return plerr;
 
-	_LOGD ("adding link '%s': %s",
-	       name, nm_platform_lnk_macsec_to_string (props, NULL, 0));
+	_LOGD ("adding macsec '%s' parent %u sci %llx",
+	       name,
+	       parent,
+	       (unsigned long long) props->sci);
 
 	if (!klass->link_macsec_add (self, name, parent, props, out_link))
 		return NM_PLATFORM_ERROR_UNSPECIFIED;
@@ -2758,8 +2601,11 @@ nm_platform_link_macvlan_add (NMPlatform *self,
 	if (plerr != NM_PLATFORM_ERROR_SUCCESS)
 		return plerr;
 
-	_LOGD ("adding link '%s': %s",
-	       name, nm_platform_lnk_macvlan_to_string (props, NULL, 0));
+	_LOGD ("adding %s '%s' parent %u mode %u",
+	       props->tap ? "macvtap" : "macvlan",
+	       name,
+	       parent,
+	       props->mode);
 
 	if (!klass->link_macvlan_add (self, name, parent, props, out_link))
 		return NM_PLATFORM_ERROR_UNSPECIFIED;
@@ -2782,6 +2628,7 @@ nm_platform_link_sit_add (NMPlatform *self,
                           const NMPlatformLink **out_link)
 {
 	NMPlatformError plerr;
+	char buffer[INET_ADDRSTRLEN];
 
 	_CHECK_SELF (self, klass, NM_PLATFORM_ERROR_BUG);
 
@@ -2792,8 +2639,12 @@ nm_platform_link_sit_add (NMPlatform *self,
 	if (plerr != NM_PLATFORM_ERROR_SUCCESS)
 		return plerr;
 
-	_LOGD ("adding link '%s': %s",
-	       name, nm_platform_lnk_sit_to_string (props, NULL, 0));
+	_LOGD (LOG_FMT_IP_TUNNEL,
+	       "sit",
+	       name,
+	       props->parent_ifindex,
+	       nm_utils_inet4_ntop (props->local, NULL),
+	       nm_utils_inet4_ntop (props->remote, buffer));
 
 	if (!klass->link_sit_add (self, name, props, out_link))
 		return NM_PLATFORM_ERROR_UNSPECIFIED;
@@ -3037,16 +2888,6 @@ nm_platform_wifi_indicate_addressing_running (NMPlatform *self, int ifindex, gbo
 	klass->wifi_indicate_addressing_running (self, ifindex, running);
 }
 
-NMSettingWirelessWakeOnWLan
-nm_platform_wifi_get_wake_on_wlan (NMPlatform *self, int ifindex)
-{
-	_CHECK_SELF (self, klass, FALSE);
-
-	g_return_val_if_fail (ifindex > 0, FALSE);
-
-	return klass->wifi_get_wake_on_wlan (self, ifindex);
-}
-
 gboolean
 nm_platform_wifi_set_wake_on_wlan (NMPlatform *self, int ifindex, NMSettingWirelessWakeOnWLan wowl)
 {
@@ -3088,46 +2929,6 @@ nm_platform_mesh_set_ssid (NMPlatform *self, int ifindex, const guint8 *ssid, gs
 	return klass->mesh_set_ssid (self, ifindex, ssid, len);
 }
 
-guint16
-nm_platform_wpan_get_pan_id (NMPlatform *self, int ifindex)
-{
-	_CHECK_SELF (self, klass, FALSE);
-
-	g_return_val_if_fail (ifindex > 0, FALSE);
-
-	return klass->wpan_get_pan_id (self, ifindex);
-}
-
-gboolean
-nm_platform_wpan_set_pan_id (NMPlatform *self, int ifindex, guint16 pan_id)
-{
-	_CHECK_SELF (self, klass, FALSE);
-
-	g_return_val_if_fail (ifindex > 0, FALSE);
-
-	return klass->wpan_set_pan_id (self, ifindex, pan_id);
-}
-
-guint16
-nm_platform_wpan_get_short_addr (NMPlatform *self, int ifindex)
-{
-	_CHECK_SELF (self, klass, FALSE);
-
-	g_return_val_if_fail (ifindex > 0, FALSE);
-
-	return klass->wpan_get_short_addr (self, ifindex);
-}
-
-gboolean
-nm_platform_wpan_set_short_addr (NMPlatform *self, int ifindex, guint16 short_addr)
-{
-	_CHECK_SELF (self, klass, FALSE);
-
-	g_return_val_if_fail (ifindex > 0, FALSE);
-
-	return klass->wpan_set_short_addr (self, ifindex, short_addr);
-}
-
 #define TO_STRING_DEV_BUF_SIZE (5+15+1)
 static const char *
 _to_string_dev (NMPlatform *self, int ifindex, char *buf, size_t size)
@@ -3213,32 +3014,6 @@ NM_UTILS_LOOKUP_STR_DEFINE (nm_platform_link_duplex_type_to_string, NMPlatformLi
 
 /*****************************************************************************/
 
-NMEthtoolFeatureStates *
-nm_platform_ethtool_get_link_features (NMPlatform *self, int ifindex)
-{
-	_CHECK_SELF_NETNS (self, klass, netns, NULL);
-
-	g_return_val_if_fail (ifindex > 0, NULL);
-
-	return nmp_utils_ethtool_get_features (ifindex);
-}
-
-gboolean
-nm_platform_ethtool_set_features (NMPlatform *self,
-                                  int ifindex,
-                                  const NMEthtoolFeatureStates *features,
-                                  const NMTernary *requested /* indexed by NMEthtoolID - _NM_ETHTOOL_ID_FEATURE_FIRST */,
-                                  gboolean do_set /* or reset */)
-{
-	_CHECK_SELF_NETNS (self, klass, netns, FALSE);
-
-	g_return_val_if_fail (ifindex > 0, FALSE);
-
-	return nmp_utils_ethtool_set_features (ifindex, features, requested, do_set);
-}
-
-/*****************************************************************************/
-
 const NMDedupMultiHeadEntry *
 nm_platform_lookup_all (NMPlatform *platform,
                         NMPCacheIdType cache_id_type,
@@ -3847,7 +3622,7 @@ ip6_address_scope_priority (const struct in6_addr *addr)
 	return 3;
 }
 
-static int
+static gint
 ip6_address_scope_cmp (gconstpointer a, gconstpointer b)
 {
 	const NMPlatformIP6Address *x = NMP_OBJECT_CAST_IP6_ADDRESS (*(const void **) a);
@@ -5182,7 +4957,7 @@ nm_platform_lnk_gre_to_string (const NMPlatformLnkGre *lnk, char *buf, gsize len
 		return buf;
 
 	g_snprintf (buf, len,
-	            lnk->is_tap ? "gretap" : "gre"
+	            "gre"
 	            "%s" /* remote */
 	            "%s" /* local */
 	            "%s" /* parent_ifindex */
@@ -5239,18 +5014,12 @@ nm_platform_lnk_ip6tnl_to_string (const NMPlatformLnkIp6Tnl *lnk, char *buf, gsi
 	char str_encap[30];
 	char str_proto[30];
 	char str_parent_ifindex[30];
-	char *str_type;
 
 	if (!nm_utils_to_string_buffer_init_null (lnk, &buf, &len))
 		return buf;
 
-	if (lnk->is_gre)
-		str_type = lnk->is_tap ? "ip6gretap" : "ip6gre";
-	else
-		str_type = "ip6tnl";
-
 	g_snprintf (buf, len,
-	            "%s" /* type */
+	            "ip6tnl"
 	            "%s" /* remote */
 	            "%s" /* local */
 	            "%s" /* parent_ifindex */
@@ -5261,7 +5030,6 @@ nm_platform_lnk_ip6tnl_to_string (const NMPlatformLnkIp6Tnl *lnk, char *buf, gsi
 	            "%s" /* proto */
 	            " flags 0x%x"
 	            "",
-	            str_type,
 	            nm_sprintf_buf (str_remote, " remote %s", nm_utils_inet6_ntop (&lnk->remote, str_remote1)),
 	            nm_sprintf_buf (str_local, " local %s", nm_utils_inet6_ntop (&lnk->local, str_local1)),
 	            lnk->parent_ifindex ? nm_sprintf_buf (str_parent_ifindex, " dev %d", lnk->parent_ifindex) : "",
@@ -5346,8 +5114,7 @@ nm_platform_lnk_macvlan_to_string (const NMPlatformLnkMacvlan *lnk, char *buf, g
 		return buf;
 
 	g_snprintf (buf, len,
-	            "%s mode %u %s",
-	            lnk->tap ? "macvtap" : "macvlan",
+	            "macvlan mode %u %s",
 	            lnk->mode,
 	            lnk->no_promisc ? "not-promisc" : "promisc");
 	return buf;
@@ -5531,91 +5298,6 @@ nm_platform_lnk_vxlan_to_string (const NMPlatformLnkVxlan *lnk, char *buf, gsize
 	return buf;
 }
 
-const char *
-nm_platform_wireguard_peer_to_string (const NMPWireGuardPeer *peer, char *buf, gsize len)
-{
-	gs_free char *public_key_b64 = NULL;
-	char s_endpoint[NM_UTILS_INET_ADDRSTRLEN + 100];
-	char s_addr[NM_UTILS_INET_ADDRSTRLEN];
-	guint i;
-
-	nm_utils_to_string_buffer_init (&buf, &len);
-
-	if (peer->endpoint_family == AF_INET) {
-		nm_sprintf_buf (s_endpoint,
-		                " endpoint %s:%u",
-		                nm_utils_inet4_ntop (peer->endpoint_addr.addr4, s_addr),
-		                (guint) peer->endpoint_port);
-	} else if (peer->endpoint_family == AF_INET6) {
-		nm_sprintf_buf (s_endpoint,
-		                " endpoint [%s]:%u",
-		                nm_utils_inet6_ntop (&peer->endpoint_addr.addr6, s_addr),
-		                (guint) peer->endpoint_port);
-	} else
-		s_endpoint[0] = '\0';
-
-	public_key_b64 = g_base64_encode (peer->public_key, sizeof (peer->public_key));
-
-	nm_utils_strbuf_append (&buf, &len,
-	                        "public-key %s"
-	                        "%s" /* preshared-key */
-	                        "%s" /* endpoint */
-	                        " rx %"G_GUINT64_FORMAT
-	                        " tx %"G_GUINT64_FORMAT
-	                        "%s", /* allowed-ips */
-	                        public_key_b64,
-	                        nm_utils_mem_all_zero (peer->preshared_key, sizeof (peer->preshared_key))
-	                          ? ""
-	                          : " preshared-key (hidden)",
-	                        s_endpoint,
-	                        peer->rx_bytes,
-	                        peer->tx_bytes,
-	                        peer->allowed_ips_len > 0
-	                          ? " allowed-ips"
-	                          : "");
-
-	for (i = 0; i < peer->allowed_ips_len; i++) {
-		const NMPWireGuardAllowedIP *allowed_ip = &peer->allowed_ips[i];
-
-		nm_utils_strbuf_append (&buf, &len,
-		                        " %s/%u",
-		                        nm_utils_inet_ntop (allowed_ip->family, &allowed_ip->addr, s_addr),
-		                        allowed_ip->mask);
-	}
-
-	return buf;
-}
-
-const char *
-nm_platform_lnk_wireguard_to_string (const NMPlatformLnkWireGuard *lnk, char *buf, gsize len)
-{
-	gs_free char *public_b64 = NULL;
-
-	if (!nm_utils_to_string_buffer_init_null (lnk, &buf, &len))
-		return buf;
-
-	if (!nm_utils_mem_all_zero (lnk->public_key, sizeof (lnk->public_key)))
-		public_b64 = g_base64_encode (lnk->public_key, sizeof (lnk->public_key));
-
-	g_snprintf (buf, len,
-	            "wireguard"
-	            "%s%s" /* public-key */
-	            "%s" /* private-key */
-	            " listen-port %u"
-	            " fwmark 0x%x",
-	            public_b64
-	              ? " public-key "
-	              : "",
-	            public_b64 ?: "",
-	            nm_utils_mem_all_zero (lnk->private_key, sizeof (lnk->private_key))
-	              ? ""
-	              : " private-key (hidden)",
-	            lnk->listen_port,
-	            lnk->fwmark);
-
-	return buf;
-}
-
 /**
  * nm_platform_ip4_address_to_string:
  * @route: pointer to NMPlatformIP4Address address structure
@@ -6093,56 +5775,6 @@ nm_platform_tfilter_cmp (const NMPlatformTfilter *a, const NMPlatformTfilter *b)
 	return 0;
 }
 
-const char *
-nm_platform_vf_to_string (const NMPlatformVF *vf, char *buf, gsize len)
-{
-	char str_mac[128], mac[128];
-	char str_spoof_check[64];
-	char str_trust[64];
-	char str_min_tx_rate[64];
-	char str_max_tx_rate[64];
-	nm_auto_free_gstring GString *gstr_vlans = NULL;
-	guint i;
-
-	if (!nm_utils_to_string_buffer_init_null (vf, &buf, &len))
-		return buf;
-
-	if (vf->mac.len) {
-		nm_utils_hwaddr_ntoa_buf (vf->mac.data, vf->mac.len, TRUE, mac, sizeof (mac));
-		nm_sprintf_buf (str_mac, " mac %s", mac);
-	} else
-		str_mac[0] = '\0';
-
-	if (vf->num_vlans) {
-		gstr_vlans = g_string_new ("");
-		for (i = 0; i < vf->num_vlans; i++) {
-			g_string_append_printf (gstr_vlans, " vlan %u", (unsigned) vf->vlans[i].id);
-			if (vf->vlans[i].qos)
-				g_string_append_printf (gstr_vlans, " qos %u", (unsigned) vf->vlans[i].qos);
-			if (vf->vlans[i].proto_ad)
-				g_string_append (gstr_vlans, " proto 802.1ad");
-		}
-	}
-
-	g_snprintf (buf, len,
-	            "%u"    /* index */
-	            "%s"    /* MAC */
-	            "%s"    /* spoof check */
-	            "%s"    /* trust */
-	            "%s"    /* min tx rate */
-	            "%s"    /* max tx rate */
-	            "%s",   /* VLANs */
-	            vf->index,
-	            str_mac,
-	            vf->spoofchk >= 0 ? nm_sprintf_buf (str_spoof_check, " spoofchk %d", vf->spoofchk) : "",
-	            vf->trust >= 0 ? nm_sprintf_buf (str_trust, " trust %d", vf->trust) : "",
-	            vf->min_tx_rate ? nm_sprintf_buf (str_min_tx_rate, " min_tx_rate %u", (unsigned) vf->min_tx_rate) : "",
-	            vf->max_tx_rate ? nm_sprintf_buf (str_max_tx_rate, " max_tx_rate %u", (unsigned) vf->max_tx_rate) : "",
-	            gstr_vlans ? gstr_vlans->str : "");
-
-	return buf;
-}
-
 void
 nm_platform_link_hash_update (const NMPlatformLink *obj, NMHashState *h)
 {
@@ -6211,8 +5843,7 @@ nm_platform_lnk_gre_hash_update (const NMPlatformLnkGre *obj, NMHashState *h)
 	                     obj->output_key,
 	                     obj->ttl,
 	                     obj->tos,
-	                     (bool) obj->path_mtu_discovery,
-	                     (bool) obj->is_tap);
+	                     (bool) obj->path_mtu_discovery);
 }
 
 int
@@ -6229,7 +5860,6 @@ nm_platform_lnk_gre_cmp (const NMPlatformLnkGre *a, const NMPlatformLnkGre *b)
 	NM_CMP_FIELD (a, b, ttl);
 	NM_CMP_FIELD (a, b, tos);
 	NM_CMP_FIELD_BOOL (a, b, path_mtu_discovery);
-	NM_CMP_FIELD_BOOL (a, b, is_tap);
 	return 0;
 }
 
@@ -6261,13 +5891,7 @@ nm_platform_lnk_ip6tnl_hash_update (const NMPlatformLnkIp6Tnl *obj, NMHashState
 	                     obj->encap_limit,
 	                     obj->proto,
 	                     obj->flow_label,
-	                     obj->flags,
-	                     obj->input_flags,
-	                     obj->output_flags,
-	                     obj->input_key,
-	                     obj->output_key,
-	                     (bool) obj->is_gre,
-	                     (bool) obj->is_tap);
+	                     obj->flags);
 }
 
 int
@@ -6283,12 +5907,6 @@ nm_platform_lnk_ip6tnl_cmp (const NMPlatformLnkIp6Tnl *a, const NMPlatformLnkIp6
 	NM_CMP_FIELD (a, b, flow_label);
 	NM_CMP_FIELD (a, b, proto);
 	NM_CMP_FIELD (a, b, flags);
-	NM_CMP_FIELD (a, b, input_flags);
-	NM_CMP_FIELD (a, b, output_flags);
-	NM_CMP_FIELD (a, b, input_key);
-	NM_CMP_FIELD (a, b, output_key);
-	NM_CMP_FIELD_BOOL (a, b, is_gre);
-	NM_CMP_FIELD_BOOL (a, b, is_tap);
 	return 0;
 }
 
@@ -6506,27 +6124,6 @@ nm_platform_lnk_vxlan_cmp (const NMPlatformLnkVxlan *a, const NMPlatformLnkVxlan
 }
 
 void
-nm_platform_lnk_wireguard_hash_update (const NMPlatformLnkWireGuard *obj, NMHashState *h)
-{
-	nm_hash_update_vals (h,
-	                     obj->listen_port,
-	                     obj->fwmark);
-	nm_hash_update (h, obj->private_key, sizeof (obj->private_key));
-	nm_hash_update (h, obj->public_key, sizeof (obj->public_key));
-}
-
-int
-nm_platform_lnk_wireguard_cmp (const NMPlatformLnkWireGuard *a, const NMPlatformLnkWireGuard *b)
-{
-	NM_CMP_SELF (a, b);
-	NM_CMP_FIELD (a, b, listen_port);
-	NM_CMP_FIELD (a, b, fwmark);
-	NM_CMP_FIELD_MEMCMP (a, b, private_key);
-	NM_CMP_FIELD_MEMCMP (a, b, public_key);
-	return 0;
-}
-
-void
 nm_platform_ip4_address_hash_update (const NMPlatformIP4Address *obj, NMHashState *h)
 {
 	nm_hash_update_vals (h,
diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h
index 11495aff..866df736 100644
--- a/src/platform/nm-platform.h
+++ b/src/platform/nm-platform.h
@@ -15,7 +15,7 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * Copyright (C) 2009 - 2018 Red Hat, Inc.
+ * Copyright (C) 2009 - 2017 Red Hat, Inc.
  */
 
 #ifndef __NETWORKMANAGER_PLATFORM_H__
@@ -608,26 +608,6 @@ extern const NMPlatformVTableRoute nm_platform_vtable_route_v4;
 extern const NMPlatformVTableRoute nm_platform_vtable_route_v6;
 
 typedef struct {
-	guint16 id;
-	guint32 qos;
-	bool proto_ad:1;
-} NMPlatformVFVlan;
-
-typedef struct {
-	guint32 index;
-	guint32 min_tx_rate;
-	guint32 max_tx_rate;
-	guint num_vlans;
-	NMPlatformVFVlan *vlans;
-	struct {
-		guint8 data[20]; /* NM_UTILS_HWADDR_LEN_MAX */
-		guint8 len;
-	} mac;
-	gint8 spoofchk;
-	gint8 trust;
-} NMPlatformVF;
-
-typedef struct {
 	in_addr_t local;
 	in_addr_t remote;
 	int parent_ifindex;
@@ -638,7 +618,6 @@ typedef struct {
 	guint8 ttl;
 	guint8 tos;
 	bool path_mtu_discovery:1;
-	bool is_tap:1;
 } NMPlatformLnkGre;
 
 typedef struct {
@@ -656,14 +635,6 @@ typedef struct {
 	guint8 proto;
 	guint flow_label;
 	guint32 flags;
-
-	/* IP6GRE only */
-	guint32 input_key;
-	guint32 output_key;
-	guint16 input_flags;
-	guint16 output_flags;
-	bool is_tap:1;
-	bool is_gre:1;
 } NMPlatformLnkIp6Tnl;
 
 typedef struct {
@@ -752,16 +723,6 @@ typedef struct {
 	bool l3miss:1;
 } NMPlatformLnkVxlan;
 
-#define NMP_WIREGUARD_PUBLIC_KEY_LEN 32
-#define NMP_WIREGUARD_SYMMETRIC_KEY_LEN 32
-
-typedef struct {
-	guint32 fwmark;
-	guint16 listen_port;
-	guint8 private_key[NMP_WIREGUARD_PUBLIC_KEY_LEN];
-	guint8 public_key[NMP_WIREGUARD_PUBLIC_KEY_LEN];
-} NMPlatformLnkWireGuard;
-
 typedef enum {
 	NM_PLATFORM_LINK_DUPLEX_UNKNOWN,
 	NM_PLATFORM_LINK_DUPLEX_HALF,
@@ -825,8 +786,7 @@ typedef struct {
 	NMPlatformError (*link_set_address) (NMPlatform *, int ifindex, gconstpointer address, size_t length);
 	NMPlatformError (*link_set_mtu) (NMPlatform *, int ifindex, guint32 mtu);
 	gboolean (*link_set_name) (NMPlatform *, int ifindex, const char *name);
-	gboolean (*link_set_sriov_params) (NMPlatform *, int ifindex, guint num_vfs, int autoprobe);
-	gboolean (*link_set_sriov_vfs) (NMPlatform *self, int ifindex, const NMPlatformVF *const *vfs);
+	gboolean (*link_set_sriov_num_vfs) (NMPlatform *, int ifindex, guint num_vfs);
 
 	char *   (*link_get_physical_port_id) (NMPlatform *, int ifindex);
 	guint    (*link_get_dev_id) (NMPlatform *, int ifindex);
@@ -869,10 +829,6 @@ typedef struct {
 	                             const char *name,
 	                             const NMPlatformLnkIp6Tnl *props,
 	                             const NMPlatformLink **out_link);
-	gboolean (*link_ip6gre_add) (NMPlatform *,
-	                             const char *name,
-	                             const NMPlatformLnkIp6Tnl *props,
-	                             const NMPlatformLink **out_link);
 	gboolean (*link_ipip_add) (NMPlatform *,
 	                           const char *name,
 	                           const NMPlatformLnkIpIp *props,
@@ -898,16 +854,12 @@ typedef struct {
 	                          const NMPlatformLink **out_link,
 	                          int *out_fd);
 
-	gboolean (*link_6lowpan_add) (NMPlatform *platform,
-	                              const char *name,
-	                              int parent,
-	                              const NMPlatformLink **out_link);
-
 	gboolean (*infiniband_partition_add) (NMPlatform *, int parent, int p_key, const NMPlatformLink **out_link);
 	gboolean (*infiniband_partition_delete) (NMPlatform *, int parent, int p_key);
 
 	gboolean    (*wifi_get_capabilities) (NMPlatform *, int ifindex, NMDeviceWifiCapabilities *caps);
 	gboolean    (*wifi_get_bssid)        (NMPlatform *, int ifindex, guint8 *bssid);
+	GByteArray *(*wifi_get_ssid)         (NMPlatform *, int ifindex);
 	guint32     (*wifi_get_frequency)    (NMPlatform *, int ifindex);
 	int         (*wifi_get_quality)      (NMPlatform *, int ifindex);
 	guint32     (*wifi_get_rate)         (NMPlatform *, int ifindex);
@@ -916,18 +868,12 @@ typedef struct {
 	void        (*wifi_set_powersave)    (NMPlatform *, int ifindex, guint32 powersave);
 	guint32     (*wifi_find_frequency)   (NMPlatform *, int ifindex, const guint32 *freqs);
 	void        (*wifi_indicate_addressing_running) (NMPlatform *, int ifindex, gboolean running);
-	NMSettingWirelessWakeOnWLan (*wifi_get_wake_on_wlan) (NMPlatform *, int ifindex);
 	gboolean    (*wifi_set_wake_on_wlan) (NMPlatform *, int ifindex, NMSettingWirelessWakeOnWLan wowl);
 
 	guint32     (*mesh_get_channel)      (NMPlatform *, int ifindex);
 	gboolean    (*mesh_set_channel)      (NMPlatform *, int ifindex, guint32 channel);
 	gboolean    (*mesh_set_ssid)         (NMPlatform *, int ifindex, const guint8 *ssid, gsize len);
 
-	guint16     (*wpan_get_pan_id)       (NMPlatform *, int ifindex);
-	gboolean    (*wpan_set_pan_id)       (NMPlatform *, int ifindex, guint16 pan_id);
-	guint16     (*wpan_get_short_addr)   (NMPlatform *, int ifindex);
-	gboolean    (*wpan_set_short_addr)   (NMPlatform *, int ifindex, guint16 short_addr);
-
 	gboolean (*object_delete) (NMPlatform *, const NMPObject *obj);
 
 	gboolean (*ip4_address_add) (NMPlatform *,
@@ -1132,7 +1078,7 @@ const NMPObject *nm_platform_link_get_obj (NMPlatform *self,
                                            gboolean visible_only);
 const NMPlatformLink *nm_platform_link_get (NMPlatform *self, int ifindex);
 const NMPlatformLink *nm_platform_link_get_by_ifname (NMPlatform *self, const char *ifname);
-const NMPlatformLink *nm_platform_link_get_by_address (NMPlatform *self, NMLinkType link_type, gconstpointer address, size_t length);
+const NMPlatformLink *nm_platform_link_get_by_address (NMPlatform *self, gconstpointer address, size_t length);
 
 GPtrArray *nm_platform_link_get_all (NMPlatform *self, gboolean sort_by_name);
 NMPlatformError nm_platform_link_dummy_add (NMPlatform *self, const char *name, const NMPlatformLink **out_link);
@@ -1216,8 +1162,7 @@ gboolean nm_platform_link_get_permanent_address (NMPlatform *self, int ifindex,
 NMPlatformError nm_platform_link_set_address (NMPlatform *self, int ifindex, const void *address, size_t length);
 NMPlatformError nm_platform_link_set_mtu (NMPlatform *self, int ifindex, guint32 mtu);
 gboolean nm_platform_link_set_name (NMPlatform *self, int ifindex, const char *name);
-gboolean nm_platform_link_set_sriov_params (NMPlatform *self, int ifindex, guint num_vfs, int autoprobe);
-gboolean nm_platform_link_set_sriov_vfs (NMPlatform *self, int ifindex, const NMPlatformVF *const *vfs);
+gboolean nm_platform_link_set_sriov_num_vfs (NMPlatform *self, int ifindex, guint num_vfs);
 
 char    *nm_platform_link_get_physical_port_id (NMPlatform *self, int ifindex);
 guint    nm_platform_link_get_dev_id (NMPlatform *self, int ifindex);
@@ -1242,10 +1187,7 @@ char *nm_platform_sysctl_slave_get_option (NMPlatform *self, int ifindex, const
 
 const NMPObject *nm_platform_link_get_lnk (NMPlatform *self, int ifindex, NMLinkType link_type, const NMPlatformLink **out_link);
 const NMPlatformLnkGre *nm_platform_link_get_lnk_gre (NMPlatform *self, int ifindex, const NMPlatformLink **out_link);
-const NMPlatformLnkGre *nm_platform_link_get_lnk_gretap (NMPlatform *self, int ifindex, const NMPlatformLink **out_link);
 const NMPlatformLnkIp6Tnl *nm_platform_link_get_lnk_ip6tnl (NMPlatform *self, int ifindex, const NMPlatformLink **out_link);
-const NMPlatformLnkIp6Tnl *nm_platform_link_get_lnk_ip6gre (NMPlatform *self, int ifindex, const NMPlatformLink **out_link);
-const NMPlatformLnkIp6Tnl *nm_platform_link_get_lnk_ip6gretap (NMPlatform *self, int ifindex, const NMPlatformLink **out_link);
 const NMPlatformLnkIpIp *nm_platform_link_get_lnk_ipip (NMPlatform *self, int ifindex, const NMPlatformLink **out_link);
 const NMPlatformLnkInfiniband *nm_platform_link_get_lnk_infiniband (NMPlatform *self, int ifindex, const NMPlatformLink **out_link);
 const NMPlatformLnkIpIp *nm_platform_link_get_lnk_ipip (NMPlatform *self, int ifindex, const NMPlatformLink **out_link);
@@ -1256,7 +1198,6 @@ const NMPlatformLnkSit *nm_platform_link_get_lnk_sit (NMPlatform *self, int ifin
 const NMPlatformLnkTun *nm_platform_link_get_lnk_tun (NMPlatform *self, int ifindex, const NMPlatformLink **out_link);
 const NMPlatformLnkVlan *nm_platform_link_get_lnk_vlan (NMPlatform *self, int ifindex, const NMPlatformLink **out_link);
 const NMPlatformLnkVxlan *nm_platform_link_get_lnk_vxlan (NMPlatform *self, int ifindex, const NMPlatformLink **out_link);
-const NMPlatformLnkWireGuard *nm_platform_link_get_lnk_wireguard (NMPlatform *self, int ifindex, const NMPlatformLink **out_link);
 
 NMPlatformError nm_platform_link_vlan_add (NMPlatform *self,
                                            const char *name,
@@ -1306,18 +1247,12 @@ void        nm_platform_wifi_set_mode         (NMPlatform *self, int ifindex, NM
 void        nm_platform_wifi_set_powersave    (NMPlatform *self, int ifindex, guint32 powersave);
 guint32     nm_platform_wifi_find_frequency   (NMPlatform *self, int ifindex, const guint32 *freqs);
 void        nm_platform_wifi_indicate_addressing_running (NMPlatform *self, int ifindex, gboolean running);
-NMSettingWirelessWakeOnWLan nm_platform_wifi_get_wake_on_wlan (NMPlatform *self, int ifindex);
 gboolean    nm_platform_wifi_set_wake_on_wlan (NMPlatform *self, int ifindex, NMSettingWirelessWakeOnWLan wowl);
 
 guint32     nm_platform_mesh_get_channel      (NMPlatform *self, int ifindex);
 gboolean    nm_platform_mesh_set_channel      (NMPlatform *self, int ifindex, guint32 channel);
 gboolean    nm_platform_mesh_set_ssid         (NMPlatform *self, int ifindex, const guint8 *ssid, gsize len);
 
-guint16     nm_platform_wpan_get_pan_id       (NMPlatform *platform, int ifindex);
-gboolean    nm_platform_wpan_set_pan_id       (NMPlatform *platform, int ifindex, guint16 pan_id);
-guint16     nm_platform_wpan_get_short_addr   (NMPlatform *platform, int ifindex);
-gboolean    nm_platform_wpan_set_short_addr   (NMPlatform *platform, int ifindex, guint16 short_addr);
-
 void                   nm_platform_ip4_address_set_addr (NMPlatformIP4Address *addr, in_addr_t address, guint8 plen);
 const struct in6_addr *nm_platform_ip6_address_get_peer (const NMPlatformIP6Address *addr);
 
@@ -1331,10 +1266,6 @@ NMPlatformError nm_platform_link_ip6tnl_add (NMPlatform *self,
                                              const char *name,
                                              const NMPlatformLnkIp6Tnl *props,
                                              const NMPlatformLink **out_link);
-NMPlatformError nm_platform_link_ip6gre_add (NMPlatform *self,
-                                             const char *name,
-                                             const NMPlatformLnkIp6Tnl *props,
-                                             const NMPlatformLink **out_link);
 NMPlatformError nm_platform_link_ipip_add (NMPlatform *self,
                                            const char *name,
                                            const NMPlatformLnkIpIp *props,
@@ -1358,13 +1289,6 @@ NMPlatformError nm_platform_link_tun_add (NMPlatform *self,
                                           const NMPlatformLnkTun *props,
                                           const NMPlatformLink **out_link,
                                           int *out_fd);
-NMPlatformError nm_platform_link_6lowpan_add (NMPlatform *self,
-                                              const char *name,
-                                              int parent,
-                                              const NMPlatformLink **out_link);
-gboolean nm_platform_link_6lowpan_get_properties (NMPlatform *self,
-                                                  int ifindex,
-                                                  int *out_parent);
 
 const NMPlatformIP6Address *nm_platform_ip6_address_get (NMPlatform *self, int ifindex, struct in6_addr address);
 
@@ -1451,14 +1375,12 @@ const char *nm_platform_lnk_sit_to_string (const NMPlatformLnkSit *lnk, char *bu
 const char *nm_platform_lnk_tun_to_string (const NMPlatformLnkTun *lnk, char *buf, gsize len);
 const char *nm_platform_lnk_vlan_to_string (const NMPlatformLnkVlan *lnk, char *buf, gsize len);
 const char *nm_platform_lnk_vxlan_to_string (const NMPlatformLnkVxlan *lnk, char *buf, gsize len);
-const char *nm_platform_lnk_wireguard_to_string (const NMPlatformLnkWireGuard *lnk, char *buf, gsize len);
 const char *nm_platform_ip4_address_to_string (const NMPlatformIP4Address *address, char *buf, gsize len);
 const char *nm_platform_ip6_address_to_string (const NMPlatformIP6Address *address, char *buf, gsize len);
 const char *nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route, char *buf, gsize len);
 const char *nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route, char *buf, gsize len);
 const char *nm_platform_qdisc_to_string (const NMPlatformQdisc *qdisc, char *buf, gsize len);
 const char *nm_platform_tfilter_to_string (const NMPlatformTfilter *tfilter, char *buf, gsize len);
-const char *nm_platform_vf_to_string (const NMPlatformVF *vf, char *buf, gsize len);
 
 const char *nm_platform_vlan_qos_mapping_to_string (const char *name,
                                                     const NMVlanQosMapping *map,
@@ -1466,11 +1388,6 @@ const char *nm_platform_vlan_qos_mapping_to_string (const char *name,
                                                     char *buf,
                                                     gsize len);
 
-struct _NMPWireGuardPeer;
-const char *nm_platform_wireguard_peer_to_string (const struct _NMPWireGuardPeer *peer,
-                                                  char *buf,
-                                                  gsize len);
-
 int nm_platform_link_cmp (const NMPlatformLink *a, const NMPlatformLink *b);
 int nm_platform_lnk_gre_cmp (const NMPlatformLnkGre *a, const NMPlatformLnkGre *b);
 int nm_platform_lnk_infiniband_cmp (const NMPlatformLnkInfiniband *a, const NMPlatformLnkInfiniband *b);
@@ -1482,7 +1399,6 @@ int nm_platform_lnk_sit_cmp (const NMPlatformLnkSit *a, const NMPlatformLnkSit *
 int nm_platform_lnk_tun_cmp (const NMPlatformLnkTun *a, const NMPlatformLnkTun *b);
 int nm_platform_lnk_vlan_cmp (const NMPlatformLnkVlan *a, const NMPlatformLnkVlan *b);
 int nm_platform_lnk_vxlan_cmp (const NMPlatformLnkVxlan *a, const NMPlatformLnkVxlan *b);
-int nm_platform_lnk_wireguard_cmp (const NMPlatformLnkWireGuard *a, const NMPlatformLnkWireGuard *b);
 int nm_platform_ip4_address_cmp (const NMPlatformIP4Address *a, const NMPlatformIP4Address *b);
 int nm_platform_ip6_address_cmp (const NMPlatformIP6Address *a, const NMPlatformIP6Address *b);
 
@@ -1519,7 +1435,6 @@ void nm_platform_lnk_sit_hash_update (const NMPlatformLnkSit *obj, NMHashState *
 void nm_platform_lnk_tun_hash_update (const NMPlatformLnkTun *obj, NMHashState *h);
 void nm_platform_lnk_vlan_hash_update (const NMPlatformLnkVlan *obj, NMHashState *h);
 void nm_platform_lnk_vxlan_hash_update (const NMPlatformLnkVxlan *obj, NMHashState *h);
-void nm_platform_lnk_wireguard_hash_update (const NMPlatformLnkWireGuard *obj, NMHashState *h);
 
 void nm_platform_qdisc_hash_update (const NMPlatformQdisc *obj, NMHashState *h);
 void nm_platform_tfilter_hash_update (const NMPlatformTfilter *obj, NMHashState *h);
@@ -1537,17 +1452,6 @@ int nm_platform_ip_address_cmp_expiry (const NMPlatformIPAddress *a, const NMPla
 gboolean nm_platform_ethtool_set_wake_on_lan (NMPlatform *self, int ifindex, NMSettingWiredWakeOnLan wol, const char *wol_password);
 gboolean nm_platform_ethtool_set_link_settings (NMPlatform *self, int ifindex, gboolean autoneg, guint32 speed, NMPlatformLinkDuplexType duplex);
 gboolean nm_platform_ethtool_get_link_settings (NMPlatform *self, int ifindex, gboolean *out_autoneg, guint32 *out_speed, NMPlatformLinkDuplexType *out_duplex);
-
-typedef struct _NMEthtoolFeatureStates NMEthtoolFeatureStates;
-
-NMEthtoolFeatureStates *nm_platform_ethtool_get_link_features (NMPlatform *self,
-                                                               int ifindex);
-gboolean nm_platform_ethtool_set_features (NMPlatform *self,
-                                           int ifindex,
-                                           const NMEthtoolFeatureStates *features,
-                                           const NMTernary *requested /* indexed by NMEthtoolID - _NM_ETHTOOL_ID_FEATURE_FIRST */,
-                                           gboolean do_set /* or reset */);
-
 const char * nm_platform_link_duplex_type_to_string (NMPlatformLinkDuplexType duplex);
 
 void nm_platform_ip4_dev_route_blacklist_set (NMPlatform *self,
diff --git a/src/platform/nmp-object.c b/src/platform/nmp-object.c
index fdc27440..50e6825b 100644
--- a/src/platform/nmp-object.c
+++ b/src/platform/nmp-object.c
@@ -15,7 +15,7 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * Copyright (C) 2015 - 2018 Red Hat, Inc.
+ * Copyright (C) 2015 - 2017 Red Hat, Inc.
  */
 
 #include "nm-default.h"
@@ -27,14 +27,10 @@
 #include <libudev.h>
 
 #include "nm-utils.h"
-#include "nm-utils/nm-secret-utils.h"
 
 #include "nm-core-utils.h"
 #include "nm-platform-utils.h"
 
-#include "wifi/nm-wifi-utils.h"
-#include "wpan/nm-wpan-utils.h"
-
 /*****************************************************************************/
 
 #define _NMLOG_DOMAIN LOGD_PLATFORM
@@ -341,103 +337,12 @@ _vlan_xgress_qos_mappings_cpy (guint *dst_n_map,
 		g_clear_pointer (dst_map, g_free);
 		*dst_n_map = src_n_map;
 		if (src_n_map > 0)
-			*dst_map = nm_memdup (src_map, sizeof (*src_map) * src_n_map);
+			*dst_map = g_memdup (src_map, sizeof (*src_map) * src_n_map);
 	}
 }
 
 /*****************************************************************************/
 
-static void
-_wireguard_allowed_ip_hash_update (const NMPWireGuardAllowedIP *ip,
-                                   NMHashState *h)
-{
-	nm_hash_update_vals (h, ip->family,
-	                        ip->mask);
-
-	if (ip->family == AF_INET)
-		nm_hash_update_val (h, ip->addr.addr4);
-	else if (ip->family == AF_INET6)
-		nm_hash_update_val (h, ip->addr.addr6);
-}
-
-static int
-_wireguard_allowed_ip_cmp (const NMPWireGuardAllowedIP *a,
-                           const NMPWireGuardAllowedIP *b)
-{
-	NM_CMP_SELF (a, b);
-
-	NM_CMP_FIELD (a, b, family);
-	NM_CMP_FIELD (a, b, mask);
-
-	if (a->family == AF_INET)
-		NM_CMP_FIELD (a, b, addr.addr4);
-	else if (a->family == AF_INET6)
-		NM_CMP_FIELD_IN6ADDR (a, b, addr.addr6);
-
-	return 0;
-}
-
-static void
-_wireguard_peer_hash_update (const NMPWireGuardPeer *peer,
-                             NMHashState *h)
-{
-	guint i;
-
-	nm_hash_update (h, peer->public_key, sizeof (peer->public_key));
-	nm_hash_update (h, peer->preshared_key, sizeof (peer->preshared_key));
-	nm_hash_update_vals (h,
-	                     peer->persistent_keepalive_interval,
-	                     peer->allowed_ips_len,
-	                     peer->rx_bytes,
-	                     peer->tx_bytes,
-	                     peer->last_handshake_time.tv_sec,
-	                     peer->last_handshake_time.tv_nsec,
-	                     peer->endpoint_port,
-	                     peer->endpoint_family);
-
-	if (peer->endpoint_family == AF_INET)
-		nm_hash_update_val (h, peer->endpoint_addr.addr4);
-	else if (peer->endpoint_family == AF_INET6)
-		nm_hash_update_val (h, peer->endpoint_addr.addr6);
-
-	for (i = 0; i < peer->allowed_ips_len; i++)
-		_wireguard_allowed_ip_hash_update (&peer->allowed_ips[i], h);
-}
-
-static int
-_wireguard_peer_cmp (const NMPWireGuardPeer *a,
-                     const NMPWireGuardPeer *b)
-{
-	guint i;
-
-	NM_CMP_SELF (a, b);
-
-	NM_CMP_FIELD (a, b, last_handshake_time.tv_sec);
-	NM_CMP_FIELD (a, b, last_handshake_time.tv_nsec);
-	NM_CMP_FIELD (a, b, rx_bytes);
-	NM_CMP_FIELD (a, b, tx_bytes);
-	NM_CMP_FIELD (a, b, allowed_ips_len);
-	NM_CMP_FIELD (a, b, persistent_keepalive_interval);
-	NM_CMP_FIELD (a, b, endpoint_port);
-	NM_CMP_FIELD (a, b, endpoint_family);
-	NM_CMP_FIELD_MEMCMP (a, b, public_key);
-	NM_CMP_FIELD_MEMCMP (a, b, preshared_key);
-
-	if (a->endpoint_family == AF_INET)
-		NM_CMP_FIELD (a, b, endpoint_addr.addr4);
-	else if (a->endpoint_family == AF_INET6)
-		NM_CMP_FIELD_IN6ADDR (a, b, endpoint_addr.addr6);
-
-	for (i = 0; i < a->allowed_ips_len; i++) {
-		NM_CMP_RETURN (_wireguard_allowed_ip_cmp (&a->allowed_ips[i],
-		                                          &b->allowed_ips[i]));
-	}
-
-	return 0;
-}
-
-/*****************************************************************************/
-
 static const char *
 _link_get_driver (struct udev_device *udevice, const char *kind, int ifindex)
 {
@@ -551,7 +456,6 @@ _vt_cmd_obj_dispose_link (NMPObject *obj)
 		udev_device_unref (obj->_link.udev.device);
 		obj->_link.udev.device = NULL;
 	}
-	g_clear_object (&obj->_link.ext_data);
 	nmp_object_unref (obj->_link.netlink.lnk);
 }
 
@@ -562,28 +466,6 @@ _vt_cmd_obj_dispose_lnk_vlan (NMPObject *obj)
 	g_free ((gpointer) obj->_lnk_vlan.egress_qos_map);
 }
 
-static void
-_wireguard_clear (NMPObjectLnkWireGuard *lnk)
-{
-	guint i;
-
-	nm_explicit_bzero (lnk->_public.private_key,
-	                   sizeof (lnk->_public.private_key));
-	for (i = 0; i < lnk->peers_len; i++) {
-		NMPWireGuardPeer *peer = (NMPWireGuardPeer *) &lnk->peers[i];
-
-		nm_explicit_bzero (peer->preshared_key, sizeof (peer->preshared_key));
-	}
-	g_free ((gpointer) lnk->peers);
-	g_free ((gpointer) lnk->_allowed_ips_buf);
-}
-
-static void
-_vt_cmd_obj_dispose_lnk_wireguard (NMPObject *obj)
-{
-	_wireguard_clear (&obj->_lnk_wireguard);
-}
-
 static NMPObject *
 _nmp_object_new_from_class (const NMPClass *klass)
 {
@@ -749,35 +631,31 @@ static const char *
 _vt_cmd_obj_to_string_link (const NMPObject *obj, NMPObjectToStringMode to_string_mode, char *buf, gsize buf_size)
 {
 	const NMPClass *klass = NMP_OBJECT_GET_CLASS (obj);
-	char *b = buf;
+	char buf2[sizeof (_nm_utils_to_string_buffer)];
+	char buf3[sizeof (_nm_utils_to_string_buffer)];
 
 	switch (to_string_mode) {
 	case NMP_OBJECT_TO_STRING_ID:
 		return klass->cmd_plobj_to_string_id (&obj->object, buf, buf_size);
 	case NMP_OBJECT_TO_STRING_ALL:
-		nm_utils_strbuf_append (&b, &buf_size,
-		                        "[%s,%p,%u,%calive,%cvisible,%cin-nl,%p; ",
-		                        klass->obj_type_name, obj, obj->parent._ref_count,
-		                        nmp_object_is_alive (obj) ? '+' : '-',
-		                        nmp_object_is_visible (obj) ? '+' : '-',
-		                        obj->_link.netlink.is_in_netlink ? '+' : '-',
-		                        obj->_link.udev.device);
-		NMP_OBJECT_GET_CLASS (obj)->cmd_plobj_to_string (&obj->object, b, buf_size);
-		nm_utils_strbuf_seek_end (&b, &buf_size);
-		if (obj->_link.netlink.lnk) {
-			nm_utils_strbuf_append_str (&b, &buf_size, "; ");
-			nmp_object_to_string (obj->_link.netlink.lnk, NMP_OBJECT_TO_STRING_ALL, b, buf_size);
-			nm_utils_strbuf_seek_end (&b, &buf_size);
-		}
-		nm_utils_strbuf_append_c (&b, &buf_size, ']');
+		g_snprintf (buf, buf_size,
+		            "[%s,%p,%u,%calive,%cvisible,%cin-nl,%p; %s]",
+		            klass->obj_type_name, obj, obj->parent._ref_count,
+		            nmp_object_is_alive (obj) ? '+' : '-',
+		            nmp_object_is_visible (obj) ? '+' : '-',
+		            obj->_link.netlink.is_in_netlink ? '+' : '-',
+		            obj->_link.udev.device,
+		            nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_PUBLIC, buf2, sizeof (buf2)));
 		return buf;
 	case NMP_OBJECT_TO_STRING_PUBLIC:
-		NMP_OBJECT_GET_CLASS (obj)->cmd_plobj_to_string (&obj->object, b, buf_size);
 		if (obj->_link.netlink.lnk) {
-			nm_utils_strbuf_seek_end (&b, &buf_size);
-			nm_utils_strbuf_append_str (&b, &buf_size, "; ");
-			nmp_object_to_string (obj->_link.netlink.lnk, NMP_OBJECT_TO_STRING_PUBLIC, b, buf_size);
-		}
+			NMP_OBJECT_GET_CLASS (obj)->cmd_plobj_to_string (&obj->object, buf2, sizeof (buf2));
+			nmp_object_to_string (obj->_link.netlink.lnk, NMP_OBJECT_TO_STRING_PUBLIC, buf3, sizeof (buf3));
+			g_snprintf (buf, buf_size,
+			            "%s; %s",
+			            buf2, buf3);
+		} else
+			NMP_OBJECT_GET_CLASS (obj)->cmd_plobj_to_string (&obj->object, buf, buf_size);
 		return buf;
 	default:
 		g_return_val_if_reached ("ERROR");
@@ -842,55 +720,6 @@ _vt_cmd_obj_to_string_lnk_vlan (const NMPObject *obj, NMPObjectToStringMode to_s
 	}
 }
 
-static const char *
-_vt_cmd_obj_to_string_lnk_wireguard (const NMPObject *obj, NMPObjectToStringMode to_string_mode, char *buf, gsize buf_size)
-{
-	const NMPClass *klass;
-	char buf2[sizeof (_nm_utils_to_string_buffer)];
-	char *b;
-	guint i;
-
-	klass = NMP_OBJECT_GET_CLASS (obj);
-
-	switch (to_string_mode) {
-	case NMP_OBJECT_TO_STRING_ID:
-		g_snprintf (buf, buf_size, "%p", obj);
-		return buf;
-	case NMP_OBJECT_TO_STRING_ALL:
-		b = buf;
-
-		nm_utils_strbuf_append (&b, &buf_size,
-		                        "[%s,%p,%u,%calive,%cvisible; %s"
-		                        "%s",
-		                        klass->obj_type_name, obj, obj->parent._ref_count,
-		                        nmp_object_is_alive (obj) ? '+' : '-',
-		                        nmp_object_is_visible (obj) ? '+' : '-',
-		                        nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_PUBLIC, buf2, sizeof (buf2)),
-		                        obj->_lnk_wireguard.peers_len > 0
-		                          ? " peers {"
-		                          : "");
-
-		for (i = 0; i < obj->_lnk_wireguard.peers_len; i++) {
-			const NMPWireGuardPeer *peer = &obj->_lnk_wireguard.peers[i];
-
-			nm_utils_strbuf_append_str (&b, &buf_size, " { ");
-			nm_platform_wireguard_peer_to_string (peer, b, buf_size);
-			nm_utils_strbuf_seek_end (&b, &buf_size);
-			nm_utils_strbuf_append_str (&b, &buf_size, " }");
-		}
-		if (obj->_lnk_wireguard.peers_len)
-			nm_utils_strbuf_append_str (&b, &buf_size, " }");
-
-		return buf;
-	case NMP_OBJECT_TO_STRING_PUBLIC:
-		NMP_OBJECT_GET_CLASS (obj)->cmd_plobj_to_string (&obj->object, buf, buf_size);
-
-		return buf;
-	default:
-		g_return_val_if_reached ("ERROR");
-	}
-}
-
 #define _vt_cmd_plobj_to_string_id(type, plat_type, ...) \
 static const char * \
 _vt_cmd_plobj_to_string_id_##type (const NMPlatformObject *_obj, char *buf, gsize buf_len) \
@@ -939,7 +768,6 @@ _vt_cmd_obj_hash_update_link (const NMPObject *obj, NMHashState *h)
 	nm_platform_link_hash_update (&obj->link, h);
 	nm_hash_update_vals (h,
 	                     obj->_link.netlink.is_in_netlink,
-	                     obj->_link.wireguard_family_id,
 	                     obj->_link.udev.device);
 	if (obj->_link.netlink.lnk)
 		nmp_object_hash_update (obj->_link.netlink.lnk, h);
@@ -959,26 +787,17 @@ _vt_cmd_obj_hash_update_lnk_vlan (const NMPObject *obj, NMHashState *h)
 	                                       h);
 }
 
-static void
-_vt_cmd_obj_hash_update_lnk_wireguard (const NMPObject *obj, NMHashState *h)
-{
-	guint i;
-
-	nm_assert (NMP_OBJECT_GET_TYPE (obj) == NMP_OBJECT_TYPE_LNK_WIREGUARD);
-
-	nm_platform_lnk_wireguard_hash_update (&obj->lnk_wireguard, h);
-
-	nm_hash_update_val (h, obj->_lnk_wireguard.peers_len);
-	for (i = 0; i < obj->_lnk_wireguard.peers_len; i++)
-		_wireguard_peer_hash_update (&obj->_lnk_wireguard.peers[i], h);
-}
-
 int
 nmp_object_cmp (const NMPObject *obj1, const NMPObject *obj2)
 {
 	const NMPClass *klass1, *klass2;
 
-	NM_CMP_SELF (obj1, obj2);
+	if (obj1 == obj2)
+		return 0;
+	if (!obj1)
+		return -1;
+	if (!obj2)
+		return 1;
 
 	g_return_val_if_fail (NMP_OBJECT_IS_VALID (obj1), -1);
 	g_return_val_if_fail (NMP_OBJECT_IS_VALID (obj2), 1);
@@ -999,11 +818,16 @@ nmp_object_cmp (const NMPObject *obj1, const NMPObject *obj2)
 static int
 _vt_cmd_obj_cmp_link (const NMPObject *obj1, const NMPObject *obj2)
 {
-	NM_CMP_RETURN (nm_platform_link_cmp (&obj1->link, &obj2->link));
-	NM_CMP_DIRECT (obj1->_link.netlink.is_in_netlink, obj2->_link.netlink.is_in_netlink);
-	NM_CMP_RETURN (nmp_object_cmp (obj1->_link.netlink.lnk, obj2->_link.netlink.lnk));
-	NM_CMP_DIRECT (obj1->_link.wireguard_family_id, obj2->_link.wireguard_family_id);
+	int i;
 
+	i = nm_platform_link_cmp (&obj1->link, &obj2->link);
+	if (i)
+		return i;
+	if (obj1->_link.netlink.is_in_netlink != obj2->_link.netlink.is_in_netlink)
+		return obj1->_link.netlink.is_in_netlink ? -1 : 1;
+	i = nmp_object_cmp (obj1->_link.netlink.lnk, obj2->_link.netlink.lnk);
+	if (i)
+		return i;
 	if (obj1->_link.udev.device != obj2->_link.udev.device) {
 		if (!obj1->_link.udev.device)
 			return -1;
@@ -1016,7 +840,6 @@ _vt_cmd_obj_cmp_link (const NMPObject *obj1, const NMPObject *obj2)
 		 * Have this check as very last. */
 		return (obj1->_link.udev.device < obj2->_link.udev.device) ? -1 : 1;
 	}
-
 	return 0;
 }
 
@@ -1042,21 +865,6 @@ _vt_cmd_obj_cmp_lnk_vlan (const NMPObject *obj1, const NMPObject *obj2)
 	return c;
 }
 
-static int
-_vt_cmd_obj_cmp_lnk_wireguard (const NMPObject *obj1, const NMPObject *obj2)
-{
-	guint i;
-
-	NM_CMP_RETURN (nm_platform_lnk_wireguard_cmp (&obj1->lnk_wireguard, &obj2->lnk_wireguard));
-
-	NM_CMP_FIELD (obj1, obj2, _lnk_wireguard.peers_len);
-
-	for (i = 0; i < obj1->_lnk_wireguard.peers_len; i++)
-		NM_CMP_RETURN (_wireguard_peer_cmp (&obj1->_lnk_wireguard.peers[i], &obj2->_lnk_wireguard.peers[i]));
-
-	return 0;
-}
-
 /* @src is a const object, which is not entirely correct for link types, where
  * we increase the ref count for src->_link.udev.device.
  * Hence, nmp_object_copy() can violate the const promise of @src.
@@ -1100,12 +908,6 @@ _vt_cmd_obj_copy_link (NMPObject *dst, const NMPObject *src)
 			nmp_object_unref (dst->_link.netlink.lnk);
 		dst->_link.netlink.lnk = src->_link.netlink.lnk;
 	}
-	if (dst->_link.ext_data != src->_link.ext_data) {
-		if (dst->_link.ext_data)
-			g_clear_object (&dst->_link.ext_data);
-		if (src->_link.ext_data)
-			dst->_link.ext_data = g_object_ref (src->_link.ext_data);
-	}
 	dst->_link = src->_link;
 }
 
@@ -1123,41 +925,6 @@ _vt_cmd_obj_copy_lnk_vlan (NMPObject *dst, const NMPObject *src)
 	                               src->_lnk_vlan.egress_qos_map);
 }
 
-static void
-_vt_cmd_obj_copy_lnk_wireguard (NMPObject *dst, const NMPObject *src)
-{
-	guint i;
-
-	nm_assert (dst != src);
-
-	_wireguard_clear (&dst->_lnk_wireguard);
-
-	dst->_lnk_wireguard = src->_lnk_wireguard;
-
-	dst->_lnk_wireguard.peers = nm_memdup (dst->_lnk_wireguard.peers,
-	                                       sizeof (NMPWireGuardPeer) * dst->_lnk_wireguard.peers_len);
-	dst->_lnk_wireguard._allowed_ips_buf = nm_memdup (dst->_lnk_wireguard._allowed_ips_buf,
-	                                                  sizeof (NMPWireGuardAllowedIP) * dst->_lnk_wireguard._allowed_ips_buf_len);
-
-	/* all the peers' pointers point into the buffer. They need to be readjusted. */
-	for (i = 0; i < dst->_lnk_wireguard.peers_len; i++) {
-		NMPWireGuardPeer *peer = (NMPWireGuardPeer *) &dst->_lnk_wireguard.peers[i];
-
-		if (peer->allowed_ips_len == 0) {
-			nm_assert (!peer->allowed_ips);
-			continue;
-		}
-		nm_assert (dst->_lnk_wireguard._allowed_ips_buf_len > 0);
-		nm_assert (src->_lnk_wireguard._allowed_ips_buf);
-		nm_assert (peer->allowed_ips >= src->_lnk_wireguard._allowed_ips_buf);
-		nm_assert (&peer->allowed_ips[peer->allowed_ips_len] <= &src->_lnk_wireguard._allowed_ips_buf[src->_lnk_wireguard._allowed_ips_buf_len]);
-
-		peer->allowed_ips = &dst->_lnk_wireguard._allowed_ips_buf[peer->allowed_ips - src->_lnk_wireguard._allowed_ips_buf];
-	}
-
-	nm_assert (nmp_object_equal (src, dst));
-}
-
 #define _vt_cmd_plobj_id_copy(type, plat_type, cmd) \
 static void \
 _vt_cmd_plobj_id_copy_##type (NMPlatformObject *_dst, const NMPlatformObject *_src) \
@@ -2935,17 +2702,6 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = {
 		.cmd_plobj_hash_update              = (void (*) (const NMPlatformObject *obj, NMHashState *h)) nm_platform_lnk_gre_hash_update,
 		.cmd_plobj_cmp                      = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_gre_cmp,
 	},
-	[NMP_OBJECT_TYPE_LNK_GRETAP - 1] = {
-		.parent                             = DEDUP_MULTI_OBJ_CLASS_INIT(),
-		.obj_type                           = NMP_OBJECT_TYPE_LNK_GRETAP,
-		.sizeof_data                        = sizeof (NMPObjectLnkGre),
-		.sizeof_public                      = sizeof (NMPlatformLnkGre),
-		.obj_type_name                      = "gretap",
-		.lnk_link_type                      = NM_LINK_TYPE_GRETAP,
-		.cmd_plobj_to_string                = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_lnk_gre_to_string,
-		.cmd_plobj_hash_update              = (void (*) (const NMPlatformObject *obj, NMHashState *h)) nm_platform_lnk_gre_hash_update,
-		.cmd_plobj_cmp                      = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_gre_cmp,
-	},
 	[NMP_OBJECT_TYPE_LNK_INFINIBAND - 1] = {
 		.parent                             = DEDUP_MULTI_OBJ_CLASS_INIT(),
 		.obj_type                           = NMP_OBJECT_TYPE_LNK_INFINIBAND,
@@ -2968,28 +2724,6 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = {
 		.cmd_plobj_hash_update              = (void (*) (const NMPlatformObject *obj, NMHashState *h)) nm_platform_lnk_ip6tnl_hash_update,
 		.cmd_plobj_cmp                      = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_ip6tnl_cmp,
 	},
-	[NMP_OBJECT_TYPE_LNK_IP6GRE - 1] = {
-		.parent                             = DEDUP_MULTI_OBJ_CLASS_INIT(),
-		.obj_type                           = NMP_OBJECT_TYPE_LNK_IP6GRE,
-		.sizeof_data                        = sizeof (NMPObjectLnkIp6Tnl),
-		.sizeof_public                      = sizeof (NMPlatformLnkIp6Tnl),
-		.obj_type_name                      = "ip6gre",
-		.lnk_link_type                      = NM_LINK_TYPE_IP6GRE,
-		.cmd_plobj_to_string                = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_lnk_ip6tnl_to_string,
-		.cmd_plobj_hash_update              = (void (*) (const NMPlatformObject *obj, NMHashState *h)) nm_platform_lnk_ip6tnl_hash_update,
-		.cmd_plobj_cmp                      = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_ip6tnl_cmp,
-	},
-	[NMP_OBJECT_TYPE_LNK_IP6GRETAP - 1] = {
-		.parent                             = DEDUP_MULTI_OBJ_CLASS_INIT(),
-		.obj_type                           = NMP_OBJECT_TYPE_LNK_IP6GRETAP,
-		.sizeof_data                        = sizeof (NMPObjectLnkIp6Tnl),
-		.sizeof_public                      = sizeof (NMPlatformLnkIp6Tnl),
-		.obj_type_name                      = "ip6gretap",
-		.lnk_link_type                      = NM_LINK_TYPE_IP6GRETAP,
-		.cmd_plobj_to_string                = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_lnk_ip6tnl_to_string,
-		.cmd_plobj_hash_update              = (void (*) (const NMPlatformObject *obj, NMHashState *h)) nm_platform_lnk_ip6tnl_hash_update,
-		.cmd_plobj_cmp                      = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_ip6tnl_cmp,
-	},
 	[NMP_OBJECT_TYPE_LNK_IPIP - 1] = {
 		.parent                             = DEDUP_MULTI_OBJ_CLASS_INIT(),
 		.obj_type                           = NMP_OBJECT_TYPE_LNK_IPIP,
@@ -3083,20 +2817,5 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = {
 		.cmd_plobj_hash_update              = (void (*) (const NMPlatformObject *obj, NMHashState *h)) nm_platform_lnk_vxlan_hash_update,
 		.cmd_plobj_cmp                      = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_vxlan_cmp,
 	},
-	[NMP_OBJECT_TYPE_LNK_WIREGUARD - 1] = {
-		.parent                             = DEDUP_MULTI_OBJ_CLASS_INIT(),
-		.obj_type                           = NMP_OBJECT_TYPE_LNK_WIREGUARD,
-		.sizeof_data                        = sizeof (NMPObjectLnkWireGuard),
-		.sizeof_public                      = sizeof (NMPlatformLnkWireGuard),
-		.obj_type_name                      = "wireguard",
-		.lnk_link_type                      = NM_LINK_TYPE_WIREGUARD,
-		.cmd_obj_hash_update                = _vt_cmd_obj_hash_update_lnk_wireguard,
-		.cmd_obj_cmp                        = _vt_cmd_obj_cmp_lnk_wireguard,
-		.cmd_obj_copy                       = _vt_cmd_obj_copy_lnk_wireguard,
-		.cmd_obj_dispose                    = _vt_cmd_obj_dispose_lnk_wireguard,
-		.cmd_obj_to_string                  = _vt_cmd_obj_to_string_lnk_wireguard,
-		.cmd_plobj_to_string                = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_lnk_wireguard_to_string,
-		.cmd_plobj_hash_update              = (void (*) (const NMPlatformObject *obj, NMHashState *h)) nm_platform_lnk_vlan_hash_update,
-		.cmd_plobj_cmp                      = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_vlan_cmp,
-	},
 };
+
diff --git a/src/platform/nmp-object.h b/src/platform/nmp-object.h
index 97be8321..f473f462 100644
--- a/src/platform/nmp-object.h
+++ b/src/platform/nmp-object.h
@@ -15,7 +15,7 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * Copyright (C) 2015 - 2018 Red Hat, Inc.
+ * Copyright (C) 2015 - 2017 Red Hat, Inc.
  */
 
 #ifndef __NMP_OBJECT_H__
@@ -27,36 +27,6 @@
 
 struct udev_device;
 
-/*****************************************************************************/
-
-typedef struct {
-	NMIPAddr addr;
-	guint8 family;
-	guint8 mask;
-} NMPWireGuardAllowedIP;
-
-typedef struct _NMPWireGuardPeer {
-	NMIPAddr endpoint_addr;
-	struct timespec last_handshake_time;
-	guint64 rx_bytes;
-	guint64 tx_bytes;
-	union {
-		const NMPWireGuardAllowedIP *allowed_ips;
-		guint _construct_idx_start;
-	};
-	union {
-		guint allowed_ips_len;
-		guint _construct_idx_end;
-	};
-	guint16 persistent_keepalive_interval;
-	guint16 endpoint_port;
-	guint8 public_key[NMP_WIREGUARD_PUBLIC_KEY_LEN];
-	guint8 preshared_key[NMP_WIREGUARD_SYMMETRIC_KEY_LEN];
-	guint8 endpoint_family;
-} NMPWireGuardPeer;
-
-/*****************************************************************************/
-
 typedef enum { /*< skip >*/
 	NMP_OBJECT_TO_STRING_ID,
 	NMP_OBJECT_TO_STRING_PUBLIC,
@@ -194,14 +164,6 @@ typedef struct {
 		 */
 		struct udev_device *device;
 	} udev;
-
-	/* Auxiliary data object for Wi-Fi and WPAN */
-	GObject *ext_data;
-
-	/* FIXME: not every NMPObjectLink should pay the price for tracking
-	 * the wireguard family id. This should be tracked via ext_data, which
-	 * would be exactly the right place. */
-	int wireguard_family_id;
 } NMPObjectLink;
 
 typedef struct {
@@ -252,14 +214,6 @@ typedef struct {
 } NMPObjectLnkVxlan;
 
 typedef struct {
-	NMPlatformLnkWireGuard _public;
-	const NMPWireGuardPeer *peers;
-	const NMPWireGuardAllowedIP *_allowed_ips_buf;
-	guint peers_len;
-	guint _allowed_ips_buf_len;
-} NMPObjectLnkWireGuard;
-
-typedef struct {
 	NMPlatformIP4Address _public;
 } NMPObjectIP4Address;
 
@@ -324,9 +278,6 @@ struct _NMPObject {
 		NMPlatformLnkVxlan      lnk_vxlan;
 		NMPObjectLnkVxlan       _lnk_vxlan;
 
-		NMPlatformLnkWireGuard  lnk_wireguard;
-		NMPObjectLnkWireGuard   _lnk_wireguard;
-
 		NMPlatformIPAddress     ip_address;
 		NMPlatformIPXAddress    ipx_address;
 		NMPlatformIP4Address    ip4_address;
diff --git a/src/platform/tests/test-cleanup.c b/src/platform/tests/test-cleanup.c
index 12d91812..8b8c87d8 100644
--- a/src/platform/tests/test-cleanup.c
+++ b/src/platform/tests/test-cleanup.c
@@ -60,7 +60,7 @@ test_cleanup_internal (void)
 	g_assert (ifindex > 0);
 
 	/* wait for kernel to add the IPv6 link local address... it takes a bit. */
-	NMTST_WAIT_ASSERT (300, {
+	NMTST_WAIT_ASSERT (100, {
 		gs_unref_array GArray *addrs = NULL;
 		const NMPlatformIP6Address *a;
 
diff --git a/src/platform/tests/test-common.c b/src/platform/tests/test-common.c
index 3dedbd10..42569d5b 100644
--- a/src/platform/tests/test-common.c
+++ b/src/platform/tests/test-common.c
@@ -1243,29 +1243,21 @@ nmtstp_link_gre_add (NMPlatform *platform,
 	const NMPlatformLink *pllink = NULL;
 	gboolean success;
 	char buffer[INET_ADDRSTRLEN];
-	NMLinkType link_type;
 
 	g_assert (nm_utils_is_valid_iface_name (name, NULL));
 
 	external_command = nmtstp_run_command_check_external (external_command);
-	link_type = lnk->is_tap ? NM_LINK_TYPE_GRETAP : NM_LINK_TYPE_GRE;
 
 	_init_platform (&platform, external_command);
 
 	if (external_command) {
 		gs_free char *dev = NULL;
-		char *obj, *type;
 
 		if (lnk->parent_ifindex)
 			dev = g_strdup_printf ("dev %s", nm_platform_link_get_name (platform, lnk->parent_ifindex));
 
-		obj = lnk->is_tap ? "link" : "tunnel";
-		type = lnk->is_tap ? "type gretap" : "mode gre";
-
-		success = !nmtstp_run_command ("ip %s add %s %s %s local %s remote %s ttl %u tos %02x %s",
-		                                obj,
+		success = !nmtstp_run_command ("ip tunnel add %s mode gre %s local %s remote %s ttl %u tos %02x %s",
 		                                name,
-		                                type,
 		                                dev ?: "",
 		                                nm_utils_inet4_ntop (lnk->local, NULL),
 		                                nm_utils_inet4_ntop (lnk->remote, buffer),
@@ -1273,11 +1265,11 @@ nmtstp_link_gre_add (NMPlatform *platform,
 		                                lnk->tos,
 		                                lnk->path_mtu_discovery ? "pmtudisc" : "nopmtudisc");
 		if (success)
-			pllink = nmtstp_assert_wait_for_link (platform, name, link_type, 100);
+			pllink = nmtstp_assert_wait_for_link (platform, name, NM_LINK_TYPE_GRE, 100);
 	} else
 		success = nm_platform_link_gre_add (platform, name, lnk, &pllink) == NM_PLATFORM_ERROR_SUCCESS;
 
-	_assert_pllink (platform, success, pllink, name, link_type);
+	_assert_pllink (platform, success, pllink, name, NM_LINK_TYPE_GRE);
 
 	return pllink;
 }
@@ -1297,7 +1289,6 @@ nmtstp_link_ip6tnl_add (NMPlatform *platform,
 	gboolean tclass_inherit;
 
 	g_assert (nm_utils_is_valid_iface_name (name, NULL));
-	g_assert (!lnk->is_gre);
 
 	external_command = nmtstp_run_command_check_external (external_command);
 
@@ -1345,56 +1336,6 @@ nmtstp_link_ip6tnl_add (NMPlatform *platform,
 }
 
 const NMPlatformLink *
-nmtstp_link_ip6gre_add (NMPlatform *platform,
-                        gboolean external_command,
-                        const char *name,
-                        const NMPlatformLnkIp6Tnl *lnk)
-{
-	const NMPlatformLink *pllink = NULL;
-	gboolean success;
-	char buffer[INET6_ADDRSTRLEN];
-	char tclass[20];
-	gboolean tclass_inherit;
-
-	g_assert (nm_utils_is_valid_iface_name (name, NULL));
-	g_assert (lnk->is_gre);
-
-	external_command = nmtstp_run_command_check_external (external_command);
-
-	_init_platform (&platform, external_command);
-
-	if (external_command) {
-		gs_free char *dev = NULL;
-
-		if (lnk->parent_ifindex)
-			dev = g_strdup_printf ("dev %s", nm_platform_link_get_name (platform, lnk->parent_ifindex));
-
-		tclass_inherit = NM_FLAGS_HAS (lnk->flags, IP6_TNL_F_USE_ORIG_TCLASS);
-
-		success = !nmtstp_run_command ("ip link add %s type %s %s local %s remote %s ttl %u tclass %s flowlabel %x",
-		                                name,
-		                                lnk->is_tap ? "ip6gretap" : "ip6gre",
-		                                dev,
-		                                nm_utils_inet6_ntop (&lnk->local, NULL),
-		                                nm_utils_inet6_ntop (&lnk->remote, buffer),
-		                                lnk->ttl,
-		                                tclass_inherit ? "inherit" : nm_sprintf_buf (tclass, "%02x", lnk->tclass),
-		                                lnk->flow_label);
-		if (success) {
-			pllink = nmtstp_assert_wait_for_link (platform,
-			                                      name,
-			                                      lnk->is_tap ? NM_LINK_TYPE_IP6GRETAP : NM_LINK_TYPE_IP6GRE,
-			                                      100);
-		}
-	} else
-		success = nm_platform_link_ip6gre_add (platform, name, lnk, &pllink) == NM_PLATFORM_ERROR_SUCCESS;
-
-	_assert_pllink (platform, success, pllink, name, lnk->is_tap ? NM_LINK_TYPE_IP6GRETAP : NM_LINK_TYPE_IP6GRE);
-
-	return pllink;
-}
-
-const NMPlatformLink *
 nmtstp_link_ipip_add (NMPlatform *platform,
                       gboolean external_command,
                       const char *name,
diff --git a/src/platform/tests/test-common.h b/src/platform/tests/test-common.h
index 1baadfa1..bd02b0d7 100644
--- a/src/platform/tests/test-common.h
+++ b/src/platform/tests/test-common.h
@@ -80,7 +80,7 @@ typedef struct {
 	gulong handler_id;
 	const char *name;
 	NMPlatformSignalChangeType change_type;
-	int received_count;
+	gint received_count;
 	GMainLoop *loop;
 	int ifindex;
 	const char *ifname;
@@ -297,10 +297,6 @@ const NMPlatformLink *nmtstp_link_ip6tnl_add (NMPlatform *platform,
                                               gboolean external_command,
                                               const char *name,
                                               const NMPlatformLnkIp6Tnl *lnk);
-const NMPlatformLink *nmtstp_link_ip6gre_add (NMPlatform *platform,
-                                              gboolean external_command,
-                                              const char *name,
-                                              const NMPlatformLnkIp6Tnl *lnk);
 const NMPlatformLink *nmtstp_link_ipip_add (NMPlatform *platform,
                                             gboolean external_command,
                                             const char *name,
diff --git a/src/platform/tests/test-general.c b/src/platform/tests/test-general.c
index eebc15d8..8708c80f 100644
--- a/src/platform/tests/test-general.c
+++ b/src/platform/tests/test-general.c
@@ -15,7 +15,7 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * Copyright (C) 2015 - 2018 Red Hat, Inc.
+ * Copyright (C) 2015 Red Hat, Inc.
  */
 
 #include "nm-default.h"
@@ -57,7 +57,7 @@ NMTST_DEFINE ();
 int
 main (int argc, char **argv)
 {
-	nmtst_init_assert_logging (&argc, &argv, "WARN", "DEFAULT");
+	nmtst_init_assert_logging (&argc, &argv, "INFO", "DEFAULT");
 
 	g_test_add_func ("/general/init_linux_platform", test_init_linux_platform);
 	g_test_add_func ("/general/link_get_all", test_link_get_all);
diff --git a/src/platform/tests/test-link.c b/src/platform/tests/test-link.c
index 057490c4..cd5880e3 100644
--- a/src/platform/tests/test-link.c
+++ b/src/platform/tests/test-link.c
@@ -25,7 +25,6 @@
 #include <sys/types.h>
 #include <linux/if_tun.h>
 
-#include "nm-utils/nm-io-utils.h"
 #include "platform/nmp-object.h"
 #include "platform/nmp-netns.h"
 #include "platform/nm-platform-utils.h"
@@ -700,7 +699,6 @@ test_software_detect (gconstpointer user_data)
 	guint i_step;
 	const gboolean ext = test_data->external_command;
 	NMPlatformLnkTun lnk_tun;
-	NMPlatformLnkGre lnk_gre = { };
 	nm_auto_close int tun_fd = -1;
 
 	nmtstp_run_command_check ("ip link add %s type dummy", PARENT_NAME);
@@ -708,6 +706,7 @@ test_software_detect (gconstpointer user_data)
 
 	switch (test_data->link_type) {
 	case NM_LINK_TYPE_GRE: {
+		NMPlatformLnkGre lnk_gre = { };
 		gboolean gracefully_skip = FALSE;
 
 		lnk_gre.local = nmtst_inet4_from_string ("192.168.233.204");
@@ -731,31 +730,6 @@ test_software_detect (gconstpointer user_data)
 		}
 		break;
 	}
-	case NM_LINK_TYPE_GRETAP: {
-		gboolean gracefully_skip = FALSE;
-
-		lnk_gre.local = nmtst_inet4_from_string ("192.168.1.133");
-		lnk_gre.remote = nmtst_inet4_from_string ("172.168.101.2");
-		lnk_gre.parent_ifindex = ifindex_parent;
-		lnk_gre.ttl = 39;
-		lnk_gre.tos = 12;
-		lnk_gre.path_mtu_discovery = FALSE;
-		lnk_gre.is_tap = TRUE;
-
-		if (!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, "gretap0")) {
-			/* Seems that the ip_gre module is not loaded... try to load it. */
-			gracefully_skip = nm_utils_modprobe (NULL, TRUE, "ip_gre", NULL) != 0;
-		}
-
-		if (!nmtstp_link_gre_add (NULL, ext, DEVICE_NAME, &lnk_gre)) {
-			if (gracefully_skip) {
-				g_test_skip ("Cannot create gretap tunnel because of missing ip_gre module (modprobe ip_gre)");
-				goto out_delete_parent;
-			}
-			g_error ("Failed adding GRETAP tunnel");
-		}
-		break;
-	}
 	case NM_LINK_TYPE_IPIP: {
 		NMPlatformLnkIpIp lnk_ipip = { };
 		gboolean gracefully_skip = FALSE;
@@ -820,58 +794,6 @@ test_software_detect (gconstpointer user_data)
 		}
 		break;
 	}
-	case NM_LINK_TYPE_IP6GRE: {
-		NMPlatformLnkIp6Tnl lnk_ip6tnl = { };
-		gboolean gracefully_skip = FALSE;
-
-		if (!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, "ip6gre0")) {
-			/* Seems that the ip6_tunnel module is not loaded... try to load it. */
-			gracefully_skip = nm_utils_modprobe (NULL, TRUE, "ip6_gre", NULL) != 0;
-		}
-
-		lnk_ip6tnl.local = *nmtst_inet6_from_string ("fd01::42");
-		lnk_ip6tnl.remote = *nmtst_inet6_from_string ("fd01::aaaa");
-		lnk_ip6tnl.parent_ifindex = ifindex_parent;
-		lnk_ip6tnl.tclass = 21;
-		lnk_ip6tnl.flow_label = 1338;
-		lnk_ip6tnl.is_gre = TRUE;
-
-		if (!nmtstp_link_ip6gre_add (NULL, ext, DEVICE_NAME, &lnk_ip6tnl)) {
-			if (gracefully_skip) {
-				g_test_skip ("Cannot create ip6gre tunnel because of missing ip6_gre module (modprobe ip6_gre)");
-				goto out_delete_parent;
-			}
-			g_error ("Failed adding IP6GRE tunnel");
-		}
-		break;
-	}
-	case NM_LINK_TYPE_IP6GRETAP: {
-		NMPlatformLnkIp6Tnl lnk_ip6tnl = { };
-		gboolean gracefully_skip = FALSE;
-
-		if (!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, "ip6gre0")) {
-			/* Seems that the ip6_tunnel module is not loaded... try to load it. */
-			gracefully_skip = nm_utils_modprobe (NULL, TRUE, "ip6_gre", NULL) != 0;
-		}
-
-		lnk_ip6tnl.local = *nmtst_inet6_from_string ("fe80::abcd");
-		lnk_ip6tnl.remote = *nmtst_inet6_from_string ("fc01::bbbb");
-		lnk_ip6tnl.parent_ifindex = ifindex_parent;
-		lnk_ip6tnl.ttl = 10;
-		lnk_ip6tnl.tclass = 22;
-		lnk_ip6tnl.flow_label = 1339;
-		lnk_ip6tnl.is_gre = TRUE;
-		lnk_ip6tnl.is_tap = TRUE;
-
-		if (!nmtstp_link_ip6gre_add (NULL, ext, DEVICE_NAME, &lnk_ip6tnl)) {
-			if (gracefully_skip) {
-				g_test_skip ("Cannot create ip6gretap tunnel because of missing ip6_gre module (modprobe ip6_gre)");
-				goto out_delete_parent;
-			}
-			g_error ("Failed adding IP6GRETAP tunnel");
-		}
-		break;
-	}
 	case NM_LINK_TYPE_MACVLAN: {
 		NMPlatformLnkMacvlan lnk_macvlan = { };
 		const NMPlatformLink *dummy;
@@ -1048,15 +970,16 @@ test_software_detect (gconstpointer user_data)
 			const NMPlatformLnkGre *plnk = &lnk->lnk_gre;
 
 			g_assert (plnk == nm_platform_link_get_lnk_gre (NM_PLATFORM_GET, ifindex, NULL));
-			g_assert (nm_platform_lnk_gre_cmp (plnk, &lnk_gre) == 0);
-
-			break;
-		}
-		case NM_LINK_TYPE_GRETAP: {
-			const NMPlatformLnkGre *plnk = &lnk->lnk_gre;
-
-			g_assert (plnk == nm_platform_link_get_lnk_gretap (NM_PLATFORM_GET, ifindex, NULL));
-			g_assert (nm_platform_lnk_gre_cmp (plnk, &lnk_gre) == 0);
+			g_assert_cmpint (plnk->parent_ifindex, ==, ifindex_parent);
+			g_assert_cmpint (plnk->input_flags, ==, 0);
+			g_assert_cmpint (plnk->output_flags, ==, 0);
+			g_assert_cmpint (plnk->input_key, ==, 0);
+			g_assert_cmpint (plnk->output_key, ==, 0);
+			nmtst_assert_ip4_address (plnk->local, "192.168.233.204");
+			nmtst_assert_ip4_address (plnk->remote, "172.168.10.25");
+			g_assert_cmpint (plnk->ttl, ==, 174);
+			g_assert_cmpint (plnk->tos, ==, 37);
+			g_assert_cmpint (plnk->path_mtu_discovery, ==, TRUE);
 			break;
 		}
 		case NM_LINK_TYPE_IP6TNL: {
@@ -1089,33 +1012,6 @@ test_software_detect (gconstpointer user_data)
 			}
 			break;
 		}
-		case NM_LINK_TYPE_IP6GRE: {
-			const NMPlatformLnkIp6Tnl *plnk = &lnk->lnk_ip6tnl;
-
-			g_assert (plnk == nm_platform_link_get_lnk_ip6gre (NM_PLATFORM_GET, ifindex, NULL));
-			g_assert_cmpint (plnk->parent_ifindex, ==, ifindex_parent);
-			nmtst_assert_ip6_address (&plnk->local, "fd01::42");
-			nmtst_assert_ip6_address (&plnk->remote, "fd01::aaaa");
-			g_assert_cmpint (plnk->tclass, ==, 21);
-			g_assert_cmpint (plnk->flow_label, ==, 1338);
-			g_assert_cmpint (plnk->is_gre, ==, TRUE);
-			g_assert_cmpint (plnk->is_tap, ==, FALSE);
-			break;
-		}
-		case NM_LINK_TYPE_IP6GRETAP: {
-			const NMPlatformLnkIp6Tnl *plnk = &lnk->lnk_ip6tnl;
-
-			g_assert (plnk == nm_platform_link_get_lnk_ip6gretap (NM_PLATFORM_GET, ifindex, NULL));
-			g_assert_cmpint (plnk->parent_ifindex, ==, ifindex_parent);
-			nmtst_assert_ip6_address (&plnk->local, "fe80::abcd");
-			nmtst_assert_ip6_address (&plnk->remote, "fc01::bbbb");
-			g_assert_cmpint (plnk->ttl, ==, 10);
-			g_assert_cmpint (plnk->tclass, ==, 22);
-			g_assert_cmpint (plnk->flow_label, ==, 1339);
-			g_assert_cmpint (plnk->is_gre, ==, TRUE);
-			g_assert_cmpint (plnk->is_tap, ==, TRUE);
-			break;
-		}
 		case NM_LINK_TYPE_IPIP: {
 			const NMPlatformLnkIpIp *plnk = &lnk->lnk_ipip;
 
@@ -1836,7 +1732,7 @@ test_create_many_links_do (guint n_devices)
 	char name[64];
 	const NMPlatformLink *pllink;
 	gs_unref_array GArray *ifindexes = g_array_sized_new (FALSE, FALSE, sizeof (int), n_devices);
-	const int EX = ((int) (nmtst_get_rand_int () % 4)) - 1;
+	const gint EX = ((int) (nmtst_get_rand_int () % 4)) - 1;
 
 	g_assert (EX >= -1 && EX <= 2);
 
@@ -2623,9 +2519,7 @@ test_sysctl_rename (void)
 	case 0: {
 		gs_free char *c = NULL;
 
-		if (nm_utils_file_get_contents (dirfd, "ifindex", 1*1024*1024,
-		                                NM_UTILS_FILE_GET_CONTENTS_FLAG_NONE,
-		                                &c, NULL, NULL) < 0)
+		if (nm_utils_file_get_contents (dirfd, "ifindex", 1*1024*1024, &c, NULL, NULL) < 0)
 			g_assert_not_reached();
 		g_assert_cmpint (ifindex[0], ==, (int) _nm_utils_ascii_str_to_int64 (c, 10, 0, G_MAXINT, -1));
 		break;
@@ -2689,9 +2583,7 @@ test_sysctl_netns_switch (void)
 	{
 		gs_free char *c = NULL;
 
-		if (nm_utils_file_get_contents (dirfd, "ifindex", 0,
-		                                NM_UTILS_FILE_GET_CONTENTS_FLAG_NONE,
-		                                &c, NULL, NULL) < 0)
+		if (nm_utils_file_get_contents (dirfd, "ifindex", 0, &c, NULL, NULL) < 0)
 			g_assert_not_reached();
 		g_assert_cmpint (ifindex, ==, (int) _nm_utils_ascii_str_to_int64 (c, 10, 0, G_MAXINT, -1));
 	}
@@ -2703,11 +2595,7 @@ test_sysctl_netns_switch (void)
 	{
 		gs_free char *c = NULL;
 
-		if (nm_utils_file_get_contents (-1,
-		                                nm_sprintf_bufa (100, "/sys/class/net/%s/ifindex", IFNAME),
-		                                0,
-		                                NM_UTILS_FILE_GET_CONTENTS_FLAG_NONE,
-		                                &c, NULL, NULL) < 0)
+		if (nm_utils_file_get_contents (-1, nm_sprintf_bufa (100, "/sys/class/net/%s/ifindex", IFNAME), 0, &c, NULL, NULL) < 0)
 			ifindex_tmp = -1;
 		else
 			ifindex_tmp = _nm_utils_ascii_str_to_int64 (c, 10, 0, G_MAXINT, -2);
@@ -2722,102 +2610,6 @@ test_sysctl_netns_switch (void)
 
 /*****************************************************************************/
 
-static void
-ethtool_features_dump (const NMEthtoolFeatureStates *features)
-{
-	guint i, j;
-
-	g_assert (features);
-
-	_LOGT (">>> %u features (%u ss-features)", features->n_states, features->n_ss_features);
-
-	for (i = 0; i < features->n_states; i++) {
-		const NMEthtoolFeatureState *s = &features->states_list[i];
-
-		_LOGT (">>> feature-list[%3u]: %3d = %-32s (%3u) | %s %s %s %s",
-		       i,
-		       (int) s->info->ethtool_id,
-		       s->info->kernel_names[s->idx_kernel_name],
-		       s->idx_ss_features,
-		       s->active ? "ACT" : "act",
-		       s->available ? "AVA" : "ava",
-		       s->never_changed ? "NCH" : "nch",
-		       s->requested ? "REQ" : "req");
-	}
-	for (i = 0; i < _NM_ETHTOOL_ID_FEATURE_NUM; i++) {
-		_LOGT (">>> feature-idx [%3u]: %-32s = %u features",
-		       i + (guint) _NM_ETHTOOL_ID_FEATURE_FIRST,
-		       nm_ethtool_data[i + _NM_ETHTOOL_ID_FEATURE_FIRST]->optname,
-		       (guint) NM_PTRARRAY_LEN (features->states_indexed[i]));
-		for (j = 0; features->states_indexed[i] && features->states_indexed[i][j]; j++) {
-			const NMEthtoolFeatureState *s = features->states_indexed[i][j];
-
-			_LOGT (">>>  %3u: %-32s | %s %s %s %s",
-			       j,
-			       s->info->kernel_names[s->idx_kernel_name],
-			       s->active ? "ACT" : "act",
-			       s->available ? "AVA" : "ava",
-			       s->never_changed ? "NCH" : "nch",
-			       s->requested ? "REQ" : "req");
-		}
-	}
-}
-
-static void
-test_ethtool_features_get (void)
-{
-	gs_unref_ptrarray GPtrArray *gfree_keeper = g_ptr_array_new_with_free_func (g_free);
-	const int IFINDEX = 1;
-	guint i;
-	guint i_run;
-
-	for (i_run = 0; i_run < 5; i_run++) {
-		NMEthtoolFeatureStates *features;
-		NMTernary *requested;
-		gboolean do_set = TRUE;
-
-		requested = g_new (NMTernary, _NM_ETHTOOL_ID_FEATURE_NUM);
-		for (i = 0; i < _NM_ETHTOOL_ID_FEATURE_NUM; i++)
-			requested[i] = NM_TERNARY_DEFAULT;
-		g_ptr_array_add (gfree_keeper, requested);
-
-		if (i_run == 0) {
-			requested[NM_ETHTOOL_ID_FEATURE_RX]                    = NM_TERNARY_FALSE;
-			requested[NM_ETHTOOL_ID_FEATURE_TSO]                   = NM_TERNARY_FALSE;
-			requested[NM_ETHTOOL_ID_FEATURE_TX_TCP6_SEGMENTATION]  = NM_TERNARY_FALSE;
-		} else if (i_run == 1)
-			do_set = FALSE;
-		else if (i_run == 2) {
-			requested[NM_ETHTOOL_ID_FEATURE_TSO]                   = NM_TERNARY_FALSE;
-			requested[NM_ETHTOOL_ID_FEATURE_TX_TCP6_SEGMENTATION]  = NM_TERNARY_TRUE;
-		} else if (i_run == 3)
-			do_set = FALSE;
-
-		_LOGT (">>> ethtool-features-get RUN %u (do-set=%s", i_run, do_set ? "set" : "reset");
-
-		features = nmp_utils_ethtool_get_features (IFINDEX);
-		g_ptr_array_add (gfree_keeper, features);
-
-		ethtool_features_dump (features);
-
-		if (_LOGT_ENABLED ()) {
-			int ignore;
-
-			ignore = system ("ethtool -k lo");
-			(void) ignore;
-		}
-
-		if (!do_set) {
-			requested = gfree_keeper->pdata[i_run * 2 - 2];
-			features = gfree_keeper->pdata[i_run * 2 - 1];
-		}
-
-		nmp_utils_ethtool_set_features (IFINDEX, features, requested, do_set);
-	}
-}
-
-/*****************************************************************************/
-
 NMTstpSetupFunc const _nmtstp_setup_platform_func = SETUP;
 
 void
@@ -2849,11 +2641,8 @@ _nmtstp_setup_tests (void)
 		g_test_add_func ("/link/external", test_external);
 
 		test_software_detect_add ("/link/software/detect/gre", NM_LINK_TYPE_GRE, 0);
-		test_software_detect_add ("/link/software/detect/gretap", NM_LINK_TYPE_GRETAP, 0);
 		test_software_detect_add ("/link/software/detect/ip6tnl/0", NM_LINK_TYPE_IP6TNL, 0);
 		test_software_detect_add ("/link/software/detect/ip6tnl/1", NM_LINK_TYPE_IP6TNL, 1);
-		test_software_detect_add ("/link/software/detect/ip6gre", NM_LINK_TYPE_IP6GRE, 0);
-		test_software_detect_add ("/link/software/detect/ip6gretap", NM_LINK_TYPE_IP6GRETAP, 0);
 		test_software_detect_add ("/link/software/detect/ipip", NM_LINK_TYPE_IPIP, 0);
 		test_software_detect_add ("/link/software/detect/macvlan", NM_LINK_TYPE_MACVLAN, 0);
 		test_software_detect_add ("/link/software/detect/macvtap", NM_LINK_TYPE_MACVTAP, 0);
@@ -2879,7 +2668,5 @@ _nmtstp_setup_tests (void)
 
 		g_test_add_func ("/general/sysctl/rename", test_sysctl_rename);
 		g_test_add_func ("/general/sysctl/netns-switch", test_sysctl_netns_switch);
-
-		g_test_add_func ("/link/ethtool/features/get", test_ethtool_features_get);
 	}
 }
diff --git a/src/platform/wifi/nm-wifi-utils.c b/src/platform/wifi/nm-wifi-utils.c
deleted file mode 100644
index 25d71c6a..00000000
--- a/src/platform/wifi/nm-wifi-utils.c
+++ /dev/null
@@ -1,240 +0,0 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
-/* NetworkManager -- Network link manager
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Copyright (C) 2005 - 2018 Red Hat, Inc.
- * Copyright (C) 2006 - 2008 Novell, Inc.
- */
-
-#include "nm-default.h"
-
-#include "nm-wifi-utils.h"
-
-#include <sys/stat.h>
-#include <stdio.h>
-#include <string.h>
-#include <fcntl.h>
-
-#include "nm-wifi-utils-private.h"
-#include "nm-wifi-utils-nl80211.h"
-#if HAVE_WEXT
-#include "nm-wifi-utils-wext.h"
-#endif
-#include "nm-core-utils.h"
-
-#include "platform/nm-platform-utils.h"
-
-G_DEFINE_ABSTRACT_TYPE (NMWifiUtils, nm_wifi_utils, G_TYPE_OBJECT)
-
-/*****************************************************************************/
-
-static void
-nm_wifi_utils_init (NMWifiUtils *self)
-{
-}
-
-static void
-nm_wifi_utils_class_init (NMWifiUtilsClass *klass)
-{
-}
-
-NMWifiUtils *
-nm_wifi_utils_new (int ifindex, struct nl_sock *genl, gboolean check_scan)
-{
-	NMWifiUtils *ret;
-
-	g_return_val_if_fail (ifindex > 0, NULL);
-
-	ret = nm_wifi_utils_nl80211_new (ifindex, genl);
-
-#if HAVE_WEXT
-	if (ret == NULL)
-		ret = nm_wifi_utils_wext_new (ifindex, check_scan);
-#endif
-
-	return ret;
-}
-
-NMDeviceWifiCapabilities
-nm_wifi_utils_get_caps (NMWifiUtils *data)
-{
-	g_return_val_if_fail (data != NULL, NM_WIFI_DEVICE_CAP_NONE);
-
-	return data->caps;
-}
-
-NM80211Mode
-nm_wifi_utils_get_mode (NMWifiUtils *data)
-{
-	g_return_val_if_fail (data != NULL, NM_802_11_MODE_UNKNOWN);
-	return NM_WIFI_UTILS_GET_CLASS (data)->get_mode (data);
-}
-
-gboolean
-nm_wifi_utils_set_mode (NMWifiUtils *data, const NM80211Mode mode)
-{
-	NMWifiUtilsClass *klass;
-
-	g_return_val_if_fail (data != NULL, FALSE);
-	g_return_val_if_fail (   (mode == NM_802_11_MODE_INFRA)
-	                      || (mode == NM_802_11_MODE_AP)
-	                      || (mode == NM_802_11_MODE_ADHOC), FALSE);
-
-	klass = NM_WIFI_UTILS_GET_CLASS (data);
-
-	/* nl80211 probably doesn't need this */
-	return klass->set_mode ? klass->set_mode (data, mode) : TRUE;
-}
-
-gboolean
-nm_wifi_utils_set_powersave (NMWifiUtils *data, guint32 powersave)
-{
-	NMWifiUtilsClass *klass;
-
-	g_return_val_if_fail (data != NULL, FALSE);
-
-	klass = NM_WIFI_UTILS_GET_CLASS (data);
-	return klass->set_powersave ? klass->set_powersave (data, powersave) : TRUE;
-}
-
-NMSettingWirelessWakeOnWLan
-nm_wifi_utils_get_wake_on_wlan (NMWifiUtils *data)
-{
-	NMWifiUtilsClass *klass;
-
-	g_return_val_if_fail (data != NULL, NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE);
-
-	klass = NM_WIFI_UTILS_GET_CLASS (data);
-
-	return klass->get_wake_on_wlan ? klass->get_wake_on_wlan (data) : NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE;
-}
-
-gboolean
-nm_wifi_utils_set_wake_on_wlan (NMWifiUtils *data, NMSettingWirelessWakeOnWLan wowl)
-{
-	NMWifiUtilsClass *klass;
-
-	g_return_val_if_fail (data != NULL, FALSE);
-
-	klass = NM_WIFI_UTILS_GET_CLASS (data);
-	return klass->set_wake_on_wlan ? klass->set_wake_on_wlan (data, wowl) : FALSE;
-}
-
-guint32
-nm_wifi_utils_get_freq (NMWifiUtils *data)
-{
-	g_return_val_if_fail (data != NULL, 0);
-	return NM_WIFI_UTILS_GET_CLASS (data)->get_freq (data);
-}
-
-guint32
-nm_wifi_utils_find_freq (NMWifiUtils *data, const guint32 *freqs)
-{
-	g_return_val_if_fail (data != NULL, 0);
-	g_return_val_if_fail (freqs != NULL, 0);
-	return NM_WIFI_UTILS_GET_CLASS (data)->find_freq (data, freqs);
-}
-
-gboolean
-nm_wifi_utils_get_bssid (NMWifiUtils *data, guint8 *out_bssid)
-{
-	g_return_val_if_fail (data != NULL, FALSE);
-	g_return_val_if_fail (out_bssid != NULL, FALSE);
-
-	memset (out_bssid, 0, ETH_ALEN);
-	return NM_WIFI_UTILS_GET_CLASS (data)->get_bssid (data, out_bssid);
-}
-
-guint32
-nm_wifi_utils_get_rate (NMWifiUtils *data)
-{
-	g_return_val_if_fail (data != NULL, 0);
-	return NM_WIFI_UTILS_GET_CLASS (data)->get_rate (data);
-}
-
-int
-nm_wifi_utils_get_qual (NMWifiUtils *data)
-{
-	g_return_val_if_fail (data != NULL, 0);
-	return NM_WIFI_UTILS_GET_CLASS (data)->get_qual (data);
-}
-
-gboolean
-nm_wifi_utils_is_wifi (int dirfd, const char *ifname)
-{
-	g_return_val_if_fail (dirfd >= 0, FALSE);
-
-	if (faccessat (dirfd, "phy80211", F_OK, 0) == 0)
-		return TRUE;
-#if HAVE_WEXT
-	if (nm_wifi_utils_wext_is_wifi (ifname))
-		return TRUE;
-#endif
-	return FALSE;
-}
-
-/* OLPC Mesh-only functions */
-
-guint32
-nm_wifi_utils_get_mesh_channel (NMWifiUtils *data)
-{
-	NMWifiUtilsClass *klass;
-
-	g_return_val_if_fail (data != NULL, FALSE);
-
-	klass = NM_WIFI_UTILS_GET_CLASS (data);
-	g_return_val_if_fail (klass->get_mesh_channel != NULL, FALSE);
-
-	return klass->get_mesh_channel (data);
-}
-
-gboolean
-nm_wifi_utils_set_mesh_channel (NMWifiUtils *data, guint32 channel)
-{
-	NMWifiUtilsClass *klass;
-
-	g_return_val_if_fail (data != NULL, FALSE);
-	g_return_val_if_fail (channel <= 13, FALSE);
-
-	klass = NM_WIFI_UTILS_GET_CLASS (data);
-	g_return_val_if_fail (klass->set_mesh_channel != NULL, FALSE);
-
-	return klass->set_mesh_channel (data, channel);
-}
-
-gboolean
-nm_wifi_utils_set_mesh_ssid (NMWifiUtils *data, const guint8 *ssid, gsize len)
-{
-	NMWifiUtilsClass *klass;
-
-	g_return_val_if_fail (data != NULL, FALSE);
-
-	klass = NM_WIFI_UTILS_GET_CLASS (data);
-	g_return_val_if_fail (klass->set_mesh_ssid != NULL, FALSE);
-
-	return klass->set_mesh_ssid (data, ssid, len);
-}
-
-gboolean
-nm_wifi_utils_indicate_addressing_running (NMWifiUtils *data, gboolean running)
-{
-	NMWifiUtilsClass *klass;
-
-	g_return_val_if_fail (data != NULL, FALSE);
-
-	klass = NM_WIFI_UTILS_GET_CLASS (data);
-	return klass->indicate_addressing_running ? klass->indicate_addressing_running (data, running) : FALSE;
-}
diff --git a/src/platform/wifi/nm-wifi-utils.h b/src/platform/wifi/nm-wifi-utils.h
deleted file mode 100644
index 6cd178bd..00000000
--- a/src/platform/wifi/nm-wifi-utils.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
-/* NetworkManager -- Network link manager
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Copyright (C) 2005 - 2018 Red Hat, Inc.
- * Copyright (C) 2006 - 2008 Novell, Inc.
- */
-
-#ifndef __WIFI_UTILS_H__
-#define __WIFI_UTILS_H__
-
-#include <net/ethernet.h>
-
-#include "nm-dbus-interface.h"
-#include "nm-setting-wireless.h"
-#include "platform/nm-netlink.h"
-
-typedef struct NMWifiUtils NMWifiUtils;
-
-#define NM_TYPE_WIFI_UTILS            (nm_wifi_utils_get_type ())
-#define NM_WIFI_UTILS(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_WIFI_UTILS, NMWifiUtils))
-#define NM_WIFI_UTILS_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_WIFI_UTILS, NMWifiUtilsClass))
-#define NM_IS_WIFI_UTILS(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_WIFI_UTILS))
-#define NM_IS_WIFI_UTILS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_WIFI_UTILS))
-#define NM_WIFI_UTILS_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_WIFI_UTILS, NMWifiUtilsClass))
-
-GType nm_wifi_utils_get_type (void);
-
-gboolean nm_wifi_utils_is_wifi (int dirfd, const char *ifname);
-
-NMWifiUtils *nm_wifi_utils_new (int ifindex, struct nl_sock *genl, gboolean check_scan);
-
-NMDeviceWifiCapabilities nm_wifi_utils_get_caps (NMWifiUtils *data);
-
-NM80211Mode nm_wifi_utils_get_mode (NMWifiUtils *data);
-
-gboolean nm_wifi_utils_set_mode (NMWifiUtils *data, const NM80211Mode mode);
-
-/* Returns frequency in MHz */
-guint32 nm_wifi_utils_get_freq (NMWifiUtils *data);
-
-/* Return the first supported frequency in the zero-terminated list.
- * Frequencies are specified in MHz. */
-guint32 nm_wifi_utils_find_freq (NMWifiUtils *data, const guint32 *freqs);
-
-/* out_bssid must be ETH_ALEN bytes */
-gboolean nm_wifi_utils_get_bssid (NMWifiUtils *data, guint8 *out_bssid);
-
-/* Returns current bitrate in Kbps */
-guint32 nm_wifi_utils_get_rate (NMWifiUtils *data);
-
-/* Returns quality 0 - 100% on succes, or -1 on error */
-int nm_wifi_utils_get_qual (NMWifiUtils *data);
-
-/* Tells the driver DHCP or SLAAC is running */
-gboolean nm_wifi_utils_indicate_addressing_running (NMWifiUtils *data, gboolean running);
-
-gboolean nm_wifi_utils_set_powersave (NMWifiUtils *data, guint32 powersave);
-
-NMSettingWirelessWakeOnWLan nm_wifi_utils_get_wake_on_wlan (NMWifiUtils *data);
-
-gboolean nm_wifi_utils_set_wake_on_wlan (NMWifiUtils *data, NMSettingWirelessWakeOnWLan wowl);
-
-/* OLPC Mesh-only functions */
-guint32 nm_wifi_utils_get_mesh_channel (NMWifiUtils *data);
-
-gboolean nm_wifi_utils_set_mesh_channel (NMWifiUtils *data, guint32 channel);
-
-gboolean nm_wifi_utils_set_mesh_ssid (NMWifiUtils *data, const guint8 *ssid, gsize len);
-
-#endif  /* __WIFI_UTILS_H__ */
diff --git a/src/platform/wifi/nm-wifi-utils-nl80211.c b/src/platform/wifi/wifi-utils-nl80211.c
index b3bb2bb6..6c2ff3f5 100644
--- a/src/platform/wifi/nm-wifi-utils-nl80211.c
+++ b/src/platform/wifi/wifi-utils-nl80211.c
@@ -15,14 +15,14 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * Copyright (C) 2005 - 2018 Red Hat, Inc.
+ * Copyright (C) 2005 - 2011 Red Hat, Inc.
  * Copyright (C) 2006 - 2008 Novell, Inc.
  * Copyright (C) 2011 Intel Corporation. All rights reserved.
  */
 
 #include "nm-default.h"
 
-#include "nm-wifi-utils-nl80211.h"
+#include "wifi-utils-nl80211.h"
 
 #include <errno.h>
 #include <string.h>
@@ -32,7 +32,7 @@
 #include <linux/nl80211.h>
 
 #include "platform/nm-netlink.h"
-#include "nm-wifi-utils-private.h"
+#include "wifi-utils-private.h"
 #include "platform/nm-platform.h"
 #include "platform/nm-platform-utils.h"
 #include "nm-utils.h"
@@ -47,20 +47,14 @@
 	} G_STMT_END
 
 typedef struct {
-	NMWifiUtils parent;
+	WifiData parent;
 	struct nl_sock *nl_sock;
 	guint32 *freqs;
 	int id;
 	int num_freqs;
 	int phy;
 	bool can_wowlan:1;
-} NMWifiUtilsNl80211;
-
-typedef struct {
-	NMWifiUtilsClass parent;
-} NMWifiUtilsNl80211Class;
-
-G_DEFINE_TYPE (NMWifiUtilsNl80211, nm_wifi_utils_nl80211, NM_TYPE_WIFI_UTILS)
+} WifiDataNl80211;
 
 static int
 ack_handler (struct nl_msg *msg, void *arg)
@@ -103,7 +97,7 @@ nla_put_failure:
 }
 
 static struct nl_msg *
-nl80211_alloc_msg (NMWifiUtilsNl80211 *nl80211, guint32 cmd, guint32 flags)
+nl80211_alloc_msg (WifiDataNl80211 *nl80211, guint32 cmd, guint32 flags)
 {
 	return _nl80211_alloc_msg (nl80211->id, nl80211->parent.ifindex, nl80211->phy, cmd, flags);
 }
@@ -160,7 +154,7 @@ _nl80211_send_and_recv (struct nl_sock *nl_sock,
 }
 
 static int
-nl80211_send_and_recv (NMWifiUtilsNl80211 *nl80211,
+nl80211_send_and_recv (WifiDataNl80211 *nl80211,
                        struct nl_msg *msg,
                        int (*valid_handler) (struct nl_msg *, void *),
                        void *valid_data)
@@ -170,11 +164,13 @@ nl80211_send_and_recv (NMWifiUtilsNl80211 *nl80211,
 }
 
 static void
-dispose (GObject *object)
+wifi_nl80211_deinit (WifiData *parent)
 {
-	NMWifiUtilsNl80211 *nl80211 = NM_WIFI_UTILS_NL80211 (object);
+	WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) parent;
 
-	g_clear_pointer (&nl80211->freqs, g_free);
+	if (nl80211->nl_sock)
+		nl_socket_free (nl80211->nl_sock);
+	g_free (nl80211->freqs);
 }
 
 struct nl80211_iface_info {
@@ -211,9 +207,9 @@ nl80211_iface_info_handler (struct nl_msg *msg, void *arg)
 }
 
 static NM80211Mode
-wifi_nl80211_get_mode (NMWifiUtils *data)
+wifi_nl80211_get_mode (WifiData *data)
 {
-	NMWifiUtilsNl80211 *nl80211 = (NMWifiUtilsNl80211 *) data;
+	WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) data;
 	struct nl80211_iface_info iface_info = {
 		.mode = NM_802_11_MODE_UNKNOWN,
 	};
@@ -229,9 +225,9 @@ wifi_nl80211_get_mode (NMWifiUtils *data)
 }
 
 static gboolean
-wifi_nl80211_set_mode (NMWifiUtils *data, const NM80211Mode mode)
+wifi_nl80211_set_mode (WifiData *data, const NM80211Mode mode)
 {
-	NMWifiUtilsNl80211 *nl80211 = (NMWifiUtilsNl80211 *) data;
+	WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) data;
 	nm_auto_nlmsg struct nl_msg *msg = NULL;
 	int err;
 
@@ -259,9 +255,9 @@ nla_put_failure:
 }
 
 static gboolean
-wifi_nl80211_set_powersave (NMWifiUtils *data, guint32 powersave)
+wifi_nl80211_set_powersave (WifiData *data, guint32 powersave)
 {
-	NMWifiUtilsNl80211 *nl80211 = (NMWifiUtilsNl80211 *) data;
+	WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) data;
 	nm_auto_nlmsg struct nl_msg *msg = NULL;
 	int err;
 
@@ -275,64 +271,10 @@ nla_put_failure:
 	return FALSE;
 }
 
-static int
-nl80211_get_wake_on_wlan_handler (struct nl_msg *msg, void *arg)
-{
-	NMSettingWirelessWakeOnWLan *wowl = arg;
-	struct nlattr *attrs[NL80211_ATTR_MAX + 1];
-	struct nlattr *trig[NUM_NL80211_WOWLAN_TRIG];
-	struct genlmsghdr *gnlh = nlmsg_data (nlmsg_hdr (msg));
-
-	nla_parse (attrs, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
-	           genlmsg_attrlen(gnlh, 0), NULL);
-
-	if (!attrs[NL80211_ATTR_WOWLAN_TRIGGERS])
-		return NL_SKIP;
-
-	nla_parse (trig, MAX_NL80211_WOWLAN_TRIG,
-	           nla_data (attrs[NL80211_ATTR_WOWLAN_TRIGGERS]),
-	           nla_len (attrs[NL80211_ATTR_WOWLAN_TRIGGERS]),
-	           NULL);
-
-	*wowl = NM_SETTING_WIRELESS_WAKE_ON_WLAN_NONE;
-	if (trig[NL80211_WOWLAN_TRIG_ANY])
-		*wowl |= NM_SETTING_WIRELESS_WAKE_ON_WLAN_ANY;
-	if (trig[NL80211_WOWLAN_TRIG_DISCONNECT])
-		*wowl |= NM_SETTING_WIRELESS_WAKE_ON_WLAN_DISCONNECT;
-	if (trig[NL80211_WOWLAN_TRIG_MAGIC_PKT])
-		*wowl |= NM_SETTING_WIRELESS_WAKE_ON_WLAN_MAGIC;
-	if (trig[NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE])
-		*wowl |= NM_SETTING_WIRELESS_WAKE_ON_WLAN_GTK_REKEY_FAILURE;
-	if (trig[NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST])
-		*wowl |= NM_SETTING_WIRELESS_WAKE_ON_WLAN_EAP_IDENTITY_REQUEST;
-	if (trig[NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE])
-		*wowl |= NM_SETTING_WIRELESS_WAKE_ON_WLAN_4WAY_HANDSHAKE;
-	if (trig[NL80211_WOWLAN_TRIG_RFKILL_RELEASE])
-		*wowl |= NM_SETTING_WIRELESS_WAKE_ON_WLAN_RFKILL_RELEASE;
-	if (trig[NL80211_WOWLAN_TRIG_TCP_CONNECTION])
-		*wowl |= NM_SETTING_WIRELESS_WAKE_ON_WLAN_TCP;
-
-	return NL_SKIP;
-}
-
-static NMSettingWirelessWakeOnWLan
-wifi_nl80211_get_wake_on_wlan (NMWifiUtils *data)
-{
-	NMWifiUtilsNl80211 *nl80211 = (NMWifiUtilsNl80211 *) data;
-	NMSettingWirelessWakeOnWLan wowl = NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE;
-	nm_auto_nlmsg struct nl_msg *msg = NULL;
-
-	msg = nl80211_alloc_msg (nl80211, NL80211_CMD_GET_WOWLAN, 0);
-
-	nl80211_send_and_recv (nl80211, msg, nl80211_get_wake_on_wlan_handler, &wowl);
-
-	return wowl;
-}
-
 static gboolean
-wifi_nl80211_set_wake_on_wlan (NMWifiUtils *data, NMSettingWirelessWakeOnWLan wowl)
+wifi_nl80211_set_wake_on_wlan (WifiData *data, NMSettingWirelessWakeOnWLan wowl)
 {
-	NMWifiUtilsNl80211 *nl80211 = (NMWifiUtilsNl80211 *) data;
+	WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) data;
 	nm_auto_nlmsg struct nl_msg *msg = NULL;
 	struct nlattr *triggers;
 	int err;
@@ -340,11 +282,11 @@ wifi_nl80211_set_wake_on_wlan (NMWifiUtils *data, NMSettingWirelessWakeOnWLan wo
 	if (wowl == NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE)
 		return TRUE;
 
-	msg = nl80211_alloc_msg (nl80211, NL80211_CMD_SET_WOWLAN, 0);
+	msg = nl80211_alloc_msg(nl80211, NL80211_CMD_SET_WOWLAN, 0);
 	if (!msg)
 		return FALSE;
 
-	triggers = nla_nest_start (msg, NL80211_ATTR_WOWLAN_TRIGGERS);
+	triggers = nla_nest_start(msg, NL80211_ATTR_WOWLAN_TRIGGERS);
 
 	if (NM_FLAGS_HAS (wowl, NM_SETTING_WIRELESS_WAKE_ON_WLAN_ANY))
 		NLA_PUT_FLAG (msg, NL80211_WOWLAN_TRIG_ANY);
@@ -364,8 +306,7 @@ wifi_nl80211_set_wake_on_wlan (NMWifiUtils *data, NMSettingWirelessWakeOnWLan wo
 	nla_nest_end(msg, triggers);
 
 	err = nl80211_send_and_recv (nl80211, msg, NULL, NULL);
-
-	return err >= 0;
+	return err ? FALSE : TRUE;
 
 nla_put_failure:
 	return FALSE;
@@ -491,7 +432,7 @@ nl80211_bss_dump_handler (struct nl_msg *msg, void *arg)
 }
 
 static void
-nl80211_get_bss_info (NMWifiUtilsNl80211 *nl80211,
+nl80211_get_bss_info (WifiDataNl80211 *nl80211,
                       struct nl80211_bss_info *bss_info)
 {
 	nm_auto_nlmsg struct nl_msg *msg = NULL;
@@ -504,9 +445,9 @@ nl80211_get_bss_info (NMWifiUtilsNl80211 *nl80211,
 }
 
 static guint32
-wifi_nl80211_get_freq (NMWifiUtils *data)
+wifi_nl80211_get_freq (WifiData *data)
 {
-	NMWifiUtilsNl80211 *nl80211 = (NMWifiUtilsNl80211 *) data;
+	WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) data;
 	struct nl80211_bss_info bss_info;
 
 	nl80211_get_bss_info (nl80211, &bss_info);
@@ -515,9 +456,9 @@ wifi_nl80211_get_freq (NMWifiUtils *data)
 }
 
 static guint32
-wifi_nl80211_find_freq (NMWifiUtils *data, const guint32 *freqs)
+wifi_nl80211_find_freq (WifiData *data, const guint32 *freqs)
 {
-	NMWifiUtilsNl80211 *nl80211 = (NMWifiUtilsNl80211 *) data;
+	WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) data;
 	int i;
 
 	for (i = 0; i < nl80211->num_freqs; i++) {
@@ -531,9 +472,9 @@ wifi_nl80211_find_freq (NMWifiUtils *data, const guint32 *freqs)
 }
 
 static gboolean
-wifi_nl80211_get_bssid (NMWifiUtils *data, guint8 *out_bssid)
+wifi_nl80211_get_bssid (WifiData *data, guint8 *out_bssid)
 {
-	NMWifiUtilsNl80211 *nl80211 = (NMWifiUtilsNl80211 *) data;
+	WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) data;
 	struct nl80211_bss_info bss_info;
 
 	nl80211_get_bss_info (nl80211, &bss_info);
@@ -615,7 +556,7 @@ nl80211_station_handler (struct nl_msg *msg, void *arg)
 }
 
 static void
-nl80211_get_ap_info (NMWifiUtilsNl80211 *nl80211,
+nl80211_get_ap_info (WifiDataNl80211 *nl80211,
                      struct nl80211_station_info *sta_info)
 {
 	nm_auto_nlmsg struct nl_msg *msg = NULL;
@@ -645,9 +586,9 @@ nla_put_failure:
 }
 
 static guint32
-wifi_nl80211_get_rate (NMWifiUtils *data)
+wifi_nl80211_get_rate (WifiData *data)
 {
-	NMWifiUtilsNl80211 *nl80211 = (NMWifiUtilsNl80211 *) data;
+	WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) data;
 	struct nl80211_station_info sta_info;
 
 	nl80211_get_ap_info (nl80211, &sta_info);
@@ -656,9 +597,9 @@ wifi_nl80211_get_rate (NMWifiUtils *data)
 }
 
 static int
-wifi_nl80211_get_qual (NMWifiUtils *data)
+wifi_nl80211_get_qual (WifiData *data)
 {
-	NMWifiUtilsNl80211 *nl80211 = (NMWifiUtilsNl80211 *) data;
+	WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) data;
 	struct nl80211_station_info sta_info;
 
 	nl80211_get_ap_info (nl80211, &sta_info);
@@ -666,9 +607,9 @@ wifi_nl80211_get_qual (NMWifiUtils *data)
 }
 
 static gboolean
-wifi_nl80211_indicate_addressing_running (NMWifiUtils *data, gboolean running)
+wifi_nl80211_indicate_addressing_running (WifiData *data, gboolean running)
 {
-	NMWifiUtilsNl80211 *nl80211 = (NMWifiUtilsNl80211 *) data;
+	WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) data;
 	nm_auto_nlmsg struct nl_msg *msg = NULL;
 	int err;
 
@@ -697,6 +638,44 @@ nla_put_failure:
 	return FALSE;
 }
 
+struct nl80211_wowlan_info {
+	gboolean enabled;
+};
+
+static int
+nl80211_wowlan_handler (struct nl_msg *msg, void *arg)
+{
+	struct nlattr *tb[NL80211_ATTR_MAX + 1];
+	struct genlmsghdr *gnlh = nlmsg_data (nlmsg_hdr (msg));
+	struct nl80211_wowlan_info *info = arg;
+
+	info->enabled = FALSE;
+
+	if (nla_parse (tb, NL80211_ATTR_MAX, genlmsg_attrdata (gnlh, 0),
+	               genlmsg_attrlen (gnlh, 0), NULL) < 0)
+		return NL_SKIP;
+
+	if (tb[NL80211_ATTR_WOWLAN_TRIGGERS])
+		info->enabled = TRUE;
+
+	return NL_SKIP;
+}
+
+static gboolean
+wifi_nl80211_get_wowlan (WifiData *data)
+{
+	WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) data;
+	nm_auto_nlmsg struct nl_msg *msg = NULL;
+	struct nl80211_wowlan_info info;
+
+	if (!nl80211->can_wowlan)
+		return FALSE;
+
+	msg = nl80211_alloc_msg (nl80211, NL80211_CMD_GET_WOWLAN, 0);
+	nl80211_send_and_recv (nl80211, msg, nl80211_wowlan_handler, &info);
+	return info.enabled;
+}
+
 struct nl80211_device_info {
 	int phy;
 	guint32 *freqs;
@@ -900,58 +879,48 @@ static int nl80211_wiphy_info_handler (struct nl_msg *msg, void *arg)
 	return NL_SKIP;
 }
 
-static void
-nm_wifi_utils_nl80211_init (NMWifiUtilsNl80211 *self)
-{
-}
-
-static void
-nm_wifi_utils_nl80211_class_init (NMWifiUtilsNl80211Class *klass)
+WifiData *
+wifi_nl80211_init (int ifindex)
 {
-	GObjectClass *object_class = G_OBJECT_CLASS (klass);
-	NMWifiUtilsClass *wifi_utils_class = NM_WIFI_UTILS_CLASS (klass);
-
-	object_class->dispose = dispose;
-
-	wifi_utils_class->get_mode = wifi_nl80211_get_mode;
-	wifi_utils_class->set_mode = wifi_nl80211_set_mode;
-	wifi_utils_class->set_powersave = wifi_nl80211_set_powersave;
-	wifi_utils_class->get_wake_on_wlan = wifi_nl80211_get_wake_on_wlan,
-	wifi_utils_class->set_wake_on_wlan = wifi_nl80211_set_wake_on_wlan,
-	wifi_utils_class->get_freq = wifi_nl80211_get_freq;
-	wifi_utils_class->find_freq = wifi_nl80211_find_freq;
-	wifi_utils_class->get_bssid = wifi_nl80211_get_bssid;
-	wifi_utils_class->get_rate = wifi_nl80211_get_rate;
-	wifi_utils_class->get_qual = wifi_nl80211_get_qual;
-	wifi_utils_class->indicate_addressing_running = wifi_nl80211_indicate_addressing_running;
-}
-
-NMWifiUtils *
-nm_wifi_utils_nl80211_new (int ifindex, struct nl_sock *genl)
-{
-	gs_unref_object NMWifiUtilsNl80211 *nl80211 = NULL;
+	static const WifiDataClass klass = {
+		.struct_size = sizeof (WifiDataNl80211),
+		.get_mode = wifi_nl80211_get_mode,
+		.set_mode = wifi_nl80211_set_mode,
+		.set_powersave = wifi_nl80211_set_powersave,
+		.set_wake_on_wlan = wifi_nl80211_set_wake_on_wlan,
+		.get_freq = wifi_nl80211_get_freq,
+		.find_freq = wifi_nl80211_find_freq,
+		.get_bssid = wifi_nl80211_get_bssid,
+		.get_rate = wifi_nl80211_get_rate,
+		.get_qual = wifi_nl80211_get_qual,
+		.get_wowlan = wifi_nl80211_get_wowlan,
+		.indicate_addressing_running = wifi_nl80211_indicate_addressing_running,
+		.deinit = wifi_nl80211_deinit,
+	};
+	WifiDataNl80211 *nl80211;
 	nm_auto_nlmsg struct nl_msg *msg = NULL;
 	struct nl80211_device_info device_info = {};
 	char ifname[IFNAMSIZ];
 
-	if (!genl)
-		return NULL;
-
 	if (!nmp_utils_if_indextoname (ifindex, ifname)) {
 		_LOGW (LOGD_PLATFORM | LOGD_WIFI,
 		       "can't determine interface name for ifindex %d", ifindex);
 		nm_sprintf_buf (ifname, "if %d", ifindex);
 	}
 
-	nl80211 = g_object_new (NM_TYPE_WIFI_UTILS_NL80211, NULL);
+	nl80211 = wifi_data_new (&klass, ifindex);
+
+	nl80211->nl_sock = nl_socket_alloc ();
+	if (nl80211->nl_sock == NULL)
+		goto error;
 
-	nl80211->parent.ifindex = ifindex;
-	nl80211->nl_sock = genl;
+	if (nl_connect (nl80211->nl_sock, NETLINK_GENERIC))
+		goto error;
 
 	nl80211->id = genl_ctrl_resolve (nl80211->nl_sock, "nl80211");
 	if (nl80211->id < 0) {
 		_LOGD (LOGD_WIFI, "genl_ctrl_resolve: failed to resolve \"nl80211\"");
-		return NULL;
+		goto error;
 	}
 
 	nl80211->phy = -1;
@@ -963,42 +932,42 @@ nm_wifi_utils_nl80211_new (int ifindex, struct nl_sock *genl)
 		_LOGD (LOGD_PLATFORM | LOGD_WIFI,
 		       "(%s): NL80211_CMD_GET_WIPHY request failed",
 		       ifname);
-		return NULL;
+		goto error;
 	}
 
 	if (!device_info.success) {
 		_LOGD (LOGD_PLATFORM | LOGD_WIFI,
 		       "(%s): NL80211_CMD_GET_WIPHY request indicated failure",
 		       ifname);
-		return NULL;
+		goto error;
 	}
 
 	if (!device_info.supported) {
 		_LOGD (LOGD_PLATFORM | LOGD_WIFI,
 		       "(%s): driver does not fully support nl80211, falling back to WEXT",
 		       ifname);
-		return NULL;
+		goto error;
 	}
 
 	if (!device_info.can_scan_ssid) {
 		_LOGE (LOGD_PLATFORM | LOGD_WIFI,
 		       "(%s): driver does not support SSID scans",
 		       ifname);
-		return NULL;
+		goto error;
 	}
 
 	if (device_info.num_freqs == 0 || device_info.freqs == NULL) {
 		nm_log_err (LOGD_PLATFORM | LOGD_WIFI,
 		            "(%s): driver reports no supported frequencies",
 		            ifname);
-		return NULL;
+		goto error;
 	}
 
 	if (device_info.caps == 0) {
 		_LOGE (LOGD_PLATFORM | LOGD_WIFI,
 		       "(%s): driver doesn't report support of any encryption",
 		       ifname);
-		return NULL;
+		goto error;
 	}
 
 	nl80211->phy = device_info.phy;
@@ -1010,5 +979,10 @@ nm_wifi_utils_nl80211_new (int ifindex, struct nl_sock *genl)
 	_LOGI (LOGD_PLATFORM | LOGD_WIFI,
 	       "(%s): using nl80211 for WiFi device control",
 	       ifname);
-	return (NMWifiUtils *) g_steal_pointer (&nl80211);
+	return (WifiData *) nl80211;
+
+error:
+	wifi_utils_unref ((WifiData *) nl80211);
+	return NULL;
 }
+
diff --git a/src/platform/wifi/nm-wifi-utils-nl80211.h b/src/platform/wifi/wifi-utils-nl80211.h
index 27f67697..aff24555 100644
--- a/src/platform/wifi/nm-wifi-utils-nl80211.h
+++ b/src/platform/wifi/wifi-utils-nl80211.h
@@ -16,24 +16,13 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
  * Copyright (C) 2011 Intel Corporation. All rights reserved.
- * Copyright (C) 2018 Red Hat, Inc.
  */
 
 #ifndef __WIFI_UTILS_NL80211_H__
 #define __WIFI_UTILS_NL80211_H__
 
-#include "nm-wifi-utils.h"
-#include "platform/nm-netlink.h"
+#include "wifi-utils.h"
 
-#define NM_TYPE_WIFI_UTILS_NL80211            (nm_wifi_utils_nl80211_get_type ())
-#define NM_WIFI_UTILS_NL80211(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_WIFI_UTILS_NL80211, NMWifiUtilsNl80211))
-#define NM_WIFI_UTILS_NL80211_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_WIFI_UTILS_NL80211, NMWifiUtilsNl80211Class))
-#define NM_IS_WIFI_UTILS_NL80211(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_WIFI_UTILS_NL80211))
-#define NM_IS_WIFI_UTILS_NL80211_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_WIFI_UTILS_NL80211))
-#define NM_WIFI_UTILS_NL80211_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_WIFI_UTILS_NL80211, NMWifiUtilsNl80211Class))
-
-GType nm_wifi_utils_nl80211_get_type (void);
-
-NMWifiUtils *nm_wifi_utils_nl80211_new (int ifindex, struct nl_sock *genl);
+WifiData *wifi_nl80211_init (int ifindex);
 
 #endif  /* __WIFI_UTILS_NL80211_H__ */
diff --git a/src/platform/wifi/nm-wifi-utils-private.h b/src/platform/wifi/wifi-utils-private.h
index bcbc1c51..627108cb 100644
--- a/src/platform/wifi/nm-wifi-utils-private.h
+++ b/src/platform/wifi/wifi-utils-private.h
@@ -15,65 +15,67 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * Copyright (C) 2011 - 2018 Red Hat, Inc.
+ * Copyright (C) 2011 Red Hat, Inc.
  */
 
 #ifndef __WIFI_UTILS_PRIVATE_H__
 #define __WIFI_UTILS_PRIVATE_H__
 
 #include "nm-dbus-interface.h"
-#include "nm-wifi-utils.h"
+#include "wifi-utils.h"
 
 typedef struct {
-	GObjectClass parent;
+	gsize struct_size;
 
-	NM80211Mode (*get_mode) (NMWifiUtils *data);
+	NM80211Mode (*get_mode) (WifiData *data);
 
-	gboolean (*set_mode) (NMWifiUtils *data, const NM80211Mode mode);
+	gboolean (*set_mode) (WifiData *data, const NM80211Mode mode);
 
 	/* Set power saving mode on an interface */
-	gboolean (*set_powersave) (NMWifiUtils *data, guint32 powersave);
-
-	/* Get WakeOnWLAN configuration on an interface */
-	NMSettingWirelessWakeOnWLan (*get_wake_on_wlan) (NMWifiUtils *data);
+	gboolean (*set_powersave) (WifiData *data, guint32 powersave);
 
 	/* Set WakeOnWLAN mode on an interface */
-	gboolean (*set_wake_on_wlan) (NMWifiUtils *data, NMSettingWirelessWakeOnWLan wowl);
+	gboolean (*set_wake_on_wlan) (WifiData *data, NMSettingWirelessWakeOnWLan wowl);
 
 	/* Return current frequency in MHz (really associated BSS frequency) */
-	guint32 (*get_freq) (NMWifiUtils *data);
+	guint32 (*get_freq) (WifiData *data);
 
 	/* Return first supported frequency in the zero-terminated list */
-	guint32 (*find_freq) (NMWifiUtils *data, const guint32 *freqs);
+	guint32 (*find_freq) (WifiData *data, const guint32 *freqs);
 
 	/* Return current bitrate in Kbps */
-	guint32 (*get_rate) (NMWifiUtils *data);
+	guint32 (*get_rate) (WifiData *data);
 
-	gboolean (*get_bssid) (NMWifiUtils *data, guint8 *out_bssid);
+	gboolean (*get_bssid) (WifiData *data, guint8 *out_bssid);
 
 	/* Return a signal strength percentage 0 - 100% for the current BSSID;
 	 * return -1 on errors or if not associated.
 	 */
-	int (*get_qual) (NMWifiUtils *data);
+	int (*get_qual) (WifiData *data);
+
+	void (*deinit) (WifiData *data);
+
+	gboolean (*get_wowlan) (WifiData *data);
 
 	/* OLPC Mesh-only functions */
 
-	guint32 (*get_mesh_channel) (NMWifiUtils *data);
+	guint32 (*get_mesh_channel) (WifiData *data);
 
 	/* channel == 0 means "auto channel" */
-	gboolean (*set_mesh_channel) (NMWifiUtils *data, guint32 channel);
+	gboolean (*set_mesh_channel) (WifiData *data, guint32 channel);
 
 	/* ssid == NULL means "auto SSID" */
-	gboolean (*set_mesh_ssid) (NMWifiUtils *data, const guint8 *ssid, gsize len);
+	gboolean (*set_mesh_ssid) (WifiData *data, const guint8 *ssid, gsize len);
 
-	gboolean (*indicate_addressing_running) (NMWifiUtils *data, gboolean running);
-} NMWifiUtilsClass;
-
-struct NMWifiUtils {
-	GObject parent;
+	gboolean (*indicate_addressing_running) (WifiData *data, gboolean running);
+} WifiDataClass;
 
+struct WifiData {
+	const WifiDataClass *klass;
 	int ifindex;
 	NMDeviceWifiCapabilities caps;
 };
 
+gpointer wifi_data_new (const WifiDataClass *klass, int ifindex);
+
 #endif  /* __WIFI_UTILS_PRIVATE_H__ */
diff --git a/src/platform/wifi/nm-wifi-utils-wext.c b/src/platform/wifi/wifi-utils-wext.c
index e52ae5a3..c8744f79 100644
--- a/src/platform/wifi/nm-wifi-utils-wext.c
+++ b/src/platform/wifi/wifi-utils-wext.c
@@ -15,13 +15,13 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * Copyright (C) 2005 - 2018 Red Hat, Inc.
+ * Copyright (C) 2005 - 2011 Red Hat, Inc.
  * Copyright (C) 2006 - 2008 Novell, Inc.
  */
 
 #include "nm-default.h"
 
-#include "nm-wifi-utils-wext.h"
+#include "wifi-utils-wext.h"
 
 #include <errno.h>
 #include <string.h>
@@ -38,24 +38,17 @@
 #include <sys/socket.h>
 #include <linux/wireless.h>
 
-#include "nm-wifi-utils-private.h"
+#include "wifi-utils-private.h"
 #include "nm-utils.h"
 #include "platform/nm-platform-utils.h"
-#include "nm-core-internal.h"
 
 typedef struct {
-	NMWifiUtils parent;
+	WifiData parent;
 	int fd;
 	struct iw_quality max_qual;
 	gint8 num_freqs;
 	guint32 freqs[IW_MAX_FREQUENCIES];
-} NMWifiUtilsWext;
-
-typedef struct {
-	NMWifiUtilsClass parent;
-} NMWifiUtilsWextClass;
-
-G_DEFINE_TYPE (NMWifiUtilsWext, nm_wifi_utils_wext, NM_TYPE_WIFI_UTILS)
+} WifiDataWext;
 
 /* Until a new wireless-tools comes out that has the defs and the structure,
  * need to copy them here.
@@ -101,11 +94,11 @@ iw_freq_to_uint32 (const struct iw_freq *freq)
 }
 
 static void
-dispose (GObject *object)
+wifi_wext_deinit (WifiData *parent)
 {
-	NMWifiUtilsWext *wext = NM_WIFI_UTILS_WEXT (object);
+	WifiDataWext *wext = (WifiDataWext *) parent;
 
-	wext->fd = nm_close (wext->fd);
+	nm_close (wext->fd);
 }
 
 static gboolean
@@ -125,9 +118,9 @@ get_ifname (int ifindex, char *buffer, const char *op)
 }
 
 static NM80211Mode
-wifi_wext_get_mode_ifname (NMWifiUtils *data, const char *ifname)
+wifi_wext_get_mode_ifname (WifiData *data, const char *ifname)
 {
-	NMWifiUtilsWext *wext = (NMWifiUtilsWext *) data;
+	WifiDataWext *wext = (WifiDataWext *) data;
 	struct iwreq wrq;
 
 	memset (&wrq, 0, sizeof (struct iwreq));
@@ -157,7 +150,7 @@ wifi_wext_get_mode_ifname (NMWifiUtils *data, const char *ifname)
 }
 
 static NM80211Mode
-wifi_wext_get_mode (NMWifiUtils *data)
+wifi_wext_get_mode (WifiData *data)
 {
 	char ifname[IFNAMSIZ];
 
@@ -168,9 +161,9 @@ wifi_wext_get_mode (NMWifiUtils *data)
 }
 
 static gboolean
-wifi_wext_set_mode (NMWifiUtils *data, const NM80211Mode mode)
+wifi_wext_set_mode (WifiData *data, const NM80211Mode mode)
 {
-	NMWifiUtilsWext *wext = (NMWifiUtilsWext *) data;
+	WifiDataWext *wext = (WifiDataWext *) data;
 	struct iwreq wrq;
 	char ifname[IFNAMSIZ];
 
@@ -210,9 +203,9 @@ wifi_wext_set_mode (NMWifiUtils *data, const NM80211Mode mode)
 }
 
 static gboolean
-wifi_wext_set_powersave (NMWifiUtils *data, guint32 powersave)
+wifi_wext_set_powersave (WifiData *data, guint32 powersave)
 {
-	NMWifiUtilsWext *wext = (NMWifiUtilsWext *) data;
+	WifiDataWext *wext = (WifiDataWext *) data;
 	struct iwreq wrq;
 	char ifname[IFNAMSIZ];
 
@@ -239,9 +232,9 @@ wifi_wext_set_powersave (NMWifiUtils *data, guint32 powersave)
 }
 
 static guint32
-wifi_wext_get_freq (NMWifiUtils *data)
+wifi_wext_get_freq (WifiData *data)
 {
-	NMWifiUtilsWext *wext = (NMWifiUtilsWext *) data;
+	WifiDataWext *wext = (WifiDataWext *) data;
 	struct iwreq wrq;
 	char ifname[IFNAMSIZ];
 
@@ -261,9 +254,9 @@ wifi_wext_get_freq (NMWifiUtils *data)
 }
 
 static guint32
-wifi_wext_find_freq (NMWifiUtils *data, const guint32 *freqs)
+wifi_wext_find_freq (WifiData *data, const guint32 *freqs)
 {
-	NMWifiUtilsWext *wext = (NMWifiUtilsWext *) data;
+	WifiDataWext *wext = (WifiDataWext *) data;
 	int i;
 
 	for (i = 0; i < wext->num_freqs; i++) {
@@ -277,9 +270,9 @@ wifi_wext_find_freq (NMWifiUtils *data, const guint32 *freqs)
 }
 
 static gboolean
-wifi_wext_get_bssid (NMWifiUtils *data, guint8 *out_bssid)
+wifi_wext_get_bssid (WifiData *data, guint8 *out_bssid)
 {
-	NMWifiUtilsWext *wext = (NMWifiUtilsWext *) data;
+	WifiDataWext *wext = (WifiDataWext *) data;
 	struct iwreq wrq;
 	char ifname[IFNAMSIZ];
 
@@ -299,9 +292,9 @@ wifi_wext_get_bssid (NMWifiUtils *data, guint8 *out_bssid)
 }
 
 static guint32
-wifi_wext_get_rate (NMWifiUtils *data)
+wifi_wext_get_rate (WifiData *data)
 {
-	NMWifiUtilsWext *wext = (NMWifiUtilsWext *) data;
+	WifiDataWext *wext = (WifiDataWext *) data;
 	struct iwreq wrq;
 	int err;
 	char ifname[IFNAMSIZ];
@@ -410,9 +403,9 @@ wext_qual_to_percent (const struct iw_quality *qual,
 }
 
 static int
-wifi_wext_get_qual (NMWifiUtils *data)
+wifi_wext_get_qual (WifiData *data)
 {
-	NMWifiUtilsWext *wext = (NMWifiUtilsWext *) data;
+	WifiDataWext *wext = (WifiDataWext *) data;
 	struct iwreq wrq;
 	struct iw_statistics stats;
 	char ifname[IFNAMSIZ];
@@ -440,13 +433,13 @@ wifi_wext_get_qual (NMWifiUtils *data)
 /* OLPC Mesh-only functions */
 
 static guint32
-wifi_wext_get_mesh_channel (NMWifiUtils *data)
+wifi_wext_get_mesh_channel (WifiData *data)
 {
-	NMWifiUtilsWext *wext = (NMWifiUtilsWext *) data;
+	WifiDataWext *wext = (WifiDataWext *) data;
 	guint32 freq;
 	int i;
 
-	freq = nm_wifi_utils_get_freq (data);
+	freq = wifi_utils_get_freq (data);
 	for (i = 0; i < wext->num_freqs; i++) {
 		if (freq == wext->freqs[i])
 			return i + 1;
@@ -455,9 +448,9 @@ wifi_wext_get_mesh_channel (NMWifiUtils *data)
 }
 
 static gboolean
-wifi_wext_set_mesh_channel (NMWifiUtils *data, guint32 channel)
+wifi_wext_set_mesh_channel (WifiData *data, guint32 channel)
 {
-	NMWifiUtilsWext *wext = (NMWifiUtilsWext *) data;
+	WifiDataWext *wext = (WifiDataWext *) data;
 	struct iwreq wrq;
 	char ifname[IFNAMSIZ];
 
@@ -484,9 +477,9 @@ wifi_wext_set_mesh_channel (NMWifiUtils *data, guint32 channel)
 }
 
 static gboolean
-wifi_wext_set_mesh_ssid (NMWifiUtils *data, const guint8 *ssid, gsize len)
+wifi_wext_set_mesh_ssid (WifiData *data, const guint8 *ssid, gsize len)
 {
-	NMWifiUtilsWext *wext = (NMWifiUtilsWext *) data;
+	WifiDataWext *wext = (WifiDataWext *) data;
 	struct iwreq wrq;
 	char buf[IW_ESSID_MAX_SIZE + 1];
 	char ifname[IFNAMSIZ];
@@ -507,13 +500,11 @@ wifi_wext_set_mesh_ssid (NMWifiUtils *data, const guint8 *ssid, gsize len)
 		return TRUE;
 
 	if (errno != ENODEV) {
-		gs_free char *ssid_str = NULL;
-
 		errsv = errno;
 		_LOGE (LOGD_PLATFORM | LOGD_WIFI | LOGD_OLPC,
 		       "(%s): error setting SSID to '%s': %s",
 		       ifname,
-		       (ssid_str = _nm_utils_ssid_to_string_arr (ssid, len)),
+		       ssid ? nm_utils_escape_ssid (ssid, len) : "(null)",
 		       strerror (errsv));
 	}
 
@@ -523,7 +514,7 @@ wifi_wext_set_mesh_ssid (NMWifiUtils *data, const guint8 *ssid, gsize len)
 /*****************************************************************************/
 
 static gboolean
-wext_can_scan_ifname (NMWifiUtilsWext *wext, const char *ifname)
+wext_can_scan_ifname (WifiDataWext *wext, const char *ifname)
 {
 	struct iwreq wrq;
 
@@ -537,7 +528,7 @@ wext_can_scan_ifname (NMWifiUtilsWext *wext, const char *ifname)
 }
 
 static gboolean
-wext_get_range_ifname (NMWifiUtilsWext *wext,
+wext_get_range_ifname (WifiDataWext *wext,
                        const char *ifname,
                        struct iw_range *range,
                        guint32 *response_len)
@@ -586,7 +577,7 @@ wext_get_range_ifname (NMWifiUtilsWext *wext,
                   NM_WIFI_DEVICE_CAP_RSN)
 
 static guint32
-wext_get_caps (NMWifiUtilsWext *wext, const char *ifname, struct iw_range *range)
+wext_get_caps (WifiDataWext *wext, const char *ifname, struct iw_range *range)
 {
 	guint32 caps = NM_WIFI_DEVICE_CAP_NONE;
 
@@ -635,38 +626,25 @@ wext_get_caps (NMWifiUtilsWext *wext, const char *ifname, struct iw_range *range
 	return caps;
 }
 
-/*****************************************************************************/
-
-static void
-nm_wifi_utils_wext_init (NMWifiUtilsWext *self)
-{
-}
-
-static void
-nm_wifi_utils_wext_class_init (NMWifiUtilsWextClass *klass)
-{
-	GObjectClass *object_class = G_OBJECT_CLASS (klass);
-	NMWifiUtilsClass *wifi_utils_class = NM_WIFI_UTILS_CLASS (klass);
-
-	object_class->dispose = dispose;
-
-	wifi_utils_class->get_mode = wifi_wext_get_mode;
-	wifi_utils_class->set_mode = wifi_wext_set_mode;
-	wifi_utils_class->set_powersave = wifi_wext_set_powersave;
-	wifi_utils_class->get_freq = wifi_wext_get_freq;
-	wifi_utils_class->find_freq = wifi_wext_find_freq;
-	wifi_utils_class->get_bssid = wifi_wext_get_bssid;
-	wifi_utils_class->get_rate = wifi_wext_get_rate;
-	wifi_utils_class->get_qual = wifi_wext_get_qual;
-	wifi_utils_class->get_mesh_channel = wifi_wext_get_mesh_channel;
-	wifi_utils_class->set_mesh_channel = wifi_wext_set_mesh_channel;
-	wifi_utils_class->set_mesh_ssid = wifi_wext_set_mesh_ssid;
-}
-
-NMWifiUtils *
-nm_wifi_utils_wext_new (int ifindex, gboolean check_scan)
+WifiData *
+wifi_wext_init (int ifindex, gboolean check_scan)
 {
-	NMWifiUtilsWext *wext;
+	static const WifiDataClass klass = {
+		.struct_size = sizeof (WifiDataWext),
+		.get_mode = wifi_wext_get_mode,
+		.set_mode = wifi_wext_set_mode,
+		.set_powersave = wifi_wext_set_powersave,
+		.get_freq = wifi_wext_get_freq,
+		.find_freq = wifi_wext_find_freq,
+		.get_bssid = wifi_wext_get_bssid,
+		.get_rate = wifi_wext_get_rate,
+		.get_qual = wifi_wext_get_qual,
+		.deinit = wifi_wext_deinit,
+		.get_mesh_channel = wifi_wext_get_mesh_channel,
+		.set_mesh_channel = wifi_wext_set_mesh_channel,
+		.set_mesh_ssid = wifi_wext_set_mesh_ssid,
+	};
+	WifiDataWext *wext;
 	struct iw_range range;
 	guint32 response_len = 0;
 	struct iw_range_with_scan_capa *scan_capa_range;
@@ -680,9 +658,8 @@ nm_wifi_utils_wext_new (int ifindex, gboolean check_scan)
 		return NULL;
 	}
 
-	wext = g_object_new (NM_TYPE_WIFI_UTILS_WEXT, NULL);
+	wext = wifi_data_new (&klass, ifindex);
 
-	wext->parent.ifindex = ifindex;
 	wext->fd = socket (PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
 	if (wext->fd < 0)
 		goto error;
@@ -754,15 +731,15 @@ nm_wifi_utils_wext_new (int ifindex, gboolean check_scan)
 	       "(%s): using WEXT for WiFi device control",
 	       ifname);
 
-	return (NMWifiUtils *) wext;
+	return (WifiData *) wext;
 
 error:
-	g_object_unref (wext);
+	wifi_utils_unref ((WifiData *) wext);
 	return NULL;
 }
 
 gboolean
-nm_wifi_utils_wext_is_wifi (const char *iface)
+wifi_wext_is_wifi (const char *iface)
 {
 	int fd;
 	struct iwreq iwr;
diff --git a/src/platform/wifi/nm-wifi-utils-wext.h b/src/platform/wifi/wifi-utils-wext.h
index 44b11afb..3ef5a173 100644
--- a/src/platform/wifi/nm-wifi-utils-wext.h
+++ b/src/platform/wifi/wifi-utils-wext.h
@@ -15,25 +15,16 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * Copyright (C) 2011 - 2018 Red Hat, Inc.
+ * Copyright (C) 2011 Red Hat, Inc.
  */
 
 #ifndef __WIFI_UTILS_WEXT_H__
 #define __WIFI_UTILS_WEXT_H__
 
-#include "nm-wifi-utils.h"
+#include "wifi-utils.h"
 
-#define NM_TYPE_WIFI_UTILS_WEXT            (nm_wifi_utils_wext_get_type ())
-#define NM_WIFI_UTILS_WEXT(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_WIFI_UTILS_WEXT, NMWifiUtilsWext))
-#define NM_WIFI_UTILS_WEXT_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_WIFI_UTILS_WEXT, NMWifiUtilsWextClass))
-#define NM_IS_WIFI_UTILS_WEXT(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_WIFI_UTILS_WEXT))
-#define NM_IS_WIFI_UTILS_WEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_WIFI_UTILS_WEXT))
-#define NM_WIFI_UTILS_WEXT_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_WIFI_UTILS_WEXT, NMWifiUtilsWextClass))
+WifiData *wifi_wext_init (int ifindex, gboolean check_scan);
 
-GType nm_wifi_utils_wext_get_type (void);
-
-NMWifiUtils *nm_wifi_utils_wext_new (int ifindex, gboolean check_scan);
-
-gboolean nm_wifi_utils_wext_is_wifi (const char *iface);
+gboolean wifi_wext_is_wifi (const char *iface);
 
 #endif  /* __WIFI_UTILS_WEXT_H__ */
diff --git a/src/platform/wifi/wifi-utils.c b/src/platform/wifi/wifi-utils.c
new file mode 100644
index 00000000..b3dd92ba
--- /dev/null
+++ b/src/platform/wifi/wifi-utils.c
@@ -0,0 +1,231 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager -- Network link manager
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2005 - 2011 Red Hat, Inc.
+ * Copyright (C) 2006 - 2008 Novell, Inc.
+ */
+
+#include "nm-default.h"
+
+#include "wifi-utils.h"
+
+#include <sys/stat.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+
+#include "wifi-utils-private.h"
+#include "wifi-utils-nl80211.h"
+#if HAVE_WEXT
+#include "wifi-utils-wext.h"
+#endif
+#include "nm-core-utils.h"
+
+#include "platform/nm-platform-utils.h"
+
+gpointer
+wifi_data_new (const WifiDataClass *klass, int ifindex)
+{
+	WifiData *data;
+
+	nm_assert (klass);
+	nm_assert (klass->struct_size > sizeof (WifiData));
+
+	data = g_malloc0 (klass->struct_size);
+	data->klass = klass;
+	data->ifindex = ifindex;
+	return data;
+}
+
+/*****************************************************************************/
+
+WifiData *
+wifi_utils_init (int ifindex, gboolean check_scan)
+{
+	WifiData *ret;
+
+	g_return_val_if_fail (ifindex > 0, NULL);
+
+	ret = wifi_nl80211_init (ifindex);
+	if (ret == NULL) {
+#if HAVE_WEXT
+		ret = wifi_wext_init (ifindex, check_scan);
+#endif
+	}
+	return ret;
+}
+
+int
+wifi_utils_get_ifindex (WifiData *data)
+{
+	g_return_val_if_fail (data != NULL, -1);
+
+	return data->ifindex;
+}
+
+NMDeviceWifiCapabilities
+wifi_utils_get_caps (WifiData *data)
+{
+	g_return_val_if_fail (data != NULL, NM_WIFI_DEVICE_CAP_NONE);
+
+	return data->caps;
+}
+
+NM80211Mode
+wifi_utils_get_mode (WifiData *data)
+{
+	g_return_val_if_fail (data != NULL, NM_802_11_MODE_UNKNOWN);
+	return data->klass->get_mode (data);
+}
+
+gboolean
+wifi_utils_set_mode (WifiData *data, const NM80211Mode mode)
+{
+	g_return_val_if_fail (data != NULL, FALSE);
+	g_return_val_if_fail (   (mode == NM_802_11_MODE_INFRA)
+	                      || (mode == NM_802_11_MODE_AP)
+	                      || (mode == NM_802_11_MODE_ADHOC), FALSE);
+
+	/* nl80211 probably doesn't need this */
+	return data->klass->set_mode ? data->klass->set_mode (data, mode) : TRUE;
+}
+
+gboolean
+wifi_utils_set_powersave (WifiData *data, guint32 powersave)
+{
+	g_return_val_if_fail (data != NULL, FALSE);
+
+	return data->klass->set_powersave ? data->klass->set_powersave (data, powersave) : TRUE;
+}
+
+gboolean
+wifi_utils_set_wake_on_wlan (WifiData *data, NMSettingWirelessWakeOnWLan wowl)
+{
+	g_return_val_if_fail (data != NULL, FALSE);
+
+	return data->klass->set_wake_on_wlan ?
+	       data->klass->set_wake_on_wlan (data, wowl) : FALSE;
+}
+
+guint32
+wifi_utils_get_freq (WifiData *data)
+{
+	g_return_val_if_fail (data != NULL, 0);
+	return data->klass->get_freq (data);
+}
+
+guint32
+wifi_utils_find_freq (WifiData *data, const guint32 *freqs)
+{
+	g_return_val_if_fail (data != NULL, 0);
+	g_return_val_if_fail (freqs != NULL, 0);
+	return data->klass->find_freq (data, freqs);
+}
+
+gboolean
+wifi_utils_get_bssid (WifiData *data, guint8 *out_bssid)
+{
+	g_return_val_if_fail (data != NULL, FALSE);
+	g_return_val_if_fail (out_bssid != NULL, FALSE);
+
+	memset (out_bssid, 0, ETH_ALEN);
+	return data->klass->get_bssid (data, out_bssid);
+}
+
+guint32
+wifi_utils_get_rate (WifiData *data)
+{
+	g_return_val_if_fail (data != NULL, 0);
+	return data->klass->get_rate (data);
+}
+
+int
+wifi_utils_get_qual (WifiData *data)
+{
+	g_return_val_if_fail (data != NULL, 0);
+	return data->klass->get_qual (data);
+}
+
+gboolean
+wifi_utils_get_wowlan (WifiData *data)
+{
+	g_return_val_if_fail (data != NULL, 0);
+
+	if (!data->klass->get_wowlan)
+		return FALSE;
+	return data->klass->get_wowlan (data);
+}
+
+void
+wifi_utils_unref (WifiData *data)
+{
+	g_return_if_fail (data != NULL);
+
+	data->klass->deinit (data);
+	g_free (data);
+}
+
+gboolean
+wifi_utils_is_wifi (int dirfd, const char *ifname)
+{
+	g_return_val_if_fail (dirfd >= 0, FALSE);
+
+	if (faccessat (dirfd, "phy80211", F_OK, 0) == 0)
+		return TRUE;
+#if HAVE_WEXT
+	if (wifi_wext_is_wifi (ifname))
+		return TRUE;
+#endif
+	return FALSE;
+}
+
+/* OLPC Mesh-only functions */
+
+guint32
+wifi_utils_get_mesh_channel (WifiData *data)
+{
+	g_return_val_if_fail (data != NULL, FALSE);
+	g_return_val_if_fail (data->klass->get_mesh_channel != NULL, FALSE);
+	return data->klass->get_mesh_channel (data);
+}
+
+gboolean
+wifi_utils_set_mesh_channel (WifiData *data, guint32 channel)
+{
+	g_return_val_if_fail (data != NULL, FALSE);
+	g_return_val_if_fail (channel <= 13, FALSE);
+	g_return_val_if_fail (data->klass->set_mesh_channel != NULL, FALSE);
+	return data->klass->set_mesh_channel (data, channel);
+}
+
+gboolean
+wifi_utils_set_mesh_ssid (WifiData *data, const guint8 *ssid, gsize len)
+{
+	g_return_val_if_fail (data != NULL, FALSE);
+	g_return_val_if_fail (data->klass->set_mesh_ssid != NULL, FALSE);
+	return data->klass->set_mesh_ssid (data, ssid, len);
+}
+
+gboolean
+wifi_utils_indicate_addressing_running (WifiData *data, gboolean running)
+{
+	g_return_val_if_fail (data != NULL, FALSE);
+	if (data->klass->indicate_addressing_running)
+		return data->klass->indicate_addressing_running (data, running);
+	return FALSE;
+}
+
diff --git a/src/platform/wifi/wifi-utils.h b/src/platform/wifi/wifi-utils.h
new file mode 100644
index 00000000..c69561de
--- /dev/null
+++ b/src/platform/wifi/wifi-utils.h
@@ -0,0 +1,79 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager -- Network link manager
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2005 - 2011 Red Hat, Inc.
+ * Copyright (C) 2006 - 2008 Novell, Inc.
+ */
+
+#ifndef __WIFI_UTILS_H__
+#define __WIFI_UTILS_H__
+
+#include <net/ethernet.h>
+
+#include "nm-dbus-interface.h"
+#include "nm-setting-wireless.h"
+
+typedef struct WifiData WifiData;
+
+gboolean wifi_utils_is_wifi (int dirfd, const char *ifname);
+
+WifiData *wifi_utils_init (int ifindex, gboolean check_scan);
+
+int wifi_utils_get_ifindex (WifiData *data);
+
+void wifi_utils_unref (WifiData *data);
+
+NMDeviceWifiCapabilities wifi_utils_get_caps (WifiData *data);
+
+NM80211Mode wifi_utils_get_mode (WifiData *data);
+
+gboolean wifi_utils_set_mode (WifiData *data, const NM80211Mode mode);
+
+/* Returns frequency in MHz */
+guint32 wifi_utils_get_freq (WifiData *data);
+
+/* Return the first supported frequency in the zero-terminated list.
+ * Frequencies are specified in MHz. */
+guint32 wifi_utils_find_freq (WifiData *data, const guint32 *freqs);
+
+/* out_bssid must be ETH_ALEN bytes */
+gboolean wifi_utils_get_bssid (WifiData *data, guint8 *out_bssid);
+
+/* Returns current bitrate in Kbps */
+guint32 wifi_utils_get_rate (WifiData *data);
+
+/* Returns quality 0 - 100% on succes, or -1 on error */
+int wifi_utils_get_qual (WifiData *data);
+
+/* Tells the driver DHCP or SLAAC is running */
+gboolean wifi_utils_indicate_addressing_running (WifiData *data, gboolean running);
+
+/* Returns true if WoWLAN is enabled on device */
+gboolean wifi_utils_get_wowlan (WifiData *data);
+
+gboolean wifi_utils_set_powersave (WifiData *data, guint32 powersave);
+
+gboolean wifi_utils_set_wake_on_wlan (WifiData *data, NMSettingWirelessWakeOnWLan wowl);
+
+/* OLPC Mesh-only functions */
+guint32 wifi_utils_get_mesh_channel (WifiData *data);
+
+gboolean wifi_utils_set_mesh_channel (WifiData *data, guint32 channel);
+
+gboolean wifi_utils_set_mesh_ssid (WifiData *data, const guint8 *ssid, gsize len);
+
+#endif  /* __WIFI_UTILS_H__ */
diff --git a/src/platform/wpan/nm-wpan-utils.c b/src/platform/wpan/nm-wpan-utils.c
deleted file mode 100644
index 0544539a..00000000
--- a/src/platform/wpan/nm-wpan-utils.c
+++ /dev/null
@@ -1,286 +0,0 @@
-/* NetworkManager -- Network link manager
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Copyright (C) 2018 Red Hat, Inc.
- */
-
-#include "nm-default.h"
-
-#include "nm-wpan-utils.h"
-
-#include "platform/linux/nl802154.h"
-#include "platform/nm-netlink.h"
-
-#define _NMLOG_PREFIX_NAME "wpan-nl802154"
-#define _NMLOG(level, domain, ...) \
-	G_STMT_START { \
-		nm_log ((level), (domain), NULL, NULL, \
-		        "%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
-		        _NMLOG_PREFIX_NAME \
-		        _NM_UTILS_MACRO_REST(__VA_ARGS__)); \
-	} G_STMT_END
-
-/*****************************************************************************/
-
-struct NMWpanUtils {
-        GObject parent;
-	int ifindex;
-	struct nl_sock *nl_sock;
-	int id;
-};
-
-typedef struct {
-        GObjectClass parent;
-} NMWpanUtilsClass;
-
-G_DEFINE_TYPE (NMWpanUtils, nm_wpan_utils, G_TYPE_OBJECT)
-
-/*****************************************************************************/
-
-static int
-ack_handler (struct nl_msg *msg, void *arg)
-{
-	int *done = arg;
-	*done = 1;
-	return NL_STOP;
-}
-
-static int
-finish_handler (struct nl_msg *msg, void *arg)
-{
-	int *done = arg;
-	*done = 1;
-	return NL_SKIP;
-}
-
-static int
-error_handler (struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg)
-{
-	int *done = arg;
-	*done = err->error;
-	return NL_SKIP;
-}
-
-static struct nl_msg *
-_nl802154_alloc_msg (int id, int ifindex, guint32 cmd, guint32 flags)
-{
-	nm_auto_nlmsg struct nl_msg *msg = NULL;
-
-	msg = nlmsg_alloc ();
-	genlmsg_put (msg, 0, 0, id, 0, flags, cmd, 0);
-	NLA_PUT_U32 (msg, NL802154_ATTR_IFINDEX, ifindex);
-	return g_steal_pointer (&msg);
-
-nla_put_failure:
-	return NULL;
-}
-
-static struct nl_msg *
-nl802154_alloc_msg (NMWpanUtils *self, guint32 cmd, guint32 flags)
-{
-	return _nl802154_alloc_msg (self->id, self->ifindex, cmd, flags);
-}
-
-static int
-_nl802154_send_and_recv (struct nl_sock *nl_sock,
-                         struct nl_msg *msg,
-                         int (*valid_handler) (struct nl_msg *, void *),
-                         void *valid_data)
-{
-	int err;
-	int done = 0;
-	const struct nl_cb cb = {
-		.err_cb     = error_handler,
-		.err_arg    = &done,
-		.finish_cb  = finish_handler,
-		.finish_arg = &done,
-		.ack_cb     = ack_handler,
-		.ack_arg    = &done,
-		.valid_cb   = valid_handler,
-		.valid_arg  = valid_data,
-	};
-
-	g_return_val_if_fail (msg != NULL, -ENOMEM);
-
-	err = nl_send_auto (nl_sock, msg);
-	if (err < 0)
-		return err;
-
-	/* Loop until one of our NL callbacks says we're done; on success
-	 * done will be 1, on error it will be < 0.
-	 */
-	while (!done) {
-		err = nl_recvmsgs (nl_sock, &cb);
-		if (err < 0 && err != -EAGAIN) {
-			_LOGW (LOGD_PLATFORM, "nl_recvmsgs() error: (%d) %s",
-			       err, nl_geterror (err));
-			break;
-		}
-	}
-
-	if (err >= 0 && done < 0)
-		err = done;
-	return err;
-}
-
-static int
-nl802154_send_and_recv (NMWpanUtils *self,
-                        struct nl_msg *msg,
-                        int (*valid_handler) (struct nl_msg *, void *),
-                        void *valid_data)
-{
-	return _nl802154_send_and_recv (self->nl_sock, msg,
-	                                valid_handler, valid_data);
-}
-
-struct nl802154_interface {
-	guint16 pan_id;
-	guint16 short_addr;
-
-	gboolean valid;
-};
-
-static int
-nl802154_get_interface_handler (struct nl_msg *msg, void *arg)
-{
-	struct nl802154_interface *info = arg;
-	struct genlmsghdr *gnlh = nlmsg_data (nlmsg_hdr (msg));
-	struct nlattr *tb[NL802154_ATTR_MAX + 1] = { 0, };
-	static const struct nla_policy nl802154_policy[NL802154_ATTR_MAX + 1] = {
-		[NL802154_ATTR_PAN_ID] =            { .type = NLA_U16 },
-		[NL802154_ATTR_SHORT_ADDR] =        { .type = NLA_U16 },
-	};
-
-	if (nla_parse (tb, NL802154_ATTR_MAX, genlmsg_attrdata (gnlh, 0),
-	               genlmsg_attrlen (gnlh, 0), nl802154_policy) < 0)
-	return NL_SKIP;
-
-	if (tb[NL802154_ATTR_PAN_ID])
-		info->pan_id = le16toh (nla_get_u16 (tb[NL802154_ATTR_PAN_ID]));
-
-	if (tb[NL802154_ATTR_SHORT_ADDR])
-		info->short_addr = le16toh (nla_get_u16 (tb[NL802154_ATTR_SHORT_ADDR]));
-
-	info->valid = TRUE;
-
-	return NL_SKIP;
-}
-
-static void
-nl802154_get_interface (NMWpanUtils *self,
-                        struct nl802154_interface *interface)
-{
-	nm_auto_nlmsg struct nl_msg *msg = NULL;
-
-	memset (interface, 0, sizeof (*interface));
-
-	msg = nl802154_alloc_msg (self, NL802154_CMD_GET_INTERFACE, 0);
-
-	nl802154_send_and_recv (self, msg, nl802154_get_interface_handler, interface);
-}
-
-/*****************************************************************************/
-
-guint16
-nm_wpan_utils_get_pan_id (NMWpanUtils *self)
-{
-	struct nl802154_interface interface;
-
-	nl802154_get_interface (self, &interface);
-
-	return interface.pan_id;
-}
-
-gboolean
-nm_wpan_utils_set_pan_id (NMWpanUtils *self, guint16 pan_id)
-{
-	nm_auto_nlmsg struct nl_msg *msg = NULL;
-	int err;
-
-	g_return_val_if_fail (self != NULL, FALSE);
-
-	msg = nl802154_alloc_msg (self, NL802154_CMD_SET_PAN_ID, 0);
-	NLA_PUT_U16 (msg, NL802154_ATTR_PAN_ID, htole16 (pan_id));
-	err = nl802154_send_and_recv (self, msg, NULL, NULL);
-	return err >= 0;
-
-nla_put_failure:
-	return FALSE;
-}
-
-guint16
-nm_wpan_utils_get_short_addr (NMWpanUtils *self)
-{
-	struct nl802154_interface interface;
-
-	nl802154_get_interface (self, &interface);
-
-	return interface.short_addr;
-}
-
-gboolean
-nm_wpan_utils_set_short_addr (NMWpanUtils *self, guint16 short_addr)
-{
-	nm_auto_nlmsg struct nl_msg *msg = NULL;
-	int err;
-
-	g_return_val_if_fail (self != NULL, FALSE);
-
-	msg = nl802154_alloc_msg (self, NL802154_CMD_SET_SHORT_ADDR, 0);
-	NLA_PUT_U16 (msg, NL802154_ATTR_SHORT_ADDR, htole16 (short_addr));
-	err = nl802154_send_and_recv (self, msg, NULL, NULL);
-	return err >= 0;
-
-nla_put_failure:
-	return FALSE;
-}
-
-/*****************************************************************************/
-
-static void
-nm_wpan_utils_init (NMWpanUtils *self)
-{
-}
-
-static void
-nm_wpan_utils_class_init (NMWpanUtilsClass *klass)
-{
-}
-
-NMWpanUtils *
-nm_wpan_utils_new (int ifindex, struct nl_sock *genl, gboolean check_scan)
-{
-	NMWpanUtils *self;
-	int id;
-
-	g_return_val_if_fail (ifindex > 0, NULL);
-
-	if (!genl)
-		return NULL;
-
-	id = genl_ctrl_resolve (genl, "nl802154");
-	if (id < 0) {
-		_LOGD (LOGD_PLATFORM, "genl_ctrl_resolve: failed to resolve \"nl802154\"");
-		return NULL;
-	}
-
-	self = g_object_new (NM_TYPE_WPAN_UTILS, NULL);
-	self->ifindex = ifindex;
-	self->nl_sock = genl;
-	self->id = id;
-
-	return self;
-}
diff --git a/src/platform/wpan/nm-wpan-utils.h b/src/platform/wpan/nm-wpan-utils.h
deleted file mode 100644
index f7d0c03e..00000000
--- a/src/platform/wpan/nm-wpan-utils.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/* NetworkManager -- Network link manager
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Copyright (C) 2018 Red Hat, Inc.
- */
-
-#ifndef __WPAN_UTILS_H__
-#define __WPAN_UTILS_H__
-
-#include <net/ethernet.h>
-
-#include "nm-dbus-interface.h"
-#include "platform/nm-netlink.h"
-
-typedef struct NMWpanUtils NMWpanUtils;
-
-#define NM_TYPE_WPAN_UTILS            (nm_wpan_utils_get_type ())
-#define NM_WPAN_UTILS(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_WPAN_UTILS, NMWpanUtils))
-#define NM_WPAN_UTILS_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_WPAN_UTILS, NMWpanUtilsClass))
-#define NM_IS_WPAN_UTILS(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_WPAN_UTILS))
-#define NM_IS_WPAN_UTILS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_WPAN_UTILS))
-#define NM_WPAN_UTILS_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_WPAN_UTILS, NMWpanUtilsClass))
-
-GType nm_wpan_utils_get_type (void);
-
-NMWpanUtils *nm_wpan_utils_new (int ifindex, struct nl_sock *genl, gboolean check_scan);
-
-guint16 nm_wpan_utils_get_pan_id (NMWpanUtils *self);
-gboolean nm_wpan_utils_set_pan_id (NMWpanUtils *self, guint16 pan_id);
-
-guint16 nm_wpan_utils_get_short_addr (NMWpanUtils *self);
-gboolean nm_wpan_utils_set_short_addr (NMWpanUtils *self, guint16 short_addr);
-
-#endif  /* __WPAN_UTILS_H__ */