diff options
-rw-r--r-- | Documentation/networking/ip-sysctl.txt | 7 | ||||
-rw-r--r-- | include/linux/ipv6.h | 2 | ||||
-rw-r--r-- | net/ipv6/addrconf.c | 35 |
3 files changed, 44 insertions, 0 deletions
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index dae980e8f1b9..72f6d52e52e6 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt | |||
@@ -1029,6 +1029,13 @@ disable_ipv6 - BOOLEAN | |||
1029 | Disable IPv6 operation. | 1029 | Disable IPv6 operation. |
1030 | Default: FALSE (enable IPv6 operation) | 1030 | Default: FALSE (enable IPv6 operation) |
1031 | 1031 | ||
1032 | accept_dad - INTEGER | ||
1033 | Whether to accept DAD (Duplicate Address Detection). | ||
1034 | 0: Disable DAD | ||
1035 | 1: Enable DAD (default) | ||
1036 | 2: Enable DAD, and disable IPv6 operation if MAC-based duplicate | ||
1037 | link-local address has been found. | ||
1038 | |||
1032 | icmp/*: | 1039 | icmp/*: |
1033 | ratelimit - INTEGER | 1040 | ratelimit - INTEGER |
1034 | Limit the maximal rates for sending ICMPv6 packets. | 1041 | Limit the maximal rates for sending ICMPv6 packets. |
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index d9d7f9b69eb4..391ad0843a46 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h | |||
@@ -164,6 +164,7 @@ struct ipv6_devconf { | |||
164 | __s32 mc_forwarding; | 164 | __s32 mc_forwarding; |
165 | #endif | 165 | #endif |
166 | __s32 disable_ipv6; | 166 | __s32 disable_ipv6; |
167 | __s32 accept_dad; | ||
167 | void *sysctl; | 168 | void *sysctl; |
168 | }; | 169 | }; |
169 | 170 | ||
@@ -196,6 +197,7 @@ enum { | |||
196 | DEVCONF_ACCEPT_SOURCE_ROUTE, | 197 | DEVCONF_ACCEPT_SOURCE_ROUTE, |
197 | DEVCONF_MC_FORWARDING, | 198 | DEVCONF_MC_FORWARDING, |
198 | DEVCONF_DISABLE_IPV6, | 199 | DEVCONF_DISABLE_IPV6, |
200 | DEVCONF_ACCEPT_DAD, | ||
199 | DEVCONF_MAX | 201 | DEVCONF_MAX |
200 | }; | 202 | }; |
201 | 203 | ||
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 8c5cff50bbed..2ec73e62202c 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -119,6 +119,7 @@ static void ipv6_regen_rndid(unsigned long data); | |||
119 | static int desync_factor = MAX_DESYNC_FACTOR * HZ; | 119 | static int desync_factor = MAX_DESYNC_FACTOR * HZ; |
120 | #endif | 120 | #endif |
121 | 121 | ||
122 | static int ipv6_generate_eui64(u8 *eui, struct net_device *dev); | ||
122 | static int ipv6_count_addresses(struct inet6_dev *idev); | 123 | static int ipv6_count_addresses(struct inet6_dev *idev); |
123 | 124 | ||
124 | /* | 125 | /* |
@@ -184,6 +185,7 @@ struct ipv6_devconf ipv6_devconf __read_mostly = { | |||
184 | .proxy_ndp = 0, | 185 | .proxy_ndp = 0, |
185 | .accept_source_route = 0, /* we do not accept RH0 by default. */ | 186 | .accept_source_route = 0, /* we do not accept RH0 by default. */ |
186 | .disable_ipv6 = 0, | 187 | .disable_ipv6 = 0, |
188 | .accept_dad = 1, | ||
187 | }; | 189 | }; |
188 | 190 | ||
189 | static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = { | 191 | static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = { |
@@ -217,6 +219,7 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = { | |||
217 | .proxy_ndp = 0, | 219 | .proxy_ndp = 0, |
218 | .accept_source_route = 0, /* we do not accept RH0 by default. */ | 220 | .accept_source_route = 0, /* we do not accept RH0 by default. */ |
219 | .disable_ipv6 = 0, | 221 | .disable_ipv6 = 0, |
222 | .accept_dad = 1, | ||
220 | }; | 223 | }; |
221 | 224 | ||
222 | /* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */ | 225 | /* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */ |
@@ -380,6 +383,9 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev) | |||
380 | */ | 383 | */ |
381 | in6_dev_hold(ndev); | 384 | in6_dev_hold(ndev); |
382 | 385 | ||
386 | if (dev->flags & (IFF_NOARP | IFF_LOOPBACK)) | ||
387 | ndev->cnf.accept_dad = -1; | ||
388 | |||
383 | #if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE) | 389 | #if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE) |
384 | if (dev->type == ARPHRD_SIT && (dev->priv_flags & IFF_ISATAP)) { | 390 | if (dev->type == ARPHRD_SIT && (dev->priv_flags & IFF_ISATAP)) { |
385 | printk(KERN_INFO | 391 | printk(KERN_INFO |
@@ -1421,6 +1427,20 @@ static void addrconf_dad_stop(struct inet6_ifaddr *ifp) | |||
1421 | 1427 | ||
1422 | void addrconf_dad_failure(struct inet6_ifaddr *ifp) | 1428 | void addrconf_dad_failure(struct inet6_ifaddr *ifp) |
1423 | { | 1429 | { |
1430 | struct inet6_dev *idev = ifp->idev; | ||
1431 | if (idev->cnf.accept_dad > 1 && !idev->cnf.disable_ipv6) { | ||
1432 | struct in6_addr addr; | ||
1433 | |||
1434 | addr.s6_addr32[0] = htonl(0xfe800000); | ||
1435 | addr.s6_addr32[1] = 0; | ||
1436 | |||
1437 | if (!ipv6_generate_eui64(addr.s6_addr + 8, idev->dev) && | ||
1438 | ipv6_addr_equal(&ifp->addr, &addr)) { | ||
1439 | /* DAD failed for link-local based on MAC address */ | ||
1440 | idev->cnf.disable_ipv6 = 1; | ||
1441 | } | ||
1442 | } | ||
1443 | |||
1424 | if (net_ratelimit()) | 1444 | if (net_ratelimit()) |
1425 | printk(KERN_INFO "%s: duplicate address detected!\n", ifp->idev->dev->name); | 1445 | printk(KERN_INFO "%s: duplicate address detected!\n", ifp->idev->dev->name); |
1426 | addrconf_dad_stop(ifp); | 1446 | addrconf_dad_stop(ifp); |
@@ -2753,6 +2773,7 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags) | |||
2753 | spin_lock_bh(&ifp->lock); | 2773 | spin_lock_bh(&ifp->lock); |
2754 | 2774 | ||
2755 | if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) || | 2775 | if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) || |
2776 | idev->cnf.accept_dad < 1 || | ||
2756 | !(ifp->flags&IFA_F_TENTATIVE) || | 2777 | !(ifp->flags&IFA_F_TENTATIVE) || |
2757 | ifp->flags & IFA_F_NODAD) { | 2778 | ifp->flags & IFA_F_NODAD) { |
2758 | ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC); | 2779 | ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC); |
@@ -2800,6 +2821,11 @@ static void addrconf_dad_timer(unsigned long data) | |||
2800 | read_unlock_bh(&idev->lock); | 2821 | read_unlock_bh(&idev->lock); |
2801 | goto out; | 2822 | goto out; |
2802 | } | 2823 | } |
2824 | if (idev->cnf.accept_dad > 1 && idev->cnf.disable_ipv6) { | ||
2825 | read_unlock_bh(&idev->lock); | ||
2826 | addrconf_dad_failure(ifp); | ||
2827 | return; | ||
2828 | } | ||
2803 | spin_lock_bh(&ifp->lock); | 2829 | spin_lock_bh(&ifp->lock); |
2804 | if (ifp->probes == 0) { | 2830 | if (ifp->probes == 0) { |
2805 | /* | 2831 | /* |
@@ -3660,6 +3686,7 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf, | |||
3660 | array[DEVCONF_MC_FORWARDING] = cnf->mc_forwarding; | 3686 | array[DEVCONF_MC_FORWARDING] = cnf->mc_forwarding; |
3661 | #endif | 3687 | #endif |
3662 | array[DEVCONF_DISABLE_IPV6] = cnf->disable_ipv6; | 3688 | array[DEVCONF_DISABLE_IPV6] = cnf->disable_ipv6; |
3689 | array[DEVCONF_ACCEPT_DAD] = cnf->accept_dad; | ||
3663 | } | 3690 | } |
3664 | 3691 | ||
3665 | static inline size_t inet6_if_nlmsg_size(void) | 3692 | static inline size_t inet6_if_nlmsg_size(void) |
@@ -4227,6 +4254,14 @@ static struct addrconf_sysctl_table | |||
4227 | .proc_handler = &proc_dointvec, | 4254 | .proc_handler = &proc_dointvec, |
4228 | }, | 4255 | }, |
4229 | { | 4256 | { |
4257 | .ctl_name = CTL_UNNUMBERED, | ||
4258 | .procname = "accept_dad", | ||
4259 | .data = &ipv6_devconf.accept_dad, | ||
4260 | .maxlen = sizeof(int), | ||
4261 | .mode = 0644, | ||
4262 | .proc_handler = &proc_dointvec, | ||
4263 | }, | ||
4264 | { | ||
4230 | .ctl_name = 0, /* sentinel */ | 4265 | .ctl_name = 0, /* sentinel */ |
4231 | } | 4266 | } |
4232 | }, | 4267 | }, |