|
@@ -119,6 +119,7 @@ static void ipv6_regen_rndid(unsigned long data);
|
|
|
static int desync_factor = MAX_DESYNC_FACTOR * HZ;
|
|
|
#endif
|
|
|
|
|
|
+static int ipv6_generate_eui64(u8 *eui, struct net_device *dev);
|
|
|
static int ipv6_count_addresses(struct inet6_dev *idev);
|
|
|
|
|
|
/*
|
|
@@ -184,6 +185,7 @@ struct ipv6_devconf ipv6_devconf __read_mostly = {
|
|
|
.proxy_ndp = 0,
|
|
|
.accept_source_route = 0, /* we do not accept RH0 by default. */
|
|
|
.disable_ipv6 = 0,
|
|
|
+ .accept_dad = 1,
|
|
|
};
|
|
|
|
|
|
static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
|
|
@@ -217,6 +219,7 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
|
|
|
.proxy_ndp = 0,
|
|
|
.accept_source_route = 0, /* we do not accept RH0 by default. */
|
|
|
.disable_ipv6 = 0,
|
|
|
+ .accept_dad = 1,
|
|
|
};
|
|
|
|
|
|
/* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */
|
|
@@ -380,6 +383,9 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev)
|
|
|
*/
|
|
|
in6_dev_hold(ndev);
|
|
|
|
|
|
+ if (dev->flags & (IFF_NOARP | IFF_LOOPBACK))
|
|
|
+ ndev->cnf.accept_dad = -1;
|
|
|
+
|
|
|
#if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE)
|
|
|
if (dev->type == ARPHRD_SIT && (dev->priv_flags & IFF_ISATAP)) {
|
|
|
printk(KERN_INFO
|
|
@@ -1421,6 +1427,20 @@ static void addrconf_dad_stop(struct inet6_ifaddr *ifp)
|
|
|
|
|
|
void addrconf_dad_failure(struct inet6_ifaddr *ifp)
|
|
|
{
|
|
|
+ struct inet6_dev *idev = ifp->idev;
|
|
|
+ if (idev->cnf.accept_dad > 1 && !idev->cnf.disable_ipv6) {
|
|
|
+ struct in6_addr addr;
|
|
|
+
|
|
|
+ addr.s6_addr32[0] = htonl(0xfe800000);
|
|
|
+ addr.s6_addr32[1] = 0;
|
|
|
+
|
|
|
+ if (!ipv6_generate_eui64(addr.s6_addr + 8, idev->dev) &&
|
|
|
+ ipv6_addr_equal(&ifp->addr, &addr)) {
|
|
|
+ /* DAD failed for link-local based on MAC address */
|
|
|
+ idev->cnf.disable_ipv6 = 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
if (net_ratelimit())
|
|
|
printk(KERN_INFO "%s: duplicate address detected!\n", ifp->idev->dev->name);
|
|
|
addrconf_dad_stop(ifp);
|
|
@@ -2753,6 +2773,7 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags)
|
|
|
spin_lock_bh(&ifp->lock);
|
|
|
|
|
|
if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) ||
|
|
|
+ idev->cnf.accept_dad < 1 ||
|
|
|
!(ifp->flags&IFA_F_TENTATIVE) ||
|
|
|
ifp->flags & IFA_F_NODAD) {
|
|
|
ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC);
|
|
@@ -2800,6 +2821,11 @@ static void addrconf_dad_timer(unsigned long data)
|
|
|
read_unlock_bh(&idev->lock);
|
|
|
goto out;
|
|
|
}
|
|
|
+ if (idev->cnf.accept_dad > 1 && idev->cnf.disable_ipv6) {
|
|
|
+ read_unlock_bh(&idev->lock);
|
|
|
+ addrconf_dad_failure(ifp);
|
|
|
+ return;
|
|
|
+ }
|
|
|
spin_lock_bh(&ifp->lock);
|
|
|
if (ifp->probes == 0) {
|
|
|
/*
|
|
@@ -3660,6 +3686,7 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
|
|
|
array[DEVCONF_MC_FORWARDING] = cnf->mc_forwarding;
|
|
|
#endif
|
|
|
array[DEVCONF_DISABLE_IPV6] = cnf->disable_ipv6;
|
|
|
+ array[DEVCONF_ACCEPT_DAD] = cnf->accept_dad;
|
|
|
}
|
|
|
|
|
|
static inline size_t inet6_if_nlmsg_size(void)
|
|
@@ -4226,6 +4253,14 @@ static struct addrconf_sysctl_table
|
|
|
.mode = 0644,
|
|
|
.proc_handler = &proc_dointvec,
|
|
|
},
|
|
|
+ {
|
|
|
+ .ctl_name = CTL_UNNUMBERED,
|
|
|
+ .procname = "accept_dad",
|
|
|
+ .data = &ipv6_devconf.accept_dad,
|
|
|
+ .maxlen = sizeof(int),
|
|
|
+ .mode = 0644,
|
|
|
+ .proc_handler = &proc_dointvec,
|
|
|
+ },
|
|
|
{
|
|
|
.ctl_name = 0, /* sentinel */
|
|
|
}
|