summary refs log tree commit diff
path: root/src/dhcp/nm-dhcp-client.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/dhcp/nm-dhcp-client.c')
-rw-r--r--src/dhcp/nm-dhcp-client.c166
1 files changed, 112 insertions, 54 deletions
diff --git a/src/dhcp/nm-dhcp-client.c b/src/dhcp/nm-dhcp-client.c
index 0906f5be..20ea092f 100644
--- a/src/dhcp/nm-dhcp-client.c
+++ b/src/dhcp/nm-dhcp-client.c
@@ -29,6 +29,10 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <uuid/uuid.h>
+#include <linux/rtnetlink.h>
+
+#include "nm-utils/nm-dedup-multi.h"
+#include "nm-utils/nm-random-utils.h"
 
 #include "NetworkManagerUtils.h"
 #include "nm-utils.h"
@@ -48,33 +52,36 @@ enum {
 static guint signals[LAST_SIGNAL] = { 0 };
 
 NM_GOBJECT_PROPERTIES_DEFINE_BASE (
+	PROP_MULTI_IDX,
+	PROP_ADDR_FAMILY,
 	PROP_IFACE,
 	PROP_IFINDEX,
 	PROP_HWADDR,
-	PROP_IPV6,
 	PROP_UUID,
-	PROP_PRIORITY,
+	PROP_ROUTE_TABLE,
+	PROP_ROUTE_METRIC,
 	PROP_TIMEOUT,
 );
 
 typedef struct _NMDhcpClientPrivate {
+	NMDedupMultiIndex *multi_idx;
 	char *       iface;
-	int          ifindex;
 	GByteArray * hwaddr;
-	gboolean     ipv6;
 	char *       uuid;
-	guint32      priority;
-	guint32      timeout;
 	GByteArray * duid;
 	GBytes *     client_id;
 	char *       hostname;
-	gboolean     use_fqdn;
-
-	NMDhcpState  state;
 	pid_t        pid;
 	guint        timeout_id;
 	guint        watch_id;
-	gboolean     info_only;
+	int          addr_family;
+	int          ifindex;
+	guint32      route_table;
+	guint32      route_metric;
+	guint32      timeout;
+	NMDhcpState  state;
+	bool         info_only:1;
+	bool         use_fqdn:1;
 } NMDhcpClientPrivate;
 
 G_DEFINE_TYPE_EXTENDED (NMDhcpClient, nm_dhcp_client, G_TYPE_OBJECT, G_TYPE_FLAG_ABSTRACT, {})
@@ -91,6 +98,14 @@ nm_dhcp_client_get_pid (NMDhcpClient *self)
 	return NM_DHCP_CLIENT_GET_PRIVATE (self)->pid;
 }
 
+NMDedupMultiIndex *
+nm_dhcp_client_get_multi_idx (NMDhcpClient *self)
+{
+	g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), NULL);
+
+	return NM_DHCP_CLIENT_GET_PRIVATE (self)->multi_idx;
+}
+
 const char *
 nm_dhcp_client_get_iface (NMDhcpClient *self)
 {
@@ -107,12 +122,12 @@ nm_dhcp_client_get_ifindex (NMDhcpClient *self)
 	return NM_DHCP_CLIENT_GET_PRIVATE (self)->ifindex;
 }
 
-gboolean
-nm_dhcp_client_get_ipv6 (NMDhcpClient *self)
+int
+nm_dhcp_client_get_addr_family (NMDhcpClient *self)
 {
-	g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), FALSE);
+	g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), AF_UNSPEC);
 
-	return NM_DHCP_CLIENT_GET_PRIVATE (self)->ipv6;
+	return NM_DHCP_CLIENT_GET_PRIVATE (self)->addr_family;
 }
 
 const char *
@@ -140,11 +155,19 @@ nm_dhcp_client_get_hw_addr (NMDhcpClient *self)
 }
 
 guint32
-nm_dhcp_client_get_priority (NMDhcpClient *self)
+nm_dhcp_client_get_route_table (NMDhcpClient *self)
+{
+	g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), RT_TABLE_MAIN);
+
+	return NM_DHCP_CLIENT_GET_PRIVATE (self)->route_table;
+}
+
+guint32
+nm_dhcp_client_get_route_metric (NMDhcpClient *self)
 {
 	g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), G_MAXUINT32);
 
