summary refs log tree commit diff
path: root/src/devices
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices')
-rw-r--r--src/devices/nm-device-factory.c5
-rw-r--r--src/devices/nm-device-infiniband.c67
-rw-r--r--src/devices/nm-device-macvlan.c9
-rw-r--r--src/devices/nm-device-vlan.c57
-rw-r--r--src/devices/nm-device.c76
-rw-r--r--src/devices/nm-device.h10
-rw-r--r--src/devices/wwan/nm-modem.c3
7 files changed, 162 insertions, 65 deletions
diff --git a/src/devices/nm-device-factory.c b/src/devices/nm-device-factory.c
index 9dfa9bcb..482eb185 100644
--- a/src/devices/nm-device-factory.c
+++ b/src/devices/nm-device-factory.c
@@ -187,10 +187,9 @@ nm_device_factory_get_connection_iface (NMDeviceFactory *factory,
 
 	klass = NM_DEVICE_FACTORY_GET_INTERFACE (factory);
 
-	if (klass->get_connection_iface)
+	ifname = g_strdup (nm_connection_get_interface_name (connection));
+	if (!ifname && klass->get_connection_iface)
 		ifname = klass->get_connection_iface (factory, connection, parent_iface);
-	else
-		ifname = g_strdup (nm_connection_get_interface_name (connection));
 
 	if (!ifname) {
 		g_set_error (error,
diff --git a/src/devices/nm-device-infiniband.c b/src/devices/nm-device-infiniband.c
index a27af314..ae9543e4 100644
--- a/src/devices/nm-device-infiniband.c
+++ b/src/devices/nm-device-infiniband.c
@@ -42,6 +42,7 @@ G_DEFINE_TYPE (NMDeviceInfiniband, nm_device_infiniband, NM_TYPE_DEVICE)
 
 typedef struct {
 	gboolean is_partition;
+	int parent_ifindex, p_key;
 } NMDeviceInfinibandPrivate;
 
 enum {
@@ -235,36 +236,43 @@ create_and_realize (NMDevice *device,
                     const NMPlatformLink **out_plink,
                     GError **error)
 {
+	NMDeviceInfinibandPrivate *priv = NM_DEVICE_INFINIBAND_GET_PRIVATE (device);
 	NMSettingInfiniband *s_infiniband;
-	int parent_ifindex, p_key;
 	NMPlatformError plerr;
 
-	if (!NM_IS_DEVICE_INFINIBAND (parent)) {
-		g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED,
-		             "Parent interface %s must be an InfiniBand interface",
-		             nm_device_get_iface (parent));
-		return FALSE;
-	}
-
 	s_infiniband = nm_connection_get_setting_infiniband (connection);
+	g_assert (s_infiniband);
 
 	/* Can only create partitions at this time */
-	p_key = nm_setting_infiniband_get_p_key (s_infiniband);
-	if (p_key < 0) {
-		g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED,
+	priv->p_key = nm_setting_infiniband_get_p_key (s_infiniband);
+	if (priv->p_key < 0) {
+		g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED,
 		                     "only InfiniBand partitions can be created");
 		return FALSE;
 	}
 
-	parent_ifindex = nm_device_get_ifindex (parent);
-	if (parent_ifindex <= 0) {
-		g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED,
+	if (!parent) {
+		g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED,
+		             "InfiniBand partitions can not be created without a parent interface");
+		return FALSE;
+	}
+
+	if (!NM_IS_DEVICE_INFINIBAND (parent)) {
+		g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED,
+		             "Parent interface %s must be an InfiniBand interface",
+		             nm_device_get_iface (parent));
+		return FALSE;
+	}
+
+	priv->parent_ifindex = nm_device_get_ifindex (parent);
+	if (priv->parent_ifindex <= 0) {
+		g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED,
 		             "failed to get InfiniBand parent %s ifindex",
 		             nm_device_get_iface (parent));
 		return FALSE;
 	}
 
-	plerr = nm_platform_link_infiniband_add (NM_PLATFORM_GET, parent_ifindex, p_key, out_plink);
+	plerr = nm_platform_link_infiniband_add (NM_PLATFORM_GET, priv->parent_ifindex, priv->p_key, out_plink);
 	if (plerr != NM_PLATFORM_ERROR_SUCCESS) {
 		g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED,
 		             "Failed to create InfiniBand P_Key interface '%s' for '%s': %s",
@@ -274,7 +282,33 @@ create_and_realize (NMDevice *device,
 		return FALSE;
 	}
 
-	NM_DEVICE_INFINIBAND_GET_PRIVATE (device)->is_partition = TRUE;
+	priv->is_partition = TRUE;
+	return TRUE;
+}
+
+static gboolean
+unrealize (NMDevice *device, GError **error)
+{
+	NMDeviceInfinibandPrivate *priv = NM_DEVICE_INFINIBAND_GET_PRIVATE (device);
+	NMPlatformError plerr;
+
+	g_return_val_if_fail (NM_IS_DEVICE_INFINIBAND (device), FALSE);
+
+	if (priv->p_key < 0) {
+		g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED,
+		             "Only InfiniBand partitions can be removed");
+		return FALSE;
+	}
+
+	plerr = nm_platform_link_infiniband_delete (NM_PLATFORM_GET, priv->parent_ifindex, priv->p_key);
+	if (plerr != NM_PLATFORM_ERROR_SUCCESS) {
+		g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED,
+		             "Failed to remove InfiniBand P_Key interface '%s': %s",
+		             nm_device_get_iface (device),
+		             nm_platform_error_to_string (plerr));
+		return FALSE;
+	}
+
 	return TRUE;
 }
 
