aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrian Haley <brian.haley@hp.com>2009-06-01 06:07:33 -0400
committerDavid S. Miller <davem@davemloft.net>2009-06-01 06:07:33 -0400
commit56d417b12e57dfe11c9b7ba4bea3882c62a55815 (patch)
tree5f7d6fedc4370333898ef7790711e0a9c73e323d
parent0220ff7fc35913dcd8cdf8fb3a0966caf4aed2f3 (diff)
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>
-rw-r--r--Documentation/networking/ip-sysctl.txt7
-rw-r--r--Documentation/networking/ipv6.txt37
-rw-r--r--include/linux/ipv6.h6
-rw-r--r--net/ipv6/addrconf.c83
-rw-r--r--net/ipv6/af_inet6.c22
5 files changed, 145 insertions, 10 deletions
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
index 3ffd233c369c..8be76235fe67 100644
--- a/Documentation/networking/ip-sysctl.txt
+++ b/Documentation/networking/ip-sysctl.txt
@@ -1057,6 +1057,13 @@ disable_ipv6 - BOOLEAN
1057 address. 1057 address.
1058 Default: FALSE (enable IPv6 operation) 1058 Default: FALSE (enable IPv6 operation)
1059 1059
1060 When this value is changed from 1 to 0 (IPv6 is being enabled),
1061 it will dynamically create a link-local address on the given
1062 interface and start Duplicate Address Detection, if necessary.
1063
1064 When this value is changed from 0 to 1 (IPv6 is being disabled),
1065 it will dynamically delete all address on the given interface.
1066
1060accept_dad - INTEGER 1067accept_dad - INTEGER
1061 Whether to accept DAD (Duplicate Address Detection). 1068 Whether to accept DAD (Duplicate Address Detection).
1062 0: Disable DAD 1069 0: Disable DAD
diff --git a/Documentation/networking/ipv6.txt b/Documentation/networking/ipv6.txt
index 268e5c103dd8..9fd7e21296c8 100644
--- a/Documentation/networking/ipv6.txt
+++ b/Documentation/networking/ipv6.txt
@@ -33,3 +33,40 @@ disable
33 33
34 A reboot is required to enable IPv6. 34 A reboot is required to enable IPv6.
35 35
36autoconf
37
38 Specifies whether to enable IPv6 address autoconfiguration
39 on all interfaces. This might be used when one does not wish
40 for addresses to be automatically generated from prefixes
41 received in Router Advertisements.
42
43 The possible values and their effects are:
44
45 0
46 IPv6 address autoconfiguration is disabled on all interfaces.
47
48 Only the IPv6 loopback address (::1) and link-local addresses
49 will be added to interfaces.
50
51 1
52 IPv6 address autoconfiguration is enabled on all interfaces.
53
54 This is the default value.
55
56disable_ipv6
57
58 Specifies whether to disable IPv6 on all interfaces.
59 This might be used when no IPv6 addresses are desired.
60
61 The possible values and their effects are:
62
63 0
64 IPv6 is enabled on all interfaces.
65
66 This is the default value.
67
68 1
69 IPv6 is disabled on all interfaces.
70
71 No IPv6 addresses will be added to interfaces.
72
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
index 476d9464ac82..c662efa68289 100644
--- a/include/linux/ipv6.h
+++ b/include/linux/ipv6.h
@@ -169,6 +169,12 @@ struct ipv6_devconf {
169 __s32 accept_dad; 169 __s32 accept_dad;
170 void *sysctl; 170 void *sysctl;
171}; 171};
172
173struct ipv6_params {
174 __s32 disable_ipv6;
175 __s32 autoconf;
176};
177extern struct ipv6_params ipv6_defaults;
172#endif 178#endif
173 179
174/* index values for the variables in ipv6_devconf */ 180/* index values for the variables in ipv6_devconf */
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;
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index b6215be0963f..85b3d0036afd 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -72,9 +72,21 @@ MODULE_LICENSE("GPL");
72static struct list_head inetsw6[SOCK_MAX]; 72static struct list_head inetsw6[SOCK_MAX];
73static DEFINE_SPINLOCK(inetsw6_lock); 73static DEFINE_SPINLOCK(inetsw6_lock);
74 74
75static int disable_ipv6 = 0; 75struct ipv6_params ipv6_defaults = {
76module_param_named(disable, disable_ipv6, int, 0); 76 .disable_ipv6 = 0,
77MODULE_PARM_DESC(disable, "Disable IPv6 such that it is non-functional"); 77 .autoconf = 1,
78};
79
80static int disable_ipv6_mod = 0;
81
82module_param_named(disable, disable_ipv6_mod, int, 0444);
83MODULE_PARM_DESC(disable, "Disable IPv6 module such that it is non-functional");
84
85module_param_named(disable_ipv6, ipv6_defaults.disable_ipv6, int, 0444);
86MODULE_PARM_DESC(disable_ipv6, "Disable IPv6 on all interfaces");
87
88module_param_named(autoconf, ipv6_defaults.autoconf, int, 0444);
89MODULE_PARM_DESC(autoconf, "Enable IPv6 address autoconfiguration on all interfaces");
78 90
79static __inline__ struct ipv6_pinfo *inet6_sk_generic(struct sock *sk) 91static __inline__ struct ipv6_pinfo *inet6_sk_generic(struct sock *sk)
80{ 92{
@@ -1038,7 +1050,7 @@ static int __init inet6_init(void)
1038 for(r = &inetsw6[0]; r < &inetsw6[SOCK_MAX]; ++r) 1050 for(r = &inetsw6[0]; r < &inetsw6[SOCK_MAX]; ++r)
1039 INIT_LIST_HEAD(r); 1051 INIT_LIST_HEAD(r);
1040 1052
1041 if (disable_ipv6) { 1053 if (disable_ipv6_mod) {
1042 printk(KERN_INFO 1054 printk(KERN_INFO
1043 "IPv6: Loaded, but administratively disabled, " 1055 "IPv6: Loaded, but administratively disabled, "
1044 "reboot required to enable\n"); 1056 "reboot required to enable\n");
@@ -1227,7 +1239,7 @@ module_init(inet6_init);
1227 1239
1228static void __exit inet6_exit(void) 1240static void __exit inet6_exit(void)
1229{ 1241{
1230 if (disable_ipv6) 1242 if (disable_ipv6_mod)
1231 return; 1243 return;
1232 1244
1233 /* First of all disallow new sockets creation. */ 1245 /* First of all disallow new sockets creation. */