Module Name:    src
Committed By:   roy
Date:           Tue Oct 11 13:59:31 UTC 2016

Modified Files:
        src/sys/netinet: if_arp.c in_var.h

Log Message:
Implement RFC 5227 2.4 Ongoing Conflict Detection and Address Defence.

If ip_dad_count is 0, then the conflict is just logged and the address
is not marked as duplicated.


To generate a diff of this commit:
cvs rdiff -u -r1.229 -r1.230 src/sys/netinet/if_arp.c
cvs rdiff -u -r1.87 -r1.88 src/sys/netinet/in_var.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/netinet/if_arp.c
diff -u src/sys/netinet/if_arp.c:1.229 src/sys/netinet/if_arp.c:1.230
--- src/sys/netinet/if_arp.c:1.229	Tue Oct 11 12:32:30 2016
+++ src/sys/netinet/if_arp.c	Tue Oct 11 13:59:30 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_arp.c,v 1.229 2016/10/11 12:32:30 roy Exp $	*/
+/*	$NetBSD: if_arp.c,v 1.230 2016/10/11 13:59:30 roy Exp $	*/
 
 /*-
  * Copyright (c) 1998, 2000, 2008 The NetBSD Foundation, Inc.
@@ -68,7 +68,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_arp.c,v 1.229 2016/10/11 12:32:30 roy Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_arp.c,v 1.230 2016/10/11 13:59:30 roy Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_ddb.h"
@@ -178,7 +178,7 @@ static	void arp_drainstub(void);
 static void arp_dad_timer(struct ifaddr *);
 static void arp_dad_start(struct ifaddr *);
 static void arp_dad_stop(struct ifaddr *);
-static void arp_dad_duplicated(struct ifaddr *);
+static void arp_dad_duplicated(struct ifaddr *, const char *);
 
 static void arp_init_llentry(struct ifnet *, struct llentry *);
 #if NTOKEN > 0
@@ -1133,16 +1133,13 @@ in_arpinput(struct mbuf *m)
 	if (in_nullhost(itaddr))
 		ARP_STATINC(ARP_STAT_RCVZEROTPA);
 
-	/* DAD check, RFC 5227 2.1.1, Probe Details */
+	/* DAD check, RFC 5227 */
 	if (in_hosteq(isaddr, myaddr) ||
 	    (in_nullhost(isaddr) && in_hosteq(itaddr, myaddr)))
 	{
-		/* If our address is tentative, mark it as duplicated */
-		if (ia->ia4_flags & IN_IFF_TENTATIVE)
-			arp_dad_duplicated((struct ifaddr *)ia);
-		/* If our address is unuseable, don't reply */
-		if (ia->ia4_flags & (IN_IFF_NOTREADY | IN_IFF_DETACHED))
-			goto out;
+		arp_dad_duplicated((struct ifaddr *)ia,
+		    lla_snprintf(ar_sha(ah), ah->ar_hln));
+		goto out;
 	}
 
 	/*
@@ -1156,14 +1153,6 @@ in_arpinput(struct mbuf *m)
 	if (in_nullhost(isaddr))
 		goto reply;
 
-	if (in_hosteq(isaddr, myaddr)) {
-		log(LOG_ERR,
-		   "duplicate IP address %s sent from link address %s\n",
-		   in_fmtaddr(isaddr), lla_snprintf(ar_sha(ah), ah->ar_hln));
-		itaddr = myaddr;
-		goto reply;
-	}
-
 	if (in_hosteq(itaddr, myaddr))
 		la = arpcreate(ifp, m, &isaddr, NULL, 1);
 	else
@@ -1774,41 +1763,45 @@ done:
 }
 
 static void
-arp_dad_duplicated(struct ifaddr *ifa)
+arp_dad_duplicated(struct ifaddr *ifa, const char *sha)
 {
 	struct in_ifaddr *ia = (struct in_ifaddr *)ifa;
-	struct ifnet *ifp;
-	struct dadq *dp;
+	struct ifnet *ifp = ifa->ifa_ifp;
+	const char *iastr = in_fmtaddr(ia->ia_addr.sin_addr);
 
-	mutex_enter(&arp_dad_lock);
-	dp = arp_dad_find(ifa);
-	if (dp == NULL) {
-		mutex_exit(&arp_dad_lock);
-		/* DAD seems to be stopping, so do nothing. */
+	if (ia->ia4_flags & (IN_IFF_TENTATIVE|IN_IFF_DUPLICATED)) {
+		log(LOG_ERR,
+		    "%s: DAD duplicate address %s from %s\n",
+		    if_name(ifp), iastr, sha);
+	} else if (ia->ia_dad_defended == 0 ||
+		   ia->ia_dad_defended < time_uptime - DEFEND_INTERVAL) {
+		ia->ia_dad_defended = time_uptime;
+		arpannounce1(ifa);
+		log(LOG_ERR,
+		    "%s: DAD defended address %s from %s\n",
+		    if_name(ifp), iastr, sha);
 		return;
+	} else {
+		/* If DAD is disabled, just report the duplicate. */
+		if (ip_dad_count == 0) {
+			log(LOG_ERR,
+			    "%s: DAD ignoring duplicate address %s from %s\n",
+			    if_name(ifp), iastr, sha);
+			return;
+		}
+		log(LOG_ERR,
+		    "%s: DAD defence failed for %s from %s\n",
+		    if_name(ifp), iastr, sha);
 	}
 
