Module Name:    src
Committed By:   roy
Date:           Wed Oct 29 01:08:31 UTC 2014

Modified Files:
        src/external/bsd/dhcpcd/dist: arp.c arp.h auth.c auth.h bpf-filter.h
            common.c common.h config.h control.c control.h defs.h dev.h
            dhcp-common.c dhcp-common.h dhcp.c dhcp.h dhcp6.c dhcp6.h
            dhcpcd-definitions.conf dhcpcd-embedded.c dhcpcd-embedded.h
            dhcpcd-run-hooks.8.in dhcpcd-run-hooks.in dhcpcd.8.in dhcpcd.c
            dhcpcd.conf dhcpcd.conf.5.in dhcpcd.h duid.c duid.h eloop.c eloop.h
            if-bsd.c if-options.c if-options.h if.c if.h ipv4.c ipv4.h ipv4ll.c
            ipv4ll.h ipv6.c ipv6.h ipv6nd.c ipv6nd.h script.c script.h

Log Message:
Sync


To generate a diff of this commit:
cvs rdiff -u -r1.3 -r1.4 src/external/bsd/dhcpcd/dist/arp.c \
    src/external/bsd/dhcpcd/dist/arp.h src/external/bsd/dhcpcd/dist/auth.c \
    src/external/bsd/dhcpcd/dist/auth.h src/external/bsd/dhcpcd/dist/common.c \
    src/external/bsd/dhcpcd/dist/common.h \
    src/external/bsd/dhcpcd/dist/config.h \
    src/external/bsd/dhcpcd/dist/control.c \
    src/external/bsd/dhcpcd/dist/control.h \
    src/external/bsd/dhcpcd/dist/defs.h src/external/bsd/dhcpcd/dist/dev.h \
    src/external/bsd/dhcpcd/dist/dhcp-common.c \
    src/external/bsd/dhcpcd/dist/dhcp-common.h \
    src/external/bsd/dhcpcd/dist/dhcp.h src/external/bsd/dhcpcd/dist/dhcp6.c \
    src/external/bsd/dhcpcd/dist/dhcp6.h \
    src/external/bsd/dhcpcd/dist/dhcpcd-definitions.conf \
    src/external/bsd/dhcpcd/dist/dhcpcd-embedded.c \
    src/external/bsd/dhcpcd/dist/dhcpcd-embedded.h \
    src/external/bsd/dhcpcd/dist/dhcpcd-run-hooks.in \
    src/external/bsd/dhcpcd/dist/dhcpcd.h src/external/bsd/dhcpcd/dist/duid.c \
    src/external/bsd/dhcpcd/dist/duid.h src/external/bsd/dhcpcd/dist/eloop.c \
    src/external/bsd/dhcpcd/dist/eloop.h \
    src/external/bsd/dhcpcd/dist/if-options.h \
    src/external/bsd/dhcpcd/dist/if.c src/external/bsd/dhcpcd/dist/if.h \
    src/external/bsd/dhcpcd/dist/ipv4.c src/external/bsd/dhcpcd/dist/ipv4.h \
    src/external/bsd/dhcpcd/dist/ipv4ll.c \
    src/external/bsd/dhcpcd/dist/ipv4ll.h src/external/bsd/dhcpcd/dist/ipv6.c \
    src/external/bsd/dhcpcd/dist/ipv6.h src/external/bsd/dhcpcd/dist/ipv6nd.h \
    src/external/bsd/dhcpcd/dist/script.h
cvs rdiff -u -r1.6 -r1.7 src/external/bsd/dhcpcd/dist/bpf-filter.h
cvs rdiff -u -r1.19 -r1.20 src/external/bsd/dhcpcd/dist/dhcp.c
cvs rdiff -u -r1.9 -r1.10 src/external/bsd/dhcpcd/dist/dhcpcd-run-hooks.8.in
cvs rdiff -u -r1.33 -r1.34 src/external/bsd/dhcpcd/dist/dhcpcd.8.in
cvs rdiff -u -r1.13 -r1.14 src/external/bsd/dhcpcd/dist/dhcpcd.c \
    src/external/bsd/dhcpcd/dist/dhcpcd.conf.5.in
cvs rdiff -u -r1.12 -r1.13 src/external/bsd/dhcpcd/dist/dhcpcd.conf \
    src/external/bsd/dhcpcd/dist/if-bsd.c
cvs rdiff -u -r1.14 -r1.15 src/external/bsd/dhcpcd/dist/if-options.c \
    src/external/bsd/dhcpcd/dist/ipv6nd.c
cvs rdiff -u -r1.11 -r1.12 src/external/bsd/dhcpcd/dist/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/arp.c
diff -u src/external/bsd/dhcpcd/dist/arp.c:1.3 src/external/bsd/dhcpcd/dist/arp.c:1.4
--- src/external/bsd/dhcpcd/dist/arp.c:1.3	Fri Oct 17 23:42:24 2014
+++ src/external/bsd/dhcpcd/dist/arp.c	Wed Oct 29 01:08:31 2014
@@ -1,5 +1,5 @@
 #include <sys/cdefs.h>
- __RCSID("$NetBSD: arp.c,v 1.3 2014/10/17 23:42:24 roy Exp $");
+ __RCSID("$NetBSD: arp.c,v 1.4 2014/10/29 01:08:31 roy Exp $");
 
 /*
  * dhcpcd - DHCP client daemon
@@ -42,7 +42,7 @@
 #include <syslog.h>
 #include <unistd.h>
 
-#define ELOOP_QUEUE 2
+#define ELOOP_QUEUE 5
 #include "config.h"
 #include "arp.h"
 #include "ipv4.h"
@@ -97,31 +97,15 @@ eexit:
 	return -1;
 }
 
-static void
-arp_failure(struct interface *ifp)
+void
+arp_report_conflicted(const struct arp_state *astate, const struct arp_msg *amsg)
 {
-	const struct dhcp_state *state = D_CSTATE(ifp);
-
-	/* If we failed without a magic cookie then we need to try
-	 * and defend our IPv4LL address. */
-	if ((state->offer != NULL &&
-	    state->offer->cookie != htonl(MAGIC_COOKIE)) ||
-	    (state->new != NULL &&
-	    state->new->cookie != htonl(MAGIC_COOKIE)))
-	{
-		ipv4ll_handle_failure(ifp);
-		return;
-	}
+	char buf[HWADDR_LEN * 3];
 
-	unlink(state->leasefile);
-	if (!state->lease.frominfo)
-		dhcp_decline(ifp);
-	eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
-	if (state->lease.frominfo)
-		dhcpcd_startinterface(ifp);
-	else
-		eloop_timeout_add_sec(ifp->ctx->eloop,
-		    DHCP_ARP_FAIL, dhcpcd_startinterface, ifp);
+	syslog(LOG_ERR, "%s: hardware address %s claims %s",
+	    astate->iface->name,
+	    hwaddr_ntoa(amsg->sha, astate->iface->hwlen, buf, sizeof(buf)),
+	    inet_ntoa(astate->failed));
 }
 
 static void
@@ -131,19 +115,14 @@ arp_packet(void *arg)
 	const struct interface *ifn;
 	uint8_t arp_buffer[ARP_LEN];
 	struct arphdr ar;
-	uint32_t reply_s;
-	uint32_t reply_t;
-	uint8_t *hw_s, *hw_t;
+	struct arp_msg arm;
 	ssize_t bytes;
 	struct dhcp_state *state;
-	struct if_options *opts = ifp->options;
-	const char *hwaddr;
-	struct in_addr ina;
-	char hwbuf[HWADDR_LEN * 3];
+	struct arp_state *astate, *astaten;
+	unsigned char *hw_s, *hw_t;
 	int flags;
 
 	state = D_STATE(ifp);
-	state->fail.s_addr = 0;
 	flags = 0;
 	while (!(flags & RAW_EOF)) {
 		bytes = if_readrawpacket(ifp, ETHERTYPE_ARP,
@@ -158,10 +137,13 @@ arp_packet(void *arg)
 		if ((size_t)bytes < sizeof(ar))
 			continue;
 		memcpy(&ar, arp_buffer, sizeof(ar));
+		/* Families must match */
+		if (ar.ar_hrd != htons(ifp->family))
+			continue;
 		/* Protocol must be IP. */
 		if (ar.ar_pro != htons(ETHERTYPE_IP))
 			continue;
-		if (ar.ar_pln != sizeof(reply_s))
+		if (ar.ar_pln != sizeof(arm.sip.s_addr))
 			continue;
 		/* Only these types are recognised */
 		if (ar.ar_op != htons(ARPOP_REPLY) &&
@@ -182,77 +164,26 @@ arp_packet(void *arg)
 		}
 		if (ifn)
 			continue;
-		/* Copy out the IP addresses */
-		memcpy(&reply_s, hw_s + ar.ar_hln, ar.ar_pln);
-		memcpy(&reply_t, hw_t + ar.ar_hln, ar.ar_pln);
-
-		/* Check for arping */
-		if (state->arping_index &&
-		    state->arping_index <= opts->arping_len &&
-		    (reply_s == opts->arping[state->arping_index - 1] ||
-		    (reply_s == 0 &&
-		    reply_t == opts->arping[state->arping_index - 1])))
-		{
-			ina.s_addr = reply_s;
-			hwaddr = hwaddr_ntoa((unsigned char *)hw_s,
-			    (size_t)ar.ar_hln, hwbuf, sizeof(hwbuf));
-			syslog(LOG_INFO,
-			    "%s: found %s on hardware address %s",
-			    ifp->name, inet_ntoa(ina), hwaddr);
-			if (dhcpcd_selectprofile(ifp, hwaddr) == -1 &&
-			    dhcpcd_selectprofile(ifp, inet_ntoa(ina)) == -1)
-			{
-				state->probes = 0;
-				/* We didn't find a profile for this
-				 * address or hwaddr, so move to the next
-				 * arping profile */
-				if (state->arping_index <
-				    ifp->options->arping_len)
-				{
-					arp_probe(ifp);
-					return;
-				}
-			}
-			dhcp_close(ifp);
-			eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
-			dhcpcd_startinterface(ifp);
-			return;
-		}
-
-		/* RFC 2131 3.1.5, Client-server interaction
-		 * RFC 3927 2.2.1, Probe Conflict Detection */
-		if (state->offer &&
-		    (reply_s == state->offer->yiaddr ||
-		    (reply_s == 0 && reply_t == state->offer->yiaddr)))
-			state->fail.s_addr = state->offer->yiaddr;
-
-		/* RFC 3927 2.5, Conflict Defense */
-		if (IN_LINKLOCAL(htonl(state->addr.s_addr)) &&
-		    reply_s == state->addr.s_addr)
-			state->fail.s_addr = state->addr.s_addr;
-
-		if (state->fail.s_addr) {
-			syslog(LOG_ERR, "%s: hardware address %s claims %s",
-			    ifp->name,
-			    hwaddr_ntoa((unsigned char *)hw_s,
-				(size_t)ar.ar_hln, hwbuf, sizeof(hwbuf)),
-			    inet_ntoa(state->fail));
-			errno = EEXIST;
-			arp_failure(ifp);
-			return;
+		/* Copy out the HW and IP addresses */
+		memcpy(&arm.sha, hw_s, ar.ar_hln);
+		memcpy(&arm.sip.s_addr, hw_s + ar.ar_hln, ar.ar_pln);
+		memcpy(&arm.tha, hw_t, ar.ar_hln);
+		memcpy(&arm.tip.s_addr, hw_t + ar.ar_hln, ar.ar_pln);
+
+		/* Run the conflicts */
+		TAILQ_FOREACH_SAFE(astate, &state->arp_states, next, astaten) {
+			if (astate->conflicted_cb)
+				astate->conflicted_cb(astate, &arm);
 		}
 	}
 }
 
-void
-arp_announce(void *arg)
+static void
+arp_open(struct interface *ifp)
 {
-	struct interface *ifp = arg;
-	struct dhcp_state *state = D_STATE(ifp);
-	struct timeval tv;
+	struct dhcp_state *state;
 
-	if (state->new == NULL)
-		return;
+	state = D_STATE(ifp);
 	if (state->arp_fd == -1) {
 		state->arp_fd = if_openrawsocket(ifp, ETHERTYPE_ARP);
 		if (state->arp_fd == -1) {
@@ -262,126 +193,157 @@ arp_announce(void *arg)
 		eloop_event_add(ifp->ctx->eloop, state->arp_fd,
 		    arp_packet, ifp, NULL, NULL);
 	}
-	if (++state->claims < ANNOUNCE_NUM)
+}
+
+static void
+arp_announced(void *arg)
+{
+	struct arp_state *astate = arg;
+
+	if (astate->announced_cb) {
+		astate->announced_cb(astate);
+		return;
+	}
+
+	/* Nothing more to do, so free us */
+	arp_free(astate);
+}
+
+static void
+arp_announce1(void *arg)
+{
+	struct arp_state *astate = arg;
+	struct interface *ifp = astate->iface;
+
+	if (++astate->claims < ANNOUNCE_NUM)
 		syslog(LOG_DEBUG,
 		    "%s: sending ARP announce (%d of %d), "
 		    "next in %d.0 seconds",
-		    ifp->name, state->claims, ANNOUNCE_NUM, ANNOUNCE_WAIT);
+		    ifp->name, astate->claims, ANNOUNCE_NUM, ANNOUNCE_WAIT);
 	else
 		syslog(LOG_DEBUG,
 		    "%s: sending ARP announce (%d of %d)",
-		    ifp->name, state->claims, ANNOUNCE_NUM);
+		    ifp->name, astate->claims, ANNOUNCE_NUM);
 	if (arp_send(ifp, ARPOP_REQUEST,
-		state->new->yiaddr, state->new->yiaddr) == -1)
+		astate->addr.s_addr, astate->addr.s_addr) == -1)
 		syslog(LOG_ERR, "send_arp: %m");
