Module Name:    src
Committed By:   martin
Date:           Fri Nov 22 08:01:50 UTC 2019

Modified Files:
        src/doc [netbsd-9]: 3RDPARTY
        src/external/bsd/dhcpcd/dist/src [netbsd-9]: arp.c arp.h control.c
            defs.h dhcp.c dhcp6.c dhcpcd.c eloop.c eloop.h if-bsd.c if.c if.h
            ipv4.c ipv6nd.c ipv6nd.h script.c

Log Message:
Pull up the following revisions, requested by roy in ticket #461:

        external/bsd/dhcpcd/dist/src/arp.c              up to 1.1.1.13
        external/bsd/dhcpcd/dist/src/arp.h              up to 1.1.1.9
        external/bsd/dhcpcd/dist/src/control.c          up to 1.1.1.9
        external/bsd/dhcpcd/dist/src/defs.h             up to 1.1.1.33
        external/bsd/dhcpcd/dist/src/dhcp.c             up to 1.30
        external/bsd/dhcpcd/dist/src/dhcp6.c            up to 1.14
        external/bsd/dhcpcd/dist/src/dhcpcd.c           up to 1.29
        external/bsd/dhcpcd/dist/src/eloop.c            up to 1.1.1.8
        external/bsd/dhcpcd/dist/src/eloop.h            up to 1.1.1.6
        external/bsd/dhcpcd/dist/src/if-bsd.c           up to 1.15
        external/bsd/dhcpcd/dist/src/if.c               up to 1.1.1.18
        external/bsd/dhcpcd/dist/src/if.h               up to 1.1.1.13
        external/bsd/dhcpcd/dist/src/ipv4.c             up to 1.1.1.19
        external/bsd/dhcpcd/dist/src/ipv6nd.c           up to 1.13
        external/bsd/dhcpcd/dist/src/ipv6nd.h           up to 1.1.1.14
        external/bsd/dhcpcd/dist/src/script.c           up to 1.1.1.12
        doc/3RDPARTY                                    (manually adjusted)

Import dhcpcd-8.1.2 with the following changes:
 * hooks: STOPPED is now run on timeout and exit
 * BSD: Use IP_REVCIF rather than IN_PKTINFO
 * DHCP: When rebinding, ensure we have a DHCP ARP state
 * RA: Sort routers when reachability changes
 * RA: Apply hoplimit, reachable and retrans timer values to kernel
 * RA: Warn if advertised MTU > interface MTU
 * dhcpcd: Report SSID connection to when we gain carrier
 * DHCP: Fix corruption of address flags when renewing


To generate a diff of this commit:
cvs rdiff -u -r1.1640.2.6 -r1.1640.2.7 src/doc/3RDPARTY
cvs rdiff -u -r1.1.1.11.2.1 -r1.1.1.11.2.2 \
    src/external/bsd/dhcpcd/dist/src/arp.c
cvs rdiff -u -r1.1.1.8 -r1.1.1.8.2.1 src/external/bsd/dhcpcd/dist/src/arp.h
cvs rdiff -u -r1.1.1.6.2.1 -r1.1.1.6.2.2 \
    src/external/bsd/dhcpcd/dist/src/control.c
cvs rdiff -u -r1.1.1.25.2.3 -r1.1.1.25.2.4 \
    src/external/bsd/dhcpcd/dist/src/defs.h
cvs rdiff -u -r1.23.2.3 -r1.23.2.4 src/external/bsd/dhcpcd/dist/src/dhcp.c \
    src/external/bsd/dhcpcd/dist/src/dhcpcd.c
cvs rdiff -u -r1.11.2.2 -r1.11.2.3 src/external/bsd/dhcpcd/dist/src/dhcp6.c
cvs rdiff -u -r1.1.1.7 -r1.1.1.7.2.1 src/external/bsd/dhcpcd/dist/src/eloop.c
cvs rdiff -u -r1.1.1.5 -r1.1.1.5.2.1 src/external/bsd/dhcpcd/dist/src/eloop.h
cvs rdiff -u -r1.10.2.2 -r1.10.2.3 src/external/bsd/dhcpcd/dist/src/if-bsd.c \
    src/external/bsd/dhcpcd/dist/src/ipv6nd.c
cvs rdiff -u -r1.1.1.14.2.2 -r1.1.1.14.2.3 \
    src/external/bsd/dhcpcd/dist/src/if.c
cvs rdiff -u -r1.1.1.10.2.2 -r1.1.1.10.2.3 \
    src/external/bsd/dhcpcd/dist/src/if.h
cvs rdiff -u -r1.1.1.16.2.2 -r1.1.1.16.2.3 \
    src/external/bsd/dhcpcd/dist/src/ipv4.c
cvs rdiff -u -r1.1.1.10.2.1 -r1.1.1.10.2.2 \
    src/external/bsd/dhcpcd/dist/src/ipv6nd.h \
    src/external/bsd/dhcpcd/dist/src/script.c

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

Modified files:

Index: src/doc/3RDPARTY
diff -u src/doc/3RDPARTY:1.1640.2.6 src/doc/3RDPARTY:1.1640.2.7
--- src/doc/3RDPARTY:1.1640.2.6	Thu Oct 17 19:34:12 2019
+++ src/doc/3RDPARTY	Fri Nov 22 08:01:49 2019
@@ -1,4 +1,4 @@
-#	$NetBSD: 3RDPARTY,v 1.1640.2.6 2019/10/17 19:34:12 martin Exp $
+#	$NetBSD: 3RDPARTY,v 1.1640.2.7 2019/11/22 08:01:49 martin Exp $
 #
 # This file contains a list of the software that has been integrated into
 # NetBSD where we are not the primary maintainer.
@@ -341,12 +341,12 @@ Notes:
 Use the dhcp2netbsd script.
 
 Package:	dhcpcd
-Version:	8.1.1
-Current Vers:	8.1.1
+Version:	8.1.2
+Current Vers:	8.1.2
 Maintainer:	roy
 Archive Site:	ftp://roy.marples.name/pub/dhcpcd/
 Home Page:	http://roy.marples.name/projects/dhcpcd/
-Date:		2019-10-16
+Date:		2019-11-13
 Mailing List: 	dhcpcd-disc...@marples.name
 License:	BSD (2-clause)
 Location:	external/bsd/dhcpcd/dist

Index: src/external/bsd/dhcpcd/dist/src/arp.c
diff -u src/external/bsd/dhcpcd/dist/src/arp.c:1.1.1.11.2.1 src/external/bsd/dhcpcd/dist/src/arp.c:1.1.1.11.2.2
--- src/external/bsd/dhcpcd/dist/src/arp.c:1.1.1.11.2.1	Sat Oct 12 14:44:32 2019
+++ src/external/bsd/dhcpcd/dist/src/arp.c	Fri Nov 22 08:01:49 2019
@@ -206,7 +206,6 @@ arp_validate(const struct interface *ifp
 	return true;
 }
 
-
 static void
 arp_packet(struct interface *ifp, uint8_t *data, size_t len)
 {
@@ -280,9 +279,9 @@ arp_close(struct interface *ifp)
 }
 
 static void
-arp_tryfree(struct interface *ifp)
+arp_tryfree(struct iarp_state *state)
 {
-	struct iarp_state *state = ARP_STATE(ifp);
+	struct interface *ifp = state->ifp;
 
 	/* If there are no more ARP states, close the socket. */
 	if (TAILQ_FIRST(&state->arp_states) == NULL) {
@@ -302,15 +301,14 @@ arp_tryfree(struct interface *ifp)
 static void
 arp_read(void *arg)
 {
-	struct interface *ifp = arg;
-	struct iarp_state *state;
+	struct iarp_state *state = arg;
+	struct interface *ifp = state->ifp;
 	uint8_t buf[ARP_LEN];
 	ssize_t bytes;
 
 	/* Some RAW mechanisms are generic file descriptors, not sockets.
 	 * This means we have no kernel call to just get one packet,
 	 * so we have to process the entire buffer. */
-	state = ARP_STATE(ifp);
 	state->bpf_flags &= ~BPF_EOF;
 	state->bpf_flags |= BPF_READING;
 	while (!(state->bpf_flags & BPF_EOF)) {
@@ -329,7 +327,7 @@ arp_read(void *arg)
 	if (state != NULL) {
 		state->bpf_flags &= ~BPF_READING;
 		/* Try and free the state if nothing left to do. */
-		arp_tryfree(ifp);
+		arp_tryfree(state);
 	}
 }
 
@@ -343,7 +341,7 @@ arp_open(struct interface *ifp)
 		state->bpf_fd = bpf_open(ifp, bpf_arp);
 		if (state->bpf_fd == -1)
 			return -1;
-		eloop_event_add(ifp->ctx->eloop, state->bpf_fd, arp_read, ifp);
+		eloop_event_add(ifp->ctx->eloop, state->bpf_fd, arp_read, state);
 	}
 	return state->bpf_fd;
 }
@@ -571,6 +569,7 @@ arp_new(struct interface *ifp, const str
 			logerr(__func__);
 			return NULL;
 		}
+		state->ifp = ifp;
 		state->bpf_fd = -1;
 		state->bpf_flags = 0;
 		TAILQ_INIT(&state->arp_states);
@@ -618,7 +617,7 @@ arp_free(struct arp_state *astate)
 	if (astate->free_cb)
 		astate->free_cb(astate);
 	free(astate);
-	arp_tryfree(ifp);
+	arp_tryfree(state);
 }
 
 void

