diff options
author | Brian Haley <brian.haley@hp.com> | 2009-06-01 06:07:33 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-06-01 06:07:33 -0400 |
commit | 56d417b12e57dfe11c9b7ba4bea3882c62a55815 (patch) | |
tree | 5f7d6fedc4370333898ef7790711e0a9c73e323d | |
parent | 0220ff7fc35913dcd8cdf8fb3a0966caf4aed2f3 (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.txt | 7 | ||||
-rw-r--r-- | Documentation/networking/ipv6.txt | 37 | ||||
-rw-r--r-- | include/linux/ipv6.h | 6 | ||||
-rw-r--r-- | net/ipv6/addrconf.c | 83 | ||||
-rw-r--r-- | net/ipv6/af_inet6.c | 22 |
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 | |||
1060 | accept_dad - INTEGER | 1067 | accept_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 | ||
36 | autoconf | ||
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 | |||
56 | disable_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 | |||
173 | struct ipv6_params { | ||
174 | __s32 disable_ipv6; | ||
175 | __s32 autoconf; | ||
176 | }; | ||
177 | extern 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 | ||
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; |
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"); | |||
72 | static struct list_head inetsw6[SOCK_MAX]; | 72 | static struct list_head inetsw6[SOCK_MAX]; |
73 | static DEFINE_SPINLOCK(inetsw6_lock); | 73 | static DEFINE_SPINLOCK(inetsw6_lock); |
74 | 74 | ||
75 | static int disable_ipv6 = 0; | 75 | struct ipv6_params ipv6_defaults = { |
76 | module_param_named(disable, disable_ipv6, int, 0); | 76 | .disable_ipv6 = 0, |
77 | MODULE_PARM_DESC(disable, "Disable IPv6 such that it is non-functional"); | 77 | .autoconf = 1, |
78 | }; | ||
79 | |||
80 | static int disable_ipv6_mod = 0; | ||
81 | |||
82 | module_param_named(disable, disable_ipv6_mod, int, 0444); | ||
83 | MODULE_PARM_DESC(disable, "Disable IPv6 module such that it is non-functional"); | ||
84 | |||
85 | module_param_named(disable_ipv6, ipv6_defaults.disable_ipv6, int, 0444); | ||
86 | MODULE_PARM_DESC(disable_ipv6, "Disable IPv6 on all interfaces"); | ||
87 | |||
88 | module_param_named(autoconf, ipv6_defaults.autoconf, int, 0444); | ||
89 | MODULE_PARM_DESC(autoconf, "Enable IPv6 address autoconfiguration on all interfaces"); | ||
78 | 90 | ||
79 | static __inline__ struct ipv6_pinfo *inet6_sk_generic(struct sock *sk) | 91 | static __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 | ||
1228 | static void __exit inet6_exit(void) | 1240 | static 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. */ |