Module Name:    src
Committed By:   roy
Date:           Wed Sep  4 13:28:57 UTC 2019

Modified Files:
        src/external/bsd/dhcpcd/dist/src: dhcp.c dhcp6.c dhcpcd.8.in dhcpcd.c
            if-bsd.c ipv6.c ipv6.h ipv6nd.c

Log Message:
Sync


To generate a diff of this commit:
cvs rdiff -u -r1.24 -r1.25 src/external/bsd/dhcpcd/dist/src/dhcp.c \
    src/external/bsd/dhcpcd/dist/src/dhcpcd.c
cvs rdiff -u -r1.11 -r1.12 src/external/bsd/dhcpcd/dist/src/dhcp6.c \
    src/external/bsd/dhcpcd/dist/src/if-bsd.c
cvs rdiff -u -r1.2 -r1.3 src/external/bsd/dhcpcd/dist/src/dhcpcd.8.in
cvs rdiff -u -r1.3 -r1.4 src/external/bsd/dhcpcd/dist/src/ipv6.c
cvs rdiff -u -r1.4 -r1.5 src/external/bsd/dhcpcd/dist/src/ipv6.h
cvs rdiff -u -r1.10 -r1.11 src/external/bsd/dhcpcd/dist/src/ipv6nd.c

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

Modified files:

