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

Bug#928351: unblock advice for dhcpcd5/7.2.1-1



Package: release.debian.org
Severity: normal
User: release.debian.org@packages.debian.org
Usertags: unblock

Hello,

I need some advice on the best way to address a trio of security-related
RC bugs in dhcpcd5 (#928056, #928104, #928105). These are fixed upstream
in 7.2.1.

The version currently in testing is 7.1.0. I've packaged 7.2.1 but
haven't yet uploaded to unstable. A debdiff is attached.

I'd much prefer to stick with upstream rather than try to cherry-pick
fixes for these kinds of issues, as I'm concerned about introducing
problems into code I'm not deeply familiar with. However as you can see
the attached debdiff is rather large.

Would an unblock request for 7.2.1 be accepted at this stage?

-- System Information:
Debian Release: buster/sid
  APT prefers testing
  APT policy: (500, 'testing'), (50, 'unstable'), (40, 'experimental')
Architecture: amd64 (x86_64)

Kernel: Linux 4.19.0-4-amd64 (SMP w/4 CPU cores)
Kernel taint flags: TAINT_OOT_MODULE, TAINT_UNSIGNED_MODULE
Locale: LANG=en_AU.UTF-8, LC_CTYPE=en_AU.UTF-8 (charmap=UTF-8), LANGUAGE=en_AU:en (charmap=UTF-8)
Shell: /bin/sh linked to /usr/bin/dash
Init: systemd (via /run/systemd/system)
LSM: AppArmor: enabled
diff -Nru dhcpcd5-7.1.0/BUILDING.md dhcpcd5-7.2.1/BUILDING.md
--- dhcpcd5-7.1.0/BUILDING.md	2019-01-22 22:53:45.000000000 +0800
+++ dhcpcd5-7.2.1/BUILDING.md	2019-04-26 21:32:54.000000000 +0800
@@ -3,9 +3,6 @@
 This attempts to document various ways of building dhcpcd for your
 platform.
 
-Building for distribution (ie making a dhcpcd source tarball) now requires
-gmake-4 or any BSD make.
-
 ## Size is an issue
 To compile small dhcpcd, maybe to be used for installation media where
 size is a concern, you can use the `--small` configure option to enable
diff -Nru dhcpcd5-7.1.0/compat/consttime_memequal.h dhcpcd5-7.2.1/compat/consttime_memequal.h
--- dhcpcd5-7.1.0/compat/consttime_memequal.h	1970-01-01 08:00:00.000000000 +0800
+++ dhcpcd5-7.2.1/compat/consttime_memequal.h	2019-04-26 21:32:54.000000000 +0800
@@ -0,0 +1,28 @@
+/*
+ * Written by Matthias Drochner <drochner@NetBSD.org>.
+ * Public domain.
+ */
+
+#ifndef CONSTTIME_MEMEQUAL_H
+#define CONSTTIME_MEMEQUAL_H
+inline static int
+consttime_memequal(const void *b1, const void *b2, size_t len)
+{
+	const unsigned char *c1 = b1, *c2 = b2;
+	unsigned int res = 0;
+
+	while (len--)
+		res |= *c1++ ^ *c2++;
+
+	/*
+	 * Map 0 to 1 and [1, 256) to 0 using only constant-time
+	 * arithmetic.
+	 *
+	 * This is not simply `!res' because although many CPUs support
+	 * branchless conditional moves and many compilers will take
+	 * advantage of them, certain compilers generate branches on
+	 * certain CPUs for `!res'.
+	 */
+	return (1 & ((res - 1) >> 8));
+}
+#endif /* CONSTTIME_MEMEQUAL_H */
diff -Nru dhcpcd5-7.1.0/configure dhcpcd5-7.2.1/configure
--- dhcpcd5-7.1.0/configure	2019-01-22 22:53:45.000000000 +0800
+++ dhcpcd5-7.2.1/configure	2019-04-26 21:32:54.000000000 +0800
@@ -13,6 +13,7 @@
 INET6=
 ARC4RANDOM=
 CLOSEFROM=
+CONSTTIME_MEMEQUAL=
 STRLCPY=
 UDEV=
 OS=
@@ -454,7 +455,7 @@
 	echo "CPPFLAGS+=	-D_XPG4_2 -D__EXTENSIONS__ -DBSD_COMP" \
 	    >>$CONFIG_MK
 	echo "DHCPCD_SRCS+=	if-sun.c" >>$CONFIG_MK
-	echo "LDADD+=		-ldlpi" >>$CONFIG_MK
+	echo "LDADD+=		-ldlpi -lkstat" >>$CONFIG_MK
 	;;
 *)
 	echo "DHCPCD_SRCS+=	if-bsd.c" >>$CONFIG_MK
@@ -846,6 +847,27 @@
 	echo "#include			\"compat/strtoi.h\"" >>$CONFIG_H
 fi
 
+if [ -z "$CONSTTIME_MEMEQUAL" ]; then
+	printf "Testing for consttime_memequal ... "
+	cat <<EOF >_consttime_memequal.c
+#include <string.h>
+int main(void) {
+	return consttime_memequal("deadbeef", "deadbeef", 8);
+}
+EOF
+	if $XCC _consttime_memequal.c -o _consttime_memequal 2>&3; then
+		CONSTTIME_MEMEQUAL=yes
+	else
+		CONSTTIME_MEMEQUAL=no
+	fi
+	echo "$CONSTTIME_MEMEQUAL"
+	rm -f _consttime_memequal.c _consttime_memequal
+fi
+if [ "$CONSTTIME_MEMEQUAL" = no ]; then
+	echo "#include			\"compat/consttime_memequal.h\"" \
+	    >>$CONFIG_H
+fi
+
 if [ -z "$DPRINTF" ]; then
 	printf "Testing for dprintf ... "
 	cat <<EOF >_dprintf.c
diff -Nru dhcpcd5-7.1.0/debian/changelog dhcpcd5-7.2.1/debian/changelog
--- dhcpcd5-7.1.0/debian/changelog	2019-02-07 05:54:56.000000000 +0800
+++ dhcpcd5-7.2.1/debian/changelog	2019-05-02 23:09:05.000000000 +0800
@@ -1,3 +1,9 @@
+dhcpcd5 (7.2.1-1) unstable; urgency=high
+
+  * Upstream release 7.2.1 (Closes: #928056, #928104, #928105)
+
+ -- Scott Leggett <scott@sl.id.au>  Thu, 02 May 2019 23:09:05 +0800
+
 dhcpcd5 (7.1.0-1) unstable; urgency=low
 
   * Upstream release 7.1.0
diff -Nru dhcpcd5-7.1.0/iconfig.mk dhcpcd5-7.2.1/iconfig.mk
--- dhcpcd5-7.1.0/iconfig.mk	2019-01-22 22:53:45.000000000 +0800
+++ dhcpcd5-7.2.1/iconfig.mk	2019-04-26 21:32:54.000000000 +0800
@@ -1,7 +1,8 @@
 # Nasty hack so that make clean works without configure being run
-# Requires gmake4
 TOP?=		.
 _CONFIG_MK!=	test -e ${TOP}/config.mk && \
 		    echo config.mk || echo config-null.mk
+_CONFIG_MK?=	$(shell test -e ${TOP}/config.mk && \
+		    echo config.mk || echo config-null.mk)
 CONFIG_MK?=	${_CONFIG_MK}
 include		${TOP}/${CONFIG_MK}
diff -Nru dhcpcd5-7.1.0/Makefile dhcpcd5-7.2.1/Makefile
--- dhcpcd5-7.1.0/Makefile	2019-01-22 22:53:45.000000000 +0800
+++ dhcpcd5-7.2.1/Makefile	2019-04-26 21:32:54.000000000 +0800
@@ -22,10 +22,10 @@
 .SUFFIXES:	.in
 
 all: config.h
-	for x in ${SUBDIRS}; do cd $$x; ${MAKE} $@; cd ..; done
+	for x in ${SUBDIRS}; do cd $$x; ${MAKE} $@ || exit $$?; cd ..; done
 
 depend: config.h
-	for x in ${SUBDIRS}; do cd $$x; ${MAKE} $@; cd ..; done
+	for x in ${SUBDIRS}; do cd $$x; ${MAKE} $@ || exit $$?; cd ..; done
 
 tests:
 	cd $@; ${MAKE} $@
@@ -36,17 +36,17 @@
 	cd $@; ${MAKE}
 
 eginstall:
-	for x in ${SUBDIRS}; do cd $$x; ${MAKE} $@; cd ..; done
+	for x in ${SUBDIRS}; do cd $$x; ${MAKE} $@ || exit $$?; cd ..; done
 
 install:
-	for x in ${SUBDIRS}; do cd $$x; ${MAKE} $@; cd ..; done
+	for x in ${SUBDIRS}; do cd $$x; ${MAKE} $@ || exit $$?; cd ..; done
 
 proginstall:
-	for x in ${SUBDIRS}; do cd $$x; ${MAKE} $@; cd ..; done
+	for x in ${SUBDIRS}; do cd $$x; ${MAKE} $@ || exit $$?; cd ..; done
 
 clean:
 	rm -rf cov-int dhcpcd.xz
-	for x in ${SUBDIRS} tests; do cd $$x; ${MAKE} $@; cd ..; done
+	for x in ${SUBDIRS} tests; do cd $$x; ${MAKE} $@ || exit $$?; cd ..; done
 
 distclean: clean
 	rm -f config.h config.mk config.log \
diff -Nru dhcpcd5-7.1.0/src/arp.c dhcpcd5-7.2.1/src/arp.c
--- dhcpcd5-7.1.0/src/arp.c	2019-01-22 22:53:45.000000000 +0800
+++ dhcpcd5-7.2.1/src/arp.c	2019-04-26 21:32:54.000000000 +0800
@@ -175,17 +175,18 @@
 	}
 }
 
-void
+static void
 arp_close(struct interface *ifp)
 {
 	struct iarp_state *state;
 
-	if ((state = ARP_STATE(ifp)) != NULL && state->bpf_fd != -1) {
-		eloop_event_delete(ifp->ctx->eloop, state->bpf_fd);
-		bpf_close(ifp, state->bpf_fd);
-		state->bpf_fd = -1;
-		state->bpf_flags |= BPF_EOF;
-	}
+	if ((state = ARP_STATE(ifp)) == NULL || state->bpf_fd == -1)
+		return;
+
+	eloop_event_delete(ifp->ctx->eloop, state->bpf_fd);
+	bpf_close(ifp, state->bpf_fd);
+	state->bpf_fd = -1;
+	state->bpf_flags |= BPF_EOF;
 }
 
 static void
@@ -400,7 +401,7 @@
 }
 
 void
-arp_announceaddr(struct dhcpcd_ctx *ctx, struct in_addr *ia)
+arp_announceaddr(struct dhcpcd_ctx *ctx, const struct in_addr *ia)
 {
 	struct interface *ifp;
 	struct ipv4_addr *iaf;
@@ -424,7 +425,7 @@
 }
 
 void
-arp_ifannounceaddr(struct interface *ifp, struct in_addr *ia)
+arp_ifannounceaddr(struct interface *ifp, const struct in_addr *ia)
 {
 	struct arp_state *astate;
 
diff -Nru dhcpcd5-7.1.0/src/arp.h dhcpcd5-7.2.1/src/arp.h
--- dhcpcd5-7.1.0/src/arp.h	2019-01-22 22:53:45.000000000 +0800
+++ dhcpcd5-7.2.1/src/arp.h	2019-04-26 21:32:54.000000000 +0800
@@ -90,13 +90,12 @@
 int arp_open(struct interface *);
 ssize_t arp_request(const struct interface *, in_addr_t, in_addr_t);
 void arp_probe(struct arp_state *);
-void arp_close(struct interface *);
 void arp_report_conflicted(const struct arp_state *, const struct arp_msg *);
 struct arp_state *arp_new(struct interface *, const struct in_addr *);
 struct arp_state *arp_find(struct interface *, const struct in_addr *);
 void arp_announce(struct arp_state *);
-void arp_announceaddr(struct dhcpcd_ctx *, struct in_addr *);
-void arp_ifannounceaddr(struct interface *, struct in_addr *);
+void arp_announceaddr(struct dhcpcd_ctx *, const struct in_addr *);
+void arp_ifannounceaddr(struct interface *, const struct in_addr *);
 void arp_cancel(struct arp_state *);
 void arp_free(struct arp_state *);
 void arp_free_but(struct arp_state *);
diff -Nru dhcpcd5-7.1.0/src/auth.c dhcpcd5-7.2.1/src/auth.c
--- dhcpcd5-7.1.0/src/auth.c	2019-01-22 22:53:45.000000000 +0800
+++ dhcpcd5-7.2.1/src/auth.c	2019-04-26 21:32:54.000000000 +0800
@@ -117,7 +117,11 @@
 
 	m = vm;
 	data = vdata;
-	/* Ensure that d is inside m which *may* not be the case for DHPCPv4 */
+	/* Ensure that d is inside m which *may* not be the case for DHCPv4.
+	 * This can occur if the authentication option is split using
+	 * DHCP long option from RFC 3399. Section 9 which does infact note that
+	 * implementations should take this into account.
+	 * Fixing this would be problematic, patches welcome. */
 	if (data < m || data > m + mlen || data + dlen > m + mlen) {
 		errno = ERANGE;
 		return NULL;
@@ -354,7 +358,7 @@
 	}
 
 	free(mm);
-	if (memcmp(d, &hmac_code, dlen)) {
+	if (!consttime_memequal(d, &hmac_code, dlen)) {
 		errno = EPERM;
 		return NULL;
 	}
diff -Nru dhcpcd5-7.1.0/src/common.c dhcpcd5-7.2.1/src/common.c
--- dhcpcd5-7.1.0/src/common.c	2019-01-22 22:53:45.000000000 +0800
+++ dhcpcd5-7.2.1/src/common.c	2019-04-26 21:32:54.000000000 +0800
@@ -200,51 +200,3 @@
 	fclose(fp);
 	return len;
 }
-
-ssize_t
-recvmsg_realloc(int fd, struct msghdr *msg, int flags)
-{
-	struct iovec *iov;
-	ssize_t slen;
-	size_t len;
-	void *n;
-
-	assert(msg != NULL);
-	assert(msg->msg_iov != NULL && msg->msg_iovlen > 0);
-	assert((flags & (MSG_PEEK | MSG_TRUNC)) == 0);
-
-	/* Assume we are reallocing the last iovec. */
-	iov = &msg->msg_iov[msg->msg_iovlen - 1];
-
-	for (;;) {
-		/* Passing MSG_TRUNC should return the actual size needed. */
-		slen = recvmsg(fd, msg, flags | MSG_PEEK | MSG_TRUNC);
-		if (slen == -1)
-			return -1;
-		if (!(msg->msg_flags & MSG_TRUNC))
-			break;
-
-		len = (size_t)slen;
-
-		/* Some kernels return the size of the receive buffer
-		 * on truncation, not the actual size needed.
-		 * So grow the buffer and try again. */
-		if (iov->iov_len == len)
-			len++;
-		else if (iov->iov_len > len)
-			break;
-		len = roundup(len, IOVEC_BUFSIZ);
-		if ((n = realloc(iov->iov_base, len)) == NULL)
-			return -1;
-		iov->iov_base = n;
-		iov->iov_len = len;
-	}
-
-	slen = recvmsg(fd, msg, flags);
-	if (slen != -1 && msg->msg_flags & MSG_TRUNC) {
-		/* This should not be possible ... */
-		errno = ENOBUFS;
-		return -1;
-	}
-	return slen;
-}
diff -Nru dhcpcd5-7.1.0/src/common.h dhcpcd5-7.2.1/src/common.h
--- dhcpcd5-7.1.0/src/common.h	2019-01-22 22:53:45.000000000 +0800
+++ dhcpcd5-7.2.1/src/common.h	2019-04-26 21:32:54.000000000 +0800
@@ -130,6 +130,14 @@
 # endif
 #endif
 
+#ifndef __fallthrough
+# if __GNUC__ >= 7
+#  define __fallthrough __attribute__((fallthrough))
+# else
+#  define __fallthrough
+# endif
+#endif
+
 /*
  * Compile Time Assertion.
  */
@@ -173,6 +181,4 @@
 const char *hwaddr_ntoa(const void *, size_t, char *, size_t);
 size_t hwaddr_aton(uint8_t *, const char *);
 size_t read_hwaddr_aton(uint8_t **, const char *);
-
-ssize_t recvmsg_realloc(int, struct msghdr *, int);
 #endif
diff -Nru dhcpcd5-7.1.0/src/control.c dhcpcd5-7.2.1/src/control.c
--- dhcpcd5-7.1.0/src/control.c	2019-01-22 22:53:45.000000000 +0800
+++ dhcpcd5-7.2.1/src/control.c	2019-04-26 21:32:54.000000000 +0800
@@ -318,7 +318,7 @@
 
 	if ((fd = make_sock(&sa, ifname, 0)) != -1) {
 		socklen_t len;
-		
+
 		len = (socklen_t)SUN_LEN(&sa);
 		if (connect(fd, (struct sockaddr *)&sa, len) == -1) {
 			close(fd);
diff -Nru dhcpcd5-7.1.0/src/defs.h dhcpcd5-7.2.1/src/defs.h
--- dhcpcd5-7.1.0/src/defs.h	2019-01-22 22:53:45.000000000 +0800
+++ dhcpcd5-7.2.1/src/defs.h	2019-04-26 21:32:54.000000000 +0800
@@ -28,7 +28,7 @@
 #define CONFIG_H
 
 #define PACKAGE			"dhcpcd"
-#define VERSION			"7.1.0"
+#define VERSION			"7.2.1"
 
 #ifndef CONFIG
 # define CONFIG			SYSCONFDIR "/" PACKAGE ".conf"
diff -Nru dhcpcd5-7.1.0/src/dhcp6.c dhcpcd5-7.2.1/src/dhcp6.c
--- dhcpcd5-7.1.0/src/dhcp6.c	2019-01-22 22:53:45.000000000 +0800
+++ dhcpcd5-7.2.1/src/dhcp6.c	2019-04-26 21:32:54.000000000 +0800
@@ -168,7 +168,7 @@
 	"No Prefix Available"
 };
 
-static void dhcp6_bind(struct interface *, const char *);
+static void dhcp6_bind(struct interface *, const char *, const char *);
 static void dhcp6_failinform(void *);
 static int dhcp6_listen(struct dhcpcd_ctx *, struct ipv6_addr *);
 static void dhcp6_recvaddr(void *);
@@ -797,8 +797,7 @@
 		m = state->new;
 		ml = state->new_len;
 	}
-	unicast = NULL;
-	/* Depending on state, get the unicast address */
+
 	switch(state->state) {
 	case DH6S_INIT: /* FALLTHROUGH */
 	case DH6S_DISCOVER:
@@ -806,7 +805,6 @@
 		break;
 	case DH6S_REQUEST:
 		type = DHCP6_REQUEST;
-		unicast = dhcp6_findmoption(m, ml, D6_OPTION_UNICAST, &uni_len);
 		break;
 	case DH6S_CONFIRM:
 		type = DHCP6_CONFIRM;
@@ -816,20 +814,33 @@
 		break;
 	case DH6S_RENEW:
 		type = DHCP6_RENEW;
-		unicast = dhcp6_findmoption(m, ml, D6_OPTION_UNICAST, &uni_len);
 		break;
 	case DH6S_INFORM:
 		type = DHCP6_INFORMATION_REQ;
 		break;
 	case DH6S_RELEASE:
 		type = DHCP6_RELEASE;
-		unicast = dhcp6_findmoption(m, ml, D6_OPTION_UNICAST, &uni_len);
 		break;
 	default:
 		errno = EINVAL;
 		return -1;
 	}
 
+	switch(state->state) {
+	case DH6S_REQUEST: /* FALLTHROUGH */
+	case DH6S_RENEW:   /* FALLTHROUGH */
+	case DH6S_RELEASE:
+		if (has_option_mask(ifo->nomask6, D6_OPTION_UNICAST)) {
+			unicast = NULL;
+			break;
+		}
+		unicast = dhcp6_findmoption(m, ml, D6_OPTION_UNICAST, &uni_len);
+		break;
+	default:
+		unicast = NULL;
+		break;
+	}
+
 	/* In non master mode we listen and send from fixed addresses.
 	 * We should try and match an address we have to unicast to,
 	 * but for now this is the safest policy. */
@@ -1157,9 +1168,12 @@
 static int
 dhcp6_sendmessage(struct interface *ifp, void (*callback)(void *))
 {
-	struct dhcp6_state *state;
-	struct dhcpcd_ctx *ctx;
-	struct sockaddr_in6 dst;
+	struct dhcp6_state *state = D6_STATE(ifp);
+	struct dhcpcd_ctx *ctx = ifp->ctx;
+	struct sockaddr_in6 dst = {
+	    .sin6_family = AF_INET6,
+	    .sin6_port = htons(DHCP6_SERVER_PORT),
+	};
 	struct timespec RTprev;
 	double rnd;
 	time_t ms;
@@ -1168,18 +1182,22 @@
 	const struct in6_addr alldhcp = IN6ADDR_LINKLOCAL_ALLDHCP_INIT;
 	struct ipv6_addr *lla;
 	int s;
+	struct iovec iov = {
+	    .iov_base = state->send, .iov_len = state->send_len,
+	};
+	unsigned char ctl[CMSG_SPACE(sizeof(struct in6_pktinfo))] = { 0 };
+	struct msghdr msg = {
+	    .msg_name = &dst, .msg_namelen = sizeof(dst),
+	    .msg_iov = &iov, .msg_iovlen = 1,
+	};
 
-	if (!callback && ifp->carrier == LINK_DOWN)
+	if (!callback && ifp->carrier <= LINK_DOWN)
 		return 0;
 
-	memset(&dst, 0, sizeof(dst));
-	dst.sin6_family = AF_INET6;
-	dst.sin6_port = htons(DHCP6_SERVER_PORT);
 #ifdef HAVE_SA_LEN
 	dst.sin6_len = sizeof(dst);
 #endif
 
-	state = D6_STATE(ifp);
 	lla = ipv6_linklocal(ifp);
 	/* We need to ensure we have sufficient scope to unicast the address */
 	/* XXX FIXME: We should check any added addresses we have like from
@@ -1262,7 +1280,7 @@
 		}
 
 logsend:
-		if (ifp->carrier != LINK_DOWN)
+		if (ifp->carrier > LINK_DOWN)
 			logdebugx("%s: %s %s (xid 0x%02x%02x%02x),"
 			    " next in %0.1f seconds",
 			    ifp->name,
@@ -1280,13 +1298,13 @@
 		/* Wait the initial delay */
 		if (state->IMD != 0) {
 			state->IMD = 0;
-			eloop_timeout_add_tv(ifp->ctx->eloop,
+			eloop_timeout_add_tv(ctx->eloop,
 			    &state->RT, callback, ifp);
 			return 0;
 		}
 	}
 
-	if (ifp->carrier == LINK_DOWN)
+	if (ifp->carrier <= LINK_DOWN)
 		return 0;
 
 	/* Update the elapsed time */
@@ -1301,31 +1319,21 @@
 	}
 #endif
 
-	ctx = ifp->ctx;
-	ctx->sndhdr.msg_name = (void *)&dst;
-	ctx->sndhdr.msg_iov[0].iov_base = state->send;
-	ctx->sndhdr.msg_iov[0].iov_len = state->send_len;
-
 	/* Set the outbound interface */
 	if (IN6_ARE_ADDR_EQUAL(&dst.sin6_addr, &alldhcp)) {
 		struct cmsghdr *cm;
-		struct in6_pktinfo pi;
+		struct in6_pktinfo pi = { .ipi6_ifindex = ifp->index };
 
 		dst.sin6_scope_id = ifp->index;
-		cm = CMSG_FIRSTHDR(&ctx->sndhdr);
+		msg.msg_control = ctl;
+		msg.msg_controllen = sizeof(ctl);
+		cm = CMSG_FIRSTHDR(&msg);
 		if (cm == NULL) /* unlikely */
 			return -1;
 		cm->cmsg_level = IPPROTO_IPV6;
 		cm->cmsg_type = IPV6_PKTINFO;
 		cm->cmsg_len = CMSG_LEN(sizeof(pi));
-		memset(&pi, 0, sizeof(pi));
-		pi.ipi6_ifindex = ifp->index;
 		memcpy(CMSG_DATA(cm), &pi, sizeof(pi));
-	} else {
-		/* Remove the control buffer as we're not dictating
-		 * which interface to use for outgoing messages. */
-		ctx->sndhdr.msg_control = NULL;
-		ctx->sndhdr.msg_controllen = 0;
 	}
 
 	if (ctx->dhcp6_fd != -1)
@@ -1337,7 +1345,7 @@
 		return -1;
 	}
 
-	if (sendmsg(s, &ctx->sndhdr, 0) == -1) {
+	if (sendmsg(s, &msg, 0) == -1) {
 		logerr("%s: %s: sendmsg", __func__, ifp->name);
 		/* Allow DHCPv6 to continue .... the errors
 		 * would be rate limited by the protocol.
@@ -1345,19 +1353,13 @@
 		 * associate with an access point. */
 	}
 
-	/* Restore the control buffer assignment. */
-	if (!IN6_ARE_ADDR_EQUAL(&dst.sin6_addr, &alldhcp)) {
-		ctx->sndhdr.msg_control = ctx->sndbuf;
-		ctx->sndhdr.msg_controllen = sizeof(ctx->sndbuf);
-	}
-
 	state->RTC++;
 	if (callback) {
 		if (state->MRC == 0 || state->RTC < state->MRC)
-			eloop_timeout_add_tv(ifp->ctx->eloop,
+			eloop_timeout_add_tv(ctx->eloop,
 			    &state->RT, callback, ifp);
 		else if (state->MRC != 0 && state->MRCcallback)
-			eloop_timeout_add_tv(ifp->ctx->eloop,
+			eloop_timeout_add_tv(ctx->eloop,
 			    &state->RT, state->MRCcallback, ifp);
 		else
 			logwarnx("%s: sent %d times with no reply",
@@ -1650,7 +1652,7 @@
 		break;
 	}
 
-	dhcp6_bind(ifp, NULL);
+	dhcp6_bind(ifp, NULL, NULL);
 
 	switch (state->state) {
 	case DH6S_BOUND:
@@ -1911,13 +1913,16 @@
 dhcp6_checkstatusok(const struct interface *ifp,
     struct dhcp6_message *m, uint8_t *p, size_t len)
 {
+	struct dhcp6_state *state;
 	uint8_t *opt;
 	uint16_t opt_len, code;
 	size_t mlen;
 	void * (*f)(void *, size_t, uint16_t, uint16_t *), *farg;
 	char buf[32], *sbuf;
 	const char *status;
+	logfunc_t *logfunc;
 
+	state = D6_STATE(ifp);
 	f = p ? dhcp6_findoption : dhcp6_findmoption;
 	if (p)
 		farg = p;
@@ -1925,6 +1930,7 @@
 		farg = m;
 	if ((opt = f(farg, len, D6_OPTION_STATUS_CODE, &opt_len)) == NULL) {
 		//logdebugx("%s: no status", ifp->name);
+		state->lerror = 0;
 		return 0;
 	}
 
@@ -1934,8 +1940,10 @@
 	}
 	memcpy(&code, opt, sizeof(code));
 	code = ntohs(code);
-	if (code == D6_STATUS_OK)
+	if (code == D6_STATUS_OK) {
+		state->lerror = 0;
 		return 1;
+	}
 
 	/* Anything after the code is a message. */
 	opt += sizeof(code);
@@ -1958,8 +1966,13 @@
 		status = sbuf;
 	}
 
-	logerrx("%s: DHCPv6 REPLY: %s", ifp->name, status);
+	if (state->lerror == code || state->state == DH6S_INIT)
+		logfunc = logdebugx;
+	else
+		logfunc = logerrx;
+	logfunc("%s: DHCPv6 REPLY: %s", ifp->name, status);
 	free(sbuf);
+	state->lerror = code;
 	return -1;
 }
 
@@ -2016,12 +2029,12 @@
 		nd = o + ol;
 		l -= (size_t)(nd - d);
 		d = nd;
-		if (ol < 24) {
+		if (ol < sizeof(ia)) {
 			errno = EINVAL;
 			logerrx("%s: IA Address option truncated", ifp->name);
 			continue;
 		}
-		memcpy(&ia, o, ol);
+		memcpy(&ia, o, sizeof(ia));
 		ia.pltime = ntohl(ia.pltime);
 		ia.vltime = ntohl(ia.vltime);
 		/* RFC 3315 22.6 */
@@ -2927,7 +2940,7 @@
 #endif
 
 static void
-dhcp6_bind(struct interface *ifp, const char *op)
+dhcp6_bind(struct interface *ifp, const char *op, const char *sfrom)
 {
 	struct dhcp6_state *state = D6_STATE(ifp);
 	bool has_new = false;
@@ -2943,8 +2956,7 @@
 	}
 	lognewinfo = has_new ? loginfox : logdebugx;
 	if (op != NULL)
-		lognewinfo("%s: %s received from %s",
-		    ifp->name, op, ifp->ctx->sfrom);
+		lognewinfo("%s: %s received from %s", ifp->name, op, sfrom);
 
 	state->reason = NULL;
 	if (state->state != DH6S_ITIMEDOUT)
@@ -3023,7 +3035,7 @@
 				 * unless those values in those fields are 0.
 				 */
 				logwarnx("%s: ignoring T1 %"PRIu32
-				    " to due address expiry",
+				    " due to address expiry",
 				    ifp->name, state->renew);
 				state->renew = state->rebind = 0;
 			}
@@ -3176,7 +3188,8 @@
 }
 
 static void
-dhcp6_recvif(struct interface *ifp, struct dhcp6_message *r, size_t len)
+dhcp6_recvif(struct interface *ifp, const char *sfrom,
+    struct dhcp6_message *r, size_t len)
 {
 	struct dhcpcd_ctx *ctx;
 	size_t i;
@@ -3211,8 +3224,7 @@
 	}
 
 	if (dhcp6_findmoption(r, len, D6_OPTION_SERVERID, NULL) == NULL) {
-		logdebugx("%s: no DHCPv6 server ID from %s",
-		    ifp->name, ctx->sfrom);
+		logdebugx("%s: no DHCPv6 server ID from %s", ifp->name, sfrom);
 		return;
 	}
 
@@ -3225,14 +3237,14 @@
 		    !dhcp6_findmoption(r, len, (uint16_t)opt->option, NULL))
 		{
 			logwarnx("%s: reject DHCPv6 (no option %s) from %s",
-			    ifp->name, opt->var, ctx->sfrom);
+			    ifp->name, opt->var, sfrom);
 			return;
 		}
 		if (has_option_mask(ifo->rejectmask6, opt->option) &&
 		    dhcp6_findmoption(r, len, (uint16_t)opt->option, NULL))
 		{
 			logwarnx("%s: reject DHCPv6 (option %s) from %s",
-			    ifp->name, opt->var, ctx->sfrom);
+			    ifp->name, opt->var, sfrom);
 			return;
 		}
 	}
