about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/devices/adsl/nm-device-adsl.c3
-rw-r--r--src/devices/bluetooth/nm-bluez5-dun.c2
-rw-r--r--src/devices/nm-device-bond.c6
-rw-r--r--src/devices/nm-device-bridge.c6
-rw-r--r--src/devices/nm-device-wireguard.c244
-rw-r--r--src/devices/nm-device.c27
-rw-r--r--src/devices/nm-lldp-listener.c16
-rw-r--r--src/devices/team/nm-device-team.c6
-rw-r--r--src/devices/wwan/nm-modem-broadband.c2
-rw-r--r--src/initrd/nmi-cmdline-reader.c2
-rw-r--r--src/nm-ip4-config.c6
-rw-r--r--src/nm-ip6-config.c3
-rw-r--r--src/nm-manager.c46
-rw-r--r--src/platform/tests/test-link.c2
-rw-r--r--src/platform/wifi/nm-wifi-utils-nl80211.c22
-rw-r--r--src/settings/nm-agent-manager.c10
-rw-r--r--src/settings/nm-settings.c6
-rw-r--r--src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c19
-rw-r--r--src/settings/plugins/ifupdown/nms-ifupdown-plugin.c2
-rw-r--r--src/supplicant/nm-supplicant-config.c14
-rw-r--r--src/supplicant/nm-supplicant-settings-verify.c100
21 files changed, 259 insertions, 285 deletions
diff --git a/src/devices/adsl/nm-device-adsl.c b/src/devices/adsl/nm-device-adsl.c
index 59c87851..34efdb01 100644
--- a/src/devices/adsl/nm-device-adsl.c
+++ b/src/devices/adsl/nm-device-adsl.c
@@ -155,6 +155,7 @@ br2684_assign_vcc (NMDeviceAdsl *self, NMSettingAdsl *s_adsl)
 	if (priv->brfd < 0) {
 		errsv = errno;
 		_LOGE (LOGD_ADSL, "failed to open ATM control socket (%d)", errsv);
+		priv->brfd = -1;
 		return FALSE;
 	}
 
@@ -206,7 +207,7 @@ br2684_assign_vcc (NMDeviceAdsl *self, NMSettingAdsl *s_adsl)
 	memset (&be, 0, sizeof (be));
 	be.backend_num = ATM_BACKEND_BR2684;
 	be.ifspec.method = BR2684_FIND_BYIFNAME;
-	strcpy (be.ifspec.spec.ifname, priv->nas_ifname);
+	nm_utils_ifname_cpy (be.ifspec.spec.ifname, priv->nas_ifname);
 	be.fcs_in = BR2684_FCSIN_NO;
 	be.fcs_out = BR2684_FCSOUT_NO;
 	be.encaps = is_llc ? BR2684_ENCAPS_LLC : BR2684_ENCAPS_VC;
diff --git a/src/devices/bluetooth/nm-bluez5-dun.c b/src/devices/bluetooth/nm-bluez5-dun.c
index 04859f9a..b9a1fa0a 100644
--- a/src/devices/bluetooth/nm-bluez5-dun.c
+++ b/src/devices/bluetooth/nm-bluez5-dun.c
@@ -386,7 +386,7 @@ nm_bluez5_dun_cleanup (NMBluez5DunContext *context)
 			struct rfcomm_dev_req req = { 0 };
 
 			req.dev_id = context->rfcomm_id;
-			ioctl (context->rfcomm_fd, RFCOMMRELEASEDEV, &req);
+			(void) ioctl (context->rfcomm_fd, RFCOMMRELEASEDEV, &req);
 			context->rfcomm_id = -1;
 		}
 		nm_close (context->rfcomm_fd);
