Module Name:    src
Committed By:   roy
Date:           Wed Apr 17 23:35:35 UTC 2019

Modified Files:
        src/external/bsd/dhcpcd/dist/src: dhcp.c dhcp6.c dhcpcd.c if-bsd.c
            if-options.c ipv6nd.c

Log Message:
Sync


To generate a diff of this commit:
cvs rdiff -u -r1.16 -r1.17 src/external/bsd/dhcpcd/dist/src/dhcp.c
cvs rdiff -u -r1.4 -r1.5 src/external/bsd/dhcpcd/dist/src/dhcp6.c \
    src/external/bsd/dhcpcd/dist/src/if-bsd.c \
    src/external/bsd/dhcpcd/dist/src/ipv6nd.c
cvs rdiff -u -r1.17 -r1.18 src/external/bsd/dhcpcd/dist/src/dhcpcd.c
cvs rdiff -u -r1.12 -r1.13 src/external/bsd/dhcpcd/dist/src/if-options.c

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

Modified files:

Index: src/external/bsd/dhcpcd/dist/src/dhcp.c
diff -u src/external/bsd/dhcpcd/dist/src/dhcp.c:1.16 src/external/bsd/dhcpcd/dist/src/dhcp.c:1.17
--- src/external/bsd/dhcpcd/dist/src/dhcp.c:1.16	Thu Feb  7 21:37:36 2019
+++ src/external/bsd/dhcpcd/dist/src/dhcp.c	Wed Apr 17 23:35:34 2019
@@ -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 @@ static void dhcp_arp_conflicted(struct a
 #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
@@ -447,7 +450,7 @@ decode_rfc3442_rt(struct rt_head *routes
 		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 +458,14 @@ decode_rfc3442_rt(struct rt_head *routes
 		{
 			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 +638,7 @@ get_option_routes(struct rt_head *routes
 			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 +646,15 @@ get_option_routes(struct rt_head *routes
 			{
 				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 +1590,11 @@ dhcp_close(struct interface *ifp)
 		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 +1612,15 @@ dhcp_openudp(struct interface *ifp)
 	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 +1711,8 @@ dhcp_sendudp(struct interface *ifp, stru
 	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 +1731,15 @@ dhcp_sendudp(struct interface *ifp, stru
 	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;
 }
 
@@ -1803,7 +1797,7 @@ send_message(struct interface *ifp, uint
 	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)
@@ -2068,11 +2062,6 @@ dhcp_arp_probed(struct arp_state *astate
 			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;
 	}
@@ -2150,11 +2139,6 @@ dhcp_arp_conflicted(struct arp_state *as
 			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 +2193,22 @@ dhcp_arp_conflicted(struct arp_state *as
 		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 +2284,10 @@ dhcp_bind(struct interface *ifp)
 				    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 +2306,42 @@ dhcp_bind(struct interface *ifp)
 	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 +2395,20 @@ dhcp_message_new(struct bootp **bootp,
 }
 
 #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,10 +2425,9 @@ dhcp_arp_address(struct interface *ifp)
 	/* 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
 	if (ia == NULL || ia->addr_flags & IN_IFF_NOTUSEABLE) {
@@ -2440,7 +2464,8 @@ static void
 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
@@ -2879,14 +2904,11 @@ dhcp_handledhcp(struct interface *ifp, s
 #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 +3212,7 @@ dhcp_handledhcp(struct interface *ifp, s
 			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 +3360,30 @@ valid_udp_packet(void *data, size_t data
 }
 
 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 +3417,7 @@ dhcp_handlepacket(struct interface *ifp,
 	 * 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 +3453,76 @@ dhcp_readpacket(void *arg)
 }
 
 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;
 
-	ctx = arg;
+	if (ifp != NULL) {
+		const struct dhcp_state *state = D_CSTATE(ifp);
 
-	/* 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) {
+		s = state->udp_fd;
+	} else
+		s = ctx->udp_fd;
+
+	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 +3632,7 @@ dhcp_initstate(struct interface *ifp)
 	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 +3762,9 @@ dhcp_start1(void *arg)
 	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 +3774,11 @@ dhcp_start1(void *arg)
 		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");

Index: src/external/bsd/dhcpcd/dist/src/dhcp6.c
diff -u src/external/bsd/dhcpcd/dist/src/dhcp6.c:1.4 src/external/bsd/dhcpcd/dist/src/dhcp6.c:1.5
--- src/external/bsd/dhcpcd/dist/src/dhcp6.c:1.4	Thu Feb  7 21:37:36 2019
+++ src/external/bsd/dhcpcd/dist/src/dhcp6.c	Wed Apr 17 23:35:34 2019
@@ -168,7 +168,7 @@ static const char * const dhcp6_statuses
 	"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 @@ dhcp6_makemessage(struct interface *ifp)
 		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 @@ dhcp6_makemessage(struct interface *ifp)
 		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 @@ dhcp6_makemessage(struct interface *ifp)
 		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 @@ dhcp6_update_auth(struct interface *ifp,
 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 @@ dhcp6_sendmessage(struct interface *ifp,
 	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)
 		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
@@ -1280,7 +1298,7 @@ logsend:
 		/* 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;
 		}
@@ -1301,31 +1319,21 @@ logsend:
 	}
 #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 @@ logsend:
 		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 @@ logsend:
 		 * 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 @@ dhcp6_fail(struct interface *ifp)
 		break;
 	}
 
-	dhcp6_bind(ifp, NULL);
+	dhcp6_bind(ifp, NULL, NULL);
 
 	switch (state->state) {
 	case DH6S_BOUND:
@@ -1911,13 +1913,16 @@ static int
 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 @@ dhcp6_checkstatusok(const struct interfa
 		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 @@ dhcp6_checkstatusok(const struct interfa
 	}
 	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 @@ dhcp6_checkstatusok(const struct interfa
 		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;
 }
 
@@ -2927,7 +2940,7 @@ dhcp6_find_delegates(struct interface *i
 #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 @@ dhcp6_bind(struct interface *ifp, const 
 	}
 	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)
@@ -3176,7 +3188,8 @@ dhcp6_bind(struct interface *ifp, const 
 }
 
 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 @@ dhcp6_recvif(struct interface *ifp, stru
 	}
 
 	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_recvif(struct interface *ifp, stru
 		    !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 @@ dhcp6_recvif(struct interface *ifp, stru
 		    (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 @@ dhcp6_recvif(struct interface *ifp, stru
 	} 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 @@ dhcp6_recvif(struct interface *ifp, stru
 				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 @@ dhcp6_recvif(struct interface *ifp, stru
 		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 @@ dhcp6_recvif(struct interface *ifp, stru
 				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 @@ dhcp6_recvif(struct interface *ifp, stru
 		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",
@@ -3456,10 +3465,10 @@ dhcp6_recvif(struct interface *ifp, stru
 			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);
@@ -3467,97 +3476,81 @@ dhcp6_recvif(struct interface *ifp, stru
 	}
 	}
 
-	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;
 	}
@@ -3591,7 +3584,7 @@ dhcp6_recv(struct dhcpcd_ctx *ctx, struc
 				    state->send->xid[0],
 				    state->send->xid[1],
 				    state->send->xid[2],
-				    ctx->sfrom);
+				    sfrom);
 			return;
 		}
 		logdebugx("%s: redirecting DHCP6 message to %s",
@@ -3599,7 +3592,7 @@ dhcp6_recv(struct dhcpcd_ctx *ctx, struc
 		ifp = ifp1;
 	}
 
-	dhcp6_recvif(ifp, r, len);
+	dhcp6_recvif(ifp, sfrom, r, len);
 }
 
 static void
@@ -3812,6 +3805,7 @@ dhcp6_start(struct interface *ifp, enum 
 
 gogogo:
 	state->state = init_state;
+	state->lerror = 0;
 	dhcp_set_leasefile(state->leasefile, sizeof(state->leasefile),
 	    AF_INET6, ifp);
 	if (ipv6_linklocal(ifp) == NULL) {
@@ -3831,18 +3825,20 @@ dhcp6_reboot(struct interface *ifp)
 	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;
 	}
 }
 
Index: src/external/bsd/dhcpcd/dist/src/if-bsd.c
diff -u src/external/bsd/dhcpcd/dist/src/if-bsd.c:1.4 src/external/bsd/dhcpcd/dist/src/if-bsd.c:1.5
--- src/external/bsd/dhcpcd/dist/src/if-bsd.c:1.4	Thu Feb  7 21:37:36 2019
+++ src/external/bsd/dhcpcd/dist/src/if-bsd.c	Wed Apr 17 23:35:34 2019
@@ -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)
 {
@@ -418,9 +424,13 @@ if_findsa(struct dhcpcd_ctx *ctx, const 
 	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;
@@ -458,11 +468,7 @@ 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 rtm rtmsg;
 	struct rt_msghdr *rtm = &rtmsg.hdr;
 	char *bp = rtmsg.buffer;
 	struct sockaddr_dl sdl;
@@ -577,7 +583,7 @@ if_route(unsigned char cmd, const struct
 			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);
 		}
@@ -605,19 +611,27 @@ if_copyrt(struct dhcpcd_ctx *ctx, struct
 {
 	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);
@@ -688,7 +702,7 @@ if_initrt(struct dhcpcd_ctx *ctx, int af
 		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);
@@ -751,7 +765,7 @@ if_addrflags(const struct interface *ifp
 
 #ifdef INET6
 static void
-ifa_scope(struct sockaddr_in6 *sin, unsigned int ifindex)
+ifa_setscope(struct sockaddr_in6 *sin, unsigned int ifindex)
 {
 
 #ifdef __KAME__
@@ -771,6 +785,23 @@ ifa_scope(struct sockaddr_in6 *sin, unsi
 #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)
 {
@@ -810,7 +841,7 @@ if_address6(unsigned char cmd, const str
 	}
 
 	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);
 
@@ -887,7 +918,7 @@ if_addrflags6(const struct interface *if
 	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;
@@ -908,7 +939,7 @@ if_getlifetime6(struct ipv6_addr *ia)
 	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;
@@ -1010,7 +1041,7 @@ if_rtm(struct dhcpcd_ctx *ctx, const str
 	}
 #endif
 
-	rt_recvrt(rtm->rtm_type, &rt);
+	rt_recvrt(rtm->rtm_type, &rt, rtm->rtm_pid);
 }
 
 static void
@@ -1095,7 +1126,7 @@ if_ifa(struct dhcpcd_ctx *ctx, const str
 			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;
@@ -1229,18 +1260,16 @@ if_dispatch(struct dhcpcd_ctx *ctx, cons
 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;
 }
 
Index: src/external/bsd/dhcpcd/dist/src/ipv6nd.c
diff -u src/external/bsd/dhcpcd/dist/src/ipv6nd.c:1.4 src/external/bsd/dhcpcd/dist/src/ipv6nd.c:1.5
--- src/external/bsd/dhcpcd/dist/src/ipv6nd.c:1.4	Thu Feb  7 21:37:36 2019
+++ src/external/bsd/dhcpcd/dist/src/ipv6nd.c	Wed Apr 17 23:35:35 2019
@@ -274,10 +274,17 @@ 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 };
+	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 };
 
 	if (ipv6_linklocal(ifp) == NULL) {
 		logdebugx("%s: delaying Router Solicitation for LL address",
@@ -286,8 +293,6 @@ ipv6nd_sendrsprobe(void *arg)
 		return;
 	}
 
-	memset(&dst, 0, sizeof(dst));
-	dst.sin6_family = AF_INET6;
 #ifdef HAVE_SA_LEN
 	dst.sin6_len = sizeof(dst);
 #endif
@@ -297,25 +302,19 @@ ipv6nd_sendrsprobe(void *arg)
 		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) {
+	if (sendmsg(ctx->nd_fd, &msg, 0) == -1) {
 		logerr(__func__);
 		/* Allow IPv6ND to continue .... at most a few errors
 		 * would be logged.
@@ -341,41 +340,42 @@ ipv6nd_sendadvertisement(void *arg)
 	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_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);
 
 	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)
+	if (sendmsg(ctx->nd_fd, &msg, 0) == -1)
 		logerr(__func__);
 
 	if (++ia->na_count < MAX_NEIGHBOR_ADVERTISEMENT) {
@@ -872,8 +872,9 @@ dhcp6_start(__unused struct interface *i
 #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;
@@ -895,33 +896,29 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx, 
 
 	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;
 	}
@@ -930,20 +927,20 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx, 
 	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;
 	}
 
@@ -968,8 +965,8 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx, 
 			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
@@ -991,8 +988,7 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx, 
 	 * 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;
@@ -1053,10 +1049,10 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx, 
 			}
 			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
@@ -1196,7 +1192,7 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx, 
 		    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
@@ -1584,8 +1580,8 @@ ipv6nd_drop(struct interface *ifp)
 }
 
 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;
@@ -1596,22 +1592,20 @@ ipv6nd_handlena(struct dhcpcd_ctx *ctx, 
 
 	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;
 	}
 
@@ -1625,7 +1619,7 @@ ipv6nd_handlena(struct dhcpcd_ctx *ctx, 
 	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;
 	}
 
@@ -1637,20 +1631,20 @@ ipv6nd_handlena(struct dhcpcd_ctx *ctx, 
 	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");
@@ -1665,81 +1659,63 @@ static void
 ipv6nd_handledata(void *arg)
 {
 	struct dhcpcd_ctx *ctx;
+	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;
 
 	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);
+	len = recvmsg(ctx->nd_fd, &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);
+	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;
-	}
-
 	/* 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

Index: src/external/bsd/dhcpcd/dist/src/dhcpcd.c
diff -u src/external/bsd/dhcpcd/dist/src/dhcpcd.c:1.17 src/external/bsd/dhcpcd/dist/src/dhcpcd.c:1.18
--- src/external/bsd/dhcpcd/dist/src/dhcpcd.c:1.17	Thu Feb  7 21:37:36 2019
+++ src/external/bsd/dhcpcd/dist/src/dhcpcd.c	Wed Apr 17 23:35:34 2019
@@ -54,6 +54,7 @@ const char dhcpcd_copyright[] = "Copyrig
 #include "dev.h"
 #include "dhcp-common.h"
 #include "dhcpcd.h"
+#include "dhcp.h"
 #include "dhcp6.h"
 #include "duid.h"
 #include "eloop.h"
@@ -978,7 +979,12 @@ dhcpcd_prestartinterface(void *arg)
 
 	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 &&
@@ -1606,9 +1612,6 @@ main(int argc, char **argv)
 	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
@@ -2142,7 +2145,6 @@ exit1:
 #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");

Index: src/external/bsd/dhcpcd/dist/src/if-options.c
diff -u src/external/bsd/dhcpcd/dist/src/if-options.c:1.12 src/external/bsd/dhcpcd/dist/src/if-options.c:1.13
--- src/external/bsd/dhcpcd/dist/src/if-options.c:1.12	Thu Feb  7 21:37:36 2019
+++ src/external/bsd/dhcpcd/dist/src/if-options.c	Wed Apr 17 23:35:34 2019
@@ -207,11 +207,12 @@ const struct option cf_options[] = {
 	{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 @@ add_environ(struct if_options *ifo, cons
 	*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 @@ add_environ(struct if_options *ifo, cons
 					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 @@ add_environ(struct if_options *ifo, cons
 		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 @@ add_environ(struct if_options *ifo, cons
 	}
 	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 @@ parse_string_hwaddr(char *sbuf, size_t s
 	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 @@ parse_string_hwaddr(char *sbuf, size_t s
 			str++;
 		}
 	}
-	if (punt_last) {
-		if (sbuf)
-			*--sbuf = '\0';
-		l--;
-	}
+	if (flags == PARSE_STRING_NULL && sbuf)
+		*sbuf = '\0';
 	return (ssize_t)l;
 }
 
@@ -654,7 +657,7 @@ parse_option(struct dhcpcd_ctx *ctx, con
 	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;
@@ -708,17 +711,33 @@ parse_option(struct dhcpcd_ctx *ctx, con
 		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) {
@@ -969,7 +988,7 @@ parse_option(struct dhcpcd_ctx *ctx, con
 			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':
@@ -1006,8 +1025,8 @@ parse_option(struct dhcpcd_ctx *ctx, con
 		/* 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) {
@@ -1112,6 +1131,7 @@ parse_option(struct dhcpcd_ctx *ctx, con
 			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;
@@ -1122,6 +1142,7 @@ parse_option(struct dhcpcd_ctx *ctx, con
 			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)
@@ -1149,40 +1170,8 @@ parse_option(struct dhcpcd_ctx *ctx, con
 				} 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)
@@ -2277,6 +2266,7 @@ default_config(struct dhcpcd_ctx *ctx)
 	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);
@@ -2626,7 +2616,8 @@ free_options(struct dhcpcd_ctx *ctx, str
 			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);

Reply via email to