@@ -3245,7 +3257,7 @@
 		    (uint8_t *)r, len, 6, r->type, auth, auth_len) == NULL)
 		{
 			logerr("%s: authentication failed from %s",
-			    ifp->name, ctx->sfrom);
+			    ifp->name, sfrom);
 			return;
 		}
 		if (state->auth.token)
@@ -3256,11 +3268,10 @@
 	} else if (ifo->auth.options & DHCPCD_AUTH_SEND) {
 		if (ifo->auth.options & DHCPCD_AUTH_REQUIRE) {
 			logerr("%s: no authentication from %s",
-			    ifp->name, ctx->sfrom);
+			    ifp->name, sfrom);
 			return;
 		}
-		logwarnx("%s: no authentication from %s",
-		    ifp->name, ctx->sfrom);
+		logwarnx("%s: no authentication from %s", ifp->name, sfrom);
 	}
 #endif
 
@@ -3274,8 +3285,7 @@
 				return;
 			break;
 		case DH6S_CONFIRM:
-			if (dhcp6_validatelease(ifp, r, len,
-						ctx->sfrom, NULL) == -1)
+			if (dhcp6_validatelease(ifp, r, len, sfrom, NULL) == -1)
 			{
 				dhcp6_startdiscover(ifp);
 				return;
@@ -3297,8 +3307,7 @@
 		case DH6S_REQUEST: /* FALLTHROUGH */
 		case DH6S_RENEW: /* FALLTHROUGH */
 		case DH6S_REBIND:
-			if (dhcp6_validatelease(ifp, r, len,
-			    ctx->sfrom, NULL) == -1)
+			if (dhcp6_validatelease(ifp, r, len, sfrom, NULL) == -1)
 			{
 				/*
 				 * If we can't use the lease, fallback to
@@ -3366,7 +3375,7 @@
 				logerrx("%s: invalid INF_MAX_RT %u",
 				    ifp->name, max_rt);
 		}
-		if (dhcp6_validatelease(ifp, r, len, ctx->sfrom, NULL) == -1)
+		if (dhcp6_validatelease(ifp, r, len, sfrom, NULL) == -1)
 			return;
 		break;
 	case DHCP6_RECONFIGURE:
@@ -3374,12 +3383,12 @@
 		if (auth == NULL) {
 #endif
 			logerrx("%s: unauthenticated %s from %s",
-			    ifp->name, op, ctx->sfrom);
+			    ifp->name, op, sfrom);
 			if (ifo->auth.options & DHCPCD_AUTH_REQUIRE)
 				return;
 #ifdef AUTH
 		}
-		loginfox("%s: %s from %s", ifp->name, op, ctx->sfrom);
+		loginfox("%s: %s from %s", ifp->name, op, sfrom);
 		o = dhcp6_findmoption(r, len, D6_OPTION_RECONF_MSG, &ol);
 		if (o == NULL) {
 			logerrx("%s: missing Reconfigure Message option",
@@ -3416,6 +3425,8 @@
 			break;
 		}
 		return;
+#else
+		break;
 #endif
 	default:
 		logerrx("%s: invalid DHCP6 type %s (%d)",
@@ -3454,10 +3465,10 @@
 			ia = TAILQ_FIRST(&state->addrs);
 		if (ia == NULL)
 			loginfox("%s: ADV (no address) from %s",
-			    ifp->name, ctx->sfrom);
+			    ifp->name, sfrom);
 		else
 			loginfox("%s: ADV %s from %s",
-			    ifp->name, ia->saddr, ctx->sfrom);
+			    ifp->name, ia->saddr, sfrom);
 		if (ifp->ctx->options & DHCPCD_TEST)
 			break;
 		dhcp6_startrequest(ifp);
@@ -3465,97 +3476,81 @@
 	}
 	}
 
-	dhcp6_bind(ifp, op);
+	dhcp6_bind(ifp, op, sfrom);
 }
 
 static void
 dhcp6_recv(struct dhcpcd_ctx *ctx, struct ipv6_addr *ia)
 {
+	struct sockaddr_in6 from;
+	unsigned char buf[64 * 1024]; /* Maximum UDP message size */
+	struct iovec iov = {
+		.iov_base = buf,
+		.iov_len = sizeof(buf),
+	};
+	unsigned char ctl[CMSG_SPACE(sizeof(struct in6_pktinfo))] = { 0 };
+	struct msghdr msg = {
+	    .msg_name = &from, .msg_namelen = sizeof(from),
+	    .msg_iov = &iov, .msg_iovlen = 1,
+	    .msg_control = ctl, .msg_controllen = sizeof(ctl),
+	};
 	int s;
 	size_t len;
 	ssize_t bytes;
+	char sfrom[INET6_ADDRSTRLEN];
 	struct interface *ifp;
 	struct dhcp6_message *r;
 	const struct dhcp6_state *state;
 	uint8_t *o;
 	uint16_t ol;
 
-	ctx->rcvhdr.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
 	s = ia != NULL ? ia->dhcp6_fd : ctx->dhcp6_fd;
-	bytes = recvmsg_realloc(s, &ctx->rcvhdr, 0);
+	bytes = recvmsg(s, &msg, 0);
 	if (bytes == -1) {
-		logerr("%s: recvmsg_realloc", __func__);
+		logerr(__func__);
 		return;
 	}
 	len = (size_t)bytes;
-	ctx->sfrom = inet_ntop(AF_INET6, &ctx->from.sin6_addr,
-	    ctx->ntopbuf, sizeof(ctx->ntopbuf));
+	inet_ntop(AF_INET6, &from.sin6_addr, sfrom, sizeof(sfrom));
 	if (len < sizeof(struct dhcp6_message)) {
-		logerrx("DHCPv6 packet too short from %s", ctx->sfrom);
+		logerrx("DHCPv6 packet too short from %s", sfrom);
 		return;
 	}
 
 	if (ia != NULL)
 		ifp = ia->iface;
 	else {
-		struct cmsghdr *cm;
-		struct in6_pktinfo pi;
-
-		pi.ipi6_ifindex = 0;
-		for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&ctx->rcvhdr);
-		    cm;
-		    cm = (struct cmsghdr *)CMSG_NXTHDR(&ctx->rcvhdr, cm))
-		{
-			if (cm->cmsg_level != IPPROTO_IPV6)
-				continue;
-			switch(cm->cmsg_type) {
-			case IPV6_PKTINFO:
-				if (cm->cmsg_len == CMSG_LEN(sizeof(pi)))
-					memcpy(&pi, CMSG_DATA(cm), sizeof(pi));
-				break;
-			}
-		}
-		if (pi.ipi6_ifindex == 0) {
-			logerrx("DHCPv6 reply did not contain index from %s",
-			    ctx->sfrom);
-			return;
-		}
-
-		TAILQ_FOREACH(ifp, ctx->ifaces, next) {
-			if (ifp->index == (unsigned int)pi.ipi6_ifindex)
-				break;
-		}
+		ifp = if_findifpfromcmsg(ctx, &msg, NULL);
 		if (ifp == NULL) {
-			logerrx("DHCPv6 reply for unexpected interface from %s",
-			    ctx->sfrom);
+			logerr(__func__);
 			return;
 		}
 	}
 
-	r = (struct dhcp6_message *)ctx->rcvhdr.msg_iov[0].iov_base;
+	r = (struct dhcp6_message *)buf;
 	o = dhcp6_findmoption(r, len, D6_OPTION_CLIENTID, &ol);
 	if (o == NULL || ol != ctx->duid_len ||
 	    memcmp(o, ctx->duid, ol) != 0)
 	{
 		logdebugx("%s: incorrect client ID from %s",
-		    ifp->name, ctx->sfrom);
+		    ifp->name, sfrom);
 		return;
 	}
 
 	if (dhcp6_findmoption(r, len, D6_OPTION_SERVERID, NULL) == NULL) {
 		logdebugx("%s: no DHCPv6 server ID from %s",
-		    ifp->name, ctx->sfrom);
+		    ifp->name, sfrom);
 		return;
 	}
 
 	if (r->type == DHCP6_RECONFIGURE) {
 		logdebugx("%s: RECONFIGURE6 recv from %s,"
 		    " sending to all interfaces",
-		    ifp->name, ctx->sfrom);
+		    ifp->name, sfrom);
 		TAILQ_FOREACH(ifp, ctx->ifaces, next) {
 			state = D6_CSTATE(ifp);
 			if (state != NULL && state->send != NULL)
-				dhcp6_recvif(ifp, r, len);
+				dhcp6_recvif(ifp, sfrom, r, len);
 		}
 		return;
 	}
@@ -3589,7 +3584,7 @@
 				    state->send->xid[0],
 				    state->send->xid[1],
 				    state->send->xid[2],
-				    ctx->sfrom);
+				    sfrom);
 			return;
 		}
 		logdebugx("%s: redirecting DHCP6 message to %s",
@@ -3597,7 +3592,7 @@
 		ifp = ifp1;
 	}
 
-	dhcp6_recvif(ifp, r, len);
+	dhcp6_recvif(ifp, sfrom, r, len);
 }
 
 static void
@@ -3810,6 +3805,7 @@
 
 gogogo:
 	state->state = init_state;
+	state->lerror = 0;
 	dhcp_set_leasefile(state->leasefile, sizeof(state->leasefile),
 	    AF_INET6, ifp);
 	if (ipv6_linklocal(ifp) == NULL) {
@@ -3829,18 +3825,20 @@
 	struct dhcp6_state *state;
 
 	state = D6_STATE(ifp);
-	if (state) {
-		switch (state->state) {
-		case DH6S_BOUND:
-			dhcp6_startrebind(ifp);
-			break;
-		case DH6S_INFORMED:
-			dhcp6_startinform(ifp);
-			break;
-		default:
-			dhcp6_startdiscover(ifp);
-			break;
-		}
+	if (state == NULL)
+		return;
+
+	state->lerror = 0;
+	switch (state->state) {
+	case DH6S_BOUND:
+		dhcp6_startrebind(ifp);
+		break;
+	case DH6S_INFORMED:
+		dhcp6_startinform(ifp);
+		break;
+	default:
+		dhcp6_startdiscover(ifp);
+		break;
 	}
 }
 
diff -Nru dhcpcd5-7.1.0/src/dhcp6.h dhcpcd5-7.2.1/src/dhcp6.h
--- dhcpcd5-7.1.0/src/dhcp6.h	2019-01-22 22:53:45.000000000 +0800
+++ dhcpcd5-7.2.1/src/dhcp6.h	2019-04-26 21:32:54.000000000 +0800
@@ -55,6 +55,8 @@
 #define DHCP6_RECONFIGURE_REQ	18
 #define DHCP6_RECONFIGURE_REPLY	19
 
+#ifdef DHCP6
+
 #define D6_OPTION_CLIENTID		1
 #define D6_OPTION_SERVERID		2
 #define D6_OPTION_IA_NA			3
@@ -204,7 +206,7 @@
 	/* The +3 is for the possible .pd extension for prefix delegation */
 	char leasefile[sizeof(LEASEFILE6) + IF_NAMESIZE + (IF_SSIDLEN * 4) +3];
 	const char *reason;
-
+	uint16_t lerror; /* Last error received from DHCPv6 reply. */
 	struct authstate auth;
 };
 
@@ -216,7 +218,6 @@
 	(D6_CSTATE((ifp)) &&						       \
 	D6_CSTATE((ifp))->reason && dhcp6_dadcompleted((ifp)))
 
-#ifdef DHCP6
 void dhcp6_printoptions(const struct dhcpcd_ctx *,
     const struct dhcp_opt *, size_t);
 const struct ipv6_addr *dhcp6_iffindaddr(const struct interface *ifp,
@@ -236,20 +237,6 @@
 void dhcp6_drop(struct interface *, const char *);
 void dhcp6_dropnondelegates(struct interface *ifp);
 int dhcp6_dump(struct interface *);
-#else
-#define dhcp6_printoptions(a, b, c) {}
-#define dhcp6_iffindaddr(a, b, c) (NULL)
-#define dhcp6_findaddr(a, b, c) (NULL)
-#define dhcp6_find_delegates(a) {}
-#define dhcp6_start(a, b) (0)
-#define dhcp6_reboot(a) {}
-#define dhcp6_renew(a) {}
-#define dhcp6_env(a, b, c, d, e) (0)
-#define dhcp6_free(a) {}
-#define dhcp6_dadcompleted(a) (0)
-#define dhcp6_drop(a, b) {}
-#define dhcp6_dropnondelegates(a) {}
-#define dhcp6_dump(a) (-1)
-#endif
+#endif /* DHCP6 */
 
-#endif
+#endif /* DHCP6_H */
diff -Nru dhcpcd5-7.1.0/src/dhcp.c dhcpcd5-7.2.1/src/dhcp.c
--- dhcpcd5-7.1.0/src/dhcp.c	2019-01-22 22:53:45.000000000 +0800
+++ dhcpcd5-7.2.1/src/dhcp.c	2019-04-26 21:32:54.000000000 +0800
@@ -86,9 +86,9 @@
 #define IPDEFTTL 64 /* RFC1340 */
 #endif
 
-/* NetBSD-7 has an incomplete IP_PKTINFO implementation. */
-#if defined(__NetBSD_Version__) && __NetBSD_Version__ < 800000000
-#undef IP_PKTINFO
+/* Support older systems with different defines */
+#if !defined(IP_RECVPKTINFO) && defined(IP_PKTINFO)
+#define IP_RECVPKTINFO IP_PKTINFO
 #endif
 
 /* Assert the correct structure size for on wire */
@@ -129,6 +129,9 @@
 #endif
 static void dhcp_handledhcp(struct interface *, struct bootp *, size_t,
     const struct in_addr *);
+#ifdef IP_PKTINFO
+static void dhcp_handleifudp(void *);
+#endif
 static int dhcp_initstate(struct interface *);
 
 void
@@ -212,6 +215,12 @@
 		}
 		l = *p++;
 
+		/* Check we can read the option data, if present */
+		if (p + l > e) {
+			errno = EINVAL;
+			return NULL;
+		}
+
 		if (o == DHO_OPTSOVERLOADED) {
 			/* Ensure we only get this option once by setting
 			 * the last bit as well as the value.
@@ -246,10 +255,6 @@
 				bp += ol;
 			}
 			ol = l;
-			if (p + ol >= e) {
-				errno = EINVAL;
-				return NULL;
-			}
 			op = p;
 			bl += ol;
 		}
@@ -447,7 +452,7 @@
 		memcpy(&gateway.s_addr, p, 4);
 		p += 4;
 
-		/* A host route is normally set by having the
+		/* An on-link host route is normally set by having the
 		 * gateway match the destination or assigned address */
 		if (gateway.s_addr == dest.s_addr ||
 		    (gateway.s_addr == bootp->yiaddr ||
@@ -455,17 +460,14 @@
 		{
 			gateway.s_addr = INADDR_ANY;
 			netmask.s_addr = INADDR_BROADCAST;
-			rt->rt_flags = RTF_HOST;
 		}
+		if (netmask.s_addr == INADDR_BROADCAST)
+			rt->rt_flags = RTF_HOST;
 
 		sa_in_init(&rt->rt_dest, &dest);
 		sa_in_init(&rt->rt_netmask, &netmask);
 		sa_in_init(&rt->rt_gateway, &gateway);
 
-		/* If CIDR is 32 then it's a host route. */
-		if (cidr == 32)
-			rt->rt_flags = RTF_HOST;
-
 		TAILQ_INSERT_TAIL(routes, rt, rt_next);
 		n++;
 	}
@@ -638,7 +640,7 @@
 			if ((rt = rt_new(ifp)) == NULL)
 				return -1;
 
-			/* A host route is normally set by having the
+			/* A on-link host route is normally set by having the
 			 * gateway match the destination or assigned address */
 			if (gateway.s_addr == dest.s_addr ||
 			     (gateway.s_addr == bootp->yiaddr ||
@@ -646,12 +648,15 @@
 			{
 				gateway.s_addr = INADDR_ANY;
 				netmask.s_addr = INADDR_BROADCAST;
-				rt->rt_flags = RTF_HOST;
 			} else
 				netmask.s_addr = route_netmask(dest.s_addr);
+			if (netmask.s_addr == INADDR_BROADCAST)
+				rt->rt_flags = RTF_HOST;
+
 			sa_in_init(&rt->rt_dest, &dest);
 			sa_in_init(&rt->rt_netmask, &netmask);
 			sa_in_init(&rt->rt_gateway, &gateway);
+
 			TAILQ_INSERT_TAIL(routes, rt, rt_next);
 			n++;
 		}
@@ -1587,6 +1592,11 @@
 		state->bpf_fd = -1;
 		state->bpf_flags |= BPF_EOF;
 	}
+	if (state->udp_fd != -1) {
+		eloop_event_delete(ifp->ctx->eloop, state->udp_fd);
+		close(state->udp_fd);
+		state->udp_fd = -1;
+	}
 
 	state->interval = 0;
 }
@@ -1604,11 +1614,15 @@
 	n = 1;
 	if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n)) == -1)
 		goto eexit;
+#ifdef IP_RECVPKTINFO
+	if (setsockopt(s, IPPROTO_IP, IP_RECVPKTINFO, &n, sizeof(n)) == -1)
+		goto eexit;
+#endif
 	memset(&sin, 0, sizeof(sin));
 	sin.sin_family = AF_INET;
 	sin.sin_port = htons(BOOTPC);
 	if (ifp) {
-		struct dhcp_state *state = D_STATE(ifp);
+		const struct dhcp_state *state = D_CSTATE(ifp);
 
 		if (state->addr)
 			sin.sin_addr.s_addr = state->addr->addr.s_addr;
@@ -1699,12 +1713,8 @@
 	struct msghdr msg;
 	struct sockaddr_in sin;
 	struct iovec iov[1];
+	struct dhcp_state *state = D_STATE(ifp);
 	ssize_t r;
-#ifdef IP_PKTINFO
-	uint8_t cmsg[CMSG_SPACE(sizeof(struct in_pktinfo))];
-	struct cmsghdr *cm;
-	struct in_pktinfo ipi;
-#endif
 
 	iov[0].iov_base = data;
 	iov[0].iov_len = len;
@@ -1723,29 +1733,15 @@
 	msg.msg_iov = iov;
 	msg.msg_iovlen = 1;
 
-#ifdef IP_PKTINFO
-	/* Set the outbound interface */
-	msg.msg_control = cmsg;
-	msg.msg_controllen = sizeof(cmsg);
-
-	memset(&ipi, 0, sizeof(ipi));
-	ipi.ipi_ifindex = ifp->index;
-	cm = CMSG_FIRSTHDR(&msg);
-	if (cm == NULL) {
-		errno = ESRCH;
-		return -1;
+	s = state->udp_fd;
+	if (s == -1) {
+		s = dhcp_openudp(ifp);
+		if (s == -1)
+			return -1;
 	}
-	cm->cmsg_level = IPPROTO_IP;
-	cm->cmsg_type = IP_PKTINFO;
-	cm->cmsg_len = CMSG_LEN(sizeof(ipi));
-	memcpy(CMSG_DATA(cm), &ipi, sizeof(ipi));
-#endif
-
-	s = dhcp_openudp(ifp);
-	if (s == -1)
-		return -1;
 	r = sendmsg(s, &msg, 0);
-	close(s);
+	if (state->udp_fd == -1)
+		close(s);
 	return r;
 }
 
@@ -1764,7 +1760,7 @@
 
 	if (!callback) {
 		/* No carrier? Don't bother sending the packet. */
-		if (ifp->carrier == LINK_DOWN)
+		if (ifp->carrier <= LINK_DOWN)
 			return;
 		logdebugx("%s: sending %s with xid 0x%x",
 		    ifp->name,
@@ -1784,7 +1780,7 @@
 		timespecnorm(&tv);
 		/* No carrier? Don't bother sending the packet.
 		 * However, we do need to advance the timeout. */
-		if (ifp->carrier == LINK_DOWN)
+		if (ifp->carrier <= LINK_DOWN)
 			goto fail;
 		logdebugx("%s: sending %s (xid 0x%x), next in %0.1f seconds",
 		    ifp->name,
@@ -1803,7 +1799,7 @@
 	else
 		to.s_addr = INADDR_ANY;
 
-	/* If unicasting, try and void sending by BPF so we don't
+	/* If unicasting, try and avoid sending by BPF so we don't
 	 * use a L2 broadcast. */
 	if (to.s_addr != INADDR_ANY && to.s_addr != INADDR_BROADCAST) {
 		if (dhcp_sendudp(ifp, &to, bootp, len) != -1)
@@ -1965,7 +1961,7 @@
 	dhcp_drop(ifp, "EXPIRE");
 	unlink(state->leasefile);
 	state->interval = 0;
-	if (!(ifp->options->options & DHCPCD_LINK) || ifp->carrier != LINK_DOWN)
+	if (!(ifp->options->options & DHCPCD_LINK) || ifp->carrier > LINK_DOWN)
 		dhcp_discover(ifp);
 }
 
@@ -2068,11 +2064,6 @@
 			return;
 		}
 		arp_free(astate);
-#ifdef KERNEL_RFC5227
-		/* As arping is finished, close the ARP socket.
-		 * The kernel will handle ACD from here. */
-		arp_close(ifp);
-#endif
 		dhcpcd_startinterface(ifp);
 		return;
 	}
@@ -2086,7 +2077,7 @@
 	    ifp->name, inet_ntoa(astate->addr));
 	if (!(ifo->options & DHCPCD_INFORM))
 		dhcp_bind(ifp);
-#ifndef IN_IFF_TENTATIVE
+#ifndef IN_IFF_DUPLICATED
 	else {
 		struct bootp *bootp;
 		size_t len;
@@ -2150,11 +2141,6 @@
 			return;
 		}
 		arp_free(astate);
-#ifdef KERNEL_RFC5227
-		/* As arping is finished, close the ARP socket.
-		 * The kernel will handle ACD from here. */
-		arp_close(ifp);
-#endif
 		eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
 		dhcpcd_startinterface(ifp);
 		return;
@@ -2209,11 +2195,22 @@
 		return;
 	}
 }
+
+static void
+dhcp_arp_announced(struct arp_state *state)
+{
+
+// TODO: DHCP addresses handle ACD?
+//#ifdef KERNEL_RFC5227
+	arp_free(state);
+//#endif
+}
 #endif
 
 void
 dhcp_bind(struct interface *ifp)
 {
+	struct dhcpcd_ctx *ctx = ifp->ctx;
 	struct dhcp_state *state = D_STATE(ifp);
 	struct if_options *ifo = ifp->options;
 	struct dhcp_lease *lease = &state->lease;
@@ -2289,10 +2286,10 @@
 				    lease->leasetime);
 		}
 	}
