diff --git a/src/rdisc/nm-fake-rdisc.c b/src/rdisc/nm-fake-rdisc.c index 36f386c36f..edf5342209 100644 --- a/src/rdisc/nm-fake-rdisc.c +++ b/src/rdisc/nm-fake-rdisc.c @@ -36,14 +36,23 @@ typedef struct { NMRDiscDHCPLevel dhcp_level; GArray *gateways; - GArray *addresses; - GArray *routes; + GArray *prefixes; GArray *dns_servers; GArray *dns_domains; int hop_limit; guint32 mtu; } FakeRa; +typedef struct { + struct in6_addr network; + int plen; + struct in6_addr gateway; + guint32 timestamp; + guint32 lifetime; + guint32 preferred; + NMRDiscPreference preference; +} FakePrefix; + typedef struct { guint receive_ra_id; GSList *ras; @@ -67,8 +76,7 @@ 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->prefixes, TRUE); g_array_free (ra->dns_servers, TRUE); g_array_free (ra->dns_domains, TRUE); g_free (ra); @@ -110,8 +118,7 @@ nm_fake_rdisc_add_ra (NMFakeRDisc *self, 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->prefixes = g_array_new (FALSE, FALSE, sizeof (FakePrefix)); 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); @@ -142,49 +149,31 @@ nm_fake_rdisc_add_gateway (NMFakeRDisc *self, } void -nm_fake_rdisc_add_address (NMFakeRDisc *self, - guint ra_id, - const char *addr, - guint32 timestamp, - guint32 lifetime, - guint32 preferred) +nm_fake_rdisc_add_prefix (NMFakeRDisc *self, + guint ra_id, + const char *network, + guint plen, + const char *gateway, + guint32 timestamp, + guint32 lifetime, + guint32 preferred, + NMRDiscPreference preference) { NMFakeRDiscPrivate *priv = NM_FAKE_RDISC_GET_PRIVATE (self); FakeRa *ra = find_ra (priv->ras, ra_id); - NMRDiscAddress *a; + FakePrefix *prefix; 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; + g_array_set_size (ra->prefixes, ra->prefixes->len + 1); + prefix = &g_array_index (ra->prefixes, FakePrefix, ra->prefixes->len - 1); + memset (prefix, 0, sizeof (*prefix)); + g_assert (inet_pton (AF_INET6, network, &prefix->network) == 1); + g_assert (inet_pton (AF_INET6, gateway, &prefix->gateway) == 1); + prefix->plen = plen; + prefix->timestamp = timestamp; + prefix->lifetime = lifetime; + prefix->preferred = preferred; + prefix->preference = preference; } void @@ -265,18 +254,31 @@ receive_ra (gpointer user_data) changed |= NM_RDISC_CONFIG_GATEWAYS; } - for (i = 0; i < ra->addresses->len; i++) { - NMRDiscAddress *item = &g_array_index (ra->addresses, NMRDiscAddress, i); + for (i = 0; i < ra->prefixes->len; i++) { + FakePrefix *item = &g_array_index (ra->prefixes, FakePrefix, i); + NMRDiscRoute route = { + .network = item->network, + .plen = item->plen, + .gateway = item->gateway, + .timestamp = item->timestamp, + .lifetime = item->lifetime, + .preference = item->preference, + }; - 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)) + if (nm_rdisc_add_route (rdisc, &route)) changed |= NM_RDISC_CONFIG_ROUTES; + + if (item->plen == 64) { + NMRDiscAddress address = { + .address = item->network, + .timestamp = item->timestamp, + .lifetime = item->lifetime, + .preferred = item->preferred, + }; + + if (nm_rdisc_complete_and_add_address (rdisc, &address)) + changed |= NM_RDISC_CONFIG_ADDRESSES; + } } for (i = 0; i < ra->dns_servers->len; i++) { diff --git a/src/rdisc/nm-fake-rdisc.h b/src/rdisc/nm-fake-rdisc.h index 74f74897fb..1082ba5ef1 100644 --- a/src/rdisc/nm-fake-rdisc.h +++ b/src/rdisc/nm-fake-rdisc.h @@ -59,20 +59,14 @@ void nm_fake_rdisc_add_gateway (NMFakeRDisc *self, guint32 lifetime, NMRDiscPreference preference); -void nm_fake_rdisc_add_address (NMFakeRDisc *self, - guint ra_id, - const char *addr, - guint32 timestamp, - guint32 lifetime, - guint32 preferred); - -void nm_fake_rdisc_add_route (NMFakeRDisc *self, +void nm_fake_rdisc_add_prefix (NMFakeRDisc *self, guint ra_id, const char *network, guint plen, const char *gateway, guint32 timestamp, guint32 lifetime, + guint32 preferred, NMRDiscPreference preference); void nm_fake_rdisc_add_dns_server (NMFakeRDisc *self, diff --git a/src/rdisc/nm-lndp-rdisc.c b/src/rdisc/nm-lndp-rdisc.c index a65ab03239..fead72cba5 100644 --- a/src/rdisc/nm-lndp-rdisc.c +++ b/src/rdisc/nm-lndp-rdisc.c @@ -163,7 +163,7 @@ receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data) /* Address */ if (ndp_msg_opt_prefix_flag_auto_addr_conf (msg, offset)) { - if (route.plen == 64 && rdisc->iid.id) { + if (route.plen == 64) { memset (&address, 0, sizeof (address)); address.address = route.network; address.timestamp = now; @@ -172,10 +172,7 @@ receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data) if (address.preferred > address.lifetime) address.preferred = address.lifetime; - /* Add the Interface Identifier to the lower 64 bits */ - nm_utils_ipv6_addr_set_interface_identfier (&address.address, rdisc->iid); - - if (nm_rdisc_add_address (rdisc, &address)) + if (nm_rdisc_complete_and_add_address (rdisc, &address)) changed |= NM_RDISC_CONFIG_ADDRESSES; } } diff --git a/src/rdisc/nm-rdisc-private.h b/src/rdisc/nm-rdisc-private.h index 59c0cf3757..c0ec739aba 100644 --- a/src/rdisc/nm-rdisc-private.h +++ b/src/rdisc/nm-rdisc-private.h @@ -27,11 +27,11 @@ void nm_rdisc_ra_received (NMRDisc *rdisc, guint32 now, NMRDiscConfigMap changed); -gboolean nm_rdisc_add_gateway (NMRDisc *rdisc, const NMRDiscGateway *new); -gboolean nm_rdisc_add_address (NMRDisc *rdisc, const NMRDiscAddress *new); -gboolean nm_rdisc_add_route (NMRDisc *rdisc, const NMRDiscRoute *new); -gboolean nm_rdisc_add_dns_server (NMRDisc *rdisc, const NMRDiscDNSServer *new); -gboolean nm_rdisc_add_dns_domain (NMRDisc *rdisc, const NMRDiscDNSDomain *new); +gboolean nm_rdisc_add_gateway (NMRDisc *rdisc, const NMRDiscGateway *new); +gboolean nm_rdisc_complete_and_add_address (NMRDisc *rdisc, NMRDiscAddress *new); +gboolean nm_rdisc_add_route (NMRDisc *rdisc, const NMRDiscRoute *new); +gboolean nm_rdisc_add_dns_server (NMRDisc *rdisc, const NMRDiscDNSServer *new); +gboolean nm_rdisc_add_dns_domain (NMRDisc *rdisc, const NMRDiscDNSDomain *new); /*********************************************************************************************/ diff --git a/src/rdisc/nm-rdisc.c b/src/rdisc/nm-rdisc.c index cad3a90eed..a7c7f631c7 100644 --- a/src/rdisc/nm-rdisc.c +++ b/src/rdisc/nm-rdisc.c @@ -87,11 +87,46 @@ nm_rdisc_add_gateway (NMRDisc *rdisc, const NMRDiscGateway *new) return !!new->lifetime; } +/** + * complete_address: + * @rdisc: the #NMRDisc + * @addr: the #NMRDiscAddress + * + * Adds the host part to the address that has network part set. + * If the address already has a host part, add a different host part + * if possible (this is useful in case DAD failed). + * + * Can fail if a different address can not be generated (DAD failure + * for an EUI-64 address or DAD counter overflow). + * + * Returns: %TRUE if the address could be completed, %FALSE otherwise. + **/ +static gboolean +complete_address (NMRDisc *rdisc, NMRDiscAddress *addr) +{ + if (!rdisc->iid.id) { + _LOGW ("complete-address: can't generate an EUI-64 address: no interface identifier"); + return FALSE; + } + + if (addr->address.s6_addr32[2] == 0x0 && addr->address.s6_addr32[3] == 0x0) { + _LOGD ("complete-address: adding an EUI-64 address"); + nm_utils_ipv6_addr_set_interface_identfier (&addr->address, rdisc->iid); + return TRUE; + } + + _LOGW ("complete-address: can't generate a new EUI-64 address"); + return FALSE; +} + gboolean -nm_rdisc_add_address (NMRDisc *rdisc, const NMRDiscAddress *new) +nm_rdisc_complete_and_add_address (NMRDisc *rdisc, NMRDiscAddress *new) { int i; + if (!complete_address (rdisc, new)) + return FALSE; + for (i = 0; i < rdisc->addresses->len; i++) { NMRDiscAddress *item = &g_array_index (rdisc->addresses, NMRDiscAddress, i); diff --git a/src/rdisc/tests/test-rdisc-fake.c b/src/rdisc/tests/test-rdisc-fake.c index 3b248dc69b..6ba8d27133 100644 --- a/src/rdisc/tests/test-rdisc-fake.c +++ b/src/rdisc/tests/test-rdisc-fake.c @@ -37,8 +37,11 @@ rdisc_new (void) NMRDisc *rdisc; const int ifindex = 1; const char *ifname = nm_platform_link_get_name (NM_PLATFORM_GET, ifindex); + NMUtilsIPv6IfaceId iid; rdisc = nm_fake_rdisc_new (ifindex, ifname); + iid.id_u8[7] = 1; + nm_rdisc_set_iid (rdisc, iid); g_assert (rdisc); return NM_FAKE_RDISC (rdisc); } @@ -145,8 +148,7 @@ test_simple (void) id = nm_fake_rdisc_add_ra (rdisc, 1, NM_RDISC_DHCP_LEVEL_OTHERCONF, 4, 1500); g_assert (id); nm_fake_rdisc_add_gateway (rdisc, id, "fe80::1", now, 10, NM_RDISC_PREFERENCE_MEDIUM); - nm_fake_rdisc_add_address (rdisc, id, "2001:db8:a:a::1", now, 10, 10); - nm_fake_rdisc_add_route (rdisc, id, "2001:db8:a:a::", 64, "fe80::1", now, 10, 10); + nm_fake_rdisc_add_prefix (rdisc, id, "2001:db8:a:a::", 64, "fe80::1", now, 10, 10, 10); nm_fake_rdisc_add_dns_server (rdisc, id, "2001:db8:c:c::1", now, 10); nm_fake_rdisc_add_dns_domain (rdisc, id, "foobar.com", now, 10); @@ -198,7 +200,7 @@ test_everything_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, TestData *dat g_assert_cmpint (rdisc->gateways->len, ==, 1); match_gateway (rdisc->gateways, 0, "fe80::2", data->timestamp1, 10, NM_RDISC_PREFERENCE_MEDIUM); g_assert_cmpint (rdisc->addresses->len, ==, 1); - match_address (rdisc->addresses, 0, "2001:db8:a:a::2", data->timestamp1, 10, 10); + match_address (rdisc->addresses, 0, "2001:db8:a:b::1", data->timestamp1, 10, 10); g_assert_cmpint (rdisc->routes->len, ==, 1); match_route (rdisc->routes, 0, "2001:db8:a:b::", 64, "fe80::2", data->timestamp1, 10, 10); g_assert_cmpint (rdisc->dns_servers->len, ==, 1); @@ -225,8 +227,7 @@ test_everything (void) id = nm_fake_rdisc_add_ra (rdisc, 1, NM_RDISC_DHCP_LEVEL_NONE, 4, 1500); g_assert (id); nm_fake_rdisc_add_gateway (rdisc, id, "fe80::1", now, 10, NM_RDISC_PREFERENCE_MEDIUM); - nm_fake_rdisc_add_address (rdisc, id, "2001:db8:a:a::1", now, 10, 10); - nm_fake_rdisc_add_route (rdisc, id, "2001:db8:a:a::", 64, "fe80::1", now, 10, 10); + nm_fake_rdisc_add_prefix (rdisc, id, "2001:db8:a:a::", 64, "fe80::1", now, 10, 10, 10); nm_fake_rdisc_add_dns_server (rdisc, id, "2001:db8:c:c::1", now, 10); nm_fake_rdisc_add_dns_domain (rdisc, id, "foobar.com", now, 10); @@ -234,15 +235,13 @@ test_everything (void) id = nm_fake_rdisc_add_ra (rdisc, 1, NM_RDISC_DHCP_LEVEL_NONE, 4, 1500); g_assert (id); nm_fake_rdisc_add_gateway (rdisc, id, "fe80::1", now, 0, NM_RDISC_PREFERENCE_MEDIUM); - nm_fake_rdisc_add_address (rdisc, id, "2001:db8:a:a::1", now, 0, 0); - nm_fake_rdisc_add_route (rdisc, id, "2001:db8:a:a::", 64, "fe80::1", now, 0, 0); + nm_fake_rdisc_add_prefix (rdisc, id, "2001:db8:a:a::", 64, "fe80::1", now, 0, 0, 0); nm_fake_rdisc_add_dns_server (rdisc, id, "2001:db8:c:c::1", now, 0); nm_fake_rdisc_add_dns_domain (rdisc, id, "foobar.com", now, 0); /* and add some new stuff */ nm_fake_rdisc_add_gateway (rdisc, id, "fe80::2", now, 10, NM_RDISC_PREFERENCE_MEDIUM); - nm_fake_rdisc_add_address (rdisc, id, "2001:db8:a:a::2", now, 10, 10); - nm_fake_rdisc_add_route (rdisc, id, "2001:db8:a:b::", 64, "fe80::2", now, 10, 10); + nm_fake_rdisc_add_prefix (rdisc, id, "2001:db8:a:b::", 64, "fe80::2", now, 10, 10, 10); nm_fake_rdisc_add_dns_server (rdisc, id, "2001:db8:c:c::2", now, 10); nm_fake_rdisc_add_dns_domain (rdisc, id, "foobar2.com", now, 10); @@ -276,7 +275,7 @@ test_preference_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, TestData *dat match_gateway (rdisc->gateways, 1, "fe80::1", data->timestamp1, 10, NM_RDISC_PREFERENCE_LOW); g_assert_cmpint (rdisc->addresses->len, ==, 2); match_address (rdisc->addresses, 0, "2001:db8:a:a::1", data->timestamp1, 10, 10); - match_address (rdisc->addresses, 1, "2001:db8:a:a::2", data->timestamp1 + 1, 10, 10); + match_address (rdisc->addresses, 1, "2001:db8:a:b::1", data->timestamp1 + 1, 10, 10); g_assert_cmpint (rdisc->routes->len, ==, 2); match_route (rdisc->routes, 0, "2001:db8:a:b::", 64, "fe80::2", data->timestamp1 + 1, 10, 10); match_route (rdisc->routes, 1, "2001:db8:a:a::", 64, "fe80::1", data->timestamp1, 10, 5); @@ -290,7 +289,7 @@ test_preference_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, TestData *dat match_gateway (rdisc->gateways, 1, "fe80::2", data->timestamp1 + 1, 10, NM_RDISC_PREFERENCE_MEDIUM); g_assert_cmpint (rdisc->addresses->len, ==, 2); match_address (rdisc->addresses, 0, "2001:db8:a:a::1", data->timestamp1 + 2, 10, 10); - match_address (rdisc->addresses, 1, "2001:db8:a:a::2", data->timestamp1 + 1, 10, 10); + match_address (rdisc->addresses, 1, "2001:db8:a:b::1", data->timestamp1 + 1, 10, 10); g_assert_cmpint (rdisc->routes->len, ==, 2); match_route (rdisc->routes, 0, "2001:db8:a:a::", 64, "fe80::1", data->timestamp1 + 2, 10, 15); match_route (rdisc->routes, 1, "2001:db8:a:b::", 64, "fe80::2", data->timestamp1 + 1, 10, 10); @@ -318,20 +317,17 @@ test_preference (void) id = nm_fake_rdisc_add_ra (rdisc, 1, NM_RDISC_DHCP_LEVEL_NONE, 4, 1500); g_assert (id); nm_fake_rdisc_add_gateway (rdisc, id, "fe80::1", now, 10, NM_RDISC_PREFERENCE_LOW); - nm_fake_rdisc_add_address (rdisc, id, "2001:db8:a:a::1", now, 10, 10); - nm_fake_rdisc_add_route (rdisc, id, "2001:db8:a:a::", 64, "fe80::1", now, 10, 5); + nm_fake_rdisc_add_prefix (rdisc, id, "2001:db8:a:a::", 64, "fe80::1", now, 10, 10, 5); id = nm_fake_rdisc_add_ra (rdisc, 1, NM_RDISC_DHCP_LEVEL_NONE, 4, 1500); g_assert (id); nm_fake_rdisc_add_gateway (rdisc, id, "fe80::2", ++now, 10, NM_RDISC_PREFERENCE_MEDIUM); - nm_fake_rdisc_add_address (rdisc, id, "2001:db8:a:a::2", now, 10, 10); - nm_fake_rdisc_add_route (rdisc, id, "2001:db8:a:b::", 64, "fe80::2", now, 10, 10); + nm_fake_rdisc_add_prefix (rdisc, id, "2001:db8:a:b::", 64, "fe80::2", now, 10, 10, 10); id = nm_fake_rdisc_add_ra (rdisc, 1, NM_RDISC_DHCP_LEVEL_NONE, 4, 1500); g_assert (id); nm_fake_rdisc_add_gateway (rdisc, id, "fe80::1", ++now, 10, NM_RDISC_PREFERENCE_HIGH); - nm_fake_rdisc_add_address (rdisc, id, "2001:db8:a:a::1", now, 10, 10); - nm_fake_rdisc_add_route (rdisc, id, "2001:db8:a:a::", 64, "fe80::1", now, 10, 15); + nm_fake_rdisc_add_prefix (rdisc, id, "2001:db8:a:a::", 64, "fe80::1", now, 10, 10, 15); g_signal_connect (rdisc, NM_RDISC_CONFIG_CHANGED, @@ -380,7 +376,6 @@ test_dns_solicit_loop_rs_sent (NMFakeRDisc *rdisc, TestData *data) id = nm_fake_rdisc_add_ra (rdisc, 0, NM_RDISC_DHCP_LEVEL_NONE, 4, 1500); g_assert (id); nm_fake_rdisc_add_gateway (rdisc, id, "fe80::1", now, 10, NM_RDISC_PREFERENCE_MEDIUM); - nm_fake_rdisc_add_address (rdisc, id, "2001:db8:a:a::1", now, 10, 10); nm_fake_rdisc_emit_new_ras (rdisc); } else if (data->rs_counter >= 6) { @@ -410,7 +405,6 @@ test_dns_solicit_loop (void) id = nm_fake_rdisc_add_ra (rdisc, 1, NM_RDISC_DHCP_LEVEL_NONE, 4, 1500); g_assert (id); nm_fake_rdisc_add_gateway (rdisc, id, "fe80::1", now, 10, NM_RDISC_PREFERENCE_LOW); - nm_fake_rdisc_add_address (rdisc, id, "2001:db8:a:a::1", now, 10, 10); nm_fake_rdisc_add_dns_server (rdisc, id, "2001:db8:c:c::1", now, 6); g_signal_connect (rdisc, diff --git a/src/rdisc/tests/test-rdisc-linux.c b/src/rdisc/tests/test-rdisc-linux.c index 184573bc2e..2d8cd080ac 100644 --- a/src/rdisc/tests/test-rdisc-linux.c +++ b/src/rdisc/tests/test-rdisc-linux.c @@ -40,6 +40,7 @@ main (int argc, char **argv) NMRDisc *rdisc; int ifindex = 1; const char *ifname; + NMUtilsIPv6IfaceId iid; nmtst_init_with_logging (&argc, &argv, NULL, "DEFAULT"); @@ -66,6 +67,8 @@ main (int argc, char **argv) return EXIT_FAILURE; } + iid.id_u8[7] = 1; + nm_rdisc_set_iid (rdisc, iid); nm_rdisc_start (rdisc); g_main_loop_run (loop);