about summary refs log tree commit diff
path: root/src/devices/nm-device-ip-tunnel.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/nm-device-ip-tunnel.c')
-rw-r--r--src/devices/nm-device-ip-tunnel.c191
1 files changed, 115 insertions, 76 deletions
diff --git a/src/devices/nm-device-ip-tunnel.c b/src/devices/nm-device-ip-tunnel.c
index 0becb5e5..0a33c82e 100644
--- a/src/devices/nm-device-ip-tunnel.c
+++ b/src/devices/nm-device-ip-tunnel.c
@@ -67,7 +67,7 @@ struct _NMDeviceIPTunnelClass {
 
 G_DEFINE_TYPE (NMDeviceIPTunnel, nm_device_ip_tunnel, NM_TYPE_DEVICE)
 
-#define NM_DEVICE_IP_TUNNEL_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMDeviceIPTunnel, NM_IS_DEVICE_IP_TUNNEL)
+#define NM_DEVICE_IP_TUNNEL_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMDeviceIPTunnel, NM_IS_DEVICE_IP_TUNNEL, NMDevice)
 
 /*****************************************************************************/
 
@@ -96,35 +96,63 @@ ip6tnl_flags_plat_to_setting (guint32 flags)
 /*****************************************************************************/
 
 static gboolean
-address_equal_pp (int family, const char *a, const char *b)
+address_equal_pp (int addr_family, const char *a, const char *b)
 {
-	char buffer1[sizeof (struct in6_addr)] = { };
-	char buffer2[sizeof (struct in6_addr)] = { };
+	const NMIPAddr *addr_a = &nm_ip_addr_zero;
+	const NMIPAddr *addr_b = &nm_ip_addr_zero;
+	NMIPAddr addr_a_val;
+	NMIPAddr addr_b_val;
 
-	g_return_val_if_fail (family == AF_INET || family == AF_INET6, FALSE);
+	nm_assert_addr_family (addr_family);
 
-	if (a)
-		inet_pton (family, a, buffer1);
-	if (b)
-		inet_pton (family, b, buffer2);
+	if (a) {
+		if (!nm_utils_parse_inaddr_bin (addr_family, a, NULL, &addr_a_val))
+			nm_assert_not_reached ();
+		addr_a = &addr_a_val;
+	}
+	if (b) {
+		if (!nm_utils_parse_inaddr_bin (addr_family, b, NULL, &addr_b_val))
+			nm_assert_not_reached ();
+		addr_b = &addr_b_val;
+	}
 
-	return !memcmp (buffer1, buffer2,
-	                family == AF_INET ? sizeof (in_addr_t) : sizeof (struct in6_addr));
+	return nm_ip_addr_equal (addr_family, addr_a, addr_b);
 }
 
 static gboolean
-address_equal_pn (int family, const char *a, const void *b)
+address_set (int addr_family,
+             char **p_addr,
+             const NMIPAddr *addr_new)
 {
-	char buffer1[sizeof (struct in6_addr)] = { };
+	nm_assert_addr_family (addr_family);
+	nm_assert (p_addr);
+	nm_assert (   !*p_addr
+	           || nm_utils_ipaddr_is_normalized (addr_family, *p_addr));
+
+	if (   !addr_new
+	    || nm_ip_addr_is_null (addr_family, addr_new)) {
+		if (nm_clear_g_free (p_addr))
+			return TRUE;
+		return FALSE;
+	}
 
-	g_return_val_if_fail (family == AF_INET || family == AF_INET6, FALSE);
+	if (*p_addr) {
+		NMIPAddr addr_val;
 
-	if (a)
-		inet_pton (family, a, buffer1);
+		if (!nm_utils_parse_inaddr_bin (addr_family,
+		                                *p_addr,
+		                                NULL,
+		                                &addr_val))
+			nm_assert_not_reached ();
 
-	return !memcmp (buffer1, b,
-	                family == AF_INET ? sizeof (in_addr_t) : sizeof (struct in6_addr));
+		if (nm_ip_addr_equal (addr_family, &addr_val, addr_new))
+			return FALSE;
+
+		g_free (*p_addr);
+	}
 
+	*p_addr = nm_utils_inet_ntop_dup (addr_family, addr_new);
+	return TRUE;
 }
 
 static void
@@ -133,10 +161,8 @@ update_properties_from_ifindex (NMDevice *device, int ifindex)
 	NMDeviceIPTunnel *self = NM_DEVICE_IP_TUNNEL (device);
 	NMDeviceIPTunnelPrivate *priv = NM_DEVICE_IP_TUNNEL_GET_PRIVATE (self);
 	int parent_ifindex = 0;
-	in_addr_t local4 = 0;
-	in_addr_t remote4 = 0;
-	struct in6_addr local6 = IN6ADDR_ANY_INIT;
-	struct in6_addr remote6 = IN6ADDR_ANY_INIT;
+	NMIPAddr local = NM_IP_ADDR_INIT;
+	NMIPAddr remote = NM_IP_ADDR_INIT;
 	guint8 ttl = 0;
 	guint8 tos = 0;
 	guint8 encap_limit = 0;
@@ -149,19 +175,19 @@ update_properties_from_ifindex (NMDevice *device, int ifindex)
 clear:
 		nm_device_parent_set_ifindex (device, 0);
 		if (priv->local) {
-			g_clear_pointer (&priv->local, g_free);
+			nm_clear_g_free (&priv->local);
 			_notify (self, PROP_LOCAL);
 		}
 		if (priv->remote) {
-			g_clear_pointer (&priv->remote, g_free);
+			nm_clear_g_free (&priv->remote);
 			_notify (self, PROP_REMOTE);
 		}
 		if (priv->input_key) {
-			g_clear_pointer (&priv->input_key, g_free);
+			nm_clear_g_free (&priv->input_key);
 			_notify (self, PROP_INPUT_KEY);
 		}
 		if (priv->output_key) {
-			g_clear_pointer (&priv->output_key, g_free);
+			nm_clear_g_free (&priv->output_key);
 			_notify (self, PROP_OUTPUT_KEY);
 		}
 
@@ -181,8 +207,8 @@ clear:
 		}
 
 		parent_ifindex = lnk->parent_ifindex;