-	if (state->claims < ANNOUNCE_NUM) {
-		eloop_timeout_add_sec(ifp->ctx->eloop,
-		    ANNOUNCE_WAIT, arp_announce, ifp);
-		return;
-	}
-	if (state->new->cookie != htonl(MAGIC_COOKIE)) {
-		/* Check if doing DHCP */
-		if (!(ifp->options->options & DHCPCD_DHCP))
-			return;
-		/* We should pretend to be at the end
-		 * of the DHCP negotation cycle unless we rebooted */
-		if (state->interval != 0)
-			state->interval = 64;
-		state->probes = 0;
-		state->claims = 0;
-		tv.tv_sec = state->interval - DHCP_RAND_MIN;
-		tv.tv_usec = (suseconds_t)arc4random_uniform(
-		    (DHCP_RAND_MAX - DHCP_RAND_MIN) * 1000000);
-		timernorm(&tv);
-		eloop_timeout_add_tv(ifp->ctx->eloop, &tv, dhcp_discover, ifp);
-	} else {
-		eloop_event_delete(ifp->ctx->eloop, state->arp_fd, 0);
-		close(state->arp_fd);
-		state->arp_fd = -1;
-	}
+	eloop_timeout_add_sec(ifp->ctx->eloop, ANNOUNCE_WAIT,
+	    astate->claims < ANNOUNCE_NUM ? arp_announce1 : arp_announced,
+	    astate);
 }
 
 void
-arp_probe(void *arg)
+arp_announce(struct arp_state *astate)
 {
-	struct interface *ifp = arg;
-	struct dhcp_state *state = D_STATE(ifp);
-	struct in_addr addr;
-	struct timeval tv;
-	int arping = 0;
 
-	if (state->arp_fd == -1) {
-		state->arp_fd = if_openrawsocket(ifp, ETHERTYPE_ARP);
-		if (state->arp_fd == -1) {
-			syslog(LOG_ERR, "%s: %s: %m", __func__, ifp->name);
-			return;
-		}
-		eloop_event_add(ifp->ctx->eloop,
-		    state->arp_fd, arp_packet, ifp, NULL, NULL);
-	}
+	arp_open(astate->iface);
+	astate->claims = 0;
+	arp_announce1(astate);
+}
 
-	if (state->arping_index < ifp->options->arping_len) {
-		addr.s_addr = ifp->options->arping[state->arping_index];
-		arping = 1;
-	} else if (state->offer) {
-		if (state->offer->yiaddr)
-			addr.s_addr = state->offer->yiaddr;
-		else
-			addr.s_addr = state->offer->ciaddr;
-	} else
-		addr.s_addr = state->addr.s_addr;
-
-	if (state->probes == 0) {
-		if (arping)
-			syslog(LOG_DEBUG, "%s: searching for %s",
-			    ifp->name, inet_ntoa(addr));
-		else
-			syslog(LOG_DEBUG, "%s: checking for %s",
-			    ifp->name, inet_ntoa(addr));
-	}
-	if (++state->probes < PROBE_NUM) {
+static void
+arp_probed(void *arg)
+{
+	struct arp_state *astate = arg;
+
+	astate->probed_cb(astate);
+}
+
+static void
+arp_probe1(void *arg)
+{
+	struct arp_state *astate = arg;
+	struct interface *ifp = astate->iface;
+	struct timeval tv;
+
+	if (++astate->probes < PROBE_NUM) {
 		tv.tv_sec = PROBE_MIN;
 		tv.tv_usec = (suseconds_t)arc4random_uniform(
 		    (PROBE_MAX - PROBE_MIN) * 1000000);
 		timernorm(&tv);
-		eloop_timeout_add_tv(ifp->ctx->eloop, &tv, arp_probe, ifp);
+		eloop_timeout_add_tv(ifp->ctx->eloop, &tv, arp_probe1, astate);
 	} else {
 		tv.tv_sec = ANNOUNCE_WAIT;
 		tv.tv_usec = 0;
-		if (arping) {
-			state->probes = 0;
-			if (++state->arping_index < ifp->options->arping_len)
-				eloop_timeout_add_tv(ifp->ctx->eloop,
-				    &tv, arp_probe, ifp);
-			else
-				eloop_timeout_add_tv(ifp->ctx->eloop,
-				    &tv, dhcpcd_startinterface, ifp);
-		} else
-			eloop_timeout_add_tv(ifp->ctx->eloop,
-			    &tv, dhcp_bind, ifp);
+		eloop_timeout_add_tv(ifp->ctx->eloop, &tv, arp_probed, astate);
 	}
 	syslog(LOG_DEBUG,
 	    "%s: sending ARP probe (%d of %d), next in %0.1f seconds",
-	    ifp->name, state->probes ? state->probes : PROBE_NUM, PROBE_NUM,
+	    ifp->name, astate->probes ? astate->probes : PROBE_NUM, PROBE_NUM,
 	    timeval_to_double(&tv));
-	if (arp_send(ifp, ARPOP_REQUEST, 0, addr.s_addr) == -1)
+	if (arp_send(ifp, ARPOP_REQUEST, 0, astate->addr.s_addr) == -1)
 		syslog(LOG_ERR, "send_arp: %m");
 }
 
 void
-arp_start(struct interface *ifp)
+arp_probe(struct arp_state *astate)
 {
-	struct dhcp_state *state = D_STATE(ifp);
 
-	state->probes = 0;
-	state->arping_index = 0;
-	arp_probe(ifp);
+	arp_open(astate->iface);
+	astate->probes = 0;
+	syslog(LOG_DEBUG, "%s: probing for %s",
+	    astate->iface->name, inet_ntoa(astate->addr));
+	arp_probe1(astate);
+}
+
+
+struct arp_state *
+arp_new(struct interface *ifp) {
+	struct arp_state *astate;
+	struct dhcp_state *state;
+
+	astate = calloc(1, sizeof(*astate));
+	if (astate == NULL) {
+		syslog(LOG_ERR, "%s: %s: %m", ifp->name, __func__);
+		return NULL;
+	}
+
+	astate->iface = ifp;
+	state = D_STATE(ifp);
+	TAILQ_INSERT_TAIL(&state->arp_states, astate, next);
+	return astate;
+}
+
+void
+arp_cancel(struct arp_state *astate)
+{
+
+	eloop_timeout_delete(astate->iface->ctx->eloop, NULL, astate);
+}
+
+void
+arp_free(struct arp_state *astate)
+{
+	struct dhcp_state *state;
+
+	if (astate) {
+		eloop_timeout_delete(astate->iface->ctx->eloop, NULL, astate);
+		state = D_STATE(astate->iface);
+		TAILQ_REMOVE(&state->arp_states, astate, next);
+		if (state->arp_ipv4ll == astate)
+			state->arp_ipv4ll = NULL;
+		free(astate);
+	}
+}
+
+void
+arp_free_but(struct arp_state *astate)
+{
+	struct arp_state *p, *n;
+	struct dhcp_state *state;
+
+	state = D_STATE(astate->iface);
+	TAILQ_FOREACH_SAFE(p, &state->arp_states, next, n) {
+		if (p != astate)
+			arp_free(p);
+	}
 }
 
 void
 arp_close(struct interface *ifp)
 {
 	struct dhcp_state *state = D_STATE(ifp);
+	struct arp_state *astate;
 
 	if (state == NULL)
 		return;
@@ -391,5 +353,8 @@ arp_close(struct interface *ifp)
 		close(state->arp_fd);
 		state->arp_fd = -1;
 	}
-}
 
+	while ((astate = TAILQ_FIRST(&state->arp_states))) {
+		arp_free(astate);
+	}
+}
Index: src/external/bsd/dhcpcd/dist/arp.h
diff -u src/external/bsd/dhcpcd/dist/arp.h:1.3 src/external/bsd/dhcpcd/dist/arp.h:1.4
--- src/external/bsd/dhcpcd/dist/arp.h:1.3	Fri Oct 17 23:42:24 2014
+++ src/external/bsd/dhcpcd/dist/arp.h	Wed Oct 29 01:08:31 2014
@@ -1,4 +1,4 @@
-/* $NetBSD: arp.h,v 1.3 2014/10/17 23:42:24 roy Exp $ */
+/* $NetBSD: arp.h,v 1.4 2014/10/29 01:08:31 roy Exp $ */
 
 /*
  * dhcpcd - DHCP client daemon
@@ -44,8 +44,35 @@
 
 #include "dhcpcd.h"
 
-void arp_announce(void *);
-void arp_probe(void *);
-void arp_start(struct interface *);
+struct arp_msg {
+	uint16_t op;
+	unsigned char sha[HWADDR_LEN];
+	struct in_addr sip;
+	unsigned char tha[HWADDR_LEN];
+	struct in_addr tip;
+};
+
+struct arp_state {
+	TAILQ_ENTRY(arp_state) next;
+	struct interface *iface;
+
+	void (*probed_cb)(struct arp_state *);
+	void (*announced_cb)(struct arp_state *);
+	void (*conflicted_cb)(struct arp_state *, const struct arp_msg *);
+
+	struct in_addr addr;
+	int probes;
+	int claims;
+	struct in_addr failed;
+};
+TAILQ_HEAD(arp_statehead, arp_state);
+
+void arp_report_conflicted(const struct arp_state *, const struct arp_msg *);
+void arp_announce(struct arp_state *);
+void arp_probe(struct arp_state *);
+struct arp_state *arp_new(struct interface *);
+void arp_cancel(struct arp_state *);
+void arp_free(struct arp_state *);
+void arp_free_but(struct arp_state *);
 void arp_close(struct interface *);
 #endif
Index: src/external/bsd/dhcpcd/dist/auth.c
diff -u src/external/bsd/dhcpcd/dist/auth.c:1.3 src/external/bsd/dhcpcd/dist/auth.c:1.4
--- src/external/bsd/dhcpcd/dist/auth.c:1.3	Fri Oct 17 23:42:24 2014
+++ src/external/bsd/dhcpcd/dist/auth.c	Wed Oct 29 01:08:31 2014
@@ -1,5 +1,5 @@
 #include <sys/cdefs.h>
- __RCSID("$NetBSD: auth.c,v 1.3 2014/10/17 23:42:24 roy Exp $");
+ __RCSID("$NetBSD: auth.c,v 1.4 2014/10/29 01:08:31 roy Exp $");
 
 /*
  * dhcpcd - DHCP client daemon
Index: src/external/bsd/dhcpcd/dist/auth.h
diff -u src/external/bsd/dhcpcd/dist/auth.h:1.3 src/external/bsd/dhcpcd/dist/auth.h:1.4
--- src/external/bsd/dhcpcd/dist/auth.h:1.3	Fri Oct 17 23:42:24 2014
+++ src/external/bsd/dhcpcd/dist/auth.h	Wed Oct 29 01:08:31 2014
@@ -1,4 +1,4 @@
-/* $NetBSD: auth.h,v 1.3 2014/10/17 23:42:24 roy Exp $ */
+/* $NetBSD: auth.h,v 1.4 2014/10/29 01:08:31 roy Exp $ */
 
 /*
  * dhcpcd - DHCP client daemon
Index: src/external/bsd/dhcpcd/dist/common.c
diff -u src/external/bsd/dhcpcd/dist/common.c:1.3 src/external/bsd/dhcpcd/dist/common.c:1.4
--- src/external/bsd/dhcpcd/dist/common.c:1.3	Fri Oct 17 23:42:24 2014
+++ src/external/bsd/dhcpcd/dist/common.c	Wed Oct 29 01:08:31 2014
@@ -1,5 +1,5 @@
 #include <sys/cdefs.h>
- __RCSID("$NetBSD: common.c,v 1.3 2014/10/17 23:42:24 roy Exp $");
+ __RCSID("$NetBSD: common.c,v 1.4 2014/10/29 01:08:31 roy Exp $");
 
 /*
  * dhcpcd - DHCP client daemon
Index: src/external/bsd/dhcpcd/dist/common.h
diff -u src/external/bsd/dhcpcd/dist/common.h:1.3 src/external/bsd/dhcpcd/dist/common.h:1.4
--- src/external/bsd/dhcpcd/dist/common.h:1.3	Fri Oct 17 23:42:24 2014
+++ src/external/bsd/dhcpcd/dist/common.h	Wed Oct 29 01:08:31 2014
@@ -1,4 +1,4 @@
-/* $NetBSD: common.h,v 1.3 2014/10/17 23:42:24 roy Exp $ */
+/* $NetBSD: common.h,v 1.4 2014/10/29 01:08:31 roy Exp $ */
 
 /*
  * dhcpcd - DHCP client daemon
Index: src/external/bsd/dhcpcd/dist/config.h
diff -u src/external/bsd/dhcpcd/dist/config.h:1.3 src/external/bsd/dhcpcd/dist/config.h:1.4
--- src/external/bsd/dhcpcd/dist/config.h:1.3	Fri Oct 17 23:42:24 2014
+++ src/external/bsd/dhcpcd/dist/config.h	Wed Oct 29 01:08:31 2014
@@ -1,4 +1,4 @@
-/* $NetBSD: config.h,v 1.3 2014/10/17 23:42:24 roy Exp $ */
+/* $NetBSD: config.h,v 1.4 2014/10/29 01:08:31 roy Exp $ */
 
 /* netbsd */
 #define SYSCONFDIR	"/etc"
