diff mbox

ipv6: make the net.ipv6.conf.all.use_tempaddr sysctl propagate to interface settings

Message ID 4EEA6EB7.4040103@canonical.com
State New
Headers show

Commit Message

Tim Gardner Dec. 15, 2011, 10:03 p.m. UTC
On 12/15/2011 12:10 PM, Mathieu Trudel-Lapierre wrote:
> On Thu, Dec 15, 2011 at 12:20 PM, Tim Gardner<tim.gardner@canonical.com>  wrote:
>> What kernel is this supposed to apply to?
>
> It was made against 3.2.0-4.10 (using ubuntu-precise.git) and tested
> against Linus' linux-2.6.git. Turns out the patch was mangled by my
> email client, so I've put it on
> http://people.ubuntu.com/~mathieu-tl/0001-ipv6-make-the-net.ipv6.conf.all.use_tempaddr-sysctl-.patch
> .
>
> Mathieu Trudel-Lapierre<mathieu-tl@ubuntu.com>
> Freenode: cyphermox, Jabber: mathieu.tl@gmail.com
> 4096R/EE018C93 1967 8F7D 03A1 8F38 732E  FF82 C126 33E1 EE01 8C93

How about this? I added a bit of error recovery in 
addrconf_sysctl_tempaddr() and simplified the logic in 
addrconf_use_tempaddr().

rtg
diff mbox

Patch

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

diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index cf88df8..77ef901 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -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