-		local4 = lnk->local;
-		remote4 = lnk->remote;
+		local.addr4 = lnk->local;
+		remote.addr4 = lnk->remote;
 		ttl = lnk->ttl;
 		tos = lnk->tos;
 		pmtud = lnk->path_mtu_discovery;
@@ -197,7 +223,7 @@ clear:
 				g_free (key);
 		} else {
 			if (priv->input_key) {
-				g_clear_pointer (&priv->input_key, g_free);
+				nm_clear_g_free (&priv->input_key);
 				_notify (self, PROP_INPUT_KEY);
 			}
 		}
@@ -212,7 +238,7 @@ clear:
 				g_free (key);
 		} else {
 			if (priv->output_key) {
-				g_clear_pointer (&priv->output_key, g_free);
+				nm_clear_g_free (&priv->output_key);
 				_notify (self, PROP_OUTPUT_KEY);
 			}
 		}
@@ -226,8 +252,8 @@ clear:
 		}
 
 		parent_ifindex = lnk->parent_ifindex;
-		local4 = lnk->local;
-		remote4 = lnk->remote;
+		local.addr4 = lnk->local;
+		remote.addr4 = lnk->remote;
 		ttl = lnk->ttl;
 		tos = lnk->tos;
 		pmtud = lnk->path_mtu_discovery;
@@ -241,8 +267,8 @@ clear:
 		}
 
 		parent_ifindex = lnk->parent_ifindex;
-		local4 = lnk->local;
-		remote4 = lnk->remote;
+		local.addr4 = lnk->local;
+		remote.addr4 = lnk->remote;
 		ttl = lnk->ttl;
 		tos = lnk->tos;
 		pmtud = lnk->path_mtu_discovery;