Index: src/external/bsd/dhcpcd/dist/control.c
diff -u src/external/bsd/dhcpcd/dist/control.c:1.3 src/external/bsd/dhcpcd/dist/control.c:1.4
--- src/external/bsd/dhcpcd/dist/control.c:1.3	Fri Oct 17 23:42:24 2014
+++ src/external/bsd/dhcpcd/dist/control.c	Wed Oct 29 01:08:31 2014
@@ -1,5 +1,5 @@
 #include <sys/cdefs.h>
- __RCSID("$NetBSD: control.c,v 1.3 2014/10/17 23:42:24 roy Exp $");
+ __RCSID("$NetBSD: control.c,v 1.4 2014/10/29 01:08:31 roy Exp $");
 
 /*
  * dhcpcd - DHCP client daemon
Index: src/external/bsd/dhcpcd/dist/control.h
diff -u src/external/bsd/dhcpcd/dist/control.h:1.3 src/external/bsd/dhcpcd/dist/control.h:1.4
--- src/external/bsd/dhcpcd/dist/control.h:1.3	Fri Oct 17 23:42:24 2014
+++ src/external/bsd/dhcpcd/dist/control.h	Wed Oct 29 01:08:31 2014
@@ -1,4 +1,4 @@
-/* $NetBSD: control.h,v 1.3 2014/10/17 23:42:24 roy Exp $ */
+/* $NetBSD: control.h,v 1.4 2014/10/29 01:08:31 roy Exp $ */
 
 /*
  * dhcpcd - DHCP client daemon
Index: src/external/bsd/dhcpcd/dist/defs.h
diff -u src/external/bsd/dhcpcd/dist/defs.h:1.3 src/external/bsd/dhcpcd/dist/defs.h:1.4
--- src/external/bsd/dhcpcd/dist/defs.h:1.3	Fri Oct 17 23:42:24 2014
+++ src/external/bsd/dhcpcd/dist/defs.h	Wed Oct 29 01:08:31 2014
@@ -1,4 +1,4 @@
-/* $NetBSD: defs.h,v 1.3 2014/10/17 23:42:24 roy Exp $ */
+/* $NetBSD: defs.h,v 1.4 2014/10/29 01:08:31 roy Exp $ */
 
 /*
  * dhcpcd - DHCP client daemon
@@ -30,7 +30,7 @@
 #define CONFIG_H
 
 #define PACKAGE			"dhcpcd"
-#define VERSION			"6.5.1"
+#define VERSION			"6.6.0"
 
 #ifndef CONFIG
 # define CONFIG			SYSCONFDIR "/" PACKAGE ".conf"
Index: src/external/bsd/dhcpcd/dist/dev.h
diff -u src/external/bsd/dhcpcd/dist/dev.h:1.3 src/external/bsd/dhcpcd/dist/dev.h:1.4
--- src/external/bsd/dhcpcd/dist/dev.h:1.3	Fri Oct 17 23:42:24 2014
+++ src/external/bsd/dhcpcd/dist/dev.h	Wed Oct 29 01:08:31 2014
@@ -1,4 +1,4 @@
-/* $NetBSD: dev.h,v 1.3 2014/10/17 23:42:24 roy Exp $ */
+/* $NetBSD: dev.h,v 1.4 2014/10/29 01:08:31 roy Exp $ */
 
 /*
  * dhcpcd - DHCP client daemon
Index: src/external/bsd/dhcpcd/dist/dhcp-common.c
diff -u src/external/bsd/dhcpcd/dist/dhcp-common.c:1.3 src/external/bsd/dhcpcd/dist/dhcp-common.c:1.4
--- src/external/bsd/dhcpcd/dist/dhcp-common.c:1.3	Fri Oct 17 23:42:24 2014
+++ src/external/bsd/dhcpcd/dist/dhcp-common.c	Wed Oct 29 01:08:31 2014
@@ -1,5 +1,5 @@
 #include <sys/cdefs.h>
- __RCSID("$NetBSD: dhcp-common.c,v 1.3 2014/10/17 23:42:24 roy Exp $");
+ __RCSID("$NetBSD: dhcp-common.c,v 1.4 2014/10/29 01:08:31 roy Exp $");
 
 /*
  * dhcpcd - DHCP client daemon
Index: src/external/bsd/dhcpcd/dist/dhcp-common.h
diff -u src/external/bsd/dhcpcd/dist/dhcp-common.h:1.3 src/external/bsd/dhcpcd/dist/dhcp-common.h:1.4
--- src/external/bsd/dhcpcd/dist/dhcp-common.h:1.3	Fri Oct 17 23:42:24 2014
+++ src/external/bsd/dhcpcd/dist/dhcp-common.h	Wed Oct 29 01:08:31 2014
@@ -1,4 +1,4 @@
-/* $NetBSD: dhcp-common.h,v 1.3 2014/10/17 23:42:24 roy Exp $ */
+/* $NetBSD: dhcp-common.h,v 1.4 2014/10/29 01:08:31 roy Exp $ */
 
 /*
  * dhcpcd - DHCP client daemon
Index: src/external/bsd/dhcpcd/dist/dhcp.h
diff -u src/external/bsd/dhcpcd/dist/dhcp.h:1.3 src/external/bsd/dhcpcd/dist/dhcp.h:1.4
--- src/external/bsd/dhcpcd/dist/dhcp.h:1.3	Fri Oct 17 23:42:24 2014
+++ src/external/bsd/dhcpcd/dist/dhcp.h	Wed Oct 29 01:08:31 2014
@@ -1,4 +1,4 @@
-/* $NetBSD: dhcp.h,v 1.3 2014/10/17 23:42:24 roy Exp $ */
+/* $NetBSD: dhcp.h,v 1.4 2014/10/29 01:08:31 roy Exp $ */
 
 /*
  * dhcpcd - DHCP client daemon
@@ -36,6 +36,7 @@
 #include <limits.h>
 #include <stdint.h>
 
+#include "arp.h"
 #include "auth.h"
 #include "dhcp-common.h"
 
@@ -68,7 +69,6 @@
 #define DHCP_MAX		64
 #define DHCP_RAND_MIN		-1
 #define DHCP_RAND_MAX		1
-#define DHCP_ARP_FAIL		2
 
 #ifdef RFC2131_STRICT
 /* Be strictly conformant for section 4.1.1 */
@@ -198,7 +198,7 @@ enum DHS {
 	DHS_REBOOT,
 	DHS_INFORM,
 	DHS_RENEW_REQUESTED,
-	DHS_INIT_IPV4LL,
+	DHS_IPV4LL_BOUND,
 	DHS_PROBE
 };
 