-	return NM_DHCP_CLIENT_GET_PRIVATE (self)->priority;
+	return NM_DHCP_CLIENT_GET_PRIVATE (self)->route_metric;
 }
 
 guint32
@@ -303,8 +326,8 @@ nm_dhcp_client_set_state (NMDhcpClient *self,
 		watch_cleanup (self);
 
 	if (new_state == NM_DHCP_STATE_BOUND) {
-		g_assert (   (priv->ipv6 && NM_IS_IP6_CONFIG (ip_config))
-		          || (!priv->ipv6 && NM_IS_IP4_CONFIG (ip_config)));
+		g_assert (   (priv->addr_family == AF_INET  && NM_IS_IP4_CONFIG (ip_config))
+		          || (priv->addr_family == AF_INET6 && NM_IS_IP6_CONFIG (ip_config)));
 		g_assert (options);
 	} else {
 		g_assert (ip_config == NULL);
@@ -319,7 +342,8 @@ nm_dhcp_client_set_state (NMDhcpClient *self,
 	if ((priv->state == new_state) && (new_state != NM_DHCP_STATE_BOUND))
 		return;
 
-	if (priv->ipv6 && new_state == NM_DHCP_STATE_BOUND) {
+	if (   priv->addr_family == AF_INET6
+	    && new_state == NM_DHCP_STATE_BOUND) {
 		char *start, *iaid;
 
 		iaid = g_hash_table_lookup (options, "iaid");
@@ -392,6 +416,10 @@ nm_dhcp_client_start_timeout (NMDhcpClient *self)
 
 	/* Set up a timeout on the transaction to kill it after the timeout */
 	g_assert (priv->timeout_id == 0);
+
+	if (priv->timeout == NM_DHCP_TIMEOUT_INFINITY)
+		return;
+
 	priv->timeout_id = g_timeout_add_seconds (priv->timeout,
 	                                          transaction_timeout,
 	                                          self);
@@ -426,10 +454,13 @@ nm_dhcp_client_start_ip4 (NMDhcpClient *self,
 
 	priv = NM_DHCP_CLIENT_GET_PRIVATE (self);
 	g_return_val_if_fail (priv->pid == -1, FALSE);
-	g_return_val_if_fail (priv->ipv6 == FALSE, FALSE);
+	g_return_val_if_fail (priv->addr_family == AF_INET, FALSE);
 	g_return_val_if_fail (priv->uuid != NULL, FALSE);
 
-	_LOGI ("activation: beginning transaction (timeout in %d seconds)", priv->timeout);
+	if (priv->timeout == NM_DHCP_TIMEOUT_INFINITY)
+		_LOGI ("activation: beginning transaction (no timeout)");
+	else
+		_LOGI ("activation: beginning transaction (timeout in %u seconds)", (guint) priv->timeout);
 
 	if (dhcp_client_id)
 		tmp = nm_dhcp_utils_client_id_string_to_bytes (dhcp_client_id);
@@ -451,8 +482,6 @@ generate_duid_from_machine_id (void)
 	gsize sumlen = sizeof (buffer);
 	const guint16 duid_type = g_htons (4);
 	uuid_t uuid;
-	GRand *generator;
-	guint i;
 	gs_free char *machine_id_s = NULL;
 	gs_free char *str = NULL;
 
@@ -468,10 +497,7 @@ generate_duid_from_machine_id (void)
 		             "or " LOCALSTATEDIR "/lib/dbus/machine-id to generate "
 		             "DHCPv6 DUID; creating non-persistent random DUID.");
 
-		generator = g_rand_new ();
-		for (i = 0; i < sizeof (buffer) / sizeof (guint32); i++)
-			((guint32 *) buffer)[i] = g_rand_int (generator);
-		g_rand_free (generator);
+		nm_utils_random_bytes (buffer, sizeof (buffer));
 	}
 
 	/* Generate a DHCP Unique Identifier for DHCPv6 using the
@@ -528,7 +554,7 @@ nm_dhcp_client_start_ip6 (NMDhcpClient *self,
 
 	priv = NM_DHCP_CLIENT_GET_PRIVATE (self);
 	g_return_val_if_fail (priv->pid == -1, FALSE);
-	g_return_val_if_fail (priv->ipv6 == TRUE, FALSE);
+	g_return_val_if_fail (priv->addr_family == AF_INET6, FALSE);
 	g_return_val_if_fail (priv->uuid != NULL, FALSE);
 
 	/* If we don't have one yet, read the default DUID for this DHCPv6 client
@@ -544,8 +570,10 @@ nm_dhcp_client_start_ip6 (NMDhcpClient *self,
 
 	priv->info_only = info_only;
 
-	_LOGI ("activation: beginning transaction (timeout in %d seconds)",
-	       priv->timeout);
+	if (priv->timeout == NM_DHCP_TIMEOUT_INFINITY)
+		_LOGI ("activation: beginning transaction (no timeout)");
+	else
+		_LOGI ("activation: beginning transaction (timeout in %u seconds)", (guint) priv->timeout);
 
 	return NM_DHCP_CLIENT_GET_CLASS (self)->ip6_start (self,
 	                                                   dhcp_anycast_addr,
@@ -744,7 +772,7 @@ nm_dhcp_client_handle_event (gpointer unused,
 		GVariant *value;
 
 		/* Copy options */
-		str_options = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+		str_options = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, g_free);
 		g_variant_iter_init (&iter, options);
 		while (g_variant_iter_next (&iter, "{&sv}", &name, &value)) {
 			maybe_add_option (self, str_options, name, value);
@@ -763,18 +791,20 @@ nm_dhcp_client_handle_event (gpointer unused,
 		/* Create the IP config */
 		g_warn_if_fail (g_hash_table_size (str_options));
 		if (g_hash_table_size (str_options)) {
-			if (priv->ipv6) {
-				prefix = nm_dhcp_utils_ip6_prefix_from_options (str_options);
-				ip_config = (GObject *) nm_dhcp_utils_ip6_config_from_options (priv->ifindex,
+			if (priv->addr_family == AF_INET) {
+				ip_config = (GObject *) nm_dhcp_utils_ip4_config_from_options (nm_dhcp_client_get_multi_idx (self),
+				                                                               priv->ifindex,
 				                                                               priv->iface,
 				                                                               str_options,
-				                                                               priv->priority,
-				                                                               priv->info_only);
+				                                                               priv->route_table,
+				                                                               priv->route_metric);
 			} else {
-				ip_config = (GObject *) nm_dhcp_utils_ip4_config_from_options (priv->ifindex,
+				prefix = nm_dhcp_utils_ip6_prefix_from_options (str_options);
+				ip_config = (GObject *) nm_dhcp_utils_ip6_config_from_options (nm_dhcp_client_get_multi_idx (self),
+				                                                               priv->ifindex,
 				                                                               priv->iface,
 				                                                               str_options,
-				                                                               priv->priority);
+				                                                               priv->info_only);
 			}
 		}
 	}
@@ -822,14 +852,14 @@ get_property (GObject *object, guint prop_id,
 	case PROP_HWADDR:
 		g_value_set_boxed (value, priv->hwaddr);
 		break;
-	case PROP_IPV6:
-		g_value_set_boolean (value, priv->ipv6);
+	case PROP_ADDR_FAMILY:
+		g_value_set_int (value, priv->addr_family);
 		break;
 	case PROP_UUID:
 		g_value_set_string (value, priv->uuid);
 		break;
-	case PROP_PRIORITY:
-		g_value_set_uint (value, priv->priority);
+	case PROP_ROUTE_METRIC:
+		g_value_set_uint (value, priv->route_metric);
 		break;
 	case PROP_TIMEOUT:
 		g_value_set_uint (value, priv->timeout);
@@ -847,6 +877,13 @@ set_property (GObject *object, guint prop_id,
 	NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE ((NMDhcpClient *) object);
 
 	switch (prop_id) {
+	case PROP_MULTI_IDX:
+		/* construct-only */
+		priv->multi_idx = g_value_get_pointer (value);
+		if (!priv->multi_idx)
+			g_return_if_reached ();
+		nm_dedup_multi_index_ref (priv->multi_idx);
+		break;
 	case PROP_IFACE:
 		/* construct-only */
 		priv->iface = g_value_dup_string (value);
@@ -860,19 +897,26 @@ set_property (GObject *object, guint prop_id,
 		/* construct-only */
 		priv->hwaddr = g_value_dup_boxed (value);
 		break;
-	case PROP_IPV6:
+	case PROP_ADDR_FAMILY:
 		/* construct-only */
-		priv->ipv6 = g_value_get_boolean (value);
+		priv->addr_family = g_value_get_int (value);
+		if (!NM_IN_SET (priv->addr_family, AF_INET, AF_INET6))
+			g_return_if_reached ();
 		break;
 	case PROP_UUID:
 		/* construct-only */
 		priv->uuid = g_value_dup_string (value);
 		break;
-	case PROP_PRIORITY:
+	case PROP_ROUTE_TABLE:
+		/* construct-only */
+		priv->route_table = g_value_get_uint (value);
+		break;
+	case PROP_ROUTE_METRIC:
 		/* construct-only */
-		priv->priority = g_value_get_uint (value);
+		priv->route_metric = g_value_get_uint (value);
 		break;
 	case PROP_TIMEOUT:
+		/* construct-only */
 		priv->timeout = g_value_get_uint (value);
 		break;
 	default:
@@ -924,6 +968,8 @@ dispose (GObject *object)
 	}
 
 	G_OBJECT_CLASS (nm_dhcp_client_parent_class)->dispose (object);
+
+	priv->multi_idx = nm_dedup_multi_index_unref (priv->multi_idx);
 }
 
 static void
@@ -940,6 +986,12 @@ nm_dhcp_client_class_init (NMDhcpClientClass *client_class)
 	client_class->stop = stop;
 	client_class->get_duid = get_duid;
 
+	obj_properties[PROP_MULTI_IDX] =
+	    g_param_spec_pointer (NM_DHCP_CLIENT_MULTI_IDX, "", "",
+	                            G_PARAM_WRITABLE
+	                          | G_PARAM_CONSTRUCT_ONLY
+	                          | G_PARAM_STATIC_STRINGS);
+
 	obj_properties[PROP_IFACE] =
 	    g_param_spec_string (NM_DHCP_CLIENT_INTERFACE, "", "",
 	                         NULL,
@@ -958,11 +1010,11 @@ nm_dhcp_client_class_init (NMDhcpClientClass *client_class)
 	                        G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
 	                        G_PARAM_STATIC_STRINGS);
 
-	obj_properties[PROP_IPV6] =
-	    g_param_spec_boolean (NM_DHCP_CLIENT_IPV6, "", "",
-	                          FALSE,
-	                          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
-	                          G_PARAM_STATIC_STRINGS);
+	obj_properties[PROP_ADDR_FAMILY] =
+	    g_param_spec_int (NM_DHCP_CLIENT_ADDR_FAMILY, "", "",
+	                      0, G_MAXINT, AF_UNSPEC,
+	                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+	                      G_PARAM_STATIC_STRINGS);
 
 	obj_properties[PROP_UUID] =
 	    g_param_spec_string (NM_DHCP_CLIENT_UUID, "", "",
@@ -970,15 +1022,21 @@ nm_dhcp_client_class_init (NMDhcpClientClass *client_class)
 	                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
 	                         G_PARAM_STATIC_STRINGS);
 
-	obj_properties[PROP_PRIORITY] =
-	    g_param_spec_uint (NM_DHCP_CLIENT_PRIORITY, "", "",
+	obj_properties[PROP_ROUTE_TABLE] =
+	    g_param_spec_uint (NM_DHCP_CLIENT_ROUTE_TABLE, "", "",
+	                       0, G_MAXUINT32, RT_TABLE_MAIN,
+	                       G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY |
+	                       G_PARAM_STATIC_STRINGS);
+
+	obj_properties[PROP_ROUTE_METRIC] =
+	    g_param_spec_uint (NM_DHCP_CLIENT_ROUTE_METRIC, "", "",
 	                       0, G_MAXUINT32, 0,
 	                       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
 	                       G_PARAM_STATIC_STRINGS);
 
 	obj_properties[PROP_TIMEOUT] =
 	    g_param_spec_uint (NM_DHCP_CLIENT_TIMEOUT, "", "",
-	                       0, G_MAXUINT, 45,
+	                       1, G_MAXINT32, NM_DHCP_TIMEOUT_DEFAULT,
 	                       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
 	                       G_PARAM_STATIC_STRINGS);