IPv6: Add 'autoconf' and 'disable_ipv6' module parameters

Add 'autoconf' and 'disable_ipv6' parameters to the IPv6 module.

The first controls if IPv6 addresses are autoconfigured from
prefixes received in Router Advertisements.  The IPv6 loopback
(::1) and link-local addresses are still configured.

The second controls if IPv6 addresses are desired at all.  No
IPv6 addresses will be added to any interfaces.

Signed-off-by: Brian Haley <brian.haley@hp.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Brian Haley
2009-06-01 03:07:33 -07:00
committed by David S. Miller
parent 0220ff7fc3
commit 56d417b12e
5 changed files with 145 additions and 10 deletions

View File

@@ -591,7 +591,6 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
{
struct inet6_ifaddr *ifa = NULL;
struct rt6_info *rt;
struct net *net = dev_net(idev->dev);
int hash;
int err = 0;
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,
goto out2;
}
if (idev->cnf.disable_ipv6 || net->ipv6.devconf_all->disable_ipv6) {
if (idev->cnf.disable_ipv6) {
err = -EACCES;
goto out2;
}
@@ -1752,6 +1751,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len)
__u32 prefered_lft;
int addr_type;
struct inet6_dev *in6_dev;
struct net *net = dev_net(dev);
pinfo = (struct prefix_info *) opt;
@@ -1809,7 +1809,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len)
if (addrconf_finite_timeout(rt_expires))
rt_expires *= HZ;
rt = rt6_lookup(dev_net(dev), &pinfo->prefix, NULL,
rt = rt6_lookup(net, &pinfo->prefix, NULL,
dev->ifindex, 1);
if (rt && addrconf_is_prefix_route(rt)) {
@@ -1846,7 +1846,6 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len)
struct inet6_ifaddr * ifp;
struct in6_addr addr;
int create = 0, update_lft = 0;
struct net *net = dev_net(dev);
if (pinfo->prefix_len == 64) {
memcpy(&addr, &pinfo->prefix, 8);
@@ -3988,6 +3987,75 @@ static int addrconf_sysctl_forward_strategy(ctl_table *table,
return addrconf_fixup_forwarding(table, valp, val);
}
static void dev_disable_change(struct inet6_dev *idev)
{
if (!idev || !idev->dev)
return;
if (idev->cnf.disable_ipv6)
addrconf_notify(NULL, NETDEV_DOWN, idev->dev);
else
addrconf_notify(NULL, NETDEV_UP, idev->dev);
}
static void addrconf_disable_change(struct net *net, __s32 newf)
{
struct net_device *dev;
struct inet6_dev *idev;
read_lock(&dev_base_lock);
for_each_netdev(net, dev) {
rcu_read_lock();
idev = __in6_dev_get(dev);
if (idev) {
int changed = (!idev->cnf.disable_ipv6) ^ (!newf);
idev->cnf.disable_ipv6 = newf;
if (changed)
dev_disable_change(idev);
}
rcu_read_unlock();
}
read_unlock(&dev_base_lock);
}
static int addrconf_disable_ipv6(struct ctl_table *table, int *p, int old)
{
struct net *net;
net = (struct net *)table->extra2;
if (p == &net->ipv6.devconf_dflt->disable_ipv6)
return 0;
if (!rtnl_trylock())
return restart_syscall();
if (p == &net->ipv6.devconf_all->disable_ipv6) {
__s32 newf = net->ipv6.devconf_all->disable_ipv6;
net->ipv6.devconf_dflt->disable_ipv6 = newf;
addrconf_disable_change(net, newf);
} else if ((!*p) ^ (!old))
dev_disable_change((struct inet6_dev *)table->extra1);
rtnl_unlock();
return 0;
}
static
int addrconf_sysctl_disable(ctl_table *ctl, int write, struct file * filp,
void __user *buffer, size_t *lenp, loff_t *ppos)
{
int *valp = ctl->data;
int val = *valp;
int ret;
ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos);
if (write)
ret = addrconf_disable_ipv6(ctl, valp, val);
return ret;
}
static struct addrconf_sysctl_table
{
struct ctl_table_header *sysctl_header;
@@ -4225,7 +4293,8 @@ static struct addrconf_sysctl_table
.data = &ipv6_devconf.disable_ipv6,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec,
.proc_handler = addrconf_sysctl_disable,
.strategy = sysctl_intvec,
},
{
.ctl_name = CTL_UNNUMBERED,
@@ -4346,6 +4415,10 @@ static int addrconf_init_net(struct net *net)
dflt = kmemdup(dflt, sizeof(ipv6_devconf_dflt), GFP_KERNEL);
if (dflt == NULL)
goto err_alloc_dflt;
} else {
/* these will be inherited by all namespaces */
dflt->autoconf = ipv6_defaults.autoconf;
dflt->disable_ipv6 = ipv6_defaults.disable_ipv6;
}
net->ipv6.devconf_all = all;