From c84b54dbfe0c56753f497dc13fa0ee40a87d0d91 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sat, 15 Feb 2014 12:16:46 +0100 Subject: [PATCH] backport patches for IPv6 privacy --- 0044-ipv6-privacy.patch | 1739 +++++++++++++++++++++++++++++++++++++++ NetworkManager.spec | 5 + 2 files changed, 1744 insertions(+) create mode 100644 0044-ipv6-privacy.patch diff --git a/0044-ipv6-privacy.patch b/0044-ipv6-privacy.patch new file mode 100644 index 0000000..afbc2ef --- /dev/null +++ b/0044-ipv6-privacy.patch @@ -0,0 +1,1739 @@ +From 9989350adbe25dccb716f8df41ac915c1e262304 Mon Sep 17 00:00:00 2001 +From: Thomas Haller +Date: Sat, 15 Feb 2014 13:20:40 +0100 +Subject: [PATCH 01/14] fix several compile errors + +Signed-off-by: Thomas Haller +--- + src/devices/nm-device.c | 2 +- + src/settings/nm-system-config-interface.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c +index c3b3f21..92de1db 100644 +--- a/src/devices/nm-device.c ++++ b/src/devices/nm-device.c +@@ -6925,7 +6925,7 @@ nm_device_add_pending_action (NMDevice *device, const char *action) + nm_device_get_iface (device), + g_slist_length (priv->pending_actions), + action); +- g_return_val_if_reached (FALSE); ++ g_return_if_reached (); + } + } + +diff --git a/src/settings/nm-system-config-interface.c b/src/settings/nm-system-config-interface.c +index 18457ea..fd36fc4 100644 +--- a/src/settings/nm-system-config-interface.c ++++ b/src/settings/nm-system-config-interface.c +@@ -141,7 +141,7 @@ gboolean + nm_system_config_interface_load_connection (NMSystemConfigInterface *config, + const char *filename) + { +- g_return_val_if_fail (config != NULL, NULL); ++ g_return_val_if_fail (config != NULL, FALSE); + + if (NM_SYSTEM_CONFIG_INTERFACE_GET_INTERFACE (config)->load_connection) + return NM_SYSTEM_CONFIG_INTERFACE_GET_INTERFACE (config)->load_connection (config, filename); +-- +1.8.5.3 + + +From 7ffd758bf4e0d57a240ec4031bf987b397950463 Mon Sep 17 00:00:00 2001 +From: Thomas Haller +Date: Tue, 21 Jan 2014 13:07:06 +0100 +Subject: [PATCH 02/14] core: add nm_utils_ascii_str_to_int64() function + +(cherry picked from commit 63075d98a59270ffcb89bb556b6ee5efc14eef0f) + +Signed-off-by: Thomas Haller +--- + src/NetworkManagerUtils.c | 60 +++++++++++++++++++++++++++++++++++++ + src/NetworkManagerUtils.h | 2 ++ + src/tests/Makefile.am | 10 +++++++ + src/tests/test-general.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 148 insertions(+) + create mode 100644 src/tests/test-general.c + +diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c +index bc3d1b2..d0937fb 100644 +--- a/src/NetworkManagerUtils.c ++++ b/src/NetworkManagerUtils.c +@@ -644,3 +644,63 @@ nm_utils_new_vlan_name (const char *parent_iface, guint32 vlan_id) + return g_strdup_printf ("%s.%d", parent_iface, vlan_id); + } + ++/* nm_utils_ascii_str_to_int64: ++ * ++ * A wrapper for g_ascii_strtoll, that checks whether the whole string ++ * can be successfully converted to a number and is within a given ++ * range. On any error, @fallback will be returned and @errno will be set ++ * to a non-zero value. Check @errno for errors. Any trailing or leading ++ * (ascii) white space is ignored and the functions is locale independent. ++ * ++ * The function is guaranteed to return a value between @min and @max ++ * (included) or @fallback. Also, the parsing is rather strict, it does ++ * not allow for any unrecognized characters, except leading and trailing ++ * white space. ++ **/ ++gint64 ++nm_utils_ascii_str_to_int64 (const char *str, guint base, gint64 min, gint64 max, gint64 fallback) ++{ ++ gint64 v; ++ char *end; ++ char *str_free = NULL; ++ ++ if (str) { ++ while (str[0] && g_ascii_isspace (str[0])) ++ str++; ++ } ++ if (!str || !str[0]) { ++ errno = EINVAL; ++ return fallback; ++ } ++ ++ if (g_ascii_isspace (str[strlen (str) - 1])) { ++ str_free = g_strdup (str); ++ g_strstrip (str_free); ++ str = str_free; ++ } ++ ++ errno = 0; ++ v = g_ascii_strtoll (str, &end, base); ++ ++ if (errno != 0) { ++ g_free (str_free); ++ return fallback; ++ } ++ ++ if (end[0] != 0) { ++ g_free (str_free); ++ errno = EINVAL; ++ return fallback; ++ } ++ ++ g_free (str_free); ++ if (v > max || v < min) { ++ errno = ERANGE; ++ return fallback; ++ } ++ ++ return v; ++} ++ ++ ++ +diff --git a/src/NetworkManagerUtils.h b/src/NetworkManagerUtils.h +index 819cb07..0904c51 100644 +--- a/src/NetworkManagerUtils.h ++++ b/src/NetworkManagerUtils.h +@@ -91,4 +91,6 @@ void nm_utils_complete_generic (NMConnection *connection, + + char *nm_utils_new_vlan_name (const char *parent_iface, guint32 vlan_id); + ++gint64 nm_utils_ascii_str_to_int64 (const char *str, guint base, gint64 min, gint64 max, gint64 fallback); ++ + #endif /* NETWORK_MANAGER_UTILS_H */ +diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am +index 3e485fd..2b42d2c 100644 +--- a/src/tests/Makefile.am ++++ b/src/tests/Makefile.am +@@ -12,6 +12,7 @@ AM_CPPFLAGS = \ + + noinst_PROGRAMS = \ + test-dhcp-options \ ++ test-general \ + test-policy-hosts \ + test-wifi-ap-utils \ + test-ip4-config \ +@@ -62,6 +63,14 @@ test_ip6_config_SOURCES = \ + test_ip6_config_LDADD = \ + $(top_builddir)/src/libNetworkManager.la + ++####### general test ####### ++ ++test_general_SOURCES = \ ++ test-general.c ++ ++test_general_LDADD = \ ++ $(top_builddir)/src/libNetworkManager.la ++ + ####### secret agent interface test ####### + + EXTRA_DIST = test-secret-agent.py +@@ -74,4 +83,5 @@ check-local: test-dhcp-options test-policy-hosts test-wifi-ap-utils test-ip4-con + $(abs_builddir)/test-wifi-ap-utils + $(abs_builddir)/test-ip4-config + $(abs_builddir)/test-ip6-config ++ $(abs_builddir)/test-general + +diff --git a/src/tests/test-general.c b/src/tests/test-general.c +new file mode 100644 +index 0000000..649653c +--- /dev/null ++++ b/src/tests/test-general.c +@@ -0,0 +1,76 @@ ++/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ ++/* ++ * 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) 2014 Red Hat, Inc. ++ * ++ */ ++ ++#include ++#include ++#include ++ ++#include "NetworkManagerUtils.h" ++ ++ ++static void ++test_nm_utils_ascii_str_to_int64_do (const char *str, guint base, gint64 min, ++ gint64 max, gint64 fallback, int exp_errno, ++ gint64 exp_val) ++{ ++ gint64 v; ++ ++ errno = 0; ++ v = nm_utils_ascii_str_to_int64 (str, base, min, max, fallback); ++ g_assert_cmpint (errno, ==, exp_errno); ++ g_assert_cmpint (v, ==, exp_val); ++} ++ ++static void ++test_nm_utils_ascii_str_to_int64 (void) ++{ ++ test_nm_utils_ascii_str_to_int64_do ("4711", 10, 0, 10000, -1, 0, 4711); ++ test_nm_utils_ascii_str_to_int64_do ("", 10, 0, 10000, -1, EINVAL, -1); ++ test_nm_utils_ascii_str_to_int64_do (NULL, 10, 0, 10000, -1, EINVAL, -1); ++ test_nm_utils_ascii_str_to_int64_do (" 1x ", 10, 0, 10000, -1, EINVAL, -1); ++ test_nm_utils_ascii_str_to_int64_do (" 10000 ", 10, 0, 10000, -1, 0, 10000); ++ test_nm_utils_ascii_str_to_int64_do (" 10001 ", 10, 0, 10000, -1, ERANGE, -1); ++ test_nm_utils_ascii_str_to_int64_do (" 0xFF ", 16, 0, 10000, -1, 0, 255); ++ test_nm_utils_ascii_str_to_int64_do (" FF ", 16, 0, 10000, -1, 0, 255); ++ test_nm_utils_ascii_str_to_int64_do (" FF ", 10, 0, 10000, -2, EINVAL, -2); ++ test_nm_utils_ascii_str_to_int64_do (" 9223372036854775807 ", 10, 0, G_MAXINT64, -2, 0, G_MAXINT64); ++ test_nm_utils_ascii_str_to_int64_do (" 0x7FFFFFFFFFFFFFFF ", 16, 0, G_MAXINT64, -2, 0, G_MAXINT64); ++ test_nm_utils_ascii_str_to_int64_do (" 7FFFFFFFFFFFFFFF ", 16, 0, G_MAXINT64, -2, 0, G_MAXINT64); ++ test_nm_utils_ascii_str_to_int64_do (" 9223372036854775808 ", 10, 0, G_MAXINT64, -2, ERANGE, -2); ++ test_nm_utils_ascii_str_to_int64_do (" -9223372036854775808 ", 10, G_MININT64, 0, -2, 0, G_MININT64); ++ test_nm_utils_ascii_str_to_int64_do (" -9223372036854775808 ", 10, G_MININT64+1, 0, -2, ERANGE, -2); ++ test_nm_utils_ascii_str_to_int64_do (" -9223372036854775809 ", 10, G_MININT64, 0, -2, ERANGE, -2); ++ test_nm_utils_ascii_str_to_int64_do ("\r\n\t10000\t\n\t\n", 10, 0, 10000, -1, 0, 10000); ++} ++ ++/*******************************************/ ++ ++int ++main (int argc, char **argv) ++{ ++ g_test_init (&argc, &argv, NULL); ++ ++ g_type_init (); ++ ++ g_test_add_func ("/general/nm_utils_ascii_str_to_int64", test_nm_utils_ascii_str_to_int64); ++ ++ return g_test_run (); ++} ++ +-- +1.8.5.3 + + +From 04320290b6c1dfb7f6ac0b8c7f9b71cffbc5730b Mon Sep 17 00:00:00 2001 +From: Dan Winship +Date: Mon, 14 Oct 2013 10:38:56 -0400 +Subject: [PATCH 03/14] core: add function nm_utils_get_ip_config_method() + +Add nm_utils_get_ip_config_method(), which returns the correct +IP config method for a connection, whether the connection has IP4 and +IP6 settings objects or not, and use that to keep some more of the +simplifications from the earlier patch. + +This is a partial backport of an upstream commit. + +(cherry picked from commit f03635e5ac829d4fc896573f2f3c6969b9d5a2e2) +--- + src/NetworkManagerUtils.c | 43 +++++++++++++++++++++++++++++++++++++++++++ + src/NetworkManagerUtils.h | 3 +++ + 2 files changed, 46 insertions(+) + +diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c +index d0937fb..bac5322 100644 +--- a/src/NetworkManagerUtils.c ++++ b/src/NetworkManagerUtils.c +@@ -576,6 +576,49 @@ get_new_connection_name (const GSList *existing, + return cname; + } + ++const char * ++nm_utils_get_ip_config_method (NMConnection *connection, ++ GType ip_setting_type) ++{ ++ NMSettingConnection *s_con; ++ NMSettingIP4Config *s_ip4; ++ NMSettingIP6Config *s_ip6; ++ const char *method; ++ ++ s_con = nm_connection_get_setting_connection (connection); ++ ++ if (ip_setting_type == NM_TYPE_SETTING_IP4_CONFIG) { ++ g_return_val_if_fail (s_con != NULL, NM_SETTING_IP4_CONFIG_METHOD_AUTO); ++ ++ if (nm_setting_connection_get_master (s_con)) ++ return NM_SETTING_IP4_CONFIG_METHOD_DISABLED; ++ else { ++ s_ip4 = nm_connection_get_setting_ip4_config (connection); ++ g_return_val_if_fail (s_ip4 != NULL, NM_SETTING_IP4_CONFIG_METHOD_AUTO); ++ method = nm_setting_ip4_config_get_method (s_ip4); ++ g_return_val_if_fail (method != NULL, NM_SETTING_IP4_CONFIG_METHOD_AUTO); ++ ++ return method; ++ } ++ ++ } else if (ip_setting_type == NM_TYPE_SETTING_IP6_CONFIG) { ++ g_return_val_if_fail (s_con != NULL, NM_SETTING_IP6_CONFIG_METHOD_AUTO); ++ ++ if (nm_setting_connection_get_master (s_con)) ++ return NM_SETTING_IP6_CONFIG_METHOD_IGNORE; ++ else { ++ s_ip6 = nm_connection_get_setting_ip6_config (connection); ++ g_return_val_if_fail (s_ip6 != NULL, NM_SETTING_IP6_CONFIG_METHOD_AUTO); ++ method = nm_setting_ip6_config_get_method (s_ip6); ++ g_return_val_if_fail (method != NULL, NM_SETTING_IP6_CONFIG_METHOD_AUTO); ++ ++ return method; ++ } ++ ++ } else ++ g_assert_not_reached (); ++} ++ + void + nm_utils_complete_generic (NMConnection *connection, + const char *ctype, +diff --git a/src/NetworkManagerUtils.h b/src/NetworkManagerUtils.h +index 0904c51..a15f74f 100644 +--- a/src/NetworkManagerUtils.h ++++ b/src/NetworkManagerUtils.h +@@ -82,6 +82,9 @@ gboolean nm_utils_get_proc_sys_net_value_with_bounds (const char *path, + gint32 valid_min, + gint32 valid_max); + ++const char *nm_utils_get_ip_config_method (NMConnection *connection, ++ GType ip_setting_type); ++ + void nm_utils_complete_generic (NMConnection *connection, + const char *ctype, + const GSList *existing, +-- +1.8.5.3 + + +From 32602714f0e06301d68be71daf38c42215b46944 Mon Sep 17 00:00:00 2001 +From: Thomas Haller +Date: Mon, 6 Jan 2014 19:59:17 +0100 +Subject: [PATCH 04/14] core: add function nm_platform_sysctl_get_int32() + +This is a partial backport of an upstream commit. + +(cherry picked from commit 2b87dbb2a990fa6aee9ca1e431a2d1ee2af453e9) + +Signed-off-by: Thomas Haller +--- + src/platform/nm-platform.c | 32 ++++++++++++++++++++++++++++++++ + src/platform/nm-platform.h | 1 + + 2 files changed, 33 insertions(+) + +diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c +index 06cdec0..cf21e5c 100644 +--- a/src/platform/nm-platform.c ++++ b/src/platform/nm-platform.c +@@ -27,6 +27,7 @@ + #include + + #include "nm-platform.h" ++#include "NetworkManagerUtils.h" + #include "nm-logging.h" + #include "nm-enum-types.h" + +@@ -243,6 +244,37 @@ nm_platform_sysctl_get (const char *path) + return klass->sysctl_get (platform, path); + } + ++/** ++ * nm_platform_sysctl_get_int32: ++ * @path: Absolute path to sysctl ++ * @fallback: default value, if the content of path could not be read ++ * as decimal integer. ++ * ++ * Returns: contents of the sysctl file parsed as s32 integer, or ++ * @fallback on error. Also, on error, @errno will be set to a non-zero ++ * value. ++ */ ++gint32 ++nm_platform_sysctl_get_int32 (const char *path, gint32 fallback) ++{ ++ char *value = NULL; ++ gint32 ret; ++ ++ g_return_val_if_fail (path, fallback); ++ ++ if (path) ++ value = nm_platform_sysctl_get (path); ++ ++ if (!value) { ++ errno = EINVAL; ++ return fallback; ++ } ++ ++ ret = nm_utils_ascii_str_to_int64 (value, 10, G_MININT32, G_MAXINT32, fallback); ++ g_free (value); ++ return ret; ++} ++ + /******************************************************************/ + + /** +diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h +index 58f51ce..d4864d0 100644 +--- a/src/platform/nm-platform.h ++++ b/src/platform/nm-platform.h +@@ -349,6 +349,7 @@ void nm_platform_query_devices (void); + + gboolean nm_platform_sysctl_set (const char *path, const char *value); + char *nm_platform_sysctl_get (const char *path); ++gint32 nm_platform_sysctl_get_int32 (const char *path, gint32 fallback); + + GArray *nm_platform_link_get_all (void); + gboolean nm_platform_dummy_add (const char *name); +-- +1.8.5.3 + + +From e72164b28a31355fb71b798b6197113d64f94335 Mon Sep 17 00:00:00 2001 +From: Thomas Haller +Date: Fri, 13 Dec 2013 20:12:57 +0100 +Subject: [PATCH 05/14] core: fix NMDevice.ip6_use_tempaddr to avoid buffer + overrun for zero char in config file + +(cherry picked from commit bb9deec9ef98ede632e69f8e5a6e017070f714a8) + +Signed-off-by: Thomas Haller +--- + src/devices/nm-device.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c +index 92de1db..e32050f 100644 +--- a/src/devices/nm-device.c ++++ b/src/devices/nm-device.c +@@ -3272,7 +3272,6 @@ static int + ip6_use_tempaddr (void) + { + char *contents = NULL; +- gsize len = 0; + const char *group_name = "[forged_group]\n"; + char *sysctl_data = NULL; + GKeyFile *keyfile; +@@ -3280,15 +3279,15 @@ ip6_use_tempaddr (void) + int tmp, ret = -1; + + /* Read file contents to a string. */ +- if (!g_file_get_contents ("/etc/sysctl.conf", &contents, &len, NULL)) +- if (!g_file_get_contents ("/lib/sysctl.d/sysctl.conf", &contents, &len, NULL)) ++ if (!g_file_get_contents ("/etc/sysctl.conf", &contents, NULL, NULL)) ++ if (!g_file_get_contents ("/lib/sysctl.d/sysctl.conf", &contents, NULL, NULL)) + return -1; + + /* Prepend a group so that we can use GKeyFile parser. */ + sysctl_data = g_strdup_printf ("%s%s", group_name, contents); + + keyfile = g_key_file_new (); +- if (!g_key_file_load_from_data (keyfile, sysctl_data, len + strlen (group_name), G_KEY_FILE_NONE, NULL)) ++ if (!g_key_file_load_from_data (keyfile, sysctl_data, -1, G_KEY_FILE_NONE, NULL)) + goto done; + + tmp = g_key_file_get_integer (keyfile, "forged_group", "net.ipv6.conf.default.use_tempaddr", &error); +-- +1.8.5.3 + + +From 3edb66027825c327ba0b24339505d99c0432623d Mon Sep 17 00:00:00 2001 +From: Thomas Haller +Date: Thu, 7 Nov 2013 20:38:08 +0100 +Subject: [PATCH 06/14] core: IPv6 mode link-local must not behave like auto + (bgo#706618, bgo#707155) + +In act_stage3_ip6_config_start, for IPv6 mode link-local, we check +if there is already an IPv6 address configured. If yes, we are +already done. + +For now, as current workaround, if the LL does not exist, we +NM_ACT_STAGE_RETURN_STOP. + +Later, we will POSTPONE and wait a timeout until we see a LL address +that is no longer TENTATIVE. The same should be done for method auto, +so that the device is usable to send router solitations (bgo#707155). + +https://bugzilla.gnome.org/show_bug.cgi?id=707155 +https://bugzilla.gnome.org/show_bug.cgi?id=706618 + +(cherry picked from commit 10bd060076befc4b711125a19831d323f9ea8595) + +Signed-off-by: Thomas Haller +--- + src/devices/nm-device.c | 30 ++++++++++++++++++++++++++++-- + 1 file changed, 28 insertions(+), 2 deletions(-) + +diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c +index e32050f..152814c 100644 +--- a/src/devices/nm-device.c ++++ b/src/devices/nm-device.c +@@ -3265,6 +3265,31 @@ addrconf6_cleanup (NMDevice *self) + + /******************************************/ + ++static int ++linklocal6_start (NMDevice *self) ++{ ++ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); ++ int i; ++ ++ if (priv->ip6_config) { ++ for (i = 0; i < nm_ip6_config_get_num_addresses (priv->ip6_config); i++) { ++ const NMPlatformIP6Address *addr = nm_ip6_config_get_address (priv->ip6_config, i); ++ ++ if (addr->plen == 128 && IN6_IS_ADDR_LINKLOCAL (&addr->address)) { ++ /* FIXME: only accept the address if it is no longer TENTATIVE */ ++ return NM_ACT_STAGE_RETURN_SUCCESS; ++ } ++ } ++ } ++ ++ /* FIXME: we should NM_ACT_STAGE_RETURN_POSTPONE and wait until with timeout ++ * we get a link local address that is no longer TENTATIVE. */ ++ nm_log_warn (LOGD_DEVICE, "[%s] starting IPv6 with mode 'link-local', but the device has no link-local addresses configured.", ++ nm_device_get_iface (self)); ++ ++ return NM_ACT_STAGE_RETURN_STOP; ++} ++ + /* Get net.ipv6.conf.default.use_tempaddr value from /etc/sysctl.conf or + * /lib/sysctl.d/sysctl.conf + */ +@@ -3387,13 +3412,14 @@ act_stage3_ip6_config_start (NMDevice *self, + + priv->dhcp6_mode = NM_RDISC_DHCP_LEVEL_NONE; + +- if ( strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO) == 0 +- || strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL) == 0) { ++ if ( strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO) == 0) { + if (!addrconf6_start (self)) { + /* IPv6 might be disabled; allow IPv4 to proceed */ + ret = NM_ACT_STAGE_RETURN_STOP; + } else + ret = NM_ACT_STAGE_RETURN_POSTPONE; ++ } 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) { + /* Router advertisements shouldn't be used in pure DHCP mode */ + if (priv->ip6_accept_ra_path) +-- +1.8.5.3 + + +From e1d059d1a2d359504900d14e9d8acf0307187e6c Mon Sep 17 00:00:00 2001 +From: Dan Williams +Date: Thu, 7 Nov 2013 21:30:25 -0600 +Subject: [PATCH 07/14] core: fix hanlding of IPv6LL address if interface + already has one + +act_stage3_ip6_config_start() expects a non-NULL NMIP6Config if the +sub-method returns NM_ACT_STAGE_RETURN_SUCCESS. + +(cherry picked from commit 72063064567312ff6412c6d9996e8a6684df3f1d) +--- + src/devices/nm-device.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c +index 152814c..4384f6a 100644 +--- a/src/devices/nm-device.c ++++ b/src/devices/nm-device.c +@@ -3420,6 +3420,11 @@ act_stage3_ip6_config_start (NMDevice *self, + ret = NM_ACT_STAGE_RETURN_POSTPONE; + } else if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL) == 0) { + ret = linklocal6_start (self); ++ if (ret == NM_ACT_STAGE_RETURN_SUCCESS) { ++ /* New blank config; LL address is already in priv->ext_ip6_config */ ++ *out_config = nm_ip6_config_new (); ++ g_assert (*out_config); ++ } + } else if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_DHCP) == 0) { + /* Router advertisements shouldn't be used in pure DHCP mode */ + if (priv->ip6_accept_ra_path) +-- +1.8.5.3 + + +From 82abe50b59f09d80507d286d7259eb9038708363 Mon Sep 17 00:00:00 2001 +From: Thomas Haller +Date: Thu, 7 Nov 2013 22:59:43 +0100 +Subject: [PATCH 08/14] core: wait for IPv6 link local address with method + 'auto' and 'link-local' (bgo#707155) + +With the methods 'auto' and 'link-local' we check now, that the device +has a usable IPv6 LL address configured (after DAD, no longer tentative). + +We wait for up to 5 seconds, for a suitable LL address to appear. +Currently, if the address does not get ready, we don't create one and +IPv6 configuration fails. + +This is relevant for the methods 'link-local' and 'auto'. In the latter +case, because we cannot send router solitations without link local +address. + +https://bugzilla.gnome.org/show_bug.cgi?id=707155 + +(cherry picked from commit c4a087c36d34e584a48b6b866fc3c12f248f8512) + +Signed-off-by: Thomas Haller +--- + src/devices/nm-device.c | 170 +++++++++++++++++++++++++++++++++++++++--------- + 1 file changed, 140 insertions(+), 30 deletions(-) + +diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c +index 4384f6a..8c20a0d 100644 +--- a/src/devices/nm-device.c ++++ b/src/devices/nm-device.c +@@ -269,6 +269,8 @@ typedef struct { + /* IP6 config from autoconf */ + NMIP6Config * ac_ip6_config; + ++ guint linklocal6_timeout_id; ++ + char * ip6_accept_ra_path; + gint32 ip6_accept_ra_save; + +@@ -345,6 +347,8 @@ static void nm_device_queued_ip_config_change_clear (NMDevice *self); + static void update_ip_config (NMDevice *self); + static void device_ip_changed (NMPlatform *platform, int ifindex, gpointer platform_object, NMPlatformReason reason, gpointer user_data); + ++static void addrconf6_start_with_link_ready (NMDevice *self); ++ + static const char const *platform_ip_signals[] = { + NM_PLATFORM_IP4_ADDRESS_ADDED, + NM_PLATFORM_IP4_ADDRESS_CHANGED, +@@ -3092,6 +3096,104 @@ dhcp6_start (NMDevice *self, + + /******************************************/ + ++static gboolean ++linklocal6_config_is_ready (const NMIP6Config *ip6_config) ++{ ++ int i; ++ ++ if (!ip6_config) ++ return FALSE; ++ ++ for (i = 0; i < nm_ip6_config_get_num_addresses (ip6_config); i++) { ++ const NMPlatformIP6Address *addr = nm_ip6_config_get_address (ip6_config, i); ++ ++ if (IN6_IS_ADDR_LINKLOCAL (&addr->address) && ++ !(addr->flags & IFA_F_TENTATIVE)) ++ return TRUE; ++ } ++ ++ return FALSE; ++} ++ ++static void ++linklocal6_cleanup (NMDevice *self) ++{ ++ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); ++ ++ if (priv->linklocal6_timeout_id) { ++ g_source_remove (priv->linklocal6_timeout_id); ++ priv->linklocal6_timeout_id = 0; ++ } ++} ++ ++static gboolean ++linklocal6_timeout_cb (gpointer user_data) ++{ ++ NMDevice *self = user_data; ++ ++ linklocal6_cleanup (self); ++ ++ nm_log_dbg (LOGD_DEVICE, "[%s] linklocal6: waiting for link-local addresses failed due to timeout", ++ nm_device_get_iface (self)); ++ ++ nm_device_activate_schedule_ip6_config_timeout (self); ++ return G_SOURCE_REMOVE; ++} ++ ++static void ++linklocal6_complete (NMDevice *self) ++{ ++ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); ++ NMConnection *connection; ++ const char *method; ++ ++ g_assert (priv->linklocal6_timeout_id); ++ g_assert (linklocal6_config_is_ready (priv->ip6_config)); ++ ++ linklocal6_cleanup (self); ++ ++ connection = nm_device_get_connection (self); ++ g_assert (connection); ++ ++ method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP6_CONFIG); ++ ++ nm_log_dbg (LOGD_DEVICE, "[%s] linklocal6: waiting for link-local addresses successful, continue with method %s", ++ nm_device_get_iface (self), method); ++ ++ if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO) == 0) ++ addrconf6_start_with_link_ready (self); ++ else if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL) == 0) ++ nm_device_activate_schedule_ip6_config_result (self); ++ else ++ g_return_if_fail (FALSE); ++} ++ ++static NMActStageReturn ++linklocal6_start (NMDevice *self) ++{ ++ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); ++ NMConnection *connection; ++ const char *method; ++ ++ linklocal6_cleanup (self); ++ ++ if (linklocal6_config_is_ready (priv->ip6_config)) ++ return NM_ACT_STAGE_RETURN_SUCCESS; ++ ++ connection = nm_device_get_connection (self); ++ g_assert (connection); ++ ++ method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP6_CONFIG); ++ nm_log_dbg (LOGD_DEVICE, "[%s] linklocal6: starting IPv6 with method '%s', but the device has no link-local addresses configured. Wait.", ++ nm_device_get_iface (self), method); ++ ++ priv->linklocal6_timeout_id = g_timeout_add_seconds (5, linklocal6_timeout_cb, self); ++ ++ return NM_ACT_STAGE_RETURN_POSTPONE; ++} ++ ++/******************************************/ ++ + static void dhcp6_cleanup (NMDevice *self, gboolean stop, gboolean release); + + static void +@@ -3218,6 +3320,7 @@ addrconf6_start (NMDevice *self) + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMConnection *connection; + const char *ip_iface = nm_device_get_ip_iface (self); ++ NMActStageReturn ret; + + connection = nm_device_get_connection (self); + g_assert (connection); +@@ -3229,23 +3332,40 @@ addrconf6_start (NMDevice *self) + } + + priv->rdisc = nm_lndp_rdisc_new (nm_device_get_ip_ifindex (self), ip_iface); +- nm_platform_sysctl_set (priv->ip6_accept_ra_path, "0"); + + if (!priv->rdisc) { + nm_log_err (LOGD_IP6, "(%s): failed to start router discovery.", ip_iface); + return FALSE; + } + +- priv->rdisc_config_changed_sigid = g_signal_connect ( +- priv->rdisc, NM_RDISC_CONFIG_CHANGED, G_CALLBACK (rdisc_config_changed), self); ++ /* ensure link local is ready... */ ++ ret = linklocal6_start (self); ++ ++ if (ret == NM_ACT_STAGE_RETURN_SUCCESS) ++ addrconf6_start_with_link_ready (self); ++ else ++ g_return_val_if_fail (ret == NM_ACT_STAGE_RETURN_POSTPONE, TRUE); ++ ++ return TRUE; ++} ++ ++static void ++addrconf6_start_with_link_ready (NMDevice *self) ++{ ++ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); ++ ++ g_assert (priv->rdisc); + + /* FIXME: what if interface has no lladdr, like PPP? */ + if (priv->hw_addr_len) + nm_rdisc_set_lladdr (priv->rdisc, (const char *) priv->hw_addr, priv->hw_addr_len); + +- nm_rdisc_start (priv->rdisc); ++ nm_platform_sysctl_set (priv->ip6_accept_ra_path, "0"); + +- return TRUE; ++ priv->rdisc_config_changed_sigid = g_signal_connect (priv->rdisc, NM_RDISC_CONFIG_CHANGED, ++ G_CALLBACK (rdisc_config_changed), self); ++ ++ nm_rdisc_start (priv->rdisc); + } + + static void +@@ -3265,31 +3385,6 @@ addrconf6_cleanup (NMDevice *self) + + /******************************************/ + +-static int +-linklocal6_start (NMDevice *self) +-{ +- NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); +- int i; +- +- if (priv->ip6_config) { +- for (i = 0; i < nm_ip6_config_get_num_addresses (priv->ip6_config); i++) { +- const NMPlatformIP6Address *addr = nm_ip6_config_get_address (priv->ip6_config, i); +- +- if (addr->plen == 128 && IN6_IS_ADDR_LINKLOCAL (&addr->address)) { +- /* FIXME: only accept the address if it is no longer TENTATIVE */ +- return NM_ACT_STAGE_RETURN_SUCCESS; +- } +- } +- } +- +- /* FIXME: we should NM_ACT_STAGE_RETURN_POSTPONE and wait until with timeout +- * we get a link local address that is no longer TENTATIVE. */ +- nm_log_warn (LOGD_DEVICE, "[%s] starting IPv6 with mode 'link-local', but the device has no link-local addresses configured.", +- nm_device_get_iface (self)); +- +- return NM_ACT_STAGE_RETURN_STOP; +-} +- + /* Get net.ipv6.conf.default.use_tempaddr value from /etc/sysctl.conf or + * /lib/sysctl.d/sysctl.conf + */ +@@ -4397,6 +4492,7 @@ nm_device_deactivate (NMDevice *self, NMDeviceStateReason reason) + + dhcp4_cleanup (self, TRUE, FALSE); + dhcp6_cleanup (self, TRUE, FALSE); ++ linklocal6_cleanup (self); + addrconf6_cleanup (self); + dnsmasq_cleanup (self); + aipd_cleanup (self); +@@ -5179,6 +5275,7 @@ dispose (GObject *object) + /* Clean up and stop DHCP */ + dhcp4_cleanup (self, deconfigure, FALSE); + dhcp6_cleanup (self, deconfigure, FALSE); ++ linklocal6_cleanup (self); + addrconf6_cleanup (self); + dnsmasq_cleanup (self); + +@@ -6346,6 +6443,7 @@ update_ip_config (NMDevice *self) + { + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + int ifindex; ++ gboolean linklocal6_just_completed = FALSE; + + ifindex = nm_device_get_ip_ifindex (self); + if (!ifindex) +@@ -6367,6 +6465,11 @@ update_ip_config (NMDevice *self) + g_clear_object (&priv->ext_ip6_config); + priv->ext_ip6_config = nm_ip6_config_capture (ifindex); + if (priv->ext_ip6_config) { ++ ++ /* Check this before modifying ext_ip6_config */ ++ linklocal6_just_completed = priv->linklocal6_timeout_id && ++ linklocal6_config_is_ready (priv->ext_ip6_config); ++ + if (priv->ac_ip6_config) + nm_ip6_config_subtract (priv->ext_ip6_config, priv->ac_ip6_config); + if (priv->dhcp6_ip6_config) +@@ -6376,6 +6479,13 @@ update_ip_config (NMDevice *self) + + ip6_config_merge_and_apply (self, FALSE, NULL); + } ++ ++ if (linklocal6_just_completed) { ++ /* linklocal6 is ready now, do the state transition... we are also ++ * invoked as g_idle_add, so no problems with reentrance doing it now. ++ */ ++ linklocal6_complete (self); ++ } + } + + static gboolean +-- +1.8.5.3 + + +From 6133195b274165a8494edcf58560e2e96b39a89d Mon Sep 17 00:00:00 2001 +From: Thomas Haller +Date: Mon, 6 Jan 2014 21:05:00 +0100 +Subject: [PATCH 09/14] core/rdisc: limit the number of autoconf addresses to + 'max_addresses' + +NetworkManager uses the sysctl value 'max_addresses' as the kernel does. +There is however a difference in what addresses are taken into account. +The kernel counts all addresses on the interface (including temporary, +private addresses and user configured ones). +NM instead only limits the number of public autoconf addresses to +'max_addresses'. This is because it is difficult for NM to count all +addresses (which can come from different sources) and it is not +necessarily a more logical behavior. Only be aware, that NM uses +the same config value as the kernel, but counts differently. + +Especially, the kernel might reach the limit earlier then NM in the +presence of temporary addresses or addresses not from SLAAC. + +Note, that the kernel uses 'max_addresses' only to limit public, autoconf +addresses. So this limit does not affect NM adding as many addresses as +it wants. + +(cherry picked from commit 84dc64c8affd658077fa3967d42374d6c3a2951c) + +Signed-off-by: Thomas Haller +--- + src/devices/nm-device.c | 23 ++++++++++++++++++++++- + src/rdisc/nm-fake-rdisc.c | 3 ++- + src/rdisc/nm-fake-rdisc.h | 2 +- + src/rdisc/nm-lndp-rdisc.c | 10 +++++++++- + src/rdisc/nm-lndp-rdisc.h | 2 +- + src/rdisc/nm-rdisc.h | 1 + + src/rdisc/tests/rdisc.c | 4 ++-- + 7 files changed, 38 insertions(+), 7 deletions(-) + +diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c +index 8c20a0d..e8ed2ba 100644 +--- a/src/devices/nm-device.c ++++ b/src/devices/nm-device.c +@@ -449,6 +449,21 @@ update_ip6_privacy_save (NMDevice *self) + } + } + ++static gint32 ++sysctl_get_ipv6_max_addresses (const char *dev) ++{ ++ gint32 max_addresses = 16; ++ char *path; ++ ++ g_return_val_if_fail (dev && *dev, max_addresses); ++ ++ path = g_strdup_printf ("/proc/sys/net/ipv6/conf/%s/max_addresses", dev); ++ max_addresses = nm_platform_sysctl_get_int32 (path, max_addresses); ++ g_free (path); ++ ++ return max_addresses; ++} ++ + /* + * Get driver info from SIOCETHTOOL ioctl() for 'iface' + * Returns driver and firmware versions to 'driver_version and' 'firmware_version' +@@ -3225,6 +3240,11 @@ rdisc_config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, NMDevice *device + /* Rebuild address list from router discovery cache. */ + nm_ip6_config_reset_addresses (priv->ac_ip6_config); + ++ /* rdisc->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 < rdisc->addresses->len; i++) { + NMRDiscAddress *discovered_address = &g_array_index (rdisc->addresses, NMRDiscAddress, i); + NMPlatformIP6Address address; +@@ -3331,7 +3351,8 @@ addrconf6_start (NMDevice *self) + priv->ac_ip6_config = NULL; + } + +- priv->rdisc = nm_lndp_rdisc_new (nm_device_get_ip_ifindex (self), ip_iface); ++ priv->rdisc = nm_lndp_rdisc_new (nm_device_get_ip_ifindex (self), ip_iface, ++ sysctl_get_ipv6_max_addresses (ip_iface)); + + if (!priv->rdisc) { + nm_log_err (LOGD_IP6, "(%s): failed to start router discovery.", ip_iface); +diff --git a/src/rdisc/nm-fake-rdisc.c b/src/rdisc/nm-fake-rdisc.c +index f39c5a2..38faa50 100644 +--- a/src/rdisc/nm-fake-rdisc.c ++++ b/src/rdisc/nm-fake-rdisc.c +@@ -36,7 +36,7 @@ G_DEFINE_TYPE (NMFakeRDisc, nm_fake_rdisc, NM_TYPE_RDISC) + /******************************************************************/ + + NMRDisc * +-nm_fake_rdisc_new (int ifindex, const char *ifname) ++nm_fake_rdisc_new (int ifindex, const char *ifname, gint32 max_addresses) + { + NMRDisc *rdisc = g_object_new (NM_TYPE_FAKE_RDISC, NULL); + +@@ -44,6 +44,7 @@ nm_fake_rdisc_new (int ifindex, const char *ifname) + + rdisc->ifindex = ifindex; + rdisc->ifname = g_strdup (ifname); ++ rdisc->max_addresses = max_addresses; + + return rdisc; + } +diff --git a/src/rdisc/nm-fake-rdisc.h b/src/rdisc/nm-fake-rdisc.h +index 248283b..cff9ee4 100644 +--- a/src/rdisc/nm-fake-rdisc.h ++++ b/src/rdisc/nm-fake-rdisc.h +@@ -44,6 +44,6 @@ typedef struct { + + GType nm_fake_rdisc_get_type (void); + +-NMRDisc *nm_fake_rdisc_new (int ifindex, const char *ifname); ++NMRDisc *nm_fake_rdisc_new (int ifindex, const char *ifname, gint32 max_addressses); + + #endif /* NM_FAKE_RDISC_H */ +diff --git a/src/rdisc/nm-lndp-rdisc.c b/src/rdisc/nm-lndp-rdisc.c +index c9bb2cf..c328f99 100644 +--- a/src/rdisc/nm-lndp-rdisc.c ++++ b/src/rdisc/nm-lndp-rdisc.c +@@ -48,7 +48,7 @@ G_DEFINE_TYPE (NMLNDPRDisc, nm_lndp_rdisc, NM_TYPE_RDISC) + /******************************************************************/ + + NMRDisc * +-nm_lndp_rdisc_new (int ifindex, const char *ifname) ++nm_lndp_rdisc_new (int ifindex, const char *ifname, gint32 max_addresses) + { + NMRDisc *rdisc; + NMLNDPRDiscPrivate *priv; +@@ -59,6 +59,7 @@ nm_lndp_rdisc_new (int ifindex, const char *ifname) + + rdisc->ifindex = ifindex; + rdisc->ifname = g_strdup (ifname); ++ rdisc->max_addresses = max_addresses; + + priv = NM_LNDP_RDISC_GET_PRIVATE (rdisc); + error = ndp_open (&priv->ndp); +@@ -113,6 +114,13 @@ add_address (NMRDisc *rdisc, const NMRDiscAddress *new) + } + } + ++ /* we create at most max_addresses autoconf addresses. This is different from ++ * what the kernel does, because it considers *all* addresses (including ++ * static and other temporary addresses). ++ **/ ++ if (rdisc->max_addresses && rdisc->addresses->len >= rdisc->max_addresses) ++ return FALSE; ++ + g_array_insert_val (rdisc->addresses, i, *new); + return TRUE; + } +diff --git a/src/rdisc/nm-lndp-rdisc.h b/src/rdisc/nm-lndp-rdisc.h +index eb6a1df..30d53db 100644 +--- a/src/rdisc/nm-lndp-rdisc.h ++++ b/src/rdisc/nm-lndp-rdisc.h +@@ -44,6 +44,6 @@ typedef struct { + + GType nm_lndp_rdisc_get_type (void); + +-NMRDisc *nm_lndp_rdisc_new (int ifindex, const char *ifname); ++NMRDisc *nm_lndp_rdisc_new (int ifindex, const char *ifname, gint32 max_addresses); + + #endif /* NM_LNDP_RDISC_H */ +diff --git a/src/rdisc/nm-rdisc.h b/src/rdisc/nm-rdisc.h +index c645bda..219b6b2 100644 +--- a/src/rdisc/nm-rdisc.h ++++ b/src/rdisc/nm-rdisc.h +@@ -106,6 +106,7 @@ typedef struct { + int ifindex; + char *ifname; + GBytes *lladdr; ++ gint32 max_addresses; + + NMRDiscDHCPLevel dhcp_level; + GArray *gateways; +diff --git a/src/rdisc/tests/rdisc.c b/src/rdisc/tests/rdisc.c +index 680bb2e..e8e2a9f 100644 +--- a/src/rdisc/tests/rdisc.c ++++ b/src/rdisc/tests/rdisc.c +@@ -12,7 +12,7 @@ main (int argc, char **argv) + { + GMainLoop *loop; + NMRDisc *rdisc; +- NMRDisc *(*new) (int ifindex, const char *ifname) = nm_lndp_rdisc_new; ++ NMRDisc *(*new) (int ifindex, const char *ifname, gint32 max_addresses) = nm_lndp_rdisc_new; + int ifindex = 1; + char ifname[IF_NAMESIZE]; + char mac[6] = { 0x02, 0xaa, 0xbb, 0xcc, 0xdd, 0xee }; +@@ -34,7 +34,7 @@ main (int argc, char **argv) + } + } + +- rdisc = new (ifindex, ifname); ++ rdisc = new (ifindex, ifname, 0); + if (!rdisc) + return EXIT_FAILURE; + +-- +1.8.5.3 + + +From dc11f1ca2ee02f986b714f1def9fe64e1de14f35 Mon Sep 17 00:00:00 2001 +From: Thomas Haller +Date: Fri, 3 Jan 2014 16:07:36 +0100 +Subject: [PATCH 10/14] core/platform: workaround new address flag in + address_to_string + +The kernel and libnl adds two new flags IFA_F_MANAGETEMPADDR +and IFA_F_NOPREFIXROUTE. Older versions of libnl do not recognize +this flag, so add a workaround to nm_platform_ip6_address_to_string() +to show "mngtmpaddr" and "noprefixroute", respectively. + +Also, add function nm_platform_check_support_libnl_extended_ifa_flags() +that checks whether libnl supports extended ifa_flags that were +added recently. + +Extended flags and the two ifa-flags above were added to libnl in close +succession. + +(cherry picked from commit 2bc61d1ad3278d4fc38d17bd6178e7e304c6339a) + +Signed-off-by: Thomas Haller +--- + src/platform/nm-platform.c | 41 ++++++++++++++++++++++++++++++++++++++++- + src/platform/nm-platform.h | 2 ++ + 2 files changed, 42 insertions(+), 1 deletion(-) + +diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c +index cf21e5c..92c9c30 100644 +--- a/src/platform/nm-platform.c ++++ b/src/platform/nm-platform.c +@@ -31,6 +31,14 @@ + #include "nm-logging.h" + #include "nm-enum-types.h" + ++/* workaround for older libnl version, that does not define these flags. */ ++#ifndef IFA_F_MANAGETEMPADDR ++#define IFA_F_MANAGETEMPADDR 0x100 ++#endif ++#ifndef IFA_F_NOPREFIXROUTE ++#define IFA_F_NOPREFIXROUTE 0x200 ++#endif ++ + #define debug(...) nm_log_dbg (LOGD_PLATFORM, __VA_ARGS__) + + #define NM_PLATFORM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_PLATFORM, NMPlatformPrivate)) +@@ -196,6 +204,22 @@ reset_error (void) + platform->error = NM_PLATFORM_ERROR_NONE; + } + ++#define IFA_F_MANAGETEMPADDR_STR "mngtmpaddr" ++#define IFA_F_NOPREFIXROUTE_STR "noprefixroute" ++gboolean ++nm_platform_check_support_libnl_extended_ifa_flags () ++{ ++ static int supported = -1; ++ ++ /* support for extended ifa-flags was added together ++ * with the IFA_F_MANAGETEMPADDR flag. So, check if libnl ++ * is able to parse this flag. */ ++ if (supported == -1) ++ supported = rtnl_addr_str2flags (IFA_F_MANAGETEMPADDR_STR) == IFA_F_MANAGETEMPADDR; ++ ++ return supported; ++} ++ + /******************************************************************/ + + /** +@@ -1688,7 +1712,22 @@ nm_platform_ip6_address_to_string (const NMPlatformIP6Address *address) + inet_ntop (AF_INET6, &address->address, s_address, sizeof (s_address)); + s_dev = address->ifindex > 0 ? nm_platform_link_get_name (address->ifindex) : NULL; + +- rtnl_addr_flags2str(address->flags, s_flags, sizeof(s_flags)); ++ rtnl_addr_flags2str(address->flags, s_flags, sizeof (s_flags)); ++ ++ /* There are two recent flags IFA_F_MANAGETEMPADDR and IFA_F_NOPREFIXROUTE. ++ * If libnl does not yet support them, add them by hand. ++ * These two flags were introduced together with the extended ifa_flags, ++ * so, check for that. ++ **/ ++ if ((address->flags && IFA_F_MANAGETEMPADDR) & !nm_platform_check_support_libnl_extended_ifa_flags ()) { ++ strncat (s_flags, s_flags[0] ? "," IFA_F_MANAGETEMPADDR_STR : IFA_F_MANAGETEMPADDR_STR, ++ sizeof (s_flags) - strlen (s_flags) - 1); ++ } ++ if ((address->flags && IFA_F_NOPREFIXROUTE) & !nm_platform_check_support_libnl_extended_ifa_flags ()) { ++ strncat (s_flags, s_flags[0] ? "," IFA_F_NOPREFIXROUTE_STR : IFA_F_NOPREFIXROUTE_STR, ++ sizeof (s_flags) - strlen (s_flags) - 1); ++ } ++ + str_flags = s_flags[0] ? g_strconcat (" flags ", s_flags, NULL) : NULL; + + g_snprintf (buffer, sizeof (buffer), "%s/%d lft %u pref %u time %u dev %s%s", +diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h +index d4864d0..26a6737 100644 +--- a/src/platform/nm-platform.h ++++ b/src/platform/nm-platform.h +@@ -444,6 +444,8 @@ int nm_platform_ip6_address_cmp (const NMPlatformIP6Address *a, const NMPlatform + int nm_platform_ip4_route_cmp (const NMPlatformIP4Route *a, const NMPlatformIP4Route *b); + int nm_platform_ip6_route_cmp (const NMPlatformIP6Route *a, const NMPlatformIP6Route *b); + ++gboolean nm_platform_check_support_libnl_extended_ifa_flags (void); ++ + #define auto_g_free __attribute__((cleanup(put_g_free))) + static void __attribute__((unused)) + put_g_free (void *ptr) +-- +1.8.5.3 + + +From 57af43c6118d8d62a8671919833864e2d5e3a270 Mon Sep 17 00:00:00 2001 +From: Thomas Haller +Date: Tue, 7 Jan 2014 17:21:12 +0100 +Subject: [PATCH 11/14] core/platform: add + check_support_kernel_extended_ifa_flags function + +The kernel adds a new capability to allow user space to manage +temporary IPv6 addresses. We need to detect this capability +to act differently, depending on whether NM has an older kernel +at hand. + +This capability got introduced together when extending the +ifa_flags to 32 bit. So, we can check the netlink message, +whether we have such an nl attribute at hand. + +(cherry picked from commit 7841f9ea0a4efdcb4540628cf65d7d9356b748f7) + +Signed-off-by: Thomas Haller +--- + src/platform/nm-linux-platform.c | 57 ++++++++++++++++++++++++++++++++++++++++ + src/platform/nm-platform.c | 11 ++++++++ + src/platform/nm-platform.h | 3 +++ + 3 files changed, 71 insertions(+) + +diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c +index 1a44c40..b60f101 100644 +--- a/src/platform/nm-linux-platform.c ++++ b/src/platform/nm-linux-platform.c +@@ -65,6 +65,8 @@ typedef struct { + + GUdevClient *udev_client; + GHashTable *udev_devices; ++ ++ int support_kernel_extended_ifa_flags; + } NMLinuxPlatformPrivate; + + #define NM_LINUX_PLATFORM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_LINUX_PLATFORM, NMLinuxPlatformPrivate)) +@@ -427,6 +429,45 @@ ethtool_get_stringset_index (const char *ifname, int stringset_id, const char *s + + /******************************************************************/ + ++static void ++_check_support_kernel_extended_ifa_flags_init (NMLinuxPlatformPrivate *priv, struct nl_msg *msg) ++{ ++ struct nlmsghdr *msg_hdr = nlmsg_hdr (msg); ++ ++ g_return_if_fail (priv->support_kernel_extended_ifa_flags == 0); ++ g_return_if_fail (msg_hdr->nlmsg_type == RTM_NEWADDR); ++ ++ /* the extended address flags are only set for AF_INET6 */ ++ if (((struct ifaddrmsg *) nlmsg_data (msg_hdr))->ifa_family != AF_INET6) ++ return; ++ ++ /* see if the nl_msg contains the IFA_FLAGS attribute. If it does, ++ * we assume, that the kernel supports extended flags, IFA_F_MANAGETEMPADDR ++ * and IFA_F_NOPREFIXROUTE (they were added together). ++ **/ ++ priv->support_kernel_extended_ifa_flags = ++ nlmsg_find_attr (msg_hdr, sizeof (struct ifaddrmsg), 8 /* IFA_FLAGS */) ++ ? 1 : -1; ++} ++ ++static gboolean ++check_support_kernel_extended_ifa_flags (NMPlatform *platform) ++{ ++ NMLinuxPlatformPrivate *priv; ++ ++ g_return_val_if_fail (NM_IS_LINUX_PLATFORM (platform), FALSE); ++ ++ priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); ++ ++ if (priv->support_kernel_extended_ifa_flags == 0) { ++ g_warn_if_reached (); ++ priv->support_kernel_extended_ifa_flags = -1; ++ } ++ ++ return priv->support_kernel_extended_ifa_flags > 0; ++} ++ ++ + /* Object type specific utilities */ + + static const char * +@@ -1195,6 +1236,14 @@ event_notification (struct nl_msg *msg, gpointer user_data) + int nle; + + event = nlmsg_hdr (msg)->nlmsg_type; ++ ++ if (priv->support_kernel_extended_ifa_flags == 0 && event == RTM_NEWADDR) { ++ /* if kernel support for extended ifa flags is still undecided, use the opportunity ++ * now and use @msg to decide it. This saves a blocking net link request. ++ **/ ++ _check_support_kernel_extended_ifa_flags_init (priv, msg); ++ } ++ + nl_msg_parse (msg, ref_object, &object); + g_return_val_if_fail (object, NL_OK); + +@@ -2744,6 +2793,12 @@ setup (NMPlatform *platform) + g_list_free (devices); + g_object_unref (enumerator); + ++ /* request all IPv6 addresses (hopeing that there is at least one), to check for ++ * the IFA_FLAGS attribute. */ ++ nle = nl_rtgen_request (priv->nlh_event, RTM_GETADDR, AF_INET6, NLM_F_DUMP); ++ if (nle != 0) ++ nm_log_warn (LOGD_PLATFORM, "Netlink error: requesting RTM_GETADDR failed with %s", nl_geterror (nle)); ++ + return TRUE; + } + +@@ -2848,4 +2903,6 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass) + platform_class->ip6_route_delete = ip6_route_delete; + platform_class->ip4_route_exists = ip4_route_exists; + platform_class->ip6_route_exists = ip6_route_exists; ++ ++ platform_class->check_support_kernel_extended_ifa_flags = check_support_kernel_extended_ifa_flags; + } +diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c +index 92c9c30..5871f86 100644 +--- a/src/platform/nm-platform.c ++++ b/src/platform/nm-platform.c +@@ -220,6 +220,17 @@ nm_platform_check_support_libnl_extended_ifa_flags () + return supported; + } + ++gboolean ++nm_platform_check_support_kernel_extended_ifa_flags () ++{ ++ g_return_val_if_fail (NM_IS_PLATFORM (platform), FALSE); ++ ++ if (!klass->check_support_kernel_extended_ifa_flags) ++ return FALSE; ++ ++ return klass->check_support_kernel_extended_ifa_flags (platform); ++} ++ + /******************************************************************/ + + /** +diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h +index 26a6737..d5b3672 100644 +--- a/src/platform/nm-platform.h ++++ b/src/platform/nm-platform.h +@@ -302,6 +302,8 @@ typedef struct { + gboolean (*ip6_route_delete) (NMPlatform *, int ifindex, struct in6_addr network, int plen, int metric); + gboolean (*ip4_route_exists) (NMPlatform *, int ifindex, in_addr_t network, int plen, int metric); + gboolean (*ip6_route_exists) (NMPlatform *, int ifindex, struct in6_addr network, int plen, int metric); ++ ++ gboolean (*check_support_kernel_extended_ifa_flags) (NMPlatform *); + } NMPlatformClass; + + /* NMPlatform signals +@@ -445,6 +447,7 @@ int nm_platform_ip4_route_cmp (const NMPlatformIP4Route *a, const NMPlatformIP4R + int nm_platform_ip6_route_cmp (const NMPlatformIP6Route *a, const NMPlatformIP6Route *b); + + gboolean nm_platform_check_support_libnl_extended_ifa_flags (void); ++gboolean nm_platform_check_support_kernel_extended_ifa_flags (void); + + #define auto_g_free __attribute__((cleanup(put_g_free))) + static void __attribute__((unused)) +-- +1.8.5.3 + + +From 399f5d8dfd7a74dbd9043015e15df3fa1644fefb Mon Sep 17 00:00:00 2001 +From: Thomas Haller +Date: Fri, 31 Jan 2014 14:54:31 +0100 +Subject: [PATCH 12/14] core/platform: fix wrong warning log in + nm-linux-platform + +According to documentation, nl_rtgen_request() returns 0 on success. +Due to a bug (fixed upstream) in older libnl versions, nl_rtgen_request() +returns the number of bytes sent, which caused logging although +succeeding. + +(cherry picked from commit 6c2f96421b1c7bfd65032bf4de2a6cfc10b3b262) + +Signed-off-by: Thomas Haller +--- + src/platform/nm-linux-platform.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c +index b60f101..7933678 100644 +--- a/src/platform/nm-linux-platform.c ++++ b/src/platform/nm-linux-platform.c +@@ -2796,7 +2796,7 @@ setup (NMPlatform *platform) + /* request all IPv6 addresses (hopeing that there is at least one), to check for + * the IFA_FLAGS attribute. */ + nle = nl_rtgen_request (priv->nlh_event, RTM_GETADDR, AF_INET6, NLM_F_DUMP); +- if (nle != 0) ++ if (nle < 0) + nm_log_warn (LOGD_PLATFORM, "Netlink error: requesting RTM_GETADDR failed with %s", nl_geterror (nle)); + + return TRUE; +-- +1.8.5.3 + + +From b7a960b1287b11ff3db02204a2ff6888efa571f5 Mon Sep 17 00:00:00 2001 +From: Thomas Haller +Date: Fri, 3 Jan 2014 17:03:35 +0100 +Subject: [PATCH 13/14] core/rdisc: add autoconf addresses as /64 (instead of + /128) + +This feature needs support from the kernel and libnl. + +If there is no system support, NM acts as before, adding the +autoconf address as /128. It does so, to prevent the kernel +from adding a route for this prefix. With system support, we +add the address as /64 and set the flag IFA_F_NOPREFIXROUTE. + +https://bugzilla.redhat.com/show_bug.cgi?id=1044590 +https://bugzilla.redhat.com/show_bug.cgi?id=1045118 + +(cherry picked from commit 39cbe772a67aece69dc30f8f394bba2eea9ca762) + +Signed-off-by: Thomas Haller +--- + src/devices/nm-device.c | 28 +++++++++++++++++++++++++++- + 1 file changed, 27 insertions(+), 1 deletion(-) + +diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c +index e8ed2ba..2e870a8 100644 +--- a/src/devices/nm-device.c ++++ b/src/devices/nm-device.c +@@ -36,6 +36,7 @@ + #include + #include + #include ++#include + + #include "libgsystem.h" + #include "nm-glib-compat.h" +@@ -68,6 +69,11 @@ + #include "nm-config.h" + #include "nm-platform.h" + ++/* workaround for older libnl version, that does not define this flag. */ ++#ifndef IFA_F_NOPREFIXROUTE ++#define IFA_F_NOPREFIXROUTE 0x200 ++#endif ++ + static void impl_device_disconnect (NMDevice *device, DBusGMethodInvocation *context); + + #include "nm-device-glue.h" +@@ -3218,6 +3224,25 @@ rdisc_config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, NMDevice *device + NMConnection *connection; + int i; + NMDeviceStateReason reason; ++ static int system_support = -1; ++ guint ifa_flags; ++ ++ if (system_support == -1) { ++ /* ++ * Check, if both libnl and the kernel are recent enough, ++ * to help user space handling RA. If it's not supported, ++ * we must add autoconf addresses as /128. ++ * The reason for /128 is to prevent the kernel from adding ++ * a prefix route for this address. ++ **/ ++ system_support = nm_platform_check_support_libnl_extended_ifa_flags () && ++ nm_platform_check_support_kernel_extended_ifa_flags (); ++ } ++ ++ /* without system_support, this flag will be ignored. ++ * Still, we set it (why not?). ++ **/ ++ ifa_flags = IFA_F_NOPREFIXROUTE; + + g_return_if_fail (priv->act_request); + connection = nm_device_get_connection (device); +@@ -3251,10 +3276,11 @@ rdisc_config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, NMDevice *device + + memset (&address, 0, sizeof (address)); + address.address = discovered_address->address; +- address.plen = 128; ++ address.plen = system_support ? 64 : 128; + address.timestamp = discovered_address->timestamp; + address.lifetime = discovered_address->lifetime; + address.preferred = discovered_address->preferred; ++ address.flags = ifa_flags; + + nm_ip6_config_add_address (priv->ac_ip6_config, &address); + } +-- +1.8.5.3 + + +From 14705adcd0a1f87d31623cd3c99978d1a5c0161a Mon Sep 17 00:00:00 2001 +From: Thomas Haller +Date: Fri, 3 Jan 2014 17:03:35 +0100 +Subject: [PATCH 14/14] core/rdisc: add support for IPv6 privacy + +Add support for ipv6-private addresses. This feature +needs support from the kernel and libnl. + +If there is no system support, temporary addresses are +not supported. Log a warning in this case. + +Depending on whether ipv6-privacy (use_tempaddr) is enabled, +we add the address flag IFA_F_MANAGETEMPADDR and the kernel +will add temporary addresses for us. + +https://bugzilla.gnome.org/show_bug.cgi?id=705170 +https://bugzilla.redhat.com/show_bug.cgi?id=1003859 +https://bugzilla.redhat.com/show_bug.cgi?id=1047139 + +(cherry picked from commit 1dea2714697b8cfe386c6665d7e556d537bebaf0) + +Signed-off-by: Thomas Haller +--- + src/devices/nm-device.c | 122 +++++++++++++++++++++++++++++++++++++----------- + 1 file changed, 96 insertions(+), 26 deletions(-) + +diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c +index 2e870a8..39146a6 100644 +--- a/src/devices/nm-device.c ++++ b/src/devices/nm-device.c +@@ -69,7 +69,10 @@ + #include "nm-config.h" + #include "nm-platform.h" + +-/* workaround for older libnl version, that does not define this flag. */ ++/* workaround for older libnl version, that does not define these flags. */ ++#ifndef IFA_F_MANAGETEMPADDR ++#define IFA_F_MANAGETEMPADDR 0x100 ++#endif + #ifndef IFA_F_NOPREFIXROUTE + #define IFA_F_NOPREFIXROUTE 0x200 + #endif +@@ -272,6 +275,7 @@ typedef struct { + + NMRDisc * rdisc; + gulong rdisc_config_changed_sigid; ++ NMSettingIP6ConfigPrivacy rdisc_use_tempaddr; + /* IP6 config from autoconf */ + NMIP6Config * ac_ip6_config; + +@@ -3218,6 +3222,53 @@ linklocal6_start (NMDevice *self) + static void dhcp6_cleanup (NMDevice *self, gboolean stop, gboolean release); + + static void ++print_support_extended_ifa_flags (NMSettingIP6ConfigPrivacy use_tempaddr) ++{ ++ static gint8 warn = 0; ++ static gint8 s_libnl = -1, s_kernel; ++ ++ if (warn >= 2) ++ return; ++ ++ if (s_libnl == -1) { ++ s_libnl = !!nm_platform_check_support_libnl_extended_ifa_flags (); ++ s_kernel = !!nm_platform_check_support_kernel_extended_ifa_flags (); ++ ++ if (s_libnl && s_kernel) { ++ nm_log_dbg (LOGD_IP6, "kernel and libnl support extended IFA_FLAGS (needed by NM for IPv6 private addresses)"); ++ warn = 2; ++ return; ++ } ++ } ++ ++ if ( use_tempaddr != NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR ++ && use_tempaddr != NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR) { ++ if (warn == 0) { ++ nm_log_dbg (LOGD_IP6, "%s%s%s %s not support extended IFA_FLAGS (needed by NM for IPv6 private addresses)", ++ !s_kernel ? "kernel" : "", ++ !s_kernel && !s_libnl ? " and " : "", ++ !s_libnl ? "libnl" : "", ++ !s_kernel && !s_libnl ? "do" : "does"); ++ warn = 1; ++ } ++ return; ++ } ++ ++ if (!s_libnl && !s_kernel) { ++ nm_log_warn (LOGD_IP6, "libnl and the kernel do not support extended IFA_FLAGS needed by NM for " ++ "IPv6 private addresses. This feature is not available"); ++ } else if (!s_libnl) { ++ nm_log_warn (LOGD_IP6, "libnl does not support extended IFA_FLAGS needed by NM for " ++ "IPv6 private addresses. This feature is not available"); ++ } else if (!s_kernel) { ++ nm_log_warn (LOGD_IP6, "The kernel does not support extended IFA_FLAGS needed by NM for " ++ "IPv6 private addresses. This feature is not available"); ++ } ++ ++ warn = 2; ++} ++ ++static void + rdisc_config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, NMDevice *device) + { + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (device); +@@ -3231,18 +3282,21 @@ rdisc_config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, NMDevice *device + /* + * Check, if both libnl and the kernel are recent enough, + * to help user space handling RA. If it's not supported, +- * we must add autoconf addresses as /128. +- * The reason for /128 is to prevent the kernel from adding +- * a prefix route for this address. ++ * we have no ipv6-privacy and must add autoconf addresses ++ * as /128. The reason for the /128 is to prevent the kernel ++ * from adding a prefix route for this address. + **/ + system_support = nm_platform_check_support_libnl_extended_ifa_flags () && + nm_platform_check_support_kernel_extended_ifa_flags (); + } + +- /* without system_support, this flag will be ignored. +- * Still, we set it (why not?). ++ /* without system_support, these flags will be ignored. ++ * Still, we set them (why not?). + **/ + 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) ++ ifa_flags |= IFA_F_MANAGETEMPADDR; + + g_return_if_fail (priv->act_request); + connection = nm_device_get_connection (device); +@@ -3361,7 +3415,7 @@ rdisc_config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, NMDevice *device + } + + static gboolean +-addrconf6_start (NMDevice *self) ++addrconf6_start (NMDevice *self, NMSettingIP6ConfigPrivacy use_tempaddr) + { + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMConnection *connection; +@@ -3385,6 +3439,9 @@ addrconf6_start (NMDevice *self) + return FALSE; + } + ++ priv->rdisc_use_tempaddr = use_tempaddr; ++ print_support_extended_ifa_flags (use_tempaddr); ++ + /* ensure link local is ready... */ + ret = linklocal6_start (self); + +@@ -3432,10 +3489,23 @@ addrconf6_cleanup (NMDevice *self) + + /******************************************/ + ++static NMSettingIP6ConfigPrivacy ++use_tempaddr_clamp (NMSettingIP6ConfigPrivacy use_tempaddr) ++{ ++ switch (use_tempaddr) { ++ case NM_SETTING_IP6_CONFIG_PRIVACY_DISABLED: ++ case NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR: ++ case NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR: ++ return use_tempaddr; ++ default: ++ return NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN; ++ } ++} ++ + /* Get net.ipv6.conf.default.use_tempaddr value from /etc/sysctl.conf or + * /lib/sysctl.d/sysctl.conf + */ +-static int ++static NMSettingIP6ConfigPrivacy + ip6_use_tempaddr (void) + { + char *contents = NULL; +@@ -3443,12 +3513,13 @@ ip6_use_tempaddr (void) + char *sysctl_data = NULL; + GKeyFile *keyfile; + GError *error = NULL; +- int tmp, ret = -1; ++ gint tmp; ++ NMSettingIP6ConfigPrivacy ret = NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN; + + /* Read file contents to a string. */ + if (!g_file_get_contents ("/etc/sysctl.conf", &contents, NULL, NULL)) + if (!g_file_get_contents ("/lib/sysctl.d/sysctl.conf", &contents, NULL, NULL)) +- return -1; ++ return NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN; + + /* Prepend a group so that we can use GKeyFile parser. */ + sysctl_data = g_strdup_printf ("%s%s", group_name, contents); +@@ -3459,7 +3530,7 @@ ip6_use_tempaddr (void) + + tmp = g_key_file_get_integer (keyfile, "forged_group", "net.ipv6.conf.default.use_tempaddr", &error); + if (error == NULL) +- ret = tmp; ++ ret = use_tempaddr_clamp (tmp); + + done: + g_free (contents); +@@ -3499,8 +3570,7 @@ act_stage3_ip6_config_start (NMDevice *self, + NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; + NMConnection *connection; + NMSettingIP6Config *s_ip6; +- const char *method = NM_SETTING_IP6_CONFIG_METHOD_AUTO; +- int conf_use_tempaddr; ++ const char *method; + NMSettingIP6ConfigPrivacy ip6_privacy = NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN; + const char *ip6_privacy_str = "0\n"; + GSList *slaves; +@@ -3554,8 +3624,19 @@ act_stage3_ip6_config_start (NMDevice *self, + + priv->dhcp6_mode = NM_RDISC_DHCP_LEVEL_NONE; + +- if ( strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO) == 0) { +- if (!addrconf6_start (self)) { ++ /* Enable/disable IPv6 Privacy Extensions. ++ * If a global value is configured by sysadmin (e.g. /etc/sysctl.conf), ++ * use that value instead of per-connection value. ++ */ ++ ip6_privacy = ip6_use_tempaddr (); ++ if (ip6_privacy == NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN) { ++ if (s_ip6) ++ ip6_privacy = nm_setting_ip6_config_get_ip6_privacy (s_ip6); ++ } ++ ip6_privacy = use_tempaddr_clamp (ip6_privacy); ++ ++ if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO) == 0) { ++ if (!addrconf6_start (self, ip6_privacy)) { + /* IPv6 might be disabled; allow IPv4 to proceed */ + ret = NM_ACT_STAGE_RETURN_STOP; + } else +@@ -3597,17 +3678,6 @@ act_stage3_ip6_config_start (NMDevice *self, + + /* Other methods (shared) aren't implemented yet */ + +- /* Enable/disable IPv6 Privacy Extensions. +- * If a global value is configured by sysadmin (e.g. /etc/sysctl.conf), +- * use that value instead of per-connection value. +- */ +- conf_use_tempaddr = ip6_use_tempaddr (); +- if (conf_use_tempaddr >= 0) +- ip6_privacy = conf_use_tempaddr; +- else if (s_ip6) +- ip6_privacy = nm_setting_ip6_config_get_ip6_privacy (s_ip6); +- ip6_privacy = CLAMP (ip6_privacy, NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN, NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR); +- + switch (ip6_privacy) { + case NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN: + case NM_SETTING_IP6_CONFIG_PRIVACY_DISABLED: +-- +1.8.5.3 + diff --git a/NetworkManager.spec b/NetworkManager.spec index a9cb6e8..58fa925 100644 --- a/NetworkManager.spec +++ b/NetworkManager.spec @@ -70,6 +70,7 @@ Patch40: platform-ignore-ipv6-ptp.patch Patch41: load-connections-ret-value.patch Patch42: bgo723163-add-and-activate-fix.patch Patch43: NM-before-network-service.patch +Patch44: 0044-ipv6-privacy.patch BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) @@ -236,6 +237,7 @@ deployments. %patch41 -p1 -b .load-connections-ret-value %patch42 -p1 -b .bgo723163-add-and-activate-fix %patch43 -p1 -b .NM-before-network-service +%patch44 -p1 -b .0044-ipv6-privacy.orig %build @@ -436,6 +438,9 @@ fi %changelog * Sun Feb 16 2014 Thomas Haller - 0.9.9.0-30.git20131003 - revert previous snapshot release 0.9.9.0-29.git20140131, instead based on 0.9.9.0-28.git20131003 +- support for ipv6 private addresses (rfc4941) (rh #1047139) +- add ipv6 autoconf addresses with /64 prefix (rh #1045118) +- wait for IPv6 LL before starting autoconf * Tue Feb 4 2014 Thomas Haller - 0.9.9.0-29.git20140131 - update to new upstream snapshot