Module Name:    src
Committed By:   roy
Date:           Tue Jan 22 15:20:21 UTC 2019

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

Log Message:
Sync


To generate a diff of this commit:
cvs rdiff -u -r1.7 -r1.8 src/external/bsd/dhcpcd/dist/src/bpf.c
cvs rdiff -u -r1.14 -r1.15 src/external/bsd/dhcpcd/dist/src/dhcp.c \
    src/external/bsd/dhcpcd/dist/src/dhcpcd.c
cvs rdiff -u -r1.2 -r1.3 src/external/bsd/dhcpcd/dist/src/dhcp6.c \
    src/external/bsd/dhcpcd/dist/src/if-bsd.c \
    src/external/bsd/dhcpcd/dist/src/ipv6nd.c
cvs rdiff -u -r1.10 -r1.11 src/external/bsd/dhcpcd/dist/src/if-options.c

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

Modified files:

Index: src/external/bsd/dhcpcd/dist/src/bpf.c
diff -u src/external/bsd/dhcpcd/dist/src/bpf.c:1.7 src/external/bsd/dhcpcd/dist/src/bpf.c:1.8
--- src/external/bsd/dhcpcd/dist/src/bpf.c:1.7	Sat Jun  2 09:44:27 2018
+++ src/external/bsd/dhcpcd/dist/src/bpf.c	Tue Jan 22 15:20:21 2019
@@ -1,6 +1,6 @@
 /*
  * dhcpcd: BPF arp and bootp filtering
- * Copyright (c) 2006-2018 Roy Marples <r...@marples.name>
+ * Copyright (c) 2006-2019 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/dhcp.c
diff -u src/external/bsd/dhcpcd/dist/src/dhcp.c:1.14 src/external/bsd/dhcpcd/dist/src/dhcp.c:1.15
--- src/external/bsd/dhcpcd/dist/src/dhcp.c:1.14	Sun Nov  4 16:30:28 2018
+++ src/external/bsd/dhcpcd/dist/src/dhcp.c	Tue Jan 22 15:20:21 2019
@@ -1,6 +1,6 @@
 /*
  * dhcpcd - DHCP client daemon
- * Copyright (c) 2006-2018 Roy Marples <r...@marples.name>
+ * Copyright (c) 2006-2019 Roy Marples <r...@marples.name>
  * All rights reserved
 
  * Redistribution and use in source and binary forms, with or without
@@ -1604,11 +1604,6 @@ dhcp_openudp(struct interface *ifp)
 	n = 1;
 	if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n)) == -1)
 		goto eexit;
-#ifdef SO_RERROR
-	n = 1;
-	if (setsockopt(s, SOL_SOCKET, SO_RERROR, &n, sizeof(n)) == -1)
-		goto eexit;
-#endif
 	memset(&sin, 0, sizeof(sin));
 	sin.sin_family = AF_INET;
 	sin.sin_port = htons(BOOTPC);
@@ -2636,6 +2631,7 @@ dhcp_reboot(struct interface *ifp)
 	 * interface gets the reply. */
 	ia = ipv4_iffindaddr(ifp, &state->lease.addr, NULL);
 	if (ia != NULL &&
+	    !(ifp->ctx->options & DHCPCD_TEST) &&
 #ifdef IN_IFF_NOTUSEABLE
 	    !(ia->addr_flags & IN_IFF_NOTUSEABLE) &&
 #endif
Index: src/external/bsd/dhcpcd/dist/src/dhcpcd.c
diff -u src/external/bsd/dhcpcd/dist/src/dhcpcd.c:1.14 src/external/bsd/dhcpcd/dist/src/dhcpcd.c:1.15
--- src/external/bsd/dhcpcd/dist/src/dhcpcd.c:1.14	Mon Aug 27 13:43:05 2018
+++ src/external/bsd/dhcpcd/dist/src/dhcpcd.c	Tue Jan 22 15:20:21 2019
@@ -1,6 +1,6 @@
 /*
  * dhcpcd - DHCP client daemon
- * Copyright (c) 2006-2018 Roy Marples <r...@marples.name>
+ * Copyright (c) 2006-2019 Roy Marples <r...@marples.name>
  * All rights reserved
 
  * Redistribution and use in source and binary forms, with or without
@@ -25,7 +25,7 @@
  * SUCH DAMAGE.
  */
 
-const char dhcpcd_copyright[] = "Copyright (c) 2006-2018 Roy Marples";
+const char dhcpcd_copyright[] = "Copyright (c) 2006-2019 Roy Marples";
 
 #include <sys/file.h>
 #include <sys/socket.h>
@@ -314,13 +314,6 @@ dhcpcd_daemonise(struct dhcpcd_ctx *ctx)
 		return 0;
 	}
 
