summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2019-09-30 13:49:20 +0200
committerMichael Biebl <biebl@debian.org>2019-09-30 13:49:20 +0200
commitd0425f68f7ee83a1dc5a6ad3688627c1b472a58b (patch)
tree978af126d9871da5f3bb07ad4180b30cefa5feb6 /src
parent555dfa331e295a3a687a7cc6870e1349ffed8f26 (diff)
New upstream version 1.20.4 upstream/1.20.4
Diffstat (limited to 'src')
-rw-r--r--src/devices/nm-device.c32
-rw-r--r--src/devices/wifi/nm-device-iwd.c1
-rw-r--r--src/devices/wifi/nm-device-olpc-mesh.c53
-rw-r--r--src/devices/wifi/nm-device-wifi-p2p.c1
-rw-r--r--src/devices/wifi/nm-device-wifi.c1
-rw-r--r--src/dhcp/nm-dhcp-nettools.c49
-rw-r--r--src/initrd/nm-initrd-generator.c4
-rw-r--r--src/initrd/nm-initrd-generator.h2
-rw-r--r--src/initrd/nmi-cmdline-reader.c62
-rw-r--r--src/initrd/tests/test-cmdline-reader.c153
-rw-r--r--src/platform/nm-linux-platform.c10
-rw-r--r--src/platform/wifi/nm-wifi-utils-nl80211.c67
-rw-r--r--src/settings/nm-settings.c40
-rw-r--r--src/supplicant/nm-supplicant-settings-verify.c2
14 files changed, 338 insertions, 139 deletions
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index 823cf48a..67e23b8f 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -3933,12 +3933,18 @@ device_link_changed (NMDevice *self)
 	if (priv->up && (!was_up || seen_down)) {
 		/* the link was down and just came up. That happens for example, while changing MTU.
 		 * We must restore IP configuration. */
-		if (!ip_config_merge_and_apply (self, AF_INET, TRUE))
-			_LOGW (LOGD_IP4, "failed applying IP4 config after link comes up again");
+		if (NM_IN_SET (priv->ip_state_4, NM_DEVICE_IP_STATE_CONF,
+		                                 NM_DEVICE_IP_STATE_DONE)) {
+			if (!ip_config_merge_and_apply (self, AF_INET, TRUE))
+				_LOGW (LOGD_IP4, "failed applying IP4 config after link comes up again");
+		}
 
 		priv->linklocal6_dad_counter = 0;
-		if (!ip_config_merge_and_apply (self, AF_INET6, TRUE))
-			_LOGW (LOGD_IP6, "failed applying IP6 config after link comes up again");
+		if (NM_IN_SET (priv->ip_state_6, NM_DEVICE_IP_STATE_CONF,
+		                                 NM_DEVICE_IP_STATE_DONE)) {
+			if (!ip_config_merge_and_apply (self, AF_INET6, TRUE))
+				_LOGW (LOGD_IP6, "failed applying IP6 config after link comes up again");
+		}
 	}
 
 	if (update_unmanaged_specs)
