aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/addrconf.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/addrconf.c')
-rw-r--r--net/ipv6/addrconf.c83
1 files changed, 78 insertions, 5 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 31938e5fb220..c3488372f12d 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -591,7 +591,6 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
591{ 591{
592 struct inet6_ifaddr *ifa = NULL; 592 struct inet6_ifaddr *ifa = NULL;
593 struct rt6_info *rt; 593 struct rt6_info *rt;
594 struct net *net = dev_net(idev->dev);
595 int hash; 594 int hash;
596 int err = 0; 595 int err = 0;
597 int addr_type = ipv6_addr_type(addr); 596 int addr_type = ipv6_addr_type(addr);
@@ -608,7 +607,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
608 goto out2; 607 goto out2;
609 } 608 }
610 609
611 if (idev->cnf.disable_ipv6 || net->ipv6.devconf_all->disable_ipv6) { 610 if (idev->cnf.disable_ipv6) {
612 err = -EACCES; 611 err = -EACCES;
613 goto out2; 612 goto out2;
614 } 613 }
@@ -1752,6 +1751,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len)
1752 __u32 prefered_lft; 1751 __u32 prefered_lft;
1753 int addr_type; 1752 int addr_type;
1754 struct inet6_dev *in6_dev; 1753 struct inet6_dev *in6_dev;
1754 struct net *net = dev_net(dev);
1755 1755
1756 pinfo = (struct prefix_info *) opt; 1756 pinfo = (struct prefix_info *) opt;
1757 1757
@@ -1809,7 +1809,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len)
1809 if (addrconf_finite_timeout(rt_expires)) 1809 if (addrconf_finite_timeout(rt_expires))
1810 rt_expires *= HZ; 1810 rt_expires *= HZ;
1811 1811
1812 rt = rt6_lookup(dev_net(dev), &pinfo->prefix, NULL, 1812 rt = rt6_lookup(net, &pinfo->prefix, NULL,
1813 dev->ifindex, 1); 1813 dev->ifindex, 1);
1814 1814
1815 if (rt && addrconf_is_prefix_route(rt)) { 1815 if (rt && addrconf_is_prefix_route(rt)) {
@@ -1846,7 +1846,6 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len)
1846 struct inet6_ifaddr * ifp; 1846 struct inet6_ifaddr * ifp;
1847 struct in6_addr addr; 1847 struct in6_addr addr;
1848 int create = 0, update_lft = 0; 1848 int create = 0, update_lft = 0;
1849 struct net *net = dev_net(dev);
1850 1849
1851 if (pinfo->prefix_len == 64) { 1850 if (pinfo->prefix_len == 64) {
1852 memcpy(&addr, &pinfo->prefix, 8); 1851 memcpy(&addr, &pinfo->prefix, 8);
@@ -3988,6 +3987,75 @@ static int addrconf_sysctl_forward_strategy(ctl_table *table,
3988 return addrconf_fixup_forwarding(table, valp, val); 3987 return addrconf_fixup_forwarding(table, valp, val);
3989} 3988}
3990 3989
3990static void dev_disable_change(struct inet6_dev *idev)
3991{
3992 if (!idev || !idev->dev)
3993 return;
3994
3995 if (idev->cnf.disable_ipv6)
3996 addrconf_notify(NULL, NETDEV_DOWN, idev->dev);
3997 else
3998 addrconf_notify(NULL, NETDEV_UP, idev->dev);
3999}
4000
4001static void addrconf_disable_change(struct net *net, __s32 newf)
4002{
4003 struct net_device *dev;
4004 struct inet6_dev *idev;
4005
4006 read_lock(&dev_base_lock);
4007 for_each_netdev(net, dev) {
4008 rcu_read_lock();
4009 idev = __in6_dev_get(dev);
4010 if (idev) {
4011 int changed = (!idev->cnf.disable_ipv6) ^ (!newf);
4012 idev->cnf.disable_ipv6 = newf;
4013 if (changed)
4014 dev_disable_change(idev);
4015 }
4016 rcu_read_unlock();
4017 }
4018 read_unlock(&dev_base_lock);
4019}
4020
4021static int addrconf_disable_ipv6(struct ctl_table *table, int *p, int old)
4022{
4023 struct net *net;
4024
4025 net = (struct net *)table->extra2;
4026
4027 if (p == &net->ipv6.devconf_dflt->disable_ipv6)
4028 return 0;
4029
4030 if (!rtnl_trylock())
4031 return restart_syscall();
4032
4033 if (p == &net->ipv6.devconf_all->disable_ipv6) {
4034 __s32 newf = net->ipv6.devconf_all->disable_ipv6;
4035 net->ipv6.devconf_dflt->disable_ipv6 = newf;
4036 addrconf_disable_change(net, newf);
4037 } else if ((!*p) ^ (!old))
4038 dev_disable_change((struct inet6_dev *)table->extra1);
4039
4040 rtnl_unlock();
4041 return 0;
4042}
4043
4044static
4045int addrconf_sysctl_disable(ctl_table *ctl, int write, struct file * filp,
4046 void __user *buffer, size_t *lenp, loff_t *ppos)
4047{
4048 int *valp = ctl->data;
4049 int val = *valp;
4050 int ret;
4051
4052 ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos);
4053
4054 if (write)
4055 ret = addrconf_disable_ipv6(ctl, valp, val);
4056 return ret;
4057}
4058
3991static struct addrconf_sysctl_table 4059static struct addrconf_sysctl_table
3992{ 4060{
3993 struct ctl_table_header *sysctl_header; 4061 struct ctl_table_header *sysctl_header;
@@ -4225,7 +4293,8 @@ static struct addrconf_sysctl_table
4225 .data = &ipv6_devconf.disable_ipv6, 4293 .data = &ipv6_devconf.disable_ipv6,
4226 .maxlen = sizeof(int), 4294 .maxlen = sizeof(int),
4227 .mode = 0644, 4295 .mode = 0644,
4228 .proc_handler = proc_dointvec, 4296 .proc_handler = addrconf_sysctl_disable,
4297 .strategy = sysctl_intvec,
4229 }, 4298 },
4230 { 4299 {
4231 .ctl_name = CTL_UNNUMBERED, 4300 .ctl_name = CTL_UNNUMBERED,
@@ -4346,6 +4415,10 @@ static int addrconf_init_net(struct net *net)
4346 dflt = kmemdup(dflt, sizeof(ipv6_devconf_dflt), GFP_KERNEL); 4415 dflt = kmemdup(dflt, sizeof(ipv6_devconf_dflt), GFP_KERNEL);
4347 if (dflt == NULL) 4416 if (dflt == NULL)
4348 goto err_alloc_dflt; 4417 goto err_alloc_dflt;
4418 } else {
4419 /* these will be inherited by all namespaces */
4420 dflt->autoconf = ipv6_defaults.autoconf;
4421 dflt->disable_ipv6 = ipv6_defaults.disable_ipv6;
4349 } 4422 }
4350 4423
4351 net->ipv6.devconf_all = all; 4424 net->ipv6.devconf_all = all;