@@ -214,12 +214,6 @@ struct dhcp_state {
 	time_t nakoff;
 	uint32_t xid;
 	int socket;
-	int probes;
-	int claims;
-	int conflicts;
-	time_t defend;
-	struct in_addr fail;
-	size_t arping_index;
 
 	int raw_fd;
 	int arp_fd;
@@ -237,6 +231,14 @@ struct dhcp_state {
 	unsigned char *clientid;
 
 	struct authstate auth;
+	struct arp_statehead arp_states;
+
+	size_t arping_index;
+
+	struct arp_state *arp_ipv4ll;
+	unsigned int conflicts;
+	time_t defend;
+	char randomstate[128];
 };
 
 #define D_STATE(ifp)							       \
@@ -283,7 +285,8 @@ void dhcp_stop(struct interface *);
 void dhcp_decline(struct interface *);
 void dhcp_discover(void *);
 void dhcp_inform(struct interface *);
-void dhcp_bind(void *);
+void dhcp_probe(struct interface *);
+void dhcp_bind(struct interface *, struct arp_state *);
 void dhcp_reboot_newopts(struct interface *, unsigned long long);
 void dhcp_close(struct interface *);
 void dhcp_free(struct interface *);
Index: src/external/bsd/dhcpcd/dist/dhcp6.c
diff -u src/external/bsd/dhcpcd/dist/dhcp6.c:1.3 src/external/bsd/dhcpcd/dist/dhcp6.c:1.4
--- src/external/bsd/dhcpcd/dist/dhcp6.c:1.3	Fri Oct 17 23:42:24 2014
+++ src/external/bsd/dhcpcd/dist/dhcp6.c	Wed Oct 29 01:08:31 2014
@@ -1,5 +1,5 @@
 #include <sys/cdefs.h>
- __RCSID("$NetBSD: dhcp6.c,v 1.3 2014/10/17 23:42:24 roy Exp $");
+ __RCSID("$NetBSD: dhcp6.c,v 1.4 2014/10/29 01:08:31 roy Exp $");
 
 /*
  * dhcpcd - DHCP client daemon
Index: src/external/bsd/dhcpcd/dist/dhcp6.h
diff -u src/external/bsd/dhcpcd/dist/dhcp6.h:1.3 src/external/bsd/dhcpcd/dist/dhcp6.h:1.4
--- src/external/bsd/dhcpcd/dist/dhcp6.h:1.3	Fri Oct 17 23:42:24 2014
+++ src/external/bsd/dhcpcd/dist/dhcp6.h	Wed Oct 29 01:08:31 2014
@@ -1,4 +1,4 @@
-/* $NetBSD: dhcp6.h,v 1.3 2014/10/17 23:42:24 roy Exp $ */
+/* $NetBSD: dhcp6.h,v 1.4 2014/10/29 01:08:31 roy Exp $ */
 
 /*
  * dhcpcd - DHCP client daemon
Index: src/external/bsd/dhcpcd/dist/dhcpcd-definitions.conf
diff -u src/external/bsd/dhcpcd/dist/dhcpcd-definitions.conf:1.3 src/external/bsd/dhcpcd/dist/dhcpcd-definitions.conf:1.4
--- src/external/bsd/dhcpcd/dist/dhcpcd-definitions.conf:1.3	Fri Oct 17 23:42:24 2014
+++ src/external/bsd/dhcpcd/dist/dhcpcd-definitions.conf	Wed Oct 29 01:08:31 2014
@@ -1,4 +1,4 @@
-# $NetBSD: dhcpcd-definitions.conf,v 1.3 2014/10/17 23:42:24 roy Exp $
+# $NetBSD: dhcpcd-definitions.conf,v 1.4 2014/10/29 01:08:31 roy Exp $
 
 # Copyright (c) 2006-2014 Roy Marples
 # All rights reserved
Index: src/external/bsd/dhcpcd/dist/dhcpcd-embedded.c
diff -u src/external/bsd/dhcpcd/dist/dhcpcd-embedded.c:1.3 src/external/bsd/dhcpcd/dist/dhcpcd-embedded.c:1.4
--- src/external/bsd/dhcpcd/dist/dhcpcd-embedded.c:1.3	Fri Oct 17 23:42:24 2014
+++ src/external/bsd/dhcpcd/dist/dhcpcd-embedded.c	Wed Oct 29 01:08:31 2014
@@ -1,5 +1,5 @@
 #include <sys/cdefs.h>
- __RCSID("$NetBSD: dhcpcd-embedded.c,v 1.3 2014/10/17 23:42:24 roy Exp $");
+ __RCSID("$NetBSD: dhcpcd-embedded.c,v 1.4 2014/10/29 01:08:31 roy Exp $");
 
 /*
  * DO NOT EDIT
Index: src/external/bsd/dhcpcd/dist/dhcpcd-embedded.h
diff -u src/external/bsd/dhcpcd/dist/dhcpcd-embedded.h:1.3 src/external/bsd/dhcpcd/dist/dhcpcd-embedded.h:1.4
--- src/external/bsd/dhcpcd/dist/dhcpcd-embedded.h:1.3	Fri Oct 17 23:42:24 2014
+++ src/external/bsd/dhcpcd/dist/dhcpcd-embedded.h	Wed Oct 29 01:08:31 2014
@@ -1,4 +1,4 @@
-/* $NetBSD: dhcpcd-embedded.h,v 1.3 2014/10/17 23:42:24 roy Exp $ */
+/* $NetBSD: dhcpcd-embedded.h,v 1.4 2014/10/29 01:08:31 roy Exp $ */
 
 /*
  * dhcpcd - DHCP client daemon
Index: src/external/bsd/dhcpcd/dist/dhcpcd-run-hooks.in
diff -u src/external/bsd/dhcpcd/dist/dhcpcd-run-hooks.in:1.3 src/external/bsd/dhcpcd/dist/dhcpcd-run-hooks.in:1.4
--- src/external/bsd/dhcpcd/dist/dhcpcd-run-hooks.in:1.3	Fri Oct 17 23:42:24 2014
+++ src/external/bsd/dhcpcd/dist/dhcpcd-run-hooks.in	Wed Oct 29 01:08:31 2014
@@ -1,5 +1,5 @@
 #!/bin/sh
-# $NetBSD: dhcpcd-run-hooks.in,v 1.3 2014/10/17 23:42:24 roy Exp $
+# $NetBSD: dhcpcd-run-hooks.in,v 1.4 2014/10/29 01:08:31 roy Exp $
 
 # dhcpcd client configuration script 
 
Index: src/external/bsd/dhcpcd/dist/dhcpcd.h
diff -u src/external/bsd/dhcpcd/dist/dhcpcd.h:1.3 src/external/bsd/dhcpcd/dist/dhcpcd.h:1.4
--- src/external/bsd/dhcpcd/dist/dhcpcd.h:1.3	Fri Oct 17 23:42:24 2014
+++ src/external/bsd/dhcpcd/dist/dhcpcd.h	Wed Oct 29 01:08:31 2014
@@ -1,4 +1,4 @@
-/* $NetBSD: dhcpcd.h,v 1.3 2014/10/17 23:42:24 roy Exp $ */
+/* $NetBSD: dhcpcd.h,v 1.4 2014/10/29 01:08:31 roy Exp $ */
 
 /*
  * dhcpcd - DHCP client daemon
Index: src/external/bsd/dhcpcd/dist/duid.c
diff -u src/external/bsd/dhcpcd/dist/duid.c:1.3 src/external/bsd/dhcpcd/dist/duid.c:1.4
--- src/external/bsd/dhcpcd/dist/duid.c:1.3	Fri Oct 17 23:42:24 2014
+++ src/external/bsd/dhcpcd/dist/duid.c	Wed Oct 29 01:08:31 2014
@@ -1,5 +1,5 @@
 #include <sys/cdefs.h>
- __RCSID("$NetBSD: duid.c,v 1.3 2014/10/17 23:42:24 roy Exp $");
+ __RCSID("$NetBSD: duid.c,v 1.4 2014/10/29 01:08:31 roy Exp $");
 
 /*
  * dhcpcd - DHCP client daemon
Index: src/external/bsd/dhcpcd/dist/duid.h
diff -u src/external/bsd/dhcpcd/dist/duid.h:1.3 src/external/bsd/dhcpcd/dist/duid.h:1.4
--- src/external/bsd/dhcpcd/dist/duid.h:1.3	Fri Oct 17 23:42:24 2014
+++ src/external/bsd/dhcpcd/dist/duid.h	Wed Oct 29 01:08:31 2014
@@ -1,4 +1,4 @@
-/* $NetBSD: duid.h,v 1.3 2014/10/17 23:42:24 roy Exp $ */
+/* $NetBSD: duid.h,v 1.4 2014/10/29 01:08:31 roy Exp $ */
 
 /*
  * dhcpcd - DHCP client daemon
Index: src/external/bsd/dhcpcd/dist/eloop.c
diff -u src/external/bsd/dhcpcd/dist/eloop.c:1.3 src/external/bsd/dhcpcd/dist/eloop.c:1.4
--- src/external/bsd/dhcpcd/dist/eloop.c:1.3	Fri Oct 17 23:42:24 2014
+++ src/external/bsd/dhcpcd/dist/eloop.c	Wed Oct 29 01:08:31 2014
@@ -1,5 +1,5 @@
 #include <sys/cdefs.h>
- __RCSID("$NetBSD: eloop.c,v 1.3 2014/10/17 23:42:24 roy Exp $");
+ __RCSID("$NetBSD: eloop.c,v 1.4 2014/10/29 01:08:31 roy Exp $");
 
 /*
  * dhcpcd - DHCP client daemon
Index: src/external/bsd/dhcpcd/dist/eloop.h
diff -u src/external/bsd/dhcpcd/dist/eloop.h:1.3 src/external/bsd/dhcpcd/dist/eloop.h:1.4
--- src/external/bsd/dhcpcd/dist/eloop.h:1.3	Fri Oct 17 23:42:24 2014
+++ src/external/bsd/dhcpcd/dist/eloop.h	Wed Oct 29 01:08:31 2014
@@ -1,4 +1,4 @@
-/* $NetBSD: eloop.h,v 1.3 2014/10/17 23:42:24 roy Exp $ */
+/* $NetBSD: eloop.h,v 1.4 2014/10/29 01:08:31 roy Exp $ */
 
 /*
  * dhcpcd - DHCP client daemon
Index: src/external/bsd/dhcpcd/dist/if-options.h
diff -u src/external/bsd/dhcpcd/dist/if-options.h:1.3 src/external/bsd/dhcpcd/dist/if-options.h:1.4
--- src/external/bsd/dhcpcd/dist/if-options.h:1.3	Fri Oct 17 23:42:24 2014
+++ src/external/bsd/dhcpcd/dist/if-options.h	Wed Oct 29 01:08:31 2014
@@ -1,4 +1,4 @@
-/* $NetBSD: if-options.h,v 1.3 2014/10/17 23:42:24 roy Exp $ */
+/* $NetBSD: if-options.h,v 1.4 2014/10/29 01:08:31 roy Exp $ */
 
 /*
  * dhcpcd - DHCP client daemon
@@ -65,6 +65,7 @@
 #define DHCPCD_LASTLEASE		(1ULL << 7)
 #define DHCPCD_INFORM			(1ULL << 8)
 #define DHCPCD_REQUEST			(1ULL << 9)
+
 #define DHCPCD_IPV4LL			(1ULL << 10)
 #define DHCPCD_DUID			(1ULL << 11)
 #define DHCPCD_PERSISTENT		(1ULL << 12)
@@ -78,7 +79,7 @@
 #define DHCPCD_QUIET			(1ULL << 21)
 #define DHCPCD_BACKGROUND		(1ULL << 22)
 #define DHCPCD_VENDORRAW		(1ULL << 23)
-#define DHCPCD_TIMEOUT_IPV4LL		(1ULL << 24)
+#define DHCPCD_NOWAITIP			(1ULL << 24) /* To force daemonise */
 #define DHCPCD_WAITIP			(1ULL << 25)
 #define DHCPCD_SLAACPRIVATE		(1ULL << 26)
 #define DHCPCD_CSR_WARNED		(1ULL << 27)
Index: src/external/bsd/dhcpcd/dist/if.c
diff -u src/external/bsd/dhcpcd/dist/if.c:1.3 src/external/bsd/dhcpcd/dist/if.c:1.4
--- src/external/bsd/dhcpcd/dist/if.c:1.3	Fri Oct 17 23:42:24 2014
+++ src/external/bsd/dhcpcd/dist/if.c	Wed Oct 29 01:08:31 2014
@@ -1,5 +1,5 @@
 #include <sys/cdefs.h>
- __RCSID("$NetBSD: if.c,v 1.3 2014/10/17 23:42:24 roy Exp $");
+ __RCSID("$NetBSD: if.c,v 1.4 2014/10/29 01:08:31 roy Exp $");
 
 /*
  * dhcpcd - DHCP client daemon
Index: src/external/bsd/dhcpcd/dist/if.h
diff -u src/external/bsd/dhcpcd/dist/if.h:1.3 src/external/bsd/dhcpcd/dist/if.h:1.4
--- src/external/bsd/dhcpcd/dist/if.h:1.3	Fri Oct 17 23:42:24 2014
+++ src/external/bsd/dhcpcd/dist/if.h	Wed Oct 29 01:08:31 2014
@@ -1,4 +1,4 @@
-/* $NetBSD: if.h,v 1.3 2014/10/17 23:42:24 roy Exp $ */
+/* $NetBSD: if.h,v 1.4 2014/10/29 01:08:31 roy Exp $ */
 
 /*
  * dhcpcd - DHCP client daemon
Index: src/external/bsd/dhcpcd/dist/ipv4.c
diff -u src/external/bsd/dhcpcd/dist/ipv4.c:1.3 src/external/bsd/dhcpcd/dist/ipv4.c:1.4
--- src/external/bsd/dhcpcd/dist/ipv4.c:1.3	Fri Oct 17 23:42:24 2014
+++ src/external/bsd/dhcpcd/dist/ipv4.c	Wed Oct 29 01:08:31 2014
@@ -1,5 +1,5 @@
 #include <sys/cdefs.h>
- __RCSID("$NetBSD: ipv4.c,v 1.3 2014/10/17 23:42:24 roy Exp $");
+ __RCSID("$NetBSD: ipv4.c,v 1.4 2014/10/29 01:08:31 roy Exp $");
 
 /*
  * dhcpcd - DHCP client daemon
@@ -136,6 +136,22 @@ ipv4_iffindaddr(struct interface *ifp,
 }
 
 struct ipv4_addr *
+ipv4_iffindlladdr(struct interface *ifp)
+{
+	struct ipv4_state *state;
+	struct ipv4_addr *ap;
+
+	state = IPV4_STATE(ifp);
+	if (state) {
+		TAILQ_FOREACH(ap, &state->addrs, next) {
+			if (IN_LINKLOCAL(htonl(ap->addr.s_addr)))
+				return ap;
+		}
+	}
+	return NULL;
+}
+
+struct ipv4_addr *
 ipv4_findaddr(struct dhcpcd_ctx *ctx, const struct in_addr *addr)
 {
 	struct interface *ifp;
@@ -770,10 +786,7 @@ ipv4_applyaddr(void *arg)
 						if (ifn->options->options &
 						    DHCPCD_ARP)
 						{
-							nstate->claims = 0;
-							nstate->probes = 0;
-							nstate->conflicts = 0;
-							arp_probe(ifn);
+							dhcp_bind(ifn, NULL);
 						} else {
 							ipv4_addaddr(ifn,
 							    &nstate->lease);
@@ -855,6 +868,7 @@ ipv4_applyaddr(void *arg)
 		delete_address(ifp);
 
 	state->added = 1;
+	state->defend = 0;
 	state->addr.s_addr = lease->addr.s_addr;
 	state->net.s_addr = lease->net.s_addr;
 
Index: src/external/bsd/dhcpcd/dist/ipv4.h
diff -u src/external/bsd/dhcpcd/dist/ipv4.h:1.3 src/external/bsd/dhcpcd/dist/ipv4.h:1.4
--- src/external/bsd/dhcpcd/dist/ipv4.h:1.3	Fri Oct 17 23:42:24 2014
+++ src/external/bsd/dhcpcd/dist/ipv4.h	Wed Oct 29 01:08:31 2014
@@ -1,4 +1,4 @@
-/* $NetBSD: ipv4.h,v 1.3 2014/10/17 23:42:24 roy Exp $ */
+/* $NetBSD: ipv4.h,v 1.4 2014/10/29 01:08:31 roy Exp $ */
 
 /*
  * dhcpcd - DHCP client daemon
@@ -74,6 +74,7 @@ int ipv4_routedeleted(struct dhcpcd_ctx 
 
 struct ipv4_addr *ipv4_iffindaddr(struct interface *,
     const struct in_addr *, const struct in_addr *);
+struct ipv4_addr *ipv4_iffindlladdr(struct interface *);
 struct ipv4_addr *ipv4_findaddr(struct dhcpcd_ctx *, const struct in_addr *);
 void ipv4_handleifa(struct dhcpcd_ctx *, int, struct if_head *, const char *,
     const struct in_addr *, const struct in_addr *, const struct in_addr *);
Index: src/external/bsd/dhcpcd/dist/ipv4ll.c
diff -u src/external/bsd/dhcpcd/dist/ipv4ll.c:1.3 src/external/bsd/dhcpcd/dist/ipv4ll.c:1.4
--- src/external/bsd/dhcpcd/dist/ipv4ll.c:1.3	Fri Oct 17 23:42:24 2014
+++ src/external/bsd/dhcpcd/dist/ipv4ll.c	Wed Oct 29 01:08:31 2014
@@ -1,5 +1,5 @@
 #include <sys/cdefs.h>
- __RCSID("$NetBSD: ipv4ll.c,v 1.3 2014/10/17 23:42:24 roy Exp $");
+ __RCSID("$NetBSD: ipv4ll.c,v 1.4 2014/10/29 01:08:31 roy Exp $");
 
 /*
  * dhcpcd - DHCP client daemon
@@ -35,7 +35,7 @@
 #include <syslog.h>
 #include <unistd.h>
 
-#define ELOOP_QUEUE 2
+#define ELOOP_QUEUE 6
 #include "config.h"
 #include "arp.h"
 #include "common.h"
@@ -73,101 +73,183 @@ ipv4ll_make_lease(uint32_t addr)
 	return dhcp;
 }
 
-static struct dhcp_message *
-ipv4ll_find_lease(uint32_t old_addr)
+static in_addr_t
+ipv4ll_pick_addr(const struct arp_state *astate)
 {
-	uint32_t addr;
+	in_addr_t addr;
+	struct interface *ifp;
+	const struct dhcp_state *state;
 
 	for (;;) {
-		addr = htonl(LINKLOCAL_ADDR |
-		    (uint32_t)(abs((int)arc4random_uniform(0xFD00)) + 0x0100));
-		if (addr != old_addr &&
-		    IN_LINKLOCAL(ntohl(addr)))
+		/* RFC 3927 Section 2.1 states that the first 256 and
+		 * last 256 addresses are reserved for future use.
+		 * See ipv4ll_start for why we don't use arc4_random. */
+		addr = ntohl(LINKLOCAL_ADDR | ((random() % 0xFD00) + 0x0100));
+
+		/* No point using a failed address */
+		if (addr == astate->failed.s_addr)
+			continue;
+
+		state = D_CSTATE(astate->iface);
+		/* Ensure we don't have the address on another interface */
+		TAILQ_FOREACH(ifp, astate->iface->ctx->ifaces, next) {
+			state = D_CSTATE(ifp);
+			if (state && state->addr.s_addr == addr)
+				break;
+		}
+
+		/* Yay, this should be a unique and workable IPv4LL address */
+		if (ifp == NULL)
 			break;
 	}