@@ -7733,8 +7739,8 @@ dhcp4_dad_cb (NMDevice *self, NMIP4Config **configs, gboolean success)
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
 
 	if (success) {
-		nm_dhcp_client_accept (priv->dhcp4.client, NULL);
-		nm_device_activate_schedule_ip_config_result (self, AF_INET, NM_IP_CONFIG_CAST (configs[1]));
+		nm_device_activate_schedule_ip_config_result (self, AF_INET,
+		                                              NM_IP_CONFIG_CAST (configs[1]));
 	} else {
 		nm_dhcp_client_decline (priv->dhcp4.client, "Address conflict detected", NULL);
 		nm_device_ip_method_failed (self, AF_INET,
@@ -9365,7 +9371,7 @@ _commit_mtu (NMDevice *self, const NMIP4Config *config)
 		s_ip6 = nm_device_get_applied_setting (self, NM_TYPE_SETTING_IP6_CONFIG);
 		if (   s_ip6
 		    && !NM_IN_STRSET (nm_setting_ip_config_get_method (s_ip6),
-		                      NM_SETTING_IP6_CONFIG_METHOD_IGNORE
+		                      NM_SETTING_IP6_CONFIG_METHOD_IGNORE,
 		                      NM_SETTING_IP6_CONFIG_METHOD_DISABLED)) {
 			/* the interface has IPv6 enabled. The MTU with IPv6 cannot be smaller
 			 * then 1280.
@@ -10722,6 +10728,18 @@ activate_stage5_ip_config_result_4 (NMDevice *self)
 		}
 	}
 
+	if (priv->dhcp4.client) {
+		gs_free_error GError *error = NULL;
+
+		if (!nm_dhcp_client_accept (priv->dhcp4.client, &error)) {
+			_LOGW (LOGD_DHCP4,
+			       "Activation: Stage 5 of 5 (IPv4 Commit) error accepting lease: %s",
+			       error->message);
+			nm_device_ip_method_failed (self, AF_INET, NM_DEVICE_STATE_REASON_DHCP_ERROR);
+			return;
+		}
+	}
+
 	/* If IPv4 wasn't the first to complete, and DHCP was used, then ensure
 	 * dispatcher scripts get the DHCP lease information.
 	 */
diff --git a/src/devices/wifi/nm-device-iwd.c b/src/devices/wifi/nm-device-iwd.c
index 9cfe5f70..6ef9ef94 100644
--- a/src/devices/wifi/nm-device-iwd.c
+++ b/src/devices/wifi/nm-device-iwd.c
@@ -2061,6 +2061,7 @@ can_reapply_change (NMDevice *device,
 		return nm_device_hash_check_invalid_keys (diffs,
 		                                          NM_SETTING_WIRELESS_SETTING_NAME,
 		                                          error,
+		                                          NM_SETTING_WIRELESS_SEEN_BSSIDS, /* ignored */
 		                                          NM_SETTING_WIRELESS_MTU); /* reapplied with IP config */
 	}
 
diff --git a/src/devices/wifi/nm-device-olpc-mesh.c b/src/devices/wifi/nm-device-olpc-mesh.c
index 3c865c55..aa50c420 100644
--- a/src/devices/wifi/nm-device-olpc-mesh.c
+++ b/src/devices/wifi/nm-device-olpc-mesh.c
@@ -82,9 +82,9 @@ get_autoconnect_allowed (NMDevice *device)
 	NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (device);
 	NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self);
 
-	/* We shall always have a companion if we're >= DISCONENCTED, and this
-	 * ought not be called until then. */
-	g_return_val_if_fail (priv->companion, FALSE);
+	/* We can't even connect if we don't have a companion yet. */
+	if (!priv->companion)
+		return FALSE;
 
 	/* We must not attempt to autoconnect when the companion is connected or
 	 * connecting, * because we'd tear down its connection. */
@@ -174,17 +174,28 @@ act_stage1_prepare (NMDevice *device, NMDeviceStateReason *out_failure_reason)
 	return NM_ACT_STAGE_RETURN_SUCCESS;
 }
 
-static void
+static gboolean
 _mesh_set_channel (NMDeviceOlpcMesh *self, guint32 channel)
 {
 	NMPlatform *platform;
 	int ifindex = nm_device_get_ifindex (NM_DEVICE (self));
+	guint32 old_channel;
 
 	platform = nm_device_get_platform (NM_DEVICE (self));
-	if (nm_platform_mesh_get_channel (platform, ifindex) != channel) {
-		if (nm_platform_mesh_set_channel (platform, ifindex, channel))
-			_notify (self, PROP_ACTIVE_CHANNEL);
-	}
+	old_channel = nm_platform_mesh_get_channel (platform, ifindex);
+
+	if (channel == 0)
+		channel = old_channel;
+
+	/* We want to call this even if the channel number is the same,
+	 * because that actually starts the mesh with the configured mesh ID. */
+	if (!nm_platform_mesh_set_channel (platform, ifindex, channel))
+		return FALSE;
+
+	if (old_channel != channel)
+		_notify (self, PROP_ACTIVE_CHANNEL);
+
+	return TRUE;
 }
 
 static NMActStageReturn
@@ -192,27 +203,35 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason)
 {
 	NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (device);
 	NMSettingOlpcMesh *s_mesh;
-	guint32 channel;
 	GBytes *ssid;
 	const char *anycast_addr;
+	gboolean success;
 
 	s_mesh = nm_device_get_applied_setting (device, NM_TYPE_SETTING_OLPC_MESH);
 
 	g_return_val_if_fail (s_mesh, NM_ACT_STAGE_RETURN_FAILURE);
 
-	channel = nm_setting_olpc_mesh_get_channel (s_mesh);
-	if (channel != 0)
-		_mesh_set_channel (self, channel);
-
 	ssid = nm_setting_olpc_mesh_get_ssid (s_mesh);
-	nm_platform_mesh_set_ssid (nm_device_get_platform (device),
-	                           nm_device_get_ifindex (device),
-	                           g_bytes_get_data (ssid, NULL),
-	                           g_bytes_get_size (ssid));
+	nm_device_take_down (NM_DEVICE (self), TRUE);
+	success = nm_platform_mesh_set_ssid (nm_device_get_platform (device),
+	                                     nm_device_get_ifindex (device),
+	                                     g_bytes_get_data (ssid, NULL),
+	                                     g_bytes_get_size (ssid));
+	nm_device_bring_up (NM_DEVICE (self), TRUE, NULL);
+	if (!success) {
+		_LOGW (LOGD_WIFI, "Unable to set the mesh ID");
+		return NM_ACT_STAGE_RETURN_FAILURE;
+	}
 
 	anycast_addr = nm_setting_olpc_mesh_get_dhcp_anycast_address (s_mesh);
 	nm_device_set_dhcp_anycast_address (device, anycast_addr);
 
+	if (!_mesh_set_channel (self, nm_setting_olpc_mesh_get_channel (s_mesh))) {
+		_LOGW (LOGD_WIFI, "Unable to set the mesh channel");
+		return NM_ACT_STAGE_RETURN_FAILURE;
+	}
+
+
 	return NM_ACT_STAGE_RETURN_SUCCESS;
 }
 