-	/* Store the pid and routing message seq number so we can identify
-	 * the last message successfully sent to the kernel.
-	 * This allows us to ignore all messages we sent after forking
-	 * and detaching. */
-	ctx->ppid = getpid();
-	ctx->pseq = ctx->sseq;
-
 	switch (pid = fork()) {
 	case -1:
 		logerr("%s: fork", __func__);
@@ -451,6 +444,10 @@ configure_interface1(struct interface *i
 		ifo->options &=
 		    ~(DHCPCD_IPV6RS | DHCPCD_DHCP6 | DHCPCD_WAITIP6);
 
+	if (!(ifo->options & DHCPCD_IPV6RS))
+		ifo->options &=
+		    ~(DHCPCD_IPV6RA_AUTOCONF | DHCPCD_IPV6RA_REQRDNSS);
+
 	/* We want to setup INET6 on the interface as soon as possible. */
 	if (ifp->active == IF_ACTIVE_USER &&
 	    ifo->options & DHCPCD_IPV6 &&
@@ -738,6 +735,7 @@ dhcpcd_handlecarrier(struct dhcpcd_ctx *
 #endif
 			dhcp_abort(ifp);
 			ipv6nd_expire(ifp, 0);
+			dhcp6_abort(ifp);
 #else
 			dhcpcd_drop(ifp, 0);
 #endif
@@ -754,19 +752,21 @@ dhcpcd_handlecarrier(struct dhcpcd_ctx *
 #endif
 			if (ifp->wireless) {
 				uint8_t ossid[IF_SSIDLEN];
-#ifdef NOCARRIER_PRESERVE_IP
 				size_t olen;
 
 				olen = ifp->ssid_len;
-#endif
 				memcpy(ossid, ifp->ssid, ifp->ssid_len);
 				if_getssid(ifp);
-#ifdef NOCARRIER_PRESERVE_IP
+
 				/* If we changed SSID network, drop leases */
 				if (ifp->ssid_len != olen ||
 				    memcmp(ifp->ssid, ossid, ifp->ssid_len))
+				{
+#ifdef NOCARRIER_PRESERVE_IP
 					dhcpcd_drop(ifp, 0);
 #endif
+					ipv4ll_reset(ifp);
+				}
 			}
 			dhcpcd_initstate(ifp, 0);
 			script_runreason(ifp, "CARRIER");

Index: src/external/bsd/dhcpcd/dist/src/dhcp6.c
diff -u src/external/bsd/dhcpcd/dist/src/dhcp6.c:1.2 src/external/bsd/dhcpcd/dist/src/dhcp6.c:1.3
--- src/external/bsd/dhcpcd/dist/src/dhcp6.c:1.2	Sun Nov  4 16:30:28 2018
+++ src/external/bsd/dhcpcd/dist/src/dhcp6.c	Tue Jan 22 15:20:21 2019
@@ -1,6 +1,6 @@
 /*
  * dhcpcd - DHCP client daemon
- * Copyright (c) 2006-2018 Roy Marples <r...@marples.name>
+ * Copyright (c) 2006-2019 Roy Marples <r...@marples.name>
  * All rights reserved
 
  * Redistribution and use in source and binary forms, with or without
@@ -1516,6 +1516,7 @@ dhcp6_dadcallback(void *arg)
 				if (valid)
 					dhcpcd_daemonise(ifp->ctx);
 			}
+			ipv6nd_advertise(ia);
 		}
 	}
 }
@@ -3194,7 +3195,7 @@ dhcp6_recvif(struct interface *ifp, stru
 	ctx = ifp->ctx;
 	state = D6_STATE(ifp);
 	if (state == NULL || state->send == NULL) {
-		logdebug("%s: DHCPv6 reply received but not running",
+		logdebugx("%s: DHCPv6 reply received but not running",
 		    ifp->name);
 		return;
 	}
@@ -3299,14 +3300,24 @@ dhcp6_recvif(struct interface *ifp, stru
 			if (dhcp6_validatelease(ifp, r, len,
 			    ctx->sfrom, NULL) == -1)
 			{
-#ifndef SMALL
-				/* PD doesn't use CONFIRM, so REBIND could
-				 * throw up an invalid prefix if we
-				 * changed link */
-				if (state->state == DH6S_REBIND &&
-				    dhcp6_hasprefixdelegation(ifp))
+				/*
+				 * If we can't use the lease, fallback to
+				 * DISCOVER and try and get a new one.
+				 *
+				 * This is needed become some servers
+				 * renumber the prefix or address
+				 * and deny the current one before it expires
+				 * rather than sending it back with a zero
+				 * lifetime along with the new prefix or
+				 * address to use.
+				 * This behavior is wrong, but moving to the
+				 * DISCOVER phase works around it.
+				 *
+				 * The currently held lease is still valid
+				 * until a new one is found.
+				 */
+				if (state->state != DH6S_DISCOVER)
 					dhcp6_startdiscover(ifp);
-#endif
 				return;
 			}
 			if (state->state == DH6S_DISCOVER)
@@ -3538,11 +3549,12 @@ dhcp6_recv(struct dhcpcd_ctx *ctx, struc
 	}
 
 	if (r->type == DHCP6_RECONFIGURE) {
-		logdebugx("%s: RECONFIGURE recv from %s,"
+		logdebugx("%s: RECONFIGURE6 recv from %s,"
 		    " sending to all interfaces",
 		    ifp->name, ctx->sfrom);
 		TAILQ_FOREACH(ifp, ctx->ifaces, next) {
-			if (D6_CSTATE(ifp) != NULL)
+			state = D6_CSTATE(ifp);
+			if (state != NULL && state->send != NULL)
 				dhcp6_recvif(ifp, r, len);
 		}
 		return;
@@ -3620,11 +3632,6 @@ dhcp6_listen(struct dhcpcd_ctx *ctx, str
 	if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &n, sizeof(n)) == -1)
 		goto errexit;
 
-#ifdef SO_RERROR
-	n = 1;
-	if (setsockopt(s, SOL_SOCKET, SO_RERROR, &n, sizeof(n)) == -1)
-		goto errexit;
-#endif
 	memset(&sa, 0, sizeof(sa));
 	sa.sin6_family = AF_INET6;
 	sa.sin6_port = htons(DHCP6_CLIENT_PORT);
@@ -3947,6 +3954,21 @@ dhcp6_dropnondelegates(struct interface 
 }
 
 void
+dhcp6_abort(struct interface *ifp)
+{
+	struct dhcp6_state *state;
+	struct ipv6_addr *ia;
+
+	eloop_timeout_delete(ifp->ctx->eloop, dhcp6_start1, ifp);
+	state = D6_STATE(ifp);
+	if (state == NULL)
+		return;
+	TAILQ_FOREACH(ia, &state->addrs, next) {
+		ipv6nd_advertise(ia);
+	}
+}
+
+void
 dhcp6_handleifa(int cmd, struct ipv6_addr *ia, pid_t pid)
 {
 	struct dhcp6_state *state;
Index: src/external/bsd/dhcpcd/dist/src/if-bsd.c
diff -u src/external/bsd/dhcpcd/dist/src/if-bsd.c:1.2 src/external/bsd/dhcpcd/dist/src/if-bsd.c:1.3
--- src/external/bsd/dhcpcd/dist/src/if-bsd.c:1.2	Sun Nov  4 16:30:28 2018
+++ src/external/bsd/dhcpcd/dist/src/if-bsd.c	Tue Jan 22 15:20:21 2019
@@ -1,6 +1,6 @@
 /*
  * BSD interface driver for dhcpcd
- * Copyright (c) 2006-2018 Roy Marples <r...@marples.name>
+ * Copyright (c) 2006-2019 Roy Marples <r...@marples.name>
  * All rights reserved
 
  * Redistribution and use in source and binary forms, with or without
@@ -125,6 +125,7 @@ int
 if_opensockets_os(struct dhcpcd_ctx *ctx)
 {
 	struct priv *priv;
+	int n;
 #if defined(RO_MSGFILTER) || defined(ROUTE_MSGFILTER)
 	unsigned char msgfilter[] = {
 	    RTM_IFINFO,
@@ -161,12 +162,14 @@ if_opensockets_os(struct dhcpcd_ctx *ctx
 	if (ctx->link_fd == -1)
 		return -1;
 
-#ifdef SO_RERROR
-	int n = 1;
-	if (setsockopt(ctx->link_fd, SOL_SOCKET, SO_RERROR,
+	/* Ignore our own route(4) messages.
+	 * Sadly there is no way of doing this for route(4) messages
+	 * generated from addresses we add/delete. */
+	n = 0;
+	if (setsockopt(ctx->link_fd, SOL_SOCKET, SO_USELOOPBACK,
 	    &n, sizeof(n)) == -1)
-		logerr(__func__);
-#endif
+		logerr("%s: SO_USELOOPBACK", __func__);
+
 #if defined(RO_MSGFILTER)
 	if (setsockopt(ctx->link_fd, PF_ROUTE, RO_MSGFILTER,
 	    &msgfilter, sizeof(msgfilter)) == -1)
@@ -471,11 +474,6 @@ if_route(unsigned char cmd, const struct
 	assert(rt != NULL);
 	ctx = rt->rt_ifp->ctx;
 
-	if ((cmd == RTM_ADD || cmd == RTM_DELETE || cmd == RTM_CHANGE) &&
-	    ctx->options & DHCPCD_DAEMONISE &&
-	    !(ctx->options & DHCPCD_DAEMONISED))
-		ctx->options |= DHCPCD_RTM_PPID;
-
 #define ADDSA(sa) do {							      \
 		memcpy(bp, (sa), (sa)->sa_len);				      \
 		bp += RT_ROUNDUP((sa)->sa_len);				      \
@@ -506,8 +504,10 @@ if_route(unsigned char cmd, const struct
 		    !sa_is_loopback(&rt->rt_gateway))
 		{
 			rtm->rtm_index = (unsigned short)rt->rt_ifp->index;
-			if (!gateway_unspec)
-				rtm->rtm_addrs |= RTA_IFP;
+#ifdef __OpenBSD__
+			if (!gateway_unspec || rt->rt_dest.sa_family!=AF_INET6)
+#endif
+			rtm->rtm_addrs |= RTA_IFP;
 			if (!sa_is_unspecified(&rt->rt_ifa))
 				rtm->rtm_addrs |= RTA_IFA;
 		}
@@ -590,7 +590,6 @@ if_route(unsigned char cmd, const struct
 	rtm->rtm_msglen = (unsigned short)(bp - (char *)rtm);
 	if (write(ctx->link_fd, rtm, rtm->rtm_msglen) == -1)
 		return -1;
-	ctx->sseq = ctx->seq;
 	return 0;
 }
 
@@ -790,6 +789,10 @@ if_address6(unsigned char cmd, const str
 	if (ia->autoconf)
 		ifa.ifra_flags |= IN6_IFF_AUTOCONF;
 #endif
+#if defined(__FreeBSD__) || defined(__DragonFly__)
+	if (ia->addr_flags & IN6_IFF_TENTATIVE)
+		ifa.ifra_flags |= IN6_IFF_TENTATIVE;
+#endif
 #ifdef IPV6_MANGETEMPADDR
 	if (ia->flags & IPV6_AF_TEMPORARY)
 		ifa.ifra_flags |= IN6_IFF_TEMPORARY;
@@ -867,7 +870,6 @@ if_address6(unsigned char cmd, const str
 	    cmd == RTM_DELADDR ? SIOCDIFADDR_IN6 : SIOCAIFADDR_IN6, &ifa);
 }
 
-#if !(defined(HAVE_IFADDRS_ADDRFLAGS) && defined(HAVE_IFAM_ADDRFLAGS))
 int
 if_addrflags6(const struct interface *ifp, const struct in6_addr *addr,
     __unused const char *alias)
@@ -888,7 +890,6 @@ if_addrflags6(const struct interface *if
 		flags = -1;
 	return flags;
 }
-#endif
 
 int
 if_getlifetime6(struct ipv6_addr *ia)
@@ -949,63 +950,27 @@ if_ifinfo(struct dhcpcd_ctx *ctx, const 
 
 	if ((ifp = if_findindex(ctx->ifaces, ifm->ifm_index)) == NULL)
 		return;
-	switch (ifm->ifm_data.ifi_link_state) {
-	case LINK_STATE_DOWN:
+
+	/* If we get LINK_STATE_UNKNOWN here, it means the interface
+	 * doesn't support reporting carrier state.
+	 * As such, we need to rely on IFF_UP.
+	 * Even if LINK_STATE_UP is reported, we also need IFF_UP as well
+	 * so for dhcpcd they are equivalent and we only need to check
+	 * LINK_STATE_DOWN. */
+	if (ifm->ifm_data.ifi_link_state == LINK_STATE_DOWN)
 		link_state = LINK_DOWN;
-		break;
-	case LINK_STATE_UP:
-		/* dhcpcd considers the link down if IFF_UP is not set. */
+	else
 		link_state = ifm->ifm_flags & IFF_UP ? LINK_UP : LINK_DOWN;
-		break;
-	default:
-		/* handle_carrier will re-load the interface flags and check for
-		 * IFF_RUNNING as some drivers that don't handle link state also
-		 * don't set IFF_RUNNING when this routing message is generated.
-		 * As such, it is a race ...*/
-		link_state = LINK_UNKNOWN;
-		break;
-	}
+
 	dhcpcd_handlecarrier(ctx, link_state,
 	    (unsigned int)ifm->ifm_flags, ifp->name);
 }
 
-static int
-if_ownmsgpid(struct dhcpcd_ctx *ctx, pid_t pid, int seq)
-{
-
-	/* Ignore messages generated by us */
-	if (getpid() == pid) {
-		ctx->options &= ~DHCPCD_RTM_PPID;
-		return 1;
-	}
-
-	/* Ignore messages sent by the parent after forking */
-	if ((ctx->options &
-	    (DHCPCD_RTM_PPID | DHCPCD_DAEMONISED)) ==
-	    (DHCPCD_RTM_PPID | DHCPCD_DAEMONISED) &&
-	    ctx->ppid == pid)
-	{
-		/* If this is the last successful message sent,
-		 * clear the check flag as it's possible another
-		 * process could re-use the same pid and also
-		 * manipulate the routing table. */
-		if (ctx->pseq == seq)
-			ctx->options &= ~DHCPCD_RTM_PPID;
-		return 1;
-	}
-
-	/* Not a message we made. */
-	return 0;
-}
-
 static void
 if_rtm(struct dhcpcd_ctx *ctx, const struct rt_msghdr *rtm)
 {
 	struct rt rt;
 
-	if (if_ownmsgpid(ctx, rtm->rtm_pid, rtm->rtm_seq))
-		return;
-
 	/* Ignore errors. */
 	if (rtm->rtm_errno != 0)
 		return;
@@ -1052,26 +1017,6 @@ if_ifa(struct dhcpcd_ctx *ctx, const str
 		return;
 
 #ifdef HAVE_IFAM_PID
-	if (if_ownmsgpid(ctx, ifam->ifam_pid, 0)) {
-#ifdef HAVE_IFAM_ADDRFLAGS
-		/* If the kernel isn't doing DAD for the newly added
-		 * address we need to let it through. */
-		if (ifam->ifam_type != RTM_NEWADDR)
-			return;
-		switch (rti_info[RTAX_IFA]->sa_family) {
-		case AF_INET:
-			if (ifam->ifam_addrflags & IN_IFF_TENTATIVE)
-				return;
-			break;
-		case AF_INET6:
-			if (ifam->ifam_addrflags & IN6_IFF_TENTATIVE)
-				return;
-			break;
-		default:
-			return;
-		}
-#endif
-	}
 	pid = ifam->ifam_pid;
 #else
 	pid = 0;
@@ -1109,12 +1054,27 @@ if_ifa(struct dhcpcd_ctx *ctx, const str
 		sin = (const void *)rti_info[RTAX_NETMASK];
 		mask.s_addr = sin != NULL && sin->sin_family == AF_INET ?
 		    sin->sin_addr.s_addr : INADDR_ANY;
+		sin = (const void *)rti_info[RTAX_BRD];
+		bcast.s_addr = sin != NULL && sin->sin_family == AF_INET ?
+		    sin->sin_addr.s_addr : INADDR_ANY;
 
 #if defined(__NetBSD_Version__) && __NetBSD_Version__ < 800000000
-		/* NetBSD-7 and older send an invalid broadcast address.
+		/*
+		 * NetBSD-7 and older send an invalid broadcast address.
 		 * So we need to query the actual address to get
-		 * the right one. */
+		 * the right one.
+		 */
 		{
+#else
+		/*
+		 * If the address was deleted, lets check if it's
+		 * a late message and it still exists (maybe modified).
+		 * If so, ignore it as deleting an address causes
+		 * dhcpcd to drop any lease to which it belongs.
+		 */
+		if (ifam->ifam_type == RTM_DELADDR) {
+#endif
+#ifdef SIOCGIFALIAS
 			struct in_aliasreq ifra;
 
 			memset(&ifra, 0, sizeof(ifra));
@@ -1126,38 +1086,37 @@ if_ifa(struct dhcpcd_ctx *ctx, const str
 			if (ioctl(ctx->pf_inet_fd, SIOCGIFALIAS, &ifra) == -1) {
 				if (errno != EADDRNOTAVAIL)
 					logerr("%s: SIOCGIFALIAS", __func__);
-				break;
+				if (ifam->ifam_type != RTM_DELADDR)
+					break;
 			}
-			bcast = ifra.ifra_broadaddr.sin_addr;
-		}
-#else
-		sin = (const void *)rti_info[RTAX_BRD];
-		bcast.s_addr = sin != NULL && sin->sin_family == AF_INET ?
-		    sin->sin_addr.s_addr : INADDR_ANY;
+#if defined(__NetBSD_Version__) && __NetBSD_Version__ < 800000000
+			else
+				bcast = ifra.ifra_broadaddr.sin_addr;
 #endif
-
-#if defined(__FreeBSD__) || defined(__DragonFly__)
-		/* FreeBSD sends RTM_DELADDR for each assigned address
-		 * to an interface just brought down.
-		 * This is wrong, because the address still exists.
-		 * So we need to ignore it.
-		 * Oddly enough this only happens for INET addresses. */
-		if (ifam->ifam_type == RTM_DELADDR) {
-			struct ifreq ifr;
-			struct sockaddr_in *ifr_sin;
-
-			memset(&ifr, 0, sizeof(ifr));
-			strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
-			ifr_sin = (void *)&ifr.ifr_addr;
-			ifr_sin->sin_family = AF_INET;
-			ifr_sin->sin_addr = addr;
-			if (ioctl(ctx->pf_inet_fd, SIOCGIFADDR, &ifr) == 0) {
-				logwarnx("%s: ignored false RTM_DELADDR for %s",
-				    ifp->name, inet_ntoa(addr));
-				break;
+#else
+#warning No SIOCGIFALIAS support
+			/*
+			 * No SIOCGIFALIAS? That sucks!
+			 * This makes this call very heavy weight, but we
+			 * really need to know if the message is late or not.
+			 */
+			const struct sockaddr *sa;
+			struct ifaddrs *ifaddrs = NULL, *ifa;
+
+			sa = rti_info[RTAX_IFA];
+			getifaddrs(&ifaddrs);
+			for (ifa = ifaddrs; ifa; ifa = ifa->ifa_next) {
+				if (ifa->ifa_addr == NULL)
+					continue;
+				if (sa_cmp(ifa->ifa_addr, sa) == 0 &&
+				    strcmp(ifa->ifa_name, ifp->name) == 0)
+					break;
 			}
-		}
+			freeifaddrs(ifaddrs);
+			if (ifa != NULL)
+				return;
 #endif
+		}
 
 #ifndef HAVE_IFAM_ADDRFLAGS
 		if (ifam->ifam_type == RTM_DELADDR)
@@ -1179,15 +1138,26 @@ if_ifa(struct dhcpcd_ctx *ctx, const str
 	{
 		struct in6_addr addr6, mask6;
 		const struct sockaddr_in6 *sin6;
+		int flags;
 
 		sin6 = (const void *)rti_info[RTAX_IFA];
 		addr6 = sin6->sin6_addr;
 		sin6 = (const void *)rti_info[RTAX_NETMASK];
 		mask6 = sin6->sin6_addr;
 
+		/*
+		 * If the address was deleted, lets check if it's
+		 * a late message and it still exists (maybe modified).
+		 * If so, ignore it as deleting an address causes
+		 * dhcpcd to drop any lease to which it belongs.
+		 */
+		if (ifam->ifam_type == RTM_DELADDR) {
+			flags = if_addrflags6(ifp, &addr6, NULL);
+			if (flags != -1)
+				break;
+			addrflags = 0;
+		}
 #ifndef HAVE_IFAM_ADDRFLAGS
-		if (ifam->ifam_type == RTM_DELADDR)
-		    addrflags = 0;
 		else if ((addrflags = if_addrflags6(ifp, &addr6, NULL)) == -1) {
 			if (errno != EADDRNOTAVAIL)
 				logerr("%s: if_addrflags6", __func__);
@@ -1286,7 +1256,8 @@ if_machinearch(char *str, size_t len)
 
 #ifdef INET6
 #if (defined(IPV6CTL_ACCEPT_RTADV) && !defined(ND6_IFF_ACCEPT_RTADV)) || \
-    defined(IPV6CTL_USETEMPADDR) || defined(IPV6CTL_TEMPVLTIME)
+    defined(IPV6CTL_USETEMPADDR) || defined(IPV6CTL_TEMPVLTIME) || \
+    defined(IPV6CTL_FORWARDING)
 #define get_inet6_sysctl(code) inet6_sysctl(code, 0, 0)
 #define set_inet6_sysctl(code, val) inet6_sysctl(code, val, 1)
 static int
@@ -1370,6 +1341,19 @@ ip6_temp_valid_lifetime(__unused const c
 }
 #endif
 
+int
+ip6_forwarding(__unused const char *ifname)
+{
+	int val;
+
+#ifdef IPV6CTL_FORWARDING
+	val = get_inet6_sysctl(IPV6CTL_FORWARDING);
+#else
+	val = get_inet6_sysctlbyname("net.inet6.ip6.forwarding");
+#endif
+	return val < 0 ? 0 : val;
+}
+
 #ifdef SIOCIFAFATTACH
 static int
 af_attach(int s, const struct interface *ifp, int af)
@@ -1399,8 +1383,20 @@ set_ifxflags(int s, const struct interfa
 	/*
 	 * If not doing autoconf, don't disable the kernel from doing it.
 	 * If we need to, we should have another option actively disable it.
+	 *
+	 * OpenBSD moved from kernel based SLAAC to userland via slaacd(8).
+	 * It has a similar featureset to dhcpcd such as stable private
+	 * addresses, but lacks the ability to handle DNS inside the RA
+	 * which is a serious shortfall in this day and age.
+	 * Appease their user base by working alongside slaacd(8) if
+	 * dhcpcd is instructed not to do auto configuration of addresses.
 	 */
-	if (ifp->options->options & DHCPCD_IPV6RS)
+#if defined(ND6_IFF_ACCEPT_RTADV)
+#define	BSD_AUTOCONF	DHCPCD_IPV6RS
+#else
+#define	BSD_AUTOCONF	DHCPCD_IPV6RA_AUTOCONF
+#endif
+	if (ifp->options->options & BSD_AUTOCONF)
 		flags &= ~IFXF_AUTOCONF6;
 	if (ifr.ifr_flags == flags)
 		return 0;
@@ -1510,13 +1506,14 @@ if_setup_inet6(const struct interface *i
 	 * and prefixes so the kernel does not expire prefixes
 	 * and default routes we are trying to own. */
 	if (ifp->options->options & DHCPCD_IPV6RS) {
-		char ifname[IFNAMSIZ + 8];
+		struct in6_ifreq ifr;
 
-		strlcpy(ifname, ifp->name, sizeof(ifname));
-		if (ioctl(s, SIOCSRTRFLUSH_IN6, (void *)&ifname) == -1 &&
+		memset(&ifr, 0, sizeof(ifr));
+		strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
+		if (ioctl(s, SIOCSRTRFLUSH_IN6, &ifr) == -1 &&
 		    errno != ENOTSUP)
 			logwarn("SIOCSRTRFLUSH_IN6");
-		if (ioctl(s, SIOCSPFXFLUSH_IN6, (void *)&ifname) == -1 &&
+		if (ioctl(s, SIOCSPFXFLUSH_IN6, &ifr) == -1 &&
 		    errno != ENOTSUP)
 			logwarn("SIOCSPFXFLUSH_IN6");
 	}
Index: src/external/bsd/dhcpcd/dist/src/ipv6nd.c
diff -u src/external/bsd/dhcpcd/dist/src/ipv6nd.c:1.2 src/external/bsd/dhcpcd/dist/src/ipv6nd.c:1.3
--- src/external/bsd/dhcpcd/dist/src/ipv6nd.c:1.2	Sun Nov  4 16:30:28 2018
+++ src/external/bsd/dhcpcd/dist/src/ipv6nd.c	Tue Jan 22 15:20:21 2019
@@ -1,6 +1,6 @@
 /*
  * dhcpcd - IPv6 ND handling
- * Copyright (c) 2006-2018 Roy Marples <r...@marples.name>
+ * Copyright (c) 2006-2019 Roy Marples <r...@marples.name>
  * All rights reserved
 
  * Redistribution and use in source and binary forms, with or without
@@ -34,6 +34,7 @@
 #include <netinet/ip6.h>
 #include <netinet/icmp6.h>
 
+#include <assert.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <stddef.h>
@@ -217,13 +218,6 @@ ipv6nd_open(struct dhcpcd_ctx *ctx)
 	    &on, sizeof(on)) == -1)
 		goto eexit;
 
-#ifdef SO_RERROR
-	on = 1;
-	if (setsockopt(ctx->nd_fd, SOL_SOCKET, SO_RERROR,
-	    &on, sizeof(on)) == -1)
-		goto eexit;
-#endif
-
 	ICMP6_FILTER_SETBLOCKALL(&filt);
 	ICMP6_FILTER_SETPASS(ND_NEIGHBOR_ADVERT, &filt);
 	ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt);
@@ -338,6 +332,135 @@ ipv6nd_sendrsprobe(void *arg)
 	}
 }
 
+static void
+ipv6nd_sendadvertisement(void *arg)
+{
+	struct ipv6_addr *ia = arg;
+	struct interface *ifp = ia->iface;
+	struct dhcpcd_ctx *ctx = ifp->ctx;
+	struct sockaddr_in6 dst;
+	struct cmsghdr *cm;
+	struct in6_pktinfo pi;
+	const struct rs_state *state = RS_CSTATE(ifp);
+
+	if (state == NULL || ifp->carrier == LINK_DOWN)
+		goto freeit;
+
+	memset(&dst, 0, sizeof(dst));
+	dst.sin6_family = AF_INET6;
+#ifdef SIN6_LEN
+	dst.sin6_len = sizeof(dst);
+#endif
+	dst.sin6_scope_id = ifp->index;
+	if (inet_pton(AF_INET6, ALLNODES, &dst.sin6_addr) != 1) {
+		logerr(__func__);
+		return;
+	}
+
+	ctx->sndhdr.msg_name = (void *)&dst;
+	ctx->sndhdr.msg_iov[0].iov_base = ia->na;
+	ctx->sndhdr.msg_iov[0].iov_len = ia->na_len;
+
+	/* Set the outbound interface. */
+	cm = CMSG_FIRSTHDR(&ctx->sndhdr);
+	assert(cm != NULL);
+	cm->cmsg_level = IPPROTO_IPV6;
+	cm->cmsg_type = IPV6_PKTINFO;
+	cm->cmsg_len = CMSG_LEN(sizeof(pi));
+	memset(&pi, 0, sizeof(pi));
+	pi.ipi6_ifindex = ifp->index;
+	memcpy(CMSG_DATA(cm), &pi, sizeof(pi));
+
+	logdebugx("%s: sending NA for %s", ifp->name, ia->saddr);
+	if (sendmsg(ctx->nd_fd, &ctx->sndhdr, 0) == -1)
+		logerr(__func__);
+
+	if (++ia->na_count < MAX_NEIGHBOR_ADVERTISEMENT) {
+		eloop_timeout_add_sec(ctx->eloop,
+		    state->retrans / 1000, ipv6nd_sendadvertisement, ia);
+		return;
+	}
+
+freeit:
+	free(ia->na);
+	ia->na = NULL;
+	ia->na_count = 0;
+}
+
+void
+ipv6nd_advertise(struct ipv6_addr *ia)
+{
+	struct dhcpcd_ctx *ctx;
+	struct interface *ifp;
+	struct ipv6_state *state;
+	struct ipv6_addr *iap, *iaf;
+	struct nd_neighbor_advert *na;
+
+	if (IN6_IS_ADDR_MULTICAST(&ia->addr))
+		return;
+
+	ctx = ia->iface->ctx;
+	if_sortinterfaces(ctx);
+	/* Find the most preferred address to advertise. */
+	iaf = NULL;
+	TAILQ_FOREACH(ifp, ctx->ifaces, next) {
+		state = IPV6_STATE(ifp);
+		if (state == NULL || ifp->carrier == LINK_DOWN)
+			continue;
+
+		TAILQ_FOREACH(iap, &state->addrs, next) {
+			if (!IN6_ARE_ADDR_EQUAL(&iap->addr, &ia->addr))
+				continue;
+
+			/* Cancel any current advertisement. */
+			eloop_timeout_delete(ctx->eloop,
+			    ipv6nd_sendadvertisement, iap);
+
+			/* Don't advertise what we can't use. */
+			if (iap->prefix_vltime == 0 ||
+			    iap->addr_flags & IN6_IFF_NOTUSEABLE)
+				continue;
+
+			if (iaf == NULL)
+				iaf = iap;
+		}
+	}
+	if (iaf == NULL)
+		return;
+
+	/* Make the packet. */
+	ifp = iaf->iface;
+	iaf->na_len = sizeof(*na);
+	if (ifp->hwlen != 0)
+		iaf->na_len += (size_t)ROUNDUP8(ifp->hwlen + 2);
+	na = calloc(1, iaf->na_len);
+	if (na == NULL) {
+		logerr(__func__);
+		return;
+	}
+
+	na->nd_na_type = ND_NEIGHBOR_ADVERT;
+	na->nd_na_flags_reserved = ND_NA_FLAG_OVERRIDE;
+	if (ip6_forwarding(ifp->name) == 1)
+		na->nd_na_flags_reserved |= ND_NA_FLAG_ROUTER;
+	na->nd_na_target = ia->addr;
+
+	if (ifp->hwlen != 0) {
+		struct nd_opt_hdr *opt;
+
+		opt = (struct nd_opt_hdr *)(na + 1);
+		opt->nd_opt_type = ND_OPT_TARGET_LINKADDR;
+		opt->nd_opt_len = (uint8_t)((ROUNDUP8(ifp->hwlen + 2)) >> 3);
+		memcpy(opt + 1, ifp->hwaddr, ifp->hwlen);
+	}
+
+	iaf->na_count = 0;
+	free(iaf->na);
+	iaf->na = na;
+	eloop_timeout_delete(ctx->eloop, ipv6nd_sendadvertisement, iaf);
+	ipv6nd_sendadvertisement(iaf);
+}
+
 void
 ipv6nd_expire(struct interface *ifp, uint32_t seconds)
 {
@@ -725,6 +848,7 @@ try_script:
 					return;
 			}
 		}
+		ipv6nd_advertise(ia);
 	}
 }
 
@@ -876,8 +1000,11 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx, 
 		if (rap->reachable > MAX_REACHABLE_TIME)
 			rap->reachable = 0;
 	}
-	if (nd_ra->nd_ra_retransmit)
-		rap->retrans = ntohl(nd_ra->nd_ra_retransmit);
+	if (nd_ra->nd_ra_retransmit) {
+		struct rs_state *state = RS_STATE(ifp);
+
+		state->retrans = rap->retrans = ntohl(nd_ra->nd_ra_retransmit);
+	}
 	if (rap->lifetime)
 		rap->expired = 0;
 	rap->hasdns = 0;
@@ -969,12 +1096,6 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx, 
 			if (ap == NULL) {
 				unsigned int flags;
 
-				if (!(pi.nd_opt_pi_flags_reserved &
-				    ND_OPT_PI_FLAG_AUTO) &&
-				    !(pi.nd_opt_pi_flags_reserved &
-				    ND_OPT_PI_FLAG_ONLINK))
-					continue;
-
 				flags = IPV6_AF_RAPFX;
 				if (pi.nd_opt_pi_flags_reserved &
 				    ND_OPT_PI_FLAG_AUTO &&
@@ -987,7 +1108,8 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx, 
 				if (ap == NULL)
 					break;
 				ap->prefix = pi_prefix;
-				ap->dadcallback = ipv6nd_dadcallback;
+				if (flags & IPV6_AF_AUTOCONF)
+					ap->dadcallback = ipv6nd_dadcallback;
 				ap->created = ap->acquired = rap->acquired;
 				TAILQ_INSERT_TAIL(&rap->addrs, ap, next);
 
@@ -997,7 +1119,8 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx, 
 				 * temporary address also exists then
 				 * extend the existing one rather than
 				 * create a new one */
-				if (ipv6_iffindaddr(ifp, &ap->addr,
+				if (flags & IPV6_AF_AUTOCONF &&
+				    ipv6_iffindaddr(ifp, &ap->addr,
 				    IN6_IFF_NOTUSEABLE) &&
 				    ipv6_settemptime(ap, 0))
 					new_ap = 0;
@@ -1635,6 +1758,7 @@ ipv6nd_startrs1(void *arg)
 		return;
 	}
 
+	state->retrans = RETRANS_TIMER;
 	state->rsprobes = 0;
 	ipv6nd_sendrsprobe(ifp);
 }

Index: src/external/bsd/dhcpcd/dist/src/if-options.c
diff -u src/external/bsd/dhcpcd/dist/src/if-options.c:1.10 src/external/bsd/dhcpcd/dist/src/if-options.c:1.11
--- src/external/bsd/dhcpcd/dist/src/if-options.c:1.10	Sat Jun  2 09:44:27 2018
+++ src/external/bsd/dhcpcd/dist/src/if-options.c	Tue Jan 22 15:20:21 2019
@@ -1,6 +1,6 @@
 /*
  * dhcpcd - DHCP client daemon
- * Copyright (c) 2006-2018 Roy Marples <r...@marples.name>
+ * Copyright (c) 2006-2019 Roy Marples <r...@marples.name>
  * All rights reserved
 
  * Redistribution and use in source and binary forms, with or without
@@ -2010,7 +2010,7 @@ err_sla:
 		arg = fp;
 		fp = strend(arg);
 		if (fp == NULL) {
-			logerrx("authtoken requies an an expiry date");
+			logerrx("authtoken requies an expiry date");
 			free(token->realm);
 			free(token);
 			return -1;

Reply via email to