aboutsummaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
authorMathieu Trudel-Lapierre <mathieu.trudel-lapierre@canonical.com>2012-01-10 14:54:34 +0100
committerLeann Ogasawara <leann.ogasawara@canonical.com>2012-06-19 00:02:21 -0700
commitd4ab397ffe5522702cbd1773a592f700cd1f6b79 (patch)
tree97cbee0906be3a6ac37df1460a4e67972b06cb86 /net
parent0f10344b7cdaa5322ba926c8da0e163918691166 (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>
Diffstat (limited to 'net')
-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",