-	if (ifp->ctx->options & DHCPCD_TEST) {
+	if (ctx->options & DHCPCD_TEST) {
 		state->reason = "TEST";
 		script_runreason(ifp, state->reason);
-		eloop_exit(ifp->ctx->eloop, EXIT_SUCCESS);
+		eloop_exit(ctx->eloop, EXIT_SUCCESS);
 		return;
 	}
 	if (state->reason == NULL) {
@@ -2311,26 +2308,42 @@
 	if (lease->leasetime == ~0U)
 		lease->renewaltime = lease->rebindtime = lease->leasetime;
 	else {
-		eloop_timeout_add_sec(ifp->ctx->eloop,
+		eloop_timeout_add_sec(ctx->eloop,
 		    (time_t)lease->renewaltime, dhcp_startrenew, ifp);
-		eloop_timeout_add_sec(ifp->ctx->eloop,
+		eloop_timeout_add_sec(ctx->eloop,
 		    (time_t)lease->rebindtime, dhcp_rebind, ifp);
-		eloop_timeout_add_sec(ifp->ctx->eloop,
+		eloop_timeout_add_sec(ctx->eloop,
 		    (time_t)lease->leasetime, dhcp_expire, ifp);
 		logdebugx("%s: renew in %"PRIu32" seconds, rebind in %"PRIu32
 		    " seconds",
 		    ifp->name, lease->renewaltime, lease->rebindtime);
 	}
 	state->state = DHS_BOUND;
-	/* Re-apply the filter because we need to accept any XID anymore. */
-	if (bpf_bootp(ifp, state->bpf_fd) == -1)
-		logerr(__func__); /* try to continue */
 	if (!state->lease.frominfo &&
 	    !(ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC)))
 		if (write_lease(ifp, state->new, state->new_len) == -1)
 			logerr(__func__);
 
 	ipv4_applyaddr(ifp);
+
+#ifdef IP_PKTINFO
+	/* Close the BPF filter as we can now receive the DHCP renew messages
+	 * on a UDP socket. */
+	if (state->udp_fd == -1 ||
+	    (state->old != NULL && state->old->yiaddr != state->new->yiaddr))
+	{
+		dhcp_close(ifp);
+		/* If not in master mode, open an address specific socket. */
+		if (ctx->udp_fd == -1) {
+			state->udp_fd = dhcp_openudp(ifp);
+			if (state->udp_fd == -1)
+				logerr(__func__);
+			else
+				eloop_event_add(ctx->eloop,
+				    state->udp_fd, dhcp_handleifudp, ifp);
+		}
+	}
+#endif
 }
 
 static void
@@ -2384,6 +2397,20 @@
 }
 
 #ifdef ARP
+static struct arp_state *
+dhcp_arp_new(struct interface *ifp, struct in_addr *addr)
+{
+	struct arp_state *astate;
+	astate = arp_new(ifp, addr);
+	if (astate == NULL)
+		return NULL;
+
+	astate->probed_cb = dhcp_arp_probed;
+	astate->conflicted_cb = dhcp_arp_conflicted;
+	astate->announced_cb = dhcp_arp_announced;
+	return astate;
+}
+
 static int
 dhcp_arp_address(struct interface *ifp)
 {
@@ -2400,12 +2427,11 @@
 	/* If the interface already has the address configured
 	 * then we can't ARP for duplicate detection. */
 	ia = ipv4_iffindaddr(ifp, &addr, NULL);
-	if ((astate = arp_new(ifp, &addr)) == NULL)
+	astate = dhcp_arp_new(ifp, &addr);
+	if (astate == NULL)
 		return -1;
-	astate->probed_cb = dhcp_arp_probed;
-	astate->conflicted_cb = dhcp_arp_conflicted;
 
-#ifdef IN_IFF_TENTATIVE
+#ifdef IN_IFF_NOTUSEABLE
 	if (ia == NULL || ia->addr_flags & IN_IFF_NOTUSEABLE) {
 		state->state = DHS_PROBE;
 		if (ia == NULL) {
@@ -2440,7 +2466,8 @@
 dhcp_arp_bind(struct interface *ifp)
 {
 
-	if (dhcp_arp_address(ifp) == 1)
+	if (ifp->ctx->options & DHCPCD_TEST ||
+	    dhcp_arp_address(ifp) == 1)
 		dhcp_bind(ifp);
 }
 #endif
@@ -2601,7 +2628,7 @@
 	state->state = DHS_REBOOT;
 	state->interval = 0;
 
-	if (ifo->options & DHCPCD_LINK && ifp->carrier == LINK_DOWN) {
+	if (ifo->options & DHCPCD_LINK && ifp->carrier <= LINK_DOWN) {
 		loginfox("%s: waiting for carrier", ifp->name);
 		return;
 	}
@@ -2691,7 +2718,7 @@
 		state->state = DHS_RELEASE;
 
 		unlink(state->leasefile);
-		if (ifp->carrier != LINK_DOWN &&
+		if (ifp->carrier > LINK_DOWN &&
 		    state->new != NULL &&
 		    state->lease.server.s_addr != INADDR_ANY)
 		{
@@ -2879,14 +2906,11 @@
 #define LOGDHCP(l, m) \
 	log_dhcp((l), (m), ifp, bootp, bootp_len, from, 1)
 
-	/* Handled in our BPF filter. */
-#if 0
 	if (bootp->op != BOOTREPLY) {
 		logdebugx("%s: op (%d) is not BOOTREPLY",
 		    ifp->name, bootp->op);
 		return;
 	}
-#endif
 
 	if (state->xid != ntohl(bootp->xid)) {
 		if (state->state != DHS_BOUND && state->state != DHS_NONE)
@@ -3190,6 +3214,7 @@
 			state->reason = "TEST";
 			script_runreason(ifp, state->reason);
 			eloop_exit(ifp->ctx->eloop, EXIT_SUCCESS);
+			state->bpf_flags |= BPF_EOF;
 			return;
 		}
 		eloop_timeout_delete(ifp->ctx->eloop, send_discover, ifp);
@@ -3337,6 +3362,30 @@
 }
 
 static void
+dhcp_handlebootp(struct interface *ifp, struct bootp *bootp, size_t len,
+    struct in_addr *from)
+{
+	size_t v;
+
+	/* udp_len must be correct because the values are checked in
+	 * valid_udp_packet(). */
+	if (len < offsetof(struct bootp, vend)) {
+		logerrx("%s: truncated packet (%zu) from %s",
+		    ifp->name, len, inet_ntoa(*from));
+		return;
+	}
+	/* To make our IS_DHCP macro easy, ensure the vendor
+	 * area has at least 4 octets. */
+	v = len - offsetof(struct bootp, vend);
+	while (v < 4) {
+		bootp->vend[v++] = '\0';
+		len++;
+	}
+
+	dhcp_handledhcp(ifp, bootp, len, from);
+}
+
+static void
 dhcp_handlepacket(struct interface *ifp, uint8_t *data, size_t len)
 {
 	struct bootp *bootp;
@@ -3370,22 +3419,7 @@
 	 * dhcpcd can work fine without the vendor area being sent.
 	 */
 	bootp = get_udp_data(data, &udp_len);
-	/* udp_len must be correct because the values are checked in
-	 * valid_udp_packet(). */
-	if (udp_len < offsetof(struct bootp, vend)) {
-		logerrx("%s: truncated packet (%zu) from %s",
-		    ifp->name, udp_len, inet_ntoa(from));
-		return;
-	}
-	/* To make our IS_DHCP macro easy, ensure the vendor
-	 * area has at least 4 octets. */
-	len = udp_len - offsetof(struct bootp, vend);
-	while (len < 4) {
-		bootp->vend[len++] = '\0';
-		udp_len++;
-	}
-
-	dhcp_handledhcp(ifp, bootp, udp_len, &from);
+	dhcp_handlebootp(ifp, bootp, udp_len, &from);
 }
 
 static void
@@ -3421,23 +3455,76 @@
 }
 
 static void
-dhcp_handleudp(void *arg)
+dhcp_readudp(struct dhcpcd_ctx *ctx, struct interface *ifp)
 {
-	struct dhcpcd_ctx *ctx;
-	uint8_t buffer[MTU_MAX];
+	struct sockaddr_in from;
+	unsigned char buf[10 * 1024]; /* Maximum MTU */
+	struct iovec iov = {
+		.iov_base = buf,
+		.iov_len = sizeof(buf),
+	};
+#ifdef IP_PKTINFO
+	unsigned char ctl[CMSG_SPACE(sizeof(struct in_pktinfo))] = { 0 };
+	char sfrom[INET_ADDRSTRLEN];
+#endif
+	struct msghdr msg = {
+	    .msg_name = &from, .msg_namelen = sizeof(from),
+	    .msg_iov = &iov, .msg_iovlen = 1,
+#ifdef IP_PKTINFO
+	    .msg_control = ctl, .msg_controllen = sizeof(ctl),
+#endif
+	};
+	int s;
+	ssize_t bytes;
+
+	if (ifp != NULL) {
+		const struct dhcp_state *state = D_CSTATE(ifp);
 
-	ctx = arg;
+		s = state->udp_fd;
+	} else
+		s = ctx->udp_fd;
 
-	/* Just read what's in the UDP fd and discard it as we always read
-	 * from the raw fd */
-	if (read(ctx->udp_fd, buffer, sizeof(buffer)) == -1) {
+	bytes = recvmsg(s, &msg, 0);
+	if (bytes == -1) {
 		logerr(__func__);
-		eloop_event_delete(ctx->eloop, ctx->udp_fd);
-		close(ctx->udp_fd);
-		ctx->udp_fd = -1;
+		return;
 	}
+
+#ifdef IP_PKTINFO
+	inet_ntop(AF_INET, &from.sin_addr, sfrom, sizeof(sfrom));
+
+	if (ifp == NULL) {
+		ifp = if_findifpfromcmsg(ctx, &msg, NULL);
+		if (ifp == NULL) {
+			logerr(__func__);
+			return;
+		}
+	}
+
+	dhcp_handlebootp(ifp, (struct bootp *)buf, (size_t)bytes,
+	    &from.sin_addr);
+#endif
+}
+
+static void
+dhcp_handleudp(void *arg)
+{
+	struct dhcpcd_ctx *ctx = arg;
+
+	dhcp_readudp(ctx, NULL);
 }
 
+#ifdef IP_PKTINFO
+static void
+dhcp_handleifudp(void *arg)
+{
+	struct interface *ifp = arg;
+
+	dhcp_readudp(ifp->ctx, ifp);
+
+}
+#endif
+
 static int
 dhcp_openbpf(struct interface *ifp)
 {
@@ -3547,6 +3634,7 @@
 	state->state = DHS_NONE;
 	/* 0 is a valid fd, so init to -1 */
 	state->bpf_fd = -1;
+	state->udp_fd = -1;
 #ifdef ARPING
 	state->arping_index = -1;
 #endif
@@ -3676,12 +3764,9 @@
 	if (ifo->arping_len && state->arping_index < ifo->arping_len) {
 		struct arp_state *astate;
 
-		astate = arp_new(ifp, NULL);
-		if (astate) {
-			astate->probed_cb = dhcp_arp_probed;
-			astate->conflicted_cb = dhcp_arp_conflicted;
+		astate = dhcp_arp_new(ifp, NULL);
+		if (astate)
 			dhcp_arp_probed(astate);
-		}
 		return;
 	}
 #endif
@@ -3691,13 +3776,11 @@
 		return;
 	}
 
-	if (ifo->options & DHCPCD_DHCP && dhcp_openbpf(ifp) == -1)
-		return;
-
 	if (ifo->options & DHCPCD_INFORM) {
 		dhcp_inform(ifp);
 		return;
 	}
+
 	if (ifp->hwlen == 0 && ifo->clientid[0] == '\0') {
 		logwarnx("%s: needs a clientid to configure", ifp->name);
 		dhcp_drop(ifp, "FAIL");
diff -Nru dhcpcd5-7.1.0/src/dhcpcd.8.in dhcpcd5-7.2.1/src/dhcpcd.8.in
--- dhcpcd5-7.1.0/src/dhcpcd.8.in	2019-01-22 22:53:45.000000000 +0800
+++ dhcpcd5-7.2.1/src/dhcpcd.8.in	2019-04-26 21:32:54.000000000 +0800
@@ -584,7 +584,7 @@
 .Nm
 will try to do as much as it can by default.
 However, there are sometimes situations where you don't want the things to be
-configured exactly how the the DHCP server wants.
+configured exactly how the DHCP server wants.
 Here are some options that deal with turning these bits off.
 .Pp
 Note that when
diff -Nru dhcpcd5-7.1.0/src/dhcpcd.c dhcpcd5-7.2.1/src/dhcpcd.c
--- dhcpcd5-7.1.0/src/dhcpcd.c	2019-01-22 22:53:45.000000000 +0800
+++ dhcpcd5-7.2.1/src/dhcpcd.c	2019-04-26 21:32:54.000000000 +0800
@@ -52,7 +52,9 @@
 #include "common.h"
 #include "control.h"
 #include "dev.h"
+#include "dhcp-common.h"
 #include "dhcpcd.h"
+#include "dhcp.h"
 #include "dhcp6.h"
 #include "duid.h"
 #include "eloop.h"
@@ -151,6 +153,7 @@
 		free(ctx->nd_opts);
 		ctx->nd_opts = NULL;
 	}
+#ifdef DHCP6
 	if (ctx->dhcp6_opts) {
 		for (opt = ctx->dhcp6_opts;
 		    ctx->dhcp6_opts_len > 0;
@@ -160,6 +163,7 @@
 		ctx->dhcp6_opts = NULL;
 	}
 #endif
+#endif
 	if (ctx->vivso) {
 		for (opt = ctx->vivso;
 		    ctx->vivso_len > 0;
@@ -205,18 +209,39 @@
 dhcpcd_ifafwaiting(const struct interface *ifp)
 {
 	unsigned long long opts;
+	bool foundany = false;
 
 	if (ifp->active != IF_ACTIVE_USER)
 		return AF_MAX;
 
+#define DHCPCD_WAITALL	(DHCPCD_WAITIP4 | DHCPCD_WAITIP6)
 	opts = ifp->options->options;
-	if (opts & DHCPCD_WAITIP4 && !ipv4_hasaddr(ifp))
-		return AF_INET;
-	if (opts & DHCPCD_WAITIP6 && !ipv6_hasaddr(ifp))
-		return AF_INET6;
-	if (opts & DHCPCD_WAITIP &&
-	    !(opts & (DHCPCD_WAITIP4 | DHCPCD_WAITIP6)) &&
-	    !ipv4_hasaddr(ifp) && !ipv6_hasaddr(ifp))
+#ifdef INET
+	if (opts & DHCPCD_WAITIP4 ||
+	    (opts & DHCPCD_WAITIP && !(opts & DHCPCD_WAITALL)))
+	{
+		bool foundaddr = ipv4_hasaddr(ifp);
+
+		if (opts & DHCPCD_WAITIP4 && !foundaddr)
+			return AF_INET;
+		if (foundaddr)
+			foundany = true;
+	}
+#endif
+#ifdef INET6
+	if (opts & DHCPCD_WAITIP6 ||
+	    (opts & DHCPCD_WAITIP && !(opts & DHCPCD_WAITALL)))
+	{
+		bool foundaddr = ipv6_hasaddr(ifp);
+
+		if (opts & DHCPCD_WAITIP6 && !foundaddr)
+			return AF_INET;
+		if (foundaddr)
+			foundany = true;
+	}
+#endif
+
+	if (opts & DHCPCD_WAITIP && !(opts & DHCPCD_WAITALL) && !foundany)
 		return AF_UNSPEC;
 	return AF_MAX;
 }
@@ -233,12 +258,16 @@
 
 	opts = ctx->options;
 	TAILQ_FOREACH(ifp, ctx->ifaces, next) {
+#ifdef INET
 		if (opts & (DHCPCD_WAITIP | DHCPCD_WAITIP4) &&
 		    ipv4_hasaddr(ifp))
 			opts &= ~(DHCPCD_WAITIP | DHCPCD_WAITIP4);
+#endif
+#ifdef INET6
 		if (opts & (DHCPCD_WAITIP | DHCPCD_WAITIP6) &&
 		    ipv6_hasaddr(ifp))
 			opts &= ~(DHCPCD_WAITIP | DHCPCD_WAITIP6);
+#endif
 		if (!(opts & DHCPCD_WAITOPTS))
 			break;
 	}
@@ -529,7 +558,7 @@
 		ifo->options |= DHCPCD_IAID;
 	}
 
-#ifdef INET6
+#ifdef DHCP6
 	if (ifo->ia_len == 0 && ifo->options & DHCPCD_IPV6 &&
 	    ifp->name[0] != '\0')
 	{
@@ -727,18 +756,30 @@
 		if (ifp->carrier != LINK_DOWN) {
 			if (ifp->carrier == LINK_UP)
 				loginfox("%s: carrier lost", ifp->name);
-			ifp->carrier = LINK_DOWN;
+#ifdef NOCARRIER_PRESERVE_IP
+			if (ifp->flags & IFF_UP)
+				ifp->carrier = LINK_DOWN_IFFUP;
+			else
+#endif
+				ifp->carrier = LINK_DOWN;
 			script_runreason(ifp, "NOCARRIER");
 #ifdef NOCARRIER_PRESERVE_IP
+			if (ifp->flags & IFF_UP) {
 #ifdef ARP
-			arp_drop(ifp);
+				arp_drop(ifp);
 #endif
-			dhcp_abort(ifp);
-			ipv6nd_expire(ifp, 0);
-			dhcp6_abort(ifp);
-#else
-			dhcpcd_drop(ifp, 0);
+#ifdef INET
+				dhcp_abort(ifp);
+#endif
+#ifdef INET6
+				ipv6nd_expire(ifp, 0);
+#endif
+#ifdef DHCP6
+				dhcp6_abort(ifp);
+#endif
+			} else
 #endif
+				dhcpcd_drop(ifp, 0);
 		}
 	} else if (carrier == LINK_UP && ifp->flags & IFF_UP) {
 		if (ifp->carrier != LINK_UP) {
@@ -765,11 +806,14 @@
 #ifdef NOCARRIER_PRESERVE_IP
 					dhcpcd_drop(ifp, 0);
 #endif
+#ifdef IPV4LL
 					ipv4ll_reset(ifp);
+#endif
 				}
 			}
 			dhcpcd_initstate(ifp, 0);
 			script_runreason(ifp, "CARRIER");
+#ifdef INET6
 #ifdef NOCARRIER_PRESERVE_IP
 			/* Set any IPv6 Routers we remembered to expire
 			 * faster than they would normally as we
@@ -778,6 +822,7 @@
 #endif
 			/* RFC4941 Section 3.5 */
 			ipv6_gentempifid(ifp);
+#endif
 			dhcpcd_startinterface(ifp);
 		}
 	}
@@ -883,10 +928,12 @@
 #endif
 	}
 
+#ifdef INET6
 	if (ifo->options & DHCPCD_IPV6 && ipv6_start(ifp) == -1) {
 		logerr("%s: ipv6_start", ifp->name);
 		ifo->options &= ~DHCPCD_IPV6;
 	}
+
 	if (ifo->options & DHCPCD_IPV6) {
 		if (ifp->active == IF_ACTIVE_USER) {
 			ipv6_startstatic(ifp);
@@ -895,7 +942,7 @@
 				ipv6nd_startrs(ifp);
 		}
 
-
+#ifdef DHCP6
 		if (ifo->options & DHCPCD_DHCP6) {
 			dhcp6_find_delegates(ifp);
 
@@ -912,7 +959,9 @@
 					logerr("%s: dhcp6_start", ifp->name);
 			}
 		}
+#endif
 	}
+#endif
 
 #ifdef INET
 	if (ifo->options & DHCPCD_IPV4 && ifp->active == IF_ACTIVE_USER) {
@@ -930,7 +979,12 @@
 
 	if ((!(ifp->ctx->options & DHCPCD_MASTER) ||
 	    ifp->options->options & DHCPCD_IF_UP) &&
-	    if_up(ifp) == -1)
+	    if_up(ifp) == -1
+#ifdef __sun
+	    /* Interface could not yet be plumbed. */
+	    && errno != ENXIO
+#endif
+	    )
 		logerr("%s: %s", __func__, ifp->name);
 
 	if (ifp->options->options & DHCPCD_LINK &&
@@ -1171,8 +1225,12 @@
 	oldopts = ifp->options->options;
 	script_runreason(ifp, "RECONFIGURE");
 	dhcpcd_initstate1(ifp, argc, argv, 0);
+#ifdef INET
 	dhcp_reboot_newopts(ifp, oldopts);
+#endif
+#ifdef DHCP6
 	dhcp6_reboot(ifp);
+#endif
 	dhcpcd_prestartinterface(ifp);
 }
 
@@ -1210,8 +1268,10 @@
 		if (ifp->active == IF_ACTIVE_USER) {
 			if (action)
 				if_reboot(ifp, argc, argv);
+#ifdef INET
 			else
 				ipv4_applyaddr(ifp);
+#endif
 		} else if (i != argc) {
 			ifp->active = IF_ACTIVE_USER;
 			dhcpcd_initstate1(ifp, argc, argv, 0);
@@ -1250,11 +1310,17 @@
 	    ifp->carrier == LINK_DOWN)
 		return;
 
+#ifdef INET
 	dhcp_renew(ifp);
+#endif
+#ifdef INET6
 #define DHCPCD_RARENEW (DHCPCD_IPV6 | DHCPCD_IPV6RS)
 	if ((ifp->options->options & DHCPCD_RARENEW) == DHCPCD_RARENEW)
 		ipv6nd_startrs(ifp);
+#endif
+#ifdef DHCP6
 	dhcp6_renew(ifp);
+#endif
 }
 
 static void
@@ -1336,16 +1402,24 @@
 		if (!ifp->active)
 			continue;
 		len++;
+#ifdef INET
 		if (D_STATE_RUNNING(ifp))
 			len++;
+#endif
+#ifdef IPV4LL
 		if (IPV4LL_STATE_RUNNING(ifp))
 			len++;
+#endif
+#ifdef INET6
 		if (IPV6_STATE_RUNNING(ifp))
 			len++;
 		if (RS_STATE_RUNNING(ifp))
 			len++;
+#endif
+#ifdef DHCP6
 		if (D6_STATE_RUNNING(ifp))
 			len++;
+#endif
 	}
 	if (write(fd->fd, &len, sizeof(len)) != sizeof(len))
 		return;
@@ -1538,9 +1612,6 @@
 	ctx.cffile = CONFIG;
 	ctx.control_fd = ctx.control_unpriv_fd = ctx.link_fd = -1;
 	ctx.pf_inet_fd = -1;
-#ifdef IFLR_ACTIVE
-	ctx.pf_link_fd = -1;
-#endif
 
 	TAILQ_INIT(&ctx.control_fds);
 #ifdef PLUGIN_DEV
@@ -1664,9 +1735,11 @@
 			printf("\nND options:\n");
 			ipv6nd_printoptions(&ctx,
 			    ifo->nd_override, ifo->nd_override_len);
+#ifdef DHCP6
 			printf("\nDHCPv6 options:\n");
 			dhcp6_printoptions(&ctx,
 			    ifo->dhcp6_override, ifo->dhcp6_override_len);
+#endif
 		}
 #endif
 		goto exit_success;
@@ -1793,12 +1866,22 @@
 		configure_interface(ifp, ctx.argc, ctx.argv, 0);
 		i = 0;
 		if (family == 0 || family == AF_INET) {
+#ifdef INET
 			if (dhcp_dump(ifp) == -1)
 				i = -1;
+#else
+			if (family == AF_INET)
+				logerrx("No INET support");
+#endif
 		}
 		if (family == 0 || family == AF_INET6) {
+#ifdef DHCP6
 			if (dhcp6_dump(ifp) == -1)
 				i = -1;
+#else
+			if (family == AF_INET6)
+				logerrx("No DHCP6 support");
+#endif
 		}
 		if (i == -1)
 			goto exit_failure;
@@ -2057,10 +2140,11 @@
 	}
 	if_closesockets(&ctx);
 	free_globals(&ctx);
+#ifdef INET6
 	ipv6_ctxfree(&ctx);
+#endif
 	dev_stop(&ctx);
 	eloop_free(ctx.eloop);
-	free(ctx.iov[0].iov_base);
 
 	if (ctx.options & DHCPCD_STARTED && !(ctx.options & DHCPCD_FORKED))
 		loginfox(PACKAGE " exited");
diff -Nru dhcpcd5-7.1.0/src/dhcpcd.conf.5.in dhcpcd5-7.2.1/src/dhcpcd.conf.5.in
--- dhcpcd5-7.1.0/src/dhcpcd.conf.5.in	2019-01-22 22:53:45.000000000 +0800
+++ dhcpcd5-7.2.1/src/dhcpcd.conf.5.in	2019-04-26 21:32:54.000000000 +0800
@@ -22,7 +22,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd September 15, 2018
+.Dd April 24, 2019
 .Dt DHCPCD.CONF 5
 .Os
 .Sh NAME
@@ -376,8 +376,7 @@
 noipv6rs                 # disable routing solicitation
 denyinterfaces eth2      # Don't touch eth2 at all
 interface eth0
-  ipv6rs                 # enable routing solicitation get the
-                         # default IPv6 route
+  ipv6rs                 # enable routing solicitation for eth0
   ia_na 1                # request an IPv6 address
   ia_pd 2 eth1/0         # request a PD and assign it to eth1
   ia_pd 3 eth2/1 eth3/2  # req a PD and assign it to eth2 and eth3
diff -Nru dhcpcd5-7.1.0/src/dhcpcd.h dhcpcd5-7.2.1/src/dhcpcd.h
--- dhcpcd5-7.1.0/src/dhcpcd.h	2019-01-22 22:53:45.000000000 +0800
+++ dhcpcd5-7.2.1/src/dhcpcd.h	2019-04-26 21:32:54.000000000 +0800
@@ -49,9 +49,10 @@
 #define IF_ACTIVE	1
 #define IF_ACTIVE_USER	2
 
-#define LINK_UP		1
-#define LINK_UNKNOWN	0
-#define LINK_DOWN	-1
+#define	LINK_UP		1
+#define	LINK_UNKNOWN	0
+#define	LINK_DOWN	-1
+#define	LINK_DOWN_IFFUP	-2
 
 #define IF_DATA_IPV4	0
 #define IF_DATA_ARP	1
@@ -84,8 +85,9 @@
 	unsigned short vlanid;
 	unsigned int metric;
 	int carrier;
-	int wireless;
-	uint8_t ssid[IF_SSIDLEN + 1]; /* NULL terminated */
+	bool media_valid;
+	bool wireless;
+	uint8_t ssid[IF_SSIDLEN];
 	unsigned int ssid_len;
 
 	char profile[PROFILE_LEN];
@@ -140,14 +142,10 @@
 	struct rt_head froutes;	/* free routes for re-use */
 
 	int pf_inet_fd;
-#ifdef IFLR_ACTIVE
-	int pf_link_fd;
-#endif
 	void *priv;
 	int link_fd;
 	int seq;	/* route message sequence no */
 	int sseq;	/* successful seq no sent */
-	struct iovec iov[1];	/* generic iovec buffer */
 
 #ifdef USE_SIGNALS
 	sigset_t sigset;
@@ -182,24 +180,19 @@
 	uint8_t *secret;
 	size_t secret_len;
 
-	unsigned char ctlbuf[IP6BUFLEN];
-	struct sockaddr_in6 from;
-	struct msghdr sndhdr;
-	struct iovec sndiov[1];
-	unsigned char sndbuf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
-	struct msghdr rcvhdr;
-	char ntopbuf[INET6_ADDRSTRLEN];
-	const char *sfrom;
-
+#ifndef __sun
 	int nd_fd;
+#endif
 	struct ra_head *ra_routers;
 
 	int dhcp6_fd;
 
 	struct dhcp_opt *nd_opts;
 	size_t nd_opts_len;
+#ifdef DHCP6
 	struct dhcp_opt *dhcp6_opts;
 	size_t dhcp6_opts_len;
+#endif
 
 #ifndef __linux__
 	int ra_global;
diff -Nru dhcpcd5-7.1.0/src/dhcp.h dhcpcd5-7.2.1/src/dhcp.h
--- dhcpcd5-7.1.0/src/dhcp.h	2019-01-22 22:53:45.000000000 +0800
+++ dhcpcd5-7.2.1/src/dhcp.h	2019-04-26 21:32:54.000000000 +0800
@@ -216,6 +216,7 @@
 
 	int bpf_fd;
 	unsigned int bpf_flags;
+	int udp_fd;
 	struct ipv4_addr *addr;
 	uint8_t added;
 
@@ -228,6 +229,7 @@
 #endif
 };
 
+#ifdef INET
 #define D_STATE(ifp)							       \
 	((struct dhcp_state *)(ifp)->if_data[IF_DATA_DHCP])
 #define D_CSTATE(ifp)							       \
@@ -243,7 +245,6 @@
 #include "dhcpcd.h"
 #include "if-options.h"
 
-#ifdef INET
 char *decode_rfc3361(const uint8_t *, size_t);
 ssize_t decode_rfc3442(char *, size_t, const uint8_t *p, size_t);
 
@@ -266,15 +267,6 @@
 void dhcp_close(struct interface *);
 void dhcp_free(struct interface *);
 int dhcp_dump(struct interface *);
-#else
-#define dhcp_start(a) {}
-#define dhcp_abort(a) {}
-#define dhcp_renew(a) {}
-#define dhcp_reboot(a, b) (b = b)
-#define dhcp_reboot_newopts(a, b) (b = b)
-#define dhcp_close(a) {}
-#define dhcp_free(a) {}
-#define dhcp_dump(a) (-1)
-#endif
+#endif /* INET */
 
-#endif
+#endif /* DHCP_H */
diff -Nru dhcpcd5-7.1.0/src/duid.c dhcpcd5-7.2.1/src/duid.c
--- dhcpcd5-7.1.0/src/duid.c	2019-01-22 22:53:45.000000000 +0800
+++ dhcpcd5-7.2.1/src/duid.c	2019-04-26 21:32:54.000000000 +0800
@@ -90,6 +90,7 @@
 	fclose(fp);
 	r = len == 1 ? -1 : 0;
 #else
+	UNUSED(uuid);
 	r = -1;
 	errno = ENOSYS;
 #endif
