summary refs log tree commit diff
path: root/src/rdisc/nm-fake-rdisc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/rdisc/nm-fake-rdisc.c')
-rw-r--r--src/rdisc/nm-fake-rdisc.c394
1 files changed, 328 insertions, 66 deletions
diff --git a/src/rdisc/nm-fake-rdisc.c b/src/rdisc/nm-fake-rdisc.c
index e631f28d..68f43c0e 100644
--- a/src/rdisc/nm-fake-rdisc.c
+++ b/src/rdisc/nm-fake-rdisc.c
@@ -24,6 +24,7 @@
 #include <arpa/inet.h>
 
 #include "nm-fake-rdisc.h"
+#include "nm-rdisc-private.h"
 
 #include "nm-logging.h"
 
@@ -31,10 +32,314 @@
 #define warning(...) nm_log_warn (LOGD_IP6, __VA_ARGS__)
 #define error(...) nm_log_err (LOGD_IP6, __VA_ARGS__)
 
+typedef struct {
+	guint id;
+	guint when;
+
+	NMRDiscDHCPLevel dhcp_level;
+	GArray *gateways;
+	GArray *addresses;
+	GArray *routes;
+	GArray *dns_servers;
+	GArray *dns_domains;
+	int hop_limit;
+	guint32 mtu;
+} FakeRa;
+
+typedef struct {
+	guint receive_ra_id;
+	GSList *ras;
+} NMFakeRDiscPrivate;
+
 #define NM_FAKE_RDISC_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_FAKE_RDISC, NMFakeRDiscPrivate))
 
 G_DEFINE_TYPE (NMFakeRDisc, nm_fake_rdisc, NM_TYPE_RDISC)
 