Index: src/external/bsd/dhcpcd/dist/src/arp.h
diff -u src/external/bsd/dhcpcd/dist/src/arp.h:1.1.1.8 src/external/bsd/dhcpcd/dist/src/arp.h:1.1.1.8.2.1
--- src/external/bsd/dhcpcd/dist/src/arp.h:1.1.1.8	Wed Jul 24 09:54:49 2019
+++ src/external/bsd/dhcpcd/dist/src/arp.h	Fri Nov 22 08:01:49 2019
@@ -78,6 +78,7 @@ struct arp_state {
 TAILQ_HEAD(arp_statehead, arp_state);
 
 struct iarp_state {
+	struct interface *ifp;
 	int bpf_fd;
 	unsigned int bpf_flags;
 	struct arp_statehead arp_states;

Index: src/external/bsd/dhcpcd/dist/src/control.c
diff -u src/external/bsd/dhcpcd/dist/src/control.c:1.1.1.6.2.1 src/external/bsd/dhcpcd/dist/src/control.c:1.1.1.6.2.2
--- src/external/bsd/dhcpcd/dist/src/control.c:1.1.1.6.2.1	Thu Sep  5 08:56:55 2019
+++ src/external/bsd/dhcpcd/dist/src/control.c	Fri Nov 22 08:01:49 2019
@@ -274,9 +274,8 @@ control_stop(struct dhcpcd_ctx *ctx)
 
 	if (ctx->control_fd == -1)
 		return 0;
-	eloop_event_delete(ctx->eloop, ctx->control_fd);
-	close(ctx->control_fd);
-	ctx->control_fd = -1;
+
+	control_close(ctx);
 	if (unlink(ctx->control_sock) == -1)
 		retval = -1;
 
@@ -455,6 +454,7 @@ control_close(struct dhcpcd_ctx *ctx)
 {
 
 	if (ctx->control_fd != -1) {
+		eloop_event_delete(ctx->eloop, ctx->control_fd);
 		close(ctx->control_fd);
 		ctx->control_fd = -1;
 	}

Index: src/external/bsd/dhcpcd/dist/src/defs.h
diff -u src/external/bsd/dhcpcd/dist/src/defs.h:1.1.1.25.2.3 src/external/bsd/dhcpcd/dist/src/defs.h:1.1.1.25.2.4
--- src/external/bsd/dhcpcd/dist/src/defs.h:1.1.1.25.2.3	Wed Oct 16 17:41:40 2019
+++ src/external/bsd/dhcpcd/dist/src/defs.h	Fri Nov 22 08:01:49 2019
@@ -29,7 +29,7 @@
 #define CONFIG_H
 
 #define PACKAGE			"dhcpcd"
-#define VERSION			"8.1.1"
+#define VERSION			"8.1.2"
 
 #ifndef CONFIG
 # define CONFIG			SYSCONFDIR "/" PACKAGE ".conf"

Index: src/external/bsd/dhcpcd/dist/src/dhcp.c
diff -u src/external/bsd/dhcpcd/dist/src/dhcp.c:1.23.2.3 src/external/bsd/dhcpcd/dist/src/dhcp.c:1.23.2.4
--- src/external/bsd/dhcpcd/dist/src/dhcp.c:1.23.2.3	Wed Oct 16 17:41:40 2019
+++ src/external/bsd/dhcpcd/dist/src/dhcp.c	Fri Nov 22 08:01:49 2019
@@ -41,6 +41,10 @@
 #include <netinet/udp.h>
 #undef __FAVOR_BSD
 
+#ifdef AF_LINK
+#  include <net/if_dl.h>
+#endif
+
 #include <assert.h>
 #include <ctype.h>
 #include <errno.h>
@@ -132,9 +136,7 @@ static void dhcp_arp_found(struct arp_st
 #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
@@ -1550,7 +1552,10 @@ dhcp_openudp(struct interface *ifp)
 	n = 1;
 	if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n)) == -1)
 		goto eexit;
-#ifdef IP_RECVPKTINFO
+#ifdef IP_RECVIF
+	if (setsockopt(s, IPPROTO_IP, IP_RECVIF, &n, sizeof(n)) == -1)
+		goto eexit;
+#else
 	if (setsockopt(s, IPPROTO_IP, IP_RECVPKTINFO, &n, sizeof(n)) == -1)
 		goto eexit;
 #endif
@@ -1647,39 +1652,36 @@ dhcp_makeudppacket(size_t *sz, const uin
 static ssize_t
 dhcp_sendudp(struct interface *ifp, struct in_addr *to, void *data, size_t len)
 {
-	int s;
-	struct msghdr msg;
-	struct sockaddr_in sin;
-	struct iovec iov[1];
-	struct dhcp_state *state = D_STATE(ifp);
-	ssize_t r;
-
-	iov[0].iov_base = data;
-	iov[0].iov_len = len;
-
-	memset(&sin, 0, sizeof(sin));
-	sin.sin_family = AF_INET;
-	sin.sin_addr = *to;
-	sin.sin_port = htons(BOOTPS);
+	struct sockaddr_in sin = {
+		.sin_family = AF_INET,
+		.sin_addr = *to,
+		.sin_port = htons(BOOTPS),
 #ifdef HAVE_SA_LEN
-	sin.sin_len = sizeof(sin);
+		.sin_len = sizeof(sin),
 #endif
+	};
+	struct iovec iov[] = {
+		{ .iov_base = data, .iov_len = len }
+	};
+	struct msghdr msg = {
+		.msg_name = (void *)&sin,
+		.msg_namelen = sizeof(sin),
+		.msg_iov = iov,
+		.msg_iovlen = 1,
+	};
+	struct dhcp_state *state = D_STATE(ifp);
+	ssize_t r;
+	int fd;
 
-	memset(&msg, 0, sizeof(msg));
-	msg.msg_name = (void *)&sin;
-	msg.msg_namelen = sizeof(sin);
-	msg.msg_iov = iov;
-	msg.msg_iovlen = 1;
-
-	s = state->udp_fd;
-	if (s == -1) {
-		s = dhcp_openudp(ifp);
-		if (s == -1)
+	fd = state->udp_fd;
+	if (fd == -1) {
+		fd = dhcp_openudp(ifp);
+		if (fd == -1)
 			return -1;
 	}
-	r = sendmsg(s, &msg, 0);
+	r = sendmsg(fd, &msg, 0);
 	if (state->udp_fd == -1)
-		close(s);
+		close(fd);
 	return r;
 }
 
@@ -1780,7 +1782,7 @@ send_message(struct interface *ifp, uint
 	 * As such we remove it from consideration without actually
 	 * stopping the interface. */
 	if (r == -1) {
-		logerr("%s: if_sendraw", ifp->name);
+		logerr("%s: bpf_send", ifp->name);
 		switch(errno) {
 		case ENETDOWN:
 		case ENETRESET:
@@ -2257,30 +2259,27 @@ dhcp_bind(struct interface *ifp)
 
 	ipv4_applyaddr(ifp);
 
-#ifdef IP_PKTINFO
 	/* Close the BPF filter as we can now receive DHCP 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__);
-				/* Address sharing without master mode is
-				 * not supported. It's also possible another
-				 * DHCP client could be running which is
-				 * even worse.
-				 * We still need to work, so re-open BPF. */
-				dhcp_openbpf(ifp);
-			} else
-				eloop_event_add(ctx->eloop,
-				    state->udp_fd, dhcp_handleifudp, ifp);
-		}
+	if (!(state->udp_fd == -1 ||
+	    (state->old != NULL && state->old->yiaddr != state->new->yiaddr)))
+		return;
+	dhcp_close(ifp);
+
+	/* If not in master mode, open an address specific socket. */
+	if (ctx->udp_fd != -1)
+		return;
+	state->udp_fd = dhcp_openudp(ifp);
+	if (state->udp_fd == -1) {
+		logerr(__func__);
+		/* Address sharing without master mode is not supported.
+		 * It's also possible another DHCP client could be running,
+		 * which is even worse.
+		 * We still need to work, so re-open BPF. */
+		dhcp_openbpf(ifp);
+		return;
 	}
-#endif
+	eloop_event_add(ctx->eloop, state->udp_fd, dhcp_handleifudp, ifp);
 }
 
 static void
@@ -2609,6 +2608,11 @@ dhcp_reboot(struct interface *ifp)
 	    ifp->name, inet_ntoa(state->lease.addr));
 
 #ifdef ARP
+#ifndef KERNEL_RFC5227
+	/* Create the DHCP ARP state so we can defend it. */
+	(void)dhcp_arp_new(ifp, &state->lease.addr);
+#endif
+
 	/* If the address exists on the interface and no other interface
 	 * is currently using it then announce it to ensure this
 	 * interface gets the reply. */
@@ -3315,7 +3319,7 @@ checksums_valid(void *packet,
 	struct ip *ip = packet;
 	union pip {
 		struct ip ip;
-		uint16_t w[sizeof(struct ip)];
+		uint16_t w[sizeof(struct ip) / 2];
 	} pip = {
 		.ip.ip_p = IPPROTO_UDP,
 		.ip.ip_src = ip->ip_src,
@@ -3350,7 +3354,7 @@ checksums_valid(void *packet,
 	uh_sump = udpp + offsetof(struct udphdr, uh_sum);
 	memset(uh_sump, 0, sizeof(udp.uh_sum));
 
-	/* Checksum psuedo header and then UDP + payload. */
+	/* Checksum pseudo header and then UDP + payload. */
 	in_cksum(pip.w, sizeof(pip.w), &csum);
 	csum = in_cksum(udpp, ntohs(udp.uh_ulen), &csum);
 
@@ -3451,6 +3455,35 @@ dhcp_readbpf(void *arg)
 }
 
 static void
+dhcp_recvmsg(struct dhcpcd_ctx *ctx, struct msghdr *msg)
+{
+	struct sockaddr_in *from = (struct sockaddr_in *)msg->msg_name;
+	struct iovec *iov = &msg->msg_iov[0];
+	struct interface *ifp;
+	const struct dhcp_state *state;
+
+	ifp = if_findifpfromcmsg(ctx, msg, NULL);
+	if (ifp == NULL) {
+		logerr(__func__);
+		return;
+	}
+	state = D_CSTATE(ifp);
+	if (state == NULL) {
+		logdebugx("%s: received BOOTP for inactive interface",
+		    ifp->name);
+		return;
+	}
+
+	if (state->bpf_fd != -1) {
+		/* Avoid a duplicate read if BPF is open for the interface. */
+		return;
+	}
+
+	dhcp_handlebootp(ifp, (struct bootp *)iov->iov_base, iov->iov_len,
+	    &from->sin_addr);
+}
+
+static void
 dhcp_readudp(struct dhcpcd_ctx *ctx, struct interface *ifp)
 {
 	const struct dhcp_state *state;
@@ -3460,16 +3493,15 @@ dhcp_readudp(struct dhcpcd_ctx *ctx, str
 		.iov_base = buf,
 		.iov_len = sizeof(buf),
 	};
-#ifdef IP_PKTINFO
+#ifdef IP_RECVIF
+	unsigned char ctl[CMSG_SPACE(sizeof(struct sockaddr_dl))] = { 0 };
+#else
 	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;
@@ -3486,31 +3518,8 @@ dhcp_readudp(struct dhcpcd_ctx *ctx, str
 		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;
-		}
-		state = D_CSTATE(ifp);
-		if (state == NULL) {
-			logdebugx("%s: received BOOTP for inactive interface",
-			    ifp->name);
-			return;
-		}
-	}
-
-	if (state->bpf_fd != -1) {
-		/* Avoid a duplicate read if BPF is open for the interface. */
-		return;
-	}
-
-	dhcp_handlebootp(ifp, (struct bootp *)(void *)buf, (size_t)bytes,
-	    &from.sin_addr);
-#endif
+	iov.iov_len = (size_t)bytes;
+	dhcp_recvmsg(ctx, &msg);
 }
 
 static void
@@ -3521,16 +3530,24 @@ dhcp_handleudp(void *arg)
 	dhcp_readudp(ctx, NULL);
 }
 
-#ifdef IP_PKTINFO
 static void
 dhcp_handleifudp(void *arg)
 {
 	struct interface *ifp = arg;
 
 	dhcp_readudp(ifp->ctx, ifp);
+}
+
+static int
+dhcp_open(struct dhcpcd_ctx *ctx)
+{
 
+	if (ctx->udp_fd != -1 || (ctx->udp_fd = dhcp_openudp(NULL)) == -1)
+		return ctx->udp_fd;
+
+	eloop_event_add(ctx->eloop, ctx->udp_fd, dhcp_handleudp, ctx);
+	return ctx->udp_fd;
 }
-#endif
 
 static int
 dhcp_openbpf(struct interface *ifp)
@@ -3740,16 +3757,13 @@ dhcp_start1(void *arg)
 	 * ICMP port unreachable message back to the DHCP server.
 	 * Only do this in master mode so we don't swallow messages
 	 * for dhcpcd running on another interface. */
-	if (ctx->udp_fd == -1 && ctx->options & DHCPCD_MASTER) {
-		ctx->udp_fd = dhcp_openudp(NULL);
-		if (ctx->udp_fd == -1) {
+	if (ctx->options & DHCPCD_MASTER) {
+		if (dhcp_open(ctx) == -1) {
 			/* Don't log an error if some other process
 			 * is handling this. */
 			if (errno != EADDRINUSE)
-				logerr("%s: dhcp_openudp", __func__);
-		} else
-			eloop_event_add(ctx->eloop,
-			    ctx->udp_fd, dhcp_handleudp, ctx);
+				logerr("%s: dhcp_open", __func__);
+		}
 	}
 
 	if (dhcp_init(ifp) == -1) {
@@ -4008,7 +4022,7 @@ dhcp_handleifa(int cmd, struct ipv4_addr
 			 * to drop the lease. */
 			dhcp_drop(ifp, "EXPIRE");
 			dhcp_start1(ifp);
-			return NULL;
+			return ia;
 		}
 	}
 
Index: src/external/bsd/dhcpcd/dist/src/dhcpcd.c
diff -u src/external/bsd/dhcpcd/dist/src/dhcpcd.c:1.23.2.3 src/external/bsd/dhcpcd/dist/src/dhcpcd.c:1.23.2.4
--- src/external/bsd/dhcpcd/dist/src/dhcpcd.c:1.23.2.3	Wed Oct 16 17:41:40 2019
+++ src/external/bsd/dhcpcd/dist/src/dhcpcd.c	Fri Nov 22 08:01:50 2019
@@ -186,6 +186,12 @@ handle_exit_timeout(void *arg)
 	ctx = arg;
 	logerrx("timed out");
 	if (!(ctx->options & DHCPCD_MASTER)) {
+		struct interface *ifp;
+
+		TAILQ_FOREACH(ifp, ctx->ifaces, next) {
+			if (ifp->active == IF_ACTIVE_USER)
+				script_runreason(ifp, "STOPPED");
+		}
 		eloop_exit(ctx->eloop, EXIT_FAILURE);
 		return;
 	}
@@ -702,6 +708,21 @@ dhcpcd_initstate(struct interface *ifp, 
 	dhcpcd_initstate1(ifp, ifp->ctx->argc, ifp->ctx->argv, options);
 }
 
+static void
+dhcpcd_reportssid(struct interface *ifp)
+{
+	char pssid[IF_SSIDLEN * 4];
+
+	if (print_string(pssid, sizeof(pssid), OT_ESCSTRING,
+	    ifp->ssid, ifp->ssid_len) == -1)
+	{
+		logerr(__func__);
+		return;
+	}
+
+	loginfox("%s: connected to Access Point `%s'", ifp->name, pssid);
+}
+
 void
 dhcpcd_handlecarrier(struct dhcpcd_ctx *ctx, int carrier, unsigned int flags,
     const char *ifname)
@@ -773,6 +794,7 @@ dhcpcd_handlecarrier(struct dhcpcd_ctx *
 				if (ifp->ssid_len != olen ||
 				    memcmp(ifp->ssid, ossid, ifp->ssid_len))
 				{
+					dhcpcd_reportssid(ifp);
 #ifdef NOCARRIER_PRESERVE_IP
 					dhcpcd_drop(ifp, 0);
 #endif
@@ -970,7 +992,8 @@ run_preinit(struct interface *ifp)
 		return;
 
 	script_runreason(ifp, "PREINIT");
-
+	if (ifp->wireless)
+		dhcpcd_reportssid(ifp);
 	if (ifp->options->options & DHCPCD_LINK && ifp->carrier != LINK_UNKNOWN)
 		script_runreason(ifp,
 		    ifp->carrier == LINK_UP ? "CARRIER" : "NOCARRIER");
@@ -1989,6 +2012,12 @@ printpidfile:
 	    ctx.options & DHCPCD_IPV4 ? " [ip4]" : "",
 	    ctx.options & DHCPCD_IPV6 ? " [ip6]" : "");
 
+#ifdef BSD
+	/* Disable the kernel RTADV sysctl as early as possible. */
+	if (ctx.options & DHCPCD_IPV6 && ctx.options & DHCPCD_IPV6RS)
+		if_disable_rtadv();
+#endif
+
 	if (if_opensockets(&ctx) == -1) {
 		logerr("%s: if_opensockets", __func__);
 		goto exit_failure;
@@ -2127,6 +2156,7 @@ exit1:
 			if_free(ifp);
 		}
 		free(ctx.ifaces);
+		ctx.ifaces = NULL;
 	}
 	free_options(&ctx, ifo);
 #ifdef HAVE_OPEN_MEMSTREAM

Index: src/external/bsd/dhcpcd/dist/src/dhcp6.c
diff -u src/external/bsd/dhcpcd/dist/src/dhcp6.c:1.11.2.2 src/external/bsd/dhcpcd/dist/src/dhcp6.c:1.11.2.3
--- src/external/bsd/dhcpcd/dist/src/dhcp6.c:1.11.2.2	Sat Oct 12 14:44:32 2019
+++ src/external/bsd/dhcpcd/dist/src/dhcp6.c	Fri Nov 22 08:01:49 2019
@@ -3465,23 +3465,10 @@ dhcp6_recvif(struct interface *ifp, cons
 }
 
 static void
-dhcp6_recv(struct dhcpcd_ctx *ctx, struct ipv6_addr *ia)
+dhcp6_recvmsg(struct dhcpcd_ctx *ctx, struct msghdr *msg, 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;
+	struct sockaddr_in6 *from = msg->msg_name;
+	size_t len = msg->msg_iov[0].iov_len;
 	char sfrom[INET6_ADDRSTRLEN];
 	struct interface *ifp;
 	struct dhcp6_message *r;
@@ -3489,14 +3476,7 @@ dhcp6_recv(struct dhcpcd_ctx *ctx, struc
 	uint8_t *o;
 	uint16_t ol;
 
-	s = ia != NULL ? ia->dhcp6_fd : ctx->dhcp6_fd;
-	bytes = recvmsg(s, &msg, 0);
-	if (bytes == -1) {
-		logerr(__func__);
-		return;
-	}
-	len = (size_t)bytes;
-	inet_ntop(AF_INET6, &from.sin6_addr, sfrom, sizeof(sfrom));
+	inet_ntop(AF_INET6, &from->sin6_addr, sfrom, sizeof(sfrom));
 	if (len < sizeof(struct dhcp6_message)) {
 		logerrx("DHCPv6 packet too short from %s", sfrom);
 		return;
@@ -3505,14 +3485,14 @@ dhcp6_recv(struct dhcpcd_ctx *ctx, struc
 	if (ia != NULL)
 		ifp = ia->iface;
 	else {
-		ifp = if_findifpfromcmsg(ctx, &msg, NULL);
+		ifp = if_findifpfromcmsg(ctx, msg, NULL);
 		if (ifp == NULL) {
 			logerr(__func__);
 			return;
 		}
 	}
 
-	r = (struct dhcp6_message *)buf;
+	r = (struct dhcp6_message *)msg->msg_iov[0].iov_base;
 	o = dhcp6_findmoption(r, len, D6_OPTION_CLIENTID, &ol);
 	if (o == NULL || ol != ctx->duid_len ||
 	    memcmp(o, ctx->duid, ol) != 0)
@@ -3581,6 +3561,35 @@ dhcp6_recv(struct dhcpcd_ctx *ctx, struc
 }
 
 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;
+	ssize_t bytes;
+
+	s = ia != NULL ? ia->dhcp6_fd : ctx->dhcp6_fd;
+	bytes = recvmsg(s, &msg, 0);
+	if (bytes == -1) {
+		logerr(__func__);
+		return;
+	}
+
+	iov.iov_len = (size_t)bytes;
+	dhcp6_recvmsg(ctx, &msg, ia);
+}
+
+static void
 dhcp6_recvaddr(void *arg)
 {
 	struct ipv6_addr *ia = arg;
@@ -3677,6 +3686,18 @@ dhcp6_activateinterfaces(struct interfac
 }
 #endif
 
+static int
+dhcp6_open(struct dhcpcd_ctx *ctx)
+{
+
+	if (ctx->dhcp6_fd != -1 ||
+	    (ctx->dhcp6_fd = dhcp6_listen(ctx, NULL)) == -1)
+		return ctx->dhcp6_fd;
+
+	eloop_event_add(ctx->eloop, ctx->dhcp6_fd, dhcp6_recvctx, ctx);
+	return ctx->dhcp6_fd;
+}
+
 static void
 dhcp6_start1(void *arg)
 {
@@ -3687,11 +3708,9 @@ dhcp6_start1(void *arg)
 	size_t i;
 	const struct dhcp_compat *dhc;
 
-	if (ctx->dhcp6_fd == -1 && ctx->options & DHCPCD_MASTER) {
-		ctx->dhcp6_fd = dhcp6_listen(ctx, NULL);
-		if (ctx->dhcp6_fd == -1)
+	if (ctx->options & DHCPCD_MASTER) {
+		if (dhcp6_open(ctx) == -1)
 			return;
-		eloop_event_add(ctx->eloop, ctx->dhcp6_fd, dhcp6_recvctx, ctx);
 	}
 
 	state = D6_STATE(ifp);

Index: src/external/bsd/dhcpcd/dist/src/eloop.c
diff -u src/external/bsd/dhcpcd/dist/src/eloop.c:1.1.1.7 src/external/bsd/dhcpcd/dist/src/eloop.c:1.1.1.7.2.1
--- src/external/bsd/dhcpcd/dist/src/eloop.c:1.1.1.7	Wed Jul 24 09:54:52 2019
+++ src/external/bsd/dhcpcd/dist/src/eloop.c	Fri Nov 22 08:01:50 2019
@@ -830,7 +830,8 @@ eloop_new(void)
 	return eloop;
 }
 
-void eloop_free(struct eloop *eloop)
+void
+eloop_clear(struct eloop *eloop)
 {
 	struct eloop_event *e;
 	struct eloop_timeout *t;
@@ -839,6 +840,12 @@ void eloop_free(struct eloop *eloop)
 		return;
 
 	free(eloop->event_fds);
+	eloop->event_fds = NULL;
+	eloop->events_len = 0;
+	eloop->events_maxfd = -1;
+	eloop->signals = NULL;
+	eloop->signals_len = 0;
+
 	while ((e = TAILQ_FIRST(&eloop->events))) {
 		TAILQ_REMOVE(&eloop->events, e, next);
 		free(e);
@@ -855,11 +862,23 @@ void eloop_free(struct eloop *eloop)
 		TAILQ_REMOVE(&eloop->free_timeouts, t, next);
 		free(t);
 	}
-#if defined(HAVE_KQUEUE) || defined(HAVE_EPOLL)
-	close(eloop->poll_fd);
-#elif defined(HAVE_POLL)
+
+#if defined(HAVE_POLL)
 	free(eloop->fds);
+	eloop->fds = NULL;
+	eloop->fds_len = 0;
+#endif
+}
+
+void
+eloop_free(struct eloop *eloop)
+{
+
+#if defined(HAVE_KQUEUE) || defined(HAVE_EPOLL)
+	if (eloop != NULL)
+		close(eloop->poll_fd);
 #endif
+	eloop_clear(eloop);
 	free(eloop);
 }
 

Index: src/external/bsd/dhcpcd/dist/src/eloop.h
diff -u src/external/bsd/dhcpcd/dist/src/eloop.h:1.1.1.5 src/external/bsd/dhcpcd/dist/src/eloop.h:1.1.1.5.2.1
--- src/external/bsd/dhcpcd/dist/src/eloop.h:1.1.1.5	Wed Jul 24 09:54:52 2019
+++ src/external/bsd/dhcpcd/dist/src/eloop.h	Fri Nov 22 08:01:50 2019
@@ -105,6 +105,7 @@ int eloop_signal_mask(struct eloop *, si
 
 struct eloop * eloop_new(void);
 int eloop_requeue(struct eloop *);
+void eloop_clear(struct eloop *);
 void eloop_free(struct eloop *);
 void eloop_exit(struct eloop *, int);
 int eloop_start(struct eloop *, sigset_t *);

Index: src/external/bsd/dhcpcd/dist/src/if-bsd.c
diff -u src/external/bsd/dhcpcd/dist/src/if-bsd.c:1.10.2.2 src/external/bsd/dhcpcd/dist/src/if-bsd.c:1.10.2.3
--- src/external/bsd/dhcpcd/dist/src/if-bsd.c:1.10.2.2	Sat Oct 12 14:44:32 2019
+++ src/external/bsd/dhcpcd/dist/src/if-bsd.c	Fri Nov 22 08:01:50 2019
@@ -1130,6 +1130,10 @@ if_ifinfo(struct dhcpcd_ctx *ctx, const 
 	case LINK_STATE_UNKNOWN:
 		link_state = LINK_UNKNOWN;
 		break;
+#ifdef LINK_STATE_FULL_DUPLEX
+	case LINK_STATE_HALF_DUPLEX:	/* FALLTHROUGH */
+	case LINK_STATE_FULL_DUPLEX:	/* FALLTHROUGH */
+#endif
 	case LINK_STATE_UP:
 		link_state = LINK_UP;
 		break;
@@ -1484,6 +1488,42 @@ inet6_sysctl(int code, int val, int acti
 }
 #endif
 
+int
+if_applyra(const struct ra *rap)
+{
+#ifdef SIOCSIFINFO_IN6
+	struct in6_ndireq ndi = { .ndi.chlim = 0 };
+	struct priv *priv = rap->iface->ctx->priv;
+	int error;
+
+	strlcpy(ndi.ifname, rap->iface->name, sizeof(ndi.ifname));
+	if (ioctl(priv->pf_inet6_fd, SIOCGIFINFO_IN6, &ndi) == -1)
+		return -1;
+
+	ndi.ndi.linkmtu = rap->mtu;
+	ndi.ndi.chlim = rap->hoplimit;
+	ndi.ndi.retrans = rap->retrans;
+	ndi.ndi.basereachable = rap->reachable;
+	error = ioctl(priv->pf_inet6_fd, SIOCSIFINFO_IN6, &ndi);
+	if (error == -1 && errno == EINVAL) {
+		/*
+		 * Very likely that this is caused by a dodgy MTU
+		 * setting specific to the interface.
+		 * Let's set it to "unspecified" and try again.
+		 * Doesn't really matter as we fix the MTU against the
+		 * routes we add as not all OS support SIOCSIFINFO_IN6.
+		 */
+		ndi.ndi.linkmtu = 0;
+		error = ioctl(priv->pf_inet6_fd, SIOCSIFINFO_IN6, &ndi);
+	}
+	return error;
+#else
+#warning OS does not allow setting of RA bits hoplimit, retrans or reachable
+	UNUSED(rap);
+	return 0;
+#endif
+}
+
 #ifdef IPV6_MANAGETEMPADDR
 #ifndef IPV6CTL_TEMPVLTIME
 #define get_inet6_sysctlbyname(code) inet6_sysctlbyname(code, 0, 0)
@@ -1620,6 +1660,22 @@ set_ifxflags(int s, const struct interfa
 #endif
 
 void
+if_disable_rtadv(void)
+{
+#if defined(IPV6CTL_ACCEPT_RTADV) && !defined(ND6_IFF_ACCEPT_RTADV)
+	int ra = get_inet6_sysctl(IPV6CTL_ACCEPT_RTADV);
+
+	if (ra == -1) {
+		if (errno != ENOENT)
+			logerr("IPV6CTL_ACCEPT_RTADV");
+	else if (ra != 0)
+		if (set_inet6_sysctl(IPV6CTL_ACCEPT_RTADV, 0) == -1)
+			logerr("IPV6CTL_ACCEPT_RTADV");
+	}
+#endif
+}
+
+void
 if_setup_inet6(const struct interface *ifp)
 {
 	struct priv *priv;
@@ -1690,21 +1746,6 @@ if_setup_inet6(const struct interface *i
 		logerr("%s: set_ifxflags", ifp->name);
 #endif
 
-#if defined(IPV6CTL_ACCEPT_RTADV) && !defined(ND6_IFF_ACCEPT_RTADV)
-	/* If we cannot control ra per interface, disable it globally. */
-	if (ifp->options->options & DHCPCD_IPV6RS) {
-		int ra = get_inet6_sysctl(IPV6CTL_ACCEPT_RTADV);
-
-		if (ra == -1) {
-			if (errno != ENOENT)
-				logerr("IPV6CTL_ACCEPT_RTADV");
-		else if (ra != 0)
-			if (set_inet6_sysctl(IPV6CTL_ACCEPT_RTADV, 0) == -1)
-				logerr("IPV6CTL_ACCEPT_RTADV");
-		}
-	}
-#endif
-
 #if defined(IPV6CTL_ACCEPT_RTADV) || defined(ND6_IFF_ACCEPT_RTADV)
 	/* Flush the kernel knowledge of advertised routers
 	 * and prefixes so the kernel does not expire prefixes
Index: src/external/bsd/dhcpcd/dist/src/ipv6nd.c
diff -u src/external/bsd/dhcpcd/dist/src/ipv6nd.c:1.10.2.2 src/external/bsd/dhcpcd/dist/src/ipv6nd.c:1.10.2.3
--- src/external/bsd/dhcpcd/dist/src/ipv6nd.c:1.10.2.2	Sat Oct 12 14:44:32 2019
+++ src/external/bsd/dhcpcd/dist/src/ipv6nd.c	Fri Nov 22 08:01:50 2019
@@ -196,36 +196,41 @@ ipv6nd_printoptions(const struct dhcpcd_
 static int
 ipv6nd_open0(void)
 {
-	int s, on;
+	int fd, on;
 	struct icmp6_filter filt;
 
 #define SOCK_FLAGS	SOCK_CLOEXEC | SOCK_NONBLOCK
-	s = xsocket(PF_INET6, SOCK_RAW | SOCK_FLAGS, IPPROTO_ICMPV6);
+	fd = xsocket(PF_INET6, SOCK_RAW | SOCK_FLAGS, IPPROTO_ICMPV6);
 #undef SOCK_FLAGS
-	if (s == -1)
+	if (fd == -1)
 		return -1;
 
 	/* RFC4861 4.1 */
 	on = 255;
-	if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
+	if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
 	    &on, sizeof(on)) == -1)
 		goto eexit;
 
 	on = 1;
-	if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVHOPLIMIT,
+	if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO,
+	    &on, sizeof(on)) == -1)
+		goto eexit;
+
+	on = 1;
+	if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT,
 	    &on, sizeof(on)) == -1)
 		goto eexit;
 
 	ICMP6_FILTER_SETBLOCKALL(&filt);
 	ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt);
-	if (setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER,
+	if (setsockopt(fd, IPPROTO_ICMPV6, ICMP6_FILTER,
 	    &filt, sizeof(filt)) == -1)
 		goto eexit;
 
-	return s;
+	return fd;
 
 eexit:
-	close(s);
+	close(fd);
 	return -1;
 }
 
@@ -233,7 +238,7 @@ eexit:
 static int
 ipv6nd_open(struct interface *ifp)
 {
-	int s;
+	int fd;
 	struct ipv6_mreq mreq = {
 	    .ipv6mr_multiaddr = IN6ADDR_LINKLOCAL_ALLNODES_INIT,
 	    .ipv6mr_interface = ifp->index
@@ -244,52 +249,44 @@ ipv6nd_open(struct interface *ifp)
 	if (state->nd_fd != -1)
 		return state->nd_fd;
 
-	s = ipv6nd_open0();
-	if (s == -1)
+	fd = ipv6nd_open0();
+	if (fd == -1)
 		return -1;
 
-	if (setsockopt(s, IPPROTO_IPV6, IPV6_BOUND_IF,
+	if (setsockopt(fd, IPPROTO_IPV6, IPV6_BOUND_IF,
 	    &ifindex, sizeof(ifindex)) == -1)
 	{
-		close(s);
+		close(fd);
 		return -1;
 	}
 
-	if (setsockopt(s, IPPROTO_IPV6, IPV6_JOIN_GROUP,
+	if (setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP,
 	    &mreq, sizeof(mreq)) == -1)
 	{
-		close(s);
+		close(fd);
 		return -1;
 	}
 
-	state->nd_fd = s;
-	eloop_event_add(ifp->ctx->eloop, s, ipv6nd_handledata, ifp);
-	return s;
+	state->nd_fd = fd;
+	eloop_event_add(ifp->ctx->eloop, fd, ipv6nd_handledata, ifp);
+	return fd;
 }
 #else
 static int
 ipv6nd_open(struct dhcpcd_ctx *ctx)
 {
-	int s, on;
+	int fd;
 
 	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);
+	fd = ipv6nd_open0();
+	if (fd == -1)
 		return -1;
-	}
 
-	ctx->nd_fd = s;
-	eloop_event_add(ctx->eloop, s, ipv6nd_handledata, ctx);
-	return s;
+	ctx->nd_fd = fd;
+	eloop_event_add(ctx->eloop, fd, ipv6nd_handledata, ctx);
+	return fd;
 }
 #endif
 
@@ -559,6 +556,76 @@ ipv6nd_startexpire(struct interface *ifp
 	    ipv6nd_expire, ifp);
 }
 
+static int
+ipv6nd_rtpref(struct ra *rap)
+{
+
+	switch (rap->flags & ND_RA_FLAG_RTPREF_MASK) {
+	case ND_RA_FLAG_RTPREF_HIGH:
+		return RTPREF_HIGH;
+	case ND_RA_FLAG_RTPREF_MEDIUM:
+	case ND_RA_FLAG_RTPREF_RSV:
+		return RTPREF_MEDIUM;
+	case ND_RA_FLAG_RTPREF_LOW:
+		return RTPREF_LOW;
+	default:
+		logerrx("%s: impossible RA flag %x", __func__, rap->flags);
+		return RTPREF_INVALID;
+	}
+	/* NOTREACHED */
+}
+
+static void
+ipv6nd_sortrouters(struct dhcpcd_ctx *ctx)
+{
+	struct ra_head sorted_routers = TAILQ_HEAD_INITIALIZER(sorted_routers);
+	struct ra *ra1, *ra2;
+
+	while ((ra1 = TAILQ_FIRST(ctx->ra_routers)) != NULL) {
+		TAILQ_REMOVE(ctx->ra_routers, ra1, next);
+		TAILQ_FOREACH(ra2, &sorted_routers, next) {
+			if (ra1->iface->metric < ra2->iface->metric)
+				continue;
+			if (ra1->expired && !ra2->expired)
+				continue;
+			if (ra1->lifetime == 0 && ra2->lifetime != 0)
+				continue;
+			if (!ra1->isreachable && ra2->reachable)
+				continue;
+			if (ipv6nd_rtpref(ra1) < ipv6nd_rtpref(ra2))
+				continue;
+			/* All things being equal, prefer older routers. */
+			if (timespeccmp(&ra1->acquired, &ra2->acquired, >=))
+				continue;
+			TAILQ_INSERT_BEFORE(ra2, ra1, next);
+			break;
+		}
+		if (ra2 == NULL)
+			TAILQ_INSERT_TAIL(&sorted_routers, ra1, next);
+	}
+
+	TAILQ_CONCAT(ctx->ra_routers, &sorted_routers, next);
+}
+
+static void
+ipv6nd_applyra(struct dhcpcd_ctx *ctx, struct interface *ifp)
+{
+	struct ra *rap;
+	struct rs_state *state = RS_STATE(ifp);
+
+	TAILQ_FOREACH(rap, ctx->ra_routers, next) {
+		if (rap->iface == ifp)
+			break;
+	}
+
+	if (rap == NULL)
+		return;
+
+	state->retrans = rap->retrans;
+	if (if_applyra(rap) == -1)
+		logerr(__func__);
+}
+
 /*
  * Neighbour reachability.
  *
@@ -585,23 +652,20 @@ ipv6nd_neighbour(struct dhcpcd_ctx *ctx,
 			break;
 	}
 
-	if (rap == NULL || rap->expired)
+	if (rap == NULL || rap->expired || rap->reachable == reachable)
 		return;
 
-	if (reachable) {
-		if (rap->isreachable)
-			return;
-		loginfox("%s: %s is reachable again",
-		    rap->iface->name, rap->sfrom);
-		rap->isreachable = true;
+	rap->isreachable = reachable;
+	loginfox("%s: %s is %s", rap->iface->name, rap->sfrom,
+	    reachable ? "reachable again" : "unreachable");
+
+	/* See if we can install a reachable default router. */
+	ipv6nd_sortrouters(ctx);
+	ipv6nd_applyra(ctx, rap->iface);
+	rt_build(ctx, AF_INET6);
+
+	if (reachable)
 		return;
-	} else {
-		if (!rap->isreachable)
-			return;
-		logwarnx("%s: %s is unreachable",
-		    rap->iface->name, rap->sfrom);
-		rap->isreachable = false;
-	}
 
 	/* If we have no reachable default routers, try and solicit one. */
 	TAILQ_FOREACH(rapr, ctx->ra_routers, next) {
@@ -723,42 +787,6 @@ ipv6nd_free(struct interface *ifp)
 }
 
 static int
-rtpref(struct ra *rap)
-{
-
-	switch (rap->flags & ND_RA_FLAG_RTPREF_MASK) {
-	case ND_RA_FLAG_RTPREF_HIGH:
-		return (RTPREF_HIGH);
-	case ND_RA_FLAG_RTPREF_MEDIUM:
-	case ND_RA_FLAG_RTPREF_RSV:
-		return (RTPREF_MEDIUM);
-	case ND_RA_FLAG_RTPREF_LOW:
-		return (RTPREF_LOW);
-	default:
-		logerrx("rtpref: impossible RA flag %x", rap->flags);
-		return (RTPREF_INVALID);
-	}
-	/* NOTREACHED */
-}
-
-static void
-add_router(struct dhcpcd_ctx *ctx, struct ra *router)
-{
-	struct ra *rap;
-
-	TAILQ_FOREACH(rap, ctx->ra_routers, next) {
-		if (router->iface->metric < rap->iface->metric ||
-		    (router->iface->metric == rap->iface->metric &&
-		    rtpref(router) > rtpref(rap)))
-		{
-			TAILQ_INSERT_BEFORE(rap, router, next);
-			return;
-		}
-	}
-	TAILQ_INSERT_TAIL(ctx->ra_routers, router, next);
-}
-
-static int
 ipv6nd_scriptrun(struct ra *rap)
 {
 	int hasdns, hasaddress, pid;
@@ -965,6 +993,7 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx,
 	struct dhcp_opt *dho;
 	bool new_rap, new_data, has_address;
 	uint32_t old_lifetime;
+	int ifmtu;
 	__printflike(1, 2) void (*logfunc)(const char *, ...);
 #ifdef IPV6_MANAGETEMPADDR
 	uint8_t new_ap;
@@ -1074,20 +1103,25 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx,
 	if (!new_rap && rap->lifetime == 0 && old_lifetime != 0)
 		logwarnx("%s: %s: no longer a default router",
 		    ifp->name, rap->sfrom);
-	if (nd_ra->nd_ra_reachable) {
+	if (nd_ra->nd_ra_curhoplimit != 0)
+		rap->hoplimit = nd_ra->nd_ra_curhoplimit;
+	else
+		rap->hoplimit = IPV6_DEFHLIM;
+	if (nd_ra->nd_ra_reachable != 0) {
 		rap->reachable = ntohl(nd_ra->nd_ra_reachable);
 		if (rap->reachable > MAX_REACHABLE_TIME)
 			rap->reachable = 0;
-	}
-	if (nd_ra->nd_ra_retransmit) {
-		struct rs_state *state = RS_STATE(ifp);
-
-		state->retrans = rap->retrans = ntohl(nd_ra->nd_ra_retransmit);
-	}
+	} else
+		rap->reachable = REACHABLE_TIME;
+	if (nd_ra->nd_ra_retransmit != 0)
+		rap->retrans = ntohl(nd_ra->nd_ra_retransmit);
+	else
+		rap->retrans = RETRANS_TIMER;
 	rap->expired = false;
 	rap->hasdns = false;
 	rap->isreachable = true;
 	has_address = false;
+	rap->mtu = 0;
 
 #ifdef IPV6_AF_TEMPORARY
 	ipv6_markaddrsstale(ifp, IPV6_AF_TEMPORARY);
@@ -1245,22 +1279,30 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx,
 
 		case ND_OPT_MTU:
 			if (len < sizeof(mtu)) {
-				logerrx("%s: short MTU option", ifp->name);
+				logfunc("%s: short MTU option", ifp->name);
 				break;
 			}
 			memcpy(&mtu, p, sizeof(mtu));
 			mtu.nd_opt_mtu_mtu = ntohl(mtu.nd_opt_mtu_mtu);
 			if (mtu.nd_opt_mtu_mtu < IPV6_MMTU) {
-				logerrx("%s: invalid MTU %d",
+				logfunc("%s: invalid MTU %d",
 				    ifp->name, mtu.nd_opt_mtu_mtu);
 				break;
 			}
-			rap->mtu = mtu.nd_opt_mtu_mtu;
+			ifmtu = if_getmtu(ifp);
+			if (ifmtu == -1)
+				logerr("if_getmtu");
+			else if (mtu.nd_opt_mtu_mtu > (uint32_t)ifmtu) {
+				logfunc("%s: advertised MTU %d"
+				    " is greater than link MTU %d",
+				    ifp->name, mtu.nd_opt_mtu_mtu, ifmtu);
+				rap->mtu = (uint32_t)ifmtu;
+			} else
+				rap->mtu = mtu.nd_opt_mtu_mtu;
 			break;
-
 		case ND_OPT_RDNSS:
 			if (len < sizeof(rdnss)) {
-				logerrx("%s: short RDNSS option", ifp->name);
+				logfunc("%s: short RDNSS option", ifp->name);
 				break;
 			}
 			memcpy(&rdnss, p, sizeof(rdnss));
@@ -1295,12 +1337,15 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx,
 		    ifp->name);
 
 	if (new_rap)
-		add_router(ifp->ctx, rap);
+		TAILQ_INSERT_TAIL(ctx->ra_routers, rap, next);
+	if (new_data)
+		ipv6nd_sortrouters(ifp->ctx);
 
 	if (ifp->ctx->options & DHCPCD_TEST) {
 		script_runreason(ifp, "TEST");
 		goto handle_flag;
 	}
+	ipv6nd_applyra(ifp->ctx, ifp);
 	ipv6_addaddrs(&rap->addrs);
 #ifdef IPV6_MANAGETEMPADDR
 	ipv6_addtempaddrs(ifp, &rap->acquired);
@@ -1719,70 +1764,37 @@ ipv6nd_drop(struct interface *ifp)
 }
 
 static void
-ipv6nd_handledata(void *arg)
+ipv6nd_recvmsg(struct dhcpcd_ctx *ctx, struct msghdr *msg)
 {
-	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 sockaddr_in6 *from = (struct sockaddr_in6 *)msg->msg_name;
 	char sfrom[INET6_ADDRSTRLEN];
 	int hoplimit = 0;
 	struct icmp6_hdr *icp;
 	struct interface *ifp;
+	size_t len = msg->msg_iov[0].iov_len;
 
-#ifdef __sun
-	struct rs_state *state;
-
-	ifp = arg;
-	state = RS_STATE(ifp);
-	ctx = ifp->ctx;
-	s = state->nd_fd;
-#else
-	ctx = arg;
-	s = ctx->nd_fd;
-#endif
-	len = recvmsg(s, &msg, 0);
-	if (len == -1) {
-		logerr(__func__);
-		return;
-	}
-	inet_ntop(AF_INET6, &from.sin6_addr, sfrom, sizeof(sfrom));
+	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", sfrom);
 		return;
 	}
 
-#ifdef __sun
-	if_findifpfromcmsg(ctx, &msg, &hoplimit);
-#else
-	ifp = if_findifpfromcmsg(ctx, &msg, &hoplimit);
+	ifp = if_findifpfromcmsg(ctx, msg, &hoplimit);
 	if (ifp == NULL) {
 		logerr(__func__);
 		return;
 	}
-#endif
 
 	/* Don't do anything if the user hasn't configured it. */
 	if (ifp->active != IF_ACTIVE_USER ||
 	    !(ifp->options->options & DHCPCD_IPV6))
 		return;
 
-	icp = (struct icmp6_hdr *)buf;
+	icp = (struct icmp6_hdr *)msg->msg_iov[0].iov_base;
 	if (icp->icmp6_code == 0) {
 		switch(icp->icmp6_type) {
 			case ND_ROUTER_ADVERT:
-				ipv6nd_handlera(ctx, &from, sfrom,
+				ipv6nd_handlera(ctx, from, sfrom,
 				    ifp, icp, (size_t)len, hoplimit);
 				return;
 		}
@@ -1793,6 +1805,47 @@ ipv6nd_handledata(void *arg)
 }
 
 static void
+ipv6nd_handledata(void *arg)
+{
+	struct dhcpcd_ctx *ctx;
+	int fd;
+	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;
+
+#ifdef __sun
+	struct interface *ifp;
+	struct rs_state *state;
+
+	ifp = arg;
+	state = RS_STATE(ifp);
+	ctx = ifp->ctx;
+	fd = state->nd_fd;
+#else
+	ctx = arg;
+	fd = ctx->nd_fd;
+#endif
+	len = recvmsg(fd, &msg, 0);
+	if (len == -1) {
+		logerr(__func__);
+		return;
+	}
+
+	iov.iov_len = (size_t)len;
+	ipv6nd_recvmsg(ctx, &msg);
+}
+
+static void
 ipv6nd_startrs1(void *arg)
 {
 	struct interface *ifp = arg;

Index: src/external/bsd/dhcpcd/dist/src/if.c
diff -u src/external/bsd/dhcpcd/dist/src/if.c:1.1.1.14.2.2 src/external/bsd/dhcpcd/dist/src/if.c:1.1.1.14.2.3
--- src/external/bsd/dhcpcd/dist/src/if.c:1.1.1.14.2.2	Sat Oct 12 14:44:32 2019
+++ src/external/bsd/dhcpcd/dist/src/if.c	Fri Nov 22 08:01:50 2019
@@ -740,9 +740,13 @@ if_findifpfromcmsg(struct dhcpcd_ctx *ct
 	struct cmsghdr *cm;
 	unsigned int ifindex = 0;
 	struct interface *ifp;
-#if defined(INET) && defined(IP_PKTINFO)
+#ifdef INET
+#ifdef IP_RECVIF
+	struct sockaddr_dl sdl;
+#else
 	struct in_pktinfo ipi;
 #endif
+#endif
 #ifdef INET6
 	struct in6_pktinfo ipi6;
 #else
@@ -753,15 +757,27 @@ if_findifpfromcmsg(struct dhcpcd_ctx *ct
 	     cm;
 	     cm = (struct cmsghdr *)CMSG_NXTHDR(msg, cm))
 	{
-#if defined(INET) && defined(IP_PKTINFO)
+#ifdef INET
 		if (cm->cmsg_level == IPPROTO_IP) {
 			switch(cm->cmsg_type) {
+#ifdef IP_RECVIF
+			case IP_RECVIF:
+				if (cm->cmsg_len <
+				    offsetof(struct sockaddr_dl, sdl_index) +
+				    sizeof(sdl.sdl_index))
+					continue;
+				memcpy(&sdl, CMSG_DATA(cm),
+				    MIN(sizeof(sdl), cm->cmsg_len));
+				ifindex = sdl.sdl_index;
+				break;
+#else
 			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
 			}
 		}
 #endif

Index: src/external/bsd/dhcpcd/dist/src/if.h
diff -u src/external/bsd/dhcpcd/dist/src/if.h:1.1.1.10.2.2 src/external/bsd/dhcpcd/dist/src/if.h:1.1.1.10.2.3
--- src/external/bsd/dhcpcd/dist/src/if.h:1.1.1.10.2.2	Sat Oct 12 14:44:32 2019
+++ src/external/bsd/dhcpcd/dist/src/if.h	Fri Nov 22 08:01:50 2019
@@ -65,6 +65,7 @@
 #include "dhcpcd.h"
 #include "ipv4.h"
 #include "ipv6.h"
+#include "ipv6nd.h"
 #include "route.h"
 
 #define EUI64_ADDR_LEN			8
@@ -195,6 +196,7 @@ int if_addrflags(const struct interface 
 #endif
 
 #ifdef INET6
+void if_disable_rtadv(void);
 void if_setup_inet6(const struct interface *);
 #ifdef IPV6_MANAGETEMPADDR
 int ip6_use_tempaddr(const char *ifname);
@@ -205,6 +207,7 @@ int ip6_temp_valid_lifetime(const char *
 #endif
 int ip6_forwarding(const char *ifname);
 
+int if_applyra(const struct ra *);
 int if_address6(unsigned char, const struct ipv6_addr *);
 int if_addrflags6(const struct interface *, const struct in6_addr *,
     const char *);

Index: src/external/bsd/dhcpcd/dist/src/ipv4.c
diff -u src/external/bsd/dhcpcd/dist/src/ipv4.c:1.1.1.16.2.2 src/external/bsd/dhcpcd/dist/src/ipv4.c:1.1.1.16.2.3
--- src/external/bsd/dhcpcd/dist/src/ipv4.c:1.1.1.16.2.2	Sat Oct 12 14:44:32 2019
+++ src/external/bsd/dhcpcd/dist/src/ipv4.c	Fri Nov 22 08:01:50 2019
@@ -654,7 +654,7 @@ ipv4_addaddr(struct interface *ifp, cons
 #endif
 		ia->flags = IPV4_AF_NEW;
 	} else
-		ia->flags |= ~IPV4_AF_NEW;
+		ia->flags &= ~IPV4_AF_NEW;
 
 	ia->mask = *mask;
 	ia->brd = *bcast;
@@ -687,7 +687,8 @@ ipv4_addaddr(struct interface *ifp, cons
 		if (errno != EEXIST)
 			logerr("%s: if_addaddress",
 			    __func__);
-		free(ia);
+		if (ia->flags & IPV4_AF_NEW)
+			free(ia);
 		return NULL;
 	}
 
@@ -941,7 +942,7 @@ ipv4_handleifa(struct dhcpcd_ctx *ctx,
 #endif
 	}
 
-	if (cmd == RTM_DELADDR && ia != NULL)
+	if (cmd == RTM_DELADDR)
 		free(ia);
 }
 
@@ -951,15 +952,13 @@ ipv4_free(struct interface *ifp)
 	struct ipv4_state *state;
 	struct ipv4_addr *ia;
 
-	if (ifp) {
-		state = IPV4_STATE(ifp);
-		if (state) {
-		        while ((ia = TAILQ_FIRST(&state->addrs))) {
-				TAILQ_REMOVE(&state->addrs, ia, next);
-				free(ia);
-			}
-			free(state->buffer);
-			free(state);
-		}
+	if (ifp == NULL || (state = IPV4_STATE(ifp)) == NULL)
+		return;
+
+	while ((ia = TAILQ_FIRST(&state->addrs))) {
+		TAILQ_REMOVE(&state->addrs, ia, next);
+		free(ia);
 	}
+	free(state->buffer);
+	free(state);
 }

Index: src/external/bsd/dhcpcd/dist/src/ipv6nd.h
diff -u src/external/bsd/dhcpcd/dist/src/ipv6nd.h:1.1.1.10.2.1 src/external/bsd/dhcpcd/dist/src/ipv6nd.h:1.1.1.10.2.2
--- src/external/bsd/dhcpcd/dist/src/ipv6nd.h:1.1.1.10.2.1	Thu Sep  5 08:56:55 2019
+++ src/external/bsd/dhcpcd/dist/src/ipv6nd.h	Fri Nov 22 08:01:50 2019
@@ -50,6 +50,7 @@ struct ra {
 	uint32_t reachable;
 	uint32_t retrans;
 	uint32_t mtu;
+	uint8_t hoplimit;
 	struct ipv6_addrhead addrs;
 	bool hasdns;
 	bool expired;
@@ -78,6 +79,10 @@ struct rs_state {
 #define	RTR_SOLICITATION_INTERVAL	4	/* seconds */
 #define	MAX_RTR_SOLICITATIONS		3	/* times */
 #define	MAX_NEIGHBOR_ADVERTISEMENT	3	/* 3 transmissions */
+
+#ifndef IPV6_DEFHLIM
+#define	IPV6_DEFHLIM			64
+#endif
 #endif
 
 /* On carrier up, expire known routers after RTR_CARRIER_EXPIRE seconds. */
Index: src/external/bsd/dhcpcd/dist/src/script.c
diff -u src/external/bsd/dhcpcd/dist/src/script.c:1.1.1.10.2.1 src/external/bsd/dhcpcd/dist/src/script.c:1.1.1.10.2.2
--- src/external/bsd/dhcpcd/dist/src/script.c:1.1.1.10.2.1	Thu Sep  5 08:56:55 2019
+++ src/external/bsd/dhcpcd/dist/src/script.c	Fri Nov 22 08:01:50 2019
@@ -86,9 +86,9 @@ if_printoptions(void)
 }
 
 static int
-exec_script(const struct dhcpcd_ctx *ctx, char *const *argv, char *const *env)
+script_exec(const struct dhcpcd_ctx *ctx, char *const *argv, char *const *env)
 {
-	pid_t pid;
+	pid_t pid = 0;
 	posix_spawnattr_t attr;
 	int r;
 #ifdef USE_SIGNALS
@@ -173,14 +173,55 @@ efprintf(FILE *fp, const char *fmt, ...)
 	return r;
 }
 
+static char **
+script_buftoenv(struct dhcpcd_ctx *ctx, char *buf, size_t len)
+{
+	char **env, **envp, *bufp, *endp;
+	size_t nenv;
+
+	/* Count the terminated env strings.
+	 * Assert that the terminations are correct. */
+	nenv = 0;
+	endp = buf + len;
+	for (bufp = buf; bufp < endp; bufp++) {
+		if (*bufp == '\0') {
+#ifndef NDEBUG
+			if (bufp + 1 < endp)
+				assert(*(bufp + 1) != '\0');
+#endif
+			nenv++;
+		}
+	}
+	assert(*(bufp - 1) == '\0');
+
+	if (ctx->script_envlen < nenv) {
+		env = reallocarray(ctx->script_env, nenv + 1, sizeof(*env));
+		if (env == NULL)
+			return NULL;
+		ctx->script_env = env;
+		ctx->script_envlen = nenv;
+	}
+
+	bufp = buf;
+	envp = ctx->script_env;
+	*envp++ = bufp++;
+	endp--; /* Avoid setting the last \0 to an invalid pointer */
+	for (; bufp < endp; bufp++) {
+		if (*bufp == '\0')
+			*envp++ = bufp + 1;
+	}
+	*envp = NULL;
+
+	return ctx->script_env;
+}
+
 static long
 make_env(const struct interface *ifp, const char *reason)
 {
 	struct dhcpcd_ctx *ctx = ifp->ctx;
 	FILE *fp;
-	char **env, **envp, *bufp, *endp, *path;
-	size_t nenv;
 	long buf_pos, i;
+	char *path;
 	int protocol = PROTO_LINK;
 	const struct if_options *ifo = ifp->options;
 	const struct interface *ifp2;
@@ -377,7 +418,7 @@ make_env(const struct interface *ifp, co
 		if (efprintf(fp, "syslog_debug=true") == -1)
 			goto eexit;
 	}
-	if (*ifp->profile) {
+	if (*ifp->profile != '\0') {
 		if (efprintf(fp, "profile=%s", ifp->profile) == -1)
 			goto eexit;
 	}
@@ -476,38 +517,8 @@ dumplease:
 	fp = NULL;
 #endif
 
-	/* Count the terminated env strings.
-	 * Assert that the terminations are correct. */
-	nenv = 0;
-	endp = ctx->script_buf + buf_pos;
-	for (bufp = ctx->script_buf; bufp < endp; bufp++) {
-		if (*bufp == '\0') {
-#ifndef NDEBUG
-			if (bufp + 1 < endp)
-				assert(*(bufp + 1) != '\0');
-#endif
-			nenv++;
-		}
-	}
-	assert(*(bufp - 1) == '\0');
-
-	if (ctx->script_envlen < nenv) {
-		env = reallocarray(ctx->script_env, nenv + 1, sizeof(*env));
-		if (env == NULL)
-			goto eexit;
-		ctx->script_env = env;
-		ctx->script_envlen = nenv;
-	}
-
-	bufp = ctx->script_buf;
-	envp = ctx->script_env;
-	*envp++ = bufp++;
-	endp--; /* Avoid setting the last \0 to an invalid pointer */
-	for (; bufp < endp; bufp++) {
-		if (*bufp == '\0')
-			*envp++ = bufp + 1;
-	}
-	*envp = NULL;
+	if (script_buftoenv(ctx, ctx->script_buf, (size_t)buf_pos) == NULL)
+		goto eexit;
 
 	return buf_pos - 1;
 
@@ -620,7 +631,7 @@ script_runreason(const struct interface 
 	argv[1] = NULL;
 	logdebugx("%s: executing `%s' %s", ifp->name, argv[0], reason);
 
-	pid = exec_script(ctx, argv, ctx->script_env);
+	pid = script_exec(ctx, argv, ctx->script_env);
 	if (pid == -1)
 		logerr("%s: %s", __func__, argv[0]);
 	else if (pid != 0) {

Reply via email to