summary refs log tree commit diff
path: root/src/dhcp/nm-dhcp-manager.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/dhcp/nm-dhcp-manager.c')
-rw-r--r--src/dhcp/nm-dhcp-manager.c118
1 files changed, 77 insertions, 41 deletions
diff --git a/src/dhcp/nm-dhcp-manager.c b/src/dhcp/nm-dhcp-manager.c
index bf22872d..f5c7c84b 100644
--- a/src/dhcp/nm-dhcp-manager.c
+++ b/src/dhcp/nm-dhcp-manager.c
@@ -43,8 +43,8 @@
 
 typedef struct {
 	const NMDhcpClientFactory *client_factory;
-	char *default_hostname;
-	CList dhcp_client_lst_head;
+	GHashTable *        clients;
+	char *              default_hostname;
 } NMDhcpManagerPrivate;
 
 struct _NMDhcpManager {
@@ -98,17 +98,21 @@ static NMDhcpClient *
 get_client_for_ifindex (NMDhcpManager *manager, int addr_family, int ifindex)
 {
 	NMDhcpManagerPrivate *priv;
-	NMDhcpClient *client;
+	GHashTableIter iter;
+	gpointer value;
 
 	g_return_val_if_fail (NM_IS_DHCP_MANAGER (manager), NULL);
 	g_return_val_if_fail (ifindex > 0, NULL);
 
 	priv = NM_DHCP_MANAGER_GET_PRIVATE (manager);
 
-	c_list_for_each_entry (client, &priv->dhcp_client_lst_head, dhcp_client_lst) {
-		if (   nm_dhcp_client_get_ifindex (client) == ifindex
-		    && nm_dhcp_client_get_addr_family (client) == addr_family)
-			return client;
+	g_hash_table_iter_init (&iter, priv->clients);
+	while (g_hash_table_iter_next (&iter, NULL, &value)) {
+		NMDhcpClient *candidate = NM_DHCP_CLIENT (value);
+
+		if (   nm_dhcp_client_get_ifindex (candidate) == ifindex
+		    && nm_dhcp_client_get_addr_family (candidate) == addr_family)
+			return candidate;
 	}
 
 	return NULL;
@@ -125,19 +129,13 @@ static void
 remove_client (NMDhcpManager *self, NMDhcpClient *client)
 {
 	g_signal_handlers_disconnect_by_func (client, client_state_changed, self);
-	c_list_unlink (&client->dhcp_client_lst);
 
 	/* Stopping the client is left up to the controlling device
 	 * explicitly since we may want to quit NetworkManager but not terminate
 	 * the DHCP client.
 	 */
-}
 
-static void
-remove_client_unref (NMDhcpManager *self, NMDhcpClient *client)
-{
-	remove_client (self, client);
-	g_object_unref (client);
+	g_hash_table_remove (NM_DHCP_MANAGER_GET_PRIVATE (self)->clients, client);
 }
 
 static void
@@ -149,7 +147,7 @@ client_state_changed (NMDhcpClient *client,
                       NMDhcpManager *self)
 {
 	if (state >= NM_DHCP_STATE_TIMEOUT)
-		remove_client_unref (self, client);
+		remove_client (self, client);
 }
 
 static NMDhcpClient *
@@ -158,12 +156,12 @@ client_start (NMDhcpManager *self,
               NMDedupMultiIndex *multi_idx,
               const char *iface,
               int ifindex,
-              GBytes *hwaddr,
+              const GByteArray *hwaddr,
               const char *uuid,
               guint32 route_table,
               guint32 route_metric,
               const struct in6_addr *ipv6_ll_addr,
-              GBytes *dhcp_client_id,
+              const char *dhcp_client_id,
               guint32 timeout,
               const char *dhcp_anycast_addr,
               const char *hostname,
@@ -181,21 +179,23 @@ client_start (NMDhcpManager *self,
 	g_return_val_if_fail (NM_IS_DHCP_MANAGER (self), NULL);
 	g_return_val_if_fail (ifindex > 0, NULL);
 	g_return_val_if_fail (uuid != NULL, NULL);
-	g_return_val_if_fail (!dhcp_client_id || g_bytes_get_size (dhcp_client_id) >= 2, NULL);
 
 	priv = NM_DHCP_MANAGER_GET_PRIVATE (self);
 
+	/* Ensure we have a usable DHCP client */
 	if (!priv->client_factory)
 		return NULL;
 
 	/* Kill any old client instance */
 	client = get_client_for_ifindex (self, addr_family, ifindex);
 	if (client) {
+		g_object_ref (client);
 		remove_client (self, client);
 		nm_dhcp_client_stop (client, FALSE);
 		g_object_unref (client);
 	}
 
+	/* And make a new one */
 	client = g_object_new (priv->client_factory->get_type (),
 	                       NM_DHCP_CLIENT_MULTI_IDX, multi_idx,
 	                       NM_DHCP_CLIENT_ADDR_FAMILY, addr_family,
@@ -206,26 +206,21 @@ client_start (NMDhcpManager *self,
 	                       NM_DHCP_CLIENT_ROUTE_TABLE, (guint) route_table,
 	                       NM_DHCP_CLIENT_ROUTE_METRIC, (guint) route_metric,
 	                       NM_DHCP_CLIENT_TIMEOUT, (guint) timeout,
-	                       NM_DHCP_CLIENT_FLAGS, (guint) (0
-	                           | (hostname_use_fqdn ? NM_DHCP_CLIENT_FLAGS_USE_FQDN  : 0)
-	                           | (info_only         ? NM_DHCP_CLIENT_FLAGS_INFO_ONLY : 0)
-	                       ),
 	                       NULL);
-	nm_assert (client && c_list_is_empty (&client->dhcp_client_lst));
-	c_list_link_tail (&priv->dhcp_client_lst_head, &client->dhcp_client_lst);
+	g_hash_table_insert (NM_DHCP_MANAGER_GET_PRIVATE (self)->clients, client, g_object_ref (client));
 	g_signal_connect (client, NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED, G_CALLBACK (client_state_changed), self);
 
 	if (addr_family == AF_INET)
-		success = nm_dhcp_client_start_ip4 (client, dhcp_client_id, dhcp_anycast_addr, hostname, last_ip4_address);
+		success = nm_dhcp_client_start_ip4 (client, dhcp_client_id, dhcp_anycast_addr, hostname, hostname_use_fqdn, last_ip4_address);
 	else
-		success = nm_dhcp_client_start_ip6 (client, dhcp_anycast_addr, ipv6_ll_addr, hostname, privacy, needed_prefixes);
+		success = nm_dhcp_client_start_ip6 (client, dhcp_anycast_addr, ipv6_ll_addr, hostname, info_only, privacy, needed_prefixes);
 
 	if (!success) {
-		remove_client_unref (self, client);
-		return NULL;
+		remove_client (self, client);
+		client = NULL;
 	}
 
-	return g_object_ref (client);
+	return client;
 }
 
 /* Caller owns a reference to the NMDhcpClient on return */
@@ -234,14 +229,14 @@ nm_dhcp_manager_start_ip4 (NMDhcpManager *self,
                            NMDedupMultiIndex *multi_idx,
                            const char *iface,
                            int ifindex,
-                           GBytes *hwaddr,
+                           const GByteArray *hwaddr,
                            const char *uuid,
                            guint32 route_table,
                            guint32 route_metric,
                            gboolean send_hostname,
                            const char *dhcp_hostname,
                            const char *dhcp_fqdn,
-                           GBytes *dhcp_client_id,
+                           const char *dhcp_client_id,
                            guint32 timeout,
                            const char *dhcp_anycast_addr,
                            const char *last_ip_address)
@@ -290,7 +285,7 @@ nm_dhcp_manager_start_ip6 (NMDhcpManager *self,
                            NMDedupMultiIndex *multi_idx,
                            const char *iface,
                            int ifindex,
-                           GBytes *hwaddr,
+                           const GByteArray *hwaddr,
                            const struct in6_addr *ll_addr,
                            const char *uuid,
                            guint32 route_table,
@@ -333,6 +328,31 @@ nm_dhcp_manager_set_default_hostname (NMDhcpManager *manager, const char *hostna
 	priv->default_hostname = g_strdup (hostname);
 }
 
+GSList *
+nm_dhcp_manager_get_lease_ip_configs (NMDhcpManager *self,
+                                      NMDedupMultiIndex *multi_idx,
+                                      int addr_family,
+                                      const char *iface,
+                                      int ifindex,
+                                      const char *uuid,
+                                      guint32 route_table,
+                                      guint32 route_metric)
+{
+	NMDhcpManagerPrivate *priv;
+
+	g_return_val_if_fail (NM_IS_DHCP_MANAGER (self), NULL);
+	g_return_val_if_fail (iface != NULL, NULL);
+	g_return_val_if_fail (ifindex >= -1, NULL);
+	g_return_val_if_fail (uuid != NULL, NULL);
+	g_return_val_if_fail (NM_IN_SET (addr_family, AF_INET, AF_INET6), NULL);
+
+	priv = NM_DHCP_MANAGER_GET_PRIVATE (self);
+	if (   priv->client_factory
+	    && priv->client_factory->get_lease_ip_configs)
+		return priv->client_factory->get_lease_ip_configs (multi_idx, addr_family, iface, ifindex, uuid, route_table, route_metric);
+	return NULL;
+}
+
 const char *
 nm_dhcp_manager_get_config (NMDhcpManager *self)
 {
@@ -358,8 +378,6 @@ nm_dhcp_manager_init (NMDhcpManager *self)
 	int i;
 	const NMDhcpClientFactory *client_factory = NULL;
 
-	c_list_init (&priv->dhcp_client_lst_head);
-
 	for (i = 0; i < G_N_ELEMENTS (_nm_dhcp_manager_factories); i++) {
 		const NMDhcpClientFactory *f = _nm_dhcp_manager_factories[i];
 
@@ -411,21 +429,38 @@ nm_dhcp_manager_init (NMDhcpManager *self)
 	nm_log_info (LOGD_DHCP, "dhcp-init: Using DHCP client '%s'", client_factory->name);
 
 	priv->client_factory = client_factory;
+	priv->clients = g_hash_table_new_full (g_direct_hash, g_direct_equal,
+	                                       NULL,
+	                                       (GDestroyNotify) g_object_unref);
 }
 
 static void
 dispose (GObject *object)
 {
-	NMDhcpManager *self = NM_DHCP_MANAGER (object);
-	NMDhcpManagerPrivate *priv = NM_DHCP_MANAGER_GET_PRIVATE (self);
-	NMDhcpClient *client, *client_safe;
-
-	c_list_for_each_entry_safe (client, client_safe, &priv->dhcp_client_lst_head, dhcp_client_lst)
-		remove_client_unref (self, client);
+	NMDhcpManagerPrivate *priv = NM_DHCP_MANAGER_GET_PRIVATE ((NMDhcpManager *) object);
+	GList *values, *iter;
+
+	if (priv->clients) {
+		values = g_hash_table_get_values (priv->clients);
+		for (iter = values; iter; iter = g_list_next (iter))
+			remove_client (NM_DHCP_MANAGER (object), NM_DHCP_CLIENT (iter->data));
+		g_list_free (values);
+	}
 
 	G_OBJECT_CLASS (nm_dhcp_manager_parent_class)->dispose (object);
+}
+
+static void
+finalize (GObject *object)
+{
+	NMDhcpManagerPrivate *priv = NM_DHCP_MANAGER_GET_PRIVATE ((NMDhcpManager *) object);
+
+	g_free (priv->default_hostname);
+
+	if (priv->clients)
+		g_hash_table_destroy (priv->clients);
 
-	nm_clear_g_free (&priv->default_hostname);
+	G_OBJECT_CLASS (nm_dhcp_manager_parent_class)->finalize (object);
 }
 
 static void
@@ -433,5 +468,6 @@ nm_dhcp_manager_class_init (NMDhcpManagerClass *manager_class)
 {
 	GObjectClass *object_class = G_OBJECT_CLASS (manager_class);
 
+	object_class->finalize = finalize;
 	object_class->dispose = dispose;
 }