+enum {
+	RS_SENT,
+	LAST_SIGNAL
+};
+static guint signals[LAST_SIGNAL] = { 0 };
+
+/******************************************************************/
+
+static void
+fake_ra_free (gpointer data)
+{
+	FakeRa *ra = data;
+
+	g_array_free (ra->gateways, TRUE);
+	g_array_free (ra->addresses, TRUE);
+	g_array_free (ra->routes, TRUE);
+	g_array_free (ra->dns_servers, TRUE);
+	g_array_free (ra->dns_domains, TRUE);
+	g_free (ra);
+}
+
+static void
+ra_dns_domain_free (gpointer data)
+{
+	g_free (((NMRDiscDNSDomain *)(data))->domain);
+}
+
+static FakeRa *
+find_ra (GSList *ras, guint id)
+{
+	GSList *iter;
+
+	for (iter = ras; iter; iter = iter->next) {
+		if (((FakeRa *) iter->data)->id == id)
+			return iter->data;
+	}
+	return NULL;
+}
+
+guint
+nm_fake_rdisc_add_ra (NMFakeRDisc *self,
+                      guint seconds_after_previous,
+                      NMRDiscDHCPLevel dhcp_level,
+                      int hop_limit,
+                      guint32 mtu)
+{
+	NMFakeRDiscPrivate *priv = NM_FAKE_RDISC_GET_PRIVATE (self);
+	static guint counter = 1;
+	FakeRa *ra;
+
+	ra = g_malloc0 (sizeof (*ra));
+	ra->id = counter++;
+	ra->when = seconds_after_previous;
+	ra->dhcp_level = dhcp_level;
+	ra->hop_limit = hop_limit;
+	ra->mtu = mtu;
+	ra->gateways = g_array_new (FALSE, FALSE, sizeof (NMRDiscGateway));
+	ra->addresses = g_array_new (FALSE, FALSE, sizeof (NMRDiscAddress));
+	ra->routes = g_array_new (FALSE, FALSE, sizeof (NMRDiscRoute));
+	ra->dns_servers = g_array_new (FALSE, FALSE, sizeof (NMRDiscDNSServer));
+	ra->dns_domains = g_array_new (FALSE, FALSE, sizeof (NMRDiscDNSDomain));
+	g_array_set_clear_func (ra->dns_domains, ra_dns_domain_free);
+
+	priv->ras = g_slist_append (priv->ras, ra);
+	return ra->id;
+}
+
+void
+nm_fake_rdisc_add_gateway (NMFakeRDisc *self,
+                           guint ra_id,
+                           const char *addr,
+                           guint32 timestamp,
+                           guint32 lifetime,
+                           NMRDiscPreference preference)
+{
+	NMFakeRDiscPrivate *priv = NM_FAKE_RDISC_GET_PRIVATE (self);
+	FakeRa *ra = find_ra (priv->ras, ra_id);
+	NMRDiscGateway *gw;
+
+	g_assert (ra);
+	g_array_set_size (ra->gateways, ra->gateways->len + 1);
+	gw = &g_array_index (ra->gateways, NMRDiscGateway, ra->gateways->len - 1);
+	g_assert (inet_pton (AF_INET6, addr, &gw->address) == 1);
+	gw->timestamp = timestamp;
+	gw->lifetime = lifetime;
+	gw->preference = preference;
+}
+
+void
+nm_fake_rdisc_add_address (NMFakeRDisc *self,
+                           guint ra_id,
+                           const char *addr,
+                           guint32 timestamp,
+                           guint32 lifetime,
+                           guint32 preferred)
+{
+	NMFakeRDiscPrivate *priv = NM_FAKE_RDISC_GET_PRIVATE (self);
+	FakeRa *ra = find_ra (priv->ras, ra_id);
+	NMRDiscAddress *a;
+
+	g_assert (ra);
+	g_array_set_size (ra->addresses, ra->addresses->len + 1);
+	a = &g_array_index (ra->addresses, NMRDiscAddress, ra->addresses->len - 1);
+	g_assert (inet_pton (AF_INET6, addr, &a->address) == 1);
+	a->timestamp = timestamp;
+	a->lifetime = lifetime;
+	a->preferred = preferred;
+}
+
+void
+nm_fake_rdisc_add_route (NMFakeRDisc *self,
+                         guint ra_id,
+                         const char *network,
+                         guint plen,
+                         const char *gateway,
+                         guint32 timestamp,
+                         guint32 lifetime,
+                         NMRDiscPreference preference)
+{
+	NMFakeRDiscPrivate *priv = NM_FAKE_RDISC_GET_PRIVATE (self);
+	FakeRa *ra = find_ra (priv->ras, ra_id);
+	NMRDiscRoute *route;
+
+	g_assert (ra);
+	g_array_set_size (ra->routes, ra->routes->len + 1);
+	route = &g_array_index (ra->routes, NMRDiscRoute, ra->routes->len - 1);
+	g_assert (inet_pton (AF_INET6, network, &route->network) == 1);
+	g_assert (inet_pton (AF_INET6, gateway, &route->gateway) == 1);
+	route->plen = plen;
+	route->timestamp = timestamp;
+	route->lifetime = lifetime;
+	route->preference = preference;
+}
+
+void
+nm_fake_rdisc_add_dns_server (NMFakeRDisc *self,
+                              guint ra_id,
+                              const char *address,
+                              guint32 timestamp,
+                              guint32 lifetime)
+{
+	NMFakeRDiscPrivate *priv = NM_FAKE_RDISC_GET_PRIVATE (self);
+	FakeRa *ra = find_ra (priv->ras, ra_id);
+	NMRDiscDNSServer *dns;
+
+	g_assert (ra);
+	g_array_set_size (ra->dns_servers, ra->dns_servers->len + 1);
+	dns = &g_array_index (ra->dns_servers, NMRDiscDNSServer, ra->dns_servers->len - 1);
+	g_assert (inet_pton (AF_INET6, address, &dns->address) == 1);
+	dns->timestamp = timestamp;
+	dns->lifetime = lifetime;
+}
+
+void
+nm_fake_rdisc_add_dns_domain (NMFakeRDisc *self,
+                              guint ra_id,
+                              const char *domain,
+                              guint32 timestamp,
+                              guint32 lifetime)
+{
+	NMFakeRDiscPrivate *priv = NM_FAKE_RDISC_GET_PRIVATE (self);
+	FakeRa *ra = find_ra (priv->ras, ra_id);
+	NMRDiscDNSDomain *dns;
+
+	g_assert (ra);
+	g_array_set_size (ra->dns_domains, ra->dns_domains->len + 1);
+	dns = &g_array_index (ra->dns_domains, NMRDiscDNSDomain, ra->dns_domains->len - 1);
+	dns->domain = g_strdup (domain);
+	dns->timestamp = timestamp;
+	dns->lifetime = lifetime;
+}
+
+gboolean
+nm_fake_rdisc_done (NMFakeRDisc *self)
+{
+	return !NM_FAKE_RDISC_GET_PRIVATE (self)->ras;
+}
+
+/******************************************************************/
+
+static gboolean
+send_rs (NMRDisc *rdisc)
+{
+	g_signal_emit (rdisc, signals[RS_SENT], 0);
+	return TRUE;
+}
+
+static gboolean
+receive_ra (gpointer user_data)
+{
+	NMFakeRDisc *self = user_data;
+	NMFakeRDiscPrivate *priv = NM_FAKE_RDISC_GET_PRIVATE (self);
+	NMRDisc *rdisc = NM_RDISC (self);
+	FakeRa *ra = priv->ras->data;
+	NMRDiscConfigMap changed = 0;
+	guint32 now = nm_utils_get_monotonic_timestamp_s ();
+	guint i;
+
+	priv->receive_ra_id = 0;
+
+	if (rdisc->dhcp_level != ra->dhcp_level) {
+		rdisc->dhcp_level = ra->dhcp_level;
+		changed |= NM_RDISC_CONFIG_DHCP_LEVEL;
+	}
+
+	for (i = 0; i < ra->gateways->len; i++) {
+		NMRDiscGateway *item = &g_array_index (ra->gateways, NMRDiscGateway, i);
+
+		if (nm_rdisc_add_gateway (rdisc, item))
+			changed |= NM_RDISC_CONFIG_GATEWAYS;
+	}
+
+	for (i = 0; i < ra->addresses->len; i++) {
+		NMRDiscAddress *item = &g_array_index (ra->addresses, NMRDiscAddress, i);
+
+		if (nm_rdisc_add_address (rdisc, item))
+			changed |= NM_RDISC_CONFIG_ADDRESSES;
+	}
+
+	for (i = 0; i < ra->routes->len; i++) {
+		NMRDiscRoute *item = &g_array_index (ra->routes, NMRDiscRoute, i);
+
+		if (nm_rdisc_add_route (rdisc, item))
+			changed |= NM_RDISC_CONFIG_ROUTES;
+	}
+
+	for (i = 0; i < ra->dns_servers->len; i++) {
+		NMRDiscDNSServer *item = &g_array_index (ra->dns_servers, NMRDiscDNSServer, i);
+
+		if (nm_rdisc_add_dns_server (rdisc, item))
+			changed |= NM_RDISC_CONFIG_DNS_SERVERS;
+	}
+
+	for (i = 0; i < ra->dns_domains->len; i++) {
+		NMRDiscDNSDomain *item = &g_array_index (ra->dns_domains, NMRDiscDNSDomain, i);
+
+		if (nm_rdisc_add_dns_domain (rdisc, item))
+			changed |= NM_RDISC_CONFIG_DNS_DOMAINS;
+	}
+
+	if (rdisc->mtu != ra->mtu) {
+		rdisc->mtu = ra->mtu;
+		changed |= NM_RDISC_CONFIG_MTU;
+	}
+
+	if (rdisc->hop_limit != ra->hop_limit) {
+		rdisc->hop_limit = ra->hop_limit;
+		changed |= NM_RDISC_CONFIG_HOP_LIMIT;
+	}
+
+	priv->ras = g_slist_remove (priv->ras, priv->ras->data);
+	fake_ra_free (ra);
+
+	nm_rdisc_ra_received (NM_RDISC (self), now, changed);
+
+	/* Schedule next RA */
+	if (priv->ras) {
+		ra = priv->ras->data;
+		priv->receive_ra_id = g_timeout_add_seconds (ra->when, receive_ra, self);
+	}
+
+	return G_SOURCE_REMOVE;
+}
+
+static void
+start (NMRDisc *rdisc)
+{
+	NMFakeRDiscPrivate *priv = NM_FAKE_RDISC_GET_PRIVATE (rdisc);
+	FakeRa *ra;
+
+	/* Queue up the first fake RA */
+	g_assert (priv->ras);
+	ra = NM_FAKE_RDISC_GET_PRIVATE (rdisc)->ras->data;
+
+	g_assert (!priv->receive_ra_id);
+	priv->receive_ra_id = g_timeout_add_seconds (ra->when, receive_ra, rdisc);
+}
+
+void
+nm_fake_rdisc_emit_new_ras (NMFakeRDisc *self)
+{
+	if (!NM_FAKE_RDISC_GET_PRIVATE (self)->receive_ra_id)
+		start (NM_RDISC (self));
+}
+
 /******************************************************************/
 
 NMRDisc *