-	return ipv4ll_make_lease(addr);
+	return addr;
 }
 
-void
-ipv4ll_start(void *arg)
+static void
+ipv4ll_probed(struct arp_state *astate)
 {
-	struct interface *ifp = arg;
-	struct dhcp_state *state = D_STATE(ifp);
-	uint32_t addr;
+	struct dhcp_state *state = D_STATE(astate->iface);
 
-	eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
-	state->probes = 0;
-	state->claims = 0;
-	if (state->addr.s_addr) {
-		state->conflicts = 0;
-		if (IN_LINKLOCAL(htonl(state->addr.s_addr))) {
-			arp_announce(ifp);
-			return;
-		}
-	}
-
-	if (state->offer == NULL)
-		addr = 0;
-	else {
-		addr = state->offer->yiaddr;
-		free(state->offer);
-	}
-	/* We maybe rebooting an IPv4LL address. */
-	if (!IN_LINKLOCAL(htonl(addr))) {
-		syslog(LOG_INFO, "%s: probing for an IPv4LL address",
-		    ifp->name);
-		addr = 0;
-	}
-	if (addr == 0)
-		state->offer = ipv4ll_find_lease(addr);
-	else
-		state->offer = ipv4ll_make_lease(addr);
-	if (state->offer == NULL)
+	free(state->offer);
+	state->offer = ipv4ll_make_lease(astate->addr.s_addr);
+	if (state->offer == NULL) {
 		syslog(LOG_ERR, "%s: %m", __func__);
-	else {
-		state->lease.frominfo = 0;
-		arp_probe(ifp);
+		return;
 	}
+	dhcp_bind(astate->iface, astate);
 }
 
-void
-ipv4ll_handle_failure(void *arg)
+static void
+ipv4ll_announced(struct arp_state *astate)
 {
-	struct interface *ifp = arg;
-	struct dhcp_state *state = D_STATE(ifp);
-	time_t up;
+	struct dhcp_state *state = D_STATE(astate->iface);
+
+	state->conflicts = 0;
+	/* Need to keep the arp state so we can defend our IP. */
+}
+
+static void
+ipv4ll_probe(void *arg)
+{
+
+	arp_probe(arg);
+}
+
+static void
+ipv4ll_conflicted(struct arp_state *astate, const struct arp_msg *amsg)
+{
+	struct dhcp_state *state = D_STATE(astate->iface);
+	in_addr_t fail;
+
+	fail = 0;
+	/* RFC 3927 2.2.1, Probe Conflict Detection */
+	if (amsg->sip.s_addr == astate->addr.s_addr ||
+	    (amsg->sip.s_addr == 0 && amsg->tip.s_addr == astate->addr.s_addr))
+		fail = astate->addr.s_addr;
+
+	/* RFC 3927 2.5, Conflict Defense */
+	if (IN_LINKLOCAL(htonl(state->addr.s_addr)) &&
+	    amsg->sip.s_addr == state->addr.s_addr)
+		fail = state->addr.s_addr;
+
+	if (fail == 0)
+		return;
+
+	astate->failed.s_addr = fail;
+	arp_report_conflicted(astate, amsg);
+
+	if (astate->failed.s_addr == state->addr.s_addr) {
+		time_t up;
 
-	if (state->fail.s_addr == state->addr.s_addr) {
 		/* RFC 3927 Section 2.5 */
 		up = uptime();
 		if (state->defend + DEFEND_INTERVAL > up) {
 			syslog(LOG_WARNING,
-			    "%s: IPv4LL %d second defence failed",
-			    ifp->name, DEFEND_INTERVAL);
-			dhcp_drop(ifp, "EXPIRE");
-			state->conflicts = -1;
+			    "%s: IPv4LL %d second defence failed for %s",
+			    astate->iface->name, DEFEND_INTERVAL,
+			    inet_ntoa(state->addr));
+			dhcp_drop(astate->iface, "EXPIRE");
 		} else {
-			syslog(LOG_DEBUG, "%s: defended IPv4LL address",
-			    ifp->name);
+			syslog(LOG_DEBUG, "%s: defended IPv4LL address %s",
+			    astate->iface->name, inet_ntoa(state->addr));
 			state->defend = up;
 			return;
 		}
 	}
 
-	free(state->offer);
-	state->offer = NULL;
-	eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
-	if (++state->conflicts > MAX_CONFLICTS) {
+	arp_cancel(astate);
+	if (++state->conflicts == MAX_CONFLICTS)
 		syslog(LOG_ERR, "%s: failed to acquire an IPv4LL address",
-		    ifp->name);
-		if (ifp->options->options & DHCPCD_DHCP) {
-			state->interval = RATE_LIMIT_INTERVAL / 2;
-			dhcp_discover(ifp);
+		    astate->iface->name);
+	astate->addr.s_addr = ipv4ll_pick_addr(astate);
+	eloop_timeout_add_sec(astate->iface->ctx->eloop,
+		state->conflicts >= MAX_CONFLICTS ?
+		RATE_LIMIT_INTERVAL : PROBE_WAIT,
+		ipv4ll_probe, astate);
+}
+
+void
+ipv4ll_start(void *arg)
+{
+	struct interface *ifp = arg;
+	struct dhcp_state *state = D_STATE(ifp);
+	struct arp_state *astate;
+	struct ipv4_addr *ap;
+
+	if (state->arp_ipv4ll)
+		return;
+
+	/* RFC 3927 Section 2.1 states that the random number generator
+	 * SHOULD be seeded with a value derived from persistent information
+	 * such as the IEEE 802 MAC address so that it usually picks
+	 * the same address without persistent storage. */
+	if (state->conflicts == 0) {
+		unsigned int seed;
+
+		if (sizeof(seed) > ifp->hwlen) {
+			seed = 0;
+			memcpy(&seed, ifp->hwaddr, ifp->hwlen);
 		} else
-			eloop_timeout_add_sec(ifp->ctx->eloop,
-			    RATE_LIMIT_INTERVAL, ipv4ll_start, ifp);
-	} else {
-		eloop_timeout_add_sec(ifp->ctx->eloop,
-		    PROBE_WAIT, ipv4ll_start, ifp);
+			memcpy(&seed, ifp->hwaddr + ifp->hwlen - sizeof(seed),
+			    sizeof(seed));
+		initstate(seed, state->randomstate, sizeof(state->randomstate));
+	}
+
+	if ((astate = arp_new(ifp)) == NULL)
+		return;
+
+	state->arp_ipv4ll = astate;
+	astate->probed_cb = ipv4ll_probed;
+	astate->announced_cb = ipv4ll_announced;
+	astate->conflicted_cb = ipv4ll_conflicted;
+
+	if (IN_LINKLOCAL(htonl(state->addr.s_addr))) {
+		astate->addr = state->addr;
+		arp_announce(astate);
+		return;
+	}
+
+	if (state->offer && IN_LINKLOCAL(ntohl(state->offer->yiaddr))) {
+		astate->addr.s_addr = state->offer->yiaddr;
+		free(state->offer);
+		state->offer = NULL;
+		ap = ipv4_iffindaddr(ifp, &astate->addr, NULL);
+	} else
+		ap = ipv4_iffindlladdr(ifp);
+	if (ap) {
+		astate->addr = ap->addr;
+		ipv4ll_probed(astate);
+		return;
+	}
+
+	setstate(state->randomstate);
+	/* We maybe rebooting an IPv4LL address. */
+	if (!IN_LINKLOCAL(htonl(astate->addr.s_addr))) {
+		syslog(LOG_INFO, "%s: probing for an IPv4LL address",
+		    ifp->name);
+		astate->addr.s_addr = INADDR_ANY;
 	}
+	if (astate->addr.s_addr == INADDR_ANY)
+		astate->addr.s_addr = ipv4ll_pick_addr(astate);
+	arp_probe(astate);
 }
Index: src/external/bsd/dhcpcd/dist/ipv4ll.h
diff -u src/external/bsd/dhcpcd/dist/ipv4ll.h:1.3 src/external/bsd/dhcpcd/dist/ipv4ll.h:1.4
--- src/external/bsd/dhcpcd/dist/ipv4ll.h:1.3	Fri Oct 17 23:42:24 2014
+++ src/external/bsd/dhcpcd/dist/ipv4ll.h	Wed Oct 29 01:08:31 2014
@@ -1,4 +1,4 @@
-/* $NetBSD: ipv4ll.h,v 1.3 2014/10/17 23:42:24 roy Exp $ */
+/* $NetBSD: ipv4ll.h,v 1.4 2014/10/29 01:08:31 roy Exp $ */
 
 /*
  * dhcpcd - DHCP client daemon
@@ -31,6 +31,7 @@
 #define IPV4LL_H
 
 void ipv4ll_start(void *);
+void ipv4ll_claimed(void *);
 void ipv4ll_handle_failure(void *);
 
 #endif
Index: src/external/bsd/dhcpcd/dist/ipv6.c
diff -u src/external/bsd/dhcpcd/dist/ipv6.c:1.3 src/external/bsd/dhcpcd/dist/ipv6.c:1.4
--- src/external/bsd/dhcpcd/dist/ipv6.c:1.3	Fri Oct 17 23:42:24 2014
+++ src/external/bsd/dhcpcd/dist/ipv6.c	Wed Oct 29 01:08:31 2014
@@ -1,5 +1,5 @@
 #include <sys/cdefs.h>
- __RCSID("$NetBSD: ipv6.c,v 1.3 2014/10/17 23:42:24 roy Exp $");
+ __RCSID("$NetBSD: ipv6.c,v 1.4 2014/10/29 01:08:31 roy Exp $");
 
 /*
  * dhcpcd - DHCP client daemon
Index: src/external/bsd/dhcpcd/dist/ipv6.h
diff -u src/external/bsd/dhcpcd/dist/ipv6.h:1.3 src/external/bsd/dhcpcd/dist/ipv6.h:1.4
--- src/external/bsd/dhcpcd/dist/ipv6.h:1.3	Fri Oct 17 23:42:24 2014
+++ src/external/bsd/dhcpcd/dist/ipv6.h	Wed Oct 29 01:08:31 2014
@@ -1,4 +1,4 @@
-/* $NetBSD: ipv6.h,v 1.3 2014/10/17 23:42:24 roy Exp $ */
+/* $NetBSD: ipv6.h,v 1.4 2014/10/29 01:08:31 roy Exp $ */
 
 /*
  * dhcpcd - DHCP client daemon
Index: src/external/bsd/dhcpcd/dist/ipv6nd.h
diff -u src/external/bsd/dhcpcd/dist/ipv6nd.h:1.3 src/external/bsd/dhcpcd/dist/ipv6nd.h:1.4
--- src/external/bsd/dhcpcd/dist/ipv6nd.h:1.3	Fri Oct 17 23:42:24 2014
+++ src/external/bsd/dhcpcd/dist/ipv6nd.h	Wed Oct 29 01:08:31 2014
@@ -1,4 +1,4 @@
-/* $NetBSD: ipv6nd.h,v 1.3 2014/10/17 23:42:24 roy Exp $ */
+/* $NetBSD: ipv6nd.h,v 1.4 2014/10/29 01:08:31 roy Exp $ */
 
 /*
  * dhcpcd - DHCP client daemon
Index: src/external/bsd/dhcpcd/dist/script.h
diff -u src/external/bsd/dhcpcd/dist/script.h:1.3 src/external/bsd/dhcpcd/dist/script.h:1.4
--- src/external/bsd/dhcpcd/dist/script.h:1.3	Fri Oct 17 23:42:24 2014
+++ src/external/bsd/dhcpcd/dist/script.h	Wed Oct 29 01:08:31 2014
@@ -1,4 +1,4 @@
-/* $NetBSD: script.h,v 1.3 2014/10/17 23:42:24 roy Exp $ */
+/* $NetBSD: script.h,v 1.4 2014/10/29 01:08:31 roy Exp $ */
 
 /*
  * dhcpcd - DHCP client daemon

Index: src/external/bsd/dhcpcd/dist/bpf-filter.h
diff -u src/external/bsd/dhcpcd/dist/bpf-filter.h:1.6 src/external/bsd/dhcpcd/dist/bpf-filter.h:1.7
--- src/external/bsd/dhcpcd/dist/bpf-filter.h:1.6	Fri Oct 17 23:42:24 2014
+++ src/external/bsd/dhcpcd/dist/bpf-filter.h	Wed Oct 29 01:08:31 2014
@@ -1,4 +1,4 @@
-/* $NetBSD: bpf-filter.h,v 1.6 2014/10/17 23:42:24 roy Exp $ */
+/* $NetBSD: bpf-filter.h,v 1.7 2014/10/29 01:08:31 roy Exp $ */
 
 /*
  * dhcpcd - DHCP client daemon

Index: src/external/bsd/dhcpcd/dist/dhcp.c
diff -u src/external/bsd/dhcpcd/dist/dhcp.c:1.19 src/external/bsd/dhcpcd/dist/dhcp.c:1.20
--- src/external/bsd/dhcpcd/dist/dhcp.c:1.19	Fri Oct 17 23:42:24 2014
+++ src/external/bsd/dhcpcd/dist/dhcp.c	Wed Oct 29 01:08:31 2014
@@ -1,5 +1,5 @@
 #include <sys/cdefs.h>
- __RCSID("$NetBSD: dhcp.c,v 1.19 2014/10/17 23:42:24 roy Exp $");
+ __RCSID("$NetBSD: dhcp.c,v 1.20 2014/10/29 01:08:31 roy Exp $");
 
 /*
  * dhcpcd - DHCP client daemon
@@ -1418,11 +1418,6 @@ dhcp_close(struct interface *ifp)
 	if (state == NULL)
 		return;
 
-	if (state->arp_fd != -1) {
-		eloop_event_delete(ifp->ctx->eloop, state->arp_fd, 0);
-		close(state->arp_fd);
-		state->arp_fd = -1;
-	}
 	if (state->raw_fd != -1) {
 		eloop_event_delete(ifp->ctx->eloop, state->raw_fd, 0);
 		close(state->raw_fd);
@@ -1676,7 +1671,7 @@ send_message(struct interface *iface, ui
 			default:
 				if (!(iface->ctx->options & DHCPCD_TEST))
 					dhcp_drop(iface, "FAIL");
-				dhcp_close(iface);
+				dhcp_free(iface);
 				eloop_timeout_delete(iface->ctx->eloop,
 				    NULL, iface);
 				callback = NULL;
@@ -1738,16 +1733,13 @@ dhcp_discover(void *arg)
 	struct if_options *ifo = ifp->options;
 	time_t timeout = ifo->timeout;
 
-	/* If we're rebooting and we're not daemonised then we need
-	 * to shorten the normal timeout to ensure we try correctly
-	 * for a fallback or IPv4LL address. */
-	if (state->state == DHS_REBOOT &&
-	    !(ifp->ctx->options & DHCPCD_DAEMONISED))
-	{
+	/* If we're rebooting then we need to shorten the normal timeout
+	 * to ensure we try for a fallback or IPv4LL address. */
+	if (state->state == DHS_REBOOT) {
 		if (ifo->reboot >= timeout)
 			timeout = 2;
 		else
-			timeout -= ifo->reboot;
+			timeout = ifo->reboot;
 	}
 
 	state->state = DHS_DISCOVER;
@@ -1758,12 +1750,8 @@ dhcp_discover(void *arg)
 		    timeout, dhcp_fallback, ifp);
 	else if (ifo->options & DHCPCD_IPV4LL &&
 	    !IN_LINKLOCAL(htonl(state->addr.s_addr)))
-	{
-		if (IN_LINKLOCAL(htonl(state->fail.s_addr)))
-			timeout = RATE_LIMIT_INTERVAL;
 		eloop_timeout_add_sec(ifp->ctx->eloop,
 		    timeout, ipv4ll_start, ifp);
-	}
 	if (ifo->options & DHCPCD_REQUEST)
 		syslog(LOG_INFO, "%s: soliciting a DHCP lease (requesting %s)",
 		    ifp->name, inet_ntoa(ifo->req_addr));
@@ -1792,7 +1780,6 @@ dhcp_expire(void *arg)
 	eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
 	dhcp_drop(ifp, "EXPIRE");
 	unlink(state->leasefile);
-
 	state->interval = 0;
 	dhcp_discover(ifp);
 }
@@ -1823,6 +1810,13 @@ dhcp_renew(void *arg)
 }
 
 static void
