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.c87
1 files changed, 81 insertions, 6 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 597487ae6ce8..8c1e86afbbf5 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -503,7 +503,7 @@ static int addrconf_fixup_forwarding(struct ctl_table *table, int *p, int old)
503 return 0; 503 return 0;
504 504
505 if (!rtnl_trylock()) 505 if (!rtnl_trylock())
506 return -ERESTARTSYS; 506 return restart_syscall();
507 507
508 if (p == &net->ipv6.devconf_all->forwarding) { 508 if (p == &net->ipv6.devconf_all->forwarding) {
509 __s32 newf = net->ipv6.devconf_all->forwarding; 509 __s32 newf = net->ipv6.devconf_all->forwarding;
@@ -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 }
@@ -1520,6 +1519,8 @@ static int addrconf_ifid_infiniband(u8 *eui, struct net_device *dev)
1520 1519
1521int __ipv6_isatap_ifid(u8 *eui, __be32 addr) 1520int __ipv6_isatap_ifid(u8 *eui, __be32 addr)
1522{ 1521{
1522 if (addr == 0)
1523 return -1;
1523 eui[0] = (ipv4_is_zeronet(addr) || ipv4_is_private_10(addr) || 1524 eui[0] = (ipv4_is_zeronet(addr) || ipv4_is_private_10(addr) ||
1524 ipv4_is_loopback(addr) || ipv4_is_linklocal_169(addr) || 1525 ipv4_is_loopback(addr) || ipv4_is_linklocal_169(addr) ||
1525 ipv4_is_private_172(addr) || ipv4_is_test_192(addr) || 1526 ipv4_is_private_172(addr) || ipv4_is_test_192(addr) ||
@@ -1750,6 +1751,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len)
1750 __u32 prefered_lft; 1751 __u32 prefered_lft;
1751 int addr_type; 1752 int addr_type;
1752 struct inet6_dev *in6_dev; 1753 struct inet6_dev *in6_dev;
1754 struct net *net = dev_net(dev);
1753 1755
1754 pinfo = (struct prefix_info *) opt; 1756 pinfo = (struct prefix_info *) opt;
1755 1757
@@ -1807,7 +1809,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len)
1807 if (addrconf_finite_timeout(rt_expires)) 1809 if (addrconf_finite_timeout(rt_expires))
1808 rt_expires *= HZ; 1810 rt_expires *= HZ;
1809 1811
1810 rt = rt6_lookup(dev_net(dev), &pinfo->prefix, NULL, 1812 rt = rt6_lookup(net, &pinfo->prefix, NULL,
1811 dev->ifindex, 1); 1813 dev->ifindex, 1);
1812 1814
1813 if (rt && addrconf_is_prefix_route(rt)) { 1815 if (rt && addrconf_is_prefix_route(rt)) {
@@ -1844,7 +1846,6 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len)
1844 struct inet6_ifaddr * ifp; 1846 struct inet6_ifaddr * ifp;
1845 struct in6_addr addr; 1847 struct in6_addr addr;
1846 int create = 0, update_lft = 0; 1848 int create = 0, update_lft = 0;
1847 struct net *net = dev_net(dev);
1848 1849
1849 if (pinfo->prefix_len == 64) { 1850 if (pinfo->prefix_len == 64) {
1850 memcpy(&addr, &pinfo->prefix, 8); 1851 memcpy(&addr, &pinfo->prefix, 8);
@@ -3986,6 +3987,75 @@ static int addrconf_sysctl_forward_strategy(ctl_table *table,
3986 return addrconf_fixup_forwarding(table, valp, val); 3987 return addrconf_fixup_forwarding(table, valp, val);
3987} 3988}
3988 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
3989static struct addrconf_sysctl_table 4059static struct addrconf_sysctl_table
3990{ 4060{
3991 struct ctl_table_header *sysctl_header; 4061 struct ctl_table_header *sysctl_header;
@@ -4223,7 +4293,8 @@ static struct addrconf_sysctl_table
4223 .data = &ipv6_devconf.disable_ipv6, 4293 .data = &ipv6_devconf.disable_ipv6,
4224 .maxlen = sizeof(int), 4294 .maxlen = sizeof(int),
4225 .mode = 0644, 4295 .mode = 0644,
4226 .proc_handler = proc_dointvec, 4296 .proc_handler = addrconf_sysctl_disable,
4297 .strategy = sysctl_intvec,
4227 }, 4298 },
4228 { 4299 {
4229 .ctl_name = CTL_UNNUMBERED, 4300 .ctl_name = CTL_UNNUMBERED,
@@ -4344,6 +4415,10 @@ static int addrconf_init_net(struct net *net)
4344 dflt = kmemdup(dflt, sizeof(ipv6_devconf_dflt), GFP_KERNEL); 4415 dflt = kmemdup(dflt, sizeof(ipv6_devconf_dflt), GFP_KERNEL);
4345 if (dflt == NULL) 4416 if (dflt == NULL)
4346 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;
4347 } 4422 }
4348 4423
4349 net->ipv6.devconf_all = all; 4424 net->ipv6.devconf_all = all;