diff -Nru dhcpcd5-7.1.0/src/if-bsd.c dhcpcd5-7.2.1/src/if-bsd.c
--- dhcpcd5-7.1.0/src/if-bsd.c	2019-01-22 22:53:45.000000000 +0800
+++ dhcpcd5-7.2.1/src/if-bsd.c	2019-04-26 21:32:54.000000000 +0800
@@ -99,14 +99,20 @@
 #endif
 
 #ifdef INET6
-static void
-ifa_scope(struct sockaddr_in6 *, unsigned int);
+static void ifa_setscope(struct sockaddr_in6 *, unsigned int);
+static unsigned int ifa_getscope(const struct sockaddr_in6 *);
 #endif
 
 struct priv {
 	int pf_inet6_fd;
 };
 
+struct rtm
+{
+	struct rt_msghdr hdr;
+	char buffer[sizeof(struct sockaddr_storage) * RTAX_MAX];
+};
+
 int
 if_init(__unused struct interface *iface)
 {
@@ -197,7 +203,6 @@
 		close(priv->pf_inet6_fd);
 }
 
-#if defined(INET) || defined(INET6)
 static void
 if_linkaddr(struct sockaddr_dl *sdl, const struct interface *ifp)
 {
@@ -208,7 +213,6 @@
 	sdl->sdl_nlen = sdl->sdl_alen = sdl->sdl_slen = 0;
 	sdl->sdl_index = (unsigned short)ifp->index;
 }
-#endif
 
 #if defined(SIOCG80211NWID) || defined(SIOCGETVLAN)
 static int if_direct_ioctl(int s, const char *ifname,
@@ -359,7 +363,6 @@
 	}
 }
 
-#if defined(INET) || defined(INET6)
 static struct interface *
 if_findsdl(struct dhcpcd_ctx *ctx, const struct sockaddr_dl *sdl)
 {
@@ -421,9 +424,13 @@
 	case AF_INET6:
 	{
 		const struct sockaddr_in6 *sin;
+		unsigned int scope;
 		struct ipv6_addr *ia;
 
 		sin = (const void *)sa;
+		scope = ifa_getscope(sin);
+		if (scope != 0)
+			return if_findindex(ctx->ifaces, scope);
 		if ((ia = ipv6_findmaskaddr(ctx, &sin->sin6_addr)))
 			return ia->iface;
 		break;
@@ -461,11 +468,7 @@
 if_route(unsigned char cmd, const struct rt *rt)
 {
 	struct dhcpcd_ctx *ctx;
-	struct rtm
-	{
-		struct rt_msghdr hdr;
-		char buffer[sizeof(struct sockaddr_storage) * RTAX_MAX];
-	} rtmsg;
+	struct rtm rtmsg;
 	struct rt_msghdr *rtm = &rtmsg.hdr;
 	char *bp = rtmsg.buffer;
 	struct sockaddr_dl sdl;
@@ -504,7 +507,17 @@
 		    !sa_is_loopback(&rt->rt_gateway))
 		{
 			rtm->rtm_index = (unsigned short)rt->rt_ifp->index;
-#ifdef __OpenBSD__
+/*
+ * OpenBSD rejects the message for on-link routes.
+ * FreeBSD-12 kernel apparently panics.
+ * I can't replicate the panic, but better safe than sorry!
+ * https://roy.marples.name/archives/dhcpcd-discuss/0002286.html
+ *
+ * Neither OS currently allows IPv6 address sharing anyway, so let's
+ * try to encourage someone to fix that by logging a waring during compile.
+ */
+#if defined(__FreeBSD__) || defined(__OpenBSD__)
+#warning OS does not allow IPv6 address sharing
 			if (!gateway_unspec || rt->rt_dest.sa_family!=AF_INET6)
 #endif
 			rtm->rtm_addrs |= RTA_IFP;
@@ -570,7 +583,7 @@
 			if_copysa(&gateway.sa, &rt->rt_gateway);
 #ifdef INET6
 			if (gateway.sa.sa_family == AF_INET6)
-				ifa_scope(&gateway.sin6, rt->rt_ifp->index);
+				ifa_setscope(&gateway.sin6, rt->rt_ifp->index);
 #endif
 			ADDSA(&gateway.sa);
 		}
@@ -598,19 +611,27 @@
 {
 	const struct sockaddr *rti_info[RTAX_MAX];
 
-	if (~rtm->rtm_addrs & (RTA_DST | RTA_GATEWAY))
+	if (~rtm->rtm_addrs & (RTA_DST | RTA_GATEWAY)) {
+		errno = EINVAL;
 		return -1;
+	}
 #ifdef RTF_CLONED
-	if (rtm->rtm_flags & RTF_CLONED)
+	if (rtm->rtm_flags & RTF_CLONED) {
+		errno = ENOTSUP;
 		return -1;
+	}
 #endif
 #ifdef RTF_LOCAL
-	if (rtm->rtm_flags & RTF_LOCAL)
+	if (rtm->rtm_flags & RTF_LOCAL) {
+		errno = ENOTSUP;
 		return -1;
+	}
 #endif
 #ifdef RTF_BROADCAST
-	if (rtm->rtm_flags & RTF_BROADCAST)
+	if (rtm->rtm_flags & RTF_BROADCAST) {
+		errno = ENOTSUP;
 		return -1;
+	}
 #endif
 
 	get_addrs(rtm->rtm_addrs, rtm + 1, rti_info);
@@ -681,15 +702,13 @@
 		rtm = (void *)p;
 		if (if_copyrt(ctx, &rt, rtm) == 0) {
 			rt.rt_dflags |= RTDF_INIT;
-			rt_recvrt(RTM_ADD, &rt);
+			rt_recvrt(RTM_ADD, &rt, rtm->rtm_pid);
 		}
 	}
 	free(buf);
 	return 0;
 }
 
-#endif
-
 #ifdef INET
 int
 if_address(unsigned char cmd, const struct ipv4_addr *ia)
@@ -746,7 +765,7 @@
 
 #ifdef INET6
 static void
-ifa_scope(struct sockaddr_in6 *sin, unsigned int ifindex)
+ifa_setscope(struct sockaddr_in6 *sin, unsigned int ifindex)
 {
 
 #ifdef __KAME__
@@ -766,6 +785,23 @@
 #endif
 }
 
+static unsigned int
+ifa_getscope(const struct sockaddr_in6 *sin)
+{
+#ifdef __KAME__
+	uint16_t scope;
+#endif
+
+	if (!IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr))
+		return 0;
+#ifdef __KAME__
+	memcpy(&scope, &sin->sin6_addr.s6_addr[2], sizeof(scope));
+	return (unsigned int)ntohs(scope);
+#else
+	return (unsigned int)sin->sin6_scope_id;
+#endif
+}
+
 int
 if_address6(unsigned char cmd, const struct ipv6_addr *ia)
 {
@@ -805,7 +841,7 @@
 	}
 
 	ADDADDR(&ifa.ifra_addr, &ia->addr);
-	ifa_scope(&ifa.ifra_addr, ia->iface->index);
+	ifa_setscope(&ifa.ifra_addr, ia->iface->index);
 	ipv6_mask(&mask, ia->prefix_len);
 	ADDADDR(&ifa.ifra_prefixmask, &mask);
 
@@ -882,7 +918,7 @@
 	strlcpy(ifr6.ifr_name, ifp->name, sizeof(ifr6.ifr_name));
 	ifr6.ifr_addr.sin6_family = AF_INET6;
 	ifr6.ifr_addr.sin6_addr = *addr;
-	ifa_scope(&ifr6.ifr_addr, ifp->index);
+	ifa_setscope(&ifr6.ifr_addr, ifp->index);
 	priv = (struct priv *)ifp->ctx->priv;
 	if (ioctl(priv->pf_inet6_fd, SIOCGIFAFLAG_IN6, &ifr6) != -1)
 		flags = ifr6.ifr_ifru.ifru_flags6;
@@ -903,14 +939,19 @@
 	strlcpy(ifr6.ifr_name, ia->iface->name, sizeof(ifr6.ifr_name));
 	ifr6.ifr_addr.sin6_family = AF_INET6;
 	ifr6.ifr_addr.sin6_addr = ia->addr;
-	ifa_scope(&ifr6.ifr_addr, ia->iface->index);
+	ifa_setscope(&ifr6.ifr_addr, ia->iface->index);
 	priv = (struct priv *)ia->iface->ctx->priv;
 	if (ioctl(priv->pf_inet6_fd, SIOCGIFALIFETIME_IN6, &ifr6) == -1)
 		return -1;
+	clock_gettime(CLOCK_MONOTONIC, &ia->created);
 
+#if defined(__FreeBSD__) || defined(__DragonFly__)
+	t = ia->created.tv_sec;
+#else
 	t = time(NULL);
-	lifetime = &ifr6.ifr_ifru.ifru_lifetime;
+#endif
 
+	lifetime = &ifr6.ifr_ifru.ifru_lifetime;
 	if (lifetime->ia6t_preferred)
 		ia->prefix_pltime = (uint32_t)(lifetime->ia6t_preferred -
 		    MIN(t, lifetime->ia6t_preferred));
@@ -920,7 +961,6 @@
 		ia->prefix_vltime = (uint32_t)(lifetime->ia6t_expire -
 		    MIN(t, lifetime->ia6t_expire));
 		/* Calculate the created time */
-		clock_gettime(CLOCK_MONOTONIC, &ia->created);
 		ia->created.tv_sec -= lifetime->ia6t_vltime - ia->prefix_vltime;
 	} else
 		ia->prefix_vltime = ND6_INFINITE_LIFETIME;
@@ -951,16 +991,22 @@
 	if ((ifp = if_findindex(ctx->ifaces, ifm->ifm_index)) == NULL)
 		return;
 
-	/* If we get LINK_STATE_UNKNOWN here, it means the interface
-	 * doesn't support reporting carrier state.
-	 * As such, we need to rely on IFF_UP.
-	 * Even if LINK_STATE_UP is reported, we also need IFF_UP as well
-	 * so for dhcpcd they are equivalent and we only need to check
-	 * LINK_STATE_DOWN. */
-	if (ifm->ifm_data.ifi_link_state == LINK_STATE_DOWN)
-		link_state = LINK_DOWN;
-	else
+	switch (ifm->ifm_data.ifi_link_state) {
+	case LINK_STATE_UNKNOWN:
+		if (ifp->media_valid) {
+			link_state = LINK_DOWN;
+			break;
+		}
+		/* Interface does not report media state, so we have
+		 * to rely on IFF_UP. */
+		/* FALLTHROUGH */
+	case LINK_STATE_UP:
 		link_state = ifm->ifm_flags & IFF_UP ? LINK_UP : LINK_DOWN;
+		break;
+	default:
+		link_state = LINK_DOWN;
+		break;
+	}
 
 	dhcpcd_handlecarrier(ctx, link_state,
 	    (unsigned int)ifm->ifm_flags, ifp->name);
@@ -999,7 +1045,7 @@
 	}
 #endif
 
-	rt_recvrt(rtm->rtm_type, &rt);
+	rt_recvrt(rtm->rtm_type, &rt, rtm->rtm_pid);
 }
 
 static void
@@ -1084,7 +1130,7 @@
 			ifra.ifra_addr.sin_len = sizeof(ifra.ifra_addr);
 			ifra.ifra_addr.sin_addr = addr;
 			if (ioctl(ctx->pf_inet_fd, SIOCGIFALIAS, &ifra) == -1) {
-				if (errno != EADDRNOTAVAIL)
+				if (errno != ENXIO && errno != EADDRNOTAVAIL)
 					logerr("%s: SIOCGIFALIAS", __func__);
 				if (ifam->ifam_type != RTM_DELADDR)
 					break;
@@ -1218,18 +1264,16 @@
 int
 if_handlelink(struct dhcpcd_ctx *ctx)
 {
-	struct msghdr msg;
+	struct rtm rtm;
+	struct iovec iov = { .iov_base = &rtm, .iov_len = sizeof(rtm) };
+	struct msghdr msg = { .msg_iov = &iov, .msg_iovlen = 1 };
 	ssize_t len;
 
-	memset(&msg, 0, sizeof(msg));
-	msg.msg_iov = ctx->iov;
-	msg.msg_iovlen = 1;
-
-	len = recvmsg_realloc(ctx->link_fd, &msg, 0);
+	len = recvmsg(ctx->link_fd, &msg, 0);
 	if (len == -1)
 		return -1;
 	if (len != 0)
-		if_dispatch(ctx, ctx->iov[0].iov_base);
+		if_dispatch(ctx, &rtm.hdr);
 	return 0;
 }
 
diff -Nru dhcpcd5-7.1.0/src/if.c dhcpcd5-7.2.1/src/if.c
--- dhcpcd5-7.1.0/src/if.c	2019-01-22 22:53:45.000000000 +0800
+++ dhcpcd5-7.2.1/src/if.c	2019-04-26 21:32:54.000000000 +0800
@@ -78,12 +78,20 @@
 
 	if (ifp == NULL)
 		return;
+#ifdef IPV4LL
 	ipv4ll_free(ifp);
+#endif
+#ifdef INET
 	dhcp_free(ifp);
 	ipv4_free(ifp);
+#endif
+#ifdef DHCP6
 	dhcp6_free(ifp);
+#endif
+#ifdef INET6
 	ipv6nd_free(ifp);
 	ipv6_free(ifp);
+#endif
 	rt_freeif(ifp);
 	free_options(ifp->ctx, ifp->options);
 	free(ifp);
@@ -101,12 +109,6 @@
 	if (ctx->pf_inet_fd == -1)
 		return -1;
 
-#ifdef IFLR_ACTIVE
-	ctx->pf_link_fd = xsocket(PF_LINK, SOCK_DGRAM | SOCK_CLOEXEC, 0);
-	if (ctx->pf_link_fd == -1)
-		return -1;
-#endif
-
 	return 0;
 }
 
@@ -116,10 +118,6 @@
 
 	if (ctx->pf_inet_fd != -1)
 		close(ctx->pf_inet_fd);
-#ifdef IFLR_ACTIVE
-	if (ctx->pf_link_fd != -1)
-		close(ctx->pf_link_fd);
-#endif
 
 	if (ctx->priv) {
 		if_closesockets_os(ctx);
@@ -138,21 +136,32 @@
 
 	memset(&ifr, 0, sizeof(ifr));
 	strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
-	if (ioctl(ifp->ctx->pf_inet_fd, SIOCGIFFLAGS, &ifr) == -1)
+	r = ioctl(ifp->ctx->pf_inet_fd, SIOCGIFFLAGS, &ifr);
+	if (r != -1)
+		ifp->flags = (unsigned int)ifr.ifr_flags;
+
+#ifdef __sun
+	return if_carrier_os(ifp);
+#else
+	if (r == -1)
 		return LINK_UNKNOWN;
-	ifp->flags = (unsigned int)ifr.ifr_flags;
 
 #ifdef SIOCGIFMEDIA
 	memset(&ifmr, 0, sizeof(ifmr));
 	strlcpy(ifmr.ifm_name, ifp->name, sizeof(ifmr.ifm_name));
 	if (ioctl(ifp->ctx->pf_inet_fd, SIOCGIFMEDIA, &ifmr) != -1 &&
 	    ifmr.ifm_status & IFM_AVALID)
+	{
+		ifp->media_valid = true;
 		r = (ifmr.ifm_status & IFM_ACTIVE) ? LINK_UP : LINK_DOWN;
-	else
+	} else {
+		ifp->media_valid = false;
 		r = ifr.ifr_flags & IFF_RUNNING ? LINK_UP : LINK_UNKNOWN;
+	}
 #else
 	r = ifr.ifr_flags & IFF_RUNNING ? LINK_UP : LINK_DOWN;
 #endif
+#endif /* __sun */
 	return r;
 }
 
@@ -330,12 +339,10 @@
 	struct ifreq ifr;
 #endif
 #ifdef IFLR_ACTIVE
-	struct if_laddrreq iflr;
+	struct if_laddrreq iflr = { .flags = IFLR_PREFIX };
+	int link_fd;
 #endif
 
-#ifdef IFLR_ACTIVE
-	memset(&iflr, 0, sizeof(iflr));
-#endif
 #elif AF_PACKET
 	const struct sockaddr_ll *sll;
 #endif
@@ -344,11 +351,21 @@
 		logerr(__func__);
 		return NULL;
 	}
-	TAILQ_INIT(ifs);
 	if (getifaddrs(ifaddrs) == -1) {
 		logerr(__func__);
-		goto out;
+		free(ifs);
+		return NULL;
+	}
+	TAILQ_INIT(ifs);
+
+#ifdef IFLR_ACTIVE
+	link_fd = xsocket(PF_LINK, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+	if (link_fd == -1) {
+		logerr(__func__);
+		free(ifs);
+		return NULL;
 	}
+#endif
 
 	for (ifa = *ifaddrs; ifa; ifa = ifa->ifa_next) {
 		if (ifa->ifa_addr != NULL) {
@@ -445,7 +462,7 @@
 			    MIN(ifa->ifa_addr->sa_len, sizeof(iflr.addr)));
 			iflr.flags = IFLR_PREFIX;
 			iflr.prefixlen = (unsigned int)sdl->sdl_alen * NBBY;
-			if (ioctl(ctx->pf_link_fd, SIOCGLIFADDR, &iflr) == -1 ||
+			if (ioctl(link_fd, SIOCGLIFADDR, &iflr) == -1 ||
 			    !(iflr.flags & IFLR_ACTIVE))
 			{
 				if_free(ifp);
@@ -462,7 +479,7 @@
 			case IFT_PPP: /* FALLTHROUGH */
 #endif
 #ifdef IFT_PROPVIRTUAL
-			case IFT_PROPVIRTUAL: /* FALLTHROUGH */
+			case IFT_PROPVIRTUAL:
 #endif
 #if defined(IFT_BRIDGE) || defined(IFT_PPP) || defined(IFT_PROPVIRTUAL)
 				/* Don't allow unless explicit */
@@ -476,6 +493,7 @@
 					    ifp->name);
 					active = IF_INACTIVE;
 				}
+				__fallthrough; /* Appease gcc-7 */
 				/* FALLTHROUGH */
 #endif
 #ifdef IFT_L2VLAN
@@ -584,7 +602,7 @@
 		 * we can work them out. */
 		ifp->metric = 200 + ifp->index;
 		if (if_getssid(ifp) != -1) {
-			ifp->wireless = 1;
+			ifp->wireless = true;
 			ifp->metric += 100;
 		}
 #endif
@@ -597,7 +615,9 @@
 		TAILQ_INSERT_TAIL(ifs, ifp, next);
 	}
 
-out:
+#ifdef IFLR_ACTIVE
+	close(link_fd);
+#endif
 	return ifs;
 }
 
@@ -698,6 +718,11 @@
 	int r;
 	struct ifreq ifr;
 
+#ifdef __sun
+	if (mtu == 0)
+		return if_mtu_os(ifp);
+#endif
+
 	memset(&ifr, 0, sizeof(ifr));
 	strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
 	ifr.ifr_mtu = mtu;
@@ -726,19 +751,24 @@
 		return -1;
 	if (si->carrier < ti->carrier)
 		return 1;
-
+#ifdef INET
 	if (D_STATE_RUNNING(si) && !D_STATE_RUNNING(ti))
 		return -1;
 	if (!D_STATE_RUNNING(si) && D_STATE_RUNNING(ti))
 		return 1;
+#endif
+#ifdef INET6
 	if (RS_STATE_RUNNING(si) && !RS_STATE_RUNNING(ti))
 		return -1;
 	if (!RS_STATE_RUNNING(si) && RS_STATE_RUNNING(ti))
 		return 1;
+#endif
+#ifdef DHCP6
 	if (D6_STATE_RUNNING(si) && !D6_STATE_RUNNING(ti))
 		return -1;
 	if (!D6_STATE_RUNNING(si) && D6_STATE_RUNNING(ti))
 		return 1;
+#endif
 
 #ifdef INET
 	/* Special attention needed here due to states and IPv4LL. */
@@ -754,6 +784,17 @@
 	return 0;
 }
 
+#ifdef ALIAS_ADDR
+int
+if_makealias(char *alias, size_t alias_len, const char *ifname, int lun)
+{
+
+	if (lun == 0)
+		return strlcpy(alias, ifname, alias_len);
+	return snprintf(alias, alias_len, "%s:%u", ifname, lun);
+}
+#endif
+
 /* Sort the interfaces into a preferred order - best first, worst last. */
 void
 if_sortinterfaces(struct dhcpcd_ctx *ctx)
@@ -783,6 +824,68 @@
 	TAILQ_CONCAT(ctx->ifaces, &sorted, next);
 }
 
+struct interface *
+if_findifpfromcmsg(struct dhcpcd_ctx *ctx, struct msghdr *msg, int *hoplimit)
+{
+	struct cmsghdr *cm;
+	unsigned int ifindex = 0;
+	struct interface *ifp;
+#if defined(INET) && defined(IP_PKTINFO)
+	struct in_pktinfo ipi;
+#endif
+#ifdef INET6
+	struct in6_pktinfo ipi6;
+#else
+	UNUSED(hoplimit);
+#endif
+
+	for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(msg);
+	     cm;
+	     cm = (struct cmsghdr *)CMSG_NXTHDR(msg, cm))
+	{
+#if defined(INET) && defined(IP_PKTINFO)
+		if (cm->cmsg_level == IPPROTO_IP) {
+			switch(cm->cmsg_type) {
+			case IP_PKTINFO:
+				if (cm->cmsg_len != CMSG_LEN(sizeof(ipi)))
+					continue;
+				memcpy(&ipi, CMSG_DATA(cm), sizeof(ipi));
+				ifindex = (unsigned int)ipi.ipi_ifindex;
+				break;
+			}
+		}
+#endif
+#ifdef INET6
+		if (cm->cmsg_level == IPPROTO_IPV6) {
+			switch(cm->cmsg_type) {
+			case IPV6_PKTINFO:
+				if (cm->cmsg_len != CMSG_LEN(sizeof(ipi6)))
+					continue;
+				memcpy(&ipi6, CMSG_DATA(cm), sizeof(ipi6));
+				ifindex = (unsigned int)ipi6.ipi6_ifindex;
+				break;
+			case IPV6_HOPLIMIT:
+				if (cm->cmsg_len != CMSG_LEN(sizeof(int)))
+					continue;
+				if (hoplimit == NULL)
+					break;
+				memcpy(hoplimit, CMSG_DATA(cm), sizeof(int));
+				break;
+			}
+		}
+#endif
+	}
+
+	/* Find the receiving interface */
+	TAILQ_FOREACH(ifp, ctx->ifaces, next) {
+		if (ifp->index == ifindex)
+			break;
+	}
+	if (ifp == NULL)
+		errno = ESRCH;
+	return ifp;
+}
+
 int
 xsocket(int domain, int type, int protocol)
 {
diff -Nru dhcpcd5-7.1.0/src/if.h dhcpcd5-7.2.1/src/if.h
--- dhcpcd5-7.1.0/src/if.h	2019-01-22 22:53:45.000000000 +0800
+++ dhcpcd5-7.2.1/src/if.h	2019-04-26 21:32:54.000000000 +0800
@@ -129,6 +129,13 @@
 #define if_setmtu(ifp, mtu) if_domtu((ifp), (mtu))
 int if_carrier(struct interface *);
 
+#ifdef ALIAS_ADDR
+int if_makealias(char *, size_t, const char *, int);
+#endif
+
+int if_carrier_os(struct interface *);
+int if_mtu_os(const struct interface *);
+
 /*
  * Helper to decode an interface name of bge0:1 to
  * devname = bge0, drvname = bge0, ppa = 0, lun = 1.
@@ -209,5 +216,7 @@
 #endif
 
 int if_machinearch(char *, size_t);
+struct interface *if_findifpfromcmsg(struct dhcpcd_ctx *,
+    struct msghdr *, int *);
 int xsocket(int, int, int);
 #endif
diff -Nru dhcpcd5-7.1.0/src/if-linux.c dhcpcd5-7.2.1/src/if-linux.c
--- dhcpcd5-7.1.0/src/if-linux.c	2019-01-22 22:53:45.000000000 +0800
+++ dhcpcd5-7.2.1/src/if-linux.c	2019-04-26 21:32:54.000000000 +0800
@@ -92,6 +92,11 @@
 #define IFF_LOWER_UP	0x10000		/* driver signals L1 up		*/
 #endif
 
+/* Buggy CentOS and RedHat */
+#ifndef SOL_NETLINK
+#define	SOL_NETLINK	270
+#endif
+
 #define bpf_insn		sock_filter
 #define BPF_SKIPTYPE
 #define BPF_ETHCOOK		-ETH_HLEN
@@ -100,7 +105,6 @@
 struct priv {
 	int route_fd;
 	uint32_t route_pid;
-	struct iovec sndrcv_iov[1];
 };
 
 /* We need this to send a broadcast for InfiniBand.
@@ -341,7 +345,6 @@
 
 	if (ctx->priv != NULL) {
 		priv = (struct priv *)ctx->priv;
-		free(priv->sndrcv_iov[0].iov_base);
 		close(priv->route_fd);
 	}
 }
@@ -351,21 +354,18 @@
     struct interface *ifp, int fd, int flags,
     int (*callback)(struct dhcpcd_ctx *, struct interface *, struct nlmsghdr *))
 {
-	struct msghdr msg;
-	struct sockaddr_nl nladdr;
+	struct sockaddr_nl nladdr = { .nl_pid = 0 };
+	struct msghdr msg = {
+	    .msg_name = &nladdr, .msg_namelen = sizeof(nladdr),
+	    .msg_iov = iov, .msg_iovlen = 1,
+	};
 	ssize_t len;
 	struct nlmsghdr *nlm;
 	int r;
 	unsigned int again;
 
-	memset(&msg, 0, sizeof(msg));
-	msg.msg_name = &nladdr;
-	msg.msg_namelen = sizeof(nladdr);
-	memset(&nladdr, 0, sizeof(nladdr));
-	msg.msg_iov = iov;
-	msg.msg_iovlen = 1;
 recv_again:
-	if ((len = recvmsg_realloc(fd, &msg, flags)) == -1)
+	if ((len = recvmsg(fd, &msg, flags)) == -1)
 		return -1;
 	if (len == 0)
 		return 0;
@@ -550,7 +550,7 @@
 		return 0;
 
 	if (if_copyrt(ctx, &rt, nlm) == 0)
-		rt_recvrt(cmd, &rt);
+		rt_recvrt(cmd, &rt, (pid_t)nlm->nlmsg_pid);
 
 	return 0;
 }
@@ -811,8 +811,13 @@
 int
 if_handlelink(struct dhcpcd_ctx *ctx)
 {
+	unsigned char buf[16 * 1024];
+	struct iovec iov = {
+		.iov_base = buf,
+		.iov_len = sizeof(buf),
+	};
 
-	return get_netlink(ctx, ctx->iov, NULL,
+	return get_netlink(ctx, &iov, NULL,
 	    ctx->link_fd, MSG_DONTWAIT, &link_netlink);
 }
 
@@ -822,12 +827,12 @@
     int (*callback)(struct dhcpcd_ctx *, struct interface *, struct nlmsghdr *))
 {
 	int s, r;
-	struct sockaddr_nl snl;
-	struct iovec iov[1];
-	struct msghdr msg;
-
-	memset(&snl, 0, sizeof(snl));
-	snl.nl_family = AF_NETLINK;
+	struct sockaddr_nl snl = { .nl_family = AF_NETLINK };
+	struct iovec iov = { .iov_base = hdr, .iov_len = hdr->nlmsg_len };
+	struct msghdr msg = {
+	    .msg_name = &snl, .msg_namelen = sizeof(snl),
+	    .msg_iov = &iov, .msg_iovlen = 1
+	};
 
 	if (protocol == NETLINK_ROUTE) {
 		struct priv *priv;
@@ -839,22 +844,17 @@
 			return -1;
 	}
 
-	memset(&msg, 0, sizeof(msg));
-	msg.msg_name = &snl;
-	msg.msg_namelen = sizeof(snl);
-	memset(&iov, 0, sizeof(iov));
-	iov[0].iov_base = hdr;
-	iov[0].iov_len = hdr->nlmsg_len;
-	msg.msg_iov = iov;
-	msg.msg_iovlen = 1;
 	/* Request a reply */
 	hdr->nlmsg_flags |= NLM_F_ACK;
 	hdr->nlmsg_seq = (uint32_t)++ctx->seq;
 	if (sendmsg(s, &msg, 0) != -1) {
-		struct priv *priv;
+		unsigned char buf[16 * 1024];
+		struct iovec riov = {
+			.iov_base = buf,
+			.iov_len = sizeof(buf),
+		};
 
-		priv = (struct priv *)ctx->priv;
-		r = get_netlink(ctx, priv->sndrcv_iov, ifp, s, 0, callback);
+		r = get_netlink(ctx, &riov, ifp, s, 0, callback);
 	} else
 		r = -1;
 	if (protocol != NETLINK_ROUTE)
@@ -1291,7 +1291,7 @@
 
 	if (if_copyrt(ctx, &rt, nlm) == 0) {
 		rt.rt_dflags |= RTDF_INIT;
-		rt_recvrt(RTM_ADD, &rt);
+		rt_recvrt(RTM_ADD, &rt, (pid_t)nlm->nlmsg_pid);
 	}
 	return 0;
 }