+dhcp_arp_announced(struct arp_state *astate)
+{
+
+	arp_close(astate->iface);
+}
+
+static void
 dhcp_rebind(void *arg)
 {
 	struct interface *ifp = arg;
@@ -1841,9 +1835,8 @@ dhcp_rebind(void *arg)
 }
 
 void
-dhcp_bind(void *arg)
+dhcp_bind(struct interface *ifp, struct arp_state *astate)
 {
-	struct interface *ifp = arg;
 	struct dhcp_state *state = D_STATE(ifp);
 	struct if_options *ifo = ifp->options;
 	struct dhcp_lease *lease = &state->lease;
@@ -1853,7 +1846,6 @@ dhcp_bind(void *arg)
 	if (state->state == DHS_BOUND)
 		goto applyaddr;
 	state->reason = NULL;
-	state->xid = 0;
 	free(state->old);
 	state->old = state->new;
 	state->new = state->offer;
@@ -1933,7 +1925,7 @@ dhcp_bind(void *arg)
 		return;
 	}
 	if (state->reason == NULL) {
-		if (state->old) {
+		if (state->old && state->new->cookie != htonl(MAGIC_COOKIE)) {
 			if (state->old->yiaddr == state->new->yiaddr &&
 			    lease->server.s_addr)
 				state->reason = "RENEW";
@@ -1958,7 +1950,11 @@ dhcp_bind(void *arg)
 		    " seconds",
 		    ifp->name, lease->renewaltime, lease->rebindtime);
 	}
-	state->state = DHS_BOUND;
+	if (!(ifo->options & DHCPCD_STATIC) &&
+	    state->new->cookie != htonl(MAGIC_COOKIE))
+		state->state = DHS_IPV4LL_BOUND;
+	else
+		state->state = DHS_BOUND;
 	if (!state->lease.frominfo &&
 	    !(ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC)))
 		if (write_lease(ifp, state->new) == -1)
@@ -1966,14 +1962,23 @@ dhcp_bind(void *arg)
 
 applyaddr:
 	ipv4_applyaddr(ifp);
-	if (dhcpcd_daemonise(ifp->ctx) == 0) {
-		if (!ipv4ll)
+	if (dhcpcd_daemonise(ifp->ctx))
+		return;
+	if (ifo->options & DHCPCD_ARP) {
+		if (state->added) {
+			if (astate == NULL) {
+				/* We don't care about what happens
+				 * to the ARP announcement */
+				astate = arp_new(ifp);
+				astate->announced_cb =
+				    dhcp_arp_announced;
+			}
+			if (astate) {
+				arp_announce(astate);
+				arp_free_but(astate);
+			}
+		} else if (!ipv4ll)
 			arp_close(ifp);
-		if (ifo->options & DHCPCD_ARP) {
-		        state->claims = 0;
-			if (state->added)
-				arp_announce(ifp);
-		}
 	}
 }
 
@@ -1983,7 +1988,7 @@ dhcp_timeout(void *arg)
 	struct interface *ifp = arg;
 	struct dhcp_state *state = D_STATE(ifp);
 
-	dhcp_bind(ifp);
+	dhcp_bind(ifp, NULL);
 	state->interval = 0;
 	dhcp_discover(ifp);
 }
@@ -2029,7 +2034,7 @@ dhcp_static(struct interface *ifp)
 	state->offer = dhcp_message_new(&ifo->req_addr, &ifo->req_mask);
 	if (state->offer) {
 		eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
-		dhcp_bind(ifp);
+		dhcp_bind(ifp, NULL);
 	}
 }
 
@@ -2065,7 +2070,7 @@ dhcp_inform(struct interface *ifp)
 			    dhcp_message_new(&ifo->req_addr, &ifo->req_mask);
 		if (state->offer) {
 			ifo->options |= DHCPCD_STATIC;
-			dhcp_bind(ifp);
+			dhcp_bind(ifp, NULL);
 			ifo->options &= ~DHCPCD_STATIC;
 		}
 	}
@@ -2102,6 +2107,7 @@ dhcp_reboot(struct interface *ifp)
 	if (state == NULL)
 		return;
 	ifo = ifp->options;
+	state->state = DHS_REBOOT;
 	state->interval = 0;
 
 	if (ifo->options & DHCPCD_LINK && ifp->carrier == LINK_DOWN) {
@@ -2120,21 +2126,21 @@ dhcp_reboot(struct interface *ifp)
 		syslog(LOG_INFO, "%s: informing address of %s",
 		    ifp->name, inet_ntoa(state->lease.addr));
 	} else if (state->offer->cookie == 0) {
-		if (ifo->options & DHCPCD_IPV4LL) {
-			state->claims = 0;
-			if (state->added)
-				arp_announce(ifp);
-		} else
-			dhcp_discover(ifp);
 		return;
 	} else {
 		syslog(LOG_INFO, "%s: rebinding lease of %s",
 		    ifp->name, inet_ntoa(state->lease.addr));
 	}
