merge: branch 'lr/ipv6-sharing'

https://bugzilla.gnome.org/show_bug.cgi?id=773777
This commit is contained in:
Lubomir Rintel 2016-11-09 17:24:44 +01:00
commit ecc6040cd8
39 changed files with 2093 additions and 1086 deletions

5
.gitignore vendored
View file

@ -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/

View file

@ -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

View file

@ -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);
}

View file

@ -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)) {

View file

@ -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)) {

View file

@ -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),

View file

@ -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

View file

@ -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);
}

View file

@ -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);

View file

@ -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));
}

View file

@ -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);

View file

@ -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

View file

@ -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,

View file

@ -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);

View file

@ -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");

View file

@ -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);

View file

@ -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 <string.h>
#include <arpa/inet.h>
#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,

View file

@ -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__ */

View file

@ -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 <string.h>
#include <arpa/inet.h>
#include <netinet/icmp6.h>
/* stdarg.h included because of a bug in ndp.h */
#include <stdarg.h>
#include <ndp.h>
#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;
}

View file

@ -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__ */

View file

@ -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__ */

File diff suppressed because it is too large Load diff

189
src/ndisc/nm-ndisc.h Normal file
View file

@ -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 <stdlib.h>
#include <netinet/in.h>
#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__ */

1
src/ndisc/tests/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/ndisc

View file

@ -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 <string.h>
#include <syslog.h>
#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 ();
}

View file

@ -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 <string.h>
#include <syslog.h>
#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;
}

View file

@ -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 ();

View file

@ -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 ();

View file

@ -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))

View file

@ -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);

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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 <stdlib.h>
#include <netinet/in.h>
#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__ */

View file

@ -1 +0,0 @@
/rdisc

View file

@ -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

View file

@ -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 */

View file

@ -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)

View file

@ -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);