@@ -1299,17 +1299,15 @@
 int
 if_initrt(struct dhcpcd_ctx *ctx, int af)
 {
-	struct nlmr nlm;
+	struct nlmr nlm = {
+	    .hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)),
+	    .hdr.nlmsg_type = RTM_GETROUTE,
+	    .hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_MATCH,
+	    .rt.rtm_table = RT_TABLE_MAIN,
+	    .rt.rtm_family = (unsigned char)af,
+	};
 
 	rt_headclear(&ctx->kroutes, af);
-
-	memset(&nlm, 0, sizeof(nlm));
-	nlm.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
-	nlm.hdr.nlmsg_type = RTM_GETROUTE;
-	nlm.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_MATCH;
-	nlm.rt.rtm_table = RT_TABLE_MAIN;
-	nlm.rt.rtm_family = (unsigned char)af;
-
 	return send_netlink(ctx, NULL, NETLINK_ROUTE, &nlm.hdr, &_if_initrt);
 }
 
@@ -1396,7 +1394,7 @@
 	};
 	struct msghdr msg = { .msg_iov = &iov, .msg_iovlen = 1 };
 #ifdef PACKET_AUXDATA
-	unsigned char cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))];
+	unsigned char cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))] = { 0 };
 	struct cmsghdr *cmsg;
 	struct tpacket_auxdata *aux;
 #endif
diff -Nru dhcpcd5-7.1.0/src/if-options.c dhcpcd5-7.2.1/src/if-options.c
--- dhcpcd5-7.1.0/src/if-options.c	2019-01-22 22:53:45.000000000 +0800
+++ dhcpcd5-7.2.1/src/if-options.c	2019-04-26 21:32:54.000000000 +0800
@@ -207,11 +207,12 @@
 	{NULL,              0,                 NULL, '\0'}
 };
 
+static const char *default_script = SCRIPT;
+
 static char *
-add_environ(struct if_options *ifo, const char *value, int uniq)
+add_environ(char ***array, const char *value, int uniq)
 {
-	char **newlist;
-	char **lst = ifo->environ;
+	char **newlist, **list = *array;
 	size_t i = 0, l, lv;
 	char *match = NULL, *p, *n;
 
@@ -229,8 +230,8 @@
 	*p++ = '\0';
 	l = strlen(match);
 
-	while (lst && lst[i]) {
-		if (match && strncmp(lst[i], match, l) == 0) {
+	while (list && list[i]) {
+		if (match && strncmp(list[i], match, l) == 0) {
 			if (uniq) {
 				n = strdup(value);
 				if (n == NULL) {
@@ -238,25 +239,25 @@
 					free(match);
 					return NULL;
 				}
-				free(lst[i]);
-				lst[i] = n;
+				free(list[i]);
+				list[i] = n;
 			} else {
 				/* Append a space and the value to it */
-				l = strlen(lst[i]);
+				l = strlen(list[i]);
 				lv = strlen(p);
-				n = realloc(lst[i], l + lv + 2);
+				n = realloc(list[i], l + lv + 2);
 				if (n == NULL) {
 					logerr(__func__);
 					free(match);
 					return NULL;
 				}
-				lst[i] = n;
-				lst[i][l] = ' ';
-				memcpy(lst[i] + l + 1, p, lv);
-				lst[i][l + lv + 1] = '\0';
+				list[i] = n;
+				list[i][l] = ' ';
+				memcpy(list[i] + l + 1, p, lv);
+				list[i][l + lv + 1] = '\0';
 			}
 			free(match);
-			return lst[i];
+			return list[i];
 		}
 		i++;
 	}
@@ -267,7 +268,7 @@
 		logerr(__func__);
 		return NULL;
 	}
-	newlist = reallocarray(lst, i + 2, sizeof(char *));
+	newlist = reallocarray(list, i + 2, sizeof(char *));
 	if (newlist == NULL) {
 		logerr(__func__);
 		free(n);
@@ -275,26 +276,31 @@
 	}
 	newlist[i] = n;
 	newlist[i + 1] = NULL;
-	ifo->environ = newlist;
+	*array = newlist;
 	return newlist[i];
 }
 
-#define parse_string(buf, len, arg) parse_string_hwaddr(buf, len, arg, 0)
+#define PARSE_STRING		0
+#define PARSE_STRING_NULL	1
+#define PARSE_HWADDR		2
+#define parse_string(a, b, c) parse_str((a), (b), (c), PARSE_STRING)
+#define parse_hwaddr(a, b, c) parse_str((a), (b), (c), PARSE_HWADDR)
 static ssize_t
-parse_string_hwaddr(char *sbuf, size_t slen, const char *str, int clid)
+parse_str(char *sbuf, size_t slen, const char *str, int flags)
 {
 	size_t l;
-	const char *p;
-	int i, punt_last = 0;
+	const char *p, *end;
+	int i;
 	char c[4], cmd;
 
+	end = str + strlen(str);
 	/* If surrounded by quotes then it's a string */
 	if (*str == '"') {
-		str++;
-		l = strlen(str);
-		p = str + l - 1;
-		if (*p == '"')
-			punt_last = 1;
+		p = end - 1;
+		if (*p == '"') {
+			str++;
+			end = p;
+		}
 	} else {
 		l = (size_t)hwaddr_aton(NULL, str);
 		if ((ssize_t) l != -1 && l > 1) {
@@ -311,13 +317,13 @@
 	l = 0;
 	/* If processing a string on the clientid, first byte should be
 	 * 0 to indicate a non hardware type */
-	if (clid && *str) {
+	if (flags == PARSE_HWADDR && *str) {
 		if (sbuf)
 			*sbuf++ = 0;
 		l++;
 	}
 	c[3] = '\0';
-	while (*str) {
+	while (str < end) {
 		if (++l > slen && sbuf) {
 			errno = ENOBUFS;
 			return -1;
@@ -385,11 +391,8 @@
 			str++;
 		}
 	}
-	if (punt_last) {
-		if (sbuf)
-			*--sbuf = '\0';
-		l--;
-	}
+	if (flags == PARSE_STRING_NULL && sbuf)
+		*sbuf = '\0';
 	return (ssize_t)l;
 }
 
@@ -541,6 +544,7 @@
 		return arg + strlen("nd_");
 	}
 
+#ifdef DHCP6
 	if (strncmp(arg, "dhcp6_", strlen("dhcp6_")) == 0) {
 		*d = ctx->dhcp6_opts;
 		*dl = ctx->dhcp6_opts_len;
@@ -553,6 +557,7 @@
 		return arg + strlen("dhcp6_");
 	}
 #endif
+#endif
 
 #ifdef INET
 	*d = ctx->dhcp_opts;
@@ -652,7 +657,7 @@
 	int e, i, t;
 	long l;
 	unsigned long u;
-	char *p = NULL, *bp, *fp, *np, **nconf;
+	char *p = NULL, *bp, *fp, *np;
 	ssize_t s;
 	struct in_addr addr, addr2;
 	in_addr_t *naddr;
@@ -706,17 +711,33 @@
 		break;
 	case 'c':
 		ARG_REQUIRED;
-		free(ifo->script);
-		ifo->script = strdup(arg);
-		if (ifo->script == NULL)
+		if (ifo->script != default_script)
+			free(ifo->script);
+		s = parse_str(NULL, 0, arg, PARSE_STRING_NULL);
+		if (s == 0) {
+			ifo->script = NULL;
+			break;
+		}
+		dl = (size_t)s;
+		if (s == -1 || (ifo->script = malloc(dl)) == NULL) {
+			ifo->script = NULL;
 			logerr(__func__);
+			return -1;
+		}
+		parse_str(ifo->script, dl, arg, PARSE_STRING_NULL);
+		if (ifo->script[0] == '\0' ||
+		    strcmp(ifo->script, "/dev/null") == 0)
+		{
+			free(ifo->script);
+			ifo->script = NULL;
+		}
 		break;
 	case 'd':
 		ifo->options |= DHCPCD_DEBUG;
 		break;
 	case 'e':
 		ARG_REQUIRED;
-		add_environ(ifo, arg, 1);
+		add_environ(&ifo->environ, arg, 1);
 		break;
 	case 'h':
 		if (!arg) {
@@ -967,7 +988,7 @@
 			return -1;
 		}
 		snprintf(p, dl, "skip_hooks=%s", arg);
-		add_environ(ifo, p, 0);
+		add_environ(&ifo->environ, p, 0);
 		free(p);
 		break;
 	case 'D':
@@ -1004,8 +1025,8 @@
 		/* Strings have a type of 0 */;
 		ifo->clientid[1] = 0;
 		if (arg)
-			s = parse_string_hwaddr((char *)ifo->clientid + 1,
-			    CLIENTID_MAX_LEN, arg, 1);
+			s = parse_hwaddr((char *)ifo->clientid + 1,
+			    CLIENTID_MAX_LEN, arg);
 		else
 			s = 0;
 		if (s == -1) {
@@ -1110,6 +1131,7 @@
 			sa_in_init(&rt->rt_gateway, &addr3);
 			TAILQ_INSERT_TAIL(&ifo->routes, rt, rt_next);
 			*fp = ' ';
+			add_environ(&ifo->config, arg, 0);
 		} else if (strncmp(arg, "routers=", strlen("routers=")) == 0) {
 			if (parse_addr(&addr, NULL, p) == -1)
 				return -1;
@@ -1120,6 +1142,7 @@
 			sa_in_init(&rt->rt_netmask, &addr2);
 			sa_in_init(&rt->rt_gateway, &addr);
 			TAILQ_INSERT_TAIL(&ifo->routes, rt, rt_next);
+			add_environ(&ifo->config, arg, 0);
 		} else if (strncmp(arg, "interface_mtu=",
 		    strlen("interface_mtu=")) == 0 ||
 		    strncmp(arg, "mtu=", strlen("mtu=")) == 0)
@@ -1147,40 +1170,8 @@
 				} else
 					ifo->req_prefix_len = 128;
 			}
-		} else {
-			dl = 0;
-			if (ifo->config != NULL) {
-				while (ifo->config[dl] != NULL) {
-					if (strncmp(ifo->config[dl], arg,
-						(size_t)(p - arg)) == 0)
-					{
-						p = strdup(arg);
-						if (p == NULL) {
-							logerr(__func__);
-							return -1;
-						}
-						free(ifo->config[dl]);
-						ifo->config[dl] = p;
-						return 1;
-					}
-					dl++;
-				}
-			}
-			p = strdup(arg);
-			if (p == NULL) {
-				logerr(__func__);
-				return -1;
-			}
-			nconf = reallocarray(ifo->config, dl+2, sizeof(char *));
-			if (nconf == NULL) {
-				logerr(__func__);
-				free(p);
-				return -1;
-			}
-			ifo->config = nconf;
-			ifo->config[dl] = p;
-			ifo->config[dl + 1] = NULL;
-		}
+		} else
+			add_environ(&ifo->config, arg, 1);
 		break;
 	case 'W':
 		if (parse_addr(&addr, &addr2, arg) != 0)
@@ -1420,9 +1411,13 @@
 			ia->sla = NULL;
 #endif
 		}
+
+#ifdef SMALL
+		break;
+#else
 		if (ia->ia_type != D6_OPTION_IA_PD)
 			break;
-#ifndef SMALL
+
 		for (p = fp; p; p = fp) {
 			fp = strwhite(p);
 			if (fp) {
@@ -2271,6 +2266,7 @@
 	ifo->options |= DHCPCD_IF_UP | DHCPCD_LINK | DHCPCD_INITIAL_DELAY;
 	ifo->timeout = DEFAULT_TIMEOUT;
 	ifo->reboot = DEFAULT_REBOOT;
+	ifo->script = UNCONST(default_script);
 	ifo->metric = -1;
 	ifo->auth.options |= DHCPCD_AUTH_REQUIRE;
 	TAILQ_INIT(&ifo->routes);
@@ -2430,8 +2426,10 @@
 #ifdef INET6
 		ctx->nd_opts = ifo->nd_override;
 		ctx->nd_opts_len = ifo->nd_override_len;
+#ifdef DHCP6
 		ctx->dhcp6_opts = ifo->dhcp6_override;
 		ctx->dhcp6_opts_len = ifo->dhcp6_override_len;
+#endif
 #else
 		for (i = 0, opt = ifo->nd_override;
 		    i < ifo->nd_override_len;
@@ -2618,7 +2616,8 @@
 			free(ifo->config);
 		}
 		rt_headclear0(ctx, &ifo->routes, AF_UNSPEC);
-		free(ifo->script);
+		if (ifo->script != default_script)
+			free(ifo->script);
 		free(ifo->arping);
 		free(ifo->blacklist);
 		free(ifo->fallback);
diff -Nru dhcpcd5-7.1.0/src/if-sun.c dhcpcd5-7.2.1/src/if-sun.c
--- dhcpcd5-7.1.0/src/if-sun.c	2019-01-22 22:53:45.000000000 +0800
+++ dhcpcd5-7.2.1/src/if-sun.c	2019-04-26 21:32:54.000000000 +0800
@@ -30,6 +30,7 @@
 #include <fcntl.h>
 #include <ifaddrs.h>
 #include <libdlpi.h>
+#include <kstat.h>
 #include <stddef.h>
 #include <stdlib.h>
 #include <stropts.h>
@@ -45,6 +46,7 @@
 #include <netinet/udp.h>
 
 #include <sys/ioctl.h>
+#include <sys/mac.h>
 #include <sys/pfmod.h>
 #include <sys/tihdr.h>
 #include <sys/utsname.h>
@@ -63,6 +65,7 @@
 #include "ipv4.h"
 #include "ipv6.h"
 #include "ipv6nd.h"
+#include "logerr.h"
 #include "route.h"
 #include "sa.h"
 
@@ -71,9 +74,9 @@
 #endif
 
 #ifndef RT_ROUNDUP
-#define RT_ROUNDUP(a)							      \
-	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
-#define RT_ADVANCE(x, n) (x += RT_ROUNDUP(salen(n)))
+#define RT_ROUNDUP(a)                                                        \
+       ((a) > 0 ? (1 + (((a) - 1) | (sizeof(int32_t) - 1))) : sizeof(int32_t))
+#define RT_ADVANCE(x, n) ((x) += RT_ROUNDUP(salen((n))))
 #endif
 
 #define COPYOUT(sin, sa) do {						      \
@@ -96,6 +99,12 @@
 #endif
 };
 
+struct rtm
+{
+	struct rt_msghdr hdr;
+	char buffer[sizeof(struct sockaddr_storage) * RTAX_MAX];
+};
+
 int
 if_init(__unused struct interface *ifp)
 {
@@ -162,6 +171,63 @@
 }
 
 int
+if_carrier_os(struct interface *ifp)
+{
+	kstat_ctl_t		*kcp;
+	kstat_t			*ksp;
+	kstat_named_t		*knp;
+	link_state_t		linkstate;
+
+	kcp = kstat_open();
+	if (kcp == NULL)
+		goto err;
+	ksp = kstat_lookup(kcp, UNCONST("link"), 0, ifp->name);
+	if (ksp == NULL)
+		goto err;
+	if (kstat_read(kcp, ksp, NULL) == -1)
+		goto err;
+	knp = kstat_data_lookup(ksp, UNCONST("link_state"));
+	if (knp == NULL)
+		goto err;
+	if (knp->data_type != KSTAT_DATA_UINT32)
+		goto err;
+	linkstate = (link_state_t)knp->value.ui32;
+	kstat_close(kcp);
+
+	switch (linkstate) {
+	case LINK_STATE_UP:
+		ifp->flags |= IFF_UP;
+		return LINK_UP;
+	case LINK_STATE_DOWN:
+		return LINK_DOWN;
+	default:
+		return LINK_UNKNOWN;
+	}
+
+err:
+	if (kcp != NULL)
+		kstat_close(kcp);
+	return LINK_UNKNOWN;
+}
+
+int
+if_mtu_os(const struct interface *ifp)
+{
+	dlpi_handle_t		dh;
+	dlpi_info_t		dlinfo;
+	int			mtu;
+
+	if (dlpi_open(ifp->name, &dh, 0) != DLPI_SUCCESS)
+		return -1;
+	if (dlpi_info(dh, &dlinfo, 0) == DLPI_SUCCESS)
+		mtu = dlinfo.di_max_sdu;
+	else
+		mtu = -1;
+	dlpi_close(dh);
+	return mtu;
+}
+
+int
 if_getssid(struct interface *ifp)
 {
 
@@ -202,6 +268,7 @@
 if_newaddr(const char *ifname, void *arg)
 {
 	struct linkwalk		*lw = arg;
+	int error;
 	struct ifaddrs		*ifa;
 	dlpi_handle_t		dh;
 	dlpi_info_t		dlinfo;
@@ -210,7 +277,10 @@
 	struct sockaddr_dl	*sdl;
 
 	ifa = NULL;
-	if (dlpi_open(ifname, &dh, 0) != DLPI_SUCCESS)
+	error = dlpi_open(ifname, &dh, 0);
+	if (error == DLPI_ENOLINK) /* Just vanished or in global zone */
+		return B_FALSE;
+	if (error != DLPI_SUCCESS)
 		goto failed1;
 	if (dlpi_info(dh, &dlinfo, 0) != DLPI_SUCCESS)
 		goto failed;
@@ -251,7 +321,7 @@
 	ifa->ifa_next = lw->lw_ifa;
 	lw->lw_ifa = ifa;
 	dlpi_close(dh);
-	return (B_FALSE);
+	return B_FALSE;
 
 failed:
 	dlpi_close(dh);
@@ -262,7 +332,7 @@
 	}
 failed1:
 	lw->lw_error = errno;
-	return (B_TRUE);
+	return B_TRUE;
 }
 
 /* Creates an empty sockaddr_dl for lo0. */
@@ -357,14 +427,16 @@
 {
 	const char *cp;
 	int i;
+	const struct sockaddr **sap;
 
 	cp = data;
 	for (i = 0; i < RTAX_MAX; i++) {
+		sap = &sa[i];
 		if (type & (1 << i)) {
-			sa[i] = (const struct sockaddr *)cp;
-			RT_ADVANCE(cp, sa[i]);
+			*sap = (const struct sockaddr *)cp;
+			RT_ADVANCE(cp, *sap);
 		} else
-			sa[i] = NULL;
+			*sap = NULL;
 	}
 	return 0;
 }
@@ -448,46 +520,108 @@
 }
 
 static void
-if_finishrt(struct rt *rt)
+if_route0(struct dhcpcd_ctx *ctx, struct rtm *rtmsg,
+    unsigned char cmd, const struct rt *rt)
 {
+	struct rt_msghdr *rtm;
+	char *bp = rtmsg->buffer;
+	socklen_t sl;
+	bool gateway_unspec;
 
-	/* Solaris has a subnet route with the gateway
-	 * of the owning address.
-	 * dhcpcd has a blank gateway here to indicate a
-	 * subnet route. */
-	if (!sa_is_unspecified(&rt->rt_gateway)) {
-		switch(rt->rt_gateway.sa_family) {
-#ifdef INET
-		case AF_INET:
-		{
-			struct in_addr *in;
+	/* WARNING: Solaris will not allow you to delete RTF_KERNEL routes.
+	 * This includes subnet/prefix routes. */
 
-			in = &satosin(&rt->rt_gateway)->sin_addr;
-			if (ipv4_iffindaddr(rt->rt_ifp, in, NULL))
-				in->s_addr = INADDR_ANY;
-			break;
-		}
-#endif
-#ifdef INET6
-		case AF_INET6:
-		{
-			struct in6_addr *in6;
+#define ADDSA(sa) do {							\
+		sl = salen((sa));					\
+		memcpy(bp, (sa), sl);					\
+		bp += RT_ROUNDUP(sl);					\
+	} while (/* CONSTCOND */ 0)
 
-			in6 = &satosin6(&rt->rt_gateway)->sin6_addr;
-			if (ipv6_iffindaddr(rt->rt_ifp, in6, 0))
-				*in6 = in6addr_any;
-			break;
+	memset(rtmsg, 0, sizeof(*rtmsg));
+	rtm = &rtmsg->hdr;
+	rtm->rtm_version = RTM_VERSION;
+	rtm->rtm_type = cmd;
+	rtm->rtm_seq = ++ctx->seq;
+	rtm->rtm_flags = rt->rt_flags;
+	rtm->rtm_addrs = RTA_DST | RTA_GATEWAY;
+
+	gateway_unspec = sa_is_unspecified(&rt->rt_gateway);
+
+	if (cmd == RTM_ADD || cmd == RTM_CHANGE) {
+		bool netmask_bcast = sa_is_allones(&rt->rt_netmask);
+
+		rtm->rtm_flags |= RTF_UP;
+		if (!(rtm->rtm_flags & RTF_REJECT) &&
+		    !sa_is_loopback(&rt->rt_gateway))
+		{
+			rtm->rtm_addrs |= RTA_IFP;
+			/* RTA_IFA is currently ignored by the kernel.
+			 * RTA_SRC and RTF_SETSRC look like what we want,
+			 * but they don't work with RTF_GATEWAY.
+			 * We set RTA_IFA just in the hope that the
+			 * kernel will one day support this. */
+			if (!sa_is_unspecified(&rt->rt_ifa))
+				rtm->rtm_addrs |= RTA_IFA;
 		}
-#endif
+
+		if (netmask_bcast)
+			rtm->rtm_flags |= RTF_HOST;
+		else if (!gateway_unspec)
+			rtm->rtm_flags |= RTF_GATEWAY;
+
+		/* Emulate the kernel by marking address generated
+		 * network routes non-static. */
+		if (!(rt->rt_dflags & RTDF_IFA_ROUTE))
+			rtm->rtm_flags |= RTF_STATIC;
+
+		if (rt->rt_mtu != 0) {
+			rtm->rtm_inits |= RTV_MTU;
+			rtm->rtm_rmx.rmx_mtu = rt->rt_mtu;
 		}
 	}
 
-	/* Solaris likes to set route MTU to match
-	 * interface MTU when adding routes.
-	 * This confuses dhcpcd as it expects MTU to be 0
-	 * when no explicit MTU has been set. */
-	if (rt->rt_mtu == (unsigned int)if_getmtu(rt->rt_ifp))
-		rt->rt_mtu = 0;
+	if (!(rtm->rtm_flags & RTF_HOST))
+		rtm->rtm_addrs |= RTA_NETMASK;
+
+	ADDSA(&rt->rt_dest);
+
+	if (gateway_unspec)
+		ADDSA(&rt->rt_ifa);
+	else
+		ADDSA(&rt->rt_gateway);
+
+	if (rtm->rtm_addrs & RTA_NETMASK)
+		ADDSA(&rt->rt_netmask);
+
+	if (rtm->rtm_addrs & RTA_IFP) {
+		struct sockaddr_dl sdl;
+
+		if_linkaddr(&sdl, rt->rt_ifp);
+		ADDSA((struct sockaddr *)&sdl);
+	}
+
+	if (rtm->rtm_addrs & RTA_IFA)
+		ADDSA(&rt->rt_ifa);
+
+#if 0
+	if (rtm->rtm_addrs & RTA_SRC)
+		ADDSA(&rt->rt_ifa);
+#endif
+
+	rtm->rtm_msglen = (unsigned short)(bp - (char *)rtm);
+}
+
+int
+if_route(unsigned char cmd, const struct rt *rt)
+{
+	struct rtm rtm;
+	struct dhcpcd_ctx *ctx = rt->rt_ifp->ctx;
+
+	if_route0(ctx, &rtm, cmd, rt);
+
+	if (write(ctx->link_fd, &rtm, rtm.hdr.rtm_msglen) == -1)
+		return -1;
+	return 0;
 }
 
 static int
@@ -509,7 +643,8 @@
 	if (rt->rt_flags & RTF_GATEWAY &&
 	    rti_info[RTAX_GATEWAY]->sa_family != AF_LINK)
 		COPYSA(&rt->rt_gateway, rti_info[RTAX_GATEWAY]);
-	COPYSA(&rt->rt_ifa, rti_info[RTAX_SRC]);
+	if (rtm->rtm_addrs & RTA_SRC)
+		COPYSA(&rt->rt_ifa, rti_info[RTAX_SRC]);
 	rt->rt_mtu = (unsigned int)rtm->rtm_rmx.rmx_mtu;
 
 	if (rtm->rtm_index)
@@ -529,15 +664,111 @@
 	return 0;
 }
 
-static int
-if_addrflags0(int fd, const char *ifname)
+static struct rt *
+if_route_get(struct dhcpcd_ctx *ctx, struct rt *rt)
+{
+	struct rtm rtm;
+	int s;
+	struct iovec iov = { .iov_base = &rtm, .iov_len = sizeof(rtm) };
+	struct msghdr msg = { .msg_iov = &iov, .msg_iovlen = 1 };
+	ssize_t len;
+	struct rt *rtw = rt;
+
+	if_route0(ctx, &rtm, RTM_GET, rt);
+	rt = NULL;
+	s = socket(PF_ROUTE, SOCK_RAW | SOCK_CLOEXEC, 0);
+	if (s == -1)
+		return NULL;
+	if (write(s, &rtm, rtm.hdr.rtm_msglen) == -1)
+		goto out;
+	if ((len = recvmsg(s, &msg, 0)) == -1)
+		goto out;
+	if ((size_t)len < sizeof(rtm.hdr) || len < rtm.hdr.rtm_msglen) {
+		errno = EINVAL;
+		goto out;
+	}
+	if (if_copyrt(ctx, rtw, &rtm.hdr) == -1)
+		goto out;
+	rt = rtw;
+
+out:
+	close(s);
+	return rt;
+}
+
+static void
+if_finishrt(struct dhcpcd_ctx *ctx, struct rt *rt)
+{
+	int mtu;
+
+	/* Solaris has a subnet route with the gateway
+	 * of the owning address.
+	 * dhcpcd has a blank gateway here to indicate a
+	 * subnet route. */
+	if (!sa_is_unspecified(&rt->rt_dest) &&
+	    !sa_is_unspecified(&rt->rt_gateway))
+	{
+		switch(rt->rt_gateway.sa_family) {
+#ifdef INET
+		case AF_INET:
+		{
+			struct in_addr *in;
+
+			in = &satosin(&rt->rt_gateway)->sin_addr;
+			if (ipv4_findaddr(ctx, in))
+				in->s_addr = INADDR_ANY;
+			break;
+		}
+#endif
+#ifdef INET6
+		case AF_INET6:
+		{
+			struct in6_addr *in6;
+
+			in6 = &satosin6(&rt->rt_gateway)->sin6_addr;
+			if (ipv6_findaddr(ctx, in6, 0))
+				*in6 = in6addr_any;
+			break;
+		}
+#endif
+		}
+	}
+
+	/* Solaris doesn't set interfaces for some routes.
+	 * This sucks, so we need to call RTM_GET to
+	 * work out the interface. */
+	if (rt->rt_ifp == NULL) {
+		if (if_route_get(ctx, rt) == NULL) {
+			rt->rt_ifp = if_loopback(ctx);
+			if (rt->rt_ifp == NULL) {
+				logerr(__func__);
+				return;
+			}
+		}
+	}
+
+	/* Solaris likes to set route MTU to match
+	 * interface MTU when adding routes.
+	 * This confuses dhcpcd as it expects MTU to be 0
+	 * when no explicit MTU has been set. */
+	mtu = if_getmtu(rt->rt_ifp);
+	if (rt->rt_mtu == (unsigned int)mtu)
+		rt->rt_mtu = 0;
+}
+
+static uint64_t
+if_addrflags0(int fd, const char *ifname, const struct sockaddr *sa)
 {
 	struct lifreq		lifr;
 
 	memset(&lifr, 0, sizeof(lifr));
 	strlcpy(lifr.lifr_name, ifname, sizeof(lifr.lifr_name));
 	if (ioctl(fd, SIOCGLIFFLAGS, &lifr) == -1)
-		return -1;
+		return 0;
+	if (ioctl(fd, SIOCGLIFADDR, &lifr) == -1)
+		return 0;
+	if (sa_cmp(sa, (struct sockaddr *)&lifr.lifr_addr) != 0)
+		return 0;
 
 	return lifr.lifr_flags;
 }
@@ -581,18 +812,61 @@
 #endif
 
 	if (if_copyrt(ctx, &rt, rtm) == 0) {
-		if_finishrt(&rt);
-		rt_recvrt(rtm->rtm_type, &rt);
+		if_finishrt(ctx, &rt);
+		rt_recvrt(rtm->rtm_type, &rt, rtm->rtm_pid);
 	}
 }
 