@@ -328,6 +362,7 @@ nm_device_infiniband_class_init (NMDeviceInfinibandClass *klass)
 	object_class->set_property = set_property;
 
 	parent_class->create_and_realize = create_and_realize;
+	parent_class->unrealize = unrealize;
 	parent_class->get_generic_capabilities = get_generic_capabilities;
 	parent_class->check_connection_compatible = check_connection_compatible;
 	parent_class->complete_connection = complete_connection;
diff --git a/src/devices/nm-device-macvlan.c b/src/devices/nm-device-macvlan.c
index cd02cb8e..c431fe89 100644
--- a/src/devices/nm-device-macvlan.c
+++ b/src/devices/nm-device-macvlan.c
@@ -223,12 +223,19 @@ create_and_realize (NMDevice *device,
 	s_macvlan = nm_connection_get_setting_macvlan (connection);
 	g_assert (s_macvlan);
 
+	if (!parent) {
+		g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED,
+		             "MACVLAN devices can not be created without a parent interface");
+		return FALSE;
+	}
+
 	parent_ifindex = nm_device_get_ifindex (parent);
 	g_warn_if_fail (parent_ifindex > 0);
 
 	lnk.mode = setting_mode_to_platform (nm_setting_macvlan_get_mode (s_macvlan));
 	if (!lnk.mode) {
-		nm_log_info (LOGD_DEVICE, "unsupported MACVLAN mode %u in connection %s",
+		g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED,
+		             "unsupported MACVLAN mode %u in connection %s",
 		             nm_setting_macvlan_get_mode (s_macvlan),
 		             nm_connection_get_uuid (connection));
 		return FALSE;
diff --git a/src/devices/nm-device-vlan.c b/src/devices/nm-device-vlan.c
index 4d606e9d..eb6527de 100644
--- a/src/devices/nm-device-vlan.c
+++ b/src/devices/nm-device-vlan.c
@@ -80,14 +80,14 @@ parent_state_changed (NMDevice *parent,
 }
 
 static void
-parent_hwaddr_changed (NMDevice *parent,
-                       GParamSpec *pspec,
-                       gpointer user_data)
+parent_hwaddr_maybe_changed (NMDevice *parent,
+                             GParamSpec *pspec,
+                             gpointer user_data)
 {
 	NMDeviceVlan *self = NM_DEVICE_VLAN (user_data);
 	NMConnection *connection;
 	NMSettingWired *s_wired;
-	const char *cloned_mac = NULL, *new_mac;
+	const char *new_mac, *old_mac;
 	NMSettingIPConfig *s_ip6;
 
 	/* Never touch assumed devices */
@@ -100,23 +100,26 @@ parent_hwaddr_changed (NMDevice *parent,
 
 	/* Update the VLAN MAC only if configuration does not specify one */
 	s_wired = nm_connection_get_setting_wired (connection);
-	if (s_wired)
-		cloned_mac = nm_setting_wired_get_cloned_mac_address (s_wired);
+	if (s_wired) {
+		if (nm_setting_wired_get_cloned_mac_address (s_wired))
+			return;
+	}
 
-	if (!cloned_mac) {
-		new_mac = nm_device_get_hw_address (parent);
-		_LOGD (LOGD_VLAN, "parent hardware address changed to %s%s%s",
-		       NM_PRINT_FMT_QUOTE_STRING (new_mac));
-		if (new_mac) {
-			nm_device_set_hw_addr (self, nm_device_get_hw_address (parent),
-			                       "set", LOGD_VLAN);
-			/* When changing the hw address the interface is taken down,
-			 * removing the IPv6 configuration; reapply it.
-			 */
-			s_ip6 = nm_connection_get_setting_ip6_config (connection);
-			if (s_ip6)
-				nm_device_reactivate_ip6_config (NM_DEVICE (self), s_ip6, s_ip6);
-		}
+	old_mac = nm_device_get_hw_address (self);
+	new_mac = nm_device_get_hw_address (parent);
+	if (nm_streq0 (old_mac, new_mac))
+		return;
+
+	_LOGD (LOGD_VLAN, "parent hardware address changed to %s%s%s",
+	       NM_PRINT_FMT_QUOTE_STRING (new_mac));
+	if (new_mac) {
+		nm_device_set_hw_addr (self, new_mac, "set", LOGD_VLAN);
+		/* When changing the hw address the interface is taken down,
+		 * removing the IPv6 configuration; reapply it.
+		 */
+		s_ip6 = nm_connection_get_setting_ip6_config (connection);
+		if (s_ip6)
+			nm_device_reactivate_ip6_config (NM_DEVICE (self), s_ip6, s_ip6);
 	}
 }
 
@@ -141,7 +144,8 @@ nm_device_vlan_set_parent (NMDeviceVlan *self, NMDevice *parent)
 		                                          device);
 
 		priv->parent_hwaddr_id = g_signal_connect (priv->parent, "notify::" NM_DEVICE_HW_ADDRESS,
-		                                           G_CALLBACK (parent_hwaddr_changed), device);
+		                                           G_CALLBACK (parent_hwaddr_maybe_changed), device);
+		parent_hwaddr_maybe_changed (parent, NULL, self);
 
 		/* Set parent-dependent unmanaged flag */
 		nm_device_set_unmanaged_by_flags (device,
@@ -218,6 +222,12 @@ create_and_realize (NMDevice *device,
 	s_vlan = nm_connection_get_setting_vlan (connection);
 	g_assert (s_vlan);
 
+	if (!parent) {
+		g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED,
+		             "VLAN devices can not be created without a parent interface");
+		return FALSE;
+	}
+
 	if (!nm_device_supports_vlans (parent)) {
 		g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED,
 		             "no support for VLANs on interface %s of type %s",
@@ -537,6 +547,7 @@ update_connection (NMDevice *device, NMConnection *connection)
 static NMActStageReturn
 act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
 {
+	NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (dev);
 	NMSettingVlan *s_vlan;
 	NMSettingWired *s_wired;
 	const char *cloned_mac;
@@ -555,6 +566,10 @@ act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
 		nm_device_set_hw_addr (dev, cloned_mac, "set", LOGD_VLAN);
 	}
 
+	/* Change MAC address to parent's one if needed */
+	if (priv->parent)
+		parent_hwaddr_maybe_changed (priv->parent, NULL, dev);
+
 	s_vlan = (NMSettingVlan *) nm_device_get_applied_setting (dev, NM_TYPE_SETTING_VLAN);
 	if (s_vlan) {
 		gs_free NMVlanQosMapping *ingress_map = NULL;
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index 3d949ec2..08cf6dce 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -280,11 +280,11 @@ typedef struct _NMDevicePrivate {
 	NMIP4Config *   wwan_ip4_config; /* WWAN configuration */
 	GSList *        vpn4_configs;   /* VPNs which use this device */
 	struct {
-		gboolean v4_has;
-		gboolean v4_is_assumed;
+		bool v4_has;
+		bool v4_is_assumed;
+		bool v6_has;
+		bool v6_is_assumed;
 		NMPlatformIP4Route v4;
-		gboolean v6_has;
-		gboolean v6_is_assumed;
 		NMPlatformIP6Route v6;
 	} default_route;
 
@@ -878,6 +878,34 @@ nm_device_get_ip6_route_metric (NMDevice *self)
 	return _get_ipx_route_metric (self, FALSE);
 }
 
+static void
+_update_default_route (NMDevice *self, int addr_family, gboolean has, gboolean is_assumed)
+{
+	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+	bool *p_has, *p_is_assumed;
+
+	nm_assert (NM_IN_SET (addr_family, 0, AF_INET, AF_INET6));
+
+	if (addr_family == AF_INET) {
+		p_has = &priv->default_route.v4_has;
+		p_is_assumed = &priv->default_route.v4_is_assumed;
+	} else {
+		p_has = &priv->default_route.v6_has;
+		p_is_assumed = &priv->default_route.v6_is_assumed;
+	}
+
+	if (*p_has == has && *p_is_assumed == is_assumed)
+		return;
+
+	*p_has = has;
+	*p_is_assumed = is_assumed;
+
+	if (addr_family == AF_INET)
+		nm_default_route_manager_ip4_update_default_route (nm_default_route_manager_get (), self);
+	else
+		nm_default_route_manager_ip6_update_default_route (nm_default_route_manager_get (), self);
+}
+
 const NMPlatformIP4Route *
 nm_device_get_ip4_default_route (NMDevice *self, gboolean *out_is_assumed)
 {
@@ -2067,8 +2095,12 @@ nm_device_unrealize (NMDevice *self, gboolean remove_resources, GError **error)
 	_LOGD (LOGD_DEVICE, "unrealize (ifindex %d)", ifindex > 0 ? ifindex : 0);
 
 	if (remove_resources) {
-		if (ifindex > 0)
+		if (NM_DEVICE_GET_CLASS (self)->unrealize) {
+			if (!NM_DEVICE_GET_CLASS (self)->unrealize (self, error))
+				return FALSE;
+		} else if (ifindex > 0) {
 			nm_platform_link_delete (NM_PLATFORM_GET, ifindex);
+		}
 	}
 
 	NM_DEVICE_GET_CLASS (self)->unrealize_notify (self);
@@ -2568,12 +2600,14 @@ nm_device_get_enslaved (NMDevice *self)
 /**
  * nm_device_removed:
  * @self: the #NMDevice
+ * @unconfigure_ip_config: whether to clear the IP config objects
+ *   of the device (provided, it is still not cleared at this point).
  *
  * Called by the manager when the device was removed. Releases the device from
  * the master in case it's enslaved.
  */
 void
-nm_device_removed (NMDevice *self)
+nm_device_removed (NMDevice *self, gboolean unconfigure_ip_config)
 {
 	NMDevicePrivate *priv;
 
@@ -2586,16 +2620,19 @@ nm_device_removed (NMDevice *self)
 		nm_device_master_release_one_slave (priv->master, self, FALSE, NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED);
 	}
 
+	if (!unconfigure_ip_config)
+		return;
+
 	/* Clean up IP configs; this does not actually deconfigure the
 	 * interface, it just clears the configuration to which policy
 	 * is reacting via NM_DEVICE_IP4_CONFIG_CHANGED/NM_DEVICE_IP6_CONFIG_CHANGED
 	 * signal. As NMPolicy registered the NMIPxConfig instances in NMDnsManager,
 	 * these would be leaked otherwise. */
-	priv->default_route.v4_has = FALSE;
-	priv->default_route.v4_is_assumed = TRUE;
+	_update_default_route (self, AF_INET,  priv->default_route.v4_has, TRUE);
+	_update_default_route (self, AF_INET6, priv->default_route.v6_has, TRUE);
+	_update_default_route (self, AF_INET,  FALSE, TRUE);
+	_update_default_route (self, AF_INET6, FALSE, TRUE);
 	nm_device_set_ip4_config (self, NULL, 0, FALSE, FALSE, NULL);
-	priv->default_route.v6_has = FALSE;
-	priv->default_route.v6_is_assumed = TRUE;
 	nm_device_set_ip6_config (self, NULL, FALSE, FALSE, NULL);
 }
 
@@ -9994,20 +10031,15 @@ _cleanup_generic_post (NMDevice *self, CleanupType cleanup_type)
 {
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
 
-	priv->default_route.v4_has = FALSE;
-	priv->default_route.v6_has = FALSE;
-
 	if (cleanup_type == CLEANUP_TYPE_DECONFIGURE) {
-		priv->default_route.v4_is_assumed = FALSE;
-		priv->default_route.v6_is_assumed = FALSE;
-		nm_default_route_manager_ip4_update_default_route (nm_default_route_manager_get (), self);
-		nm_default_route_manager_ip6_update_default_route (nm_default_route_manager_get (), self);
+		_update_default_route (self, AF_INET,  FALSE, FALSE);
+		_update_default_route (self, AF_INET6, FALSE, FALSE);
+	} else {
+		_update_default_route (self, AF_INET,  priv->default_route.v4_has, TRUE);
+		_update_default_route (self, AF_INET6, priv->default_route.v6_has, TRUE);
 	}
-
-	priv->default_route.v4_is_assumed = TRUE;
-	priv->default_route.v6_is_assumed = TRUE;
-	nm_default_route_manager_ip4_update_default_route (nm_default_route_manager_get (), self);
-	nm_default_route_manager_ip6_update_default_route (nm_default_route_manager_get (), self);
+	_update_default_route (self, AF_INET,  FALSE, TRUE);
+	_update_default_route (self, AF_INET6, FALSE, TRUE);
 
 	priv->v4_commit_first_time = TRUE;
 	priv->v6_commit_first_time = TRUE;
diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h
index 368e77f7..9f689850 100644
--- a/src/devices/nm-device.h
+++ b/src/devices/nm-device.h
@@ -180,6 +180,14 @@ typedef struct {
 	void        (*realize_start_notify) (NMDevice *self, const NMPlatformLink *plink);
 
 	/**
+	 * unrealize():
+	 * @self: the #NMDevice
+	 *
+	 * Remove the device backing resources.
+	 */
+	gboolean               (*unrealize) (NMDevice *self, GError **error);
+
+	/**
 	 * unrealize_notify():
 	 * @self: the #NMDevice
 	 *
@@ -377,7 +385,7 @@ gboolean        nm_device_has_unmodified_applied_connection (NMDevice *self,
                                                              NMSettingCompareFlags compare_flags);
 NMSetting *     nm_device_get_applied_setting   (NMDevice *dev, GType setting_type);
 
-void            nm_device_removed               (NMDevice *dev);
+void            nm_device_removed               (NMDevice *self, gboolean unconfigure_ip_config);
 
 gboolean        nm_device_is_available          (NMDevice *dev, NMDeviceCheckDevAvailableFlags flags);
 gboolean        nm_device_has_carrier           (NMDevice *dev);
diff --git a/src/devices/wwan/nm-modem.c b/src/devices/wwan/nm-modem.c
index 2a8a9d1e..804a6d9c 100644
--- a/src/devices/wwan/nm-modem.c
+++ b/src/devices/wwan/nm-modem.c
@@ -742,7 +742,8 @@ cancel_get_secrets (NMModem *self)
 {
 	NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self);
 
-	nm_act_request_cancel_secrets (priv->act_request, priv->secrets_id);
+	if (priv->secrets_id)
+		nm_act_request_cancel_secrets (priv->act_request, priv->secrets_id);
 }
 
 static void