aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMathieu Trudel-Lapierre <mathieu.trudel-lapierre@canonical.com>2012-01-10 14:54:34 +0100
committerJohn Rigby <john.rigby@linaro.org>2012-06-25 15:02:19 -0600
commit53359cdc8a18bf1ba22b1d9066a3576d151c0702 (patch)
tree58eabef542e2fea60069a3f473188157f665232e
parent9893c238a10ade4969d75f04825f05db4cf3d771 (diff)
UBUNTU: SAUCE: 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> Signed-off-by: Tim Gardner <tim.gardner@canonical.com>
-rw-r--r--net/ipv6/addrconf.c80
1 files changed, 79 insertions, 1 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 8f6411c9718..246b533ad5a 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -4360,6 +4360,84 @@ 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) {
+ /* If ipv6 is enabled, try to bring down and back up the
+ * interface to get new temporary addresses created
+ */
+ addrconf_notify(NULL, NETDEV_DOWN, idev->dev);
+ 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 (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) {
+ __s32 newf = net->ipv6.devconf_all->use_tempaddr;
+ net->ipv6.devconf_dflt->use_tempaddr = newf;
+ addrconf_tempaddr_change(net, newf);
+ } 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 val = *valp;
+ loff_t pos = *ppos;
+ int ret;
+
+ ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
+
+ if (write)
+ ret = addrconf_use_tempaddr(ctl, valp, val);
+ if (ret)
+ *ppos = pos;
+ return ret;
+}
+#endif
+
static struct addrconf_sysctl_table
{
struct ctl_table_header *sysctl_header;
@@ -4450,7 +4528,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",