+static bool
+if_getalias(struct interface *ifp, const struct sockaddr *sa, char *alias)
+{
+	struct ifaddrs		*ifaddrs, *ifa;
+	struct interface	*ifpx;
+	bool			found;
+
+	ifaddrs = NULL;
+	if (getallifaddrs(sa->sa_family, &ifaddrs, 0) == -1)
+		return false;
+	found = false;
+	for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
+		if (ifa->ifa_addr == NULL)
+			continue;
+		if (sa_cmp(sa, ifa->ifa_addr) != 0)
+			continue;
+		/* Check it's for the right interace. */
+		ifpx = if_find(ifp->ctx->ifaces, ifa->ifa_name);
+		if (ifp == ifpx) {
+			strlcpy(alias, ifa->ifa_name, IF_NAMESIZE);
+			found = true;
+			break;
+		}
+	}
+	freeifaddrs(ifaddrs);
+	return found;
+}
+
+static int
+if_getbrdaddr(struct dhcpcd_ctx *ctx, const char *ifname, struct in_addr *brd)
+{
+	struct lifreq lifr = { 0 };
+	int r;
+
+	memset(&lifr, 0, sizeof(lifr));
+	strlcpy(lifr.lifr_name, ifname, sizeof(lifr.lifr_name));
+	errno = 0;
+	r = ioctl(ctx->pf_inet_fd, SIOCGLIFBRDADDR, &lifr, sizeof(lifr));
+	if (r != -1)
+		COPYOUT(*brd, (struct sockaddr *)&lifr.lifr_broadaddr);
+	return r;
+}
+
 static void
 if_ifa(struct dhcpcd_ctx *ctx, const struct ifa_msghdr *ifam)
 {
 	struct interface	*ifp;
 	const struct sockaddr	*sa, *rti_info[RTAX_MAX];
 	int			flags;
-	const char		*ifalias;
+	char			ifalias[IF_NAMESIZE];
 
 	/* XXX We have no way of knowing who generated these
 	 * messages wich truely sucks because we want to
@@ -601,6 +875,7 @@
 		return;
 	sa = (const void *)(ifam + 1);
 	get_addrs(ifam->ifam_addrs, sa, rti_info);
+
 	if ((sa = rti_info[RTAX_IFA]) == NULL)
 		return;
 
@@ -617,31 +892,8 @@
 	 *   ifam_alias
 	 *   ifam_pid
 	 */
-
-	ifalias = ifp->name;
-	if (ifam->ifam_type != RTM_DELADDR && sa->sa_family != AF_LINK) {
-		struct ifaddrs	*ifaddrs, *ifa;
-
-		ifaddrs = NULL;
-		if (getallifaddrs(sa->sa_family, &ifaddrs, 0) == -1)
-			return;
-		for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
-			if (ifa->ifa_addr != NULL) {
-				if (sa_cmp(sa, ifa->ifa_addr) == 0) {
-					/* Check it's for the right interace. */
-					struct interface	*ifpx;
-
-					ifpx = if_find(ctx->ifaces,
-					    ifa->ifa_name);
-					if (ifp == ifpx) {
-						ifalias = ifa->ifa_name;
-						break;
-					}
-				}
-			}
-		}
-		freeifaddrs(ifaddrs);
-	}
+	if (ifam->ifam_type != RTM_DELADDR && !if_getalias(ifp, sa, ifalias))
+		return;
 
 	switch (sa->sa_family) {
 	case AF_LINK:
@@ -664,12 +916,25 @@
 		COPYOUT(mask, rti_info[RTAX_NETMASK]);
 		COPYOUT(bcast, rti_info[RTAX_BRD]);
 
-		if (ifam->ifam_type != RTM_DELADDR) {
-			flags = if_addrflags0(ctx->pf_inet_fd, ifalias);
-			if (flags == -1)
-				break;
-		} else
-			flags = 0;
+		if (ifam->ifam_type == RTM_DELADDR) {
+			struct ipv4_addr *ia;
+
+			ia = ipv4_iffindaddr(ifp, &addr, &mask);
+			if (ia == NULL)
+				return;
+			strlcpy(ifalias, ia->alias, sizeof(ifalias));
+		} else if (bcast.s_addr == INADDR_ANY) {
+			/* Work around a bug where broadcast
+			 * address is not correctly reported. */
+			if (if_getbrdaddr(ctx, ifalias, &bcast) == -1)
+				return;
+		}
+		flags = if_addrflags(ifp, &addr, ifalias);
+		if (ifam->ifam_type == RTM_DELADDR) {
+			if (flags != -1)
+				return;
+		} else if (flags == -1)
+			return;
 
 		ipv4_handleifa(ctx,
 		    ifam->ifam_type == RTM_CHGADDR ?
@@ -689,15 +954,20 @@
 		sin6 = (const void *)rti_info[RTAX_NETMASK];
 		mask6 = sin6->sin6_addr;
 
-		if (ifam->ifam_type != RTM_DELADDR) {
-			const struct priv	 *priv;
+		if (ifam->ifam_type == RTM_DELADDR) {
+			struct ipv6_addr	*ia;
 
-			priv = (struct priv *)ctx->priv;
-			flags = if_addrflags0(priv->pf_inet6_fd, ifalias);
-			if (flags == -1)
-				break;
-		} else
-			flags = 0;
+			ia = ipv6_iffindaddr(ifp, &addr6, 0);
+			if (ia == NULL)
+				return;
+			strlcpy(ifalias, ia->alias, sizeof(ifalias));
+		}
+		flags = if_addrflags6(ifp, &addr6, ifalias);
+		if (ifam->ifam_type == RTM_DELADDR) {
+			if (flags != -1)
+				return;
+		} else if (flags == -1)
+			return;
 
 		ipv6_handleifa(ctx,
 		    ifam->ifam_type == RTM_CHGADDR ?
@@ -714,15 +984,18 @@
 {
 	struct interface *ifp;
 	int state;
+	unsigned int flags;
 
 	if ((ifp = if_findindex(ctx->ifaces, ifm->ifm_index)) == NULL)
 		return;
-	if (ifm->ifm_flags & IFF_OFFLINE || !(ifm->ifm_flags & IFF_UP))
+	flags = (unsigned int)ifm->ifm_flags;
+	if (ifm->ifm_flags & IFF_OFFLINE)
 		state = LINK_DOWN;
-	else
+	else {
 		state = LINK_UP;
-	dhcpcd_handlecarrier(ctx, state,
-	    (unsigned int)ifm->ifm_flags, ifp->name);
+		flags |= IFF_UP;
+	}
+	dhcpcd_handlecarrier(ctx, state, flags, ifp->name);
 }
 
 static void
@@ -752,17 +1025,15 @@
 int
 if_handlelink(struct dhcpcd_ctx *ctx)
 {
-	struct msghdr msg;
+	struct rtm rtm;
+	struct iovec iov = { .iov_base = &rtm, .iov_len = sizeof(rtm) };
+	struct msghdr msg = { .msg_iov = &iov, .msg_iovlen = 1 };
 	ssize_t len;
 
-	memset(&msg, 0, sizeof(msg));
-	msg.msg_iov = ctx->iov;
-	msg.msg_iovlen = 1;
-
-	if ((len = recvmsg_realloc(ctx->link_fd, &msg, 0)) == -1)
+	if ((len = recvmsg(ctx->link_fd, &msg, 0)) == -1)
 		return -1;
 	if (len != 0)
-		if_dispatch(ctx, ctx->iov[0].iov_base);
+		if_dispatch(ctx, &rtm.hdr);
 	return 0;
 }
 
@@ -784,7 +1055,8 @@
 
 static int
 if_addaddr(int fd, const char *ifname,
-    struct sockaddr_storage *addr, struct sockaddr_storage *mask)
+    struct sockaddr_storage *addr, struct sockaddr_storage *mask,
+    struct sockaddr_storage *brd)
 {
 	struct lifreq		lifr;
 
@@ -801,6 +1073,13 @@
 	if (ioctl(fd, SIOCSLIFADDR, &lifr) == -1)
 		return -1;
 
+	/* Then assign the broadcast address. */
+	if (brd != NULL) {
+		lifr.lifr_broadaddr = *brd;
+		if (ioctl(fd, SIOCSLIFBRDADDR, &lifr) == -1)
+			return -1;
+	}
+
 	/* Now bring it up. */
 	if (ioctl(fd, SIOCGLIFFLAGS, &lifr) == -1)
 		return -1;
@@ -809,6 +1088,7 @@
 		if (ioctl(fd, SIOCSLIFFLAGS, &lifr) == -1)
 			return -1;
 	}
+
 	return 0;
 }
 
@@ -837,15 +1117,20 @@
 static int
 if_plumbif(const struct dhcpcd_ctx *ctx, int af, const char *ifname)
 {
-	dlpi_handle_t		dh;
-	int			fd, af_fd, mux_fd, retval;
+	dlpi_handle_t		dh, dh_arp = NULL;
+	int			fd, af_fd, mux_fd, arp_fd = -1, mux_id, retval;
+	uint64_t		flags;
 	struct lifreq		lifr;
 	const char		*udp_dev;
+	struct strioctl		ioc;
+	struct if_spec		spec;
+
+	if (if_nametospec(ifname, &spec) == -1)
+		return -1;
 
-	memset(&lifr, 0, sizeof(lifr));
 	switch (af) {
 	case AF_INET:
-		lifr.lifr_flags = IFF_IPV4;
+		flags = IFF_IPV4;
 		af_fd = ctx->pf_inet_fd;
 		udp_dev = UDP_DEV_NAME;
 		break;
@@ -854,7 +1139,7 @@
 		struct priv *priv;
 
 		/* We will take care of setting the link local address. */
-		lifr.lifr_flags = IFF_IPV6 | IFF_NOLINKLOCAL;
+		flags = IFF_IPV6 | IFF_NOLINKLOCAL;
 		priv = (struct priv *)ctx->priv;
 		af_fd = priv->pf_inet6_fd;
 		udp_dev = UDP6_DEV_NAME;
@@ -875,13 +1160,17 @@
 	mux_fd = -1;
 	if (ioctl(fd, I_PUSH, IP_MOD_NAME) == -1)
 		goto out;
+	memset(&lifr, 0, sizeof(lifr));
 	strlcpy(lifr.lifr_name, ifname, sizeof(lifr.lifr_name));
+	lifr.lifr_ppa = spec.ppa;
+	lifr.lifr_flags = flags;
 	if (ioctl(fd, SIOCSLIFNAME, &lifr) == -1)
 		goto out;
 
 	/* Get full flags. */
 	if (ioctl(af_fd, SIOCGLIFFLAGS, &lifr) == -1)
 		goto out;
+	flags = lifr.lifr_flags;
 
 	/* Open UDP as a multiplexor to PLINK the interface stream.
 	 * UDP is used because STREAMS will not let you PLINK a driver
@@ -893,20 +1182,49 @@
 		;
 	if (errno != EINVAL)
 		goto out;
+	if(ioctl(mux_fd, I_PUSH, ARP_MOD_NAME) == -1)
+		goto out;
 
-	if (lifr.lifr_flags & IFF_IPV4 && !(lifr.lifr_flags & IFF_NOARP)) {
-		if (ioctl(mux_fd, I_PUSH, ARP_MOD_NAME) == -1)
+	if (flags & (IFF_NOARP | IFF_IPV6)) {
+		/* PLINK the interface stream so it persists. */
+		if (ioctl(mux_fd, I_PLINK, fd) == -1)
 			goto out;
+		goto done;
 	}
 
+	if (dlpi_open(ifname, &dh_arp, DLPI_NOATTACH) != DLPI_SUCCESS)
+		goto out;
+	arp_fd = dlpi_fd(dh_arp);
+	if (ioctl(arp_fd, I_PUSH, ARP_MOD_NAME) == -1)
+		goto out;
+
+	memset(&lifr, 0, sizeof(lifr));
+	strlcpy(lifr.lifr_name, ifname, sizeof(lifr.lifr_name));
+	lifr.lifr_ppa = spec.ppa;
+	lifr.lifr_flags = flags;
+	memset(&ioc, 0, sizeof(ioc));
+	ioc.ic_cmd = SIOCSLIFNAME;
+	ioc.ic_dp = (char *)&lifr;
+	ioc.ic_len = sizeof(lifr);
+	if (ioctl(arp_fd, I_STR, &ioc) == -1)
+		goto out;
+
 	/* PLINK the interface stream so it persists. */
-	if (ioctl(mux_fd, I_PLINK, fd) == -1)
+	mux_id = ioctl(mux_fd, I_PLINK, fd);
+	if (mux_id == -1)
+		goto out;
+	if (ioctl(mux_fd, I_PLINK, arp_fd) == -1) {
+		ioctl(mux_fd, I_PUNLINK, mux_id);
 		goto out;
+	}
 
+done:
 	retval = 0;
 
 out:
 	dlpi_close(dh);
+	if (dh_arp != NULL)
+		dlpi_close(dh_arp);
 	if (mux_fd != -1)
 		close(mux_fd);
 	return retval;
@@ -915,15 +1233,11 @@
 static int
 if_unplumbif(const struct dhcpcd_ctx *ctx, int af, const char *ifname)
 {
-	struct sockaddr_storage		addr, mask;
+	struct sockaddr_storage		addr = { .ss_family = af };
 	int				fd;
 
 	/* For the time being, don't unplumb the interface, just
 	 * set the address to zero. */
-	memset(&addr, 0, sizeof(addr));
-	addr.ss_family = af;
-	memset(&mask, 0, sizeof(mask));
-	mask.ss_family = af;
 	switch (af) {
 #ifdef INET
 	case AF_INET:
@@ -944,7 +1258,8 @@
 		errno = EAFNOSUPPORT;
 		return -1;
 	}
-	return if_addaddr(fd, ifname, &addr, &mask);
+	return if_addaddr(fd, ifname, &addr, &addr,
+	    af == AF_INET ? &addr : NULL);
 }
 
 static int
@@ -962,102 +1277,6 @@
 		return if_unplumbif(ctx, af, ifname);
 }
 
-int
-if_route(unsigned char cmd, const struct rt *rt)
-{
-	struct dhcpcd_ctx *ctx;
-	struct rtm
-	{
-		struct rt_msghdr hdr;
-		char buffer[sizeof(struct sockaddr_storage) * RTAX_MAX];
-	} rtmsg;
-	struct rt_msghdr *rtm;
-	char *bp = rtmsg.buffer;
-	size_t l;
-
-	/* WARNING: Solaris will not allow you to delete RTF_KERNEL routes.
-	 * This includes subnet/prefix routes. */
-
-	ctx = rt->rt_ifp->ctx;
-
-#define ADDSA(sa) do {							      \
-		l = RT_ROUNDUP(salen((sa)));				      \
-		memcpy(bp, (sa), l);					      \
-		bp += l;						      \
-	} while (/* CONSTCOND */ 0)
-
-	memset(&rtmsg, 0, sizeof(rtmsg));
-	rtm = &rtmsg.hdr;
-	rtm->rtm_version = RTM_VERSION;
-	rtm->rtm_type = cmd;
-	rtm->rtm_seq = ++ctx->seq;
-	rtm->rtm_flags = rt->rt_flags;
-	rtm->rtm_addrs = RTA_DST | RTA_GATEWAY;
-
-	if (cmd == RTM_ADD || cmd == RTM_CHANGE) {
-		bool netmask_bcast = sa_is_allones(&rt->rt_netmask);
-
-		rtm->rtm_flags |= RTF_UP;
-		if (!(rtm->rtm_flags & RTF_REJECT) &&
-		    !sa_is_loopback(&rt->rt_gateway))
-		{
-			rtm->rtm_addrs |= RTA_IFP;
-			if (!sa_is_unspecified(&rt->rt_ifa))
-				rtm->rtm_addrs |= RTA_IFA;
-		}
-		if (netmask_bcast)
-			rtm->rtm_flags |= RTF_HOST;
-		else
-			rtm->rtm_flags |= RTF_GATEWAY;
-
-		/* Emulate the kernel by marking address generated
-		 * network routes non-static. */
-		if (!(rt->rt_dflags & RTDF_IFA_ROUTE))
-			rtm->rtm_flags |= RTF_STATIC;
-
-		if (rt->rt_mtu != 0) {
-			rtm->rtm_inits |= RTV_MTU;
-			rtm->rtm_rmx.rmx_mtu = rt->rt_mtu;
-		}
-	}
-
-	ADDSA(&rt->rt_dest);
-
-	if (sa_is_unspecified(&rt->rt_gateway))
-		ADDSA(&rt->rt_ifa);
-	else
-		ADDSA(&rt->rt_gateway);
-
-	if (rtm->rtm_addrs & RTA_NETMASK)
-		ADDSA(&rt->rt_netmask);
-
-	if (rtm->rtm_addrs & RTA_IFP) {
-		struct sockaddr_dl sdl;
-
-		if_linkaddr(&sdl, rt->rt_ifp);
-		ADDSA((struct sockaddr *)&sdl);
-	}
-
-/* This no workie :/ */
-#if 1
-	/* route(1M) says RTA_IFA is accepted but ignored
-	 * it's unclear how RTA_SRC is different. */
-	if (rtm->rtm_addrs & RTA_IFA) {
-		rtm->rtm_addrs &= ~RTA_IFA;
-		rtm->rtm_addrs |= RTA_SRC;
-	}
-	if (rtm->rtm_addrs & RTA_SRC)
-		ADDSA(&rt->rt_ifa);
-#endif
-
-#undef ADDSA
-
-	rtm->rtm_msglen = (unsigned short)(bp - (char *)rtm);
-	if (write(ctx->link_fd, rtm, rtm->rtm_msglen) == -1)
-		return -1;
-	return 0;
-}
-
 #ifdef INET
 static int
 if_walkrt(struct dhcpcd_ctx *ctx, char *data, size_t len)
@@ -1086,6 +1305,7 @@
 		default:
 			break;
 		}
+
 		memset(&rt, 0, sizeof(rt));
 		rt.rt_dflags |= RTDF_INIT;
 		in.s_addr = re->ipRouteDest;
@@ -1098,13 +1318,10 @@
 		in.s_addr = re->ipRouteInfo.re_src_addr;
 		sa_in_init(&rt.rt_ifa, &in);
 		rt.rt_mtu = re->ipRouteInfo.re_max_frag;
-
 		if_octetstr(ifname, &re->ipRouteIfIndex, sizeof(ifname));
 		rt.rt_ifp = if_find(ctx->ifaces, ifname);
-		if (rt.rt_ifp != NULL) {
-			if_finishrt(&rt);
-			rt_recvrt(RTM_ADD, &rt);
-		}
+		if_finishrt(ctx, &rt);
+		rt_recvrt(RTM_ADD, &rt, 0);
 	} while (++re < e);
 	return 0;
 }
@@ -1139,20 +1356,19 @@
 		default:
 			break;
 		}
+
 		memset(&rt, 0, sizeof(rt));
 		rt.rt_dflags |= RTDF_INIT;
 		sa_in6_init(&rt.rt_dest, &re->ipv6RouteDest);
 		ipv6_mask(&in6, re->ipv6RoutePfxLength);
 		sa_in6_init(&rt.rt_netmask, &in6);
 		sa_in6_init(&rt.rt_gateway, &re->ipv6RouteNextHop);
+		sa_in6_init(&rt.rt_ifa, &re->ipv6RouteInfo.re_src_addr);
 		rt.rt_mtu = re->ipv6RouteInfo.re_max_frag;
-
 		if_octetstr(ifname, &re->ipv6RouteIfIndex, sizeof(ifname));
 		rt.rt_ifp = if_find(ctx->ifaces, ifname);
-		if (rt.rt_ifp != NULL) {
-			if_finishrt(&rt);
-			rt_recvrt(RTM_ADD, &rt);
-		}
+		if_finishrt(ctx, &rt);
+		rt_recvrt(RTM_ADD, &rt, 0);
 	} while (++re < e);
 	return 0;
 }
@@ -1298,8 +1514,10 @@
 int
 if_address(unsigned char cmd, const struct ipv4_addr *ia)
 {
-	struct sockaddr_storage	ss_addr, ss_mask;
-	struct sockaddr_in	*sin_addr, *sin_mask;
+	union {
+		struct sockaddr		sa;
+		struct sockaddr_storage ss;
+	} addr, mask, brd;
 
 	/* Either remove the alias or ensure it exists. */
 	if (if_plumb(cmd, ia->iface->ctx, AF_INET, ia->alias) == -1)
@@ -1313,24 +1531,27 @@
 		return -1;
 	}
 
-	sin_addr = (struct sockaddr_in *)&ss_addr;
-	sin_addr->sin_family = AF_INET;
-	sin_addr->sin_addr = ia->addr;
-	sin_mask = (struct sockaddr_in *)&ss_mask;
-	sin_mask->sin_family = AF_INET;
-	sin_mask->sin_addr = ia->mask;
-	return if_addaddr(ia->iface->ctx->pf_inet_fd,
-	    ia->alias, &ss_addr, &ss_mask);
+	/* We need to update the index now */
+	ia->iface->index = if_nametoindex(ia->alias);
+
+	sa_in_init(&addr.sa, &ia->addr);
+	sa_in_init(&mask.sa, &ia->mask);
+	sa_in_init(&brd.sa, &ia->brd);
+	return if_addaddr(ia->iface->ctx->pf_inet_fd, ia->alias,
+	    &addr.ss, &mask.ss, &brd.ss);
 }
 
 int
