tech-net archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: IPv4 Address Flags



On 21/04/2015 09:46, Roy Marples wrote:
> This patch adds the following flags to IPv4 and mimics the IPv6
> behaviour of the same flags:
>   IN_IFF_TENTATIVE
>   IN_IFF_DUPLICATED
>   IN_IFF_DETACHED
>   IN_IFF_NOTREADY (IN_IFF_TENTATIVE | IN_IFF_DUPLICATED)

New patch attached after making already committed adjustments to make a
few things more protocol agnostic.

Suggested by dyoung@

Roy

Index: sbin/ifconfig/af_inet.c
===================================================================
RCS file: /cvsroot/src/sbin/ifconfig/af_inet.c,v
retrieving revision 1.15
diff -u -r1.15 af_inet.c
--- sbin/ifconfig/af_inet.c	13 Dec 2010 17:35:08 -0000	1.15
+++ sbin/ifconfig/af_inet.c	22 Apr 2015 21:02:41 -0000
@@ -62,12 +62,14 @@
 static void in_constructor(void) __attribute__((constructor));
 static void in_status(prop_dictionary_t, prop_dictionary_t, bool);
 static void in_commit_address(prop_dictionary_t, prop_dictionary_t);
+static bool in_addr_tentative(struct ifaddrs *ifa);
 static void in_alias(const char *, prop_dictionary_t, prop_dictionary_t,
     struct in_aliasreq *);
 
 static struct afswtch af = {
 	.af_name = "inet", .af_af = AF_INET, .af_status = in_status,
-	.af_addr_commit = in_commit_address
+	.af_addr_commit = in_commit_address,
+	.af_addr_tentative = in_addr_tentative
 };
 
 static void
@@ -137,6 +139,21 @@
 			strlcpy(hbuf, "", sizeof(hbuf)); /* some message? */
 		printf(" broadcast %s", hbuf);
 	}
+
+#ifdef IN_IFF_TENTATIVE
+	memcpy(&ifr.ifr_addr, &creq->ifra_addr, creq->ifra_addr.sin_len);
+	if (prog_ioctl(s, SIOCGIFAFLAG_IN, &ifr) == -1) {
+		if (errno != EADDRNOTAVAIL)
+			warn("SIOCGIFAFLAG_IN");
+	} else {
+		if (ifr.ifr_addrflags & IN_IFF_TENTATIVE)
+			printf(" tentative");
+		if (ifr.ifr_addrflags & IN_IFF_DUPLICATED)
+			printf(" duplicated");
+		if (ifr.ifr_addrflags & IN_IFF_DETACHED)
+			printf(" detached");
+	}
+#endif
 }
 
 static void
@@ -203,6 +220,26 @@
 	commit_address(env, oenv, &inparam);
 }
 
