[NetworkManager/f20] backport patches for IPv6 privacy
thaller
thaller at fedoraproject.org
Sun Feb 16 14:39:22 UTC 2014
commit c84b54dbfe0c56753f497dc13fa0ee40a87d0d91
Author: Thomas Haller <thaller at redhat.com>
Date: Sat Feb 15 12:16:46 2014 +0100
backport patches for IPv6 privacy
0044-ipv6-privacy.patch | 1739 +++++++++++++++++++++++++++++++++++++++++++++++
NetworkManager.spec | 5 +
2 files changed, 1744 insertions(+), 0 deletions(-)
---
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 <thaller at redhat.com>
+Date: Sat, 15 Feb 2014 13:20:40 +0100
+Subject: [PATCH 01/14] fix several compile errors
+
+Signed-off-by: Thomas Haller <thaller at redhat.com>
+---
+ 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 <thaller at redhat.com>
+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 <thaller at redhat.com>
+---
+ 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 <glib.h>
++#include <string.h>
++#include <errno.h>
++
++#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 <danw at gnome.org>
+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 <thaller at redhat.com>
+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 <thaller at redhat.com>
+---
+ 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 <netlink/route/addr.h>
+
+ #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 <thaller at redhat.com>
+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 <thaller at redhat.com>
+---
+ 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 <thaller at redhat.com>
+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 <thaller at redhat.com>
+---
+ 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 <dcbw at redhat.com>
+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 <thaller at redhat.com>
+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 <thaller at redhat.com>
+---
+ 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 <thaller at redhat.com>
+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 <thaller at redhat.com>
+---
+ 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 <thaller at redhat.com>
+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 <thaller at redhat.com>
+---
+ 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 <thaller at redhat.com>
+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 <thaller at redhat.com>
+---
+ 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 <thaller at redhat.com>
+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 <thaller at redhat.com>
+---
+ 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 <thaller at redhat.com>
+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 <thaller at redhat.com>
+---
+ 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 <arpa/inet.h>
+ #include <fcntl.h>
+ #include <linux/if.h>
++#include <netlink/route/addr.h>
+
+ #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 <thaller at redhat.com>
+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 <thaller at redhat.com>
+---
+ 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 <thaller at redhat.com> - 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 <thaller at redhat.com> - 0.9.9.0-29.git20140131
- update to new upstream snapshot
More information about the scm-commits
mailing list