diff --git a/src/devices/wifi/nm-device-wifi-p2p.c b/src/devices/wifi/nm-device-wifi-p2p.c
index c5826e24..c9e6189b 100644
--- a/src/devices/wifi/nm-device-wifi-p2p.c
+++ b/src/devices/wifi/nm-device-wifi-p2p.c
@@ -828,6 +828,7 @@ supplicant_group_iface_state_cb (NMSupplicantInterface *iface,
 
 static void
 supplicant_group_iface_group_finished_cb (NMSupplicantInterface *iface,
+                                          const char *iface_path,
                                           void *user_data)
 {
 	NMDeviceWifiP2P *self = NM_DEVICE_WIFI_P2P (user_data);
diff --git a/src/devices/wifi/nm-device-wifi.c b/src/devices/wifi/nm-device-wifi.c
index 2ffba47a..8c80b0aa 100644
--- a/src/devices/wifi/nm-device-wifi.c
+++ b/src/devices/wifi/nm-device-wifi.c
@@ -3254,6 +3254,7 @@ can_reapply_change (NMDevice *device,
 		return nm_device_hash_check_invalid_keys (diffs,
 		                                          NM_SETTING_WIRELESS_SETTING_NAME,
 		                                          error,
+		                                          NM_SETTING_WIRELESS_SEEN_BSSIDS, /* ignored */
 		                                          NM_SETTING_WIRELESS_MTU, /* reapplied with IP config */
 		                                          NM_SETTING_WIRELESS_WAKE_ON_WLAN);
 	}
diff --git a/src/dhcp/nm-dhcp-nettools.c b/src/dhcp/nm-dhcp-nettools.c
index 9a0c6906..6140a916 100644
--- a/src/dhcp/nm-dhcp-nettools.c
+++ b/src/dhcp/nm-dhcp-nettools.c
@@ -368,10 +368,13 @@ lease_parse_address (NDhcp4ClientLease *lease,
 {
 	char addr_str[NM_UTILS_INET_ADDRSTRLEN];
 	const gint64 ts = nm_utils_get_monotonic_timestamp_ns ();
+	const gint64 ts_clock_boottime = nm_utils_monotonic_timestamp_as_boottime (ts, 1);
 	struct in_addr a_address;
 	struct in_addr a_netmask;
 	guint32 a_plen;
-	guint64 a_lifetime;
+	guint64 nettools_lifetime;
+	gint64 a_lifetime;
+	gint64 a_expiry;
 
 	n_dhcp4_client_lease_get_yiaddr (lease, &a_address);
 	if (a_address.s_addr == INADDR_ANY) {
@@ -380,7 +383,29 @@ lease_parse_address (NDhcp4ClientLease *lease,
 	}
 
 	/* n_dhcp4_client_lease_get_lifetime() never fails */
-	n_dhcp4_client_lease_get_lifetime (lease, &a_lifetime);
+	n_dhcp4_client_lease_get_lifetime (lease, &nettools_lifetime);
+	/* FIXME: n_dhcp4_client_lease_get_lifetime() returns the time in nsec of CLOCK_BOOTTIME.
+	 * We want to retrieve the original lifetime value in seconds, so we approximate it in a_lifetime.
+	 * Use a nettools API to retrieve the original value as passed by the server.
+	 */
+	if (nettools_lifetime == G_MAXUINT64) {
+		a_lifetime = NM_PLATFORM_LIFETIME_PERMANENT;
+		a_expiry = NM_PLATFORM_LIFETIME_PERMANENT;
+	} else {
+		gint64 ts_time = time (NULL);
+
+		a_lifetime = ((gint64) nettools_lifetime - ts_clock_boottime) / NM_UTILS_NS_PER_SECOND;
+		/* A lease time of 0 is allowed on some dhcp servers, so, let's accept it. */
+		if (a_lifetime < 0)
+			a_lifetime = 0;
+		else if (a_lifetime > NM_PLATFORM_LIFETIME_PERMANENT)
+			a_lifetime = NM_PLATFORM_LIFETIME_PERMANENT - 1;
+
+		if (ts_time > NM_PLATFORM_LIFETIME_PERMANENT - a_lifetime)
+			a_expiry = NM_PLATFORM_LIFETIME_PERMANENT - 1;
+		else
+			a_expiry = ts_time + a_lifetime;
+	}
 
 	if (!lease_get_in_addr (lease, NM_DHCP_OPTION_DHCP4_SUBNET_MASK, &a_netmask)) {
 		nm_utils_error_set_literal (error, NM_UTILS_ERROR_UNKNOWN, "could not get netmask from lease");
@@ -400,12 +425,20 @@ lease_parse_address (NDhcp4ClientLease *lease,
 	                           NM_DHCP_OPTION_DHCP4_SUBNET_MASK,
 	                           nm_utils_inet4_ntop (a_netmask.s_addr, addr_str));
 
-	LOG_LEASE (LOGD_DHCP4, "expires in %u seconds",
-	           (guint) ((a_lifetime - ts)/1000000000));
+	LOG_LEASE (LOGD_DHCP4, "%s '%u' seconds (at %lld)",
+	           nm_dhcp_option_request_string (_nm_dhcp_option_dhcp4_options,
+	                                          NM_DHCP_OPTION_DHCP4_IP_ADDRESS_LEASE_TIME),
+	           (guint) a_lifetime,
+	           (long long) a_expiry);
 	nm_dhcp_option_add_option_u64 (options,
 	                               _nm_dhcp_option_dhcp4_options,
 	                               NM_DHCP_OPTION_DHCP4_IP_ADDRESS_LEASE_TIME,
-	                               (guint64) (a_lifetime / 1000000000));
+	                               (guint64) a_lifetime);
+
+	nm_dhcp_option_add_option_u64 (options,
+	                               _nm_dhcp_option_dhcp4_options,
+	                               NM_DHCP_OPTION_DHCP4_NM_EXPIRY,
+	                               (guint64) a_expiry);
 
 	nm_ip4_config_add_address (ip4_config,
 	                           &((const NMPlatformIP4Address) {
@@ -413,9 +446,9 @@ lease_parse_address (NDhcp4ClientLease *lease,
 	                                   .peer_address = a_address.s_addr,
 	                                   .plen         = a_plen,
 	                                   .addr_source  = NM_IP_CONFIG_SOURCE_DHCP,
-	                                   .timestamp    = ts / 1000000000,
-	                                   .lifetime     = (a_lifetime - ts) / 1000000000,
-	                                   .preferred    = (a_lifetime - ts) / 1000000000,
+	                                   .timestamp    = ts / NM_UTILS_NS_PER_SECOND,
+	                                   .lifetime     = a_lifetime,
+	                                   .preferred    = a_lifetime,
 	                           }));
 
 	return TRUE;
diff --git a/src/initrd/nm-initrd-generator.c b/src/initrd/nm-initrd-generator.c
index c916459d..0ff3428e 100644
--- a/src/initrd/nm-initrd-generator.c
+++ b/src/initrd/nm-initrd-generator.c
@@ -95,7 +95,7 @@ main (int argc, char *argv[])
 	int errsv;
 
 	option_context = g_option_context_new ("-- [ip=...] [rd.route=...] [bridge=...] [bond=...] [team=...] [vlan=...] "
-	                                       "[bootdev=...] [nameserver=...] [rd.peerdns=...] [rd.bootif=...] [BOOTIF=...] ... ");
+	                                       "[bootdev=...] [nameserver=...] [rd.peerdns=...] [rd.bootif=...] [BOOTIF=...] [rd.znet=...] ... ");
 
 	g_option_context_set_summary (option_context, "Generate early NetworkManager configuration.");
 	g_option_context_set_description (option_context,
@@ -127,7 +127,7 @@ main (int argc, char *argv[])
 		return 1;
 	}
 
-	connections = nmi_cmdline_reader_parse (sysfs_dir, remaining);
+	connections = nmi_cmdline_reader_parse (sysfs_dir, (const char *const*) remaining);
 	g_hash_table_foreach (connections, output_conn, connections_dir);
 	g_hash_table_destroy (connections);
 
diff --git a/src/initrd/nm-initrd-generator.h b/src/initrd/nm-initrd-generator.h
index dab6fb64..7ff9a92e 100644
--- a/src/initrd/nm-initrd-generator.h
+++ b/src/initrd/nm-initrd-generator.h
@@ -41,6 +41,6 @@ GHashTable *nmi_ibft_read (const char *sysfs_dir);
 
 gboolean nmi_ibft_update_connection_from_nic (NMConnection *connection, GHashTable *nic, GError **error);
 
-GHashTable *nmi_cmdline_reader_parse (const char *sysfs_dir, char **argv);
+GHashTable *nmi_cmdline_reader_parse (const char *sysfs_dir, const char *const*argv);
 
 #endif  /* __NM_INITRD_GENERATOR_H__ */
diff --git a/src/initrd/nmi-cmdline-reader.c b/src/initrd/nmi-cmdline-reader.c
index 7a3af8d6..8ae6aa36 100644
--- a/src/initrd/nmi-cmdline-reader.c
+++ b/src/initrd/nmi-cmdline-reader.c
@@ -690,6 +690,43 @@ parse_rd_peerdns (GHashTable *connections, char *argument)
 }
 
 static void
+parse_rd_znet (GHashTable *connections, char *argument)
+{
+	const char *nettype;
+	const char *subchannels[4] = { 0, 0, 0, 0 };
+	const char *tmp;
+	NMConnection *connection;
+	NMSettingWired *s_wired;
+
+	nettype = get_word (&argument, ',');
+	subchannels[0] = get_word (&argument, ',');
+	subchannels[1] = get_word (&argument, ',');
+	if (!nm_streq0 (nettype, "ctc"))
+		subchannels[2] = get_word (&argument, ',');
+
+	connection = get_conn (connections, NULL, NM_SETTING_WIRED_SETTING_NAME);
+	s_wired = nm_connection_get_setting_wired (connection);
+	g_object_set (s_wired,
+	              NM_SETTING_WIRED_S390_NETTYPE, nettype,
+	              NM_SETTING_WIRED_S390_SUBCHANNELS, &subchannels,
+	              NULL);
+
+	while ((tmp = get_word (&argument, ',')) != NULL) {
+		char *val;
+
+		val = strchr (tmp, '=');
+		if (val) {
+			gs_free char *key = NULL;
+
+			key = g_strndup (tmp, val - tmp);
+			val[0] = '\0';
+			val++;
+			nm_setting_wired_add_s390_option (s_wired, key, val);
+		}
+	}
+}
+
+static void
 _normalize_conn (gpointer key, gpointer value, gpointer user_data)
 {
 	NMConnection *connection = value;
@@ -698,20 +735,24 @@ _normalize_conn (gpointer key, gpointer value, gpointer user_data)
 }
 
 GHashTable *
-nmi_cmdline_reader_parse (const char *sysfs_dir, char **argv)
+nmi_cmdline_reader_parse (const char *sysfs_dir, const char *const*argv)
 {
 	GHashTable *connections;
 	const char *tag;
-	char *argument;
 	gboolean ignore_bootif = FALSE;
 	gboolean neednet = FALSE;
-	char *bootif = NULL;
+	gs_free char *bootif_val = NULL;
 	int i;
 
 	connections = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, g_object_unref);
 
 	for (i = 0; argv[i]; i++) {
-		argument = argv[i];
+		gs_free char *argument_clone = NULL;
+		char *argument;
+
+		argument_clone = g_strdup (argv[i]);
+		argument = argument_clone;
+
 		tag = get_word (&argument, '=');
 		if (strcmp (tag, "ip") == 0)
 			parse_ip (connections, sysfs_dir, argument);
@@ -735,15 +776,20 @@ nmi_cmdline_reader_parse (const char *sysfs_dir, char **argv)
 			ignore_bootif = !_nm_utils_ascii_str_to_bool (argument, TRUE);
 		else if (strcmp (tag, "rd.neednet") == 0)
 			neednet = _nm_utils_ascii_str_to_bool (argument, TRUE);
-		else if (strcasecmp (tag, "BOOTIF") == 0)
-			bootif = argument;
+		else if (strcmp (tag, "rd.znet") == 0)
+			parse_rd_znet (connections, argument);
+		else if (strcasecmp (tag, "BOOTIF") == 0) {
+			nm_clear_g_free (&bootif_val);
+			bootif_val = g_strdup (argument);
+		}
 	}
 
 	if (ignore_bootif)
-		bootif = NULL;
-	if (bootif) {
+		nm_clear_g_free (&bootif_val);
+	if (bootif_val) {
 		NMConnection *connection;
 		NMSettingWired *s_wired;
+		const char *bootif = bootif_val;
 
 		if (   !nm_utils_hwaddr_valid (bootif, ETH_ALEN)
 		    && g_str_has_prefix (bootif, "01-")
diff --git a/src/initrd/tests/test-cmdline-reader.c b/src/initrd/tests/test-cmdline-reader.c
index 9bae73a2..a8a6e825 100644
--- a/src/initrd/tests/test-cmdline-reader.c
+++ b/src/initrd/tests/test-cmdline-reader.c
@@ -39,14 +39,14 @@ static void
 test_auto (void)
 {
 	gs_unref_hashtable GHashTable *connections = NULL;
-	gs_strfreev char **argv = g_strdupv ((char *[]){ "ip=auto", NULL });
+	const char *const*ARGV = NM_MAKE_STRV ("ip=auto");
 	NMConnection *connection;
 	NMSettingConnection *s_con;
 	NMSettingWired *s_wired;
 	NMSettingIPConfig *s_ip4;
 	NMSettingIPConfig *s_ip6;
 
-	connections = nmi_cmdline_reader_parse (TEST_INITRD_DIR "/sysfs", argv);
+	connections = nmi_cmdline_reader_parse (TEST_INITRD_DIR "/sysfs", ARGV);
 	g_assert (connections);
 	g_assert_cmpint (g_hash_table_size (connections), ==, 1);
 
@@ -91,13 +91,13 @@ static void
 test_if_auto_with_mtu (void)
 {
 	gs_unref_hashtable GHashTable *connections = NULL;
-	gs_strfreev char **argv = g_strdupv ((char *[]){ "ip=eth0:auto:1666", NULL });
+	const char *const*ARGV = NM_MAKE_STRV ("ip=eth0:auto:1666");
 	NMConnection *connection;
 	NMSettingWired *s_wired;
 	NMSettingIPConfig *s_ip4;
 	NMSettingIPConfig *s_ip6;
 
-	connections = nmi_cmdline_reader_parse (TEST_INITRD_DIR "/sysfs", argv);
+	connections = nmi_cmdline_reader_parse (TEST_INITRD_DIR "/sysfs", ARGV);
 	g_assert (connections);
 	g_assert_cmpint (g_hash_table_size (connections), ==, 1);
 
@@ -126,12 +126,12 @@ static void
 test_if_dhcp6 (void)
 {
 	gs_unref_hashtable GHashTable *connections = NULL;
-	gs_strfreev char **argv = g_strdupv ((char *[]){ "ip=eth1:dhcp6", NULL });
+	const char *const*ARGV = NM_MAKE_STRV ("ip=eth1:dhcp6");
 	NMConnection *connection;
 	NMSettingIPConfig *s_ip4;
 	NMSettingIPConfig *s_ip6;
 
-	connections = nmi_cmdline_reader_parse (TEST_INITRD_DIR "/sysfs", argv);
+	connections = nmi_cmdline_reader_parse (TEST_INITRD_DIR "/sysfs", ARGV);
 	g_assert (connections);
 	g_assert_cmpint (g_hash_table_size (connections), ==, 1);
 	connection = g_hash_table_lookup (connections, "eth1");
@@ -155,13 +155,13 @@ static void
 test_if_auto_with_mtu_and_mac (void)
 {
 	gs_unref_hashtable GHashTable *connections = NULL;
-	gs_strfreev char **argv = g_strdupv ((char *[]){ "ip=eth2:auto6:2048:00:53:ef:12:34:56", NULL });
+	const char *const*ARGV = NM_MAKE_STRV ("ip=eth2:auto6:2048:00:53:ef:12:34:56");
 	NMConnection *connection;
 	NMSettingWired *s_wired;
 	NMSettingIPConfig *s_ip4;
 	NMSettingIPConfig *s_ip6;
 
-	connections = nmi_cmdline_reader_parse (TEST_INITRD_DIR "/sysfs", argv);
+	connections = nmi_cmdline_reader_parse (TEST_INITRD_DIR "/sysfs", ARGV);
 	g_assert (connections);
 	g_assert_cmpint (g_hash_table_size (connections), ==, 1);
 
@@ -191,16 +191,15 @@ static void
 test_if_ip4_manual (void)
 {
 	gs_unref_hashtable GHashTable *connections = NULL;
-	gs_strfreev char **argv = g_strdupv ((char *[]){
-		"ip=192.0.2.2::192.0.2.1:255.255.255.0:"
-		"hostname0.example.com:eth3::192.0.2.53",
-		"ip=203.0.113.2::203.0.113.1:26:"
-		"hostname1.example.com:eth4", NULL });
+	const char *const*ARGV = NM_MAKE_STRV ("ip=192.0.2.2::192.0.2.1:255.255.255.0:"
+	                                       "hostname0.example.com:eth3::192.0.2.53",
+	                                       "ip=203.0.113.2::203.0.113.1:26:"
+	                                       "hostname1.example.com:eth4");
 	NMConnection *connection;
 	NMSettingIPConfig *s_ip4;
 	NMIPAddress *ip_addr;
 
-	connections = nmi_cmdline_reader_parse (TEST_INITRD_DIR "/sysfs", argv);
+	connections = nmi_cmdline_reader_parse (TEST_INITRD_DIR "/sysfs", ARGV);
 	g_assert (connections);
 	g_assert_cmpint (g_hash_table_size (connections), ==, 2);
 
@@ -248,16 +247,13 @@ static void
 test_if_ip6_manual (void)
 {
 	gs_unref_hashtable GHashTable *connections = NULL;
-	gs_strfreev char **argv = g_strdupv ((char *[]){
-		"ip=[2001:0db8::02]/64::[2001:0db8::01]::"
-		"hostname0.example.com:eth4::[2001:0db8::53]",
-		NULL
-	});
+	const char *const*ARGV = NM_MAKE_STRV ("ip=[2001:0db8::02]/64::[2001:0db8::01]::"
+	                                       "hostname0.example.com:eth4::[2001:0db8::53]");
 	NMConnection *connection;
 	NMSettingIPConfig *s_ip6;
 	NMIPAddress *ip_addr;
 
-	connections = nmi_cmdline_reader_parse (TEST_INITRD_DIR "/sysfs", argv);
+	connections = nmi_cmdline_reader_parse (TEST_INITRD_DIR "/sysfs", ARGV);
 	g_assert (connections);
 	g_assert_cmpint (g_hash_table_size (connections), ==, 1);
 
@@ -286,17 +282,16 @@ static void
 test_multiple (void)
 {
 	gs_unref_hashtable GHashTable *connections = NULL;
-	gs_strfreev char **argv = g_strdupv ((char *[]){ "ip=192.0.2.2:::::eth0",
-	                                                 "ip=[2001:db8::2]:::::eth0",
-	                                                 "BOOTIF=00:53:AB:cd:02:03",
-	                                                 NULL });
+	const char *const*ARGV = NM_MAKE_STRV ("ip=192.0.2.2:::::eth0",
+	                                       "ip=[2001:db8::2]:::::eth0",
+	                                       "BOOTIF=00:53:AB:cd:02:03");
 	NMConnection *connection;
 	NMSettingWired *s_wired;
 	NMSettingIPConfig *s_ip4;
 	NMSettingIPConfig *s_ip6;
 	NMIPAddress *ip_addr;
 
-	connections = nmi_cmdline_reader_parse (TEST_INITRD_DIR "/sysfs", argv);
+	connections = nmi_cmdline_reader_parse (TEST_INITRD_DIR "/sysfs", ARGV);
 	g_assert (connections);
 	g_assert_cmpint (g_hash_table_size (connections), ==, 1);
 
@@ -332,11 +327,10 @@ static void
 test_some_more (void)
 {
 	gs_unref_hashtable GHashTable *connections = NULL;
-	gs_strfreev char **argv = g_strdupv ((char *[]){ "bootdev=eth1", "hail", "nameserver=[2001:DB8:3::53]",
-	                                                 "satan", "nameserver=192.0.2.53", "worship",
-	                                                 "BOOTIF=01-00-53-AB-cd-02-03", "doom", "rd.peerdns=0",
-	                                                 "rd.route=[2001:DB8:3::/48]:[2001:DB8:2::1]:ens10",
-	                                                 NULL });
+	const char *const*ARGV = NM_MAKE_STRV ("bootdev=eth1", "hail", "nameserver=[2001:DB8:3::53]",
+	                                       "satan", "nameserver=192.0.2.53", "worship",
+	                                       "BOOTIF=01-00-53-AB-cd-02-03", "doom", "rd.peerdns=0",
+	                                       "rd.route=[2001:DB8:3::/48]:[2001:DB8:2::1]:ens10");
 	NMConnection *connection;
 	NMSettingConnection *s_con;
 	NMSettingWired *s_wired;
@@ -344,7 +338,7 @@ test_some_more (void)
 	NMSettingIPConfig *s_ip6;
 	NMIPRoute *ip_route;
 
-	connections = nmi_cmdline_reader_parse (TEST_INITRD_DIR "/sysfs", argv);
+	connections = nmi_cmdline_reader_parse (TEST_INITRD_DIR "/sysfs", ARGV);
 	g_assert (connections);
 	g_assert_cmpint (g_hash_table_size (connections), ==, 2);
 
@@ -415,9 +409,9 @@ static void
 test_no_bootif (void)
 {
 	gs_unref_hashtable GHashTable *connections = NULL;
-	gs_strfreev char **argv = g_strdupv ((char *[]){ "BOOTIF=01-00-53-AB-cd-02-03", "rd.bootif=0", NULL });
+	const char *const*ARGV = NM_MAKE_STRV ("BOOTIF=01-00-53-AB-cd-02-03", "rd.bootif=0");
 
-	connections = nmi_cmdline_reader_parse (TEST_INITRD_DIR "/sysfs", argv);
+	connections = nmi_cmdline_reader_parse (TEST_INITRD_DIR "/sysfs", ARGV);
 	g_assert (connections);
 	g_assert_cmpint (g_hash_table_size (connections), ==, 0);
 }
@@ -426,10 +420,9 @@ static void
 test_bond (void)
 {
 	gs_unref_hashtable GHashTable *connections = NULL;
-	gs_strfreev char **argv = g_strdupv ((char *[]){ "rd.route=192.0.2.53::bong0",
-	                                                 "bond=bong0:eth0,eth1:mode=balance-rr",
-	                                                 "nameserver=203.0.113.53",
-	                                                 NULL });
+	const char *const*ARGV = NM_MAKE_STRV ("rd.route=192.0.2.53::bong0",
+	                                       "bond=bong0:eth0,eth1:mode=balance-rr",
+	                                       "nameserver=203.0.113.53");
 	NMConnection *connection;
 	NMSettingConnection *s_con;
 	NMSettingIPConfig *s_ip4;
@@ -438,7 +431,7 @@ test_bond (void)
 	NMIPRoute *ip_route;
 	const char *master_uuid;
 
-	connections = nmi_cmdline_reader_parse (TEST_INITRD_DIR "/sysfs", argv);
+	connections = nmi_cmdline_reader_parse (TEST_INITRD_DIR "/sysfs", ARGV);
 	g_assert (connections);
 	g_assert_cmpint (g_hash_table_size (connections), ==, 3);
 
@@ -509,7 +502,7 @@ static void
 test_bond_default (void)
 {
 	gs_unref_hashtable GHashTable *connections = NULL;
-	gs_strfreev char **argv = g_strdupv ((char *[]){ "bond", NULL });
+	const char *const*ARGV = NM_MAKE_STRV ("bond");
 	NMConnection *connection;
 	NMSettingConnection *s_con;
 	NMSettingIPConfig *s_ip4;
@@ -517,7 +510,7 @@ test_bond_default (void)
 	NMSettingBond *s_bond;
 	const char *master_uuid;
 
-	connections = nmi_cmdline_reader_parse (TEST_INITRD_DIR "/sysfs", argv);
+	connections = nmi_cmdline_reader_parse (TEST_INITRD_DIR "/sysfs", ARGV);
 	g_assert (connections);
 	g_assert_cmpint (g_hash_table_size (connections), ==, 2);
 
@@ -569,7 +562,7 @@ static void
 test_bridge (void)
 {
 	gs_unref_hashtable GHashTable *connections = NULL;
-	gs_strfreev char **argv = g_strdupv ((char *[]){ "bridge=bridge0:eth0,eth1", "rd.route=192.0.2.53::bridge0", NULL });
+	const char *const*ARGV = NM_MAKE_STRV ("bridge=bridge0:eth0,eth1", "rd.route=192.0.2.53::bridge0");
 	NMConnection *connection;
 	NMSettingConnection *s_con;
 	NMSettingIPConfig *s_ip4;
@@ -578,7 +571,7 @@ test_bridge (void)
 	NMIPRoute *ip_route;
 	const char *master_uuid;
 
-	connections = nmi_cmdline_reader_parse (TEST_INITRD_DIR "/sysfs", argv);
+	connections = nmi_cmdline_reader_parse (TEST_INITRD_DIR "/sysfs", ARGV);
 	g_assert (connections);
 	g_assert_cmpint (g_hash_table_size (connections), ==, 3);
 
@@ -646,7 +639,7 @@ static void
 test_bridge_default (void)
 {
 	gs_unref_hashtable GHashTable *connections = NULL;
-	gs_strfreev char **argv = g_strdupv ((char *[]){ "bridge", NULL });
+	const char *const*ARGV = NM_MAKE_STRV ("bridge");
 	NMConnection *connection;
 	NMSettingConnection *s_con;
 	NMSettingIPConfig *s_ip4;
@@ -654,7 +647,7 @@ test_bridge_default (void)
 	NMSettingBridge *s_bridge;
 	const char *master_uuid;
 
-	connections = nmi_cmdline_reader_parse (TEST_INITRD_DIR "/sysfs", argv);
+	connections = nmi_cmdline_reader_parse (TEST_INITRD_DIR "/sysfs", ARGV);
 	g_assert (connections);
 	g_assert_cmpint (g_hash_table_size (connections), ==, 2);
 
@@ -704,7 +697,7 @@ static void
 test_team (void)
 {
 	gs_unref_hashtable GHashTable *connections = NULL;
-	gs_strfreev char **argv = g_strdupv ((char *[]){ "team=team0:eth0,eth1", "ip=team0:dhcp6", NULL });
+	const char *const*ARGV = NM_MAKE_STRV ("team=team0:eth0,eth1", "ip=team0:dhcp6");
 	NMConnection *connection;
 	NMSettingConnection *s_con;
 	NMSettingIPConfig *s_ip4;
@@ -712,7 +705,7 @@ test_team (void)
 	NMSettingTeam *s_team;
 	const char *master_uuid;
 
-	connections = nmi_cmdline_reader_parse (TEST_INITRD_DIR "/sysfs", argv);
+	connections = nmi_cmdline_reader_parse (TEST_INITRD_DIR "/sysfs", ARGV);
 	g_assert (connections);
 	g_assert_cmpint (g_hash_table_size (connections), ==, 3);
 
@@ -774,10 +767,10 @@ static void
 test_ibft (void)
 {
 	gs_unref_hashtable GHashTable *connections = NULL;
-	gs_strfreev char **argv = g_strdupv ((char *[]){ "ip=ibft", NULL });
+	const char *const*ARGV = NM_MAKE_STRV ("ip=ibft");
 	NMConnection *connection;
 
-	connections = nmi_cmdline_reader_parse (TEST_INITRD_DIR "/sysfs", argv);
+	connections = nmi_cmdline_reader_parse (TEST_INITRD_DIR "/sysfs", ARGV);
 	g_assert (connections);
 	g_assert_cmpint (g_hash_table_size (connections), ==, 2);
 
@@ -796,13 +789,72 @@ static void
 test_ignore_extra (void)
 {
 	gs_unref_hashtable GHashTable *connections = NULL;
-	gs_strfreev char **argv = g_strdupv ((char *[]){ "blabla", "extra", "lalala", NULL });
+	const char *const*ARGV = NM_MAKE_STRV ("blabla", "extra", "lalala");
 
-	connections = nmi_cmdline_reader_parse (TEST_INITRD_DIR "/sysfs", argv);
+	connections = nmi_cmdline_reader_parse (TEST_INITRD_DIR "/sysfs", ARGV);
 	g_assert (connections);
 	g_assert_cmpint (g_hash_table_size (connections), ==, 0);
 }
 
+static void
+test_rd_znet (void)
+{
+	gs_unref_hashtable GHashTable *connections = NULL;
+	const char *const*const ARGV = NM_MAKE_STRV ("ip=10.11.12.13::10.11.12.1:24:foo.example.com:enc800:none",
+	                                             "rd.znet=ctc,0.0.0800,0.0.0801,layer2=0,portno=1");
+	GHashTableIter h_iter;
+	NMConnection *connection;
+	NMSettingWired *s_wired;
+	const char *const*v_subchannels;
+	const NMUtilsNamedValue s390_options[] = {
+		{ .name = "layer2", .value_str = "0" },
+		{ .name = "portno", .value_str = "1" },
+	};
+	int i_s390_options_keys;
+
+	connections = nmi_cmdline_reader_parse (TEST_INITRD_DIR "/sysfs", ARGV);
+	g_assert (connections);
+	g_assert_cmpint (g_hash_table_size (connections), ==, 1);
+
+	g_hash_table_iter_init (&h_iter, connections);
+	if (!g_hash_table_iter_next (&h_iter, NULL, (gpointer *) &connection))
+		g_assert_not_reached ();
+	if (g_hash_table_iter_next (&h_iter, NULL, NULL))
+		g_assert_not_reached ();
+
+	g_assert (NM_IS_CONNECTION (connection));
+	s_wired = nm_connection_get_setting_wired (connection);
+	g_assert (NM_IS_SETTING_WIRED (s_wired));
+
+	v_subchannels = nm_setting_wired_get_s390_subchannels (s_wired);
+	g_assert (v_subchannels);
+	g_assert_cmpstr (v_subchannels[0], ==, "0.0.0800");
+	g_assert_cmpstr (v_subchannels[1], ==, "0.0.0801");
+	g_assert_cmpstr (v_subchannels[2], ==, NULL);
+
+	g_assert_cmpint (nm_setting_wired_get_num_s390_options (s_wired), ==, G_N_ELEMENTS (s390_options));
+	for (i_s390_options_keys = 0; i_s390_options_keys < G_N_ELEMENTS (s390_options); i_s390_options_keys++) {
+		const NMUtilsNamedValue *s390_option = &s390_options[i_s390_options_keys];
+		const char *k;
+		const char *v;
+		const char *v2;
+
+		g_assert (s390_option->name);
+		g_assert (s390_option->value_str);
+		v = nm_setting_wired_get_s390_option_by_key (s_wired, s390_option->name);
+		g_assert (v);
+		g_assert_cmpstr (v, ==, s390_option->value_str);
+
+		if (!nm_setting_wired_get_s390_option (s_wired, i_s390_options_keys, &k, &v2))
+			g_assert_not_reached ();
+		g_assert_cmpstr (k, ==, s390_option->name);
+		g_assert (v == v2);
+		g_assert_cmpstr (v2, ==, s390_option->value_str);
+	}
+
+	nmtst_assert_connection_verifies_without_normalization (connection);
+}
+
 NMTST_DEFINE ();
 
 int main (int argc, char **argv)
@@ -825,6 +877,7 @@ int main (int argc, char **argv)
 	g_test_add_func ("/initrd/cmdline/bridge/default", test_bridge_default);
 	g_test_add_func ("/initrd/cmdline/ibft", test_ibft);
 	g_test_add_func ("/initrd/cmdline/ignore_extra", test_ignore_extra);
+	g_test_add_func ("/initrd/cmdline/rd_zdnet", test_rd_znet);
 
 	return g_test_run ();
 }
diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c
index e2e1e581..d222527d 100644
--- a/src/platform/nm-linux-platform.c
+++ b/src/platform/nm-linux-platform.c
@@ -2879,19 +2879,11 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr
 	    && obj->_link.ext_data == NULL) {
 		switch (obj->link.type) {
 		case NM_LINK_TYPE_WIFI:
+		case NM_LINK_TYPE_OLPC_MESH:
 			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)),
diff --git a/src/platform/wifi/nm-wifi-utils-nl80211.c b/src/platform/wifi/nm-wifi-utils-nl80211.c
index 84a93f4f..36901f83 100644
--- a/src/platform/wifi/nm-wifi-utils-nl80211.c
+++ b/src/platform/wifi/nm-wifi-utils-nl80211.c
@@ -706,6 +706,7 @@ struct nl80211_device_info {
 	int phy;
 	guint32 *freqs;
 	int num_freqs;
+	guint32 freq;
 	guint32 caps;
 	gboolean can_scan;
 	gboolean can_scan_ssid;
@@ -767,6 +768,11 @@ static int nl80211_wiphy_info_handler (struct nl_msg *msg, void *arg)
 
 	info->phy = nla_get_u32 (tb[NL80211_ATTR_WIPHY]);
 
+	if (tb[NL80211_ATTR_WIPHY_FREQ])
+		info->freq = nla_get_u32 (tb[NL80211_ATTR_WIPHY_FREQ]);
+	else
+		info->freq = 0;
+
 	if (tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]) {
 		info->can_scan_ssid =
 			nla_get_u8 (tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]) > 0;
@@ -912,6 +918,64 @@ static int nl80211_wiphy_info_handler (struct nl_msg *msg, void *arg)
 	return NL_SKIP;
 }
 
+static guint32
+wifi_nl80211_get_mesh_channel (NMWifiUtils *data)
+{
+	NMWifiUtilsNl80211 *self = (NMWifiUtilsNl80211 *) data;
+	nm_auto_nlmsg struct nl_msg *msg = NULL;
+	struct nl80211_device_info device_info = { .self = self };
+	int i;
+
+	msg = nl80211_alloc_msg (self, NL80211_CMD_GET_WIPHY, 0);
+
+	if (nl80211_send_and_recv (self, msg, nl80211_wiphy_info_handler,
+	                           &device_info) < 0) {
+		_LOGW ("NL80211_CMD_GET_WIPHY request failed");
+		return 0;
+	}
+
+	for (i = 0; i < self->num_freqs; i++) {
+		if (device_info.freq == self->freqs[i])
+			return i + 1;
+	}
+	return 0;
+}
+
+static gboolean
+wifi_nl80211_set_mesh_channel (NMWifiUtils *data, guint32 channel)
+{
+	NMWifiUtilsNl80211 *self = (NMWifiUtilsNl80211 *) data;
+	nm_auto_nlmsg struct nl_msg *msg = NULL;
+	int err;
+
+	if (channel > self->num_freqs)
+		return FALSE;
+
+	msg = nl80211_alloc_msg (self, NL80211_CMD_SET_WIPHY, 0);
+	NLA_PUT_U32 (msg, NL80211_ATTR_WIPHY_FREQ, self->freqs[channel - 1]);
+	err = nl80211_send_and_recv (self, msg, NULL, NULL);
+	return err >= 0;
+
+nla_put_failure:
+	g_return_val_if_reached (FALSE);
+}
+
+static gboolean
+wifi_nl80211_set_mesh_ssid (NMWifiUtils *data, const guint8 *ssid, gsize len)
+{
+	NMWifiUtilsNl80211 *self = (NMWifiUtilsNl80211 *) data;
+	nm_auto_nlmsg struct nl_msg *msg = NULL;
+	int err;
+
+	msg = nl80211_alloc_msg (self, NL80211_CMD_SET_INTERFACE, 0);
+	NLA_PUT (msg, NL80211_ATTR_MESH_ID, len, ssid);
+	err = nl80211_send_and_recv (self, msg, NULL, NULL);
+	return err >= 0;
+
+nla_put_failure:
+	g_return_val_if_reached (FALSE);
+}
+
 static void
 nm_wifi_utils_nl80211_init (NMWifiUtilsNl80211 *self)
 {
@@ -936,6 +1000,9 @@ nm_wifi_utils_nl80211_class_init (NMWifiUtilsNl80211Class *klass)
 	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;
+	wifi_utils_class->get_mesh_channel = wifi_nl80211_get_mesh_channel;
+	wifi_utils_class->set_mesh_channel = wifi_nl80211_set_mesh_channel;
+	wifi_utils_class->set_mesh_ssid = wifi_nl80211_set_mesh_ssid;
 }
 
 NMWifiUtils *
diff --git a/src/settings/nm-settings.c b/src/settings/nm-settings.c
index 4bdcb522..6529cc58 100644
--- a/src/settings/nm-settings.c
+++ b/src/settings/nm-settings.c
@@ -3379,26 +3379,13 @@ static gboolean
 have_connection_for_device (NMSettings *self, NMDevice *device)
 {
 	NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
-	NMSettingWired *s_wired;
-	const char *setting_hwaddr;
-	const char *perm_hw_addr;
 	NMSettingsConnection *sett_conn;
 
 	g_return_val_if_fail (NM_IS_SETTINGS (self), FALSE);
 
-	perm_hw_addr = nm_device_get_permanent_hw_address (device);
-
-	/* Find a wired connection locked to the given MAC address, if any */
+	/* Find a wired connection matching for the device, if any */
 	c_list_for_each_entry (sett_conn, &priv->connections_lst_head, _connections_lst) {
 		NMConnection *connection = nm_settings_connection_get_connection (sett_conn);
-		NMSettingConnection *s_con = nm_connection_get_setting_connection (connection);
-		const char *ctype;
-		const char *iface;
-
-		ctype = nm_setting_connection_get_connection_type (s_con);
-		if (!NM_IN_STRSET (ctype, NM_SETTING_WIRED_SETTING_NAME,
-		                          NM_SETTING_PPPOE_SETTING_NAME))
-			continue;
 
 		if (!nm_device_check_connection_compatible (device, connection, NULL))
 			continue;
@@ -3410,27 +3397,7 @@ have_connection_for_device (NMSettings *self, NMDevice *device)
 		                  NM_SETTINGS_CONNECTION_INT_FLAGS_VOLATILE))
 			continue;
 
-		iface = nm_setting_connection_get_interface_name (s_con);
-		if (!nm_streq0 (iface, nm_device_get_iface (device)))
-			continue;
-
-		s_wired = nm_connection_get_setting_wired (connection);
-		if (   !s_wired
-		    && nm_streq (ctype, NM_SETTING_PPPOE_SETTING_NAME)) {
-			/* No wired setting; therefore the PPPoE connection applies to any device */
-			return TRUE;
-		}
-
-		setting_hwaddr = nm_setting_wired_get_mac_address (s_wired);
-		if (setting_hwaddr) {
-			/* A connection mac-locked to this device */
-			if (   perm_hw_addr
-			    && nm_utils_hwaddr_matches (setting_hwaddr, -1, perm_hw_addr, -1))
-				return TRUE;
-		} else {
-			/* A connection that applies to any wired device */
-			return TRUE;
-		}
+		return TRUE;
 	}
 
 	/* See if there's a known non-NetworkManager configuration for the device */
@@ -3486,7 +3453,8 @@ device_realized (NMDevice *device, GParamSpec *pspec, NMSettings *self)
 	/* If the device isn't managed or it already has a default wired connection,
 	 * ignore it.
 	 */
-	if (   !nm_device_get_managed (device, FALSE)
+	if (   !NM_DEVICE_GET_CLASS (device)->new_default_connection
+	    || !nm_device_get_managed (device, FALSE)
 	    || g_object_get_qdata (G_OBJECT (device), _default_wired_connection_quark ())
 	    || have_connection_for_device (self, device)
 	    || nm_config_get_no_auto_default_for_device (priv->config, device))
diff --git a/src/supplicant/nm-supplicant-settings-verify.c b/src/supplicant/nm-supplicant-settings-verify.c
index b37fae9e..25cc0bc6 100644
--- a/src/supplicant/nm-supplicant-settings-verify.c
+++ b/src/supplicant/nm-supplicant-settings-verify.c
@@ -69,7 +69,7 @@ static const char *const proto_allowed[] =    { "WPA", "RSN", NULL };
 static const char *const key_mgmt_allowed[] = { "WPA-PSK", "WPA-PSK-SHA256", "FT-PSK",
                                                 "WPA-EAP", "WPA-EAP-SHA256", "FT-EAP", "FT-EAP-SHA384",
                                                 "FILS-SHA256", "FILS-SHA384",
-                                                "IEEE8021X", "WPA-NONE", "SAE",
+                                                "IEEE8021X", "WPA-NONE", "SAE", "FT-SAE",
                                                 "NONE", NULL };
 static const char *const auth_alg_allowed[] = { "OPEN", "SHARED", "LEAP", NULL };
 static const char *const eap_allowed[] =      { "LEAP", "MD5", "TLS", "PEAP", "TTLS", "SIM",