+static bool
+in_addr_tentative(struct ifaddrs *ifa)
+{
+#ifdef IN_IFF_TENTATIVE
+	int s;
+	struct ifreq ifr;
+
+	memset(&ifr, 0, sizeof(ifr));
+	strncpy(ifr.ifr_name, ifa->ifa_name, sizeof(ifr.ifr_name));
+	ifr.ifr_addr = *ifa->ifa_addr;
+	if ((s = getsock(AF_INET)) == -1)
+		err(EXIT_FAILURE, "%s: getsock", __func__);
+	if (ioctl(s, SIOCGIFAFLAG_IN, &ifr) == -1)
+		err(EXIT_FAILURE, "SIOCGIFAFLAG_IN");
+	return ifr.ifr_addrflags & IN_IFF_TENTATIVE ? true : false;
+#else
+	return false;
+#endif
+}
+
 static void
 in_constructor(void)
 {
Index: sys/net/if.h
===================================================================
RCS file: /cvsroot/src/sys/net/if.h,v
retrieving revision 1.188
diff -u -r1.188 if.h
--- sys/net/if.h	20 Apr 2015 10:19:54 -0000	1.188
+++ sys/net/if.h	22 Apr 2015 21:03:01 -0000
@@ -594,6 +594,7 @@
 		struct	sockaddr ifru_broadaddr;
 		struct	sockaddr_storage ifru_space;
 		short	ifru_flags;
+		int	ifru_addrflags;
 		int	ifru_metric;
 		int	ifru_mtu;
 		int	ifru_dlt;
@@ -609,6 +610,7 @@
 #define	ifr_broadaddr	ifr_ifru.ifru_broadaddr	/* broadcast address */
 #define	ifr_space	ifr_ifru.ifru_space	/* sockaddr_storage */
 #define	ifr_flags	ifr_ifru.ifru_flags	/* flags */
+#define	ifr_addrflags	ifr_ifru.ifru_addrflags	/* addr flags */
 #define	ifr_metric	ifr_ifru.ifru_metric	/* metric */
 #define	ifr_mtu		ifr_ifru.ifru_mtu	/* mtu */
 #define	ifr_dlt		ifr_ifru.ifru_dlt	/* data link type (DLT_*) */
Index: sys/net/if_spppsubr.c
===================================================================
RCS file: /cvsroot/src/sys/net/if_spppsubr.c,v
retrieving revision 1.132
diff -u -r1.132 if_spppsubr.c
--- sys/net/if_spppsubr.c	20 Apr 2015 10:19:54 -0000	1.132
+++ sys/net/if_spppsubr.c	22 Apr 2015 21:03:04 -0000
@@ -4875,7 +4875,7 @@
 
 found:
 	{
-		int error;
+		int error, hostIsNew;
 		struct sockaddr_in new_sin = *si;
 		struct sockaddr_in new_dst = *dest;
 
@@ -4886,8 +4886,13 @@
 		 */
 		in_ifscrub(ifp, ifatoia(ifa));
 
-		if (myaddr != 0)
-			new_sin.sin_addr.s_addr = htonl(myaddr);
+		hostIsNew = 0;
+		if (myaddr != 0) {
+			if (new_sin.sin_addr.s_addr != htonl(myaddr)) {
+				new_sin.sin_addr.s_addr = htonl(myaddr);
+				hostIsNew = 1;
+			}
+		}
 		if (hisaddr != 0) {
 			new_dst.sin_addr.s_addr = htonl(hisaddr);
 			if (new_dst.sin_addr.s_addr != dest->sin_addr.s_addr) {
@@ -4895,7 +4900,7 @@
 				*dest = new_dst; /* fix dstaddr in place */
 			}
 		}
-		error = in_ifinit(ifp, ifatoia(ifa), &new_sin, 0);
+		error = in_ifinit(ifp, ifatoia(ifa), &new_sin, 0, hostIsNew);
 		if (debug && error)
 		{
 			log(LOG_DEBUG, "%s: sppp_set_ip_addrs: in_ifinit "
@@ -4948,7 +4953,7 @@
 		if (sp->ipcp.flags & IPCP_HISADDR_DYN)
 			/* replace peer addr in place */
 			dest->sin_addr.s_addr = sp->ipcp.saved_hisaddr;
-		in_ifinit(ifp, ifatoia(ifa), &new_sin, 0);
+		in_ifinit(ifp, ifatoia(ifa), &new_sin, 0, 0);
 		(void)pfil_run_hooks(if_pfil,
 		    (struct mbuf **)SIOCDIFADDR, ifp, PFIL_IFADDR);
 	}
Index: sys/netinet/if_arp.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/if_arp.c,v
retrieving revision 1.162
diff -u -r1.162 if_arp.c
--- sys/netinet/if_arp.c	23 Mar 2015 18:33:17 -0000	1.162
+++ sys/netinet/if_arp.c	22 Apr 2015 21:03:05 -0000
@@ -95,6 +95,7 @@
 #include <sys/sysctl.h>
 #include <sys/socketvar.h>
 #include <sys/percpu.h>
+#include <sys/cprng.h>
 
 #include <net/ethertypes.h>
 #include <net/if.h>
@@ -102,6 +103,7 @@
 #include <net/if_token.h>
 #include <net/if_types.h>
 #include <net/if_ether.h>
+#include <net/net_osdep.h>
 #include <net/route.h>
 #include <net/net_stats.h>
 
@@ -142,6 +144,14 @@
 #define	rt_expire rt_rmx.rmx_expire
 #define	rt_pksent rt_rmx.rmx_pksent
 
+int		ip_dad_count = PROBE_NUM;
+#ifdef ARP_DEBUG
+static int	arp_debug = 1;
+#else
+static int	arp_debug = 0;
+#endif
+#define arplog(x)	do { if (arp_debug) log x; } while (/*CONSTCOND*/ 0)
+
 static	struct sockaddr *arp_setgate(struct rtentry *, struct sockaddr *,
 	    const struct sockaddr *);
 static	void arptfree(struct llinfo_arp *);
@@ -153,6 +163,9 @@
 static	void in_arpinput(struct mbuf *);
 static	void arp_drainstub(void);
 
+static void arp_dad_timer(struct ifaddr *);
+static void arp_dad_duplicated(struct ifaddr *);
+
 LIST_HEAD(llinfo_arpq, llinfo_arp) llinfo_arp;
 struct	ifqueue arpintrq = {
 	.ifq_head = NULL,
@@ -511,6 +524,14 @@
 
 		in = &ifatoia(ifa)->ia_addr.sin_addr;
 
+		if (ifatoia(ifa)->ia4_flags &
+		    (IN_IFF_NOTREADY | IN_IFF_DETACHED))
+		{
+			arplog((LOG_DEBUG, "arp_request: %s not ready\n",
+			   in_fmtaddr(*in)));
+			return;
+		}
+
 		arprequest(ifa->ifa_ifp, in, in,
 		    CLLADDR(ifa->ifa_ifp->if_sadl));
 		return;
@@ -601,10 +622,17 @@
 		}
 		/* Announce a new entry if requested. */
 		if (rt->rt_flags & RTF_ANNOUNCE) {
-			arprequest(ifp,
-			    &satocsin(rt_getkey(rt))->sin_addr,
-			    &satocsin(rt_getkey(rt))->sin_addr,
-			    CLLADDR(satocsdl(gate)));
+			INADDR_TO_IA(satocsin(rt_getkey(rt))->sin_addr, ia);
+			while (ia && ia->ia_ifp != ifp)
+				NEXT_IA_WITH_SAME_ADDR(ia);
+			if (ia == NULL ||
+			    ia->ia4_flags & (IN_IFF_NOTREADY | IN_IFF_DETACHED))
+				;
+			else
+				arprequest(ifp,
+				    &satocsin(rt_getkey(rt))->sin_addr,
+				    &satocsin(rt_getkey(rt))->sin_addr,
+				    CLLADDR(satocsdl(gate)));
 		}
 		/*FALLTHROUGH*/
 	case RTM_RESOLVE:
@@ -999,16 +1027,6 @@
 	if (m->m_flags & (M_BCAST|M_MCAST))
 		ARP_STATINC(ARP_STAT_RCVMCAST);
 
-	/*
-	 * If the target IP address is zero, ignore the packet.
-	 * This prevents the code below from tring to answer
-	 * when we are using IP address zero (booting).
-	 */
-	if (in_nullhost(itaddr)) {
-		ARP_STATINC(ARP_STAT_RCVZEROTPA);
-		goto out;
-	}
-
 
 	/*
 	 * Search for a matching interface address
@@ -1089,13 +1107,38 @@
 	/*
 	 * If the source IP address is zero, this is an RFC 5227 ARP probe
 	 */
-	if (in_nullhost(isaddr)) {
+	if (in_nullhost(isaddr))
 		ARP_STATINC(ARP_STAT_RCVZEROSPA);
-		goto reply;
+	else if (in_hosteq(isaddr, myaddr))
+		ARP_STATINC(ARP_STAT_RCVLOCALSPA);
+
+	if (in_nullhost(itaddr))
+		ARP_STATINC(ARP_STAT_RCVZEROTPA);
+
+	/* DAD check, RFC 5227 2.1.1, Probe Details */
+	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;
 	}
 
+	/*
+	 * If the target IP address is zero, ignore the packet.
+	 * This prevents the code below from tring to answer
+	 * when we are using IP address zero (booting).
+	 */
+	if (in_nullhost(itaddr))
+		goto out;
+
+	if (in_nullhost(isaddr))
+		goto reply;
+
 	if (in_hosteq(isaddr, myaddr)) {
-		ARP_STATINC(ARP_STAT_RCVLOCALSPA);
 		log(LOG_ERR,
 		   "duplicate IP address %s sent from link address %s\n",
 		   in_fmtaddr(isaddr), lla_snprintf(ar_sha(ah), ah->ar_hln));
@@ -1211,6 +1254,9 @@
 	}
 	ARP_STATINC(ARP_STAT_RCVREQUEST);
 	if (in_hosteq(itaddr, myaddr)) {
+		/* If our address is unuseable, don't reply */
+		if (ia->ia4_flags & (IN_IFF_NOTREADY | IN_IFF_DETACHED))
+			goto out;
 		/* I am the target */
 		tha = ar_tha(ah);
 		if (tha)
@@ -1358,19 +1404,321 @@
 arp_ifinit(struct ifnet *ifp, struct ifaddr *ifa)
 {
 	struct in_addr *ip;
+	struct in_ifaddr *ia = (struct in_ifaddr *)ifa;
 
 	/*
 	 * Warn the user if another station has this IP address,
 	 * but only if the interface IP address is not zero.
 	 */
 	ip = &IA_SIN(ifa)->sin_addr;
-	if (!in_nullhost(*ip))
+	if (!in_nullhost(*ip) &&
+	    (ia->ia4_flags & (IN_IFF_NOTREADY | IN_IFF_DETACHED)) == 0)
 		arprequest(ifp, ip, ip, CLLADDR(ifp->if_sadl));
 
 	ifa->ifa_rtrequest = arp_rtrequest;
 	ifa->ifa_flags |= RTF_CLONING;
 }
 
+TAILQ_HEAD(dadq_head, dadq);
+struct dadq {
+	TAILQ_ENTRY(dadq) dad_list;
+	struct ifaddr *dad_ifa;
+	int dad_count;		/* max ARP to send */
+	int dad_arp_tcount;	/* # of trials to send ARP */
+	int dad_arp_ocount;	/* ARP sent so far */
+	int dad_arp_announce;	/* max ARP announcements */
+	int dad_arp_acount;	/* # of announcements */
+	struct callout dad_timer_ch;
+};
+MALLOC_JUSTDEFINE(M_IPARP, "ARP DAD", "ARP DAD Structure");
+
+static struct dadq_head dadq;
+static int dad_init = 0;
+static int dad_maxtry = 15;     /* max # of *tries* to transmit DAD packet */
+
+static struct dadq *
+arp_dad_find(struct ifaddr *ifa)
+{
+	struct dadq *dp;
+
+	TAILQ_FOREACH(dp, &dadq, dad_list) {
+		if (dp->dad_ifa == ifa)
+			return dp;
+	}
+	return NULL;
+}
+
+static void
+arp_dad_starttimer(struct dadq *dp, int ticks)
+{
+
+	callout_reset(&dp->dad_timer_ch, ticks,
+	    (void (*)(void *))arp_dad_timer, (void *)dp->dad_ifa);
+}
+
+static void
+arp_dad_stoptimer(struct dadq *dp)
+{
+
+	callout_stop(&dp->dad_timer_ch);
+}
+
+static void
+arp_dad_output(struct dadq *dp, struct ifaddr *ifa)
+{
+	struct in_ifaddr *ia = (struct in_ifaddr *)ifa;
+	struct ifnet *ifp = ifa->ifa_ifp;
+	struct in_addr sip;
+
+	dp->dad_arp_tcount++;
+	if ((ifp->if_flags & IFF_UP) == 0)
+		return;
+	if ((ifp->if_flags & IFF_RUNNING) == 0)
+		return;
+
+	dp->dad_arp_tcount = 0;
+	dp->dad_arp_ocount++;
+
+	memset(&sip, 0, sizeof(sip));
+	arprequest(ifa->ifa_ifp, &sip, &ia->ia_addr.sin_addr,
+	    CLLADDR(ifa->ifa_ifp->if_sadl));
+}
+
+/*
+ * Start Duplicate Address Detection (DAD) for specified interface address.
+ */
+void
+arp_dad_start(struct ifaddr *ifa)
+{
+	struct in_ifaddr *ia = (struct in_ifaddr *)ifa;
+	struct dadq *dp;
+
+	if (!dad_init) {
+		TAILQ_INIT(&dadq);
+		dad_init++;
+	}
+
+	/*
+	 * If we don't need DAD, don't do it.
+	 * - DAD is disabled (ip_dad_count == 0)
+	 */
+	if (!(ia->ia4_flags & IN_IFF_TENTATIVE)) {
+		log(LOG_DEBUG,
+			"arp_dad_start: called with non-tentative address "
+			"%s(%s)\n",
+			in_fmtaddr(ia->ia_addr.sin_addr),
+			ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???");
+		return;
+	}
+	if (!ip_dad_count) {
+		struct in_addr *ip = &IA_SIN(ifa)->sin_addr;
+
+		ia->ia4_flags &= ~IN_IFF_TENTATIVE;
+		rt_newaddrmsg(RTM_NEWADDR, ifa, 0, NULL);
+		arprequest(ifa->ifa_ifp, ip, ip,
+		    CLLADDR(ifa->ifa_ifp->if_sadl));
+		return;
+	}
+	if (ifa->ifa_ifp == NULL)
+		panic("arp_dad_start: ifa->ifa_ifp == NULL");
+	if (!(ifa->ifa_ifp->if_flags & IFF_UP))
+		return;
+	if (arp_dad_find(ifa) != NULL) {
+		/* DAD already in progress */
+		return;
+	}
+
+	dp = malloc(sizeof(*dp), M_IPARP, M_NOWAIT);
+	if (dp == NULL) {
+		log(LOG_ERR, "arp_dad_start: memory allocation failed for "
+			"%s(%s)\n",
+			in_fmtaddr(ia->ia_addr.sin_addr),
+			ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???");
+		return;
+	}
+	memset(dp, 0, sizeof(*dp));
+	callout_init(&dp->dad_timer_ch, CALLOUT_MPSAFE);
+	TAILQ_INSERT_TAIL(&dadq, (struct dadq *)dp, dad_list);
+
+	arplog((LOG_DEBUG, "%s: starting DAD for %s\n", if_name(ifa->ifa_ifp),
+	    in_fmtaddr(ia->ia_addr.sin_addr)));
+
+	/*
+	 * Send ARP packet for DAD, ip_dad_count times.
+	 * Note that we must delay the first transmission.
+	 */
+	dp->dad_ifa = ifa;
+	ifaref(ifa);	/* just for safety */
+	dp->dad_count = ip_dad_count;
+	dp->dad_arp_announce = 0; /* Will be set when starting to announce */
+	dp->dad_arp_acount = dp->dad_arp_ocount = dp->dad_arp_tcount = 0;
+
+	arp_dad_starttimer(dp, cprng_fast32() % (PROBE_WAIT * hz));
+}
+
+/*
+ * terminate DAD unconditionally.  used for address removals.
+ */
+void
+arp_dad_stop(struct ifaddr *ifa)
+{
+	struct dadq *dp;
+
+	if (!dad_init)
+		return;
+	dp = arp_dad_find(ifa);
+	if (dp == NULL) {
+		/* DAD wasn't started yet */
+		return;
+	}
+
+	arp_dad_stoptimer(dp);
+
+	TAILQ_REMOVE(&dadq, dp, dad_list);
+	free(dp, M_IPARP);
+	dp = NULL;
+	ifafree(ifa);
+}
+
+static void
+arp_dad_timer(struct ifaddr *ifa)
+{
+	struct in_ifaddr *ia = (struct in_ifaddr *)ifa;
+	struct dadq *dp;
+	struct in_addr *ip;
+
+	mutex_enter(softnet_lock);
+	KERNEL_LOCK(1, NULL);
+
+	/* Sanity check */
+	if (ia == NULL) {
+		log(LOG_ERR, "arp_dad_timer: called with null parameter\n");
+		goto done;
+	}
+	dp = arp_dad_find(ifa);
+	if (dp == NULL) {
+		log(LOG_ERR, "arp_dad_timer: DAD structure not found\n");
+		goto done;
+	}
+	if (ia->ia4_flags & IN_IFF_DUPLICATED) {
+		log(LOG_ERR, "nd4_dad_timer: called with duplicate address "
+			"%s(%s)\n",
+			in_fmtaddr(ia->ia_addr.sin_addr),
+			ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???");
+		goto done;
+	}
+	if ((ia->ia4_flags & IN_IFF_TENTATIVE) == 0 && dp->dad_arp_acount == 0){
+		log(LOG_ERR, "arp_dad_timer: called with non-tentative address "
+			"%s(%s)\n",
+			in_fmtaddr(ia->ia_addr.sin_addr),
+			ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???");
+		goto done;
+	}
+
+	/* timeouted with IFF_{RUNNING,UP} check */
+	if (dp->dad_arp_tcount > dad_maxtry) {
+		arplog((LOG_INFO, "%s: could not run DAD, driver problem?\n",
+			if_name(ifa->ifa_ifp)));
+
+		TAILQ_REMOVE(&dadq, dp, dad_list);
+		free(dp, M_IPARP);
+		dp = NULL;
+		ifafree(ifa);
+		goto done;
+	}
+
+	/* Need more checks? */
+	if (dp->dad_arp_ocount < dp->dad_count) {
+		int delay;
+
+		/*
+		 * We have more ARP to go.  Send ARP packet for DAD.
+		 */
+		arp_dad_output(dp, ifa);
+		if (dp->dad_arp_ocount < dp->dad_count)
+			delay = (PROBE_MIN * hz) +
+			    (cprng_fast32() %
+			    ((PROBE_MAX * hz) - (PROBE_MIN * hz)));
+		else
+			delay = ANNOUNCE_WAIT * hz;
+		arp_dad_starttimer(dp, delay);
+		goto done;
+	} else if (dp->dad_arp_acount == 0) {
+		/*
+		 * We are done with DAD.
+		 * No duplicate address found.
+		 */
+		ia->ia4_flags &= ~IN_IFF_TENTATIVE;
+		rt_newaddrmsg(RTM_NEWADDR, ifa, 0, NULL);
+		arplog((LOG_DEBUG,
+		    "%s: DAD complete for %s - no duplicates found\n",
+		    if_name(ifa->ifa_ifp),
+		    in_fmtaddr(ia->ia_addr.sin_addr)));
+		dp->dad_arp_announce = ANNOUNCE_NUM;
+		goto announce;
+	} else if (dp->dad_arp_acount < dp->dad_arp_announce) {
+announce:
+		/*
+		 * Announce the address.
+		 */
+		ip = &IA_SIN(ifa)->sin_addr;
+		arprequest(ifa->ifa_ifp, ip, ip,
+		    CLLADDR(ifa->ifa_ifp->if_sadl));
+		dp->dad_arp_acount++;
+		if (dp->dad_arp_acount < dp->dad_arp_announce) {
+			arp_dad_starttimer(dp, ANNOUNCE_INTERVAL * hz);
+			goto done;
+		}
+		arplog((LOG_DEBUG,
+		    "%s: ARP announcement complete for %s\n",
+		    if_name(ifa->ifa_ifp),
+		    in_fmtaddr(ia->ia_addr.sin_addr)));
+	}
+
+	TAILQ_REMOVE(&dadq, dp, dad_list);
+	free(dp, M_IPARP);
+	dp = NULL;
+	ifafree(ifa);
+
+done:
+	KERNEL_UNLOCK_ONE(NULL);
+	mutex_exit(softnet_lock);
+}
+
+static void
+arp_dad_duplicated(struct ifaddr *ifa)
+{
+	struct in_ifaddr *ia = (struct in_ifaddr *)ifa;
+	struct ifnet *ifp;
+	struct dadq *dp;
+
+	dp = arp_dad_find(ifa);
+	if (dp == NULL) {
+		log(LOG_ERR, "arp_dad_duplicated: DAD structure not found\n");
+		return;
+	}
+
+	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);
+
+	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);
+	free(dp, M_IPARP);
+	dp = NULL;
+	ifafree(ifa);
+}
+
 /*
  * Called from 10 Mb/s Ethernet interrupt handlers
  * when ether packet type ETHERTYPE_REVARP
@@ -1734,6 +2082,13 @@
 			SYSCTL_DESCR("log ARP packets from non-local network"),
 			NULL, 0, &log_unknown_network, 0,
 			CTL_NET,PF_INET, node->sysctl_num, CTL_CREATE, CTL_EOL);
+
+	sysctl_createv(clog, 0, NULL, NULL,
+		       CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
+		       CTLTYPE_INT, "debug",
+		       SYSCTL_DESCR("Enable ARP DAD debug output"),
+		       NULL, 0, &arp_debug, 0,
+		       CTL_NET, PF_INET, node->sysctl_num, CTL_CREATE, CTL_EOL);
 }
 
 #endif /* INET */
Index: sys/netinet/if_inarp.h
===================================================================
RCS file: /cvsroot/src/sys/netinet/if_inarp.h,v
retrieving revision 1.44
diff -u -r1.44 if_inarp.h
--- sys/netinet/if_inarp.h	30 Sep 2012 05:13:12 -0000	1.44
+++ sys/netinet/if_inarp.h	22 Apr 2015 21:03:05 -0000
@@ -56,6 +56,22 @@
 };
 
 #ifdef _KERNEL
+
+/* ARP timings from RFC5227 */
+#define PROBE_WAIT               1
+#define PROBE_NUM                3
+#define PROBE_MIN                1
+#define PROBE_MAX                2
+#define ANNOUNCE_WAIT            2
+#define ANNOUNCE_NUM             2
+#define ANNOUNCE_INTERVAL        2
+#define MAX_CONFLICTS           10
+#define RATE_LIMIT_INTERVAL     60
+#define DEFEND_INTERVAL         10
+
+#include <sys/malloc.h>
+MALLOC_DECLARE(M_IPARP);
+
 extern struct ifqueue arpintrq;
 void arp_ifinit(struct ifnet *, struct ifaddr *);
 void arp_rtrequest(int, struct rtentry *, const struct rt_addrinfo *);
@@ -69,6 +85,9 @@
 int arpioctl(u_long, void *);
 void arpwhohas(struct ifnet *, struct in_addr *);
 
+void arp_dad_start(struct ifaddr *);
+void arp_dad_stop(struct ifaddr *);
+
 void revarpinput(struct mbuf *);
 void in_revarpinput(struct mbuf *);
 void revarprequest(struct ifnet *);
Index: sys/netinet/in.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/in.c,v
retrieving revision 1.151
diff -u -r1.151 in.c
--- sys/netinet/in.c	26 Feb 2015 12:58:36 -0000	1.151
+++ sys/netinet/in.c	22 Apr 2015 21:03:06 -0000
@@ -100,6 +100,7 @@
 #include <sys/param.h>
 #include <sys/ioctl.h>
 #include <sys/errno.h>
+#include <sys/kernel.h>
 #include <sys/malloc.h>
 #include <sys/socket.h>
 #include <sys/socketvar.h>
@@ -373,6 +374,7 @@
 	case SIOCAIFADDR:
 	case SIOCDIFADDR:
 	case SIOCGIFALIAS:
+	case SIOCGIFAFLAG_IN:
 		if (ifra->ifra_addr.sin_family == AF_INET)
 			LIST_FOREACH(ia,
 			    &IN_IFADDR_HASH(ifra->ifra_addr.sin_addr.s_addr),
@@ -382,7 +384,10 @@
 				    ifra->ifra_addr.sin_addr))
 					break;
 			}
-		if ((cmd == SIOCDIFADDR || cmd == SIOCGIFALIAS) && ia == NULL)
+		if ((cmd == SIOCDIFADDR ||
+		    cmd == SIOCGIFALIAS ||
+		    cmd == SIOCGIFAFLAG_IN) &&
+		    ia == NULL)
 			return (EADDRNOTAVAIL);
 
 		if (cmd == SIOCDIFADDR &&
@@ -391,6 +396,16 @@
 		}
 		/* FALLTHROUGH */
 	case SIOCSIFADDR:
+		hostIsNew = 1;
+		if (ia == NULL || ia->ia_addr.sin_family != AF_INET)
+			;
+		else if (ifra->ifra_addr.sin_len == 0) {
+			ifra->ifra_addr = ia->ia_addr;
+			hostIsNew = 0;
+		} else if (in_hosteq(ia->ia_addr.sin_addr,
+		           ifra->ifra_addr.sin_addr))
+			hostIsNew = 0;
+		/* FALLTHROUGH */
 	case SIOCSIFDSTADDR:
 		if (ifra->ifra_addr.sin_family != AF_INET)
 			return (EAFNOSUPPORT);
@@ -399,7 +414,7 @@
 		if (ifp == NULL)
 			panic("in_control");
 
-		if (cmd == SIOCGIFALIAS)
+		if (cmd == SIOCGIFALIAS || cmd == SIOCGIFAFLAG_IN)
 			break;
 
 		if (ia == NULL &&
@@ -509,7 +524,7 @@
 
 	case SIOCSIFADDR:
 		error = in_ifinit(ifp, ia, satocsin(ifreq_getaddr(cmd, ifr)),
-		    1);
+		    1, hostIsNew);
 		if (error == 0) {
 			(void)pfil_run_hooks(if_pfil,
 			    (struct mbuf **)SIOCSIFADDR, ifp, PFIL_IFADDR);
@@ -520,20 +535,11 @@
 		in_ifscrub(ifp, ia);
 		ia->ia_sockmask = *satocsin(ifreq_getaddr(cmd, ifr));
 		ia->ia_subnetmask = ia->ia_sockmask.sin_addr.s_addr;
-		error = in_ifinit(ifp, ia, NULL, 0);
+		error = in_ifinit(ifp, ia, NULL, 0, 0);
 		break;
 
 	case SIOCAIFADDR:
 		maskIsNew = 0;
-		hostIsNew = 1;
-		if (ia->ia_addr.sin_family != AF_INET)
-			;
-		else if (ifra->ifra_addr.sin_len == 0) {
-			ifra->ifra_addr = ia->ia_addr;
-			hostIsNew = 0;
-		} else if (in_hosteq(ia->ia_addr.sin_addr,
-		           ifra->ifra_addr.sin_addr))
-			hostIsNew = 0;
 		if (ifra->ifra_mask.sin_len) {
 			/* Only scrub if we control the prefix route,
 			 * otherwise userland gets a bogus message */
@@ -554,7 +560,8 @@
 		}
 		if (ifra->ifra_addr.sin_family == AF_INET &&
 		    (hostIsNew || maskIsNew)) {
-			error = in_ifinit(ifp, ia, &ifra->ifra_addr, 0);
+			error = in_ifinit(ifp, ia, &ifra->ifra_addr, 0,
+			    hostIsNew);
 		}
 		if ((ifp->if_flags & IFF_BROADCAST) &&
 		    (ifra->ifra_broadaddr.sin_family == AF_INET))
@@ -577,6 +584,10 @@
 			      sizeof(ifra->ifra_broadaddr));
 		break;
 
+	case SIOCGIFAFLAG_IN:
+		ifr->ifr_addrflags = ia->ia4_flags;
+		break;
+
 	case SIOCDIFADDR:
 		in_purgeaddr(&ia->ia_ifa);
 		(void)pfil_run_hooks(if_pfil, (struct mbuf **)SIOCDIFADDR,
@@ -652,6 +663,9 @@
 	struct ifnet *ifp = ifa->ifa_ifp;
 	struct in_ifaddr *ia = (void *) ifa;
 
+        /* stop DAD processing */
+	arp_dad_stop(ifa);
+
 	in_ifscrub(ifp, ia);
 	in_ifremlocal(ifa);
 	LIST_REMOVE(ia, ia_hash);
@@ -870,7 +884,7 @@
  */
 int
 in_ifinit(struct ifnet *ifp, struct in_ifaddr *ia,
-    const struct sockaddr_in *sin, int scrub)
+    const struct sockaddr_in *sin, int scrub, int hostIsNew)
 {
 	u_int32_t i;
 	struct sockaddr_in oldaddr;
@@ -888,6 +902,14 @@
 	ia->ia_addr = *sin;
 	LIST_INSERT_HEAD(&IN_IFADDR_HASH(ia->ia_addr.sin_addr.s_addr), ia, ia_hash);
 
+	/* Set IN_IFF flags early for arp_ifinit() */
+	if (hostIsNew && if_do_dad(ifp) && !in_nullhost(ia->ia_addr.sin_addr)) {
+		if (ifp->if_link_state == LINK_STATE_DOWN)
+			ia->ia4_flags |= IN_IFF_DETACHED;
+		else
+			ia->ia4_flags |= IN_IFF_TENTATIVE;
+	}
+
 	/*
 	 * Give the interface a chance to initialize
 	 * if this is its first address,
@@ -956,6 +978,12 @@
 		addr.s_addr = INADDR_ALLHOSTS_GROUP;
 		ia->ia_allhosts = in_addmulti(&addr, ifp);
 	}
+
+	if (hostIsNew && if_do_dad(ifp) &&
+	    !in_nullhost(ia->ia_addr.sin_addr) &&
+	    ia->ia4_flags & IN_IFF_TENTATIVE)
+		arp_dad_start((struct ifaddr *)ia);
+
 	return (error);
 bad:
 	splx(s);
@@ -1122,6 +1150,101 @@
 }
 
 /*
+ * perform DAD when interface becomes IFF_UP.
+ */
+void
+in_if_link_up(struct ifnet *ifp)
+{
+	struct ifaddr *ifa;
+	struct in_ifaddr *ia;
+
+	/* Ensure it's sane to run DAD */
+	if (ifp->if_link_state == LINK_STATE_DOWN)
+		return;
+	if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
+		return;
+
+	IFADDR_FOREACH(ifa, ifp) {
+		if (ifa->ifa_addr->sa_family != AF_INET)
+			continue;
+		ia = (struct in_ifaddr *)ifa;
+
+		/* If detached then mark as tentative */
+		if (ia->ia4_flags & IN_IFF_DETACHED) {
+			ia->ia4_flags &= ~IN_IFF_DETACHED;
+			if (if_do_dad(ifp))
+				ia->ia4_flags |= IN_IFF_TENTATIVE;
+			else if ((ia->ia4_flags & IN_IFF_TENTATIVE) == 0)
+				rt_newaddrmsg(RTM_NEWADDR, ifa, 0, NULL);
+		}
+
+		if (ia->ia4_flags & IN_IFF_TENTATIVE) {
+			/* Clear the duplicated flag as we're starting DAD. */
+			ia->ia4_flags &= ~IN_IFF_DUPLICATED;
+			arp_dad_start(ifa);
+		}
+	}
+}
+
+void
+in_if_up(struct ifnet *ifp)
+{
+
+	/* interface may not support link state, so bring it up also */
+	in_if_link_up(ifp);
+}
+
+/*
+ * Mark all addresses as detached.
+ */
+void
+in_if_link_down(struct ifnet *ifp)
+{
+	struct ifaddr *ifa;
+	struct in_ifaddr *ia;
+
+	IFADDR_FOREACH(ifa, ifp) {
+		if (ifa->ifa_addr->sa_family != AF_INET)
+			continue;
+		ia = (struct in_ifaddr *)ifa;
+
+		/* Stop DAD processing */
+		arp_dad_stop(ifa);
+
+		/*
+		 * Mark the address as detached.
+		 */
+		if (!(ia->ia4_flags & IN_IFF_DETACHED)) {
+			ia->ia4_flags |= IN_IFF_DETACHED;
+			ia->ia4_flags &=
+			    ~(IN_IFF_TENTATIVE | IN_IFF_DUPLICATED);
+			rt_newaddrmsg(RTM_NEWADDR, ifa, 0, NULL);
+		}
+	}
+}
+
+void
+in_if_down(struct ifnet *ifp)
+{
+
+	in_if_link_down(ifp);
+}
+
+void
+in_if_link_state_change(struct ifnet *ifp, int link_state)
+{
+
+	switch (link_state) {
+	case LINK_STATE_DOWN:
+		in_if_link_down(ifp);
+		break;
+	case LINK_STATE_UP:
+		in_if_link_up(ifp);
+		break;
+	}
+}
+
+/*
  * in_lookup_multi: look up the in_multi record for a given IP
  * multicast address on a given interface.  If no matching record is
  * found, return NULL.
@@ -1375,7 +1498,7 @@
 		if (imo->imo_multicast_ifp != NULL) {
 			ifp = imo->imo_multicast_ifp;
 			IFP_TO_IA(ifp, ia);		/* XXX */
-			if (ia == 0) {
+			if (ia == 0 || ia->ia4_flags & IN_IFF_NOTREADY) {
 				*errorp = EADDRNOTAVAIL;
 				return NULL;
 			}
@@ -1384,6 +1507,10 @@
 	if (ia->ia_ifa.ifa_getifa != NULL) {
 		ia = ifatoia((*ia->ia_ifa.ifa_getifa)(&ia->ia_ifa,
 		                                      sintosa(sin)));
+		if (ia == NULL) {
+			*errorp = EADDRNOTAVAIL;
+			return NULL;
+		}
 	}
 #ifdef GETIFA_DEBUG
 	else
Index: sys/netinet/in.h
===================================================================
RCS file: /cvsroot/src/sys/netinet/in.h,v
retrieving revision 1.96
diff -u -r1.96 in.h
--- sys/netinet/in.h	10 Feb 2015 19:11:52 -0000	1.96
+++ sys/netinet/in.h	22 Apr 2015 21:03:07 -0000
@@ -467,7 +467,8 @@
 #define	IPCTL_RANDOMID	       22	/* use random IP ids (if configured) */
 #define	IPCTL_LOOPBACKCKSUM    23	/* do IP checksum on loopback */
 #define	IPCTL_STATS		24	/* IP statistics */
-#define	IPCTL_MAXID	       25
+#define	IPCTL_DAD_COUNT        25	/* DAD packets to send */
+#define	IPCTL_MAXID	       26
 
 #define	IPCTL_NAMES { \
 	{ 0, 0 }, \
@@ -495,6 +496,7 @@
 	{ "random_id", CTLTYPE_INT }, \
 	{ "do_loopback_cksum", CTLTYPE_INT }, \
 	{ "stats", CTLTYPE_STRUCT }, \
+	{ "dad_count", CTLTYPE_INT }, \
 }
 #endif /* _NETBSD_SOURCE */
 
@@ -564,6 +566,12 @@
 int	in_localaddr(struct in_addr);
 void	in_socktrim(struct sockaddr_in *);
 
+void	in_if_link_up(struct ifnet *);
+void	in_if_link_down(struct ifnet *);
+void	in_if_up(struct ifnet *);
+void	in_if_down(struct ifnet *);
+void	in_if_link_state_change(struct ifnet *, int);
+
 struct route;
 struct ip_moptions;
 
Index: sys/netinet/in_pcb.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/in_pcb.c,v
retrieving revision 1.156
diff -u -r1.156 in_pcb.c
--- sys/netinet/in_pcb.c	3 Apr 2015 20:01:07 -0000	1.156
+++ sys/netinet/in_pcb.c	22 Apr 2015 21:03:07 -0000
@@ -287,6 +287,8 @@
 			ia = ifatoia(ifa_ifwithaddr(sintosa(sin)));
 		if (ia == NULL)
 			return (EADDRNOTAVAIL);
+		if (ia->ia4_flags & (IN_IFF_NOTREADY | IN_IFF_DETACHED))
+			return (EADDRNOTAVAIL);
 	}
 
 	inp->inp_laddr = sin->sin_addr;
Index: sys/netinet/in_proto.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/in_proto.c,v
retrieving revision 1.111
diff -u -r1.111 in_proto.c
--- sys/netinet/in_proto.c	10 Feb 2015 19:11:52 -0000	1.111
+++ sys/netinet/in_proto.c	22 Apr 2015 21:03:07 -0000
@@ -384,6 +384,8 @@
 	.dom_rtattach = rt_inithead,
 	.dom_rtoffset = 32,
 	.dom_maxrtkey = sizeof(struct ip_pack4),
+	.dom_if_up = in_if_up,
+	.dom_if_down = in_if_down,
 #ifdef IPSELSRC
 	.dom_ifattach = in_domifattach,
 	.dom_ifdetach = in_domifdetach,
@@ -391,6 +393,7 @@
 	.dom_ifattach = NULL,
 	.dom_ifdetach = NULL,
 #endif
+	.dom_if_link_state_change = in_if_link_state_change,
 	.dom_ifqueues = { NULL, NULL },
 	.dom_link = { NULL },
 	.dom_mowner = MOWNER_INIT("",""),
Index: sys/netinet/in_selsrc.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/in_selsrc.c,v
retrieving revision 1.11
diff -u -r1.11 in_selsrc.c
--- sys/netinet/in_selsrc.c	25 Feb 2014 18:30:12 -0000	1.11
+++ sys/netinet/in_selsrc.c	22 Apr 2015 21:03:07 -0000
@@ -300,6 +300,7 @@
 	struct in_ifsysctl *isc;
 	struct in_ifselsrc *iss;
 	int best_score[IN_SCORE_SRC_MAX], score[IN_SCORE_SRC_MAX];
+	struct in_ifaddr *ia;
 
 	if (ifa->ifa_addr->sa_family != AF_INET ||
 	    dst0 == NULL || dst0->sa_family != AF_INET) {	/* Possible. */
@@ -346,6 +347,9 @@
 
 		if (alt_ifa == ifa || src->sin_family != AF_INET)
 			continue;
+		ia = (struct in_ifaddr *)alt_ifa;
+		if (ia->ia4_flags & IN_IFF_NOTREADY)
+			continue;
 
 		in_score(score_src, score, NULL, &src->sin_addr,
 		         alt_ifa->ifa_preference, idx, &dst->sin_addr);
@@ -363,6 +367,13 @@
 			best_ifa = alt_ifa;
 		}
 	}
+
+	ia = (struct in_ifaddr *)best_ifa;
+	if (ia->ia4_flags & IN_IFF_NOTREADY) {
+		errno = EADDRNOTAVAIL;
+		return NULL;
+	}
+
 #ifdef GETIFA_DEBUG
 	if (in_selsrc_debug) {
 		printf("%s: choose src %#" PRIx32 " score ", __func__,
Index: sys/netinet/in_var.h
===================================================================
RCS file: /cvsroot/src/sys/netinet/in_var.h,v
retrieving revision 1.70
diff -u -r1.70 in_var.h
--- sys/netinet/in_var.h	1 Jul 2014 05:49:18 -0000	1.70
+++ sys/netinet/in_var.h	22 Apr 2015 21:03:08 -0000
@@ -66,6 +66,13 @@
 
 #include <sys/queue.h>
 
+#define IN_IFF_TENTATIVE	0x01	/* tentative address */
+#define IN_IFF_DUPLICATED	0x02	/* DAD detected duplicate */
+#define IN_IFF_DETACHED		0x04	/* may be detached from the link */
+
+/* do not input/output */
+#define IN_IFF_NOTREADY (IN_IFF_TENTATIVE | IN_IFF_DUPLICATED)
+
 /*
  * Interface address, Internet version.  One of these structures
  * is allocated for each interface with an Internet address.
@@ -92,6 +99,7 @@
 	struct	in_multi *ia_allhosts;	/* multicast address record for
 					   the allhosts multicast group */
 	uint16_t ia_idsalt;		/* ip_id salt for this ia */
+	int	ia4_flags;		/* address flags */
 };
 
 struct	in_aliasreq {
@@ -101,6 +109,7 @@
 #define	ifra_broadaddr	ifra_dstaddr
 	struct	sockaddr_in ifra_mask;
 };
+
 /*
  * Given a pointer to an in_ifaddr (ifaddr),
  * return a pointer to the addr as a sockaddr_in.
@@ -217,6 +226,8 @@
 
 extern pktqueue_t *ip_pktq;
 
+extern int ip_dad_count;		/* Duplicate Address Detection probes */
+
 /*
  * Structure used by functions below to remember position when stepping
  * through all of the in_multi records.
@@ -240,7 +251,7 @@
 struct ifaddr;
 
 int	in_ifinit(struct ifnet *,
-	    struct in_ifaddr *, const struct sockaddr_in *, int);
+	    struct in_ifaddr *, const struct sockaddr_in *, int, int);
 void	in_savemkludge(struct in_ifaddr *);
 void	in_restoremkludge(struct in_ifaddr *, struct ifnet *);
 void	in_purgemkludge(struct ifnet *);
Index: sys/netinet/ip_icmp.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/ip_icmp.c,v
retrieving revision 1.135
diff -u -r1.135 ip_icmp.c
--- sys/netinet/ip_icmp.c	2 Dec 2014 20:25:47 -0000	1.135
+++ sys/netinet/ip_icmp.c	22 Apr 2015 21:03:08 -0000
@@ -703,6 +703,8 @@
 
 	/* Look for packet addressed to us */
 	INADDR_TO_IA(t, ia);
+	if (ia->ia4_flags & IN_IFF_NOTREADY)
+		ia = NULL;
 
 	/* look for packet sent to broadcast address */
 	if (ia == NULL && m->m_pkthdr.rcvif &&
@@ -712,7 +714,9 @@
 				continue;
 			if (in_hosteq(t,ifatoia(ifa)->ia_broadaddr.sin_addr)) {
 				ia = ifatoia(ifa);
-				break;
+				if ((ia->ia4_flags & IN_IFF_NOTREADY) == 0)
+					break;
+				ia = NULL;
 			}
 		}
 	}
Index: sys/netinet/ip_input.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/ip_input.c,v
retrieving revision 1.320
diff -u -r1.320 ip_input.c
--- sys/netinet/ip_input.c	26 Mar 2015 04:05:58 -0000	1.320
+++ sys/netinet/ip_input.c	22 Apr 2015 21:03:09 -0000
@@ -593,11 +593,13 @@
 	 *
 	 * Traditional 4.4BSD did not consult IFF_UP at all.
 	 * The behavior here is to treat addresses on !IFF_UP interface
-	 * as not mine.
+	 * or IN_IFF_NOTREADY addresses as not mine.
 	 */
 	downmatch = 0;
 	LIST_FOREACH(ia, &IN_IFADDR_HASH(ip->ip_dst.s_addr), ia_hash) {
 		if (in_hosteq(ia->ia_addr.sin_addr, ip->ip_dst)) {
+			if (ia->ia4_flags & IN_IFF_NOTREADY)
+				continue;
 			if (checkif && ia->ia_ifp != ifp)
 				continue;
 			if ((ia->ia_ifp->if_flags & IFF_UP) != 0)
@@ -613,6 +615,8 @@
 			if (ifa->ifa_addr->sa_family != AF_INET)
 				continue;
 			ia = ifatoia(ifa);
+			if (ia->ia4_flags & IN_IFF_NOTREADY)
+				continue;
 			if (in_hosteq(ip->ip_dst, ia->ia_broadaddr.sin_addr) ||
 			    in_hosteq(ip->ip_dst, ia->ia_netbroadcast) ||
 			    /*
@@ -1641,6 +1645,14 @@
 		       sysctl_net_inet_ip_stats, 0, NULL, 0,
 		       CTL_NET, PF_INET, IPPROTO_IP, IPCTL_STATS,
 		       CTL_EOL);
+	sysctl_createv(clog, 0, NULL, NULL,
+		       CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
+		       CTLTYPE_INT, "dad_count",
+		       SYSCTL_DESCR("Number of Duplicate Address Detection "
+				    "probes to send"),
+		       NULL, 0, &ip_dad_count, 0,
+		       CTL_NET, PF_INET, IPPROTO_IP,
+		       IPCTL_DAD_COUNT, CTL_EOL);
 
 	/* anonportalgo RFC6056 subtree */
 	const struct sysctlnode *portalgo_node;
Index: sys/netinet/raw_ip.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/raw_ip.c,v
retrieving revision 1.147
diff -u -r1.147 raw_ip.c
--- sys/netinet/raw_ip.c	3 Apr 2015 20:01:07 -0000	1.147
+++ sys/netinet/raw_ip.c	22 Apr 2015 21:03:09 -0000
@@ -563,6 +563,7 @@
 	struct sockaddr_in *addr = (struct sockaddr_in *)nam;
 	int error = 0;
 	int s;
+	struct ifaddr *ia;
 
 	KASSERT(solocked(so));
 	KASSERT(inp != NULL);
@@ -580,11 +581,19 @@
 		error = EAFNOSUPPORT;
 		goto release;
 	}
-	if (!in_nullhost(addr->sin_addr) &&
-	    ifa_ifwithaddr(sintosa(addr)) == 0) {
+	if ((ia = ifa_ifwithaddr(sintosa(addr))) == 0 &&
+	    !in_nullhost(addr->sin_addr))
+	{
 		error = EADDRNOTAVAIL;
 		goto release;
 	}
+        if (ia && ((struct in_ifaddr *)ia)->ia4_flags &
+	            (IN6_IFF_NOTREADY | IN_IFF_DETACHED))
+	{
+		error = EADDRNOTAVAIL;
+		goto release;
+	}
+
 	inp->inp_laddr = addr->sin_addr;
 
 release:
Index: sys/netinet6/nd6_rtr.c
===================================================================
RCS file: /cvsroot/src/sys/netinet6/nd6_rtr.c,v
retrieving revision 1.98
diff -u -r1.98 nd6_rtr.c
--- sys/netinet6/nd6_rtr.c	25 Feb 2015 12:45:34 -0000	1.98
+++ sys/netinet6/nd6_rtr.c	22 Apr 2015 21:03:12 -0000
@@ -272,8 +272,15 @@
 	}
 	if (nd_ra->nd_ra_retransmit)
 		ndi->retrans = ntohl(nd_ra->nd_ra_retransmit);
-	if (nd_ra->nd_ra_curhoplimit)
-		ndi->chlim = nd_ra->nd_ra_curhoplimit;
+	if (nd_ra->nd_ra_curhoplimit) {
+		if (ndi->chlim < nd_ra->nd_ra_curhoplimit)
+			ndi->chlim = nd_ra->nd_ra_curhoplimit;
+		else if (ndi->chlim != nd_ra->nd_ra_curhoplimit)
+			log(LOG_ERR, "nd_ra_input: lower CurHopLimit sent from "
+			   "%s on %s (current=%d, received=%d), ignored\n",
+			   ip6_sprintf(&ip6->ip6_src),
+			   if_name(ifp), ndi->chlim, nd_ra->nd_ra_curhoplimit);
+	}
 	dr = defrtrlist_update(&drtr);
     }
 
Index: sys/sys/sockio.h
===================================================================
RCS file: /cvsroot/src/sys/sys/sockio.h,v
retrieving revision 1.32
diff -u -r1.32 sockio.h
--- sys/sys/sockio.h	5 Oct 2013 23:16:54 -0000	1.32
+++ sys/sys/sockio.h	22 Apr 2015 21:03:13 -0000
@@ -72,6 +72,7 @@
 
 #define	SIOCAIFADDR	 _IOW('i', 26, struct ifaliasreq)/* add/chg IF alias */
 #define	SIOCGIFALIAS	_IOWR('i', 27, struct ifaliasreq)/* get IF alias */
+#define	SIOCGIFAFLAG_IN _IOWR('i', 39, struct ifreq)	 /* get addr flags */
 
 #define	SIOCALIFADDR	 _IOW('i', 28, struct if_laddrreq) /* add IF addr */
 #define	SIOCGLIFADDR	_IOWR('i', 29, struct if_laddrreq) /* get IF addr */


Home | Main Index | Thread Index | Old Index