@@ -267,8 +293,8 @@ clear:
 		}
 
 		parent_ifindex = lnk->parent_ifindex;
-		local6 = lnk->local;
-		remote6 = lnk->remote;
+		local.addr6 = lnk->local;
+		remote.addr6 = lnk->remote;
 		ttl = lnk->ttl;
 		tos = lnk->tclass;
 		encap_limit = lnk->encap_limit;
@@ -288,7 +314,7 @@ clear:
 					g_free (key);
 			} else {
 				if (priv->input_key) {
-					g_clear_pointer (&priv->input_key, g_free);
+					nm_clear_g_free (&priv->input_key);
 					_notify (self, PROP_INPUT_KEY);
 				}
 			}
@@ -303,7 +329,7 @@ clear:
 					g_free (key);
 			} else {
 				if (priv->output_key) {
-					g_clear_pointer (&priv->output_key, g_free);
+					nm_clear_g_free (&priv->output_key);
 					_notify (self, PROP_OUTPUT_KEY);
 				}
 			}
@@ -313,35 +339,10 @@ clear:
 
 	nm_device_parent_set_ifindex (device, parent_ifindex);
 
-	if (priv->addr_family == AF_INET) {
-		if (!address_equal_pn (AF_INET, priv->local, &local4)) {
-			g_clear_pointer (&priv->local, g_free);
-			if (local4)
-				priv->local = nm_utils_inet4_ntop_dup (local4);
-			_notify (self, PROP_LOCAL);
-		}
-
-		if (!address_equal_pn (AF_INET, priv->remote, &remote4)) {
-			g_clear_pointer (&priv->remote, g_free);
-			if (remote4)
-				priv->remote = nm_utils_inet4_ntop_dup (remote4);
-			_notify (self, PROP_REMOTE);
-		}
-	} else {
-		if (!address_equal_pn (AF_INET6, priv->local, &local6)) {
-			g_clear_pointer (&priv->local, g_free);
-			if (memcmp (&local6, &in6addr_any, sizeof (in6addr_any)))
-				priv->local = nm_utils_inet6_ntop_dup (&local6);
-			_notify (self, PROP_LOCAL);
-		}
-
-		if (!address_equal_pn (AF_INET6, priv->remote, &remote6)) {
-			g_clear_pointer (&priv->remote, g_free);
-			if (memcmp (&remote6, &in6addr_any, sizeof (in6addr_any)))
-				priv->remote = nm_utils_inet6_ntop_dup (&remote6);
-			_notify (self, PROP_REMOTE);
-		}
-	}
+	if (address_set (priv->addr_family, &priv->local, &local))
+		_notify (self, PROP_LOCAL);
+	if (address_set (priv->addr_family, &priv->remote, &remote))
+		_notify (self, PROP_REMOTE);
 
 out:
 