diff --git a/src/devices/nm-device-bond.c b/src/devices/nm-device-bond.c
index fd79348d..50494526 100644
--- a/src/devices/nm-device-bond.c
+++ b/src/devices/nm-device-bond.c
@@ -414,6 +414,12 @@ release_slave (NMDevice *device,
 	gboolean success;
 	gs_free char *address = NULL;
 	int ifindex_slave;
+	int ifindex;
+
+	ifindex = nm_device_get_ifindex (device);
+	if (   ifindex <= 0
+	    || !nm_platform_link_get (nm_device_get_platform (device), ifindex))
+		configure = FALSE;
 
 	ifindex_slave = nm_device_get_ip_ifindex (slave);
 
diff --git a/src/devices/nm-device-bridge.c b/src/devices/nm-device-bridge.c
index ade9eb0d..91d824b3 100644
--- a/src/devices/nm-device-bridge.c
+++ b/src/devices/nm-device-bridge.c
@@ -626,6 +626,12 @@ release_slave (NMDevice *device,
 	NMDeviceBridge *self = NM_DEVICE_BRIDGE (device);
 	gboolean success;
 	int ifindex_slave;
+	int ifindex;
+
+	ifindex = nm_device_get_ifindex (device);
+	if (   ifindex <= 0
+	    || !nm_platform_link_get (nm_device_get_platform (device), ifindex))
+		configure = FALSE;
 
 	ifindex_slave = nm_device_get_ip_ifindex (slave);
 
diff --git a/src/devices/nm-device-wireguard.c b/src/devices/nm-device-wireguard.c
index d36573cf..e3b8e8b4 100644
--- a/src/devices/nm-device-wireguard.c
+++ b/src/devices/nm-device-wireguard.c
@@ -265,157 +265,51 @@ done:
 	*out_enabled_v6 = (enabled_v6 == TRUE);
 }
 
+#define AUTO_RANDOM_RANGE 500u
+
 static guint32
-_auto_default_route_find_unused_table (NMPlatform *platform)
+_auto_default_route_get_auto_fwmark (const char *uuid)
 {
-	guint32 table;
-	int is_ipv4;
-
-	for (table = 51820; TRUE; table++) {
-		const NMDedupMultiHeadEntry *head_entry;
-		const guint32 table_coerced = nm_platform_route_table_coerce (table);
-		NMDedupMultiIter iter;
-		const NMPObject *plobj;
-
-		/* find a table/fwmark that is not yet in use. */
-
-		for (is_ipv4 = 0; is_ipv4 < 2; is_ipv4++) {
-			head_entry = nm_platform_lookup_object (platform,
-			                                          is_ipv4
-			                                        ? NMP_OBJECT_TYPE_IP4_ROUTE
-			                                        : NMP_OBJECT_TYPE_IP6_ROUTE,
-			                                        -1);
-			nmp_cache_iter_for_each (&iter, head_entry, &plobj) {
-				if (NMP_OBJECT_CAST_IP_ROUTE (plobj)->table_coerced == table_coerced)
-					goto try_next_table;
-			}
-		}
-
-		head_entry = nm_platform_lookup_object_by_addr_family (platform,
-		                                                       NMP_OBJECT_TYPE_ROUTING_RULE,
-		                                                       AF_UNSPEC);
-		nmp_cache_iter_for_each (&iter, head_entry, &plobj) {
-			const NMPlatformRoutingRule *rr = NMP_OBJECT_CAST_ROUTING_RULE (plobj);
-
-			if (rr->fwmark == table)
-				goto try_next_table;
-		}
-
-		head_entry = nm_platform_lookup_obj_type (platform, NMP_OBJECT_TYPE_LINK);
-		nmp_cache_iter_for_each (&iter, head_entry, &plobj) {
-			const NMPObject *lnk_wg;
-
-			if (plobj->link.type != NM_LINK_TYPE_WIREGUARD)
-				continue;
-
-			lnk_wg = plobj->_link.netlink.lnk;
-
-			if (!lnk_wg)
-				continue;
+	guint64 rnd_seed;
 
-			if (NMP_OBJECT_GET_TYPE (lnk_wg) != NMP_OBJECT_TYPE_LNK_WIREGUARD)
-				continue;
+	/* we use the generated number as fwmark but also as routing table for
+	 * the default-route.
+	 *
+	 * We pick a number
+	 *
+	 * - based on the connection's UUID (as stable seed).
+	 * - larger than 51820u (arbitrarily)
+	 * - one out of AUTO_RANDOM_RANGE
+	 */
 
-			if (NMP_OBJECT_CAST_LNK_WIREGUARD (lnk_wg)->fwmark == table)
-				goto try_next_table;
-		}
+	rnd_seed = c_siphash_hash (NM_HASH_SEED_16 (0xb9, 0x39, 0x8e, 0xed, 0x15, 0xb3, 0xd1, 0xc4, 0x5f, 0x45, 0x00, 0x4f, 0xec, 0xc2, 0x2b, 0x7e),
+	                           (const guint8 *) uuid,
+	                           uuid ? strlen (uuid) + 1u : 0u);
 
-		return table;
-try_next_table:
-		;
-	}
+	return 51820u + (rnd_seed % AUTO_RANDOM_RANGE);
 }
 
-#define PRIO_WIDTH ((guint32) 2)
-
-static gboolean
-_auto_default_route_find_priority_exists (const NMDedupMultiHeadEntry *head_entry,
-                                          guint32 priority)
-{
-	NMDedupMultiIter iter;
-	const NMPObject *plobj;
-
-	nmp_cache_iter_for_each (&iter, head_entry, &plobj) {
-		const NMPlatformRoutingRule *rr = NMP_OBJECT_CAST_ROUTING_RULE (plobj);
-
-		/* we don't differenciate between IPv4 vs. IPv6. There should be no
-		 * conflicting rules with the same priority. */
-		if (   rr->priority >= priority
-		    && rr->priority < priority + PRIO_WIDTH)
-			return TRUE;
-	}
-
-	return FALSE;
-}
+#define PRIO_WIDTH 2u
 
 static guint32
-_auto_default_route_find_priority (NMPlatform *platform,
-                                   const char *uuid)
+_auto_default_route_get_auto_priority (const char *uuid)
 {
-	const NMDedupMultiHeadEntry *head_entry;
+	const guint32 RANGE_TOP = 32766u - 1000u;
 	guint64 rnd_seed;
-	const guint32 PRIME_NUMBER = 1111567573u;
-	const guint32 RANGE_TOP = ((32766u - 2u * PRIO_WIDTH) / PRIO_WIDTH);
-	const guint32 RANGE_LEN1 = 200u;
-	const guint32 RANGE_LEN2 = (RANGE_TOP - 100u) - RANGE_LEN1;
-	guint32 range_len;
-	guint32 range_top;
-	guint32 prio_candidate = 0;
-	guint32 i_step;
-	guint32 i;
-
-	/* For the auto-default-route policy routing rule we add 4 rules (2 Ipv4 and 2 IPv6).
-	 * Hence, we choose a priority for the first (of the two rules) and the second
-	 * rule gets priority + 1.
-	 * We want a priority that is
-	 *   - unused so far.
-	 *   - smaller than 32766u (which is the priority of the default rules for IPv4 and IPv6)
-	 *   - stable for each connection but different between connections (we hash the UUID
-	 *     as a "random" seed)
-	 *   - if possible, close to 32766u (RANGE_LEN1). Only otherwise fallback to the entire
-	 *     range (RANGE_LEN2).
-	 */
 
-	rnd_seed = c_siphash_hash ((const guint8 [16]) { 0xb9, 0x39, 0x8e, 0xed, 0x15, 0xb3, 0xd1, 0xc4, 0x5f, 0x45, 0x00, 0x4f, 0xec, 0xc2, 0x2b, 0x7e },
+	/* we pick a priority for the routing rules as follows:
+	 *
+	 * - use the connection's UUID as stable seed for the "random" number.
+	 * - have it smaller than RANGE_TOP (32766u - 1000u), where 32766u is the priority of the default
+	 *   rules
+	 * - we add 2 rules (PRIO_WIDTH). Hence only pick even priorites.
+	 * - pick one out of AUTO_RANDOM_RANGE. */
+
+	rnd_seed = c_siphash_hash (NM_HASH_SEED_16 (0x99, 0x22, 0x4d, 0x7c, 0x37, 0xda, 0x8e, 0x7b, 0x2f, 0x55, 0x16, 0x7b, 0x75, 0xda, 0x42, 0xdc),
 	                           (const guint8 *) uuid,
 	                           uuid ? strlen (uuid) + 1u : 0u);
 
-	head_entry = nm_platform_lookup_object_by_addr_family (platform,
-	                                                       NMP_OBJECT_TYPE_ROUTING_RULE,
-	                                                       AF_UNSPEC);
-
-	range_len = RANGE_LEN1;
-	range_top = RANGE_TOP;
-
-again:
-	i_step = ((guint32) rnd_seed) % range_len;
-	for (i = 0; i < range_len; i++) {
-
-		/* we sample the range in a stable, but somewhat arbitrary order to
-		 * find an unused priority. */
-		i_step = (i_step + PRIME_NUMBER) % range_len;
-
-		nm_assert (i_step < range_top);
-
-		prio_candidate = (range_top - i_step) * PRIO_WIDTH;
-
-		nm_assert (prio_candidate < 32766u);
-
-		if (!_auto_default_route_find_priority_exists (head_entry, prio_candidate))
-			return prio_candidate;
-	}
-
-	if (range_len == RANGE_LEN1) {
-		/* within the narrow range close to RANGE_TOP we couldn't find any unused
-		 * priority. Retry with the entire range... */
-		range_len = RANGE_LEN2;
-		range_top -= RANGE_LEN1;
-		goto again;
-	}
-
-	/* Couldn't find an unused one? Very odd, this really should not happen unless there
-	 * are thousands of rules already. Just pick the last one we sampled. */
-	return prio_candidate;
+	return RANGE_TOP - (((rnd_seed % (PRIO_WIDTH * AUTO_RANDOM_RANGE)) / PRIO_WIDTH) * PRIO_WIDTH);
 }
 
 static void
@@ -423,10 +317,10 @@ _auto_default_route_init (NMDeviceWireGuard *self)
 {
 	NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE (self);
 	NMConnection *connection;
-	NMSettingWireGuard *s_wg;
-	gboolean enabled_v4;
-	gboolean enabled_v6;
+	gboolean enabled_v4 = FALSE;
+	gboolean enabled_v6 = FALSE;
 	gboolean refreshing_only;
+	guint32 new_fwmark = 0;
 	guint32 old_fwmark;
 	char sbuf1[100];
 
@@ -436,40 +330,47 @@ _auto_default_route_init (NMDeviceWireGuard *self)
 
 	refreshing_only =    priv->auto_default_route_initialized
 	                  && priv->auto_default_route_refresh;
-	priv->auto_default_route_refresh = FALSE;
+
+	old_fwmark = priv->auto_default_route_fwmark;
 
 	connection = nm_device_get_applied_connection (NM_DEVICE (self));
+	if (connection) {
+		NMSettingWireGuard *s_wg;
 
-	s_wg = _nm_connection_get_setting (connection, NM_TYPE_SETTING_WIREGUARD);
+		s_wg = _nm_connection_get_setting (connection, NM_TYPE_SETTING_WIREGUARD);
 
-	old_fwmark = priv->auto_default_route_fwmark;
+		new_fwmark = nm_setting_wireguard_get_fwmark (s_wg);
+
+		_auto_default_route_get_enabled (s_wg,
+		                                 connection,
+		                                 &enabled_v4,
+		                                 &enabled_v6);
+	}
 
-	priv->auto_default_route_fwmark = nm_setting_wireguard_get_fwmark (s_wg);
+	if (   (   enabled_v4
+	        || enabled_v6)
+	    && new_fwmark == 0u) {
+		if (refreshing_only)
+			new_fwmark = old_fwmark;
+		else
+			new_fwmark = _auto_default_route_get_auto_fwmark (nm_connection_get_uuid (connection));
+	}
 
-	_auto_default_route_get_enabled (s_wg,
-	                                 connection,
-	                                 &enabled_v4,
-	                                 &enabled_v6);
+	priv->auto_default_route_refresh = FALSE;
+	priv->auto_default_route_fwmark = new_fwmark;
 	priv->auto_default_route_enabled_4 = enabled_v4;
 	priv->auto_default_route_enabled_6 = enabled_v6;
 	priv->auto_default_route_initialized = TRUE;
 
-	if (   (   priv->auto_default_route_enabled_4
-	        || priv->auto_default_route_enabled_6)
-	    && priv->auto_default_route_fwmark == 0u) {
-		if (refreshing_only)
-			priv->auto_default_route_fwmark = old_fwmark;
-		else
-			priv->auto_default_route_fwmark = _auto_default_route_find_unused_table (nm_device_get_platform (NM_DEVICE (self)));
+	if (connection) {
+		_LOGT (LOGD_DEVICE,
+		       "auto-default-route is %s for IPv4 and %s for IPv6%s",
+		       priv->auto_default_route_enabled_4 ? "enabled" : "disabled",
+		       priv->auto_default_route_enabled_6 ? "enabled" : "disabled",
+		         priv->auto_default_route_enabled_4 || priv->auto_default_route_enabled_6
+		       ? nm_sprintf_buf (sbuf1, " (fwmark 0x%x)", priv->auto_default_route_fwmark)
+		       : "");
 	}
-
-	_LOGT (LOGD_DEVICE,
-	       "auto-default-route is %s for IPv4 and %s for IPv6%s",
-	       priv->auto_default_route_enabled_4 ? "enabled" : "disabled",
-	       priv->auto_default_route_enabled_6 ? "enabled" : "disabled",
-	         priv->auto_default_route_enabled_4 || priv->auto_default_route_enabled_6
-	       ? nm_sprintf_buf (sbuf1, " (fwmark 0x%x)", priv->auto_default_route_fwmark)
-	       : "");
 }
 
 static GPtrArray *
@@ -506,8 +407,7 @@ get_extra_rules (NMDevice *device)
 			if (priv->auto_default_route_priority_initialized)
 				priority = priv->auto_default_route_priority;
 			else {
-				priority = _auto_default_route_find_priority (nm_device_get_platform (device),
-				                                              nm_connection_get_uuid (connection));
+				priority = _auto_default_route_get_auto_priority (nm_connection_get_uuid (connection));
 				priv->auto_default_route_priority = priority;
 				priv->auto_default_route_priority_initialized = TRUE;
 			}
@@ -624,7 +524,7 @@ _peers_remove (NMDeviceWireGuardPrivate *priv,
 	nm_clear_g_cancellable (&peer_data->ep_resolv.cancellable);
 	g_slice_free (PeerData, peer_data);
 
-	if (c_list_is_empty (&peer_data->lst_peers)) {
+	if (c_list_is_empty (&priv->lst_peers_head)) {
 		nm_clear_g_source (&priv->resolve_next_try_id);
 		nm_clear_g_source (&priv->link_config_delayed_id);
 	}
@@ -1567,7 +1467,7 @@ link_config (NMDeviceWireGuard *self,
 	                                       plpeers_len,
 	                                       wg_change_flags);
 
-	nm_explicit_bzero (plpeers, sizeof (plpeers) * plpeers_len);
+	nm_explicit_bzero (plpeers, sizeof (plpeers[0]) * plpeers_len);
 
 	if (r < 0) {
 		NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_CONFIG_FAILED);
@@ -1618,6 +1518,17 @@ link_config_delayed_resolver_cb (gpointer user_data)
 }
 
 static NMActStageReturn
+act_stage1_prepare (NMDevice *device, NMDeviceStateReason *out_failure_reason)
+{
+	NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE (device);
+
+	priv->auto_default_route_initialized = FALSE;
+	priv->auto_default_route_priority_initialized = FALSE;
+
+	return NM_DEVICE_CLASS (nm_device_wireguard_parent_class)->act_stage1_prepare (device, out_failure_reason);
+}
+
+static NMActStageReturn
 act_stage2_config (NMDevice *device,
                    NMDeviceStateReason *out_failure_reason)
 {
@@ -2057,6 +1968,7 @@ nm_device_wireguard_class_init (NMDeviceWireGuardClass *klass)
 	device_class->connection_type_check_compatible = NM_SETTING_WIREGUARD_SETTING_NAME;
 	device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES (NM_LINK_TYPE_WIREGUARD);
 
+	device_class->act_stage1_prepare = act_stage1_prepare;
 	device_class->state_changed = device_state_changed;
 	device_class->create_and_realize = create_and_realize;
 	device_class->act_stage2_config = act_stage2_config;
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index feb5110d..f07c4f09 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -3186,14 +3186,11 @@ nm_device_check_connectivity (NMDevice *self,
                               NMDeviceConnectivityCallback callback,
                               gpointer user_data)
 {
-	NMDeviceConnectivityHandle *handle;
-
 	if (!concheck_is_possible (self))
 		return NULL;
 
 	concheck_periodic_schedule_set (self, addr_family, CONCHECK_SCHEDULE_CHECK_EXTERNAL);
-	handle = concheck_start (self, addr_family, callback, user_data, FALSE);
-	return handle;
+	return concheck_start (self, addr_family, callback, user_data, FALSE);
 }
 
 void
@@ -4153,13 +4150,14 @@ nm_device_create_and_realize (NMDevice *self,
 {
 	nm_auto_nmpobj const NMPObject *plink_keep_alive = NULL;
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
-	const NMPlatformLink *plink = NULL;
+	const NMPlatformLink *plink;
 
 	/* Must be set before device is realized */
-	priv->nm_owned = !nm_platform_link_get_by_ifname (nm_device_get_platform (self), priv->iface);
-
+	plink = nm_platform_link_get_by_ifname (nm_device_get_platform (self), priv->iface);
+	priv->nm_owned = !plink || !link_type_compatible (self, plink->type, NULL, NULL);
 	_LOGD (LOGD_DEVICE, "create (is %snm-owned)", priv->nm_owned ? "" : "not ");
 
+	plink = NULL;
 	/* Create any resources the device needs */
 	if (NM_DEVICE_GET_CLASS (self)->create_and_realize) {
 		if (!NM_DEVICE_GET_CLASS (self)->create_and_realize (self, connection, parent, &plink, error))
@@ -4986,7 +4984,6 @@ nm_device_master_release_slaves (NMDevice *self)
 {
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
 	NMDeviceStateReason reason;
-	gboolean configure = TRUE;
 	CList *iter, *safe;
 
 	/* Don't release the slaves if this connection doesn't belong to NM. */
@@ -4997,14 +4994,10 @@ nm_device_master_release_slaves (NMDevice *self)
 	if (priv->state == NM_DEVICE_STATE_FAILED)
 		reason = NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED;
 
-	if (   priv->ifindex <= 0
-	    || !nm_platform_link_get (nm_device_get_platform (self), priv->ifindex))
-		configure = FALSE;
-
 	c_list_for_each_safe (iter, safe, &priv->slaves) {
 		SlaveInfo *info = c_list_entry (iter, SlaveInfo, lst_slave);
 
-		nm_device_master_release_one_slave (self, info->slave, configure, reason);
+		nm_device_master_release_one_slave (self, info->slave, TRUE, reason);
 	}
 }
 
@@ -15121,6 +15114,7 @@ _set_state_full (NMDevice *self,
 	gboolean no_firmware = FALSE;
 	NMSettingsConnection *sett_conn;
 	NMSettingSriov *s_sriov;
+	gboolean concheck_now;
 
 	g_return_if_fail (NM_IS_DEVICE (self));
 
@@ -15456,8 +15450,11 @@ _set_state_full (NMDevice *self,
 	if (ip_config_valid (old_state) && !ip_config_valid (state))
 	    notify_ip_properties (self);
 
-	concheck_update_interval (self, AF_INET, state == NM_DEVICE_STATE_ACTIVATED);
-	concheck_update_interval (self, AF_INET6, state == NM_DEVICE_STATE_ACTIVATED);
+	concheck_now =    NM_IN_SET (state, NM_DEVICE_STATE_ACTIVATED,
+	                                    NM_DEVICE_STATE_DISCONNECTED)
+	               || old_state >= NM_DEVICE_STATE_ACTIVATED;
+	concheck_update_interval (self, AF_INET, concheck_now);
+	concheck_update_interval (self, AF_INET6, concheck_now);
 
 	/* Dispose of the cached activation request */
 	if (req)
diff --git a/src/devices/nm-lldp-listener.c b/src/devices/nm-lldp-listener.c
index c0d78315..469ccce1 100644
--- a/src/devices/nm-lldp-listener.c
+++ b/src/devices/nm-lldp-listener.c
@@ -224,7 +224,7 @@ _lldp_attr_set_str (LldpAttrData *pdata, LldpAttrId attr_id, const char *v_strin
 }
 
 static void
-_lldp_attr_take_str_ptr (LldpAttrData *pdata, LldpAttrId attr_id, char *str)
+_lldp_attr_set_str_take (LldpAttrData *pdata, LldpAttrId attr_id, char *str)
 {
 	nm_assert (pdata);
 	nm_assert (_lldp_attr_id_to_type (attr_id) == LLDP_ATTR_TYPE_STRING);
@@ -232,8 +232,10 @@ _lldp_attr_take_str_ptr (LldpAttrData *pdata, LldpAttrId attr_id, char *str)
 	pdata = &pdata[attr_id];
 
 	/* we ignore duplicate fields silently. */
-	if (pdata->attr_type != LLDP_ATTR_TYPE_NONE)
+	if (pdata->attr_type != LLDP_ATTR_TYPE_NONE) {
+		g_free (str);
 		return;
+	}
 
 	pdata->attr_type = LLDP_ATTR_TYPE_STRING;
 	pdata->v_string = str;
@@ -265,8 +267,7 @@ _lldp_attr_set_vardict (LldpAttrData *pdata, LldpAttrId attr_id, GVariant *varia
 
 	/* we ignore duplicate fields silently */
 	if (pdata->attr_type != LLDP_ATTR_TYPE_NONE) {
-		if (g_variant_is_floating (variant))
-			g_variant_unref (variant);
+		nm_g_variant_unref_floating (variant);
 		return;
 	}
 
@@ -685,9 +686,10 @@ lldp_neighbor_new (sd_lldp_neighbor *neighbor_sd, GError **error)
 				                        g_variant_dict_end (&dict));
 
 				_lldp_attr_set_uint32 (neigh->attrs, LLDP_ATTR_ID_IEEE_802_1_VID, vid);
-				_lldp_attr_take_str_ptr (neigh->attrs,
-				                         LLDP_ATTR_ID_IEEE_802_1_VLAN_NAME,
-				                         name_to_free ?: g_strdup (name));
+				if (name_to_free)
+					_lldp_attr_set_str_take (neigh->attrs, LLDP_ATTR_ID_IEEE_802_1_VLAN_NAME, name_to_free);
+				else
+					_lldp_attr_set_str (neigh->attrs, LLDP_ATTR_ID_IEEE_802_1_VLAN_NAME, name);
 				break;
 			}
 			default:
diff --git a/src/devices/team/nm-device-team.c b/src/devices/team/nm-device-team.c
index a60a9fda..4661a840 100644
--- a/src/devices/team/nm-device-team.c
+++ b/src/devices/team/nm-device-team.c
@@ -775,6 +775,12 @@ release_slave (NMDevice *device,
 	NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (self);
 	gboolean success;
 	int ifindex_slave;
+	int ifindex;
+
+	ifindex = nm_device_get_ifindex (device);
+	if (   ifindex <= 0
+	    || !nm_platform_link_get (nm_device_get_platform (device), ifindex))
+		configure = FALSE;
 
 	ifindex_slave = nm_device_get_ip_ifindex (slave);
 
diff --git a/src/devices/wwan/nm-modem-broadband.c b/src/devices/wwan/nm-modem-broadband.c
index 5716500a..216fedfe 100644
--- a/src/devices/wwan/nm-modem-broadband.c
+++ b/src/devices/wwan/nm-modem-broadband.c
@@ -1134,7 +1134,7 @@ simple_disconnect_ready (GObject *source_object,
 {
 	MMModemSimple *modem_iface = MM_MODEM_SIMPLE (source_object);
 	DisconnectContext *ctx = user_data;
-	GError *error = NULL;
+	gs_free_error GError *error = NULL;
 
 	if (!mm_modem_simple_disconnect_finish (modem_iface, res, &error)) {
 		if (   ctx->warn
diff --git a/src/initrd/nmi-cmdline-reader.c b/src/initrd/nmi-cmdline-reader.c
index ccdd1f29..7a3af8d6 100644
--- a/src/initrd/nmi-cmdline-reader.c
+++ b/src/initrd/nmi-cmdline-reader.c
@@ -244,7 +244,7 @@ parse_ip (GHashTable *connections, const char *sysfs_dir, char *argument)
 			dns[0] = tmp;
 			dns[1] = get_word (&argument, ':');
 			dns_addr_family[1] = guess_ip_address_family (dns[1]);
-			if (argument && *argument)
+			if (*argument)
 				_LOGW (LOGD_CORE, "Ignoring extra: '%s'.", argument);
 		} else {
 			mtu = tmp;
diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c
index 86c82925..36e75bb2 100644
--- a/src/nm-ip4-config.c
+++ b/src/nm-ip4-config.c
@@ -544,6 +544,9 @@ _addresses_sort_cmp (gconstpointer a, gconstpointer b, gpointer user_data)
 	const NMPlatformIP4Address *a2 = NMP_OBJECT_CAST_IP4_ADDRESS (*((const NMPObject **) b));
 	guint32 n1, n2;
 
+	nm_assert (a1);
+	nm_assert (a2);
+
 	/* Sort by address type. For example link local will
 	 * be sorted *after* a global address. */
 	p1 = _addresses_sort_cmp_get_prio (a1->address);
@@ -577,6 +580,9 @@ sort_captured_addresses (const CList *lst_a, const CList *lst_b, gconstpointer u
 	const NMPlatformIP4Address *addr_a = NMP_OBJECT_CAST_IP4_ADDRESS (c_list_entry (lst_a, NMDedupMultiEntry, lst_entries)->obj);
 	const NMPlatformIP4Address *addr_b = NMP_OBJECT_CAST_IP4_ADDRESS (c_list_entry (lst_b, NMDedupMultiEntry, lst_entries)->obj);
 
+	nm_assert (addr_a);
+	nm_assert (addr_b);
+
 	/* Primary addresses first */
 	return NM_FLAGS_HAS (addr_a->n_ifa_flags, IFA_F_SECONDARY) -
 	       NM_FLAGS_HAS (addr_b->n_ifa_flags, IFA_F_SECONDARY);
diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c
index 1096fb42..1810d511 100644
--- a/src/nm-ip6-config.c
+++ b/src/nm-ip6-config.c
@@ -318,6 +318,9 @@ sort_captured_addresses (const CList *lst_a, const CList *lst_b, gconstpointer u
 	const NMPlatformIP6Address *addr_a = NMP_OBJECT_CAST_IP6_ADDRESS (c_list_entry (lst_a, NMDedupMultiEntry, lst_entries)->obj);
 	const NMPlatformIP6Address *addr_b = NMP_OBJECT_CAST_IP6_ADDRESS (c_list_entry (lst_b, NMDedupMultiEntry, lst_entries)->obj);
 
+	nm_assert (addr_a);
+	nm_assert (addr_b);
+
 	return _addresses_sort_cmp (addr_a, addr_b,
 	                            ((NMSettingIP6ConfigPrivacy) GPOINTER_TO_INT (user_data)) == NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR);
 }
diff --git a/src/nm-manager.c b/src/nm-manager.c
index 6ea53502..64cdb9ae 100644
--- a/src/nm-manager.c
+++ b/src/nm-manager.c
@@ -2698,6 +2698,7 @@ recheck_assume_connection (NMManager *self,
 	gboolean was_unmanaged = FALSE;
 	gboolean generated = FALSE;
 	NMDeviceState state;
+	gboolean activation_type_assume;
 
 	g_return_val_if_fail (NM_IS_MANAGER (self), FALSE);
 	g_return_val_if_fail (NM_IS_DEVICE (device), FALSE);
@@ -2721,10 +2722,42 @@ recheck_assume_connection (NMManager *self,
 	if (!sett_conn)
 		return FALSE;
 
+	activation_type_assume = !generated;
+
+	if (state == NM_DEVICE_STATE_UNMANAGED) {
+		gs_free char *initramfs_lease = g_strdup_printf (RUNSTATEDIR "/initramfs/net.%s.lease",
+		                                                 nm_device_get_iface (device));
+		gs_free char *connection_lease = g_strdup_printf (NMRUNDIR "/dhclient-%s-%s.lease",
+		                                                  nm_settings_connection_get_uuid (sett_conn),
+		                                                  nm_device_get_iface (device));
+
+		if (rename (initramfs_lease, connection_lease) == 0) {
+			/*
+			 * We've managed to steal the lease used by initramfs before it
+			 * killed off the dhclient. We need to take ownership of the configured
+			 * connection and act like the device was configured by us.
+			 * Otherwise the address would just expire.
+			 */
+			_LOG2I (LOGD_DEVICE, device, "assume: taking over an initramfs-configured connection");
+			activation_type_assume = TRUE;
+
+			if (generated) {
+				nm_settings_connection_update (sett_conn,
+				                               NULL,
+				                               NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP,
+				                               0,
+				                               NM_SETTINGS_CONNECTION_INT_FLAGS_VOLATILE,
+				                               NM_SETTINGS_CONNECTION_UPDATE_REASON_NONE,
+				                               "assume-initrd",
+				                               NULL);
+			}
+		}
+	}
+
 	nm_device_sys_iface_state_set (device,
-	                               generated
-	                                   ? NM_DEVICE_SYS_IFACE_STATE_EXTERNAL
-	                                   : NM_DEVICE_SYS_IFACE_STATE_ASSUME);
+	                                 activation_type_assume
+	                               ? NM_DEVICE_SYS_IFACE_STATE_ASSUME
+	                               : NM_DEVICE_SYS_IFACE_STATE_EXTERNAL);
 
 	/* Move device to DISCONNECTED to activate the connection */
 	if (state == NM_DEVICE_STATE_UNMANAGED) {
@@ -2768,8 +2801,8 @@ recheck_assume_connection (NMManager *self,
 		                                 NULL,
 		                                 device,
 		                                 subject,
-		                                 generated ? NM_ACTIVATION_TYPE_EXTERNAL : NM_ACTIVATION_TYPE_ASSUME,
-		                                 generated ? NM_ACTIVATION_REASON_EXTERNAL : NM_ACTIVATION_REASON_ASSUME,
+		                                 activation_type_assume ? NM_ACTIVATION_TYPE_ASSUME : NM_ACTIVATION_TYPE_EXTERNAL,
+		                                 activation_type_assume ? NM_ACTIVATION_REASON_ASSUME : NM_ACTIVATION_REASON_EXTERNAL,
 		                                 NM_ACTIVATION_STATE_FLAG_LIFETIME_BOUND_TO_PROFILE_VISIBILITY,
 		                                 &error);
 
@@ -2785,7 +2818,8 @@ recheck_assume_connection (NMManager *self,
 				                         NM_DEVICE_STATE_REASON_CONFIG_FAILED);
 			}
 
-			if (generated) {
+			if (   generated
+			    && !activation_type_assume) {
 				_LOG2D (LOGD_DEVICE, device, "assume: deleting generated connection after assuming failed");
 				nm_settings_connection_delete (sett_conn, FALSE);
 			} else {
diff --git a/src/platform/tests/test-link.c b/src/platform/tests/test-link.c
index 5926dac1..27ec3f07 100644
--- a/src/platform/tests/test-link.c
+++ b/src/platform/tests/test-link.c
@@ -257,7 +257,7 @@ test_slave (int master, int type, SignalData *master_changed)
 	case NM_LINK_TYPE_TEAM:
 		g_assert (nm_platform_link_set_down (NM_PLATFORM_GET, ifindex));
 		accept_signal (link_changed);
-		accept_signals (master_changed, 0, 2);
+		accept_signals (master_changed, 0, 3);
 		break;
 	default:
 		break;
diff --git a/src/platform/wifi/nm-wifi-utils-nl80211.c b/src/platform/wifi/nm-wifi-utils-nl80211.c
index 164dada4..84a93f4f 100644
--- a/src/platform/wifi/nm-wifi-utils-nl80211.c
+++ b/src/platform/wifi/nm-wifi-utils-nl80211.c
@@ -284,8 +284,8 @@ nl80211_get_wake_on_wlan_handler (struct nl_msg *msg, void *arg)
 	struct genlmsghdr *gnlh = nlmsg_data (nlmsg_hdr (msg));
 
 	nla_parse_arr (attrs,
-	               genlmsg_attrdata(gnlh, 0),
-	               genlmsg_attrlen(gnlh, 0),
+	               genlmsg_attrdata (gnlh, 0),
+	               genlmsg_attrlen (gnlh, 0),
 	               NULL);
 
 	if (!attrs[NL80211_ATTR_WOWLAN_TRIGGERS])
@@ -343,10 +343,10 @@ wifi_nl80211_set_wake_on_wlan (NMWifiUtils *data, NMSettingWirelessWakeOnWLan wo
 		return TRUE;
 
 	msg = nl80211_alloc_msg (self, NL80211_CMD_SET_WOWLAN, 0);
-	if (!msg)
-		return FALSE;
 
 	triggers = nla_nest_start (msg, NL80211_ATTR_WOWLAN_TRIGGERS);
+	if (!triggers)
+		goto nla_put_failure;
 
 	if (NM_FLAGS_HAS (wowl, NM_SETTING_WIRELESS_WAKE_ON_WLAN_ANY))
 		NLA_PUT_FLAG (msg, NL80211_WOWLAN_TRIG_ANY);
@@ -363,7 +363,7 @@ wifi_nl80211_set_wake_on_wlan (NMWifiUtils *data, NMSettingWirelessWakeOnWLan wo
 	if (NM_FLAGS_HAS (wowl, NM_SETTING_WIRELESS_WAKE_ON_WLAN_RFKILL_RELEASE))
 		NLA_PUT_FLAG (msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE);
 
-	nla_nest_end(msg, triggers);
+	nla_nest_end (msg, triggers);
 
 	err = nl80211_send_and_recv (self, msg, NULL, NULL);
 
@@ -634,14 +634,12 @@ nl80211_get_ap_info (NMWifiUtilsNl80211 *self,
 		return;
 
 	msg = nl80211_alloc_msg (self, NL80211_CMD_GET_STATION, 0);
-	if (msg) {
-		NLA_PUT (msg, NL80211_ATTR_MAC, ETH_ALEN, bss_info.bssid);
+	NLA_PUT (msg, NL80211_ATTR_MAC, ETH_ALEN, bss_info.bssid);
 
-		nl80211_send_and_recv (self, msg, nl80211_station_handler, sta_info);
-		if (!sta_info->signal_valid) {
-			/* Fall back to bss_info signal quality (both are in percent) */
-			sta_info->signal = bss_info.beacon_signal;
-		}
+	nl80211_send_and_recv (self, msg, nl80211_station_handler, sta_info);
+	if (!sta_info->signal_valid) {
+		/* Fall back to bss_info signal quality (both are in percent) */
+		sta_info->signal = bss_info.beacon_signal;
 	}
 
 	return;
diff --git a/src/settings/nm-agent-manager.c b/src/settings/nm-agent-manager.c
index d361c06a..2f9827d5 100644
--- a/src/settings/nm-agent-manager.c
+++ b/src/settings/nm-agent-manager.c
@@ -1593,16 +1593,6 @@ static const NMDBusInterfaceInfoExtended interface_info_agent_manager = {
 			),
 			NM_DEFINE_DBUS_METHOD_INFO_EXTENDED (
 				NM_DEFINE_GDBUS_METHOD_INFO_INIT (
-					"RegisterWithCapabilities",
-					.in_args = NM_DEFINE_GDBUS_ARG_INFOS (
-						NM_DEFINE_GDBUS_ARG_INFO ("identifier",   "s"),
-						NM_DEFINE_GDBUS_ARG_INFO ("capabilities", "u"),
-					),
-				),
-				.handle = impl_agent_manager_register_with_capabilities,
-			),
-			NM_DEFINE_DBUS_METHOD_INFO_EXTENDED (
-				NM_DEFINE_GDBUS_METHOD_INFO_INIT (
 					"Unregister",
 				),
 				.handle = impl_agent_manager_unregister,
diff --git a/src/settings/nm-settings.c b/src/settings/nm-settings.c
index 430d2776..42a7bca0 100644
--- a/src/settings/nm-settings.c
+++ b/src/settings/nm-settings.c
@@ -1455,7 +1455,7 @@ _add_connection_to_first_plugin (NMSettings *self,
                                  GError **error)
 {
 	NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
-	GError *first_error = NULL;
+	gs_free_error GError *first_error = NULL;
 	GSList *iter;
 	const char *uuid;
 
@@ -1561,7 +1561,7 @@ _add_connection_to_first_plugin (NMSettings *self,
 	}
 
 	nm_assert (first_error);
-	g_propagate_error (error, first_error);
+	g_propagate_error (error, g_steal_pointer (&first_error));
 	return FALSE;
 }
 
@@ -2866,7 +2866,7 @@ _clear_connections_cached_list (NMSettingsPrivate *priv)
 	 * it. That is a bug, this code just tries to make it blow up
 	 * more eagerly. */
 	memset (priv->connections_cached_list,
-	        0xdeaddead,
+	        0x43,
 	        sizeof (NMSettingsConnection *) * (priv->connections_len + 1));
 #endif
 
diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c
index 900a3fc1..9c3ae10a 100644
--- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c
+++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c
@@ -3629,7 +3629,10 @@ make_wpa_setting (shvarFile *ifcfg,
 	wpa_sae = nm_streq0 (v, "SAE");
 	wpa_eap = nm_streq0 (v, "WPA-EAP");
 	ieee8021x = nm_streq0 (v, "IEEE8021X");
-	if (!wpa_psk && !wpa_sae && !wpa_eap && !ieee8021x)
+	if (   !wpa_psk
+	    && !wpa_sae
+	    && !wpa_eap
+	    && !ieee8021x)
 		return NULL; /* Not WPA or Dynamic WEP */
 
 	/* WPS */
@@ -3689,11 +3692,13 @@ make_wpa_setting (shvarFile *ifcfg,
 			g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-none", NULL);
 		else if (wpa_psk)
 			g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-psk", NULL);
-		else if (wpa_sae)
+		else {
+			nm_assert (wpa_sae);
 			g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "sae", NULL);
-		else
-			g_assert_not_reached ();
-	} else if (wpa_eap || ieee8021x) {
+		}
+	} else {
+		nm_assert (wpa_eap || ieee8021x);
+
 		/* Adhoc mode is mutually exclusive with any 802.1x-based authentication */
 		if (adhoc) {
 			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
@@ -3710,10 +3715,6 @@ make_wpa_setting (shvarFile *ifcfg,
 
 			g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, lower, NULL);
 		}
-	} else {
-		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
-		             "Unknown wireless KEY_MGMT type '%s'", v);
-		return NULL;
 	}
 
 	i_val = NM_SETTING_WIRELESS_SECURITY_PMF_DEFAULT;
diff --git a/src/settings/plugins/ifupdown/nms-ifupdown-plugin.c b/src/settings/plugins/ifupdown/nms-ifupdown-plugin.c
index 93f1813c..475ecbb6 100644
--- a/src/settings/plugins/ifupdown/nms-ifupdown-plugin.c
+++ b/src/settings/plugins/ifupdown/nms-ifupdown-plugin.c
@@ -321,10 +321,10 @@ load_eni_ifaces (NMSIfupdownPlugin *self)
 
 			sd_repl = g_hash_table_lookup (eni_ifaces, block->name);
 			if (sd_repl) {
-				storage = g_steal_pointer (&sd_repl->storage);
 				_LOGD ("parse: replace connection \"%s\" (%s)",
 				       block->name,
 				       nm_settings_storage_get_uuid (sd_repl->storage));
+				storage = g_steal_pointer (&sd_repl->storage);
 				g_hash_table_remove (eni_ifaces, block->name);
 			}
 
diff --git a/src/supplicant/nm-supplicant-config.c b/src/supplicant/nm-supplicant-config.c
index 806c087c..f6e3c7da 100644
--- a/src/supplicant/nm-supplicant-config.c
+++ b/src/supplicant/nm-supplicant-config.c
@@ -139,11 +139,17 @@ nm_supplicant_config_add_option_with_type (NMSupplicantConfig *self,
 	else {
 		type = nm_supplicant_settings_verify_setting (key, value, len);
 		if (type == TYPE_INVALID) {
-			char buf[255];
-			memset (&buf[0], 0, sizeof (buf));
-			memcpy (&buf[0], value, len > 254 ? 254 : len);
+			gs_free char *str_free = NULL;
+			const char *str;
+
+			str = nm_utils_buf_utf8safe_escape (value, len, NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL, &str_free);
+
+			str = nm_strquote_a (255, str);
+
 			g_set_error (error, NM_SUPPLICANT_ERROR, NM_SUPPLICANT_ERROR_CONFIG,
-			             "key '%s' and/or value '%s' invalid", key, hidden ?: buf);
+			             "key '%s' and/or value %s invalid",
+			             key,
+			             hidden ?: str);
 			return FALSE;
 		}
 	}
diff --git a/src/supplicant/nm-supplicant-settings-verify.c b/src/supplicant/nm-supplicant-settings-verify.c
index 1bd71320..b37fae9e 100644
--- a/src/supplicant/nm-supplicant-settings-verify.c
+++ b/src/supplicant/nm-supplicant-settings-verify.c
@@ -30,7 +30,7 @@ struct Opt {
 	const gint32     int_low;  /* Inclusive */
 	const gint32     int_high; /* Inclusive; max length for strings */
 	const gboolean   str_allowed_multiple;
-	const char **    str_allowed;
+	const char *const*str_allowed;
 };
 
 static gboolean validate_type_int     (const struct Opt * opt,
@@ -63,31 +63,31 @@ static const struct validate_entry validate_table[] = {
 	{ TYPE_KEYWORD, validate_type_keyword },
 };
 
-const char * pairwise_allowed[] = { "CCMP", "TKIP", "NONE", NULL };
-const char * group_allowed[] =    { "CCMP", "TKIP", "WEP104", "WEP40", NULL };
-const char * proto_allowed[] =    { "WPA", "RSN", NULL };
-const char * 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",
-                                    "NONE", NULL };
-const char * auth_alg_allowed[] = { "OPEN", "SHARED", "LEAP", NULL };
-const char * eap_allowed[] =      { "LEAP", "MD5", "TLS", "PEAP", "TTLS", "SIM",
-                                    "PSK", "FAST", "PWD", NULL };
-
-const char * phase1_allowed[] =   {"peapver=0", "peapver=1", "peaplabel=1",
-                                    "peap_outer_success=0", "include_tls_length=1",
-                                    "sim_min_num_chal=3", "fast_provisioning=0",
-                                    "fast_provisioning=1", "fast_provisioning=2",
-                                    "fast_provisioning=3", "tls_disable_tlsv1_0=0",
-                                    "tls_disable_tlsv1_0=1", "tls_disable_tlsv1_1=0",
-                                    "tls_disable_tlsv1_1=1", "tls_disable_tlsv1_2=0",
-                                    "tls_disable_tlsv1_2=1", NULL };
-const char * phase2_allowed[] =   {"auth=PAP", "auth=CHAP", "auth=MSCHAP",
-                                   "auth=MSCHAPV2", "auth=GTC", "auth=OTP",
-                                   "auth=MD5", "auth=TLS", "autheap=MD5",
-                                   "autheap=MSCHAPV2", "autheap=OTP",
-                                   "autheap=GTC", "autheap=TLS", NULL };
+static const char *const pairwise_allowed[] = { "CCMP", "TKIP", "NONE", NULL };
+static const char *const group_allowed[] =    { "CCMP", "TKIP", "WEP104", "WEP40", NULL };
+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",
+                                                "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",
+                                                "PSK", "FAST", "PWD", NULL };
+
+static const char *const phase1_allowed[] =   { "peapver=0", "peapver=1", "peaplabel=1",
+                                                "peap_outer_success=0", "include_tls_length=1",
+                                                "sim_min_num_chal=3", "fast_provisioning=0",
+                                                "fast_provisioning=1", "fast_provisioning=2",
+                                                "fast_provisioning=3", "tls_disable_tlsv1_0=0",
+                                                "tls_disable_tlsv1_0=1", "tls_disable_tlsv1_1=0",
+                                                "tls_disable_tlsv1_1=1", "tls_disable_tlsv1_2=0",
+                                                "tls_disable_tlsv1_2=1", NULL };
+static const char *const phase2_allowed[] =   { "auth=PAP", "auth=CHAP", "auth=MSCHAP",
+                                                "auth=MSCHAPV2", "auth=GTC", "auth=OTP",
+                                                "auth=MD5", "auth=TLS", "autheap=MD5",
+                                                "autheap=MSCHAPV2", "autheap=OTP",
+                                                "autheap=GTC", "autheap=TLS", NULL };
 
 static const struct Opt opt_table[] = {
 	{ "ssid",               TYPE_BYTES,   0, 32,FALSE,  NULL },
@@ -206,10 +206,7 @@ validate_type_keyword (const struct Opt * opt,
                        const char * value,
                        const guint32 len)
 {
-	char **allowed;
-	char **candidates = NULL;
-	char **candidate;
-	gboolean found = FALSE;
+	gs_free char *value_free = NULL;
 
 	g_return_val_if_fail (opt != NULL, FALSE);
 	g_return_val_if_fail (value != NULL, FALSE);
@@ -218,26 +215,33 @@ validate_type_keyword (const struct Opt * opt,
 	if (!opt->str_allowed)
 		return TRUE;
 
-	candidates = g_strsplit (value, " ", 0);
-	if (!candidates)
-		goto out;
+	value = nm_strndup_a (300, value, len, &value_free);
 
 	/* validate each space-separated word in 'value' */
-	for (candidate = candidates; *candidate; candidate++) {
-		found = FALSE;
-		for (allowed = (char **) opt->str_allowed; *allowed; allowed++) {
-			if (strcmp (*candidate, *allowed) == 0) {
-				found = TRUE;
-				break;
-			}
+
+	while (TRUE) {
+		char *s;
+
+		while (value[0] == ' ')
+			value++;
+
+		if (value[0] == '\0')
+			return TRUE;
+
+		s = strchr (value, ' ');
+		if (s) {
+			s[0] = '\0';
+			s++;
 		}
-		if (!found)
-			break;
-	}
 
-out:
-	g_strfreev (candidates);
-	return found;
+		if (nm_utils_strv_find_first ((char **) opt->str_allowed, -1, value) < 0)
+			return FALSE;
+
+		if (!s)
+			return TRUE;
+
+		value = s;
+	}
 }
 
 OptType
@@ -254,7 +258,9 @@ nm_supplicant_settings_verify_setting (const char * key,
 	g_return_val_if_fail (value != NULL, FALSE);
 
 	if (strcmp (key, "mode") == 0) {
-		if (strcmp (value, "1") && strcmp (value, "2") && strcmp (value, "5"))
+		if (len != 1)
+			return TYPE_INVALID;
+		if (!NM_IN_SET (value[0], '1', '2', '5'))
 			return TYPE_INVALID;
 		return TYPE_INT;
 	}