-if_addrflags(const struct interface *ifp, __unused const struct in_addr *addr,
+if_addrflags(const struct interface *ifp, const struct in_addr *addr,
     const char *alias)
 {
-	int		flags, aflags;
-
-	aflags = if_addrflags0(ifp->ctx->pf_inet_fd, alias);
-	if (aflags == -1)
+	union sa_ss	ss;
+	uint64_t	aflags;
+	int		flags;
+
+	sa_in_init(&ss.sa, addr);
+	aflags = if_addrflags0(ifp->ctx->pf_inet_fd, alias, &ss.sa);
+	if (aflags == 0)
 		return -1;
 	flags = 0;
 	if (aflags & IFF_DUPLICATE)
@@ -1344,9 +1565,12 @@
 int
 if_address6(unsigned char cmd, const struct ipv6_addr *ia)
 {
-	struct sockaddr_storage	ss_addr, ss_mask;
-	struct sockaddr_in6	*sin6_addr, *sin6_mask;
-	struct priv		*priv;
+	union {
+		struct sockaddr		sa;
+		struct sockaddr_in6	sin6;
+		struct sockaddr_storage ss;
+	} addr, mask;
+	const struct priv		*priv;
 	int			r;
 
 	/* Either remove the alias or ensure it exists. */
@@ -1361,29 +1585,30 @@
 		return -1;
 	}
 
-	priv = (struct priv *)ia->iface->ctx->priv;
-	sin6_addr = (struct sockaddr_in6 *)&ss_addr;
-	sin6_addr->sin6_family = AF_INET6;
-	sin6_addr->sin6_addr = ia->addr;
-	sin6_mask = (struct sockaddr_in6 *)&ss_mask;
-	sin6_mask->sin6_family = AF_INET6;
-	ipv6_mask(&sin6_mask->sin6_addr, ia->prefix_len);
-	r = if_addaddr(priv->pf_inet6_fd,
-	    ia->alias, &ss_addr, &ss_mask);
+	sa_in6_init(&addr.sa, &ia->addr);
+	mask.sin6.sin6_family = AF_INET6;
+	ipv6_mask(&mask.sin6.sin6_addr, ia->prefix_len);
+	priv = (const struct priv *)ia->iface->ctx->priv;
+	r = if_addaddr(priv->pf_inet6_fd, ia->alias, &addr.ss, &mask.ss, NULL);
 	if (r == -1 && errno == EEXIST)
 		return 0;
 	return r;
 }
 
 int
-if_addrflags6(const struct interface *ifp, __unused const struct in6_addr *addr,
+if_addrflags6(const struct interface *ifp, const struct in6_addr *addr,
     const char *alias)
 {
 	struct priv		*priv;
-	int			aflags, flags;
+	union sa_ss		ss;
+	uint64_t		aflags;
+	int			flags;
 
 	priv = (struct priv *)ifp->ctx->priv;
-	aflags = if_addrflags0(priv->pf_inet6_fd, alias);
+	sa_in6_init(&ss.sa, addr);
+	aflags = if_addrflags0(priv->pf_inet6_fd, alias, &ss.sa);
+	if (aflags == 0)
+		return -1;
 	flags = 0;
 	if (aflags & IFF_DUPLICATE)
 		flags |= IN6_IFF_DUPLICATED;
@@ -1404,4 +1629,11 @@
 {
 
 }
+
+int
+ip6_forwarding(__unused const char *ifname)
+{
+
+	return 1;
+}
 #endif
diff -Nru dhcpcd5-7.1.0/src/ipv4.c dhcpcd5-7.2.1/src/ipv4.c
--- dhcpcd5-7.1.0/src/ipv4.c	2019-01-22 22:53:45.000000000 +0800
+++ dhcpcd5-7.2.1/src/ipv4.c	2019-04-26 21:32:54.000000000 +0800
@@ -200,8 +200,10 @@
 {
 	const struct dhcp_state *dstate;
 
+#ifdef IPV4LL
 	if (IPV4LL_STATE_RUNNING(ifp))
 		return 1;
+#endif
 
 	dstate = D_CSTATE(ifp);
 	return (dstate &&
@@ -425,20 +427,25 @@
 inet_getroutes(struct dhcpcd_ctx *ctx, struct rt_head *routes)
 {
 	struct interface *ifp;
+#ifdef IPV4LL
 	struct rt def;
 	bool have_default;
+#endif
 
 	TAILQ_FOREACH(ifp, ctx->ifaces, next) {
 		if (!ifp->active)
 			continue;
 		if (inet_dhcproutes(routes, ifp) == -1)
 			return false;
+#ifdef IPV4LL
 		if (ipv4ll_subnetroute(routes, ifp) == -1)
 			return false;
+#endif
 		if (inet_routerhostroute(routes, ifp) == -1)
 			return false;
 	}
 
+#ifdef IPV4LL
 	/* If there is no default route, see if we can use an IPv4LL one. */
 	memset(&def, 0, sizeof(def));
 	def.rt_dest.sa_family = AF_INET;
@@ -450,6 +457,7 @@
 				break;
 		}
 	}
+#endif
 
 	return true;
 }
@@ -555,10 +563,12 @@
 	lun = 0;
 	state = IPV4_STATE(ia->iface);
 find_lun:
-	if (lun == 0)
-		strlcpy(alias, ia->iface->name, sizeof(alias));
-	else
-		snprintf(alias, sizeof(alias), "%s:%u", ia->iface->name, lun);
+	if (if_makealias(alias, IF_NAMESIZE, ia->iface->name, lun) >=
+	    IF_NAMESIZE)
+	{
+		errno = ENOMEM;
+		return -1;
+	}
 	TAILQ_FOREACH(iap, &state->addrs, next) {
 		if (iap->alias[0] != '\0' && iap->addr.s_addr == INADDR_ANY) {
 			/* No address assigned? Lets use it. */
@@ -698,15 +708,12 @@
 		    (DHCPCD_EXITING | DHCPCD_PERSISTENT))
 		{
 			if (state->added) {
-				struct in_addr addr;
-
-				addr = lease->addr;
 				delete_address(ifp);
 				rt_build(ifp->ctx, AF_INET);
 #ifdef ARP
 				/* Announce the preferred address to
 				 * kick ARP caches. */
-				arp_announceaddr(ifp->ctx, &addr);
+				arp_announceaddr(ifp->ctx, &lease->addr);
 #endif
 			}
 			script_runreason(ifp, state->reason);
diff -Nru dhcpcd5-7.1.0/src/ipv4.h dhcpcd5-7.2.1/src/ipv4.h
--- dhcpcd5-7.1.0/src/ipv4.h	2019-01-22 22:53:45.000000000 +0800
+++ dhcpcd5-7.2.1/src/ipv4.h	2019-04-26 21:32:54.000000000 +0800
@@ -62,9 +62,8 @@
     * While it supports DaD, to seems to only expose IFF_DUPLICATE
     * so we have no way of knowing if it's tentative or not.
     * I don't even know if Solaris has any special treatment for tentative. */
-#  define IN_IFF_TENTATIVE	0
 #  define IN_IFF_DUPLICATED	0x02
-#  define IN_IFF_DETACHED	0
+#  define IN_IFF_NOTUSEABLE	IN_IFF_DUPLICATED
 #endif
 
 #ifdef IN_IFF_TENTATIVE
@@ -139,11 +138,6 @@
     int, pid_t);
 
 void ipv4_free(struct interface *);
-#else
-#define ipv4_sortinterfaces(a) {}
-#define ipv4_applyaddr(a) {}
-#define ipv4_free(a) {}
-#define ipv4_hasaddr(a) (0)
-#endif
+#endif /* INET */
 
-#endif
+#endif /* IPV4_H */
diff -Nru dhcpcd5-7.1.0/src/ipv4ll.c dhcpcd5-7.2.1/src/ipv4ll.c
--- dhcpcd5-7.1.0/src/ipv4ll.c	2019-01-22 22:53:45.000000000 +0800
+++ dhcpcd5-7.2.1/src/ipv4ll.c	2019-04-26 21:32:54.000000000 +0800
@@ -232,7 +232,7 @@
 ipv4ll_probe(void *arg)
 {
 
-#ifdef IN_IFF_TENTATIVE
+#ifdef IN_IFF_DUPLICATED
 	ipv4ll_probed(arg);
 #else
 	arp_probe(arg);
@@ -305,6 +305,8 @@
 		ipv4_deladdr(state->addr, 1);
 		state->down = 1;
 		state->addr = NULL;
+		if_initrt(ifp->ctx, AF_INET);
+		rt_build(ifp->ctx, AF_INET);
 		script_runreason(ifp, "IPV4LL");
 	}
 
@@ -402,7 +404,7 @@
 	if (ia == NULL)
 		ia = ipv4_iffindlladdr(ifp);
 
-#ifdef IN_IFF_TENTATIVE
+#ifdef IN_IFF_DUPLICATED
 	if (ia != NULL && ia->addr_flags & IN_IFF_DUPLICATED) {
 		ipv4_deladdr(ia, 0);
 		ia = NULL;
@@ -417,6 +419,8 @@
 			    ifp->name, inet_ntoa(ia->addr));
 			return;
 		}
+#endif
+#ifdef IN_IFF_DUPLICATED
 		loginfox("%s: using IPv4LL address %s", ifp->name, ia->saddr);
 #endif
 		ipv4ll_probed(astate);
@@ -427,7 +431,7 @@
 	if (state->pickedaddr.s_addr == INADDR_ANY)
 		state->pickedaddr.s_addr = ipv4ll_pickaddr(astate);
 	astate->addr = state->pickedaddr;
-#ifdef IN_IFF_TENTATIVE
+#ifdef IN_IFF_DUPLICATED
 	ipv4ll_probed(astate);
 #else
 	arp_probe(astate);
diff -Nru dhcpcd5-7.1.0/src/ipv4ll.h dhcpcd5-7.2.1/src/ipv4ll.h
--- dhcpcd5-7.1.0/src/ipv4ll.h	2019-01-22 22:53:45.000000000 +0800
+++ dhcpcd5-7.2.1/src/ipv4ll.h	2019-04-26 21:32:54.000000000 +0800
@@ -71,12 +71,6 @@
 void ipv4ll_reset(struct interface *);
 void ipv4ll_drop(struct interface *);
 void ipv4ll_free(struct interface *);
-#else
-#define	IPV4LL_STATE_RUNNING(ifp)	(0)
-#define	ipv4ll_subnetroute(route, ifp)	(0)
-#define	ipv4ll_defaultroute(route, ifp)	(0)
-#define	ipv4ll_handlert(a, b, c)	(0)
-#define	ipv4ll_free(a)			{}
 #endif
 
 #endif
diff -Nru dhcpcd5-7.1.0/src/ipv6.c dhcpcd5-7.2.1/src/ipv6.c
--- dhcpcd5-7.1.0/src/ipv6.c	2019-01-22 22:53:45.000000000 +0800
+++ dhcpcd5-7.2.1/src/ipv6.c	2019-04-26 21:32:54.000000000 +0800
@@ -30,6 +30,7 @@
 #include <sys/socket.h>
 #include <sys/stat.h>
 
+#include <arpa/inet.h>
 #include <net/if.h>
 #include <net/route.h>
 #include <netinet/in.h>
@@ -128,30 +129,17 @@
 ipv6_init(struct dhcpcd_ctx *ctx)
 {
 
-	if (ctx->sndhdr.msg_iovlen == 1)
+	if (ctx->ra_routers != NULL)
 		return 0;
 
-	if (ctx->ra_routers == NULL) {
-		ctx->ra_routers = malloc(sizeof(*ctx->ra_routers));
-		if (ctx->ra_routers == NULL)
-			return -1;
-	}
+	ctx->ra_routers = malloc(sizeof(*ctx->ra_routers));
+	if (ctx->ra_routers == NULL)
+		return -1;
 	TAILQ_INIT(ctx->ra_routers);
 
-	ctx->sndhdr.msg_namelen = sizeof(struct sockaddr_in6);
-	ctx->sndhdr.msg_iov = ctx->sndiov;
-	ctx->sndhdr.msg_iovlen = 1;
-	ctx->sndhdr.msg_control = ctx->sndbuf;
-	ctx->sndhdr.msg_controllen = sizeof(ctx->sndbuf);
-	ctx->rcvhdr.msg_name = &ctx->from;
-	ctx->rcvhdr.msg_namelen = sizeof(ctx->from);
-	ctx->rcvhdr.msg_iov = ctx->iov;
-	ctx->rcvhdr.msg_iovlen = 1;
-	ctx->rcvhdr.msg_control = ctx->ctlbuf;
-	// controllen is set at recieve
-	//ctx->rcvhdr.msg_controllen = sizeof(ctx->rcvbuf);
-
+#ifndef __sun
 	ctx->nd_fd = -1;
+#endif
 	ctx->dhcp6_fd = -1;
 	return 0;
 }
@@ -638,6 +626,10 @@
 	uint32_t pltime, vltime;
 	bool vltime_was_zero;
 	__printflike(1, 2) void (*logfunc)(const char *, ...);
+#ifdef __sun
+	struct ipv6_state *state;
+	struct ipv6_addr *ia2;
+#endif
 
 	/* Remember the interface of the address. */
 	ifp = ia->iface;
@@ -773,13 +765,13 @@
 }
 
 #ifdef ALIAS_ADDR
-/* Find the next logical aliase address we can use. */
+/* Find the next logical alias address we can use. */
 static int
 ipv6_aliasaddr(struct ipv6_addr *ia, struct ipv6_addr **repl)
 {
 	struct ipv6_state *state;
 	struct ipv6_addr *iap;
-	unsigned int unit;
+	unsigned int lun;
 	char alias[IF_NAMESIZE];
 
 	if (ia->alias[0] != '\0')
@@ -798,12 +790,14 @@
 		}
 	}
 
-	unit = 0;
+	lun = 0;
 find_unit:
-	if (unit == 0)
-		strlcpy(alias, ia->iface->name, sizeof(alias));
-	else
-		snprintf(alias, sizeof(alias), "%s:%u", ia->iface->name, unit);
+	if (if_makealias(alias, IF_NAMESIZE, ia->iface->name, lun) >=
+	    IF_NAMESIZE)
+	{
+		errno = ENOMEM;
+		return -1;
+	}
 	TAILQ_FOREACH(iap, &state->addrs, next) {
 		if (iap->alias[0] == '\0')
 			continue;
@@ -819,11 +813,11 @@
 	}
 
 	if (iap != NULL) {
-		if (unit == UINT_MAX) {
+		if (lun == UINT_MAX) {
 			errno = ERANGE;
 			return -1;
 		}
-		unit++;
+		lun++;
 		goto find_unit;
 	}
 
@@ -882,10 +876,14 @@
 struct ipv6_addr *
 ipv6_findaddr(struct dhcpcd_ctx *ctx, const struct in6_addr *addr, unsigned int flags)
 {
-	struct ipv6_addr *dap, *nap;
+	struct ipv6_addr *nap;
+#ifdef DHCP6
+	struct ipv6_addr *dap;
+#endif
 
-	dap = dhcp6_findaddr(ctx, addr, flags);
 	nap = ipv6nd_findaddr(ctx, addr, flags);
+#ifdef DHCP6
+	dap = dhcp6_findaddr(ctx, addr, flags);
 	if (!dap && !nap)
 		return NULL;
 	if (dap && !nap)
@@ -895,6 +893,9 @@
 	if (nap->iface->metric < dap->iface->metric)
 		return nap;
 	return dap;
+#else
+	return nap;
+#endif
 }
 
 ssize_t
@@ -1183,8 +1184,10 @@
 
 	if (ipv6nd_iffindaddr(ifp, NULL, 0) != NULL)
 		return 1;
+#ifdef DHCP6
 	if (dhcp6_iffindaddr(ifp, NULL, 0) != NULL)
 		return 1;
+#endif
 	return 0;
 }
 
@@ -2269,6 +2272,7 @@
 	return 0;
 }
 
+#ifdef DHCP6
 static int
 inet6_dhcproutes(struct rt_head *routes, struct dhcpcd_ctx *ctx,
     enum DH6S dstate)
@@ -2292,6 +2296,7 @@
 	}
 	return 0;
 }
+#endif
 
 bool
 inet6_getroutes(struct dhcpcd_ctx *ctx, struct rt_head *routes)
@@ -2307,6 +2312,7 @@
 	if (inet6_raroutes(routes, ctx, 0, &have_default) == -1)
 		return false;
 
+#ifdef DHCP6
 	/* We have no way of knowing if prefixes added by DHCP are reachable
 	 * or not, so we have to assume they are.
 	 * Add bound before delegated so we can prefer interfaces better */
@@ -2314,6 +2320,7 @@
 		return false;
 	if (inet6_dhcproutes(routes, ctx, DH6S_DELEGATED) == -1)
 		return false;
+#endif
 
 #ifdef HAVE_ROUTE_METRIC
 	/* If we have an unreachable router, we really do need to remove the
diff -Nru dhcpcd5-7.1.0/src/ipv6.h dhcpcd5-7.2.1/src/ipv6.h
--- dhcpcd5-7.1.0/src/ipv6.h	2019-01-22 22:53:45.000000000 +0800
+++ dhcpcd5-7.2.1/src/ipv6.h	2019-04-26 21:32:54.000000000 +0800
@@ -44,9 +44,6 @@
 #  endif
 #endif
 
-#define	ALLNODES		"ff02::1"
-#define	ALLROUTERS		"ff02::2"
-
 #define EUI64_GBIT		0x01
 #define EUI64_UBIT		0x02
 #define EUI64_TO_IFID(in6)	do {(in6)->s6_addr[8] ^= EUI64_UBIT; } while (0)
@@ -77,6 +74,17 @@
 	(((d)->s6_addr32[3] ^ (a)->s6_addr32[3]) & (m)->s6_addr32[3]) == 0 )
 #endif
 
+#ifndef IN6ADDR_LINKLOCAL_ALLNODES_INIT
+#define	IN6ADDR_LINKLOCAL_ALLNODES_INIT				\
+	{{{ 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	\
+	    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }}}
+#endif
+#ifndef IN6ADDR_LINKLOCAL_ALLROUTERS_INIT
+#define	IN6ADDR_LINKLOCAL_ALLROUTERS_INIT			\
+	{{{ 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	\
+	    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 }}}
+#endif
+
 /*
  * BSD kernels don't inform userland of DAD results.
  * See the discussion here:
@@ -140,6 +148,7 @@
 #  define IN6_IFF_DETACHED	0
 #endif
 
+#ifdef INET6
 TAILQ_HEAD(ipv6_addrhead, ipv6_addr);
 struct ipv6_addr {
 	TAILQ_ENTRY(ipv6_addr) next;
@@ -223,7 +232,6 @@
 	((const struct ipv6_state *)(ifp)->if_data[IF_DATA_IPV6])
 #define IPV6_STATE_RUNNING(ifp) ipv6_staticdadcompleted((ifp))
 
-#ifdef INET6
 
 int ipv6_init(struct dhcpcd_ctx *);
 int ipv6_makestableprivate(struct in6_addr *addr,
@@ -282,16 +290,6 @@
 ssize_t ipv6_env(char **, const char *, const struct interface *);
 void ipv6_ctxfree(struct dhcpcd_ctx *);
 bool inet6_getroutes(struct dhcpcd_ctx *, struct rt_head *);
+#endif /* INET6 */
 
-#else
-#define ipv6_start(a) (-1)
-#define ipv6_startstatic(a)
-#define ipv6_staticdadcompleted(a) (0)
-#define ipv6_hasaddr(a) (0)
-#define ipv6_free_ll_callbacks(a) {}
-#define ipv6_free(a) {}
-#define ipv6_ctxfree(a) {}
-#define ipv6_gentempifid(a) {}
-#endif
-
-#endif
+#endif /* INET6_H */
diff -Nru dhcpcd5-7.1.0/src/ipv6nd.c dhcpcd5-7.2.1/src/ipv6nd.c
--- dhcpcd5-7.1.0/src/ipv6nd.c	2019-01-22 22:53:45.000000000 +0800
+++ dhcpcd5-7.2.1/src/ipv6nd.c	2019-04-26 21:32:54.000000000 +0800
@@ -45,6 +45,7 @@
 #define ELOOP_QUEUE 3
 #include "common.h"
 #include "dhcpcd.h"
+#include "dhcp-common.h"
 #include "dhcp6.h"
 #include "eloop.h"
 #include "if.h"
@@ -189,54 +190,106 @@
 }
 
 static int
-ipv6nd_open(struct dhcpcd_ctx *ctx)
+ipv6nd_open0(void)
 {
-	int on;
+	int s, on;
 	struct icmp6_filter filt;
 
-	if (ctx->nd_fd != -1)
-		return ctx->nd_fd;
 #define SOCK_FLAGS	SOCK_CLOEXEC | SOCK_NONBLOCK
-	ctx->nd_fd = xsocket(PF_INET6, SOCK_RAW | SOCK_FLAGS, IPPROTO_ICMPV6);
+	s = xsocket(PF_INET6, SOCK_RAW | SOCK_FLAGS, IPPROTO_ICMPV6);
 #undef SOCK_FLAGS
-	if (ctx->nd_fd == -1)
+	if (s == -1)
 		return -1;
 
 	/* RFC4861 4.1 */
 	on = 255;
-	if (setsockopt(ctx->nd_fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
-	    &on, sizeof(on)) == -1)
-		goto eexit;
-
-	on = 1;
-	if (setsockopt(ctx->nd_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO,
+	if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
 	    &on, sizeof(on)) == -1)
 		goto eexit;
 
 	on = 1;
-	if (setsockopt(ctx->nd_fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT,
+	if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVHOPLIMIT,
 	    &on, sizeof(on)) == -1)
 		goto eexit;
 
 	ICMP6_FILTER_SETBLOCKALL(&filt);
 	ICMP6_FILTER_SETPASS(ND_NEIGHBOR_ADVERT, &filt);
 	ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt);
-	if (setsockopt(ctx->nd_fd, IPPROTO_ICMPV6, ICMP6_FILTER,
+	if (setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER,
 	    &filt, sizeof(filt)) == -1)
 		goto eexit;
 
-	eloop_event_add(ctx->eloop, ctx->nd_fd,  ipv6nd_handledata, ctx);
-	return ctx->nd_fd;
+	return s;
 
 eexit:
-	if (ctx->nd_fd != -1) {
-		eloop_event_delete(ctx->eloop, ctx->nd_fd);
-		close(ctx->nd_fd);
-		ctx->nd_fd = -1;
-	}
+	close(s);
 	return -1;
 }
 
+#ifdef __sun
+static int
+ipv6nd_open(struct interface *ifp)
+{
+	int s;
+	struct ipv6_mreq mreq = {
+	    .ipv6mr_multiaddr = IN6ADDR_LINKLOCAL_ALLNODES_INIT,
+	    .ipv6mr_interface = ifp->index
+	};
+	struct rs_state *state = RS_STATE(ifp);
+	uint_t ifindex = ifp->index;
+
+	if (state->nd_fd != -1)
+		return state->nd_fd;
+
+	s = ipv6nd_open0();
+	if (s == -1)
+		return -1;
+
+	if (setsockopt(s, IPPROTO_IPV6, IPV6_BOUND_IF,
+	    &ifindex, sizeof(ifindex)) == -1)
+	{
+		close(s);
+		return -1;
+	}
+
+	if (setsockopt(s, IPPROTO_IPV6, IPV6_JOIN_GROUP,
+	    &mreq, sizeof(mreq)) == -1)
+	{
+		close(s);
+		return -1;
+	}
+
+	state->nd_fd = s;
+	eloop_event_add(ifp->ctx->eloop, s, ipv6nd_handledata, ifp);
+	return s;
+}
+#else
+static int
+ipv6nd_open(struct dhcpcd_ctx *ctx)
+{
+	int s, on;
+
+	if (ctx->nd_fd != -1)
+		return ctx->nd_fd;
+
+	s = ipv6nd_open0();
+	if (s == -1)
+		return -1;
+
+	on = 1;
+	if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO,
+	    &on, sizeof(on)) == -1)
+	{
+		close(s);
+		return -1;
+	}
+
+	ctx->nd_fd = s;
+	eloop_event_add(ctx->eloop, s, ipv6nd_handledata, ctx);
+	return s;
+}
+#endif
+
 static int
 ipv6nd_makersprobe(struct interface *ifp)
 {
@@ -272,11 +325,22 @@
 ipv6nd_sendrsprobe(void *arg)
 {
 	struct interface *ifp = arg;
-	struct dhcpcd_ctx *ctx;
-	struct rs_state *state;
-	struct sockaddr_in6 dst;
+	struct rs_state *state = RS_STATE(ifp);
+	struct sockaddr_in6 dst = {
+		.sin6_family = AF_INET6,
+		.sin6_addr = IN6ADDR_LINKLOCAL_ALLROUTERS_INIT,
+		.sin6_scope_id = ifp->index,
+	};
+	struct iovec iov = { .iov_base = state->rs, .iov_len = state->rslen };
+	unsigned char ctl[CMSG_SPACE(sizeof(struct in6_pktinfo))] = { 0 };
+	struct msghdr msg = {
+	    .msg_name = &dst, .msg_namelen = sizeof(dst),
+	    .msg_iov = &iov, .msg_iovlen = 1,
+	    .msg_control = ctl, .msg_controllen = sizeof(ctl),
+	};
 	struct cmsghdr *cm;
-	struct in6_pktinfo pi;
+	struct in6_pktinfo pi = { .ipi6_ifindex = ifp->index };
+	int s;
 
 	if (ipv6_linklocal(ifp) == NULL) {
 		logdebugx("%s: delaying Router Solicitation for LL address",
@@ -285,36 +349,26 @@
 		return;
 	}
 
-	memset(&dst, 0, sizeof(dst));
-	dst.sin6_family = AF_INET6;
 #ifdef HAVE_SA_LEN
 	dst.sin6_len = sizeof(dst);
 #endif
-	dst.sin6_scope_id = ifp->index;
-	if (inet_pton(AF_INET6, ALLROUTERS, &dst.sin6_addr) != 1) {
-		logerr(__func__);
-		return;
-	}
-
-	state = RS_STATE(ifp);
-	ctx = ifp->ctx;
-	ctx->sndhdr.msg_name = (void *)&dst;
-	ctx->sndhdr.msg_iov[0].iov_base = state->rs;
-	ctx->sndhdr.msg_iov[0].iov_len = state->rslen;
 
 	/* Set the outbound interface */
-	cm = CMSG_FIRSTHDR(&ctx->sndhdr);
+	cm = CMSG_FIRSTHDR(&msg);
 	if (cm == NULL) /* unlikely */
 		return;
 	cm->cmsg_level = IPPROTO_IPV6;
 	cm->cmsg_type = IPV6_PKTINFO;
 	cm->cmsg_len = CMSG_LEN(sizeof(pi));
-	memset(&pi, 0, sizeof(pi));
-	pi.ipi6_ifindex = ifp->index;
 	memcpy(CMSG_DATA(cm), &pi, sizeof(pi));
 
 	logdebugx("%s: sending Router Solicitation", ifp->name);
-	if (sendmsg(ctx->nd_fd, &ctx->sndhdr, 0) == -1) {
+#ifdef __sun
+	s = state->nd_fd;
+#else
+	s = ifp->ctx->nd_fd;
+#endif
+	if (sendmsg(s, &msg, 0) == -1) {
 		logerr(__func__);
 		/* Allow IPv6ND to continue .... at most a few errors
 		 * would be logged.
@@ -328,7 +382,9 @@
 	else {
 		logwarnx("%s: no IPv6 Routers available", ifp->name);
 		ipv6nd_drop(ifp);
+#ifdef DHCP6
 		dhcp6_dropnondelegates(ifp);
+#endif
 	}
 }
 
@@ -338,42 +394,51 @@
 	struct ipv6_addr *ia = arg;
 	struct interface *ifp = ia->iface;
 	struct dhcpcd_ctx *ctx = ifp->ctx;
-	struct sockaddr_in6 dst;
+	struct sockaddr_in6 dst = {
+	    .sin6_family = AF_INET6,
+	    .sin6_addr = IN6ADDR_LINKLOCAL_ALLNODES_INIT,
+	    .sin6_scope_id = ifp->index,
+	};
+	struct iovec iov = { .iov_base = ia->na, .iov_len = ia->na_len };
+	unsigned char ctl[CMSG_SPACE(sizeof(struct in6_pktinfo))] = { 0 };
+	struct msghdr msg = {
+	    .msg_name = &dst, .msg_namelen = sizeof(dst),
+	    .msg_iov = &iov, .msg_iovlen = 1,
+	    .msg_control = ctl, .msg_controllen = sizeof(ctl),
+	};
 	struct cmsghdr *cm;
-	struct in6_pktinfo pi;
+	struct in6_pktinfo pi = { .ipi6_ifindex = ifp->index };
 	const struct rs_state *state = RS_CSTATE(ifp);
+	int s;
 
-	if (state == NULL || ifp->carrier == LINK_DOWN)
+	if (state == NULL || ifp->carrier <= LINK_DOWN)
 		goto freeit;
 
-	memset(&dst, 0, sizeof(dst));
-	dst.sin6_family = AF_INET6;
 #ifdef SIN6_LEN
 	dst.sin6_len = sizeof(dst);
 #endif
-	dst.sin6_scope_id = ifp->index;
-	if (inet_pton(AF_INET6, ALLNODES, &dst.sin6_addr) != 1) {
-		logerr(__func__);
-		return;
-	}
-
-	ctx->sndhdr.msg_name = (void *)&dst;
-	ctx->sndhdr.msg_iov[0].iov_base = ia->na;
-	ctx->sndhdr.msg_iov[0].iov_len = ia->na_len;
 
 	/* Set the outbound interface. */
-	cm = CMSG_FIRSTHDR(&ctx->sndhdr);
+	cm = CMSG_FIRSTHDR(&msg);
 	assert(cm != NULL);
 	cm->cmsg_level = IPPROTO_IPV6;
 	cm->cmsg_type = IPV6_PKTINFO;
 	cm->cmsg_len = CMSG_LEN(sizeof(pi));
-	memset(&pi, 0, sizeof(pi));
-	pi.ipi6_ifindex = ifp->index;
 	memcpy(CMSG_DATA(cm), &pi, sizeof(pi));
-
 	logdebugx("%s: sending NA for %s", ifp->name, ia->saddr);
-	if (sendmsg(ctx->nd_fd, &ctx->sndhdr, 0) == -1)
+#ifdef __sun
+	s = state->nd_fd;
+#else
+	s = ctx->nd_fd;
+#endif
+	if (sendmsg(s, &msg, 0) == -1)
+#ifdef __OpenBSD__
+/* This isn't too critical as they don't support IPv6 address sharing */
+#warning Cannot send NA messages on OpenBSD
+		logdebug(__func__);
+#else
 		logerr(__func__);
+#endif
 
 	if (++ia->na_count < MAX_NEIGHBOR_ADVERTISEMENT) {
 		eloop_timeout_add_sec(ctx->eloop,
@@ -405,7 +470,7 @@
 	iaf = NULL;
 	TAILQ_FOREACH(ifp, ctx->ifaces, next) {
 		state = IPV6_STATE(ifp);
-		if (state == NULL || ifp->carrier == LINK_DOWN)
+		if (state == NULL || ifp->carrier <= LINK_DOWN)
 			continue;
 
 		TAILQ_FOREACH(iap, &state->addrs, next) {
@@ -616,6 +681,11 @@
 	if (state == NULL)
 		return 0;
 
+	ctx = ifp->ctx;
+#ifdef __sun
+	eloop_event_delete(ctx->eloop, state->nd_fd);
+	close(state->nd_fd);
+#endif
 	free(state->rs);
 	free(state);
 	ifp->if_data[IF_DATA_IPV6ND] = NULL;
@@ -627,9 +697,9 @@
 		}
 	}
 
+#ifndef __sun
 	/* If we don't have any more IPv6 enabled interfaces,
 	 * close the global socket and release resources */
-	ctx = ifp->ctx;
 	TAILQ_FOREACH(ifp, ctx->ifaces, next) {
 		if (RS_STATE(ifp))
 			break;
@@ -641,6 +711,7 @@
 			ctx->nd_fd = -1;
 		}
 	}
+#endif
 
 	return n;
 }
@@ -855,7 +926,10 @@
 #ifndef DHCP6
 /* If DHCPv6 is compiled out, supply a shim to provide an error message
  * if IPv6RA requests DHCPv6. */
-#undef dhcp6_start
+enum DH6S {
+	DH6S_REQUEST,
+	DH6S_INFORM,
+};
 static int
 dhcp6_start(__unused struct interface *ifp, __unused enum DH6S init_state)
 {
@@ -866,8 +940,9 @@
 #endif
 
 static void
-ipv6nd_handlera(struct dhcpcd_ctx *ctx, struct interface *ifp,
-    struct icmp6_hdr *icp, size_t len, int hoplimit)
+ipv6nd_handlera(struct dhcpcd_ctx *ctx,
+    const struct sockaddr_in6 *from, const char *sfrom,
+    struct interface *ifp, struct icmp6_hdr *icp, size_t len, int hoplimit)
 {
 	size_t i, olen;
 	struct nd_router_advert *nd_ra;
@@ -889,33 +964,29 @@
 
 	if (ifp == NULL) {
 #ifdef DEBUG_RS
-		logdebugx("RA for unexpected interface from %s",
-		    ctx->sfrom);
+		logdebugx("RA for unexpected interface from %s", sfrom);
 #endif
 		return;
 	}
 
 	if (len < sizeof(struct nd_router_advert)) {
-		logerrx("IPv6 RA packet too short from %s", ctx->sfrom);
+		logerrx("IPv6 RA packet too short from %s", sfrom);
 		return;
 	}
 
 	/* RFC 4861 7.1.2 */
 	if (hoplimit != 255) {
-		logerrx("invalid hoplimit(%d) in RA from %s",
-		    hoplimit, ctx->sfrom);
+		logerrx("invalid hoplimit(%d) in RA from %s", hoplimit, sfrom);
 		return;
 	}
-
-	if (!IN6_IS_ADDR_LINKLOCAL(&ctx->from.sin6_addr)) {
-		logerrx("RA from non local address %s", ctx->sfrom);
+	if (!IN6_IS_ADDR_LINKLOCAL(&from->sin6_addr)) {
+		logerrx("RA from non local address %s", sfrom);
 		return;
 	}
 
 	if (!(ifp->options->options & DHCPCD_IPV6RS)) {
 #ifdef DEBUG_RS
-		logerrx("%s: unexpected RA from %s",
-		    ifp->name, ctx->sfrom);
+		logerrx("%s: unexpected RA from %s", ifp->name, sfrom);
 #endif
 		return;
 	}
@@ -924,20 +995,20 @@
 	if (ipv6_linklocal(ifp) == NULL) {
 #ifdef DEBUG_RS
 		logdebugx("%s: received RA from %s (no link-local)",
-		    ifp->name, ctx->sfrom);
+		    ifp->name, sfrom);
 #endif
 		return;
 	}
 
-	if (ipv6_iffindaddr(ifp, &ctx->from.sin6_addr, IN6_IFF_TENTATIVE)) {
+	if (ipv6_iffindaddr(ifp, &from->sin6_addr, IN6_IFF_TENTATIVE)) {
 		logdebugx("%s: ignoring RA from ourself %s",
-		    ifp->name, ctx->sfrom);
+		    ifp->name, sfrom);
 		return;
 	}
 
 	TAILQ_FOREACH(rap, ctx->ra_routers, next) {
 		if (ifp == rap->iface &&
-		    IN6_ARE_ADDR_EQUAL(&rap->from, &ctx->from.sin6_addr))
+		    IN6_ARE_ADDR_EQUAL(&rap->from, &from->sin6_addr))
 			break;
 	}
 
@@ -962,8 +1033,8 @@
 			return;
 		}
 		rap->iface = ifp;
-		rap->from = ctx->from.sin6_addr;
-		strlcpy(rap->sfrom, ctx->sfrom, sizeof(rap->sfrom));
+		rap->from = from->sin6_addr;
+		strlcpy(rap->sfrom, sfrom, sizeof(rap->sfrom));
 		TAILQ_INIT(&rap->addrs);
 		new_rap = true;
 	} else
@@ -985,8 +1056,7 @@
 	 * in accordance with the own prefix times which would result in too
 	 * much needless log spam. */
 	logfunc = new_rap ? loginfox : logdebugx,
-	logfunc("%s: Router Advertisement from %s",
-	    ifp->name, ctx->sfrom);
+	logfunc("%s: Router Advertisement from %s", ifp->name, rap->sfrom);
 
 	clock_gettime(CLOCK_MONOTONIC, &rap->acquired);
 	rap->flags = nd_ra->nd_ra_flags_reserved;
@@ -1047,10 +1117,10 @@
 			}
 			if (dho != NULL)
 				logwarnx("%s: reject RA (option %s) from %s",
-				    ifp->name, dho->var, ctx->sfrom);
+				    ifp->name, dho->var, rap->sfrom);
 			else
 				logwarnx("%s: reject RA (option %d) from %s",
-				    ifp->name, ndo.nd_opt_type, ctx->sfrom);
+				    ifp->name, ndo.nd_opt_type, rap->sfrom);
 			if (new_rap)
 				ipv6nd_removefreedrop_ra(rap, 0, 0);
 			else
@@ -1190,7 +1260,7 @@
 		    dho->option))
 		{
 			logwarnx("%s: reject RA (no option %s) from %s",
-			    ifp->name, dho->var, ctx->sfrom);
+			    ifp->name, dho->var, rap->sfrom);
 			if (new_rap)
 				ipv6nd_removefreedrop_ra(rap, 0, 0);
 			else