@@ -52,85 +357,42 @@ nm_fake_rdisc_new (int ifindex, const char *ifname)
 }
 
 static void
-delayed_start (NMRDisc *rdisc)
+nm_fake_rdisc_init (NMFakeRDisc *fake_rdisc)
 {
-	int changed =
-		NM_RDISC_CONFIG_GATEWAYS | NM_RDISC_CONFIG_ADDRESSES | NM_RDISC_CONFIG_ROUTES |
-		NM_RDISC_CONFIG_DNS_SERVERS | NM_RDISC_CONFIG_DNS_DOMAINS;
-	debug ("%d", rdisc->dhcp_level);
-
-	g_signal_emit_by_name (
-			rdisc, NM_RDISC_CONFIG_CHANGED, changed);
 }
 
 static void
-start (NMRDisc *rdisc)
+dispose (GObject *object)
 {
-	g_idle_add ((GSourceFunc) (delayed_start), rdisc);
-}
+	NMFakeRDiscPrivate *priv = NM_FAKE_RDISC_GET_PRIVATE (object);
 
-/******************************************************************/
+	if (priv->receive_ra_id) {
+		g_source_remove (priv->receive_ra_id);
+		priv->receive_ra_id = 0;
+	}
 
-static void
-nm_fake_rdisc_init (NMFakeRDisc *fake_rdisc)
-{
-	NMRDisc *rdisc = NM_RDISC (fake_rdisc);
-	NMRDiscGateway gateway;
-	NMRDiscAddress address;
-	NMRDiscRoute route;
-	NMRDiscDNSServer dns_server;
-	NMRDiscDNSDomain dns_domain;
-
-	rdisc->dhcp_level = NM_RDISC_DHCP_LEVEL_NONE;
-
-	memset (&gateway, 0, sizeof (gateway));
-	inet_pton (AF_INET6, "fe80::1", &gateway.address);
-	g_array_append_val (rdisc->gateways, gateway);
-	inet_pton (AF_INET6, "fe80::2", &gateway.address);
-	g_array_append_val (rdisc->gateways, gateway);
-	inet_pton (AF_INET6, "fe80::3", &gateway.address);
-	g_array_append_val (rdisc->gateways, gateway);
-
-	memset (&address, 0, sizeof (address));
-	inet_pton (AF_INET6, "2001:db8:a:a::1", &address.address);
-	g_array_append_val (rdisc->addresses, address);
-	inet_pton (AF_INET6, "2001:db8:a:a::2", &address.address);
-	g_array_append_val (rdisc->addresses, address);
-	inet_pton (AF_INET6, "2001:db8:f:f::1", &address.address);
-	g_array_append_val (rdisc->addresses, address);
-
-	memset (&route, 0, sizeof (route));
-	route.plen = 64;
-	inet_pton (AF_INET6, "2001:db8:a:a::", &route.network);
-	g_array_append_val (rdisc->routes, route);
-	inet_pton (AF_INET6, "2001:db8:b:b::", &route.network);
-	g_array_append_val (rdisc->routes, route);
-
-	memset (&dns_server, 0, sizeof (dns_server));
-	inet_pton (AF_INET6, "2001:db8:c:c::1", &dns_server.address);
-	g_array_append_val (rdisc->dns_servers, dns_server);
-	inet_pton (AF_INET6, "2001:db8:c:c::2", &dns_server.address);
-	g_array_append_val (rdisc->dns_servers, dns_server);
-	inet_pton (AF_INET6, "2001:db8:c:c::3", &dns_server.address);
-	g_array_append_val (rdisc->dns_servers, dns_server);
-	inet_pton (AF_INET6, "2001:db8:c:c::4", &dns_server.address);
-	g_array_append_val (rdisc->dns_servers, dns_server);
-	inet_pton (AF_INET6, "2001:db8:c:c::5", &dns_server.address);
-	g_array_append_val (rdisc->dns_servers, dns_server);
-
-	memset (&dns_domain, 0, sizeof (dns_domain));
-	dns_domain.domain = g_strdup ("example.net");
-	g_array_append_val (rdisc->dns_domains, dns_domain);
-	dns_domain.domain = g_strdup ("example.com");
-	g_array_append_val (rdisc->dns_domains, dns_domain);
-	dns_domain.domain = g_strdup ("example.org");
-	g_array_append_val (rdisc->dns_domains, dns_domain);
+	g_slist_free_full (priv->ras, fake_ra_free);
+	priv->ras = NULL;
+
+	G_OBJECT_CLASS (nm_fake_rdisc_parent_class)->dispose (object);
 }
 
 static void
 nm_fake_rdisc_class_init (NMFakeRDiscClass *klass)
 {
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
 	NMRDiscClass *rdisc_class = NM_RDISC_CLASS (klass);
 
+	g_type_class_add_private (klass, sizeof (NMFakeRDiscPrivate));
+
+	object_class->dispose = dispose;
 	rdisc_class->start = start;
+	rdisc_class->send_rs = send_rs;
+
+	signals[RS_SENT] = g_signal_new (
+			NM_FAKE_RDISC_RS_SENT,
+			G_OBJECT_CLASS_TYPE (klass),
+			G_SIGNAL_RUN_FIRST,
+			0,  NULL, NULL, NULL,
+			G_TYPE_NONE, 0);
 }