Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1b34be74 authored by YOSHIFUJI Hideaki's avatar YOSHIFUJI Hideaki
Browse files

ipv6 addrconf: add accept_dad sysctl to control DAD operation.

- If 0, disable DAD.
- If 1, perform DAD (default).
- If >1, perform DAD and disable IPv6 operation if DAD for MAC-based
  link-local address has been failed (RFC4862 5.4.5).

We do not follow RFC4862 by default.  Refer to the netdev thread entitled
"Linux IPv6 DAD not full conform to RFC 4862 ?"
	http://www.spinics.net/lists/netdev/msg52027.html



Signed-off-by: default avatarYOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
parent 778d80be
Loading
Loading
Loading
Loading
+7 −0
Original line number Original line Diff line number Diff line
@@ -1029,6 +1029,13 @@ disable_ipv6 - BOOLEAN
	Disable IPv6 operation.
	Disable IPv6 operation.
	Default: FALSE (enable IPv6 operation)
	Default: FALSE (enable IPv6 operation)


accept_dad - INTEGER
	Whether to accept DAD (Duplicate Address Detection).
	0: Disable DAD
	1: Enable DAD (default)
	2: Enable DAD, and disable IPv6 operation if MAC-based duplicate
	   link-local address has been found.

icmp/*:
icmp/*:
ratelimit - INTEGER
ratelimit - INTEGER
	Limit the maximal rates for sending ICMPv6 packets.
	Limit the maximal rates for sending ICMPv6 packets.
+2 −0
Original line number Original line Diff line number Diff line
@@ -164,6 +164,7 @@ struct ipv6_devconf {
	__s32		mc_forwarding;
	__s32		mc_forwarding;
#endif
#endif
	__s32		disable_ipv6;
	__s32		disable_ipv6;
	__s32		accept_dad;
	void		*sysctl;
	void		*sysctl;
};
};


@@ -196,6 +197,7 @@ enum {
	DEVCONF_ACCEPT_SOURCE_ROUTE,
	DEVCONF_ACCEPT_SOURCE_ROUTE,
	DEVCONF_MC_FORWARDING,
	DEVCONF_MC_FORWARDING,
	DEVCONF_DISABLE_IPV6,
	DEVCONF_DISABLE_IPV6,
	DEVCONF_ACCEPT_DAD,
	DEVCONF_MAX
	DEVCONF_MAX
};
};


+35 −0
Original line number Original line Diff line number Diff line
@@ -119,6 +119,7 @@ static void ipv6_regen_rndid(unsigned long data);
static int desync_factor = MAX_DESYNC_FACTOR * HZ;
static int desync_factor = MAX_DESYNC_FACTOR * HZ;
#endif
#endif


static int ipv6_generate_eui64(u8 *eui, struct net_device *dev);
static int ipv6_count_addresses(struct inet6_dev *idev);
static int ipv6_count_addresses(struct inet6_dev *idev);


/*
/*
@@ -184,6 +185,7 @@ struct ipv6_devconf ipv6_devconf __read_mostly = {
	.proxy_ndp		= 0,
	.proxy_ndp		= 0,
	.accept_source_route	= 0,	/* we do not accept RH0 by default. */
	.accept_source_route	= 0,	/* we do not accept RH0 by default. */
	.disable_ipv6		= 0,
	.disable_ipv6		= 0,
	.accept_dad		= 1,
};
};


static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
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,
	.proxy_ndp		= 0,
	.accept_source_route	= 0,	/* we do not accept RH0 by default. */
	.accept_source_route	= 0,	/* we do not accept RH0 by default. */
	.disable_ipv6		= 0,
	.disable_ipv6		= 0,
	.accept_dad		= 1,
};
};


/* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */
/* 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);
	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 defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE)
	if (dev->type == ARPHRD_SIT && (dev->priv_flags & IFF_ISATAP)) {
	if (dev->type == ARPHRD_SIT && (dev->priv_flags & IFF_ISATAP)) {
		printk(KERN_INFO
		printk(KERN_INFO
@@ -1421,6 +1427,20 @@ static void addrconf_dad_stop(struct inet6_ifaddr *ifp)


void addrconf_dad_failure(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())
	if (net_ratelimit())
		printk(KERN_INFO "%s: duplicate address detected!\n", ifp->idev->dev->name);
		printk(KERN_INFO "%s: duplicate address detected!\n", ifp->idev->dev->name);
	addrconf_dad_stop(ifp);
	addrconf_dad_stop(ifp);
@@ -2753,6 +2773,7 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags)
	spin_lock_bh(&ifp->lock);
	spin_lock_bh(&ifp->lock);


	if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) ||
	if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) ||
	    idev->cnf.accept_dad < 1 ||
	    !(ifp->flags&IFA_F_TENTATIVE) ||
	    !(ifp->flags&IFA_F_TENTATIVE) ||
	    ifp->flags & IFA_F_NODAD) {
	    ifp->flags & IFA_F_NODAD) {
		ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC);
		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);
		read_unlock_bh(&idev->lock);
		goto out;
		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);
	spin_lock_bh(&ifp->lock);
	if (ifp->probes == 0) {
	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;
	array[DEVCONF_MC_FORWARDING] = cnf->mc_forwarding;
#endif
#endif
	array[DEVCONF_DISABLE_IPV6] = cnf->disable_ipv6;
	array[DEVCONF_DISABLE_IPV6] = cnf->disable_ipv6;
	array[DEVCONF_ACCEPT_DAD] = cnf->accept_dad;
}
}


static inline size_t inet6_if_nlmsg_size(void)
static inline size_t inet6_if_nlmsg_size(void)
@@ -4226,6 +4253,14 @@ static struct addrconf_sysctl_table
			.mode		=	0644,
			.mode		=	0644,
			.proc_handler	=	&proc_dointvec,
			.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 */
			.ctl_name	=	0,	/* sentinel */
		}
		}