summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2020-01-31 12:10:14 +0100
committerMichael Biebl <biebl@debian.org>2020-01-31 12:10:14 +0100
commitf3c6d0765dff885e168b94f28e06ecc640315a74 (patch)
tree30d67309f4d9b48ad269dfad6e80e5c15373ea75 /src
parent90c93214efba0966274224a93a77d235d4f8c034 (diff)
New upstream version 1.22.6 upstream/1.22.6
Diffstat (limited to 'src')
-rw-r--r--src/devices/nm-device.c138
-rw-r--r--src/devices/nm-device.h1
-rw-r--r--src/dhcp/nm-dhcp-client.c29
-rw-r--r--src/dhcp/nm-dhcp-client.h3
-rw-r--r--src/dhcp/nm-dhcp-nettools.c10
-rw-r--r--src/dhcp/nm-dhcp-options.c2
-rw-r--r--src/dhcp/nm-dhcp-systemd.c8
-rw-r--r--src/initrd/nmi-cmdline-reader.c85
-rw-r--r--src/initrd/nmi-ibft-reader.c1
-rw-r--r--src/initrd/tests/test-cmdline-reader.c46
-rw-r--r--src/initrd/tests/test-ibft-reader.c3
-rw-r--r--src/ndisc/nm-ndisc.c2
-rw-r--r--src/nm-iface-helper.c1
-rw-r--r--src/nm-manager.c40
-rw-r--r--src/supplicant/nm-supplicant-interface.c2
15 files changed, 244 insertions, 127 deletions
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index e7a4a059..05104049 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -76,7 +76,7 @@ _LOG_DECLARE_SELF (NMDevice);
 /*****************************************************************************/
 
 #define DEFAULT_AUTOCONNECT    TRUE
-#define DHCP_GRACE_PERIOD_SEC  480
+#define DHCP_GRACE_PERIOD_MULTIPLIER 2U
 
 #define CARRIER_WAIT_TIME_MS 6000
 #define CARRIER_WAIT_TIME_AFTER_MTU_MS 10000
@@ -7474,6 +7474,41 @@ ensure_con_ip_config (NMDevice *self, int addr_family)
 /*****************************************************************************/
 /* DHCPv4 stuff */
 