@@ -1239,8 +1309,10 @@
 		if (new_data && dhcp6_start(ifp, DH6S_INFORM) == -1)
 			LOG_DHCP6("dhcp6_start: %s", ifp->name);
 	} else {
+#ifdef DHCP6
 		if (new_data)
 			logdebugx("%s: No DHCPv6 instruction in RA", ifp->name);
+#endif
 nodhcp6:
 		if (ifp->ctx->options & DHCPCD_TEST) {
 			eloop_exit(ifp->ctx->eloop, EXIT_SUCCESS);
@@ -1451,19 +1523,21 @@
 	struct interface *ifp;
 	struct ra *rap, *ran;
 	struct timespec now, lt, expire, next;
-	uint8_t expired, anyvalid, valid, validone;
+	bool expired, valid, validone;
 	struct ipv6_addr *ia;
+#ifdef DHCP6
+	bool anyvalid = false;
+#endif
 
 	ifp = arg;
 	clock_gettime(CLOCK_MONOTONIC, &now);
-	expired = 0;
+	expired = false;
 	timespecclear(&next);
 
-	anyvalid = 0;
 	TAILQ_FOREACH_SAFE(rap, ifp->ctx->ra_routers, next, ran) {
 		if (rap->iface != ifp)
 			continue;
-		valid = validone = 0;
+		valid = validone = false;
 		if (rap->lifetime) {
 			lt.tv_sec = (time_t)rap->lifetime;
 			lt.tv_nsec = 0;
@@ -1477,7 +1551,7 @@
 					rap->lifetime = 0;
 				}
 			} else {
-				valid = 1;
+				valid = true;
 				timespecsub(&expire, &now, &lt);
 				if (!timespecisset(&next) ||
 				    timespeccmp(&next, &lt, >))
@@ -1492,7 +1566,7 @@
 			if (ia->prefix_vltime == 0)
 				continue;
 			if (ia->prefix_vltime == ND6_INFINITE_LIFETIME) {
-				validone = 1;
+				validone = true;
 				continue;
 			}
 			lt.tv_sec = (time_t)ia->prefix_vltime;
@@ -1510,13 +1584,13 @@
 				ia->prefix_vltime = ia->prefix_pltime = 0;
 				ia->flags &=
 				    ~(IPV6_AF_ADDED | IPV6_AF_DADCOMPLETED);
-				expired = 1;
+				expired = true;
 			} else {
 				timespecsub(&expire, &now, &lt);
 				if (!timespecisset(&next) ||
 				    timespeccmp(&next, &lt, >))
 					next = lt;
-				validone = 1;
+				validone = true;
 			}
 		}
 
@@ -1529,8 +1603,10 @@
 		 * as well punt it. */
 		if (!valid && !validone)
 			ipv6nd_free_ra(rap);
+#ifdef DHCP6
 		else
-			anyvalid = 1;
+			anyvalid = true;
+#endif
 	}
 
 	if (timespecisset(&next))
@@ -1541,9 +1617,11 @@
 		script_runreason(ifp, "ROUTERADVERT");
 	}
 
+#ifdef DHCP6
 	/* No valid routers? Kill any DHCPv6. */
 	if (!anyvalid)
 		dhcp6_dropnondelegates(ifp);
+#endif
 }
 
 void
@@ -1570,8 +1648,8 @@
 }
 
 static void
-ipv6nd_handlena(struct dhcpcd_ctx *ctx, struct interface *ifp,
-    struct icmp6_hdr *icp, size_t len, int hoplimit)
+ipv6nd_handlena(struct dhcpcd_ctx *ctx, const char *sfrom,
+    struct interface *ifp, struct icmp6_hdr *icp, size_t len, int hoplimit)
 {
 	struct nd_neighbor_advert *nd_na;
 	struct in6_addr nd_na_target;
@@ -1582,22 +1660,20 @@
 
 	if (ifp == NULL) {
 #ifdef DEBUG_NS
-		logdebugx("NA for unexpected interface from %s",
-		    ctx->sfrom);
+		logdebugx("NA for unexpected interface from %s", sfrom);
 #endif
 		return;
 	}
 
 	if ((size_t)len < sizeof(struct nd_neighbor_advert)) {
-		logerrx("%s: IPv6 NA too short from %s",
-		    ifp->name, ctx->sfrom);
+		logerrx("%s: IPv6 NA too short from %s", ifp->name, sfrom);
 		return;
 	}
 
 	/* RFC 4861 7.1.2 */
 	if (hoplimit != 255) {
 		logerrx("invalid hoplimit(%d) in NA from %s",
-		    hoplimit, ctx->sfrom);
+		    hoplimit, sfrom);
 		return;
 	}
 
@@ -1611,7 +1687,7 @@
 	memcpy(&nd_na_target, &nd_na->nd_na_target, sizeof(nd_na_target));
 	if (IN6_IS_ADDR_MULTICAST(&nd_na_target)) {
 		logerrx("%s: NA multicast address %s (%s)",
-		    ifp->name, taddr, ctx->sfrom);
+		    ifp->name, taddr, sfrom);
 		return;
 	}
 
@@ -1623,20 +1699,20 @@
 	if (rap == NULL) {
 #ifdef DEBUG_NS
 		logdebugx("%s: unexpected NA from %s for %s",
-		    ifp->name, ctx->sfrom, taddr);
+		    ifp->name, sfrom, taddr);
 #endif
 		return;
 	}
 
 #ifdef DEBUG_NS
 	logdebugx("%s: %sNA for %s from %s",
-	    ifp->name, is_solicited ? "solicited " : "", taddr, ctx->sfrom);
+	    ifp->name, is_solicited ? "solicited " : "", taddr, sfrom);
 #endif
 
 	/* Node is no longer a router, so remove it from consideration */
 	if (!is_router && !rap->expired) {
 		loginfox("%s: %s not a router (%s)",
-		    ifp->name, taddr, ctx->sfrom);
+		    ifp->name, taddr, sfrom);
 		rap->expired = 1;
 		rt_build(ifp->ctx,  AF_INET6);
 		script_runreason(ifp, "ROUTERADVERT");
@@ -1651,81 +1727,78 @@
 ipv6nd_handledata(void *arg)
 {
 	struct dhcpcd_ctx *ctx;
+	int s;
+	struct sockaddr_in6 from;
+	unsigned char buf[64 * 1024]; /* Maximum ICMPv6 size */
+	struct iovec iov = {
+		.iov_base = buf,
+		.iov_len = sizeof(buf),
+	};
+	unsigned char ctl[CMSG_SPACE(sizeof(struct in6_pktinfo)) + CMSG_SPACE(sizeof(int))] = { 0 };
+	struct msghdr msg = {
+	    .msg_name = &from, .msg_namelen = sizeof(from),
+	    .msg_iov = &iov, .msg_iovlen = 1,
+	    .msg_control = ctl, .msg_controllen = sizeof(ctl),
+	};
 	ssize_t len;
-	struct cmsghdr *cm;
-	int hoplimit;
-	struct in6_pktinfo pkt;
+	char sfrom[INET6_ADDRSTRLEN];
+	int hoplimit = 0;
 	struct icmp6_hdr *icp;
 	struct interface *ifp;
 
+#ifdef __sun
+	struct rs_state *state;
+
+	ifp = arg;
+	state = RS_STATE(ifp);
+	ctx = ifp->ctx;
+	s = state->nd_fd;
+#else
 	ctx = arg;
-	ctx->rcvhdr.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo)) +
-	    CMSG_SPACE(sizeof(int));
-	len = recvmsg_realloc(ctx->nd_fd, &ctx->rcvhdr, 0);
+	s = ctx->nd_fd;
+#endif
+	len = recvmsg(s, &msg, 0);
 	if (len == -1) {
 		logerr(__func__);
 		return;
 	}
-	ctx->sfrom = inet_ntop(AF_INET6, &ctx->from.sin6_addr,
-	    ctx->ntopbuf, INET6_ADDRSTRLEN);
+	inet_ntop(AF_INET6, &from.sin6_addr, sfrom, sizeof(sfrom));
 	if ((size_t)len < sizeof(struct icmp6_hdr)) {
-		logerrx("IPv6 ICMP packet too short from %s", ctx->sfrom);
+		logerrx("IPv6 ICMP packet too short from %s", sfrom);
 		return;
 	}
 
-	pkt.ipi6_ifindex = 0;
-	hoplimit = 0;
-	for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&ctx->rcvhdr);
-	     cm;
-	     cm = (struct cmsghdr *)CMSG_NXTHDR(&ctx->rcvhdr, cm))
-	{
-		if (cm->cmsg_level != IPPROTO_IPV6)
-			continue;
-		switch(cm->cmsg_type) {
-		case IPV6_PKTINFO:
-			if (cm->cmsg_len == CMSG_LEN(sizeof(pkt)))
-				memcpy(&pkt, CMSG_DATA(cm), sizeof(pkt));
-			break;
-		case IPV6_HOPLIMIT:
-			if (cm->cmsg_len == CMSG_LEN(sizeof(int)))
-				memcpy(&hoplimit, CMSG_DATA(cm), sizeof(int));
-			break;
-		}
-	}
-
-	if (pkt.ipi6_ifindex == 0) {
-		logerrx("IPv6 RA/NA did not contain index from %s", ctx->sfrom);
+#ifdef __sun
+	if_findifpfromcmsg(ctx, &msg, &hoplimit);
+#else
+	ifp = if_findifpfromcmsg(ctx, &msg, &hoplimit);
+	if (ifp == NULL) {
+		logerr(__func__);
 		return;
 	}
-
-	/* Find the receiving interface */
-	TAILQ_FOREACH(ifp, ctx->ifaces, next) {
-		if (ifp->index == (unsigned int)pkt.ipi6_ifindex)
-			break;
-	}
+#endif
 
 	/* Don't do anything if the user hasn't configured it. */
-	if (ifp != NULL &&
-	    (ifp->active != IF_ACTIVE_USER ||
-	    !(ifp->options->options & DHCPCD_IPV6)))
+	if (ifp->active != IF_ACTIVE_USER ||
+	    !(ifp->options->options & DHCPCD_IPV6))
 		return;
 
-	icp = (struct icmp6_hdr *)ctx->rcvhdr.msg_iov[0].iov_base;
+	icp = (struct icmp6_hdr *)buf;
 	if (icp->icmp6_code == 0) {
 		switch(icp->icmp6_type) {
 			case ND_NEIGHBOR_ADVERT:
-				ipv6nd_handlena(ctx, ifp, icp, (size_t)len,
-				   hoplimit);
+				ipv6nd_handlena(ctx, sfrom,
+				    ifp, icp, (size_t)len, hoplimit);
 				return;
 			case ND_ROUTER_ADVERT:
-				ipv6nd_handlera(ctx, ifp, icp, (size_t)len,
-				   hoplimit);
+				ipv6nd_handlera(ctx, &from, sfrom,
+				    ifp, icp, (size_t)len, hoplimit);
 				return;
 		}
 	}
 
 	logerrx("invalid IPv6 type %d or code %d from %s",
-	    icp->icmp6_type, icp->icmp6_code, ctx->sfrom);
+	    icp->icmp6_type, icp->icmp6_code, sfrom);
 }
 
 static void
@@ -1735,11 +1808,6 @@
 	struct rs_state *state;
 
 	loginfox("%s: soliciting an IPv6 router", ifp->name);
-	if (ipv6nd_open(ifp->ctx) == -1) {
-		logerr(__func__);
-		return;
-	}
-
 	state = RS_STATE(ifp);
 	if (state == NULL) {
 		ifp->if_data[IF_DATA_IPV6ND] = calloc(1, sizeof(*state));
@@ -1748,7 +1816,22 @@
 			logerr(__func__);
 			return;
 		}
+#ifdef __sun
+		state->nd_fd = -1;
+#endif
+	}
+
+#ifdef __sun
+	if (ipv6nd_open(ifp) == -1) {
+		logerr(__func__);
+		return;
 	}
+#else
+	if (ipv6nd_open(ifp->ctx) == -1) {
+		logerr(__func__);
+		return;
+	}
+#endif
 
 	/* Always make a new probe as the underlying hardware
 	 * address could have changed. */
diff -Nru dhcpcd5-7.1.0/src/ipv6nd.h dhcpcd5-7.2.1/src/ipv6nd.h
--- dhcpcd5-7.1.0/src/ipv6nd.h	2019-01-22 22:53:45.000000000 +0800
+++ dhcpcd5-7.2.1/src/ipv6nd.h	2019-04-26 21:32:54.000000000 +0800
@@ -28,6 +28,8 @@
 #ifndef IPV6ND_H
 #define IPV6ND_H
 
+#ifdef INET6
+
 #include <time.h>
 
 #include "config.h"
@@ -59,6 +61,9 @@
 	size_t rslen;
 	int rsprobes;
 	uint32_t retrans;
+#ifdef __sun
+	int nd_fd;
+#endif
 };
 
 #define	RS_STATE(a) ((struct rs_state *)(ifp)->if_data[IF_DATA_IPV6ND])
@@ -87,7 +92,6 @@
 #define	IPV6ND_REACHABLE		(1 << 0)
 #define	IPV6ND_ROUTER			(1 << 1)
 
-#ifdef INET6
 void ipv6nd_printoptions(const struct dhcpcd_ctx *,
     const struct dhcp_opt *, size_t);
 void ipv6nd_startrs(struct interface *);
@@ -106,12 +110,6 @@
 void ipv6nd_expire(struct interface *, uint32_t);
 void ipv6nd_drop(struct interface *);
 void ipv6nd_neighbour(struct dhcpcd_ctx *, struct in6_addr *, int);
-#else
-#define ipv6nd_startrs(a) {}
-#define ipv6nd_free(a) {}
-#define ipv6nd_hasra(a) (0)
-#define ipv6nd_dadcompleted(a) (0)
-#define ipv6nd_expire(a, b) {}
-#endif
+#endif /* INET6 */
 
-#endif
+#endif /* IPV6ND_H */
diff -Nru dhcpcd5-7.1.0/src/Makefile dhcpcd5-7.2.1/src/Makefile
--- dhcpcd5-7.1.0/src/Makefile	2019-01-22 22:53:45.000000000 +0800
+++ dhcpcd5-7.2.1/src/Makefile	2019-04-26 21:32:54.000000000 +0800
@@ -45,7 +45,7 @@
 		$< > $@
 
 all: ${TOP}/config.h ${PROG} ${SCRIPTS} ${MAN5} ${MAN8}
-	for x in ${SUBDIRS}; do cd $$x; ${MAKE} $@; cd ..; done
+	for x in ${SUBDIRS}; do cd $$x; ${MAKE} $@ || exit $$?; cd ..; done
 
 dev:
 	cd dev && ${MAKE}
@@ -84,7 +84,7 @@
 	${INSTALL} -d ${DESTDIR}${DBDIR}
 
 proginstall: _proginstall ${EMBEDDEDINSTALL}
-	for x in ${SUBDIRS}; do cd $$x; ${MAKE} $@; cd ..; done
+	for x in ${SUBDIRS}; do cd $$x; ${MAKE} $@ || exit $$?; cd ..; done
 
 _maninstall: ${MAN5} ${MAN8}
 	${INSTALL} -d ${DESTDIR}${MANDIR}/man5
@@ -130,7 +130,7 @@
 
 clean:
 	rm -f ${OBJS} ${PROG} ${PROG}.core ${CLEANFILES}
-	for x in ${SUBDIRS}; do cd $$x; ${MAKE} $@; cd ..; done
+	for x in ${SUBDIRS}; do cd $$x; ${MAKE} $@ || exit $$?; cd ..; done
 
 distclean: clean
 	rm -f .depend
diff -Nru dhcpcd5-7.1.0/src/route.c dhcpcd5-7.2.1/src/route.c
--- dhcpcd5-7.1.0/src/route.c	2019-01-22 22:53:45.000000000 +0800
+++ dhcpcd5-7.2.1/src/route.c	2019-04-26 21:32:54.000000000 +0800
@@ -272,7 +272,7 @@
 /* If something other than dhcpcd removes a route,
  * we need to remove it from our internal table. */
 void
-rt_recvrt(int cmd, const struct rt *rt)
+rt_recvrt(int cmd, const struct rt *rt, pid_t pid)
 {
 	struct dhcpcd_ctx *ctx;
 	struct rt *f;
@@ -288,8 +288,11 @@
 			rt_free(f);
 		}
 		if ((f = rt_find(&ctx->routes, rt)) != NULL) {
+			char buf[32];
+
 			TAILQ_REMOVE(&ctx->routes, f, rt_next);
-			rt_desc("deleted", f);
+			snprintf(buf, sizeof(buf), "pid %d deleted", pid);
+			rt_desc(buf, f);
 			rt_free(f);
 		}
 		break;
@@ -303,7 +306,7 @@
 		break;
 	}
 
-#if defined(INET) && defined(HAVE_ROUTE_METRIC)
+#if defined(IPV4LL) && defined(HAVE_ROUTE_METRIC)
 	if (rt->rt_dest.sa_family == AF_INET)
 		ipv4ll_recvrt(cmd, rt);
 #endif
diff -Nru dhcpcd5-7.1.0/src/route.h dhcpcd5-7.2.1/src/route.h
--- dhcpcd5-7.1.0/src/route.h	2019-01-22 22:53:45.000000000 +0800
+++ dhcpcd5-7.2.1/src/route.h	2019-04-26 21:32:54.000000000 +0800
@@ -92,7 +92,7 @@
 struct rt * rt_new0(struct dhcpcd_ctx *);
 void rt_setif(struct rt *, struct interface *);
 struct rt * rt_new(struct interface *);
-void rt_recvrt(int, const struct rt *);
+void rt_recvrt(int, const struct rt *, pid_t);
 void rt_build(struct dhcpcd_ctx *, int);
 
 #endif
diff -Nru dhcpcd5-7.1.0/src/script.c dhcpcd5-7.2.1/src/script.c
--- dhcpcd5-7.1.0/src/script.c	2019-01-22 22:53:45.000000000 +0800
+++ dhcpcd5-7.2.1/src/script.c	2019-04-26 21:32:54.000000000 +0800
@@ -251,7 +251,7 @@
 	const struct ipv4ll_state *istate;
 #endif
 #endif
-#ifdef INET6
+#ifdef DHCP6
 	const struct dhcp6_state *d6_state;
 #endif
 
@@ -261,14 +261,16 @@
 	istate = IPV4LL_CSTATE(ifp);
 #endif
 #endif
-#ifdef INET6
+#ifdef DHCP6
 	d6_state = D6_CSTATE(ifp);
 #endif
 	if (strcmp(reason, "TEST") == 0) {
 		if (1 == 2) {}
 #ifdef INET6
+#ifdef DHCP6
 		else if (d6_state && d6_state->new)
 			protocol = PROTO_DHCP6;
+#endif
 		else if (ipv6nd_hasra(ifp))
 			protocol = PROTO_RA;
 #endif
@@ -284,8 +286,10 @@
 #ifdef INET6
 	else if (strcmp(reason, "STATIC6") == 0)
 		protocol = PROTO_STATIC6;
+#ifdef DHCP6
 	else if (reason[strlen(reason) - 1] == '6')
 		protocol = PROTO_DHCP6;
+#endif
 	else if (strcmp(reason, "ROUTERADVERT") == 0)
 		protocol = PROTO_RA;
 #endif
@@ -379,7 +383,9 @@
 #endif
 #ifdef INET6
 	    || (protocol == PROTO_STATIC6 && IPV6_STATE_RUNNING(ifp))
+#ifdef DHCP6
 	    || (protocol == PROTO_DHCP6 && d6_state && d6_state->new)
+#endif
 	    || (protocol == PROTO_RA && ipv6nd_hasra(ifp))
 #endif
 	    )
@@ -463,7 +469,7 @@
 			goto eexit;
 	}
 #endif
-#ifdef INET6
+#ifdef DHCP6
 	if (protocol == PROTO_DHCP6 && d6_state && d6_state->old) {
 		n = dhcp6_env(NULL, NULL, ifp,
 		    d6_state->old, d6_state->old_len);
@@ -534,6 +540,7 @@
 			elen += (size_t)n;
 		}
 	}
+#ifdef DHCP6
 	if (protocol == PROTO_DHCP6 && D6_STATE_RUNNING(ifp)) {
 		n = dhcp6_env(NULL, NULL, ifp,
 		    d6_state->new, d6_state->new_len);
@@ -550,6 +557,7 @@
 			elen += (size_t)n;
 		}
 	}
+#endif
 	if (protocol == PROTO_RA) {
 		n = ipv6nd_env(NULL, NULL, ifp);
 		if (n > 0) {
@@ -632,7 +640,7 @@
 #ifdef INET
 	const struct dhcp_state *d;
 #endif
-#ifdef INET6
+#ifdef DHCP6
 	const struct dhcp6_state *d6;
 #endif
 
@@ -641,6 +649,7 @@
 		reason = "CARRIER";
 		break;
 	case LINK_DOWN:
+	case LINK_DOWN_IFFUP:
 		reason = "NOCARRIER";
 		break;
 	default:
@@ -672,12 +681,14 @@
 		if (send_interface1(fd, ifp, "ROUTERADVERT") == -1)
 			retval = -1;
 	}
+#ifdef DHCP6
 	if (D6_STATE_RUNNING(ifp)) {
 		d6 = D6_CSTATE(ifp);
 		if (send_interface1(fd, ifp, d6->reason) == -1)
 			retval = -1;
 	}
 #endif
+#endif
 
 	return retval;
 }
@@ -693,9 +704,7 @@
 	int status = 0;
 	struct fd_list *fd;
 
-	if (ifp->options->script &&
-	    (ifp->options->script[0] == '\0' ||
-	    strcmp(ifp->options->script, "/dev/null") == 0) &&
+	if (ifp->options->script == NULL &&
 	    TAILQ_FIRST(&ifp->ctx->control_fds) == NULL)
 		return 0;
 
@@ -706,12 +715,10 @@
 		return -1;
 	}
 
-	if (ifp->options->script &&
-	    (ifp->options->script[0] == '\0' ||
-	    strcmp(ifp->options->script, "/dev/null") == 0))
+	if (ifp->options->script == NULL)
 		goto send_listeners;
 
-	argv[0] = ifp->options->script ? ifp->options->script : UNCONST(SCRIPT);
+	argv[0] = ifp->options->script;
 	argv[1] = NULL;
 	logdebugx("%s: executing `%s' %s", ifp->name, argv[0], reason);
 
diff -Nru dhcpcd5-7.1.0/tests/Makefile dhcpcd5-7.2.1/tests/Makefile
--- dhcpcd5-7.1.0/tests/Makefile	2019-01-22 22:53:45.000000000 +0800
+++ dhcpcd5-7.2.1/tests/Makefile	2019-04-26 21:32:54.000000000 +0800
@@ -1,16 +1,16 @@
 SUBDIRS=	crypt eloop-bench
 
 all: 
-	for x in ${SUBDIRS}; do cd $$x; ${MAKE} $@; cd ..; done
+	for x in ${SUBDIRS}; do cd $$x; ${MAKE} $@ || exit $$?; cd ..; done
 
 install:
 
 proginstall:
 
 clean:
-	for x in ${SUBDIRS}; do cd $$x; ${MAKE} $@; cd ..; done
+	for x in ${SUBDIRS}; do cd $$x; ${MAKE} $@ || exit $$?; cd ..; done
 
 test:
-	for x in ${SUBDIRS}; do cd $$x; ${MAKE} $@; cd ..; done
+	for x in ${SUBDIRS}; do cd $$x; ${MAKE} $@ || exit $$?; cd ..; done
 
 tests: test

Reply to: