diff options
Diffstat (limited to 'net/ipv6/addrconf.c')
-rw-r--r-- | net/ipv6/addrconf.c | 83 |
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 | ||
3990 | static 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 | |||
4001 | static 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 | |||
4021 | static 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 | |||
4044 | static | ||
4045 | int 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 | |||
3991 | static struct addrconf_sysctl_table | 4059 | static 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; |