-	ifp = ifa->ifa_ifp;
-	log(LOG_ERR,
-	    "%s: DAD detected duplicate IPv4 address %s: ARP out=%d\n",
-	    if_name(ifp), in_fmtaddr(ia->ia_addr.sin_addr),
-	    dp->dad_arp_ocount);
+	arp_dad_stop(ifa);
 
 	ia->ia4_flags &= ~IN_IFF_TENTATIVE;
-	ia->ia4_flags |= IN_IFF_DUPLICATED;
-
-	/* We are done with DAD, with duplicated address found. (failure) */
-	arp_dad_stoptimer(dp);
-
-	/* Inform the routing socket that DAD has completed */
-	rt_newaddrmsg(RTM_NEWADDR, ifa, 0, NULL);
-
-	TAILQ_REMOVE(&dadq, dp, dad_list);
-	mutex_exit(&arp_dad_lock);
-
-	free(dp, M_IPARP);
-	dp = NULL;
-	ifafree(ifa);
+	if ((ia->ia4_flags & IN_IFF_DUPLICATED) == 0) {
+		ia->ia4_flags |= IN_IFF_DUPLICATED;
+		/* Inform the routing socket of the duplicate address */
+		rt_newaddrmsg(RTM_NEWADDR, ifa, 0, NULL);
+	}
 }
 
 /*

Index: src/sys/netinet/in_var.h
diff -u src/sys/netinet/in_var.h:1.87 src/sys/netinet/in_var.h:1.88
--- src/sys/netinet/in_var.h:1.87	Thu Sep 29 15:18:18 2016
+++ src/sys/netinet/in_var.h	Tue Oct 11 13:59:30 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: in_var.h,v 1.87 2016/09/29 15:18:18 roy Exp $	*/
+/*	$NetBSD: in_var.h,v 1.88 2016/10/11 13:59:30 roy Exp $	*/
 
 /*-
  * Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -107,6 +107,7 @@ struct in_ifaddr {
 	int	ia4_flags;		/* address flags */
 	void	(*ia_dad_start) (struct ifaddr *);	/* DAD start function */
 	void	(*ia_dad_stop) (struct ifaddr *);	/* DAD stop function */
+	time_t	ia_dad_defended;	/* last time of DAD defence */
 
 #ifdef _KERNEL
 	struct pslist_entry	ia_hash_pslist_entry;

Reply via email to