-	state->state = DHS_REBOOT;
 	state->xid = dhcp_xid(ifp);
 	state->lease.server.s_addr = 0;
 	eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
+
+	/* Need to add this before dhcp_expire and friends. */
+	if (!ifo->fallback && ifo->reboot && ifo->options & DHCPCD_IPV4LL &&
+	    !IN_LINKLOCAL(htonl(state->addr.s_addr)))
+		eloop_timeout_add_sec(ifp->ctx->eloop,
+		    ifo->reboot, ipv4ll_start, ifp);
+
 	if (ifo->fallback)
 		eloop_timeout_add_sec(ifp->ctx->eloop,
 		    ifo->reboot, dhcp_fallback, ifp);
@@ -2162,16 +2168,19 @@ dhcp_drop(struct interface *ifp, const c
 	struct timespec ts;
 #endif
 
+	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. */
-	eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
-
-	state = D_STATE(ifp);
-	if (state == NULL)
+	if (state == NULL) {
+		eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
 		return;
-	dhcp_auth_reset(&state->auth);
-	dhcp_close(ifp);
-	arp_close(ifp);
+	}
+	/* Don't reset DHCP state if we have an IPv4LL address and link is up */
+	if (state->state != DHS_IPV4LL_BOUND || ifp->carrier != LINK_UP) {
+		eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
+		dhcp_auth_reset(&state->auth);
+		dhcp_close(ifp);
+	}
 	if (ifp->options->options & DHCPCD_RELEASE) {
 		unlink(state->leasefile);
 		if (ifp->carrier != LINK_DOWN &&
@@ -2299,6 +2308,103 @@ whitelisted_ip(const struct if_options *
 }
 
 static void
+dhcp_arp_probed(struct arp_state *astate)
+{
+	struct dhcp_state *state;
+	struct if_options *ifo;
+
+	/* We didn't find a profile for this
+	 * address or hwaddr, so move to the next
+	 * arping profile */
+	state = D_STATE(astate->iface);
+	ifo = astate->iface->options;
+	if (state->arping_index < ifo->arping_len) {
+		if (++state->arping_index < ifo->arping_len) {
+			astate->addr.s_addr =
+			    ifo->arping[state->arping_index - 1];
+			arp_probe(astate);
+		}
+		dhcpcd_startinterface(astate->iface);
+		return;
+	}
+	dhcp_close(astate->iface);
+	eloop_timeout_delete(astate->iface->ctx->eloop, NULL, astate->iface);
+	dhcp_bind(astate->iface, astate);
+}
+
+static void
+dhcp_arp_conflicted(struct arp_state *astate, const struct arp_msg *amsg)
+{
+	struct dhcp_state *state;
+	struct if_options *ifo;
+
+	state = D_STATE(astate->iface);
+	ifo = astate->iface->options;
+	if (state->arping_index &&
+	    state->arping_index <= ifo->arping_len &&
+	    (amsg->sip.s_addr == ifo->arping[state->arping_index - 1] ||
+	    (amsg->sip.s_addr == 0 &&
+	    amsg->tip.s_addr == ifo->arping[state->arping_index - 1])))
+	{
+		char buf[HWADDR_LEN * 3];
+
+		astate->failed.s_addr = ifo->arping[state->arping_index - 1];
+		arp_report_conflicted(astate, amsg);
+		hwaddr_ntoa(amsg->sha, astate->iface->hwlen, buf, sizeof(buf));
+		if (dhcpcd_selectprofile(astate->iface, buf) == -1 &&
+		    dhcpcd_selectprofile(astate->iface,
+		        inet_ntoa(astate->failed)) == -1)
+		{
+			/* We didn't find a profile for this
+			 * address or hwaddr, so move to the next
+			 * arping profile */
+			dhcp_arp_probed(astate);
+			return;
+		}
+		dhcp_close(astate->iface);
+		arp_close(astate->iface);
+		eloop_timeout_delete(astate->iface->ctx->eloop, NULL,
+		    astate->iface);
+		dhcpcd_startinterface(astate->iface);
+	}
+
+	if (state->offer == NULL)
+		return;
+
+	/* RFC 2131 3.1.5, Client-server interaction */
+	if (amsg->sip.s_addr == state->offer->yiaddr ||
+	    (amsg->sip.s_addr == 0 && amsg->tip.s_addr == state->offer->yiaddr))
+	{
+		astate->failed.s_addr = state->offer->yiaddr;
+		arp_report_conflicted(astate, amsg);
+		unlink(state->leasefile);
+		if (!state->lease.frominfo)
+			dhcp_decline(astate->iface);
+		eloop_timeout_delete(astate->iface->ctx->eloop, NULL,
+		    astate->iface);
+		eloop_timeout_add_sec(astate->iface->ctx->eloop,
+		    DHCP_RAND_MAX, dhcp_discover, astate->iface);
+	}
+}
+
+void
+dhcp_probe(struct interface *ifp)
+{
+	const struct dhcp_state *state;
+	struct arp_state *astate;
+
+	astate = arp_new(ifp);
+	if (astate) {
+		state = D_CSTATE(ifp);
+		astate->addr = state->addr;
+		astate->probed_cb = dhcp_arp_probed;
+		astate->conflicted_cb = dhcp_arp_conflicted;
+		astate->announced_cb = dhcp_arp_announced;
+		arp_probe(astate);
+	}
+}
+
+static void
 dhcp_handledhcp(struct interface *iface, struct dhcp_message **dhcpp,
     const struct in_addr *from)
 {
@@ -2438,7 +2544,8 @@ dhcp_handledhcp(struct interface *iface,
 			    iface->name, msg);
 			free(msg);
 		}
-		if (state->state == DHS_DISCOVER &&
+		if ((state->state == DHS_DISCOVER ||
+		    state->state == DHS_IPV4LL_BOUND) &&
 		    get_option_uint8(iface->ctx, &tmp, dhcp,
 		    DHO_AUTOCONFIGURE) == 0)
 		{
@@ -2446,7 +2553,8 @@ dhcp_handledhcp(struct interface *iface,
 			case 0:
 				log_dhcp(LOG_WARNING, "IPv4LL disabled from",
 				    iface, dhcp, from);
-				dhcp_close(iface);
+				dhcp_drop(iface, "EXPIRE");
+				arp_close(iface);
 				eloop_timeout_delete(iface->ctx->eloop,
 				    NULL, iface);
 				eloop_timeout_add_sec(iface->ctx->eloop,
@@ -2499,7 +2607,7 @@ dhcp_handledhcp(struct interface *iface,
 	}
 
 	if ((type == 0 || type == DHCP_OFFER) &&
-	    state->state == DHS_DISCOVER)
+	    (state->state == DHS_DISCOVER || state->state == DHS_IPV4LL_BOUND))
 	{
 		lease->frominfo = 0;
 		lease->addr.s_addr = dhcp->yiaddr;
@@ -2580,15 +2688,20 @@ dhcp_handledhcp(struct interface *iface,
 		 * then we can't ARP for duplicate detection. */
 		addr.s_addr = state->offer->yiaddr;
 		if (!ipv4_iffindaddr(iface, &addr, NULL)) {
-			state->claims = 0;
-			state->probes = 0;
-			state->conflicts = 0;
-			arp_probe(iface);
+			struct arp_state *astate;
+
+			astate = arp_new(iface);
+			if (astate) {
+				astate->addr = addr;
+				astate->probed_cb = dhcp_arp_probed;
+				astate->conflicted_cb = dhcp_arp_conflicted;
+				arp_probe(astate);
+			}
 			return;
 		}
 	}
 
-	dhcp_bind(iface);
+	dhcp_bind(iface, NULL);
 }
 
 static size_t
@@ -2672,6 +2785,7 @@ dhcp_handlepacket(void *arg)
 			syslog(LOG_ERR, "%s: dhcp if_readrawpacket: %m",
 			    ifp->name);
 			dhcp_close(ifp);
+			arp_close(ifp);
 			break;
 		}
 		if (valid_udp_packet(ifp->ctx->packet, bytes,
@@ -2793,6 +2907,8 @@ dhcp_dump(struct interface *ifp)
 	ifp->if_data[IF_DATA_DHCP] = state = calloc(1, sizeof(*state));
 	if (state == NULL)
 		goto eexit;
+	state->raw_fd = state->arp_fd = -1;
+	TAILQ_INIT(&state->arp_states);
 	snprintf(state->leasefile, sizeof(state->leasefile),
 	    LEASEFILE, ifp->name);
 	state->new = read_lease(ifp);
@@ -2819,6 +2935,8 @@ dhcp_free(struct interface *ifp)
 	struct dhcp_state *state = D_STATE(ifp);
 	struct dhcpcd_ctx *ctx;
 
+	dhcp_close(ifp);
+	arp_close(ifp);
 	if (state) {
 		free(state->old);
 		free(state->new);
@@ -2868,6 +2986,7 @@ dhcp_init(struct interface *ifp)
 			return -1;
 		/* 0 is a valid fd, so init to -1 */
 		state->raw_fd = state->arp_fd = -1;
+		TAILQ_INIT(&state->arp_states);
 	}
 
 	state->state = DHS_INIT;
@@ -2963,16 +3082,20 @@ dhcp_start1(void *arg)
 		return;
 	}
 
-	/* Close any pre-existing sockets as we're starting over */
-	dhcp_close(ifp);
-
 	state = D_STATE(ifp);
 	state->start_uptime = uptime();
 	free(state->offer);
 	state->offer = NULL;
 
 	if (state->arping_index < ifo->arping_len) {
-		arp_start(ifp);
+		struct arp_state *astate;
+
+		astate = arp_new(ifp);
+		if (astate) {
+			astate->probed_cb = dhcp_arp_probed;
+			astate->conflicted_cb = dhcp_arp_conflicted;
+			dhcp_arp_probed(astate);
+		}
 		return;
 	}
 
@@ -3041,11 +3164,13 @@ dhcp_start1(void *arg)
 		return;
 	}
 
-	if (state->offer == NULL)
+	if (state->offer == NULL || state->offer->cookie == 0) {
+		/* If we don't have an address yet, enter the reboot
+		 * state to ensure at least fallback in short order. */
+		if (state->addr.s_addr == INADDR_ANY)
+			state->state = DHS_REBOOT;
 		dhcp_discover(ifp);
-	else if (state->offer->cookie == 0 && ifo->options & DHCPCD_IPV4LL)
-		ipv4ll_start(ifp);
-	else
+	} else
 		dhcp_reboot(ifp);
 }
 

Index: src/external/bsd/dhcpcd/dist/dhcpcd-run-hooks.8.in
diff -u src/external/bsd/dhcpcd/dist/dhcpcd-run-hooks.8.in:1.9 src/external/bsd/dhcpcd/dist/dhcpcd-run-hooks.8.in:1.10
--- src/external/bsd/dhcpcd/dist/dhcpcd-run-hooks.8.in:1.9	Fri Oct 17 23:42:24 2014
+++ src/external/bsd/dhcpcd/dist/dhcpcd-run-hooks.8.in	Wed Oct 29 01:08:31 2014
@@ -1,4 +1,4 @@
-.\"     $NetBSD: dhcpcd-run-hooks.8.in,v 1.9 2014/10/17 23:42:24 roy Exp $
+.\"     $NetBSD: dhcpcd-run-hooks.8.in,v 1.10 2014/10/29 01:08:31 roy Exp $
 .\" Copyright (c) 2006-2014 Roy Marples
 .\" All rights reserved
 .\"

Index: src/external/bsd/dhcpcd/dist/dhcpcd.8.in
diff -u src/external/bsd/dhcpcd/dist/dhcpcd.8.in:1.33 src/external/bsd/dhcpcd/dist/dhcpcd.8.in:1.34
--- src/external/bsd/dhcpcd/dist/dhcpcd.8.in:1.33	Fri Oct 17 23:42:24 2014
+++ src/external/bsd/dhcpcd/dist/dhcpcd.8.in	Wed Oct 29 01:08:31 2014
@@ -1,4 +1,4 @@
-.\"     $NetBSD: dhcpcd.8.in,v 1.33 2014/10/17 23:42:24 roy Exp $
+.\"     $NetBSD: dhcpcd.8.in,v 1.34 2014/10/29 01:08:31 roy Exp $
 .\" Copyright (c) 2006-2014 Roy Marples
 .\" All rights reserved
 .\"

Index: src/external/bsd/dhcpcd/dist/dhcpcd.c
diff -u src/external/bsd/dhcpcd/dist/dhcpcd.c:1.13 src/external/bsd/dhcpcd/dist/dhcpcd.c:1.14
--- src/external/bsd/dhcpcd/dist/dhcpcd.c:1.13	Fri Oct 17 23:42:24 2014
+++ src/external/bsd/dhcpcd/dist/dhcpcd.c	Wed Oct 29 01:08:31 2014
@@ -1,5 +1,5 @@
 #include <sys/cdefs.h>
- __RCSID("$NetBSD: dhcpcd.c,v 1.13 2014/10/17 23:42:24 roy Exp $");
+ __RCSID("$NetBSD: dhcpcd.c,v 1.14 2014/10/29 01:08:31 roy Exp $");
 
 /*
  * dhcpcd - DHCP client daemon
@@ -188,28 +188,15 @@ static void
 handle_exit_timeout(void *arg)
 {
 	struct dhcpcd_ctx *ctx;
-	int timeout;
 
 	ctx = arg;
 	syslog(LOG_ERR, "timed out");
-	if (!(ctx->options & DHCPCD_IPV4) ||
-	    !(ctx->options & DHCPCD_TIMEOUT_IPV4LL))
-	{
-		if (ctx->options & DHCPCD_MASTER) {
-			/* We've timed out, so remove the waitip requirements.
-			 * If the user doesn't like this they can always set
-			 * an infinite timeout. */
-			ctx->options &=
-			    ~(DHCPCD_WAITIP | DHCPCD_WAITIP4 | DHCPCD_WAITIP6);
-			dhcpcd_daemonise(ctx);
-		} else
-			eloop_exit(ctx->eloop, EXIT_FAILURE);
+	if (!(ctx->options & DHCPCD_MASTER)) {
+		eloop_exit(ctx->eloop, EXIT_FAILURE);
 		return;
 	}
-	ctx->options &= ~DHCPCD_TIMEOUT_IPV4LL;
-	timeout = (PROBE_NUM * PROBE_MAX) + (PROBE_WAIT * 2) + DHCP_MAX_DELAY;
-	syslog(LOG_WARNING, "allowing %d seconds for IPv4LL timeout", timeout);
-	eloop_timeout_add_sec(ctx->eloop, timeout, handle_exit_timeout, ctx);
+	ctx->options |= DHCPCD_NOWAITIP;
+	dhcpcd_daemonise(ctx);
 }
 
 int
@@ -260,7 +247,7 @@ dhcpcd_daemonise(struct dhcpcd_ctx *ctx)
 	int sidpipe[2], fd;
 
 	if (ctx->options & DHCPCD_DAEMONISE &&
-	    !(ctx->options & DHCPCD_DAEMONISED))
+	    !(ctx->options & (DHCPCD_DAEMONISED | DHCPCD_NOWAITIP)))
 	{
 		if (!dhcpcd_ipwaited(ctx))
 			return 0;
@@ -329,6 +316,7 @@ stop_interface(struct interface *ifp)
 	dhcp6_drop(ifp, NULL);
 	ipv6nd_drop(ifp);
 	dhcp_drop(ifp, "STOP");
+	arp_close(ifp);
 	eloop_timeout_delete(ctx->eloop, NULL, ifp);
 	if (ifp->options->options & DHCPCD_DEPARTED)
 		script_runreason(ifp, "DEPARTED");
@@ -371,14 +359,20 @@ configure_interface1(struct interface *i
 	if (ifo->metric != -1)
 		ifp->metric = (unsigned int)ifo->metric;
 
+	if (!(ifo->options & DHCPCD_IPV4))
+		ifo->options &= ~(DHCPCD_DHCP | DHCPCD_IPV4LL);
+
 	if (!(ifo->options & DHCPCD_IPV6))
-		ifo->options &= ~DHCPCD_IPV6RS;
+		ifo->options &= ~(DHCPCD_IPV6RS | DHCPCD_DHCP6);
 
 	if (ifo->options & DHCPCD_SLAACPRIVATE)
 		ifo->options |= DHCPCD_IPV6RA_OWN;
 
 	/* We want to disable kernel interface RA as early as possible. */
 	if (ifo->options & DHCPCD_IPV6RS) {
+		/* If not doing any DHCP, disable the RDNSS requirement. */
+		if (!(ifo->options & (DHCPCD_DHCP | DHCPCD_DHCP6)))
+			ifo->options &= ~DHCPCD_IPV6RA_REQRDNSS;
 		ra_global = if_checkipv6(ifp->ctx, NULL,
 		    ifp->ctx->options & DHCPCD_IPV6RA_OWN ? 1 : 0);
 		ra_iface = if_checkipv6(ifp->ctx, ifp,
@@ -574,6 +568,7 @@ dhcpcd_handlecarrier(struct dhcpcd_ctx *
 			 * do nothing. */
 			ipv6_free_ll_callbacks(ifp);
 			dhcp_drop(ifp, "EXPIRE");
+			arp_close(ifp);
 		}
 	} else if (carrier == LINK_UP && ifp->flags & IFF_UP) {
 		if (ifp->carrier != LINK_UP) {
@@ -1706,8 +1701,6 @@ main(int argc, char **argv)
 			if (dhcpcd_daemonise(&ctx))
 				goto exit_success;
 		} else if (t > 0) {
-			if (ctx.options & DHCPCD_IPV4LL)
-				ctx.options |= DHCPCD_TIMEOUT_IPV4LL;
 			eloop_timeout_add_sec(ctx.eloop, t,
 			    handle_exit_timeout, &ctx);
 		}
Index: src/external/bsd/dhcpcd/dist/dhcpcd.conf.5.in
diff -u src/external/bsd/dhcpcd/dist/dhcpcd.conf.5.in:1.13 src/external/bsd/dhcpcd/dist/dhcpcd.conf.5.in:1.14
--- src/external/bsd/dhcpcd/dist/dhcpcd.conf.5.in:1.13	Fri Oct 17 23:42:24 2014
+++ src/external/bsd/dhcpcd/dist/dhcpcd.conf.5.in	Wed Oct 29 01:08:31 2014
@@ -1,4 +1,4 @@
-.\"     $NetBSD: dhcpcd.conf.5.in,v 1.13 2014/10/17 23:42:24 roy Exp $
+.\"     $NetBSD: dhcpcd.conf.5.in,v 1.14 2014/10/29 01:08:31 roy Exp $
 .\" Copyright (c) 2006-2014 Roy Marples
 .\" All rights reserved
 .\"
@@ -456,7 +456,8 @@ Suppress any dhcpcd output to the consol
 .It Ic reboot Ar seconds
 Allow
 .Ar reboot
-seconds before moving to the DISCOVER phase if we have an old lease to use.
+seconds before moving to the DISCOVER phase if we have an old lease to use
+and moving from DISCOVER to IPv4LL if no reply.
 The default is 5 seconds.
 A setting of 0 seconds causes
 .Nm dhcpcd

Index: src/external/bsd/dhcpcd/dist/dhcpcd.conf
diff -u src/external/bsd/dhcpcd/dist/dhcpcd.conf:1.12 src/external/bsd/dhcpcd/dist/dhcpcd.conf:1.13
--- src/external/bsd/dhcpcd/dist/dhcpcd.conf:1.12	Fri Oct 17 23:42:24 2014
+++ src/external/bsd/dhcpcd/dist/dhcpcd.conf	Wed Oct 29 01:08:31 2014
@@ -1,4 +1,4 @@
-# $NetBSD: dhcpcd.conf,v 1.12 2014/10/17 23:42:24 roy Exp $
+# $NetBSD: dhcpcd.conf,v 1.13 2014/10/29 01:08:31 roy Exp $
 
 # A sample configuration for dhcpcd.
 # See dhcpcd.conf(5) for details.
Index: src/external/bsd/dhcpcd/dist/if-bsd.c
diff -u src/external/bsd/dhcpcd/dist/if-bsd.c:1.12 src/external/bsd/dhcpcd/dist/if-bsd.c:1.13
--- src/external/bsd/dhcpcd/dist/if-bsd.c:1.12	Fri Oct 17 23:42:24 2014
+++ src/external/bsd/dhcpcd/dist/if-bsd.c	Wed Oct 29 01:08:31 2014
@@ -1,5 +1,5 @@
 #include <sys/cdefs.h>
- __RCSID("$NetBSD: if-bsd.c,v 1.12 2014/10/17 23:42:24 roy Exp $");
+ __RCSID("$NetBSD: if-bsd.c,v 1.13 2014/10/29 01:08:31 roy Exp $");
 
 /*
  * dhcpcd - DHCP client daemon

Index: src/external/bsd/dhcpcd/dist/if-options.c
diff -u src/external/bsd/dhcpcd/dist/if-options.c:1.14 src/external/bsd/dhcpcd/dist/if-options.c:1.15
--- src/external/bsd/dhcpcd/dist/if-options.c:1.14	Fri Oct 17 23:42:24 2014
+++ src/external/bsd/dhcpcd/dist/if-options.c	Wed Oct 29 01:08:31 2014
@@ -1,5 +1,5 @@
 #include <sys/cdefs.h>
- __RCSID("$NetBSD: if-options.c,v 1.14 2014/10/17 23:42:24 roy Exp $");
+ __RCSID("$NetBSD: if-options.c,v 1.15 2014/10/29 01:08:31 roy Exp $");
 
 /*
  * dhcpcd - DHCP client daemon
Index: src/external/bsd/dhcpcd/dist/ipv6nd.c
diff -u src/external/bsd/dhcpcd/dist/ipv6nd.c:1.14 src/external/bsd/dhcpcd/dist/ipv6nd.c:1.15
--- src/external/bsd/dhcpcd/dist/ipv6nd.c:1.14	Fri Oct 17 23:42:24 2014
+++ src/external/bsd/dhcpcd/dist/ipv6nd.c	Wed Oct 29 01:08:31 2014
@@ -1,5 +1,5 @@
 #include <sys/cdefs.h>
- __RCSID("$NetBSD: ipv6nd.c,v 1.14 2014/10/17 23:42:24 roy Exp $");
+ __RCSID("$NetBSD: ipv6nd.c,v 1.15 2014/10/29 01:08:31 roy Exp $");
 
 /*
  * dhcpcd - DHCP client daemon
@@ -1610,7 +1610,7 @@ ipv6nd_startrs(struct interface *ifp)
 	    MAX_RTR_SOLICITATION_DELAY * 1000000);
 	timernorm(&tv);
 	syslog(LOG_DEBUG,
-	    "%s: delaying IPv6 router solictation for %0.1f seconds",
+	    "%s: delaying IPv6 router solicitation for %0.1f seconds",
 	    ifp->name, timeval_to_double(&tv));
 	eloop_timeout_add_tv(ifp->ctx->eloop, &tv, ipv6nd_startrs1, ifp);
 	return;

Index: src/external/bsd/dhcpcd/dist/script.c
diff -u src/external/bsd/dhcpcd/dist/script.c:1.11 src/external/bsd/dhcpcd/dist/script.c:1.12
--- src/external/bsd/dhcpcd/dist/script.c:1.11	Fri Oct 17 23:42:24 2014
+++ src/external/bsd/dhcpcd/dist/script.c	Wed Oct 29 01:08:31 2014
@@ -1,5 +1,5 @@
 #include <sys/cdefs.h>
- __RCSID("$NetBSD: script.c,v 1.11 2014/10/17 23:42:24 roy Exp $");
+ __RCSID("$NetBSD: script.c,v 1.12 2014/10/29 01:08:31 roy Exp $");
 
 /*
  * dhcpcd - DHCP client daemon
@@ -338,7 +338,11 @@ make_env(const struct interface *ifp, co
 		}
 	}
 	*--p = '\0';
-	if (strcmp(reason, "TEST") == 0) {
+	if (strcmp(reason, "TEST") == 0 ||
+	    strcmp(reason, "PREINIT") == 0 ||
+	    strcmp(reason, "CARRIER") == 0 ||
+	    strcmp(reason, "UNKNOWN") == 0)
+	{
 		env[9] = strdup("if_up=false");
 		env[10] = strdup("if_down=false");
 	} else if (1 == 2 /* appease ifdefs */

Reply via email to