+static guint32
+get_dhcp_timeout (NMDevice *self, int addr_family)
+{
+	NMDeviceClass *klass;
+	NMConnection *connection;
+	NMSettingIPConfig *s_ip;
+	guint32 timeout;
+
+	nm_assert (NM_IS_DEVICE (self));
+	nm_assert_addr_family (addr_family);
+
+	connection = nm_device_get_applied_connection (self);
+
+	s_ip = nm_connection_get_setting_ip_config (connection, addr_family);
+
+	timeout = nm_setting_ip_config_get_dhcp_timeout (s_ip);
+	if (timeout)
+		return timeout;
+
+	timeout = nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA,
+	                                                       addr_family == AF_INET
+	                                                         ? NM_CON_DEFAULT ("ipv4.dhcp-timeout")
+	                                                         : NM_CON_DEFAULT ("ipv6.dhcp-timeout"),
+	                                                       self,
+	                                                       0, G_MAXINT32, 0);
+	if (timeout)
+		return timeout;
+
+	klass = NM_DEVICE_GET_CLASS (self);
+	if (klass->get_dhcp_timeout)
+		timeout = klass->get_dhcp_timeout (self, addr_family);
+
+	return timeout ?: NM_DHCP_TIMEOUT_DEFAULT;
+}
+
 static void
 dhcp4_cleanup (NMDevice *self, CleanupType cleanup_type, gboolean release)
 {
@@ -7723,9 +7758,10 @@ ip_config_merge_and_apply (NMDevice *self,
 }
 
 static gboolean
-dhcp4_lease_change (NMDevice *self, NMIP4Config *config)
+dhcp4_lease_change (NMDevice *self, NMIP4Config *config, gboolean bound)
 {
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+	gs_free_error GError *error = NULL;
 
 	g_return_val_if_fail (config, FALSE);
 
@@ -7736,6 +7772,15 @@ dhcp4_lease_change (NMDevice *self, NMIP4Config *config)
 		return FALSE;
 	}
 
+	/* TODO: we should perform DAD again whenever we obtain a
+	 * new lease after an expiry. But what should we do if
+	 * a duplicate address is detected? Fail the connection;
+	 * restart DHCP; continue without an address? */
+	if (bound && !nm_dhcp_client_accept (priv->dhcp4.client, &error)) {
+		_LOGW (LOGD_DHCP4, "error accepting lease: %s", error->message);
+		return FALSE;
+	}
+
 	nm_dispatcher_call_device (NM_DISPATCHER_ACTION_DHCP4_CHANGE,
 	                           self,
 	                           NULL,
@@ -7799,12 +7844,24 @@ dhcp4_fail (NMDevice *self, NMDhcpState dhcp_state)
 	 * wait for some time before failing the IP method.
 	 */
 	if (!priv->dhcp4.grace_id) {
-		priv->dhcp4.grace_id = g_timeout_add_seconds (DHCP_GRACE_PERIOD_SEC,
+		guint32 timeout;
+
+		/* Start a grace period equal to the DHCP timeout multiplied
+		 * by a constant factor. */
+		timeout = get_dhcp_timeout (self, AF_INET);
+		if (timeout < G_MAXUINT32 / DHCP_GRACE_PERIOD_MULTIPLIER) {
+			timeout *= DHCP_GRACE_PERIOD_MULTIPLIER;
+			_LOGI (LOGD_DHCP4,
+			       "DHCPv4: trying to acquire a new lease within %u seconds",
+			       timeout);
+		} else {
+			timeout = G_MAXUINT32;
+			_LOGI (LOGD_DHCP4, "DHCPv4: trying to acquire a new lease");
+		}
+
+		priv->dhcp4.grace_id = g_timeout_add_seconds (timeout,
 		                                              dhcp4_grace_period_expired,
 		                                              self);
-		_LOGI (LOGD_DHCP4,
-		       "DHCPv4: %u seconds grace period started",
-		       DHCP_GRACE_PERIOD_SEC);
 		goto clear_config;
 	}
 	return;
@@ -7853,6 +7910,7 @@ dhcp4_state_changed (NMDhcpClient *client,
 
 	switch (state) {
 	case NM_DHCP_STATE_BOUND:
+	case NM_DHCP_STATE_EXTENDED:
 		if (!ip4_config) {
 			_LOGW (LOGD_DHCP4, "failed to get IPv4 config in response to DHCP event.");
 			dhcp4_fail (self, state);
@@ -7895,7 +7953,8 @@ dhcp4_state_changed (NMDhcpClient *client,
 
 			ipv4_dad_start (self, configs, dhcp4_dad_cb);
 		} else if (priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE) {
-			if (dhcp4_lease_change (self, ip4_config))
+			if (dhcp4_lease_change (self, ip4_config,
+			                        state == NM_DHCP_STATE_BOUND))
 				nm_device_update_metered (self);
 			else
 				dhcp4_fail (self, state);
@@ -7919,41 +7978,6 @@ dhcp4_state_changed (NMDhcpClient *client,
 	}
 }
 
-static int
-get_dhcp_timeout (NMDevice *self, int addr_family)
-{
-	NMDeviceClass *klass;
-	NMConnection *connection;
-	NMSettingIPConfig *s_ip;
-	guint32 timeout;
-
-	nm_assert (NM_IS_DEVICE (self));
-	nm_assert_addr_family (addr_family);
-
-	connection = nm_device_get_applied_connection (self);
-
-	s_ip = nm_connection_get_setting_ip_config (connection, addr_family);
-
-	timeout = nm_setting_ip_config_get_dhcp_timeout (s_ip);
-	if (timeout)
-		return timeout;
-
-	timeout = nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA,
-	                                                       addr_family == AF_INET
-	                                                         ? NM_CON_DEFAULT ("ipv4.dhcp-timeout")
-	                                                         : NM_CON_DEFAULT ("ipv6.dhcp-timeout"),
-	                                                       self,
-	                                                       0, G_MAXINT32, 0);
-	if (timeout)
-		return timeout;
-
-	klass = NM_DEVICE_GET_CLASS (self);
-	if (klass->get_dhcp_timeout)
-		timeout = klass->get_dhcp_timeout (self, addr_family);
-
-	return timeout ?: NM_DHCP_TIMEOUT_DEFAULT;
-}
-
 /**
  * dhcp_get_iaid:
  * @self: the #NMDevice
@@ -8627,12 +8651,24 @@ dhcp6_fail (NMDevice *self, NMDhcpState dhcp_state)
 		 * wait for some time before failing the IP method.
 		 */
 		if (!priv->dhcp6.grace_id) {
-			priv->dhcp6.grace_id = g_timeout_add_seconds (DHCP_GRACE_PERIOD_SEC,
+			guint32 timeout;
+
+			/* Start a grace period equal to the DHCP timeout multiplied
+			 * by a constant factor. */
+			timeout = get_dhcp_timeout (self, AF_INET6);
+			if (timeout < G_MAXUINT32 / DHCP_GRACE_PERIOD_MULTIPLIER) {
+				timeout *= DHCP_GRACE_PERIOD_MULTIPLIER;
+				_LOGI (LOGD_DHCP6,
+				       "DHCPv6: trying to acquire a new lease within %u seconds",
+				       timeout);
+			} else {
+				timeout = G_MAXUINT32;
+				_LOGI (LOGD_DHCP6, "DHCPv6: trying to acquire a new lease");
+			}
+
+			priv->dhcp6.grace_id = g_timeout_add_seconds (timeout,
 			                                              dhcp6_grace_period_expired,
 			                                              self);
-			_LOGI (LOGD_DHCP6,
-			       "DHCPv6: %u seconds grace period started",
-			       DHCP_GRACE_PERIOD_SEC);
 			goto clear_config;
 		}
 	} else {
@@ -8670,6 +8706,7 @@ dhcp6_state_changed (NMDhcpClient *client,
 
 	switch (state) {
 	case NM_DHCP_STATE_BOUND:
+	case NM_DHCP_STATE_EXTENDED:
 		nm_clear_g_source (&priv->dhcp6.grace_id);
 		/* If the server sends multiple IPv6 addresses, we receive a state
 		 * changed event for each of them. Use the event ID to merge IPv6
@@ -15515,6 +15552,12 @@ _set_state_full (NMDevice *self,
 	       reason_to_string_a (reason),
 	       _sys_iface_state_to_str (priv->sys_iface_state));
 
+	/* in order to prevent triggering any callback caused
+	 * by the device not having any pending action anymore
+	 * we add one here that gets removed at the end of the function */
+	nm_device_add_pending_action (self,
+	                              NM_PENDING_ACTION_IN_STATE_CHANGE,
+	                              TRUE);
 	priv->in_state_changed = TRUE;
 
 	priv->state = state;
@@ -15821,6 +15864,9 @@ _set_state_full (NMDevice *self,
 		g_object_unref (req);
 
 	priv->in_state_changed = FALSE;
+	nm_device_remove_pending_action (self,
+	                                 NM_PENDING_ACTION_IN_STATE_CHANGE,
+	                                 TRUE);
 
 	if ((old_state > NM_DEVICE_STATE_UNMANAGED) != (state > NM_DEVICE_STATE_UNMANAGED))
 		_notify (self, PROP_MANAGED);
diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h
index 518c66ca..66f9aa97 100644
--- a/src/devices/nm-device.h
+++ b/src/devices/nm-device.h
@@ -53,6 +53,7 @@ nm_device_state_reason_check (NMDeviceStateReason reason)
 }
 
 #define NM_PENDING_ACTION_AUTOACTIVATE              "autoactivate"
+#define NM_PENDING_ACTION_IN_STATE_CHANGE           "in-state-change"
 #define NM_PENDING_ACTION_RECHECK_AVAILABLE         "recheck-available"
 #define NM_PENDING_ACTION_CARRIER_WAIT              "carrier-wait"
 #define NM_PENDING_ACTION_WAITING_FOR_SUPPLICANT    "waiting-for-supplicant"
diff --git a/src/dhcp/nm-dhcp-client.c b/src/dhcp/nm-dhcp-client.c
index 0a07b26c..faac18e0 100644
--- a/src/dhcp/nm-dhcp-client.c
+++ b/src/dhcp/nm-dhcp-client.c
@@ -317,6 +317,7 @@ nm_dhcp_client_get_use_fqdn (NMDhcpClient *self)
 static const char *state_table[NM_DHCP_STATE_MAX + 1] = {
 	[NM_DHCP_STATE_UNKNOWN]    = "unknown",
 	[NM_DHCP_STATE_BOUND]      = "bound",
+	[NM_DHCP_STATE_EXTENDED]   = "extended",
 	[NM_DHCP_STATE_TIMEOUT]    = "timeout",
 	[NM_DHCP_STATE_EXPIRE]     = "expire",
 	[NM_DHCP_STATE_DONE]       = "done",
@@ -336,13 +337,14 @@ static NMDhcpState
 reason_to_state (NMDhcpClient *self, const char *iface, const char *reason)
 {
 	if (g_ascii_strcasecmp (reason, "bound") == 0 ||
-	    g_ascii_strcasecmp (reason, "bound6") == 0 ||
-	    g_ascii_strcasecmp (reason, "renew") == 0 ||
-	    g_ascii_strcasecmp (reason, "renew6") == 0 ||
-	    g_ascii_strcasecmp (reason, "reboot") == 0 ||
-	    g_ascii_strcasecmp (reason, "rebind") == 0 ||
-	    g_ascii_strcasecmp (reason, "rebind6") == 0)
+	    g_ascii_strcasecmp (reason, "bound6") == 0)
 		return NM_DHCP_STATE_BOUND;
+	else if (g_ascii_strcasecmp (reason, "renew") == 0 ||
+	         g_ascii_strcasecmp (reason, "renew6") == 0 ||
+	         g_ascii_strcasecmp (reason, "reboot") == 0 ||
+	         g_ascii_strcasecmp (reason, "rebind") == 0 ||
+	         g_ascii_strcasecmp (reason, "rebind6") == 0)
+		return NM_DHCP_STATE_EXTENDED;
 	else if (g_ascii_strcasecmp (reason, "timeout") == 0)
 		return NM_DHCP_STATE_TIMEOUT;
 	else if (g_ascii_strcasecmp (reason, "nak") == 0 ||
@@ -415,7 +417,7 @@ nm_dhcp_client_set_state (NMDhcpClient *self,
 	NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE (self);
 	gs_free char *event_id = NULL;
 
-	if (new_state == NM_DHCP_STATE_BOUND) {
+	if (NM_IN_SET (new_state, NM_DHCP_STATE_BOUND, NM_DHCP_STATE_EXTENDED)) {
 		g_return_if_fail (NM_IS_IP_CONFIG (ip_config, priv->addr_family));
 		g_return_if_fail (options);
 	} else {
@@ -430,10 +432,11 @@ nm_dhcp_client_set_state (NMDhcpClient *self,
 
 	/* The client may send same-state transitions for RENEW/REBIND events and
 	 * the lease may have changed, so handle same-state transitions for the
-	 * BOUND state.  Ignore same-state transitions for other events since
-	 * the lease won't have changed and the state was already handled.
+	 * EXTENDED and BOUND states.  Ignore same-state transitions for other
+	 * events since the lease won't have changed and the state was already handled.
 	 */
-	if ((priv->state == new_state) && (new_state != NM_DHCP_STATE_BOUND))
+	if (   (priv->state == new_state)
+	    && !NM_IN_SET (new_state, NM_DHCP_STATE_BOUND, NM_DHCP_STATE_EXTENDED))
 		return;
 
 	if (_LOGI_ENABLED ()) {
@@ -448,7 +451,7 @@ nm_dhcp_client_set_state (NMDhcpClient *self,
 	}
 
 	if (   priv->addr_family == AF_INET6
-	    && new_state == NM_DHCP_STATE_BOUND) {
+	    && NM_IN_SET (new_state, NM_DHCP_STATE_BOUND, NM_DHCP_STATE_EXTENDED)) {
 		char *start, *iaid;
 
 		iaid = g_hash_table_lookup (options, "iaid");
@@ -877,7 +880,7 @@ nm_dhcp_client_handle_event (gpointer unused,
 	_LOGD ("DHCP state '%s' -> '%s' (reason: '%s')",
 	       state_to_string (old_state), state_to_string (new_state), reason);
 
-	if (new_state == NM_DHCP_STATE_BOUND) {
+	if (NM_IN_SET (new_state, NM_DHCP_STATE_BOUND, NM_DHCP_STATE_EXTENDED)) {
 		GVariantIter iter;
 		const char *name;
 		GVariant *value;
@@ -918,7 +921,7 @@ nm_dhcp_client_handle_event (gpointer unused,
 		nm_dhcp_client_emit_ipv6_prefix_delegated (self, &prefix);
 	} else {
 		/* Fail if no valid IP config was received */
-		if (   new_state == NM_DHCP_STATE_BOUND
+		if (   NM_IN_SET (new_state, NM_DHCP_STATE_BOUND, NM_DHCP_STATE_EXTENDED)
 		    && !ip_config) {
 			_LOGW ("client bound but IP config not received");
 			new_state = NM_DHCP_STATE_FAIL;
diff --git a/src/dhcp/nm-dhcp-client.h b/src/dhcp/nm-dhcp-client.h
index 6a431fa8..884de850 100644
--- a/src/dhcp/nm-dhcp-client.h
+++ b/src/dhcp/nm-dhcp-client.h
@@ -43,7 +43,8 @@
 
 typedef enum {
 	NM_DHCP_STATE_UNKNOWN = 0,
-	NM_DHCP_STATE_BOUND,        /* new lease or lease changed */
+	NM_DHCP_STATE_BOUND,        /* new lease */
+	NM_DHCP_STATE_EXTENDED,     /* lease extended */
 	NM_DHCP_STATE_TIMEOUT,      /* timed out contacting server */
 	NM_DHCP_STATE_DONE,         /* client quit or stopped */
 	NM_DHCP_STATE_EXPIRE,       /* lease expired or NAKed */
diff --git a/src/dhcp/nm-dhcp-nettools.c b/src/dhcp/nm-dhcp-nettools.c
index b4c0a451..036a46ba 100644
--- a/src/dhcp/nm-dhcp-nettools.c
+++ b/src/dhcp/nm-dhcp-nettools.c
@@ -977,7 +977,7 @@ lease_save (NMDhcpNettools *self, NDhcp4ClientLease *lease, const char *lease_fi
 }
 
 static void
-bound4_handle (NMDhcpNettools *self, NDhcp4ClientLease *lease)
+bound4_handle (NMDhcpNettools *self, NDhcp4ClientLease *lease, gboolean extended)
 {
 	NMDhcpNettoolsPrivate *priv = NM_DHCP_NETTOOLS_GET_PRIVATE (self);
 	const char *iface = nm_dhcp_client_get_iface (NM_DHCP_CLIENT (self));
@@ -985,7 +985,7 @@ bound4_handle (NMDhcpNettools *self, NDhcp4ClientLease *lease)
 	gs_unref_hashtable GHashTable *options = NULL;
 	GError *error = NULL;
 
-	_LOGT ("lease available");
+	_LOGT ("lease available (%s)", extended ? "extended" : "new");
 
 	ip4_config = lease_to_ip4_config (nm_dhcp_client_get_multi_idx (NM_DHCP_CLIENT (self)),
 	                                  iface,
@@ -1006,7 +1006,7 @@ bound4_handle (NMDhcpNettools *self, NDhcp4ClientLease *lease)
 	lease_save (self, lease, priv->lease_file);
 
 	nm_dhcp_client_set_state (NM_DHCP_CLIENT (self),
-	                          NM_DHCP_STATE_BOUND,
+	                          extended ? NM_DHCP_STATE_EXTENDED : NM_DHCP_STATE_BOUND,
 	                          NM_IP_CONFIG_CAST (ip4_config),
 	                          options);
 }
@@ -1037,10 +1037,10 @@ dhcp4_event_handle (NMDhcpNettools *self,
 		break;
 	case N_DHCP4_CLIENT_EVENT_GRANTED:
 		priv->lease = n_dhcp4_client_lease_ref (event->granted.lease);
-		bound4_handle (self, event->granted.lease);
+		bound4_handle (self, event->granted.lease, FALSE);
 		break;
 	case N_DHCP4_CLIENT_EVENT_EXTENDED:
-		bound4_handle (self, event->extended.lease);
+		bound4_handle (self, event->extended.lease, TRUE);
 		break;
 	case N_DHCP4_CLIENT_EVENT_DOWN:
 		/* ignore down events, they are purely informational */
diff --git a/src/dhcp/nm-dhcp-options.c b/src/dhcp/nm-dhcp-options.c
index 4c003f31..1d391f3e 100644
--- a/src/dhcp/nm-dhcp-options.c
+++ b/src/dhcp/nm-dhcp-options.c
@@ -34,7 +34,7 @@ const NMDhcpOption _nm_dhcp_option_dhcp4_options[] = {
 	REQ (NM_DHCP_OPTION_DHCP4_NIS_DOMAIN,                        "nis_domain",                      TRUE ),
 	REQ (NM_DHCP_OPTION_DHCP4_NIS_SERVERS,                       "nis_servers",                     TRUE ),
 	REQ (NM_DHCP_OPTION_DHCP4_NTP_SERVER,                        "ntp_servers",                     TRUE ),
-	REQ (NM_DHCP_OPTION_DHCP4_SERVER_ID,                         "dhcp_server_identifier",          TRUE ),
+	REQ (NM_DHCP_OPTION_DHCP4_SERVER_ID,                         "dhcp_server_identifier",          FALSE ),
 	REQ (NM_DHCP_OPTION_DHCP4_DOMAIN_SEARCH_LIST,                "domain_search",                   TRUE ),
 	REQ (NM_DHCP_OPTION_DHCP4_PRIVATE_CLASSLESS_STATIC_ROUTE,    "ms_classless_static_routes",      TRUE ),
 	REQ (NM_DHCP_OPTION_DHCP4_PRIVATE_PROXY_AUTODISCOVERY,       "wpad",                            TRUE ),
diff --git a/src/dhcp/nm-dhcp-systemd.c b/src/dhcp/nm-dhcp-systemd.c
index 1518d465..6e6aa243 100644
--- a/src/dhcp/nm-dhcp-systemd.c
+++ b/src/dhcp/nm-dhcp-systemd.c
@@ -477,7 +477,7 @@ lease_to_ip4_config (NMDedupMultiIndex *multi_idx,
 /*****************************************************************************/
 
 static void
-bound4_handle (NMDhcpSystemd *self)
+bound4_handle (NMDhcpSystemd *self, gboolean extended)
 {
 	NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE (self);
 	const char *iface = nm_dhcp_client_get_iface (NM_DHCP_CLIENT (self));
@@ -514,7 +514,7 @@ bound4_handle (NMDhcpSystemd *self)
 	dhcp_lease_save (lease, priv->lease_file);
 
 	nm_dhcp_client_set_state (NM_DHCP_CLIENT (self),
-	                          NM_DHCP_STATE_BOUND,
+	                          extended ? NM_DHCP_STATE_EXTENDED : NM_DHCP_STATE_BOUND,
 	                          NM_IP_CONFIG_CAST (ip4_config),
 	                          options);
 }
@@ -538,8 +538,10 @@ dhcp_event_cb (sd_dhcp_client *client, int event, gpointer user_data)
 		break;
 	case SD_DHCP_CLIENT_EVENT_RENEW:
 	case SD_DHCP_CLIENT_EVENT_IP_CHANGE:
+		bound4_handle (self, TRUE);
+		break;
 	case SD_DHCP_CLIENT_EVENT_IP_ACQUIRE:
-		bound4_handle (self);
+		bound4_handle (self, FALSE);
 		break;
 	case SD_DHCP_CLIENT_EVENT_SELECTING:
 		break;
diff --git a/src/initrd/nmi-cmdline-reader.c b/src/initrd/nmi-cmdline-reader.c
index c32ef1cf..2cb93a2d 100644
--- a/src/initrd/nmi-cmdline-reader.c
+++ b/src/initrd/nmi-cmdline-reader.c
@@ -195,6 +195,47 @@ _base_setting_set (NMConnection *connection, const char *property, const char *v
 }
 
 static void
+read_all_connections_from_fw (GHashTable *connections, const char *sysfs_dir)
+{
+	gs_unref_hashtable GHashTable *ibft = NULL;
+	NMConnection *connection;
+	GHashTableIter iter;
+	const char *mac;
+	GHashTable *nic;
+	const char *index;
+	GError *error = NULL;
+
+	ibft = nmi_ibft_read (sysfs_dir);
+
+	g_hash_table_iter_init (&iter, ibft);
+	while (g_hash_table_iter_next (&iter, (gpointer *) &mac, (gpointer *) &nic)) {
+		connection = nm_simple_connection_new ();
+
+		index = g_hash_table_lookup (nic, "index");
+		if (!index) {
+			_LOGW (LOGD_CORE, "Ignoring an iBFT entry without an index");
+			continue;
+		}
+
+		if (!nmi_ibft_update_connection_from_nic (connection, nic, &error)) {
+			_LOGW (LOGD_CORE, "Unable to merge iBFT configuration: %s", error->message);
+			g_error_free (error);
+		}
+
+		g_hash_table_insert (connections,
+		                     g_strdup_printf ("ibft%s", index),
+		                     connection);
+	}
+
+	connection = nmi_dt_reader_parse (sysfs_dir);
+	if (connection) {
+		g_hash_table_insert (connections,
+		                     g_strdup ("ofw"),
+		                     connection);
+	}
+}
+
+static void
 parse_ip (GHashTable *connections, const char *sysfs_dir, char *argument)
 {
 	NMConnection *connection;
@@ -258,44 +299,7 @@ parse_ip (GHashTable *connections, const char *sysfs_dir, char *argument)
 
 	if (ifname == NULL && (   g_strcmp0 (kind, "fw") == 0
 	                       || g_strcmp0 (kind, "ibft") == 0)) {
-		GHashTableIter iter;
-		const char *mac;
-		GHashTable *nic;
-		const char *index;
-
-		/* This is the ip=ibft case. Just take all we got from iBFT
-		 * and don't process anything else, since there's no ifname
-		 * specified to apply it to. */
-		if (!ibft)
-			ibft = nmi_ibft_read (sysfs_dir);
-
-		g_hash_table_iter_init (&iter, ibft);
-		while (g_hash_table_iter_next (&iter, (gpointer)&mac, (gpointer)&nic)) {
-			connection = nm_simple_connection_new ();
-
-			index = g_hash_table_lookup (nic, "index");
-			if (!index) {
-				_LOGW (LOGD_CORE, "Ignoring an iBFT entry without an index");
-				continue;
-			}
-
-			if (!nmi_ibft_update_connection_from_nic (connection, nic, &error)) {
-				_LOGW (LOGD_CORE, "Unable to merge iBFT configuration: %s", error->message);
-				g_error_free (error);
-			}
-
-			g_hash_table_insert (connections,
-			                     g_strdup_printf ("ibft%s", index),
-			                     connection);
-		}
-
-		connection = nmi_dt_reader_parse (sysfs_dir);
-		if (connection) {
-			g_hash_table_insert (connections,
-			                     g_strdup ("ofw"),
-			                     connection);
-		}
-
+		read_all_connections_from_fw (connections, sysfs_dir);
 		return;
 	}
 
@@ -421,8 +425,7 @@ parse_ip (GHashTable *connections, const char *sysfs_dir, char *argument)
 		if (mac) {
 			g_strchomp (mac);
 			mac_up = g_ascii_strup (mac, -1);
-			if (!ibft)
-				ibft = nmi_ibft_read (sysfs_dir);
+			ibft = nmi_ibft_read (sysfs_dir);
 			nic = g_hash_table_lookup (ibft, mac_up);
 			if (!nic)
 				_LOGW (LOGD_CORE, "No iBFT NIC for %s (%s)", ifname, mac_up);
@@ -838,6 +841,8 @@ nmi_cmdline_reader_parse (const char *sysfs_dir, const char *const*argv)
 			parse_nameserver (connections, argument);
 		else if (strcmp (tag, "rd.peerdns") == 0)
 			parse_rd_peerdns (connections, argument);
+		else if (strcmp (tag, "rd.iscsi.ibft") == 0 && _nm_utils_ascii_str_to_bool (argument, TRUE))
+			read_all_connections_from_fw (connections, sysfs_dir);
 		else if (strcmp (tag, "rd.bootif") == 0)
 			ignore_bootif = !_nm_utils_ascii_str_to_bool (argument, TRUE);
 		else if (strcmp (tag, "rd.neednet") == 0)
diff --git a/src/initrd/nmi-ibft-reader.c b/src/initrd/nmi-ibft-reader.c
index ffce98fc..47b90ebf 100644
--- a/src/initrd/nmi-ibft-reader.c
+++ b/src/initrd/nmi-ibft-reader.c
@@ -296,6 +296,7 @@ connection_setting_add (GHashTable *nic,
 	              NM_SETTING_CONNECTION_TYPE, type,
 	              NM_SETTING_CONNECTION_UUID, uuid,
 	              NM_SETTING_CONNECTION_ID, id,
+	              NM_SETTING_CONNECTION_INTERFACE_NAME, NULL,
 	              NULL);
 
 	g_free (uuid);
diff --git a/src/initrd/tests/test-cmdline-reader.c b/src/initrd/tests/test-cmdline-reader.c
index 1d4bb9a6..8951e491 100644
--- a/src/initrd/tests/test-cmdline-reader.c
+++ b/src/initrd/tests/test-cmdline-reader.c
@@ -768,10 +768,30 @@ test_team (void)
 }
 
 static void
-test_ibft (void)
+test_ibft_ip_dev (void)
+{
+	const char *const*ARGV = NM_MAKE_STRV ("ip=eth0:ibft");
+	gs_unref_hashtable GHashTable *connections = NULL;
+	NMSettingConnection *s_con;
+	NMConnection *connection;
+
+	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, "eth0");
+	g_assert (connection);
+
+	s_con = nm_connection_get_setting_connection (connection);
+	g_assert (s_con);
+	g_assert_cmpstr (nm_setting_connection_get_connection_type (s_con), ==, NM_SETTING_VLAN_SETTING_NAME);
+	g_assert_cmpstr (nm_setting_connection_get_interface_name (s_con), ==, NULL);
+}
+
+static void
+_test_ibft_ip (const char *const*ARGV)
 {
 	gs_unref_hashtable GHashTable *connections = NULL;
-	const char *const*ARGV = NM_MAKE_STRV ("ip=ibft");
 	NMConnection *connection;
 
 	connections = nmi_cmdline_reader_parse (TEST_INITRD_DIR "/sysfs", ARGV);
@@ -782,11 +802,29 @@ test_ibft (void)
 	g_assert (connection);
 	nmtst_assert_connection_verifies_without_normalization (connection);
 	g_assert_cmpstr (nm_connection_get_id (connection), ==, "iBFT VLAN Connection 0");
+	g_assert_cmpstr (nm_connection_get_interface_name (connection), ==, NULL);
 
 	connection = g_hash_table_lookup (connections, "ibft2");
 	g_assert (connection);
 	nmtst_assert_connection_verifies_without_normalization (connection);
 	g_assert_cmpstr (nm_connection_get_id (connection), ==, "iBFT Connection 2");
+	g_assert_cmpstr (nm_connection_get_interface_name (connection), ==, NULL);
+}
+
+static void
+test_ibft_ip (void)
+{
+	const char *const*ARGV = NM_MAKE_STRV ("ip=ibft");
+
+	_test_ibft_ip (ARGV);
+}
+
+static void
+test_ibft_rd_iscsi_ibft (void)
+{
+	const char *const*ARGV = NM_MAKE_STRV ("rd.iscsi.ibft");
+
+	_test_ibft_ip (ARGV);
 }
 
 static void
@@ -1045,7 +1083,9 @@ int main (int argc, char **argv)
 	g_test_add_func ("/initrd/cmdline/team", test_team);
 	g_test_add_func ("/initrd/cmdline/bridge", test_bridge);
 	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/ibft/ip_dev", test_ibft_ip_dev);
+	g_test_add_func ("/initrd/cmdline/ibft/ip", test_ibft_ip);
+	g_test_add_func ("/initrd/cmdline/ibft/rd_iscsi_ibft", test_ibft_rd_iscsi_ibft);
 	g_test_add_func ("/initrd/cmdline/ignore_extra", test_ignore_extra);
 	g_test_add_func ("/initrd/cmdline/rd_znet", test_rd_znet);
 	g_test_add_func ("/initrd/cmdline/rd_znet/legacy", test_rd_znet_legacy);
diff --git a/src/initrd/tests/test-ibft-reader.c b/src/initrd/tests/test-ibft-reader.c
index 932c1a48..f7709543 100644
--- a/src/initrd/tests/test-ibft-reader.c
+++ b/src/initrd/tests/test-ibft-reader.c
@@ -65,6 +65,7 @@ test_read_ibft_dhcp (void)
 	g_assert (s_con);
 	g_assert_cmpstr (nm_setting_connection_get_connection_type (s_con), ==, NM_SETTING_WIRED_SETTING_NAME);
 	g_assert_cmpstr (nm_setting_connection_get_id (s_con), ==, "iBFT Connection 1");
+	g_assert_cmpstr (nm_setting_connection_get_interface_name (s_con), ==, NULL);
 	g_assert_cmpint (nm_setting_connection_get_timestamp (s_con), ==, 0);
 	g_assert (nm_setting_connection_get_autoconnect (s_con));
 
@@ -109,6 +110,7 @@ test_read_ibft_static (void)
 	g_assert (s_con);
 	g_assert_cmpstr (nm_setting_connection_get_connection_type (s_con), ==, NM_SETTING_WIRED_SETTING_NAME);
 	g_assert_cmpstr (nm_setting_connection_get_id (s_con), ==, "iBFT Connection 0");
+	g_assert_cmpstr (nm_setting_connection_get_interface_name (s_con), ==, NULL);
 	g_assert_cmpint (nm_setting_connection_get_timestamp (s_con), ==, 0);
 	g_assert (nm_setting_connection_get_autoconnect (s_con));
 
@@ -178,6 +180,7 @@ test_read_ibft_vlan (void)
 	s_con = nm_connection_get_setting_connection (connection);
 	g_assert (s_con);
 	g_assert_cmpstr (nm_setting_connection_get_connection_type (s_con), ==, NM_SETTING_VLAN_SETTING_NAME);
+	g_assert_cmpstr (nm_setting_connection_get_interface_name (s_con), ==, NULL);
 
 	/* ===== WIRED SETTING ===== */
 	s_wired = nm_connection_get_setting_wired (connection);
diff --git a/src/ndisc/nm-ndisc.c b/src/ndisc/nm-ndisc.c
index 41201e24..8dda03a7 100644
--- a/src/ndisc/nm-ndisc.c
+++ b/src/ndisc/nm-ndisc.c
@@ -923,7 +923,7 @@ nm_ndisc_start (NMNDisc *ndisc)
 	switch (priv->node_type) {
 	case NM_NDISC_NODE_TYPE_HOST:
 		ra_wait_secs = (((gint64) priv->router_solicitations) * priv->router_solicitation_interval) + 1;
-		ra_wait_secs = CLAMP (ra_wait_secs, 30, 120);
+		ra_wait_secs = MAX (ra_wait_secs, 30);
 		priv->ra_timeout_id = g_timeout_add_seconds (ra_wait_secs, ndisc_ra_timeout_cb, ndisc);
 		_LOGD ("scheduling RA timeout in %d seconds", (int) ra_wait_secs);
 		solicit_routers (ndisc);
diff --git a/src/nm-iface-helper.c b/src/nm-iface-helper.c
index bfb7af57..20a0b674 100644
--- a/src/nm-iface-helper.c
+++ b/src/nm-iface-helper.c
@@ -106,6 +106,7 @@ dhcp4_state_changed (NMDhcpClient *client,
 
 	switch (state) {
 	case NM_DHCP_STATE_BOUND:
+	case NM_DHCP_STATE_EXTENDED:
 		g_assert (ip4_config);
 		g_assert (nm_ip4_config_get_ifindex (ip4_config) == gl.ifindex);
 
diff --git a/src/nm-manager.c b/src/nm-manager.c
index 3696c789..6d3a5ddb 100644
--- a/src/nm-manager.c
+++ b/src/nm-manager.c
@@ -2011,6 +2011,20 @@ system_create_virtual_device (NMManager *self, NMConnection *connection)
 		return device;
 	}
 
+	if (!find_master (self,
+	                  connection,
+	                  device,
+	                  NULL,
+	                  NULL,
+	                  NULL,
+	                  &error)) {
+		_LOG3D (LOGD_DEVICE, connection,
+		        "skip activation: %s",
+		        error->message);
+		g_error_free (error);
+		return device;
+	}
+
 	/* Create backing resources if the device has any autoconnect connections */
 	connections = nm_settings_get_connections_clone (priv->settings, NULL,
 	                                                 NULL, NULL,
@@ -4649,6 +4663,19 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError *
 	if (nm_active_connection_get_activation_type (active) == NM_ACTIVATION_TYPE_MANAGED)
 		nm_device_sys_iface_state_set (device, NM_DEVICE_SYS_IFACE_STATE_MANAGED);
 
+	/* Try to find the master connection/device if the connection has a dependency */
+	if (!find_master (self,
+	                  applied,
+	                  device,
+	                  &master_connection,
+	                  &master_device,
+	                  &master_ac,
+	                  error)) {
+		g_prefix_error (error, "Can not find a master for %s: ",
+		                nm_settings_connection_get_id (sett_conn));
+		return FALSE;
+	}
+
 	/* Create any backing resources the device needs */
 	if (!nm_device_is_real (device)) {
 		NMDevice *parent;
@@ -4717,19 +4744,6 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError *
 		}
 	}
 
-	/* Try to find the master connection/device if the connection has a dependency */
-	if (!find_master (self,
-	                  applied,
-	                  device,
-	                  &master_connection,
-	                  &master_device,
-	                  &master_ac,
-	                  error)) {
-		g_prefix_error (error, "Can not find a master for %s: ",
-		                nm_settings_connection_get_id (sett_conn));
-		return FALSE;
-	}
-
 	/* Ensure there's a master active connection the new connection we're
 	 * activating can depend on.
 	 */
diff --git a/src/supplicant/nm-supplicant-interface.c b/src/supplicant/nm-supplicant-interface.c
index 6ef29311..c19da11c 100644
--- a/src/supplicant/nm-supplicant-interface.c
+++ b/src/supplicant/nm-supplicant-interface.c
@@ -3184,5 +3184,5 @@ nm_supplicant_interface_class_init (NMSupplicantInterfaceClass *klass)
 	                  G_SIGNAL_RUN_LAST,
 	                  0,
 	                  NULL, NULL, NULL,
-	                  G_TYPE_NONE, 1, G_TYPE_VARIANT);
+	                  G_TYPE_NONE, 1, G_TYPE_STRING);
 }