From 7f40d4617865fdfcbee2894fcf9f06f2eb3b9575 Mon Sep 17 00:00:00 2001
From: Mathieu Trudel-Lapierre <mathieu.trudel-lapierre@canonical.com>
Date: Thu, 15 Dec 2011 13:39:03 -0500
Subject: [PATCH] ipv6: make the net.ipv6.conf.all.use_tempaddr sysctl propagate to interface settings
The description for IPV6_PRIVACY mentions using .../all/use_tempaddr to enable
IPv6 Privacy Extensions, and IP sysctl documentation mentions 'all' as setting
all interface-specific settings. We make sure at least use_tempaddr actually
works as documented.
Signed-off-by: Mathieu Trudel-Lapierre <mathieu.trudel-lapierre@canonical.com>
---
net/ipv6/addrconf.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 83 insertions(+), 1 deletions(-)
@@ -4340,6 +4340,88 @@ int addrconf_sysctl_disable(ctl_table *ctl, int write,
return ret;
}
+#ifdef CONFIG_IPV6_PRIVACY
+static void dev_tempaddr_change(struct inet6_dev *idev)
+{
+ if (!idev || !idev->dev)
+ return;
+
+ if (idev->cnf.disable_ipv6)
+ addrconf_notify(NULL, NETDEV_DOWN, idev->dev);
+ else
+ addrconf_notify(NULL, NETDEV_UP, idev->dev);
+}
+
+static void addrconf_tempaddr_change(struct net *net, __s32 newf)
+{
+ struct net_device *dev;
+ struct inet6_dev *idev;
+
+ rcu_read_lock();
+ for_each_netdev_rcu(net, dev) {
+ idev = __in6_dev_get(dev);
+ if (idev) {
+ int changed = (!idev->cnf.use_tempaddr) ^ (!newf);
+ idev->cnf.use_tempaddr = newf;
+ if (changed)
+ dev_tempaddr_change(idev);
+ }
+ }
+ rcu_read_unlock();
+}
+
+static int addrconf_use_tempaddr(struct ctl_table *table, int *p, int old)
+{
+ struct net *net;
+
+ net = (struct net *)table->extra2;
+
+ if (!net || p == &net->ipv6.devconf_dflt->use_tempaddr)
+ return 0;
+
+ if (!rtnl_trylock()) {
+ /* Restore the original values before restarting */
+ *p = old;
+ return restart_syscall();
+ }
+
+ if (p == &net->ipv6.devconf_all->use_tempaddr) {
+ net->ipv6.devconf_dflt->use_tempaddr = *p;
+ addrconf_tempaddr_change(net, *p);
+ } else if (*p != old)
+ dev_tempaddr_change((struct inet6_dev *)table->extra1);
+
+ rtnl_unlock();
+ return 0;
+}
+
+static
+int addrconf_sysctl_tempaddr(ctl_table *ctl, int write,
+ void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+ int *valp = ctl->data;
+ int old = *valp;
+ loff_t pos = *ppos;
+ int ret;
+
+ ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
+ if (ret)
+ goto out;
+
+ *valp = !!(*valp); /* 0 or 1 */
+
+ if (write)
+ ret = addrconf_use_tempaddr(ctl, valp, old);
+
+out:
+ if (ret) {
+ *valp = old;
+ *ppos = pos;
+ }
+ return ret;
+}
+#endif
+
static struct addrconf_sysctl_table
{
struct ctl_table_header *sysctl_header;
@@ -4431,7 +4513,7 @@ static struct addrconf_sysctl_table
.data = &ipv6_devconf.use_tempaddr,
.maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = proc_dointvec,
+ .proc_handler = addrconf_sysctl_tempaddr,
},
{
.procname = "temp_valid_lft",
--
1.7.0.4