Module Name:    src
Committed By:   roy
Date:           Fri Apr 21 16:54:26 UTC 2023

Modified Files:
        src/external/bsd/dhcpcd/dist/hooks: 20-resolv.conf 29-lookup-hostname
            30-hostname 50-ntp.conf
        src/external/bsd/dhcpcd/dist/src: bpf.c dhcp.c dhcp6.c dhcpcd.c
            if-bsd.c if-options.c ipv6.c ipv6.h ipv6nd.c logerr.c privsep.c
            script.c

Log Message:
Merge changes


To generate a diff of this commit:
cvs rdiff -u -r1.6 -r1.7 src/external/bsd/dhcpcd/dist/hooks/20-resolv.conf
cvs rdiff -u -r1.2 -r1.3 \
    src/external/bsd/dhcpcd/dist/hooks/29-lookup-hostname
cvs rdiff -u -r1.5 -r1.6 src/external/bsd/dhcpcd/dist/hooks/30-hostname \
    src/external/bsd/dhcpcd/dist/hooks/50-ntp.conf
cvs rdiff -u -r1.18 -r1.19 src/external/bsd/dhcpcd/dist/src/bpf.c
cvs rdiff -u -r1.46 -r1.47 src/external/bsd/dhcpcd/dist/src/dhcp.c
cvs rdiff -u -r1.28 -r1.29 src/external/bsd/dhcpcd/dist/src/dhcp6.c \
    src/external/bsd/dhcpcd/dist/src/ipv6nd.c
cvs rdiff -u -r1.49 -r1.50 src/external/bsd/dhcpcd/dist/src/dhcpcd.c
cvs rdiff -u -r1.27 -r1.28 src/external/bsd/dhcpcd/dist/src/if-bsd.c
cvs rdiff -u -r1.32 -r1.33 src/external/bsd/dhcpcd/dist/src/if-options.c
cvs rdiff -u -r1.17 -r1.18 src/external/bsd/dhcpcd/dist/src/ipv6.c
cvs rdiff -u -r1.13 -r1.14 src/external/bsd/dhcpcd/dist/src/ipv6.h \
    src/external/bsd/dhcpcd/dist/src/privsep.c
cvs rdiff -u -r1.12 -r1.13 src/external/bsd/dhcpcd/dist/src/logerr.c
cvs rdiff -u -r1.14 -r1.15 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/external/bsd/dhcpcd/dist/hooks/20-resolv.conf
diff -u src/external/bsd/dhcpcd/dist/hooks/20-resolv.conf:1.6 src/external/bsd/dhcpcd/dist/hooks/20-resolv.conf:1.7
--- src/external/bsd/dhcpcd/dist/hooks/20-resolv.conf:1.6	Mon Dec 28 13:57:40 2020
+++ src/external/bsd/dhcpcd/dist/hooks/20-resolv.conf	Fri Apr 21 16:54:26 2023
@@ -11,7 +11,7 @@ nocarrier_roaming_dir="$state_dir/roamin
 NL="
 "
 : ${resolvconf:=resolvconf}
-if type "$resolvconf" >/dev/null 2>&1; then
+if command -v "$resolvconf" >/dev/null 2>&1; then
 	have_resolvconf=true
 else
 	have_resolvconf=false

Index: src/external/bsd/dhcpcd/dist/hooks/29-lookup-hostname
diff -u src/external/bsd/dhcpcd/dist/hooks/29-lookup-hostname:1.2 src/external/bsd/dhcpcd/dist/hooks/29-lookup-hostname:1.3
--- src/external/bsd/dhcpcd/dist/hooks/29-lookup-hostname:1.2	Sat Sep 22 13:17:46 2018
+++ src/external/bsd/dhcpcd/dist/hooks/29-lookup-hostname	Fri Apr 21 16:54:26 2023
@@ -4,20 +4,20 @@ lookup_hostname()
 {
 	[ -z "$new_ip_address" ] && return 1
 	# Silly ISC programs love to send error text to stdout
-	if type dig >/dev/null 2>&1; then
+	if command -v dig >/dev/null 2>&1; then
 		h=$(dig +short -x $new_ip_address)
 		if [ $? = 0 ]; then
 			echo "$h" | sed 's/\.$//'
 			return 0
 		fi
-	elif type host >/dev/null 2>&1; then
+	elif command -v host >/dev/null 2>&1; then
 		h=$(host $new_ip_address)
 		if [ $? = 0 ]; then 
 			echo "$h" \
 			| sed 's/.* domain name pointer \(.*\)./\1/'
 			return 0
 		fi
-	elif type getent >/dev/null 2>&1; then
+	elif command -v getent >/dev/null 2>&1; then
 		h=$(getent hosts $new_ip_address)
 		if [ $? = 0 ]; then
 			echo "$h" | sed 's/[^ ]* *\([^ ]*\).*/\1/'

Index: src/external/bsd/dhcpcd/dist/hooks/30-hostname
diff -u src/external/bsd/dhcpcd/dist/hooks/30-hostname:1.5 src/external/bsd/dhcpcd/dist/hooks/30-hostname:1.6
--- src/external/bsd/dhcpcd/dist/hooks/30-hostname:1.5	Fri Oct 22 13:23:20 2021
+++ src/external/bsd/dhcpcd/dist/hooks/30-hostname	Fri Apr 21 16:54:26 2023
@@ -25,7 +25,7 @@ _hostname()
 	if [ -z "${1+x}" ]; then
 		if [ -r /proc/sys/kernel/hostname ]; then
 			read name </proc/sys/kernel/hostname && echo "$name"
-		elif type hostname >/dev/null 2>/dev/null; then
+		elif command -v hostname >/dev/null 2>/dev/null; then
 			hostname
 		elif sysctl kern.hostname >/dev/null 2>&1; then
 			sysctl -n kern.hostname
@@ -39,7 +39,7 @@ _hostname()
 
 	if [ -w /proc/sys/kernel/hostname ]; then
 		echo "$1" >/proc/sys/kernel/hostname
-	elif [ -n "$1" ] && type hostname >/dev/null 2>&1; then
+	elif [ -n "$1" ] && command -v hostname >/dev/null 2>&1; then
 		hostname "$1"
 	elif sysctl kern.hostname >/dev/null 2>&1; then
 		sysctl -w "kern.hostname=$1" >/dev/null
Index: src/external/bsd/dhcpcd/dist/hooks/50-ntp.conf
diff -u src/external/bsd/dhcpcd/dist/hooks/50-ntp.conf:1.5 src/external/bsd/dhcpcd/dist/hooks/50-ntp.conf:1.6
--- src/external/bsd/dhcpcd/dist/hooks/50-ntp.conf:1.5	Fri Nov 20 13:24:58 2020
+++ src/external/bsd/dhcpcd/dist/hooks/50-ntp.conf	Fri Apr 21 16:54:26 2023
@@ -43,7 +43,7 @@ fi
 
 # Debian has a separate file for DHCP config to avoid stamping on
 # the master.
-if [ "$ntp_service" = ntpd ] && type invoke-rc.d >/dev/null 2>&1; then
+if [ "$ntp_service" = ntpd ] && command -v invoke-rc.d >/dev/null 2>&1; then
 	[ -e /var/lib/ntp ] || mkdir /var/lib/ntp
 	: ${ntp_service:=ntp}
 	: ${NTP_DHCP_CONF:=/var/lib/ntp/ntp.conf.dhcp}
@@ -113,7 +113,7 @@ add_ntp_conf()
 	[ -e "$cf" ] && rm "$cf"
 	[ -d "$ntp_conf_dir" ] || mkdir -p "$ntp_conf_dir"
 	if [ -n "$new_ntp_servers" ]; then
-		for x in $new_ntp_servers; do
+		for x in $(uniqify $new_ntp_servers); do
 			echo "server $x" >> "$cf"
 		done
 	fi
@@ -131,7 +131,7 @@ remove_ntp_conf()
 # For ease of use, map DHCP6 names onto our DHCP4 names
 case "$reason" in
 BOUND6|RENEW6|REBIND6|REBOOT6|INFORM6)
-	new_ntp_servers="$new_dhcp6_sntp_servers"
+	new_ntp_servers="$new_dhcp6_sntp_servers $new_dhcp6_ntp_server_addr $new_dhcp6_ntp_server_fqdn"
 ;;
 esac
 

Index: src/external/bsd/dhcpcd/dist/src/bpf.c
diff -u src/external/bsd/dhcpcd/dist/src/bpf.c:1.18 src/external/bsd/dhcpcd/dist/src/bpf.c:1.19
--- src/external/bsd/dhcpcd/dist/src/bpf.c:1.18	Fri Oct 22 13:23:20 2021
+++ src/external/bsd/dhcpcd/dist/src/bpf.c	Fri Apr 21 16:54:26 2023
@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: BSD-2-Clause */
 /*
  * dhcpcd: BPF arp and bootp filtering
- * Copyright (c) 2006-2021 Roy Marples <r...@marples.name>
+ * Copyright (c) 2006-2023 Roy Marples <r...@marples.name>
  * All rights reserved
 
  * Redistribution and use in source and binary forms, with or without
@@ -45,7 +45,6 @@
 
 #include <errno.h>
 #include <fcntl.h>
-#include <paths.h>
 #include <stddef.h>
 #include <stdlib.h>
 #include <string.h>
@@ -155,6 +154,11 @@ bpf_open(const struct interface *ifp,
 	struct bpf_version pv = { .bv_major = 0, .bv_minor = 0 };
 	struct ifreq ifr = { .ifr_flags = 0 };
 	int ibuf_len = 0;
+#ifdef O_CLOEXEC
+#define BPF_OPEN_FLAGS O_RDWR | O_NONBLOCK | O_CLOEXEC
+#else
+#define BPF_OPEN_FLAGS O_RDWR | O_NONBLOCK
+#endif
 #ifdef BIOCIMMEDIATE
 	unsigned int flags;
 #endif
@@ -167,25 +171,19 @@ bpf_open(const struct interface *ifp,
 		return NULL;
 	bpf->bpf_ifp = ifp;
 
-#ifdef _PATH_BPF
-	bpf->bpf_fd = open(_PATH_BPF, O_RDWR | O_NONBLOCK
-#ifdef O_CLOEXEC
-		| O_CLOEXEC
-#endif
-	);
-#else
-	char device[32];
-	int n = 0;
+	/* /dev/bpf is a cloner on modern kernels */
+	bpf->bpf_fd = open("/dev/bpf", BPF_OPEN_FLAGS);
 
-	do {
-		snprintf(device, sizeof(device), "/dev/bpf%d", n++);
-		bpf->bpf_fd = open(device, O_RDWR | O_NONBLOCK
-#ifdef O_CLOEXEC
-				| O_CLOEXEC
-#endif
-		);
-	} while (bpf->bpf_fd == -1 && errno == EBUSY);
-#endif
+	/* Support older kernels where /dev/bpf is not a cloner */
+	if (bpf->bpf_fd == -1) {
+		char device[32];
+		int n = 0;
+
+		do {
+			snprintf(device, sizeof(device), "/dev/bpf%d", n++);
+			bpf->bpf_fd = open(device, BPF_OPEN_FLAGS);
+		} while (bpf->bpf_fd == -1 && errno == EBUSY);
+	}
 
 	if (bpf->bpf_fd == -1)
 		goto eexit;

Index: src/external/bsd/dhcpcd/dist/src/dhcp.c
diff -u src/external/bsd/dhcpcd/dist/src/dhcp.c:1.46 src/external/bsd/dhcpcd/dist/src/dhcp.c:1.47
--- src/external/bsd/dhcpcd/dist/src/dhcp.c:1.46	Fri Oct 22 13:23:20 2021
+++ src/external/bsd/dhcpcd/dist/src/dhcp.c	Fri Apr 21 16:54:26 2023
@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: BSD-2-Clause */
 /*
  * dhcpcd - DHCP client daemon
- * Copyright (c) 2006-2021 Roy Marples <r...@marples.name>
+ * Copyright (c) 2006-2023 Roy Marples <r...@marples.name>
  * All rights reserved
 
  * Redistribution and use in source and binary forms, with or without
@@ -84,11 +84,6 @@
 /* We should define a maximum for the NAK exponential backoff */
 #define NAKOFF_MAX              60
 
-/* Wait N nanoseconds between sending a RELEASE and dropping the address.
- * This gives the kernel enough time to actually send it. */
-#define RELEASE_DELAY_S		0
-#define RELEASE_DELAY_NS	10000000
-
 #ifndef IPDEFTTL
 #define IPDEFTTL 64 /* RFC1340 */
 #endif