Index: src/external/bsd/dhcpcd/dist/src/dhcp.c
diff -u src/external/bsd/dhcpcd/dist/src/dhcp.c:1.24 src/external/bsd/dhcpcd/dist/src/dhcp.c:1.25
--- src/external/bsd/dhcpcd/dist/src/dhcp.c:1.24	Wed Aug 21 17:12:19 2019
+++ src/external/bsd/dhcpcd/dist/src/dhcp.c	Wed Sep  4 13:28:56 2019
@@ -1176,11 +1176,8 @@ read_lease(struct interface *ifp, struct
 	bytes = dhcp_read_lease_fd(fd, (void **)&lease);
 	if (fd_opened)
 		close(fd);
-	if (bytes == 0) {
-		free(lease);
-		logerr("%s: dhcp_read_lease_fd", __func__);
+	if (bytes == 0)
 		return 0;
-	}
 
 	/* Ensure the packet is at lease BOOTP sized
 	 * with a vendor area of 4 octets
@@ -1584,7 +1581,7 @@ eexit:
 }
 
 static uint16_t
-in_cksum(void *data, size_t len, uint32_t *isum)
+in_cksum(const void *data, size_t len, uint32_t *isum)
 {
 	const uint16_t *word = data;
 	uint32_t sum = isum != NULL ? *isum : 0;
@@ -1593,7 +1590,7 @@ in_cksum(void *data, size_t len, uint32_
 		sum += *word++;
 
 	if (len == 1)
-		sum += *(const uint8_t *)word;
+		sum += htons((uint16_t)(*(const uint8_t *)word << 8));
 
 	if (isum != NULL)
 		*isum = sum;
@@ -2237,7 +2234,7 @@ dhcp_bind(struct interface *ifp)
 	ipv4_applyaddr(ifp);
 
 #ifdef IP_PKTINFO
-	/* Close the BPF filter as we can now receive the DHCP renew messages
+	/* 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))
@@ -2246,9 +2243,15 @@ dhcp_bind(struct interface *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)
+			if (state->udp_fd == -1) {
 				logerr(__func__);
-			else
+				/* 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);
 		}
@@ -3293,7 +3296,8 @@ valid_udp_packet(void *packet, size_t pl
 	pseudo_ip.ip_len = udp->uh_ulen;
 	csum = 0;
 	in_cksum(&pseudo_ip, sizeof(pseudo_ip), &csum);
-	if (in_cksum(udp, ntohs(udp->uh_ulen), &csum) != uh_sum) {
+	csum = in_cksum(udp, ntohs(udp->uh_ulen), &csum);
+	if (csum != uh_sum) {
 		errno = EINVAL;
 		return -1;
 	}
@@ -3662,6 +3666,7 @@ static void
 dhcp_start1(void *arg)
 {
 	struct interface *ifp = arg;
+	struct dhcpcd_ctx *ctx = ifp->ctx;
 	struct if_options *ifo = ifp->options;
 	struct dhcp_state *state;
 	struct stat st;
@@ -3672,17 +3677,19 @@ dhcp_start1(void *arg)
 		return;
 
 	/* Listen on *.*.*.*:bootpc so that the kernel never sends an
-	 * ICMP port unreachable message back to the DHCP server */
-	if (ifp->ctx->udp_fd == -1) {
-		ifp->ctx->udp_fd = dhcp_openudp(NULL);
-		if (ifp->ctx->udp_fd == -1) {
+	 * 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) {
 			/* Don't log an error if some other process
 			 * is handling this. */
 			if (errno != EADDRINUSE)
 				logerr("%s: dhcp_openudp", __func__);
 		} else
-			eloop_event_add(ifp->ctx->eloop,
-			    ifp->ctx->udp_fd, dhcp_handleudp, ifp->ctx);
+			eloop_event_add(ctx->eloop,
+			    ctx->udp_fd, dhcp_handleudp, ctx);
 	}
 
 	if (dhcp_init(ifp) == -1) {
Index: src/external/bsd/dhcpcd/dist/src/dhcpcd.c
diff -u src/external/bsd/dhcpcd/dist/src/dhcpcd.c:1.24 src/external/bsd/dhcpcd/dist/src/dhcpcd.c:1.25
--- src/external/bsd/dhcpcd/dist/src/dhcpcd.c:1.24	Wed Aug 21 17:12:19 2019
+++ src/external/bsd/dhcpcd/dist/src/dhcpcd.c	Wed Sep  4 13:28:56 2019
@@ -950,12 +950,7 @@ dhcpcd_prestartinterface(void *arg)
 
 	if ((!(ifp->ctx->options & DHCPCD_MASTER) ||
 	    ifp->options->options & DHCPCD_IF_UP) &&
-	    if_up(ifp) == -1
-#ifdef __sun
-	    /* Interface could not yet be plumbed. */
-	    && errno != ENXIO
-#endif
-	    )
+	    if_up(ifp) == -1)
 		logerr("%s: %s", __func__, ifp->name);
 
 	dhcpcd_startinterface(ifp);

Index: src/external/bsd/dhcpcd/dist/src/dhcp6.c
diff -u src/external/bsd/dhcpcd/dist/src/dhcp6.c:1.11 src/external/bsd/dhcpcd/dist/src/dhcp6.c:1.12
--- src/external/bsd/dhcpcd/dist/src/dhcp6.c:1.11	Tue Jul 30 10:25:03 2019
+++ src/external/bsd/dhcpcd/dist/src/dhcp6.c	Wed Sep  4 13:28:56 2019
@@ -2488,22 +2488,22 @@ dhcp6_readlease(struct interface *ifp, i
 	struct dhcp6_state *state;
 	struct stat st;
 	int fd;
-	struct dhcp6_message *lease;
 	time_t now;
 	int retval;
-	bool fd_opened;
+	bool read_stdin, fd_opened;
 #ifdef AUTH
 	uint8_t *o;
 	uint16_t ol;
 #endif
 
 	state = D6_STATE(ifp);
-	if (state->leasefile[0] == '\0') {
+	read_stdin = state->leasefile[0] == '\0';
+	if (read_stdin) {
 		logdebugx("reading standard input");
 		fd = fileno(stdin);
 		fd_opened = false;
 	} else {
-		logdebugx("%s: reading lease `%s'", ifp->name, state->leasefile);
+		logdebugx("%s: reading lease `%s'", ifp->name,state->leasefile);
 		fd = open(state->leasefile, O_RDONLY);
 		if (fd != -1 && fstat(fd, &st) == -1) {
 			close(fd);
@@ -2514,19 +2514,19 @@ dhcp6_readlease(struct interface *ifp, i
 	if (fd == -1)
 		return -1;
 	retval = -1;
-	lease = NULL;
 	free(state->new);
-	state->new_len = dhcp_read_lease_fd(fd, (void **)&lease);
-	state->new = lease;
+	state->new_len = dhcp_read_lease_fd(fd, (void **)&state->new);
 	if (fd_opened)
 		close(fd);
-	if (state->new_len == 0)
-		goto ex;
 
-	if (ifp->ctx->options & DHCPCD_DUMPLEASE ||
-	    state->leasefile[0] == '\0')
+	if (ifp->ctx->options & DHCPCD_DUMPLEASE || read_stdin)
 		return 0;
 
+	if (state->new_len == 0) {
+		retval = 0;
+		goto ex;
+	}
+
 	/* If not validating IA's and if they have expired,
 	 * skip to the auth check. */
 	if (!validate) {
@@ -2546,14 +2546,12 @@ dhcp6_readlease(struct interface *ifp, i
 		goto ex;
 
 	if (state->expire != ND6_INFINITE_LIFETIME &&
-	    state->leasefile[0] != '\0')
+	    (time_t)state->expire < now - st.st_mtime &&
+	    !(ifp->options->options & DHCPCD_LASTLEASE_EXTEND))
 	{
-		if ((time_t)state->expire < now - st.st_mtime &&
-		    !(ifp->options->options & DHCPCD_LASTLEASE_EXTEND)) {
-			logdebugx("%s: discarding expired lease", ifp->name);
-			retval = 0;
-			goto ex;
-		}
+		logdebugx("%s: discarding expired lease", ifp->name);
+		retval = 0;
+		goto ex;
 	}
 
 auth:
@@ -2586,12 +2584,10 @@ auth:
 
 ex:
 	dhcp6_freedrop_addrs(ifp, 0, NULL);
+	unlink(state->leasefile);
 	free(state->new);
 	state->new = NULL;
 	state->new_len = 0;
-	if (!(ifp->ctx->options & DHCPCD_DUMPLEASE) &&
-	    state->leasefile[0] != '\0')
-		unlink(state->leasefile);
 	return retval;
 }
 
Index: src/external/bsd/dhcpcd/dist/src/if-bsd.c
diff -u src/external/bsd/dhcpcd/dist/src/if-bsd.c:1.11 src/external/bsd/dhcpcd/dist/src/if-bsd.c:1.12
--- src/external/bsd/dhcpcd/dist/src/if-bsd.c:1.11	Wed Aug 21 17:12:19 2019
+++ src/external/bsd/dhcpcd/dist/src/if-bsd.c	Wed Sep  4 13:28:56 2019
@@ -141,7 +141,7 @@ if_opensockets_os(struct dhcpcd_ctx *ctx
 #ifdef RTM_IFANNOUNCE
 	    RTM_IFANNOUNCE,
 #endif
-	    RTM_ADD, RTM_CHANGE, RTM_DELETE,
+	    RTM_ADD, RTM_CHANGE, RTM_DELETE, RTM_MISS,
 #ifdef RTM_CHGADDR
 	    RTM_CHGADDR,
 #endif
@@ -639,7 +639,11 @@ if_copyrt(struct dhcpcd_ctx *ctx, struct
 {
 	const struct sockaddr *rti_info[RTAX_MAX];
 
-	if (~rtm->rtm_addrs & (RTA_DST | RTA_GATEWAY)) {
+	if (!(rtm->rtm_addrs & RTA_DST)) {
+		errno = EINVAL;
+		return -1;
+	}
+	if (rtm->rtm_type != RTM_MISS && !(rtm->rtm_addrs & RTA_GATEWAY)) {
 		errno = EINVAL;
 		return -1;
 	}
@@ -674,12 +678,24 @@ if_copyrt(struct dhcpcd_ctx *ctx, struct
 		if (rt->rt_netmask.sa_family == 255) /* Why? */
 			rt->rt_netmask.sa_family = rt->rt_dest.sa_family;
 	}
-	/* dhcpcd likes an unspecified gateway to indicate via the link. */
-	if (rt->rt_flags & RTF_GATEWAY &&
-	    rti_info[RTAX_GATEWAY]->sa_family != AF_LINK)
-		if_copysa(&rt->rt_gateway, rti_info[RTAX_GATEWAY]);
+
+	/* dhcpcd likes an unspecified gateway to indicate via the link.
+	 * However we need to know if gateway was a link with an address. */
+	if (rtm->rtm_addrs & RTA_GATEWAY) {
+		if (rti_info[RTAX_GATEWAY]->sa_family == AF_LINK) {
+			const struct sockaddr_dl *sdl;
+
+			sdl = (const struct sockaddr_dl*)
+			    (const void *)rti_info[RTAX_GATEWAY];
+			if (sdl->sdl_alen != 0)
+				rt->rt_dflags |= RTDF_GATELINK;
+		} else if (rtm->rtm_flags & RTF_GATEWAY)
+			if_copysa(&rt->rt_gateway, rti_info[RTAX_GATEWAY]);
+	}
+
 	if (rtm->rtm_addrs & RTA_IFA)
 		if_copysa(&rt->rt_ifa, rti_info[RTAX_IFA]);
+
 	rt->rt_mtu = (unsigned int)rtm->rtm_rmx.rmx_mtu;
 
 	if (rtm->rtm_index)
@@ -691,6 +707,9 @@ if_copyrt(struct dhcpcd_ctx *ctx, struct
 	else
 		rt->rt_ifp = if_findsa(ctx, rti_info[RTAX_DST]);
 
+	if (rt->rt_ifp == NULL && rtm->rtm_type == RTM_MISS)
+		rt->rt_ifp = if_find(ctx->ifaces, "lo0");
+
 	if (rt->rt_ifp == NULL) {
 		errno = ESRCH;
 		return -1;
@@ -1070,30 +1089,30 @@ if_rtm(struct dhcpcd_ctx *ctx, const str
 		return 0;
 
 	if (if_copyrt(ctx, &rt, rtm) == -1)
-		return -1;
+		return errno == ENOTSUP ? 0 : -1;
 
 #ifdef INET6
 	/*
 	 * BSD announces host routes.
 	 * As such, we should be notified of reachability by its
 	 * existance with a hardware address.
+	 * Ensure we don't call this for a newly incomplete state.
 	 */
-	if (rt.rt_dest.sa_family == AF_INET6 && rt.rt_flags & RTF_HOST) {
-		struct sockaddr_in6 dest;
-		struct sockaddr_dl sdl;
+	if (rt.rt_dest.sa_family == AF_INET6 &&
+	    (rt.rt_flags & RTF_HOST || rtm->rtm_type == RTM_MISS) &&
+	    !(rtm->rtm_type == RTM_ADD && !(rt.rt_dflags & RTDF_GATELINK)))
+	{
+		bool reachable;
 
-		memcpy(&dest, &rt.rt_dest, rt.rt_dest.sa_len);
-		if (rt.rt_gateway.sa_family == AF_LINK)
-			memcpy(&sdl, &rt.rt_gateway, rt.rt_gateway.sa_len);
-		else
-			sdl.sdl_alen = 0;
-		ipv6nd_neighbour(ctx, &dest.sin6_addr,
-		    rtm->rtm_type != RTM_DELETE && sdl.sdl_alen ?
-		    IPV6ND_REACHABLE : 0);
+		reachable = (rtm->rtm_type == RTM_ADD ||
+		    rtm->rtm_type == RTM_CHANGE) &&
+		    rt.rt_dflags & RTDF_GATELINK;
+		ipv6nd_neighbour(ctx, &rt.rt_ss_dest.sin6.sin6_addr, reachable);
 	}
 #endif
 
-	rt_recvrt(rtm->rtm_type, &rt, rtm->rtm_pid);
+	if (rtm->rtm_type != RTM_MISS)
+		rt_recvrt(rtm->rtm_type, &rt, rtm->rtm_pid);
 	return 0;
 }
 
@@ -1299,7 +1318,8 @@ if_dispatch(struct dhcpcd_ctx *ctx, cons
 		return if_ifinfo(ctx, (const void *)rtm);
 	case RTM_ADD:		/* FALLTHROUGH */
 	case RTM_CHANGE:	/* FALLTHROUGH */
-	case RTM_DELETE:
+	case RTM_DELETE:	/* FALLTHROUGH */
+	case RTM_MISS:
 		return if_rtm(ctx, (const void *)rtm);
 #ifdef RTM_CHGADDR
 	case RTM_CHGADDR:	/* FALLTHROUGH */

Index: src/external/bsd/dhcpcd/dist/src/dhcpcd.8.in
diff -u src/external/bsd/dhcpcd/dist/src/dhcpcd.8.in:1.2 src/external/bsd/dhcpcd/dist/src/dhcpcd.8.in:1.3
--- src/external/bsd/dhcpcd/dist/src/dhcpcd.8.in:1.2	Fri Jul 26 10:39:29 2019
+++ src/external/bsd/dhcpcd/dist/src/dhcpcd.8.in	Wed Sep  4 13:28:56 2019
@@ -24,7 +24,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd July 25, 2019
+.Dd August 28, 2019
 .Dt DHCPCD 8
 .Os
 .Sh NAME
@@ -71,7 +71,7 @@
 .Fl k , Fl Fl release
 .Op interface
 .Nm
-.Fl U, Fl Fl dumplease
+.Fl U , Fl Fl dumplease
 .Ar interface
 .Nm
 .Fl Fl version
@@ -260,7 +260,7 @@ otheriwse if persistent storage is avail
 (link local address + time) is generated,
 otherwise DUID-LL is generated (link local address).
 This, plus the IAID will be used as the
-.Fl I, Fl Fl clientid .
+.Fl I , Fl Fl clientid .
 The DUID generated will be held in
 .Pa @DBDIR@/duid
 and should not be copied to other hosts.
@@ -470,7 +470,7 @@ This option is only needed when
 .Nm
 is not processing IPv6RA messages and the need for DHCPv6 Information Request
 exists.
-.It Fl S, Fl Fl static Ar value
+.It Fl S , Fl Fl static Ar value
 Configures a static DHCP
 .Ar value .
 If you set
@@ -660,7 +660,7 @@ Quiet
 .Nm
 on the command line, only warnings and errors will be displayed.
 The messages are still logged though.
-.It Fl T, Fl Fl test
+.It Fl T , Fl Fl test
 On receipt of DHCP messages just call
 .Pa @SCRIPT@
 with the reason of TEST which echos the DHCP variables found in the message
@@ -673,7 +673,7 @@ option is not sent in TEST mode so that 
 To test INFORM the interface needs to be configured with the desired address
 before starting
 .Nm .
-.It Fl U, Fl Fl dumplease Ar interface
+.It Fl U , Fl Fl dumplease Ar interface
 Dumps the last lease for the
 .Ar interface
 to stdout.
@@ -683,20 +683,20 @@ Use the
 or
 .Fl 6
 flags to specify an address family.
-.It Fl V, Fl Fl variables
+.It Fl V , Fl Fl variables
 Display a list of option codes, the associated variable and encoding for use in
 .Xr dhcpcd-run-hooks 8 .
 Variables are prefixed with new_ and old_ unless the option number is -.
 Variables without an option are part of the DHCP message and cannot be
 directly requested.
-.It Fl W, Fl Fl whitelist Ar address Ns Op /cidr
+.It Fl W , Fl Fl whitelist Ar address Ns Op /cidr
 Only accept packets from
 .Ar address Ns Op /cidr .
-.Fl X, Fl Fl blacklist
+.Fl X , Fl Fl blacklist
 is ignored if
-.Fl W, Fl Fl whitelist
+.Fl W , Fl Fl whitelist
 is set.
-.It Fl X, Fl Fl blacklist Ar address Ns Op Ar /cidr
+.It Fl X , Fl Fl blacklist Ar address Ns Op Ar /cidr
 Ignore all packets from
 .Ar address Ns Op Ar /cidr .
 .It Fl Z , Fl Fl denyinterfaces Ar pattern
@@ -771,6 +771,7 @@ If you always use the same options, put 
 .It Pa @SCRIPT@
 Bourne shell script that is run to configure or de-configure an interface.
 .It Pa @LIBDIR@/dhcpcd/dev
+Linux
 .Pa /dev
 management modules.
 .It Pa @HOOKDIR@
@@ -818,7 +819,7 @@ Control socket to per interface daemon.
 .Xr dhcpcd-run-hooks 8 ,
 .Xr resolvconf 8
 .Sh STANDARDS
-RFC\ 951, RFC\ 1534, RFC\ 2104, RFC\ 2131, RFC\ 2132, RFC\ 2563, RFC\ 2855, 
+RFC\ 951, RFC\ 1534, RFC\ 2104, RFC\ 2131, RFC\ 2132, RFC\ 2563, RFC\ 2855,
 RFC\ 3004, RFC\ 3118, RFC\ 3203, RFC\ 3315, RFC\ 3361, RFC\ 3633, RFC\ 3396,
 RFC\ 3397, RFC\ 3442, RFC\ 3495, RFC\ 3925, RFC\ 3927, RFC\ 4039, RFC\ 4075,
 RFC\ 4242, RFC\ 4361, RFC\ 4390, RFC\ 4702, RFC\ 4074, RFC\ 4861, RFC\ 4833,

Index: src/external/bsd/dhcpcd/dist/src/ipv6.c
diff -u src/external/bsd/dhcpcd/dist/src/ipv6.c:1.3 src/external/bsd/dhcpcd/dist/src/ipv6.c:1.4
--- src/external/bsd/dhcpcd/dist/src/ipv6.c:1.3	Tue Jul 30 10:25:03 2019
+++ src/external/bsd/dhcpcd/dist/src/ipv6.c	Wed Sep  4 13:28:56 2019
@@ -629,7 +629,7 @@ ipv6_addaddr1(struct ipv6_addr *ia, cons
 	uint32_t pltime, vltime;
 	__printflike(1, 2) void (*logfunc)(const char *, ...);
 #ifdef ND6_ADVERTISE
-	bool vltime_was_zero;
+	bool vltime_was_zero = ia->prefix_vltime == 0;
 #endif
 #ifdef __sun
 	struct ipv6_state *state;
@@ -641,7 +641,11 @@ ipv6_addaddr1(struct ipv6_addr *ia, cons
 	if (ia->flags & IPV6_AF_DADCOMPLETED) {
 		logdebugx("%s: IP address %s already exists",
 		    ia->iface->name, ia->saddr);
+#ifdef ND6_ADVERTISE
+		goto advertise;
+#else
 		return 0;
+#endif
 	}
 #endif
 
@@ -707,9 +711,6 @@ ipv6_addaddr1(struct ipv6_addr *ia, cons
 		    " seconds",
 		    ifp->name, ia->prefix_pltime, ia->prefix_vltime);
 
-#ifdef ND6_ADVERTISE
-	vltime_was_zero = ia->prefix_vltime == 0;
-#endif
 	if (if_address6(RTM_NEWADDR, ia) == -1) {
 		logerr(__func__);
 		/* Restore real pltime and vltime */
@@ -774,6 +775,9 @@ ipv6_addaddr1(struct ipv6_addr *ia, cons
 #endif
 
 #ifdef ND6_ADVERTISE
+#ifdef __sun
+advertise:
+#endif
 	/* Re-advertise the preferred address to be safe. */
 	if (!vltime_was_zero)
 		ipv6nd_advertise(ia);
@@ -1060,6 +1064,31 @@ ipv6_getstate(struct interface *ifp)
 	return state;
 }
 
+struct ipv6_addr *
+ipv6_ifanyglobal(struct interface *ifp)
+{
+	struct ipv6_state *state;
+	struct ipv6_addr *ia;
+
+	if (ifp->carrier == LINK_DOWN)
+		return NULL;
+
+	state = IPV6_STATE(ifp);
+	if (state == NULL)
+		return NULL;
+
+	TAILQ_FOREACH(ia, &state->addrs, next) {
+		if (IN6_IS_ADDR_LINKLOCAL(&ia->addr))
+			continue;
+		/* Let's be optimistic.
+		 * Any decent OS won't forward or accept traffic
+		 * from/to tentative or detached addresses. */
+		if (!(ia->addr_flags & IN6_IFF_DUPLICATED))
+			break;
+	}
+	return ia;
+}
+
 void
 ipv6_handleifa(struct dhcpcd_ctx *ctx,
     int cmd, struct if_head *ifs, const char *ifname,
@@ -1069,6 +1098,22 @@ ipv6_handleifa(struct dhcpcd_ctx *ctx,
 	struct ipv6_state *state;
 	struct ipv6_addr *ia;
 	struct ll_callback *cb;
+	bool anyglobal;
+
+#ifdef __sun
+	struct sockaddr_in6 subnet;
+
+	/* Solaris on-link route is an unspecified address! */
+	if (IN6_IS_ADDR_UNSPECIFIED(addr)) {
+		if (if_getsubnet(ctx, ifname, AF_INET6,
+		    &subnet, sizeof(subnet)) == -1)
+		{
+			logerr(__func__);
+			return;
+		}
+		addr = &subnet.sin6_addr;
+	}
+#endif
 
 #if 0
 	char dbuf[INET6_ADDRSTRLEN];
@@ -1076,8 +1121,8 @@ ipv6_handleifa(struct dhcpcd_ctx *ctx,
 
 	dbp = inet_ntop(AF_INET6, &addr->s6_addr,
 	    dbuf, INET6_ADDRSTRLEN);
-	loginfox("%s: cmd %d addr %s",
-	    ifname, cmd, dbp);
+	loginfox("%s: cmd %d addr %s addrflags %d",
+	    ifname, cmd, dbp, addrflags);
 #endif
 
 	if (ifs == NULL)
@@ -1088,6 +1133,7 @@ ipv6_handleifa(struct dhcpcd_ctx *ctx,
 		return;
 	if ((state = ipv6_getstate(ifp)) == NULL)
 		return;
+	anyglobal = ipv6_ifanyglobal(ifp) != NULL;
 
 	TAILQ_FOREACH(ia, &state->addrs, next) {
 		if (IN6_ARE_ADDR_EQUAL(&ia->addr, addr))
@@ -1187,6 +1233,7 @@ ipv6_handleifa(struct dhcpcd_ctx *ctx,
 	if (ia == NULL)
 		return;
 
+	ctx->options &= ~DHCPCD_RTBUILD;
 	ipv6nd_handleifa(cmd, ia, pid);
 #ifdef DHCP6
 	dhcp6_handleifa(cmd, ia, pid);
@@ -1198,6 +1245,15 @@ out:
 		ipv6_freeaddr(ia);
 	else if (!(ia->addr_flags & IN6_IFF_NOTUSEABLE))
 		ia->flags |= IPV6_AF_DADCOMPLETED;
+
+	/* If we've not already called rt_build via the IPv6ND
+	 * or DHCP6 handlers and the existance of any useable
+	 * global address on the interface has changed,
+	 * call rt_build to add/remove the default route. */
+	if (ifp->active && ifp->options->options & DHCPCD_IPV6 &&
+	    !(ctx->options & DHCPCD_RTBUILD) &&
+	    (ipv6_ifanyglobal(ifp) != NULL) != anyglobal)
+		rt_build(ctx, AF_INET6);
 }
 
 int
@@ -1498,7 +1554,13 @@ ipv6_newaddr(struct interface *ifp, cons
 			goto err;
 	} else if (ia->flags & IPV6_AF_RAPFX) {
 		ia->prefix = *addr;
+#ifdef __sun
+		ia->addr = *addr;
+		cbp = inet_ntop(AF_INET6, &ia->addr, buf, sizeof(buf));
+		goto paddr;
+#else
 		return ia;
+#endif
 	} else if (ia->flags & (IPV6_AF_REQUEST | IPV6_AF_DELEGATEDPFX) &&
 	           prefix_len != 128)
 	{
@@ -2273,6 +2335,8 @@ inet6_raroutes(rb_tree_t *routes, struct
 		}
 		if (rap->lifetime == 0)
 			continue;
+		if (ipv6_ifanyglobal(rap->iface) == NULL)
+			continue;
 		rt = inet6_makerouter(rap);
 		if (rt == NULL)
 			continue;

Index: src/external/bsd/dhcpcd/dist/src/ipv6.h
diff -u src/external/bsd/dhcpcd/dist/src/ipv6.h:1.4 src/external/bsd/dhcpcd/dist/src/ipv6.h:1.5
--- src/external/bsd/dhcpcd/dist/src/ipv6.h:1.4	Wed Aug 21 17:12:19 2019
+++ src/external/bsd/dhcpcd/dist/src/ipv6.h	Wed Sep  4 13:28:56 2019
@@ -110,9 +110,9 @@
     * While it supports DaD, to seems to only expose IFF_DUPLICATE
     * so we have no way of knowing if it's tentative or not.
     * I don't even know if Solaris has any special treatment for tentative. */
-#  define IN6_IFF_TENTATIVE	0
+#  define IN6_IFF_TENTATIVE	0x02
 #  define IN6_IFF_DUPLICATED	0x04
-#  define IN6_IFF_DETACHED	0
+#  define IN6_IFF_DETACHED	0x00
 #endif
 
 #define IN6_IFF_NOTUSEABLE \
@@ -159,7 +159,7 @@
 #if !defined(SMALL) && \
     ((defined(__DragonFly_version) && __DragonFly_version >= 500703) || \
     (defined(__NetBSD_Version__) && __NetBSD_Version__ >= 899002800) || \
-    defined(__linux__))
+    defined(__linux__) || defined(__sun))
 #  define ND6_ADVERTISE
 #endif
 
@@ -273,6 +273,7 @@ int ipv6_handleifa_addrs(int, struct ipv
 struct ipv6_addr *ipv6_iffindaddr(struct interface *,
     const struct in6_addr *, int);
 int ipv6_hasaddr(const struct interface *);
+struct ipv6_addr *ipv6_ifanyglobal(struct interface *);
 int ipv6_findaddrmatch(const struct ipv6_addr *, const struct in6_addr *,
     unsigned int);
 struct ipv6_addr *ipv6_findaddr(struct dhcpcd_ctx *,

Index: src/external/bsd/dhcpcd/dist/src/ipv6nd.c
diff -u src/external/bsd/dhcpcd/dist/src/ipv6nd.c:1.10 src/external/bsd/dhcpcd/dist/src/ipv6nd.c:1.11
--- src/external/bsd/dhcpcd/dist/src/ipv6nd.c:1.10	Tue Jul 30 10:25:03 2019
+++ src/external/bsd/dhcpcd/dist/src/ipv6nd.c	Wed Sep  4 13:28:56 2019
@@ -217,7 +217,6 @@ ipv6nd_open0(void)
 		goto eexit;
 
 	ICMP6_FILTER_SETBLOCKALL(&filt);
-	ICMP6_FILTER_SETPASS(ND_NEIGHBOR_ADVERT, &filt);
 	ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt);
 	if (setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER,
 	    &filt, sizeof(filt)) == -1)
@@ -460,6 +459,11 @@ ipv6nd_advertise(struct ipv6_addr *ia)
 	if (IN6_IS_ADDR_MULTICAST(&ia->addr))
 		return;
 
+#ifdef __sun
+	if (!(ia->flags & IPV6_AF_AUTOCONF) && ia->flags & IPV6_AF_RAPFX)
+		return;
+#endif
+
 	ctx = ia->iface->ctx;
 	/* Find the most preferred address to advertise. */
 	iaf = NULL;
@@ -555,45 +559,60 @@ ipv6nd_startexpire(struct interface *ifp
 	    ipv6nd_expire, ifp);
 }
 
-static void
-ipv6nd_reachable(struct ra *rap, int flags)
+/*
+ * Neighbour reachability.
+ *
+ * RFC 4681 6.2.5 says when a node is no longer a router it MUST
+ * send a RA with a zero lifetime.
+ * All OS's I know of set the NA router flag if they are a router
+ * or not and disregard that they are actively advertising or
+ * shutting down. If the interface is disabled, it cant't send a NA at all.
+ *
+ * As such we CANNOT rely on the NA Router flag and MUST use
+ * unreachability or receive a RA with a lifetime of zero to remove
+ * the node as a default router.
+ */
+void
+ipv6nd_neighbour(struct dhcpcd_ctx *ctx, struct in6_addr *addr, bool reachable)
 {
+	struct ra *rap, *rapr;
+
+	if (ctx->ra_routers == NULL)
+		return;
+
+	TAILQ_FOREACH(rap, ctx->ra_routers, next) {
+		if (IN6_ARE_ADDR_EQUAL(&rap->from, addr))
+			break;
+	}
 
-	if (rap->lifetime == 0)
+	if (rap == NULL || rap->expired)
 		return;
 
-	if (flags & IPV6ND_REACHABLE) {
-		if (rap->expired == 0)
+	if (reachable) {
+		if (rap->isreachable)
 			return;
 		loginfox("%s: %s is reachable again",
 		    rap->iface->name, rap->sfrom);
-		rap->expired = 0;
+		rap->isreachable = true;
+		return;
 	} else {
-		if (rap->expired != 0)
+		if (!rap->isreachable)
 			return;
-		logwarnx("%s: %s is unreachable, expiring it",
+		logwarnx("%s: %s is unreachable",
 		    rap->iface->name, rap->sfrom);
-		rap->expired = 1;
+		rap->isreachable = false;
 	}
 
-	rt_build(rap->iface->ctx, AF_INET6);
-	/* XXX Not really an RA */
-	script_runreason(rap->iface, "ROUTERADVERT");
-}
-
-void
-ipv6nd_neighbour(struct dhcpcd_ctx *ctx, struct in6_addr *addr, int flags)
-{
-	struct ra *rap;
-
-	if (ctx->ra_routers) {
-	        TAILQ_FOREACH(rap, ctx->ra_routers, next) {
-			if (IN6_ARE_ADDR_EQUAL(&rap->from, addr)) {
-				ipv6nd_reachable(rap, flags);
-				break;
-			}
-		}
+	/* If we have no reachable default routers, try and solicit one. */
+	TAILQ_FOREACH(rapr, ctx->ra_routers, next) {
+		if (rap == rapr || rap->iface != rapr->iface)
+			continue;
+		if (rapr->isreachable && !rapr->expired && rapr->lifetime)
+			break;
 	}
+
+	if (rapr == NULL)
+		ipv6nd_startrs(rap->iface);
 }
 
 const struct ipv6_addr *
@@ -944,7 +963,7 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx,
 	struct in6_addr pi_prefix;
 	struct ipv6_addr *ap;
 	struct dhcp_opt *dho;
-	bool new_rap, new_data;
+	bool new_rap, new_data, has_address;
 	uint32_t old_lifetime;
 	__printflike(1, 2) void (*logfunc)(const char *, ...);
 #ifdef IPV6_MANAGETEMPADDR
@@ -1026,6 +1045,7 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx,
 		strlcpy(rap->sfrom, sfrom, sizeof(rap->sfrom));
 		TAILQ_INIT(&rap->addrs);
 		new_rap = true;
+		rap->isreachable = true;
 	} else
 		new_rap = false;
 	if (rap->data_len == 0) {
@@ -1044,7 +1064,7 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx,
 	 * routers like to decrease the advertised valid and preferred times
 	 * in accordance with the own prefix times which would result in too
 	 * much needless log spam. */
-	logfunc = new_rap ? loginfox : logdebugx,
+	logfunc = new_data || !rap->isreachable ? loginfox : logdebugx,
 	logfunc("%s: Router Advertisement from %s", ifp->name, rap->sfrom);
 
 	clock_gettime(CLOCK_MONOTONIC, &rap->acquired);
@@ -1064,9 +1084,10 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx,
 
 		state->retrans = rap->retrans = ntohl(nd_ra->nd_ra_retransmit);
 	}
-	if (rap->lifetime)
-		rap->expired = 0;
-	rap->hasdns = 0;
+	rap->expired = false;
+	rap->hasdns = false;
+	rap->isreachable = true;
+	has_address = false;
 
 #ifdef IPV6_AF_TEMPORARY
 	ipv6_markaddrsstale(ifp, IPV6_AF_TEMPORARY);
@@ -1200,6 +1221,9 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx,
 			    ntohl(pi.nd_opt_pi_valid_time);
 			ap->prefix_pltime =
 			    ntohl(pi.nd_opt_pi_preferred_time);
+			if (ap->prefix_vltime != 0 &&
+			    ap->flags & IPV6_AF_AUTOCONF)
+				has_address = true;
 
 #ifdef IPV6_MANAGETEMPADDR
 			/* RFC4941 Section 3.3.3 */
@@ -1266,6 +1290,10 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx,
 		}
 	}
 
+	if (new_data && !has_address && rap->lifetime && !ipv6_ifanyglobal(ifp))
+		logwarnx("%s: no global addresses for default route",
+		    ifp->name);
+
 	if (new_rap)
 		add_router(ifp->ctx, rap);
 
@@ -1316,20 +1344,21 @@ nodhcp6:
 	ipv6nd_expirera(ifp);
 }
 
-int
-ipv6nd_hasra(const struct interface *ifp)
+bool
+ipv6nd_hasralifetime(const struct interface *ifp, bool lifetime)
 {
 	const struct ra *rap;
 
 	if (ifp->ctx->ra_routers) {
 		TAILQ_FOREACH(rap, ifp->ctx->ra_routers, next)
-			if (rap->iface == ifp && !rap->expired)
-				return 1;
+			if (rap->iface == ifp && !rap->expired &&
+			    (!lifetime ||rap->lifetime))
+				return true;
 	}
-	return 0;
+	return false;
 }
 
-int
+bool
 ipv6nd_hasradhcp(const struct interface *ifp)
 {
 	const struct ra *rap;
@@ -1338,11 +1367,11 @@ ipv6nd_hasradhcp(const struct interface 
 		TAILQ_FOREACH(rap, ifp->ctx->ra_routers, next) {
 			if (rap->iface == ifp &&
 			    !rap->expired &&
-			    (rap->flags & (ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER)))
-				return 1;
+			    (rap->flags &(ND_RA_FLAG_MANAGED|ND_RA_FLAG_OTHER)))
+				return true;
 		}
 	}
-	return 0;
+	return false;
 }
 
 static const uint8_t *
@@ -1399,7 +1428,7 @@ ipv6nd_env(FILE *fp, const struct interf
 	clock_gettime(CLOCK_MONOTONIC, &now);
 	i = n = 0;
 	TAILQ_FOREACH(rap, ifp->ctx->ra_routers, next) {
-		if (rap->iface != ifp)
+		if (rap->iface != ifp || rap->expired)
 			continue;
 		i++;
 		snprintf(ndprefix, sizeof(ndprefix), "nd%zu", i);
@@ -1503,7 +1532,7 @@ ipv6nd_expirera(void *arg)
 	struct interface *ifp;
 	struct ra *rap, *ran;
 	struct timespec now, lt, expire, next;
-	bool expired, valid, validone;
+	bool expired, valid;
 	struct ipv6_addr *ia;
 	size_t len, olen;
 	uint8_t *p;
@@ -1522,9 +1551,9 @@ ipv6nd_expirera(void *arg)
 	timespecclear(&next);
 
 	TAILQ_FOREACH_SAFE(rap, ifp->ctx->ra_routers, next, ran) {
-		if (rap->iface != ifp)
+		if (rap->iface != ifp || rap->expired)
 			continue;
-		valid = validone = false;
+		valid = false;
 		if (rap->lifetime) {
 			lt.tv_sec = (time_t)rap->lifetime;
 			lt.tv_nsec = 0;
@@ -1533,8 +1562,8 @@ ipv6nd_expirera(void *arg)
 				if (!rap->expired) {
 					logwarnx("%s: %s: router expired",
 					    ifp->name, rap->sfrom);
-					rap->expired = expired = 1;
 					rap->lifetime = 0;
+					expired = true;
 				}
 			} else {
 				valid = true;
@@ -1552,7 +1581,7 @@ ipv6nd_expirera(void *arg)
 			if (ia->prefix_vltime == 0)
 				continue;
 			if (ia->prefix_vltime == ND6_INFINITE_LIFETIME) {
-				validone = true;
+				valid = true;
 				continue;
 			}
 			lt.tv_sec = (time_t)ia->prefix_vltime;
@@ -1576,7 +1605,7 @@ ipv6nd_expirera(void *arg)
 				if (!timespecisset(&next) ||
 				    timespeccmp(&next, &lt, >))
 					next = lt;
-				validone = true;
+				valid = true;
 			}
 		}
 
@@ -1626,7 +1655,7 @@ ipv6nd_expirera(void *arg)
 			if (ltime == 0)
 				continue;
 			if (ltime == ND6_INFINITE_LIFETIME) {
-				validone = true;
+				valid = true;
 				continue;
 			}
 
@@ -1643,15 +1672,15 @@ ipv6nd_expirera(void *arg)
 			    timespeccmp(&next, &lt, >))
 			{
 				next = lt;
-				validone = true;
+				valid = true;
 			}
 		}
 
-		if (valid || validone)
+		if (valid)
 			continue;
 
-		/* Router has expired. Let's not keep a lot of them.
-		 * We should work out if all the options have expired .... */
+		/* Router has expired. Let's not keep a lot of them. */
+		rap->expired = true;
 		if (++nexpired > EXPIRED_MAX)
 			ipv6nd_free_ra(rap);
 	}
@@ -1670,7 +1699,7 @@ void
 ipv6nd_drop(struct interface *ifp)
 {
 	struct ra *rap, *ran;
-	uint8_t expired = 0;
+	bool expired = false;
 
 	if (ifp->ctx->ra_routers == NULL)
 		return;
@@ -1678,7 +1707,7 @@ ipv6nd_drop(struct interface *ifp)
 	eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
 	TAILQ_FOREACH_SAFE(rap, ifp->ctx->ra_routers, next, ran) {
 		if (rap->iface == ifp) {
-			rap->expired = expired = 1;
+			rap->expired = expired = true;
 			ipv6nd_drop_ra(rap);
 		}
 	}
@@ -1690,82 +1719,6 @@ ipv6nd_drop(struct interface *ifp)
 }
 
 static void
-ipv6nd_handlena(struct dhcpcd_ctx *ctx, const char *sfrom,
-    struct interface *ifp, struct icmp6_hdr *icp, size_t len, int hoplimit)
-{
-	struct nd_neighbor_advert *nd_na;
-	struct in6_addr nd_na_target;
-	struct ra *rap;
-	uint32_t is_router, is_solicited;
-	char buf[INET6_ADDRSTRLEN];
-	const char *taddr;
-
-	if (ifp == NULL) {
-#ifdef DEBUG_NS
-		logdebugx("NA for unexpected interface from %s", sfrom);
-#endif
-		return;
-	}
-
-	if ((size_t)len < sizeof(struct nd_neighbor_advert)) {
-		logerrx("%s: IPv6 NA too short from %s", ifp->name, sfrom);
-		return;
-	}
-
-	/* RFC 4861 7.1.2 */
-	if (hoplimit != 255) {
-		logerrx("invalid hoplimit(%d) in NA from %s",
-		    hoplimit, sfrom);
-		return;
-	}
-
-	nd_na = (struct nd_neighbor_advert *)icp;
-	is_router = nd_na->nd_na_flags_reserved & ND_NA_FLAG_ROUTER;
-	is_solicited = nd_na->nd_na_flags_reserved & ND_NA_FLAG_SOLICITED;
-	taddr = inet_ntop(AF_INET6, &nd_na->nd_na_target,
-	    buf, INET6_ADDRSTRLEN);
-
-	/* nd_na->nd_na_target is not aligned. */
-	memcpy(&nd_na_target, &nd_na->nd_na_target, sizeof(nd_na_target));
-	if (IN6_IS_ADDR_MULTICAST(&nd_na_target)) {
-		logerrx("%s: NA multicast address %s (%s)",
-		    ifp->name, taddr, sfrom);
-		return;
-	}
-
-	TAILQ_FOREACH(rap, ctx->ra_routers, next) {
-		if (rap->iface == ifp &&
-		    IN6_ARE_ADDR_EQUAL(&rap->from, &nd_na_target))
-			break;
-	}
-	if (rap == NULL) {
-#ifdef DEBUG_NS
-		logdebugx("%s: unexpected NA from %s for %s",
-		    ifp->name, sfrom, taddr);
-#endif
-		return;
-	}
-
-#ifdef DEBUG_NS
-	logdebugx("%s: %sNA for %s from %s",
-	    ifp->name, is_solicited ? "solicited " : "", taddr, sfrom);
-#endif
-
-	/* Node is no longer a router, so remove it from consideration */
-	if (!is_router && !rap->expired) {
-		loginfox("%s: %s not a router (%s)",
-		    ifp->name, taddr, sfrom);
-		rap->expired = 1;
-		rt_build(ifp->ctx,  AF_INET6);
-		script_runreason(ifp, "ROUTERADVERT");
-		return;
-	}
-
-	if (is_solicited && is_router && rap->lifetime)
-		ipv6nd_reachable(rap, IPV6ND_REACHABLE);
-}
-
-static void
 ipv6nd_handledata(void *arg)
 {
 	struct dhcpcd_ctx *ctx;
@@ -1828,10 +1781,6 @@ ipv6nd_handledata(void *arg)
 	icp = (struct icmp6_hdr *)buf;
 	if (icp->icmp6_code == 0) {
 		switch(icp->icmp6_type) {
-			case ND_NEIGHBOR_ADVERT:
-				ipv6nd_handlena(ctx, sfrom,
-				    ifp, icp, (size_t)len, hoplimit);
-				return;
 			case ND_ROUTER_ADVERT:
 				ipv6nd_handlera(ctx, &from, sfrom,
 				    ifp, icp, (size_t)len, hoplimit);

Reply via email to