summary refs log tree commit diff
path: root/src/devices/nm-device-tun.c
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2018-04-23 18:00:21 +0200
committerMichael Biebl <biebl@debian.org>2018-04-23 18:00:21 +0200
commitf60117b41d5433be1b4a96d82cd11d0c3dce9b63 (patch)
tree2dd55c4ab0fdcbe9cddb26adb4a554b1a45c73c8 /src/devices/nm-device-tun.c
parent7e9ff09fcb2366b383b7ebbec80d2f6fff117290 (diff)
New upstream version 1.11.3 upstream/1.11.3
Diffstat (limited to 'src/devices/nm-device-tun.c')
-rw-r--r--src/devices/nm-device-tun.c355
1 files changed, 179 insertions, 176 deletions
diff --git a/src/devices/nm-device-tun.c b/src/devices/nm-device-tun.c
index a7d7c0bf..c3ce4b73 100644
--- a/src/devices/nm-device-tun.c
+++ b/src/devices/nm-device-tun.c
@@ -25,6 +25,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sys/types.h>
+#include <linux/if_tun.h>
 
 #include "nm-act-request.h"
 #include "nm-device-private.h"
@@ -34,8 +35,6 @@
 #include "nm-setting-tun.h"
 #include "nm-core-internal.h"
 
-#include "introspection/org.freedesktop.NetworkManager.Device.Tun.h"
-
 #include "nm-device-logging.h"
 _LOG_DECLARE_SELF(NMDeviceTun);
 
