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.c35
1 files changed, 35 insertions, 0 deletions
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);
119static int desync_factor = MAX_DESYNC_FACTOR * HZ; 119static int desync_factor = MAX_DESYNC_FACTOR * HZ;
120#endif 120#endif
121 121
122static int ipv6_generate_eui64(u8 *eui, struct net_device *dev);
122static int ipv6_count_addresses(struct inet6_dev *idev); 123static 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
189static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = { 191static 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
1422void addrconf_dad_failure(struct inet6_ifaddr *ifp) 1428void 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
3665static inline size_t inet6_if_nlmsg_size(void) 3692static 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 },