@@ -137,7 +132,7 @@ static void dhcp_arp_found(struct arp_st
 #endif
 static void dhcp_handledhcp(struct interface *, struct bootp *, size_t,
     const struct in_addr *);
-static void dhcp_handleifudp(void *);
+static void dhcp_handleifudp(void *, unsigned short);
 static int dhcp_initstate(struct interface *);
 
 void
@@ -400,7 +395,7 @@ print_rfc3442(FILE *fp, const uint8_t *d
 
 static int
 decode_rfc3442_rt(rb_tree_t *routes, struct interface *ifp,
-    const uint8_t *data, size_t dl, const struct bootp *bootp)
+    const uint8_t *data, size_t dl)
 {
 	const uint8_t *p = data;
 	const uint8_t *e;
@@ -447,15 +442,6 @@ decode_rfc3442_rt(rb_tree_t *routes, str
 		memcpy(&gateway.s_addr, p, 4);
 		p += 4;
 
-		/* 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 ||
-		    gateway.s_addr == bootp->ciaddr))
-		{
-			gateway.s_addr = INADDR_ANY;
-			netmask.s_addr = INADDR_BROADCAST;
-		}
 		if (netmask.s_addr == INADDR_BROADCAST)
 			rt->rt_flags = RTF_HOST;
 
@@ -594,7 +580,7 @@ get_option_routes(rb_tree_t *routes, str
 		if (p)
 			csr = "MS ";
 	}
-	if (p && (n = decode_rfc3442_rt(routes, ifp, p, len, bootp)) != -1) {
+	if (p && (n = decode_rfc3442_rt(routes, ifp, p, len)) != -1) {
 		const struct dhcp_state *state;
 
 		state = D_CSTATE(ifp);
@@ -782,7 +768,7 @@ make_message(struct bootp **bootpm, cons
 
 	bootp->op = BOOTREQUEST;
 	bootp->htype = (uint8_t)ifp->hwtype;
-	if (ifp->hwlen != 0 && ifp->hwlen < sizeof(bootp->chaddr)) {
+	if (ifp->hwlen != 0 && ifp->hwlen <= sizeof(bootp->chaddr)) {
 		bootp->hlen = (uint8_t)ifp->hwlen;
 		memcpy(&bootp->chaddr, &ifp->hwaddr, ifp->hwlen);
 	}
@@ -2005,7 +1991,7 @@ dhcp_finish_dad(struct interface *ifp, s
 {
 	struct dhcp_state *state = D_STATE(ifp);
 
-	if (state->state != DHS_PROBE)
+	if (state->state == DHS_BOUND)
 		return;
 	if (state->offer == NULL || state->offer->yiaddr != ia->s_addr)
 		return;
@@ -2407,7 +2393,9 @@ openudp:
 		dhcp_openbpf(ifp);
 		return;
 	}
-	eloop_event_add(ctx->eloop, state->udp_rfd, dhcp_handleifudp, ifp);
+	if (eloop_event_add(ctx->eloop, state->udp_rfd, ELE_READ,
+	    dhcp_handleifudp, ifp) == -1)
+		logerr("%s: eloop_event_add", __func__);
 }
 
 static size_t
@@ -2753,12 +2741,8 @@ dhcp_reboot(struct interface *ifp)
 void
 dhcp_drop(struct interface *ifp, const char *reason)
 {
-	struct dhcp_state *state;
-#ifdef RELEASE_SLOW
-	struct timespec ts;
-#endif
+	struct dhcp_state *state = D_STATE(ifp);
 
-	state = D_STATE(ifp);
 	/* dhcp_start may just have been called and we don't yet have a state
 	 * but we do have a timeout, so punt it. */
 	if (state == NULL || state->state == DHS_NONE) {
@@ -2792,12 +2776,6 @@ dhcp_drop(struct interface *ifp, const c
 			    ifp->name, inet_ntoa(state->lease.addr));
 			dhcp_new_xid(ifp);
 			send_message(ifp, DHCP_RELEASE, NULL);
-#ifdef RELEASE_SLOW
-			/* Give the packet a chance to go */
-			ts.tv_sec = RELEASE_DELAY_S;
-			ts.tv_nsec = RELEASE_DELAY_NS;
-			nanosleep(&ts, NULL);
-#endif
 		}
 	}
 #ifdef AUTH
@@ -2818,10 +2796,6 @@ dhcp_drop(struct interface *ifp, const c
 	dhcp_auth_reset(&state->auth);
 #endif
 
-	/* Close DHCP ports so a changed interface family is picked
-	 * up by a new BPF state. */
-	dhcp_close(ifp);
-
 	state->state = DHS_NONE;
 	free(state->offer);
 	state->offer = NULL;
@@ -2845,6 +2819,10 @@ dhcp_drop(struct interface *ifp, const c
 	state->lease.addr.s_addr = 0;
 	ifp->options->options &= ~(DHCPCD_CSR_WARNED |
 	    DHCPCD_ROUTER_HOST_ROUTE_WARNED);
+
+	/* Close DHCP ports so a changed interface family is picked
+	 * up by a new BPF state. */
+	dhcp_close(ifp);
 }
 
 static int
@@ -3623,7 +3601,7 @@ dhcp_packet(struct interface *ifp, uint8
 }
 
 static void
-dhcp_readbpf(void *arg)
+dhcp_readbpf(void *arg, unsigned short events)
 {
 	struct interface *ifp = arg;
 	uint8_t buf[FRAMELEN_MAX];
@@ -3631,6 +3609,9 @@ dhcp_readbpf(void *arg)
 	struct dhcp_state *state = D_STATE(ifp);
 	struct bpf *bpf = state->bpf;
 
+	if (events != ELE_READ)
+		logerrx("%s: unexpected event 0x%04x", __func__, events);
+
 	bpf->bpf_flags &= ~BPF_EOF;
 	while (!(bpf->bpf_flags & BPF_EOF)) {
 		bytes = bpf_read(bpf, buf, sizeof(buf));
@@ -3694,7 +3675,8 @@ dhcp_recvmsg(struct dhcpcd_ctx *ctx, str
 }
 
 static void
-dhcp_readudp(struct dhcpcd_ctx *ctx, struct interface *ifp)
+dhcp_readudp(struct dhcpcd_ctx *ctx, struct interface *ifp,
+    unsigned short events)
 {
 	const struct dhcp_state *state;
 	struct sockaddr_in from;
@@ -3722,6 +3704,9 @@ dhcp_readudp(struct dhcpcd_ctx *ctx, str
 	int s;
 	ssize_t bytes;
 
+	if (events != ELE_READ)
+		logerrx("%s: unexpected event 0x%04x", __func__, events);
+
 	if (ifp != NULL) {
 		state = D_CSTATE(ifp);
 		s = state->udp_rfd;
@@ -3739,19 +3724,19 @@ dhcp_readudp(struct dhcpcd_ctx *ctx, str
 }
 
 static void
-dhcp_handleudp(void *arg)
+dhcp_handleudp(void *arg, unsigned short events)
 {
 	struct dhcpcd_ctx *ctx = arg;
 
-	dhcp_readudp(ctx, NULL);
+	dhcp_readudp(ctx, NULL, events);
 }
 
 static void
-dhcp_handleifudp(void *arg)
+dhcp_handleifudp(void *arg, unsigned short events)
 {
 	struct interface *ifp = arg;
 
-	dhcp_readudp(ifp->ctx, ifp);
+	dhcp_readudp(ifp->ctx, ifp, events);
 }
 
 static int
@@ -3786,8 +3771,9 @@ dhcp_openbpf(struct interface *ifp)
 		return -1;
 	}
 
-	eloop_event_add(ifp->ctx->eloop,
-	    state->bpf->bpf_fd, dhcp_readbpf, ifp);
+	if (eloop_event_add(ifp->ctx->eloop, state->bpf->bpf_fd, ELE_READ,
+	    dhcp_readbpf, ifp) == -1)
+		logerr("%s: eloop_event_add", __func__);
 	return 0;
 }
 
@@ -3833,6 +3819,7 @@ dhcp_free(struct interface *ifp)
 
 		free(ctx->opt_buffer);
 		ctx->opt_buffer = NULL;
+		ctx->opt_buffer_len = 0;
 	}
 }
 
@@ -3963,7 +3950,9 @@ dhcp_start1(void *arg)
 			logerr(__func__);
 			return;
 		}
-		eloop_event_add(ctx->eloop, ctx->udp_rfd, dhcp_handleudp, ctx);
+		if (eloop_event_add(ctx->eloop, ctx->udp_rfd, ELE_READ,
+		    dhcp_handleudp, ctx) == -1)
+			logerr("%s: eloop_event_add", __func__);
 	}
 	if (!IN_PRIVSEP(ctx) && ctx->udp_wfd == -1) {
 		ctx->udp_wfd = xsocket(PF_INET, SOCK_RAW|SOCK_CXNB,IPPROTO_UDP);

Index: src/external/bsd/dhcpcd/dist/src/dhcp6.c
diff -u src/external/bsd/dhcpcd/dist/src/dhcp6.c:1.28 src/external/bsd/dhcpcd/dist/src/dhcp6.c:1.29
--- src/external/bsd/dhcpcd/dist/src/dhcp6.c:1.28	Fri Oct 22 13:23:20 2021
+++ src/external/bsd/dhcpcd/dist/src/dhcp6.c	Fri Apr 21 16:54:26 2023
@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: BSD-2-Clause */
 /*
  * dhcpcd - DHCP client daemon
- * Copyright (c) 2006-2021 Roy Marples <r...@marples.name>
+ * Copyright (c) 2006-2023 Roy Marples <r...@marples.name>
  * All rights reserved
 
  * Redistribution and use in source and binary forms, with or without
@@ -147,12 +147,18 @@ struct dhcp_compat {
 	uint16_t dhcp6_opt;
 };
 
+/*
+ * RFC 5908 deprecates OPTION_SNTP_SERVERS.
+ * But we can support both as the hook scripts will uniqify the
+ * results if the server returns both options.
+ */
 static const struct dhcp_compat dhcp_compats[] = {
 	{ DHO_DNSSERVER,	D6_OPTION_DNS_SERVERS },
 	{ DHO_HOSTNAME,		D6_OPTION_FQDN },
 	{ DHO_DNSDOMAIN,	D6_OPTION_FQDN },
 	{ DHO_NISSERVER,	D6_OPTION_NIS_SERVERS },
 	{ DHO_NTPSERVER,	D6_OPTION_SNTP_SERVERS },
+	{ DHO_NTPSERVER,	D6_OPTION_NTP_SERVER },
 	{ DHO_RAPIDCOMMIT,	D6_OPTION_RAPID_COMMIT },
 	{ DHO_FQDN,		D6_OPTION_FQDN },
 	{ DHO_VIVCO,		D6_OPTION_VENDOR_CLASS },
@@ -173,7 +179,7 @@ static const char * const dhcp6_statuses
 
 static void dhcp6_bind(struct interface *, const char *, const char *);
 static void dhcp6_failinform(void *);
-static void dhcp6_recvaddr(void *);
+static void dhcp6_recvaddr(void *, unsigned short);
 static void dhcp6_startdecline(struct interface *);
 
 #ifdef SMALL
@@ -962,6 +968,8 @@ dhcp6_makemessage(struct interface *ifp)
 		else
 			ia_na_len = sizeof(ia_na);
 		memcpy(ia_na.iaid, ifia->iaid, sizeof(ia_na.iaid));
+		/* RFC 8415 21.4 and 21.21 state that T1 and T2 should be zero.
+		 * An RFC compliant server MUST ignore them anyway. */
 		ia_na.t1 = 0;
 		ia_na.t2 = 0;
 		COPYIN(ifia->ia_type, &ia_na, ia_na_len);
@@ -980,11 +988,16 @@ dhcp6_makemessage(struct interface *ifp)
 				continue;
 			if (ap->ia_type == D6_OPTION_IA_PD) {
 #ifndef SMALL
-				struct dhcp6_pd_addr pdp;
+				struct dhcp6_pd_addr pdp = {
+				    .prefix_len = ap->prefix_len,
+				    /*
+				     * RFC 8415 21.22 states that the
+				     * valid and preferred lifetimes sent by
+				     * the client SHOULD be zero and MUST
+				     * be ignored by the server.
+				     */
+				};
 
-				pdp.pltime = htonl(ap->prefix_pltime);
-				pdp.vltime = htonl(ap->prefix_vltime);
-				pdp.prefix_len = ap->prefix_len;
 				/* pdp.prefix is not aligned, so copy it in. */
 				memcpy(&pdp.prefix, &ap->prefix, sizeof(pdp.prefix));
 				COPYIN(D6_OPTION_IAPREFIX, &pdp, sizeof(pdp));
@@ -1019,11 +1032,16 @@ dhcp6_makemessage(struct interface *ifp)
 				}
 #endif
 			} else {
-				struct dhcp6_ia_addr ia;
+				struct dhcp6_ia_addr ia = {
+				    .addr = ap->addr,
+				    /*
+				     * RFC 8415 21.6 states that the
+				     * valid and preferred lifetimes sent by
+				     * the client SHOULD be zero and MUST
+				     * be ignored by the server.
+				     */
+				};
 
-				ia.addr = ap->addr;
-				ia.pltime = htonl(ap->prefix_pltime);
-				ia.vltime = htonl(ap->prefix_vltime);
 				COPYIN(D6_OPTION_IA_ADDR, &ia, sizeof(ia));
 				ia_na_len = (uint16_t)
 				    (ia_na_len + sizeof(o) + sizeof(ia));
@@ -1219,7 +1237,7 @@ dhcp6_sendmessage(struct interface *ifp,
 	struct dhcp6_state *state = D6_STATE(ifp);
 	struct dhcpcd_ctx *ctx = ifp->ctx;
 	unsigned int RT;
-	bool broadcast = true;
+	bool multicast = true;
 	struct sockaddr_in6 dst = {
 	    .sin6_family = AF_INET6,
 	    /* Setting the port on Linux gives EINVAL when sending.
@@ -1259,24 +1277,24 @@ dhcp6_sendmessage(struct interface *ifp,
 			/* Unicasting is denied for these types. */
 			break;
 		default:
-			broadcast = false;
+			multicast = false;
 			inet_ntop(AF_INET6, &state->unicast, uaddr,
 			    sizeof(uaddr));
 			break;
 		}
 	}
-	dst.sin6_addr = broadcast ? alldhcp : state->unicast;
+	dst.sin6_addr = multicast ? alldhcp : state->unicast;
 
 	if (!callback) {
 		logdebugx("%s: %s %s with xid 0x%02x%02x%02x%s%s",
 		    ifp->name,
-		    broadcast ? "broadcasting" : "unicasting",
+		    multicast ? "multicasting" : "unicasting",
 		    dhcp6_get_op(state->send->type),
 		    state->send->xid[0],
 		    state->send->xid[1],
 		    state->send->xid[2],
-		    !broadcast ? " " : "",
-		    !broadcast ? uaddr : "");
+		    !multicast ? " " : "",
+		    !multicast ? uaddr : "");
 		RT = 0;
 	} else {
 		if (state->IMD &&
@@ -1314,13 +1332,13 @@ dhcp6_sendmessage(struct interface *ifp,
 			    " next in %0.1f seconds",
 			    ifp->name,
 			    state->IMD != 0 ? "delaying" :
-			    broadcast ? "broadcasting" : "unicasting",
+			    multicast ? "multicasting" : "unicasting",
 			    dhcp6_get_op(state->send->type),
 			    state->send->xid[0],
 			    state->send->xid[1],
 			    state->send->xid[2],
-			    state->IMD == 0 && !broadcast ? " " : "",
-			    state->IMD == 0 && !broadcast ? uaddr : "",
+			    state->IMD == 0 && !multicast ? " " : "",
+			    state->IMD == 0 && !multicast ? uaddr : "",
 			    (float)RT / MSEC_PER_SEC);
 
 		/* Wait the initial delay */
@@ -1347,7 +1365,7 @@ dhcp6_sendmessage(struct interface *ifp,
 #endif
 
 	/* Set the outbound interface */
-	if (broadcast) {
+	if (multicast) {
 		struct cmsghdr *cm;
 		struct in6_pktinfo pi = { .ipi6_ifindex = ifp->index };
 
@@ -2254,8 +2272,8 @@ dhcp6_findpd(struct interface *ifp, cons
 			if (!(a->flags & IPV6_AF_DELEGATEDPFX))
 				a->flags |= IPV6_AF_NEW | IPV6_AF_DELEGATEDPFX;
 			a->flags &= ~(IPV6_AF_STALE |
-			              IPV6_AF_EXTENDED |
-			              IPV6_AF_REQUEST);
+				      IPV6_AF_EXTENDED |
+				      IPV6_AF_REQUEST);
 			if (a->prefix_vltime != pdp.vltime)
 				a->flags |= IPV6_AF_NEW;
 		}
@@ -2407,7 +2425,7 @@ dhcp6_findia(struct interface *ifp, stru
 				logwarnx("%s: IAID %s T1(%d) > T2(%d) from %s",
 				    ifp->name,
 				    hwaddr_ntoa(iaid, sizeof(iaid), buf,
-				                sizeof(buf)),
+						sizeof(buf)),
 				    ia.t1, ia.t2, sfrom);
 				continue;
 			}
@@ -2840,7 +2858,7 @@ dhcp6_script_try_run(struct interface *i
 		if (ap->flags & IPV6_AF_ONLINK) {
 			if (!(ap->flags & IPV6_AF_DADCOMPLETED) &&
 			    ipv6_iffindaddr(ap->iface, &ap->addr,
-			                    IN6_IFF_TENTATIVE))
+					    IN6_IFF_TENTATIVE))
 				ap->flags |= IPV6_AF_DADCOMPLETED;
 			if ((ap->flags & IPV6_AF_DADCOMPLETED) == 0
 #ifndef SMALL
@@ -3091,7 +3109,7 @@ dhcp6_bind(struct interface *ifp, const 
 		if (state->reason == NULL)
 			state->reason = "INFORM6";
 		o = dhcp6_findmoption(state->new, state->new_len,
-		                      D6_OPTION_INFO_REFRESH_TIME, &ol);
+				      D6_OPTION_INFO_REFRESH_TIME, &ol);
 		if (o == NULL || ol != sizeof(uint32_t))
 			state->renew = IRT_DEFAULT;
 		else {
@@ -3711,7 +3729,7 @@ recvif:
 }
 
 static void
-dhcp6_recv(struct dhcpcd_ctx *ctx, struct ipv6_addr *ia)
+dhcp6_recv(struct dhcpcd_ctx *ctx, struct ipv6_addr *ia, unsigned short events)
 {
 	struct sockaddr_in6 from;
 	union {
@@ -3733,6 +3751,9 @@ dhcp6_recv(struct dhcpcd_ctx *ctx, struc
 	int s;
 	ssize_t bytes;
 
+	if (events != ELE_READ)
+		logerrx("%s: unexpected event 0x%04x", __func__, events);
+
 	s = ia != NULL ? ia->dhcp6_fd : ctx->dhcp6_rfd;
 	bytes = recvmsg(s, &msg, 0);
 	if (bytes == -1) {
@@ -3745,19 +3766,20 @@ dhcp6_recv(struct dhcpcd_ctx *ctx, struc
 }
 
 static void
-dhcp6_recvaddr(void *arg)
+
+dhcp6_recvaddr(void *arg, unsigned short events)
 {
 	struct ipv6_addr *ia = arg;
 
-	dhcp6_recv(ia->iface->ctx, ia);
+	dhcp6_recv(ia->iface->ctx, ia, events);
 }
 
 static void
-dhcp6_recvctx(void *arg)
+dhcp6_recvctx(void *arg, unsigned short events)
 {
 	struct dhcpcd_ctx *ctx = arg;
 
-	dhcp6_recv(ctx, NULL);
+	dhcp6_recv(ctx, NULL, events);
 }
 
 int
@@ -3878,7 +3900,9 @@ dhcp6_start1(void *arg)
 			logerr(__func__);
 			return;
 		}
-		eloop_event_add(ctx->eloop, ctx->dhcp6_rfd, dhcp6_recvctx, ctx);
+		if (eloop_event_add(ctx->eloop, ctx->dhcp6_rfd, ELE_READ,
+		    dhcp6_recvctx, ctx) == -1)
+			logerr("%s: eloop_event_add", __func__);
 	}
 
 	if (!IN_PRIVSEP(ctx) && ctx->dhcp6_wfd == -1) {
@@ -4197,13 +4221,13 @@ dhcp6_handleifa(int cmd, struct ipv6_add
 			if (ia->dhcp6_fd == -1)
 				ia->dhcp6_fd = dhcp6_openudp(ia->iface->index,
 				    &ia->addr);
-			if (ia->dhcp6_fd != -1)
-				eloop_event_add(ia->iface->ctx->eloop,
-				ia->dhcp6_fd, dhcp6_recvaddr, ia);
+			if (ia->dhcp6_fd != -1 &&
+			    eloop_event_add(ia->iface->ctx->eloop,
+			    ia->dhcp6_fd, ELE_READ, dhcp6_recvaddr, ia) == -1)
+				logerr("%s: eloop_event_add", __func__);
 		}
 	}
 
-
 	if ((state = D6_STATE(ifp)) != NULL)
 		ipv6_handleifa_addrs(cmd, &state->addrs, ia, pid);
 }
@@ -4314,7 +4338,7 @@ dhcp6_env(FILE *fp, const char *prefix, 
 
 delegated:
 #ifndef SMALL
-        /* Needed for Delegated Prefixes */
+	/* Needed for Delegated Prefixes */
 	state = D6_CSTATE(ifp);
 	TAILQ_FOREACH(ap, &state->addrs, next) {
 		if (ap->delegating_prefix)
@@ -4333,7 +4357,7 @@ delegated:
 		}
 		if (fprintf(fp, "%s", ap->saddr) == -1)
 			return -1;
-        }
+	}
 	if (fputc('\0', fp) == EOF)
 		return -1;
 #endif
Index: src/external/bsd/dhcpcd/dist/src/ipv6nd.c
diff -u src/external/bsd/dhcpcd/dist/src/ipv6nd.c:1.28 src/external/bsd/dhcpcd/dist/src/ipv6nd.c:1.29
--- src/external/bsd/dhcpcd/dist/src/ipv6nd.c:1.28	Fri Oct 22 13:23:20 2021
+++ src/external/bsd/dhcpcd/dist/src/ipv6nd.c	Fri Apr 21 16:54:26 2023
@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: BSD-2-Clause */
 /*
  * dhcpcd - IPv6 ND handling
- * Copyright (c) 2006-2021 Roy Marples <r...@marples.name>
+ * Copyright (c) 2006-2023 Roy Marples <r...@marples.name>
  * All rights reserved
 
  * Redistribution and use in source and binary forms, with or without
@@ -78,7 +78,7 @@ struct nd_opt_rdnss {           /* RDNSS
 	uint8_t		nd_opt_rdnss_len;
 	uint16_t	nd_opt_rdnss_reserved;
 	uint32_t	nd_opt_rdnss_lifetime;
-        /* followed by list of IP prefixes */
+	/* followed by list of IP prefixes */
 };
 __CTASSERT(sizeof(struct nd_opt_rdnss) == 8);
 #endif
@@ -92,7 +92,7 @@ struct nd_opt_dnssl {		/* DNSSL option R
 	uint32_t	nd_opt_dnssl_lifetime;
 	/* followed by list of DNS servers */
 };
-__CTASSERT(sizeof(struct nd_opt_rdnss) == 8);
+__CTASSERT(sizeof(struct nd_opt_dnssl) == 8);
 #endif
 
 /* Impossible options, so we can easily add extras */
@@ -131,7 +131,7 @@ __CTASSERT(sizeof(struct nd_opt_rdnss) =
 //#define DEBUG_NS
 //
 
-static void ipv6nd_handledata(void *);
+static void ipv6nd_handledata(void *, unsigned short);
 
 /*
  * Android ships buggy ICMP6 filter headers.
@@ -281,8 +281,14 @@ ipv6nd_openif(struct interface *ifp)
 		return -1;
 	}
 
+	if (eloop_event_add(ifp->ctx->eloop, fd, ELE_READ,
+	    ipv6nd_handledata, ifp) == -1)
+	{
+		close(fd);
+		return -1;
+	}
+
 	state->nd_fd = fd;
-	eloop_event_add(ifp->ctx->eloop, fd, ipv6nd_handledata, ifp);
 	return fd;
 }
 #endif
@@ -388,7 +394,9 @@ ipv6nd_sendrsprobe(void *arg)
 			logerr(__func__);
 			return;
 		}
-		eloop_event_add(ctx->eloop, ctx->nd_fd, ipv6nd_handledata, ctx);
+		if (eloop_event_add(ctx->eloop, ctx->nd_fd, ELE_READ,
+		    ipv6nd_handledata, ctx) == -1)
+			logerr("%s: eloop_event_add", __func__);
 	}
 	s = ifp->ctx->nd_fd;
 #endif
@@ -1306,6 +1314,9 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx,
 
 		switch (ndo.nd_opt_type) {
 		case ND_OPT_PREFIX_INFORMATION:
+		{
+			uint32_t vltime, pltime;
+
 			loglevel = new_data ? LOG_ERR : LOG_DEBUG;
 			if (ndo.nd_opt_len != 4) {
 				logmessage(loglevel,
@@ -1329,9 +1340,10 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx,
 				    ifp->name);
 				continue;
 			}
-			if (ntohl(pi.nd_opt_pi_preferred_time) >
-			    ntohl(pi.nd_opt_pi_valid_time))
-			{
+
+			vltime = ntohl(pi.nd_opt_pi_valid_time);
+			pltime = ntohl(pi.nd_opt_pi_preferred_time);
+			if (pltime > vltime) {
 				logmessage(loglevel, "%s: pltime > vltime",
 				    ifp->name);
 				continue;
@@ -1356,10 +1368,15 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx,
 				    &pi_prefix, pi.nd_opt_pi_prefix_len, flags);
 				if (ia == NULL)
 					break;
+
 				ia->prefix = pi_prefix;
+				ia->created = ia->acquired = rap->acquired;
+				ia->prefix_vltime = vltime;
+				ia->prefix_pltime = pltime;
+
 				if (flags & IPV6_AF_AUTOCONF)
 					ia->dadcallback = ipv6nd_dadcallback;
-				ia->created = ia->acquired = rap->acquired;
+
 				TAILQ_INSERT_TAIL(&rap->addrs, ia, next);
 
 #ifdef IPV6_MANAGETEMPADDR
@@ -1376,18 +1393,58 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx,
 				else
 					new_ia = true;
 #endif
+
 			} else {
-#ifdef IPV6_MANAGETEMPADDR
-				new_ia = false;
-#endif
+				uint32_t rmtime;
+
+				/*
+				 * RFC 4862 5.5.3.e
+				 * Don't terminate existing connections.
+				 * This means that to actually remove the
+				 * existing prefix, the RA needs to stop
+				 * broadcasting the prefix and just let it
+				 * expire in 2 hours.
+				 * It might want to broadcast it to reduce
+				 * the vltime if it was greater than 2 hours
+				 * to start with/
+				 */
+				ia->prefix_pltime = pltime;
+				if (ia->prefix_vltime) {
+					uint32_t elapsed;
+
+					elapsed = (uint32_t)eloop_timespec_diff(
+						&rap->acquired, &ia->acquired,
+						NULL);
+					rmtime = ia->prefix_vltime - elapsed;
+					if (rmtime > ia->prefix_vltime)
+						rmtime = 0;
+				} else
+					rmtime = 0;
+				if (vltime > MIN_EXTENDED_VLTIME ||
+				    vltime > rmtime)
+					ia->prefix_vltime = vltime;
+				else if (rmtime <= MIN_EXTENDED_VLTIME)
+					/* No SEND support from RFC 3971 so
+					 * leave vltime alone */
+					ia->prefix_vltime = rmtime;
+				else
+					ia->prefix_vltime = MIN_EXTENDED_VLTIME;
+
+				/* Ensure pltime still fits */
+				if (pltime < ia->prefix_vltime)
+					ia->prefix_pltime = pltime;
+				else
+					ia->prefix_pltime = ia->prefix_vltime;
+
 				ia->flags |= flags;
 				ia->flags &= ~IPV6_AF_STALE;
 				ia->acquired = rap->acquired;
+
+#ifdef IPV6_MANAGETEMPADDR
+				new_ia = false;
+#endif
 			}
-			ia->prefix_vltime =
-			    ntohl(pi.nd_opt_pi_valid_time);
-			ia->prefix_pltime =
-			    ntohl(pi.nd_opt_pi_preferred_time);
+
 			if (ia->prefix_vltime != 0 &&
 			    ia->flags & IPV6_AF_AUTOCONF)
 				has_address = true;
@@ -1410,6 +1467,7 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx,
 			}
 #endif
 			break;
+		}
 
 		case ND_OPT_MTU:
 			if (len < sizeof(mtu)) {
@@ -1977,7 +2035,7 @@ ipv6nd_recvmsg(struct dhcpcd_ctx *ctx, s
 }
 
 static void
-ipv6nd_handledata(void *arg)
+ipv6nd_handledata(void *arg, unsigned short events)
 {
 	struct dhcpcd_ctx *ctx;
 	int fd;
@@ -2013,6 +2071,10 @@ ipv6nd_handledata(void *arg)
 	ctx = arg;
 	fd = ctx->nd_fd;
 #endif
+
+	if (events != ELE_READ)
+		logerrx("%s: unexpected event 0x%04x", __func__, events);
+
 	len = recvmsg(fd, &msg, 0);
 	if (len == -1) {
 		logerr(__func__);

Index: src/external/bsd/dhcpcd/dist/src/dhcpcd.c
diff -u src/external/bsd/dhcpcd/dist/src/dhcpcd.c:1.49 src/external/bsd/dhcpcd/dist/src/dhcpcd.c:1.50
--- src/external/bsd/dhcpcd/dist/src/dhcpcd.c:1.49	Fri Oct 22 13:23:20 2021
+++ src/external/bsd/dhcpcd/dist/src/dhcpcd.c	Fri Apr 21 16:54:26 2023
@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: BSD-2-Clause */
 /*
  * dhcpcd - DHCP client daemon
- * Copyright (c) 2006-2021 Roy Marples <r...@marples.name>
+ * Copyright (c) 2006-2023 Roy Marples <r...@marples.name>
  * All rights reserved
 
  * Redistribution and use in source and binary forms, with or without
@@ -26,7 +26,7 @@
  * SUCH DAMAGE.
  */
 
-static const char dhcpcd_copyright[] = "Copyright (c) 2006-2021 Roy Marples";
+static const char dhcpcd_copyright[] = "Copyright (c) 2006-2023 Roy Marples";
 
 #include <sys/file.h>
 #include <sys/ioctl.h>
@@ -1105,15 +1105,19 @@ out:
 		if_free(ifp);
 	}
 	free(ifs);
+	if_freeifaddrs(ctx, &ifaddrs);
 
 	return e;
 }
 
 static void
-dhcpcd_handlelink(void *arg)
+dhcpcd_handlelink(void *arg, unsigned short events)
 {
 	struct dhcpcd_ctx *ctx = arg;
 
+	if (events != ELE_READ)
+		logerrx("%s: unexpected event 0x%04x", __func__, events);
+
 	if (if_handlelink(ctx) == -1) {
 		if (errno == ENOBUFS || errno == ENOMEM) {
 			dhcpcd_linkoverflow(ctx);
@@ -1241,6 +1245,7 @@ dhcpcd_linkoverflow(struct dhcpcd_ctx *c
 	if_markaddrsstale(ctx->ifaces);
 	if_learnaddrs(ctx, ctx->ifaces, &ifaddrs);
 	if_deletestaleaddrs(ctx->ifaces);
+	if_freeifaddrs(ctx, &ifaddrs);
 }
 
 void
@@ -1406,7 +1411,7 @@ dhcpcd_renew(struct dhcpcd_ctx *ctx)
 
 #ifdef USE_SIGNALS
 #define sigmsg "received %s, %s"
-static void
+void
 dhcpcd_signal_cb(int sig, void *arg)
 {
 	struct dhcpcd_ctx *ctx = arg;
@@ -1465,8 +1470,12 @@ dhcpcd_signal_cb(int sig, void *arg)
 			logerr("logopen");
 		return;
 	case SIGCHLD:
+#ifdef PRIVSEP
+		ps_root_signalcb(sig, ctx);
+#else
 		while (waitpid(-1, NULL, WNOHANG) > 0)
 			;
+#endif
 		return;
 	default:
 		logerrx("received signal %d but don't know what to do with it",
@@ -1648,15 +1657,18 @@ dumperr:
 	return 0;
 }
 
-static void dhcpcd_readdump1(void *);
+static void dhcpcd_readdump1(void *, unsigned short);
 
 static void
-dhcpcd_readdump2(void *arg)
+dhcpcd_readdump2(void *arg, unsigned short events)
 {
 	struct dhcpcd_ctx *ctx = arg;
 	ssize_t len;
 	int exit_code = EXIT_FAILURE;
 
+	if (events != ELE_READ)
+		logerrx("%s: unexpected event 0x%04x", __func__, events);
+
 	len = read(ctx->control_fd, ctx->ctl_buf + ctx->ctl_bufpos,
 	    ctx->ctl_buflen - ctx->ctl_bufpos);
 	if (len == -1) {
@@ -1675,8 +1687,9 @@ dhcpcd_readdump2(void *arg)
 	fflush(stdout);
 	if (--ctx->ctl_extra != 0) {
 		putchar('\n');
-		eloop_event_add(ctx->eloop, ctx->control_fd,
-		    dhcpcd_readdump1, ctx);
+		if (eloop_event_add(ctx->eloop, ctx->control_fd, ELE_READ,
+		    dhcpcd_readdump1, ctx) == -1)
+			logerr("%s: eloop_event_add", __func__);
 		return;
 	}
 	exit_code = EXIT_SUCCESS;
@@ -1687,11 +1700,14 @@ finished:
 }
 
 static void
-dhcpcd_readdump1(void *arg)
+dhcpcd_readdump1(void *arg, unsigned short events)
 {
 	struct dhcpcd_ctx *ctx = arg;
 	ssize_t len;
 
+	if (events != ELE_READ)
+		logerrx("%s: unexpected event 0x%04x", __func__, events);
+
 	len = read(ctx->control_fd, &ctx->ctl_buflen, sizeof(ctx->ctl_buflen));
 	if (len != sizeof(ctx->ctl_buflen)) {
 		if (len != -1)
@@ -1709,8 +1725,9 @@ dhcpcd_readdump1(void *arg)
 		goto err;
 
 	ctx->ctl_bufpos = 0;
-	eloop_event_add(ctx->eloop, ctx->control_fd,
-	    dhcpcd_readdump2, ctx);
+	if (eloop_event_add(ctx->eloop, ctx->control_fd, ELE_READ,
+	    dhcpcd_readdump2, ctx) == -1)
+		logerr("%s: eloop_event_add", __func__);
 	return;
 
 err:
@@ -1719,11 +1736,14 @@ err:
 }
 
 static void
-dhcpcd_readdump0(void *arg)
+dhcpcd_readdump0(void *arg, unsigned short events)
 {
 	struct dhcpcd_ctx *ctx = arg;
 	ssize_t len;
 
+	if (events != ELE_READ)
+		logerrx("%s: unexpected event 0x%04x", __func__, events);
+
 	len = read(ctx->control_fd, &ctx->ctl_extra, sizeof(ctx->ctl_extra));
 	if (len != sizeof(ctx->ctl_extra)) {
 		if (len != -1)
@@ -1738,8 +1758,9 @@ dhcpcd_readdump0(void *arg)
 		return;
 	}
 
-	eloop_event_add(ctx->eloop, ctx->control_fd,
-	    dhcpcd_readdump1, ctx);
+	if (eloop_event_add(ctx->eloop, ctx->control_fd, ELE_READ,
+	    dhcpcd_readdump1, ctx) == -1)
+		logerr("%s: eloop_event_add", __func__);
 }
 
 static void
@@ -1759,17 +1780,20 @@ dhcpcd_readdump(struct dhcpcd_ctx *ctx)
 	if (eloop_timeout_add_sec(ctx->eloop, 5,
 	    dhcpcd_readdumptimeout, ctx) == -1)
 		return -1;
-	return eloop_event_add(ctx->eloop, ctx->control_fd,
+	return eloop_event_add(ctx->eloop, ctx->control_fd, ELE_READ,
 	    dhcpcd_readdump0, ctx);
 }
 
 static void
-dhcpcd_fork_cb(void *arg)
+dhcpcd_fork_cb(void *arg, unsigned short events)
 {
 	struct dhcpcd_ctx *ctx = arg;
 	int exit_code;
 	ssize_t len;
 
+	if (!(events & ELE_READ))
+		logerrx("%s: unexpected event 0x%04x", __func__, events);
+
 	len = read(ctx->fork_fd, &exit_code, sizeof(exit_code));
 	if (len == -1) {
 		logerr(__func__);
@@ -1786,12 +1810,15 @@ dhcpcd_fork_cb(void *arg)
 }
 
 static void
-dhcpcd_stderr_cb(void *arg)
+dhcpcd_stderr_cb(void *arg, unsigned short events)
 {
 	struct dhcpcd_ctx *ctx = arg;
 	char log[BUFSIZ];
 	ssize_t len;
 
+	if (events != ELE_READ)
+		logerrx("%s: unexpected event 0x%04x", __func__, events);
+
 	len = read(ctx->stderr_fd, log, sizeof(log));
 	if (len == -1) {
 		if (errno != ECONNRESET)
@@ -1803,6 +1830,24 @@ dhcpcd_stderr_cb(void *arg)
 	fprintf(stderr, "%s", log);
 }
 
+static void
+dhcpcd_pidfile_timeout(void *arg)
+{
+	struct dhcpcd_ctx *ctx = arg;
+	pid_t pid;
+
+	pid = pidfile_read(ctx->pidfile);
+
+	if(pid == -1)
+		eloop_exit(ctx->eloop, EXIT_SUCCESS);
+	else if (++ctx->duid_len >= 100) { /* overload duid_len */
+		logerrx("pid %d failed to exit", pid);
+		eloop_exit(ctx->eloop, EXIT_FAILURE);
+	} else
+		eloop_timeout_add_msec(ctx->eloop, 100,
+		    dhcpcd_pidfile_timeout, ctx);
+}
+
 int
 main(int argc, char **argv, char **envp)
 {
@@ -1897,8 +1942,7 @@ main(int argc, char **argv, char **envp)
 	ctx.dhcp6_wfd = -1;
 #endif
 #ifdef PRIVSEP
-	ctx.ps_root_fd = ctx.ps_log_fd = ctx.ps_data_fd = -1;
-	ctx.ps_inet_fd = ctx.ps_control_fd = -1;
+	ctx.ps_log_fd = -1;
 	TAILQ_INIT(&ctx.ps_processes);
 #endif
 
@@ -1940,12 +1984,6 @@ main(int argc, char **argv, char **envp)
 			sig = SIGHUP;
 			siga = "HUP";
 			break;
-		case 'g':
-		case 'p':
-			/* Force going via command socket as we're
-			 * out of user definable signals. */
-			i = 4;
-			break;
 		case 'q':
 			/* -qq disables console output entirely.
 			 * This is important for systemd because it logs
@@ -2095,6 +2133,14 @@ printpidfile:
 			snprintf(ctx.pidfile, sizeof(ctx.pidfile),
 			    PIDFILE, "", "", "");
 			ctx.options |= DHCPCD_MANAGER;
+
+			/*
+			 * If we are given any interfaces, we
+			 * cannot send a signal as that would impact
+			 * other interfaces.
+			 */
+			if (optind != argc)
+				sig = 0;
 		}
 		if (ctx.options & DHCPCD_PRINT_PIDFILE) {
 			printf("%s\n", ctx.pidfile);
@@ -2130,31 +2176,20 @@ printpidfile:
 		if (pid != 0 && pid != -1)
 			loginfox("sending signal %s to pid %d", siga, pid);
 		if (pid == 0 || pid == -1 || kill(pid, sig) != 0) {
-			if (sig != SIGHUP && sig != SIGUSR1 && errno != EPERM)
-				logerrx(PACKAGE" not running");
 			if (pid != 0 && pid != -1 && errno != ESRCH) {
 				logerr("kill");
 				goto exit_failure;
 			}
 			unlink(ctx.pidfile);
-			if (sig != SIGHUP && sig != SIGUSR1)
-				goto exit_failure;
+			/* We can still continue and send the command
+			 * via the control socket. */
 		} else {
-			struct timespec ts;
-
 			if (sig == SIGHUP || sig == SIGUSR1)
 				goto exit_success;
 			/* Spin until it exits */
 			loginfox("waiting for pid %d to exit", pid);
-			ts.tv_sec = 0;
-			ts.tv_nsec = 100000000; /* 10th of a second */
-			for(i = 0; i < 100; i++) {
-				nanosleep(&ts, NULL);
-				if (pidfile_read(ctx.pidfile) == -1)
-					goto exit_success;
-			}
-			logerrx("pid %d failed to exit", pid);
-			goto exit_failure;
+			dhcpcd_pidfile_timeout(&ctx);
+			goto run_loop;
 		}
 	}
 #endif
@@ -2207,12 +2242,8 @@ printpidfile:
 	}
 #endif
 
-	/* Test against siga instead of sig to avoid gcc
-	 * warning about a bogus potential signed overflow.
-	 * The end result will be the same. */
-	if ((siga == NULL || i == 4 || ctx.ifc != 0) &&
-	    !(ctx.options & DHCPCD_TEST))
-	{
+	/* Try and contact the manager process to send the instruction. */
+	if (!(ctx.options & DHCPCD_TEST)) {
 		ctx.options |= DHCPCD_FORKED; /* avoid socket unlink */
 		if (!(ctx.options & DHCPCD_MANAGER))
 			ctx.control_fd = control_open(argv[optind], family,
@@ -2249,9 +2280,14 @@ printpidfile:
 		} else {
 			if (errno != ENOENT)
 				logerr("%s: control_open", __func__);
-			if (ctx.options & DHCPCD_DUMPLEASE) {
+			/* If asking dhcpcd to exit and we failed to
+			 * send a signal or a message then we
+			 * don't proceed past here. */
+			if (ctx.options & DHCPCD_DUMPLEASE ||
+			    sig == SIGTERM || sig == SIGALRM)
+			{
 				if (errno == ENOENT)
-					logerrx("dhcpcd is not running");
+					logerrx(PACKAGE" is not running");
 				goto exit_failure;
 			}
 			if (errno == EPERM || errno == EACCES)
@@ -2286,9 +2322,9 @@ printpidfile:
 	if (!(ctx.options & DHCPCD_DAEMONISE))
 		goto start_manager;
 
-	if (xsocketpair(AF_UNIX, SOCK_DGRAM | SOCK_CXNB, 0, fork_fd) == -1 ||
+	if (xsocketpair(AF_UNIX, SOCK_SEQPACKET|SOCK_CXNB, 0, fork_fd) == -1 ||
 	    (ctx.stderr_valid &&
-	    xsocketpair(AF_UNIX, SOCK_DGRAM | SOCK_CXNB, 0, stderr_fd) == -1))
+	    xsocketpair(AF_UNIX, SOCK_SEQPACKET|SOCK_CXNB, 0, stderr_fd) == -1))
 	{
 		logerr("socketpair");
 		goto exit_failure;
@@ -2306,7 +2342,9 @@ printpidfile:
 			goto exit_failure;
 		}
 #endif
-		eloop_event_add(ctx.eloop, ctx.fork_fd, dhcpcd_fork_cb, &ctx);
+		if (eloop_event_add(ctx.eloop, ctx.fork_fd, ELE_READ,
+		    dhcpcd_fork_cb, &ctx) == -1)
+			logerr("%s: eloop_event_add", __func__);
 
 		/*
 		 * Redirect stderr to the stderr socketpair.
@@ -2335,6 +2373,7 @@ printpidfile:
 			logerr("fork");
 			goto exit_failure;
 		case 0:
+			eloop_forked(ctx.eloop);
 			break;
 		default:
 			ctx.options |= DHCPCD_FORKED; /* A lie */
@@ -2353,7 +2392,9 @@ printpidfile:
 			goto exit_failure;
 		}
 #endif
-		eloop_event_add(ctx.eloop, ctx.fork_fd, dhcpcd_fork_cb, &ctx);
+		if (eloop_event_add(ctx.eloop, ctx.fork_fd, ELE_READ,
+		    dhcpcd_fork_cb, &ctx) == -1)
+			logerr("%s: eloop_event_add", __func__);
 
 		if (ctx.stderr_valid) {
 			ctx.stderr_fd = stderr_fd[0];
@@ -2364,8 +2405,9 @@ printpidfile:
 				goto exit_failure;
 			}
 #endif
-			eloop_event_add(ctx.eloop, ctx.stderr_fd,
-			    dhcpcd_stderr_cb, &ctx);
+			if (eloop_event_add(ctx.eloop, ctx.stderr_fd, ELE_READ,
+			    dhcpcd_stderr_cb, &ctx) == -1)
+				logerr("%s: eloop_event_add", __func__);
 		}
 #ifdef PRIVSEP
 		if (IN_PRIVSEP(&ctx) && ps_managersandbox(&ctx, NULL) == -1)
@@ -2447,7 +2489,9 @@ start_manager:
 
 	/* Start handling kernel messages for interfaces, addresses and
 	 * routes. */
-	eloop_event_add(ctx.eloop, ctx.link_fd, dhcpcd_handlelink, &ctx);
+	if (eloop_event_add(ctx.eloop, ctx.link_fd, ELE_READ,
+	    dhcpcd_handlelink, &ctx) == -1)
+		logerr("%s: eloop_event_add", __func__);
 
 #ifdef PRIVSEP
 	if (IN_PRIVSEP(&ctx) && ps_managersandbox(&ctx, "stdio route") == -1)
@@ -2497,6 +2541,8 @@ start_manager:
 			dhcpcd_initstate1(ifp, argc, argv, 0);
 	}
 	if_learnaddrs(&ctx, ctx.ifaces, &ifaddrs);
+	if_freeifaddrs(&ctx, &ifaddrs);
+	ifaddrs = NULL;
 
 	if (ctx.options & DHCPCD_BACKGROUND)
 		dhcpcd_daemonise(&ctx);
@@ -2567,17 +2613,7 @@ exit_failure:
 exit1:
 	if (!(ctx.options & DHCPCD_TEST) && control_stop(&ctx) == -1)
 		logerr("%s: control_stop", __func__);
-	if (ifaddrs != NULL) {
-#ifdef PRIVSEP_GETIFADDRS
-		if (IN_PRIVSEP(&ctx))
-			free(ifaddrs);
-		else
-#endif
-			freeifaddrs(ifaddrs);
-	}
-	/* ps_stop will clear DHCPCD_PRIVSEP but we need to
-	 * remember it to avoid attemping to remove the pidfile */
-	oi = ctx.options & DHCPCD_PRIVSEP ? 1 : 0;
+	if_freeifaddrs(&ctx, &ifaddrs);
 #ifdef PRIVSEP
 	ps_stop(&ctx);
 #endif
@@ -2611,14 +2647,20 @@ exit1:
 #ifdef PLUGIN_DEV
 	dev_stop(&ctx);
 #endif
-#ifdef PRIVSEP
-	eloop_free(ctx.ps_eloop);
-#endif
-	eloop_free(ctx.eloop);
 	if (ctx.script != dhcpcd_default_script)
 		free(ctx.script);
+#ifdef PRIVSEP
+	if (ps_stopwait(&ctx) != EXIT_SUCCESS)
+		i = EXIT_FAILURE;
+#endif
 	if (ctx.options & DHCPCD_STARTED && !(ctx.options & DHCPCD_FORKED))
 		loginfox(PACKAGE " exited");
+#ifdef PRIVSEP
+	if (ps_root_stop(&ctx) == -1)
+		i = EXIT_FAILURE;
+	eloop_free(ctx.ps_eloop);
+#endif
+	eloop_free(ctx.eloop);
 	logclose();
 	free(ctx.logfile);
 	free(ctx.ctl_buf);
@@ -2632,7 +2674,7 @@ exit1:
 		    write(ctx.fork_fd, &i, sizeof(i)) == -1)
 			logerr("%s: write", __func__);
 	}
-	if (ctx.options & DHCPCD_FORKED || oi != 0)
+	if (ctx.options & (DHCPCD_FORKED | DHCPCD_PRIVSEP))
 		_exit(i); /* so atexit won't remove our pidfile */
 #endif
 	return i;

Index: src/external/bsd/dhcpcd/dist/src/if-bsd.c
diff -u src/external/bsd/dhcpcd/dist/src/if-bsd.c:1.27 src/external/bsd/dhcpcd/dist/src/if-bsd.c:1.28
--- src/external/bsd/dhcpcd/dist/src/if-bsd.c:1.27	Fri Oct 22 13:23:20 2021
+++ src/external/bsd/dhcpcd/dist/src/if-bsd.c	Fri Apr 21 16:54:26 2023
@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: BSD-2-Clause */
 /*
  * BSD interface driver for dhcpcd
- * Copyright (c) 2006-2021 Roy Marples <r...@marples.name>
+ * Copyright (c) 2006-2023 Roy Marples <r...@marples.name>
  * All rights reserved
 
  * Redistribution and use in source and binary forms, with or without
@@ -104,6 +104,7 @@
  * just won't work without explicit configuration. */
 static const char * const ifnames_ignore[] = {
 	"bridge",
+	"epair",	/* Virtual patch cable */
 	"fwe",		/* Firewire */
 	"fwip",		/* Firewire */
 	"tap",
@@ -112,10 +113,6 @@ static const char * const ifnames_ignore
 	NULL
 };
 
-struct priv {
-	int pf_inet6_fd;
-};
-
 struct rtm
 {
 	struct rt_msghdr hdr;
@@ -222,6 +219,12 @@ if_opensockets_os(struct dhcpcd_ctx *ctx
 		ps_rights_limit_fd_sockopt(ctx->link_fd);
 #endif
 
+
+#if defined(SIOCALIFADDR) && defined(IFLR_ACTIVE) /*NetBSD */
+	priv->pf_link_fd = socket(PF_LINK, SOCK_DGRAM, 0);
+	if (priv->pf_link_fd == -1)
+		logerr("%s: socket(PF_LINK)", __func__);
+#endif
 	return 0;
 }
 
@@ -233,6 +236,10 @@ if_closesockets_os(struct dhcpcd_ctx *ct
 	priv = (struct priv *)ctx->priv;
 	if (priv->pf_inet6_fd != -1)
 		close(priv->pf_inet6_fd);
+#if defined(SIOCALIFADDR) && defined(IFLR_ACTIVE) /*NetBSD */
+	if (priv->pf_link_fd != -1)
+		close(priv->pf_link_fd);
+#endif
 	free(priv);
 	ctx->priv = NULL;
 	free(ctx->rt_missfilter);
@@ -242,22 +249,14 @@ if_closesockets_os(struct dhcpcd_ctx *ct
 static int
 if_ioctllink(struct dhcpcd_ctx *ctx, unsigned long req, void *data, size_t len)
 {
-	int s;
-	int retval;
+	struct priv *priv = (struct priv *)ctx->priv;
 
 #ifdef PRIVSEP
 	if (ctx->options & DHCPCD_PRIVSEP)
 		return (int)ps_root_ioctllink(ctx, req, data, len);
-#else
-	UNUSED(ctx);
 #endif
 
-	s = socket(PF_LINK, SOCK_DGRAM, 0);
-	if (s == -1)
-		return -1;
-	retval = ioctl(s, req, data, len);
-	close(s);
-	return retval;
+	return ioctl(priv->pf_link_fd, req, data, len);
 }
 #endif
 
@@ -914,37 +913,47 @@ if_copyrt(struct dhcpcd_ctx *ctx, struct
 	return 0;
 }
 
+static int
+if_sysctl(struct dhcpcd_ctx *ctx,
+    const int *name, u_int namelen,
+    void *oldp, size_t *oldlenp, void *newp, size_t newlen)
+{
+#if defined(PRIVSEP) && defined(HAVE_CAPSICUM)
+	if (IN_PRIVSEP(ctx))
+		return (int)ps_root_sysctl(ctx, name, namelen,
+		    oldp, oldlenp, newp, newlen);
+#else
+	UNUSED(ctx);
+#endif
+
+	return sysctl(name, namelen, oldp, oldlenp, newp, newlen);
+}
+
 int
 if_initrt(struct dhcpcd_ctx *ctx, rb_tree_t *kroutes, int af)
 {
 	struct rt_msghdr *rtm;
-	int mib[6];
-	size_t needed;
+	int mib[6] = { CTL_NET, PF_ROUTE, 0, af, NET_RT_DUMP, 0 };
+	size_t bufl;
 	char *buf, *p, *end;
 	struct rt rt, *rtn;
 
-	mib[0] = CTL_NET;
-	mib[1] = PF_ROUTE;
-	mib[2] = 0;
-	mib[3] = af;
-	mib[4] = NET_RT_DUMP;
-	mib[5] = 0;
-
-	if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1)
+	if (if_sysctl(ctx, mib, __arraycount(mib), NULL, &bufl, NULL, 0) == -1)
 		return -1;
-	if (needed == 0)
+	if (bufl == 0)
 		return 0;
-	if ((buf = malloc(needed)) == NULL)
+	if ((buf = malloc(bufl)) == NULL)
 		return -1;
-	if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1) {
+	if (if_sysctl(ctx, mib, __arraycount(mib), buf, &bufl, NULL, 0) == -1)
+	{
 		free(buf);
 		return -1;
 	}
 
-	end = buf + needed;
+	end = buf + bufl;
 	for (p = buf; p < end; p += rtm->rtm_msglen) {
 		rtm = (void *)p;
-		if (p + rtm->rtm_msglen >= end) {
+		if (p + sizeof(*rtm) > end || p + rtm->rtm_msglen > end) {
 			errno = EINVAL;
 			break;
 		}
@@ -1246,8 +1255,8 @@ if_rtm(struct dhcpcd_ctx *ctx, const str
 
 	/* Ignore messages from ourself. */
 #ifdef PRIVSEP
-	if (ctx->ps_root_pid != 0) {
-		if (rtm->rtm_pid == ctx->ps_root_pid)
+	if (ctx->ps_root != NULL) {
+		if (rtm->rtm_pid == ctx->ps_root->psp_pid)
 			return 0;
 	}
 #endif
@@ -1298,8 +1307,8 @@ if_ifa(struct dhcpcd_ctx *ctx, const str
 	 * We need to process address flag changes though. */
 	if (ifam->ifam_type == RTM_DELADDR) {
 #ifdef PRIVSEP
-		if (ctx->ps_root_pid != 0) {
-			if (ifam->ifam_pid == ctx->ps_root_pid)
+		if (ctx->ps_root != NULL) {
+			if (ifam->ifam_pid == ctx->ps_root->psp_pid)
 				return 0;
 		} else
 #endif
@@ -1649,12 +1658,11 @@ inet6_sysctl(int code, int val, int acti
 	mib[3] = code;
 	size = sizeof(val);
 	if (action) {
-		if (sysctl(mib, sizeof(mib)/sizeof(mib[0]),
-		    NULL, 0, &val, size) == -1)
+		if (sysctl(mib, __arraycount(mib), NULL, 0, &val, size) == -1)
 			return -1;
 		return 0;
 	}
-	if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), &val, &size, NULL, 0) == -1)
+	if (sysctl(mib, __arraycount(mib), &val, &size, NULL, 0) == -1)
 		return -1;
 	return val;
 }

Index: src/external/bsd/dhcpcd/dist/src/if-options.c
diff -u src/external/bsd/dhcpcd/dist/src/if-options.c:1.32 src/external/bsd/dhcpcd/dist/src/if-options.c:1.33
--- src/external/bsd/dhcpcd/dist/src/if-options.c:1.32	Fri Oct 22 13:23:20 2021
+++ src/external/bsd/dhcpcd/dist/src/if-options.c	Fri Apr 21 16:54:26 2023
@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: BSD-2-Clause */
 /*
  * dhcpcd - DHCP client daemon
- * Copyright (c) 2006-2021 Roy Marples <r...@marples.name>
+ * Copyright (c) 2006-2023 Roy Marples <r...@marples.name>
  * All rights reserved
 
  * Redistribution and use in source and binary forms, with or without
@@ -193,7 +193,10 @@ add_environ(char ***array, const char *v
 	l = strlen(match);
 
 	while (list && list[i]) {
-		if (match && strncmp(list[i], match, l) == 0) {
+		/* We know that it must contain '=' due to the above test */
+		size_t listl = (size_t)(strchr(list[i], '=') - list[i]);
+
+		if (l == listl && strncmp(list[i], match, l) == 0) {
 			if (uniq) {
 				n = strdup(value);
 				if (n == NULL) {
@@ -266,7 +269,13 @@ parse_str(char *sbuf, size_t slen, const
 		}
 	} else {
 		l = (size_t)hwaddr_aton(NULL, str);
-		if ((ssize_t) l != -1 && l > 1) {
+		if (l > 0) {
+			if ((ssize_t)l == -1) {
+				errno = ENOBUFS;
+				return -1;
+			}
+			if (sbuf == NULL)
+				return (ssize_t)l;
 			if (l > slen) {
 				errno = ENOBUFS;
 				return -1;
@@ -1108,8 +1117,13 @@ parse_option(struct dhcpcd_ctx *ctx, con
 			logerrx("static assignment required");
 			return -1;
 		}
-		p++;
+		p = strskipwhite(++p);
 		if (strncmp(arg, "ip_address=", strlen("ip_address=")) == 0) {
+			if (p == NULL) {
+				ifo->options &= ~DHCPCD_STATIC;
+				ifo->req_addr.s_addr = INADDR_ANY;
+				break;
+			}
 			if (parse_addr(&ifo->req_addr,
 			    ifo->req_mask.s_addr == 0 ? &ifo->req_mask : NULL,
 			    p) != 0)
@@ -1120,11 +1134,19 @@ parse_option(struct dhcpcd_ctx *ctx, con
 		} else if (strncmp(arg, "subnet_mask=",
 		    strlen("subnet_mask=")) == 0)
 		{
+			if (p == NULL) {
+				ifo->req_mask.s_addr = INADDR_ANY;
+				break;
+			}
 			if (parse_addr(&ifo->req_mask, NULL, p) != 0)
 				return -1;
 		} else if (strncmp(arg, "broadcast_address=",
 		    strlen("broadcast_address=")) == 0)
 		{
+			if (p == NULL) {
+				ifo->req_brd.s_addr = INADDR_ANY;
+				break;
+			}
 			if (parse_addr(&ifo->req_brd, NULL, p) != 0)
 				return -1;
 		} else if (strncmp(arg, "routes=", strlen("routes=")) == 0 ||
@@ -1137,6 +1159,12 @@ parse_option(struct dhcpcd_ctx *ctx, con
 		{
 			struct in_addr addr3;
 
+			if (p == NULL) {
+				rt_headclear(&ifo->routes, AF_INET);
+				add_environ(&ifo->config, arg, 1);
+				break;
+			}
+
 			fp = np = strwhite(p);
 			if (np == NULL) {
 				logerrx("all routes need a gateway");
@@ -1159,6 +1187,11 @@ parse_option(struct dhcpcd_ctx *ctx, con
 			if (rt_proto_add_ctx(&ifo->routes, rt, ctx))
 				add_environ(&ifo->config, arg, 0);
 		} else if (strncmp(arg, "routers=", strlen("routers=")) == 0) {
+			if (p == NULL) {
+				rt_headclear(&ifo->routes, AF_INET);
+				add_environ(&ifo->config, arg, 1);
+				break;
+			}
 			if (parse_addr(&addr, NULL, p) == -1)
 				return -1;
 			if ((rt = rt_new0(ctx)) == NULL)
@@ -1173,6 +1206,8 @@ parse_option(struct dhcpcd_ctx *ctx, con
 		    strlen("interface_mtu=")) == 0 ||
 		    strncmp(arg, "mtu=", strlen("mtu=")) == 0)
 		{
+			if (p == NULL)
+				break;
 			ifo->mtu = (unsigned int)strtou(p, NULL, 0,
 			    MTU_MIN, MTU_MAX, &e);
 			if (e) {
@@ -1180,6 +1215,12 @@ parse_option(struct dhcpcd_ctx *ctx, con
 				return -1;
 			}
 		} else if (strncmp(arg, "ip6_address=", strlen("ip6_address=")) == 0) {
+			if (p == NULL) {
+				memset(&ifo->req_addr6, 0,
+				    sizeof(ifo->req_addr6));
+				break;
+			}
+
 			np = strchr(p, '/');
 			if (np)
 				*np++ = '\0';
@@ -1205,8 +1246,9 @@ parse_option(struct dhcpcd_ctx *ctx, con
 				return -1;
 			}
 		} else
-			add_environ(&ifo->config, arg, 1);
+			add_environ(&ifo->config, arg, p == NULL ? 1 : 0);
 		break;
+
 	case 'W':
 		if (parse_addr(&addr, &addr2, arg) != 0)
 			return -1;
@@ -2061,7 +2103,7 @@ err_sla:
 		arg = fp;
 		fp = strend(arg);
 		if (fp == NULL) {
-			logerrx("authtoken requies an a key");
+			logerrx("authtoken requires a realm");
 			goto invalid_token;
 		}
 		*fp++ = '\0';
@@ -2114,7 +2156,7 @@ err_sla:
 			if (s == -1)
 				logerr("token_len");
 			else
-				logerrx("authtoken needs a key");
+				logerrx("authtoken requires a key");
 			goto invalid_token;
 		}
 		token->key_len = (size_t)s;
@@ -2229,6 +2271,24 @@ invalid_token:
 			ifo->options |= DHCPCD_SLAACPRIVATE;
 		else
 			ifo->options &= ~DHCPCD_SLAACPRIVATE;
+#ifdef INET6
+		if (strcmp(arg, "token") == 0) {
+			if (np == NULL) {
+				logerrx("slaac token: no token specified");
+				return -1;
+			}
+			arg = np;
+			np = strwhite(np);
+			if (np != NULL) {
+				*np++ = '\0';
+				np = strskipwhite(np);
+			}
+			if (inet_pton(AF_INET6, arg, &ifo->token) != 1) {
+				logerrx("slaac token: invalid token");
+				return -1;
+			}
+		}
+#endif
 		if (np != NULL &&
 		    (strcmp(np, "temp") == 0 || strcmp(np, "temporary") == 0))
 			ifo->options |= DHCPCD_SLAACTEMP;

Index: src/external/bsd/dhcpcd/dist/src/ipv6.c
diff -u src/external/bsd/dhcpcd/dist/src/ipv6.c:1.17 src/external/bsd/dhcpcd/dist/src/ipv6.c:1.18
--- src/external/bsd/dhcpcd/dist/src/ipv6.c:1.17	Fri Oct 22 13:23:20 2021
+++ src/external/bsd/dhcpcd/dist/src/ipv6.c	Fri Apr 21 16:54:26 2023
@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: BSD-2-Clause */
 /*
  * dhcpcd - DHCP client daemon
- * Copyright (c) 2006-2021 Roy Marples <r...@marples.name>
+ * Copyright (c) 2006-2023 Roy Marples <r...@marples.name>
  * All rights reserved
 
  * Redistribution and use in source and binary forms, with or without
@@ -359,51 +359,6 @@ again:
 }
 #endif
 
-int
-ipv6_makeaddr(struct in6_addr *addr, struct interface *ifp,
-    const struct in6_addr *prefix, int prefix_len, unsigned int flags)
-{
-	const struct ipv6_addr *ap;
-	int dad;
-
-	if (prefix_len < 0 || prefix_len > 120) {
-		errno = EINVAL;
-		return -1;
-	}
-
-#ifdef IPV6_AF_TEMPORARY
-	if (flags & IPV6_AF_TEMPORARY)
-		return ipv6_maketemporaryaddress(addr, prefix, prefix_len, ifp);
-#else
-	UNUSED(flags);
-#endif
-
-	if (ifp->options->options & DHCPCD_SLAACPRIVATE) {
-		dad = 0;
-		if (ipv6_makestableprivate(addr,
-		    prefix, prefix_len, ifp, &dad) == -1)
-			return -1;
-		return dad;
-	}
-
-	if (prefix_len > 64) {
-		errno = EINVAL;
-		return -1;
-	}
-	if ((ap = ipv6_linklocal(ifp)) == NULL) {
-		/* We delay a few functions until we get a local-link address
-		 * so this should never be hit. */
-		errno = ENOENT;
-		return -1;
-	}
-
-	/* Make the address from the first local-link address */
-	memcpy(addr, prefix, sizeof(*prefix));
-	addr->s6_addr32[2] = ap->addr.s6_addr32[2];
-	addr->s6_addr32[3] = ap->addr.s6_addr32[3];
-	return 0;
-}
-
 static int
 ipv6_makeprefix(struct in6_addr *prefix, const struct in6_addr *addr, int len)
 {
@@ -478,6 +433,68 @@ ipv6_prefixlen(const struct in6_addr *ma
 	return (uint8_t)(x * NBBY + y);
 }
 
+int
+ipv6_makeaddr(struct in6_addr *addr, struct interface *ifp,
+    const struct in6_addr *prefix, int prefix_len, unsigned int flags)
+{
+	const struct ipv6_addr *ap;
+	const struct if_options *ifo = ifp->options;
+	int dad;
+
+	if (prefix_len < 0 || prefix_len > 120) {
+		errno = EINVAL;
+		return -1;
+	}
+
+#ifdef IPV6_AF_TEMPORARY
+	if (flags & IPV6_AF_TEMPORARY)
+		return ipv6_maketemporaryaddress(addr, prefix, prefix_len, ifp);
+#else
+	UNUSED(flags);
+#endif
+
+	if (ifo->options & DHCPCD_SLAACPRIVATE) {
+		dad = 0;
+		if (ipv6_makestableprivate(addr,
+		    prefix, prefix_len, ifp, &dad) == -1)
+			return -1;
+		return dad;
+	} else if (!IN6_IS_ADDR_UNSPECIFIED(&ifo->token)) {
+		int bytes = prefix_len / NBBY;
+		int bits = prefix_len % NBBY;
+
+		// Copy the token into the address.
+		*addr = ifo->token;
+
+		// If we have any dangling bits, just copy that in also.
+		// XXX Can we preserve part of the token still?
+		if (bits != 0)
+			bytes++;
+
+		// Copy the prefix in.
+		if (bytes > 0)
+			memcpy(addr->s6_addr, prefix->s6_addr, (size_t)bytes);
+		return 0;
+	}
+
+	if (prefix_len > 64) {
+		errno = EINVAL;
+		return -1;
+	}
+	if ((ap = ipv6_linklocal(ifp)) == NULL) {
+		/* We delay a few functions until we get a local-link address
+		 * so this should never be hit. */
+		errno = ENOENT;
+		return -1;
+	}
+
+	/* Make the address from the first local-link address */
+	memcpy(addr, prefix, sizeof(*prefix));
+	addr->s6_addr32[2] = ap->addr.s6_addr32[2];
+	addr->s6_addr32[3] = ap->addr.s6_addr32[3];
+	return 0;
+}
+
 static void
 in6_to_h64(uint64_t *vhigh, uint64_t *vlow, const struct in6_addr *addr)
 {

Index: src/external/bsd/dhcpcd/dist/src/ipv6.h
diff -u src/external/bsd/dhcpcd/dist/src/ipv6.h:1.13 src/external/bsd/dhcpcd/dist/src/ipv6.h:1.14
--- src/external/bsd/dhcpcd/dist/src/ipv6.h:1.13	Fri Oct 22 13:23:20 2021
+++ src/external/bsd/dhcpcd/dist/src/ipv6.h	Fri Apr 21 16:54:26 2023
@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: BSD-2-Clause */
 /*
  * dhcpcd - DHCP client daemon
- * Copyright (c) 2006-2021 Roy Marples <r...@marples.name>
+ * Copyright (c) 2006-2023 Roy Marples <r...@marples.name>
  * All rights reserved
 
  * Redistribution and use in source and binary forms, with or without
Index: src/external/bsd/dhcpcd/dist/src/privsep.c
diff -u src/external/bsd/dhcpcd/dist/src/privsep.c:1.13 src/external/bsd/dhcpcd/dist/src/privsep.c:1.14
--- src/external/bsd/dhcpcd/dist/src/privsep.c:1.13	Fri Oct 22 13:23:20 2021
+++ src/external/bsd/dhcpcd/dist/src/privsep.c	Fri Apr 21 16:54:26 2023
@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: BSD-2-Clause */
 /*
  * Privilege Separation for dhcpcd
- * Copyright (c) 2006-2021 Roy Marples <r...@marples.name>
+ * Copyright (c) 2006-2023 Roy Marples <r...@marples.name>
  * All rights reserved
 
  * Redistribution and use in source and binary forms, with or without
@@ -75,6 +75,7 @@
 
 #ifdef HAVE_CAPSICUM
 #include <sys/capsicum.h>
+#include <sys/procdesc.h>
 #include <capsicum_helpers.h>
 #endif
 #ifdef HAVE_UTIL_H
@@ -144,33 +145,27 @@ ps_dropprivs(struct dhcpcd_ctx *ctx)
 
 	struct rlimit rzero = { .rlim_cur = 0, .rlim_max = 0 };
 
-	if (ctx->ps_control_pid != getpid()) {
-		/* Prohibit new files, sockets, etc */
-#if defined(__linux__) || defined(__sun) || defined(__OpenBSD__)
-		/*
-		 * If poll(2) is called with nfds > RLIMIT_NOFILE
-		 * then it returns EINVAL.
-		 * This blows.
-		 * Do the best we can and limit to what we need.
-		 * An attacker could potentially close a file and
-		 * open a new one still, but that cannot be helped.
-		 */
-		unsigned long maxfd;
-		maxfd = (unsigned long)eloop_event_count(ctx->eloop);
-		if (IN_PRIVSEP_SE(ctx))
-			maxfd++; /* XXX why? */
-
-		struct rlimit rmaxfd = {
-		    .rlim_cur = maxfd,
-		    .rlim_max = maxfd
-		};
-		if (setrlimit(RLIMIT_NOFILE, &rmaxfd) == -1)
-			logerr("setrlimit RLIMIT_NOFILE");
-#else
+	/* Prohibit new files, sockets, etc */
+	/*
+	 * If poll(2) is called with nfds>RLIMIT_NOFILE then it returns EINVAL.
+	 * We don't know the final value of nfds at this point *easily*.
+	 * Sadly, this is a POSIX limitation and most platforms adhere to it.
+	 * However, some are not that strict and are whitelisted below.
+	 * Also, if we're not using poll then we can be restrictive.
+	 *
+	 * For the non whitelisted platforms there should be a sandbox to
+	 * fallback to where we don't allow new files, etc:
+	 *      Linux:seccomp, FreeBSD:capsicum, OpenBSD:pledge
+	 * Solaris users are sadly out of luck on both counts.
+	 */
+#if defined(__NetBSD__) || defined(__DragonFly__) || \
+    defined(HAVE_KQUEUE) || defined(HAVE_EPOLL)
+	/* The control proxy *does* need to create new fd's via accept(2). */
+	if (ctx->ps_ctl == NULL || ctx->ps_ctl->psp_pid != getpid()) {
 		if (setrlimit(RLIMIT_NOFILE, &rzero) == -1)
 			logerr("setrlimit RLIMIT_NOFILE");
-#endif
 	}
+#endif
 
 #define DHC_NOCHKIO	(DHCPCD_STARTED | DHCPCD_DAEMONISE)
 	/* Prohibit writing to files.
@@ -324,17 +319,41 @@ ps_rights_limit_stdio(struct dhcpcd_ctx 
 }
 #endif
 
+#ifdef HAVE_CAPSICUM
+static void
+ps_processhangup(void *arg, unsigned short events)
+{
+	struct ps_process *psp = arg;
+	struct dhcpcd_ctx *ctx = psp->psp_ctx;
+
+	if (!(events & ELE_HANGUP))
+		logerrx("%s: unexpected event 0x%04x", __func__, events);
+
+	logdebugx("%s%s%s exited from PID %d",
+	    psp->psp_ifname, psp->psp_ifname[0] != '\0' ? ": " : "",
+	    psp->psp_name, psp->psp_pid);
+
+	ps_freeprocess(psp);
+
+	if (!(ctx->options & DHCPCD_EXITING))
+		return;
+	if (!(ps_waitforprocs(ctx)))
+		eloop_exit(ctx->ps_eloop, EXIT_SUCCESS);
+}
+#endif
+
 pid_t
-ps_dostart(struct dhcpcd_ctx *ctx,
-    pid_t *priv_pid, int *priv_fd,
-    void (*recv_msg)(void *), void (*recv_unpriv_msg),
-    void *recv_ctx, int (*callback)(void *), void (*signal_cb)(int, void *),
+ps_startprocess(struct ps_process *psp,
+    void (*recv_msg)(void *, unsigned short),
+    void (*recv_unpriv_msg)(void *, unsigned short),
+    int (*callback)(struct ps_process *), void (*signal_cb)(int, void *),
     unsigned int flags)
 {
+	struct dhcpcd_ctx *ctx = psp->psp_ctx;
 	int fd[2];
 	pid_t pid;
 
-	if (xsocketpair(AF_UNIX, SOCK_DGRAM | SOCK_CXNB, 0, fd) == -1) {
+	if (xsocketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CXNB, 0, fd) == -1) {
 		logerr("%s: socketpair", __func__);
 		return -1;
 	}
@@ -349,37 +368,62 @@ ps_dostart(struct dhcpcd_ctx *ctx,
 	}
 #endif
 
-	switch (pid = fork()) {
+#ifdef HAVE_CAPSICUM
+	pid = pdfork(&psp->psp_pfd, PD_CLOEXEC);
+#else
+	pid = fork();
+#endif
+	switch (pid) {
 	case -1:
+#ifdef HAVE_CAPSICUM
+		logerr("pdfork");
+#else
 		logerr("fork");
+#endif
 		return -1;
 	case 0:
-		*priv_fd = fd[1];
+		psp->psp_pid = getpid();
+		psp->psp_fd = fd[1];
 		close(fd[0]);
 		break;
 	default:
-		*priv_pid = pid;
-		*priv_fd = fd[0];
+		psp->psp_pid = pid;
+		psp->psp_fd = fd[0];
 		close(fd[1]);
 		if (recv_unpriv_msg == NULL)
 			;
-		else if (eloop_event_add(ctx->eloop, *priv_fd,
-		    recv_unpriv_msg, recv_ctx) == -1)
+		else if (eloop_event_add(ctx->eloop, psp->psp_fd, ELE_READ,
+		    recv_unpriv_msg, psp) == -1)
 		{
-			logerr("%s: eloop_event_add", __func__);
+			logerr("%s: eloop_event_add fd %d",
+			    __func__, psp->psp_fd);
 			return -1;
 		}
+#ifdef HAVE_CAPSICUM
+		if (eloop_event_add(ctx->eloop, psp->psp_pfd, ELE_HANGUP,
+		    ps_processhangup, psp) == -1)
+		{
+			logerr("%s: eloop_event_add pfd %d",
+			    __func__, psp->psp_pfd);
+			return -1;
+		}
+#endif
+		psp->psp_started = true;
 		return pid;
 	}
 
-	ctx->options |= DHCPCD_FORKED;
-	if (ctx->fork_fd != -1) {
-		close(ctx->fork_fd);
-		ctx->fork_fd = -1;
-	}
-	pidfile_clean();
 
-	eloop_clear(ctx->eloop);
+#ifdef PLUGIN_DEV
+	/* If we are not the root process, stop listening to devices. */
+	if (ctx->ps_root != psp)
+		dev_stop(ctx);
+#endif
+
+	ctx->options |= DHCPCD_FORKED;
+	if (ctx->ps_log_fd != -1)
+		logsetfd(ctx->ps_log_fd);
+	eloop_clear(ctx->eloop, -1);
+	eloop_forked(ctx->eloop);
 	eloop_signal_set_cb(ctx->eloop,
 	    dhcpcd_signals, dhcpcd_signals_len, signal_cb, ctx);
 	/* ctx->sigset aready has the initial sigmask set in main() */
@@ -388,16 +432,31 @@ ps_dostart(struct dhcpcd_ctx *ctx,
 		goto errexit;
 	}
 
-	/* We are not root */
-	if (priv_fd != &ctx->ps_root_fd) {
-		ps_freeprocesses(ctx, recv_ctx);
-		if (ctx->ps_root_fd != -1) {
-			close(ctx->ps_root_fd);
-			ctx->ps_root_fd = -1;
-		}
+	if (ctx->fork_fd != -1) {
+		/* Already removed from eloop thanks to above clear. */
+		close(ctx->fork_fd);
+		ctx->fork_fd = -1;
+	}
 
+	/* This process has no need of the blocking inner eloop. */
+	if (!(flags & PSF_ELOOP)) {
+		eloop_free(ctx->ps_eloop);
+		ctx->ps_eloop = NULL;
+	} else
+		eloop_forked(ctx->ps_eloop);
+
+	pidfile_clean();
+	ps_freeprocesses(ctx, psp);
+
+	if (ctx->ps_root != psp) {
+		ctx->options &= ~DHCPCD_PRIVSEPROOT;
+		ctx->ps_root = NULL;
+		if (ctx->ps_log_root_fd != -1) {
+			/* Already removed from eloop thanks to above clear. */
+			close(ctx->ps_log_root_fd);
+			ctx->ps_log_root_fd = -1;
+		}
 #ifdef PRIVSEP_RIGHTS
-		/* We cannot limit the root process in any way. */
 		if (ps_rights_limit_stdio(ctx) == -1) {
 			logerr("ps_rights_limit_stdio");
 			goto errexit;
@@ -405,58 +464,88 @@ ps_dostart(struct dhcpcd_ctx *ctx,
 #endif
 	}
 
-	if (priv_fd != &ctx->ps_inet_fd && ctx->ps_inet_fd != -1) {
-		close(ctx->ps_inet_fd);
-		ctx->ps_inet_fd = -1;
-	}
+	if (ctx->ps_inet != psp)
+		ctx->ps_inet = NULL;
+	if (ctx->ps_ctl != psp)
+		ctx->ps_ctl = NULL;
+
+#if 0
+	char buf[1024];
+	errno = 0;
+	ssize_t xx = recv(psp->psp_fd, buf, sizeof(buf), MSG_PEEK);
+	logerr("pid %d test fd %d recv peek %zd", getpid(), psp->psp_fd, xx);
+#endif
 
-	if (eloop_event_add(ctx->eloop, *priv_fd, recv_msg, recv_ctx) == -1)
+	if (eloop_event_add(ctx->eloop, psp->psp_fd, ELE_READ,
+	    recv_msg, psp) == -1)
 	{
-		logerr("%s: eloop_event_add", __func__);
+		logerr("%d %s: eloop_event_add XX fd %d", getpid(), __func__, psp->psp_fd);
 		goto errexit;
 	}
 
-	if (callback(recv_ctx) == -1)
+	if (callback(psp) == -1)
 		goto errexit;
 
 	if (flags & PSF_DROPPRIVS)
 		ps_dropprivs(ctx);
 
+	psp->psp_started = true;
 	return 0;
 
 errexit:
-	/* Failure to start root or inet processes is fatal. */
-	if (priv_fd == &ctx->ps_root_fd || priv_fd == &ctx->ps_inet_fd)
-		(void)ps_sendcmd(ctx, *priv_fd, PS_STOP, 0, NULL, 0);
-	shutdown(*priv_fd, SHUT_RDWR);
-	*priv_fd = -1;
+	if (psp->psp_fd != -1) {
+		close(psp->psp_fd);
+		psp->psp_fd = -1;
+	}
 	eloop_exit(ctx->eloop, EXIT_FAILURE);
 	return -1;
 }
 
+void
+ps_process_timeout(void *arg)
+{
+	struct dhcpcd_ctx *ctx = arg;
+
+	logerrx("%s: timed out", __func__);
+	eloop_exit(ctx->eloop, EXIT_FAILURE);
+}
+
 int
-ps_dostop(struct dhcpcd_ctx *ctx, pid_t *pid, int *fd)
+ps_stopprocess(struct ps_process *psp)
 {
 	int err = 0;
 
+	if (psp == NULL)
+		return 0;
+
+	psp->psp_started = false;
+
 #ifdef PRIVSEP_DEBUG
-	logdebugx("%s: pid=%d fd=%d", __func__, *pid, *fd);
+	logdebugx("%s: me=%d pid=%d fd=%d %s", __func__,
+	    getpid(), psp->psp_pid, psp->psp_fd, psp->psp_name);
 #endif
 
-	if (*fd != -1) {
-		eloop_event_delete(ctx->eloop, *fd);
-		if (ps_sendcmd(ctx, *fd, PS_STOP, 0, NULL, 0) == -1) {
+	if (psp->psp_fd != -1) {
+		eloop_event_delete(psp->psp_ctx->eloop, psp->psp_fd);
+#if 0
+		if (ps_sendcmd(psp->psp_ctx, psp->psp_fd, PS_STOP, 0,
+		    NULL, 0) == -1)
+		{
+			logerr("%d %d %s %s", getpid(), psp->psp_pid, psp->psp_name, __func__);
+			err = -1;
+		}
+		shutdown(psp->psp_fd, SHUT_WR);
+#else
+		if (shutdown(psp->psp_fd, SHUT_WR) == -1) {
 			logerr(__func__);
 			err = -1;
 		}
-		(void)shutdown(*fd, SHUT_RDWR);
-		close(*fd);
-		*fd = -1;
+#endif
+		psp->psp_fd = -1;
 	}
 
 	/* Don't wait for the process as it may not respond to the shutdown
 	 * request. We'll reap the process on receipt of SIGCHLD. */
-	*pid = 0;
 	return err;
 }
 
@@ -467,6 +556,13 @@ ps_start(struct dhcpcd_ctx *ctx)
 
 	TAILQ_INIT(&ctx->ps_processes);
 
+	/* We need an inner eloop to block with. */
+	if ((ctx->ps_eloop = eloop_new()) == NULL)
+		return -1;
+	eloop_signal_set_cb(ctx->ps_eloop,
+	    dhcpcd_signals, dhcpcd_signals_len,
+	    dhcpcd_signal_cb, ctx);
+
 	switch (pid = ps_root_start(ctx)) {
 	case -1:
 		logerr("ps_root_start");
@@ -557,7 +653,7 @@ ps_managersandbox(struct dhcpcd_ctx *ctx
 	 * If it cannot be opened before chrooting then syslog(3) will fail.
 	 * openlog(3) does not return an error which doubly sucks.
 	 */
-	if (ctx->ps_root_fd == -1) {
+	if (ctx->ps_root == NULL) {
 		unsigned int logopts = loggetopts();
 
 		logopts &= ~LOGERR_LOG;
@@ -606,39 +702,106 @@ ps_stop(struct dhcpcd_ctx *ctx)
 	    ctx->eloop == NULL)
 		return 0;
 
-	r = ps_ctl_stop(ctx);
-	if (r != 0)
-		ret = r;
-
-	r = ps_inet_stop(ctx);
-	if (r != 0)
-		ret = r;
-
-	/* We've been chrooted, so we need to tell the
-	 * privileged proxy to remove the pidfile. */
-	ps_root_unlink(ctx, ctx->pidfile);
-
-	r = ps_root_stop(ctx);
-	if (r != 0)
-		ret = r;
+	if (ctx->ps_ctl != NULL) {
+		r = ps_ctl_stop(ctx);
+		if (r != 0)
+			ret = r;
+	}
+
+	if (ctx->ps_inet != NULL) {
+		r = ps_inet_stop(ctx);
+		if (r != 0)
+			ret = r;
+	}
+
+	if (ctx->ps_root != NULL) {
+		if (ps_root_stopprocesses(ctx) == -1)
+			ret = -1;
+	}
 
-	ctx->options &= ~DHCPCD_PRIVSEP;
 	return ret;
 }
 
+bool
+ps_waitforprocs(struct dhcpcd_ctx *ctx)
+{
+	struct ps_process *psp = TAILQ_FIRST(&ctx->ps_processes);
+
+	if (psp == NULL)
+		return false;
+
+	/* Different processes */
+	if (psp != TAILQ_LAST(&ctx->ps_processes, ps_process_head))
+		return true;
+
+	return !psp->psp_started;
+}
+
+int
+ps_stopwait(struct dhcpcd_ctx *ctx)
+{
+	int error = EXIT_SUCCESS;
+
+	if (ctx->ps_eloop == NULL || !ps_waitforprocs(ctx))
+		return 0;
+
+	ctx->options |= DHCPCD_EXITING;
+	if (eloop_timeout_add_sec(ctx->ps_eloop, PS_PROCESS_TIMEOUT,
+	    ps_process_timeout, ctx) == -1)
+		logerr("%s: eloop_timeout_add_sec", __func__);
+	eloop_enter(ctx->ps_eloop);
+
+#ifdef HAVE_CAPSICUM
+	struct ps_process *psp;
+
+	TAILQ_FOREACH(psp, &ctx->ps_processes, next) {
+		if (psp->psp_pfd == -1)
+			continue;
+		if (eloop_event_add(ctx->ps_eloop, psp->psp_pfd,
+		    ELE_HANGUP, ps_processhangup, psp) == -1)
+			logerr("%s: eloop_event_add pfd %d",
+			    __func__, psp->psp_pfd);
+	}
+#endif
+
+	error = eloop_start(ctx->ps_eloop, &ctx->sigset);
+	if (error != EXIT_SUCCESS)
+		logerr("%s: eloop_start", __func__);
+
+	eloop_timeout_delete(ctx->ps_eloop, ps_process_timeout, ctx);
+
+	return error;
+}
+
 void
 ps_freeprocess(struct ps_process *psp)
 {
+	struct dhcpcd_ctx *ctx = psp->psp_ctx;
+
+	TAILQ_REMOVE(&ctx->ps_processes, psp, next);
 
-	TAILQ_REMOVE(&psp->psp_ctx->ps_processes, psp, next);
 	if (psp->psp_fd != -1) {
-		eloop_event_delete(psp->psp_ctx->eloop, psp->psp_fd);
+		eloop_event_delete(ctx->eloop, psp->psp_fd);
 		close(psp->psp_fd);
 	}
 	if (psp->psp_work_fd != -1) {
-		eloop_event_delete(psp->psp_ctx->eloop, psp->psp_work_fd);
+		eloop_event_delete(ctx->eloop, psp->psp_work_fd);
 		close(psp->psp_work_fd);
 	}
+#ifdef HAVE_CAPSICUM
+	if (psp->psp_pfd != -1) {
+		eloop_event_delete(ctx->eloop, psp->psp_pfd);
+		if (ctx->ps_eloop != NULL)
+			eloop_event_delete(ctx->ps_eloop, psp->psp_pfd);
+		close(psp->psp_pfd);
+	}
+#endif
+	if (ctx->ps_root == psp)
+		ctx->ps_root = NULL;
+	if (ctx->ps_inet == psp)
+		ctx->ps_inet = NULL;
+	if (ctx->ps_ctl == psp)
+		ctx->ps_ctl = NULL;
 #ifdef INET
 	if (psp->psp_bpf != NULL)
 		bpf_close(psp->psp_bpf);
@@ -649,12 +812,23 @@ ps_freeprocess(struct ps_process *psp)
 static void
 ps_free(struct dhcpcd_ctx *ctx)
 {
-	struct ps_process *psp;
-	bool stop = ctx->ps_root_pid == getpid();
+	struct ps_process *ppsp, *psp;
+	bool stop;
+
+	if (ctx->ps_root != NULL)
+		ppsp = ctx->ps_root;
+	else if (ctx->ps_ctl != NULL)
+		ppsp = ctx->ps_ctl;
+	else
+		ppsp = NULL;
+	if (ppsp != NULL)
+		stop = ppsp->psp_pid == getpid();
+	else
+		stop = false;
 
 	while ((psp = TAILQ_FIRST(&ctx->ps_processes)) != NULL) {
-		if (stop)
-			ps_dostop(ctx, &psp->psp_pid, &psp->psp_fd);
+		if (stop && psp != ppsp)
+			ps_stopprocess(psp);
 		ps_freeprocess(psp);
 	}
 }
@@ -760,7 +934,6 @@ ps_sendpsmmsg(struct dhcpcd_ctx *ctx, in
 
 	len = writev(fd, iov, iovlen);
 	if (len == -1) {
-		logerr(__func__);
 		if (ctx->options & DHCPCD_FORKED &&
 		    !(ctx->options & DHCPCD_PRIVSEPROOT))
 			eloop_exit(ctx->eloop, EXIT_FAILURE);
@@ -896,7 +1069,8 @@ nobufs:
 }
 
 ssize_t
-ps_recvmsg(struct dhcpcd_ctx *ctx, int rfd, uint16_t cmd, int wfd)
+ps_recvmsg(struct dhcpcd_ctx *ctx, int rfd, unsigned short events,
+    uint16_t cmd, int wfd)
 {
 	struct sockaddr_storage ss = { .ss_family = AF_UNSPEC };
 	uint8_t controlbuf[sizeof(struct sockaddr_storage)] = { 0 };
@@ -909,32 +1083,33 @@ ps_recvmsg(struct dhcpcd_ctx *ctx, int r
 		.msg_control = controlbuf, .msg_controllen = sizeof(controlbuf),
 		.msg_iov = iov, .msg_iovlen = 1,
 	};
+	ssize_t len;
 
-	ssize_t len = recvmsg(rfd, &msg, 0);
+	if (!(events & ELE_READ))
+		logerrx("%s: unexpected event 0x%04x", __func__, events);
 
+	len = recvmsg(rfd, &msg, 0);
 	if (len == -1)
 		logerr("%s: recvmsg", __func__);
 	if (len == -1 || len == 0) {
-		if (ctx->options & DHCPCD_FORKED &&
-		    !(ctx->options & DHCPCD_PRIVSEPROOT))
+		if (ctx->options & DHCPCD_FORKED)
 			eloop_exit(ctx->eloop,
-			    len == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
+			    len != -1 ? EXIT_SUCCESS : EXIT_FAILURE);
 		return len;
 	}
 
 	iov[0].iov_len = (size_t)len;
 	len = ps_sendcmdmsg(wfd, cmd, &msg);
 	if (len == -1) {
-		logerr("ps_sendcmdmsg");
-		if (ctx->options & DHCPCD_FORKED &&
-		    !(ctx->options & DHCPCD_PRIVSEPROOT))
+		logerr("%s: ps_sendcmdmsg", __func__);
+		if (ctx->options & DHCPCD_FORKED)
 			eloop_exit(ctx->eloop, EXIT_FAILURE);
 	}
 	return len;
 }
 
 ssize_t
-ps_recvpsmsg(struct dhcpcd_ctx *ctx, int fd,
+ps_recvpsmsg(struct dhcpcd_ctx *ctx, int fd, unsigned short events,
     ssize_t (*callback)(void *, struct ps_msghdr *, struct msghdr *),
     void *cbctx)
 {
@@ -945,6 +1120,9 @@ ps_recvpsmsg(struct dhcpcd_ctx *ctx, int
 	struct msghdr msg = { .msg_iov = iov, .msg_iovlen = 1 };
 	bool stop = false;
 
+	if (!(events & ELE_READ))
+		logerrx("%s: unexpected event 0x%04x", __func__, events);
+
 	len = read(fd, &psm, sizeof(psm));
 #ifdef PRIVSEP_DEBUG
 	logdebugx("%s: %zd", __func__, len);
@@ -966,13 +1144,11 @@ ps_recvpsmsg(struct dhcpcd_ctx *ctx, int
 	}
 
 	if (stop) {
+		ctx->options |= DHCPCD_EXITING;
 #ifdef PRIVSEP_DEBUG
 		logdebugx("process %d stopping", getpid());
 #endif
 		ps_free(ctx);
-#ifdef PLUGIN_DEV
-		dev_stop(ctx);
-#endif
 		eloop_exit(ctx->eloop, len != -1 ? EXIT_SUCCESS : EXIT_FAILURE);
 		return len;
 	}
@@ -994,6 +1170,8 @@ ps_findprocess(struct dhcpcd_ctx *ctx, s
 	struct ps_process *psp;
 
 	TAILQ_FOREACH(psp, &ctx->ps_processes, next) {
+		if (!(psp->psp_started))
+			continue;
 		if (memcmp(&psp->psp_id, psid, sizeof(psp->psp_id)) == 0)
 			return psp;
 	}
@@ -1002,6 +1180,19 @@ ps_findprocess(struct dhcpcd_ctx *ctx, s
 }
 
 struct ps_process *
+ps_findprocesspid(struct dhcpcd_ctx *ctx, pid_t pid)
+{
+	struct ps_process *psp;
+
+	TAILQ_FOREACH(psp, &ctx->ps_processes, next) {
+		if (psp->psp_pid == pid)
+			return psp;
+	}
+	errno = ESRCH;
+	return NULL;
+}
+
+struct ps_process *
 ps_newprocess(struct dhcpcd_ctx *ctx, struct ps_id *psid)
 {
 	struct ps_process *psp;
@@ -1012,6 +1203,12 @@ ps_newprocess(struct dhcpcd_ctx *ctx, st
 	psp->psp_ctx = ctx;
 	memcpy(&psp->psp_id, psid, sizeof(psp->psp_id));
 	psp->psp_work_fd = -1;
+#ifdef HAVE_CAPSICUM
+	psp->psp_pfd = -1;
+#endif
+
+	if (!(ctx->options & DHCPCD_MANAGER))
+		strlcpy(psp->psp_ifname, ctx->ifv[0], sizeof(psp->psp_name));
 	TAILQ_INSERT_TAIL(&ctx->ps_processes, psp, next);
 	return psp;
 }

Index: src/external/bsd/dhcpcd/dist/src/logerr.c
diff -u src/external/bsd/dhcpcd/dist/src/logerr.c:1.12 src/external/bsd/dhcpcd/dist/src/logerr.c:1.13
--- src/external/bsd/dhcpcd/dist/src/logerr.c:1.12	Fri Oct 22 13:23:20 2021
+++ src/external/bsd/dhcpcd/dist/src/logerr.c	Fri Apr 21 16:54:26 2023
@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: BSD-2-Clause */
 /*
  * logerr: errx with logging
- * Copyright (c) 2006-2021 Roy Marples <r...@marples.name>
+ * Copyright (c) 2006-2023 Roy Marples <r...@marples.name>
  * All rights reserved
 
  * Redistribution and use in source and binary forms, with or without

Index: src/external/bsd/dhcpcd/dist/src/script.c
diff -u src/external/bsd/dhcpcd/dist/src/script.c:1.14 src/external/bsd/dhcpcd/dist/src/script.c:1.15
--- src/external/bsd/dhcpcd/dist/src/script.c:1.14	Fri Oct 22 13:23:20 2021
+++ src/external/bsd/dhcpcd/dist/src/script.c	Fri Apr 21 16:54:26 2023
@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: BSD-2-Clause */
 /*
  * dhcpcd - DHCP client daemon
- * Copyright (c) 2006-2021 Roy Marples <r...@marples.name>
+ * Copyright (c) 2006-2023 Roy Marples <r...@marples.name>
  * All rights reserved
 
  * Redistribution and use in source and binary forms, with or without

Reply via email to