@@ -51,8 +50,7 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMDeviceTun,
 );
 
 typedef struct {
-	NMPlatformTunProperties props;
-	const char *mode;
+	NMPlatformLnkTun props;
 } NMDeviceTunPrivate;
 
 struct _NMDeviceTun {
@@ -71,48 +69,62 @@ G_DEFINE_TYPE (NMDeviceTun, nm_device_tun, NM_TYPE_DEVICE)
 /*****************************************************************************/
 
 static void
-update_properties (NMDeviceTun *self)
+update_properties_from_struct (NMDeviceTun *self,
+                               const NMPlatformLnkTun *props)
 {
 	NMDeviceTunPrivate *priv = NM_DEVICE_TUN_GET_PRIVATE (self);
-	GObject *object = G_OBJECT (self);
-	NMPlatformTunProperties props;
+	const NMPlatformLnkTun props0 = { };
+
+	if (!props) {
+		/* allow passing %NULL to reset all properties. */
+		props = &props0;
+	}
+
+	g_object_freeze_notify (G_OBJECT (self));
+
+#define CHECK_PROPERTY_CHANGED_VALID(field, prop) \
+	G_STMT_START { \
+		if (   priv->props.field != props->field \
+		    || priv->props.field##_valid != props->field##_valid) { \
+			priv->props.field##_valid = props->field##_valid; \
+			priv->props.field = props->field; \
+			_notify (self, prop); \
+		} \
+	} G_STMT_END
+
+#define CHECK_PROPERTY_CHANGED(field, prop) \
+	G_STMT_START { \
+		if (priv->props.field != props->field) { \
+			priv->props.field = props->field; \
+			_notify (self, prop); \
+		} \
+	} G_STMT_END
+
+	CHECK_PROPERTY_CHANGED_VALID (owner, PROP_OWNER);
+	CHECK_PROPERTY_CHANGED_VALID (group, PROP_GROUP);
+	CHECK_PROPERTY_CHANGED (type, PROP_MODE);
+	CHECK_PROPERTY_CHANGED (pi, PROP_NO_PI);
+	CHECK_PROPERTY_CHANGED (vnet_hdr, PROP_VNET_HDR);
+	CHECK_PROPERTY_CHANGED (multi_queue, PROP_MULTI_QUEUE);
+
+	g_object_thaw_notify (G_OBJECT (self));
+}
+
+static void
+update_properties (NMDeviceTun *self)
+{
+	NMPlatformLnkTun props_storage;
+	const NMPlatformLnkTun *props = NULL;
 	int ifindex;
 
 	ifindex = nm_device_get_ifindex (NM_DEVICE (self));
-	if (ifindex > 0) {
-		if (!nm_platform_link_tun_get_properties (nm_device_get_platform (NM_DEVICE (self)), ifindex, &props)) {
-			_LOGD (LOGD_DEVICE, "tun-properties: cannot loading tun properties from platform for ifindex %d", ifindex);
-			ifindex = 0;
-		} else if (g_strcmp0 (priv->mode, props.mode) != 0) {
-			/* if the mode differs, we ignore what we loaded. A NMDeviceTun cannot
-			 * change the mode after construction. */
-			_LOGD (LOGD_DEVICE, "tun-properties: loading tun properties yielded tun-mode %s%s%s, but %s%s%s expected (ifindex %d)",
-			       NM_PRINT_FMT_QUOTE_STRING (props.mode),
-			       NM_PRINT_FMT_QUOTE_STRING (priv->mode),
-			       ifindex);
-			ifindex = 0;
-		}
-	} else
-		_LOGD (LOGD_DEVICE, "tun-properties: ignore loading properties due to missing ifindex");
-	if (ifindex <= 0)
-		memset (&props, 0, sizeof (props));
-
-	g_object_freeze_notify (object);
-
-	if (priv->props.owner != props.owner)
-		_notify (self, PROP_OWNER);
-	if (priv->props.group != props.group)
-		_notify (self, PROP_GROUP);
-	if (priv->props.no_pi != props.no_pi)
-		_notify (self, PROP_NO_PI);
-	if (priv->props.vnet_hdr != props.vnet_hdr)
-		_notify (self, PROP_VNET_HDR);
-	if (priv->props.multi_queue != props.multi_queue)
-		_notify (self, PROP_MULTI_QUEUE);
-
-	memcpy (&priv->props, &props, sizeof (NMPlatformTunProperties));
-
-	g_object_thaw_notify (object);
+	if (   ifindex > 0
+	    && nm_platform_link_tun_get_properties (nm_device_get_platform (NM_DEVICE (self)),
+	                                            ifindex,
+	                                            &props_storage))
+		props = &props_storage;
+
+	update_properties_from_struct (self, props);
 }
 
 static NMDeviceCapabilities
@@ -133,7 +145,7 @@ static gboolean
 complete_connection (NMDevice *device,
                      NMConnection *connection,
                      const char *specific_object,
-                     const GSList *existing_connections,
+                     NMConnection *const*existing_connections,
                      GError **error)
 {
 	NMSettingTun *s_tun;
@@ -157,61 +169,57 @@ complete_connection (NMDevice *device,
 	return TRUE;
 }
 
-static int
-tun_mode_from_string (const char *string)
-{
-	if (!g_strcmp0 (string, "tap"))
-		return NM_SETTING_TUN_MODE_TAP;
-	else
-		return NM_SETTING_TUN_MODE_TUN;
-}
-
 static void
 update_connection (NMDevice *device, NMConnection *connection)
 {
 	NMDeviceTun *self = NM_DEVICE_TUN (device);
-	NMSettingTun *s_tun = nm_connection_get_setting_tun (connection);
-	NMPlatformTunProperties props;
+	NMDeviceTunPrivate *priv = NM_DEVICE_TUN_GET_PRIVATE (self);
+	NMSettingTun *s_tun;
 	NMSettingTunMode mode;
-	gint64 user, group;
-	char *str;
+	char s_buf[100];
+	const char *str;
 
-	if (!s_tun) {
-		s_tun = (NMSettingTun *) nm_setting_tun_new ();
-		nm_connection_add_setting (connection, (NMSetting *) s_tun);
-	}
+	/* Note: since we read tun properties from sysctl for older kernels,
+	 *       we don't get proper change notifications. Make sure that all our
+	 *       tun properties are up to date at this point. We should not do this,
+	 *       if we would entirely rely on netlink events. */
+	update_properties (NM_DEVICE_TUN (device));
 
-	if (!nm_platform_link_tun_get_properties (nm_device_get_platform (device), nm_device_get_ifindex (device), &props)) {
-		_LOGW (LOGD_PLATFORM, "failed to get TUN interface info while updating connection.");
+	switch (priv->props.type) {
+	case IFF_TUN: mode = NM_SETTING_TUN_MODE_TUN; break;
+	case IFF_TAP: mode = NM_SETTING_TUN_MODE_TAP; break;
+	default:
+		/* Huh? */
 		return;
 	}
 
-	mode = tun_mode_from_string (props.mode);
+	s_tun = nm_connection_get_setting_tun (connection);
+	if (!s_tun) {
+		s_tun = (NMSettingTun *) nm_setting_tun_new ();
+		nm_connection_add_setting (connection, (NMSetting *) s_tun);
+	}
 
 	if (mode != nm_setting_tun_get_mode (s_tun))
-		g_object_set (G_OBJECT (s_tun), NM_SETTING_TUN_MODE, mode, NULL);
-
-	user = _nm_utils_ascii_str_to_int64 (nm_setting_tun_get_owner (s_tun), 10, 0, G_MAXINT32, -1);
-	group = _nm_utils_ascii_str_to_int64 (nm_setting_tun_get_group (s_tun), 10, 0, G_MAXINT32, -1);
+		g_object_set (G_OBJECT (s_tun), NM_SETTING_TUN_MODE, (guint) mode, NULL);
 
-	if (props.owner != user) {
-		str = props.owner >= 0 ? g_strdup_printf ("%" G_GINT32_FORMAT, (gint32) props.owner) : NULL;
+	str = priv->props.owner_valid
+	      ? nm_sprintf_buf (s_buf, "%" G_GINT32_FORMAT, priv->props.owner)
+	      : NULL;
+	if (!nm_streq0 (str, nm_setting_tun_get_owner (s_tun)))
 		g_object_set (G_OBJECT (s_tun), NM_SETTING_TUN_OWNER, str, NULL);
-		g_free (str);
-	}
 
-	if (props.group != group) {
-		str = props.group >= 0 ? g_strdup_printf ("%" G_GINT32_FORMAT, (gint32) props.group) : NULL;
+	str = priv->props.group_valid
+	      ? nm_sprintf_buf (s_buf, "%" G_GINT32_FORMAT, priv->props.group)
+	      : NULL;
+	if (!nm_streq0 (str, nm_setting_tun_get_group (s_tun)))
 		g_object_set (G_OBJECT (s_tun), NM_SETTING_TUN_GROUP, str, NULL);
-		g_free (str);
-	}
 
-	if ((!props.no_pi) != nm_setting_tun_get_pi (s_tun))
-		g_object_set (G_OBJECT (s_tun), NM_SETTING_TUN_PI, !props.no_pi, NULL);
-	if (props.vnet_hdr != nm_setting_tun_get_vnet_hdr (s_tun))
-		g_object_set (G_OBJECT (s_tun), NM_SETTING_TUN_VNET_HDR, props.vnet_hdr, NULL);
-	if (props.multi_queue != nm_setting_tun_get_multi_queue (s_tun))
-		g_object_set (G_OBJECT (s_tun), NM_SETTING_TUN_MULTI_QUEUE, props.multi_queue, NULL);
+	if (priv->props.pi != nm_setting_tun_get_pi (s_tun))
+		g_object_set (G_OBJECT (s_tun), NM_SETTING_TUN_PI, (gboolean) priv->props.pi, NULL);
+	if (priv->props.vnet_hdr != nm_setting_tun_get_vnet_hdr (s_tun))
+		g_object_set (G_OBJECT (s_tun), NM_SETTING_TUN_VNET_HDR, (gboolean) priv->props.vnet_hdr, NULL);
+	if (priv->props.multi_queue != nm_setting_tun_get_multi_queue (s_tun))
+		g_object_set (G_OBJECT (s_tun), NM_SETTING_TUN_MULTI_QUEUE, (gboolean) priv->props.multi_queue, NULL);
 }
 
 static gboolean
@@ -222,23 +230,42 @@ create_and_realize (NMDevice *device,
                     GError **error)
 {
 	const char *iface = nm_device_get_iface (device);
+	NMPlatformLnkTun props = { };
 	NMPlatformError plerr;
 	NMSettingTun *s_tun;
-	gint64 user, group;
+	gint64 owner, group;
 
 	s_tun = nm_connection_get_setting_tun (connection);
-	g_assert (s_tun);
+	g_return_val_if_fail (s_tun, FALSE);
+
+	switch (nm_setting_tun_get_mode (s_tun)) {
+	case NM_SETTING_TUN_MODE_TAP: props.type = IFF_TAP; break;
+	case NM_SETTING_TUN_MODE_TUN: props.type = IFF_TUN; break;
+	default:
+		g_return_val_if_reached (FALSE);
+	}
 
-	user = _nm_utils_ascii_str_to_int64 (nm_setting_tun_get_owner (s_tun), 10, 0, G_MAXINT32, -1);
+	owner = _nm_utils_ascii_str_to_int64 (nm_setting_tun_get_owner (s_tun), 10, 0, G_MAXINT32, -1);
+	if (owner != -1) {
+		props.owner_valid = TRUE;
+		props.owner = owner;
+	}
 	group = _nm_utils_ascii_str_to_int64 (nm_setting_tun_get_group (s_tun), 10, 0, G_MAXINT32, -1);
+	if (group != -1) {
+		props.group_valid = TRUE;
+		props.group = group;
+	}
 
-	plerr = nm_platform_link_tun_add (nm_device_get_platform (device), iface,
-	                                  nm_setting_tun_get_mode (s_tun) == NM_SETTING_TUN_MODE_TAP,
-	                                  user, group,
-	                                  nm_setting_tun_get_pi (s_tun),
-	                                  nm_setting_tun_get_vnet_hdr (s_tun),
-	                                  nm_setting_tun_get_multi_queue (s_tun),
-	                                  out_plink);
+	props.pi = nm_setting_tun_get_pi (s_tun);
+	props.vnet_hdr = nm_setting_tun_get_vnet_hdr (s_tun);
+	props.multi_queue = nm_setting_tun_get_multi_queue (s_tun);
+	props.persist = TRUE;
+
+	plerr = nm_platform_link_tun_add (nm_device_get_platform (device),
+	                                  iface,
+	                                  &props,
+	                                  out_plink,
+	                                  NULL);
 	if (plerr != NM_PLATFORM_ERROR_SUCCESS) {
 		g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED,
 		             "Failed to create TUN/TAP interface '%s' for '%s': %s",
@@ -252,13 +279,22 @@ create_and_realize (NMDevice *device,
 }
 
 static gboolean
+_same_og (const char *str, gboolean og_valid, guint32 og_num)
+{
+	gint64 v;
+
+	v = _nm_utils_ascii_str_to_int64 (str, 10, 0, G_MAXINT32, -1);
+	return    (!og_valid && (           v  == (gint64) -1))
+	       || ( og_valid && (((guint32) v) == og_num     ));
+}
+
+static gboolean
 check_connection_compatible (NMDevice *device, NMConnection *connection)
 {
 	NMDeviceTun *self = NM_DEVICE_TUN (device);
 	NMDeviceTunPrivate *priv = NM_DEVICE_TUN_GET_PRIVATE (self);
 	NMSettingTunMode mode;
 	NMSettingTun *s_tun;
-	gint64 user, group;
 
 	if (!NM_DEVICE_CLASS (nm_device_tun_parent_class)->check_connection_compatible (device, connection))
 		return FALSE;
@@ -268,18 +304,21 @@ check_connection_compatible (NMDevice *device, NMConnection *connection)
 		return FALSE;
 
 	if (nm_device_is_real (device)) {
-		mode = tun_mode_from_string (priv->mode);
-		if (mode != nm_setting_tun_get_mode (s_tun))
+		switch (priv->props.type) {
+		case IFF_TUN: mode = NM_SETTING_TUN_MODE_TUN; break;
+		case IFF_TAP: mode = NM_SETTING_TUN_MODE_TAP; break;
+		default:
+			/* Huh? */
 			return FALSE;
+		}
 
-		user = _nm_utils_ascii_str_to_int64 (nm_setting_tun_get_owner (s_tun), 10, 0, G_MAXINT32, -1);
-		group = _nm_utils_ascii_str_to_int64 (nm_setting_tun_get_group (s_tun), 10, 0, G_MAXINT32, -1);
-
-		if (user != priv->props.owner)
+		if (mode != nm_setting_tun_get_mode (s_tun))
+			return FALSE;
+		if (!_same_og (nm_setting_tun_get_owner (s_tun), priv->props.owner_valid, priv->props.owner))
 			return FALSE;
-		if (group != priv->props.group)
+		if (!_same_og (nm_setting_tun_get_group (s_tun), priv->props.group_valid, priv->props.group))
 			return FALSE;
-		if (nm_setting_tun_get_pi (s_tun) == priv->props.no_pi)
+		if (nm_setting_tun_get_pi (s_tun) != priv->props.pi)
 			return FALSE;
 		if (nm_setting_tun_get_vnet_hdr (s_tun) != priv->props.vnet_hdr)
 			return FALSE;
@@ -302,7 +341,7 @@ act_stage1_prepare (NMDevice *device, NMDeviceStateReason *out_failure_reason)
 		return ret;
 
 	/* Nothing to do for TUN devices */
-	if (g_strcmp0 (priv->mode, "tap"))
+	if (priv->props.type == IFF_TUN)
 		return NM_ACT_STAGE_RETURN_SUCCESS;
 
 	if (!nm_device_hw_addr_set_cloned (device, nm_device_get_applied_connection (device), FALSE))
@@ -314,16 +353,8 @@ act_stage1_prepare (NMDevice *device, NMDeviceStateReason *out_failure_reason)
 static void
 unrealize_notify (NMDevice *device)
 {
-	NMDeviceTun *self = NM_DEVICE_TUN (device);
-	NMDeviceTunPrivate *priv = NM_DEVICE_TUN_GET_PRIVATE (self);
-	guint i;
-
 	NM_DEVICE_CLASS (nm_device_tun_parent_class)->unrealize_notify (device);
-
-	memset (&priv->props, 0, sizeof (NMPlatformTunProperties));
-
-	for (i = 1; i < _PROPERTY_ENUMS_LAST; i++)
-		g_object_notify_by_pspec ((GObject *) self, obj_properties[i]);
+	update_properties_from_struct (NM_DEVICE_TUN (device), NULL);
 }
 
 /*****************************************************************************/
@@ -334,19 +365,25 @@ get_property (GObject *object, guint prop_id,
 {
 	NMDeviceTun *self = NM_DEVICE_TUN (object);
 	NMDeviceTunPrivate *priv = NM_DEVICE_TUN_GET_PRIVATE (self);
+	const char *s;
 
 	switch (prop_id) {
 	case PROP_OWNER:
-		g_value_set_int64 (value, priv->props.owner);
+		g_value_set_int64 (value, priv->props.owner_valid ? (gint64) priv->props.owner : (gint64) -1);
 		break;
 	case PROP_GROUP:
-		g_value_set_int64 (value, priv->props.group);
+		g_value_set_int64 (value, priv->props.group_valid ? (gint64) priv->props.group : (gint64) -1);
 		break;
 	case PROP_MODE:
-		g_value_set_string (value, priv->mode);
+		switch (priv->props.type) {
+		case IFF_TUN: s = "tun"; break;
+		case IFF_TAP: s = "tap"; break;
+		default:      s = NULL;  break;
+		}
+		g_value_set_static_string (value, s);
 		break;
 	case PROP_NO_PI:
-		g_value_set_boolean (value, priv->props.no_pi);
+		g_value_set_boolean (value, !priv->props.pi);
 		break;
 	case PROP_VNET_HDR:
 		g_value_set_boolean (value, priv->props.vnet_hdr);
@@ -360,33 +397,6 @@ get_property (GObject *object, guint prop_id,
 	}
 }
 
-static void
-set_property (GObject *object, guint prop_id,
-              const GValue *value, GParamSpec *pspec)
-{
-	NMDeviceTun *self = NM_DEVICE_TUN (object);
-	NMDeviceTunPrivate *priv = NM_DEVICE_TUN_GET_PRIVATE (self);
-	const char *str;
-
-	switch (prop_id) {
-	case PROP_MODE:
-		/* construct-only */
-		str = g_value_get_string (value);
-
-		/* mode is G_PARAM_STATIC_STRINGS */
-		if (g_strcmp0 (str, "tun") == 0)
-			priv->mode = "tun";
-		else if (g_strcmp0 (str, "tap") == 0)
-			priv->mode = "tap";
-		else
-			g_return_if_fail (FALSE);
-		break;
-	default:
-		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-		break;
-	}
-}
-
 /*****************************************************************************/
 
 static void
@@ -394,16 +404,37 @@ nm_device_tun_init (NMDeviceTun *self)
 {
 }
 
+static const NMDBusInterfaceInfoExtended interface_info_device_tun = {
+	.parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT (
+		NM_DBUS_INTERFACE_DEVICE_TUN,
+		.signals = NM_DEFINE_GDBUS_SIGNAL_INFOS (
+			&nm_signal_info_property_changed_legacy,
+		),
+		.properties = NM_DEFINE_GDBUS_PROPERTY_INFOS (
+			NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Owner",      "x",  NM_DEVICE_TUN_OWNER),
+			NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Group",      "x",  NM_DEVICE_TUN_GROUP),
+			NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Mode",       "s",  NM_DEVICE_TUN_MODE),
+			NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("NoPi",       "b",  NM_DEVICE_TUN_NO_PI),
+			NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("VnetHdr",    "b",  NM_DEVICE_TUN_VNET_HDR),
+			NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("MultiQueue", "b",  NM_DEVICE_TUN_MULTI_QUEUE),
+			NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("HwAddress",  "s",  NM_DEVICE_HW_ADDRESS),
+		),
+	),
+	.legacy_property_changed = TRUE,
+};
+
 static void
 nm_device_tun_class_init (NMDeviceTunClass *klass)
 {
 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass);
 	NMDeviceClass *device_class = NM_DEVICE_CLASS (klass);
 
-	NM_DEVICE_CLASS_DECLARE_TYPES (klass, NULL, NM_LINK_TYPE_TUN, NM_LINK_TYPE_TAP)
+	NM_DEVICE_CLASS_DECLARE_TYPES (klass, NULL, NM_LINK_TYPE_TUN)
 
 	object_class->get_property = get_property;
-	object_class->set_property = set_property;
+
+	dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_tun);
 
 	device_class->connection_type = NM_SETTING_TUN_SETTING_NAME;
 	device_class->link_changed = link_changed;
@@ -428,9 +459,8 @@ nm_device_tun_class_init (NMDeviceTunClass *klass)
 
 	obj_properties[PROP_MODE] =
 	     g_param_spec_string (NM_DEVICE_TUN_MODE, "", "",
-	                          "tun",
-	                          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
-	                          G_PARAM_STATIC_STRINGS);
+	                          NULL,
+	                          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
 
 	obj_properties[PROP_NO_PI] =
 	     g_param_spec_boolean (NM_DEVICE_TUN_NO_PI, "", "",
@@ -448,10 +478,6 @@ nm_device_tun_class_init (NMDeviceTunClass *klass)
 	                           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
 
 	g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
-
-	nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass),
-	                                        NMDBUS_TYPE_DEVICE_TUN_SKELETON,
-	                                        NULL);
 }
 
 
@@ -467,42 +493,19 @@ create_device (NMDeviceFactory *factory,
                NMConnection *connection,
                gboolean *out_ignore)
 {
-	NMSettingTun *s_tun;
-	NMLinkType link_type = NM_LINK_TYPE_UNKNOWN;
-	const char *mode;
-
-	if (plink) {
-		link_type = plink->type;
-	} else if (connection) {
-		s_tun = nm_connection_get_setting_tun (connection);
-		if (!s_tun)
-			return NULL;
-		switch (nm_setting_tun_get_mode (s_tun)) {
-		case NM_SETTING_TUN_MODE_TUN:
-			link_type = NM_LINK_TYPE_TUN;
-			break;
-		case NM_SETTING_TUN_MODE_TAP:
-			link_type = NM_LINK_TYPE_TAP;
-			break;
-		case NM_SETTING_TUN_MODE_UNKNOWN:
-			g_return_val_if_reached (NULL);
-		}
-	}
-
-	g_return_val_if_fail (link_type != NM_LINK_TYPE_UNKNOWN, NULL);
-	mode = link_type == NM_LINK_TYPE_TUN ? "tun" : "tap";
+	g_return_val_if_fail (!plink || plink->type == NM_LINK_TYPE_TUN, NULL);
+	g_return_val_if_fail (!connection || nm_streq0 (nm_connection_get_connection_type (connection), NM_SETTING_TUN_SETTING_NAME), NULL);
 
 	return (NMDevice *) g_object_new (NM_TYPE_DEVICE_TUN,
 	                                  NM_DEVICE_IFACE, iface,
 	                                  NM_DEVICE_TYPE_DESC, "Tun",
 	                                  NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_TUN,
-	                                  NM_DEVICE_LINK_TYPE, link_type,
-	                                  NM_DEVICE_TUN_MODE, mode,
+	                                  NM_DEVICE_LINK_TYPE, (guint) NM_LINK_TYPE_TUN,
 	                                  NULL);
 }
 
 NM_DEVICE_FACTORY_DEFINE_INTERNAL (TUN, Tun, tun,
-	NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_TUN, NM_LINK_TYPE_TAP)
+	NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_TUN)
 	NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_TUN_SETTING_NAME),
 	factory_class->create_device = create_device;
 );