diff --git a/.gitignore b/.gitignore index d2632d4d09..21de7800fa 100644 --- a/.gitignore +++ b/.gitignore @@ -247,8 +247,8 @@ test-*.trs /src/dhcp-manager/tests/test-dhcp-utils /src/dnsmasq-manager/tests/test-dnsmasq-utils /src/nm-iface-helper -/src/rdisc/tests/test-rdisc-fake -/src/rdisc/tests/test-rdisc-linux +/src/ndisc/tests/test-ndisc-fake +/src/ndisc/tests/test-ndisc-linux /src/settings/plugins/ibft/tests/test-ibft /src/settings/plugins/ifcfg-rh/nmdbus-ifcfg-rh.[ch] /src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh @@ -289,3 +289,4 @@ test-*.trs /src/devices/wifi/tests/test-wifi-ap-utils /src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh-utils /src/settings/plugins/ifnet/tests/check_ifnet +/src/rdisc/ diff --git a/Makefile.am b/Makefile.am index 643a7ff118..80729373cc 100644 --- a/Makefile.am +++ b/Makefile.am @@ -900,7 +900,7 @@ src_cppflags = \ -I$(top_srcdir)/src/platform \ -I$(top_srcdir)/src/platform/wifi \ -I$(top_srcdir)/src/ppp-manager \ - -I$(top_srcdir)/src/rdisc \ + -I$(top_srcdir)/src/ndisc \ -I$(top_srcdir)/src/settings \ -I$(top_srcdir)/src/supplicant-manager \ -I$(top_srcdir)/src/vpn-manager \ @@ -1142,11 +1142,11 @@ src_libNetworkManagerBase_la_SOURCES = \ src/platform/wifi/wifi-utils.c \ src/platform/wifi/wifi-utils.h \ \ - src/rdisc/nm-lndp-rdisc.c \ - src/rdisc/nm-lndp-rdisc.h \ - src/rdisc/nm-rdisc.c \ - src/rdisc/nm-rdisc.h \ - src/rdisc/nm-rdisc-private.h \ + src/ndisc/nm-lndp-ndisc.c \ + src/ndisc/nm-lndp-ndisc.h \ + src/ndisc/nm-ndisc.c \ + src/ndisc/nm-ndisc.h \ + src/ndisc/nm-ndisc-private.h \ \ src/nm-exported-object.c \ src/nm-exported-object.h \ @@ -1381,8 +1381,8 @@ src_tests_cppflags_linux = $(src_tests_cppflags) -DSETUP=nm_linux_platform_setup src_libNetworkManagerTest_la_CPPFLAGS = $(src_tests_cppflags) src_libNetworkManagerTest_la_SOURCES = \ - src/rdisc/nm-fake-rdisc.c \ - src/rdisc/nm-fake-rdisc.h \ + src/ndisc/nm-fake-ndisc.c \ + src/ndisc/nm-fake-ndisc.h \ src/platform/nm-fake-platform.c \ src/platform/nm-fake-platform.h \ src/platform/tests/test-common.c \ @@ -2613,26 +2613,26 @@ src_devices_tests_test_arping_LDADD = \ src/libNetworkManagerTest.la ############################################################################### -# src/rdisc/tests +# src/ndisc/tests ############################################################################### -src_rdisc_tests_ldflags = \ +src_ndisc_tests_ldflags = \ $(CODE_COVERAGE_LDFLAGS) -src_rdisc_tests_ldadd = \ +src_ndisc_tests_ldadd = \ src/libNetworkManagerTest.la \ $(GLIB_LIBS) -check_programs += src/rdisc/tests/test-rdisc-fake -check_programs_norun += src/rdisc/tests/test-rdisc-linux +check_programs += src/ndisc/tests/test-ndisc-fake +check_programs_norun += src/ndisc/tests/test-ndisc-linux -src_rdisc_tests_test_rdisc_linux_CPPFLAGS = $(src_tests_cppflags) -src_rdisc_tests_test_rdisc_linux_LDFLAGS = $(src_rdisc_tests_flags) -src_rdisc_tests_test_rdisc_linux_LDADD = $(src_rdisc_tests_ldadd) +src_ndisc_tests_test_ndisc_linux_CPPFLAGS = $(src_tests_cppflags) +src_ndisc_tests_test_ndisc_linux_LDFLAGS = $(src_ndisc_tests_flags) +src_ndisc_tests_test_ndisc_linux_LDADD = $(src_ndisc_tests_ldadd) -src_rdisc_tests_test_rdisc_fake_CPPFLAGS = $(src_tests_cppflags) -src_rdisc_tests_test_rdisc_fake_LDFLAGS = $(src_rdisc_tests_flags) -src_rdisc_tests_test_rdisc_fake_LDADD = $(src_rdisc_tests_ldadd) +src_ndisc_tests_test_ndisc_fake_CPPFLAGS = $(src_tests_cppflags) +src_ndisc_tests_test_ndisc_fake_LDFLAGS = $(src_ndisc_tests_flags) +src_ndisc_tests_test_ndisc_fake_LDADD = $(src_ndisc_tests_ldadd) ############################################################################### # src/supplicant-manager/tests diff --git a/clients/cli/nmcli.c b/clients/cli/nmcli.c index 890dc0d062..6e27c3d668 100644 --- a/clients/cli/nmcli.c +++ b/clients/cli/nmcli.c @@ -520,7 +520,7 @@ nmc_get_client (NmCli *nmc) if (!nmc->client) { nmc->client = nm_client_new (NULL, &error); if (!nmc->client) { - g_critical (_("Error: Could not create NMClient object: %s."), error->message); + g_printerr ("%s\n", error->message); g_clear_error (&error); exit (NMC_RESULT_ERROR_UNKNOWN); } diff --git a/libnm-core/nm-setting-ip6-config.c b/libnm-core/nm-setting-ip6-config.c index 50b3654301..4ef3333dc3 100644 --- a/libnm-core/nm-setting-ip6-config.c +++ b/libnm-core/nm-setting-ip6-config.c @@ -172,34 +172,38 @@ verify (NMSetting *setting, NMConnection *connection, GError **error) } else if ( !strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE) || !strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL) || !strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_SHARED)) { - if (nm_setting_ip_config_get_num_dns (s_ip) > 0) { - g_set_error (error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("this property is not allowed for '%s=%s'"), - NM_SETTING_IP_CONFIG_METHOD, method); - g_prefix_error (error, "%s.%s: ", NM_SETTING_IP6_CONFIG_SETTING_NAME, NM_SETTING_IP_CONFIG_DNS); - return FALSE; - } - if (nm_setting_ip_config_get_num_dns_searches (s_ip) > 0) { - g_set_error (error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("this property is not allowed for '%s=%s'"), - NM_SETTING_IP_CONFIG_METHOD, method); - g_prefix_error (error, "%s.%s: ", NM_SETTING_IP6_CONFIG_SETTING_NAME, NM_SETTING_IP_CONFIG_DNS_SEARCH); - return FALSE; - } + /* Shared allows IP addresses and DNS; link-local and disabled do not */ + if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_SHARED) != 0) { + if (nm_setting_ip_config_get_num_dns (s_ip) > 0) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("this property is not allowed for '%s=%s'"), + NM_SETTING_IP_CONFIG_METHOD, method); + g_prefix_error (error, "%s.%s: ", NM_SETTING_IP6_CONFIG_SETTING_NAME, NM_SETTING_IP_CONFIG_DNS); + return FALSE; + } - if (nm_setting_ip_config_get_num_addresses (s_ip) > 0) { - g_set_error (error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("this property is not allowed for '%s=%s'"), - NM_SETTING_IP_CONFIG_METHOD, method); - g_prefix_error (error, "%s.%s: ", NM_SETTING_IP6_CONFIG_SETTING_NAME, NM_SETTING_IP_CONFIG_ADDRESSES); - return FALSE; + if (nm_setting_ip_config_get_num_dns_searches (s_ip) > 0) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("this property is not allowed for '%s=%s'"), + NM_SETTING_IP_CONFIG_METHOD, method); + g_prefix_error (error, "%s.%s: ", NM_SETTING_IP6_CONFIG_SETTING_NAME, NM_SETTING_IP_CONFIG_DNS_SEARCH); + return FALSE; + } + + if (nm_setting_ip_config_get_num_addresses (s_ip) > 0) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("this property is not allowed for '%s=%s'"), + NM_SETTING_IP_CONFIG_METHOD, method); + g_prefix_error (error, "%s.%s: ", NM_SETTING_IP6_CONFIG_SETTING_NAME, NM_SETTING_IP_CONFIG_ADDRESSES); + return FALSE; + } } } else if ( !strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO) || !strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_DHCP)) { diff --git a/libnm-util/nm-setting-ip6-config.c b/libnm-util/nm-setting-ip6-config.c index 9ad93ac16c..37bdd0ed73 100644 --- a/libnm-util/nm-setting-ip6-config.c +++ b/libnm-util/nm-setting-ip6-config.c @@ -868,14 +868,17 @@ verify (NMSetting *setting, GSList *all_settings, GError **error) return FALSE; } - if (g_slist_length (priv->addresses)) { - g_set_error (error, - NM_SETTING_IP6_CONFIG_ERROR, - NM_SETTING_IP6_CONFIG_ERROR_NOT_ALLOWED_FOR_METHOD, - _("this property is not allowed for '%s=%s'"), - NM_SETTING_IP6_CONFIG_METHOD, priv->method); - g_prefix_error (error, "%s.%s: ", NM_SETTING_IP6_CONFIG_SETTING_NAME, NM_SETTING_IP6_CONFIG_ADDRESSES); - return FALSE; + /* Shared allows IP addresses; link-local and disabled do not */ + if (strcmp (priv->method, NM_SETTING_IP6_CONFIG_METHOD_SHARED) != 0) { + if (g_slist_length (priv->addresses)) { + g_set_error (error, + NM_SETTING_IP6_CONFIG_ERROR, + NM_SETTING_IP6_CONFIG_ERROR_NOT_ALLOWED_FOR_METHOD, + _("this property is not allowed for '%s=%s'"), + NM_SETTING_IP6_CONFIG_METHOD, priv->method); + g_prefix_error (error, "%s.%s: ", NM_SETTING_IP6_CONFIG_SETTING_NAME, NM_SETTING_IP6_CONFIG_ADDRESSES); + return FALSE; + } } } else if ( !strcmp (priv->method, NM_SETTING_IP6_CONFIG_METHOD_AUTO) || !strcmp (priv->method, NM_SETTING_IP6_CONFIG_METHOD_DHCP)) { diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 7b41ee911b..d3b6d95581 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -40,8 +40,8 @@ #include "NetworkManagerUtils.h" #include "nm-manager.h" #include "nm-platform.h" -#include "nm-rdisc.h" -#include "nm-lndp-rdisc.h" +#include "nm-ndisc.h" +#include "nm-lndp-ndisc.h" #include "nm-dhcp-manager.h" #include "nm-act-request.h" #include "nm-proxy-config.h" @@ -83,6 +83,8 @@ enum { AUTH_REQUEST, IP4_CONFIG_CHANGED, IP6_CONFIG_CHANGED, + IP6_PREFIX_DELEGATED, + IP6_SUBNET_NEEDED, REMOVED, RECHECK_AUTO_ACTIVATE, RECHECK_ASSUME, @@ -373,10 +375,10 @@ typedef struct _NMDevicePrivate { guint32 ip6_mtu; NMIP6Config * dad6_ip6_config; - NMRDisc * rdisc; - gulong rdisc_changed_id; - gulong rdisc_timeout_id; - NMSettingIP6ConfigPrivacy rdisc_use_tempaddr; + NMNDisc * ndisc; + gulong ndisc_changed_id; + gulong ndisc_timeout_id; + NMSettingIP6ConfigPrivacy ndisc_use_tempaddr; /* IP6 config from autoconf */ NMIP6Config * ac_ip6_config; @@ -387,8 +389,9 @@ typedef struct _NMDevicePrivate { struct { NMDhcpClient * client; - NMRDiscDHCPLevel mode; + NMNDiscDHCPLevel mode; gulong state_sigid; + gulong prefix_sigid; NMDhcp6Config * config; /* IP6 config from DHCP */ NMIP6Config * ip6_config; @@ -396,8 +399,11 @@ typedef struct _NMDevicePrivate { char * event_id; guint restart_id; guint num_tries_left; + guint needed_prefixes; } dhcp6; + gboolean needs_ip6_subnet; + /* allow autoconnect feature */ bool autoconnect; @@ -1626,7 +1632,7 @@ nm_device_update_dynamic_ip_setup (NMDevice *self) return; } } - if (priv->rdisc) { + if (priv->ndisc) { /* FIXME: todo */ } if (priv->dnsmasq_manager) { @@ -1811,6 +1817,73 @@ device_recheck_slave_status (NMDevice *self, const NMPlatformLink *plink) } } +static void +ndisc_set_router_config (NMNDisc *ndisc, NMDevice *self) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + guint32 now = nm_utils_get_monotonic_timestamp_s (); + GArray *addresses, *dns_servers, *dns_domains; + guint len, i; + + if (nm_ndisc_get_node_type (ndisc) != NM_NDISC_NODE_TYPE_ROUTER) + return; + + /* Addresses whose prefixes we announce. */ + len = nm_ip6_config_get_num_addresses (priv->ip6_config); + addresses = g_array_sized_new (FALSE, FALSE, sizeof (NMNDiscAddress), len); + for (i = 0; i < len; i++) { + const NMPlatformIP6Address *addr = nm_ip6_config_get_address (priv->ip6_config, i); + NMNDiscAddress *ndisc_addr; + + if (IN6_IS_ADDR_LINKLOCAL (&addr->address)) + continue; + + if ( addr->n_ifa_flags & IFA_F_TENTATIVE + || addr->n_ifa_flags & IFA_F_DADFAILED) + continue; + + if (addr->plen != 64) + continue; + + ndisc_addr = &g_array_index (addresses, NMNDiscAddress, addresses->len-1); + ndisc_addr->address = addr->address; + ndisc_addr->timestamp = addr->timestamp; + ndisc_addr->lifetime = addr->lifetime; + ndisc_addr->preferred = addr->preferred; + } + + /* DNS servers. */ + len = nm_ip6_config_get_num_nameservers (priv->ip6_config); + dns_servers = g_array_sized_new (FALSE, FALSE, sizeof (NMNDiscDNSServer), len); + for (i = 0; i < len; i++) { + const struct in6_addr *nameserver = nm_ip6_config_get_nameserver (priv->ip6_config, i); + NMNDiscDNSServer *ndisc_nameserver; + + ndisc_nameserver = &g_array_index (dns_servers, NMNDiscDNSServer, dns_servers->len-1); + ndisc_nameserver->address = *nameserver; + ndisc_nameserver->timestamp = now; + ndisc_nameserver->lifetime = NM_NDISC_ROUTER_LIFETIME; + } + + /* DNS domains. */ + len = nm_ip6_config_get_num_searches (priv->ip6_config); + dns_domains = g_array_sized_new (FALSE, FALSE, sizeof (NMNDiscDNSDomain), len); + for (i = 0; i < len; i++) { + const char *search = nm_ip6_config_get_search (priv->ip6_config, i); + NMNDiscDNSDomain *ndisc_search; + + ndisc_search = &g_array_index (dns_domains, NMNDiscDNSDomain, dns_domains->len-1); + ndisc_search->domain = g_strdup (search); + ndisc_search->timestamp = now; + ndisc_search->lifetime = NM_NDISC_ROUTER_LIFETIME; + } + + nm_ndisc_set_config (ndisc, addresses, dns_servers, dns_domains); + g_array_free (addresses, TRUE); + g_array_free (dns_servers, TRUE); + g_array_free (dns_domains, TRUE); +} + static gboolean device_link_changed (NMDevice *self) { @@ -1896,11 +1969,9 @@ device_link_changed (NMDevice *self) nm_device_emit_recheck_auto_activate (self); } - if (priv->rdisc && info.inet6_token.id) { - if (nm_rdisc_set_iid (priv->rdisc, info.inet6_token)) { + if (priv->ndisc && info.inet6_token.id) { + if (nm_ndisc_set_iid (priv->ndisc, info.inet6_token)) _LOGD (LOGD_DEVICE, "IPv6 tokenized identifier present on device %s", priv->iface); - nm_rdisc_start (priv->rdisc); - } } if (klass->link_changed) @@ -5268,6 +5339,7 @@ connection_ip6_method_requires_carrier (NMConnection *connection, static const char *ip6_carrier_methods[] = { NM_SETTING_IP6_CONFIG_METHOD_AUTO, NM_SETTING_IP6_CONFIG_METHOD_DHCP, + NM_SETTING_IP6_CONFIG_METHOD_SHARED, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL, NULL }; @@ -5428,13 +5500,14 @@ dhcp6_cleanup (NMDevice *self, CleanupType cleanup_type, gboolean release) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - priv->dhcp6.mode = NM_RDISC_DHCP_LEVEL_NONE; + priv->dhcp6.mode = NM_NDISC_DHCP_LEVEL_NONE; g_clear_object (&priv->dhcp6.ip6_config); g_clear_pointer (&priv->dhcp6.event_id, g_free); nm_clear_g_source (&priv->dhcp6.restart_id); if (priv->dhcp6.client) { nm_clear_g_signal_handler (priv->dhcp6.client, &priv->dhcp6.state_sigid); + nm_clear_g_signal_handler (priv->dhcp6.client, &priv->dhcp6.prefix_sigid); if ( cleanup_type == CLEANUP_TYPE_DECONFIGURE || cleanup_type == CLEANUP_TYPE_REMOVED) @@ -5635,7 +5708,7 @@ END_ADD_DEFAULT_ROUTE: } nm_ip6_config_addresses_sort (composite, - priv->rdisc ? priv->rdisc_use_tempaddr : NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); + priv->ndisc ? priv->ndisc_use_tempaddr : NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); /* Allow setting MTU etc */ if (commit) { @@ -5755,7 +5828,7 @@ dhcp6_fail (NMDevice *self, gboolean timeout) dhcp6_cleanup (self, CLEANUP_TYPE_DECONFIGURE, FALSE); - if (priv->dhcp6.mode == NM_RDISC_DHCP_LEVEL_MANAGED) { + if (priv->dhcp6.mode == NM_NDISC_DHCP_LEVEL_MANAGED) { /* Don't fail if there are static addresses configured on * the device, instead retry after some time. */ @@ -5801,7 +5874,7 @@ dhcp6_timeout (NMDevice *self, NMDhcpClient *client) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - if (priv->dhcp6.mode == NM_RDISC_DHCP_LEVEL_MANAGED) + if (priv->dhcp6.mode == NM_NDISC_DHCP_LEVEL_MANAGED) dhcp6_fail (self, TRUE); else { /* not a hard failure; just live with the RA info */ @@ -5878,7 +5951,7 @@ dhcp6_state_changed (NMDhcpClient *client, * may exit right after getting a response from the server. That's * normal. In that case we just ignore the exit. */ - if (priv->dhcp6.mode == NM_RDISC_DHCP_LEVEL_OTHERCONF) + if (priv->dhcp6.mode == NM_NDISC_DHCP_LEVEL_OTHERCONF) break; /* Otherwise, fall through */ case NM_DHCP_STATE_FAIL: @@ -5889,6 +5962,19 @@ dhcp6_state_changed (NMDhcpClient *client, } } +static void +dhcp6_prefix_delegated (NMDhcpClient *client, + NMPlatformIP6Address *prefix, + gpointer user_data) +{ + NMDevice *self = NM_DEVICE (user_data); + + /* Just re-emit. The device just contributes the prefix to the + * pool in NMPolicy, which decides about subnet allocation + * on the shared devices. */ + g_signal_emit (self, signals[IP6_PREFIX_DELEGATED], 0, prefix); +} + static gboolean dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection) { @@ -5925,8 +6011,9 @@ dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection) nm_setting_ip_config_get_dhcp_hostname (s_ip6), priv->dhcp_timeout, priv->dhcp_anycast_address, - (priv->dhcp6.mode == NM_RDISC_DHCP_LEVEL_OTHERCONF) ? TRUE : FALSE, - nm_setting_ip6_config_get_ip6_privacy (NM_SETTING_IP6_CONFIG (s_ip6))); + (priv->dhcp6.mode == NM_NDISC_DHCP_LEVEL_OTHERCONF) ? TRUE : FALSE, + nm_setting_ip6_config_get_ip6_privacy (NM_SETTING_IP6_CONFIG (s_ip6)), + priv->dhcp6.needed_prefixes); if (tmp) g_byte_array_free (tmp, TRUE); @@ -5935,6 +6022,10 @@ dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection) NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED, G_CALLBACK (dhcp6_state_changed), self); + priv->dhcp6.prefix_sigid = g_signal_connect (priv->dhcp6.client, + NM_DHCP_CLIENT_SIGNAL_PREFIX_DELEGATED, + G_CALLBACK (dhcp6_prefix_delegated), + self); } return !!priv->dhcp6.client; @@ -6001,6 +6092,95 @@ nm_device_dhcp6_renew (NMDevice *self, gboolean release) /*****************************************************************************/ +/* + * Called on the requesting interface when a subnet can't be obtained + * from known prefixes for a newly active shared connection. + */ +void +nm_device_request_ip6_prefixes (NMDevice *self, int needed_prefixes) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + + priv->dhcp6.needed_prefixes = needed_prefixes; + + if (priv->dhcp6.client) { + _LOGD (LOGD_IP6, "ipv6-pd: asking DHCPv6 for %d prefixes", needed_prefixes); + nm_device_dhcp6_renew (self, FALSE); + } else { + _LOGI (LOGD_IP6, "ipv6-pd: device doesn't use DHCPv6, can't request prefixes"); + } +} + +gboolean +nm_device_needs_ip6_subnet (NMDevice *self) +{ + return NM_DEVICE_GET_PRIVATE (self)->needs_ip6_subnet; +} + +/* + * Called on the ipv6.method=shared interface when a new subnet is allocated + * or the prefix from which it is allocated is renewed. + */ +void +nm_device_use_ip6_subnet (NMDevice *self, const NMPlatformIP6Address *subnet) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMPlatformIP6Address address = *subnet; + + if (!priv->ac_ip6_config) + priv->ac_ip6_config = nm_ip6_config_new (nm_device_get_ip_ifindex (self)); + + /* Assign a ::1 address in the subnet for us. */ + address.address.s6_addr32[3] |= htonl (1); + nm_ip6_config_add_address (priv->ac_ip6_config, &address); + + _LOGD (LOGD_IP6, "ipv6-pd: using %s address (preferred for %u seconds)", + nm_utils_inet6_ntop (&address.address, NULL), + subnet->preferred); + + /* This also updates the ndisc if there are actual changes. */ + if (!ip6_config_merge_and_apply (self, TRUE, NULL)) + _LOGW (LOGD_IP6, "ipv6-pd: failed applying IP6 config for connection sharing"); +} + +/* + * Called whenever the policy picks a default IPv6 device. + * The ipv6.method=shared devices just reuse its DNS configuration. + */ +void +nm_device_copy_ip6_dns_config (NMDevice *self, NMDevice *from_device) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMIP6Config *from_config = NULL; + int i; + + if (priv->ac_ip6_config) { + nm_ip6_config_reset_nameservers (priv->ac_ip6_config); + nm_ip6_config_reset_searches (priv->ac_ip6_config); + } else + priv->ac_ip6_config = nm_ip6_config_new (nm_device_get_ip_ifindex (self)); + + if (from_device) + from_config = nm_device_get_ip6_config (from_device); + if (!from_config) + return; + + for (i = 0; i < nm_ip6_config_get_num_nameservers (from_config); i++) { + nm_ip6_config_add_nameserver (priv->ac_ip6_config, + nm_ip6_config_get_nameserver (from_config, i)); + } + + for (i = 0; i < nm_ip6_config_get_num_searches (from_config); i++) { + nm_ip6_config_add_search (priv->ac_ip6_config, + nm_ip6_config_get_search (from_config, i)); + } + + if (!ip6_config_merge_and_apply (self, TRUE, NULL)) + _LOGW (LOGD_IP6, "ipv6-pd: failed applying DNS config for connection sharing"); +} + +/*****************************************************************************/ + static void linklocal6_cleanup (NMDevice *self) { @@ -6045,7 +6225,8 @@ linklocal6_complete (NMDevice *self) _LOGD (LOGD_DEVICE, "linklocal6: waiting for link-local addresses successful, continue with method %s", method); - if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO) == 0) { + if ( strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO) == 0 + || strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_SHARED) == 0) { if (!addrconf6_start_with_link_ready (self)) { /* Time out IPv6 instead of failing the entire activation */ nm_device_activate_schedule_ip6_config_timeout (self); @@ -6234,9 +6415,9 @@ nm_device_ipv6_set_mtu (NMDevice *self, guint32 mtu) } static void -rdisc_config_changed (NMRDisc *rdisc, const NMRDiscData *rdata, guint changed_int, NMDevice *self) +ndisc_config_changed (NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_int, NMDevice *self) { - NMRDiscConfigMap changed = changed_int; + NMNDiscConfigMap changed = changed_int; NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); int i; int system_support; @@ -6252,8 +6433,8 @@ rdisc_config_changed (NMRDisc *rdisc, const NMRDiscData *rdata, guint changed_in if (system_support) ifa_flags = IFA_F_NOPREFIXROUTE; - if ( priv->rdisc_use_tempaddr == NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR - || priv->rdisc_use_tempaddr == NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR) + if ( priv->ndisc_use_tempaddr == NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR + || priv->ndisc_use_tempaddr == NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR) { /* without system_support, this flag will be ignored. Still set it, doesn't seem to do any harm. */ ifa_flags |= IFA_F_MANAGETEMPADDR; @@ -6264,25 +6445,25 @@ rdisc_config_changed (NMRDisc *rdisc, const NMRDiscData *rdata, guint changed_in if (!priv->ac_ip6_config) priv->ac_ip6_config = nm_ip6_config_new (nm_device_get_ip_ifindex (self)); - if (changed & NM_RDISC_CONFIG_GATEWAYS) { - /* Use the first gateway as ordered in router discovery cache. */ + if (changed & NM_NDISC_CONFIG_GATEWAYS) { + /* Use the first gateway as ordered in neighbor discovery cache. */ if (rdata->gateways_n) nm_ip6_config_set_gateway (priv->ac_ip6_config, &rdata->gateways[0].address); else nm_ip6_config_set_gateway (priv->ac_ip6_config, NULL); } - if (changed & NM_RDISC_CONFIG_ADDRESSES) { - /* Rebuild address list from router discovery cache. */ + if (changed & NM_NDISC_CONFIG_ADDRESSES) { + /* Rebuild address list from neighbor discovery cache. */ nm_ip6_config_reset_addresses (priv->ac_ip6_config); - /* rdisc->addresses contains at most max_addresses entries. + /* ndisc->addresses contains at most max_addresses entries. * This is different from what the kernel does, which * also counts static and temporary addresses when checking * max_addresses. **/ for (i = 0; i < rdata->addresses_n; i++) { - const NMRDiscAddress *discovered_address = &rdata->addresses[i]; + const NMNDiscAddress *discovered_address = &rdata->addresses[i]; NMPlatformIP6Address address; memset (&address, 0, sizeof (address)); @@ -6293,24 +6474,24 @@ rdisc_config_changed (NMRDisc *rdisc, const NMRDiscData *rdata, guint changed_in address.preferred = discovered_address->preferred; if (address.preferred > address.lifetime) address.preferred = address.lifetime; - address.addr_source = NM_IP_CONFIG_SOURCE_RDISC; + address.addr_source = NM_IP_CONFIG_SOURCE_NDISC; address.n_ifa_flags = ifa_flags; nm_ip6_config_add_address (priv->ac_ip6_config, &address); } } - if (changed & NM_RDISC_CONFIG_ROUTES) { - /* Rebuild route list from router discovery cache. */ + if (changed & NM_NDISC_CONFIG_ROUTES) { + /* Rebuild route list from neighbor discovery cache. */ nm_ip6_config_reset_routes (priv->ac_ip6_config); for (i = 0; i < rdata->routes_n; i++) { - const NMRDiscRoute *discovered_route = &rdata->routes[i]; + const NMNDiscRoute *discovered_route = &rdata->routes[i]; const NMPlatformIP6Route route = { .network = discovered_route->network, .plen = discovered_route->plen, .gateway = discovered_route->gateway, - .rt_source = NM_IP_CONFIG_SOURCE_RDISC, + .rt_source = NM_IP_CONFIG_SOURCE_NDISC, .metric = nm_device_get_ip6_route_metric (self), }; @@ -6318,34 +6499,34 @@ rdisc_config_changed (NMRDisc *rdisc, const NMRDiscData *rdata, guint changed_in } } - if (changed & NM_RDISC_CONFIG_DNS_SERVERS) { - /* Rebuild DNS server list from router discovery cache. */ + if (changed & NM_NDISC_CONFIG_DNS_SERVERS) { + /* Rebuild DNS server list from neighbor discovery cache. */ nm_ip6_config_reset_nameservers (priv->ac_ip6_config); for (i = 0; i < rdata->dns_servers_n; i++) nm_ip6_config_add_nameserver (priv->ac_ip6_config, &rdata->dns_servers[i].address); } - if (changed & NM_RDISC_CONFIG_DNS_DOMAINS) { - /* Rebuild domain list from router discovery cache. */ - nm_ip6_config_reset_domains (priv->ac_ip6_config); + if (changed & NM_NDISC_CONFIG_DNS_DOMAINS) { + /* Rebuild domain list from neighbor discovery cache. */ + nm_ip6_config_reset_searches (priv->ac_ip6_config); for (i = 0; i < rdata->dns_domains_n; i++) - nm_ip6_config_add_domain (priv->ac_ip6_config, rdata->dns_domains[i].domain); + nm_ip6_config_add_search (priv->ac_ip6_config, rdata->dns_domains[i].domain); } - if (changed & NM_RDISC_CONFIG_DHCP_LEVEL) { + if (changed & NM_NDISC_CONFIG_DHCP_LEVEL) { dhcp6_cleanup (self, CLEANUP_TYPE_DECONFIGURE, TRUE); priv->dhcp6.mode = rdata->dhcp_level; - if (priv->dhcp6.mode != NM_RDISC_DHCP_LEVEL_NONE) { + if (priv->dhcp6.mode != NM_NDISC_DHCP_LEVEL_NONE) { NMDeviceStateReason reason; _LOGD (LOGD_DEVICE | LOGD_DHCP6, "Activation: Stage 3 of 5 (IP Configure Start) starting DHCPv6" " as requested by IPv6 router..."); if (!dhcp6_start (self, FALSE, &reason)) { - if (priv->dhcp6.mode == NM_RDISC_DHCP_LEVEL_MANAGED) { + if (priv->dhcp6.mode == NM_NDISC_DHCP_LEVEL_MANAGED) { nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason); return; } @@ -6353,17 +6534,17 @@ rdisc_config_changed (NMRDisc *rdisc, const NMRDiscData *rdata, guint changed_in } } - if (changed & NM_RDISC_CONFIG_HOP_LIMIT) + if (changed & NM_NDISC_CONFIG_HOP_LIMIT) nm_platform_sysctl_set_ip6_hop_limit_safe (NM_PLATFORM_GET, nm_device_get_ip_iface (self), rdata->hop_limit); - if (changed & NM_RDISC_CONFIG_MTU) + if (changed & NM_NDISC_CONFIG_MTU) priv->ip6_mtu = rdata->mtu; nm_device_activate_schedule_ip6_config_result (self); } static void -rdisc_ra_timeout (NMRDisc *rdisc, NMDevice *self) +ndisc_ra_timeout (NMNDisc *ndisc, NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); @@ -6393,13 +6574,13 @@ addrconf6_start_with_link_ready (NMDevice *self) NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMUtilsIPv6IfaceId iid; - g_assert (priv->rdisc); + g_assert (priv->ndisc); if (nm_device_get_ip_iface_identifier (self, &iid, FALSE)) { _LOGD (LOGD_IP6, "addrconf6: using the device EUI-64 identifier"); - nm_rdisc_set_iid (priv->rdisc, iid); + nm_ndisc_set_iid (priv->ndisc, iid); } else { - /* Don't abort the addrconf at this point -- if rdisc needs the iid + /* Don't abort the addrconf at this point -- if ndisc needs the iid * it will notice this itself. */ _LOGI (LOGD_IP6, "addrconf6: no interface identifier; IPv6 adddress creation may fail"); } @@ -6408,24 +6589,55 @@ addrconf6_start_with_link_ready (NMDevice *self) if (!ip6_config_merge_and_apply (self, TRUE, NULL)) _LOGW (LOGD_IP6, "failed to apply manual IPv6 configuration"); - nm_device_ipv6_sysctl_set (self, "accept_ra", "1"); - nm_device_ipv6_sysctl_set (self, "accept_ra_defrtr", "0"); - nm_device_ipv6_sysctl_set (self, "accept_ra_pinfo", "0"); - nm_device_ipv6_sysctl_set (self, "accept_ra_rtr_pref", "0"); + /* XXX: These sysctls would probably be better set by the lndp ndisc itself. */ + switch (nm_ndisc_get_node_type (priv->ndisc)) { + case NM_NDISC_NODE_TYPE_HOST: + /* Accepting prefixes from discovered routers. */ + nm_device_ipv6_sysctl_set (self, "accept_ra", "1"); + nm_device_ipv6_sysctl_set (self, "accept_ra_defrtr", "0"); + nm_device_ipv6_sysctl_set (self, "accept_ra_pinfo", "0"); + nm_device_ipv6_sysctl_set (self, "accept_ra_rtr_pref", "0"); + break; + case NM_NDISC_NODE_TYPE_ROUTER: + /* We're the router. */ + nm_device_ipv6_sysctl_set (self, "forwarding", "1"); + nm_device_activate_schedule_ip6_config_result (self); + priv->needs_ip6_subnet = TRUE; + g_signal_emit (self, signals[IP6_SUBNET_NEEDED], 0); + break; + default: + g_assert_not_reached (); + } - priv->rdisc_changed_id = g_signal_connect (priv->rdisc, - NM_RDISC_CONFIG_CHANGED, - G_CALLBACK (rdisc_config_changed), + priv->ndisc_changed_id = g_signal_connect (priv->ndisc, + NM_NDISC_CONFIG_RECEIVED, + G_CALLBACK (ndisc_config_changed), self); - priv->rdisc_timeout_id = g_signal_connect (priv->rdisc, - NM_RDISC_RA_TIMEOUT, - G_CALLBACK (rdisc_ra_timeout), + priv->ndisc_timeout_id = g_signal_connect (priv->ndisc, + NM_NDISC_RA_TIMEOUT, + G_CALLBACK (ndisc_ra_timeout), self); - nm_rdisc_start (priv->rdisc); + ndisc_set_router_config (priv->ndisc, self); + nm_ndisc_start (priv->ndisc); return TRUE; } +static NMNDiscNodeType +ndisc_node_type (NMDevice *self) +{ + NMConnection *connection; + + connection = nm_device_get_applied_connection (self); + g_assert (connection); + + if (strcmp (nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP6_CONFIG), + NM_SETTING_IP4_CONFIG_METHOD_SHARED) == 0) + return NM_NDISC_NODE_TYPE_ROUTER; + else + return NM_NDISC_NODE_TYPE_HOST; +} + static gboolean addrconf6_start (NMDevice *self, NMSettingIP6ConfigPrivacy use_tempaddr) { @@ -6451,21 +6663,22 @@ addrconf6_start (NMDevice *self, NMSettingIP6ConfigPrivacy use_tempaddr) stable_id = _get_stable_id (connection, &stable_type); if (stable_id) { - priv->rdisc = nm_lndp_rdisc_new (NM_PLATFORM_GET, + priv->ndisc = nm_lndp_ndisc_new (NM_PLATFORM_GET, nm_device_get_ip_ifindex (self), nm_device_get_ip_iface (self), stable_type, stable_id, nm_setting_ip6_config_get_addr_gen_mode (s_ip6), + ndisc_node_type (self), &error); } - if (!priv->rdisc) { - _LOGE (LOGD_IP6, "addrconf6: failed to start router discovery: %s", error->message); + if (!priv->ndisc) { + _LOGE (LOGD_IP6, "addrconf6: failed to start neighbor discovery: %s", error->message); g_error_free (error); return FALSE; } - priv->rdisc_use_tempaddr = use_tempaddr; + priv->ndisc_use_tempaddr = use_tempaddr; if ( NM_IN_SET (use_tempaddr, NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR, NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR) && !nm_platform_check_support_kernel_extended_ifa_flags (NM_PLATFORM_GET)) { @@ -6483,7 +6696,7 @@ addrconf6_start (NMDevice *self, NMSettingIP6ConfigPrivacy use_tempaddr) return TRUE; } - /* success; already have the LL address; kick off router discovery */ + /* success; already have the LL address; kick off neighbor discovery */ g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS); return addrconf6_start_with_link_ready (self); } @@ -6493,13 +6706,13 @@ addrconf6_cleanup (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - nm_clear_g_signal_handler (priv->rdisc, &priv->rdisc_changed_id); - nm_clear_g_signal_handler (priv->rdisc, &priv->rdisc_timeout_id); + nm_clear_g_signal_handler (priv->ndisc, &priv->ndisc_changed_id); + nm_clear_g_signal_handler (priv->ndisc, &priv->ndisc_timeout_id); nm_device_remove_pending_action (self, PENDING_ACTION_AUTOCONF6, FALSE); g_clear_object (&priv->ac_ip6_config); - g_clear_object (&priv->rdisc); + g_clear_object (&priv->ndisc); } /*****************************************************************************/ @@ -6509,6 +6722,7 @@ static const char *ip6_properties_to_save[] = { "accept_ra_defrtr", "accept_ra_pinfo", "accept_ra_rtr_pref", + "forwarding", "disable_ipv6", "hop_limit", "use_tempaddr", @@ -6666,12 +6880,10 @@ ip6_requires_slaves (NMConnection *connection) method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP6_CONFIG); /* SLAAC, DHCP, and Link-Local depend on connectivity (and thus slaves) - * to complete addressing. SLAAC and DHCP obviously need a peer to - * provide a prefix, while Link-Local must perform DAD on the local link. + * to complete addressing. SLAAC and DHCP need a peer to provide a prefix. */ return strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO) == 0 - || strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_DHCP) == 0 - || strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL) == 0; + || strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_DHCP) == 0; } static NMActStageReturn @@ -6716,7 +6928,7 @@ act_stage3_ip6_config_start (NMDevice *self, } } - priv->dhcp6.mode = NM_RDISC_DHCP_LEVEL_NONE; + priv->dhcp6.mode = NM_NDISC_DHCP_LEVEL_NONE; priv->dhcp6.num_tries_left = DHCP_NUM_TRIES_MAX; method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP6_CONFIG); @@ -6756,7 +6968,8 @@ act_stage3_ip6_config_start (NMDevice *self, ip6_privacy = _ip6_privacy_get (self); - if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO) == 0) { + if ( strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO) == 0 + || strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_SHARED) == 0) { if (!addrconf6_start (self, ip6_privacy)) { /* IPv6 might be disabled; allow IPv4 to proceed */ ret = NM_ACT_STAGE_RETURN_IP_FAIL; @@ -6765,7 +6978,7 @@ act_stage3_ip6_config_start (NMDevice *self, } else if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL) == 0) { ret = linklocal6_start (self); } else if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_DHCP) == 0) { - priv->dhcp6.mode = NM_RDISC_DHCP_LEVEL_MANAGED; + priv->dhcp6.mode = NM_NDISC_DHCP_LEVEL_MANAGED; if (!dhcp6_start (self, TRUE, reason)) { /* IPv6 might be disabled; allow IPv4 to proceed */ ret = NM_ACT_STAGE_RETURN_IP_FAIL; @@ -6776,8 +6989,6 @@ act_stage3_ip6_config_start (NMDevice *self, } else _LOGW (LOGD_IP6, "unhandled IPv6 config method '%s'; will fail", method); - /* Other methods (shared) aren't implemented yet */ - if ( ret != NM_ACT_STAGE_RETURN_FAILURE && !nm_device_uses_assumed_connection (self)) { switch (ip6_privacy) { @@ -6986,12 +7197,16 @@ fw_change_zone_cb_ip_check (NMFirewallManager *firewall_manager, gpointer user_data) { NMDevice *self = user_data; + NMDevicePrivate *priv; if (!fw_change_zone_handle (self, call_id, error)) return; /* FIXME: fail the device on error? */ - nm_device_start_ip_check (self); + + priv = NM_DEVICE_GET_PRIVATE (self); + if (priv->ip4_state == IP_DONE || priv->ip6_state == IP_DONE) + nm_device_start_ip_check (self); } /* @@ -7161,14 +7376,14 @@ share_init (void) if (!nm_platform_sysctl_set (NM_PLATFORM_GET, "/proc/sys/net/ipv4/ip_forward", "1")) { errsv = errno; - nm_log_err (LOGD_SHARING, "share: error starting IP forwarding: (%d) %s", + nm_log_err (LOGD_SHARING, "share: error enabling IPv4 forwarding: (%d) %s", errsv, strerror (errsv)); return FALSE; } if (!nm_platform_sysctl_set (NM_PLATFORM_GET, "/proc/sys/net/ipv4/ip_dynaddr", "1")) { errsv = errno; - nm_log_err (LOGD_SHARING, "share: error starting IP forwarding: (%d) %s", + nm_log_err (LOGD_SHARING, "share: error enabling dynamic addresses: (%d) %s", errsv, strerror (errsv)); } @@ -7340,7 +7555,7 @@ activate_stage5_ip4_config_commit (NMDevice *self) if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_SHARED) == 0) { if (!start_sharing (self, priv->ip4_config)) { _LOGW (LOGD_SHARING, "Activation: Stage 5 of 5 (IPv4 Commit) start sharing failed."); - nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_SHARED_START_FAILED); + nm_device_ip_method_failed (self, AF_INET, NM_DEVICE_STATE_REASON_SHARED_START_FAILED); return; } } @@ -7462,9 +7677,11 @@ activate_stage5_ip6_config_commit (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMActRequest *req; + const char *method; NMConnection *connection; NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE; int ip_ifindex; + int errsv; req = nm_device_get_act_request (self); g_assert (req); @@ -7480,7 +7697,7 @@ activate_stage5_ip6_config_commit (NMDevice *self) } if (ip6_config_merge_and_apply (self, TRUE, &reason)) { - if ( priv->dhcp6.mode != NM_RDISC_DHCP_LEVEL_NONE + if ( priv->dhcp6.mode != NM_NDISC_DHCP_LEVEL_NONE && priv->ip6_state == IP_CONF) { if (priv->dhcp6.ip6_config) { /* If IPv6 wasn't the first IP to complete, and DHCP was used, @@ -7501,6 +7718,17 @@ activate_stage5_ip6_config_commit (NMDevice *self) nm_device_remove_pending_action (self, PENDING_ACTION_DHCP6, FALSE); nm_device_remove_pending_action (self, PENDING_ACTION_AUTOCONF6, FALSE); + /* Start IPv6 forwarding if we need it */ + method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP6_CONFIG); + + if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_SHARED) == 0) { + if (!nm_platform_sysctl_set (NM_PLATFORM_GET, "/proc/sys/net/ipv6/conf/all/forwarding", "1")) { + errsv = errno; + _LOGE (LOGD_SHARING, "share: error enabling IPv6 forwarding: (%d) %s", errsv, strerror (errsv)); + nm_device_ip_method_failed (self, AF_INET6, NM_DEVICE_STATE_REASON_SHARED_START_FAILED); + } + } + /* Check if we have to wait for DAD */ if (priv->ip6_state == IP_CONF && !priv->dad6_ip6_config) { priv->dad6_ip6_config = dad6_get_pending_addresses (self); @@ -8799,6 +9027,9 @@ nm_device_set_ip6_config (NMDevice *self, } nm_device_queue_recheck_assume (self); + + if (priv->ndisc) + ndisc_set_router_config (priv->ndisc, self); } if (reason) @@ -9069,10 +9300,10 @@ nm_device_start_ip_check (NMDevice *self) * first IP method completes. Any subsequently completing IP method doesn't * get checked. */ - g_assert (!priv->gw_ping.watch); - g_assert (!priv->gw_ping.timeout); - g_assert (!priv->gw_ping.pid); - g_assert (priv->ip4_state == IP_DONE || priv->ip6_state == IP_DONE); + g_return_if_fail (!priv->gw_ping.watch); + g_return_if_fail (!priv->gw_ping.timeout); + g_return_if_fail (!priv->gw_ping.pid); + g_return_if_fail (priv->ip4_state == IP_DONE || priv->ip6_state == IP_DONE); connection = nm_device_get_applied_connection (self); g_assert (connection); @@ -9633,8 +9864,8 @@ queued_ip6_config_change (gpointer user_data) if (IN6_IS_ADDR_LINKLOCAL (&addr->address)) need_ipv6ll = TRUE; - else if (priv->rdisc) - nm_rdisc_dad_failed (priv->rdisc, &addr->address); + else if (priv->ndisc) + nm_ndisc_dad_failed (priv->ndisc, &addr->address); } /* If no IPv6 link-local address exists but other addresses do then we @@ -10808,6 +11039,8 @@ _cleanup_generic_post (NMDevice *self, CleanupType cleanup_type) g_slist_free_full (priv->vpn6_configs, g_object_unref); priv->vpn6_configs = NULL; + priv->needs_ip6_subnet = FALSE; + clear_act_request (self); /* Clear legacy IPv4 address property */ @@ -11045,7 +11278,7 @@ nm_device_spawn_iface_helper (NMDevice *self) g_ptr_array_add (argv, g_strdup ("--slaac-required")); g_ptr_array_add (argv, g_strdup ("--slaac-tempaddr")); - g_ptr_array_add (argv, g_strdup_printf ("%d", priv->rdisc_use_tempaddr)); + g_ptr_array_add (argv, g_strdup_printf ("%d", priv->ndisc_use_tempaddr)); if (nm_device_get_ip_iface_identifier (self, &iid, FALSE)) { g_ptr_array_add (argv, g_strdup ("--iid")); @@ -11115,6 +11348,7 @@ ip6_managed_setup (NMDevice *self) nm_device_ipv6_sysctl_set (self, "accept_ra_pinfo", "0"); nm_device_ipv6_sysctl_set (self, "accept_ra_rtr_pref", "0"); nm_device_ipv6_sysctl_set (self, "use_tempaddr", "0"); + nm_device_ipv6_sysctl_set (self, "forwarding", "0"); } static void @@ -13092,6 +13326,20 @@ nm_device_class_init (NMDeviceClass *klass) 0, NULL, NULL, NULL, G_TYPE_NONE, 2, G_TYPE_OBJECT, G_TYPE_OBJECT); + signals[IP6_PREFIX_DELEGATED] = + g_signal_new (NM_DEVICE_IP6_PREFIX_DELEGATED, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + 0, NULL, NULL, NULL, + G_TYPE_NONE, 1, G_TYPE_POINTER); + + signals[IP6_SUBNET_NEEDED] = + g_signal_new (NM_DEVICE_IP6_SUBNET_NEEDED, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + 0, NULL, NULL, NULL, + G_TYPE_NONE, 0); + signals[REMOVED] = g_signal_new (NM_DEVICE_REMOVED, G_OBJECT_CLASS_TYPE (object_class), diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h index 356331189c..ab6852e40e 100644 --- a/src/devices/nm-device.h +++ b/src/devices/nm-device.h @@ -82,6 +82,8 @@ #define NM_DEVICE_AUTH_REQUEST "auth-request" #define NM_DEVICE_IP4_CONFIG_CHANGED "ip4-config-changed" #define NM_DEVICE_IP6_CONFIG_CHANGED "ip6-config-changed" +#define NM_DEVICE_IP6_PREFIX_DELEGATED "ip6-prefix-delegated" +#define NM_DEVICE_IP6_SUBNET_NEEDED "ip6-subnet-needed" #define NM_DEVICE_REMOVED "removed" #define NM_DEVICE_RECHECK_AUTO_ACTIVATE "recheck-auto-activate" #define NM_DEVICE_RECHECK_ASSUME "recheck-assume" @@ -439,6 +441,16 @@ void nm_device_set_enabled (NMDevice *device, gboolean enabled); RfKillType nm_device_get_rfkill_type (NMDevice *device); +/* IPv6 prefix delegation */ + +void nm_device_request_ip6_prefixes (NMDevice *self, int needed_prefixes); + +gboolean nm_device_needs_ip6_subnet (NMDevice *self); + +void nm_device_use_ip6_subnet (NMDevice *self, const NMPlatformIP6Address *subnet); + +void nm_device_copy_ip6_dns_config (NMDevice *self, NMDevice *from_device); + /** * NMUnmanagedFlags: * @NM_UNMANAGED_NONE: placeholder value diff --git a/src/dhcp-manager/nm-dhcp-client.c b/src/dhcp-manager/nm-dhcp-client.c index 0e28726363..ec981e0ead 100644 --- a/src/dhcp-manager/nm-dhcp-client.c +++ b/src/dhcp-manager/nm-dhcp-client.c @@ -41,6 +41,7 @@ enum { SIGNAL_STATE_CHANGED, + SIGNAL_PREFIX_DELEGATED, LAST_SIGNAL }; @@ -511,7 +512,8 @@ nm_dhcp_client_start_ip6 (NMDhcpClient *self, const struct in6_addr *ll_addr, const char *hostname, gboolean info_only, - NMSettingIP6ConfigPrivacy privacy) + NMSettingIP6ConfigPrivacy privacy, + guint needed_prefixes) { NMDhcpClientPrivate *priv; gs_free char *str = NULL; @@ -544,7 +546,8 @@ nm_dhcp_client_start_ip6 (NMDhcpClient *self, ll_addr, info_only, privacy, - priv->duid); + priv->duid, + needed_prefixes); } void @@ -709,6 +712,7 @@ nm_dhcp_client_handle_event (gpointer unused, guint32 new_state; GHashTable *str_options = NULL; GObject *ip_config = NULL; + NMPlatformIP6Address prefix = { 0, }; g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), FALSE); g_return_val_if_fail (iface != NULL, FALSE); @@ -741,10 +745,20 @@ nm_dhcp_client_handle_event (gpointer unused, g_variant_unref (value); } + if (nm_logging_enabled (LOGL_DEBUG, LOGD_DHCP6)) { + GHashTableIter hash_iter; + gpointer key, val; + + g_hash_table_iter_init (&hash_iter, str_options); + while (g_hash_table_iter_next (&hash_iter, &key, &val)) + _LOGD ("option '%s'=>'%s'", (const char *) key, (const char *) val); + } + /* 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, priv->iface, str_options, @@ -756,17 +770,26 @@ nm_dhcp_client_handle_event (gpointer unused, str_options, priv->priority); } - - /* Fail if no valid IP config was received */ - if (ip_config == NULL) { - _LOGW ("client bound but IP config not received"); - new_state = NM_DHCP_STATE_FAIL; - g_clear_pointer (&str_options, g_hash_table_unref); - } } } - nm_dhcp_client_set_state (self, new_state, ip_config, str_options); + if (!IN6_IS_ADDR_UNSPECIFIED (&prefix.address)) { + /* If we got an IPv6 prefix to delegate, we don't change the state + * of the DHCP client instance. Instead, we just signal the prefix + * to the device. */ + g_signal_emit (G_OBJECT (self), + signals[SIGNAL_PREFIX_DELEGATED], 0, + &prefix); + } else { + /* Fail if no valid IP config was received */ + if (new_state == NM_DHCP_STATE_BOUND && ip_config == NULL) { + _LOGW ("client bound but IP config not received"); + new_state = NM_DHCP_STATE_FAIL; + g_clear_pointer (&str_options, g_hash_table_unref); + } + + nm_dhcp_client_set_state (self, new_state, ip_config, str_options); + } if (str_options) g_hash_table_destroy (str_options); @@ -963,5 +986,12 @@ nm_dhcp_client_class_init (NMDhcpClientClass *client_class) G_STRUCT_OFFSET (NMDhcpClientClass, state_changed), NULL, NULL, NULL, G_TYPE_NONE, 4, G_TYPE_UINT, G_TYPE_OBJECT, G_TYPE_HASH_TABLE, G_TYPE_STRING); -} + signals[SIGNAL_PREFIX_DELEGATED] = + g_signal_new (NM_DHCP_CLIENT_SIGNAL_PREFIX_DELEGATED, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMDhcpClientClass, state_changed), + NULL, NULL, NULL, + G_TYPE_NONE, 1, G_TYPE_POINTER); +} diff --git a/src/dhcp-manager/nm-dhcp-client.h b/src/dhcp-manager/nm-dhcp-client.h index 9a2d21f713..7a083ae7a3 100644 --- a/src/dhcp-manager/nm-dhcp-client.h +++ b/src/dhcp-manager/nm-dhcp-client.h @@ -40,6 +40,7 @@ #define NM_DHCP_CLIENT_TIMEOUT "timeout" #define NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED "state-changed" +#define NM_DHCP_CLIENT_SIGNAL_PREFIX_DELEGATED "prefix-delegated" typedef enum { NM_DHCP_STATE_UNKNOWN = 0, @@ -73,7 +74,8 @@ typedef struct { const struct in6_addr *ll_addr, gboolean info_only, NMSettingIP6ConfigPrivacy privacy, - const GByteArray *duid); + const GByteArray *duid, + guint needed_prefixes); void (*stop) (NMDhcpClient *self, gboolean release, @@ -133,7 +135,8 @@ gboolean nm_dhcp_client_start_ip6 (NMDhcpClient *self, const struct in6_addr *ll_addr, const char *hostname, gboolean info_only, - NMSettingIP6ConfigPrivacy privacy); + NMSettingIP6ConfigPrivacy privacy, + guint needed_prefixes); void nm_dhcp_client_stop (NMDhcpClient *self, gboolean release); diff --git a/src/dhcp-manager/nm-dhcp-dhclient.c b/src/dhcp-manager/nm-dhcp-dhclient.c index a055e54179..64d93744f2 100644 --- a/src/dhcp-manager/nm-dhcp-dhclient.c +++ b/src/dhcp-manager/nm-dhcp-dhclient.c @@ -330,7 +330,8 @@ dhclient_start (NMDhcpClient *client, const char *mode_opt, const GByteArray *duid, gboolean release, - pid_t *out_pid) + pid_t *out_pid, + int prefixes) { NMDhcpDhclient *self = NM_DHCP_DHCLIENT (client); NMDhcpDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE (self); @@ -424,6 +425,8 @@ dhclient_start (NMDhcpClient *client, g_ptr_array_add (argv, (gpointer) "-6"); if (mode_opt) g_ptr_array_add (argv, (gpointer) mode_opt); + while (prefixes--) + g_ptr_array_add (argv, (gpointer) "-P"); } g_ptr_array_add (argv, (gpointer) "-sf"); /* Set script file */ g_ptr_array_add (argv, (gpointer) nm_dhcp_helper_path); @@ -503,7 +506,7 @@ ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last if (priv->conf_file) { if (new_client_id) nm_dhcp_client_set_client_id (client, new_client_id); - success = dhclient_start (client, NULL, NULL, FALSE, NULL); + success = dhclient_start (client, NULL, NULL, FALSE, NULL, 0); } else _LOGW ("error creating dhclient configuration file"); @@ -516,7 +519,8 @@ ip6_start (NMDhcpClient *client, const struct in6_addr *ll_addr, gboolean info_only, NMSettingIP6ConfigPrivacy privacy, - const GByteArray *duid) + const GByteArray *duid, + guint needed_prefixes) { NMDhcpDhclient *self = NM_DHCP_DHCLIENT (client); NMDhcpDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE (self); @@ -532,7 +536,7 @@ ip6_start (NMDhcpClient *client, return FALSE; } - return dhclient_start (client, info_only ? "-S" : "-N", duid, FALSE, NULL); + return dhclient_start (client, info_only ? "-S" : "-N", duid, FALSE, NULL, needed_prefixes); } static void @@ -557,7 +561,7 @@ stop (NMDhcpClient *client, gboolean release, const GByteArray *duid) if (release) { pid_t rpid = -1; - if (dhclient_start (client, NULL, duid, TRUE, &rpid)) { + if (dhclient_start (client, NULL, duid, TRUE, &rpid, 0)) { /* Wait a few seconds for the release to happen */ nm_dhcp_client_stop_pid (rpid, nm_dhcp_client_get_iface (client)); } diff --git a/src/dhcp-manager/nm-dhcp-dhcpcd.c b/src/dhcp-manager/nm-dhcp-dhcpcd.c index 6b7fe38bbf..c8643881fc 100644 --- a/src/dhcp-manager/nm-dhcp-dhcpcd.c +++ b/src/dhcp-manager/nm-dhcp-dhcpcd.c @@ -185,7 +185,8 @@ ip6_start (NMDhcpClient *client, const struct in6_addr *ll_addr, gboolean info_only, NMSettingIP6ConfigPrivacy privacy, - const GByteArray *duid) + const GByteArray *duid, + guint needed_prefixes) { NMDhcpDhcpcd *self = NM_DHCP_DHCPCD (client); diff --git a/src/dhcp-manager/nm-dhcp-manager.c b/src/dhcp-manager/nm-dhcp-manager.c index dee4039a5c..6cb5c105b9 100644 --- a/src/dhcp-manager/nm-dhcp-manager.c +++ b/src/dhcp-manager/nm-dhcp-manager.c @@ -166,7 +166,8 @@ client_start (NMDhcpManager *self, const char *fqdn, gboolean info_only, NMSettingIP6ConfigPrivacy privacy, - const char *last_ip4_address) + const char *last_ip4_address, + guint needed_prefixes) { NMDhcpManagerPrivate *priv; NMDhcpClient *client; @@ -206,7 +207,7 @@ client_start (NMDhcpManager *self, g_signal_connect (client, NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED, G_CALLBACK (client_state_changed), self); if (ipv6) - success = nm_dhcp_client_start_ip6 (client, dhcp_anycast_addr, ipv6_ll_addr, hostname, info_only, privacy); + success = nm_dhcp_client_start_ip6 (client, dhcp_anycast_addr, ipv6_ll_addr, hostname, info_only, privacy, needed_prefixes); else success = nm_dhcp_client_start_ip4 (client, dhcp_client_id, dhcp_anycast_addr, hostname, fqdn, last_ip4_address); @@ -254,7 +255,7 @@ nm_dhcp_manager_start_ip4 (NMDhcpManager *self, } return client_start (self, iface, ifindex, hwaddr, uuid, priority, FALSE, NULL, dhcp_client_id, timeout, dhcp_anycast_addr, hostname, - fqdn, FALSE, 0, last_ip_address); + fqdn, FALSE, 0, last_ip_address, 0); } /* Caller owns a reference to the NMDhcpClient on return */ @@ -271,7 +272,8 @@ nm_dhcp_manager_start_ip6 (NMDhcpManager *self, guint32 timeout, const char *dhcp_anycast_addr, gboolean info_only, - NMSettingIP6ConfigPrivacy privacy) + NMSettingIP6ConfigPrivacy privacy, + guint needed_prefixes) { const char *hostname = NULL; @@ -281,7 +283,7 @@ nm_dhcp_manager_start_ip6 (NMDhcpManager *self, hostname = get_send_hostname (self, dhcp_hostname); return client_start (self, iface, ifindex, hwaddr, uuid, priority, TRUE, ll_addr, NULL, timeout, dhcp_anycast_addr, hostname, NULL, info_only, - privacy, NULL); + privacy, NULL, needed_prefixes); } void diff --git a/src/dhcp-manager/nm-dhcp-manager.h b/src/dhcp-manager/nm-dhcp-manager.h index e525180d43..a948b60970 100644 --- a/src/dhcp-manager/nm-dhcp-manager.h +++ b/src/dhcp-manager/nm-dhcp-manager.h @@ -69,7 +69,8 @@ NMDhcpClient * nm_dhcp_manager_start_ip6 (NMDhcpManager *manager, guint32 timeout, const char *dhcp_anycast_addr, gboolean info_only, - NMSettingIP6ConfigPrivacy privacy); + NMSettingIP6ConfigPrivacy privacy, + guint needed_prefixes); GSList * nm_dhcp_manager_get_lease_ip_configs (NMDhcpManager *self, const char *iface, diff --git a/src/dhcp-manager/nm-dhcp-systemd.c b/src/dhcp-manager/nm-dhcp-systemd.c index 4e3f85deb9..b6c9e27c17 100644 --- a/src/dhcp-manager/nm-dhcp-systemd.c +++ b/src/dhcp-manager/nm-dhcp-systemd.c @@ -894,7 +894,8 @@ ip6_start (NMDhcpClient *client, const struct in6_addr *ll_addr, gboolean info_only, NMSettingIP6ConfigPrivacy privacy, - const GByteArray *duid) + const GByteArray *duid, + guint needed_prefixes) { NMDhcpSystemd *self = NM_DHCP_SYSTEMD (client); NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE (self); @@ -916,7 +917,12 @@ ip6_start (NMDhcpClient *client, return FALSE; } - _LOGT ("dhcp-client6: set %p", priv->client4); + if (needed_prefixes > 0) { + _LOGW ("dhcp-client6: prefix delegation not yet supported, won't supply %d prefixes\n", + needed_prefixes); + } + + _LOGT ("dhcp-client6: set %p", priv->client6); if (info_only) sd_dhcp6_client_set_information_request (priv->client6, 1); diff --git a/src/dhcp-manager/nm-dhcp-utils.c b/src/dhcp-manager/nm-dhcp-utils.c index a7d4f4a4ee..4205d021b7 100644 --- a/src/dhcp-manager/nm-dhcp-utils.c +++ b/src/dhcp-manager/nm-dhcp-utils.c @@ -604,6 +604,54 @@ ip6_add_domain_search (gpointer data, gpointer user_data) nm_ip6_config_add_search (NM_IP6_CONFIG (user_data), (const char *) data); } +NMPlatformIP6Address +nm_dhcp_utils_ip6_prefix_from_options (GHashTable *options) +{ + gs_strfreev gchar **split_addr = NULL; + NMPlatformIP6Address address = { 0, }; + struct in6_addr tmp_addr; + char *str = NULL; + int prefix; + + g_return_val_if_fail (options != NULL, address); + + str = g_hash_table_lookup (options, "ip6_prefix"); + if (!str) + return address; + + split_addr = g_strsplit (str, "/", 2); + if (split_addr[0] == NULL && split_addr[1] == NULL) { + nm_log_warn (LOGD_DHCP6, "DHCP returned prefix without length '%s'", str); + return address; + } + + if (!inet_pton (AF_INET6, split_addr[0], &tmp_addr)) { + nm_log_warn (LOGD_DHCP6, "DHCP returned invalid prefix '%s'", str); + return address; + } + + prefix = _nm_utils_ascii_str_to_int64 (split_addr[1], 10, 0, 128, -1); + if (prefix < 0) { + nm_log_warn (LOGD_DHCP6, "DHCP returned prefix with invalid length '%s'", str); + return address; + } + + address.address = tmp_addr; + address.addr_source = NM_IP_CONFIG_SOURCE_DHCP; + address.plen = prefix; + address.timestamp = nm_utils_get_monotonic_timestamp_s (); + + str = g_hash_table_lookup (options, "max_life"); + if (str) + address.lifetime = strtoul (str, NULL, 10); + + str = g_hash_table_lookup (options, "preferred_life"); + if (str) + address.preferred = strtoul (str, NULL, 10); + + return address; +} + NMIP6Config * nm_dhcp_utils_ip6_config_from_options (int ifindex, const char *iface, @@ -615,8 +663,6 @@ nm_dhcp_utils_ip6_config_from_options (int ifindex, struct in6_addr tmp_addr; NMPlatformIP6Address address; char *str = NULL; - GHashTableIter iter; - gpointer key, value; g_return_val_if_fail (options != NULL, NULL); @@ -624,12 +670,6 @@ nm_dhcp_utils_ip6_config_from_options (int ifindex, address.plen = 128; address.timestamp = nm_utils_get_monotonic_timestamp_s (); - g_hash_table_iter_init (&iter, options); - while (g_hash_table_iter_next (&iter, &key, &value)) { - _LOG2D (LOGD_DHCP6, iface, "(%s): option '%s'=>'%s'", - iface, (const char *) key, (const char *) value); - } - ip6_config = nm_ip6_config_new (ifindex); str = g_hash_table_lookup (options, "max_life"); diff --git a/src/dhcp-manager/nm-dhcp-utils.h b/src/dhcp-manager/nm-dhcp-utils.h index 6540b1ff80..b45c5e89a2 100644 --- a/src/dhcp-manager/nm-dhcp-utils.h +++ b/src/dhcp-manager/nm-dhcp-utils.h @@ -35,6 +35,8 @@ NMIP6Config *nm_dhcp_utils_ip6_config_from_options (int ifindex, guint priority, gboolean info_only); +NMPlatformIP6Address nm_dhcp_utils_ip6_prefix_from_options (GHashTable *options); + char * nm_dhcp_utils_duid_to_string (const GByteArray *duid); GBytes * nm_dhcp_utils_client_id_string_to_bytes (const char *client_id); diff --git a/src/rdisc/nm-fake-rdisc.c b/src/ndisc/nm-fake-ndisc.c similarity index 65% rename from src/rdisc/nm-fake-rdisc.c rename to src/ndisc/nm-fake-ndisc.c index aee94a39be..f1ada6c0cd 100644 --- a/src/rdisc/nm-fake-rdisc.c +++ b/src/ndisc/nm-fake-ndisc.c @@ -1,5 +1,5 @@ /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* nm-fake-rdisc.c - Fake implementation of router discovery +/* nm-fake-ndisc.c - Fake implementation of neighbor discovery * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,14 +20,14 @@ #include "nm-default.h" -#include "nm-fake-rdisc.h" +#include "nm-fake-ndisc.h" #include #include -#include "nm-rdisc-private.h" +#include "nm-ndisc-private.h" -#define _NMLOG_PREFIX_NAME "rdisc-fake" +#define _NMLOG_PREFIX_NAME "ndisc-fake" /*****************************************************************************/ @@ -35,7 +35,7 @@ typedef struct { guint id; guint when; - NMRDiscDHCPLevel dhcp_level; + NMNDiscDHCPLevel dhcp_level; GArray *gateways; GArray *prefixes; GArray *dns_servers; @@ -51,7 +51,7 @@ typedef struct { guint32 timestamp; guint32 lifetime; guint32 preferred; - NMRDiscPreference preference; + NMNDiscPreference preference; } FakePrefix; /*****************************************************************************/ @@ -65,20 +65,20 @@ static guint signals[LAST_SIGNAL] = { 0 }; typedef struct { guint receive_ra_id; GSList *ras; -} NMFakeRDiscPrivate; +} NMFakeNDiscPrivate; -struct _NMFakeRRDisc { - NMRDisc parent; - NMFakeRDiscPrivate _priv; +struct _NMFakeRNDisc { + NMNDisc parent; + NMFakeNDiscPrivate _priv; }; -struct _NMFakeRRDiscClass { - NMRDiscClass parent; +struct _NMFakeRNDiscClass { + NMNDiscClass parent; }; -G_DEFINE_TYPE (NMFakeRDisc, nm_fake_rdisc, NM_TYPE_RDISC) +G_DEFINE_TYPE (NMFakeNDisc, nm_fake_ndisc, NM_TYPE_NDISC) -#define NM_FAKE_RDISC_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMFakeRDisc, NM_IS_FAKE_RDISC) +#define NM_FAKE_NDISC_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMFakeNDisc, NM_IS_FAKE_NDISC) /*****************************************************************************/ @@ -97,7 +97,7 @@ fake_ra_free (gpointer data) static void ra_dns_domain_free (gpointer data) { - g_free (((NMRDiscDNSDomain *)(data))->domain); + g_free (((NMNDiscDNSDomain *)(data))->domain); } static FakeRa * @@ -113,13 +113,13 @@ find_ra (GSList *ras, guint id) } guint -nm_fake_rdisc_add_ra (NMFakeRDisc *self, +nm_fake_ndisc_add_ra (NMFakeNDisc *self, guint seconds_after_previous, - NMRDiscDHCPLevel dhcp_level, + NMNDiscDHCPLevel dhcp_level, int hop_limit, guint32 mtu) { - NMFakeRDiscPrivate *priv = NM_FAKE_RDISC_GET_PRIVATE (self); + NMFakeNDiscPrivate *priv = NM_FAKE_NDISC_GET_PRIVATE (self); static guint counter = 1; FakeRa *ra; @@ -129,10 +129,10 @@ nm_fake_rdisc_add_ra (NMFakeRDisc *self, ra->dhcp_level = dhcp_level; ra->hop_limit = hop_limit; ra->mtu = mtu; - ra->gateways = g_array_new (FALSE, FALSE, sizeof (NMRDiscGateway)); + ra->gateways = g_array_new (FALSE, FALSE, sizeof (NMNDiscGateway)); 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)); + ra->dns_servers = g_array_new (FALSE, FALSE, sizeof (NMNDiscDNSServer)); + ra->dns_domains = g_array_new (FALSE, FALSE, sizeof (NMNDiscDNSDomain)); g_array_set_clear_func (ra->dns_domains, ra_dns_domain_free); priv->ras = g_slist_append (priv->ras, ra); @@ -140,20 +140,20 @@ nm_fake_rdisc_add_ra (NMFakeRDisc *self, } void -nm_fake_rdisc_add_gateway (NMFakeRDisc *self, +nm_fake_ndisc_add_gateway (NMFakeNDisc *self, guint ra_id, const char *addr, guint32 timestamp, guint32 lifetime, - NMRDiscPreference preference) + NMNDiscPreference preference) { - NMFakeRDiscPrivate *priv = NM_FAKE_RDISC_GET_PRIVATE (self); + NMFakeNDiscPrivate *priv = NM_FAKE_NDISC_GET_PRIVATE (self); FakeRa *ra = find_ra (priv->ras, ra_id); - NMRDiscGateway *gw; + NMNDiscGateway *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); + gw = &g_array_index (ra->gateways, NMNDiscGateway, ra->gateways->len - 1); g_assert (inet_pton (AF_INET6, addr, &gw->address) == 1); gw->timestamp = timestamp; gw->lifetime = lifetime; @@ -161,7 +161,7 @@ nm_fake_rdisc_add_gateway (NMFakeRDisc *self, } void -nm_fake_rdisc_add_prefix (NMFakeRDisc *self, +nm_fake_ndisc_add_prefix (NMFakeNDisc *self, guint ra_id, const char *network, guint plen, @@ -169,9 +169,9 @@ nm_fake_rdisc_add_prefix (NMFakeRDisc *self, guint32 timestamp, guint32 lifetime, guint32 preferred, - NMRDiscPreference preference) + NMNDiscPreference preference) { - NMFakeRDiscPrivate *priv = NM_FAKE_RDISC_GET_PRIVATE (self); + NMFakeNDiscPrivate *priv = NM_FAKE_NDISC_GET_PRIVATE (self); FakeRa *ra = find_ra (priv->ras, ra_id); FakePrefix *prefix; @@ -189,70 +189,70 @@ nm_fake_rdisc_add_prefix (NMFakeRDisc *self, } void -nm_fake_rdisc_add_dns_server (NMFakeRDisc *self, +nm_fake_ndisc_add_dns_server (NMFakeNDisc *self, guint ra_id, const char *address, guint32 timestamp, guint32 lifetime) { - NMFakeRDiscPrivate *priv = NM_FAKE_RDISC_GET_PRIVATE (self); + NMFakeNDiscPrivate *priv = NM_FAKE_NDISC_GET_PRIVATE (self); FakeRa *ra = find_ra (priv->ras, ra_id); - NMRDiscDNSServer *dns; + NMNDiscDNSServer *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); + dns = &g_array_index (ra->dns_servers, NMNDiscDNSServer, 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, +nm_fake_ndisc_add_dns_domain (NMFakeNDisc *self, guint ra_id, const char *domain, guint32 timestamp, guint32 lifetime) { - NMFakeRDiscPrivate *priv = NM_FAKE_RDISC_GET_PRIVATE (self); + NMFakeNDiscPrivate *priv = NM_FAKE_NDISC_GET_PRIVATE (self); FakeRa *ra = find_ra (priv->ras, ra_id); - NMRDiscDNSDomain *dns; + NMNDiscDNSDomain *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 = &g_array_index (ra->dns_domains, NMNDiscDNSDomain, ra->dns_domains->len - 1); dns->domain = g_strdup (domain); dns->timestamp = timestamp; dns->lifetime = lifetime; } gboolean -nm_fake_rdisc_done (NMFakeRDisc *self) +nm_fake_ndisc_done (NMFakeNDisc *self) { - return !NM_FAKE_RDISC_GET_PRIVATE (self)->ras; + return !NM_FAKE_NDISC_GET_PRIVATE (self)->ras; } /*****************************************************************************/ static gboolean -send_rs (NMRDisc *rdisc, GError **error) +send_rs (NMNDisc *ndisc, GError **error) { - g_signal_emit (rdisc, signals[RS_SENT], 0); + g_signal_emit (ndisc, 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); - NMRDiscDataInternal *rdata = rdisc->rdata; + NMFakeNDisc *self = user_data; + NMFakeNDiscPrivate *priv = NM_FAKE_NDISC_GET_PRIVATE (self); + NMNDisc *ndisc = NM_NDISC (self); + NMNDiscDataInternal *rdata = ndisc->rdata; FakeRa *ra = priv->ras->data; - NMRDiscConfigMap changed = 0; + NMNDiscConfigMap changed = 0; guint32 now = nm_utils_get_monotonic_timestamp_s (); guint i; - NMRDiscDHCPLevel dhcp_level; + NMNDiscDHCPLevel dhcp_level; priv->receive_ra_id = 0; @@ -261,19 +261,19 @@ receive_ra (gpointer user_data) if (rdata->public.dhcp_level != dhcp_level) { rdata->public.dhcp_level = dhcp_level; - changed |= NM_RDISC_CONFIG_DHCP_LEVEL; + changed |= NM_NDISC_CONFIG_DHCP_LEVEL; } for (i = 0; i < ra->gateways->len; i++) { - NMRDiscGateway *item = &g_array_index (ra->gateways, NMRDiscGateway, i); + NMNDiscGateway *item = &g_array_index (ra->gateways, NMNDiscGateway, i); - if (nm_rdisc_add_gateway (rdisc, item)) - changed |= NM_RDISC_CONFIG_GATEWAYS; + if (nm_ndisc_add_gateway (ndisc, item)) + changed |= NM_NDISC_CONFIG_GATEWAYS; } for (i = 0; i < ra->prefixes->len; i++) { FakePrefix *item = &g_array_index (ra->prefixes, FakePrefix, i); - NMRDiscRoute route = { + NMNDiscRoute route = { .network = item->network, .plen = item->plen, .gateway = item->gateway, @@ -284,11 +284,11 @@ receive_ra (gpointer user_data) g_assert (route.plen > 0 && route.plen <= 128); - if (nm_rdisc_add_route (rdisc, &route)) - changed |= NM_RDISC_CONFIG_ROUTES; + if (nm_ndisc_add_route (ndisc, &route)) + changed |= NM_NDISC_CONFIG_ROUTES; if (item->plen == 64) { - NMRDiscAddress address = { + NMNDiscAddress address = { .address = item->network, .timestamp = item->timestamp, .lifetime = item->lifetime, @@ -296,39 +296,39 @@ receive_ra (gpointer user_data) .dad_counter = 0, }; - if (nm_rdisc_complete_and_add_address (rdisc, &address)) - changed |= NM_RDISC_CONFIG_ADDRESSES; + if (nm_ndisc_complete_and_add_address (ndisc, &address)) + changed |= NM_NDISC_CONFIG_ADDRESSES; } } for (i = 0; i < ra->dns_servers->len; i++) { - NMRDiscDNSServer *item = &g_array_index (ra->dns_servers, NMRDiscDNSServer, i); + NMNDiscDNSServer *item = &g_array_index (ra->dns_servers, NMNDiscDNSServer, i); - if (nm_rdisc_add_dns_server (rdisc, item)) - changed |= NM_RDISC_CONFIG_DNS_SERVERS; + if (nm_ndisc_add_dns_server (ndisc, item)) + changed |= NM_NDISC_CONFIG_DNS_SERVERS; } for (i = 0; i < ra->dns_domains->len; i++) { - NMRDiscDNSDomain *item = &g_array_index (ra->dns_domains, NMRDiscDNSDomain, i); + NMNDiscDNSDomain *item = &g_array_index (ra->dns_domains, NMNDiscDNSDomain, i); - if (nm_rdisc_add_dns_domain (rdisc, item)) - changed |= NM_RDISC_CONFIG_DNS_DOMAINS; + if (nm_ndisc_add_dns_domain (ndisc, item)) + changed |= NM_NDISC_CONFIG_DNS_DOMAINS; } if (rdata->public.mtu != ra->mtu) { rdata->public.mtu = ra->mtu; - changed |= NM_RDISC_CONFIG_MTU; + changed |= NM_NDISC_CONFIG_MTU; } if (rdata->public.hop_limit != ra->hop_limit) { rdata->public.hop_limit = ra->hop_limit; - changed |= NM_RDISC_CONFIG_HOP_LIMIT; + changed |= NM_NDISC_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); + nm_ndisc_ra_received (NM_NDISC (self), now, changed); /* Schedule next RA */ if (priv->ras) { @@ -340,9 +340,9 @@ receive_ra (gpointer user_data) } static void -start (NMRDisc *rdisc) +start (NMNDisc *ndisc) { - NMFakeRDiscPrivate *priv = NM_FAKE_RDISC_GET_PRIVATE ((NMFakeRDisc *) rdisc); + NMFakeNDiscPrivate *priv = NM_FAKE_NDISC_GET_PRIVATE ((NMFakeNDisc *) ndisc); FakeRa *ra; /* Queue up the first fake RA */ @@ -350,58 +350,59 @@ start (NMRDisc *rdisc) ra = priv->ras->data; g_assert (!priv->receive_ra_id); - priv->receive_ra_id = g_timeout_add_seconds (ra->when, receive_ra, rdisc); + priv->receive_ra_id = g_timeout_add_seconds (ra->when, receive_ra, ndisc); } void -nm_fake_rdisc_emit_new_ras (NMFakeRDisc *self) +nm_fake_ndisc_emit_new_ras (NMFakeNDisc *self) { - if (!NM_FAKE_RDISC_GET_PRIVATE (self)->receive_ra_id) - start (NM_RDISC (self)); + if (!NM_FAKE_NDISC_GET_PRIVATE (self)->receive_ra_id) + start (NM_NDISC (self)); } /*****************************************************************************/ static void -nm_fake_rdisc_init (NMFakeRDisc *fake_rdisc) +nm_fake_ndisc_init (NMFakeNDisc *fake_ndisc) { } -NMRDisc * -nm_fake_rdisc_new (int ifindex, const char *ifname) +NMNDisc * +nm_fake_ndisc_new (int ifindex, const char *ifname) { - return g_object_new (NM_TYPE_FAKE_RDISC, - NM_RDISC_IFINDEX, ifindex, - NM_RDISC_IFNAME, ifname, + return g_object_new (NM_TYPE_FAKE_NDISC, + NM_NDISC_IFINDEX, ifindex, + NM_NDISC_IFNAME, ifname, + NM_NDISC_NODE_TYPE, (int) NM_NDISC_NODE_TYPE_HOST, NULL); } static void dispose (GObject *object) { - NMFakeRDiscPrivate *priv = NM_FAKE_RDISC_GET_PRIVATE ((NMFakeRDisc *) object); + NMFakeNDiscPrivate *priv = NM_FAKE_NDISC_GET_PRIVATE ((NMFakeNDisc *) object); nm_clear_g_source (&priv->receive_ra_id); g_slist_free_full (priv->ras, fake_ra_free); priv->ras = NULL; - G_OBJECT_CLASS (nm_fake_rdisc_parent_class)->dispose (object); + G_OBJECT_CLASS (nm_fake_ndisc_parent_class)->dispose (object); } static void -nm_fake_rdisc_class_init (NMFakeRDiscClass *klass) +nm_fake_ndisc_class_init (NMFakeNDiscClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); - NMRDiscClass *rdisc_class = NM_RDISC_CLASS (klass); + NMNDiscClass *ndisc_class = NM_NDISC_CLASS (klass); object_class->dispose = dispose; - rdisc_class->start = start; - rdisc_class->send_rs = send_rs; + ndisc_class->start = start; + ndisc_class->send_rs = send_rs; signals[RS_SENT] = - g_signal_new (NM_FAKE_RDISC_RS_SENT, + g_signal_new (NM_FAKE_NDISC_RS_SENT, G_OBJECT_CLASS_TYPE (klass), G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL, diff --git a/src/rdisc/nm-fake-rdisc.h b/src/ndisc/nm-fake-ndisc.h similarity index 55% rename from src/rdisc/nm-fake-rdisc.h rename to src/ndisc/nm-fake-ndisc.h index 5f6509568d..2544c45644 100644 --- a/src/rdisc/nm-fake-rdisc.h +++ b/src/ndisc/nm-fake-ndisc.h @@ -1,5 +1,5 @@ /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* nm-fake-rdisc.h - Fake implementation of router discovery +/* nm-fake-ndisc.h - Fake implementation of neighbor discovery * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,41 +18,41 @@ * Copyright (C) 2013 Red Hat, Inc. */ -#ifndef __NETWORKMANAGER_FAKE_RDISC_H__ -#define __NETWORKMANAGER_FAKE_RDISC_H__ +#ifndef __NETWORKMANAGER_FAKE_NDISC_H__ +#define __NETWORKMANAGER_FAKE_NDISC_H__ -#include "nm-rdisc.h" +#include "nm-ndisc.h" -#define NM_TYPE_FAKE_RDISC (nm_fake_rdisc_get_type ()) -#define NM_FAKE_RDISC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_FAKE_RDISC, NMFakeRDisc)) -#define NM_FAKE_RDISC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_FAKE_RDISC, NMFakeRDiscClass)) -#define NM_IS_FAKE_RDISC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_FAKE_RDISC)) -#define NM_IS_FAKE_RDISC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_FAKE_RDISC)) -#define NM_FAKE_RDISC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_FAKE_RDISC, NMFakeRDiscClass)) +#define NM_TYPE_FAKE_NDISC (nm_fake_ndisc_get_type ()) +#define NM_FAKE_NDISC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_FAKE_NDISC, NMFakeNDisc)) +#define NM_FAKE_NDISC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_FAKE_NDISC, NMFakeNDiscClass)) +#define NM_IS_FAKE_NDISC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_FAKE_NDISC)) +#define NM_IS_FAKE_NDISC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_FAKE_NDISC)) +#define NM_FAKE_NDISC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_FAKE_NDISC, NMFakeNDiscClass)) -#define NM_FAKE_RDISC_RS_SENT "rs-sent" +#define NM_FAKE_NDISC_RS_SENT "rs-sent" -typedef struct _NMFakeRRDisc NMFakeRDisc; -typedef struct _NMFakeRRDiscClass NMFakeRDiscClass; +typedef struct _NMFakeRNDisc NMFakeNDisc; +typedef struct _NMFakeRNDiscClass NMFakeNDiscClass; -GType nm_fake_rdisc_get_type (void); +GType nm_fake_ndisc_get_type (void); -NMRDisc *nm_fake_rdisc_new (int ifindex, const char *ifname); +NMNDisc *nm_fake_ndisc_new (int ifindex, const char *ifname); -guint nm_fake_rdisc_add_ra (NMFakeRDisc *self, +guint nm_fake_ndisc_add_ra (NMFakeNDisc *self, guint seconds, - NMRDiscDHCPLevel dhcp_level, + NMNDiscDHCPLevel dhcp_level, int hop_limit, guint32 mtu); -void nm_fake_rdisc_add_gateway (NMFakeRDisc *self, +void nm_fake_ndisc_add_gateway (NMFakeNDisc *self, guint ra_id, const char *addr, guint32 timestamp, guint32 lifetime, - NMRDiscPreference preference); + NMNDiscPreference preference); -void nm_fake_rdisc_add_prefix (NMFakeRDisc *self, +void nm_fake_ndisc_add_prefix (NMFakeNDisc *self, guint ra_id, const char *network, guint plen, @@ -60,22 +60,22 @@ void nm_fake_rdisc_add_prefix (NMFakeRDisc *self, guint32 timestamp, guint32 lifetime, guint32 preferred, - NMRDiscPreference preference); + NMNDiscPreference preference); -void nm_fake_rdisc_add_dns_server (NMFakeRDisc *self, +void nm_fake_ndisc_add_dns_server (NMFakeNDisc *self, guint ra_id, const char *address, guint32 timestamp, guint32 lifetime); -void nm_fake_rdisc_add_dns_domain (NMFakeRDisc *self, +void nm_fake_ndisc_add_dns_domain (NMFakeNDisc *self, guint ra_id, const char *domain, guint32 timestamp, guint32 lifetime); -void nm_fake_rdisc_emit_new_ras (NMFakeRDisc *self); +void nm_fake_ndisc_emit_new_ras (NMFakeNDisc *self); -gboolean nm_fake_rdisc_done (NMFakeRDisc *self); +gboolean nm_fake_ndisc_done (NMFakeNDisc *self); -#endif /* __NETWORKMANAGER_FAKE_RDISC_H__ */ +#endif /* __NETWORKMANAGER_FAKE_NDISC_H__ */ diff --git a/src/rdisc/nm-lndp-rdisc.c b/src/ndisc/nm-lndp-ndisc.c similarity index 50% rename from src/rdisc/nm-lndp-rdisc.c rename to src/ndisc/nm-lndp-ndisc.c index db2965b155..d711e60459 100644 --- a/src/rdisc/nm-lndp-rdisc.c +++ b/src/ndisc/nm-lndp-ndisc.c @@ -1,5 +1,5 @@ /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* nm-lndp-rdisc.c - Router discovery implementation using libndp +/* nm-lndp-ndisc.c - Router discovery implementation using libndp * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,20 +20,21 @@ #include "nm-default.h" -#include "nm-lndp-rdisc.h" +#include "nm-lndp-ndisc.h" #include #include +#include /* stdarg.h included because of a bug in ndp.h */ #include #include -#include "nm-rdisc-private.h" +#include "nm-ndisc-private.h" #include "NetworkManagerUtils.h" #include "nm-platform.h" #include "nmp-netns.h" -#define _NMLOG_PREFIX_NAME "rdisc-lndp" +#define _NMLOG_PREFIX_NAME "ndisc-lndp" /*****************************************************************************/ @@ -42,32 +43,31 @@ typedef struct { GIOChannel *event_channel; guint event_id; - guint ra_timeout_id; /* first RA timeout */ -} NMLndpRDiscPrivate; +} NMLndpNDiscPrivate; /*****************************************************************************/ -struct _NMLndpRDisc { - NMRDisc parent; - NMLndpRDiscPrivate _priv; +struct _NMLndpNDisc { + NMNDisc parent; + NMLndpNDiscPrivate _priv; }; -struct _NMLndpRDiscClass { - NMRDiscClass parent; +struct _NMLndpNDiscClass { + NMNDiscClass parent; }; /*****************************************************************************/ -G_DEFINE_TYPE (NMLndpRDisc, nm_lndp_rdisc, NM_TYPE_RDISC) +G_DEFINE_TYPE (NMLndpNDisc, nm_lndp_ndisc, NM_TYPE_NDISC) -#define NM_LNDP_RDISC_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMLndpRDisc, NM_IS_LNDP_RDISC) +#define NM_LNDP_NDISC_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMLndpNDisc, NM_IS_LNDP_NDISC) /*****************************************************************************/ static gboolean -send_rs (NMRDisc *rdisc, GError **error) +send_rs (NMNDisc *ndisc, GError **error) { - NMLndpRDiscPrivate *priv = NM_LNDP_RDISC_GET_PRIVATE ((NMLndpRDisc *) rdisc); + NMLndpNDiscPrivate *priv = NM_LNDP_NDISC_GET_PRIVATE ((NMLndpNDisc *) ndisc); struct ndp_msg *msg; int errsv; @@ -78,7 +78,7 @@ send_rs (NMRDisc *rdisc, GError **error) "cannot create router solicitation"); return FALSE; } - ndp_msg_ifindex_set (msg, nm_rdisc_get_ifindex (rdisc)); + ndp_msg_ifindex_set (msg, nm_ndisc_get_ifindex (ndisc)); errsv = ndp_msg_send (priv->ndp, msg); ndp_msg_destroy (msg); @@ -93,19 +93,19 @@ send_rs (NMRDisc *rdisc, GError **error) return TRUE; } -_NM_UTILS_LOOKUP_DEFINE (static, translate_preference, enum ndp_route_preference, NMRDiscPreference, - NM_UTILS_LOOKUP_DEFAULT (NM_RDISC_PREFERENCE_INVALID), - NM_UTILS_LOOKUP_ITEM (NDP_ROUTE_PREF_LOW, NM_RDISC_PREFERENCE_LOW), - NM_UTILS_LOOKUP_ITEM (NDP_ROUTE_PREF_MEDIUM, NM_RDISC_PREFERENCE_MEDIUM), - NM_UTILS_LOOKUP_ITEM (NDP_ROUTE_PREF_HIGH, NM_RDISC_PREFERENCE_HIGH), +_NM_UTILS_LOOKUP_DEFINE (static, translate_preference, enum ndp_route_preference, NMNDiscPreference, + NM_UTILS_LOOKUP_DEFAULT (NM_NDISC_PREFERENCE_INVALID), + NM_UTILS_LOOKUP_ITEM (NDP_ROUTE_PREF_LOW, NM_NDISC_PREFERENCE_LOW), + NM_UTILS_LOOKUP_ITEM (NDP_ROUTE_PREF_MEDIUM, NM_NDISC_PREFERENCE_MEDIUM), + NM_UTILS_LOOKUP_ITEM (NDP_ROUTE_PREF_HIGH, NM_NDISC_PREFERENCE_HIGH), ); static int receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data) { - NMRDisc *rdisc = (NMRDisc *) user_data; - NMRDiscDataInternal *rdata = rdisc->rdata; - NMRDiscConfigMap changed = 0; + NMNDisc *ndisc = (NMNDisc *) user_data; + NMNDiscDataInternal *rdata = ndisc->rdata; + NMNDiscConfigMap changed = 0; struct ndp_msgra *msgra = ndp_msgra (msg); struct in6_addr gateway_addr; guint32 now = nm_utils_get_monotonic_timestamp_s (); @@ -132,24 +132,24 @@ receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data) * rewrite the flag with every inbound RA. */ { - NMRDiscDHCPLevel dhcp_level; + NMNDiscDHCPLevel dhcp_level; if (ndp_msgra_flag_managed (msgra)) - dhcp_level = NM_RDISC_DHCP_LEVEL_MANAGED; + dhcp_level = NM_NDISC_DHCP_LEVEL_MANAGED; else if (ndp_msgra_flag_other (msgra)) - dhcp_level = NM_RDISC_DHCP_LEVEL_OTHERCONF; + dhcp_level = NM_NDISC_DHCP_LEVEL_OTHERCONF; else - dhcp_level = NM_RDISC_DHCP_LEVEL_NONE; + dhcp_level = NM_NDISC_DHCP_LEVEL_NONE; /* when receiving multiple RA (possibly from different routers), * let's keep the "most managed" level. */ - G_STATIC_ASSERT_EXPR (NM_RDISC_DHCP_LEVEL_MANAGED > NM_RDISC_DHCP_LEVEL_OTHERCONF); - G_STATIC_ASSERT_EXPR (NM_RDISC_DHCP_LEVEL_OTHERCONF > NM_RDISC_DHCP_LEVEL_NONE); + G_STATIC_ASSERT_EXPR (NM_NDISC_DHCP_LEVEL_MANAGED > NM_NDISC_DHCP_LEVEL_OTHERCONF); + G_STATIC_ASSERT_EXPR (NM_NDISC_DHCP_LEVEL_OTHERCONF > NM_NDISC_DHCP_LEVEL_NONE); dhcp_level = MAX (dhcp_level, rdata->public.dhcp_level); if (dhcp_level != rdata->public.dhcp_level) { rdata->public.dhcp_level = dhcp_level; - changed |= NM_RDISC_CONFIG_DHCP_LEVEL; + changed |= NM_NDISC_CONFIG_DHCP_LEVEL; } } @@ -161,15 +161,15 @@ receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data) */ gateway_addr = *ndp_msg_addrto (msg); { - NMRDiscGateway gateway = { + NMNDiscGateway gateway = { .address = gateway_addr, .timestamp = now, .lifetime = ndp_msgra_router_lifetime (msgra), .preference = translate_preference (ndp_msgra_route_preference (msgra)), }; - if (nm_rdisc_add_gateway (rdisc, &gateway)) - changed |= NM_RDISC_CONFIG_GATEWAYS; + if (nm_ndisc_add_gateway (ndisc, &gateway)) + changed |= NM_NDISC_CONFIG_GATEWAYS; } /* Addresses & Routes */ @@ -185,21 +185,21 @@ receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data) nm_utils_ip6_address_clear_host_address (&r_network, ndp_msg_opt_prefix (msg, offset), r_plen); if (ndp_msg_opt_prefix_flag_on_link (msg, offset)) { - NMRDiscRoute route = { + NMNDiscRoute route = { .network = r_network, .plen = r_plen, .timestamp = now, .lifetime = ndp_msg_opt_prefix_valid_time (msg, offset), }; - if (nm_rdisc_add_route (rdisc, &route)) - changed |= NM_RDISC_CONFIG_ROUTES; + if (nm_ndisc_add_route (ndisc, &route)) + changed |= NM_NDISC_CONFIG_ROUTES; } /* Address */ if ( r_plen == 64 && ndp_msg_opt_prefix_flag_auto_addr_conf (msg, offset)) { - NMRDiscAddress address = { + NMNDiscAddress address = { .address = r_network, .timestamp = now, .lifetime = ndp_msg_opt_prefix_valid_time (msg, offset), @@ -208,12 +208,12 @@ receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data) if (address.preferred > address.lifetime) address.preferred = address.lifetime; - if (nm_rdisc_complete_and_add_address (rdisc, &address)) - changed |= NM_RDISC_CONFIG_ADDRESSES; + if (nm_ndisc_complete_and_add_address (ndisc, &address)) + changed |= NM_NDISC_CONFIG_ADDRESSES; } } ndp_msg_opt_for_each_offset(offset, msg, NDP_MSG_OPT_ROUTE) { - NMRDiscRoute route = { + NMNDiscRoute route = { .gateway = gateway_addr, .plen = ndp_msg_opt_route_prefix_len (msg, offset), .timestamp = now, @@ -226,8 +226,8 @@ receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data) /* Routers through this particular gateway */ nm_utils_ip6_address_clear_host_address (&route.network, ndp_msg_opt_route_prefix (msg, offset), route.plen); - if (nm_rdisc_add_route (rdisc, &route)) - changed |= NM_RDISC_CONFIG_ROUTES; + if (nm_ndisc_add_route (ndisc, &route)) + changed |= NM_NDISC_CONFIG_ROUTES; } /* DNS information */ @@ -236,7 +236,7 @@ receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data) int addr_index; ndp_msg_opt_rdnss_for_each_addr (addr, addr_index, msg, offset) { - NMRDiscDNSServer dns_server = { + NMNDiscDNSServer dns_server = { .address = *addr, .timestamp = now, .lifetime = ndp_msg_opt_rdnss_lifetime (msg, offset), @@ -249,8 +249,8 @@ receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data) */ if (dns_server.lifetime && dns_server.lifetime < 7200) dns_server.lifetime = 7200; - if (nm_rdisc_add_dns_server (rdisc, &dns_server)) - changed |= NM_RDISC_CONFIG_DNS_SERVERS; + if (nm_ndisc_add_dns_server (ndisc, &dns_server)) + changed |= NM_NDISC_CONFIG_DNS_SERVERS; } } ndp_msg_opt_for_each_offset(offset, msg, NDP_MSG_OPT_DNSSL) { @@ -258,7 +258,7 @@ receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data) int domain_index; ndp_msg_opt_dnssl_for_each_domain (domain, domain_index, msg, offset) { - NMRDiscDNSDomain dns_domain = { + NMNDiscDNSDomain dns_domain = { .domain = domain, .timestamp = now, .lifetime = ndp_msg_opt_rdnss_lifetime (msg, offset), @@ -271,15 +271,15 @@ receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data) */ if (dns_domain.lifetime && dns_domain.lifetime < 7200) dns_domain.lifetime = 7200; - if (nm_rdisc_add_dns_domain (rdisc, &dns_domain)) - changed |= NM_RDISC_CONFIG_DNS_DOMAINS; + if (nm_ndisc_add_dns_domain (ndisc, &dns_domain)) + changed |= NM_NDISC_CONFIG_DNS_DOMAINS; } } hop_limit = ndp_msgra_curhoplimit (msgra); if (rdata->public.hop_limit != hop_limit) { rdata->public.hop_limit = hop_limit; - changed |= NM_RDISC_CONFIG_HOP_LIMIT; + changed |= NM_NDISC_CONFIG_HOP_LIMIT; } /* MTU */ @@ -288,7 +288,7 @@ receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data) if (mtu >= 1280) { if (rdata->public.mtu != mtu) { rdata->public.mtu = mtu; - changed |= NM_RDISC_CONFIG_MTU; + changed |= NM_NDISC_CONFIG_MTU; } } else { /* All sorts of bad things would happen if we accepted this. @@ -299,19 +299,189 @@ receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data) } } - nm_rdisc_ra_received (rdisc, now, changed); + nm_ndisc_ra_received (ndisc, now, changed); + return 0; +} + +static void * +_ndp_msg_add_option (struct ndp_msg *msg, int len) +{ + void *ret = (uint8_t *)msg + ndp_msg_payload_len (msg); + + len += ndp_msg_payload_len (msg); + if (len > ndp_msg_payload_maxlen (msg)) + return NULL; + + ndp_msg_payload_len_set (msg, len); + return ret; +} + +#define NM_ND_OPT_RDNSS 25 +typedef struct { + struct nd_opt_hdr header; + uint16_t reserved; + uint32_t lifetime;; + struct in6_addr addrs[0]; +} NMLndpRdnssOption; + +#define NM_ND_OPT_DNSSL 31 +typedef struct { + struct nd_opt_hdr header; + uint16_t reserved; + uint32_t lifetime; + char search_list[0]; +} NMLndpDnsslOption; + +static gboolean +send_ra (NMNDisc *ndisc, GError **error) +{ + NMLndpNDiscPrivate *priv = NM_LNDP_NDISC_GET_PRIVATE ((NMLndpNDisc *) ndisc); + NMNDiscDataInternal *rdata = ndisc->rdata; + guint32 now = nm_utils_get_monotonic_timestamp_s (); + int errsv; + struct in6_addr *addr; + struct ndp_msg *msg; + struct nd_opt_prefix_info *prefix; + int i; + + errsv = ndp_msg_new (&msg, NDP_MSG_RA); + if (errsv) { + errsv = errsv > 0 ? errsv : -errsv; + g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, + "cannot create a router advertisement"); + return FALSE; + } + + ndp_msg_ifindex_set (msg, nm_ndisc_get_ifindex (ndisc)); + + /* Multicast to all nodes. */ + addr = ndp_msg_addrto (msg); + addr->s6_addr32[0] = htonl(0xff020000); + addr->s6_addr32[1] = 0; + addr->s6_addr32[2] = 0; + addr->s6_addr32[3] = htonl(0x1); + + ndp_msgra_router_lifetime_set (ndp_msgra (msg), NM_NDISC_ROUTER_LIFETIME); + + /* The device let us know about all addresses that the device got + * whose prefixes are suitable for delegating. Let's announce them. */ + for (i = 0; i < rdata->addresses->len; i++) { + NMNDiscAddress *address = &g_array_index (rdata->addresses, NMNDiscAddress, i); + guint32 age = now - address->timestamp; + guint32 lifetime = address->lifetime; + guint32 preferred = address->preferred; + + /* Clamp the life times if they're not forever. */ + if (lifetime != 0xffffffff) + lifetime = lifetime > age ? lifetime - age : 0; + if (preferred != 0xffffffff) + preferred = preferred > age ? preferred - age : 0; + + prefix = _ndp_msg_add_option (msg, sizeof(*prefix)); + if (!prefix) { + /* Maybe we could sent separate RAs, but why bother... */ + _LOGW ("The RA is too big, had to omit some some prefixes."); + break; + } + + prefix->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION; + prefix->nd_opt_pi_len = 4; + prefix->nd_opt_pi_prefix_len = 64; + prefix->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_ONLINK; + prefix->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_AUTO; + prefix->nd_opt_pi_valid_time = htonl(lifetime); + prefix->nd_opt_pi_preferred_time = htonl(preferred); + prefix->nd_opt_pi_prefix.s6_addr32[0] = address->address.s6_addr32[0]; + prefix->nd_opt_pi_prefix.s6_addr32[1] = address->address.s6_addr32[1]; + prefix->nd_opt_pi_prefix.s6_addr32[2] = 0; + prefix->nd_opt_pi_prefix.s6_addr32[3] = 0; + } + + if (rdata->dns_servers->len) { + NMLndpRdnssOption *option; + int len = sizeof(*option) + sizeof(option->addrs[0]) * rdata->dns_servers->len; + + option = _ndp_msg_add_option (msg, len); + if (option) { + option->header.nd_opt_type = NM_ND_OPT_RDNSS; + option->header.nd_opt_len = len / 8; + option->lifetime = htonl (900); + + for (i = 0; i < rdata->dns_servers->len; i++) { + NMNDiscDNSServer *dns_server = &g_array_index (rdata->dns_servers, NMNDiscDNSServer, i); + option->addrs[i] = dns_server->address; + } + } else { + _LOGW ("The RA is too big, had to omit DNS information."); + } + + } + + if (rdata->dns_domains->len) { + NMLndpDnsslOption *option; + NMNDiscDNSDomain *dns_server; + int len = sizeof(*option); + char *search_list; + + for (i = 0; i < rdata->dns_domains->len; i++) { + dns_server = &g_array_index (rdata->dns_domains, NMNDiscDNSDomain, i); + len += strlen (dns_server->domain) + 2; + } + len = (len + 8) & ~0x7; + + option = _ndp_msg_add_option (msg, len); + if (option) { + option->header.nd_opt_type = NM_ND_OPT_DNSSL; + option->header.nd_opt_len = len / 8; + option->lifetime = htonl (900); + + search_list = option->search_list; + for (i = 0; i < rdata->dns_domains->len; i++) { + NMNDiscDNSDomain *dns_domain = &g_array_index (rdata->dns_domains, NMNDiscDNSDomain, i); + uint8_t domain_len = strlen (dns_domain->domain); + + *search_list++ = domain_len; + memcpy (search_list, dns_domain->domain, domain_len); + search_list += domain_len; + *search_list++ = '\0'; + } + } else { + _LOGW ("The RA is too big, had to omit DNS search list."); + } + } + + errsv = ndp_msg_send (priv->ndp, msg); + + ndp_msg_destroy (msg); + if (errsv) { + errsv = errsv > 0 ? errsv : -errsv; + g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, + "%s (%d)", + g_strerror (errsv), errsv); + return FALSE; + } + + return TRUE; +} + +static int +receive_rs (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data) +{ + NMNDisc *ndisc = user_data; + + nm_ndisc_rs_received (ndisc); return 0; } static gboolean -event_ready (GIOChannel *source, GIOCondition condition, NMRDisc *rdisc) +event_ready (GIOChannel *source, GIOCondition condition, NMNDisc *ndisc) { nm_auto_pop_netns NMPNetns *netns = NULL; - NMLndpRDiscPrivate *priv = NM_LNDP_RDISC_GET_PRIVATE ((NMLndpRDisc *) rdisc); + NMLndpNDiscPrivate *priv = NM_LNDP_NDISC_GET_PRIVATE ((NMLndpNDisc *) ndisc); _LOGD ("processing libndp events"); - if (!nm_rdisc_netns_push (rdisc, &netns)) + if (!nm_ndisc_netns_push (ndisc, &netns)) return G_SOURCE_CONTINUE; ndp_callall_eventfd_handler (priv->ndp); @@ -319,18 +489,30 @@ event_ready (GIOChannel *source, GIOCondition condition, NMRDisc *rdisc) } static void -start (NMRDisc *rdisc) +start (NMNDisc *ndisc) { - NMLndpRDiscPrivate *priv = NM_LNDP_RDISC_GET_PRIVATE ((NMLndpRDisc *) rdisc); + NMLndpNDiscPrivate *priv = NM_LNDP_NDISC_GET_PRIVATE ((NMLndpNDisc *) ndisc); int fd = ndp_get_eventfd (priv->ndp); + g_return_if_fail (!priv->event_channel); + g_return_if_fail (!priv->event_id); + priv->event_channel = g_io_channel_unix_new (fd); - priv->event_id = g_io_add_watch (priv->event_channel, G_IO_IN, (GIOFunc) event_ready, rdisc); + priv->event_id = g_io_add_watch (priv->event_channel, G_IO_IN, (GIOFunc) event_ready, ndisc); /* Flush any pending messages to avoid using obsolete information */ - event_ready (priv->event_channel, 0, rdisc); + event_ready (priv->event_channel, 0, ndisc); - ndp_msgrcv_handler_register (priv->ndp, receive_ra, NDP_MSG_RA, nm_rdisc_get_ifindex (rdisc), rdisc); + switch (nm_ndisc_get_node_type (ndisc)) { + case NM_NDISC_NODE_TYPE_HOST: + ndp_msgrcv_handler_register (priv->ndp, receive_ra, NDP_MSG_RA, nm_ndisc_get_ifindex (ndisc), ndisc); + break; + case NM_NDISC_NODE_TYPE_ROUTER: + ndp_msgrcv_handler_register (priv->ndp, receive_rs, NDP_MSG_RS, nm_ndisc_get_ifindex (ndisc), ndisc); + break; + default: + g_assert_not_reached (); + } } /*****************************************************************************/ @@ -347,22 +529,23 @@ ipv6_sysctl_get (NMPlatform *platform, const char *ifname, const char *property, } static void -nm_lndp_rdisc_init (NMLndpRDisc *lndp_rdisc) +nm_lndp_ndisc_init (NMLndpNDisc *lndp_ndisc) { } -NMRDisc * -nm_lndp_rdisc_new (NMPlatform *platform, +NMNDisc * +nm_lndp_ndisc_new (NMPlatform *platform, int ifindex, const char *ifname, NMUtilsStableType stable_type, const char *network_id, NMSettingIP6ConfigAddrGenMode addr_gen_mode, + NMNDiscNodeType node_type, GError **error) { nm_auto_pop_netns NMPNetns *netns = NULL; - NMRDisc *rdisc; - NMLndpRDiscPrivate *priv; + NMNDisc *ndisc; + NMLndpNDiscPrivate *priv; int errsv; g_return_val_if_fail (NM_IS_PLATFORM (platform), NULL); @@ -371,25 +554,26 @@ nm_lndp_rdisc_new (NMPlatform *platform, if (!nm_platform_netns_push (platform, &netns)) return NULL; - rdisc = g_object_new (NM_TYPE_LNDP_RDISC, - NM_RDISC_PLATFORM, platform, - NM_RDISC_STABLE_TYPE, (int) stable_type, - NM_RDISC_IFINDEX, ifindex, - NM_RDISC_IFNAME, ifname, - NM_RDISC_NETWORK_ID, network_id, - NM_RDISC_ADDR_GEN_MODE, (int) addr_gen_mode, - NM_RDISC_MAX_ADDRESSES, ipv6_sysctl_get (platform, ifname, + ndisc = g_object_new (NM_TYPE_LNDP_NDISC, + NM_NDISC_PLATFORM, platform, + NM_NDISC_STABLE_TYPE, (int) stable_type, + NM_NDISC_IFINDEX, ifindex, + NM_NDISC_IFNAME, ifname, + NM_NDISC_NETWORK_ID, network_id, + NM_NDISC_ADDR_GEN_MODE, (int) addr_gen_mode, + NM_NDISC_NODE_TYPE, (int) node_type, + NM_NDISC_MAX_ADDRESSES, ipv6_sysctl_get (platform, ifname, "max_addresses", - 0, G_MAXINT32, NM_RDISC_MAX_ADDRESSES_DEFAULT), - NM_RDISC_ROUTER_SOLICITATIONS, ipv6_sysctl_get (platform, ifname, + 0, G_MAXINT32, NM_NDISC_MAX_ADDRESSES_DEFAULT), + NM_NDISC_ROUTER_SOLICITATIONS, ipv6_sysctl_get (platform, ifname, "router_solicitations", - 1, G_MAXINT32, NM_RDISC_ROUTER_SOLICITATIONS_DEFAULT), - NM_RDISC_ROUTER_SOLICITATION_INTERVAL, ipv6_sysctl_get (platform, ifname, + 1, G_MAXINT32, NM_NDISC_ROUTER_SOLICITATIONS_DEFAULT), + NM_NDISC_ROUTER_SOLICITATION_INTERVAL, ipv6_sysctl_get (platform, ifname, "router_solicitation_interval", - 1, G_MAXINT32, NM_RDISC_ROUTER_SOLICITATION_INTERVAL_DEFAULT), + 1, G_MAXINT32, NM_NDISC_ROUTER_SOLICITATION_INTERVAL_DEFAULT), NULL); - priv = NM_LNDP_RDISC_GET_PRIVATE ((NMLndpRDisc *) rdisc); + priv = NM_LNDP_NDISC_GET_PRIVATE ((NMLndpNDisc *) ndisc); errsv = ndp_open (&priv->ndp); @@ -398,37 +582,47 @@ nm_lndp_rdisc_new (NMPlatform *platform, g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, "failure creating libndp socket: %s (%d)", g_strerror (errsv), errsv); - g_object_unref (rdisc); + g_object_unref (ndisc); return NULL; } - return rdisc; + return ndisc; } static void dispose (GObject *object) { - NMRDisc *rdisc = (NMRDisc *) object; - NMLndpRDiscPrivate *priv = NM_LNDP_RDISC_GET_PRIVATE ((NMLndpRDisc *) rdisc); + NMNDisc *ndisc = (NMNDisc *) object; + NMLndpNDiscPrivate *priv = NM_LNDP_NDISC_GET_PRIVATE ((NMLndpNDisc *) ndisc); nm_clear_g_source (&priv->event_id); g_clear_pointer (&priv->event_channel, g_io_channel_unref); if (priv->ndp) { - ndp_msgrcv_handler_unregister (priv->ndp, receive_ra, NDP_MSG_RA, nm_rdisc_get_ifindex (rdisc), rdisc); + switch (nm_ndisc_get_node_type (ndisc)) { + case NM_NDISC_NODE_TYPE_HOST: + ndp_msgrcv_handler_unregister (priv->ndp, receive_rs, NDP_MSG_RA, nm_ndisc_get_ifindex (ndisc), ndisc); + break; + case NM_NDISC_NODE_TYPE_ROUTER: + ndp_msgrcv_handler_unregister (priv->ndp, receive_ra, NDP_MSG_RA, nm_ndisc_get_ifindex (ndisc), ndisc); + break; + default: + g_assert_not_reached (); + } ndp_close (priv->ndp); priv->ndp = NULL; } - G_OBJECT_CLASS (nm_lndp_rdisc_parent_class)->dispose (object); + G_OBJECT_CLASS (nm_lndp_ndisc_parent_class)->dispose (object); } static void -nm_lndp_rdisc_class_init (NMLndpRDiscClass *klass) +nm_lndp_ndisc_class_init (NMLndpNDiscClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); - NMRDiscClass *rdisc_class = NM_RDISC_CLASS (klass); + NMNDiscClass *ndisc_class = NM_NDISC_CLASS (klass); object_class->dispose = dispose; - rdisc_class->start = start; - rdisc_class->send_rs = send_rs; + ndisc_class->start = start; + ndisc_class->send_rs = send_rs; + ndisc_class->send_ra = send_ra; } diff --git a/src/rdisc/nm-lndp-rdisc.h b/src/ndisc/nm-lndp-ndisc.h similarity index 53% rename from src/rdisc/nm-lndp-rdisc.h rename to src/ndisc/nm-lndp-ndisc.h index e2b47c0400..f042fb74a2 100644 --- a/src/rdisc/nm-lndp-rdisc.h +++ b/src/ndisc/nm-lndp-ndisc.h @@ -1,5 +1,5 @@ /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* nm-lndp-rdisc.h - Implementation of router discovery using libndp +/* nm-lndp-ndisc.h - Implementation of neighbor discovery using libndp * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,30 +18,31 @@ * Copyright (C) 2013 Red Hat, Inc. */ -#ifndef __NETWORKMANAGER_LNDP_RDISC_H__ -#define __NETWORKMANAGER_LNDP_RDISC_H__ +#ifndef __NETWORKMANAGER_LNDP_NDISC_H__ +#define __NETWORKMANAGER_LNDP_NDISC_H__ -#include "nm-rdisc.h" +#include "nm-ndisc.h" #include "nm-core-utils.h" -#define NM_TYPE_LNDP_RDISC (nm_lndp_rdisc_get_type ()) -#define NM_LNDP_RDISC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_LNDP_RDISC, NMLndpRDisc)) -#define NM_LNDP_RDISC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_LNDP_RDISC, NMLndpRDiscClass)) -#define NM_IS_LNDP_RDISC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_LNDP_RDISC)) -#define NM_IS_LNDP_RDISC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_LNDP_RDISC)) -#define NM_LNDP_RDISC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_LNDP_RDISC, NMLndpRDiscClass)) +#define NM_TYPE_LNDP_NDISC (nm_lndp_ndisc_get_type ()) +#define NM_LNDP_NDISC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_LNDP_NDISC, NMLndpNDisc)) +#define NM_LNDP_NDISC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_LNDP_NDISC, NMLndpNDiscClass)) +#define NM_IS_LNDP_NDISC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_LNDP_NDISC)) +#define NM_IS_LNDP_NDISC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_LNDP_NDISC)) +#define NM_LNDP_NDISC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_LNDP_NDISC, NMLndpNDiscClass)) -typedef struct _NMLndpRDisc NMLndpRDisc; -typedef struct _NMLndpRDiscClass NMLndpRDiscClass; +typedef struct _NMLndpNDisc NMLndpNDisc; +typedef struct _NMLndpNDiscClass NMLndpNDiscClass; -GType nm_lndp_rdisc_get_type (void); +GType nm_lndp_ndisc_get_type (void); -NMRDisc *nm_lndp_rdisc_new (NMPlatform *platform, +NMNDisc *nm_lndp_ndisc_new (NMPlatform *platform, int ifindex, const char *ifname, NMUtilsStableType stable_type, const char *network_id, NMSettingIP6ConfigAddrGenMode addr_gen_mode, + NMNDiscNodeType node_type, GError **error); -#endif /* __NETWORKMANAGER_LNDP_RDISC_H__ */ +#endif /* __NETWORKMANAGER_LNDP_NDISC_H__ */ diff --git a/src/rdisc/nm-rdisc-private.h b/src/ndisc/nm-ndisc-private.h similarity index 67% rename from src/rdisc/nm-rdisc-private.h rename to src/ndisc/nm-ndisc-private.h index cc2f1ae10d..2308675a7d 100644 --- a/src/rdisc/nm-rdisc-private.h +++ b/src/ndisc/nm-ndisc-private.h @@ -1,5 +1,5 @@ /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* nm-rdisc.h - Perform IPv6 router discovery +/* nm-ndisc.h - Perform IPv6 neighbor discovery * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,15 +18,15 @@ * Copyright 2015 Red Hat, Inc. */ -#ifndef __NETWORKMANAGER_RDISC_PRIVATE_H__ -#define __NETWORKMANAGER_RDISC_PRIVATE_H__ +#ifndef __NETWORKMANAGER_NDISC_PRIVATE_H__ +#define __NETWORKMANAGER_NDISC_PRIVATE_H__ -#include "nm-rdisc.h" +#include "nm-ndisc.h" -/* Functions only used by rdisc implementations */ +/* Functions only used by ndisc implementations */ -struct _NMRDiscDataInternal { - NMRDiscData public; +struct _NMNDiscDataInternal { + NMNDiscData public; GArray *gateways; GArray *addresses; GArray *routes; @@ -34,20 +34,21 @@ struct _NMRDiscDataInternal { GArray *dns_domains; }; -typedef struct _NMRDiscDataInternal NMRDiscDataInternal; +typedef struct _NMNDiscDataInternal NMNDiscDataInternal; -void nm_rdisc_ra_received (NMRDisc *rdisc, guint32 now, NMRDiscConfigMap changed); +void nm_ndisc_ra_received (NMNDisc *ndisc, guint32 now, NMNDiscConfigMap changed); +void nm_ndisc_rs_received (NMNDisc *ndisc); -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); +gboolean nm_ndisc_add_gateway (NMNDisc *ndisc, const NMNDiscGateway *new); +gboolean nm_ndisc_complete_and_add_address (NMNDisc *ndisc, NMNDiscAddress *new); +gboolean nm_ndisc_add_route (NMNDisc *ndisc, const NMNDiscRoute *new); +gboolean nm_ndisc_add_dns_server (NMNDisc *ndisc, const NMNDiscDNSServer *new); +gboolean nm_ndisc_add_dns_domain (NMNDisc *ndisc, const NMNDiscDNSDomain *new); /*****************************************************************************/ #define _NMLOG_DOMAIN LOGD_IP6 -#define _NMLOG(level, ...) _LOG(level, _NMLOG_DOMAIN, rdisc, __VA_ARGS__) +#define _NMLOG(level, ...) _LOG(level, _NMLOG_DOMAIN, ndisc, __VA_ARGS__) #define _LOG(level, domain, self, ...) \ G_STMT_START { \ @@ -55,14 +56,14 @@ gboolean nm_rdisc_add_dns_domain (NMRDisc *rdisc, const NMRDiscDNSDoma const NMLogDomain __domain = (domain); \ \ if (nm_logging_enabled (__level, __domain)) { \ - NMRDisc *const __self = (self); \ + NMNDisc *const __self = (self); \ char __prefix[64]; \ \ _nm_log (__level, __domain, 0, \ "%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \ (__self \ ? ({ \ - const char *__ifname = nm_rdisc_get_ifname (__self); \ + const char *__ifname = nm_ndisc_get_ifname (__self); \ nm_sprintf_buf (__prefix, "%s[%p,%s%s%s]", \ _NMLOG_PREFIX_NAME, __self, \ NM_PRINT_FMT_QUOTE_STRING (__ifname)); \ @@ -74,4 +75,4 @@ gboolean nm_rdisc_add_dns_domain (NMRDisc *rdisc, const NMRDiscDNSDoma /*****************************************************************************/ -#endif /* __NETWORKMANAGER_RDISC_PRIVATE_H__ */ +#endif /* __NETWORKMANAGER_NDISC_PRIVATE_H__ */ diff --git a/src/rdisc/nm-rdisc.c b/src/ndisc/nm-ndisc.c similarity index 58% rename from src/rdisc/nm-rdisc.c rename to src/ndisc/nm-ndisc.c index c7437a106c..1294c9974b 100644 --- a/src/rdisc/nm-rdisc.c +++ b/src/ndisc/nm-ndisc.c @@ -1,5 +1,5 @@ /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* nm-rdisc.c - Perform IPv6 router discovery +/* nm-ndisc.c - Perform IPv6 neighbor discovery * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,7 +20,7 @@ #include "nm-default.h" -#include "nm-rdisc.h" +#include "nm-ndisc.h" #include #include @@ -28,25 +28,34 @@ #include "nm-setting-ip6-config.h" -#include "nm-rdisc-private.h" +#include "nm-ndisc-private.h" #include "nm-utils.h" #include "nm-platform.h" #include "nmp-netns.h" -#define _NMLOG_PREFIX_NAME "rdisc" +#define _NMLOG_PREFIX_NAME "ndisc" /*****************************************************************************/ -struct _NMRDiscPrivate { +struct _NMNDiscPrivate { /* this *must* be the first field. */ - NMRDiscDataInternal rdata; + NMNDiscDataInternal rdata; - gint32 solicitations_left; - guint send_rs_id; - gint32 last_rs; + union { + gint32 solicitations_left; + gint32 announcements_left; + }; + union { + guint send_rs_id; + guint send_ra_id; + }; + union { + gint32 last_rs; + gint32 last_ra; + }; guint ra_timeout_id; /* first RA timeout */ guint timeout_id; /* prefix/dns/etc lifetime timeout */ - char *last_send_rs_error; + char *last_error; NMUtilsIPv6IfaceId iid; /* immutable values: */ @@ -58,12 +67,13 @@ struct _NMRDiscPrivate { gint32 max_addresses; gint32 router_solicitations; gint32 router_solicitation_interval; + NMNDiscNodeType node_type; NMPlatform *platform; NMPNetns *netns; }; -typedef struct _NMRDiscPrivate NMRDiscPrivate; +typedef struct _NMNDiscPrivate NMNDiscPrivate; NM_GOBJECT_PROPERTIES_DEFINE_BASE ( PROP_PLATFORM, @@ -75,6 +85,7 @@ NM_GOBJECT_PROPERTIES_DEFINE_BASE ( PROP_MAX_ADDRESSES, PROP_ROUTER_SOLICITATIONS, PROP_ROUTER_SOLICITATION_INTERVAL, + PROP_NODE_TYPE, ); enum { @@ -85,32 +96,32 @@ enum { static guint signals[LAST_SIGNAL] = { 0 }; -G_DEFINE_TYPE (NMRDisc, nm_rdisc, G_TYPE_OBJECT) +G_DEFINE_TYPE (NMNDisc, nm_ndisc, G_TYPE_OBJECT) -#define NM_RDISC_GET_PRIVATE(self) _NM_GET_PRIVATE_PTR(self, NMRDisc, NM_IS_RDISC) +#define NM_NDISC_GET_PRIVATE(self) _NM_GET_PRIVATE_PTR(self, NMNDisc, NM_IS_NDISC) /*****************************************************************************/ -static void _config_changed_log (NMRDisc *rdisc, NMRDiscConfigMap changed); +static void _config_changed_log (NMNDisc *ndisc, NMNDiscConfigMap changed); /*****************************************************************************/ NMPNetns * -nm_rdisc_netns_get (NMRDisc *self) +nm_ndisc_netns_get (NMNDisc *self) { - g_return_val_if_fail (NM_IS_RDISC (self), NULL); + g_return_val_if_fail (NM_IS_NDISC (self), NULL); - return NM_RDISC_GET_PRIVATE (self)->netns; + return NM_NDISC_GET_PRIVATE (self)->netns; } gboolean -nm_rdisc_netns_push (NMRDisc *self, NMPNetns **netns) +nm_ndisc_netns_push (NMNDisc *self, NMPNetns **netns) { - NMRDiscPrivate *priv; + NMNDiscPrivate *priv; - g_return_val_if_fail (NM_IS_RDISC (self), FALSE); + g_return_val_if_fail (NM_IS_NDISC (self), FALSE); - priv = NM_RDISC_GET_PRIVATE (self); + priv = NM_NDISC_GET_PRIVATE (self); if ( priv->netns && !nmp_netns_push (priv->netns)) { NM_SET_OUT (netns, NULL); @@ -124,25 +135,33 @@ nm_rdisc_netns_push (NMRDisc *self, NMPNetns **netns) /*****************************************************************************/ int -nm_rdisc_get_ifindex (NMRDisc *self) +nm_ndisc_get_ifindex (NMNDisc *self) { - g_return_val_if_fail (NM_IS_RDISC (self), 0); + g_return_val_if_fail (NM_IS_NDISC (self), 0); - return NM_RDISC_GET_PRIVATE (self)->ifindex; + return NM_NDISC_GET_PRIVATE (self)->ifindex; } const char * -nm_rdisc_get_ifname (NMRDisc *self) +nm_ndisc_get_ifname (NMNDisc *self) { - g_return_val_if_fail (NM_IS_RDISC (self), NULL); + g_return_val_if_fail (NM_IS_NDISC (self), NULL); - return NM_RDISC_GET_PRIVATE (self)->ifname; + return NM_NDISC_GET_PRIVATE (self)->ifname; +} + +NMNDiscNodeType +nm_ndisc_get_node_type (NMNDisc *self) +{ + g_return_val_if_fail (NM_IS_NDISC (self), NM_NDISC_NODE_TYPE_INVALID); + + return NM_NDISC_GET_PRIVATE (self)->node_type; } /*****************************************************************************/ -static const NMRDiscData * -_data_complete (NMRDiscDataInternal *data) +static const NMNDiscData * +_data_complete (NMNDiscDataInternal *data) { #define _SET(data, field) \ G_STMT_START { \ @@ -161,24 +180,24 @@ _data_complete (NMRDiscDataInternal *data) } static void -_emit_config_change (NMRDisc *self, NMRDiscConfigMap changed) +_emit_config_change (NMNDisc *self, NMNDiscConfigMap changed) { _config_changed_log (self, changed); g_signal_emit (self, signals[CONFIG_CHANGED], 0, - _data_complete (&NM_RDISC_GET_PRIVATE (self)->rdata), + _data_complete (&NM_NDISC_GET_PRIVATE (self)->rdata), (guint) changed); } /*****************************************************************************/ gboolean -nm_rdisc_add_gateway (NMRDisc *rdisc, const NMRDiscGateway *new) +nm_ndisc_add_gateway (NMNDisc *ndisc, const NMNDiscGateway *new) { - NMRDiscDataInternal *rdata = &NM_RDISC_GET_PRIVATE(rdisc)->rdata; + NMNDiscDataInternal *rdata = &NM_NDISC_GET_PRIVATE(ndisc)->rdata; int i, insert_idx = -1; for (i = 0; i < rdata->gateways->len; i++) { - NMRDiscGateway *item = &g_array_index (rdata->gateways, NMRDiscGateway, i); + NMNDiscGateway *item = &g_array_index (rdata->gateways, NMNDiscGateway, i); if (IN6_ARE_ADDR_EQUAL (&item->address, &new->address)) { if (new->lifetime == 0) { @@ -207,8 +226,8 @@ nm_rdisc_add_gateway (NMRDisc *rdisc, const NMRDiscGateway *new) /** * complete_address: - * @rdisc: the #NMRDisc - * @addr: the #NMRDiscAddress + * @ndisc: the #NMNDisc + * @addr: the #NMNDiscAddress * * 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 @@ -220,14 +239,14 @@ nm_rdisc_add_gateway (NMRDisc *rdisc, const NMRDiscGateway *new) * Returns: %TRUE if the address could be completed, %FALSE otherwise. **/ static gboolean -complete_address (NMRDisc *rdisc, NMRDiscAddress *addr) +complete_address (NMNDisc *ndisc, NMNDiscAddress *addr) { - NMRDiscPrivate *priv; + NMNDiscPrivate *priv; GError *error = NULL; - g_return_val_if_fail (NM_IS_RDISC (rdisc), FALSE); + g_return_val_if_fail (NM_IS_NDISC (ndisc), FALSE); - priv = NM_RDISC_GET_PRIVATE (rdisc); + priv = NM_NDISC_GET_PRIVATE (ndisc); if (priv->addr_gen_mode == NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY) { if (!nm_utils_ipv6_addr_set_stable_privacy (priv->stable_type, &addr->address, @@ -259,21 +278,15 @@ complete_address (NMRDisc *rdisc, NMRDiscAddress *addr) return FALSE; } -gboolean -nm_rdisc_complete_and_add_address (NMRDisc *rdisc, NMRDiscAddress *new) +static gboolean +nm_ndisc_add_address (NMNDisc *ndisc, const NMNDiscAddress *new) { - NMRDiscPrivate *priv; - NMRDiscDataInternal *rdata; + NMNDiscPrivate *priv = NM_NDISC_GET_PRIVATE (ndisc); + NMNDiscDataInternal *rdata = &priv->rdata; int i; - if (!complete_address (rdisc, new)) - return FALSE; - - priv = NM_RDISC_GET_PRIVATE (rdisc); - rdata = &priv->rdata; - for (i = 0; i < rdata->addresses->len; i++) { - NMRDiscAddress *item = &g_array_index (rdata->addresses, NMRDiscAddress, i); + NMNDiscAddress *item = &g_array_index (rdata->addresses, NMNDiscAddress, i); if (IN6_ARE_ADDR_EQUAL (&item->address, &new->address)) { gboolean changed; @@ -303,28 +316,37 @@ nm_rdisc_complete_and_add_address (NMRDisc *rdisc, NMRDiscAddress *new) } gboolean -nm_rdisc_add_route (NMRDisc *rdisc, const NMRDiscRoute *new) +nm_ndisc_complete_and_add_address (NMNDisc *ndisc, NMNDiscAddress *new) { - NMRDiscPrivate *priv; - NMRDiscDataInternal *rdata; + if (!complete_address (ndisc, new)) + return FALSE; + + return nm_ndisc_add_address (ndisc, new); +} + +gboolean +nm_ndisc_add_route (NMNDisc *ndisc, const NMNDiscRoute *new) +{ + NMNDiscPrivate *priv; + NMNDiscDataInternal *rdata; int i, insert_idx = -1; if (new->plen == 0 || new->plen > 128) { /* Only expect non-default routes. The router has no idea what the * local configuration or user preferences are, so sending routes - * with a prefix length of 0 must be ignored by NMRDisc. + * with a prefix length of 0 must be ignored by NMNDisc. * - * Also, upper layers also don't expect that NMRDisc exposes routes + * Also, upper layers also don't expect that NMNDisc exposes routes * with a plen or zero or larger then 128. */ g_return_val_if_reached (FALSE); } - priv = NM_RDISC_GET_PRIVATE (rdisc); + priv = NM_NDISC_GET_PRIVATE (ndisc); rdata = &priv->rdata; for (i = 0; i < rdata->routes->len; i++) { - NMRDiscRoute *item = &g_array_index (rdata->routes, NMRDiscRoute, i); + NMNDiscRoute *item = &g_array_index (rdata->routes, NMNDiscRoute, i); if (IN6_ARE_ADDR_EQUAL (&item->network, &new->network) && item->plen == new->plen) { if (new->lifetime == 0) { @@ -352,17 +374,17 @@ nm_rdisc_add_route (NMRDisc *rdisc, const NMRDiscRoute *new) } gboolean -nm_rdisc_add_dns_server (NMRDisc *rdisc, const NMRDiscDNSServer *new) +nm_ndisc_add_dns_server (NMNDisc *ndisc, const NMNDiscDNSServer *new) { - NMRDiscPrivate *priv; - NMRDiscDataInternal *rdata; + NMNDiscPrivate *priv; + NMNDiscDataInternal *rdata; int i; - priv = NM_RDISC_GET_PRIVATE (rdisc); + priv = NM_NDISC_GET_PRIVATE (ndisc); rdata = &priv->rdata; for (i = 0; i < rdata->dns_servers->len; i++) { - NMRDiscDNSServer *item = &g_array_index (rdata->dns_servers, NMRDiscDNSServer, i); + NMNDiscDNSServer *item = &g_array_index (rdata->dns_servers, NMNDiscDNSServer, i); if (IN6_ARE_ADDR_EQUAL (&item->address, &new->address)) { if (new->lifetime == 0) { @@ -384,18 +406,18 @@ nm_rdisc_add_dns_server (NMRDisc *rdisc, const NMRDiscDNSServer *new) /* Copies new->domain if 'new' is added to the dns_domains list */ gboolean -nm_rdisc_add_dns_domain (NMRDisc *rdisc, const NMRDiscDNSDomain *new) +nm_ndisc_add_dns_domain (NMNDisc *ndisc, const NMNDiscDNSDomain *new) { - NMRDiscPrivate *priv; - NMRDiscDataInternal *rdata; - NMRDiscDNSDomain *item; + NMNDiscPrivate *priv; + NMNDiscDataInternal *rdata; + NMNDiscDNSDomain *item; int i; - priv = NM_RDISC_GET_PRIVATE (rdisc); + priv = NM_NDISC_GET_PRIVATE (ndisc); rdata = &priv->rdata; for (i = 0; i < rdata->dns_domains->len; i++) { - item = &g_array_index (rdata->dns_domains, NMRDiscDNSDomain, i); + item = &g_array_index (rdata->dns_domains, NMNDiscDNSDomain, i); if (!g_strcmp0 (item->domain, new->domain)) { gboolean changed; @@ -417,7 +439,7 @@ nm_rdisc_add_dns_domain (NMRDisc *rdisc, const NMRDiscDNSDomain *new) if (new->lifetime) { g_array_insert_val (rdata->dns_domains, i, *new); - item = &g_array_index (rdata->dns_domains, NMRDiscDNSDomain, i); + item = &g_array_index (rdata->dns_domains, NMNDiscDNSDomain, i); item->domain = g_strdup (new->domain); } return !!new->lifetime; @@ -425,9 +447,184 @@ nm_rdisc_add_dns_domain (NMRDisc *rdisc, const NMRDiscDNSDomain *new) /*****************************************************************************/ +#define _MAYBE_WARN(...) G_STMT_START { \ + gboolean _different_message; \ + \ + _different_message = g_strcmp0 (priv->last_error, error->message) != 0; \ + _NMLOG (_different_message ? LOGL_WARN : LOGL_DEBUG, __VA_ARGS__); \ + if (_different_message) { \ + g_clear_pointer (&priv->last_error, g_free); \ + priv->last_error = g_strdup (error->message); \ + } \ + } G_STMT_END + +static gboolean +send_rs_timeout (NMNDisc *ndisc) +{ + nm_auto_pop_netns NMPNetns *netns = NULL; + NMNDiscClass *klass = NM_NDISC_GET_CLASS (ndisc); + NMNDiscPrivate *priv = NM_NDISC_GET_PRIVATE (ndisc); + GError *error = NULL; + + priv->send_rs_id = 0; + + if (!nm_ndisc_netns_push (ndisc, &netns)) + return G_SOURCE_REMOVE; + + if (klass->send_rs (ndisc, &error)) { + _LOGD ("router solicitation sent"); + priv->solicitations_left--; + g_clear_pointer (&priv->last_error, g_free); + } else { + _MAYBE_WARN ("failure sending router solicitation: %s", error->message); + g_clear_error (&error); + } + + priv->last_rs = nm_utils_get_monotonic_timestamp_s (); + if (priv->solicitations_left > 0) { + _LOGD ("scheduling router solicitation retry in %d seconds.", + (int) priv->router_solicitation_interval); + priv->send_rs_id = g_timeout_add_seconds (priv->router_solicitation_interval, + (GSourceFunc) send_rs_timeout, ndisc); + } else { + _LOGD ("did not receive a router advertisement after %d solicitations.", + (int) priv->router_solicitations); + } + + return G_SOURCE_REMOVE; +} + +static void +solicit_routers (NMNDisc *ndisc) +{ + NMNDiscPrivate *priv = NM_NDISC_GET_PRIVATE (ndisc); + gint64 next, now; + + if (priv->send_rs_id) + return; + + now = nm_utils_get_monotonic_timestamp_s (); + priv->solicitations_left = priv->router_solicitations; + + next = (((gint64) priv->last_rs) + priv->router_solicitation_interval) - now; + next = CLAMP (next, 0, G_MAXINT32); + _LOGD ("scheduling explicit router solicitation request in %" G_GINT64_FORMAT " seconds.", + next); + priv->send_rs_id = g_timeout_add_seconds ((guint32) next, (GSourceFunc) send_rs_timeout, ndisc); +} + +static gboolean +announce_router (NMNDisc *ndisc) +{ + nm_auto_pop_netns NMPNetns *netns = NULL; + NMNDiscClass *klass = NM_NDISC_GET_CLASS (ndisc); + NMNDiscPrivate *priv = NM_NDISC_GET_PRIVATE (ndisc); + GError *error = NULL; + + if (!nm_ndisc_netns_push (ndisc, &netns)) + return G_SOURCE_REMOVE; + + priv->last_ra = nm_utils_get_monotonic_timestamp_s (); + if (klass->send_ra (ndisc, &error)) { + _LOGD ("router advertisement sent"); + g_clear_pointer (&priv->last_error, g_free); + } else { + _MAYBE_WARN ("failure sending router advertisement: %s", error->message); + g_clear_error (&error); + } + + if (--priv->announcements_left) { + _LOGD ("will resend an initial router advertisement"); + + /* Schedule next initial announcement retransmit. */ + priv->send_ra_id = g_timeout_add_seconds (g_random_int_range (NM_NDISC_ROUTER_ADVERT_DELAY, + NM_NDISC_ROUTER_ADVERT_INITIAL_INTERVAL), + (GSourceFunc) announce_router, ndisc); + } else { + _LOGD ("will send an unsolicited router advertisement"); + + /* Schedule next unsolicited announcement. */ + priv->announcements_left = 1; + priv->send_ra_id = g_timeout_add_seconds (NM_NDISC_ROUTER_ADVERT_MAX_INTERVAL, + (GSourceFunc) announce_router, + ndisc); + } + + return G_SOURCE_REMOVE; +} + +static void +announce_router_initial (NMNDisc *ndisc) +{ + NMNDiscPrivate *priv = NM_NDISC_GET_PRIVATE (ndisc); + + _LOGD ("will send an initial router advertisement"); + + /* Retry three more times. */ + priv->announcements_left = NM_NDISC_ROUTER_ADVERTISEMENTS_DEFAULT; + + /* Unschedule an unsolicited resend if we are allowed to send now. */ + if (G_LIKELY (nm_utils_get_monotonic_timestamp_s () - priv->last_ra > NM_NDISC_ROUTER_ADVERT_DELAY)) + nm_clear_g_source (&priv->send_ra_id); + + /* Schedule the initial send rather early. Clamp the delay by minimal + * delay and not the initial advert internal so that we start fast. */ + if (G_LIKELY (!priv->send_ra_id)) { + priv->send_ra_id = g_timeout_add_seconds (g_random_int_range (0, NM_NDISC_ROUTER_ADVERT_DELAY), + (GSourceFunc) announce_router, ndisc); + } +} + +static void +announce_router_solicited (NMNDisc *ndisc) +{ + NMNDiscPrivate *priv = NM_NDISC_GET_PRIVATE (ndisc); + + _LOGD ("will send an solicited router advertisement"); + + /* Unschedule an unsolicited resend if we are allowed to send now. */ + if (nm_utils_get_monotonic_timestamp_s () - priv->last_ra > NM_NDISC_ROUTER_ADVERT_DELAY) + nm_clear_g_source (&priv->send_ra_id); + + if (!priv->send_ra_id) { + priv->send_ra_id = g_timeout_add (g_random_int_range (0, NM_NDISC_ROUTER_ADVERT_DELAY_MS), + (GSourceFunc) announce_router, ndisc); + } +} + +/*****************************************************************************/ + +void +nm_ndisc_set_config (NMNDisc *ndisc, + const GArray *addresses, + const GArray *dns_servers, + const GArray *dns_domains) +{ + int changed = FALSE; + guint i; + + for (i = 0; i < addresses->len; i++) { + if (nm_ndisc_add_address (ndisc, &g_array_index (addresses, NMNDiscAddress, i))) + changed = TRUE; + } + + for (i = 0; i < dns_servers->len; i++) { + if (nm_ndisc_add_dns_server (ndisc, &g_array_index (dns_servers, NMNDiscDNSServer, i))) + changed = TRUE; + } + + for (i = 0; i < dns_domains->len; i++) { + if (nm_ndisc_add_dns_domain (ndisc, &g_array_index (dns_domains, NMNDiscDNSDomain, i))) + changed = TRUE; + } + + if (changed) + announce_router_initial (ndisc); +} + /** - * nm_rdisc_set_iid: - * @rdisc: the #NMRDisc + * nm_ndisc_set_iid: + * @ndisc: the #NMNDisc * @iid: the new interface ID * * Sets the "Modified EUI-64" interface ID to be used when generating @@ -445,14 +642,14 @@ nm_rdisc_add_dns_domain (NMRDisc *rdisc, const NMRDiscDNSDomain *new) * Returns: %TRUE if addresses need to be regenerated, %FALSE otherwise. **/ gboolean -nm_rdisc_set_iid (NMRDisc *rdisc, const NMUtilsIPv6IfaceId iid) +nm_ndisc_set_iid (NMNDisc *ndisc, const NMUtilsIPv6IfaceId iid) { - NMRDiscPrivate *priv; - NMRDiscDataInternal *rdata; + NMNDiscPrivate *priv; + NMNDiscDataInternal *rdata; - g_return_val_if_fail (NM_IS_RDISC (rdisc), FALSE); + g_return_val_if_fail (NM_IS_NDISC (ndisc), FALSE); - priv = NM_RDISC_GET_PRIVATE (rdisc); + priv = NM_NDISC_GET_PRIVATE (ndisc); rdata = &priv->rdata; if (priv->iid.id != iid.id) { @@ -464,7 +661,8 @@ nm_rdisc_set_iid (NMRDisc *rdisc, const NMUtilsIPv6IfaceId iid) if (rdata->addresses->len) { _LOGD ("IPv6 interface identifier changed, flushing addresses"); g_array_remove_range (rdata->addresses, 0, rdata->addresses->len); - _emit_config_change (rdisc, NM_RDISC_CONFIG_ADDRESSES); + _emit_config_change (ndisc, NM_NDISC_CONFIG_ADDRESSES); + solicit_routers (ndisc); } return TRUE; } @@ -473,160 +671,103 @@ nm_rdisc_set_iid (NMRDisc *rdisc, const NMUtilsIPv6IfaceId iid) } static gboolean -send_rs_timeout (NMRDisc *rdisc) +ndisc_ra_timeout_cb (gpointer user_data) { - nm_auto_pop_netns NMPNetns *netns = NULL; - NMRDiscClass *klass = NM_RDISC_GET_CLASS (rdisc); - NMRDiscPrivate *priv = NM_RDISC_GET_PRIVATE (rdisc); - GError *error = NULL; + NMNDisc *ndisc = NM_NDISC (user_data); - priv->send_rs_id = 0; - - if (!nm_rdisc_netns_push (rdisc, &netns)) - return G_SOURCE_REMOVE; - - if (klass->send_rs (rdisc, &error)) { - _LOGD ("router solicitation sent"); - priv->solicitations_left--; - g_clear_pointer (&priv->last_send_rs_error, g_free); - } else { - gboolean different_message; - - different_message = g_strcmp0 (priv->last_send_rs_error, error->message) != 0; - _NMLOG (different_message ? LOGL_WARN : LOGL_DEBUG, - "failure sending router solicitation: %s", error->message); - if (different_message) { - g_clear_pointer (&priv->last_send_rs_error, g_free); - priv->last_send_rs_error = g_strdup (error->message); - } - g_clear_error (&error); - } - - priv->last_rs = nm_utils_get_monotonic_timestamp_s (); - if (priv->solicitations_left > 0) { - _LOGD ("scheduling router solicitation retry in %d seconds.", - (int) priv->router_solicitation_interval); - priv->send_rs_id = g_timeout_add_seconds (priv->router_solicitation_interval, - (GSourceFunc) send_rs_timeout, rdisc); - } else { - _LOGD ("did not receive a router advertisement after %d solicitations.", - (int) priv->router_solicitations); - } - - return G_SOURCE_REMOVE; -} - -static void -solicit (NMRDisc *rdisc) -{ - NMRDiscPrivate *priv = NM_RDISC_GET_PRIVATE (rdisc); - gint64 next, now; - - if (priv->send_rs_id) - return; - - now = nm_utils_get_monotonic_timestamp_s (); - - priv->solicitations_left = priv->router_solicitations; - - next = (((gint64) priv->last_rs) + priv->router_solicitation_interval) - now; - next = CLAMP (next, 0, G_MAXINT32); - _LOGD ("scheduling explicit router solicitation request in %" G_GINT64_FORMAT " seconds.", - next); - priv->send_rs_id = g_timeout_add_seconds ((guint32) next, (GSourceFunc) send_rs_timeout, rdisc); -} - -static gboolean -rdisc_ra_timeout_cb (gpointer user_data) -{ - NMRDisc *rdisc = NM_RDISC (user_data); - - NM_RDISC_GET_PRIVATE (rdisc)->ra_timeout_id = 0; - g_signal_emit (rdisc, signals[RA_TIMEOUT], 0); + NM_NDISC_GET_PRIVATE (ndisc)->ra_timeout_id = 0; + g_signal_emit (ndisc, signals[RA_TIMEOUT], 0); return G_SOURCE_REMOVE; } void -nm_rdisc_start (NMRDisc *rdisc) +nm_ndisc_start (NMNDisc *ndisc) { nm_auto_pop_netns NMPNetns *netns = NULL; - NMRDiscPrivate *priv = NM_RDISC_GET_PRIVATE (rdisc); - NMRDiscClass *klass = NM_RDISC_GET_CLASS (rdisc); + NMNDiscPrivate *priv = NM_NDISC_GET_PRIVATE (ndisc); + NMNDiscClass *klass = NM_NDISC_GET_CLASS (ndisc); gint64 ra_wait_secs; - g_assert (klass->start); + g_return_if_fail (klass->start); + g_return_if_fail (!priv->ra_timeout_id); - _LOGD ("starting router discovery: %d", priv->ifindex); + _LOGD ("starting neighbor discovery: %d", priv->ifindex); - if (!nm_rdisc_netns_push (rdisc, &netns)) + if (!nm_ndisc_netns_push (ndisc, &netns)) return; - nm_clear_g_source (&priv->ra_timeout_id); - ra_wait_secs = (((gint64) priv->router_solicitations) * priv->router_solicitation_interval) + 1; - ra_wait_secs = CLAMP (ra_wait_secs, 30, 120); - priv->ra_timeout_id = g_timeout_add_seconds (ra_wait_secs, rdisc_ra_timeout_cb, rdisc); - _LOGD ("scheduling RA timeout in %d seconds", (int) ra_wait_secs); + klass->start (ndisc); - if (klass->start) - klass->start (rdisc); - - solicit (rdisc); + switch (priv->node_type) { + case NM_NDISC_NODE_TYPE_HOST: + ra_wait_secs = (((gint64) priv->router_solicitations) * priv->router_solicitation_interval) + 1; + ra_wait_secs = CLAMP (ra_wait_secs, 30, 120); + priv->ra_timeout_id = g_timeout_add_seconds (ra_wait_secs, ndisc_ra_timeout_cb, ndisc); + _LOGD ("scheduling RA timeout in %d seconds", (int) ra_wait_secs); + solicit_routers (ndisc); + break; + case NM_NDISC_NODE_TYPE_ROUTER: + announce_router_initial (ndisc); + break; + default: + g_assert_not_reached (); + } } void -nm_rdisc_dad_failed (NMRDisc *rdisc, struct in6_addr *address) +nm_ndisc_dad_failed (NMNDisc *ndisc, struct in6_addr *address) { - NMRDiscDataInternal *rdata; + NMNDiscDataInternal *rdata; int i; gboolean changed = FALSE; - rdata = &NM_RDISC_GET_PRIVATE (rdisc)->rdata; + rdata = &NM_NDISC_GET_PRIVATE (ndisc)->rdata; for (i = 0; i < rdata->addresses->len; i++) { - NMRDiscAddress *item = &g_array_index (rdata->addresses, NMRDiscAddress, i); + NMNDiscAddress *item = &g_array_index (rdata->addresses, NMNDiscAddress, i); if (!IN6_ARE_ADDR_EQUAL (&item->address, address)) continue; _LOGD ("DAD failed for discovered address %s", nm_utils_inet6_ntop (address, NULL)); - if (!complete_address (rdisc, item)) + if (!complete_address (ndisc, item)) g_array_remove_index (rdata->addresses, i--); changed = TRUE; } if (changed) - _emit_config_change (rdisc, NM_RDISC_CONFIG_ADDRESSES); + _emit_config_change (ndisc, NM_NDISC_CONFIG_ADDRESSES); } #define CONFIG_MAP_MAX_STR 7 static void -config_map_to_string (NMRDiscConfigMap map, char *p) +config_map_to_string (NMNDiscConfigMap map, char *p) { - if (map & NM_RDISC_CONFIG_DHCP_LEVEL) + if (map & NM_NDISC_CONFIG_DHCP_LEVEL) *p++ = 'd'; - if (map & NM_RDISC_CONFIG_GATEWAYS) + if (map & NM_NDISC_CONFIG_GATEWAYS) *p++ = 'G'; - if (map & NM_RDISC_CONFIG_ADDRESSES) + if (map & NM_NDISC_CONFIG_ADDRESSES) *p++ = 'A'; - if (map & NM_RDISC_CONFIG_ROUTES) + if (map & NM_NDISC_CONFIG_ROUTES) *p++ = 'R'; - if (map & NM_RDISC_CONFIG_DNS_SERVERS) + if (map & NM_NDISC_CONFIG_DNS_SERVERS) *p++ = 'S'; - if (map & NM_RDISC_CONFIG_DNS_DOMAINS) + if (map & NM_NDISC_CONFIG_DNS_DOMAINS) *p++ = 'D'; *p = '\0'; } static const char * -dhcp_level_to_string (NMRDiscDHCPLevel dhcp_level) +dhcp_level_to_string (NMNDiscDHCPLevel dhcp_level) { switch (dhcp_level) { - case NM_RDISC_DHCP_LEVEL_NONE: + case NM_NDISC_DHCP_LEVEL_NONE: return "none"; - case NM_RDISC_DHCP_LEVEL_OTHERCONF: + case NM_NDISC_DHCP_LEVEL_OTHERCONF: return "otherconf"; - case NM_RDISC_DHCP_LEVEL_MANAGED: + case NM_NDISC_DHCP_LEVEL_MANAGED: return "managed"; default: return "INVALID"; @@ -636,10 +777,10 @@ dhcp_level_to_string (NMRDiscDHCPLevel dhcp_level) #define expiry(item) (item->timestamp + item->lifetime) static void -_config_changed_log (NMRDisc *rdisc, NMRDiscConfigMap changed) +_config_changed_log (NMNDisc *ndisc, NMNDiscConfigMap changed) { - NMRDiscPrivate *priv; - NMRDiscDataInternal *rdata; + NMNDiscPrivate *priv; + NMNDiscDataInternal *rdata; int i; char changedstr[CONFIG_MAP_MAX_STR]; char addrstr[INET6_ADDRSTRLEN]; @@ -647,26 +788,26 @@ _config_changed_log (NMRDisc *rdisc, NMRDiscConfigMap changed) if (!_LOGD_ENABLED ()) return; - priv = NM_RDISC_GET_PRIVATE (rdisc); + priv = NM_NDISC_GET_PRIVATE (ndisc); rdata = &priv->rdata; config_map_to_string (changed, changedstr); - _LOGD ("router discovery configuration changed [%s]:", changedstr); + _LOGD ("neighbor discovery configuration changed [%s]:", changedstr); _LOGD (" dhcp-level %s", dhcp_level_to_string (priv->rdata.public.dhcp_level)); for (i = 0; i < rdata->gateways->len; i++) { - NMRDiscGateway *gateway = &g_array_index (rdata->gateways, NMRDiscGateway, i); + NMNDiscGateway *gateway = &g_array_index (rdata->gateways, NMNDiscGateway, i); inet_ntop (AF_INET6, &gateway->address, addrstr, sizeof (addrstr)); _LOGD (" gateway %s pref %d exp %u", addrstr, gateway->preference, expiry (gateway)); } for (i = 0; i < rdata->addresses->len; i++) { - NMRDiscAddress *address = &g_array_index (rdata->addresses, NMRDiscAddress, i); + NMNDiscAddress *address = &g_array_index (rdata->addresses, NMNDiscAddress, i); inet_ntop (AF_INET6, &address->address, addrstr, sizeof (addrstr)); _LOGD (" address %s exp %u", addrstr, expiry (address)); } for (i = 0; i < rdata->routes->len; i++) { - NMRDiscRoute *route = &g_array_index (rdata->routes, NMRDiscRoute, i); + NMNDiscRoute *route = &g_array_index (rdata->routes, NMNDiscRoute, i); inet_ntop (AF_INET6, &route->network, addrstr, sizeof (addrstr)); _LOGD (" route %s/%d via %s pref %d exp %u", addrstr, (int) route->plen, @@ -674,28 +815,28 @@ _config_changed_log (NMRDisc *rdisc, NMRDiscConfigMap changed) expiry (route)); } for (i = 0; i < rdata->dns_servers->len; i++) { - NMRDiscDNSServer *dns_server = &g_array_index (rdata->dns_servers, NMRDiscDNSServer, i); + NMNDiscDNSServer *dns_server = &g_array_index (rdata->dns_servers, NMNDiscDNSServer, i); inet_ntop (AF_INET6, &dns_server->address, addrstr, sizeof (addrstr)); _LOGD (" dns_server %s exp %u", addrstr, expiry (dns_server)); } for (i = 0; i < rdata->dns_domains->len; i++) { - NMRDiscDNSDomain *dns_domain = &g_array_index (rdata->dns_domains, NMRDiscDNSDomain, i); + NMNDiscDNSDomain *dns_domain = &g_array_index (rdata->dns_domains, NMNDiscDNSDomain, i); _LOGD (" dns_domain %s exp %u", dns_domain->domain, expiry (dns_domain)); } } static void -clean_gateways (NMRDisc *rdisc, guint32 now, NMRDiscConfigMap *changed, guint32 *nextevent) +clean_gateways (NMNDisc *ndisc, guint32 now, NMNDiscConfigMap *changed, guint32 *nextevent) { - NMRDiscDataInternal *rdata; + NMNDiscDataInternal *rdata; guint i; - rdata = &NM_RDISC_GET_PRIVATE (rdisc)->rdata; + rdata = &NM_NDISC_GET_PRIVATE (ndisc)->rdata; for (i = 0; i < rdata->gateways->len; i++) { - NMRDiscGateway *item = &g_array_index (rdata->gateways, NMRDiscGateway, i); + NMNDiscGateway *item = &g_array_index (rdata->gateways, NMNDiscGateway, i); guint64 expiry = (guint64) item->timestamp + item->lifetime; if (item->lifetime == G_MAXUINT32) @@ -703,22 +844,22 @@ clean_gateways (NMRDisc *rdisc, guint32 now, NMRDiscConfigMap *changed, guint32 if (now >= expiry) { g_array_remove_index (rdata->gateways, i--); - *changed |= NM_RDISC_CONFIG_GATEWAYS; + *changed |= NM_NDISC_CONFIG_GATEWAYS; } else if (*nextevent > expiry) *nextevent = expiry; } } static void -clean_addresses (NMRDisc *rdisc, guint32 now, NMRDiscConfigMap *changed, guint32 *nextevent) +clean_addresses (NMNDisc *ndisc, guint32 now, NMNDiscConfigMap *changed, guint32 *nextevent) { - NMRDiscDataInternal *rdata; + NMNDiscDataInternal *rdata; guint i; - rdata = &NM_RDISC_GET_PRIVATE (rdisc)->rdata; + rdata = &NM_NDISC_GET_PRIVATE (ndisc)->rdata; for (i = 0; i < rdata->addresses->len; i++) { - NMRDiscAddress *item = &g_array_index (rdata->addresses, NMRDiscAddress, i); + NMNDiscAddress *item = &g_array_index (rdata->addresses, NMNDiscAddress, i); guint64 expiry = (guint64) item->timestamp + item->lifetime; if (item->lifetime == G_MAXUINT32) @@ -726,22 +867,22 @@ clean_addresses (NMRDisc *rdisc, guint32 now, NMRDiscConfigMap *changed, guint32 if (now >= expiry) { g_array_remove_index (rdata->addresses, i--); - *changed |= NM_RDISC_CONFIG_ADDRESSES; + *changed |= NM_NDISC_CONFIG_ADDRESSES; } else if (*nextevent > expiry) *nextevent = expiry; } } static void -clean_routes (NMRDisc *rdisc, guint32 now, NMRDiscConfigMap *changed, guint32 *nextevent) +clean_routes (NMNDisc *ndisc, guint32 now, NMNDiscConfigMap *changed, guint32 *nextevent) { - NMRDiscDataInternal *rdata; + NMNDiscDataInternal *rdata; guint i; - rdata = &NM_RDISC_GET_PRIVATE (rdisc)->rdata; + rdata = &NM_NDISC_GET_PRIVATE (ndisc)->rdata; for (i = 0; i < rdata->routes->len; i++) { - NMRDiscRoute *item = &g_array_index (rdata->routes, NMRDiscRoute, i); + NMNDiscRoute *item = &g_array_index (rdata->routes, NMNDiscRoute, i); guint64 expiry = (guint64) item->timestamp + item->lifetime; if (item->lifetime == G_MAXUINT32) @@ -749,22 +890,22 @@ clean_routes (NMRDisc *rdisc, guint32 now, NMRDiscConfigMap *changed, guint32 *n if (now >= expiry) { g_array_remove_index (rdata->routes, i--); - *changed |= NM_RDISC_CONFIG_ROUTES; + *changed |= NM_NDISC_CONFIG_ROUTES; } else if (*nextevent > expiry) *nextevent = expiry; } } static void -clean_dns_servers (NMRDisc *rdisc, guint32 now, NMRDiscConfigMap *changed, guint32 *nextevent) +clean_dns_servers (NMNDisc *ndisc, guint32 now, NMNDiscConfigMap *changed, guint32 *nextevent) { - NMRDiscDataInternal *rdata; + NMNDiscDataInternal *rdata; guint i; - rdata = &NM_RDISC_GET_PRIVATE (rdisc)->rdata; + rdata = &NM_NDISC_GET_PRIVATE (ndisc)->rdata; for (i = 0; i < rdata->dns_servers->len; i++) { - NMRDiscDNSServer *item = &g_array_index (rdata->dns_servers, NMRDiscDNSServer, i); + NMNDiscDNSServer *item = &g_array_index (rdata->dns_servers, NMNDiscDNSServer, i); guint64 expiry = (guint64) item->timestamp + item->lifetime; guint64 refresh = (guint64) item->timestamp + item->lifetime / 2; @@ -773,24 +914,24 @@ clean_dns_servers (NMRDisc *rdisc, guint32 now, NMRDiscConfigMap *changed, guint if (now >= expiry) { g_array_remove_index (rdata->dns_servers, i--); - *changed |= NM_RDISC_CONFIG_DNS_SERVERS; + *changed |= NM_NDISC_CONFIG_DNS_SERVERS; } else if (now >= refresh) - solicit (rdisc); + solicit_routers (ndisc); else if (*nextevent > refresh) *nextevent = refresh; } } static void -clean_dns_domains (NMRDisc *rdisc, guint32 now, NMRDiscConfigMap *changed, guint32 *nextevent) +clean_dns_domains (NMNDisc *ndisc, guint32 now, NMNDiscConfigMap *changed, guint32 *nextevent) { - NMRDiscDataInternal *rdata; + NMNDiscDataInternal *rdata; guint i; - rdata = &NM_RDISC_GET_PRIVATE (rdisc)->rdata; + rdata = &NM_NDISC_GET_PRIVATE (ndisc)->rdata; for (i = 0; i < rdata->dns_domains->len; i++) { - NMRDiscDNSDomain *item = &g_array_index (rdata->dns_domains, NMRDiscDNSDomain, i); + NMNDiscDNSDomain *item = &g_array_index (rdata->dns_domains, NMNDiscDNSDomain, i); guint64 expiry = (guint64) item->timestamp + item->lifetime; guint64 refresh = (guint64) item->timestamp + item->lifetime / 2; @@ -799,9 +940,9 @@ clean_dns_domains (NMRDisc *rdisc, guint32 now, NMRDiscConfigMap *changed, guint if (now >= expiry) { g_array_remove_index (rdata->dns_domains, i--); - *changed |= NM_RDISC_CONFIG_DNS_DOMAINS; + *changed |= NM_NDISC_CONFIG_DNS_DOMAINS; } else if (now >= refresh) - solicit (rdisc); + solicit_routers (ndisc); else if (*nextevent > refresh) *nextevent = refresh; } @@ -810,51 +951,60 @@ clean_dns_domains (NMRDisc *rdisc, guint32 now, NMRDiscConfigMap *changed, guint static gboolean timeout_cb (gpointer user_data); static void -check_timestamps (NMRDisc *rdisc, guint32 now, NMRDiscConfigMap changed) +check_timestamps (NMNDisc *ndisc, guint32 now, NMNDiscConfigMap changed) { - NMRDiscPrivate *priv = NM_RDISC_GET_PRIVATE (rdisc); + NMNDiscPrivate *priv = NM_NDISC_GET_PRIVATE (ndisc); /* Use a magic date in the distant future (~68 years) */ guint32 never = G_MAXINT32; guint32 nextevent = never; nm_clear_g_source (&priv->timeout_id); - clean_gateways (rdisc, now, &changed, &nextevent); - clean_addresses (rdisc, now, &changed, &nextevent); - clean_routes (rdisc, now, &changed, &nextevent); - clean_dns_servers (rdisc, now, &changed, &nextevent); - clean_dns_domains (rdisc, now, &changed, &nextevent); + clean_gateways (ndisc, now, &changed, &nextevent); + clean_addresses (ndisc, now, &changed, &nextevent); + clean_routes (ndisc, now, &changed, &nextevent); + clean_dns_servers (ndisc, now, &changed, &nextevent); + clean_dns_domains (ndisc, now, &changed, &nextevent); if (changed) - _emit_config_change (rdisc, changed); + _emit_config_change (ndisc, changed); if (nextevent != never) { g_return_if_fail (nextevent > now); _LOGD ("scheduling next now/lifetime check: %u seconds", nextevent - now); - priv->timeout_id = g_timeout_add_seconds (nextevent - now, timeout_cb, rdisc); + priv->timeout_id = g_timeout_add_seconds (nextevent - now, timeout_cb, ndisc); } } static gboolean timeout_cb (gpointer user_data) { - NMRDisc *self = user_data; + NMNDisc *self = user_data; - NM_RDISC_GET_PRIVATE (self)->timeout_id = 0; + NM_NDISC_GET_PRIVATE (self)->timeout_id = 0; check_timestamps (self, nm_utils_get_monotonic_timestamp_s (), 0); return G_SOURCE_REMOVE; } void -nm_rdisc_ra_received (NMRDisc *rdisc, guint32 now, NMRDiscConfigMap changed) +nm_ndisc_ra_received (NMNDisc *ndisc, guint32 now, NMNDiscConfigMap changed) { - NMRDiscPrivate *priv = NM_RDISC_GET_PRIVATE (rdisc); + NMNDiscPrivate *priv = NM_NDISC_GET_PRIVATE (ndisc); nm_clear_g_source (&priv->ra_timeout_id); nm_clear_g_source (&priv->send_rs_id); - g_clear_pointer (&priv->last_send_rs_error, g_free); - check_timestamps (rdisc, now, changed); + g_clear_pointer (&priv->last_error, g_free); + check_timestamps (ndisc, now, changed); +} + +void +nm_ndisc_rs_received (NMNDisc *ndisc) +{ + NMNDiscPrivate *priv = NM_NDISC_GET_PRIVATE (ndisc); + + g_clear_pointer (&priv->last_error, g_free); + announce_router_solicited (ndisc); } /*****************************************************************************/ @@ -862,15 +1012,15 @@ nm_rdisc_ra_received (NMRDisc *rdisc, guint32 now, NMRDiscConfigMap changed) static void dns_domain_free (gpointer data) { - g_free (((NMRDiscDNSDomain *)(data))->domain); + g_free (((NMNDiscDNSDomain *)(data))->domain); } static void set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { - NMRDisc *self = NM_RDISC (object); - NMRDiscPrivate *priv = NM_RDISC_GET_PRIVATE (self); + NMNDisc *self = NM_NDISC (object); + NMNDiscPrivate *priv = NM_NDISC_GET_PRIVATE (self); switch (prop_id) { case PROP_PLATFORM: @@ -921,6 +1071,10 @@ set_property (GObject *object, guint prop_id, /* construct-only */ priv->router_solicitation_interval = g_value_get_int (value); break; + case PROP_NODE_TYPE: + /* construct-only */ + priv->node_type = g_value_get_int (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -928,21 +1082,21 @@ set_property (GObject *object, guint prop_id, } static void -nm_rdisc_init (NMRDisc *rdisc) +nm_ndisc_init (NMNDisc *ndisc) { - NMRDiscPrivate *priv; - NMRDiscDataInternal *rdata; + NMNDiscPrivate *priv; + NMNDiscDataInternal *rdata; - priv = G_TYPE_INSTANCE_GET_PRIVATE (rdisc, NM_TYPE_RDISC, NMRDiscPrivate); - rdisc->_priv = priv; + priv = G_TYPE_INSTANCE_GET_PRIVATE (ndisc, NM_TYPE_NDISC, NMNDiscPrivate); + ndisc->_priv = priv; rdata = &priv->rdata; - rdata->gateways = g_array_new (FALSE, FALSE, sizeof (NMRDiscGateway)); - rdata->addresses = g_array_new (FALSE, FALSE, sizeof (NMRDiscAddress)); - rdata->routes = g_array_new (FALSE, FALSE, sizeof (NMRDiscRoute)); - rdata->dns_servers = g_array_new (FALSE, FALSE, sizeof (NMRDiscDNSServer)); - rdata->dns_domains = g_array_new (FALSE, FALSE, sizeof (NMRDiscDNSDomain)); + rdata->gateways = g_array_new (FALSE, FALSE, sizeof (NMNDiscGateway)); + rdata->addresses = g_array_new (FALSE, FALSE, sizeof (NMNDiscAddress)); + rdata->routes = g_array_new (FALSE, FALSE, sizeof (NMNDiscRoute)); + rdata->dns_servers = g_array_new (FALSE, FALSE, sizeof (NMNDiscDNSServer)); + rdata->dns_domains = g_array_new (FALSE, FALSE, sizeof (NMNDiscDNSDomain)); g_array_set_clear_func (rdata->dns_domains, dns_domain_free); priv->rdata.public.hop_limit = 64; @@ -955,24 +1109,25 @@ nm_rdisc_init (NMRDisc *rdisc) static void dispose (GObject *object) { - NMRDisc *rdisc = NM_RDISC (object); - NMRDiscPrivate *priv = NM_RDISC_GET_PRIVATE (rdisc); + NMNDisc *ndisc = NM_NDISC (object); + NMNDiscPrivate *priv = NM_NDISC_GET_PRIVATE (ndisc); nm_clear_g_source (&priv->ra_timeout_id); nm_clear_g_source (&priv->send_rs_id); - g_clear_pointer (&priv->last_send_rs_error, g_free); + nm_clear_g_source (&priv->send_ra_id); + g_clear_pointer (&priv->last_error, g_free); nm_clear_g_source (&priv->timeout_id); - G_OBJECT_CLASS (nm_rdisc_parent_class)->dispose (object); + G_OBJECT_CLASS (nm_ndisc_parent_class)->dispose (object); } static void finalize (GObject *object) { - NMRDisc *rdisc = NM_RDISC (object); - NMRDiscPrivate *priv = NM_RDISC_GET_PRIVATE (rdisc); - NMRDiscDataInternal *rdata = &priv->rdata; + NMNDisc *ndisc = NM_NDISC (object); + NMNDiscPrivate *priv = NM_NDISC_GET_PRIVATE (ndisc); + NMNDiscDataInternal *rdata = &priv->rdata; g_free (priv->ifname); g_free (priv->network_id); @@ -986,85 +1141,91 @@ finalize (GObject *object) g_clear_object (&priv->netns); g_clear_object (&priv->platform); - G_OBJECT_CLASS (nm_rdisc_parent_class)->finalize (object); + G_OBJECT_CLASS (nm_ndisc_parent_class)->finalize (object); } static void -nm_rdisc_class_init (NMRDiscClass *klass) +nm_ndisc_class_init (NMNDiscClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); - g_type_class_add_private (klass, sizeof (NMRDiscPrivate)); + g_type_class_add_private (klass, sizeof (NMNDiscPrivate)); object_class->set_property = set_property; object_class->dispose = dispose; object_class->finalize = finalize; obj_properties[PROP_PLATFORM] = - g_param_spec_object (NM_RDISC_PLATFORM, "", "", + g_param_spec_object (NM_NDISC_PLATFORM, "", "", NM_TYPE_PLATFORM, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); obj_properties[PROP_IFINDEX] = - g_param_spec_int (NM_RDISC_IFINDEX, "", "", + g_param_spec_int (NM_NDISC_IFINDEX, "", "", 0, G_MAXINT, 0, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); obj_properties[PROP_IFNAME] = - g_param_spec_string (NM_RDISC_IFNAME, "", "", + g_param_spec_string (NM_NDISC_IFNAME, "", "", NULL, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); obj_properties[PROP_STABLE_TYPE] = - g_param_spec_int (NM_RDISC_STABLE_TYPE, "", "", + g_param_spec_int (NM_NDISC_STABLE_TYPE, "", "", NM_UTILS_STABLE_TYPE_UUID, NM_UTILS_STABLE_TYPE_STABLE_ID, NM_UTILS_STABLE_TYPE_UUID, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); obj_properties[PROP_NETWORK_ID] = - g_param_spec_string (NM_RDISC_NETWORK_ID, "", "", + g_param_spec_string (NM_NDISC_NETWORK_ID, "", "", NULL, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); obj_properties[PROP_ADDR_GEN_MODE] = - g_param_spec_int (NM_RDISC_ADDR_GEN_MODE, "", "", + g_param_spec_int (NM_NDISC_ADDR_GEN_MODE, "", "", NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64, NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY, NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); obj_properties[PROP_MAX_ADDRESSES] = - g_param_spec_int (NM_RDISC_MAX_ADDRESSES, "", "", - 0, G_MAXINT32, NM_RDISC_MAX_ADDRESSES_DEFAULT, + g_param_spec_int (NM_NDISC_MAX_ADDRESSES, "", "", + 0, G_MAXINT32, NM_NDISC_MAX_ADDRESSES_DEFAULT, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); obj_properties[PROP_ROUTER_SOLICITATIONS] = - g_param_spec_int (NM_RDISC_ROUTER_SOLICITATIONS, "", "", - 1, G_MAXINT32, NM_RDISC_ROUTER_SOLICITATIONS_DEFAULT, + g_param_spec_int (NM_NDISC_ROUTER_SOLICITATIONS, "", "", + 1, G_MAXINT32, NM_NDISC_ROUTER_SOLICITATIONS_DEFAULT, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); obj_properties[PROP_ROUTER_SOLICITATION_INTERVAL] = - g_param_spec_int (NM_RDISC_ROUTER_SOLICITATION_INTERVAL, "", "", - 1, G_MAXINT32, NM_RDISC_ROUTER_SOLICITATION_INTERVAL_DEFAULT, + g_param_spec_int (NM_NDISC_ROUTER_SOLICITATION_INTERVAL, "", "", + 1, G_MAXINT32, NM_NDISC_ROUTER_SOLICITATION_INTERVAL_DEFAULT, + G_PARAM_WRITABLE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); + obj_properties[PROP_NODE_TYPE] = + g_param_spec_int (NM_NDISC_NODE_TYPE, "", "", + NM_NDISC_NODE_TYPE_INVALID, NM_NDISC_NODE_TYPE_ROUTER, NM_NDISC_NODE_TYPE_INVALID, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); signals[CONFIG_CHANGED] = - g_signal_new (NM_RDISC_CONFIG_CHANGED, + g_signal_new (NM_NDISC_CONFIG_RECEIVED, G_OBJECT_CLASS_TYPE (klass), G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL, G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_UINT); signals[RA_TIMEOUT] = - g_signal_new (NM_RDISC_RA_TIMEOUT, + g_signal_new (NM_NDISC_RA_TIMEOUT, G_OBJECT_CLASS_TYPE (klass), G_SIGNAL_RUN_FIRST, 0, diff --git a/src/ndisc/nm-ndisc.h b/src/ndisc/nm-ndisc.h new file mode 100644 index 0000000000..7c67289d1e --- /dev/null +++ b/src/ndisc/nm-ndisc.h @@ -0,0 +1,189 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* nm-ndisc.h - Perform IPv6 neighbor discovery + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2013 Red Hat, Inc. + */ + +#ifndef __NETWORKMANAGER_NDISC_H__ +#define __NETWORKMANAGER_NDISC_H__ + +#include +#include + +#include "nm-setting-ip6-config.h" +#include "NetworkManagerUtils.h" + +#define NM_TYPE_NDISC (nm_ndisc_get_type ()) +#define NM_NDISC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_NDISC, NMNDisc)) +#define NM_NDISC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_NDISC, NMNDiscClass)) +#define NM_IS_NDISC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_NDISC)) +#define NM_IS_NDISC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_NDISC)) +#define NM_NDISC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_NDISC, NMNDiscClass)) + +#define NM_NDISC_PLATFORM "platform" +#define NM_NDISC_IFINDEX "ifindex" +#define NM_NDISC_IFNAME "ifname" +#define NM_NDISC_NETWORK_ID "network-id" +#define NM_NDISC_ADDR_GEN_MODE "addr-gen-mode" +#define NM_NDISC_STABLE_TYPE "stable-type" +#define NM_NDISC_NODE_TYPE "node-type" +#define NM_NDISC_MAX_ADDRESSES "max-addresses" +#define NM_NDISC_ROUTER_SOLICITATIONS "router-solicitations" +#define NM_NDISC_ROUTER_SOLICITATION_INTERVAL "router-solicitation-interval" + +#define NM_NDISC_CONFIG_RECEIVED "config-received" +#define NM_NDISC_RA_TIMEOUT "ra-timeout" + +typedef enum { + NM_NDISC_DHCP_LEVEL_UNKNOWN, + NM_NDISC_DHCP_LEVEL_NONE, + NM_NDISC_DHCP_LEVEL_OTHERCONF, + NM_NDISC_DHCP_LEVEL_MANAGED +} NMNDiscDHCPLevel; + +typedef enum { + NM_NDISC_PREFERENCE_INVALID, + NM_NDISC_PREFERENCE_LOW, + NM_NDISC_PREFERENCE_MEDIUM, + NM_NDISC_PREFERENCE_HIGH +} NMNDiscPreference; + +typedef struct { + struct in6_addr address; + guint32 timestamp; + guint32 lifetime; + NMNDiscPreference preference; +} NMNDiscGateway; + +typedef struct { + struct in6_addr address; + guint8 dad_counter; + guint32 timestamp; + guint32 lifetime; + guint32 preferred; +} NMNDiscAddress; + +typedef struct { + struct in6_addr network; + guint8 plen; + struct in6_addr gateway; + guint32 timestamp; + guint32 lifetime; + NMNDiscPreference preference; +} NMNDiscRoute; + +typedef struct { + struct in6_addr address; + guint32 timestamp; + guint32 lifetime; +} NMNDiscDNSServer; + +typedef struct { + char *domain; + guint32 timestamp; + guint32 lifetime; +} NMNDiscDNSDomain; + +typedef enum { + NM_NDISC_CONFIG_DHCP_LEVEL = 1 << 0, + NM_NDISC_CONFIG_GATEWAYS = 1 << 1, + NM_NDISC_CONFIG_ADDRESSES = 1 << 2, + NM_NDISC_CONFIG_ROUTES = 1 << 3, + NM_NDISC_CONFIG_DNS_SERVERS = 1 << 4, + NM_NDISC_CONFIG_DNS_DOMAINS = 1 << 5, + NM_NDISC_CONFIG_HOP_LIMIT = 1 << 6, + NM_NDISC_CONFIG_MTU = 1 << 7, +} NMNDiscConfigMap; + +typedef enum { + NM_NDISC_NODE_TYPE_INVALID, + NM_NDISC_NODE_TYPE_HOST, + NM_NDISC_NODE_TYPE_ROUTER, +} NMNDiscNodeType; + +#define NM_NDISC_MAX_ADDRESSES_DEFAULT 16 +#define NM_NDISC_ROUTER_SOLICITATIONS_DEFAULT 3 /* RFC4861 MAX_RTR_SOLICITATIONS */ +#define NM_NDISC_ROUTER_SOLICITATION_INTERVAL_DEFAULT 4 /* RFC4861 RTR_SOLICITATION_INTERVAL */ +#define NM_NDISC_ROUTER_ADVERTISEMENTS_DEFAULT 3 /* RFC4861 MAX_INITIAL_RTR_ADVERTISEMENTS */ +#define NM_NDISC_ROUTER_ADVERT_DELAY 3 /* RFC4861 MIN_DELAY_BETWEEN_RAS */ +#define NM_NDISC_ROUTER_ADVERT_INITIAL_INTERVAL 16 /* RFC4861 MAX_INITIAL_RTR_ADVERT_INTERVAL */ +#define NM_NDISC_ROUTER_ADVERT_DELAY_MS 500 /* RFC4861 MAX_RA_DELAY_TIME */ +#define NM_NDISC_ROUTER_ADVERT_MAX_INTERVAL 600 /* RFC4861 MaxRtrAdvInterval default */ +#define NM_NDISC_ROUTER_LIFETIME 900 /* 1.5 * NM_NDISC_ROUTER_ADVERT_MAX_INTERVAL */ + +struct _NMNDiscPrivate; +struct _NMNDiscDataInternal; + +typedef struct { + NMNDiscDHCPLevel dhcp_level; + guint32 mtu; + int hop_limit; + + guint gateways_n; + guint addresses_n; + guint routes_n; + guint dns_servers_n; + guint dns_domains_n; + + const NMNDiscGateway *gateways; + const NMNDiscAddress *addresses; + const NMNDiscRoute *routes; + const NMNDiscDNSServer *dns_servers; + const NMNDiscDNSDomain *dns_domains; +} NMNDiscData; + +/** + * NMNDisc: + * + * Interface-specific structure that handles incoming router advertisements, + * caches advertised items and removes them when they are obsolete. + */ +typedef struct { + GObject parent; + union { + struct _NMNDiscPrivate *_priv; + struct _NMNDiscDataInternal *rdata; + }; +} NMNDisc; + +typedef struct { + GObjectClass parent; + + void (*start) (NMNDisc *ndisc); + gboolean (*send_rs) (NMNDisc *ndisc, GError **error); + gboolean (*send_ra) (NMNDisc *ndisc, GError **error); +} NMNDiscClass; + +GType nm_ndisc_get_type (void); + +int nm_ndisc_get_ifindex (NMNDisc *self); +const char *nm_ndisc_get_ifname (NMNDisc *self); +NMNDiscNodeType nm_ndisc_get_node_type (NMNDisc *self); + +gboolean nm_ndisc_set_iid (NMNDisc *ndisc, const NMUtilsIPv6IfaceId iid); +void nm_ndisc_start (NMNDisc *ndisc); +void nm_ndisc_dad_failed (NMNDisc *ndisc, struct in6_addr *address); +void nm_ndisc_set_config (NMNDisc *ndisc, + const GArray *addresses, + const GArray *dns_servers, + const GArray *dns_domains); + +NMPlatform *nm_ndisc_get_platform (NMNDisc *self); +NMPNetns *nm_ndisc_netns_get (NMNDisc *self); +gboolean nm_ndisc_netns_push (NMNDisc *self, NMPNetns **netns); + +#endif /* __NETWORKMANAGER_NDISC_H__ */ diff --git a/src/ndisc/tests/.gitignore b/src/ndisc/tests/.gitignore new file mode 100644 index 0000000000..605f4b0125 --- /dev/null +++ b/src/ndisc/tests/.gitignore @@ -0,0 +1 @@ +/ndisc diff --git a/src/rdisc/tests/test-rdisc-fake.c b/src/ndisc/tests/test-ndisc-fake.c similarity index 60% rename from src/rdisc/tests/test-rdisc-fake.c rename to src/ndisc/tests/test-ndisc-fake.c index 02ffb5100e..dce066eaf8 100644 --- a/src/rdisc/tests/test-rdisc-fake.c +++ b/src/ndisc/tests/test-ndisc-fake.c @@ -1,5 +1,5 @@ /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* rdisc.c - test program +/* ndisc.c - test program * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,32 +23,32 @@ #include #include -#include "nm-rdisc.h" -#include "nm-fake-rdisc.h" +#include "nm-ndisc.h" +#include "nm-fake-ndisc.h" #include "nm-fake-platform.h" #include "nm-test-utils-core.h" -static NMFakeRDisc * -rdisc_new (void) +static NMFakeNDisc * +ndisc_new (void) { - NMRDisc *rdisc; + NMNDisc *ndisc; 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); + ndisc = nm_fake_ndisc_new (ifindex, ifname); iid.id_u8[7] = 1; - nm_rdisc_set_iid (rdisc, iid); - g_assert (rdisc); - return NM_FAKE_RDISC (rdisc); + nm_ndisc_set_iid (ndisc, iid); + g_assert (ndisc); + return NM_FAKE_NDISC (ndisc); } static void -match_gateway (const NMRDiscData *rdata, guint idx, const char *addr, guint32 ts, guint32 lt, NMRDiscPreference pref) +match_gateway (const NMNDiscData *rdata, guint idx, const char *addr, guint32 ts, guint32 lt, NMNDiscPreference pref) { - const NMRDiscGateway *gw; + const NMNDiscGateway *gw; char buf[INET6_ADDRSTRLEN]; g_assert (rdata); @@ -64,9 +64,9 @@ match_gateway (const NMRDiscData *rdata, guint idx, const char *addr, guint32 ts } static void -match_address (const NMRDiscData *rdata, guint idx, const char *addr, guint32 ts, guint32 lt, guint32 preferred) +match_address (const NMNDiscData *rdata, guint idx, const char *addr, guint32 ts, guint32 lt, guint32 preferred) { - const NMRDiscAddress *a; + const NMNDiscAddress *a; char buf[INET6_ADDRSTRLEN]; g_assert (rdata); @@ -82,9 +82,9 @@ match_address (const NMRDiscData *rdata, guint idx, const char *addr, guint32 ts } static void -match_route (const NMRDiscData *rdata, guint idx, const char *nw, int plen, const char *gw, guint32 ts, guint32 lt, NMRDiscPreference pref) +match_route (const NMNDiscData *rdata, guint idx, const char *nw, int plen, const char *gw, guint32 ts, guint32 lt, NMNDiscPreference pref) { - const NMRDiscRoute *route; + const NMNDiscRoute *route; char buf[INET6_ADDRSTRLEN]; g_assert (rdata); @@ -103,9 +103,9 @@ match_route (const NMRDiscData *rdata, guint idx, const char *nw, int plen, cons } static void -match_dns_server (const NMRDiscData *rdata, guint idx, const char *addr, guint32 ts, guint32 lt) +match_dns_server (const NMNDiscData *rdata, guint idx, const char *addr, guint32 ts, guint32 lt) { - const NMRDiscDNSServer *dns; + const NMNDiscDNSServer *dns; char buf[INET6_ADDRSTRLEN]; g_assert (rdata); @@ -120,9 +120,9 @@ match_dns_server (const NMRDiscData *rdata, guint idx, const char *addr, guint32 } static void -match_dns_domain (const NMRDiscData *rdata, guint idx, const char *domain, guint32 ts, guint32 lt) +match_dns_domain (const NMNDiscData *rdata, guint idx, const char *domain, guint32 ts, guint32 lt) { - const NMRDiscDNSDomain *dns; + const NMNDiscDNSDomain *dns; g_assert (rdata); g_assert_cmpint (idx, <, rdata->dns_domains_n); @@ -145,26 +145,26 @@ typedef struct { } TestData; static void -test_simple_changed (NMRDisc *rdisc, const NMRDiscData *rdata, guint changed_int, TestData *data) +test_simple_changed (NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_int, TestData *data) { - NMRDiscConfigMap changed = changed_int; + NMNDiscConfigMap changed = changed_int; - g_assert_cmpint (changed, ==, NM_RDISC_CONFIG_DHCP_LEVEL | - NM_RDISC_CONFIG_GATEWAYS | - NM_RDISC_CONFIG_ADDRESSES | - NM_RDISC_CONFIG_ROUTES | - NM_RDISC_CONFIG_DNS_SERVERS | - NM_RDISC_CONFIG_DNS_DOMAINS | - NM_RDISC_CONFIG_HOP_LIMIT | - NM_RDISC_CONFIG_MTU); - g_assert_cmpint (rdata->dhcp_level, ==, NM_RDISC_DHCP_LEVEL_OTHERCONF); - match_gateway (rdata, 0, "fe80::1", data->timestamp1, 10, NM_RDISC_PREFERENCE_MEDIUM); + g_assert_cmpint (changed, ==, NM_NDISC_CONFIG_DHCP_LEVEL | + NM_NDISC_CONFIG_GATEWAYS | + NM_NDISC_CONFIG_ADDRESSES | + NM_NDISC_CONFIG_ROUTES | + NM_NDISC_CONFIG_DNS_SERVERS | + NM_NDISC_CONFIG_DNS_DOMAINS | + NM_NDISC_CONFIG_HOP_LIMIT | + NM_NDISC_CONFIG_MTU); + g_assert_cmpint (rdata->dhcp_level, ==, NM_NDISC_DHCP_LEVEL_OTHERCONF); + match_gateway (rdata, 0, "fe80::1", data->timestamp1, 10, NM_NDISC_PREFERENCE_MEDIUM); match_address (rdata, 0, "2001:db8:a:a::1", data->timestamp1, 10, 10); match_route (rdata, 0, "2001:db8:a:a::", 64, "fe80::1", data->timestamp1, 10, 10); match_dns_server (rdata, 0, "2001:db8:c:c::1", data->timestamp1, 10); match_dns_domain (rdata, 0, "foobar.com", data->timestamp1, 10); - g_assert (nm_fake_rdisc_done (NM_FAKE_RDISC (rdisc))); + g_assert (nm_fake_ndisc_done (NM_FAKE_NDISC (ndisc))); data->counter++; g_main_loop_quit (data->loop); } @@ -172,67 +172,67 @@ test_simple_changed (NMRDisc *rdisc, const NMRDiscData *rdata, guint changed_int static void test_simple (void) { - NMFakeRDisc *rdisc = rdisc_new (); + NMFakeNDisc *ndisc = ndisc_new (); guint32 now = nm_utils_get_monotonic_timestamp_s (); TestData data = { g_main_loop_new (NULL, FALSE), 0, 0, now }; guint id; - id = nm_fake_rdisc_add_ra (rdisc, 1, NM_RDISC_DHCP_LEVEL_OTHERCONF, 4, 1500); + id = nm_fake_ndisc_add_ra (ndisc, 1, NM_NDISC_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_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); + nm_fake_ndisc_add_gateway (ndisc, id, "fe80::1", now, 10, NM_NDISC_PREFERENCE_MEDIUM); + nm_fake_ndisc_add_prefix (ndisc, id, "2001:db8:a:a::", 64, "fe80::1", now, 10, 10, 10); + nm_fake_ndisc_add_dns_server (ndisc, id, "2001:db8:c:c::1", now, 10); + nm_fake_ndisc_add_dns_domain (ndisc, id, "foobar.com", now, 10); - g_signal_connect (rdisc, - NM_RDISC_CONFIG_CHANGED, + g_signal_connect (ndisc, + NM_NDISC_CONFIG_RECEIVED, G_CALLBACK (test_simple_changed), &data); - nm_rdisc_start (NM_RDISC (rdisc)); + nm_ndisc_start (NM_NDISC (ndisc)); g_main_loop_run (data.loop); g_assert_cmpint (data.counter, ==, 1); - g_object_unref (rdisc); + g_object_unref (ndisc); g_main_loop_unref (data.loop); } static void -test_everything_rs_sent (NMRDisc *rdisc, TestData *data) +test_everything_rs_sent (NMNDisc *ndisc, TestData *data) { g_assert_cmpint (data->rs_counter, ==, 0); data->rs_counter++; } static void -test_everything_changed (NMRDisc *rdisc, const NMRDiscData *rdata, guint changed_int, TestData *data) +test_everything_changed (NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_int, TestData *data) { - NMRDiscConfigMap changed = changed_int; + NMNDiscConfigMap changed = changed_int; if (data->counter == 0) { g_assert_cmpint (data->rs_counter, ==, 1); - g_assert_cmpint (changed, ==, NM_RDISC_CONFIG_DHCP_LEVEL | - NM_RDISC_CONFIG_GATEWAYS | - NM_RDISC_CONFIG_ADDRESSES | - NM_RDISC_CONFIG_ROUTES | - NM_RDISC_CONFIG_DNS_SERVERS | - NM_RDISC_CONFIG_DNS_DOMAINS | - NM_RDISC_CONFIG_HOP_LIMIT | - NM_RDISC_CONFIG_MTU); - match_gateway (rdata, 0, "fe80::1", data->timestamp1, 10, NM_RDISC_PREFERENCE_MEDIUM); + g_assert_cmpint (changed, ==, NM_NDISC_CONFIG_DHCP_LEVEL | + NM_NDISC_CONFIG_GATEWAYS | + NM_NDISC_CONFIG_ADDRESSES | + NM_NDISC_CONFIG_ROUTES | + NM_NDISC_CONFIG_DNS_SERVERS | + NM_NDISC_CONFIG_DNS_DOMAINS | + NM_NDISC_CONFIG_HOP_LIMIT | + NM_NDISC_CONFIG_MTU); + match_gateway (rdata, 0, "fe80::1", data->timestamp1, 10, NM_NDISC_PREFERENCE_MEDIUM); match_address (rdata, 0, "2001:db8:a:a::1", data->timestamp1, 10, 10); match_route (rdata, 0, "2001:db8:a:a::", 64, "fe80::1", data->timestamp1, 10, 10); match_dns_server (rdata, 0, "2001:db8:c:c::1", data->timestamp1, 10); match_dns_domain (rdata, 0, "foobar.com", data->timestamp1, 10); } else if (data->counter == 1) { - g_assert_cmpint (changed, ==, NM_RDISC_CONFIG_GATEWAYS | - NM_RDISC_CONFIG_ADDRESSES | - NM_RDISC_CONFIG_ROUTES | - NM_RDISC_CONFIG_DNS_SERVERS | - NM_RDISC_CONFIG_DNS_DOMAINS); + g_assert_cmpint (changed, ==, NM_NDISC_CONFIG_GATEWAYS | + NM_NDISC_CONFIG_ADDRESSES | + NM_NDISC_CONFIG_ROUTES | + NM_NDISC_CONFIG_DNS_SERVERS | + NM_NDISC_CONFIG_DNS_DOMAINS); g_assert_cmpint (rdata->gateways_n, ==, 1); - match_gateway (rdata, 0, "fe80::2", data->timestamp1, 10, NM_RDISC_PREFERENCE_MEDIUM); + match_gateway (rdata, 0, "fe80::2", data->timestamp1, 10, NM_NDISC_PREFERENCE_MEDIUM); g_assert_cmpint (rdata->addresses_n, ==, 1); match_address (rdata, 0, "2001:db8:a:b::1", data->timestamp1, 10, 10); g_assert_cmpint (rdata->routes_n, ==, 1); @@ -242,7 +242,7 @@ test_everything_changed (NMRDisc *rdisc, const NMRDiscData *rdata, guint changed g_assert_cmpint (rdata->dns_domains_n, ==, 1); match_dns_domain (rdata, 0, "foobar2.com", data->timestamp1, 10); - g_assert (nm_fake_rdisc_done (NM_FAKE_RDISC (rdisc))); + g_assert (nm_fake_ndisc_done (NM_FAKE_NDISC (ndisc))); g_main_loop_quit (data->loop); } else g_assert_not_reached (); @@ -253,62 +253,62 @@ test_everything_changed (NMRDisc *rdisc, const NMRDiscData *rdata, guint changed static void test_everything (void) { - NMFakeRDisc *rdisc = rdisc_new (); + NMFakeNDisc *ndisc = ndisc_new (); guint32 now = nm_utils_get_monotonic_timestamp_s (); TestData data = { g_main_loop_new (NULL, FALSE), 0, 0, now }; guint id; - id = nm_fake_rdisc_add_ra (rdisc, 1, NM_RDISC_DHCP_LEVEL_NONE, 4, 1500); + id = nm_fake_ndisc_add_ra (ndisc, 1, NM_NDISC_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_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); + nm_fake_ndisc_add_gateway (ndisc, id, "fe80::1", now, 10, NM_NDISC_PREFERENCE_MEDIUM); + nm_fake_ndisc_add_prefix (ndisc, id, "2001:db8:a:a::", 64, "fe80::1", now, 10, 10, 10); + nm_fake_ndisc_add_dns_server (ndisc, id, "2001:db8:c:c::1", now, 10); + nm_fake_ndisc_add_dns_domain (ndisc, id, "foobar.com", now, 10); /* expire everything from the first RA in the second */ - id = nm_fake_rdisc_add_ra (rdisc, 1, NM_RDISC_DHCP_LEVEL_NONE, 4, 1500); + id = nm_fake_ndisc_add_ra (ndisc, 1, NM_NDISC_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_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); + nm_fake_ndisc_add_gateway (ndisc, id, "fe80::1", now, 0, NM_NDISC_PREFERENCE_MEDIUM); + nm_fake_ndisc_add_prefix (ndisc, id, "2001:db8:a:a::", 64, "fe80::1", now, 0, 0, 0); + nm_fake_ndisc_add_dns_server (ndisc, id, "2001:db8:c:c::1", now, 0); + nm_fake_ndisc_add_dns_domain (ndisc, 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_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); + nm_fake_ndisc_add_gateway (ndisc, id, "fe80::2", now, 10, NM_NDISC_PREFERENCE_MEDIUM); + nm_fake_ndisc_add_prefix (ndisc, id, "2001:db8:a:b::", 64, "fe80::2", now, 10, 10, 10); + nm_fake_ndisc_add_dns_server (ndisc, id, "2001:db8:c:c::2", now, 10); + nm_fake_ndisc_add_dns_domain (ndisc, id, "foobar2.com", now, 10); - g_signal_connect (rdisc, - NM_RDISC_CONFIG_CHANGED, + g_signal_connect (ndisc, + NM_NDISC_CONFIG_RECEIVED, G_CALLBACK (test_everything_changed), &data); - g_signal_connect (rdisc, - NM_FAKE_RDISC_RS_SENT, + g_signal_connect (ndisc, + NM_FAKE_NDISC_RS_SENT, G_CALLBACK (test_everything_rs_sent), &data); - nm_rdisc_start (NM_RDISC (rdisc)); + nm_ndisc_start (NM_NDISC (ndisc)); g_main_loop_run (data.loop); g_assert_cmpint (data.counter, ==, 2); g_assert_cmpint (data.rs_counter, ==, 1); - g_object_unref (rdisc); + g_object_unref (ndisc); g_main_loop_unref (data.loop); } static void -test_preference_changed (NMRDisc *rdisc, const NMRDiscData *rdata, guint changed_int, TestData *data) +test_preference_changed (NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_int, TestData *data) { - NMRDiscConfigMap changed = changed_int; + NMNDiscConfigMap changed = changed_int; if (data->counter == 1) { - g_assert_cmpint (changed, ==, NM_RDISC_CONFIG_GATEWAYS | - NM_RDISC_CONFIG_ADDRESSES | - NM_RDISC_CONFIG_ROUTES); + g_assert_cmpint (changed, ==, NM_NDISC_CONFIG_GATEWAYS | + NM_NDISC_CONFIG_ADDRESSES | + NM_NDISC_CONFIG_ROUTES); g_assert_cmpint (rdata->gateways_n, ==, 2); - match_gateway (rdata, 0, "fe80::2", data->timestamp1 + 1, 10, NM_RDISC_PREFERENCE_MEDIUM); - match_gateway (rdata, 1, "fe80::1", data->timestamp1, 10, NM_RDISC_PREFERENCE_LOW); + match_gateway (rdata, 0, "fe80::2", data->timestamp1 + 1, 10, NM_NDISC_PREFERENCE_MEDIUM); + match_gateway (rdata, 1, "fe80::1", data->timestamp1, 10, NM_NDISC_PREFERENCE_LOW); g_assert_cmpint (rdata->addresses_n, ==, 2); match_address (rdata, 0, "2001:db8:a:a::1", data->timestamp1, 10, 10); match_address (rdata, 1, "2001:db8:a:b::1", data->timestamp1 + 1, 10, 10); @@ -316,13 +316,13 @@ test_preference_changed (NMRDisc *rdisc, const NMRDiscData *rdata, guint changed match_route (rdata, 0, "2001:db8:a:b::", 64, "fe80::2", data->timestamp1 + 1, 10, 10); match_route (rdata, 1, "2001:db8:a:a::", 64, "fe80::1", data->timestamp1, 10, 5); } else if (data->counter == 2) { - g_assert_cmpint (changed, ==, NM_RDISC_CONFIG_GATEWAYS | - NM_RDISC_CONFIG_ADDRESSES | - NM_RDISC_CONFIG_ROUTES); + g_assert_cmpint (changed, ==, NM_NDISC_CONFIG_GATEWAYS | + NM_NDISC_CONFIG_ADDRESSES | + NM_NDISC_CONFIG_ROUTES); g_assert_cmpint (rdata->gateways_n, ==, 2); - match_gateway (rdata, 0, "fe80::1", data->timestamp1 + 2, 10, NM_RDISC_PREFERENCE_HIGH); - match_gateway (rdata, 1, "fe80::2", data->timestamp1 + 1, 10, NM_RDISC_PREFERENCE_MEDIUM); + match_gateway (rdata, 0, "fe80::1", data->timestamp1 + 2, 10, NM_NDISC_PREFERENCE_HIGH); + match_gateway (rdata, 1, "fe80::2", data->timestamp1 + 1, 10, NM_NDISC_PREFERENCE_MEDIUM); g_assert_cmpint (rdata->addresses_n, ==, 2); match_address (rdata, 0, "2001:db8:a:a::1", data->timestamp1 + 2, 10, 10); match_address (rdata, 1, "2001:db8:a:b::1", data->timestamp1 + 1, 10, 10); @@ -330,7 +330,7 @@ test_preference_changed (NMRDisc *rdisc, const NMRDiscData *rdata, guint changed match_route (rdata, 0, "2001:db8:a:a::", 64, "fe80::1", data->timestamp1 + 2, 10, 15); match_route (rdata, 1, "2001:db8:a:b::", 64, "fe80::2", data->timestamp1 + 1, 10, 10); - g_assert (nm_fake_rdisc_done (NM_FAKE_RDISC (rdisc))); + g_assert (nm_fake_ndisc_done (NM_FAKE_NDISC (ndisc))); g_main_loop_quit (data->loop); } @@ -340,7 +340,7 @@ test_preference_changed (NMRDisc *rdisc, const NMRDiscData *rdata, guint changed static void test_preference (void) { - NMFakeRDisc *rdisc = rdisc_new (); + NMFakeNDisc *ndisc = ndisc_new (); guint32 now = nm_utils_get_monotonic_timestamp_s (); TestData data = { g_main_loop_new (NULL, FALSE), 0, 0, now }; guint id; @@ -350,36 +350,36 @@ test_preference (void) * not get duplicates in the gateway list. */ - id = nm_fake_rdisc_add_ra (rdisc, 1, NM_RDISC_DHCP_LEVEL_NONE, 4, 1500); + id = nm_fake_ndisc_add_ra (ndisc, 1, NM_NDISC_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_prefix (rdisc, id, "2001:db8:a:a::", 64, "fe80::1", now, 10, 10, 5); + nm_fake_ndisc_add_gateway (ndisc, id, "fe80::1", now, 10, NM_NDISC_PREFERENCE_LOW); + nm_fake_ndisc_add_prefix (ndisc, 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); + id = nm_fake_ndisc_add_ra (ndisc, 1, NM_NDISC_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_prefix (rdisc, id, "2001:db8:a:b::", 64, "fe80::2", now, 10, 10, 10); + nm_fake_ndisc_add_gateway (ndisc, id, "fe80::2", ++now, 10, NM_NDISC_PREFERENCE_MEDIUM); + nm_fake_ndisc_add_prefix (ndisc, 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); + id = nm_fake_ndisc_add_ra (ndisc, 1, NM_NDISC_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_prefix (rdisc, id, "2001:db8:a:a::", 64, "fe80::1", now, 10, 10, 15); + nm_fake_ndisc_add_gateway (ndisc, id, "fe80::1", ++now, 10, NM_NDISC_PREFERENCE_HIGH); + nm_fake_ndisc_add_prefix (ndisc, id, "2001:db8:a:a::", 64, "fe80::1", now, 10, 10, 15); - g_signal_connect (rdisc, - NM_RDISC_CONFIG_CHANGED, + g_signal_connect (ndisc, + NM_NDISC_CONFIG_RECEIVED, G_CALLBACK (test_preference_changed), &data); - nm_rdisc_start (NM_RDISC (rdisc)); + nm_ndisc_start (NM_NDISC (ndisc)); g_main_loop_run (data.loop); g_assert_cmpint (data.counter, ==, 3); - g_object_unref (rdisc); + g_object_unref (ndisc); g_main_loop_unref (data.loop); } static void -test_dns_solicit_loop_changed (NMRDisc *rdisc, const NMRDiscData *rdata, guint changed_int, TestData *data) +test_dns_solicit_loop_changed (NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_int, TestData *data) { data->counter++; } @@ -393,7 +393,7 @@ success_timeout (TestData *data) } static void -test_dns_solicit_loop_rs_sent (NMFakeRDisc *rdisc, TestData *data) +test_dns_solicit_loop_rs_sent (NMFakeNDisc *ndisc, TestData *data) { guint32 now = nm_utils_get_monotonic_timestamp_s (); guint id; @@ -409,11 +409,11 @@ test_dns_solicit_loop_rs_sent (NMFakeRDisc *rdisc, TestData *data) * DNS servers reaching 1/2 lifetime, emit a new RA without the DNS * servers again. */ - id = nm_fake_rdisc_add_ra (rdisc, 0, NM_RDISC_DHCP_LEVEL_NONE, 4, 1500); + id = nm_fake_ndisc_add_ra (ndisc, 0, NM_NDISC_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_ndisc_add_gateway (ndisc, id, "fe80::1", now, 10, NM_NDISC_PREFERENCE_MEDIUM); - nm_fake_rdisc_emit_new_ras (rdisc); + nm_fake_ndisc_emit_new_ras (ndisc); } else if (data->rs_counter >= 6) { /* Fail if we've sent too many solicitations in the past 4 seconds */ g_assert_cmpint (now - data->first_solicit, >, 4); @@ -426,7 +426,7 @@ test_dns_solicit_loop_rs_sent (NMFakeRDisc *rdisc, TestData *data) static void test_dns_solicit_loop (void) { - NMFakeRDisc *rdisc = rdisc_new (); + NMFakeNDisc *ndisc = ndisc_new (); guint32 now = nm_utils_get_monotonic_timestamp_s (); TestData data = { g_main_loop_new (NULL, FALSE), 0, 0, now, 0 }; guint id; @@ -438,25 +438,25 @@ test_dns_solicit_loop (void) * first. */ - id = nm_fake_rdisc_add_ra (rdisc, 1, NM_RDISC_DHCP_LEVEL_NONE, 4, 1500); + id = nm_fake_ndisc_add_ra (ndisc, 1, NM_NDISC_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_dns_server (rdisc, id, "2001:db8:c:c::1", now, 6); + nm_fake_ndisc_add_gateway (ndisc, id, "fe80::1", now, 10, NM_NDISC_PREFERENCE_LOW); + nm_fake_ndisc_add_dns_server (ndisc, id, "2001:db8:c:c::1", now, 6); - g_signal_connect (rdisc, - NM_RDISC_CONFIG_CHANGED, + g_signal_connect (ndisc, + NM_NDISC_CONFIG_RECEIVED, G_CALLBACK (test_dns_solicit_loop_changed), &data); - g_signal_connect (rdisc, - NM_FAKE_RDISC_RS_SENT, + g_signal_connect (ndisc, + NM_FAKE_NDISC_RS_SENT, G_CALLBACK (test_dns_solicit_loop_rs_sent), &data); - nm_rdisc_start (NM_RDISC (rdisc)); + nm_ndisc_start (NM_NDISC (ndisc)); g_main_loop_run (data.loop); g_assert_cmpint (data.counter, ==, 3); - g_object_unref (rdisc); + g_object_unref (ndisc); g_main_loop_unref (data.loop); } @@ -468,16 +468,16 @@ main (int argc, char **argv) nmtst_init_with_logging (&argc, &argv, NULL, "DEFAULT"); if (nmtst_test_quick ()) { - g_print ("Skipping test: don't run long running test %s (NMTST_DEBUG=slow)\n", g_get_prgname () ?: "test-rdisc-fake"); + g_print ("Skipping test: don't run long running test %s (NMTST_DEBUG=slow)\n", g_get_prgname () ?: "test-ndisc-fake"); return g_test_run (); } nm_fake_platform_setup (); - g_test_add_func ("/rdisc/simple", test_simple); - g_test_add_func ("/rdisc/everything-changed", test_everything); - g_test_add_func ("/rdisc/preference-changed", test_preference); - g_test_add_func ("/rdisc/dns-solicit-loop", test_dns_solicit_loop); + g_test_add_func ("/ndisc/simple", test_simple); + g_test_add_func ("/ndisc/everything-changed", test_everything); + g_test_add_func ("/ndisc/preference-changed", test_preference); + g_test_add_func ("/ndisc/dns-solicit-loop", test_dns_solicit_loop); return g_test_run (); } diff --git a/src/rdisc/tests/test-rdisc-linux.c b/src/ndisc/tests/test-ndisc-linux.c similarity index 84% rename from src/rdisc/tests/test-rdisc-linux.c rename to src/ndisc/tests/test-ndisc-linux.c index 299abf3eeb..e621eba952 100644 --- a/src/rdisc/tests/test-rdisc-linux.c +++ b/src/ndisc/tests/test-ndisc-linux.c @@ -1,5 +1,5 @@ /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* rdisc.c - test program +/* ndisc.c - test program * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,8 +23,8 @@ #include #include -#include "nm-rdisc.h" -#include "nm-lndp-rdisc.h" +#include "nm-ndisc.h" +#include "nm-lndp-ndisc.h" #include "nm-linux-platform.h" @@ -36,7 +36,7 @@ int main (int argc, char **argv) { GMainLoop *loop; - NMRDisc *rdisc; + NMNDisc *ndisc; int ifindex = 1; const char *ifname; NMUtilsIPv6IfaceId iid = { }; @@ -61,25 +61,26 @@ main (int argc, char **argv) return EXIT_FAILURE; } - rdisc = nm_lndp_rdisc_new (NM_PLATFORM_GET, + ndisc = nm_lndp_ndisc_new (NM_PLATFORM_GET, ifindex, ifname, NM_UTILS_STABLE_TYPE_UUID, "8ce666e8-d34d-4fb1-b858-f15a7al28086", NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64, + NM_NDISC_NODE_TYPE_HOST, &error); - if (!rdisc) { - g_print ("Failed to create NMRDisc instance: %s\n", error->message); + if (!ndisc) { + g_print ("Failed to create NMNDisc instance: %s\n", error->message); g_error_free (error); return EXIT_FAILURE; } iid.id_u8[7] = 1; - nm_rdisc_set_iid (rdisc, iid); - nm_rdisc_start (rdisc); + nm_ndisc_set_iid (ndisc, iid); + nm_ndisc_start (ndisc); g_main_loop_run (loop); - g_clear_object (&rdisc); + g_clear_object (&ndisc); return EXIT_SUCCESS; } diff --git a/src/nm-core-utils.c b/src/nm-core-utils.c index c48bf6cd45..d4d9be5bc8 100644 --- a/src/nm-core-utils.c +++ b/src/nm-core-utils.c @@ -3511,14 +3511,15 @@ nm_utils_lifetime_get (guint32 timestamp, nm_assert (now >= 0); - if (lifetime == 0) { + if (timestamp == 0 && lifetime == 0) { + /* We treat lifetime==0 && timestamp == 0 addresses as permanent addresses to allow easy + * creation of such addresses (without requiring to set the lifetime fields to + * NM_PLATFORM_LIFETIME_PERMANENT). The real lifetime==0 addresses (E.g. DHCP6 telling us + * to drop an address will have timestamp set. + */ *out_lifetime = NM_PLATFORM_LIFETIME_PERMANENT; *out_preferred = NM_PLATFORM_LIFETIME_PERMANENT; - - /* We treat lifetime==0 as permanent addresses to allow easy creation of such addresses - * (without requiring to set the lifetime fields to NM_PLATFORM_LIFETIME_PERMANENT). - * In that case we also expect that the other fields (timestamp and preferred) are left unset. */ - g_return_val_if_fail (timestamp == 0 && preferred == 0, TRUE); + g_return_val_if_fail (preferred == 0, TRUE); } else { if (now <= 0) now = nm_utils_get_monotonic_timestamp_s (); diff --git a/src/nm-iface-helper.c b/src/nm-iface-helper.c index a64f876126..cd437752fd 100644 --- a/src/nm-iface-helper.c +++ b/src/nm-iface-helper.c @@ -40,8 +40,8 @@ extern unsigned int if_nametoindex (const char *__ifname); #include "NetworkManagerUtils.h" #include "nm-linux-platform.h" #include "nm-dhcp-manager.h" -#include "nm-rdisc.h" -#include "nm-lndp-rdisc.h" +#include "nm-ndisc.h" +#include "nm-lndp-ndisc.h" #include "nm-utils.h" #include "nm-setting-ip6-config.h" #include "systemd/nm-sd.h" @@ -146,10 +146,10 @@ dhcp4_state_changed (NMDhcpClient *client, } static void -rdisc_config_changed (NMRDisc *rdisc, const NMRDiscData *rdata, guint changed_int, gpointer user_data) +ndisc_config_changed (NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_int, gpointer user_data) { - NMRDiscConfigMap changed = changed_int; - static NMIP6Config *rdisc_config = NULL; + NMNDiscConfigMap changed = changed_int; + static NMIP6Config *ndisc_config = NULL; NMIP6Config *existing; static int system_support = -1; guint32 ifa_flags = 0x00; @@ -176,30 +176,30 @@ rdisc_config_changed (NMRDisc *rdisc, const NMRDiscData *rdata, guint changed_in } existing = nm_ip6_config_capture (gl.ifindex, FALSE, global_opt.tempaddr); - if (rdisc_config) - nm_ip6_config_subtract (existing, rdisc_config); + if (ndisc_config) + nm_ip6_config_subtract (existing, ndisc_config); else - rdisc_config = nm_ip6_config_new (gl.ifindex); + ndisc_config = nm_ip6_config_new (gl.ifindex); - if (changed & NM_RDISC_CONFIG_GATEWAYS) { - /* Use the first gateway as ordered in router discovery cache. */ + if (changed & NM_NDISC_CONFIG_GATEWAYS) { + /* Use the first gateway as ordered in neighbor discovery cache. */ if (rdata->gateways_n) - nm_ip6_config_set_gateway (rdisc_config, &rdata->gateways[0].address); + nm_ip6_config_set_gateway (ndisc_config, &rdata->gateways[0].address); else - nm_ip6_config_set_gateway (rdisc_config, NULL); + nm_ip6_config_set_gateway (ndisc_config, NULL); } - if (changed & NM_RDISC_CONFIG_ADDRESSES) { - /* Rebuild address list from router discovery cache. */ - nm_ip6_config_reset_addresses (rdisc_config); + if (changed & NM_NDISC_CONFIG_ADDRESSES) { + /* Rebuild address list from neighbor discovery cache. */ + nm_ip6_config_reset_addresses (ndisc_config); - /* rdisc->addresses contains at most max_addresses entries. + /* ndisc->addresses contains at most max_addresses entries. * This is different from what the kernel does, which * also counts static and temporary addresses when checking * max_addresses. **/ for (i = 0; i < rdata->addresses_n; i++) { - const NMRDiscAddress *discovered_address = &rdata->addresses[i]; + const NMNDiscAddress *discovered_address = &rdata->addresses[i]; NMPlatformIP6Address address; memset (&address, 0, sizeof (address)); @@ -210,52 +210,52 @@ rdisc_config_changed (NMRDisc *rdisc, const NMRDiscData *rdata, guint changed_in address.preferred = discovered_address->preferred; if (address.preferred > address.lifetime) address.preferred = address.lifetime; - address.addr_source = NM_IP_CONFIG_SOURCE_RDISC; + address.addr_source = NM_IP_CONFIG_SOURCE_NDISC; address.n_ifa_flags = ifa_flags; - nm_ip6_config_add_address (rdisc_config, &address); + nm_ip6_config_add_address (ndisc_config, &address); } } - if (changed & NM_RDISC_CONFIG_ROUTES) { - /* Rebuild route list from router discovery cache. */ - nm_ip6_config_reset_routes (rdisc_config); + if (changed & NM_NDISC_CONFIG_ROUTES) { + /* Rebuild route list from neighbor discovery cache. */ + nm_ip6_config_reset_routes (ndisc_config); for (i = 0; i < rdata->routes_n; i++) { - const NMRDiscRoute *discovered_route = &rdata->routes[i]; + const NMNDiscRoute *discovered_route = &rdata->routes[i]; const NMPlatformIP6Route route = { .network = discovered_route->network, .plen = discovered_route->plen, .gateway = discovered_route->gateway, - .rt_source = NM_IP_CONFIG_SOURCE_RDISC, + .rt_source = NM_IP_CONFIG_SOURCE_NDISC, .metric = global_opt.priority_v6, }; - nm_ip6_config_add_route (rdisc_config, &route); + nm_ip6_config_add_route (ndisc_config, &route); } } - if (changed & NM_RDISC_CONFIG_DHCP_LEVEL) { + if (changed & NM_NDISC_CONFIG_DHCP_LEVEL) { /* Unsupported until systemd DHCPv6 is ready */ } - if (changed & NM_RDISC_CONFIG_HOP_LIMIT) + if (changed & NM_NDISC_CONFIG_HOP_LIMIT) nm_platform_sysctl_set_ip6_hop_limit_safe (NM_PLATFORM_GET, global_opt.ifname, rdata->hop_limit); - if (changed & NM_RDISC_CONFIG_MTU) { + if (changed & NM_NDISC_CONFIG_MTU) { char val[16]; g_snprintf (val, sizeof (val), "%d", rdata->mtu); nm_platform_sysctl_set (NM_PLATFORM_GET, nm_utils_ip6_property_path (global_opt.ifname, "mtu"), val); } - nm_ip6_config_merge (existing, rdisc_config, NM_IP_CONFIG_MERGE_DEFAULT); + nm_ip6_config_merge (existing, ndisc_config, NM_IP_CONFIG_MERGE_DEFAULT); if (!nm_ip6_config_commit (existing, gl.ifindex, TRUE)) _LOGW (LOGD_IP6, "failed to apply IPv6 config"); } static void -rdisc_ra_timeout (NMRDisc *rdisc, gpointer user_data) +ndisc_ra_timeout (NMNDisc *ndisc, gpointer user_data) { if (global_opt.slaac_required) { _LOGW (LOGD_IP6, "IPv6 timed out or failed, quitting..."); @@ -337,13 +337,13 @@ ip6_address_changed (NMPlatform *platform, int iface, NMPlatformIP6Address *addr, int change_type_i, - NMRDisc *rdisc) + NMNDisc *ndisc) { const NMPlatformSignalChangeType change_type = change_type_i; if ( (change_type == NM_PLATFORM_SIGNAL_CHANGED && addr->n_ifa_flags & IFA_F_DADFAILED) || (change_type == NM_PLATFORM_SIGNAL_REMOVED && addr->n_ifa_flags & IFA_F_TENTATIVE)) - nm_rdisc_dad_failed (rdisc, &addr->address); + nm_ndisc_dad_failed (ndisc, &addr->address); } int @@ -354,7 +354,7 @@ main (int argc, char *argv[]) gboolean wrote_pidfile = FALSE; gs_free char *pidfile = NULL; gs_unref_object NMDhcpClient *dhcp4_client = NULL; - gs_unref_object NMRDisc *rdisc = NULL; + gs_unref_object NMNDisc *ndisc = NULL; GByteArray *hwaddr = NULL; size_t hwaddr_len = 0; gconstpointer tmp; @@ -502,13 +502,15 @@ main (int argc, char *argv[]) stable_type = (global_opt.stable_id[0] - '0'); stable_id = &global_opt.stable_id[2]; } - rdisc = nm_lndp_rdisc_new (NM_PLATFORM_GET, gl.ifindex, global_opt.ifname, + ndisc = nm_lndp_ndisc_new (NM_PLATFORM_GET, gl.ifindex, global_opt.ifname, stable_type, stable_id, - global_opt.addr_gen_mode, NULL); - g_assert (rdisc); + global_opt.addr_gen_mode, + NM_NDISC_NODE_TYPE_HOST, + NULL); + g_assert (ndisc); if (iid) - nm_rdisc_set_iid (rdisc, *iid); + nm_ndisc_set_iid (ndisc, *iid); nm_platform_sysctl_set (NM_PLATFORM_GET, nm_utils_ip6_property_path (global_opt.ifname, "accept_ra"), "1"); nm_platform_sysctl_set (NM_PLATFORM_GET, nm_utils_ip6_property_path (global_opt.ifname, "accept_ra_defrtr"), "0"); @@ -518,16 +520,16 @@ main (int argc, char *argv[]) g_signal_connect (NM_PLATFORM_GET, NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED, G_CALLBACK (ip6_address_changed), - rdisc); - g_signal_connect (rdisc, - NM_RDISC_CONFIG_CHANGED, - G_CALLBACK (rdisc_config_changed), + ndisc); + g_signal_connect (ndisc, + NM_NDISC_CONFIG_RECEIVED, + G_CALLBACK (ndisc_config_changed), NULL); - g_signal_connect (rdisc, - NM_RDISC_RA_TIMEOUT, - G_CALLBACK (rdisc_ra_timeout), + g_signal_connect (ndisc, + NM_NDISC_RA_TIMEOUT, + G_CALLBACK (ndisc_ra_timeout), NULL); - nm_rdisc_start (rdisc); + nm_ndisc_start (ndisc); } sd_id = nm_sd_event_attach_default (); diff --git a/src/nm-manager.c b/src/nm-manager.c index 61f7404712..e6b60d1863 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -3404,18 +3404,6 @@ validate_activation_request (NMManager *self, goto error; } - /* Not implemented yet, we want to fail early */ - if ( nm_connection_get_setting_connection (connection) - && nm_connection_get_setting_ip6_config (connection) - && !strcmp (nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP6_CONFIG), - NM_SETTING_IP6_CONFIG_METHOD_SHARED)) { - g_set_error_literal (error, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_CONNECTION_NOT_AVAILABLE, - "Sharing IPv6 connections is not supported yet."); - goto error; - } - /* Check whether it's a VPN or not */ if ( nm_connection_get_setting_vpn (connection) || nm_connection_is_type (connection, NM_SETTING_VPN_SETTING_NAME)) diff --git a/src/nm-policy.c b/src/nm-policy.c index 6993438cf0..8be0dbcf7e 100644 --- a/src/nm-policy.c +++ b/src/nm-policy.c @@ -88,6 +88,8 @@ typedef struct { char *orig_hostname; /* hostname at NM start time */ char *cur_hostname; /* hostname we want to assign */ gboolean hostname_changed; /* TRUE if NM ever set the hostname */ + + GArray *ip6_prefix_delegations; /* pool of ip6 prefixes delegated to all devices */ } NMPolicyPrivate; struct _NMPolicy { @@ -133,6 +135,236 @@ static void schedule_activate_all (NMPolicy *self); /*****************************************************************************/ +typedef struct { + NMPlatformIP6Address prefix; + NMDevice *device; /* The requesting ("uplink") device */ + guint64 next_subnet; /* Cache of the next subnet number to be + * assigned from this prefix */ + GHashTable *subnets; /* ifindex -> NMPlatformIP6Address */ +} IP6PrefixDelegation; + +static void +_clear_ip6_subnet (gpointer key, gpointer value, gpointer user_data) +{ + NMPlatformIP6Address *subnet = value; + NMDevice *device = nm_manager_get_device_by_ifindex (nm_manager_get (), + GPOINTER_TO_INT (key)); + + if (!device) + return; + + /* We can not remove a subnet we already started announcing. + * Just un-prefer it. */ + subnet->preferred = 0; + nm_device_use_ip6_subnet (device, subnet); + g_slice_free (NMPlatformIP6Address, subnet); +} + +static void +clear_ip6_prefix_delegation (gpointer data) +{ + IP6PrefixDelegation *delegation = data; + + _LOGD (LOGD_IP6, "ipv6-pd: undelegating prefix %s/%d", + nm_utils_inet6_ntop (&delegation->prefix.address, NULL), + delegation->prefix.plen); + + g_hash_table_foreach (delegation->subnets, _clear_ip6_subnet, NULL); + g_hash_table_destroy (delegation->subnets); +} + +static void +expire_ip6_delegations (NMPolicy *self) +{ + NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); + guint32 now = nm_utils_get_monotonic_timestamp_s (); + IP6PrefixDelegation *delegation = NULL; + int i; + + for (i = 0; i < priv->ip6_prefix_delegations->len; i++) { + delegation = &g_array_index (priv->ip6_prefix_delegations, + IP6PrefixDelegation, i); + if (delegation->prefix.timestamp + delegation->prefix.lifetime < now) + g_array_remove_index_fast (priv->ip6_prefix_delegations, i); + } +} + +/* + * Try to obtain a new subnet for a particular active connection from given + * delegated prefix, possibly reusing the existing subnet. + * Return value of FALSE indicates no more subnets are available from + * this prefix (and other prefix should be used -- and requested if necessary). + */ +static gboolean +ip6_subnet_from_delegation (IP6PrefixDelegation *delegation, NMDevice *device) +{ + NMPlatformIP6Address *subnet; + int ifindex = nm_device_get_ifindex (device); + + subnet = g_hash_table_lookup (delegation->subnets, GINT_TO_POINTER (ifindex)); + if (!subnet) { + /* Check for out-of-prefixes condition. */ + if (delegation->next_subnet >= (1 << (64 - delegation->prefix.plen))) { + _LOGD (LOGD_IP6, "ipv6-pd: no more prefixes in %s/%d", + nm_utils_inet6_ntop (&delegation->prefix.address, NULL), + delegation->prefix.plen); + return FALSE; + } + + /* Allocate a new subnet. */ + subnet = g_slice_new0 (NMPlatformIP6Address); + g_hash_table_insert (delegation->subnets, GINT_TO_POINTER (ifindex), subnet); + + subnet->plen = 64; + subnet->address.s6_addr32[0] = delegation->prefix.address.s6_addr32[0] + | htonl (delegation->next_subnet >> 32); + subnet->address.s6_addr32[1] = delegation->prefix.address.s6_addr32[1] + | htonl (delegation->next_subnet); + + /* Out subnet pool management is pretty unsophisticated. We only add + * the subnets and index them by ifindex. That keeps the implementation + * simple and the dead entries make it easy to reuse the same subnet on + * subsequent activations. On the other hand they may waste the subnet + * space. */ + delegation->next_subnet++; + } + + subnet->timestamp = delegation->prefix.timestamp; + subnet->lifetime = delegation->prefix.lifetime; + subnet->preferred = delegation->prefix.preferred; + + _LOGD (LOGD_IP6, "ipv6-pd: %s allocated from a /%d prefix on %s", + nm_utils_inet6_ntop (&subnet->address, NULL), + delegation->prefix.plen, + nm_device_get_iface (device)); + + nm_device_use_ip6_subnet (device, subnet); + + return TRUE; +} + +/* + * Try to obtain a subnet from each prefix delegated to given requesting + * ("uplink") device and assign it to the downlink device. + * Requests a new prefix if no subnet could be found. + */ +static void +ip6_subnet_from_device (NMPolicy *self, NMDevice *from_device, NMDevice *device) +{ + NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); + IP6PrefixDelegation *delegation = NULL; + gboolean got_subnet = FALSE; + int have_prefixes = 0; + int i; + + expire_ip6_delegations (self); + + for (i = 0; i < priv->ip6_prefix_delegations->len; i++) { + delegation = &g_array_index (priv->ip6_prefix_delegations, + IP6PrefixDelegation, i); + + if (delegation->device != from_device) + continue; + + if (ip6_subnet_from_delegation (delegation, device)) + got_subnet = TRUE; + have_prefixes++; + } + + if (!got_subnet) { + _LOGI (LOGD_IP6, "ipv6-pd: none of %d prefixes of %s can be shared on %s", + have_prefixes, nm_device_get_iface (from_device), + nm_device_get_iface (device)); + nm_device_request_ip6_prefixes (from_device, have_prefixes + 1); + } +} + +static void +ip6_remove_device_prefix_delegations (NMPolicy *self, NMDevice *device) +{ + NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); + IP6PrefixDelegation *delegation = NULL; + int i; + + for (i = 0; i < priv->ip6_prefix_delegations->len; i++) { + delegation = &g_array_index (priv->ip6_prefix_delegations, + IP6PrefixDelegation, i); + if (delegation->device == device) + g_array_remove_index_fast (priv->ip6_prefix_delegations, i); + } +} + +static void +device_ip6_prefix_delegated (NMDevice *device, + NMPlatformIP6Address *prefix, + gpointer user_data) +{ + NMPolicyPrivate *priv = user_data; + NMPolicy *self = _PRIV_TO_SELF (priv); + IP6PrefixDelegation *delegation = NULL; + const GSList *connections, *iter; + int i; + + _LOGI (LOGD_IP6, "ipv6-pd: received a prefix %s/%d from %s", + nm_utils_inet6_ntop (&prefix->address, NULL), + prefix->plen, + nm_device_get_iface (device)); + + expire_ip6_delegations (self); + + for (i = 0; i < priv->ip6_prefix_delegations->len; i++) { + /* Look for an already known prefix to update. */ + delegation = &g_array_index (priv->ip6_prefix_delegations, IP6PrefixDelegation, i); + if (IN6_ARE_ADDR_EQUAL (&delegation->prefix.address, &prefix->address)) + break; + } + + if (i == priv->ip6_prefix_delegations->len) { + /* Allocate a delegation delegation for new prefix. */ + g_array_set_size (priv->ip6_prefix_delegations, i + 1); + delegation = &g_array_index (priv->ip6_prefix_delegations, IP6PrefixDelegation, i); + delegation->subnets = g_hash_table_new (NULL, NULL); + delegation->next_subnet = 0; + } + + delegation->device = device; + delegation->prefix = *prefix; + + /* The newly activated connections are added to the list beginning, + * so traversing it from the beginning makes it likely for newly + * activated connections that have no subnet assigned to be served + * first. That is a simple yet fair policy, which is good. */ + connections = nm_manager_get_active_connections (priv->manager); + for (iter = connections; iter; iter = g_slist_next (iter)) { + NMDevice *to_device = nm_active_connection_get_device (iter->data); + + if (nm_device_needs_ip6_subnet (to_device)) + ip6_subnet_from_delegation (delegation, to_device); + } +} + +static void +device_ip6_subnet_needed (NMDevice *device, + gpointer user_data) +{ + NMPolicyPrivate *priv = user_data; + NMPolicy *self = _PRIV_TO_SELF (priv); + + _LOGD (LOGD_IP6, "ipv6-pd: %s needs a subnet", + nm_device_get_iface (device)); + + if (!priv->default_device6) { + /* We request the prefixes when the default IPv6 device is set. */ + _LOGI (LOGD_IP6, "ipv6-pd: no device to obtain a subnet to share on %s from", + nm_device_get_iface (device)); + return; + } + ip6_subnet_from_device (self, priv->default_device6, device); + nm_device_copy_ip6_dns_config (device, priv->default_device6); +} + +/*****************************************************************************/ + static NMDevice * get_best_ip4_device (NMPolicy *self, gboolean fully_activated) { @@ -544,6 +776,21 @@ get_best_ip6_config (NMPolicy *self, out_vpn); } +static void +update_ip6_dns_delegation (NMPolicy *self) +{ + NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); + const GSList *connections, *iter; + + connections = nm_manager_get_active_connections (priv->manager); + for (iter = connections; iter; iter = g_slist_next (iter)) { + NMDevice *device = nm_active_connection_get_device (iter->data); + + if (device && nm_device_needs_ip6_subnet (device)) + nm_device_copy_ip6_dns_config (device, priv->default_device6); + } +} + static void update_ip6_dns (NMPolicy *self, NMDnsManager *dns_mgr) { @@ -562,6 +809,24 @@ update_ip6_dns (NMPolicy *self, NMDnsManager *dns_mgr) */ nm_dns_manager_add_ip6_config (dns_mgr, ip_iface, ip6_config, dns_type); } + + update_ip6_dns_delegation (self); +} + +static void +update_ip6_prefix_delegation (NMPolicy *self) +{ + NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); + const GSList *connections, *iter; + + /* There's new default IPv6 connection, try to get a prefix for everyone. */ + connections = nm_manager_get_active_connections (priv->manager); + for (iter = connections; iter; iter = g_slist_next (iter)) { + NMDevice *device = nm_active_connection_get_device (iter->data); + + if (device && nm_device_needs_ip6_subnet (device)) + ip6_subnet_from_device (self, priv->default_device6, device); + } } static void @@ -615,8 +880,10 @@ update_ip6_routing (NMPolicy *self, gboolean force_update) if (default_device6 == priv->default_device6) return; - priv->default_device6 = default_device6; + + update_ip6_prefix_delegation (self); + connection = nm_active_connection_get_applied_connection (best_ac); _LOGI (LOGD_CORE, "set '%s' (%s) as default for IPv6 routing and DNS", nm_connection_get_id (connection), ip_iface); @@ -1276,6 +1543,7 @@ device_state_changed (NMDevice *device, } } } + ip6_remove_device_prefix_delegations (self, device); break; case NM_DEVICE_STATE_DISCONNECTED: /* Reset retry counts for a device's connections when carrier on; if cable @@ -1394,6 +1662,8 @@ device_ip6_config_changed (NMDevice *device, nm_dns_manager_end_updates (priv->dns_manager, __func__); } +/*****************************************************************************/ + static void device_autoconnect_changed (NMDevice *device, GParamSpec *pspec, @@ -1432,6 +1702,8 @@ devices_list_register (NMPolicy *self, NMDevice *device) g_signal_connect_after (device, NM_DEVICE_STATE_CHANGED, (GCallback) device_state_changed, priv); g_signal_connect (device, NM_DEVICE_IP4_CONFIG_CHANGED, (GCallback) device_ip4_config_changed, priv); g_signal_connect (device, NM_DEVICE_IP6_CONFIG_CHANGED, (GCallback) device_ip6_config_changed, priv); + g_signal_connect (device, NM_DEVICE_IP6_PREFIX_DELEGATED, (GCallback) device_ip6_prefix_delegated, priv); + g_signal_connect (device, NM_DEVICE_IP6_SUBNET_NEEDED, (GCallback) device_ip6_subnet_needed, priv); g_signal_connect (device, "notify::" NM_DEVICE_AUTOCONNECT, (GCallback) device_autoconnect_changed, priv); g_signal_connect (device, NM_DEVICE_RECHECK_AUTO_ACTIVATE, (GCallback) device_recheck_auto_activate, priv); } @@ -1458,6 +1730,10 @@ device_removed (NMManager *manager, NMDevice *device, gpointer user_data) NMPolicyPrivate *priv = user_data; NMPolicy *self = _PRIV_TO_SELF (priv); + /* XXX is this needed? The delegations are cleaned up + * on transition to deactivated too. */ + ip6_remove_device_prefix_delegations (self, device); + /* Clear any idle callbacks for this device */ clear_pending_activate_check (self, device); @@ -1886,6 +2162,8 @@ nm_policy_init (NMPolicy *self) NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); priv->devices = g_hash_table_new (NULL, NULL); + priv->ip6_prefix_delegations = g_array_new (FALSE, FALSE, sizeof (IP6PrefixDelegation)); + g_array_set_clear_func (priv->ip6_prefix_delegations, clear_ip6_prefix_delegation); } static void @@ -2006,6 +2284,8 @@ dispose (GObject *object) g_signal_handlers_disconnect_by_data (priv->manager, priv); } + g_array_free (priv->ip6_prefix_delegations, TRUE); + nm_assert (NM_IS_MANAGER (priv->manager)); G_OBJECT_CLASS (nm_policy_parent_class)->dispose (object); diff --git a/src/nm-types.h b/src/nm-types.h index 45c9284f3f..8f0cc5849f 100644 --- a/src/nm-types.h +++ b/src/nm-types.h @@ -79,7 +79,7 @@ typedef enum { NM_IP_CONFIG_SOURCE_WWAN, NM_IP_CONFIG_SOURCE_VPN, NM_IP_CONFIG_SOURCE_DHCP, - NM_IP_CONFIG_SOURCE_RDISC, + NM_IP_CONFIG_SOURCE_NDISC, NM_IP_CONFIG_SOURCE_USER, } NMIPConfigSource; diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index bd69298fe8..c180f3c841 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -2579,7 +2579,7 @@ sysctl_set (NMPlatform *platform, const char *path, const char *value) /* Try to write the entire value three times if a partial write occurs */ errsv = 0; - for (tries = 0, nwrote = 0; tries < 3 && nwrote != len; tries++) { + for (tries = 0, nwrote = 0; tries < 3 && nwrote < len - 1; tries++) { nwrote = write (fd, actual, len); if (nwrote == -1) { errsv = errno; @@ -2593,12 +2593,12 @@ sysctl_set (NMPlatform *platform, const char *path, const char *value) if (nwrote == -1 && errsv != EEXIST) { _LOGE ("sysctl: failed to set '%s' to '%s': (%d) %s", path, value, errsv, strerror (errsv)); - } else if (nwrote < len) { + } else if (nwrote < len - 1) { _LOGE ("sysctl: failed to set '%s' to '%s' after three attempts", path, value); } - if (nwrote != len) { + if (nwrote < len - 1) { if (close (fd) != 0) { if (errsv != 0) errno = errsv; diff --git a/src/platform/nm-platform-utils.c b/src/platform/nm-platform-utils.c index 068801ee69..f3983d3d74 100644 --- a/src/platform/nm-platform-utils.c +++ b/src/platform/nm-platform-utils.c @@ -469,7 +469,7 @@ nmp_utils_ip_config_source_coerce_to_rtprot (NMIPConfigSource source) return RTPROT_KERNEL; case NM_IP_CONFIG_SOURCE_DHCP: return RTPROT_DHCP; - case NM_IP_CONFIG_SOURCE_RDISC: + case NM_IP_CONFIG_SOURCE_NDISC: return RTPROT_RA; default: @@ -501,7 +501,7 @@ nmp_utils_ip_config_source_coerce_from_rtprot (NMIPConfigSource source) return NM_IP_CONFIG_SOURCE_KERNEL; case NM_IP_CONFIG_SOURCE_RTPROT_RA: - return NM_IP_CONFIG_SOURCE_RDISC; + return NM_IP_CONFIG_SOURCE_NDISC; case NM_IP_CONFIG_SOURCE_RTPROT_DHCP: return NM_IP_CONFIG_SOURCE_DHCP; @@ -538,7 +538,7 @@ nmp_utils_ip_config_source_to_string (NMIPConfigSource source, char *buf, gsize case NM_IP_CONFIG_SOURCE_WWAN: s = "wwan"; break; case NM_IP_CONFIG_SOURCE_VPN: s = "vpn"; break; case NM_IP_CONFIG_SOURCE_DHCP: s = "dhcp"; break; - case NM_IP_CONFIG_SOURCE_RDISC: s = "rdisc"; break; + case NM_IP_CONFIG_SOURCE_NDISC: s = "ndisc"; break; case NM_IP_CONFIG_SOURCE_USER: s = "user"; break; default: break; diff --git a/src/rdisc/nm-rdisc.h b/src/rdisc/nm-rdisc.h deleted file mode 100644 index 9e5e9349bc..0000000000 --- a/src/rdisc/nm-rdisc.h +++ /dev/null @@ -1,170 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* nm-rdisc.h - Perform IPv6 router discovery - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Copyright (C) 2013 Red Hat, Inc. - */ - -#ifndef __NETWORKMANAGER_RDISC_H__ -#define __NETWORKMANAGER_RDISC_H__ - -#include -#include - -#include "nm-setting-ip6-config.h" -#include "NetworkManagerUtils.h" - -#define NM_TYPE_RDISC (nm_rdisc_get_type ()) -#define NM_RDISC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_RDISC, NMRDisc)) -#define NM_RDISC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_RDISC, NMRDiscClass)) -#define NM_IS_RDISC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_RDISC)) -#define NM_IS_RDISC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_RDISC)) -#define NM_RDISC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_RDISC, NMRDiscClass)) - -#define NM_RDISC_PLATFORM "platform" -#define NM_RDISC_IFINDEX "ifindex" -#define NM_RDISC_IFNAME "ifname" -#define NM_RDISC_NETWORK_ID "network-id" -#define NM_RDISC_ADDR_GEN_MODE "addr-gen-mode" -#define NM_RDISC_STABLE_TYPE "stable-type" -#define NM_RDISC_MAX_ADDRESSES "max-addresses" -#define NM_RDISC_ROUTER_SOLICITATIONS "router-solicitations" -#define NM_RDISC_ROUTER_SOLICITATION_INTERVAL "router-solicitation-interval" - -#define NM_RDISC_CONFIG_CHANGED "config-changed" -#define NM_RDISC_RA_TIMEOUT "ra-timeout" - -typedef enum { - NM_RDISC_DHCP_LEVEL_UNKNOWN, - NM_RDISC_DHCP_LEVEL_NONE, - NM_RDISC_DHCP_LEVEL_OTHERCONF, - NM_RDISC_DHCP_LEVEL_MANAGED -} NMRDiscDHCPLevel; - -typedef enum { - NM_RDISC_PREFERENCE_INVALID, - NM_RDISC_PREFERENCE_LOW, - NM_RDISC_PREFERENCE_MEDIUM, - NM_RDISC_PREFERENCE_HIGH -} NMRDiscPreference; - -typedef struct { - struct in6_addr address; - guint32 timestamp; - guint32 lifetime; - NMRDiscPreference preference; -} NMRDiscGateway; - -typedef struct { - struct in6_addr address; - guint8 dad_counter; - guint32 timestamp; - guint32 lifetime; - guint32 preferred; -} NMRDiscAddress; - -typedef struct { - struct in6_addr network; - guint8 plen; - struct in6_addr gateway; - guint32 timestamp; - guint32 lifetime; - NMRDiscPreference preference; -} NMRDiscRoute; - -typedef struct { - struct in6_addr address; - guint32 timestamp; - guint32 lifetime; -} NMRDiscDNSServer; - -typedef struct { - char *domain; - guint32 timestamp; - guint32 lifetime; -} NMRDiscDNSDomain; - -typedef enum { - NM_RDISC_CONFIG_DHCP_LEVEL = 1 << 0, - NM_RDISC_CONFIG_GATEWAYS = 1 << 1, - NM_RDISC_CONFIG_ADDRESSES = 1 << 2, - NM_RDISC_CONFIG_ROUTES = 1 << 3, - NM_RDISC_CONFIG_DNS_SERVERS = 1 << 4, - NM_RDISC_CONFIG_DNS_DOMAINS = 1 << 5, - NM_RDISC_CONFIG_HOP_LIMIT = 1 << 6, - NM_RDISC_CONFIG_MTU = 1 << 7, -} NMRDiscConfigMap; - -#define NM_RDISC_MAX_ADDRESSES_DEFAULT 16 -#define NM_RDISC_ROUTER_SOLICITATIONS_DEFAULT 3 -#define NM_RDISC_ROUTER_SOLICITATION_INTERVAL_DEFAULT 4 - -struct _NMRDiscPrivate; -struct _NMRDiscDataInternal; - -typedef struct { - NMRDiscDHCPLevel dhcp_level; - guint32 mtu; - int hop_limit; - - guint gateways_n; - guint addresses_n; - guint routes_n; - guint dns_servers_n; - guint dns_domains_n; - - const NMRDiscGateway *gateways; - const NMRDiscAddress *addresses; - const NMRDiscRoute *routes; - const NMRDiscDNSServer *dns_servers; - const NMRDiscDNSDomain *dns_domains; -} NMRDiscData; - -/** - * NMRDisc: - * - * Interface-specific structure that handles incoming router advertisements, - * caches advertised items and removes them when they are obsolete. - */ -typedef struct { - GObject parent; - union { - struct _NMRDiscPrivate *_priv; - struct _NMRDiscDataInternal *rdata; - }; -} NMRDisc; - -typedef struct { - GObjectClass parent; - - void (*start) (NMRDisc *rdisc); - gboolean (*send_rs) (NMRDisc *rdisc, GError **error); -} NMRDiscClass; - -GType nm_rdisc_get_type (void); - -int nm_rdisc_get_ifindex (NMRDisc *self); -const char *nm_rdisc_get_ifname (NMRDisc *self); - -gboolean nm_rdisc_set_iid (NMRDisc *rdisc, const NMUtilsIPv6IfaceId iid); -void nm_rdisc_start (NMRDisc *rdisc); -void nm_rdisc_dad_failed (NMRDisc *rdisc, struct in6_addr *address); - -NMPlatform *nm_rdisc_get_platform (NMRDisc *self); -NMPNetns *nm_rdisc_netns_get (NMRDisc *self); -gboolean nm_rdisc_netns_push (NMRDisc *self, NMPNetns **netns); - -#endif /* __NETWORKMANAGER_RDISC_H__ */ diff --git a/src/rdisc/tests/.gitignore b/src/rdisc/tests/.gitignore deleted file mode 100644 index a773713bb0..0000000000 --- a/src/rdisc/tests/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/rdisc diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c index 142c2251a5..978804f498 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c @@ -1381,7 +1381,7 @@ make_ip6_setting (shvarFile *ifcfg, char *route6_path = NULL; gs_free char *dns_options_free = NULL; const char *dns_options = NULL; - gboolean ipv6init, ipv6forwarding, ipv6_autoconf, dhcp6 = FALSE; + gboolean ipv6init, ipv6forwarding, dhcp6 = FALSE; char *method = NM_SETTING_IP6_CONFIG_METHOD_MANUAL; char *ipv6addr, *ipv6addr_secondaries; char **list = NULL, **iter; @@ -1392,7 +1392,6 @@ make_ip6_setting (shvarFile *ifcfg, gboolean ip6_privacy = FALSE, ip6_privacy_prefer_public_ip; NMSettingIP6ConfigPrivacy ip6_privacy_val; NMSettingIP6ConfigAddrGenMode addr_gen_mode; - char *tmp; s_ip6 = (NMSettingIPConfig *) nm_setting_ip6_config_new (); @@ -1455,10 +1454,12 @@ make_ip6_setting (shvarFile *ifcfg, method = NM_SETTING_IP6_CONFIG_METHOD_IGNORE; /* IPv6 is disabled */ else { ipv6forwarding = svGetValueBoolean (ifcfg, "IPV6FORWARDING", FALSE); - ipv6_autoconf = svGetValueBoolean (ifcfg, "IPV6_AUTOCONF", !ipv6forwarding); + str_value = svGetValueString (ifcfg, "IPV6_AUTOCONF"); dhcp6 = svGetValueBoolean (ifcfg, "DHCPV6C", FALSE); - if (ipv6_autoconf) + if (!g_strcmp0 (str_value, "shared")) + method = NM_SETTING_IP6_CONFIG_METHOD_SHARED; + else if (svParseBoolean (str_value, !ipv6forwarding)) method = NM_SETTING_IP6_CONFIG_METHOD_AUTO; else if (dhcp6) method = NM_SETTING_IP6_CONFIG_METHOD_DHCP; @@ -1476,20 +1477,20 @@ make_ip6_setting (shvarFile *ifcfg, /* TODO - handle other methods */ /* Read IPv6 Privacy Extensions configuration */ - tmp = svGetValueString (ifcfg, "IPV6_PRIVACY"); - if (tmp) { - ip6_privacy = svGetValueBoolean (ifcfg, "IPV6_PRIVACY", FALSE); + str_value = svGetValueString (ifcfg, "IPV6_PRIVACY"); + if (str_value) { + ip6_privacy = svParseBoolean (str_value, FALSE); if (!ip6_privacy) - ip6_privacy = g_strcmp0 (tmp, "rfc4941") == 0 || - g_strcmp0 (tmp, "rfc3041") == 0; + ip6_privacy = (g_strcmp0 (str_value, "rfc4941") == 0) || + (g_strcmp0 (str_value, "rfc3041") == 0); } ip6_privacy_prefer_public_ip = svGetValueBoolean (ifcfg, "IPV6_PRIVACY_PREFER_PUBLIC_IP", FALSE); - ip6_privacy_val = tmp ? + ip6_privacy_val = str_value ? (ip6_privacy ? (ip6_privacy_prefer_public_ip ? NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR : NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR) : NM_SETTING_IP6_CONFIG_PRIVACY_DISABLED) : NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN; - g_free (tmp); + g_free (str_value); g_object_set (s_ip6, NM_SETTING_IP_CONFIG_METHOD, method, @@ -1574,14 +1575,14 @@ make_ip6_setting (shvarFile *ifcfg, } /* IPv6 addressing mode configuration */ - tmp = svGetValueString (ifcfg, "IPV6_ADDR_GEN_MODE"); - if (tmp) { - if (nm_utils_enum_from_str (nm_setting_ip6_config_addr_gen_mode_get_type (), tmp, + str_value = svGetValueString (ifcfg, "IPV6_ADDR_GEN_MODE"); + if (str_value) { + if (nm_utils_enum_from_str (nm_setting_ip6_config_addr_gen_mode_get_type (), str_value, (int *) &addr_gen_mode, NULL)) g_object_set (s_ip6, NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE, addr_gen_mode, NULL); else PARSE_WARNING ("Invalid IPV6_ADDR_GEN_MODE"); - g_free (tmp); + g_free (str_value); } else { g_object_set (s_ip6, NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE, @@ -1590,10 +1591,10 @@ make_ip6_setting (shvarFile *ifcfg, } /* IPv6 tokenized interface identifier */ - tmp = svGetValueString (ifcfg, "IPV6_TOKEN"); - if (tmp) { - g_object_set (s_ip6, NM_SETTING_IP6_CONFIG_TOKEN, tmp, NULL); - g_free (tmp); + str_value = svGetValueString (ifcfg, "IPV6_TOKEN"); + if (str_value) { + g_object_set (s_ip6, NM_SETTING_IP6_CONFIG_TOKEN, str_value, NULL); + g_free (str_value); } /* DNS servers diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c index d456f1a2a6..1696e1ad43 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c @@ -2477,8 +2477,8 @@ write_ip6_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) svUnsetValue (ifcfg, "DHCPV6C"); } else if (!strcmp (value, NM_SETTING_IP6_CONFIG_METHOD_SHARED)) { svSetValueString (ifcfg, "IPV6INIT", "yes"); + svSetValueString (ifcfg, "IPV6_AUTOCONF", "shared"); svUnsetValue (ifcfg, "DHCPV6C"); - /* TODO */ } /* Write out IP addresses */ diff --git a/src/tests/test-general.c b/src/tests/test-general.c index 2596cff6af..a7337ba7b0 100644 --- a/src/tests/test-general.c +++ b/src/tests/test-general.c @@ -29,7 +29,7 @@ #include "nm-test-utils-core.h" /* Reference implementation for nm_utils_ip6_address_clear_host_address. - * Taken originally from set_address_masked(), src/rdisc/nm-lndp-rdisc.c + * Taken originally from set_address_masked(), src/ndisc/nm-lndp-ndisc.c **/ static void ip6_address_clear_host_address_reference (struct in6_addr *dst, struct in6_addr *src, guint8 plen) diff --git a/src/tests/test-ip6-config.c b/src/tests/test-ip6-config.c index 05b0320610..8e34f6c945 100644 --- a/src/tests/test-ip6-config.c +++ b/src/tests/test-ip6-config.c @@ -288,7 +288,7 @@ test_nm_ip6_config_addresses_sort (void) nm_ip6_config_reset_addresses (config); ADDR_ADD("2607:f0d0:1002:51::4", NULL, 64, 0, NM_IP_CONFIG_SOURCE_USER, 0, 0, 0, 0); ADDR_ADD("2607:f0d0:1002:51::5", NULL, 64, 0, NM_IP_CONFIG_SOURCE_USER, 0, 0, 0, 0); - ADDR_ADD("2607:f0d0:1002:51::6", NULL, 64, 0, NM_IP_CONFIG_SOURCE_RDISC, 0, 0, 0, IFA_F_MANAGETEMPADDR); + ADDR_ADD("2607:f0d0:1002:51::6", NULL, 64, 0, NM_IP_CONFIG_SOURCE_NDISC, 0, 0, 0, IFA_F_MANAGETEMPADDR); ADDR_ADD("2607:f0d0:1002:51::3", NULL, 64, 0, NM_IP_CONFIG_SOURCE_USER, 0, 0, 0, IFA_F_SECONDARY); ADDR_ADD("2607:f0d0:1002:51::8", NULL, 64, 0, NM_IP_CONFIG_SOURCE_USER, 0, 0, 0, IFA_F_SECONDARY); ADDR_ADD("2607:f0d0:1002:51::0", NULL, 64, 0, NM_IP_CONFIG_SOURCE_KERNEL, 0, 0, 0, IFA_F_SECONDARY); @@ -307,7 +307,7 @@ test_nm_ip6_config_addresses_sort (void) ADDR_ADD("2607:f0d0:1002:51::5", NULL, 64, 0, NM_IP_CONFIG_SOURCE_USER, 0, 0, 0, 0); ADDR_ADD("2607:f0d0:1002:51::8", NULL, 64, 0, NM_IP_CONFIG_SOURCE_USER, 0, 0, 0, IFA_F_SECONDARY); ADDR_ADD("2607:f0d0:1002:51::0", NULL, 64, 0, NM_IP_CONFIG_SOURCE_KERNEL, 0, 0, 0, IFA_F_SECONDARY); - ADDR_ADD("2607:f0d0:1002:51::6", NULL, 64, 0, NM_IP_CONFIG_SOURCE_RDISC, 0, 0, 0, IFA_F_MANAGETEMPADDR); + ADDR_ADD("2607:f0d0:1002:51::6", NULL, 64, 0, NM_IP_CONFIG_SOURCE_NDISC, 0, 0, 0, IFA_F_MANAGETEMPADDR); ADDR_ADD("fec0::1", NULL, 128, 0, NM_IP_CONFIG_SOURCE_KERNEL, 0, 0, 0, 0); ADDR_ADD("fe80::208:74ff:feda:625c", NULL, 128, 0, NM_IP_CONFIG_SOURCE_KERNEL, 0, 0, 0, 0); ADDR_ADD("fe80::208:74ff:feda:625d", NULL, 128, 0, NM_IP_CONFIG_SOURCE_KERNEL, 0, 0, 0, 0);