@@ -657,11 +658,44 @@ create_and_realize (NMDevice *device,
 	gint64 val;
 	NMIPTunnelMode mode;
 	int r;
+	gs_free char *hwaddr = NULL;
+	guint8 mac_address[ETH_ALEN];
+	gboolean mac_address_valid = FALSE;
 
 	s_ip_tunnel = nm_connection_get_setting_ip_tunnel (connection);
-	g_assert (s_ip_tunnel);
+	nm_assert (NM_IS_SETTING_IP_TUNNEL (s_ip_tunnel));
 
 	mode = nm_setting_ip_tunnel_get_mode (s_ip_tunnel);
+
+	if (   nm_device_hw_addr_get_cloned (device,
+	                                     connection,
+	                                     FALSE,
+	                                     &hwaddr,
+	                                     NULL,
+	                                     NULL)
+	    && hwaddr) {
+		/* FIXME: we set the MAC address when creating the interface, while the
+		 * NMDevice is still unrealized. As we afterwards realize the device, it
+		 * forgets the parameters for the cloned MAC address, and in stage 1
+		 * it might create a different MAC address. That should be fixed by
+		 * better handling device realization. */
+		if (!nm_utils_hwaddr_aton (hwaddr, mac_address, ETH_ALEN)) {
+			g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED,
+			             "Invalid hardware address '%s'",
+			             hwaddr);
+			g_return_val_if_reached (FALSE);
+		}
+
+		if (NM_IN_SET (mode, NM_IP_TUNNEL_MODE_GRE)) {
+			g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED,
+			             "Invalid hardware address '%s' for tunnel type",
+			             hwaddr);
+			return FALSE;
+		}
+
+		mac_address_valid = TRUE;
+	}
+
 	switch (mode) {
 	case NM_IP_TUNNEL_MODE_GRETAP:
 		lnk_gre.is_tap = TRUE;
@@ -702,7 +736,12 @@ create_and_realize (NMDevice *device,
 			lnk_gre.output_flags = NM_GRE_KEY;
 		}
 
-		r = nm_platform_link_gre_add (nm_device_get_platform (device), iface, &lnk_gre, out_plink);
+		r = nm_platform_link_gre_add (nm_device_get_platform (device),
+		                              iface,
+		                              mac_address_valid ? mac_address : NULL,
+		                              mac_address_valid ? ETH_ALEN : 0,
+		                              &lnk_gre,
+		                              out_plink);
 		if (r < 0) {
 			g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED,
 			             "Failed to create GRE interface '%s' for '%s': %s",
@@ -896,7 +935,7 @@ static void
 get_property (GObject *object, guint prop_id,
               GValue *value, GParamSpec *pspec)
 {
-	NMDeviceIPTunnelPrivate *priv = NM_DEVICE_IP_TUNNEL_GET_PRIVATE ((NMDeviceIPTunnel *) object);
+	NMDeviceIPTunnelPrivate *priv = NM_DEVICE_IP_TUNNEL_GET_PRIVATE (object);
 
 	switch (prop_id) {
 	case PROP_MODE:
@@ -942,7 +981,7 @@ static void
 set_property (GObject *object, guint prop_id,
               const GValue *value, GParamSpec *pspec)
 {
-	NMDeviceIPTunnelPrivate *priv = NM_DEVICE_IP_TUNNEL_GET_PRIVATE ((NMDeviceIPTunnel *) object);
+	NMDeviceIPTunnelPrivate *priv = NM_DEVICE_IP_TUNNEL_GET_PRIVATE (object);
 
 	switch (prop_id) {
 	case PROP_MODE:
@@ -963,7 +1002,7 @@ nm_device_ip_tunnel_init (NMDeviceIPTunnel *self)
 static void
 constructed (GObject *object)
 {
-	NMDeviceIPTunnelPrivate *priv = NM_DEVICE_IP_TUNNEL_GET_PRIVATE ((NMDeviceIPTunnel *) object);
+	NMDeviceIPTunnelPrivate *priv = NM_DEVICE_IP_TUNNEL_GET_PRIVATE (object);
 
 	if (NM_IN_SET (priv->mode,
 	               NM_IP_TUNNEL_MODE_IPIP6,
@@ -983,10 +1022,10 @@ dispose (GObject *object)
 	NMDeviceIPTunnel *self = NM_DEVICE_IP_TUNNEL (object);
 	NMDeviceIPTunnelPrivate *priv = NM_DEVICE_IP_TUNNEL_GET_PRIVATE (self);
 
-	g_clear_pointer (&priv->local, g_free);
-	g_clear_pointer (&priv->remote, g_free);
-	g_clear_pointer (&priv->input_key, g_free);
-	g_clear_pointer (&priv->output_key, g_free);
+	nm_clear_g_free (&priv->local);
+	nm_clear_g_free (&priv->remote);
+	nm_clear_g_free (&priv->input_key);
+	nm_clear_g_free (&priv->output_key);
 
 	G_OBJECT_CLASS (nm_device_ip_tunnel_parent_class)->dispose (object);
 }