Project import
diff --git a/dhcpcd-6.8.2/Android.mk b/dhcpcd-6.8.2/Android.mk
new file mode 100644
index 0000000..2a41dd5
--- /dev/null
+++ b/dhcpcd-6.8.2/Android.mk
@@ -0,0 +1,87 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# dhcpcd-6.8.2 is D-Bus enabled and compatible with Brillo daemons. dhcpcd
+# is the standard version of this daemon used in Android.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := dhcpcd-6.8.2
+LOCAL_SRC_FILES := \
+    common.c \
+    control.c \
+    dhcpcd.c \
+    duid.c \
+    eloop.c \
+    if.c \
+    if-options.c \
+    dhcp-common.c \
+    auth.c \
+    if-linux.c \
+    if-linux-wext.c \
+    arp.c \
+    dhcp.c \
+    ipv4.c \
+    ipv4ll.c \
+    script-stub.c \
+    ifaddrs.c \
+    crypt/md5.c \
+    crypt/hmac_md5.c \
+    compat/closefrom.c \
+    compat/strtoi.c \
+    dhcpcd-embedded.c \
+    compat/posix_spawn.c
+
+# Always support IPv4.
+LOCAL_CFLAGS += -DINET
+
+LOCAL_CFLAGS += -D_BSD_SOURCE
+
+ifeq ($(DHCPCD_USE_IPV6), yes)
+LOCAL_SRC_FILES += ipv6.c ipv6nd.c dhcp6.c
+LOCAL_SRC_FILES += crypt/sha256.c
+LOCAL_C_INCLUDES += $(LOCAL_PATH)/crypt
+LOCAL_CFLAGS += -DINET6
+endif
+
+ifeq ($(DHCPCD_USE_DBUS), yes)
+LOCAL_SRC_FILES += dbus/dbus-dict.c dbus/rpc-dbus.c
+LOCAL_CFLAGS += -DCONFIG_DBUS -DPASSIVE_MODE
+LOCAL_SHARED_LIBRARIES += libdbus
+else
+LOCAL_SRC_FILES += rpc-stub.c
+endif
+
+# Compiler complains about implicit function delcarations in dhcpcd.c,
+# if-options.c, dhcp-common.c, and crypt/sha256.c.
+LOCAL_CFLAGS += -Wno-implicit-function-declaration
+# Compiler complains about signed-unsigned comparison in dhcp-common.c.
+LOCAL_CFLAGS += -Wno-sign-compare
+# Compiler complains about unused parameters in function stubs in rpc-stub.c.
+LOCAL_CFLAGS += -Wno-unused-parameter
+# Compiler complains about possibly uninitialized variables in rpc-dbus.c.
+LOCAL_CFLAGS += -Wno-maybe-uninitialized
+
+LOCAL_SHARED_LIBRARIES += libc libcutils libnetutils
+include $(BUILD_EXECUTABLE)
+
+# Each build target using dhcpcd-6.8.2 should define its own source
+# and destination for its dhcpcd.conf file.
+# include $(CLEAR_VARS)
+# LOCAL_MODULE := dhcpcd-6.8.2.conf
+# LOCAL_MODULE_CLASS := ETC
+# LOCAL_MODULE_PATH := $(TARGET_OUT)/etc/dhcpcd-6.8.2
+# LOCAL_SRC_FILES := android.conf
+# include $(BUILD_PREBUILT)
diff --git a/dhcpcd-6.8.2/GNUmakefile b/dhcpcd-6.8.2/GNUmakefile
new file mode 100644
index 0000000..5565294
--- /dev/null
+++ b/dhcpcd-6.8.2/GNUmakefile
@@ -0,0 +1,12 @@
+# GNU Make does not automagically include .depend
+# Luckily it does read GNUmakefile over Makefile so we can work around it
+
+# Nasty hack so that make clean works without configure being run
+TOP?=		.
+CONFIG_MK?=	$(shell test -e ${TOP}/config.mk && \
+		    echo config.mk || echo config-null.mk)
+
+include Makefile
+ifneq ($(wildcard .depend), )
+include .depend
+endif
diff --git a/dhcpcd-6.8.2/MODULE_LICENSE_BSD_LIKE b/dhcpcd-6.8.2/MODULE_LICENSE_BSD_LIKE
new file mode 100644
index 0000000..3c10a83
--- /dev/null
+++ b/dhcpcd-6.8.2/MODULE_LICENSE_BSD_LIKE
@@ -0,0 +1 @@
+~EMPTY~
diff --git a/dhcpcd-6.8.2/Makefile b/dhcpcd-6.8.2/Makefile
new file mode 100644
index 0000000..d016c4b
--- /dev/null
+++ b/dhcpcd-6.8.2/Makefile
@@ -0,0 +1,216 @@
+# dhcpcd Makefile
+
+PROG=		dhcpcd
+SRCS=		common.c control.c dhcpcd.c duid.c eloop.c
+SRCS+=		if.c if-options.c
+SRCS+=		dhcp-common.c
+PKG_CONFIG ?= pkg-config
+
+CFLAGS?=	-O2
+MKDIRS=
+
+TOP?=		.
+include ${TOP}/iconfig.mk
+
+CSTD?=		c99
+CFLAGS+=	-std=${CSTD}
+
+SRCS+=		${DHCPCD_SRCS}
+
+SRCS+=		auth.c
+CPPFLAGS+=	-I./crypt
+CRYPT_SRCS=	crypt/hmac_md5.c ${MD5_SRC} ${SHA256_SRC}
+
+OBJS+=		${SRCS:.c=.o} ${COMPAT_SRCS:.c=.o} ${CRYPT_SRCS:.c=.o}
+
+SCRIPT=		${LIBEXECDIR}/dhcpcd-run-hooks
+HOOKDIR=	${LIBEXECDIR}/dhcpcd-hooks
+
+MAN5=		dhcpcd.conf.5
+MAN8=		dhcpcd.8 dhcpcd-run-hooks.8
+CLEANFILES=	dhcpcd.conf.5 dhcpcd.8 dhcpcd-run-hooks.8
+
+SCRIPTS=	dhcpcd-run-hooks
+
+FILES=		dhcpcd.conf
+
+ifeq ($(DBUS_SUPPORT),yes)
+FILES+= 	dbus/dhcpcd-dbus.conf
+
+_DBUSCFLAGS_SH= $(PKG_CONFIG) --cflags dbus-1
+_DBUSCFLAGS!= ${_DBUSCFLAGS_SH}
+DBUSCFLAGS= ${_DBUSCFLAGS}$(shell ${_DBUSCFLAGS_SH})
+
+_DBUSLIBS_SH= $(PKG_CONFIG) --libs dbus-1
+_DBUSLIBS!= ${_DBUSLIBS_SH}
+DBUSLIBS= ${_DBUSLIBS}$(shell ${_DBUSLIBS_SH})
+DBUSDIR= ${SYSCONFDIR}/dbus-1/system.d
+
+CFLAGS+= ${DBUSCFLAGS}
+LDADD+= ${DBUSLIBS}
+endif
+
+# Linux needs librt
+_LIBRT_SH=	[ "$$(uname -s)" = "Linux" ] && echo "-lrt" || echo ""
+_LIBRT!= 	${_LIBRT_SH}
+LIBRT?=		${_LIBRT} $(shell ${_LIBRT_SH})
+LDADD+=		${LIBRT}
+
+SCRIPTSDIR=	${LIBEXECDIR}
+CLEANFILES+=	dhcpcd-run-hooks
+
+FILESDIR=	${SYSCONFDIR}
+
+SUBDIRS=	${MKDIRS}
+
+ifeq ($(HOOK_SUPPORT),yes)
+SUBDIRS+= 	dhcpcd-hooks
+endif
+
+SED_RUNDIR=		-e 's:@RUNDIR@:${RUNDIR}:g'
+SED_DBDIR=		-e 's:@DBDIR@:${DBDIR}:g'
+SED_LIBDIR=		-e 's:@LIBDIR@:${LIBDIR}:g'
+SED_HOOKDIR=		-e 's:@HOOKDIR@:${HOOKDIR}:g'
+SED_SERVICEEXISTS=	-e 's:@SERVICEEXISTS@:${SERVICEEXISTS}:g'
+SED_SERVICECMD=		-e 's:@SERVICECMD@:${SERVICECMD}:g'
+SED_SERVICESTATUS=	-e 's:@SERVICESTATUS@:${SERVICESTATUS}:g'
+SED_SCRIPT=		-e 's:@SCRIPT@:${SCRIPT}:g'
+SED_SYS=		-e 's:@SYSCONFDIR@:${SYSCONFDIR}:g'
+
+DEPEND!=	test -e .depend && echo ".depend" || echo ""
+VERSION!=	sed -n 's/\#define VERSION[[:space:]]*"\(.*\)".*/\1/p' defs.h
+
+FOSSILID?=	current
+
+DISTPREFIX?=	${PROG}-${VERSION}
+DISTFILEGZ?=	${DISTPREFIX}.tar.gz
+DISTFILE?=	${DISTPREFIX}.tar.bz2
+
+HOST_SH?=	/bin/sh
+
+CLEANFILES+=	*.tar.bz2
+
+.PHONY:		import import-bsd dev test
+
+.SUFFIXES:	.in
+
+.in:
+	${SED} ${SED_RUNDIR} ${SED_DBDIR} ${SED_LIBDIR} ${SED_HOOKDIR} \
+		${SED_SYS} ${SED_SCRIPT} \
+		${SED_SERVICEEXISTS} ${SED_SERVICECMD} ${SED_SERVICESTATUS} \
+		$< > $@
+
+all: config.h ${PROG} ${SCRIPTS} ${MAN5} ${MAN8} ${FILES}
+	for x in ${SUBDIRS}; do cd $$x; ${MAKE} $@; cd ..; done
+
+dev:
+	cd dev && ${MAKE}
+
+.c.o:
+	${CC} ${CFLAGS} ${CPPFLAGS} -c $< -o $@
+
+CLEANFILES+=	dhcpcd-embedded.h dhcpcd-embedded.c
+
+dhcpcd-embedded.h: genembedh dhcpcd-definitions.conf dhcpcd-embedded.h.in
+	${HOST_SH} ${.ALLSRC} $^ > $@
+
+dhcpcd-embedded.c: genembedc dhcpcd-definitions.conf
+	${HOST_SH} ${.ALLSRC} $^ > $@
+
+if-options.c: dhcpcd-embedded.h
+
+.depend: ${SRCS} ${COMPAT_SRCS} ${CRYPT_SRCS}
+	${CC} ${CPPFLAGS} -MM ${SRCS} ${COMPAT_SRCS} ${CRYPT_SRCS} > .depend
+
+depend: .depend
+
+${PROG}: ${DEPEND} ${OBJS}
+	${CC} ${LDFLAGS} -o $@ ${OBJS} ${LDADD}
+
+test:
+	cd $@; ${MAKE} $@; ./$@
+
+_embeddedinstall: dhcpcd-definitions.conf
+	${INSTALL} -d ${DESTDIR}${SCRIPTSDIR}
+	${INSTALL} -m ${CONFMODE} dhcpcd-definitions.conf ${DESTDIR}${SCRIPTSDIR}
+
+_proginstall: ${PROG}
+	${INSTALL} -d ${DESTDIR}${SBINDIR}
+	${INSTALL} -m ${BINMODE} ${PROG} ${DESTDIR}${SBINDIR}
+	${INSTALL} -d ${DESTDIR}${DBDIR}
+
+_scriptsinstall: ${SCRIPTS}
+	${INSTALL} -d ${DESTDIR}${SCRIPTSDIR}
+	${INSTALL} -m ${BINMODE} ${SCRIPTS} ${DESTDIR}${SCRIPTSDIR}
+
+proginstall: _proginstall ${SCRIPTSINSTALL} ${EMBEDDEDINSTALL}
+	for x in ${SUBDIRS}; do cd $$x; ${MAKE} $@; cd ..; done
+
+_maninstall: ${MAN5} ${MAN8}
+	${INSTALL} -d ${DESTDIR}${MANDIR}/man5
+	${INSTALL} -m ${MANMODE} ${MAN5} ${DESTDIR}${MANDIR}/man5
+	${INSTALL} -d ${DESTDIR}${MANDIR}/man8
+	${INSTALL} -m ${MANMODE} ${MAN8} ${DESTDIR}${MANDIR}/man8
+
+_dbusinstall: dbus/dhcpcd-dbus.conf
+	${INSTALL} -d ${DESTDIR}${DBUSDIR}
+	${INSTALL} -m ${CONFMODE} dbus/dhcpcd-dbus.conf \
+		${DESTDIR}${DBUSDIR}/dhcpcd.conf
+
+_confinstall: ${DBUSINSTALL}
+	${INSTALL} -d ${DESTDIR}${SYSCONFDIR}
+	test -e ${DESTDIR}${SYSCONFDIR}/dhcpcd.conf || \
+		${INSTALL} -m ${CONFMODE} dhcpcd.conf ${DESTDIR}${SYSCONFDIR}
+
+install: proginstall _confinstall
+
+clean:
+	rm -f ${OBJS} ${PROG} ${PROG}.core ${CLEANFILES}
+	for x in ${SUBDIRS} test; do cd $$x; ${MAKE} $@; cd ..; done
+
+distclean: clean
+	rm -f .depend config.h config.mk config.log
+
+dist:
+	fossil tarball --name ${DISTPREFIX} ${FOSSILID} ${DISTFILEGZ}
+	gunzip -c ${DISTFILEGZ} |  bzip2 >${DISTFILE}
+	rm ${DISTFILEGZ}
+
+snapshot:
+	rm -rf /tmp/${DISTPREFIX}
+	${INSTALL} -d /tmp/${DISTPREFIX}
+	cp -RPp * /tmp/${DISTPREFIX}
+	cd /tmp/${DISTPREFIX} && ${MAKE} distclean
+	cd /tmp && tar -cvjpf ${DISTFILE} ${DISTPREFIX}
+	mv /tmp/${DISTFILE} .
+	ls -l ${DISTFILE}
+
+import: ${SRCS}
+	rm -rf /tmp/${DISTPREFIX}
+	${INSTALL} -d /tmp/${DISTPREFIX}
+	cp ${SRCS} dhcpcd.conf dhcpcd-definitions.conf *.in /tmp/${DISTPREFIX}
+	cp $$(${CC} ${CPPFLAGS} -DDEPGEN -MM ${SRCS} | \
+		sed -e 's/^.*\.c //g' -e 's/.*\.c$$//g' -e 's/\\//g' | \
+		tr ' ' '\n' | \
+		sed -e '/^compat\//d' | \
+		sed -e '/^crypt\//d' | \
+		sort -u) /tmp/${DISTPREFIX}; \
+	if test -n "${CRYPT_SRCS}"; then \
+		${INSTALL} -d /tmp/${DISTPREFIX}/crypt; \
+		cp ${CRYPT_SRCS} /tmp/${DISTPREFIX}/crypt; \
+		cp $$(${CC} ${CPPFLAGS} -DDEPGEN -MM ${CRYPT_SRCS} | \
+			sed -e 's/^.*c //g' -e 's/.*\.c$$//g' -e 's/\\//g' | \
+			tr ' ' '\n' | sed -e '/\/\.\.\//d'  | \
+			sort -u) /tmp/${DISTPREFIX}/crypt; \
+	fi;
+	if test -n "${COMPAT_SRCS}"; then \
+		${INSTALL} -d /tmp/${DISTPREFIX}/compat; \
+		cp ${COMPAT_SRCS} /tmp/${DISTPREFIX}/compat; \
+		cp $$(${CC} ${CPPFLAGS} -DDEPGEN -MM ${COMPAT_SRCS} | \
+			sed -e 's/^.*c //g' -e 's/.*\.c$$//g' -e 's/\\//g' | \
+			tr ' ' '\n' | \
+			sort -u) /tmp/${DISTPREFIX}/compat; \
+	fi;
+	cd dhcpcd-hooks; ${MAKE} DISTPREFIX=${DISTPREFIX} $@
+
+include Makefile.inc
diff --git a/dhcpcd-6.8.2/Makefile.inc b/dhcpcd-6.8.2/Makefile.inc
new file mode 100644
index 0000000..22151ab
--- /dev/null
+++ b/dhcpcd-6.8.2/Makefile.inc
@@ -0,0 +1,12 @@
+# System definitions
+
+PICFLAG?=	-fPIC
+
+BINMODE?=	0555
+NONBINMODE?=	0444
+MANMODE?=	${NONBINMODE}
+CONFMODE?=	0644
+
+CC?=		cc
+INSTALL?=	install
+SED?=		sed
diff --git a/dhcpcd-6.8.2/NOTICE b/dhcpcd-6.8.2/NOTICE
new file mode 100644
index 0000000..98438b9
--- /dev/null
+++ b/dhcpcd-6.8.2/NOTICE
@@ -0,0 +1,136 @@
+dhcpcd - DHCP client daemon
+Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
+All rights reserved
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+
+
+dhcp_bpf_filter taken from bpf.c in dhcp-3.1.0
+
+Copyright (c) 2004,2007 by Internet Systems Consortium, Inc. ("ISC")
+Copyright (c) 1996-2003 by Internet Software Consortium
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+Internet Systems Consortium, Inc.
+950 Charter Street
+Redwood City, CA 94063
+<info@isc.org>
+http://www.isc.org/
+
+
+
+$NetBSD: queue.h,v 1.65 2013/12/25 17:19:34 christos Exp $
+
+Copyright (c) 1991, 1993
+The Regents of the University of California.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. Neither the name of the University nor the names of its contributors
+   may be used to endorse or promote products derived from this software
+   without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+@(#)queue.h     8.5 (Berkeley) 8/20/94
+
+
+
+compat/arc4random_uniform.c, compat/arc4random_uniform.h
+Copyright (c) 2008, Damien Miller <djm@openbsd.org>
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+
+
+Arc4 random number generator for OpenBSD.
+Copyright 1996 David Mazieres <dm@lcs.mit.edu>.
+
+Modification and redistribution in source and binary forms is
+permitted provided that due credit is given to the author and the
+OpenBSD project by leaving this copyright notice intact.
+
+
+
+crypt/sha256.c, crypt/sha256.h
+Copyright 2005 Colin Percival
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
diff --git a/dhcpcd-6.8.2/README b/dhcpcd-6.8.2/README
new file mode 100644
index 0000000..17c1c5e
--- /dev/null
+++ b/dhcpcd-6.8.2/README
@@ -0,0 +1,149 @@
+dhcpcd - DHCP client daemon
+Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
+
+
+Installation
+------------
+./configure; make; make install
+man dhcpcd for command line options
+man dhcpcd.conf for configuration options
+man dhcpcd-run-hooks to learn how to hook scripts into dhcpcd events
+
+
+Notes
+-----
+If you're cross compiling you may need set the platform if OS is different
+from the host.
+--target=sparc-sun-netbsd5.0
+
+If you're building for an MMU-less system where fork() does not work, you
+should ./configure --disable-fork.
+This also puts the --no-background flag on and stops the --background flag
+from working.
+
+You can change the default dirs with these knobs.
+For example, to satisfy FHS compliance you would do this:-
+./configure --libexecdir=/lib/dhcpcd dbdir=/var/lib/dhcpcd
+
+We now default to using -std=c99. For 64-bit linux, this always works, but
+for 32-bit linux it requires either gnu99 or a patch to asm/types.h.
+Most distros patch linux headers so this should work fine.
+linux-2.6.24 finally ships with a working 32-bit header.
+If your linux headers are older, or your distro hasn't patched them you can
+set CSTD=gnu99 to work around this.
+
+Some BSD systems do not allow the manipulation of automatically added subnet
+routes. You can find discussion here:
+    http://mail-index.netbsd.org/tech-net/2008/12/03/msg000896.html
+BSD systems where this has been fixed or is known to work are:
+    NetBSD-5.0
+    FreeBSD-10.0
+
+Some BSD systems protect against IPv6 NS/NA messages by ensuring that the
+source address matches a prefix on the recieved by a RA message.
+This is an error as the correct check is for on-link prefixes as the
+kernel may not be handling RA itself.
+BSD systems where this has been fixed or is known to work are:
+    NetBSD-7.0
+    OpenBSD-5.0
+    patch submitted against FreeBSD-10.0
+
+Some BSD systems do not announce IPv6 address flag changes, such as
+IN6_IFF_TENTATIVE, IN6_IFF_DUPLICATED, etc. On these systems,
+dhcpcd will poll a freshly added address until either IN6_IFF_TENTATIVE is
+cleared or IN6_IFF_DUPLICATED is set and take action accordingly.
+BSD systems where this has been fixed or is known to work are:
+    NetBSD-7.0
+
+Some BSD systems do not announce cached neighbour route changes based
+on reachability to userland. For such systems, IPv6 routers will always
+be assumed to be reachable until they either stop being a router or expire.
+BSD systems where this has been fixed or is known to work are:
+    NetBSD-7.99.3
+
+Linux prior to 3.17 won't allow userland to manage IPv6 temporary addresses.
+Either upgrade or don't allow dhcpcd to manage the RA,
+so don't set either "ipv6ra_own" or "slaac private" in dhcpcd.conf if you
+want to have working IPv6 temporary addresses.
+SLAAC private addresses are just as private, just stable.
+
+ArchLinux presently sanitises all kernel headers to the latest version
+regardless of the version for your CPU. As such, Arch presently ships a
+3.12 kernel with 3.17 headers which claim that it suppors temporary address
+management and no automatic prefix route generation, both of which are
+obviously false. You will have to patch support either in the kernel or
+out of the headers (or dhcpcd itself) to have correct operation.
+
+We try and detect how dhcpcd should interact with system services at runtime.
+If we cannot auto-detect how do to this, or it is wrong then
+you can change this by passing shell commands to --serviceexists,
+--servicecmd and optionally --servicestatus to ./configure or overriding
+the service variables in a hook.
+
+Some systems have /dev management systems and some of these like to rename
+interfaces. As this system would listen in the same way as dhcpcd to new
+interface arrivals, dhcpcd needs to listen to the /dev management sytem
+instead of the kernel. However, if the /dev management system breaks, stops
+working, or changes to a new one, dhcpcd should still try and continue to work.
+To facilitate this, dhcpcd allows a plugin to load to instruct dhcpcd when it
+can use an interface. As of the time of writing only udev support is included.
+You can disable this with --without-dev, or without-udev
+
+To shrink dhcpcd you can disable IPv4 or IPv6:
+	--disable-inet
+	--disable-inet6
+
+You can also move the embedded extended configuration from the dhcpcd binary
+to an external file (LIBEXECDIR/dhcpcd-definitions.conf)
+	--disable-embedded
+If dhcpcd cannot load this file at runtime, dhcpcd will work but will not be
+able to decode any DHCP/DHCPv6 options that are not defined by the user
+in /etc/dhcpcd.conf.
+
+To prepare dhcpcd for import into a platform source tree (like NetBSD)
+you can use the make import target to create /tmp/dhcpcd-$version and
+populate it with all the source files and hooks needed.
+In this instance, you may wish to disable some configured tests when
+the binary has to run on older versions which lack support, such as getline.
+./configure --without-getline
+
+Building for distribution (ie making a dhcpcd source tarball) now requires
+gmake-4 or any BSD make.
+
+
+Hooks
+-----
+Not all the hooks in dhcpcd-hooks are installed by default.
+By default we install 01-test, 02-dump, 10-mtu, 10-wpa_supplicant,
+15-timezone, 20-resolv.conf, 29-lookup-hostname and 30-hostname.
+The default dhcpcd.conf disables the lookup-hostname hook by default.
+The configure program attempts to find hooks for systems you have installed.
+To add more simply
+./configure -with-hook=ntp.conf
+
+Some system services expose the name of the service we are in,
+by default dhcpcd will pick RC_SVCNAME from the environment.
+You can override this in CPPFLAGS+= -DRC_SVCNAME="YOUR_SVCNAME".
+This is important because dhcpcd will scrub the environment aside from $PATH
+before running hooks.
+This variable could be used to facilitate service re-entry so this chain could
+happen in a custom OS hook:
+  dhcpcd service marked inactive && dhcpcd service starts
+  dependant services are not started because dhcpcd is inactive (not stopped)
+  dhcpcd hook tests $if_oneup && $if_ipwaited
+  if true, mark the dhcpcd service as started and then start dependencies
+  if false and the dhcpcd service was previously started, mark as inactive and
+     stop any dependant services.
+
+
+Compatibility
+-------------
+dhcpcd-5.0 is only fully command line compatible with dhcpcd-4.0
+For compatibility with older versions, use dhcpcd-4.0
+
+
+ChangeLog
+---------
+We no longer supply a ChangeLog.
+However, you're more than welcome to read the commit log at
+http://roy.marples.name/projects/dhcpcd/timeline/
diff --git a/dhcpcd-6.8.2/arp.c b/dhcpcd-6.8.2/arp.c
new file mode 100644
index 0000000..1db1e89
--- /dev/null
+++ b/dhcpcd-6.8.2/arp.c
@@ -0,0 +1,433 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
+#include <errno.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define ELOOP_QUEUE 5
+#include "config.h"
+#include "arp.h"
+#include "if.h"
+#include "ipv4.h"
+#include "common.h"
+#include "dhcp.h"
+#include "dhcpcd.h"
+#include "eloop.h"
+#include "if.h"
+#include "if-options.h"
+#include "ipv4ll.h"
+
+#define ARP_LEN								      \
+	(sizeof(struct arphdr) + (2 * sizeof(uint32_t)) + (2 * HWADDR_LEN))
+
+static ssize_t
+arp_request(const struct interface *ifp, in_addr_t sip, in_addr_t tip,
+	    const uint8_t *dest_hw_addr)
+{
+	uint8_t arp_buffer[ARP_LEN];
+	struct arphdr ar;
+	size_t len;
+	uint8_t *p;
+
+	ar.ar_hrd = htons(ifp->family);
+	ar.ar_pro = htons(ETHERTYPE_IP);
+	ar.ar_hln = ifp->hwlen;
+	ar.ar_pln = sizeof(sip);
+	ar.ar_op = htons(ARPOP_REQUEST);
+
+	p = arp_buffer;
+	len = 0;
+
+#define CHECK(fun, b, l)						\
+	do {								\
+		if (len + (l) > sizeof(arp_buffer))			\
+			goto eexit;					\
+		fun(p, (b), (l));					\
+		p += (l);						\
+		len += (l);						\
+	} while (/* CONSTCOND */ 0)
+#define APPEND(b, l)	CHECK(memcpy, b, l)
+#define ZERO(l)		CHECK(memset, 0, l)
+
+	APPEND(&ar, sizeof(ar));
+	APPEND(ifp->hwaddr, ifp->hwlen);
+	APPEND(&sip, sizeof(sip));
+	if (dest_hw_addr)
+		APPEND(dest_hw_addr, ifp->hwlen);
+	else
+		ZERO(ifp->hwlen);
+	APPEND(&tip, sizeof(tip));
+	return if_sendrawpacket(ifp, ETHERTYPE_ARP, arp_buffer, len,
+				dest_hw_addr);
+
+eexit:
+	errno = ENOBUFS;
+	return -1;
+}
+
+void
+arp_report_conflicted(const struct arp_state *astate, const struct arp_msg *amsg)
+{
+
+	if (amsg) {
+		char buf[HWADDR_LEN * 3];
+
+		logger(astate->iface->ctx, 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));
+	} else
+		logger(astate->iface->ctx, LOG_ERR,
+		    "%s: DAD detected %s",
+		    astate->iface->name, inet_ntoa(astate->failed));
+}
+
+static void
+arp_packet(void *arg)
+{
+	struct interface *ifp = arg;
+	const struct interface *ifn;
+	uint8_t arp_buffer[ARP_LEN];
+	struct arphdr ar;
+	struct arp_msg arm;
+	ssize_t bytes;
+	struct dhcp_state *state;
+	struct arp_state *astate, *astaten;
+	unsigned char *hw_s, *hw_t;
+	int flags;
+
+	state = D_STATE(ifp);
+	state->failed.s_addr = 0;
+	flags = 0;
+	while (!(flags & RAW_EOF)) {
+		bytes = if_readrawpacket(ifp, ETHERTYPE_ARP,
+		    arp_buffer, sizeof(arp_buffer), &flags);
+		if (bytes == -1) {
+			logger(ifp->ctx, LOG_ERR,
+			    "%s: arp if_readrawpacket: %m", ifp->name);
+			dhcp_close(ifp);
+			return;
+		}
+		/* We must have a full ARP header */
+		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(arm.sip.s_addr))
+			continue;
+		/* Only these types are recognised */
+		if (ar.ar_op != htons(ARPOP_REPLY) &&
+		    ar.ar_op != htons(ARPOP_REQUEST))
+			continue;
+
+		/* Get pointers to the hardware addreses */
+		hw_s = arp_buffer + sizeof(ar);
+		hw_t = hw_s + ar.ar_hln + ar.ar_pln;
+		/* Ensure we got all the data */
+		if ((hw_t + ar.ar_hln + ar.ar_pln) - arp_buffer > bytes)
+			continue;
+		/* Ignore messages from ourself */
+		TAILQ_FOREACH(ifn, ifp->ctx->ifaces, next) {
+			if (ar.ar_hln == ifn->hwlen &&
+			    memcmp(hw_s, ifn->hwaddr, ifn->hwlen) == 0)
+				break;
+		}
+		if (ifn)
+			continue;
+		/* 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);
+		}
+	}
+}
+
+static void
+arp_open(struct interface *ifp)
+{
+	struct dhcp_state *state;
+
+	state = D_STATE(ifp);
+	if (state->arp_fd == -1) {
+		state->arp_fd = if_openrawsocket(ifp, ETHERTYPE_ARP);
+		if (state->arp_fd == -1) {
+			logger(ifp->ctx, LOG_ERR, "%s: %s: %m",
+			    __func__, ifp->name);
+			return;
+		}
+		eloop_event_add(ifp->ctx->eloop, state->arp_fd,
+		    arp_packet, ifp, NULL, NULL);
+	}
+}
+
+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)
+		logger(ifp->ctx, LOG_DEBUG,
+		    "%s: ARP announcing %s (%d of %d), "
+		    "next in %d.0 seconds",
+		    ifp->name, inet_ntoa(astate->addr),
+		    astate->claims, ANNOUNCE_NUM, ANNOUNCE_WAIT);
+	else
+		logger(ifp->ctx, LOG_DEBUG,
+		    "%s: ARP announcing %s (%d of %d)",
+		    ifp->name, inet_ntoa(astate->addr),
+		    astate->claims, ANNOUNCE_NUM);
+	if (arp_request(ifp, astate->addr.s_addr, astate->addr.s_addr,
+			NULL) == -1)
+		logger(ifp->ctx, LOG_ERR, "send_arp: %m");
+	eloop_timeout_add_sec(ifp->ctx->eloop, ANNOUNCE_WAIT,
+	    astate->claims < ANNOUNCE_NUM ? arp_announce1 : arp_announced,
+	    astate);
+}
+
+void
+arp_announce(struct arp_state *astate)
+{
+
+	arp_open(astate->iface);
+	astate->claims = 0;
+	arp_announce1(astate);
+}
+
+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 timespec tv;
+	uint8_t *dest_hwaddr = NULL;
+
+	if (++astate->probes < PROBE_NUM) {
+		tv.tv_sec = PROBE_MIN;
+		tv.tv_nsec = (suseconds_t)arc4random_uniform(
+		    (PROBE_MAX - PROBE_MIN) * NSEC_PER_SEC);
+		timespecnorm(&tv);
+		eloop_timeout_add_tv(ifp->ctx->eloop, &tv, arp_probe1, astate);
+	} else {
+		tv.tv_sec = ANNOUNCE_WAIT;
+		tv.tv_nsec = 0;
+		eloop_timeout_add_tv(ifp->ctx->eloop, &tv, arp_probed, astate);
+	}
+	logger(ifp->ctx, LOG_INFO,
+	    "%s: ARP probing %s (%d of %d), next in %0.1f seconds",
+	    ifp->name, inet_ntoa(astate->addr),
+	    astate->probes ? astate->probes : PROBE_NUM, PROBE_NUM,
+	    timespec_to_double(&tv));
+	if (astate->dest_hwlen == ifp->hwlen)
+		dest_hwaddr = astate->dest_hwaddr;
+	if (arp_request(ifp, astate->src_addr.s_addr,
+			astate->addr.s_addr, dest_hwaddr) == -1)
+		logger(ifp->ctx, LOG_ERR, "send_arp: %m");
+}
+
+void
+arp_probe(struct arp_state *astate)
+{
+
+	arp_open(astate->iface);
+	astate->probes = 0;
+	logger(astate->iface->ctx, LOG_DEBUG, "%s: probing for %s",
+	    astate->iface->name, inet_ntoa(astate->addr));
+	arp_probe1(astate);
+}
+
+static struct arp_state *
+arp_find(struct interface *ifp, const struct in_addr *addr)
+{
+	struct arp_state *astate;
+	struct dhcp_state *state;
+
+	state = D_STATE(ifp);
+	TAILQ_FOREACH(astate, &state->arp_states, next) {
+		if (astate->addr.s_addr == addr->s_addr && astate->iface == ifp)
+			return astate;
+	}
+	errno = ESRCH;
+	return NULL;
+}
+
+struct arp_state *
+arp_new(struct interface *ifp, const struct in_addr *addr)
+{
+	struct arp_state *astate;
+	struct dhcp_state *state;
+
+	if (addr && (astate = arp_find(ifp, addr)))
+		return astate;
+
+	if ((astate = calloc(1, sizeof(*astate))) == NULL) {
+		logger(ifp->ctx, LOG_ERR, "%s: %s: %m", ifp->name, __func__);
+		return NULL;
+	}
+	state = D_STATE(ifp);
+	astate->iface = ifp;
+	if (addr)
+		astate->addr = *addr;
+	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) {
+			ipv4ll_stop(astate->iface);
+			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;
+
+	if (state->arp_fd != -1) {
+		eloop_event_delete(ifp->ctx->eloop, state->arp_fd, 0);
+		close(state->arp_fd);
+		state->arp_fd = -1;
+	}
+
+	while ((astate = TAILQ_FIRST(&state->arp_states))) {
+#ifndef __clang_analyzer__
+		/* clang guard needed for a more compex variant on this bug:
+		 * http://llvm.org/bugs/show_bug.cgi?id=18222 */
+		arp_free(astate);
+#endif
+	}
+}
+
+void
+arp_handleifa(int cmd, struct interface *ifp, const struct in_addr *addr,
+    int flags)
+{
+#ifdef IN_IFF_DUPLICATED
+	struct dhcp_state *state = D_STATE(ifp);
+	struct arp_state *astate, *asn;
+
+	if (cmd != RTM_NEWADDR || (state = D_STATE(ifp)) == NULL)
+		return;
+
+	TAILQ_FOREACH_SAFE(astate, &state->arp_states, next, asn) {
+		if (astate->addr.s_addr == addr->s_addr) {
+			if (flags & IN_IFF_DUPLICATED) {
+				if (astate->conflicted_cb)
+					astate->conflicted_cb(astate, NULL);
+			} else if (!(flags & IN_IFF_NOTUSEABLE)) {
+				if (astate->probed_cb)
+					astate->probed_cb(astate);
+			}
+		}
+	}
+#else
+	UNUSED(cmd);
+	UNUSED(ifp);
+	UNUSED(addr);
+	UNUSED(flags);
+#endif
+}
diff --git a/dhcpcd-6.8.2/arp.h b/dhcpcd-6.8.2/arp.h
new file mode 100644
index 0000000..0daf615
--- /dev/null
+++ b/dhcpcd-6.8.2/arp.h
@@ -0,0 +1,85 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef ARP_H
+#define ARP_H
+
+/* ARP timings from RFC5227 */
+#define PROBE_WAIT		 1
+#define PROBE_NUM		 3
+#define PROBE_MIN		 1
+#define PROBE_MAX		 2
+#define ANNOUNCE_WAIT		 2
+#define ANNOUNCE_NUM		 2
+#define ANNOUNCE_INTERVAL	 2
+#define MAX_CONFLICTS		10
+#define RATE_LIMIT_INTERVAL	60
+#define DEFEND_INTERVAL		10
+
+#include "dhcpcd.h"
+
+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 src_addr;
+	struct in_addr addr;
+	int probes;
+	int claims;
+	struct in_addr failed;
+	uint8_t dest_hwlen;
+	unsigned char dest_hwaddr[HWADDR_LEN];
+};
+TAILQ_HEAD(arp_statehead, arp_state);
+
+#ifdef INET
+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 *, const struct in_addr *);
+void arp_cancel(struct arp_state *);
+void arp_free(struct arp_state *);
+void arp_free_but(struct arp_state *);
+void arp_close(struct interface *);
+
+void arp_handleifa(int, struct interface *, const struct in_addr *, int);
+#else
+#define arp_close(a) {}
+#endif
+#endif
diff --git a/dhcpcd-6.8.2/auth.c b/dhcpcd-6.8.2/auth.c
new file mode 100644
index 0000000..4bfbfdc
--- /dev/null
+++ b/dhcpcd-6.8.2/auth.c
@@ -0,0 +1,671 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/file.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "config.h"
+#include "auth.h"
+#include "crypt/crypt.h"
+#include "dhcp.h"
+#include "dhcp6.h"
+#include "dhcpcd.h"
+
+#ifdef __sun
+#define htonll
+#define ntohll
+#endif
+
+#ifndef htonll
+#if (BYTE_ORDER == LITTLE_ENDIAN)
+static inline uint64_t
+htonll(uint64_t x)
+{
+
+	return (uint64_t)htonl((uint32_t)(x >> 32)) |
+	    (uint64_t)htonl((uint32_t)(x & 0xffffffff)) << 32;
+}
+#else	/* (BYTE_ORDER == LITTLE_ENDIAN) */
+#define htonll(x) (x)
+#endif
+#endif  /* htonll */
+
+#ifndef ntohll
+#if (BYTE_ORDER == LITTLE_ENDIAN)
+static inline uint64_t
+ntohll(uint64_t x)
+{
+
+	return (uint64_t)ntohl((uint32_t)(x >> 32)) |
+	    (uint64_t)ntohl((uint32_t)(x & 0xffffffff)) << 32;
+}
+#else	/* (BYTE_ORDER == LITTLE_ENDIAN) */
+#define ntohll(x) (x)
+#endif
+#endif  /* ntohll */
+
+#define HMAC_LENGTH	16
+
+void
+dhcp_auth_reset(struct authstate *state)
+{
+
+	state->replay = 0;
+	if (state->token) {
+		free(state->token->key);
+		free(state->token->realm);
+		free(state->token);
+		state->token = NULL;
+	}
+	if (state->reconf) {
+		free(state->reconf->key);
+		free(state->reconf->realm);
+		free(state->reconf);
+		state->reconf = NULL;
+	}
+}
+
+/*
+ * Authenticate a DHCP message.
+ * m and mlen refer to the whole message.
+ * t is the DHCP type, pass it 4 or 6.
+ * data and dlen refer to the authentication option within the message.
+ */
+const struct token *
+dhcp_auth_validate(struct authstate *state, const struct auth *auth,
+    const uint8_t *m, size_t mlen, int mp,  int mt,
+    const uint8_t *data, size_t dlen)
+{
+	uint8_t protocol, algorithm, rdm, *mm, type;
+	uint64_t replay;
+	uint32_t secretid;
+	const uint8_t *d, *realm;
+	size_t realm_len;
+	const struct token *t;
+	time_t now;
+	uint8_t hmac[HMAC_LENGTH];
+
+	if (dlen < 3 + sizeof(replay)) {
+		errno = EINVAL;
+		return NULL;
+	}
+
+	/* Ensure that d is inside m which *may* not be the case for DHPCPv4 */
+	if (data < m || data > m + mlen || data + dlen > m + mlen) {
+		errno = ERANGE;
+		return NULL;
+	}
+
+	d = data;
+	protocol = *d++;
+	algorithm = *d++;
+	rdm = *d++;
+	if (!(auth->options & DHCPCD_AUTH_SEND)) {
+		/* If we didn't send any authorisation, it can only be a
+		 * reconfigure key */
+		if (protocol != AUTH_PROTO_RECONFKEY) {
+			errno = EINVAL;
+			return NULL;
+		}
+	} else if (protocol != auth->protocol ||
+		    algorithm != auth->algorithm ||
+		    rdm != auth->rdm)
+	{
+		/* As we don't require authentication, we should still
+		 * accept a reconfigure key */
+		if (protocol != AUTH_PROTO_RECONFKEY ||
+		    auth->options & DHCPCD_AUTH_REQUIRE)
+		{
+			errno = EPERM;
+			return NULL;
+		}
+	}
+	dlen -= 3;
+
+	memcpy(&replay, d, sizeof(replay));
+	replay = ntohll(replay);
+	if (state->token) {
+		if (state->replay == (replay ^ 0x8000000000000000ULL)) {
+			/* We don't know if the singular point is increasing
+			 * or decreasing. */
+			errno = EPERM;
+			return NULL;
+		}
+		if ((uint64_t)(replay - state->replay) <= 0) {
+			/* Replay attack detected */
+			errno = EPERM;
+			return NULL;
+		}
+	}
+	d+= sizeof(replay);
+	dlen -= sizeof(replay);
+
+	realm = NULL;
+	realm_len = 0;
+
+	/* Extract realm and secret.
+	 * Rest of data is MAC. */
+	switch (protocol) {
+	case AUTH_PROTO_TOKEN:
+		secretid = 0;
+		break;
+	case AUTH_PROTO_DELAYED:
+		if (dlen < sizeof(secretid) + sizeof(hmac)) {
+			errno = EINVAL;
+			return NULL;
+		}
+		memcpy(&secretid, d, sizeof(secretid));
+		d += sizeof(secretid);
+		dlen -= sizeof(secretid);
+		break;
+	case AUTH_PROTO_DELAYEDREALM:
+		if (dlen < sizeof(secretid) + sizeof(hmac)) {
+			errno = EINVAL;
+			return NULL;
+		}
+		realm_len = dlen - (sizeof(secretid) + sizeof(hmac));
+		if (realm_len) {
+			realm = d;
+			d += realm_len;
+			dlen -= realm_len;
+		}
+		memcpy(&secretid, d, sizeof(secretid));
+		d += sizeof(secretid);
+		dlen -= sizeof(secretid);
+		break;
+	case AUTH_PROTO_RECONFKEY:
+		if (dlen != 1 + 16) {
+			errno = EINVAL;
+			return NULL;
+		}
+		type = *d++;
+		dlen--;
+		switch (type) {
+		case 1:
+			if ((mp == 4 && mt == DHCP_ACK) ||
+			    (mp == 6 && mt == DHCP6_REPLY))
+			{
+				if (state->reconf == NULL) {
+					state->reconf =
+					    malloc(sizeof(*state->reconf));
+					if (state->reconf == NULL)
+						return NULL;
+					state->reconf->key = malloc(16);
+					if (state->reconf->key == NULL) {
+						free(state->reconf);
+						state->reconf = NULL;
+						return NULL;
+					}
+					state->reconf->secretid = 0;
+					state->reconf->expire = 0;
+					state->reconf->realm = NULL;
+					state->reconf->realm_len = 0;
+					state->reconf->key_len = 16;
+				}
+				memcpy(state->reconf->key, d, 16);
+			} else {
+				errno = EINVAL;
+				return NULL;
+			}
+			if (state->reconf == NULL)
+				errno = ENOENT;
+			/* Free the old token so we log acceptance */
+			if (state->token) {
+				free(state->token);
+				state->token = NULL;
+			}
+			/* Nothing to validate, just accepting the key */
+			return state->reconf;
+		case 2:
+			if (!((mp == 4 && mt == DHCP_FORCERENEW) ||
+			    (mp == 6 && mt == DHCP6_RECONFIGURE)))
+			{
+				errno = EINVAL;
+				return NULL;
+			}
+			if (state->reconf == NULL) {
+				errno = ENOENT;
+				return NULL;
+			}
+			t = state->reconf;
+			goto gottoken;
+		default:
+			errno = EINVAL;
+			return NULL;
+		}
+	default:
+		errno = ENOTSUP;
+		return NULL;
+	}
+
+	/* Find a token for the realm and secret */
+	secretid = ntohl(secretid);
+	TAILQ_FOREACH(t, &auth->tokens, next) {
+		if (t->secretid == secretid &&
+		    t->realm_len == realm_len &&
+		    (t->realm_len == 0 ||
+		    memcmp(t->realm, realm, t->realm_len) == 0))
+			break;
+	}
+	if (t == NULL) {
+		errno = ESRCH;
+		return NULL;
+	}
+	if (t->expire) {
+		if (time(&now) == -1)
+			return NULL;
+		if (t->expire < now) {
+			errno = EFAULT;
+			return NULL;
+		}
+	}
+
+gottoken:
+	/* First message from the server */
+	if (state->token &&
+	    (state->token->secretid != t->secretid ||
+	    state->token->realm_len != t->realm_len ||
+	    memcmp(state->token->realm, t->realm, t->realm_len)))
+	{
+		errno = EPERM;
+		return NULL;
+	}
+
+	/* Special case as no hashing needs to be done. */
+	if (protocol == AUTH_PROTO_TOKEN) {
+		if (dlen != t->key_len || memcmp(d, t->key, dlen)) {
+			errno = EPERM;
+			return NULL;
+		}
+		goto finish;
+	}
+
+	/* Make a duplicate of the message, but zero out the MAC part */
+	mm = malloc(mlen);
+	if (mm == NULL)
+		return NULL;
+	memcpy(mm, m, mlen);
+	memset(mm + (d - m), 0, dlen);
+
+	/* RFC3318, section 5.2 - zero giaddr and hops */
+	if (mp == 4) {
+		*(mm + offsetof(struct dhcp_message, hwopcount)) = '\0';
+		memset(mm + offsetof(struct dhcp_message, giaddr), 0, 4);
+	}
+
+	memset(hmac, 0, sizeof(hmac));
+	switch (algorithm) {
+	case AUTH_ALG_HMAC_MD5:
+		hmac_md5(mm, mlen, t->key, t->key_len, hmac);
+		break;
+	default:
+		errno = ENOSYS;
+		free(mm);
+		return NULL;
+	}
+
+	free(mm);
+	if (memcmp(d, &hmac, dlen)) {
+		errno = EPERM;
+		return NULL;
+	}
+
+finish:
+	/* If we got here then authentication passed */
+	state->replay = replay;
+	if (state->token == NULL) {
+		/* We cannot just save a pointer because a reconfigure will
+		 * recreate the token list. So we duplicate it. */
+		state->token = malloc(sizeof(*state->token));
+		if (state->token) {
+			state->token->secretid = t->secretid;
+			state->token->key = malloc(t->key_len);
+			if (state->token->key) {
+				state->token->key_len = t->key_len;
+				memcpy(state->token->key, t->key, t->key_len);
+			} else {
+				free(state->token);
+				state->token = NULL;
+				return NULL;
+			}
+			if (t->realm_len) {
+				state->token->realm = malloc(t->realm_len);
+				if (state->token->realm) {
+					state->token->realm_len = t->realm_len;
+					memcpy(state->token->realm, t->realm,
+					    t->realm_len);
+				} else {
+					free(state->token->key);
+					free(state->token);
+					state->token = NULL;
+					return NULL;
+				}
+			} else {
+				state->token->realm = NULL;
+				state->token->realm_len = 0;
+			}
+		}
+		/* If we cannot save the token, we must invalidate */
+		if (state->token == NULL)
+			return NULL;
+	}
+
+	return t;
+}
+
+static uint64_t
+get_next_rdm_monotonic_counter(struct auth *auth)
+{
+	FILE *fp;
+	uint64_t rdm;
+#ifdef LOCK_EX
+	int flocked;
+#endif
+
+	fp = fopen(RDM_MONOFILE, "r+");
+	if (fp == NULL) {
+		if (errno != ENOENT)
+			return ++auth->last_replay; /* report error? */
+		fp = fopen(RDM_MONOFILE, "w");
+		if (fp == NULL)
+			return ++auth->last_replay; /* report error? */
+#ifdef LOCK_EX
+		flocked = flock(fileno(fp), LOCK_EX);
+#endif
+		rdm = 0;
+	} else {
+#ifdef LOCK_EX
+		flocked = flock(fileno(fp), LOCK_EX);
+#endif
+		if (fscanf(fp, "0x%016" PRIu64, &rdm) != 1)
+			rdm = 0; /* truncated? report error? */
+	}
+
+	rdm++;
+	if (fseek(fp, 0, SEEK_SET) == -1 ||
+	    ftruncate(fileno(fp), 0) == -1 ||
+	    fprintf(fp, "0x%016" PRIu64 "\n", rdm) != 19)
+	{
+		if (!auth->last_replay_set) {
+			auth->last_replay = rdm;
+			auth->last_replay_set = 1;
+		} else
+			rdm = ++auth->last_replay;
+		/* report error? */
+	}
+	fflush(fp);
+#ifdef LOCK_EX
+	if (flocked == 0)
+		flock(fileno(fp), LOCK_UN);
+#endif
+	fclose(fp);
+	return rdm;
+}
+
+#define JAN_1970       2208988800U    /* 1970 - 1900 in seconds */
+static uint64_t
+get_next_rdm_monotonic_clock(struct auth *auth)
+{
+	struct timespec ts;
+	uint32_t pack[2];
+	double frac;
+	uint64_t rdm;
+
+	if (clock_gettime(CLOCK_REALTIME, &ts) != 0)
+		return ++auth->last_replay; /* report error? */
+	pack[0] = htonl((uint32_t)ts.tv_sec + JAN_1970);
+	frac = ((double)ts.tv_nsec / 1e9 * 0x100000000ULL);
+	pack[1] = htonl((uint32_t)frac);
+
+	memcpy(&rdm, &pack, sizeof(rdm));
+	return rdm;
+}
+
+static uint64_t
+get_next_rdm_monotonic(struct auth *auth)
+{
+
+	if (auth->options & DHCPCD_AUTH_RDM_COUNTER)
+		return get_next_rdm_monotonic_counter(auth);
+	return get_next_rdm_monotonic_clock(auth);
+}
+
+/*
+ * Encode a DHCP message.
+ * Either we know which token to use from the server response
+ * or we are using a basic configuration token.
+ * token is the token to encrypt with.
+ * m and mlen refer to the whole message.
+ * mp is the DHCP type, pass it 4 or 6.
+ * mt is the DHCP message type.
+ * data and dlen refer to the authentication option within the message.
+ */
+ssize_t
+dhcp_auth_encode(struct auth *auth, const struct token *t,
+    uint8_t *m, size_t mlen, int mp, int mt,
+    uint8_t *data, size_t dlen)
+{
+	uint64_t rdm;
+	uint8_t hmac[HMAC_LENGTH];
+	time_t now;
+	uint8_t hops, *p, info;
+	uint32_t giaddr, secretid;
+
+	if (auth->protocol == 0 && t == NULL) {
+		TAILQ_FOREACH(t, &auth->tokens, next) {
+			if (t->secretid == 0 &&
+			    t->realm_len == 0)
+			break;
+		}
+		if (t == NULL) {
+			errno = EINVAL;
+			return -1;
+		}
+		if (t->expire) {
+			if (time(&now) == -1)
+				return -1;
+			if (t->expire < now) {
+				errno = EPERM;
+				return -1;
+			}
+		}
+	}
+
+	switch(auth->protocol) {
+	case AUTH_PROTO_TOKEN:
+	case AUTH_PROTO_DELAYED:
+	case AUTH_PROTO_DELAYEDREALM:
+		/* We don't ever send a reconf key */
+		break;
+	default:
+		errno = ENOTSUP;
+		return -1;
+	}
+
+	switch(auth->algorithm) {
+	case AUTH_ALG_HMAC_MD5:
+		break;
+	default:
+		errno = ENOTSUP;
+		return -1;
+	}
+
+	switch(auth->rdm) {
+	case AUTH_RDM_MONOTONIC:
+		break;
+	default:
+		errno = ENOTSUP;
+		return -1;
+	}
+
+	/* DISCOVER or INFORM messages don't write auth info */
+	if ((mp == 4 && (mt == DHCP_DISCOVER || mt == DHCP_INFORM)) ||
+	    (mp == 6 && (mt == DHCP6_SOLICIT || mt == DHCP6_INFORMATION_REQ)))
+		info = 0;
+	else
+		info = 1;
+
+	/* Work out the auth area size.
+	 * We only need to do this for DISCOVER messages */
+	if (data == NULL) {
+		dlen = 1 + 1 + 1 + 8;
+		switch(auth->protocol) {
+		case AUTH_PROTO_TOKEN:
+			dlen += t->key_len;
+			break;
+		case AUTH_PROTO_DELAYEDREALM:
+			if (info && t)
+				dlen += t->realm_len;
+			/* FALLTHROUGH */
+		case AUTH_PROTO_DELAYED:
+			if (info && t)
+				dlen += sizeof(t->secretid) + sizeof(hmac);
+			break;
+		}
+		return (ssize_t)dlen;
+	}
+
+	if (dlen < 1 + 1 + 1 + 8) {
+		errno = ENOBUFS;
+		return -1;
+	}
+
+	/* Ensure that d is inside m which *may* not be the case for DHPCPv4 */
+	if (data < m || data > m + mlen || data + dlen > m + mlen) {
+		errno = ERANGE;
+		return -1;
+	}
+
+	/* Write out our option */
+	*data++ = auth->protocol;
+	*data++ = auth->algorithm;
+	*data++ = auth->rdm;
+	switch (auth->rdm) {
+	case AUTH_RDM_MONOTONIC:
+		rdm = get_next_rdm_monotonic(auth);
+		break;
+	default:
+		/* This block appeases gcc, clang doesn't need it */
+		rdm = get_next_rdm_monotonic(auth);
+		break;
+	}
+	rdm = htonll(rdm);
+	memcpy(data, &rdm, 8);
+	data += 8;
+	dlen -= 1 + 1 + 1 + 8;
+
+	/* Special case as no hashing needs to be done. */
+	if (auth->protocol == AUTH_PROTO_TOKEN) {
+		/* Should be impossible, but still */
+		if (t == NULL) {
+			errno = EINVAL;
+			return -1;
+		}
+		if (dlen < t->key_len) {
+			errno =	ENOBUFS;
+			return -1;
+		}
+		memcpy(data, t->key, t->key_len);
+		return (ssize_t)(dlen - t->key_len);
+	}
+
+	/* DISCOVER or INFORM messages don't write auth info */
+	if (!info)
+		return (ssize_t)dlen;
+
+	/* Loading a saved lease without an authentication option */
+	if (t == NULL)
+		return 0;
+
+	/* Write out the Realm */
+	if (auth->protocol == AUTH_PROTO_DELAYEDREALM) {
+		if (dlen < t->realm_len) {
+			errno = ENOBUFS;
+			return -1;
+		}
+		memcpy(data, t->realm, t->realm_len);
+		data += t->realm_len;
+		dlen -= t->realm_len;
+	}
+
+	/* Write out the SecretID */
+	if (auth->protocol == AUTH_PROTO_DELAYED ||
+	    auth->protocol == AUTH_PROTO_DELAYEDREALM)
+	{
+		if (dlen < sizeof(t->secretid)) {
+			errno = ENOBUFS;
+			return -1;
+		}
+		secretid = htonl(t->secretid);
+		memcpy(data, &secretid, sizeof(secretid));
+		data += sizeof(secretid);
+		dlen -= sizeof(secretid);
+	}
+
+	/* Zero what's left, the MAC */
+	memset(data, 0, dlen);
+
+	/* RFC3318, section 5.2 - zero giaddr and hops */
+	if (mp == 4) {
+		p = m + offsetof(struct dhcp_message, hwopcount);
+		hops = *p;
+		*p = '\0';
+		p = m + offsetof(struct dhcp_message, giaddr);
+		memcpy(&giaddr, p, sizeof(giaddr));
+		memset(p, 0, sizeof(giaddr));
+	} else {
+		/* appease GCC again */
+		hops = 0;
+		giaddr = 0;
+	}
+
+	/* Create our hash and write it out */
+	switch(auth->algorithm) {
+	case AUTH_ALG_HMAC_MD5:
+		hmac_md5(m, mlen, t->key, t->key_len, hmac);
+		memcpy(data, hmac, sizeof(hmac));
+		break;
+	}
+
+	/* RFC3318, section 5.2 - restore giaddr and hops */
+	if (mp == 4) {
+		p = m + offsetof(struct dhcp_message, hwopcount);
+		*p = hops;
+		p = m + offsetof(struct dhcp_message, giaddr);
+		memcpy(p, &giaddr, sizeof(giaddr));
+	}
+
+	/* Done! */
+	return (int)(dlen - sizeof(hmac)); /* should be zero */
+}
diff --git a/dhcpcd-6.8.2/auth.h b/dhcpcd-6.8.2/auth.h
new file mode 100644
index 0000000..0dea410
--- /dev/null
+++ b/dhcpcd-6.8.2/auth.h
@@ -0,0 +1,86 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef AUTH_H
+#define AUTH_H
+
+#include "config.h"
+
+#define DHCPCD_AUTH_SEND	(1 << 0)
+#define DHCPCD_AUTH_REQUIRE	(1 << 1)
+#define DHCPCD_AUTH_RDM_COUNTER	(1 << 2)
+
+#define DHCPCD_AUTH_SENDREQUIRE	(DHCPCD_AUTH_SEND | DHCPCD_AUTH_REQUIRE)
+
+#define AUTH_PROTO_TOKEN	0
+#define AUTH_PROTO_DELAYED	1
+#define AUTH_PROTO_DELAYEDREALM	2
+#define AUTH_PROTO_RECONFKEY	3
+
+#define AUTH_ALG_HMAC_MD5	1
+
+#define AUTH_RDM_MONOTONIC	0
+
+struct token {
+	TAILQ_ENTRY(token) next;
+	uint32_t secretid;
+	size_t realm_len;
+	unsigned char *realm;
+	size_t key_len;
+	unsigned char *key;
+	time_t expire;
+};
+
+TAILQ_HEAD(token_head, token);
+
+struct auth {
+	int options;
+	uint8_t protocol;
+	uint8_t algorithm;
+	uint8_t rdm;
+	uint64_t last_replay;
+	uint8_t last_replay_set;
+	struct token_head tokens;
+};
+
+struct authstate {
+	uint64_t replay;
+	struct token *token;
+	struct token *reconf;
+};
+
+void dhcp_auth_reset(struct authstate *);
+
+const struct token * dhcp_auth_validate(struct authstate *,
+    const struct auth *,
+    const uint8_t *, size_t, int, int,
+    const uint8_t *, size_t);
+
+ssize_t dhcp_auth_encode(struct auth *, const struct token *,
+    uint8_t *, size_t, int, int,
+    uint8_t *, size_t);
+#endif
diff --git a/dhcpcd-6.8.2/bpf-filter.h b/dhcpcd-6.8.2/bpf-filter.h
new file mode 100644
index 0000000..08df683
--- /dev/null
+++ b/dhcpcd-6.8.2/bpf-filter.h
@@ -0,0 +1,99 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2008 Roy Marples <roy@marples.name>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef BPF_ETHCOOK
+# define BPF_ETHCOOK 0
+#endif
+#ifndef BPF_WHOLEPACKET
+# define BPF_WHOLEPACKET ~0U
+#endif
+static const struct bpf_insn arp_bpf_filter [] = {
+#ifndef BPF_SKIPTYPE
+	/* Make sure this is an ARP packet... */
+	BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 12),
+	BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_ARP, 0, 3),
+#endif
+	/* Make sure this is an ARP REQUEST... */
+	BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 20 + BPF_ETHCOOK),
+	BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPOP_REQUEST, 2, 0),
+	/* or ARP REPLY... */
+	BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 20 + BPF_ETHCOOK),
+	BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPOP_REPLY, 0, 1),
+	/* If we passed all the tests, ask for the whole packet. */
+	BPF_STMT(BPF_RET + BPF_K, BPF_WHOLEPACKET),
+	/* Otherwise, drop it. */
+	BPF_STMT(BPF_RET + BPF_K, 0),
+};
+#define arp_bpf_filter_len sizeof(arp_bpf_filter) / sizeof(arp_bpf_filter[0])
+
+
+/* dhcp_bpf_filter taken from bpf.c in dhcp-3.1.0
+ *
+ * Copyright (c) 2004,2007 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996-2003 by Internet Software Consortium
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *   Internet Systems Consortium, Inc.
+ *   950 Charter Street
+ *   Redwood City, CA 94063
+ *   <info@isc.org>
+ *   http://www.isc.org/
+ */
+
+static const struct bpf_insn dhcp_bpf_filter [] = {
+#ifndef BPF_SKIPTYPE
+	/* Make sure this is an IP packet... */
+	BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 12),
+	BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 0, 8),
+#endif
+	/* Make sure it's a UDP packet... */
+	BPF_STMT(BPF_LD + BPF_B + BPF_ABS, 23 + BPF_ETHCOOK),
+	BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 6),
+	/* Make sure this isn't a fragment... */
+	BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 20 + BPF_ETHCOOK),
+	BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 4, 0),
+	/* Get the IP header length... */
+	BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, 14 + BPF_ETHCOOK),
+	/* Make sure it's to the right port... */
+	BPF_STMT(BPF_LD + BPF_H + BPF_IND, 16 + BPF_ETHCOOK),
+	BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, DHCP_CLIENT_PORT, 0, 1),
+	/* If we passed all the tests, ask for the whole packet. */
+	BPF_STMT(BPF_RET + BPF_K, BPF_WHOLEPACKET),
+	/* Otherwise, drop it. */
+	BPF_STMT(BPF_RET + BPF_K, 0),
+};
+#define dhcp_bpf_filter_len sizeof(dhcp_bpf_filter) / sizeof(dhcp_bpf_filter[0])
diff --git a/dhcpcd-6.8.2/common.c b/dhcpcd-6.8.2/common.c
new file mode 100644
index 0000000..ccad014
--- /dev/null
+++ b/dhcpcd-6.8.2/common.c
@@ -0,0 +1,370 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef __APPLE__
+#  include <mach/mach_time.h>
+#  include <mach/kern_return.h>
+#endif
+
+#include <sys/param.h>
+#include <sys/time.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#ifdef BSD
+#  include <paths.h>
+#endif
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "common.h"
+#include "dhcpcd.h"
+#include "if-options.h"
+
+#ifndef _PATH_DEVNULL
+#  define _PATH_DEVNULL "/dev/null"
+#endif
+
+const char *
+get_hostname(char *buf, size_t buflen, int short_hostname)
+{
+	char *p;
+
+	if (gethostname(buf, buflen) != 0)
+		return NULL;
+	buf[buflen - 1] = '\0';
+	if (strcmp(buf, "(none)") == 0 ||
+	    strcmp(buf, "localhost") == 0 ||
+	    strncmp(buf, "localhost.", strlen("localhost.")) == 0 ||
+	    buf[0] == '.')
+		return NULL;
+
+	if (short_hostname) {
+		p = strchr(buf, '.');
+		if (p)
+			*p = '\0';
+	}
+
+	return buf;
+}
+
+/* Handy function to get the time.
+ * We only care about time advancements, not the actual time itself
+ * Which is why we use CLOCK_MONOTONIC, but it is not available on all
+ * platforms.
+ */
+#define NO_MONOTONIC "host does not support a monotonic clock - timing can skew"
+int
+get_monotonic(struct timespec *ts)
+{
+
+#if defined(_POSIX_MONOTONIC_CLOCK) && defined(CLOCK_MONOTONIC)
+	return clock_gettime(CLOCK_MONOTONIC, ts);
+#elif defined(__APPLE__)
+	/* We can use mach kernel functions here.
+	 * This is crap though - why can't they implement clock_gettime?*/
+	static struct mach_timebase_info info = { 0, 0 };
+	static double factor = 0.0;
+	uint64_t nano;
+	long rem;
+
+	if (!posix_clock_set) {
+		if (mach_timebase_info(&info) == KERN_SUCCESS) {
+			factor = (double)info.numer / (double)info.denom;
+			clock_monotonic = posix_clock_set = 1;
+		}
+	}
+	if (clock_monotonic) {
+		nano = mach_absolute_time();
+		if ((info.denom != 1 || info.numer != 1) && factor != 0.0)
+			nano *= factor;
+		ts->tv_sec = nano / NSEC_PER_SEC;
+		ts->tv_nsec = nano % NSEC_PER_SEC;
+		if (ts->tv_nsec < 0) {
+			ts->tv_sec--;
+			ts->tv_nsec += NSEC_PER_SEC;
+		}
+		return 0;
+	}
+#endif
+
+#if 0
+	/* Something above failed, so fall back to gettimeofday */
+	if (!posix_clock_set) {
+		logger(NULL, LOG_WARNING, NO_MONOTONIC);
+		posix_clock_set = 1;
+	}
+#endif
+	{
+		struct timeval tv;
+		if (gettimeofday(&tv, NULL) == 0) {
+			TIMEVAL_TO_TIMESPEC(&tv, ts);
+			return 0;
+		}
+	}
+
+	return -1;
+}
+
+#if USE_LOGFILE
+void
+logger_open(struct dhcpcd_ctx *ctx)
+{
+
+	if (ctx->logfile) {
+		int f = O_CREAT | O_APPEND | O_TRUNC;
+
+#ifdef O_CLOEXEC
+		f |= O_CLOEXEC;
+#endif
+		ctx->log_fd = open(ctx->logfile, O_WRONLY | f, 0644);
+		if (ctx->log_fd == -1)
+			warn("open: %s", ctx->logfile);
+#ifndef O_CLOEXEC
+		else {
+			if (fcntl(ctx->log_fd, F_GETFD, &f) == -1 ||
+			    fcntl(ctx->log_fd, F_SETFD, f | FD_CLOEXEC) == -1)
+				warn("fcntl: %s", ctx->logfile);
+		}
+#endif
+	} else
+		openlog(PACKAGE, LOG_PID | LOG_PERROR, LOG_DAEMON);
+}
+
+void
+logger_close(struct dhcpcd_ctx *ctx)
+{
+
+	if (ctx->log_fd != -1) {
+		close(ctx->log_fd);
+		ctx->log_fd = -1;
+	}
+	closelog();
+}
+
+void
+logger(struct dhcpcd_ctx *ctx, int pri, const char *fmt, ...)
+{
+	va_list va;
+	int serrno;
+#ifndef HAVE_PRINTF_M
+	char fmt_cpy[1024];
+#endif
+
+	if (pri >= LOG_DEBUG && ctx && !(ctx->options & DHCPCD_DEBUG))
+		return;
+
+	serrno = errno;
+	va_start(va, fmt);
+
+#ifndef HAVE_PRINTF_M
+	/* Print strerrno(errno) in place of %m */
+	if (ctx == NULL || !(ctx->options & DHCPCD_QUIET) || ctx->log_fd != -1)
+	{
+		const char *p;
+		char *fp = fmt_cpy, *serr = NULL;
+		size_t fmt_left = sizeof(fmt_cpy) - 1, fmt_wrote;
+
+		for (p = fmt; *p != '\0'; p++) {
+			if (p[0] == '%' && p[1] == '%') {
+				if (fmt_left < 2)
+					break;
+				*fp++ = '%';
+				*fp++ = '%';
+				fmt_left -= 2;
+				p++;
+			} else if (p[0] == '%' && p[1] == 'm') {
+				if (serr == NULL)
+					serr = strerror(serrno);
+				fmt_wrote = strlcpy(fp, serr, fmt_left);
+				if (fmt_wrote > fmt_left)
+					break;
+				fp += fmt_wrote;
+				fmt_left -= fmt_wrote;
+				p++;
+			} else {
+				*fp++ = *p;
+				--fmt_left;
+			}
+			if (fmt_left == 0)
+				break;
+		}
+		*fp++ = '\0';
+		fmt = fmt_cpy;
+	}
+
+#endif
+
+	if (ctx == NULL || !(ctx->options & DHCPCD_QUIET)) {
+		va_list vac;
+
+		va_copy(vac, va);
+		vfprintf(pri <= LOG_ERR ? stderr : stdout, fmt, vac);
+		fputc('\n', pri <= LOG_ERR ? stderr : stdout);
+		va_end(vac);
+	}
+
+#ifdef HAVE_PRINTF_M
+	errno = serrno;
+#endif
+	if (ctx && ctx->log_fd != -1) {
+		struct timeval tv;
+		char buf[32];
+
+		/* Write the time, syslog style. month day time - */
+		if (gettimeofday(&tv, NULL) != -1) {
+			time_t now;
+			struct tm tmnow;
+
+			tzset();
+			now = tv.tv_sec;
+			localtime_r(&now, &tmnow);
+			strftime(buf, sizeof(buf), "%b %d %T ", &tmnow);
+			dprintf(ctx->log_fd, "%s", buf);
+		}
+
+		vdprintf(ctx->log_fd, fmt, va);
+		dprintf(ctx->log_fd, "\n");
+	} else
+		vsyslog(pri, fmt, va);
+	va_end(va);
+}
+#endif
+
+ssize_t
+setvar(struct dhcpcd_ctx *ctx,
+    char ***e, const char *prefix, const char *var, const char *value)
+{
+	size_t len = strlen(var) + strlen(value) + 3;
+
+	if (prefix)
+		len += strlen(prefix) + 1;
+	**e = malloc(len);
+	if (**e == NULL) {
+		logger(ctx, LOG_ERR, "%s: %m", __func__);
+		return -1;
+	}
+	if (prefix)
+		snprintf(**e, len, "%s_%s=%s", prefix, var, value);
+	else
+		snprintf(**e, len, "%s=%s", var, value);
+	(*e)++;
+	return (ssize_t)len;
+}
+
+ssize_t
+setvard(struct dhcpcd_ctx *ctx,
+    char ***e, const char *prefix, const char *var, size_t value)
+{
+	char buffer[32];
+
+	snprintf(buffer, sizeof(buffer), "%zu", value);
+	return setvar(ctx, e, prefix, var, buffer);
+}
+
+
+time_t
+uptime(void)
+{
+	struct timespec tv;
+
+	if (get_monotonic(&tv) == -1)
+		return -1;
+	return tv.tv_sec;
+}
+
+char *
+hwaddr_ntoa(const unsigned char *hwaddr, size_t hwlen, char *buf, size_t buflen)
+{
+	char *p;
+	size_t i;
+
+	if (buf == NULL) {
+		return NULL;
+	}
+
+	if (hwlen * 3 > buflen) {
+		errno = ENOBUFS;
+		return 0;
+	}
+
+	p = buf;
+	for (i = 0; i < hwlen; i++) {
+		if (i > 0)
+			*p ++= ':';
+		p += snprintf(p, 3, "%.2x", hwaddr[i]);
+	}
+	*p ++= '\0';
+	return buf;
+}
+
+size_t
+hwaddr_aton(unsigned char *buffer, const char *addr)
+{
+	char c[3];
+	const char *p = addr;
+	unsigned char *bp = buffer;
+	size_t len = 0;
+
+	c[2] = '\0';
+	while (*p) {
+		c[0] = *p++;
+		c[1] = *p++;
+		/* Ensure that digits are hex */
+		if (isxdigit((unsigned char)c[0]) == 0 ||
+		    isxdigit((unsigned char)c[1]) == 0)
+		{
+			errno = EINVAL;
+			return 0;
+		}
+		/* We should have at least two entries 00:01 */
+		if (len == 0 && *p == '\0') {
+			errno = EINVAL;
+			return 0;
+		}
+		/* Ensure that next data is EOL or a seperator with data */
+		if (!(*p == '\0' || (*p == ':' && *(p + 1) != '\0'))) {
+			errno = EINVAL;
+			return 0;
+		}
+		if (*p)
+			p++;
+		if (bp)
+			*bp++ = (unsigned char)strtol(c, NULL, 16);
+		len++;
+	}
+	return len;
+}
diff --git a/dhcpcd-6.8.2/common.h b/dhcpcd-6.8.2/common.h
new file mode 100644
index 0000000..76215bf
--- /dev/null
+++ b/dhcpcd-6.8.2/common.h
@@ -0,0 +1,190 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef COMMON_H
+#define COMMON_H
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <stdio.h>
+#include <syslog.h>
+
+#include "config.h"
+#include "defs.h"
+#include "dhcpcd.h"
+
+#ifndef HOSTNAME_MAX_LEN
+#define HOSTNAME_MAX_LEN	250	/* 255 - 3 (FQDN) - 2 (DNS enc) */
+#endif
+
+#ifndef MIN
+#define MIN(a,b)		((/*CONSTCOND*/(a)<(b))?(a):(b))
+#define MAX(a,b)		((/*CONSTCOND*/(a)>(b))?(a):(b))
+#endif
+
+#define UNCONST(a)		((void *)(unsigned long)(const void *)(a))
+#define STRINGIFY(a)		#a
+#define TOSTRING(a)		STRINGIFY(a)
+#define UNUSED(a)		(void)(a)
+
+#define USEC_PER_SEC		1000000L
+#define USEC_PER_NSEC		1000L
+#define NSEC_PER_SEC		1000000000L
+#define MSEC_PER_SEC		1000L
+#define MSEC_PER_NSEC		1000000L
+
+/* Some systems don't define timespec macros */
+#ifndef timespecclear
+#define timespecclear(tsp)      (tsp)->tv_sec = (time_t)((tsp)->tv_nsec = 0L)
+#define timespecisset(tsp)      ((tsp)->tv_sec || (tsp)->tv_nsec)
+#define timespeccmp(tsp, usp, cmp)                                      \
+        (((tsp)->tv_sec == (usp)->tv_sec) ?                             \
+            ((tsp)->tv_nsec cmp (usp)->tv_nsec) :                       \
+            ((tsp)->tv_sec cmp (usp)->tv_sec))
+#define timespecadd(tsp, usp, vsp)                                      \
+        do {                                                            \
+                (vsp)->tv_sec = (tsp)->tv_sec + (usp)->tv_sec;          \
+                (vsp)->tv_nsec = (tsp)->tv_nsec + (usp)->tv_nsec;       \
+                if ((vsp)->tv_nsec >= 1000000000L) {                    \
+                        (vsp)->tv_sec++;                                \
+                        (vsp)->tv_nsec -= 1000000000L;                  \
+                }                                                       \
+        } while (/* CONSTCOND */ 0)
+#define timespecsub(tsp, usp, vsp)                                      \
+        do {                                                            \
+                (vsp)->tv_sec = (tsp)->tv_sec - (usp)->tv_sec;          \
+                (vsp)->tv_nsec = (tsp)->tv_nsec - (usp)->tv_nsec;       \
+                if ((vsp)->tv_nsec < 0) {                               \
+                        (vsp)->tv_sec--;                                \
+                        (vsp)->tv_nsec += 1000000000L;                  \
+                }                                                       \
+        } while (/* CONSTCOND */ 0)
+#endif
+
+#define timespec_to_double(tv)						     \
+	((double)(tv)->tv_sec + (double)((tv)->tv_nsec) / 1000000000.0)
+#define timespecnorm(tv) do {						     \
+	while ((tv)->tv_nsec >=  NSEC_PER_SEC) {			     \
+		(tv)->tv_sec++;						     \
+		(tv)->tv_nsec -= NSEC_PER_SEC;				     \
+	}								     \
+} while (0 /* CONSTCOND */);
+#define ts_to_ms(ms, tv) do {						     \
+	ms = (tv)->tv_sec * MSEC_PER_SEC;				     \
+	ms += (tv)->tv_nsec / MSEC_PER_NSEC;				     \
+} while (0 /* CONSTCOND */);
+#define ms_to_ts(tv, ms) do {						     \
+	(tv)->tv_sec = ms / MSEC_PER_SEC;				     \
+	(tv)->tv_nsec = (suseconds_t)(ms - ((tv)->tv_sec * MSEC_PER_SEC))    \
+	    * MSEC_PER_NSEC;						     \
+} while (0 /* CONSTCOND */);
+
+#ifndef TIMEVAL_TO_TIMESPEC
+#define	TIMEVAL_TO_TIMESPEC(tv, ts) do {				\
+	(ts)->tv_sec = (tv)->tv_sec;					\
+	(ts)->tv_nsec = (tv)->tv_usec * USEC_PER_NSEC;			\
+} while (0 /* CONSTCOND */)
+#endif
+
+#if __GNUC__ > 2 || defined(__INTEL_COMPILER)
+# ifndef __dead
+#  define __dead __attribute__((__noreturn__))
+# endif
+# ifndef __packed
+#  define __packed   __attribute__((__packed__))
+# endif
+# ifndef __printflike
+#  define __printflike(a, b) __attribute__((format(printf, a, b)))
+# endif
+# ifndef __unused
+#  define __unused   __attribute__((__unused__))
+# endif
+#else
+# ifndef __dead
+#  define __dead
+# endif
+# ifndef __packed
+#  define __packed
+# endif
+# ifndef __printflike
+#  define __printflike
+# endif
+# ifndef __unused
+#  define __unused
+# endif
+#endif
+
+/* We don't really need this as our supported systems define __restrict
+ * automatically for us, but it is here for completeness. */
+#ifndef __restrict
+# if defined(__lint__)
+#  define __restrict
+# elif __STDC_VERSION__ >= 199901L
+#  define __restrict restrict
+# elif !(2 < __GNUC__ || (2 == __GNU_C && 95 <= __GNUC_VERSION__))
+#  define __restrict
+# endif
+#endif
+
+void get_line_free(void);
+const char *get_hostname(char *, size_t, int);
+extern int clock_monotonic;
+int get_monotonic(struct timespec *);
+
+/* We could shave a few k off the binary size by just using the
+ * syslog(3) interface.
+ * However, this results in a ugly output on the command line
+ * and relies on syslogd(8) starting before dhcpcd which is not
+ * always the case. */
+#ifndef USE_LOGFILE
+# define USE_LOGFILE 1
+#endif
+#if USE_LOGFILE
+void logger_open(struct dhcpcd_ctx *);
+#define logger_mask(ctx, lvl) setlogmask((lvl))
+__printflike(3, 4) void logger(struct dhcpcd_ctx *, int, const char *, ...);
+void logger_close(struct dhcpcd_ctx *);
+#else
+#define logger_open(ctx) openlog(PACKAGE, LOG_PERROR | LOG_PID, LOG_DAEMON)
+#define logger_mask(ctx, lvl) setlogmask((lvl))
+#define logger(ctx, pri, fmt, ...)			\
+	do {						\
+		UNUSED((ctx));				\
+		syslog((pri), (fmt), ##__VA_ARGS__);	\
+	} while (0 /*CONSTCOND */)
+#define logger_close(ctx) closelog()
+#endif
+
+ssize_t setvar(struct dhcpcd_ctx *,
+    char ***, const char *, const char *, const char *);
+ssize_t setvard(struct dhcpcd_ctx *,
+    char ***, const char *, const char *, size_t);
+time_t uptime(void);
+
+char *hwaddr_ntoa(const unsigned char *, size_t, char *, size_t);
+size_t hwaddr_aton(unsigned char *, const char *);
+#endif
diff --git a/dhcpcd-6.8.2/compat/arc4random.c b/dhcpcd-6.8.2/compat/arc4random.c
new file mode 100644
index 0000000..1321aed
--- /dev/null
+++ b/dhcpcd-6.8.2/compat/arc4random.c
@@ -0,0 +1,151 @@
+/*
+ * Arc4 random number generator for OpenBSD.
+ * Copyright 1996 David Mazieres <dm@lcs.mit.edu>.
+ *
+ * Modification and redistribution in source and binary forms is
+ * permitted provided that due credit is given to the author and the
+ * OpenBSD project by leaving this copyright notice intact.
+ */
+
+/*
+ * This code is derived from section 17.1 of Applied Cryptography,
+ * second edition, which describes a stream cipher allegedly
+ * compatible with RSA Labs "RC4" cipher (the actual description of
+ * which is a trade secret).  The same algorithm is used as a stream
+ * cipher called "arcfour" in Tatu Ylonen's ssh package.
+ *
+ * Here the stream cipher has been modified always to include the time
+ * when initializing the state.  That makes it impossible to
+ * regenerate the same random sequence twice, so this can't be used
+ * for encryption, but will generate good random numbers.
+ *
+ * RC4 is a registered trademark of RSA Laboratories.
+ */
+
+#include <sys/time.h>
+
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "arc4random.h"
+
+struct arc4_stream {
+	uint8_t i;
+	uint8_t j;
+	uint8_t s[256];
+	size_t count;
+	pid_t stir_pid;
+};
+
+#define S(n) (n)
+#define S4(n) S(n), S(n + 1), S(n + 2), S(n + 3)
+#define S16(n) S4(n), S4(n + 4), S4(n + 8), S4(n + 12)
+#define S64(n) S16(n), S16(n + 16), S16(n + 32), S16(n + 48)
+#define S256 S64(0), S64(64), S64(128), S64(192)
+
+static struct arc4_stream rs = { .i = 0xff, .j = 0, .s = { S256 },
+                    .count = 0, .stir_pid = 0 };
+
+#undef S
+#undef S4
+#undef S16
+#undef S64
+#undef S256
+
+static void
+arc4_addrandom(struct arc4_stream *as, unsigned char *dat, int datlen)
+{
+	int n;
+	uint8_t si;
+
+	as->i--;
+	for (n = 0; n < 256; n++) {
+		as->i = (uint8_t)(as->i + 1);
+		si = as->s[as->i];
+		as->j = (uint8_t)(as->j + si + dat[n % datlen]);
+		as->s[as->i] = as->s[as->j];
+		as->s[as->j] = si;
+	}
+	as->j = as->i;
+}
+
+static uint8_t
+arc4_getbyte(struct arc4_stream *as)
+{
+	uint8_t si, sj;
+
+	as->i = (uint8_t)(as->i + 1);
+	si = as->s[as->i];
+	as->j = (uint8_t)(as->j + si);
+	sj = as->s[as->j];
+	as->s[as->i] = sj;
+	as->s[as->j] = si;
+	return (as->s[(si + sj) & 0xff]);
+}
+
+static uint32_t
+arc4_getword(struct arc4_stream *as)
+{
+	int val;
+
+	val = arc4_getbyte(as) << 24;
+	val |= arc4_getbyte(as) << 16;
+	val |= arc4_getbyte(as) << 8;
+	val |= arc4_getbyte(as);
+	return (uint32_t)val;
+}
+
+static void
+arc4_stir(struct arc4_stream *as)
+{
+	int fd;
+	struct {
+		struct timeval tv;
+		unsigned int rnd[(128 - sizeof(struct timeval)) /
+			sizeof(unsigned int)];
+	}       rdat;
+	size_t n;
+
+	gettimeofday(&rdat.tv, NULL);
+	fd = open("/dev/urandom", O_RDONLY);
+	if (fd != -1) {
+		(void)read(fd, rdat.rnd, sizeof(rdat.rnd));
+		close(fd);
+	}
+
+	/* fd < 0?  Ah, what the heck. We'll just take
+	 * whatever was on the stack... */
+	arc4_addrandom(as, (void *) &rdat, sizeof(rdat));
+
+	/*
+	 * Throw away the first N words of output, as suggested in the
+	 * paper "Weaknesses in the Key Scheduling Algorithm of RC4"
+	 * by Fluher, Mantin, and Shamir.  (N = 256 in our case.)
+	 */
+	for (n = 0; n < 256 * sizeof(uint32_t); n++)
+		arc4_getbyte(as);
+	as->count = 1600000;
+}
+
+static void
+arc4_stir_if_needed(struct arc4_stream *as)
+{
+	pid_t pid;
+
+	pid = getpid();
+	if (as->count <= sizeof(uint32_t) || !as->stir_pid != pid) {
+		as->stir_pid = pid;
+		arc4_stir(as);
+	} else
+		as->count -= sizeof(uint32_t);
+}
+
+uint32_t
+arc4random()
+{
+
+	arc4_stir_if_needed(&rs);
+	return arc4_getword(&rs);
+}
diff --git a/dhcpcd-6.8.2/compat/arc4random.h b/dhcpcd-6.8.2/compat/arc4random.h
new file mode 100644
index 0000000..d8ae3c7
--- /dev/null
+++ b/dhcpcd-6.8.2/compat/arc4random.h
@@ -0,0 +1,34 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2014 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef ARC4RANDOM_H
+#define ARC4RANDOM_H
+
+#include <stdint.h>
+
+uint32_t arc4random(void);
+#endif
diff --git a/dhcpcd-6.8.2/compat/arc4random_uniform.c b/dhcpcd-6.8.2/compat/arc4random_uniform.c
new file mode 100644
index 0000000..b597551
--- /dev/null
+++ b/dhcpcd-6.8.2/compat/arc4random_uniform.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2008, Damien Miller <djm@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+
+/* We need to include config.h so we pickup either the system arc4random
+ * or our compat one. */
+#include "../config.h"
+
+/*
+ * Calculate a uniformly distributed random number less than upper_bound
+ * avoiding "modulo bias".
+ *
+ * Uniformity is achieved by generating new random numbers until the one
+ * returned is outside the range [0, 2**32 % upper_bound).  This
+ * guarantees the selected random number will be inside
+ * [2**32 % upper_bound, 2**32) which maps back to [0, upper_bound)
+ * after reduction modulo upper_bound.
+ */
+uint32_t
+arc4random_uniform(uint32_t upper_bound)
+{
+	uint32_t r, min;
+
+	if (upper_bound < 2)
+		return 0;
+
+	/* 2**32 % x == (2**32 - x) % x */
+	min = -upper_bound % upper_bound;
+
+	/*
+	 * This could theoretically loop forever but each retry has
+	 * p > 0.5 (worst case, usually far better) of selecting a
+	 * number inside the range we need, so it should rarely need
+	 * to re-roll.
+	 */
+	do
+		r = arc4random();
+	while (r < min);
+
+	return r % upper_bound;
+}
diff --git a/dhcpcd-6.8.2/compat/arc4random_uniform.h b/dhcpcd-6.8.2/compat/arc4random_uniform.h
new file mode 100644
index 0000000..e6a9b74
--- /dev/null
+++ b/dhcpcd-6.8.2/compat/arc4random_uniform.h
@@ -0,0 +1,34 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2014 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef ARC4RANDOM_UNIFORM_H
+#define ARC4RANDOM_UNIFORM_H
+
+#include <stdint.h>
+
+uint32_t arc4random_uniform(uint32_t);
+#endif
diff --git a/dhcpcd-6.8.2/compat/closefrom.c b/dhcpcd-6.8.2/compat/closefrom.c
new file mode 100644
index 0000000..ab57c77
--- /dev/null
+++ b/dhcpcd-6.8.2/compat/closefrom.c
@@ -0,0 +1,49 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2009 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <unistd.h>
+
+#include "closefrom.h"
+
+int
+closefrom(int fd)
+{
+	long max;
+	int i, r;
+
+#ifdef _SC_OPEN_MAX
+	max = sysconf(_SC_OPEN_MAX);
+#else
+	max = getdtablesize();
+#endif
+	r = 0;
+	for (i = fd; i < max; i++) {
+		if (close(i) == -1)
+			r = -1;
+	}
+	return r;
+}
diff --git a/dhcpcd-6.8.2/compat/closefrom.h b/dhcpcd-6.8.2/compat/closefrom.h
new file mode 100644
index 0000000..ed21068
--- /dev/null
+++ b/dhcpcd-6.8.2/compat/closefrom.h
@@ -0,0 +1,31 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2009 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef CLOSEFROM_H
+#define CLOSEFROM_H
+int closefrom(int);
+#endif
diff --git a/dhcpcd-6.8.2/compat/dprintf.c b/dhcpcd-6.8.2/compat/dprintf.c
new file mode 100644
index 0000000..33748d0
--- /dev/null
+++ b/dhcpcd-6.8.2/compat/dprintf.c
@@ -0,0 +1,65 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2014 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <unistd.h>
+
+#include "dprintf.h"
+
+int
+vdprintf(int fd, const char * __restrict fmt, va_list va)
+{
+	int e;
+	FILE *fp;
+
+	if ((e = dup(fd)) == -1)
+		return -1;
+
+	if ((fp = fdopen(e, "r+")) == NULL) {
+		close(e);
+		return -1;
+	}
+
+	e = vfprintf(fp, fmt, va);
+	fclose(fp);
+	return e;
+}
+
+int
+dprintf(int fd, const char * __restrict fmt, ...)
+{
+	int e;
+	va_list va;
+
+	va_start(va, fmt);
+	e = vdprintf(fd, fmt, va);
+	va_end(va);
+	return e;
+}
+
diff --git a/dhcpcd-6.8.2/compat/dprintf.h b/dhcpcd-6.8.2/compat/dprintf.h
new file mode 100644
index 0000000..b8cd497
--- /dev/null
+++ b/dhcpcd-6.8.2/compat/dprintf.h
@@ -0,0 +1,43 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2014 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef DPRINTF_H
+#define DPRINTF_H
+
+#include <stdarg.h>
+
+#ifndef __printflike
+# if __GNUC__ > 2 || defined(__INTEL_COMPILER)
+#  define __printflike(a, b) __attribute__((format(printf, a, b)))
+# else
+#  define __printflike(a, b)
+# endif
+#endif
+
+__printflike(2, 0) int vdprintf(int, const char * __restrict, va_list);
+__printflike(2, 3) int dprintf(int, const char * __restrict, ...);
+#endif
diff --git a/dhcpcd-6.8.2/compat/endian.h b/dhcpcd-6.8.2/compat/endian.h
new file mode 100644
index 0000000..8d01738
--- /dev/null
+++ b/dhcpcd-6.8.2/compat/endian.h
@@ -0,0 +1,71 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2014 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef ENDIAN_H
+#define ENDIAN_H
+
+#include <stdint.h>
+
+inline static void
+be32enc(uint8_t *buf, uint32_t u)
+{
+
+	buf[0] = (uint8_t)((u >> 24) & 0xff);
+	buf[1] = (uint8_t)((u >> 16) & 0xff);
+	buf[2] = (uint8_t)((u >> 8) & 0xff);
+	buf[3] = (uint8_t)(u & 0xff);
+}
+
+inline static void
+be64enc(uint8_t *buf, uint64_t u)
+{
+
+	be32enc(buf, (uint32_t)(u >> 32));
+	be32enc(buf + sizeof(uint32_t), (uint32_t)(u & 0xffffffffULL));
+}
+
+inline static uint16_t
+be16dec(const uint8_t *buf)
+{
+
+	return (uint16_t)(buf[0] << 8 | buf[1]);
+}
+
+inline static uint32_t
+be32dec(const uint8_t *buf)
+{
+
+	return (uint32_t)((uint32_t)be16dec(buf) << 16 | be16dec(buf + 2));
+}
+
+inline static uint64_t
+be64dec(const uint8_t *buf)
+{
+
+	return (uint64_t)((uint64_t)be32dec(buf) << 32 | be32dec(buf + 4));
+}
+#endif
diff --git a/dhcpcd-6.8.2/compat/getline.c b/dhcpcd-6.8.2/compat/getline.c
new file mode 100644
index 0000000..8c0cbdf
--- /dev/null
+++ b/dhcpcd-6.8.2/compat/getline.c
@@ -0,0 +1,75 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2009 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "getline.h"
+
+/* Redefine a small buffer for our simple text config files */
+#undef BUFSIZ
+#define BUFSIZ 128
+
+ssize_t
+getline(char ** __restrict buf, size_t * __restrict buflen,
+    FILE * __restrict fp)
+{
+	size_t bytes, newlen;
+	char *newbuf, *p;
+
+	if (buf == NULL || buflen == NULL) {
+		errno = EINVAL;
+		return -1;
+	}
+	if (*buf == NULL)
+		*buflen = 0;
+
+	bytes = 0;
+	do {
+		if (feof(fp))
+			break;
+		if (*buf == NULL || bytes != 0 || *buflen < BUFSIZ) {
+			newlen = *buflen + BUFSIZ;
+			newbuf = realloc(*buf, newlen);
+			if (newbuf == NULL)
+				return -1;
+			*buf = newbuf;
+			*buflen = newlen;
+		}
+		p = *buf + bytes;
+		memset(p, 0, BUFSIZ);
+		if (fgets(p, BUFSIZ, fp) == NULL)
+			break;
+		bytes += strlen(p);
+	} while (bytes == 0 || *(*buf + (bytes - 1)) != '\n');
+	if (bytes == 0)
+		return -1;
+	return bytes;
+}
diff --git a/dhcpcd-6.8.2/compat/getline.h b/dhcpcd-6.8.2/compat/getline.h
new file mode 100644
index 0000000..3db807a
--- /dev/null
+++ b/dhcpcd-6.8.2/compat/getline.h
@@ -0,0 +1,36 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2009 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef GETLINE_H
+#define GETLINE_H
+
+#include <sys/types.h>
+#include <stdio.h>
+
+ssize_t getline(char ** __restrict buf, size_t * __restrict buflen,
+    FILE * __restrict fp);
+#endif
diff --git a/dhcpcd-6.8.2/compat/pollts.c b/dhcpcd-6.8.2/compat/pollts.c
new file mode 100644
index 0000000..905dad6
--- /dev/null
+++ b/dhcpcd-6.8.2/compat/pollts.c
@@ -0,0 +1,63 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2013 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/time.h>
+#include <sys/types.h>
+
+#include <limits.h>
+#include <poll.h>
+#include <signal.h>
+#include <unistd.h>
+
+#include "pollts.h"
+
+#warning "This pollts(2) implementation is not entirely race condition safe."
+#warning "Only operating system support for pollts(2) can correct this."
+
+int
+pollts(struct pollfd *__restrict fds, nfds_t nfds,
+    const struct timespec *__restrict ts, const sigset_t *__restrict sigmask)
+{
+	int r, timeout;
+	sigset_t oldset;
+
+	if (ts == NULL)
+		timeout = -1;
+	else if (ts->tv_sec > INT_MAX / 1000 ||
+	    (ts->tv_sec == INT_MAX / 1000 &&
+	    (ts->tv_nsec + 999999) / 1000000 > INT_MAX % 1000000))
+		timeout = INT_MAX;
+	else
+		timeout = ts->tv_sec * 1000 + (ts->tv_nsec + 999999) / 1000000;
+	if (sigmask && sigprocmask(SIG_SETMASK, sigmask, &oldset) == -1)
+		return -1;
+	r = poll(fds, nfds, timeout);
+	if (sigmask && sigprocmask(SIG_SETMASK, &oldset, NULL) == -1)
+		return -1;
+
+	return r;
+}
diff --git a/dhcpcd-6.8.2/compat/pollts.h b/dhcpcd-6.8.2/compat/pollts.h
new file mode 100644
index 0000000..8fc63d0
--- /dev/null
+++ b/dhcpcd-6.8.2/compat/pollts.h
@@ -0,0 +1,39 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2013 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef PPOLL_H
+#define PPOLL_H
+
+#include <poll.h>
+#include <signal.h>
+#include <time.h>
+
+int
+pollts(struct pollfd *__restrict, nfds_t, const struct timespec *__restrict,
+    const sigset_t *__restrict);
+
+#endif
diff --git a/dhcpcd-6.8.2/compat/posix_spawn.c b/dhcpcd-6.8.2/compat/posix_spawn.c
new file mode 100644
index 0000000..0cb142e
--- /dev/null
+++ b/dhcpcd-6.8.2/compat/posix_spawn.c
@@ -0,0 +1,157 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2012 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* This implementation of posix_spawn is only suitable for the needs of dhcpcd
+ * but it could easily be extended to other applications. */
+
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <errno.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "../common.h"
+#include "posix_spawn.h"
+
+#ifndef _NSIG
+#ifdef _SIG_MAXSIG
+#define _NSIG _SIG_MAXSIG + 1
+#else
+/* Guess */
+#define _NSIG SIGPWR + 1
+#endif
+#endif
+
+extern char **environ;
+
+static int
+posix_spawnattr_handle(const posix_spawnattr_t *attrp)
+{
+	struct sigaction sa;
+	int i;
+
+	if (attrp->posix_attr_flags & POSIX_SPAWN_SETSIGMASK)
+		sigprocmask(SIG_SETMASK, &attrp->posix_attr_sigmask, NULL);
+
+	if (attrp->posix_attr_flags & POSIX_SPAWN_SETSIGDEF) {
+		memset(&sa, 0, sizeof(sa));
+		sa.sa_handler = SIG_DFL;
+		for (i = 1; i < _NSIG; i++) {
+			if (sigismember(&attrp->posix_attr_sigdefault, i)) {
+				if (sigaction(i, &sa, NULL) == -1)
+					return -1;
+			}
+		}
+	}
+
+	return 0;
+}
+
+inline static int
+is_vfork_safe(short int flags)
+{
+	return !(flags & (POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK));
+}
+
+int
+posix_spawn(pid_t *pid, const char *path,
+	const posix_spawn_file_actions_t *file_actions,
+	const posix_spawnattr_t *attrp,
+	char *const argv[], char *const envp[])
+{
+	short int flags;
+	pid_t p;
+	volatile int error;
+
+	error = 0;
+	flags = attrp ? attrp->posix_attr_flags : 0;
+	if (file_actions == NULL && is_vfork_safe(flags))
+		p = vfork();
+	else
+#ifdef THERE_IS_NO_FORK
+		return ENOSYS;
+#else
+		p = fork();
+#endif
+	switch (p) {
+	case -1:
+		return errno;
+	case 0:
+		if (attrp) {
+			error = posix_spawnattr_handle(attrp);
+			if (error)
+				_exit(127);
+		}
+		execve(path, argv, envp);
+		error = errno;
+		_exit(127);
+	default:
+		if (error != 0)
+			waitpid(p, NULL, WNOHANG);
+		else if (pid != NULL)
+			*pid = p;
+		return error;
+	}
+}
+
+int
+posix_spawnattr_init(posix_spawnattr_t *attr)
+{
+
+	memset(attr, 0, sizeof(*attr));
+	attr->posix_attr_flags = 0;
+	sigprocmask(0, NULL, &attr->posix_attr_sigmask);
+	sigemptyset(&attr->posix_attr_sigdefault);
+	return 0;
+}
+
+int
+posix_spawnattr_setflags(posix_spawnattr_t *attr, short flags)
+{
+
+	attr->posix_attr_flags = flags;
+	return 0;
+}
+
+int
+posix_spawnattr_setsigmask(posix_spawnattr_t *attr, const sigset_t *sigmask)
+{
+
+	attr->posix_attr_sigmask = *sigmask;
+	return 0;
+}
+
+int
+posix_spawnattr_setsigdefault(posix_spawnattr_t *attr, const sigset_t *sigmask)
+{
+
+	attr->posix_attr_sigdefault = *sigmask;
+	return 0;
+}
diff --git a/dhcpcd-6.8.2/compat/posix_spawn.h b/dhcpcd-6.8.2/compat/posix_spawn.h
new file mode 100644
index 0000000..ccfb0f0
--- /dev/null
+++ b/dhcpcd-6.8.2/compat/posix_spawn.h
@@ -0,0 +1,53 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2012 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef POSIX_SPAWN_H
+#define POSIX_SPAWN_H
+
+#include <signal.h>
+
+typedef struct {
+	short posix_attr_flags;
+#define POSIX_SPAWN_SETSIGDEF		0x10
+#define POSIX_SPAWN_SETSIGMASK		0x20
+	sigset_t posix_attr_sigmask;
+	sigset_t posix_attr_sigdefault;
+} posix_spawnattr_t;
+
+typedef struct {
+//	int unused;
+} posix_spawn_file_actions_t;
+
+int posix_spawn(pid_t *, const char *,
+    const posix_spawn_file_actions_t *, const posix_spawnattr_t *,
+    char *const [], char *const []);
+int posix_spawnattr_init(posix_spawnattr_t *);
+int posix_spawnattr_setflags(posix_spawnattr_t *, short);
+int posix_spawnattr_setsigmask(posix_spawnattr_t *, const sigset_t *);
+int posix_spawnattr_setsigdefault(posix_spawnattr_t *, const sigset_t *);
+
+#endif
diff --git a/dhcpcd-6.8.2/compat/pselect.c b/dhcpcd-6.8.2/compat/pselect.c
new file mode 100644
index 0000000..78911fa
--- /dev/null
+++ b/dhcpcd-6.8.2/compat/pselect.c
@@ -0,0 +1,65 @@
+/* 
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2013 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/time.h>
+#include <sys/types.h>
+
+#include <limits.h>
+#include <poll.h>
+#include <signal.h>
+#include <unistd.h>
+
+#include "pollts.h"
+
+int
+pollts(struct pollfd *__restrict fds, nfds_t nfds,
+    const struct timespec *__restrict ts, const sigset_t *__restrict sigmask)
+{
+	fd_set read_fds;
+	nfds_t n;
+	int maxfd, r;
+
+	FD_ZERO(&read_fds);
+	maxfd = 0;
+	for (n = 0; n < nfds; n++) {
+		if (fds[n].events & POLLIN) {
+			FD_SET(fds[n].fd, &read_fds);
+			if (fds[n].fd > maxfd)
+				maxfd = fds[n].fd;
+		}
+	}
+
+	r = pselect(maxfd + 1, &read_fds, NULL, NULL, ts, sigmask);
+	if (r > 0) {
+		for (n = 0; n < nfds; n++) {
+			fds[n].revents =
+			    FD_ISSET(fds[n].fd, &read_fds) ? POLLIN : 0;
+		}
+	}
+
+	return r;
+}
diff --git a/dhcpcd-6.8.2/compat/queue.h b/dhcpcd-6.8.2/compat/queue.h
new file mode 100644
index 0000000..99ac6b9
--- /dev/null
+++ b/dhcpcd-6.8.2/compat/queue.h
@@ -0,0 +1,175 @@
+/*	$NetBSD: queue.h,v 1.65 2013/12/25 17:19:34 christos Exp $	*/
+
+/*
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)queue.h	8.5 (Berkeley) 8/20/94
+ */
+
+#ifndef COMPAT_QUEUE_H
+#define COMPAT_QUEUE_H
+
+/*
+ * Tail queue definitions.
+ */
+#ifndef TAILQ_END
+#define	TAILQ_END(head)			(NULL)
+#endif
+
+#ifndef TAILQ_HEAD
+#define	_TAILQ_HEAD(name, type, qual)					\
+struct name {								\
+	qual type *tqh_first;		/* first element */		\
+	qual type *qual *tqh_last;	/* addr of last next element */	\
+}
+#define TAILQ_HEAD(name, type)	_TAILQ_HEAD(name, struct type,)
+
+#define	TAILQ_HEAD_INITIALIZER(head)					\
+	{ TAILQ_END(head), &(head).tqh_first }
+
+#define	_TAILQ_ENTRY(type, qual)					\
+struct {								\
+	qual type *tqe_next;		/* next element */		\
+	qual type *qual *tqe_prev;	/* address of previous next element */\
+}
+#define TAILQ_ENTRY(type)	_TAILQ_ENTRY(struct type,)
+#endif /* !TAILQ_HEAD */
+
+/*
+ * Tail queue access methods.
+ */
+#ifndef TAILQ_FIRST
+#define	TAILQ_FIRST(head)		((head)->tqh_first)
+#define	TAILQ_NEXT(elm, field)		((elm)->field.tqe_next)
+#define	TAILQ_LAST(head, headname) \
+	(*(((struct headname *)((head)->tqh_last))->tqh_last))
+#define	TAILQ_PREV(elm, headname, field) \
+	(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
+#define	TAILQ_EMPTY(head)		(TAILQ_FIRST(head) == TAILQ_END(head))
+#endif /* !TAILQ_FIRST */
+
+#ifndef TAILQ_FOREACH
+#define	TAILQ_FOREACH(var, head, field)					\
+	for ((var) = ((head)->tqh_first);				\
+	    (var) != TAILQ_END(head);					\
+	    (var) = ((var)->field.tqe_next))
+
+#define	TAILQ_FOREACH_REVERSE(var, head, headname, field)		\
+	for ((var) = (*(((struct headname *)((head)->tqh_last))->tqh_last));\
+	    (var) != TAILQ_END(head);					\
+	    (var) = (*(((struct headname *)((var)->field.tqe_prev))->tqh_last)))
+#endif /* !TAILQ_FOREACH */
+
+#ifndef TAILQ_INIT
+#define	TAILQ_INIT(head) do {						\
+	(head)->tqh_first = TAILQ_END(head);				\
+	(head)->tqh_last = &(head)->tqh_first;				\
+} while (/*CONSTCOND*/0)
+
+#define	TAILQ_INSERT_HEAD(head, elm, field) do {			\
+	if (((elm)->field.tqe_next = (head)->tqh_first) != TAILQ_END(head))\
+		(head)->tqh_first->field.tqe_prev =			\
+		    &(elm)->field.tqe_next;				\
+	else								\
+		(head)->tqh_last = &(elm)->field.tqe_next;		\
+	(head)->tqh_first = (elm);					\
+	(elm)->field.tqe_prev = &(head)->tqh_first;			\
+} while (/*CONSTCOND*/0)
+
+#define	TAILQ_INSERT_TAIL(head, elm, field) do {			\
+	(elm)->field.tqe_next = TAILQ_END(head);			\
+	(elm)->field.tqe_prev = (head)->tqh_last;			\
+	*(head)->tqh_last = (elm);					\
+	(head)->tqh_last = &(elm)->field.tqe_next;			\
+} while (/*CONSTCOND*/0)
+
+#define	TAILQ_INSERT_AFTER(head, listelm, elm, field) do {		\
+	if (((elm)->field.tqe_next = (listelm)->field.tqe_next) !=	\
+	    TAILQ_END(head))						\
+		(elm)->field.tqe_next->field.tqe_prev =			\
+		    &(elm)->field.tqe_next;				\
+	else								\
+		(head)->tqh_last = &(elm)->field.tqe_next;		\
+	(listelm)->field.tqe_next = (elm);				\
+	(elm)->field.tqe_prev = &(listelm)->field.tqe_next;		\
+} while (/*CONSTCOND*/0)
+
+#define	TAILQ_INSERT_BEFORE(listelm, elm, field) do {			\
+	(elm)->field.tqe_prev = (listelm)->field.tqe_prev;		\
+	(elm)->field.tqe_next = (listelm);				\
+	*(listelm)->field.tqe_prev = (elm);				\
+	(listelm)->field.tqe_prev = &(elm)->field.tqe_next;		\
+} while (/*CONSTCOND*/0)
+
+#define	TAILQ_REMOVE(head, elm, field) do {				\
+	if (((elm)->field.tqe_next) != TAILQ_END(head))			\
+		(elm)->field.tqe_next->field.tqe_prev =			\
+		    (elm)->field.tqe_prev;				\
+	else								\
+		(head)->tqh_last = (elm)->field.tqe_prev;		\
+	*(elm)->field.tqe_prev = (elm)->field.tqe_next;			\
+} while (/*CONSTCOND*/0)
+#endif /* !TAILQ_INIT */
+
+#ifndef TAILQ_REPLACE
+#define TAILQ_REPLACE(head, elm, elm2, field) do {                      \
+        if (((elm2)->field.tqe_next = (elm)->field.tqe_next) !=		\
+	    TAILQ_END(head))						\
+                (elm2)->field.tqe_next->field.tqe_prev =                \
+                    &(elm2)->field.tqe_next;                            \
+        else                                                            \
+                (head)->tqh_last = &(elm2)->field.tqe_next;             \
+        (elm2)->field.tqe_prev = (elm)->field.tqe_prev;                 \
+        *(elm2)->field.tqe_prev = (elm2);                               \
+} while (/*CONSTCOND*/0)
+#endif /* !TAILQ_REPLACE */
+
+#ifndef TAILQ_FOREACH_SAFE
+#define	TAILQ_FOREACH_SAFE(var, head, field, next)			\
+	for ((var) = TAILQ_FIRST(head);					\
+	    (var) != TAILQ_END(head) &&					\
+	    ((next) = TAILQ_NEXT(var, field), 1); (var) = (next))
+
+#define	TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, prev)	\
+	for ((var) = TAILQ_LAST((head), headname);			\
+	    (var) != TAILQ_END(head) &&					\
+	    ((prev) = TAILQ_PREV((var), headname, field), 1); (var) = (prev))
+#endif /* !TAILQ_FOREACH_SAFE */
+
+#ifndef TAILQ_CONCAT
+#define	TAILQ_CONCAT(head1, head2, field) do {				\
+	if (!TAILQ_EMPTY(head2)) {					\
+		*(head1)->tqh_last = (head2)->tqh_first;		\
+		(head2)->tqh_first->field.tqe_prev = (head1)->tqh_last;	\
+		(head1)->tqh_last = (head2)->tqh_last;			\
+		TAILQ_INIT((head2));					\
+	}								\
+} while (/*CONSTCOND*/0)
+#endif /* !TAILQ_CONCAT */
+
+#endif	/* !COMAPT_QUEUE_H */
diff --git a/dhcpcd-6.8.2/compat/strlcpy.c b/dhcpcd-6.8.2/compat/strlcpy.c
new file mode 100644
index 0000000..47776a0
--- /dev/null
+++ b/dhcpcd-6.8.2/compat/strlcpy.c
@@ -0,0 +1,52 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2009 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+
+#include "strlcpy.h"
+
+size_t
+strlcpy(char *dst, const char *src, size_t size)
+{
+	const char *s = src;
+	size_t n = size;
+
+	if (n && --n)
+		do {
+			if (!(*dst++ = *src++))
+				break;
+		} while (--n);
+
+	if (!n) {
+		if (size)
+			*dst = '\0';
+		while (*src++);
+	}
+
+
+	return (size_t)(src - s - 1);
+}
diff --git a/dhcpcd-6.8.2/compat/strlcpy.h b/dhcpcd-6.8.2/compat/strlcpy.h
new file mode 100644
index 0000000..951390a
--- /dev/null
+++ b/dhcpcd-6.8.2/compat/strlcpy.h
@@ -0,0 +1,34 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2009 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef STRLCPY_H
+#define STRLCPY_H
+
+#include <sys/types.h>
+
+size_t strlcpy(char *, const char *, size_t);
+#endif
diff --git a/dhcpcd-6.8.2/compat/strtoi.c b/dhcpcd-6.8.2/compat/strtoi.c
new file mode 100644
index 0000000..701d57b
--- /dev/null
+++ b/dhcpcd-6.8.2/compat/strtoi.c
@@ -0,0 +1,112 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <errno.h>
+#include <inttypes.h>
+#include <stdlib.h>
+
+#include "strtoi.h"
+
+intmax_t
+strtoi(const char * __restrict nptr, char ** __restrict endptr, int base,
+    intmax_t lo, intmax_t hi, int *rstatus)
+{
+	int serrno;
+	intmax_t r;
+	char *ep;
+	int rep;
+
+	if (endptr == NULL)
+		endptr = &ep;
+	if (rstatus == NULL)
+		rstatus = &rep;
+
+	serrno = errno;
+	errno = 0;
+	r = strtoimax(nptr, endptr, base);
+	*rstatus = errno;
+	errno = serrno;
+
+	if (*rstatus == 0) {
+		if (nptr == *endptr)
+			*rstatus = ECANCELED;
+		else if (**endptr != '\0')
+			*rstatus = ENOTSUP;
+	}
+
+	if (r < lo) {
+		if (*rstatus == 0)
+			*rstatus = ERANGE;
+		return lo;
+	}
+	if (r > hi) {
+		if (*rstatus == 0)
+			*rstatus = ERANGE;
+		return hi;
+	}
+	return r;
+}
+
+uintmax_t
+strtou(const char * __restrict nptr, char ** __restrict endptr, int base,
+    uintmax_t lo, uintmax_t hi, int *rstatus)
+{
+	int serrno;
+	uintmax_t r;
+	char *ep;
+	int rep;
+
+	if (endptr == NULL)
+		endptr = &ep;
+	if (rstatus == NULL)
+		rstatus = &rep;
+
+	serrno = errno;
+	errno = 0;
+	r = strtoumax(nptr, endptr, base);
+	*rstatus = errno;
+	errno = serrno;
+
+	if (*rstatus == 0) {
+		if (nptr == *endptr)
+			*rstatus = ECANCELED;
+		else if (**endptr != '\0')
+			*rstatus = ENOTSUP;
+	}
+
+	if (r < lo) {
+		if (*rstatus == 0)
+			*rstatus = ERANGE;
+		return lo;
+	}
+	if (r > hi) {
+		if (*rstatus == 0)
+			*rstatus = ERANGE;
+		return hi;
+	}
+	return r;
+}
diff --git a/dhcpcd-6.8.2/compat/strtoi.h b/dhcpcd-6.8.2/compat/strtoi.h
new file mode 100644
index 0000000..4b0c878
--- /dev/null
+++ b/dhcpcd-6.8.2/compat/strtoi.h
@@ -0,0 +1,37 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef STRTOI_H
+#define STRTOI_H
+
+#include <inttypes.h>
+
+intmax_t strtoi(const char * __restrict nptr, char ** __restrict endptr,
+    int base, intmax_t lo, intmax_t hi, int *rstatus);
+uintmax_t strtou(const char * __restrict nptr, char ** __restrict endptr,
+    int base, uintmax_t lo, uintmax_t hi, int *rstatus);
+#endif
diff --git a/dhcpcd-6.8.2/config-null.mk b/dhcpcd-6.8.2/config-null.mk
new file mode 100644
index 0000000..c7a8de3
--- /dev/null
+++ b/dhcpcd-6.8.2/config-null.mk
@@ -0,0 +1,3 @@
+# This space left intentionally blank
+
+DHCPCD_SRCS+=	dhcpcd-embedded.c
diff --git a/dhcpcd-6.8.2/config.h b/dhcpcd-6.8.2/config.h
new file mode 100644
index 0000000..c4c943d
--- /dev/null
+++ b/dhcpcd-6.8.2/config.h
@@ -0,0 +1,18 @@
+/* linux */
+#define SYSCONFDIR	"/system/etc/dhcpcd-6.8.2"
+#define SBINDIR	"/system/etc/dhcpcd-6.8.2"
+#define LIBEXECDIR	"/system/etc/dhcpcd-6.8.2"
+#define DBDIR	"/data/misc/dhcp-6.8.2"
+#define RUNDIR	"/data/misc/dhcp-6.8.2"
+#define HAVE_EPOLL
+#ifndef NBBY
+#define NBBY  8
+#endif
+#include "compat/closefrom.h"
+#include "compat/endian.h"
+#include "compat/posix_spawn.h"
+#include "compat/queue.h"
+#include "compat/strtoi.h"
+
+#include <signal.h>
+#include <linux/rtnetlink.h>
diff --git a/dhcpcd-6.8.2/configure b/dhcpcd-6.8.2/configure
new file mode 100755
index 0000000..fe612d9
--- /dev/null
+++ b/dhcpcd-6.8.2/configure
@@ -0,0 +1,1263 @@
+#!/bin/sh
+# Try and be like autotools configure, but without autotools
+
+echo "configure args: $*"
+exec 3>config.log
+
+# Ensure that we do not inherit these from env
+HOOKSET=false
+INET=
+INET6=
+ARC4RANDOM=
+CLOSEFROM=
+GETLINE=
+STRLCPY=
+UDEV=
+OS=
+BUILD=
+HOST=
+HOSTCC=
+TARGET=
+DEBUG=
+FORK=
+STATIC=
+INCLUDEDIR=
+DEVS=
+EMBEDDED=
+POLL=
+DBUS=
+
+for x do
+	opt=${x%%=*}
+	var=${x#*=}
+	case "$opt" in
+	--os|OS) OS=$var;;
+	--debug) DEBUG=$var;;
+	--disable-debug) DEBUG=no;;
+	--enable-debug) DEBUG=yes;;
+	--fork) FORK=$var;;
+	--disable-fork) FORK=no;;
+	--enable-fork) FORK=yes;;
+	--disable-static) STATIC=no;;
+	--enable-static) STATIC=yes;;
+	--disable-ipv4) INET=no;;
+	--enable-ipv4) INET=yes;;
+	--disable-ipv6) INET6=no;;
+	--enable-ipv6) INET6=yes;;
+	--disable-embedded) EMBEDDED=no;;
+	--enable-embedded) EMBEDDED=yes;;
+	--enable-dbus) DBUS=yes;;
+	--disable-dbus) DBUS=no;;
+	--prefix) PREFIX=$var;;
+	--sysconfdir) SYSCONFDIR=$var;;
+	--bindir|--sbindir) SBINDIR=$var;;
+	--libexecdir) LIBEXECDIR=$var;;
+	--statedir|--localstatedir) STATEDIR=$var;;
+	--dbdir) DBDIR=$var;;
+	--rundir) RUNDIR=$var;;
+	--mandir) MANDIR=$var;;
+	--with-ccopts|CFLAGS) CFLAGS=$var;;
+	CC) CC=$var;;
+	CPPFLAGS) CPPFLAGS=$var;;
+	--with-hook) HOOKSCRIPTS="$HOOKSCRIPTS${HOOKSCRIPTS:+ }$var";;
+	--with-hooks|HOOKSCRIPTS) HOOKSCRIPTS=$var; HOOKSET=true;;
+	--build) BUILD=$var;;
+	--host) HOST=$var; HOSTCC=$var-;;
+	--target) TARGET=$var;;
+	--libdir) LIBDIR=$var;;
+	--without-arc4random) ARC4RANDOM=no;;
+	--without-closefrom) CLOSEFROM=no;;
+	--without-getline) GETLINE=no;;
+	--without-strlcpy) STRLCPY=no;;
+        --without-posix_spawn) POSIX_SPAWN=no;;
+	--without-md5) MD5=no;;
+	--without-sha2) SHA2=no;;
+	--without-sha256) SHA2=no;;
+	--without-dev) DEV=no;;
+	--without-udev) UDEV=no;;
+	--with-poll) POLL="$var";;
+	--serviceexists) SERVICEEXISTS=$var;;
+	--servicecmd) SERVICECMD=$var;;
+	--servicestatus) SERVICESTATUS=$var;;
+	--includedir) eval INCLUDEDIR="$INCLUDEDIR${INCLUDEDIR:+ }$var";;
+	--datadir|--infodir) ;; # ignore autotools
+	--disable-maintainer-mode|--disable-dependency-tracking) ;;
+	--disable-silent-rules) ;;
+	-V|--version)
+		v=$(sed -ne 's/.*VERSION[[:space:]]*"\([^"]*\).*/\1/p' defs.h);
+		c=$(sed -ne 's/^.*copyright\[\] = "\([^"]*\).*/\1/p' dhcpcd.c);
+		echo "dhcpcd-$v $c";
+		exit 0;;
+	-h|--help) cat <<EOF
+\`configure' configures this package to adapt to many kinds of systems.
+
+Usage: configure [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE.  See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+  -h, --help              display this help and exit
+      --help=short        display options specific to this package
+  -V, --version           display version information and exit
+
+Installation directories:
+  --prefix=PREFIX         install architecture-independent files in PREFIX [/]
+
+By default, \`make install' will install all the files in \'/sbin',
+\`/libexec', etc. You can specify
+an installation prefix other than \`/' using \`--prefix',
+for instance \`--prefix=$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+  --bindir=DIR            user executables [PREFIX/bin]
+  --sbindir=DIR           system admin executables [PREFIX/sbin]
+  --libexecdir=DIR        program executables [PREFIX/libexec]
+  --sysconfdir=DIR        read-only single-machine data [PREFIX/etc]
+  --localstatedir=DIR     modifiable single-machine data [PREFIX/var]
+  --libdir=DIR            object code libraries [PREFIX/lib]
+  --includedir=DIR        C header files [PREFIX/include]
+  --mandir=DIR            man documentation [PREFIX/man]
+
+System types:
+  --build=BUILD           configure for building on BUILD [guessed]
+  --host=HOST       build programs to run on HOST [BUILD]
+  --target=TARGET   configure for building compilers for TARGET [HOST]
+
+Optional Features:
+  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
+  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
+
+Some influential environment variables:
+  CC          C compiler command
+  CFLAGS      C compiler flags
+  LDFLAGS     linker flags, e.g. -L<lib dir> if you have libraries in a
+              nonstandard directory <lib dir>
+  CPPFLAGS    C/C++ preprocessor flags, e.g. -I<include dir> if you have
+              headers in a nonstandard directory <include dir>
+  CPP         C preprocessor
+
+Use these variables to override the choices made by \`configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+EOF
+exit 0
+;;
+	*) echo "$0: WARNING: unknown option $opt" >&2;;
+	esac
+done
+
+: ${SED:=sed}
+: ${GREP:=grep}
+: ${WC:=wc}
+
+: ${FORK:=yes}
+: ${SYSCONFDIR:=$PREFIX/etc}
+: ${SBINDIR:=$PREFIX/sbin}
+: ${LIBDIR:=$PREFIX/lib}
+: ${LIBEXECDIR:=$PREFIX/libexec}
+: ${STATEDIR:=/var}
+: ${DBDIR:=$STATEDIR/db}
+: ${RUNDIR:=$STATEDIR/run}
+: ${MANDIR:=${PREFIX:-/usr}/share/man}
+
+eval SYSCONFDIR="$SYSCONFDIR"
+eval LIBDIR="$LIBDIR"
+eval LIBEXECDIR="$LIBEXECDIR"
+eval STATEDIR="$STATEDIR"
+eval DBDIR="$DBDIR"
+eval RUNDIR="$RUNDIR"
+eval MANDIR="$MANDIR"
+
+_which()
+{
+	x="$(which "$1" 2>/dev/null)"
+	if [ -n "$x" ]; then
+		echo "$x"
+		return 0
+	fi
+	for x in /sbin/"$1" /usr/sbin/"$1" \
+		/usr/pkg/sbin/"$1" /usr/local/sbin/"$1"
+	do
+		if [ -e "$x" ]; then
+			echo "$x"
+			return 0
+		fi
+	done
+	return 1
+}
+
+CONFIG_H=config.h
+CONFIG_MK=config.mk
+
+if [ -z "$BUILD" ]; then
+	# autoconf target triplet: cpu-vendor-os
+	BUILD=$(uname -m)-unknown-$(uname -s | tr '[:upper:]' '[:lower:]')
+fi
+: ${HOST:=$BUILD}
+
+if [ -z "$OS" ]; then
+	echo "Deriving operating system from ... $HOST"
+	# Derive OS from cpu-vendor-[kernel-]os
+	CPU=${HOST%%-*}
+	REST=${HOST#*-}
+	if [ "$CPU" != "$REST" ]; then
+		VENDOR=${REST%%-*}
+		REST=${REST#*-}
+		if [ "$VENDOR" != "$REST" ]; then
+			# Use kernel if given, otherwise os
+			OS=${REST%%-*}
+		else
+			# 2 tupple
+			OS=$VENDOR
+			VENDOR=
+		fi
+	fi
+
+        # Work with cpu-kernel-os, ie Debian
+	case "$VENDOR" in
+	linux*|kfreebsd*) OS=$VENDOR; VENDOR= ;;
+	esac
+	# Special case
+	case "$OS" in
+	gnu*) OS=hurd;; # No HURD support as yet
+	esac
+fi
+
+echo "Configuring dhcpcd for ... $OS"
+rm -f $CONFIG_H $CONFIG_MK
+echo "# $OS" >$CONFIG_MK
+echo "/* $OS */" >$CONFIG_H
+
+for x in SYSCONFDIR SBINDIR LIBDIR LIBEXECDIR DBDIR RUNDIR; do
+	eval v=\$$x
+	# Make files look nice for import
+	l=$((10 - ${#x}))
+	unset t
+	[ $l -gt 3 ] && t="	"
+	echo "$x=$t	$v" >>$CONFIG_MK
+	unset t
+	[ $l -gt 2 ] && t="	"
+	echo "#define $x$t	\"$v\"" >>$CONFIG_H
+done
+echo "LIBDIR=		$LIBDIR" >>$CONFIG_MK
+echo "MANDIR=		$MANDIR" >>$CONFIG_MK
+
+# Always obey CC.
+if [ -n "$CC" ]; then
+	HOSTCC=
+else
+	CC=cc
+	_COMPILERS="cc clang gcc pcc icc"
+fi
+# Only look for a cross compiler if --host and --build are not the same
+if [ -n "$HOSTCC" -a "$BUILD" != "$HOST" ]; then
+	for _CC in $_COMPILERS; do
+		_CC=$(_which "$HOSTCC$_CC")
+		if [ -x "$_CC" ]; then
+			CC=$_CC
+			break
+		fi
+	done
+fi
+if ! type "$CC" >/dev/null 2>&1; then
+	for _CC in $_COMPILERS; do
+		_CC=$(_which "$_CC")
+		if [ -x "$_CC" ]; then
+			CC=$_CC
+			break
+		fi
+	done
+fi
+
+# Set to blank, then append user config
+# We do this so our SED call to append to XCC remains portable
+if [ -n "$CFLAGS" ]; then
+	echo "CFLAGS=" >>$CONFIG_MK
+	echo "CFLAGS+=	$CFLAGS" >>$CONFIG_MK
+fi
+if [ -n "$CPPFLAGS" ]; then
+	echo "CPPFLAGS=" >>$CONFIG_MK
+	echo "CPPFLAGS+=	$CPPFLAGS" >>$CONFIG_MK
+fi
+if [ -n "$LDFLAGS" ]; then
+	echo "LDFLAGS=" >>$CONFIG_MK
+	echo "LDFLAGS+=	$LDFLAGS" >>$CONFIG_MK
+fi
+
+# NetBSD: Even if we build for $PREFIX, the clueless user might move us to /
+LDELF=/libexec/ld.elf_so
+if [ -e "$LDELF" ]; then
+	echo "Linking against $LDELF"
+	echo "LDFLAGS+=	-Wl,-dynamic-linker=$LDELF" >>$CONFIG_MK
+	echo "LDFLAGS+=	-Wl,-rpath=${LIBDIR}" >>$CONFIG_MK
+fi
+
+if [ -z "$PREFIX" -o "$PREFIX" = / ]; then
+	ALLOW_USR_LIBS=false
+else
+	ALLOW_USR_LIBS=true
+fi
+case "$OS" in
+linux*|sunos*) ;;
+*)
+	if ! [ -x "$LDELF" -o -x /libexec/ld-elf.so.[0-9]* ] && \
+	    [ -z "$PREFIX" -o "$PREFIX" = "/" ]
+	then
+		echo "Forcing a static build for $OS and \$PREFIX of /"
+		STATIC=yes
+		ALLOW_USR_LIBS=true
+	fi
+	;;
+esac
+if [ "$STATIC" = yes ]; then
+	echo "LDFLAGS+=	-static" >>$CONFIG_MK
+fi
+for x in $INCLUDEDIR; do
+	echo "CPPFLAGS+=	-I$x" >>$CONFIG_MK
+done
+
+if [ -z "$DEBUG" -a -f .fslckout ]; then
+	printf "Found fossil checkout ... "
+	DEBUG=yes
+fi
+if [ -n "$DEBUG" -a "$DEBUG" != no -a "$DEBUG" != false ]; then
+	echo "Adding debugging CFLAGS"
+	cat <<EOF >>$CONFIG_MK
+CFLAGS+=	-g -Wall -Wextra
+CFLAGS+=	-Wmissing-prototypes -Wmissing-declarations
+CFLAGS+=	-Wmissing-format-attribute -Wnested-externs
+CFLAGS+=	-Winline -Wcast-align -Wcast-qual -Wpointer-arith
+CFLAGS+=	-Wreturn-type -Wswitch -Wshadow
+CFLAGS+=	-Wcast-qual -Wwrite-strings
+CFLAGS+=	-Wconversion
+CFLAGS+=	-Wformat=2
+CFLAGS+=	-Wpointer-sign -Wmissing-noreturn
+EOF
+	case "$OS" in
+	mirbsd*|openbsd*);; # OpenBSD has many redundant decs in system headers
+	*)		echo "CFLAGS+=	-Wredundant-decls" >>$CONFIG_MK;;
+	esac
+
+	case "$OS" in
+	sunos*);;
+	*)		echo "CFLAGS+=	-Wstrict-overflow" >>$CONFIG_MK;;
+	esac
+fi
+
+if [ -z "$EMBEDDED" -o "$EMBEDDED" = yes ]; then
+	echo "dhcpcd-definitions.conf will be embedded in dhcpcd itself"
+	echo "DHCPCD_SRCS+=	dhcpcd-embedded.c" >>$CONFIG_MK
+else
+	echo "dhcpcd-definitions.conf will be installed to $LIBEXECDIR"
+	echo "CFLAGS+= -DEMBEDDED_CONFIG=\\\"$LIBEXECDIR/dhcpcd-definitions.conf\\\"" >>$CONFIG_MK
+	echo "EMBEDDEDINSTALL=	_embeddedinstall" >>$CONFIG_MK
+fi
+
+if [ -n "$FORK" -a "$FORK" != yes -a "$FORK" != true ]; then
+	echo "There is no fork"
+	echo "CPPFLAGS+=	-DTHERE_IS_NO_FORK" >>$CONFIG_MK
+fi
+
+case "$OS" in
+freebsd*|kfreebsd*)
+	echo "CPPFLAGS+=	-D_GNU_SOURCE" >>$CONFIG_MK
+	echo "DHCPCD_SRCS+=	if-bsd.c" >>$CONFIG_MK
+	;;
+linux*)
+	echo "CPPFLAGS+=	-D_GNU_SOURCE" >>$CONFIG_MK
+	# Large File Support, should be fine for 32-bit systems.
+	# But if this is the case, why is it not set by default?
+	echo "CPPFLAGS+=	-D_FILE_OFFSET_BITS=64" >>$CONFIG_MK
+	echo "CPPFLAGS+=	-D_LARGEFILE_SOURCE" >>$CONFIG_MK
+	echo "CPPFLAGS+=	-D_LARGEFILE64_SOURCE" >>$CONFIG_MK
+	echo "DHCPCD_SRCS+=	if-linux.c" >>$CONFIG_MK
+	# for RTM_NEWADDR and friends
+	echo "#include		<asm/types.h> /* fix broken headers */" >>$CONFIG_H
+	echo "#include		<linux/rtnetlink.h>" >>$CONFIG_H
+	;;
+qnx*)
+	echo "CPPFLAGS+=	-D__EXT" >>$CONFIG_MK
+	echo "DHCPCD_SRCS+=	if-bsd.c" >>$CONFIG_MK
+	;;
+sunos*)
+	echo "WARNING!!! Solaris support is at early development stage!" >&2
+	echo "so don't expect it to work just yet, patches welcome" >&2
+	echo "CPPFLAGS+=	-D_XPG4_2 -D__EXTENSIONS__ -DBSD_COMP" \
+	    >>$CONFIG_MK
+	echo "DHCPCD_SRCS+=	if-sun.c" >>$CONFIG_MK
+
+	# IPv6 won't work, but it will at least compile.
+	echo "CPPFLAGS+=	-DIN6_IFF_DETACHED=0" >>$CONFIG_MK
+	echo "CPPFLAGS+=	-DIN6_IFF_TENTATIVE=0" >>$CONFIG_MK
+	echo "CPPFLAGS+=	-DIN6_IFF_DUPLICATED=0" >>$CONFIG_MK
+	;;
+*)
+	echo "DHCPCD_SRCS+=	if-bsd.c" >>$CONFIG_MK
+	;;
+esac
+
+if [ -z "$INET" -o "$INET" = yes ]; then
+	echo "CPPFLAGS+=	-DINET" >>$CONFIG_MK
+	echo "DHCPCD_SRCS+=	arp.c dhcp.c ipv4.c ipv4ll.c" >>$CONFIG_MK
+fi
+if [ -z "$INET6" -o "$INET6" = yes ]; then
+	echo "CPPFLAGS+=	-DINET6" >>$CONFIG_MK
+	echo "DHCPCD_SRCS+=	ipv6.c ipv6nd.c dhcp6.c" >>$CONFIG_MK
+fi
+
+if [ "$DBUS" = yes ]; then
+	echo "DBUS_SUPPORT= yes" >>$CONFIG_MK
+	echo "DBUSINSTALL=  _dbusinstall" >>$CONFIG_MK
+	echo "CPPFLAGS+=    -DPASSIVE_MODE" >>$CONFIG_MK
+	echo "DHCPCD_SRCS+= dbus/dbus-dict.c dbus/rpc-dbus.c" >>$CONFIG_MK
+else
+	echo "DHCPCD_SRCS+= rpc-stub.c" >>$CONFIG_MK
+fi
+
+if [ -z  "$HOOKSCRIPTS" ]; then
+	echo "DHCPCD_SRCS+= script-stub.c" >>$CONFIG_MK
+else
+	echo "HOOK_SUPPORT= yes" >>$CONFIG_MK
+	echo "SCRIPTSINSTALL=  _scriptsinstall" >>$CONFIG_MK
+	echo "DHCPCD_SRCS+= script.c" >>$CONFIG_MK
+fi
+
+echo "Using compiler .. $CC"
+# Add CPPFLAGS and CFLAGS to CC for testing features
+XCC="$CC `$SED -n -e 's/CPPFLAGS+=*\(.*\)/\1/p' $CONFIG_MK`"
+XCC="$XCC `$SED -n -e 's/CFLAGS+=*\(.*\)/\1/p' $CONFIG_MK`"
+
+# Now test we can use the compiler with our CFLAGS
+cat <<EOF >_test.c
+int main(void) {
+	return 0;
+}
+EOF
+_CC=false
+if $XCC _test.c -o _test >/dev/null 2>&3; then
+	[ -x _test ] && _CC=true
+fi
+rm -f _test.c _test
+if ! $_CC; then
+	echo "$CC does not create executables"
+	exit 1
+fi
+[ "$CC" != cc ] && echo "CC=	$CC" >>$CONFIG_MK
+$CC --version | $SED -e '1!d'
+
+if [ "$OS" = linux ]; then
+	printf "Testing for nl80211 ... "
+	cat <<EOF >_nl80211.c
+#include <linux/nl80211.h>
+int main(void) {
+	return 0;
+}
+EOF
+	if $XCC _nl80211.c -o _nl80211 2>&3; then
+		echo "yes"
+		echo "#define HAVE_NL80211_H" >>$CONFIG_H
+	else
+		echo "no"
+	fi
+	rm -f _nl80211.c _nl80211
+
+	# Even though we have nl80211, we only use it as a fallback
+	# because it's currently possible to configure a kernel
+	# where the SSID associated to won't be reported by nl80211
+	# but will be via WEXT.
+	echo "DHCPCD_SRCS+=	if-linux-wext.c" >>$CONFIG_MK
+fi
+
+abort=false
+# We require the libc to support non standard functions, like getifaddrs
+printf "Testing for getifaddrs ... "
+cat <<EOF >_getifaddrs.c
+#include <sys/types.h>
+#include <ifaddrs.h>
+int main(void) {
+	struct ifaddrs *ifap;
+	return getifaddrs(&ifap);
+}
+EOF
+if $XCC _getifaddrs.c -o _getifaddrs 2>&3; then
+	echo "yes"
+elif $XCC _getifaddrs.c -o _getifaddrs -lsocket 2>&3; then
+	echo "yes (-lsocket)"
+	echo "LDADD+=		-lsocket" >>$CONFIG_MK
+else
+	echo "no"
+	echo "libc support for getifaddrs is required - aborting" >&2
+	abort=true
+fi
+rm -f _getifaddrs.c _getifaddrs
+$abort && exit 1
+
+printf "Testing for clock_gettime ... "
+cat <<EOF >_clock_gettime.c
+#include <time.h>
+int main(void) {
+	struct timespec ts;
+	return clock_gettime(CLOCK_MONOTONIC, &ts);
+}
+EOF
+if $XCC _clock_gettime.c -o _clock_gettime 2>&3; then
+	echo "yes"
+elif $XCC _clock_gettime.c -lrt -o _clock_gettime 2>&3; then
+	echo "yes (-lrt)"
+	echo "LDADD+=		-lrt" >>$CONFIG_MK
+else
+	echo "no"
+	echo "libc support for clock_getttime is required - aborting" >&2
+	abort=true
+fi
+rm -f _clock_gettime.c _clock_gettime
+$abort && exit 1
+
+printf "Testing for inet_ntoa ... "
+cat <<EOF >_inet_ntoa.c
+#include <netinet/in.h>
+#include <arpa/inet.h>
+int main(void) {
+	struct in_addr in;
+	inet_ntoa(in);
+	return 0;
+}
+EOF
+if $XCC _inet_ntoa.c -o _inet_ntoa 2>&3; then
+	echo "yes"
+elif $XCC _inet_ntoa.c -lnsl -o _inet_ntoa 2>&3; then
+	echo "yes (-lnsl)"
+	echo "LDADD+=		-lnsl" >>$CONFIG_MK
+elif $XCC _inet_ntoa.c -lsocket -o _inet_ntoa 2>&3; then
+	echo "yes (-lsocket)"
+	echo "LDADD+=		-lsocket" >>$CONFIG_MK	
+else
+	echo "no"
+	echo "libc support for inet_ntoa is required - aborting" >&2
+	abort=true
+fi
+rm -f _inet_ntoa.c _inet_ntoa
+$abort && exit 1
+
+if [ -z "$ARC4RANDOM" ]; then
+	printf "Testing for arc4random ... "
+	cat <<EOF >_arc4random.c
+#include <stdlib.h>
+int main(void) {
+	arc4random();
+	return 0;
+}
+EOF
+	if $XCC _arc4random.c -o _arc4random 2>&3; then
+		ARC4RANDOM=yes
+	else
+		ARC4RANDOM=no
+	fi
+	echo "$ARC4RANDOM"
+	rm -f _arc4random.c _arc4random
+fi
+if [ "$ARC4RANDOM" = no ]; then
+	echo "COMPAT_SRCS+=	compat/arc4random.c" >>$CONFIG_MK
+	echo "#include		\"compat/arc4random.h\"" >>$CONFIG_H
+fi
+
+if [ -z "$ARC4RANDOM_UNIFORM" ]; then
+	printf "Testing for arc4random_uniform ... "
+	cat <<EOF >_arc4random_uniform.c
+#include <stdlib.h>
+int main(void) {
+	arc4random_uniform(100);
+	return 0;
+}
+EOF
+	if $XCC _arc4random_uniform.c -o _arc4random_uniform 2>&3; then
+		ARC4RANDOM_UNIFORM=yes
+	else
+		ARC4RANDOM_UNIFORM=no
+	fi
+	echo "$ARC4RANDOM"
+	rm -f _arc4random_uniform.c _arc4random_uniform
+fi
+if [ "$ARC4RANDOM_UNIFORM" = no ]; then
+	echo "COMPAT_SRCS+=	compat/arc4random_uniform.c" >>$CONFIG_MK
+	echo "#include		\"compat/arc4random_uniform.h\"" >>$CONFIG_H
+fi
+
+if [ -z "$CLOSEFROM" ]; then
+	printf "Testing for closefrom ... "
+	cat <<EOF >_closefrom.c
+#include <unistd.h>
+int main(void) {
+	closefrom(3);
+	return 0;
+}
+EOF
+	if $XCC _closefrom.c -o _closefrom 2>&3; then
+		CLOSEFROM=yes
+	else
+		CLOSEFROM=no
+	fi
+	echo "$CLOSEFROM"
+	rm -f _closefrom.c _closefrom
+fi
+if [ "$CLOSEFROM" = no ]; then
+	echo "COMPAT_SRCS+=	compat/closefrom.c" >>$CONFIG_MK
+	echo "#include		\"compat/closefrom.h\"" >>$CONFIG_H
+fi
+
+if [ -z "$GETLINE" ]; then
+	printf "Testing for getline ... "
+	cat <<EOF >_getline.c
+#include <stdio.h>
+int main(void) {
+	char *buf = NULL;
+	size_t n = 0;
+	getline(&buf, &n, stdin);
+	return 0;
+}
+EOF
+	if $XCC _getline.c -o _getline 2>&3; then
+		GETLINE=yes
+	else
+		GETLINE=no
+	fi
+	echo "$GETLINE"
+	rm -f _getline.c _getline
+fi
+if [ "$GETLINE" = no ]; then
+	echo "COMPAT_SRCS+=	compat/getline.c" >>$CONFIG_MK
+	echo "#include		\"compat/getline.h\"" >>$CONFIG_H
+fi
+
+if [ -z "$STRLCPY" ]; then
+	printf "Testing for strlcpy ... "
+	cat <<EOF >_strlcpy.c
+#include <string.h>
+int main(void) {
+	const char s1[] = "foo";
+	char s2[10];
+	strlcpy(s2, s1, sizeof(s2));
+	return 0;
+}
+EOF
+	if $XCC _strlcpy.c -o _strlcpy 2>&3; then
+		STRLCPY=yes
+	else
+		STRLCPY=no
+	fi
+	echo "$STRLCPY"
+	rm -f _strlcpy.c _strlcpy
+fi
+if [ "$STRLCPY" = no ]; then
+	echo "COMPAT_SRCS+=	compat/strlcpy.c" >>$CONFIG_MK
+	echo "#include		\"compat/strlcpy.h\"" >>$CONFIG_H
+fi
+
+if [ -z "$STRTOI" ]; then
+	printf "Testing for strtoi ... "
+	cat <<EOF >_strtoi.c
+#include <stdlib.h>
+#include <limits.h>
+#include <inttypes.h>
+int main(void) {
+	int e;
+	return strtoi("1234", NULL, 0, 0, INT32_MAX, &e);
+}
+EOF
+	if $XCC _strtoi.c -o _strtoi 2>&3; then
+		STRTOI=yes
+	else
+		STRTOI=no
+	fi
+	echo "$STRTOI"
+	rm -f _strtoi.c _strtoi
+fi
+if [ "$STRTOI" = no ]; then
+	echo "COMPAT_SRCS+=	compat/strtoi.c" >>$CONFIG_MK
+	echo "#include		\"compat/strtoi.h\"" >>$CONFIG_H
+fi
+
+if [ -z "$DPRINTF" ]; then
+	printf "Testing for dprintf ... "
+	cat <<EOF >_dprintf.c
+#include <stdio.h>
+int main(void) {
+	return dprintf(0, "%d", 0);
+}
+EOF
+	if $XCC _dprintf.c -o _dprintf 2>&3; then
+		DPRINTF=yes
+	else
+		DPRINTF=no
+	fi
+	echo "$DPRINTF"
+	rm -f _dprintf.c _dprintf
+fi
+if [ "$DPRINTF" = no ]; then
+	echo "COMPAT_SRCS+=	compat/dprintf.c" >>$CONFIG_MK
+	echo "#include		\"compat/dprintf.h\"" >>$CONFIG_H
+fi
+
+if [ -z "$TAILQ_FOREACH_SAFE" ]; then
+	printf "Testing for TAILQ_FOREACH_SAFE ... "
+	cat <<EOF >_queue.c
+#include <sys/queue.h>
+int main(void) {
+#ifndef TAILQ_FOREACH_SAFE
+#error TAILQ_FOREACH_SAFE
+#endif
+	return 0;
+}
+EOF
+	if $XCC _queue.c -o _queue 2>&3; then
+		TAILQ_FOREACH_SAFE=yes
+		TAILQ_FOREACH=yes
+	else
+		TAILQ_FOREACH_SAFE=no
+	fi
+	echo "$TAILQ_FOREACH_SAFE"
+	rm -f _queue.c _queue
+fi
+
+if [ -z "$TAILQ_CONCAT" ]; then
+	printf "Testing for TAILQ_CONCAT ..."
+	cat <<EOF >_queue.c
+#include <sys/queue.h>
+int main(void) {
+#ifndef TAILQ_CONCAT
+#error TAILQ_CONCAT
+#endif
+	return 0;
+}
+EOF
+	if $XCC _queue.c -o _queue 2>&3; then
+		TAILQ_CONCAT=yes
+		TAILQ_FOREACH=yes
+	else
+		TAILQ_CONCAT=no
+	fi
+	echo "$TAILQ_CONCAT"
+	rm -f _queue.c _queue
+fi
+
+if [ -z "$TAILQ_FOREACH" ]; then
+	printf "Testing for TAILQ_FOREACH ... "
+	cat <<EOF >_queue.c
+#include <sys/queue.h>
+int main(void) {
+#ifndef TAILQ_FOREACH
+#error TAILQ_FOREACH
+#endif
+	return 0;
+}
+EOF
+	if $XCC _queue.c -o _queue 2>&3; then
+		TAILQ_FOREACH=yes
+	else
+		TAILQ_FOREACH=no
+	fi
+	echo "$TAILQ_FOREACH"
+	rm -f _queue.c _queue
+fi
+
+if [ "$TAILQ_FOREACH_SAFE" = no -o "$TAILQ_CONCAT" = no ]; then
+	# If we don't include sys/queue.h then clang analyser finds
+	# too many false positives.
+	# See http://llvm.org/bugs/show_bug.cgi?id=18222
+	# Strictly speaking this isn't needed, but I like it to help
+	# catch any nasties.
+	if [ "$TAILQ_FOREACH" = yes ]; then
+		echo "#include		<sys/queue.h>">>$CONFIG_H
+	fi
+	echo "#include		\"compat/queue.h\"">>$CONFIG_H
+else
+	echo "#include		<sys/queue.h>" >>$CONFIG_H
+fi
+
+if [ -z "$POSIX_SPAWN" ]; then
+	printf "Testing for posix_spawn ... "
+	cat <<EOF >_posix_spawn.c
+#include <spawn.h>
+#include <stdlib.h>
+
+#ifdef __OpenBSD__
+#  include <sys/param.h>
+#  if OpenBSD<201505
+#    error posix_spawn was fixed in OpenBSD-5.7
+#  endif
+#endif
+
+int main(void) {
+	posix_spawn(NULL, NULL, NULL, NULL, NULL, NULL);
+	return 0;
+}
+EOF
+	if $XCC _posix_spawn.c -o _posix_spawn 2>&3; then
+		POSIX_SPAWN=yes
+	else
+		POSIX_SPAWN=no
+	fi
+	echo "$POSIX_SPAWN"
+	rm -f _posix_spawn.c _posix_spawn
+fi
+if [ "$POSIX_SPAWN" = no ]; then
+	echo "COMPAT_SRCS+=	compat/posix_spawn.c" >>$CONFIG_MK
+else
+	echo "#define HAVE_SPAWN_H" >>$CONFIG_H
+fi
+
+if [ -z "$POLL" ]; then
+	printf "Testing for kqueue1 ... "
+	cat <<EOF >_kqueue.c
+#include <sys/types.h>
+#include <sys/event.h>
+int main(void) {
+	return kqueue1(0);
+}
+EOF
+	if $XCC _kqueue.c -o _kqueue 2>&3; then
+		POLL=kqueue1
+ 		echo "yes"
+ 	else
+ 		echo "no"
+ 	fi
+	rm -f _kqueue.c _kqueue
+fi
+if [ -z "$POLL" ]; then
+	printf "Testing for kqueue ... "
+	cat <<EOF >_kqueue.c
+#include <sys/types.h>
+#include <sys/event.h>
+int main(void) {
+	return kqueue();
+}
+EOF
+	if $XCC _kqueue.c -o _kqueue 2>&3; then
+		POLL=kqueue
+ 		echo "yes"
+ 	else
+ 		echo "no"
+ 	fi
+	rm -f _kqueue.c _kqueue
+fi
+if [ -z "$POLL" ]; then
+	printf "Testing for epoll ... "
+	cat <<EOF >_epoll.c
+#ifdef __linux__
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 37)
+#error kernel has buggy epoll_wait timeout
+#endif
+#endif
+
+#include <sys/epoll.h>
+#include <unistd.h>
+int main(void) {
+	epoll_create1(EPOLL_CLOEXEC);
+	epoll_pwait(-1, NULL, 0, 0, NULL);
+	return 0;
+}
+EOF
+	if $XCC _epoll.c -o _epoll 2>&3; then
+		POLL=epoll
+		echo "#define HAVE_EPOLL" >>$CONFIG_MK
+		echo "yes"
+	else
+		echo "no"
+	fi
+	rm -f _epoll.c _epoll
+fi
+if [ -z "$POLL" ]; then
+	printf "Testing for ppoll ... "
+	cat <<EOF >_ppoll.c
+#include <poll.h>
+#include <stdlib.h>
+int main(void) {
+	ppoll(NULL, 0, NULL, NULL);
+	return 0;
+}
+EOF
+	if $XCC _ppoll.c -o _ppoll 2>&3; then
+		POLL=ppoll
+ 		echo "yes"
+ 	else
+ 		echo "no"
+ 	fi
+	rm -f _ppoll.c _ppoll
+fi
+if [ -z "$POLL" ]; then
+	printf "Testing for pselect ... "
+	cat <<EOF >_pselect.c
+#include <sys/select.h>
+#include <stdlib.h>
+int main(void) {
+	pselect(0, NULL, NULL, NULL, NULL, NULL);
+	return 0;
+}
+EOF
+	if $XCC _pselect.c -o _pselect 2>&3; then
+		POLL=pselect
+		echo "yes"
+	else
+		echo "no"
+	fi
+	rm -f _pselect.c _pselect
+fi
+case "$POLL" in
+kqueue1)
+	echo "#define HAVE_KQUEUE" >>$CONFIG_H
+	echo "#define HAVE_KQUEUE1" >>$CONFIG_H
+	;;
+kqueue)
+	echo "#define HAVE_KQUEUE" >>$CONFIG_H
+	;;
+epoll)
+	echo "#define HAVE_EPOLL" >>$CONFIG_H
+	;;
+ppoll)
+	echo "#define pollts		ppoll" >>$CONFIG_H
+	;;
+pselect)
+	echo "COMPAT_SRCS+=	compat/pselect.c" >>$CONFIG_MK
+	echo "#include		\"compat/pollts.h\"" >>$CONFIG_H
+	;;
+*)
+	echo "COMPAT_SRCS+=	compat/pollts.c" >>$CONFIG_MK
+	echo "#include		\"compat/pollts.h\"" >>$CONFIG_H
+	;;
+esac
+
+if [ -z "$BE64ENC" ]; then
+	printf "Testing for be64enc ... "
+	cat <<EOF >_be64enc.c
+#include <sys/endian.h>
+#include <stdlib.h>
+int main(void) {
+	be64enc(NULL, 0);
+}
+EOF
+	if $XCC _be64enc.c -o _be64enc 2>&3; then
+		BE64ENC=yes
+	else
+		BE64ENC=no
+	fi
+	echo "$BE64ENC"
+	rm -f _be64enc.c _be64enc
+fi
+if [ "$BE64ENC" = no ]; then
+	echo "#include		\"compat/endian.h\"" >>$CONFIG_H
+fi
+
+if [ -z "$MD5" ]; then
+	MD5_LIB=
+	printf "Testing for MD5Init ... "
+	cat <<EOF >_md5.c
+#include <sys/types.h>
+#include <md5.h>
+#include <stdlib.h>
+int main(void) {
+	MD5_CTX context;
+	MD5Init(&context);
+	return 0;
+}
+EOF
+	# We only want to link to libmd if it exists in /lib
+	if $ALLOW_USR_LIBS; then
+		set -- /
+	else
+		set -- $(ls /lib/libmd.so.* 2>/dev/null)
+	fi
+	if $XCC _md5.c -o _md5 2>&3; then
+		MD5=yes
+	elif [ -e "$1" ] && $XCC _md5.c -lmd -o _md5 2>&3; then
+		MD5="yes (-lmd)"
+		MD5_LIB=-lmd
+	else
+		MD5=no
+	fi
+	echo "$MD5"
+	rm -f _md5.c _md5
+fi
+if [ "$MD5" = no ]; then
+	echo "MD5_SRC=	crypt/md5.c" >>$CONFIG_MK
+else
+	echo "MD5_SRC=" >>$CONFIG_MK
+	echo "#define HAVE_MD5_H" >>$CONFIG_H
+	[ -n "$MD5_LIB" ] && echo "LDADD+=		$MD5_LIB" >>$CONFIG_MK
+fi
+
+if [ -z "$SHA2_H" -a -z "$SHA2" -o "$SHA2" != no ]; then
+	printf "Testing for sha2.h ... "
+	if [ -e /usr/include/sha2.h ]; then
+		SHA2_H=sha2.h
+	elif [ -e /usr/include/sha256.h ]; then
+		SHA2_H=sha256.h
+	fi
+	if [ -n "$SHA2_H" ]; then
+		echo "$SHA2_H"
+	else
+		echo "no"
+	fi
+fi
+
+if [ -z "$SHA2" ]; then
+	SHA2_LIB=
+	SHA2_RENAMED=
+	printf "Testing for SHA256_Init ... "
+	cat <<EOF >_sha256.c
+#include <sys/types.h>
+EOF
+	[ -n "$SHA2_H" ] && echo "#include <$SHA2_H>">>_sha256.c
+	cat <<EOF >>_sha256.c
+#include <stdlib.h>
+int main(void) {
+	SHA256_CTX context;
+	SHA256_Init(&context);
+	return 0;
+}
+EOF
+	# We only want to link to libmd if it exists in /lib
+	if $ALLOW_USR_LIBS; then
+		set -- /
+	else
+		set -- $(ls /lib/libmd.so.* 2>/dev/null)
+	fi
+	if $XCC _sha256.c -o _sha256 2>&3; then
+		SHA2=yes
+	elif [ -e "$1" ] && $XCC _sha256.c -lmd -o _sha256 2>&3; then
+		SHA2="yes (-lmd)"
+		SHA2_LIB=-lmd
+	else
+		SHA2=no
+	fi
+	echo "$SHA2"
+	rm -f _sha256.c _sha256
+	if [ "$SHA2" = no ]; then
+		# Did OpenBSD really change this? grrrr
+		printf "Testing for SHA256Init ... "
+		cat <<EOF >_sha256.c
+#include <sys/types.h>
+EOF
+		[ -n "$SHA2_H" ] && echo "#include <$SHA2_H>">>_sha256.c
+		cat <<EOF >>_sha256.c
+#include <stdlib.h>
+int main(void) {
+	SHA2_CTX context;
+	SHA256Init(&context);
+	return 0;
+}
+EOF
+		# We only want to link to libmd if it exists in /lib
+		if $ALLOW_USR_LIBS; then
+			set -- /
+		else
+			set -- $(ls /lib/libmd.so.* 2>/dev/null)
+		fi
+		if $XCC	_sha256.c -o _sha256 2>&3; then
+			SHA2=yes
+			SHA2_RENAMED=yes
+		elif [ -e "$1" ] && $XCC _sha256.c -lmd -o _sha256 2>&3
+		then
+			SHA2="yes (-lmd)"
+			SHA2_LIB=-lmd
+			SHA2_RENAMED=yes
+		else
+			SHA2=no
+		fi
+		echo "$SHA2"
+		rm -f _sha256.c _sha256
+	fi
+fi
+if [ "$SHA2" = no ]; then
+	echo "SHA256_SRC=	crypt/sha256.c" >>$CONFIG_MK
+else
+	echo "SHA256_SRC=" >>$CONFIG_MK
+	echo "#define SHA2_H		<$SHA2_H>" >>$CONFIG_H
+	if [ "$SHA2_RENAMED" = yes ]; then
+		echo "#define SHA256_CTX	SHA2_CTX" >>$CONFIG_H
+		echo "#define SHA256_Init	SHA256Init" >>$CONFIG_H
+		echo "#define SHA256_Update	SHA256Update" >>$CONFIG_H
+		echo "#define SHA256_Final	SHA256Final" >>$CONFIG_H
+	fi
+	[ -n "$SHA2_LIB" ] && echo "LDADD+=		$SHA2_LIB" >>$CONFIG_MK
+fi
+
+if [ "$DEV" != no -a "$UDEV" != no ]; then
+	printf "Checking for libudev ... "
+	if type pkg-config >/dev/null 2>&1; then
+		LIBUDEV_CFLAGS=$(pkg-config --cflags libudev 2>&3)
+		LIBUDEV_LIBS=$(pkg-config --libs libudev 2>&3)
+	fi
+fi
+if [ "$DEV" != no -a "$UDEV" != no -a -n "$LIBUDEV_LIBS" ]; then
+	echo "yes"
+	[ -z "$DEV" ] && DEV=yes
+	echo "DEV_PLUGINS+=	udev" >>$CONFIG_MK
+	if [ -n "$LIBUDEV_CFLAGS" ]; then
+		echo "LIBUDEV_CFLAGS=		$LIBUDEV_CFLAGS" >>$CONFIG_MK
+	fi
+	echo "LIBUDEV_LIBS=	$LIBUDEV_LIBS" >>$CONFIG_MK
+
+	printf "Checking udev_monitor_filter_add_match_subsystem_devtype ... "
+	cat <<EOF >_udev.c
+#include <libudev.h>
+#include <stdlib.h>
+int main(void) {
+	udev_monitor_filter_add_match_subsystem_devtype(NULL, NULL, NULL);
+	return 0;
+}
+EOF
+	if $XCC $LIBUDEV_CFLAGS _udev.c -o _udev $LIBUDEV_LIBS 2>&3
+	then
+		echo "yes"
+	else
+		echo "LIBUDEV_CPPFLAGS+=	-DLIBUDEV_NOFILTER" >>$CONFIG_MK
+		echo "no"
+	fi
+	rm -f _udev.c _udev
+
+	printf "Checking udev_device_get_is_initialized ... "
+	cat <<EOF >_udev.c
+#include <libudev.h>
+#include <stdlib.h>
+int main(void) {
+	udev_device_get_is_initialized(NULL);
+	return 0;
+}
+EOF
+	if $XCC $LIBUDEV_CFLAGS _udev.c -o _udev $LIBUDEV_LIBS 2>&3
+	then
+		echo "yes"
+	else
+		echo "LIBUDEV_CPPFLAGS+=	-DLIBUDEV_NOINIT" >>$CONFIG_MK
+		echo "no"
+	fi
+	rm -f _udev.c _udev
+elif [ "$DEV" != no -a "$UDEV" != no ]; then
+	echo "no"
+fi
+
+if [ "$DEV" = yes ]; then
+	echo "DHCPCD_SRCS+=	dev.c" >>$CONFIG_MK
+	echo "CPPFLAGS+=	-DPLUGIN_DEV" >>$CONFIG_MK
+	echo "MKDIRS+=	dev" >>$CONFIG_MK
+
+	printf "Testing for dlopen ... "
+	cat <<EOF >_dlopen.c
+#include <dlfcn.h>
+#include <stdlib.h>
+int main(void) {
+	dlopen(NULL, 0);
+	return 0;
+}
+EOF
+	if $XCC _dlopen.c -o _dlopen 2>&3; then
+		echo "yes"
+	elif $XCC _dlopen.c -ldl -o _dlopen 2>&3; then
+		echo "yes (-ldl)"
+		echo "LDADD+=		-ldl" >>$CONFIG_MK
+	else
+		echo "no"
+		echo "libc for dlopen is required - aborting"
+	fi
+	rm -f _dlopen.c _dlopen
+	$abort && exit 1
+fi
+
+# Transform for a make file
+SERVICEEXISTS=$(echo "$SERVICEEXISTS" | $SED \
+	-e 's:\\:\\\\:g' \
+	-e 's:\&:\\\&:g' \
+	-e 's:\$:\\\\\$\$:g' \
+)
+echo "SERVICEEXISTS=	$SERVICEEXISTS" >>config.mk
+SERVICECMD=$(echo "$SERVICECMD" | $SED \
+	-e 's:\\:\\\\:g' \
+	-e 's:\&:\\\&:g' \
+	-e 's:\$:\\\\\$\$:g' \
+)
+echo "SERVICECMD=	$SERVICECMD" >>config.mk
+SERVICESTATUS=$(echo "$SERVICESTATUS" | $SED \
+	-e 's:\\:\\\\:g' \
+	-e 's:\&:\\\&:g' \
+	-e 's:\$:\\\\\$\$:g' \
+)
+echo "SERVICESTATUS=	$SERVICESTATUS" >>config.mk
+
+HOOKS=
+if ! $HOOKSET; then
+	printf "Checking for ntpd ... "
+	NTPD=$(_which ntpd)
+	if [ -n "$NTPD" ]; then
+		echo "$NTPD (50-ntp.conf)"
+		HOOKS="$HOOKS${HOOKS:+ }50-ntp.conf"
+	else
+		echo "not found"
+	fi
+
+	printf "Checking for ypbind ... "
+	YPBIND=$(_which ypbind)
+	if [ -n "$YPBIND" ]; then
+		YPHOOK="50-ypbind"
+		if strings "$YPBIND" | $GREP -q yp\\.conf; then
+			YPHOOK="50-yp.conf"
+			YPOS="Linux"
+		elif strings "$YPBIND" | $GREP -q \\.ypservers; then
+			YPOS="NetBSD"
+			echo "YPDOMAIN_DIR=	/var/yp" >>$CONFIG_MK
+			echo "YPDOMAIN_SUFFIX=.ypservers" >>$CONFIG_MK
+		elif strings "$YPBIND" | $GREP -q /etc/yp; then
+			YPOS="OpenBSD"
+			echo "YPDOMAIN_DIR=	/etc/yp" >>$CONFIG_MK
+			echo "YPDOMAIN_SUFFIX=" >>$CONFIG_MK
+		else
+			YPOS="FreeBSD"
+			echo "YPDOMAIN_DIR=" >>$CONFIG_MK
+			echo "YPDOMAIN_SUFFIX=" >>$CONFIG_MK
+		fi
+		echo "$YPBIND ($YPHOOK${YPOS:+ }$YPOS)"
+		HOOKS="$HOOKS${HOOKS:+ }$YPHOOK"
+	else
+		echo "not found"
+	fi
+fi
+
+if cd dhcpcd-hooks; then
+	for x in $HOOKSCRIPTS; do
+		printf "Finding hook $x ... "
+		for h in [0-9][0-9]"-$x" \
+		    [0-9][0-9]"-$x.sh" \
+		    [0-9][0-9]"-$x.conf"
+		do
+			[ -e "$h" ] && break
+		done
+		if [ ! -e "$h" ]; then
+			echo "no"
+		else
+			echo "$h"
+			case " $HOOKS " in
+			*" $h "*)	;;
+			*)		HOOKS="$HOOKS${HOOKS:+ }$h";;
+			esac
+		fi
+	done
+	cd ..
+fi
+echo "HOOKSCRIPTS=	$HOOKS" >>$CONFIG_MK
+
+echo
+echo "   SYSCONFDIR =		$SYSCONFDIR"
+echo "   SBINDIR =		$SBINDIR"
+echo "   LIBDIR =		$LIBDIR"
+echo "   LIBEXECDIR =		$LIBEXECDIR"
+echo "   DBDIR =		$DBDIR"
+echo "   RUNDIR =		$RUNDIR"
+echo "   MANDIR =		$MANDIR"
+echo "   HOOKSCRIPTS =	$HOOKS"
+echo
+
+rm -f dhcpcd tests/test
diff --git a/dhcpcd-6.8.2/control.c b/dhcpcd-6.8.2/control.c
new file mode 100644
index 0000000..1e53d0e
--- /dev/null
+++ b/dhcpcd-6.8.2/control.c
@@ -0,0 +1,443 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/uio.h>
+#include <sys/un.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "config.h"
+#include "common.h"
+#include "dhcpcd.h"
+#include "control.h"
+#include "eloop.h"
+
+#ifndef SUN_LEN
+#define SUN_LEN(su) \
+            (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
+#endif
+
+static void
+control_queue_purge(struct dhcpcd_ctx *ctx, char *data)
+{
+	int found;
+	struct fd_list *fp;
+	struct fd_data *fpd;
+
+	/* If no other fd queue has the same data, free it */
+	found = 0;
+	TAILQ_FOREACH(fp, &ctx->control_fds, next) {
+		TAILQ_FOREACH(fpd, &fp->queue, next) {
+			if (fpd->data == data) {
+				found = 1;
+				break;
+			}
+		}
+	}
+	if (!found)
+		free(data);
+}
+
+static void
+control_queue_free(struct fd_list *fd)
+{
+	struct fd_data *fdp;
+
+	while ((fdp = TAILQ_FIRST(&fd->queue))) {
+		TAILQ_REMOVE(&fd->queue, fdp, next);
+		if (fdp->freeit)
+			control_queue_purge(fd->ctx, fdp->data);
+		free(fdp);
+	}
+	while ((fdp = TAILQ_FIRST(&fd->free_queue))) {
+		TAILQ_REMOVE(&fd->free_queue, fdp, next);
+		free(fdp);
+	}
+}
+
+static void
+control_delete(struct fd_list *fd)
+{
+
+	TAILQ_REMOVE(&fd->ctx->control_fds, fd, next);
+	eloop_event_delete(fd->ctx->eloop, fd->fd, 0);
+	close(fd->fd);
+	control_queue_free(fd);
+	free(fd);
+}
+
+static void
+control_handle_data(void *arg)
+{
+	struct fd_list *fd = arg;
+	char buffer[1024], *e, *p, *argvp[255], **ap, *a;
+	ssize_t bytes;
+	size_t len;
+	int argc;
+
+	bytes = read(fd->fd, buffer, sizeof(buffer) - 1);
+	if (bytes == -1 || bytes == 0) {
+		/* Control was closed or there was an error.
+		 * Remove it from our list. */
+		control_delete(fd);
+		return;
+	}
+	buffer[bytes] = '\0';
+	p = buffer;
+	e = buffer + bytes;
+
+	/* Each command is \n terminated
+	 * Each argument is NULL separated */
+	while (p < e) {
+		argc = 0;
+		ap = argvp;
+		while (p < e) {
+			argc++;
+			if ((size_t)argc >= sizeof(argvp) / sizeof(argvp[0])) {
+				errno = ENOBUFS;
+				return;
+			}
+			a = *ap++ = p;
+			len = strlen(p);
+			p += len + 1;
+			if (len && a[len - 1] == '\n') {
+				a[len - 1] = '\0';
+				break;
+			}
+		}
+		*ap = NULL;
+		if (dhcpcd_handleargs(fd->ctx, fd, argc, argvp) == -1) {
+			logger(fd->ctx, LOG_ERR,
+			    "%s: dhcpcd_handleargs: %m", __func__);
+			if (errno != EINTR && errno != EAGAIN) {
+				control_delete(fd);
+				return;
+			}
+		}
+	}
+}
+
+static void
+control_handle1(struct dhcpcd_ctx *ctx, int lfd, unsigned int fd_flags)
+{
+	struct sockaddr_un run;
+	socklen_t len;
+	struct fd_list *l;
+	int fd, flags;
+
+	len = sizeof(run);
+	if ((fd = accept(lfd, (struct sockaddr *)&run, &len)) == -1)
+		return;
+	if ((flags = fcntl(fd, F_GETFD, 0)) == -1 ||
+	    fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
+	{
+		close(fd);
+	        return;
+	}
+	if ((flags = fcntl(fd, F_GETFL, 0)) == -1 ||
+	    fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1)
+	{
+		close(fd);
+	        return;
+	}
+	l = malloc(sizeof(*l));
+	if (l) {
+		l->ctx = ctx;
+		l->fd = fd;
+		l->flags = fd_flags;
+		TAILQ_INIT(&l->queue);
+		TAILQ_INIT(&l->free_queue);
+		TAILQ_INSERT_TAIL(&ctx->control_fds, l, next);
+		eloop_event_add(ctx->eloop, l->fd,
+		    control_handle_data, l, NULL, NULL);
+	} else
+		close(fd);
+}
+
+static void
+control_handle(void *arg)
+{
+	struct dhcpcd_ctx *ctx = arg;
+
+	control_handle1(ctx, ctx->control_fd, 0);
+}
+
+static void
+control_handle_unpriv(void *arg)
+{
+	struct dhcpcd_ctx *ctx = arg;
+
+	control_handle1(ctx, ctx->control_unpriv_fd, FD_UNPRIV);
+}
+
+static int
+make_sock(struct sockaddr_un *sa, const char *ifname, int unpriv)
+{
+	int fd;
+
+#ifdef SOCK_CLOEXEC
+	if ((fd = socket(AF_UNIX,
+	    SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)) == -1)
+		return -1;
+#else
+	int flags;
+
+	if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
+		return -1;
+	if ((flags = fcntl(fd, F_GETFD, 0)) == -1 ||
+	    fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
+	{
+		close(fd);
+	        return -1;
+	}
+	if ((flags = fcntl(fd, F_GETFL, 0)) == -1 ||
+	    fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1)
+	{
+		close(fd);
+	        return -1;
+	}
+#endif
+	memset(sa, 0, sizeof(*sa));
+	sa->sun_family = AF_UNIX;
+	if (unpriv)
+		strlcpy(sa->sun_path, UNPRIVSOCKET, sizeof(sa->sun_path));
+	else {
+		snprintf(sa->sun_path, sizeof(sa->sun_path), CONTROLSOCKET,
+		    ifname ? "-" : "", ifname ? ifname : "");
+	}
+	return fd;
+}
+
+#define S_PRIV (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)
+#define S_UNPRIV (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
+
+static int
+control_start1(struct dhcpcd_ctx *ctx, const char *ifname, mode_t fmode)
+{
+	struct sockaddr_un sa;
+	int fd;
+	socklen_t len;
+
+	if ((fd = make_sock(&sa, ifname, (fmode & S_UNPRIV) == S_UNPRIV)) == -1)
+		return -1;
+	len = (socklen_t)SUN_LEN(&sa);
+	unlink(sa.sun_path);
+	if (bind(fd, (struct sockaddr *)&sa, len) == -1 ||
+	    chmod(sa.sun_path, fmode) == -1 ||
+	    (ctx->control_group &&
+	    chown(sa.sun_path, geteuid(), ctx->control_group) == -1) ||
+	    listen(fd, sizeof(ctx->control_fds)) == -1)
+	{
+		close(fd);
+		unlink(sa.sun_path);
+		return -1;
+	}
+	
+	if ((fmode & S_UNPRIV) != S_UNPRIV)
+		strlcpy(ctx->control_sock, sa.sun_path,
+		    sizeof(ctx->control_sock));
+	return fd;
+}
+
+int
+control_start(struct dhcpcd_ctx *ctx, const char *ifname)
+{
+	int fd;
+
+	if ((fd = control_start1(ctx, ifname, S_PRIV)) == -1)
+		return -1;
+
+	ctx->control_fd = fd;
+	eloop_event_add(ctx->eloop, fd, control_handle, ctx, NULL, NULL);
+
+	if (ifname == NULL && (fd = control_start1(ctx, NULL, S_UNPRIV)) != -1){
+		/* We must be in master mode, so create an unpriviledged socket
+		 * to allow normal users to learn the status of dhcpcd. */
+		ctx->control_unpriv_fd = fd;
+		eloop_event_add(ctx->eloop, fd, control_handle_unpriv,
+		    ctx, NULL, NULL);
+	}
+	return ctx->control_fd;
+}
+
+int
+control_stop(struct dhcpcd_ctx *ctx)
+{
+	int retval = 0;
+	struct fd_list *l;
+
+	if (ctx->options & DHCPCD_FORKED)
+		goto freeit;
+
+	if (ctx->control_fd == -1)
+		return 0;
+	eloop_event_delete(ctx->eloop, ctx->control_fd, 0);
+	close(ctx->control_fd);
+	ctx->control_fd = -1;
+	if (unlink(ctx->control_sock) == -1)
+		retval = -1;
+
+	if (ctx->control_unpriv_fd != -1) {
+		eloop_event_delete(ctx->eloop, ctx->control_unpriv_fd, 0);
+		close(ctx->control_unpriv_fd);
+		ctx->control_unpriv_fd = -1;
+		if (unlink(UNPRIVSOCKET) == -1)
+			retval = -1;
+	}
+
+freeit:
+	while ((l = TAILQ_FIRST(&ctx->control_fds))) {
+		TAILQ_REMOVE(&ctx->control_fds, l, next);
+		eloop_event_delete(ctx->eloop, l->fd, 0);
+		close(l->fd);
+		control_queue_free(l);
+		free(l);
+	}
+
+	return retval;
+}
+
+int
+control_open(struct dhcpcd_ctx *ctx, const char *ifname)
+{
+	struct sockaddr_un sa;
+	socklen_t len;
+
+	if ((ctx->control_fd = make_sock(&sa, ifname, 0)) == -1)
+		return -1;
+	len = (socklen_t)SUN_LEN(&sa);
+	if (connect(ctx->control_fd, (struct sockaddr *)&sa, len) == -1) {
+		close(ctx->control_fd);
+		ctx->control_fd = -1;
+		return -1;
+	}
+	return 0;
+}
+
+ssize_t
+control_send(struct dhcpcd_ctx *ctx, int argc, char * const *argv)
+{
+	char buffer[1024];
+	int i;
+	size_t len, l;
+
+	if (argc > 255) {
+		errno = ENOBUFS;
+		return -1;
+	}
+	len = 0;
+	for (i = 0; i < argc; i++) {
+		l = strlen(argv[i]) + 1;
+		if (len + l > sizeof(buffer)) {
+			errno = ENOBUFS;
+			return -1;
+		}
+		memcpy(buffer + len, argv[i], l);
+		len += l;
+	}
+	return write(ctx->control_fd, buffer, len);
+}
+
+static void
+control_writeone(void *arg)
+{
+	struct fd_list *fd;
+	struct iovec iov[2];
+	struct fd_data *data;
+
+	fd = arg;
+	data = TAILQ_FIRST(&fd->queue);
+	iov[0].iov_base = &data->data_len;
+	iov[0].iov_len = sizeof(size_t);
+	iov[1].iov_base = data->data;
+	iov[1].iov_len = data->data_len;
+	if (writev(fd->fd, iov, 2) == -1) {
+		logger(fd->ctx, LOG_ERR,
+		    "%s: writev fd %d: %m", __func__, fd->fd);
+		if (errno != EINTR && errno != EAGAIN)
+			control_delete(fd);
+		return;
+	}
+
+	TAILQ_REMOVE(&fd->queue, data, next);
+	if (data->freeit)
+		control_queue_purge(fd->ctx, data->data);
+	data->data = NULL; /* safety */
+	data->data_len = 0;
+	TAILQ_INSERT_TAIL(&fd->free_queue, data, next);
+
+	if (TAILQ_FIRST(&fd->queue) == NULL)
+		eloop_event_delete(fd->ctx->eloop, fd->fd, 1);
+}
+
+int
+control_queue(struct fd_list *fd, char *data, size_t data_len, uint8_t fit)
+{
+	struct fd_data *d;
+	size_t n;
+
+	d = TAILQ_FIRST(&fd->free_queue);
+	if (d) {
+		TAILQ_REMOVE(&fd->free_queue, d, next);
+	} else {
+		n = 0;
+		TAILQ_FOREACH(d, &fd->queue, next) {
+			if (++n == CONTROL_QUEUE_MAX) {
+				errno = ENOBUFS;
+				return -1;
+			}
+		}
+		d = malloc(sizeof(*d));
+		if (d == NULL)
+			return -1;
+	}
+	d->data = data;
+	d->data_len = data_len;
+	d->freeit = fit;
+	TAILQ_INSERT_TAIL(&fd->queue, d, next);
+	eloop_event_add(fd->ctx->eloop, fd->fd,
+	    NULL, NULL, control_writeone, fd);
+	return 0;
+}
+
+void
+control_close(struct dhcpcd_ctx *ctx)
+{
+
+	if (ctx->control_fd != -1) {
+		close(ctx->control_fd);
+		ctx->control_fd = -1;
+	}
+}
diff --git a/dhcpcd-6.8.2/control.h b/dhcpcd-6.8.2/control.h
new file mode 100644
index 0000000..1b5a619
--- /dev/null
+++ b/dhcpcd-6.8.2/control.h
@@ -0,0 +1,64 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef CONTROL_H
+#define CONTROL_H
+
+#include "dhcpcd.h"
+
+/* Limit queue size per fd */
+#define CONTROL_QUEUE_MAX	100
+
+struct fd_data {
+	TAILQ_ENTRY(fd_data) next;
+	char *data;
+	size_t data_len;
+	uint8_t freeit;
+};
+TAILQ_HEAD(fd_data_head, fd_data);
+
+struct fd_list {
+	TAILQ_ENTRY(fd_list) next;
+	struct dhcpcd_ctx *ctx;
+	int fd;
+	unsigned int flags;
+	struct fd_data_head queue;
+	struct fd_data_head free_queue;
+};
+TAILQ_HEAD(fd_list_head, fd_list);
+
+#define FD_LISTEN	(1<<0)
+#define FD_UNPRIV	(1<<1)
+
+int control_start(struct dhcpcd_ctx *, const char *);
+int control_stop(struct dhcpcd_ctx *);
+int control_open(struct dhcpcd_ctx *, const char *);
+ssize_t control_send(struct dhcpcd_ctx *, int, char * const *);
+int control_queue(struct fd_list *fd, char *data, size_t data_len, uint8_t fit);
+void control_close(struct dhcpcd_ctx *ctx);
+
+#endif
diff --git a/dhcpcd-6.8.2/crypt/crypt.h b/dhcpcd-6.8.2/crypt/crypt.h
new file mode 100644
index 0000000..c919dc4
--- /dev/null
+++ b/dhcpcd-6.8.2/crypt/crypt.h
@@ -0,0 +1,33 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef CRYPT_H
+#define CRYPT_H
+
+void hmac_md5(const uint8_t *, size_t, const uint8_t *, size_t, uint8_t *);
+
+#endif
diff --git a/dhcpcd-6.8.2/crypt/hmac_md5.c b/dhcpcd-6.8.2/crypt/hmac_md5.c
new file mode 100644
index 0000000..453ea09
--- /dev/null
+++ b/dhcpcd-6.8.2/crypt/hmac_md5.c
@@ -0,0 +1,89 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <inttypes.h>
+#include <string.h>
+
+#include "crypt.h"
+
+#include "../config.h"
+#ifdef HAVE_MD5_H
+#  ifndef DEPGEN
+#    include <md5.h>
+#  endif
+#else
+#  include "md5.h"
+#endif
+
+#define HMAC_PAD_LEN	64
+#define IPAD		0x36
+#define OPAD		0x5C
+
+/* hmac_md5 as per RFC3118 */
+void
+hmac_md5(const uint8_t *text, size_t text_len,
+    const uint8_t *key, size_t key_len,
+    uint8_t *digest)
+{
+	uint8_t k_ipad[HMAC_PAD_LEN], k_opad[HMAC_PAD_LEN];
+	uint8_t tk[MD5_DIGEST_LENGTH];
+	int i;
+	MD5_CTX context;
+
+	/* Ensure key is no bigger than HMAC_PAD_LEN */
+	if (key_len > HMAC_PAD_LEN) {
+		MD5Init(&context);
+		MD5Update(&context, key, (unsigned int)key_len);
+		MD5Final(tk, &context);
+		key = tk;
+		key_len = MD5_DIGEST_LENGTH;
+	}
+
+	/* store key in pads */
+	memcpy(k_ipad, key, key_len);
+	memcpy(k_opad, key, key_len);
+	memset(k_ipad + key_len, 0, sizeof(k_ipad) - key_len);
+	memset(k_opad + key_len, 0, sizeof(k_opad) - key_len);
+
+	/* XOR key with ipad and opad values */
+	for (i = 0; i < HMAC_PAD_LEN; i++) {
+		k_ipad[i] ^= IPAD;
+		k_opad[i] ^= OPAD;
+	}
+
+	/* inner MD5 */
+	MD5Init(&context);
+	MD5Update(&context, k_ipad, HMAC_PAD_LEN);
+	MD5Update(&context, text, (unsigned int)text_len);
+	MD5Final(digest, &context);
+
+	/* outer MD5 */
+	MD5Init(&context);
+	MD5Update(&context, k_opad, HMAC_PAD_LEN);
+	MD5Update(&context, digest, MD5_DIGEST_LENGTH);
+	MD5Final(digest, &context);
+}
diff --git a/dhcpcd-6.8.2/crypt/md5.c b/dhcpcd-6.8.2/crypt/md5.c
new file mode 100644
index 0000000..dea2356
--- /dev/null
+++ b/dhcpcd-6.8.2/crypt/md5.c
@@ -0,0 +1,242 @@
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest.	This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+
+#include <sys/param.h>
+#include <inttypes.h>
+
+#include <string.h>
+
+#include "md5.h"
+
+#define PUT_64BIT_LE(cp, value) do {					\
+	(cp)[7] = (uint8_t)((value) >> 56);				\
+	(cp)[6] = (uint8_t)((value) >> 48);				\
+	(cp)[5] = (uint8_t)((value) >> 40);				\
+	(cp)[4] = (uint8_t)((value) >> 32);				\
+	(cp)[3] = (uint8_t)((value) >> 24);				\
+	(cp)[2] = (uint8_t)((value) >> 16);				\
+	(cp)[1] = (uint8_t)((value) >> 8);				\
+	(cp)[0] = (uint8_t)(value); } while (0)
+
+#define PUT_32BIT_LE(cp, value) do {					\
+	(cp)[3] = (uint8_t)((value) >> 24);				\
+	(cp)[2] = (uint8_t)((value) >> 16);				\
+	(cp)[1] = (uint8_t)((value) >> 8);				\
+	(cp)[0] = (uint8_t)(value); } while (0)
+
+static uint8_t PADDING[MD5_BLOCK_LENGTH] = {
+	0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/*
+ * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void
+MD5Init(MD5_CTX *ctx)
+{
+	ctx->count = 0;
+	ctx->state[0] = 0x67452301;
+	ctx->state[1] = 0xefcdab89;
+	ctx->state[2] = 0x98badcfe;
+	ctx->state[3] = 0x10325476;
+}
+
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, data, s) \
+	( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data.  MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+static void
+MD5Transform(uint32_t state[4], const uint8_t block[MD5_BLOCK_LENGTH])
+{
+	uint32_t a, b, c, d, in[MD5_BLOCK_LENGTH / 4];
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+	memcpy(in, block, sizeof(in));
+#else
+	for (a = 0; a < MD5_BLOCK_LENGTH / 4; a++) {
+		in[a] = (uint32_t)(
+		    (uint32_t)(block[a * 4 + 0]) |
+		    (uint32_t)(block[a * 4 + 1]) <<  8 |
+		    (uint32_t)(block[a * 4 + 2]) << 16 |
+		    (uint32_t)(block[a * 4 + 3]) << 24);
+	}
+#endif
+
+	a = state[0];
+	b = state[1];
+	c = state[2];
+	d = state[3];
+
+	MD5STEP(F1, a, b, c, d, in[ 0] + 0xd76aa478,  7);
+	MD5STEP(F1, d, a, b, c, in[ 1] + 0xe8c7b756, 12);
+	MD5STEP(F1, c, d, a, b, in[ 2] + 0x242070db, 17);
+	MD5STEP(F1, b, c, d, a, in[ 3] + 0xc1bdceee, 22);
+	MD5STEP(F1, a, b, c, d, in[ 4] + 0xf57c0faf,  7);
+	MD5STEP(F1, d, a, b, c, in[ 5] + 0x4787c62a, 12);
+	MD5STEP(F1, c, d, a, b, in[ 6] + 0xa8304613, 17);
+	MD5STEP(F1, b, c, d, a, in[ 7] + 0xfd469501, 22);
+	MD5STEP(F1, a, b, c, d, in[ 8] + 0x698098d8,  7);
+	MD5STEP(F1, d, a, b, c, in[ 9] + 0x8b44f7af, 12);
+	MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+	MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+	MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122,  7);
+	MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+	MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+	MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+	MD5STEP(F2, a, b, c, d, in[ 1] + 0xf61e2562,  5);
+	MD5STEP(F2, d, a, b, c, in[ 6] + 0xc040b340,  9);
+	MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+	MD5STEP(F2, b, c, d, a, in[ 0] + 0xe9b6c7aa, 20);
+	MD5STEP(F2, a, b, c, d, in[ 5] + 0xd62f105d,  5);
+	MD5STEP(F2, d, a, b, c, in[10] + 0x02441453,  9);
+	MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+	MD5STEP(F2, b, c, d, a, in[ 4] + 0xe7d3fbc8, 20);
+	MD5STEP(F2, a, b, c, d, in[ 9] + 0x21e1cde6,  5);
+	MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6,  9);
+	MD5STEP(F2, c, d, a, b, in[ 3] + 0xf4d50d87, 14);
+	MD5STEP(F2, b, c, d, a, in[ 8] + 0x455a14ed, 20);
+	MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905,  5);
+	MD5STEP(F2, d, a, b, c, in[ 2] + 0xfcefa3f8,  9);
+	MD5STEP(F2, c, d, a, b, in[ 7] + 0x676f02d9, 14);
+	MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+	MD5STEP(F3, a, b, c, d, in[ 5] + 0xfffa3942,  4);
+	MD5STEP(F3, d, a, b, c, in[ 8] + 0x8771f681, 11);
+	MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+	MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+	MD5STEP(F3, a, b, c, d, in[ 1] + 0xa4beea44,  4);
+	MD5STEP(F3, d, a, b, c, in[ 4] + 0x4bdecfa9, 11);
+	MD5STEP(F3, c, d, a, b, in[ 7] + 0xf6bb4b60, 16);
+	MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+	MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6,  4);
+	MD5STEP(F3, d, a, b, c, in[ 0] + 0xeaa127fa, 11);
+	MD5STEP(F3, c, d, a, b, in[ 3] + 0xd4ef3085, 16);
+	MD5STEP(F3, b, c, d, a, in[ 6] + 0x04881d05, 23);
+	MD5STEP(F3, a, b, c, d, in[ 9] + 0xd9d4d039,  4);
+	MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+	MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+	MD5STEP(F3, b, c, d, a, in[2 ] + 0xc4ac5665, 23);
+
+	MD5STEP(F4, a, b, c, d, in[ 0] + 0xf4292244,  6);
+	MD5STEP(F4, d, a, b, c, in[7 ] + 0x432aff97, 10);
+	MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+	MD5STEP(F4, b, c, d, a, in[5 ] + 0xfc93a039, 21);
+	MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3,  6);
+	MD5STEP(F4, d, a, b, c, in[3 ] + 0x8f0ccc92, 10);
+	MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+	MD5STEP(F4, b, c, d, a, in[1 ] + 0x85845dd1, 21);
+	MD5STEP(F4, a, b, c, d, in[8 ] + 0x6fa87e4f,  6);
+	MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+	MD5STEP(F4, c, d, a, b, in[6 ] + 0xa3014314, 15);
+	MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+	MD5STEP(F4, a, b, c, d, in[4 ] + 0xf7537e82,  6);
+	MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+	MD5STEP(F4, c, d, a, b, in[2 ] + 0x2ad7d2bb, 15);
+	MD5STEP(F4, b, c, d, a, in[9 ] + 0xeb86d391, 21);
+
+	state[0] += a;
+	state[1] += b;
+	state[2] += c;
+	state[3] += d;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void
+MD5Update(MD5_CTX *ctx, const unsigned char *input, size_t len)
+{
+	size_t have, need;
+
+	/* Check how many bytes we already have and how many more we need. */
+	have = (size_t)((ctx->count >> 3) & (MD5_BLOCK_LENGTH - 1));
+	need = MD5_BLOCK_LENGTH - have;
+
+	/* Update bitcount */
+	ctx->count += (uint64_t)len << 3;
+
+	if (len >= need) {
+		if (have != 0) {
+			memcpy(ctx->buffer + have, input, need);
+			MD5Transform(ctx->state, ctx->buffer);
+			input += need;
+			len -= need;
+			have = 0;
+		}
+
+		/* Process data in MD5_BLOCK_LENGTH-byte chunks. */
+		while (len >= MD5_BLOCK_LENGTH) {
+			MD5Transform(ctx->state, input);
+			input += MD5_BLOCK_LENGTH;
+			len -= MD5_BLOCK_LENGTH;
+		}
+	}
+
+	/* Handle any remaining bytes of data. */
+	if (len != 0)
+		memcpy(ctx->buffer + have, input, len);
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void
+MD5Final(unsigned char digest[MD5_DIGEST_LENGTH], MD5_CTX *ctx)
+{
+	uint8_t count[8];
+	size_t padlen;
+	int i;
+
+	/* Convert count to 8 bytes in little endian order. */
+	PUT_64BIT_LE(count, ctx->count);
+
+	/* Pad out to 56 mod 64. */
+	padlen = MD5_BLOCK_LENGTH -
+	    ((ctx->count >> 3) & (MD5_BLOCK_LENGTH - 1));
+	if (padlen < 1 + 8)
+		padlen += MD5_BLOCK_LENGTH;
+	MD5Update(ctx, PADDING, padlen - 8);		/* padlen - 8 <= 64 */
+	MD5Update(ctx, count, 8);
+
+	if (digest != NULL) {
+		for (i = 0; i < 4; i++)
+			PUT_32BIT_LE(digest + i * 4, ctx->state[i]);
+	}
+	memset(ctx, 0, sizeof(*ctx));	/* in case it's sensitive */
+}
+
+
diff --git a/dhcpcd-6.8.2/crypt/md5.h b/dhcpcd-6.8.2/crypt/md5.h
new file mode 100644
index 0000000..402309c
--- /dev/null
+++ b/dhcpcd-6.8.2/crypt/md5.h
@@ -0,0 +1,33 @@
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest.	This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+
+#ifndef MD5_H_
+#define MD5_H_
+
+#define MD5_DIGEST_LENGTH	16
+#define MD5_BLOCK_LENGTH	64
+
+typedef struct MD5Context {
+	uint32_t state[4];	/* state (ABCD) */
+	uint64_t count;		/* number of bits, modulo 2^64 (lsb first) */
+	unsigned char buffer[MD5_BLOCK_LENGTH]; /* input buffer */
+} MD5_CTX;
+
+void	MD5Init(MD5_CTX *);
+void	MD5Update(MD5_CTX *, const unsigned char *, size_t);
+void	MD5Final(unsigned char[MD5_DIGEST_LENGTH], MD5_CTX *);
+#endif
diff --git a/dhcpcd-6.8.2/crypt/sha256.c b/dhcpcd-6.8.2/crypt/sha256.c
new file mode 100644
index 0000000..7e3ab0f
--- /dev/null
+++ b/dhcpcd-6.8.2/crypt/sha256.c
@@ -0,0 +1,294 @@
+/*-
+ * Copyright 2005 Colin Percival
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <inttypes.h>
+
+#include <string.h>
+
+#include "../common.h"
+#include "sha256.h"
+
+#if BYTE_ORDER == BIG_ENDIAN
+
+/* Copy a vector of big-endian uint32_t into a vector of bytes */
+#define be32enc_vect(dst, src, len)	\
+	memcpy((void *)dst, (const void *)src, (size_t)len)
+
+/* Copy a vector of bytes into a vector of big-endian uint32_t */
+#define be32dec_vect(dst, src, len)	\
+	memcpy((void *)dst, (const void *)src, (size_t)len)
+
+#else /* BYTE_ORDER != BIG_ENDIAN */
+
+/*
+ * Encode a length len/4 vector of (uint32_t) into a length len vector of
+ * (unsigned char) in big-endian form.  Assumes len is a multiple of 4.
+ */
+static void
+be32enc_vect(unsigned char *dst, const uint32_t *src, size_t len)
+{
+	size_t i;
+
+	for (i = 0; i < len / 4; i++)
+		be32enc(dst + i * 4, src[i]);
+}
+
+/*
+ * Decode a big-endian length len vector of (unsigned char) into a length
+ * len/4 vector of (uint32_t).  Assumes len is a multiple of 4.
+ */
+static void
+be32dec_vect(uint32_t *dst, const unsigned char *src, size_t len)
+{
+	size_t i;
+
+	for (i = 0; i < len / 4; i++)
+		dst[i] = be32dec(src + i * 4);
+}
+
+#endif /* BYTE_ORDER != BIG_ENDIAN */
+
+/* Elementary functions used by SHA256 */
+#define Ch(x, y, z)	((x & (y ^ z)) ^ z)
+#define Maj(x, y, z)	((x & (y | z)) | (y & z))
+#define SHR(x, n)	(x >> n)
+#define ROTR(x, n)	((x >> n) | (x << (32 - n)))
+#define S0(x)		(ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22))
+#define S1(x)		(ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25))
+#define s0(x)		(ROTR(x, 7) ^ ROTR(x, 18) ^ SHR(x, 3))
+#define s1(x)		(ROTR(x, 17) ^ ROTR(x, 19) ^ SHR(x, 10))
+
+/* SHA256 round function */
+#define RND(a, b, c, d, e, f, g, h, k)			\
+	t0 = h + S1(e) + Ch(e, f, g) + k;		\
+	t1 = S0(a) + Maj(a, b, c);			\
+	d += t0;					\
+	h  = t0 + t1;
+
+/* Adjusted round function for rotating state */
+#define RNDr(S, W, i, k)			\
+	RND(S[(64 - i) % 8], S[(65 - i) % 8],	\
+	    S[(66 - i) % 8], S[(67 - i) % 8],	\
+	    S[(68 - i) % 8], S[(69 - i) % 8],	\
+	    S[(70 - i) % 8], S[(71 - i) % 8],	\
+	    W[i] + k)
+
+/*
+ * SHA256 block compression function.  The 256-bit state is transformed via
+ * the 512-bit input block to produce a new state.
+ */
+static void
+SHA256_Transform(uint32_t * state, const unsigned char block[64])
+{
+	uint32_t W[64];
+	uint32_t S[8];
+	uint32_t t0, t1;
+	int i;
+
+	/* 1. Prepare message schedule W. */
+	be32dec_vect(W, block, 64);
+	for (i = 16; i < 64; i++)
+		W[i] = s1(W[i - 2]) + W[i - 7] + s0(W[i - 15]) + W[i - 16];
+
+	/* 2. Initialize working variables. */
+	memcpy(S, state, 32);
+
+	/* 3. Mix. */
+	RNDr(S, W, 0, 0x428a2f98);
+	RNDr(S, W, 1, 0x71374491);
+	RNDr(S, W, 2, 0xb5c0fbcf);
+	RNDr(S, W, 3, 0xe9b5dba5);
+	RNDr(S, W, 4, 0x3956c25b);
+	RNDr(S, W, 5, 0x59f111f1);
+	RNDr(S, W, 6, 0x923f82a4);
+	RNDr(S, W, 7, 0xab1c5ed5);
+	RNDr(S, W, 8, 0xd807aa98);
+	RNDr(S, W, 9, 0x12835b01);
+	RNDr(S, W, 10, 0x243185be);
+	RNDr(S, W, 11, 0x550c7dc3);
+	RNDr(S, W, 12, 0x72be5d74);
+	RNDr(S, W, 13, 0x80deb1fe);
+	RNDr(S, W, 14, 0x9bdc06a7);
+	RNDr(S, W, 15, 0xc19bf174);
+	RNDr(S, W, 16, 0xe49b69c1);
+	RNDr(S, W, 17, 0xefbe4786);
+	RNDr(S, W, 18, 0x0fc19dc6);
+	RNDr(S, W, 19, 0x240ca1cc);
+	RNDr(S, W, 20, 0x2de92c6f);
+	RNDr(S, W, 21, 0x4a7484aa);
+	RNDr(S, W, 22, 0x5cb0a9dc);
+	RNDr(S, W, 23, 0x76f988da);
+	RNDr(S, W, 24, 0x983e5152);
+	RNDr(S, W, 25, 0xa831c66d);
+	RNDr(S, W, 26, 0xb00327c8);
+	RNDr(S, W, 27, 0xbf597fc7);
+	RNDr(S, W, 28, 0xc6e00bf3);
+	RNDr(S, W, 29, 0xd5a79147);
+	RNDr(S, W, 30, 0x06ca6351);
+	RNDr(S, W, 31, 0x14292967);
+	RNDr(S, W, 32, 0x27b70a85);
+	RNDr(S, W, 33, 0x2e1b2138);
+	RNDr(S, W, 34, 0x4d2c6dfc);
+	RNDr(S, W, 35, 0x53380d13);
+	RNDr(S, W, 36, 0x650a7354);
+	RNDr(S, W, 37, 0x766a0abb);
+	RNDr(S, W, 38, 0x81c2c92e);
+	RNDr(S, W, 39, 0x92722c85);
+	RNDr(S, W, 40, 0xa2bfe8a1);
+	RNDr(S, W, 41, 0xa81a664b);
+	RNDr(S, W, 42, 0xc24b8b70);
+	RNDr(S, W, 43, 0xc76c51a3);
+	RNDr(S, W, 44, 0xd192e819);
+	RNDr(S, W, 45, 0xd6990624);
+	RNDr(S, W, 46, 0xf40e3585);
+	RNDr(S, W, 47, 0x106aa070);
+	RNDr(S, W, 48, 0x19a4c116);
+	RNDr(S, W, 49, 0x1e376c08);
+	RNDr(S, W, 50, 0x2748774c);
+	RNDr(S, W, 51, 0x34b0bcb5);
+	RNDr(S, W, 52, 0x391c0cb3);
+	RNDr(S, W, 53, 0x4ed8aa4a);
+	RNDr(S, W, 54, 0x5b9cca4f);
+	RNDr(S, W, 55, 0x682e6ff3);
+	RNDr(S, W, 56, 0x748f82ee);
+	RNDr(S, W, 57, 0x78a5636f);
+	RNDr(S, W, 58, 0x84c87814);
+	RNDr(S, W, 59, 0x8cc70208);
+	RNDr(S, W, 60, 0x90befffa);
+	RNDr(S, W, 61, 0xa4506ceb);
+	RNDr(S, W, 62, 0xbef9a3f7);
+	RNDr(S, W, 63, 0xc67178f2);
+
+	/* 4. Mix local working variables into global state */
+	for (i = 0; i < 8; i++)
+		state[i] += S[i];
+}
+
+static unsigned char PAD[64] = {
+	0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* Add padding and terminating bit-count. */
+static void
+SHA256_Pad(SHA256_CTX * ctx)
+{
+	unsigned char len[8];
+	uint32_t r, plen;
+
+	/*
+	 * Convert length to a vector of bytes -- we do this now rather
+	 * than later because the length will change after we pad.
+	 */
+	be64enc(len, ctx->count);
+
+	/* Add 1--64 bytes so that the resulting length is 56 mod 64 */
+	r = (ctx->count >> 3) & 0x3f;
+	plen = (r < 56) ? (56 - r) : (120 - r);
+	SHA256_Update(ctx, PAD, (size_t)plen);
+
+	/* Add the terminating bit-count */
+	SHA256_Update(ctx, len, 8);
+}
+
+/* SHA-256 initialization.  Begins a SHA-256 operation. */
+void
+SHA256_Init(SHA256_CTX * ctx)
+{
+
+	/* Zero bits processed so far */
+	ctx->count = 0;
+
+	/* Magic initialization constants */
+	ctx->state[0] = 0x6A09E667;
+	ctx->state[1] = 0xBB67AE85;
+	ctx->state[2] = 0x3C6EF372;
+	ctx->state[3] = 0xA54FF53A;
+	ctx->state[4] = 0x510E527F;
+	ctx->state[5] = 0x9B05688C;
+	ctx->state[6] = 0x1F83D9AB;
+	ctx->state[7] = 0x5BE0CD19;
+}
+
+/* Add bytes into the hash */
+void
+SHA256_Update(SHA256_CTX * ctx, const void *in, size_t len)
+{
+	uint64_t bitlen;
+	uint32_t r;
+	const unsigned char *src = in;
+
+	/* Number of bytes left in the buffer from previous updates */
+	r = (ctx->count >> 3) & 0x3f;
+
+	/* Convert the length into a number of bits */
+	bitlen = len << 3;
+
+	/* Update number of bits */
+	ctx->count += bitlen;
+
+	/* Handle the case where we don't need to perform any transforms */
+	if (len < 64 - r) {
+		memcpy(&ctx->buf[r], src, len);
+		return;
+	}
+
+	/* Finish the current block */
+	memcpy(&ctx->buf[r], src, 64 - r);
+	SHA256_Transform(ctx->state, ctx->buf);
+	src += 64 - r;
+	len -= 64 - r;
+
+	/* Perform complete blocks */
+	while (len >= 64) {
+		SHA256_Transform(ctx->state, src);
+		src += 64;
+		len -= 64;
+	}
+
+	/* Copy left over data into buffer */
+	memcpy(ctx->buf, src, len);
+}
+
+/*
+ * SHA-256 finalization.  Pads the input data, exports the hash value,
+ * and clears the context state.
+ */
+void
+SHA256_Final(unsigned char digest[32], SHA256_CTX * ctx)
+{
+
+	/* Add padding */
+	SHA256_Pad(ctx);
+
+	/* Write the hash */
+	be32enc_vect(digest, ctx->state, 32);
+
+	/* Clear the context state */
+	memset((void *)ctx, 0, sizeof(*ctx));
+}
diff --git a/dhcpcd-6.8.2/crypt/sha256.h b/dhcpcd-6.8.2/crypt/sha256.h
new file mode 100644
index 0000000..34025e3
--- /dev/null
+++ b/dhcpcd-6.8.2/crypt/sha256.h
@@ -0,0 +1,50 @@
+/*-
+ * Copyright 2005 Colin Percival
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef SHA256_H_
+#define SHA256_H_
+
+#include <sys/types.h>
+
+#define SHA256_DIGEST_LENGTH		32
+
+typedef struct SHA256Context {
+	uint32_t state[8];
+	uint64_t count;
+	unsigned char buf[64];
+} SHA256_CTX;
+
+void	SHA256_Init(SHA256_CTX *);
+void	SHA256_Update(SHA256_CTX *, const void *, size_t);
+void	SHA256_Final(unsigned char [32], SHA256_CTX *);
+char   *SHA256_End(SHA256_CTX *, char *);
+char   *SHA256_File(const char *, char *);
+char   *SHA256_FileChunk(const char *, char *, off_t, off_t);
+char   *SHA256_Data(const void *, unsigned int, char *);
+
+#endif
diff --git a/dhcpcd-6.8.2/dbus/dbus-dict.c b/dhcpcd-6.8.2/dbus/dbus-dict.c
new file mode 100644
index 0000000..995b82d
--- /dev/null
+++ b/dhcpcd-6.8.2/dbus/dbus-dict.c
@@ -0,0 +1,298 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <syslog.h>
+
+#include <dbus/dbus.h>
+
+#include "../config.h"
+#include "dbus-dict.h"
+
+static dbus_bool_t
+append_sanitized_string(DBusMessageIter *iter, const char *value)
+{
+	dbus_bool_t ret;
+	int len = strlen(value);
+	char *sanitized_value = NULL;
+	int i;
+
+	for (i = 0; i < len; i++) {
+		if (isascii(value[i]) || isprint(value[i])) {
+			if (sanitized_value)
+				sanitized_value[i] = value[i];
+		} else {
+			if (sanitized_value == NULL) {
+				sanitized_value = malloc(len + 1);
+				if (sanitized_value == NULL) {
+					syslog(LOG_ERR, "DBus string parameter "
+					       "sanitization failed due to "
+					       "malloc failure");
+					return FALSE;
+				}
+				memcpy(sanitized_value, value, i);
+			}
+			sanitized_value[i] = '?';
+		}
+	}
+	if (sanitized_value) {
+		syslog(LOG_ERR, "DBus string parameter sanitization"
+                       " was invoked");
+		sanitized_value[i] = '\0';
+		ret = dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
+	            &sanitized_value);
+
+		free(sanitized_value);
+	} else {
+		ret = dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
+	            &value);
+	}
+
+	return ret;
+}
+
+static int
+append_config_value(DBusMessageIter *entry, int type,
+    const char *data)
+{
+	int retval;
+	DBusMessageIter var;
+	unsigned char byte;
+	dbus_uint16_t u16;
+	dbus_uint32_t u32;
+	dbus_int16_t i16;
+	dbus_int32_t i32;
+	struct in_addr in;
+
+	retval = -1;
+	switch (type) {
+	case DBUS_TYPE_BOOLEAN:
+		if (*data == '0' || *data == '\0')
+			u32 = 0;
+		else
+			u32 = 1;
+		dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
+		    DBUS_TYPE_BOOLEAN_AS_STRING, &var);
+		if (dbus_message_iter_append_basic(&var,
+			DBUS_TYPE_BOOLEAN, &u32))
+			retval = 0;
+		break;
+	case DBUS_TYPE_BYTE:
+		byte = strtoul(data, NULL, 0);
+		dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
+		    DBUS_TYPE_BYTE_AS_STRING, &var);
+		if (dbus_message_iter_append_basic(&var, DBUS_TYPE_BYTE,
+			&byte))
+			retval = 0;
+		break;
+	case DBUS_TYPE_STRING:
+		dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
+		    DBUS_TYPE_STRING_AS_STRING, &var);
+		if (append_sanitized_string(&var, data))
+			retval = 0;
+		break;
+	case DBUS_TYPE_INT16:
+		i16 = strtol(data, NULL, 0);
+		dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
+		    DBUS_TYPE_INT16_AS_STRING, &var);
+		if (dbus_message_iter_append_basic(&var,
+			DBUS_TYPE_INT16, &i16))
+			retval = 0;
+		break;
+	case DBUS_TYPE_UINT16:
+		u16 = strtoul(data, NULL, 0);
+		dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
+		    DBUS_TYPE_UINT16_AS_STRING, &var);
+		if (dbus_message_iter_append_basic(&var,
+			DBUS_TYPE_UINT16, &u16))
+			retval = 0;
+		break;
+	case DBUS_TYPE_INT32:
+		i32 = strtol(data, NULL, 0);
+		dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
+		    DBUS_TYPE_INT32_AS_STRING, &var);
+		if (dbus_message_iter_append_basic(&var,
+			DBUS_TYPE_INT32, &i32))
+			retval = 0;
+		break;
+	case DBUS_TYPE_UINT32:
+		if (strchr(data, '.') != NULL && inet_aton(data, &in) == 1)
+			u32 = in.s_addr;
+		else
+			u32 = strtoul(data, NULL, 0);
+		dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
+		    DBUS_TYPE_UINT32_AS_STRING, &var);
+		if (dbus_message_iter_append_basic(&var,
+			DBUS_TYPE_UINT32, &u32))
+			retval = 0;
+		break;
+	default:
+		retval = 1;
+		break;
+	}
+	if (retval == 0)
+		dbus_message_iter_close_container(entry, &var);
+	else if (retval == 1)
+		retval = 0;
+
+	return retval;
+}
+
+static int
+append_config_byte_array(DBusMessageIter *entry, const char *data)
+{
+	DBusMessageIter var, array;
+	dbus_bool_t ok = TRUE;
+	uint8_t u8, u8_2;
+	size_t len;
+	const char *it, *end;
+	const char *tsa, *ts;
+
+	tsa = DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_BYTE_AS_STRING;
+	ts = DBUS_TYPE_BYTE_AS_STRING;
+
+	dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT, tsa, &var);
+	dbus_message_iter_open_container(&var, DBUS_TYPE_ARRAY, ts, &array);
+
+	len = strlen(data);
+	it = data;
+	end = data + len;
+
+	/* "a12" is treated as "0a12" */
+	if (len & 1) {
+		ok = (sscanf(it++, "%1hhx", &u8) == 1) &&
+			dbus_message_iter_append_basic(&array, DBUS_TYPE_BYTE,
+						       &u8);
+	}
+
+	while (ok && it < end) {
+		/* sscanf("1z", "%2hhx", &u8) will store 0x01 in u8 and
+		 * will return 1 */
+		ok = (sscanf(it++, "%1hhx", &u8) == 1) &&
+			(sscanf(it++, "%1hhx", &u8_2) == 1);
+		if (!ok)
+			break;
+
+		u8 = (u8 << 4) | u8_2;
+		ok = dbus_message_iter_append_basic(&array, DBUS_TYPE_BYTE, &u8);
+	}
+
+	dbus_message_iter_close_container(&var, &array);
+	dbus_message_iter_close_container(entry, &var);
+	return ok ? 0 : -1;
+}
+
+static int
+append_config_array(DBusMessageIter *entry, int type, const char *data)
+{
+	int retval;
+	char *ns, *p, *tok;
+	const char *tsa, *ts;
+	DBusMessageIter var, array;
+	dbus_bool_t ok;
+	dbus_uint32_t u32;
+	struct in_addr in;
+
+	if (type == DBUS_TYPE_BYTE)
+		return append_config_byte_array(entry, data);
+
+	switch (type) {
+	case DBUS_TYPE_STRING:
+		tsa = DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING;
+		ts = DBUS_TYPE_STRING_AS_STRING;
+		break;
+	case DBUS_TYPE_UINT32:
+		tsa = DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_UINT32_AS_STRING;
+		ts = DBUS_TYPE_UINT32_AS_STRING;
+		break;
+	default:
+		return -1;
+	}
+
+	ns = p = strdup(data);
+	if (ns == NULL)
+		return -1;
+	retval = 0;
+
+	dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT, tsa, &var);
+	dbus_message_iter_open_container(&var, DBUS_TYPE_ARRAY, ts, &array);
+	while ((tok = strsep(&p, " ")) != NULL) {
+		if (*tok == '\0')
+			continue;
+		switch(type) {
+		case DBUS_TYPE_STRING:
+			ok = append_sanitized_string(&array, tok);
+			break;
+		case DBUS_TYPE_UINT32:
+			if (strchr(tok, '.') != NULL &&
+			    inet_aton(tok, &in) == 1)
+				u32 = in.s_addr;
+			else
+				u32 = strtoul(tok, NULL, 0);
+			ok = dbus_message_iter_append_basic(&array,
+			    DBUS_TYPE_UINT32, &u32);
+			break;
+		default:
+			ok = FALSE;
+			break;
+		}
+		if (!ok)
+			break;
+	}
+	dbus_message_iter_close_container(&var, &array);
+	dbus_message_iter_close_container(entry, &var);
+	free(ns);
+	return retval;
+}
+
+int
+dict_append_config_item(DBusMessageIter *iter, const struct o_dbus *op,
+    const char *data)
+{
+	int retval;
+	DBusMessageIter entry;
+
+	retval = 0;
+	if (*data == '\0')
+		return retval;
+	dbus_message_iter_open_container(iter,
+	    DBUS_TYPE_DICT_ENTRY,
+	    NULL,
+	    &entry);
+	append_sanitized_string(&entry, op->name);
+	if (op->type == DBUS_TYPE_ARRAY)
+		retval = append_config_array(&entry, op->sub_type, data);
+	else
+		retval = append_config_value(&entry, op->type, data);
+	dbus_message_iter_close_container(iter, &entry);
+	return retval;
+}
diff --git a/dhcpcd-6.8.2/dbus/dbus-dict.h b/dhcpcd-6.8.2/dbus/dbus-dict.h
new file mode 100644
index 0000000..5b558be
--- /dev/null
+++ b/dhcpcd-6.8.2/dbus/dbus-dict.h
@@ -0,0 +1,43 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef DBUS_DICT_H
+#define DBUS_DICT_H
+
+#include <dbus/dbus.h>
+
+struct o_dbus {
+	const char *var;
+	int type;
+	int sub_type;
+	const char *name;
+};
+
+int dict_append_config_item(DBusMessageIter *,
+    const struct o_dbus *, const char *);
+
+#endif
diff --git a/dhcpcd-6.8.2/dbus/dhcpcd-dbus.conf b/dhcpcd-6.8.2/dbus/dhcpcd-dbus.conf
new file mode 100644
index 0000000..766cc59
--- /dev/null
+++ b/dhcpcd-6.8.2/dbus/dhcpcd-dbus.conf
@@ -0,0 +1,21 @@
+<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<busconfig>
+  <!-- Both root and dhcp can own the dhcpcd service -->
+  <policy user="root">
+    <allow own="org.chromium.dhcpcd"/>
+    <allow send_interface="org.chromium.dhcpcd" />
+    <allow send_destination="org.chromium.dhcpcd" />
+  </policy>
+  <policy user="dhcp">
+    <allow own="org.chromium.dhcpcd"/>
+    <allow send_interface="org.chromium.dhcpcd" />
+    <allow send_destination="org.chromium.dhcpcd" />
+  </policy>
+
+  <policy context="default">
+    <allow send_interface="org.chromium.dhcpcd" />
+    <allow send_interface="org.freedesktop.DBus.Introspectable" />
+    <allow send_destination="org.chromium.dhcpcd" />
+</policy>
+</busconfig>
diff --git a/dhcpcd-6.8.2/dbus/org.chromium.dhcpcd.in b/dhcpcd-6.8.2/dbus/org.chromium.dhcpcd.in
new file mode 100644
index 0000000..f2b01f3
--- /dev/null
+++ b/dhcpcd-6.8.2/dbus/org.chromium.dhcpcd.in
@@ -0,0 +1,4 @@
+[D-BUS Service]
+Name=org.chromium.dhcpcd
+Exec=@BINDIR@/dhcpcd
+User=root
diff --git a/dhcpcd-6.8.2/dbus/rpc-dbus.c b/dhcpcd-6.8.2/dbus/rpc-dbus.c
new file mode 100644
index 0000000..438aa00
--- /dev/null
+++ b/dhcpcd-6.8.2/dbus/rpc-dbus.c
@@ -0,0 +1,761 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <errno.h>
+#include <poll.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include <dbus/dbus.h>
+
+#include "../config.h"
+#include "../eloop.h"
+#include "../dhcp.h"
+#ifdef INET6
+#include "../dhcp6.h"
+#endif
+#include "../rpc-interface.h"
+#include "dbus-dict.h"
+
+#define SERVICE_NAME 	"org.chromium.dhcpcd"
+#define SERVICE_PATH    "/org/chromium/dhcpcd"
+#define S_EINVAL	SERVICE_NAME ".InvalidArgument"
+#define S_ARGS		"Not enough arguments"
+
+static DBusConnection *connection;
+static struct dhcpcd_ctx *dhcpcd_ctx;
+
+static const char dhcpcd_introspection_xml[] =
+    "    <method name=\"GetVersion\">\n"
+    "      <arg name=\"version\" direction=\"out\" type=\"s\"/>\n"
+    "    </method>\n"
+    "    <method name=\"Rebind\">\n"
+    "      <arg name=\"interface\" direction=\"in\" type=\"s\"/>\n"
+    "    </method>\n"
+    "    <method name=\"Release\">\n"
+    "      <arg name=\"interface\" direction=\"in\" type=\"s\"/>\n"
+    "    </method>\n"
+    "    <method name=\"Stop\">\n"
+    "      <arg name=\"interface\" direction=\"in\" type=\"s\"/>\n"
+    "    </method>\n"
+    "    <signal name=\"Event\">\n"
+    "      <arg name=\"configuration\" type=\"usa{sv}\"/>\n"
+    "    </signal>\n"
+    "    <signal name=\"StatusChanged\">\n"
+    "      <arg name=\"status\" type=\"us\"/>\n"
+    "    </signal>\n";
+
+static const char service_watch_rule[] = "interface=" DBUS_INTERFACE_DBUS
+	",type=signal,member=NameOwnerChanged";
+
+static const char introspection_header_xml[] =
+    "<!DOCTYPE node PUBLIC \"-//freedesktop//"
+    "DTD D-BUS Object Introspection 1.0//EN\"\n"
+    "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
+    "<node name=\"" SERVICE_PATH "\">\n"
+    "  <interface name=\"org.freedesktop.DBus.Introspectable\">\n"
+    "    <method name=\"Introspect\">\n"
+    "      <arg name=\"data\" direction=\"out\" type=\"s\"/>\n"
+    "    </method>\n"
+    "  </interface>\n"
+    "  <interface name=\"" SERVICE_NAME "\">\n";
+
+static const char introspection_footer_xml[] =
+    "  </interface>\n"
+    "</node>\n";
+
+static const struct o_dbus dhos[] = {
+	{ "ip_address=", DBUS_TYPE_UINT32, 0, "IPAddress" },
+	{ "server_name=", DBUS_TYPE_STRING, 0, "ServerName"},
+	{ "subnet_mask=", DBUS_TYPE_UINT32, 0, "SubnetMask" },
+	{ "subnet_cidr=", DBUS_TYPE_BYTE, 0, "SubnetCIDR" },
+	{ "network_number=", DBUS_TYPE_UINT32, 0, "NetworkNumber" },
+	{ "classless_static_routes=", DBUS_TYPE_STRING, 0,
+	  "ClasslessStaticRoutes" },
+	{ "ms_classless_static_routes=", DBUS_TYPE_STRING, 0,
+	  "MSClasslessStaticRoutes" },
+	{ "static_routes=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32,
+	  "StaticRoutes"} ,
+	{ "routers=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, "Routers" },
+	{ "time_offset=", DBUS_TYPE_UINT32, 0, "TimeOffset" },
+	{ "time_servers=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, "TimeServers" },
+	{ "ien116_name_servers=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32,
+	  "IEN116NameServers" },
+	{ "domain_name_servers=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32,
+	  "DomainNameServers" },
+	{ "log_servers=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, "LogServers" },
+	{ "cookie_servers=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32,
+	  "CookieServers" },
+	{ "lpr_servers=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, "LPRServers" },
+	{ "impress_servers=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32,
+	  "ImpressServers" },
+	{ "resource_location_servers=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32,
+	  "ResourceLocationServers" },
+	{ "host_name=", DBUS_TYPE_STRING, 0, "Hostname" },
+	{ "boot_size=", DBUS_TYPE_UINT16, 0, "BootSize" },
+	{ "merit_dump=", DBUS_TYPE_STRING, 0, "MeritDump" },
+	{ "domain_name=", DBUS_TYPE_STRING, 0, "DomainName" },
+	{ "swap_server=", DBUS_TYPE_UINT32, 0, "SwapServer" },
+	{ "root_path=", DBUS_TYPE_STRING, 0, "RootPath" },
+	{ "extensions_path=", DBUS_TYPE_STRING, 0, "ExtensionsPath" },
+	{ "ip_forwarding=", DBUS_TYPE_BOOLEAN, 0, "IPForwarding" },
+	{ "non_local_source_routing=", DBUS_TYPE_BOOLEAN, 0,
+	  "NonLocalSourceRouting" },
+	{ "policy_filter=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32,
+	  "PolicyFilter" },
+	{ "max_dgram_reassembly=", DBUS_TYPE_INT16, 0,
+	  "MaxDatagramReassembly" },
+	{ "default_ip_ttl=", DBUS_TYPE_UINT16, 0, "DefaultIPTTL" },
+	{ "path_mtu_aging_timeout=", DBUS_TYPE_UINT32, 0,
+	  "PathMTUAgingTimeout" },
+	{ "path_mtu_plateau_table=" ,DBUS_TYPE_ARRAY, DBUS_TYPE_UINT16,
+	  "PolicyFilter"} ,
+	{ "interface_mtu=", DBUS_TYPE_UINT16, 0, "InterfaceMTU" },
+	{ "all_subnets_local=", DBUS_TYPE_BOOLEAN, 0, "AllSubnetsLocal" },
+	{ "broadcast_address=", DBUS_TYPE_UINT32, 0, "BroadcastAddress" },
+	{ "perform_mask_discovery=", DBUS_TYPE_BOOLEAN, 0,
+	  "PerformMaskDiscovery" },
+	{ "mask_supplier=", DBUS_TYPE_BOOLEAN, 0, "MaskSupplier" },
+	{ "router_discovery=", DBUS_TYPE_BOOLEAN, 0, "RouterDiscovery" },
+	{ "router_solicitiation_address=", DBUS_TYPE_UINT32, 0,
+	  "RouterSolicationAddress" },
+	{ "trailer_encapsulation=", DBUS_TYPE_BOOLEAN, 0,
+	  "TrailerEncapsulation" },
+	{ "arp_cache_timeout=", DBUS_TYPE_UINT32, 0, "ARPCacheTimeout" },
+	{ "ieee802_3_encapsulation=", DBUS_TYPE_UINT16, 0,
+	  "IEEE8023Encapsulation" },
+	{ "default_tcp_ttl=", DBUS_TYPE_BYTE, 0, "DefaultTCPTTL" },
+	{ "tcp_keepalive_interval=", DBUS_TYPE_UINT32, 0,
+	  "TCPKeepAliveInterval" },
+	{ "tcp_keepalive_garbage=", DBUS_TYPE_BOOLEAN, 0,
+	  "TCPKeepAliveGarbage" },
+	{ "nis_domain=", DBUS_TYPE_STRING, 0, "NISDomain" },
+	{ "nis_servers=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, "NISServers" },
+	{ "ntp_servers=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, "NTPServers" },
+	{ "vendor_encapsulated_options=", DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
+	  "VendorEncapsulatedOptions" },
+	{ "netbios_name_servers=" ,DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32,
+	  "NetBIOSNameServers" },
+	{ "netbios_dd_server=", DBUS_TYPE_UINT32, 0, "NetBIOSDDServer" },
+	{ "netbios_node_type=", DBUS_TYPE_BYTE, 0, "NetBIOSNodeType" },
+	{ "netbios_scope=", DBUS_TYPE_STRING, 0, "NetBIOSScope" },
+	{ "font_servers=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, "FontServers" },
+	{ "x_display_manager=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32,
+	  "XDisplayManager" },
+	{ "dhcp_requested_address=", DBUS_TYPE_UINT32, 0,
+	  "DHCPRequestedAddress" },
+	{ "dhcp_lease_time=", DBUS_TYPE_UINT32, 0, "DHCPLeaseTime" },
+	{ "dhcp_option_overload=", DBUS_TYPE_BOOLEAN, 0,
+	  "DHCPOptionOverload" },
+	{ "dhcp_message_type=", DBUS_TYPE_BYTE, 0, "DHCPMessageType" },
+	{ "dhcp_server_identifier=", DBUS_TYPE_UINT32, 0,
+	  "DHCPServerIdentifier" },
+	{ "dhcp_message=", DBUS_TYPE_STRING, 0, "DHCPMessage" },
+	{ "dhcp_max_message_size=", DBUS_TYPE_UINT16, 0,
+	  "DHCPMaxMessageSize" },
+	{ "dhcp_renewal_time=", DBUS_TYPE_UINT32, 0, "DHCPRenewalTime" },
+	{ "dhcp_rebinding_time=", DBUS_TYPE_UINT32, 0, "DHCPRebindingTime" },
+	{ "nisplus_domain=", DBUS_TYPE_STRING, 0, "NISPlusDomain" },
+	{ "nisplus_servers=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32,
+	  "NISPlusServers" },
+	{ "tftp_server_name=", DBUS_TYPE_STRING, 0, "TFTPServerName" },
+	{ "bootfile_name=", DBUS_TYPE_STRING, 0, "BootFileName" },
+	{ "mobile_ip_home_agent=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32,
+	  "MobileIPHomeAgent" },
+	{ "smtp_server=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, "SMTPServer" },
+	{ "pop_server=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, "POPServer" },
+	{ "nntp_server=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, "NNTPServer" },
+	{ "www_server=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, "WWWServer" },
+	{ "finger_server=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32,
+	  "FingerServer" },
+	{ "irc_server=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, "IRCServer" },
+	{ "streettalk_server=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32,
+	  "StreetTalkServer" },
+	{ "streettalk_directory_assistance_server=", DBUS_TYPE_ARRAY,
+	  DBUS_TYPE_UINT32, "StreetTalkDirectoryAssistanceServer" },
+	{ "user_class=", DBUS_TYPE_STRING, 0, "UserClass" },
+	{ "new_fqdn_name=", DBUS_TYPE_STRING, 0, "FQDNName" },
+	{ "nds_servers=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, "NDSServers" },
+	{ "nds_tree_name=", DBUS_TYPE_STRING, 0, "NDSTreeName" },
+	{ "nds_context=", DBUS_TYPE_STRING, 0, "NDSContext" },
+	{ "bcms_controller_names=", DBUS_TYPE_STRING, 0,
+	  "BCMSControllerNames" },
+	{ "client_last_transaction_time=", DBUS_TYPE_UINT32, 0,
+	  "ClientLastTransactionTime" },
+	{ "associated_ip=", DBUS_TYPE_UINT32, 0, "AssociatedIP" },
+	{ "uap_servers=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, "UAPServers" },
+	{ "netinfo_server_address=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32,
+	  "NetinfoServerAddress" },
+	{ "netinfo_server_tag=", DBUS_TYPE_STRING, 0, "NetinfoServerTag" },
+	{ "default_url=", DBUS_TYPE_STRING, 0, "DefaultURL" },
+	{ "subnet_selection=", DBUS_TYPE_UINT32, 0, "SubnetSelection" },
+	{ "domain_search=", DBUS_TYPE_ARRAY, DBUS_TYPE_STRING,
+	  "DomainSearch" },
+	{ "wpad_url=", DBUS_TYPE_STRING, 0, "WebProxyAutoDiscoveryUrl" },
+#ifdef INET6
+	{ "dhcp6_server_id=", DBUS_TYPE_STRING, 0,
+	  "DHCPv6ServerIdentifier" },
+	{ "dhcp6_ia_na1_ia_addr1=", DBUS_TYPE_STRING, 0, "DHCPv6Address" },
+	{ "dhcp6_ia_na1_ia_addr1_vltime=", DBUS_TYPE_UINT32, 0,
+	  "DHCPv6AddressLeaseTime" },
+	{ "dhcp6_name_servers=", DBUS_TYPE_ARRAY, DBUS_TYPE_STRING,
+	  "DHCPv6NameServers" },
+	{ "dhcp6_domain_search=", DBUS_TYPE_ARRAY, DBUS_TYPE_STRING,
+	  "DHCPv6DomainSearch" },
+	{ "dhcp6_ia_pd1_prefix1=", DBUS_TYPE_STRING, 0,
+	  "DHCPv6DelegatedPrefix" },
+	{ "dhcp6_ia_pd1_prefix1_length=", DBUS_TYPE_UINT32, 0,
+	  "DHCPv6DelegatedPrefixLength" },
+	{ "dhcp6_ia_pd1_prefix1_vltime=", DBUS_TYPE_UINT32, 0,
+	  "DHCPv6DelegatedPrefixLeaseTime" },
+#endif
+	{ NULL, 0, 0, NULL }
+};
+
+static int
+append_config(DBusMessageIter *iter,
+    const char *prefix, char **env, ssize_t elen)
+{
+	char **eenv, *p;
+	const struct o_dbus *dhop;
+	size_t l, lp;
+	int retval;
+
+	retval = 0;
+	lp = strlen(prefix);
+	for (eenv = env + elen; env < eenv; env++) {
+		p = env[0];
+		for (dhop = dhos; dhop->var; dhop++) {
+			l = strlen(dhop->var);
+			if (strncmp(p, dhop->var, l) == 0) {
+				retval = dict_append_config_item(iter,
+				    dhop, p + l);
+				break;
+			}
+			if (strncmp(p, prefix, lp) == 0 &&
+			    strncmp(p + lp, dhop->var, l) == 0)
+			{
+				retval = dict_append_config_item(iter,
+				    dhop, p + l + lp);
+				break;
+			}
+		}
+		if (retval == -1)
+			break;
+	}
+	return retval;
+}
+
+static DBusHandlerResult
+get_dbus_error(DBusConnection *con, DBusMessage *msg,
+		  const char *name, const char *fmt, ...)
+{
+	char buffer[1024];
+	DBusMessage *reply;
+	va_list args;
+
+	va_start(args, fmt);
+	vsnprintf(buffer, sizeof(buffer), fmt, args);
+	va_end(args);
+	reply = dbus_message_new_error(msg, name, buffer);
+	dbus_connection_send(con, reply, NULL);
+	dbus_message_unref(reply);
+	return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static dbus_bool_t
+dbus_send_message(const struct interface *ifp, const char *reason,
+    const char *prefix, struct dhcp_message *message)
+{
+	const struct if_options *ifo = ifp->options;
+	DBusMessage* msg;
+	DBusMessageIter args, dict;
+	int pid = getpid();
+	char **env = NULL;
+	ssize_t e, elen;
+	int retval;
+	int success = FALSE;
+
+	syslog(LOG_INFO, "event %s on interface %s", reason, ifp->name);
+
+	msg = dbus_message_new_signal(SERVICE_PATH, SERVICE_NAME, "Event");
+	if (msg == NULL) {
+		syslog(LOG_ERR, "failed to make a configure message");
+		return FALSE;
+	}
+	dbus_message_iter_init_append(msg, &args);
+	dbus_message_iter_append_basic(&args, DBUS_TYPE_UINT32, &pid);
+	dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &reason);
+	dbus_message_iter_open_container(&args, DBUS_TYPE_ARRAY,
+	    DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+	    DBUS_TYPE_STRING_AS_STRING
+	    DBUS_TYPE_VARIANT_AS_STRING
+	    DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
+	    &dict);
+	if (prefix == NULL || message == NULL)
+		retval = 0;
+	else {
+		e = dhcp_env(NULL, NULL, message, ifp);
+		if (e > 0) {
+			char *config_prefix = strdup(prefix);
+			if (config_prefix == NULL) {
+				logger(dhcpcd_ctx, LOG_ERR,
+				       "Memory exhausted (strdup)");
+				eloop_exit(dhcpcd_ctx->eloop, EXIT_FAILURE);
+			}
+			char *p = config_prefix + strlen(config_prefix) - 1;
+			if (p >= config_prefix && *p == '_')
+				*p = '\0';
+			env = calloc(e + 1, sizeof(char *));
+			if (env == NULL) {
+				logger(dhcpcd_ctx, LOG_ERR,
+				       "Memory exhausted (calloc)");
+				eloop_exit(dhcpcd_ctx->eloop, EXIT_FAILURE);
+			}
+			elen = dhcp_env(env, config_prefix, message, ifp);
+			free(config_prefix);
+		}
+		retval = append_config(&dict, prefix, env, elen);
+	}
+
+	/* Release memory allocated for env. */
+	if (env) {
+		char **current = env;
+		while (*current)
+			free(*current++);
+		free(env);
+	}
+
+	dbus_message_iter_close_container(&args, &dict);
+	if (retval == 0) {
+		success = dbus_connection_send(connection, msg, NULL);
+		if (!success)
+			syslog(LOG_ERR, "failed to send dhcp to dbus");
+	} else
+		syslog(LOG_ERR, "failed to construct dbus message");
+	dbus_message_unref(msg);
+
+	return success;
+}
+
+#ifdef INET6
+static dbus_bool_t
+dbus_send_dhcpv6_message(const struct interface *ifp, const char *reason,
+    const char *prefix, struct dhcp6_message *message, size_t length)
+{
+	const struct if_options *ifo = ifp->options;
+	DBusMessage* msg;
+	DBusMessageIter args, dict;
+	int pid = getpid();
+	char **env = NULL;
+	ssize_t e, elen;
+	int retval;
+	int success = FALSE;
+
+	syslog(LOG_INFO, "event %s on interface %s", reason, ifp->name);
+
+	msg = dbus_message_new_signal(SERVICE_PATH, SERVICE_NAME, "Event");
+	if (msg == NULL) {
+		syslog(LOG_ERR, "failed to make a configure message");
+		return FALSE;
+	}
+	dbus_message_iter_init_append(msg, &args);
+	dbus_message_iter_append_basic(&args, DBUS_TYPE_UINT32, &pid);
+	dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &reason);
+	dbus_message_iter_open_container(&args, DBUS_TYPE_ARRAY,
+	    DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+	    DBUS_TYPE_STRING_AS_STRING
+	    DBUS_TYPE_VARIANT_AS_STRING
+	    DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
+	    &dict);
+	if (prefix == NULL || message == NULL)
+		retval = 0;
+	else {
+		e = dhcp6_env(NULL, NULL, ifp, message, length);
+		if (e > 0) {
+			char *config_prefix = strdup(prefix);
+			if (config_prefix == NULL) {
+				logger(dhcpcd_ctx, LOG_ERR,
+				       "Memory exhausted (strdup)");
+				eloop_exit(dhcpcd_ctx->eloop, EXIT_FAILURE);
+			}
+			char *p = config_prefix + strlen(config_prefix) - 1;
+			if (p >= config_prefix && *p == '_')
+				*p = '\0';
+			env = calloc(e + 1, sizeof(char *));
+			if (env == NULL) {
+				logger(dhcpcd_ctx, LOG_ERR,
+				       "Memory exhausted (calloc)");
+				eloop_exit(dhcpcd_ctx->eloop, EXIT_FAILURE);
+			}
+			elen = dhcp6_env(env, "new", ifp, message, length);
+			free(config_prefix);
+		}
+		retval = append_config(&dict, prefix, env, elen);
+	}
+
+	/* Release memory allocated for env. */
+	if (env) {
+		char **current = env;
+		while (*current)
+			free(*current++);
+		free(env);
+	}
+
+	dbus_message_iter_close_container(&args, &dict);
+	if (retval == 0) {
+		success = dbus_connection_send(connection, msg, NULL);
+		if (!success)
+			syslog(LOG_ERR, "failed to send dhcpv6 to dbus");
+	} else
+		syslog(LOG_ERR, "failed to construct dbus message");
+	dbus_message_unref(msg);
+
+	return success;
+}
+#endif
+
+static DBusHandlerResult
+introspect(DBusConnection *con, DBusMessage *msg)
+{
+	DBusMessage *reply;
+	char *xml;
+	size_t len;
+
+	len = sizeof(introspection_header_xml) - 1
+	    + sizeof(dhcpcd_introspection_xml) - 1
+	    + sizeof(introspection_footer_xml) - 1
+	    + 1; /* terminal \0 */
+	xml = malloc(len);
+	if (xml == NULL)
+		return DBUS_HANDLER_RESULT_HANDLED;
+	snprintf(xml, len, "%s%s%s",
+	    introspection_header_xml,
+	    dhcpcd_introspection_xml,
+	    introspection_footer_xml);
+	reply = dbus_message_new_method_return(msg);
+	dbus_message_append_args(reply,
+	    DBUS_TYPE_STRING, &xml,
+	    DBUS_TYPE_INVALID);
+	dbus_connection_send(con, reply, NULL);
+	dbus_message_unref(reply);
+	free(xml);
+	return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusHandlerResult
+version(DBusConnection *con, DBusMessage *msg, const char *ver)
+{
+	DBusMessage *reply;
+
+	reply = dbus_message_new_method_return(msg);
+	dbus_message_append_args(reply,
+	    DBUS_TYPE_STRING, &ver,
+	    DBUS_TYPE_INVALID);
+	dbus_connection_send(con, reply, NULL);
+	dbus_message_unref(reply);
+	return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusHandlerResult
+dbus_ack(DBusConnection *con, DBusMessage *msg)
+{
+	DBusMessage *reply;
+
+	reply = dbus_message_new_method_return(msg);
+	dbus_connection_send(con, reply, NULL);
+	dbus_message_unref(reply);
+	return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusHandlerResult
+msg_handler(DBusConnection *con, DBusMessage *msg, __unused void *data)
+{
+#define	IsMethod(msg, method) \
+	dbus_message_is_method_call(msg, SERVICE_NAME, method)
+
+	if (dbus_message_is_method_call(msg, DBUS_INTERFACE_INTROSPECTABLE,
+					"Introspect")) {
+		return introspect(con, msg);
+	} else if (IsMethod(msg, "GetVersion")) {
+		return version(con, msg, VERSION);
+	} else if (IsMethod(msg, "Rebind")) {
+		const char *iface_name;
+		if (!dbus_message_get_args(msg, NULL,
+				   DBUS_TYPE_STRING, &iface_name,
+				   DBUS_TYPE_INVALID)) {
+			logger(dhcpcd_ctx, LOG_ERR,
+			       "Invalid arguments for Rebind");
+			return get_dbus_error(con, msg, S_EINVAL, S_ARGS);
+		}
+		dhcpcd_start_interface(dhcpcd_ctx, iface_name);
+		return dbus_ack(con, msg);
+	} else if (IsMethod(msg, "Release")) {
+		const char *iface_name;
+		if (!dbus_message_get_args(msg, NULL,
+				   DBUS_TYPE_STRING, &iface_name,
+				   DBUS_TYPE_INVALID)) {
+			logger(dhcpcd_ctx, LOG_ERR,
+			       "Invalid arguments for Release");
+			return get_dbus_error(con, msg, S_EINVAL, S_ARGS);
+		}
+		dhcpcd_release_ipv4(dhcpcd_ctx, iface_name);
+		return dbus_ack(con, msg);
+	} else if (IsMethod(msg, "Stop")) {
+		const char *iface_name;
+		if (!dbus_message_get_args(msg, NULL,
+				   DBUS_TYPE_STRING, &iface_name,
+				   DBUS_TYPE_INVALID)) {
+			logger(dhcpcd_ctx, LOG_ERR,
+			       "Invalid arguments for Stop");
+			return get_dbus_error(con, msg, S_EINVAL, S_ARGS);
+		}
+		dhcpcd_stop_interface(dhcpcd_ctx, iface_name);
+		(void) dbus_ack(con, msg);
+		exit(EXIT_FAILURE);
+	} else if (dbus_message_is_signal(msg, DBUS_INTERFACE_LOCAL,
+					  "Disconnected")) {
+		dhcpcd_stop_interfaces(dhcpcd_ctx);
+		exit(EXIT_FAILURE);
+	}
+	return get_dbus_error(con, msg, S_EINVAL, S_ARGS);
+#undef IsMethod
+}
+
+static void
+dbus_handle_event(DBusWatch *watch, int flags)
+{
+	dbus_watch_handle((DBusWatch *)watch, flags);
+
+	if (connection != NULL) {
+		dbus_connection_ref(connection);
+		while (dbus_connection_dispatch(connection) ==
+				DBUS_DISPATCH_DATA_REMAINS)
+				;
+		dbus_connection_unref(connection);
+	}
+}
+
+static void
+dbus_read_event(void *watch)
+{
+	dbus_handle_event((DBusWatch *)watch, DBUS_WATCH_READABLE);
+}
+
+static void
+dbus_write_event(void *watch)
+{
+	dbus_handle_event((DBusWatch *)watch, DBUS_WATCH_WRITABLE);
+}
+
+static dbus_bool_t
+add_watch(DBusWatch *watch, __unused void *data)
+{
+	int fd, flags;
+	void (*read_event)(void *) = NULL;
+	void *read_arg = NULL;
+	void (*write_event)(void *) = NULL;
+	void *write_arg = NULL;
+
+	fd = dbus_watch_get_unix_fd(watch);
+	flags = dbus_watch_get_flags(watch);
+	if (flags & DBUS_WATCH_READABLE) {
+		read_event = dbus_read_event;
+		read_arg = watch;
+	}
+	if (flags & DBUS_WATCH_WRITABLE) {
+		write_event = dbus_write_event;
+		write_arg = watch;
+	}
+
+	if (eloop_event_add(dhcpcd_ctx->eloop, fd, read_event, read_arg,
+			    write_event, write_arg) == 0)
+		return TRUE;
+	return FALSE;
+}
+
+static void
+remove_watch(DBusWatch *watch, __unused void *data)
+{
+	int fd, flags;
+	int write_only = 0;
+	fd = dbus_watch_get_unix_fd(watch);
+	flags = dbus_watch_get_flags(watch);
+	if (!(flags & DBUS_WATCH_READABLE) && (flags & DBUS_WATCH_WRITABLE))
+		write_only = 1;
+	eloop_event_delete(dhcpcd_ctx->eloop, fd, write_only);
+}
+
+static DBusHandlerResult
+dhcpcd_dbus_filter(DBusConnection *conn, DBusMessage *msg, void *user_data)
+{
+	const char *service = NULL;
+	const char *old_owner = NULL;
+	const char *new_owner = NULL;
+
+	if (!dbus_message_is_signal(msg, DBUS_INTERFACE_DBUS,
+				    "NameOwnerChanged"))
+		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+	if (!dbus_message_get_args(msg, NULL,
+				   DBUS_TYPE_STRING, &service,
+				   DBUS_TYPE_STRING, &old_owner,
+				   DBUS_TYPE_STRING, &new_owner,
+				   DBUS_TYPE_INVALID)) {
+		syslog(LOG_ERR,
+		       "Invalid arguments for NameOwnerChanged signal");
+		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+	}
+	if (strcmp(service, "org.chromium.flimflam") == 0 &&
+	    strlen(new_owner) == 0) {
+		syslog(LOG_INFO, "exiting because flimflamd has died");
+		dhcpcd_stop_interfaces(dhcpcd_ctx);
+		exit(EXIT_FAILURE);
+	}
+	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+int
+rpc_init(struct dhcpcd_ctx *ctx)
+{
+	DBusObjectPathVTable vt = {
+		NULL, &msg_handler, NULL, NULL, NULL, NULL
+	};
+	DBusError err;
+	int ret;
+
+	dhcpcd_ctx = ctx;
+
+	dbus_error_init(&err);
+	connection = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
+	if (connection == NULL) {
+		if (dbus_error_is_set(&err))
+			syslog(LOG_ERR, "%s", err.message);
+		else
+			syslog(LOG_ERR, "failed to get a dbus connection");
+		return -1;
+	}
+	atexit(rpc_close);
+
+	if (!dbus_connection_set_watch_functions(connection,
+		add_watch, remove_watch, NULL, NULL, NULL))
+	{
+		syslog(LOG_ERR, "dbus: failed to set watch functions");
+		return -1;
+	}
+	if (!dbus_connection_register_object_path(connection,
+		SERVICE_PATH, &vt, NULL))
+	{
+		syslog(LOG_ERR, "dbus: failed to register object path");
+		return -1;
+	}
+	dbus_connection_add_filter(connection, dhcpcd_dbus_filter, NULL, NULL);
+	dbus_bus_add_match(connection, service_watch_rule, &err);
+	if (dbus_error_is_set(&err)) {
+		syslog(LOG_ERR, "Cannot add rule: %s", err.message);
+		return -1;
+	}
+	return 0;
+}
+
+void
+rpc_close(void)
+{
+	if (connection) {
+		dbus_bus_remove_match(connection, service_watch_rule, NULL);
+		dbus_connection_remove_filter(connection,
+					      dhcpcd_dbus_filter,
+					      NULL);
+		dbus_connection_unref(connection);
+		connection = NULL;
+	}
+}
+
+void
+rpc_signal_status(const char *status)
+{
+	DBusMessage *msg;
+	DBusMessageIter args;
+	int pid = getpid();
+
+	syslog(LOG_INFO, "status changed to %s", status);
+
+	msg = dbus_message_new_signal(SERVICE_PATH, SERVICE_NAME,
+	    "StatusChanged");
+	if (msg == NULL) {
+		syslog(LOG_ERR, "failed to make a status changed message");
+		return;
+	}
+	dbus_message_iter_init_append(msg, &args);
+	dbus_message_iter_append_basic(&args, DBUS_TYPE_UINT32, &pid);
+	dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &status);
+	if (!dbus_connection_send(connection, msg, NULL))
+		syslog(LOG_ERR, "failed to send status to dbus");
+	dbus_message_unref(msg);
+}
+
+
+int
+rpc_update_ipv4(struct interface *ifp)
+{
+	struct dhcp_state *state = D_STATE(ifp);
+	if (state->new != NULL) {
+		/* push state over d-bus */
+		dbus_send_message(ifp, state->reason, "new_", state->new);
+		rpc_signal_status("Bound");
+	} else {
+		rpc_signal_status("Release");
+	}
+	return 0;
+}
+
+#ifdef INET6
+int
+rpc_update_ipv6(struct interface *ifp)
+{
+	struct dhcp6_state *state = D6_STATE(ifp);
+	if (state->new != NULL) {
+		/* push state over d-bus */
+		dbus_send_dhcpv6_message(ifp, state->reason, "new_",
+					 state->new, state->new_len);
+		rpc_signal_status("Bound6");
+	} else {
+		rpc_signal_status("Release6");
+	}
+	return 0;
+}
+#endif
+
+int
+rpc_notify_unicast_arp(struct interface *ifp) {
+	struct dhcp_state *state = D_STATE(ifp);
+	return dbus_send_message(ifp, "GATEWAY-ARP", "saved_", state->offer);
+}
diff --git a/dhcpcd-6.8.2/dbus/test/introspection b/dhcpcd-6.8.2/dbus/test/introspection
new file mode 100755
index 0000000..772a1db
--- /dev/null
+++ b/dhcpcd-6.8.2/dbus/test/introspection
@@ -0,0 +1,9 @@
+#!/usr/bin/python
+
+import dbus
+
+bus = dbus.SystemBus()
+
+object = dbus.Interface(bus.get_object("org.chromium.dhcpcd", '/'),
+				"org.freedesktop.DBus.Introspectable")
+print object.Introspect()
diff --git a/dhcpcd-6.8.2/dbus/test/monitor b/dhcpcd-6.8.2/dbus/test/monitor
new file mode 100755
index 0000000..11d17b8
--- /dev/null
+++ b/dhcpcd-6.8.2/dbus/test/monitor
@@ -0,0 +1,19 @@
+#!/usr/bin/python
+
+import gobject
+import dbus
+import dbus.mainloop.glib
+
+def event(pid, reason, value):
+	print "pid %s %s: %s" % (pid, reason, value)
+
+if __name__ == '__main__':
+	dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+
+	bus = dbus.SystemBus()
+
+	bus.add_signal_receiver(event, bus_name="org.chromium.dhcpcd",
+	    signal_name = "Event")
+
+	mainloop = gobject.MainLoop()
+	mainloop.run()
diff --git a/dhcpcd-6.8.2/defs.h b/dhcpcd-6.8.2/defs.h
new file mode 100644
index 0000000..43f9354
--- /dev/null
+++ b/dhcpcd-6.8.2/defs.h
@@ -0,0 +1,76 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef CONFIG_H
+#define CONFIG_H
+
+#define PACKAGE			"dhcpcd"
+#define VERSION			"6.8.2"
+
+#ifndef CONFIG
+# define CONFIG			SYSCONFDIR "/" PACKAGE ".conf"
+#endif
+#ifndef SCRIPT
+# define SCRIPT			LIBEXECDIR "/" PACKAGE "-run-hooks"
+#endif
+#ifndef DEVDIR
+# define DEVDIR			LIBDIR "/" PACKAGE "/dev"
+#endif
+#ifndef DUID
+# define DUID			SYSCONFDIR "/" PACKAGE ".duid"
+#endif
+#ifndef SECRET
+# define SECRET			SYSCONFDIR "/" PACKAGE ".secret"
+#endif
+#ifndef LEASEFILE
+# define LEASEFILE		DBDIR "/" PACKAGE "-%s%s%s.lease"
+#endif
+#ifndef LEASEFILE6
+# define LEASEFILE6		LEASEFILE "6"
+#endif
+#ifndef PIDFILE
+# define PIDFILE		RUNDIR "/" PACKAGE "%s%s%s.pid"
+#endif
+#ifndef CONTROLSOCKET
+# define CONTROLSOCKET		RUNDIR "/" PACKAGE "%s%s.sock"
+#endif
+#ifndef UNPRIVSOCKET
+# define UNPRIVSOCKET		RUNDIR "/" PACKAGE ".unpriv.sock"
+#endif
+#ifndef RDM_MONOFILE
+# define RDM_MONOFILE		DBDIR "/" PACKAGE "-rdm.monotonic"
+#endif
+
+#ifndef NO_SIGNALS
+#  define USE_SIGNALS
+#endif
+#ifndef USE_SIGNALS
+#  ifndef THERE_IS_NO_FORK
+#    define THERE_IS_NO_FORK
+#  endif
+#endif
+
+#endif
diff --git a/dhcpcd-6.8.2/dev.c b/dhcpcd-6.8.2/dev.c
new file mode 100644
index 0000000..6c6b111
--- /dev/null
+++ b/dhcpcd-6.8.2/dev.c
@@ -0,0 +1,188 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <dirent.h>
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define _INDEV
+#include "common.h"
+#include "dev.h"
+#include "eloop.h"
+#include "dhcpcd.h"
+
+int
+dev_initialized(struct dhcpcd_ctx *ctx, const char *ifname)
+{
+
+	if (ctx->dev == NULL)
+		return 1;
+	return ctx->dev->initialized(ifname);
+}
+
+int
+dev_listening(struct dhcpcd_ctx *ctx)
+{
+
+	if (ctx->dev == NULL)
+		return 0;
+	return ctx->dev->listening();
+}
+
+static void
+dev_stop1(struct dhcpcd_ctx *ctx, int stop)
+{
+
+	if (ctx->dev) {
+		if (stop)
+			logger(ctx, LOG_DEBUG,
+			    "dev: unloaded %s", ctx->dev->name);
+		eloop_event_delete(ctx->eloop, ctx->dev_fd, 0);
+		ctx->dev->stop();
+		free(ctx->dev);
+		ctx->dev = NULL;
+		ctx->dev_fd = -1;
+	}
+	if (ctx->dev_handle) {
+		dlclose(ctx->dev_handle);
+		ctx->dev_handle = NULL;
+	}
+}
+
+void
+dev_stop(struct dhcpcd_ctx *ctx)
+{
+
+	dev_stop1(ctx,!(ctx->options & DHCPCD_FORKED));
+}
+
+static int
+dev_start2(struct dhcpcd_ctx *ctx, const char *name)
+{
+	char file[PATH_MAX];
+	void *h;
+	void (*fptr)(struct dev *, const struct dev_dhcpcd *);
+	int r;
+	struct dev_dhcpcd dev_dhcpcd;
+
+	snprintf(file, sizeof(file), DEVDIR "/%s", name);
+	h = dlopen(file, RTLD_LAZY);
+	if (h == NULL) {
+		logger(ctx, LOG_ERR, "dlopen: %s", dlerror());
+		return -1;
+	}
+	fptr = (void (*)(struct dev *, const struct dev_dhcpcd *))
+	    dlsym(h, "dev_init");
+	if (fptr == NULL) {
+		logger(ctx, LOG_ERR, "dlsym: %s", dlerror());
+		dlclose(h);
+		return -1;
+	}
+	ctx->dev = calloc(1, sizeof(*ctx->dev));
+	dev_dhcpcd.handle_interface = &dhcpcd_handleinterface;
+	fptr(ctx->dev, &dev_dhcpcd);
+	if (ctx->dev->start  == NULL || (r = ctx->dev->start()) == -1) {
+		free(ctx->dev);
+		ctx->dev = NULL;
+		dlclose(h);
+		return -1;
+	}
+	logger(ctx, LOG_INFO, "dev: loaded %s", ctx->dev->name);
+	ctx->dev_handle = h;
+	return r;
+}
+
+static int
+dev_start1(struct dhcpcd_ctx *ctx)
+{
+	DIR *dp;
+	struct dirent *d;
+	int r;
+
+	if (ctx->dev) {
+		logger(ctx, LOG_ERR, "dev: already started %s", ctx->dev->name);
+		return -1;
+	}
+
+	if (ctx->dev_load)
+		return dev_start2(ctx, ctx->dev_load);
+
+	dp = opendir(DEVDIR);
+	if (dp == NULL) {
+		logger(ctx, LOG_DEBUG, "dev: %s: %m", DEVDIR);
+		return 0;
+	}
+
+	r = 0;
+	while ((d = readdir(dp))) {
+		if (d->d_name[0] == '.')
+			continue;
+
+		r = dev_start2(ctx, d->d_name);
+		if (r != -1)
+			break;
+	}
+	closedir(dp);
+	return r;
+}
+
+static void
+dev_handle_data(void *arg)
+{
+	struct dhcpcd_ctx *ctx;
+
+	ctx = arg;
+	if (ctx->dev->handle_device(arg) == -1) {
+		/* XXX: an error occured. should we restart dev? */
+	}
+}
+
+int
+dev_start(struct dhcpcd_ctx *ctx)
+{
+
+	if (ctx->dev_fd != -1) {
+		logger(ctx, LOG_ERR, "%s: already started on fd %d", __func__,
+		    ctx->dev_fd);
+		return ctx->dev_fd;
+	}
+
+	ctx->dev_fd = dev_start1(ctx);
+	if (ctx->dev_fd != -1) {
+		if (eloop_event_add(ctx->eloop,
+			ctx->dev_fd, dev_handle_data, ctx, NULL, NULL) == -1)
+		{
+			logger(ctx, LOG_ERR,
+			    "%s: eloop_event_add: %m", __func__);
+			dev_stop1(ctx, 1);
+			return -1;
+		}
+	}
+
+	return ctx->dev_fd;
+}
diff --git a/dhcpcd-6.8.2/dev.h b/dhcpcd-6.8.2/dev.h
new file mode 100644
index 0000000..cc6aee3
--- /dev/null
+++ b/dhcpcd-6.8.2/dev.h
@@ -0,0 +1,60 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef DEV_H
+#define DEV_H
+
+// dev plugin setup
+struct dev {
+	const char *name;
+	int (*initialized)(const char *);
+	int (*listening)(void);
+	int (*handle_device)(void *);
+	int (*start)(void);
+	void (*stop)(void);
+};
+
+struct dev_dhcpcd {
+	int (*handle_interface)(void *, int, const char *);
+};
+
+int dev_init(struct dev *, const struct dev_dhcpcd *);
+
+// hooks for dhcpcd
+#ifdef PLUGIN_DEV
+#include "dhcpcd.h"
+int dev_initialized(struct dhcpcd_ctx *, const char *);
+int dev_listening(struct dhcpcd_ctx *);
+int dev_start(struct dhcpcd_ctx *);
+void dev_stop(struct dhcpcd_ctx *);
+#else
+#define dev_initialized(a, b) (1)
+#define dev_listening(a) (0)
+#define dev_start(a) {}
+#define dev_stop(a) {}
+#endif
+
+#endif
diff --git a/dhcpcd-6.8.2/dev/Makefile b/dhcpcd-6.8.2/dev/Makefile
new file mode 100644
index 0000000..e6b3a2c
--- /dev/null
+++ b/dhcpcd-6.8.2/dev/Makefile
@@ -0,0 +1,42 @@
+TOP?=	../
+include ${TOP}/Makefile.inc
+include ${TOP}/config.mk
+
+CFLAGS?=	-O2
+CSTD?=		c99
+CFLAGS+=	-std=${CSTD}
+
+DEVDIR=		${LIBDIR}/dhcpcd/dev
+DSRC=		${DEV_PLUGINS:=.c}
+DOBJ=		${DSRC:.c=.o}
+DSOBJ=		${DOBJ:.o=.So}
+DPLUGS=		${DEV_PLUGINS:=.so}
+
+CLEANFILES+=	${DSOBJ} ${DPLUGS}
+
+.SUFFIXES:	.So .so
+
+.c.So:
+	${CC} ${PICFLAG} -DPIC ${CPPFLAGS} ${CFLAGS} -c $< -o $@
+
+.So.so: ${DSOBJ}
+	${CC} ${LDFLAGS} -shared -Wl,-x -o $@ -Wl,-soname,$@ \
+	    $< ${LIBS}
+
+all: ${DPLUGS}
+
+udev.So:
+CFLAGS+=	${LIBUDEV_CFLAGS}
+CPPFLAGS+=	${LIBUDEV_CPPFLAGS}
+
+udev.so:
+LIBS+=		${LIBUDEV_LIBS}
+
+proginstall: ${DPLUGS}
+	${INSTALL} -d ${DESTDIR}${DEVDIR}
+	${INSTALL} -m ${BINMODE} ${PROG} ${DPLUGS} ${DESTDIR}${DEVDIR}
+
+install: proginstall
+
+clean:
+	rm -f ${CLEANFILES}
diff --git a/dhcpcd-6.8.2/dev/udev.c b/dhcpcd-6.8.2/dev/udev.c
new file mode 100644
index 0000000..4f7030e
--- /dev/null
+++ b/dhcpcd-6.8.2/dev/udev.c
@@ -0,0 +1,179 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef LIBUDEV_NOINIT
+#  define LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE
+#  warning This version of udev is too old does not support
+#  warning per device initialization checks.
+#  warning As such, dhcpcd will need to depend on the
+#  warning udev-settle service or similar if starting
+#  warning in master mode.
+#endif
+
+#include <libudev.h>
+#include <string.h>
+#include <syslog.h>
+
+#include "../common.h"
+#include "../dev.h"
+
+static const char udev_name[] = "udev";
+static struct udev *udev;
+static struct udev_monitor *monitor;
+
+static struct dev_dhcpcd dhcpcd;
+
+static int
+udev_listening(void)
+{
+
+	return monitor ? 1 : 0;
+}
+
+static int
+udev_initialized(const char *ifname)
+{
+	struct udev_device *device;
+	int r;
+
+	device = udev_device_new_from_subsystem_sysname(udev, "net", ifname);
+	if (device) {
+#ifndef LIBUDEV_NOINIT
+		r = udev_device_get_is_initialized(device);
+#else
+		r = 1;
+#endif
+		udev_device_unref(device);
+	} else
+		r = 0;
+	return r;
+}
+
+static int
+udev_handle_device(void *ctx)
+{
+	struct udev_device *device;
+	const char *subsystem, *ifname, *action;
+
+	device = udev_monitor_receive_device(monitor);
+	if (device == NULL) {
+		syslog(LOG_ERR, "libudev: received NULL device");
+		return -1;
+	}
+
+	subsystem = udev_device_get_subsystem(device);
+	ifname = udev_device_get_sysname(device);
+	action = udev_device_get_action(device);
+
+	/* udev filter documentation says "usually" so double check */
+	if (strcmp(subsystem, "net") == 0) {
+		syslog(LOG_DEBUG, "%s: libudev: %s", ifname, action);
+		if (strcmp(action, "add") == 0 || strcmp(action, "move") == 0)
+			dhcpcd.handle_interface(ctx, 1, ifname);
+		else if (strcmp(action, "remove") == 0)
+			dhcpcd.handle_interface(ctx, -1, ifname);
+	}
+
+	udev_device_unref(device);
+	return 1;
+}
+
+static void
+udev_stop(void)
+{
+
+	if (monitor) {
+		udev_monitor_unref(monitor);
+		monitor = NULL;
+	}
+
+	if (udev) {
+		udev_unref(udev);
+		udev = NULL;
+	}
+}
+
+static int
+udev_start(void)
+{
+	int fd;
+
+	if (udev) {
+		syslog(LOG_ERR, "udev: already started");
+		return -1;
+	}
+
+	syslog(LOG_DEBUG, "udev: starting");
+	udev = udev_new();
+	if (udev == NULL) {
+		syslog(LOG_ERR, "udev_new: %m");
+		return -1;
+	}
+	monitor = udev_monitor_new_from_netlink(udev, "udev");
+	if (monitor == NULL) {
+		syslog(LOG_ERR, "udev_monitor_new_from_netlink: %m");
+		goto bad;
+	}
+#ifndef LIBUDEV_NOFILTER
+	if (udev_monitor_filter_add_match_subsystem_devtype(monitor,
+	    "net", NULL) != 0)
+	{
+		syslog(LOG_ERR,
+		    "udev_monitor_filter_add_match_subsystem_devtype: %m");
+		goto bad;
+	}
+#endif
+	if (udev_monitor_enable_receiving(monitor) != 0) {
+		syslog(LOG_ERR, "udev_monitor_enable_receiving: %m");
+		goto bad;
+	}
+	fd = udev_monitor_get_fd(monitor);
+	if (fd == -1) {
+		syslog(LOG_ERR, "udev_monitor_get_fd: %m");
+		goto bad;
+	}
+	return fd;
+
+bad:
+	udev_stop();
+	return -1;
+}
+
+int
+dev_init(struct dev *dev, const struct dev_dhcpcd *dev_dhcpcd)
+{
+
+	dev->name = udev_name;
+	dev->initialized = udev_initialized;
+	dev->listening = udev_listening;
+	dev->handle_device = udev_handle_device;
+	dev->stop = udev_stop;
+	dev->start = udev_start;
+
+	dhcpcd = *dev_dhcpcd;
+
+	return 0;
+}
diff --git a/dhcpcd-6.8.2/dhcp-common.c b/dhcpcd-6.8.2/dhcp-common.c
new file mode 100644
index 0000000..588684e
--- /dev/null
+++ b/dhcpcd-6.8.2/dhcp-common.c
@@ -0,0 +1,929 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/utsname.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "config.h"
+
+#include "common.h"
+#include "dhcp-common.h"
+#include "dhcp.h"
+#include "if.h"
+#include "ipv6.h"
+
+void
+dhcp_print_option_encoding(const struct dhcp_opt *opt, int cols)
+{
+
+	while (cols < 40) {
+		putchar(' ');
+		cols++;
+	}
+	putchar('\t');
+	if (opt->type & EMBED)
+		printf(" embed");
+	if (opt->type & ENCAP)
+		printf(" encap");
+	if (opt->type & INDEX)
+		printf(" index");
+	if (opt->type & ARRAY)
+		printf(" array");
+	if (opt->type & UINT8)
+		printf(" byte");
+	else if (opt->type & UINT16)
+		printf(" uint16");
+	else if (opt->type & SINT16)
+		printf(" sint16");
+	else if (opt->type & UINT32)
+		printf(" uint32");
+	else if (opt->type & SINT32)
+		printf(" sint32");
+	else if (opt->type & ADDRIPV4)
+		printf(" ipaddress");
+	else if (opt->type & ADDRIPV6)
+		printf(" ip6address");
+	else if (opt->type & FLAG)
+		printf(" flag");
+	else if (opt->type & RFC3397)
+		printf(" domain");
+	else if (opt->type & DOMAIN)
+		printf(" dname");
+	else if (opt->type & ASCII)
+		printf(" ascii");
+	else if (opt->type & RAW)
+		printf(" raw");
+	else if (opt->type & BINHEX)
+		printf(" binhex");
+	else if (opt->type & STRING)	
+		printf(" string");
+	if (opt->type & RFC3361)	
+		printf(" rfc3361");
+	if (opt->type & RFC3442)
+		printf(" rfc3442");
+	if (opt->type & RFC5969)
+		printf(" rfc5969");
+	if (opt->type & REQUEST)
+		printf(" request");
+	if (opt->type & NOREQ)
+		printf(" norequest");
+	putchar('\n');
+}
+
+struct dhcp_opt *
+vivso_find(uint32_t iana_en, const void *arg)
+{
+	const struct interface *ifp;
+	size_t i;
+	struct dhcp_opt *opt;
+
+	ifp = arg;
+	for (i = 0, opt = ifp->options->vivso_override;
+	    i < ifp->options->vivso_override_len;
+	    i++, opt++)
+		if (opt->option == iana_en)
+			return opt;
+	for (i = 0, opt = ifp->ctx->vivso;
+	    i < ifp->ctx->vivso_len;
+	    i++, opt++)
+		if (opt->option == iana_en)
+			return opt;
+	return NULL;
+}
+
+ssize_t
+dhcp_vendor(char *str, size_t len)
+{
+	struct utsname utn;
+	char *p;
+	int l;
+
+	if (uname(&utn) != 0)
+		return (ssize_t)snprintf(str, len, "%s-%s",
+		    PACKAGE, VERSION);
+	p = str;
+	l = snprintf(p, len,
+	    "%s-%s:%s-%s:%s", PACKAGE, VERSION,
+	    utn.sysname, utn.release, utn.machine);
+	if (l == -1 || (size_t)(l + 1) > len)
+		return -1;
+	p += l;
+	len -= (size_t)l;
+	l = if_machinearch(p, len);
+	if (l == -1 || (size_t)(l + 1) > len)
+		return -1;
+	p += l;
+	return p - str;
+}
+
+int
+make_option_mask(const struct dhcp_opt *dopts, size_t dopts_len,
+    const struct dhcp_opt *odopts, size_t odopts_len,
+    uint8_t *mask, const char *opts, int add)
+{
+	char *token, *o, *p;
+	const struct dhcp_opt *opt;
+	int match, e;
+	unsigned int n;
+	size_t i;
+
+	if (opts == NULL)
+		return -1;
+	o = p = strdup(opts);
+	while ((token = strsep(&p, ", "))) {
+		if (*token == '\0')
+			continue;
+		match = 0;
+		for (i = 0, opt = odopts; i < odopts_len; i++, opt++) {
+			if (strcmp(opt->var, token) == 0)
+				match = 1;
+			else {
+				n = (unsigned int)strtou(token, NULL, 0,
+				    0, UINT_MAX, &e);
+				if (e == 0 && opt->option == n)
+					match = 1;
+			}
+			if (match)
+				break;
+		}
+		if (match == 0) {
+			for (i = 0, opt = dopts; i < dopts_len; i++, opt++) {
+				if (strcmp(opt->var, token) == 0)
+				        match = 1;
+				else {
+					n = (unsigned int)strtou(token, NULL, 0,
+					    0, UINT_MAX, &e);
+					if (e == 0 && opt->option == n)
+						match = 1;
+				}
+				if (match)
+					break;
+			}
+		}
+		if (!match || !opt->option) {
+			free(o);
+			errno = ENOENT;
+			return -1;
+		}
+		if (add == 2 && !(opt->type & ADDRIPV4)) {
+			free(o);
+			errno = EINVAL;
+			return -1;
+		}
+		if (add == 1 || add == 2)
+			add_option_mask(mask, opt->option);
+		else
+			del_option_mask(mask, opt->option);
+	}
+	free(o);
+	return 0;
+}
+
+size_t
+encode_rfc1035(const char *src, uint8_t *dst)
+{
+	uint8_t *p;
+	uint8_t *lp;
+	size_t len;
+	uint8_t has_dot;
+
+	if (src == NULL || *src == '\0')
+		return 0;
+
+	if (dst) {
+		p = dst;
+		lp = p++;
+	}
+	/* Silence bogus GCC warnings */
+	else
+		p = lp = NULL;
+
+	len = 1;
+	has_dot = 0;
+	for (; *src; src++) {
+		if (*src == '\0')
+			break;
+		if (*src == '.') {
+			/* Skip the trailing . */
+			if (src[1] == '\0')
+				break;
+			has_dot = 1;
+			if (dst) {
+				*lp = (uint8_t)(p - lp - 1);
+				if (*lp == '\0')
+					return len;
+				lp = p++;
+			}
+		} else if (dst)
+			*p++ = (uint8_t)*src;
+		len++;
+	}
+
+	if (dst) {
+		*lp = (uint8_t)(p - lp - 1);
+		if (has_dot)
+			*p++ = '\0';
+	}
+
+	if (has_dot)
+		len++;
+
+	return len;
+}
+
+/* Decode an RFC3397 DNS search order option into a space
+ * separated string. Returns length of string (including
+ * terminating zero) or zero on error. out may be NULL
+ * to just determine output length. */
+ssize_t
+decode_rfc3397(char *out, size_t len, const uint8_t *p, size_t pl)
+{
+	const char *start;
+	size_t start_len, l, count;
+	const uint8_t *r, *q = p, *e;
+	int hops;
+	uint8_t ltype;
+
+	count = 0;
+	start = out;
+	start_len = len;
+	q = p;
+	e = p + pl;
+	while (q < e) {
+		r = NULL;
+		hops = 0;
+		/* Check we are inside our length again in-case
+		 * the name isn't fully qualified (ie, not terminated) */
+		while (q < e && (l = (size_t)*q++)) {
+			ltype = l & 0xc0;
+			if (ltype == 0x80 || ltype == 0x40)
+				return -1;
+			else if (ltype == 0xc0) { /* pointer */
+				if (q == e) {
+					errno = ERANGE;
+					return -1;
+				}
+				l = (l & 0x3f) << 8;
+				l |= *q++;
+				/* save source of first jump. */
+				if (!r)
+					r = q;
+				hops++;
+				if (hops > 255) {
+					errno = ERANGE;
+					return -1;
+				}
+				q = p + l;
+				if (q >= e) {
+					errno = ERANGE;
+					return -1;
+				}
+			} else {
+				/* straightforward name segment, add with '.' */
+				if (q + l > e) {
+					errno = ERANGE;
+					return -1;
+				}
+				count += l + 1;
+				if (out) {
+					if (l + 1 > len) {
+						errno = ENOBUFS;
+						return -1;
+					}
+					memcpy(out, q, l);
+					out += l;
+					*out++ = '.';
+					len -= l;
+					len--;
+				}
+				q += l;
+			}
+		}
+		/* change last dot to space */
+		if (out && out != start)
+			*(out - 1) = ' ';
+		if (r)
+			q = r;
+	}
+
+	/* change last space to zero terminator */
+	if (out) {
+		if (out != start)
+			*(out - 1) = '\0';
+		else if (start_len > 0)
+			*out = '\0';
+	}
+
+	if (count)
+		/* Don't count the trailing NUL */
+		count--;
+	return (ssize_t)count;
+}
+
+/* Check for a valid domain name as per RFC1123 with the exception of
+ * allowing - and _ (but not at start or end) as they seem to be widely used. */
+static int
+valid_domainname(char *lbl, int type)
+{
+	char *slbl, *lst;
+	unsigned char c;
+	int start, len, errset;
+
+	if (lbl == NULL || *lbl == '\0') {
+		errno = EINVAL;
+		return 0;
+	}
+
+	slbl = lbl;
+	lst = NULL;
+	start = 1;
+	len = errset = 0;
+	for (;;) {
+		c = (unsigned char)*lbl++;
+		if (c == '\0')
+			return 1;
+		if (c == ' ') {
+			if (lbl - 1 == slbl) /* No space at start */
+				break;
+			if (!(type & ARRAY))
+				break;
+			/* Skip to the next label */
+			if (!start) {
+				start = 1;
+				lst = lbl - 1;
+			}
+			if (len)
+				len = 0;
+			continue;
+		}
+		if (c == '.') {
+			if (*lbl == '.')
+				break;
+			len = 0;
+			continue;
+		}
+		if (((c == '-' || c == '_') &&
+		    !start && *lbl != ' ' && *lbl != '\0') ||
+		    isalnum(c))
+		{
+			if (++len > 63) {
+				errno = ERANGE;
+				errset = 1;
+				break;
+			}
+		} else
+			break;
+		if (start)
+			start = 0;
+	}
+
+	if (!errset)
+		errno = EINVAL;
+	if (lst) {
+		/* At least one valid domain, return it */
+		*lst = '\0';
+		return 1;
+	}
+	return 0;
+}
+
+/*
+ * Prints a chunk of data to a string.
+ * PS_SHELL goes as it is these days, it's upto the target to validate it.
+ * PS_SAFE has all non ascii and non printables changes to escaped octal.
+ */
+static const char hexchrs[] = "0123456789abcdef";
+ssize_t
+print_string(char *dst, size_t len, int type, const uint8_t *data, size_t dl)
+{
+	char *odst;
+	uint8_t c;
+	const uint8_t *e;
+	size_t bytes;
+
+	odst = dst;
+	bytes = 0;
+	e = data + dl;
+
+	while (data < e) {
+		c = *data++;
+		if (type & BINHEX) {
+			if (dst) {
+				if (len  == 0 || len == 1) {
+					errno = ENOSPC;
+					return -1;
+				}
+				*dst++ = hexchrs[(c & 0xF0) >> 4];
+				*dst++ = hexchrs[(c & 0x0F)];
+				len -= 2;
+			}
+			bytes += 2;
+			continue;
+		}
+		if (type & ASCII && (!isascii(c))) {
+			errno = EINVAL;
+			break;
+		}
+		if (!(type & (ASCII | RAW | ESCSTRING | ESCFILE)) /* plain */ &&
+		    (!isascii(c) && !isprint(c)))
+		{
+			errno = EINVAL;
+			break;
+		}
+		if ((type & (ESCSTRING | ESCFILE) &&
+		    (c == '\\' || !isascii(c) || !isprint(c))) ||
+		    (type & ESCFILE && (c == '/' || c == ' ')))
+		{
+			errno = EINVAL;
+			if (c == '\\') {
+				if (dst) {
+					if (len  == 0 || len == 1) {
+						errno = ENOSPC;
+						return -1;
+					}
+					*dst++ = '\\'; *dst++ = '\\';
+					len -= 2;
+				}
+				bytes += 2;
+				continue;
+			}
+			if (dst) {
+				if (len < 5) {
+					errno = ENOSPC;
+					return -1;
+				}
+				*dst++ = '\\';
+		                *dst++ = (char)(((c >> 6) & 03) + '0');
+		                *dst++ = (char)(((c >> 3) & 07) + '0');
+		                *dst++ = (char)(( c       & 07) + '0');
+				len -= 4;
+			}
+			bytes += 4;
+		} else {
+			if (dst) {
+				if (len == 0) {
+					errno = ENOSPC;
+					return -1;
+				}
+				*dst++ = (char)c;
+				len--;
+			}
+			bytes++;
+		}
+	}
+
+	/* NULL */
+	if (dst) {
+		if (len == 0) {
+			errno = ENOSPC;
+			return -1;
+		}
+		*dst = '\0';
+
+		/* Now we've printed it, validate the domain */
+		if (type & DOMAIN && !valid_domainname(odst, type)) {
+			*odst = '\0';
+			return 1;
+		}
+
+	}
+
+	return (ssize_t)bytes;
+}
+
+#define ADDR6SZ		16
+static size_t
+dhcp_optlen(const struct dhcp_opt *opt, size_t dl)
+{
+	size_t sz;
+
+	if (opt->type & ADDRIPV6)
+		sz = ADDR6SZ;
+	else if (opt->type & (UINT32 | ADDRIPV4))
+		sz = sizeof(uint32_t);
+	else if (opt->type & UINT16)
+		sz = sizeof(uint16_t);
+	else if (opt->type & (UINT8 | BITFLAG))
+		sz = sizeof(uint8_t);
+	else if (opt->type & FLAG)
+		return 0;
+	else {
+		/* All other types are variable length */
+		if (opt->len) {
+			if ((size_t)opt->len > dl) {
+				errno = ENODATA;
+				return -1;
+			}
+			return (ssize_t)opt->len;
+		}
+		return (ssize_t)dl;
+	}
+	if (dl < sz) {
+		errno = ENODATA;
+		return -1;
+	}
+
+	/* Trim any extra data.
+	 * Maybe we need a settng to reject DHCP options with extra data? */
+	if (opt->type & ARRAY)
+		return (ssize_t)(dl - (dl % sz));
+	return (ssize_t)sz;
+}
+
+#ifdef INET6
+#define PO_IFNAME
+#else
+#define PO_IFNAME __unused
+#endif
+
+ssize_t
+print_option(char *s, size_t len, int type, const uint8_t *data, size_t dl,
+    PO_IFNAME const char *ifname)
+{
+	const uint8_t *e, *t;
+	uint16_t u16;
+	int16_t s16;
+	uint32_t u32;
+	int32_t s32;
+	struct in_addr addr;
+	ssize_t bytes = 0, sl;
+	size_t l;
+	char *tmp;
+
+	if (type & RFC3397) {
+		sl = decode_rfc3397(NULL, 0, data, dl);
+		if (sl == 0 || sl == -1)
+			return sl;
+		l = (size_t)sl + 1;
+		tmp = malloc(l);
+		if (tmp == NULL)
+			return -1;
+		decode_rfc3397(tmp, l, data, dl);
+		sl = print_string(s, len, type, (uint8_t *)tmp, l - 1);
+		free(tmp);
+		return sl;
+	}
+
+#ifdef INET
+	if (type & RFC3361) {
+		if ((tmp = decode_rfc3361(data, dl)) == NULL)
+			return -1;
+		l = strlen(tmp);
+		sl = print_string(s, len, type, (uint8_t *)tmp, l);
+		free(tmp);
+		return sl;
+	}
+
+	if (type & RFC3442)
+		return decode_rfc3442(s, len, data, dl);
+
+	if (type & RFC5969)
+		return decode_rfc5969(s, len, data, dl);
+#endif
+
+	if (type & STRING)
+		return print_string(s, len, type, data, dl);
+
+	if (type & FLAG) {
+		if (s) {
+			*s++ = '1';
+			*s = '\0';
+		}
+		return 1;
+	}
+
+	if (!s) {
+		if (type & UINT8)
+			l = 3;
+		else if (type & UINT16) {
+			l = 5;
+			dl /= 2;
+		} else if (type & SINT16) {
+			l = 6;
+			dl /= 2;
+		} else if (type & UINT32) {
+			l = 10;
+			dl /= 4;
+		} else if (type & SINT32) {
+			l = 11;
+			dl /= 4;
+		} else if (type & ADDRIPV4) {
+			l = 16;
+			dl /= 4;
+		}
+#ifdef INET6
+		else if (type & ADDRIPV6) {
+			e = data + dl;
+			l = 0;
+			while (data < e) {
+				if (l)
+					l++; /* space */
+				sl = ipv6_printaddr(NULL, 0, data, ifname);
+				if (sl != -1)
+					l += (size_t)sl;
+				data += 16;
+			}
+			return (ssize_t)l;
+		}
+#endif
+		else {
+			errno = EINVAL;
+			return -1;
+		}
+		return (ssize_t)(l * dl);
+	}
+
+	t = data;
+	e = data + dl;
+	while (data < e) {
+		if (data != t) {
+			*s++ = ' ';
+			bytes++;
+			len--;
+		}
+		if (type & UINT8) {
+			sl = snprintf(s, len, "%u", *data);
+			data++;
+		} else if (type & UINT16) {
+			memcpy(&u16, data, sizeof(u16));
+			u16 = ntohs(u16);
+			sl = snprintf(s, len, "%u", u16);
+			data += sizeof(u16);
+		} else if (type & SINT16) {
+			memcpy(&u16, data, sizeof(u16));
+			s16 = (int16_t)ntohs(u16);
+			sl = snprintf(s, len, "%d", s16);
+			data += sizeof(u16);
+		} else if (type & UINT32) {
+			memcpy(&u32, data, sizeof(u32));
+			u32 = ntohl(u32);
+			sl = snprintf(s, len, "%u", u32);
+			data += sizeof(u32);
+		} else if (type & SINT32) {
+			memcpy(&u32, data, sizeof(u32));
+			s32 = (int32_t)ntohl(u32);
+			sl = snprintf(s, len, "%d", s32);
+			data += sizeof(u32);
+		} else if (type & ADDRIPV4) {
+			memcpy(&addr.s_addr, data, sizeof(addr.s_addr));
+			sl = snprintf(s, len, "%s", inet_ntoa(addr));
+			data += sizeof(addr.s_addr);
+		}
+#ifdef INET6
+		else if (type & ADDRIPV6) {
+			ssize_t r;
+
+			r = ipv6_printaddr(s, len, data, ifname);
+			if (r != -1)
+				sl = r;
+			else
+				sl = 0;
+			data += 16;
+		}
+#endif
+		else
+			sl = 0;
+		if (len <= sl) {
+			bytes += len;
+			break;
+		}
+		len -= (size_t)sl;
+		bytes += sl;
+		s += sl;
+	}
+
+	return bytes;
+}
+
+/* Lease file name is formatted according to the expectation of the ChromiumOS's
+ * connection manager (shill). */
+int
+dhcp_set_leasefile(char *leasefile, size_t len, int family,
+    const struct interface *ifp, const char *extra)
+{
+	char ssid[len];
+
+	if (ifp->name[0] == '\0') {
+		strlcpy(leasefile, ifp->ctx->pidfile, len);
+		return 0;
+	}
+
+	if (strlen(ifp->lease_identifier) > 0) {
+		return snprintf(leasefile, len,
+				family == AF_INET ? LEASEFILE : LEASEFILE6,
+				ifp->lease_identifier, "", extra);
+	}
+	return snprintf(leasefile, len,
+			family == AF_INET ? LEASEFILE : LEASEFILE6,
+			ifp->name, "", extra);
+}
+
+static size_t
+dhcp_envoption1(struct dhcpcd_ctx *ctx, char **env, const char *prefix,
+    const struct dhcp_opt *opt, int vname, const uint8_t *od, size_t ol,
+    const char *ifname)
+{
+	ssize_t len;
+	size_t e;
+	char *v, *val;
+
+	/* Ensure a valid length */
+	ol = (size_t)dhcp_optlen(opt, ol);
+	if ((ssize_t)ol == -1)
+		return 0;
+
+	len = print_option(NULL, 0, opt->type, od, ol, ifname);
+	if (len < 0)
+		return 0;
+	if (vname)
+		e = strlen(opt->var) + 1;
+	else
+		e = 0;
+	if (prefix)
+		e += strlen(prefix);
+	e += (size_t)len + 2;
+	if (env == NULL)
+		return e;
+	v = val = *env = malloc(e);
+	if (v == NULL) {
+		logger(ctx, LOG_ERR, "%s: %m", __func__);
+		return 0;
+	}
+	if (vname)
+		v += snprintf(val, e, "%s_%s=", prefix, opt->var);
+	else
+		v += snprintf(val, e, "%s=", prefix);
+	if (len != 0)
+		print_option(v, (size_t)len + 1, opt->type, od, ol, ifname);
+	return e;
+}
+
+size_t
+dhcp_envoption(struct dhcpcd_ctx *ctx, char **env, const char *prefix,
+    const char *ifname, struct dhcp_opt *opt,
+    const uint8_t *(*dgetopt)(struct dhcpcd_ctx *,
+    size_t *, unsigned int *, size_t *,
+    const uint8_t *, size_t, struct dhcp_opt **),
+    const uint8_t *od, size_t ol)
+{
+	size_t e, i, n, eos, eol;
+	unsigned int eoc;
+	const uint8_t *eod;
+	int ov;
+	struct dhcp_opt *eopt, *oopt;
+	char *pfx;
+
+	/* If no embedded or encapsulated options, it's easy */
+	if (opt->embopts_len == 0 && opt->encopts_len == 0) {
+		if (dhcp_envoption1(ctx, env == NULL ? NULL : &env[0],
+		    prefix, opt, 1, od, ol, ifname))
+			return 1;
+		return 0;
+	}
+
+	/* Create a new prefix based on the option */
+	if (env) {
+		if (opt->type & INDEX) {
+			if (opt->index > 999) {
+				errno = ENOBUFS;
+				logger(ctx, LOG_ERR, "%s: %m", __func__);
+				return 0;
+			}
+		}
+		e = strlen(prefix) + strlen(opt->var) + 2 +
+		    (opt->type & INDEX ? 3 : 0);
+		pfx = malloc(e);
+		if (pfx == NULL) {
+			logger(ctx, LOG_ERR, "%s: %m", __func__);
+			return 0;
+		}
+		if (opt->type & INDEX)
+			snprintf(pfx, e, "%s_%s%d", prefix,
+			    opt->var, ++opt->index);
+		else
+			snprintf(pfx, e, "%s_%s", prefix, opt->var);
+	} else
+		pfx = NULL;
+
+	/* Embedded options are always processed first as that
+	 * is a fixed layout */
+	n = 0;
+	for (i = 0, eopt = opt->embopts; i < opt->embopts_len; i++, eopt++) {
+		e = dhcp_optlen(eopt, ol);
+		if (e == 0) {
+			/* An option was expected, but there is not enough
+			 * data for it.
+			 * This may not be an error as some options like
+			 * DHCP FQDN in RFC4702 have a string as the last
+			 * option which is optional.
+			 * FIXME: Add an flag to the options to indicate
+			 * wether this is allowable or not. */
+			 if (ol != 0 || i + 1 < opt->embopts_len)
+				logger(ctx, LOG_WARNING,
+				    "%s: %s: malformed option %d",
+				    ifname, __func__, opt->option);
+			 goto out;
+		}
+		/* Use the option prefix if the embedded option
+		 * name is different.
+		 * This avoids new_fqdn_fqdn which would be silly. */
+		ov = strcmp(opt->var, eopt->var);
+		if (dhcp_envoption1(ctx, env == NULL ? NULL : &env[n],
+		    pfx, eopt, ov, od, e, ifname))
+			n++;
+		od += e;
+		ol -= e;
+	}
+
+	/* Enumerate our encapsulated options */
+	if (opt->encopts_len && ol > 0) {
+		/* Zero any option indexes
+		 * We assume that referenced encapsulated options are NEVER
+		 * recursive as the index order could break. */
+		for (i = 0, eopt = opt->encopts;
+		    i < opt->encopts_len;
+		    i++, eopt++)
+		{
+			eoc = opt->option;
+			if (eopt->type & OPTION) {
+				dgetopt(ctx, NULL, &eoc, NULL, NULL, 0, &oopt);
+				if (oopt)
+					oopt->index = 0;
+			}
+		}
+
+		while ((eod = dgetopt(ctx, &eos, &eoc, &eol, od, ol, &oopt))) {
+			for (i = 0, eopt = opt->encopts;
+			    i < opt->encopts_len;
+			    i++, eopt++)
+			{
+				if (eopt->option == eoc) {
+					if (eopt->type & OPTION) {
+						if (oopt == NULL)
+							/* Report error? */
+							continue;
+					}
+					n += dhcp_envoption(ctx,
+					    env == NULL ? NULL : &env[n], pfx,
+					    ifname,
+					    eopt->type & OPTION ? oopt : eopt,
+					    dgetopt, eod, eol);
+					break;
+				}
+			}
+			od += eos + eol;
+			ol -= eos + eol;
+		}
+	}
+
+out:
+	if (env)
+		free(pfx);
+
+	/* Return number of options found */
+	return n;
+}
+
+void
+dhcp_zero_index(struct dhcp_opt *opt)
+{
+	size_t i;
+	struct dhcp_opt *o;
+
+	opt->index = 0;
+	for (i = 0, o = opt->embopts; i < opt->embopts_len; i++, o++)
+		dhcp_zero_index(o);
+	for (i = 0, o = opt->encopts; i < opt->encopts_len; i++, o++)
+		dhcp_zero_index(o);
+}
diff --git a/dhcpcd-6.8.2/dhcp-common.h b/dhcpcd-6.8.2/dhcp-common.h
new file mode 100644
index 0000000..a87d32a
--- /dev/null
+++ b/dhcpcd-6.8.2/dhcp-common.h
@@ -0,0 +1,120 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef DHCPCOMMON_H
+#define DHCPCOMMON_H
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+
+#include <stdint.h>
+
+#include "common.h"
+#include "dhcpcd.h"
+
+/* Max MTU - defines dhcp option length */
+#define MTU_MAX             1500
+#define MTU_MIN             576
+
+#define REQUEST		(1 << 0)
+#define UINT8		(1 << 1)
+#define UINT16		(1 << 2)
+#define SINT16		(1 << 3)
+#define UINT32		(1 << 4)
+#define SINT32		(1 << 5)
+#define ADDRIPV4	(1 << 6)
+#define STRING		(1 << 7)
+#define ARRAY		(1 << 8)
+#define RFC3361		(1 << 9)
+#define RFC3397		(1 << 10)
+#define RFC3442		(1 << 11)
+#define RFC5969		(1 << 12)
+#define ADDRIPV6	(1 << 13)
+#define BINHEX		(1 << 14)
+#define FLAG		(1 << 15)
+#define NOREQ		(1 << 16)
+#define EMBED		(1 << 17)
+#define ENCAP		(1 << 18)
+#define INDEX		(1 << 19)
+#define OPTION		(1 << 20)
+#define DOMAIN		(1 << 21)
+#define ASCII		(1 << 22)
+#define RAW		(1 << 23)
+#define ESCSTRING	(1 << 24)
+#define ESCFILE		(1 << 25)
+#define BITFLAG		(1 << 26)
+
+struct dhcp_opt {
+	uint32_t option; /* Also used for IANA Enterpise Number */
+	int type;
+	size_t len;
+	char *var;
+
+	int index; /* Index counter for many instances of the same option */
+
+	/* Embedded options.
+	 * The option code is irrelevant here. */
+	struct dhcp_opt *embopts;
+	size_t embopts_len;
+
+	/* Encapsulated options */
+	struct dhcp_opt *encopts;
+	size_t encopts_len;
+};
+
+struct dhcp_opt *vivso_find(uint32_t, const void *);
+
+ssize_t dhcp_vendor(char *, size_t);
+
+void dhcp_print_option_encoding(const struct dhcp_opt *opt, int cols);
+#define add_option_mask(var, val) \
+	((var)[(val) >> 3] = (uint8_t)((var)[(val) >> 3] | 1 << ((val) & 7)))
+#define del_option_mask(var, val) \
+	((var)[(val) >> 3] = (uint8_t)((var)[(val) >> 3] & ~(1 << ((val) & 7))))
+#define has_option_mask(var, val) \
+	((var)[(val) >> 3] & (uint8_t)(1 << ((val) & 7)))
+int make_option_mask(const struct dhcp_opt *, size_t,
+    const struct dhcp_opt *, size_t,
+    uint8_t *, const char *, int);
+
+size_t encode_rfc1035(const char *src, uint8_t *dst);
+ssize_t decode_rfc3397(char *, size_t, const uint8_t *, size_t);
+ssize_t print_string(char *, size_t, int, const uint8_t *, size_t);
+ssize_t print_option(char *, size_t, int, const uint8_t *, size_t,
+    const char *);
+int dhcp_set_leasefile(char *, size_t, int,
+    const struct interface *, const char *);
+
+size_t dhcp_envoption(struct dhcpcd_ctx *,
+    char **, const char *, const char *, struct dhcp_opt *,
+    const uint8_t *(*dgetopt)(struct dhcpcd_ctx *,
+    size_t *, unsigned int *, size_t *,
+    const uint8_t *, size_t, struct dhcp_opt **),
+    const uint8_t *od, size_t ol);
+void dhcp_zero_index(struct dhcp_opt *);
+
+#endif
diff --git a/dhcpcd-6.8.2/dhcp.c b/dhcpcd-6.8.2/dhcp.c
new file mode 100644
index 0000000..f1cdc36
--- /dev/null
+++ b/dhcpcd-6.8.2/dhcp.c
@@ -0,0 +1,3807 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+
+#include <arpa/inet.h>
+#include <net/if.h>
+#include <net/route.h>
+#include <netinet/if_ether.h>
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#define __FAVOR_BSD /* Nasty glibc hack so we can use BSD semantics for UDP */
+#include <netinet/udp.h>
+#undef __FAVOR_BSD
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define ELOOP_QUEUE 2
+#include "config.h"
+#include "arp.h"
+#include "common.h"
+#include "dhcp.h"
+#include "dhcpcd.h"
+#include "dhcp-common.h"
+#include "duid.h"
+#include "eloop.h"
+#include "if.h"
+#include "ipv4.h"
+#include "ipv4ll.h"
+#include "rpc-interface.h"
+#include "script.h"
+
+#define DAD		"Duplicate address detected"
+#define DHCP_MIN_LEASE	20
+
+#define IPV4A		ADDRIPV4 | ARRAY
+#define IPV4R		ADDRIPV4 | REQUEST
+
+/* We should define a maximum for the NAK exponential backoff */
+#define NAKOFF_MAX              60
+
+/* Wait N nanoseconds between sending a RELEASE and dropping the address.
+ * This gives the kernel enough time to actually send it. */
+#define RELEASE_DELAY_S		0
+#define RELEASE_DELAY_NS	10000000
+
+#ifndef IPDEFTTL
+#define IPDEFTTL 64 /* RFC1340 */
+#endif
+
+struct dhcp_op {
+	uint8_t value;
+	const char *name;
+};
+
+static const struct dhcp_op dhcp_ops[] = {
+	{ DHCP_DISCOVER,   "DISCOVER" },
+	{ DHCP_OFFER,      "OFFER" },
+	{ DHCP_REQUEST,    "REQUEST" },
+	{ DHCP_DECLINE,    "DECLINE" },
+	{ DHCP_ACK,        "ACK" },
+	{ DHCP_NAK,        "NAK" },
+	{ DHCP_RELEASE,    "RELEASE" },
+	{ DHCP_INFORM,     "INFORM" },
+	{ DHCP_FORCERENEW, "DHCP_FORCERENEW"},
+	{ 0, NULL }
+};
+
+static const char * const dhcp_params[] = {
+	"ip_address",
+	"subnet_cidr",
+	"network_number",
+	"filename",
+	"server_name",
+	NULL
+};
+
+struct udp_dhcp_packet
+{
+	struct ip ip;
+	struct udphdr udp;
+	struct dhcp_message dhcp;
+};
+
+static const size_t udp_dhcp_len = sizeof(struct udp_dhcp_packet);
+
+static int dhcp_open(struct interface *ifp);
+
+void
+dhcp_printoptions(const struct dhcpcd_ctx *ctx,
+    const struct dhcp_opt *opts, size_t opts_len)
+{
+	const char * const *p;
+	size_t i, j;
+	const struct dhcp_opt *opt, *opt2;
+	int cols;
+
+	for (p = dhcp_params; *p; p++)
+		printf("    %s\n", *p);
+
+	for (i = 0, opt = ctx->dhcp_opts; i < ctx->dhcp_opts_len; i++, opt++) {
+		for (j = 0, opt2 = opts; j < opts_len; j++, opt2++)
+			if (opt->option == opt2->option)
+				break;
+		if (j == opts_len) {
+			cols = printf("%03d %s", opt->option, opt->var);
+			dhcp_print_option_encoding(opt, cols);
+		}
+	}
+	for (i = 0, opt = opts; i < opts_len; i++, opt++) {
+		cols = printf("%03d %s", opt->option, opt->var);
+		dhcp_print_option_encoding(opt, cols);
+	}
+}
+
+#define get_option_raw(ctx, dhcp, opt) get_option(ctx, dhcp, opt, NULL)
+static const uint8_t *
+get_option(struct dhcpcd_ctx *ctx,
+    const struct dhcp_message *dhcp, unsigned int opt, size_t *len)
+{
+	const uint8_t *p = dhcp->options;
+	const uint8_t *e = p + sizeof(dhcp->options);
+	uint8_t l, ol = 0;
+	uint8_t o = 0;
+	uint8_t overl = 0;
+	uint8_t *bp = NULL;
+	const uint8_t *op = NULL;
+	size_t bl = 0;
+
+	/* Check we have the magic cookie */
+	if (dhcp->cookie != htonl(MAGIC_COOKIE)) {
+		errno = ENOTSUP;
+		return NULL;
+	}
+
+	/* DHCP options are in TLV format with T and L each being a single
+	 * bytes.  In general, here we have p -> T, ol=p+1 -> L, op -> V.
+	 * We must make sure there is enough room to read both T and L.
+	 */
+	while (p + 1 < e) {
+		o = *p++;
+		if (o == opt) {
+			if (op) {
+				if (!ctx->opt_buffer) {
+					ctx->opt_buffer =
+					    malloc(DHCP_OPTION_LEN +
+					    BOOTFILE_LEN + SERVERNAME_LEN);
+					if (ctx->opt_buffer == NULL)
+						return NULL;
+				}
+				if (!bp)
+					bp = ctx->opt_buffer;
+				memcpy(bp, op, ol);
+				bp += ol;
+			}
+			ol = (p + *p < e) ? *p : e - (p + 1);
+			if (p + ol > e) {
+				errno = EINVAL;
+				return NULL;
+			}
+			op = p + 1;
+			bl += ol;
+		}
+		switch (o) {
+		case DHO_PAD:
+			continue;
+		case DHO_END:
+			if (overl & 1) {
+				/* bit 1 set means parse boot file */
+				overl = (uint8_t)(overl & ~1);
+				p = dhcp->bootfile;
+				e = p + sizeof(dhcp->bootfile);
+			} else if (overl & 2) {
+				/* bit 2 set means parse server name */
+				overl = (uint8_t)(overl & ~2);
+				p = dhcp->servername;
+				e = p + sizeof(dhcp->servername);
+			} else
+				goto exit;
+			break;
+		case DHO_OPTIONSOVERLOADED:
+			/* Ensure we only get this option once by setting
+			 * the last bit as well as the value.
+			 * This is valid because only the first two bits
+			 * actually mean anything in RFC2132 Section 9.3 */
+			if (!overl)
+				overl = 0x80 | p[1];
+			break;
+		}
+		l = *p++;
+		p += l;
+	}
+
+exit:
+	if (len)
+		*len = bl;
+	if (bp) {
+		memcpy(bp, op, ol);
+		return (const uint8_t *)ctx->opt_buffer;
+	}
+	if (op)
+		return op;
+	errno = ENOENT;
+	return NULL;
+}
+
+int
+get_option_addr(struct dhcpcd_ctx *ctx,
+    struct in_addr *a, const struct dhcp_message *dhcp,
+    uint8_t option)
+{
+	const uint8_t *p;
+	size_t len;
+
+	p = get_option(ctx, dhcp, option, &len);
+	if (!p || len < (ssize_t)sizeof(a->s_addr))
+		return -1;
+	memcpy(&a->s_addr, p, sizeof(a->s_addr));
+	return 0;
+}
+
+static int
+get_option_uint32(struct dhcpcd_ctx *ctx,
+    uint32_t *i, const struct dhcp_message *dhcp, uint8_t option)
+{
+	const uint8_t *p;
+	size_t len;
+	uint32_t d;
+
+	p = get_option(ctx, dhcp, option, &len);
+	if (!p || len < (ssize_t)sizeof(d))
+		return -1;
+	memcpy(&d, p, sizeof(d));
+	if (i)
+		*i = ntohl(d);
+	return 0;
+}
+
+static int
+get_option_uint8(struct dhcpcd_ctx *ctx,
+    uint8_t *i, const struct dhcp_message *dhcp, uint8_t option)
+{
+	const uint8_t *p;
+	size_t len;
+
+	p = get_option(ctx, dhcp, option, &len);
+	if (!p || len < (ssize_t)sizeof(*p))
+		return -1;
+	if (i)
+		*i = *(p);
+	return 0;
+}
+
+ssize_t
+decode_rfc3442(char *out, size_t len, const uint8_t *p, size_t pl)
+{
+	const uint8_t *e;
+	size_t bytes = 0, ocets;
+	int b;
+	uint8_t cidr;
+	struct in_addr addr;
+	char *o = out;
+
+	/* Minimum is 5 -first is CIDR and a router length of 4 */
+	if (pl < 5) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	e = p + pl;
+	while (p < e) {
+		cidr = *p++;
+		if (cidr > 32) {
+			errno = EINVAL;
+			return -1;
+		}
+		ocets = (size_t)(cidr + 7) / NBBY;
+		if (p + 4 + ocets > e) {
+			errno = ERANGE;
+			return -1;
+		}
+		if (!out) {
+			p += 4 + ocets;
+			bytes += ((4 * 4) * 2) + 4;
+			continue;
+		}
+		if ((((4 * 4) * 2) + 4) > len) {
+			errno = ENOBUFS;
+			return -1;
+		}
+		if (o != out) {
+			*o++ = ' ';
+			len--;
+		}
+		/* If we have ocets then we have a destination and netmask */
+		if (ocets > 0) {
+			addr.s_addr = 0;
+			memcpy(&addr.s_addr, p, ocets);
+			b = snprintf(o, len, "%s/%d", inet_ntoa(addr), cidr);
+			p += ocets;
+		} else
+			b = snprintf(o, len, "0.0.0.0/0");
+		o += b;
+		len -= (size_t)b;
+
+		/* Finally, snag the router */
+		memcpy(&addr.s_addr, p, 4);
+		p += 4;
+		b = snprintf(o, len, " %s", inet_ntoa(addr));
+		o += b;
+		len -= (size_t)b;
+	}
+
+	if (out)
+		return o - out;
+	return (ssize_t)bytes;
+}
+
+static struct rt_head *
+decode_rfc3442_rt(struct dhcpcd_ctx *ctx, const uint8_t *data, size_t dl)
+{
+	const uint8_t *p = data;
+	const uint8_t *e;
+	uint8_t cidr;
+	size_t ocets;
+	struct rt_head *routes;
+	struct rt *rt = NULL;
+
+	/* Minimum is 5 -first is CIDR and a router length of 4 */
+	if (dl < 5)
+		return NULL;
+
+	routes = malloc(sizeof(*routes));
+	TAILQ_INIT(routes);
+	e = p + dl;
+	while (p < e) {
+		cidr = *p++;
+		if (cidr > 32) {
+			ipv4_freeroutes(routes);
+			errno = EINVAL;
+			return NULL;
+		}
+
+		ocets = (size_t)(cidr + 7) / NBBY;
+		if (p + 4 + ocets > e) {
+			ipv4_freeroutes(routes);
+			errno = ERANGE;
+			return NULL;
+		}
+
+		rt = calloc(1, sizeof(*rt));
+		if (rt == NULL) {
+			logger(ctx, LOG_ERR, "%s: %m", __func__);
+			ipv4_freeroutes(routes);
+			return NULL;
+		}
+		TAILQ_INSERT_TAIL(routes, rt, next);
+
+		/* If we have ocets then we have a destination and netmask */
+		if (ocets > 0) {
+			memcpy(&rt->dest.s_addr, p, ocets);
+			p += ocets;
+			rt->net.s_addr = htonl(~0U << (32 - cidr));
+		}
+
+		/* Finally, snag the router */
+		memcpy(&rt->gate.s_addr, p, 4);
+		p += 4;
+	}
+	return routes;
+}
+
+char *
+decode_rfc3361(const uint8_t *data, size_t dl)
+{
+	uint8_t enc;
+	size_t l;
+	ssize_t r;
+	char *sip = NULL;
+	struct in_addr addr;
+	char *p;
+
+	if (dl < 2) {
+		errno = EINVAL;
+		return 0;
+	}
+
+	enc = *data++;
+	dl--;
+	switch (enc) {
+	case 0:
+		if ((r = decode_rfc3397(NULL, 0, data, dl)) > 0) {
+			l = (size_t)r;
+			sip = malloc(l);
+			if (sip == NULL)
+				return 0;
+			decode_rfc3397(sip, l, data, dl);
+		}
+		break;
+	case 1:
+		if (dl == 0 || dl % 4 != 0) {
+			errno = EINVAL;
+			break;
+		}
+		addr.s_addr = INADDR_BROADCAST;
+		l = ((dl / sizeof(addr.s_addr)) * ((4 * 4) + 1)) + 1;
+		sip = p = malloc(l);
+		if (sip == NULL)
+			return 0;
+		while (dl != 0) {
+			memcpy(&addr.s_addr, data, sizeof(addr.s_addr));
+			data += sizeof(addr.s_addr);
+			p += snprintf(p, l - (size_t)(p - sip),
+			    "%s ", inet_ntoa(addr));
+			dl -= sizeof(addr.s_addr);
+		}
+		*--p = '\0';
+		break;
+	default:
+		errno = EINVAL;
+		return 0;
+	}
+
+	return sip;
+}
+
+/* Decode an RFC5969 6rd order option into a space
+ * separated string. Returns length of string (including
+ * terminating zero) or zero on error. */
+ssize_t
+decode_rfc5969(char *out, size_t len, const uint8_t *p, size_t pl)
+{
+	uint8_t ipv4masklen, ipv6prefixlen;
+	uint8_t ipv6prefix[16];
+	uint8_t br[4];
+	int i;
+	ssize_t b, bytes = 0;
+
+	if (pl < 22) {
+		errno = EINVAL;
+		return 0;
+	}
+
+	ipv4masklen = *p++;
+	pl--;
+	ipv6prefixlen = *p++;
+	pl--;
+
+	for (i = 0; i < 16; i++) {
+		ipv6prefix[i] = *p++;
+		pl--;
+	}
+	if (out) {
+		b= snprintf(out, len,
+		    "%d %d "
+		    "%02x%02x:%02x%02x:"
+		    "%02x%02x:%02x%02x:"
+		    "%02x%02x:%02x%02x:"
+		    "%02x%02x:%02x%02x",
+		    ipv4masklen, ipv6prefixlen,
+		    ipv6prefix[0], ipv6prefix[1], ipv6prefix[2], ipv6prefix[3],
+		    ipv6prefix[4], ipv6prefix[5], ipv6prefix[6], ipv6prefix[7],
+		    ipv6prefix[8], ipv6prefix[9], ipv6prefix[10],ipv6prefix[11],
+		    ipv6prefix[12],ipv6prefix[13],ipv6prefix[14], ipv6prefix[15]
+		);
+
+		len -= (size_t)b;
+		out += b;
+		bytes += b;
+	} else {
+		bytes += 16 * 2 + 8 + 2 + 1 + 2;
+	}
+
+	while (pl >= 4) {
+		br[0] = *p++;
+		br[1] = *p++;
+		br[2] = *p++;
+		br[3] = *p++;
+		pl -= 4;
+
+		if (out) {
+			b= snprintf(out, len, " %d.%d.%d.%d",
+			    br[0], br[1], br[2], br[3]);
+			len -= (size_t)b;
+			out += b;
+			bytes += b;
+		} else {
+			bytes += (4 * 4);
+		}
+	}
+
+	return bytes;
+}
+
+static char *
+get_option_string(struct dhcpcd_ctx *ctx,
+    const struct dhcp_message *dhcp, uint8_t option)
+{
+	size_t len;
+	const uint8_t *p;
+	char *s;
+
+	p = get_option(ctx, dhcp, option, &len);
+	if (!p || len == 0 || *p == '\0')
+		return NULL;
+
+	s = malloc(sizeof(char) * (len + 1));
+	if (s) {
+		memcpy(s, p, len);
+		s[len] = '\0';
+	}
+	return s;
+}
+
+/* This calculates the netmask that we should use for static routes.
+ * This IS different from the calculation used to calculate the netmask
+ * for an interface address. */
+static uint32_t
+route_netmask(uint32_t ip_in)
+{
+	/* used to be unsigned long - check if error */
+	uint32_t p = ntohl(ip_in);
+	uint32_t t;
+
+	if (IN_CLASSA(p))
+		t = ~IN_CLASSA_NET;
+	else {
+		if (IN_CLASSB(p))
+			t = ~IN_CLASSB_NET;
+		else {
+			if (IN_CLASSC(p))
+				t = ~IN_CLASSC_NET;
+			else
+				t = 0;
+		}
+	}
+
+	while (t & p)
+		t >>= 1;
+
+	return (htonl(~t));
+}
+
+/* We need to obey routing options.
+ * If we have a CSR then we only use that.
+ * Otherwise we add static routes and then routers. */
+struct rt_head *
+get_option_routes(struct interface *ifp, const struct dhcp_message *dhcp)
+{
+	struct if_options *ifo = ifp->options;
+	const uint8_t *p;
+	const uint8_t *e;
+	struct rt_head *routes = NULL;
+	struct rt *route = NULL;
+	size_t len;
+	const char *csr = "";
+
+	/* If we have CSR's then we MUST use these only */
+	if (!has_option_mask(ifo->nomask, DHO_CSR))
+		p = get_option(ifp->ctx, dhcp, DHO_CSR, &len);
+	else
+		p = NULL;
+	/* Check for crappy MS option */
+	if (!p && !has_option_mask(ifo->nomask, DHO_MSCSR)) {
+		p = get_option(ifp->ctx, dhcp, DHO_MSCSR, &len);
+		if (p)
+			csr = "MS ";
+	}
+	if (p) {
+		routes = decode_rfc3442_rt(ifp->ctx, p, len);
+		if (routes) {
+			const struct dhcp_state *state;
+
+			state = D_CSTATE(ifp);
+			if (!(ifo->options & DHCPCD_CSR_WARNED) &&
+			    !(state->added & STATE_FAKE))
+			{
+				logger(ifp->ctx, LOG_DEBUG,
+				    "%s: using %sClassless Static Routes",
+				    ifp->name, csr);
+				ifo->options |= DHCPCD_CSR_WARNED;
+			}
+			return routes;
+		}
+	}
+
+	/* OK, get our static routes first. */
+	routes = malloc(sizeof(*routes));
+	if (routes == NULL) {
+		logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
+		return NULL;
+	}
+	TAILQ_INIT(routes);
+	if (!has_option_mask(ifo->nomask, DHO_STATICROUTE))
+		p = get_option(ifp->ctx, dhcp, DHO_STATICROUTE, &len);
+	else
+		p = NULL;
+	/* RFC 2131 Section 5.8 states length MUST be in multiples of 8 */
+	if (p && len % 8 == 0) {
+		e = p + len;
+		while (p < e) {
+			if ((route = calloc(1, sizeof(*route))) == NULL) {
+				logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
+				ipv4_freeroutes(routes);
+				return NULL;
+			}
+			memcpy(&route->dest.s_addr, p, 4);
+			p += 4;
+			memcpy(&route->gate.s_addr, p, 4);
+			p += 4;
+			/* RFC 2131 Section 5.8 states default route is
+			 * illegal */
+			if (route->dest.s_addr == htonl(INADDR_ANY)) {
+				errno = EINVAL;
+				free(route);
+				continue;
+			}
+			route->net.s_addr = route_netmask(route->dest.s_addr);
+			TAILQ_INSERT_TAIL(routes, route, next);
+		}
+	}
+
+	/* Now grab our routers */
+	if (!has_option_mask(ifo->nomask, DHO_ROUTER))
+		p = get_option(ifp->ctx, dhcp, DHO_ROUTER, &len);
+	else
+		p = NULL;
+	if (p) {
+		e = p + len;
+		while (p < e) {
+			if ((route = calloc(1, sizeof(*route))) == NULL) {
+				logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
+				ipv4_freeroutes(routes);
+				return NULL;
+			}
+			memcpy(&route->gate.s_addr, p, 4);
+			p += 4;
+			TAILQ_INSERT_TAIL(routes, route, next);
+		}
+	}
+
+	return routes;
+}
+
+#define PUTADDR(_type, _val)						      \
+	{								      \
+		*p++ = _type;						      \
+		*p++ = 4;						      \
+		memcpy(p, &_val.s_addr, 4);				      \
+		p += 4;							      \
+	}
+
+int
+dhcp_message_add_addr(struct dhcp_message *dhcp,
+    uint8_t type, struct in_addr addr)
+{
+	uint8_t *p;
+	size_t len;
+
+	p = dhcp->options;
+	while (*p != DHO_END) {
+		p++;
+		p += *p + 1;
+	}
+
+	len = (size_t)(p - (uint8_t *)dhcp);
+	if (len + 6 > sizeof(*dhcp)) {
+		errno = ENOMEM;
+		return -1;
+	}
+
+	PUTADDR(type, addr);
+	*p = DHO_END;
+	return 0;
+}
+
+ssize_t
+make_message(struct dhcp_message **message,
+    const struct interface *ifp,
+    uint8_t type)
+{
+	struct dhcp_message *dhcp;
+	uint8_t *m, *lp, *p, *auth;
+	uint8_t *n_params = NULL, auth_len;
+	uint32_t ul;
+	uint16_t sz;
+	size_t len, i;
+	const struct dhcp_opt *opt;
+	struct if_options *ifo = ifp->options;
+	const struct dhcp_state *state = D_CSTATE(ifp);
+	const struct dhcp_lease *lease = &state->lease;
+	time_t up = uptime() - state->start_uptime;
+	char hbuf[HOSTNAME_MAX_LEN + 1];
+	const char *hostname;
+	const struct vivco *vivco;
+
+	dhcp = calloc(1, sizeof (*dhcp));
+	if (dhcp == NULL)
+		return -1;
+	m = (uint8_t *)dhcp;
+	p = dhcp->options;
+
+	if ((type == DHCP_INFORM || type == DHCP_RELEASE ||
+		(type == DHCP_REQUEST &&
+		    state->net.s_addr == lease->net.s_addr &&
+		    (state->new == NULL ||
+			state->new->cookie == htonl(MAGIC_COOKIE)))))
+	{
+		dhcp->ciaddr = state->addr.s_addr;
+		/* In-case we haven't actually configured the address yet */
+		if (type == DHCP_INFORM && state->addr.s_addr == 0)
+			dhcp->ciaddr = lease->addr.s_addr;
+	}
+
+	dhcp->op = DHCP_BOOTREQUEST;
+	dhcp->hwtype = (uint8_t)ifp->family;
+	switch (ifp->family) {
+	case ARPHRD_ETHER:
+	case ARPHRD_IEEE802:
+		dhcp->hwlen = (uint8_t)ifp->hwlen;
+		memcpy(&dhcp->chaddr, &ifp->hwaddr, ifp->hwlen);
+		break;
+	}
+
+	if (ifo->options & DHCPCD_BROADCAST &&
+	    dhcp->ciaddr == 0 &&
+	    type != DHCP_DECLINE &&
+	    type != DHCP_RELEASE)
+		dhcp->flags = htons(BROADCAST_FLAG);
+
+	if (type != DHCP_DECLINE && type != DHCP_RELEASE) {
+		if (up < 0 || up > (time_t)UINT16_MAX)
+			dhcp->secs = htons((uint16_t)UINT16_MAX);
+		else
+			dhcp->secs = htons((uint16_t)up);
+	}
+	dhcp->xid = htonl(state->xid);
+	dhcp->cookie = htonl(MAGIC_COOKIE);
+
+	if (!(ifo->options & DHCPCD_BOOTP)) {
+		*p++ = DHO_MESSAGETYPE;
+		*p++ = 1;
+		*p++ = type;
+	}
+
+	if (state->clientid) {
+		*p++ = DHO_CLIENTID;
+		memcpy(p, state->clientid, (size_t)state->clientid[0] + 1);
+		p += state->clientid[0] + 1;
+	}
+
+	if (lease->addr.s_addr && lease->cookie == htonl(MAGIC_COOKIE)) {
+		if (type == DHCP_DECLINE ||
+		    (type == DHCP_REQUEST &&
+			lease->addr.s_addr != state->addr.s_addr))
+		{
+			PUTADDR(DHO_IPADDRESS, lease->addr);
+			if (lease->server.s_addr)
+				PUTADDR(DHO_SERVERID, lease->server);
+		}
+
+		if (type == DHCP_RELEASE) {
+			if (lease->server.s_addr)
+				PUTADDR(DHO_SERVERID, lease->server);
+		}
+	}
+
+	if (type == DHCP_DECLINE) {
+		*p++ = DHO_MESSAGE;
+		len = strlen(DAD);
+		*p++ = (uint8_t)len;
+		memcpy(p, DAD, len);
+		p += len;
+	}
+
+	if (type == DHCP_DISCOVER &&
+	    !(ifp->ctx->options & DHCPCD_TEST) &&
+	    has_option_mask(ifo->requestmask, DHO_RAPIDCOMMIT))
+	{
+		/* RFC 4039 Section 3 */
+		*p++ = DHO_RAPIDCOMMIT;
+		*p++ = 0;
+	}
+
+	if (type == DHCP_DISCOVER && ifo->options & DHCPCD_REQUEST)
+		PUTADDR(DHO_IPADDRESS, ifo->req_addr);
+
+	/* RFC 2563 Auto Configure */
+	if (type == DHCP_DISCOVER && ifo->options & DHCPCD_IPV4LL) {
+		*p++ = DHO_AUTOCONFIGURE;
+		*p++ = 1;
+		*p++ = 1;
+	}
+
+	if (type == DHCP_DISCOVER ||
+	    type == DHCP_INFORM ||
+	    type == DHCP_REQUEST)
+	{
+		if (!(ifo->options & DHCPCD_BOOTP)) {
+			int mtu;
+
+			*p++ = DHO_MAXMESSAGESIZE;
+			*p++ = 2;
+			mtu = if_getmtu(ifp->name);
+			if (mtu < MTU_MIN) {
+				if (if_setmtu(ifp->name, MTU_MIN) == 0)
+					sz = MTU_MIN;
+			} else if (mtu > MTU_MAX) {
+				/* Even though our MTU could be greater than
+				 * MTU_MAX (1500) dhcpcd does not presently
+				 * handle DHCP packets any bigger. */
+				mtu = MTU_MAX;
+			}
+			sz = htons((uint16_t)mtu);
+			memcpy(p, &sz, 2);
+			p += 2;
+		}
+
+		if (ifo->userclass[0]) {
+			*p++ = DHO_USERCLASS;
+			memcpy(p, ifo->userclass,
+			    (size_t)ifo->userclass[0] + 1);
+			p += ifo->userclass[0] + 1;
+		}
+
+		if (ifo->vendorclassid[0]) {
+			*p++ = DHO_VENDORCLASSID;
+			memcpy(p, ifo->vendorclassid,
+			    (size_t)ifo->vendorclassid[0] + 1);
+			p += ifo->vendorclassid[0] + 1;
+		}
+
+		if (type != DHCP_INFORM) {
+			if (ifo->leasetime != 0) {
+				*p++ = DHO_LEASETIME;
+				*p++ = 4;
+				ul = htonl(ifo->leasetime);
+				memcpy(p, &ul, 4);
+				p += 4;
+			}
+		}
+
+		if (ifo->hostname[0] == '\0')
+			hostname = get_hostname(hbuf, sizeof(hbuf),
+			    ifo->options & DHCPCD_HOSTNAME_SHORT ? 1 : 0);
+		else
+			hostname = ifo->hostname;
+
+		/*
+		 * RFC4702 3.1 States that if we send the Client FQDN option
+		 * then we MUST NOT also send the Host Name option.
+		 * Technically we could, but that is not RFC conformant and
+		 * also seems to break some DHCP server implemetations such as
+		 * Windows. On the other hand, ISC dhcpd is just as non RFC
+		 * conformant by not accepting a partially qualified FQDN.
+		 */
+		if (ifo->fqdn != FQDN_DISABLE) {
+			/* IETF DHC-FQDN option (81), RFC4702 */
+			*p++ = DHO_FQDN;
+			lp = p;
+			*p++ = 3;
+			/*
+			 * Flags: 0000NEOS
+			 * S: 1 => Client requests Server to update
+			 *         a RR in DNS as well as PTR
+			 * O: 1 => Server indicates to client that
+			 *         DNS has been updated
+			 * E: 1 => Name data is DNS format
+			 * N: 1 => Client requests Server to not
+			 *         update DNS
+			 */
+			if (hostname)
+				*p++ = (uint8_t)((ifo->fqdn & 0x09) | 0x04);
+			else
+				*p++ = (FQDN_NONE & 0x09) | 0x04;
+			*p++ = 0; /* from server for PTR RR */
+			*p++ = 0; /* from server for A RR if S=1 */
+			if (hostname) {
+				i = encode_rfc1035(hostname, p);
+				*lp = (uint8_t)(*lp + i);
+				p += i;
+			}
+		} else if (ifo->options & DHCPCD_HOSTNAME && hostname) {
+			*p++ = DHO_HOSTNAME;
+			len = strlen(hostname);
+			*p++ = (uint8_t)len;
+			memcpy(p, hostname, len);
+			p += len;
+		}
+
+		/* vendor is already encoded correctly, so just add it */
+		if (ifo->vendor[0]) {
+			*p++ = DHO_VENDOR;
+			memcpy(p, ifo->vendor, (size_t)ifo->vendor[0] + 1);
+			p += ifo->vendor[0] + 1;
+		}
+
+		if ((ifo->auth.options & DHCPCD_AUTH_SENDREQUIRE) !=
+		    DHCPCD_AUTH_SENDREQUIRE)
+		{
+			/* We support HMAC-MD5 */
+			*p++ = DHO_FORCERENEW_NONCE;
+			*p++ = 1;
+			*p++ = AUTH_ALG_HMAC_MD5;
+		}
+
+		if (ifo->vivco_len) {
+			*p++ = DHO_VIVCO;
+			lp = p++;
+			*lp = sizeof(ul);
+			ul = htonl(ifo->vivco_en);
+			memcpy(p, &ul, sizeof(ul));
+			p += sizeof(ul);
+			for (i = 0, vivco = ifo->vivco;
+			    i < ifo->vivco_len;
+			    i++, vivco++)
+			{
+				len = (size_t)(p - m) + vivco->len + 1;
+				if (len > sizeof(*dhcp))
+					goto toobig;
+				if (vivco->len + 2 + *lp > 255) {
+					logger(ifp->ctx, LOG_ERR,
+					    "%s: VIVCO option too big",
+					    ifp->name);
+					free(dhcp);
+					return -1;
+				}
+				*p++ = (uint8_t)vivco->len;
+				memcpy(p, vivco->data, vivco->len);
+				p += vivco->len;
+				*lp = (uint8_t)(*lp + vivco->len + 1);
+			}
+		}
+
+		len = (size_t)((p - m) + 3);
+		if (len > sizeof(*dhcp))
+			goto toobig;
+		*p++ = DHO_PARAMETERREQUESTLIST;
+		n_params = p;
+		*p++ = 0;
+		for (i = 0, opt = ifp->ctx->dhcp_opts;
+		    i < ifp->ctx->dhcp_opts_len;
+		    i++, opt++)
+		{
+			if (!(opt->type & REQUEST ||
+			    has_option_mask(ifo->requestmask, opt->option)))
+				continue;
+			if (opt->type & NOREQ)
+				continue;
+			if (type == DHCP_INFORM &&
+			    (opt->option == DHO_RENEWALTIME ||
+				opt->option == DHO_REBINDTIME))
+				continue;
+			len = (size_t)((p - m) + 2);
+			if (len > sizeof(*dhcp))
+				goto toobig;
+			*p++ = (uint8_t)opt->option;
+		}
+		for (i = 0, opt = ifo->dhcp_override;
+		    i < ifo->dhcp_override_len;
+		    i++, opt++)
+		{
+			/* Check if added above */
+			for (lp = n_params + 1; lp < p; lp++)
+				if (*lp == (uint8_t)opt->option)
+					break;
+			if (lp < p)
+				continue;
+			if (!(opt->type & REQUEST ||
+			    has_option_mask(ifo->requestmask, opt->option)))
+				continue;
+			if (opt->type & NOREQ)
+				continue;
+			if (type == DHCP_INFORM &&
+			    (opt->option == DHO_RENEWALTIME ||
+				opt->option == DHO_REBINDTIME))
+				continue;
+			len = (size_t)((p - m) + 2);
+			if (len > sizeof(*dhcp))
+				goto toobig;
+			*p++ = (uint8_t)opt->option;
+		}
+		*n_params = (uint8_t)(p - n_params - 1);
+	}
+
+	/* silence GCC */
+	auth_len = 0;
+	auth = NULL;
+
+	if (ifo->auth.options & DHCPCD_AUTH_SEND) {
+		ssize_t alen = dhcp_auth_encode(&ifo->auth,
+		    state->auth.token,
+		    NULL, 0, 4, type, NULL, 0);
+		if (alen != -1 && alen > UINT8_MAX) {
+			errno = ERANGE;
+			alen = -1;
+		}
+		if (alen == -1)
+			logger(ifp->ctx, LOG_ERR,
+			    "%s: dhcp_auth_encode: %m", ifp->name);
+		else if (alen != 0) {
+			auth_len = (uint8_t)alen;
+			len = (size_t)((p + alen) - m);
+			if (len > sizeof(*dhcp))
+				goto toobig;
+			*p++ = DHO_AUTHENTICATION;
+			*p++ = auth_len;
+			auth = p;
+			p += auth_len;
+		}
+	}
+
+	*p++ = DHO_END;
+
+	/* Pad out to the BOOTP minimum message length.
+	 * Some DHCP servers incorrectly require this. */
+	while (p - m < BOOTP_MESSAGE_LENTH_MIN)
+		*p++ = DHO_PAD;
+
+	len = (size_t)(p - m);
+	if (ifo->auth.options & DHCPCD_AUTH_SEND && auth_len != 0)
+		dhcp_auth_encode(&ifo->auth, state->auth.token,
+		    m, len, 4, type, auth, auth_len);
+
+	*message = dhcp;
+	return (ssize_t)len;
+
+toobig:
+	logger(ifp->ctx, LOG_ERR, "%s: DHCP messge too big", ifp->name);
+	free(dhcp);
+	return -1;
+}
+
+static ssize_t
+write_lease(const struct interface *ifp, const struct dhcp_message *dhcp)
+{
+	int fd;
+	size_t len;
+	ssize_t bytes;
+	const uint8_t *e, *p;
+	uint8_t l;
+	uint8_t o = 0;
+	const struct dhcp_state *state = D_CSTATE(ifp);
+	uint8_t write_buffer[sizeof(*dhcp) + sizeof(state->server_info) + 1];
+	uint8_t *w;
+
+	/* We don't write BOOTP leases */
+	if (IS_BOOTP(ifp, dhcp)) {
+		unlink(state->leasefile);
+		return 0;
+	}
+
+	logger(ifp->ctx, LOG_DEBUG, "%s: writing lease `%s'",
+	    ifp->name, state->leasefile);
+
+	fd = open(state->leasefile, O_WRONLY | O_CREAT | O_TRUNC, 0600);
+	if (fd == -1)
+		return -1;
+
+	/* Only write as much as we need */
+	p = dhcp->options;
+	e = p + sizeof(dhcp->options);
+	len = sizeof(*dhcp);
+	while (p < e) {
+		o = *p;
+		if (o == DHO_END) {
+			len = (size_t)(p - (const uint8_t *)dhcp);
+			break;
+		}
+		p++;
+		if (o != DHO_PAD) {
+			l = *p++;
+			p += l;
+		}
+	}
+
+	memcpy(write_buffer, dhcp, len);
+	w = write_buffer + len;
+
+	/* Copy in server info if this is available. */
+	if (state->server_info.gw_hwlen != 0) {
+		*w++ = DHO_END;
+		memcpy(w, &state->server_info, sizeof(state->server_info));
+		len += sizeof(state->server_info) + 1;
+	}
+
+	bytes = write(fd, write_buffer, len);
+	close(fd);
+	return bytes;
+}
+
+static struct dhcp_message *
+read_lease(struct interface *ifp)
+{
+	int fd;
+	struct dhcp_message *dhcp;
+	struct dhcp_state *state = D_STATE(ifp);
+	uint8_t read_buffer[sizeof(*dhcp) + sizeof(state->server_info) + 1];
+	const uint8_t *options_startp =
+			read_buffer + offsetof(struct dhcp_message, options);
+	const uint8_t *options_endp = options_startp + sizeof(dhcp->options);
+	uint8_t option_len;
+	uint8_t option_type = 0;
+	ssize_t bytes;
+	const uint8_t *auth;
+	uint8_t type;
+	size_t auth_len;
+
+	memset(&state->server_info, 0, sizeof(state->server_info));
+	fd = open(state->leasefile, O_RDONLY);
+	if (fd == -1) {
+		if (errno != ENOENT)
+			logger(ifp->ctx, LOG_ERR, "%s: open `%s': %m",
+			    ifp->name, state->leasefile);
+		return NULL;
+	}
+	logger(ifp->ctx, LOG_DEBUG, "%s: reading lease `%s'",
+	    ifp->name, state->leasefile);
+	bytes = read(fd, read_buffer, sizeof(read_buffer));
+	close(fd);
+
+	/* Lease file should at minimum contain all fields before options. */
+	if (read_buffer + bytes < options_startp)
+		return NULL;
+
+	dhcp = calloc(1, sizeof(*dhcp));
+	if (dhcp == NULL) {
+		return NULL;
+	}
+
+	if (options_endp > read_buffer + bytes)
+		options_endp = read_buffer + bytes;
+
+	while (options_startp < options_endp) {
+		option_type = *options_startp++;
+		if (option_type == DHO_END)
+			break;
+		if (option_type != DHO_PAD) {
+			option_len = *options_startp++;
+			options_startp += option_len;
+		}
+	}
+	memcpy(dhcp, read_buffer, options_startp - read_buffer);
+
+	/* We may have found a BOOTP server */
+	if (get_option_uint8(ifp->ctx, &type, dhcp, DHO_MESSAGETYPE) == -1)
+		type = 0;
+
+	/* Authenticate the message */
+	auth = get_option(ifp->ctx, dhcp, DHO_AUTHENTICATION, &auth_len);
+	if (auth) {
+		if (dhcp_auth_validate(&state->auth, &ifp->options->auth,
+		    (uint8_t *)dhcp, sizeof(*dhcp), 4, type,
+		    auth, auth_len) == NULL)
+		{
+			logger(ifp->ctx, LOG_DEBUG,
+			    "%s: dhcp_auth_validate: %m", ifp->name);
+			free(dhcp);
+			return NULL;
+		}
+		if (state->auth.token)
+			logger(ifp->ctx, LOG_DEBUG,
+			    "%s: validated using 0x%08" PRIu32,
+			    ifp->name, state->auth.token->secretid);
+		else
+			logger(ifp->ctx, LOG_DEBUG,
+			    "%s: accepted reconfigure key", ifp->name);
+	}
+
+	/*
+	 * DHCP server information is stored after the DHO_END character
+	 * in the lease file.  The first byte of the server information
+	 * is the length of the gateway hardware address.
+	 */
+	options_endp = read_buffer + bytes;
+	if (options_startp >= options_endp ||
+	    options_startp + sizeof(state->server_info) > options_endp)
+		return dhcp;
+
+	logger(ifp->ctx, LOG_DEBUG, "%s: found server info in lease '%s'",
+	       ifp->name, state->leasefile);
+
+	memcpy(&state->server_info, options_startp, sizeof(state->server_info));
+	if (state->server_info.gw_hwlen != ifp->hwlen) {
+		logger(ifp->ctx, LOG_ERR, "%s: lease file %s has incompatible"
+		       "MAC address length %d (expected %zd)",
+		       ifp->name, state->leasefile,
+		       state->server_info.gw_hwlen, ifp->hwlen);
+		memset(&state->server_info, 0, sizeof(state->server_info));
+	}
+	return dhcp;
+}
+
+static const struct dhcp_opt *
+dhcp_getoverride(const struct if_options *ifo, unsigned int o)
+{
+	size_t i;
+	const struct dhcp_opt *opt;
+
+	for (i = 0, opt = ifo->dhcp_override;
+	    i < ifo->dhcp_override_len;
+	    i++, opt++)
+	{
+		if (opt->option == o)
+			return opt;
+	}
+	return NULL;
+}
+
+static const uint8_t *
+dhcp_getoption(struct dhcpcd_ctx *ctx,
+    size_t *os, unsigned int *code, size_t *len,
+    const uint8_t *od, size_t ol, struct dhcp_opt **oopt)
+{
+	size_t i;
+	struct dhcp_opt *opt;
+
+	if (od) {
+		if (ol < 2) {
+			errno = EINVAL;
+			return NULL;
+		}
+		*os = 2; /* code + len */
+		*code = (unsigned int)*od++;
+		*len = (size_t)*od++;
+		if (*len > ol - *os) {
+			errno = EINVAL;
+			return NULL;
+		}
+	}
+
+	*oopt = NULL;
+	for (i = 0, opt = ctx->dhcp_opts; i < ctx->dhcp_opts_len; i++, opt++) {
+		if (opt->option == *code) {
+			*oopt = opt;
+			break;
+		}
+	}
+
+	return od;
+}
+
+ssize_t
+dhcp_env(char **env, const char *prefix, const struct dhcp_message *dhcp,
+    const struct interface *ifp)
+{
+	const struct if_options *ifo;
+	const uint8_t *p;
+	struct in_addr addr;
+	struct in_addr net;
+	struct in_addr brd;
+	struct dhcp_opt *opt, *vo;
+	size_t e, i, pl;
+	char **ep;
+	char cidr[4], safe[(BOOTFILE_LEN * 4) + 1];
+	uint8_t overl = 0;
+	uint32_t en;
+
+	e = 0;
+	ifo = ifp->options;
+	get_option_uint8(ifp->ctx, &overl, dhcp, DHO_OPTIONSOVERLOADED);
+
+	if (env == NULL) {
+		if (dhcp->yiaddr || dhcp->ciaddr)
+			e += 5;
+		if (*dhcp->bootfile && !(overl & 1))
+			e++;
+		if (*dhcp->servername && !(overl & 2))
+			e++;
+		for (i = 0, opt = ifp->ctx->dhcp_opts;
+		    i < ifp->ctx->dhcp_opts_len;
+		    i++, opt++)
+		{
+			if (has_option_mask(ifo->nomask, opt->option))
+				continue;
+			if (dhcp_getoverride(ifo, opt->option))
+				continue;
+			p = get_option(ifp->ctx, dhcp, opt->option, &pl);
+			if (!p)
+				continue;
+			e += dhcp_envoption(ifp->ctx, NULL, NULL, ifp->name,
+			    opt, dhcp_getoption, p, pl);
+		}
+		for (i = 0, opt = ifo->dhcp_override;
+		    i < ifo->dhcp_override_len;
+		    i++, opt++)
+		{
+			if (has_option_mask(ifo->nomask, opt->option))
+				continue;
+			p = get_option(ifp->ctx, dhcp, opt->option, &pl);
+			if (!p)
+				continue;
+			e += dhcp_envoption(ifp->ctx, NULL, NULL, ifp->name,
+			    opt, dhcp_getoption, p, pl);
+		}
+		return (ssize_t)e;
+	}
+
+	ep = env;
+	if (dhcp->yiaddr || dhcp->ciaddr) {
+		/* Set some useful variables that we derive from the DHCP
+		 * message but are not necessarily in the options */
+		addr.s_addr = dhcp->yiaddr ? dhcp->yiaddr : dhcp->ciaddr;
+		setvar(ifp->ctx, &ep, prefix, "ip_address", inet_ntoa(addr));
+		if (get_option_addr(ifp->ctx, &net,
+		    dhcp, DHO_SUBNETMASK) == -1) {
+			net.s_addr = ipv4_getnetmask(addr.s_addr);
+			setvar(ifp->ctx, &ep, prefix,
+			    "subnet_mask", inet_ntoa(net));
+		}
+		snprintf(cidr, sizeof(cidr), "%d", inet_ntocidr(net));
+		setvar(ifp->ctx, &ep, prefix, "subnet_cidr", cidr);
+		if (get_option_addr(ifp->ctx, &brd,
+		    dhcp, DHO_BROADCAST) == -1) {
+			brd.s_addr = addr.s_addr | ~net.s_addr;
+			setvar(ifp->ctx, &ep, prefix,
+			    "broadcast_address", inet_ntoa(brd));
+		}
+		addr.s_addr = dhcp->yiaddr & net.s_addr;
+		setvar(ifp->ctx, &ep, prefix,
+		    "network_number", inet_ntoa(addr));
+	}
+
+	if (*dhcp->bootfile && !(overl & 1)) {
+		print_string(safe, sizeof(safe), STRING,
+		    dhcp->bootfile, sizeof(dhcp->bootfile));
+		setvar(ifp->ctx, &ep, prefix, "filename", safe);
+	}
+	if (*dhcp->servername && !(overl & 2)) {
+		print_string(safe, sizeof(safe), STRING | DOMAIN,
+		    dhcp->servername, sizeof(dhcp->servername));
+		setvar(ifp->ctx, &ep, prefix, "server_name", safe);
+	}
+
+	/* Zero our indexes */
+	if (env) {
+		for (i = 0, opt = ifp->ctx->dhcp_opts;
+		    i < ifp->ctx->dhcp_opts_len;
+		    i++, opt++)
+			dhcp_zero_index(opt);
+		for (i = 0, opt = ifp->options->dhcp_override;
+		    i < ifp->options->dhcp_override_len;
+		    i++, opt++)
+			dhcp_zero_index(opt);
+		for (i = 0, opt = ifp->ctx->vivso;
+		    i < ifp->ctx->vivso_len;
+		    i++, opt++)
+			dhcp_zero_index(opt);
+	}
+
+	for (i = 0, opt = ifp->ctx->dhcp_opts;
+	    i < ifp->ctx->dhcp_opts_len;
+	    i++, opt++)
+	{
+		if (has_option_mask(ifo->nomask, opt->option))
+			continue;
+		if (dhcp_getoverride(ifo, opt->option))
+			continue;
+		if ((p = get_option(ifp->ctx, dhcp, opt->option, &pl))) {
+			ep += dhcp_envoption(ifp->ctx, ep, prefix, ifp->name,
+			    opt, dhcp_getoption, p, pl);
+			if (opt->option == DHO_VIVSO &&
+			    pl > (int)sizeof(uint32_t))
+			{
+			        memcpy(&en, p, sizeof(en));
+				en = ntohl(en);
+				vo = vivso_find(en, ifp);
+				if (vo) {
+					/* Skip over en + total size */
+					p += sizeof(en) + 1;
+					pl -= sizeof(en) + 1;
+					ep += dhcp_envoption(ifp->ctx,
+					    ep, prefix, ifp->name,
+					    vo, dhcp_getoption, p, pl);
+				}
+			}
+		}
+	}
+
+	for (i = 0, opt = ifo->dhcp_override;
+	    i < ifo->dhcp_override_len;
+	    i++, opt++)
+	{
+		if (has_option_mask(ifo->nomask, opt->option))
+			continue;
+		if ((p = get_option(ifp->ctx, dhcp, opt->option, &pl)))
+			ep += dhcp_envoption(ifp->ctx, ep, prefix, ifp->name,
+			    opt, dhcp_getoption, p, pl);
+	}
+
+	return ep - env;
+}
+
+static void
+get_lease(struct dhcpcd_ctx *ctx,
+    struct dhcp_lease *lease, const struct dhcp_message *dhcp)
+{
+
+	lease->cookie = dhcp->cookie;
+	/* BOOTP does not set yiaddr for replies when ciaddr is set. */
+	if (dhcp->yiaddr)
+		lease->addr.s_addr = dhcp->yiaddr;
+	else
+		lease->addr.s_addr = dhcp->ciaddr;
+	if (get_option_addr(ctx, &lease->net, dhcp, DHO_SUBNETMASK) == -1)
+		lease->net.s_addr = ipv4_getnetmask(lease->addr.s_addr);
+	if (get_option_addr(ctx, &lease->brd, dhcp, DHO_BROADCAST) == -1)
+		lease->brd.s_addr = lease->addr.s_addr | ~lease->net.s_addr;
+	if (get_option_uint32(ctx, &lease->leasetime, dhcp, DHO_LEASETIME) != 0)
+		lease->leasetime = ~0U; /* Default to infinite lease */
+	if (get_option_uint32(ctx, &lease->renewaltime,
+	    dhcp, DHO_RENEWALTIME) != 0)
+		lease->renewaltime = 0;
+	if (get_option_uint32(ctx, &lease->rebindtime,
+	    dhcp, DHO_REBINDTIME) != 0)
+		lease->rebindtime = 0;
+	if (get_option_addr(ctx, &lease->server, dhcp, DHO_SERVERID) != 0)
+		lease->server.s_addr = INADDR_ANY;
+}
+
+static const char *
+get_dhcp_op(uint8_t type)
+{
+	const struct dhcp_op *d;
+
+	for (d = dhcp_ops; d->name; d++)
+		if (d->value == type)
+			return d->name;
+	return NULL;
+}
+
+static void
+dhcp_fallback(void *arg)
+{
+	struct interface *iface;
+
+	iface = (struct interface *)arg;
+	dhcpcd_selectprofile(iface, iface->options->fallback);
+	dhcpcd_startinterface(iface);
+}
+
+uint32_t
+dhcp_xid(const struct interface *ifp)
+{
+	uint32_t xid;
+
+	if (ifp->options->options & DHCPCD_XID_HWADDR &&
+	    ifp->hwlen >= sizeof(xid))
+		/* The lower bits are probably more unique on the network */
+		memcpy(&xid, (ifp->hwaddr + ifp->hwlen) - sizeof(xid),
+		    sizeof(xid));
+	else
+		xid = arc4random();
+
+	return xid;
+}
+
+void
+dhcp_close(struct interface *ifp)
+{
+	struct dhcp_state *state = D_STATE(ifp);
+
+	if (state == NULL)
+		return;
+
+	if (state->raw_fd != -1) {
+		eloop_event_delete(ifp->ctx->eloop, state->raw_fd, 0);
+		close(state->raw_fd);
+		state->raw_fd = -1;
+	}
+
+	state->interval = 0;
+}
+
+static int
+dhcp_openudp(struct interface *ifp)
+{
+	int s;
+	struct sockaddr_in sin;
+	int n;
+	struct dhcp_state *state;
+#ifdef SO_BINDTODEVICE
+	struct ifreq ifr;
+	char *p;
+#endif
+
+#ifdef SOCK_CLOEXEC
+	if ((s = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP)) == -1)
+		return -1;
+#else
+	if ((s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
+		return -1;
+	if ((n = fcntl(s, F_GETFD, 0)) == -1 ||
+	    fcntl(s, F_SETFD, n | FD_CLOEXEC) == -1)
+	{
+		close(s);
+	        return -1;
+	}
+#endif
+
+	n = 1;
+	if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n)) == -1)
+		goto eexit;
+#ifdef SO_BINDTODEVICE
+	if (ifp) {
+		memset(&ifr, 0, sizeof(ifr));
+		strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
+		/* We can only bind to the real device */
+		p = strchr(ifr.ifr_name, ':');
+		if (p)
+			*p = '\0';
+		if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, &ifr,
+		    sizeof(ifr)) == -1)
+		        goto eexit;
+	}
+#endif
+	memset(&sin, 0, sizeof(sin));
+	sin.sin_family = AF_INET;
+	sin.sin_port = htons(DHCP_CLIENT_PORT);
+	if (ifp) {
+		state = D_STATE(ifp);
+		sin.sin_addr.s_addr = state->addr.s_addr;
+	} else
+		state = NULL; /* appease gcc */
+	if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) == -1)
+		goto eexit;
+
+	return s;
+
+eexit:
+	close(s);
+	return -1;
+}
+
+static uint16_t
+checksum(const void *data, unsigned int len)
+{
+	const uint8_t *addr = data;
+	uint32_t sum = 0;
+
+	while (len > 1) {
+		sum += (uint32_t)(addr[0] * 256 + addr[1]);
+		addr += 2;
+		len -= 2;
+	}
+
+	if (len == 1)
+		sum += (uint32_t)(*addr * 256);
+
+	sum = (sum >> 16) + (sum & 0xffff);
+	sum += (sum >> 16);
+
+	return (uint16_t)~htons((uint16_t)sum);
+}
+
+static struct udp_dhcp_packet *
+dhcp_makeudppacket(size_t *sz, const uint8_t *data, size_t length,
+	struct in_addr source, struct in_addr dest)
+{
+	struct udp_dhcp_packet *udpp;
+	struct ip *ip;
+	struct udphdr *udp;
+
+	udpp = calloc(1, sizeof(*udpp));
+	if (udpp == NULL)
+		return NULL;
+	ip = &udpp->ip;
+	udp = &udpp->udp;
+
+	/* OK, this is important :)
+	 * We copy the data to our packet and then create a small part of the
+	 * ip structure and an invalid ip_len (basically udp length).
+	 * We then fill the udp structure and put the checksum
+	 * of the whole packet into the udp checksum.
+	 * Finally we complete the ip structure and ip checksum.
+	 * If we don't do the ordering like so then the udp checksum will be
+	 * broken, so find another way of doing it! */
+
+	memcpy(&udpp->dhcp, data, length);
+
+	ip->ip_p = IPPROTO_UDP;
+	ip->ip_src.s_addr = source.s_addr;
+	if (dest.s_addr == 0)
+		ip->ip_dst.s_addr = INADDR_BROADCAST;
+	else
+		ip->ip_dst.s_addr = dest.s_addr;
+
+	udp->uh_sport = htons(DHCP_CLIENT_PORT);
+	udp->uh_dport = htons(DHCP_SERVER_PORT);
+	udp->uh_ulen = htons((uint16_t)(sizeof(*udp) + length));
+	ip->ip_len = udp->uh_ulen;
+	udp->uh_sum = checksum(udpp, sizeof(*udpp));
+
+	ip->ip_v = IPVERSION;
+	ip->ip_hl = sizeof(*ip) >> 2;
+	ip->ip_id = (uint16_t)arc4random_uniform(UINT16_MAX);
+	ip->ip_ttl = IPDEFTTL;
+	ip->ip_len = htons((uint16_t)(sizeof(*ip) + sizeof(*udp) + length));
+	ip->ip_sum = checksum(ip, sizeof(*ip));
+
+	*sz = sizeof(*ip) + sizeof(*udp) + length;
+	return udpp;
+}
+
+static void
+send_message(struct interface *ifp, uint8_t type,
+    void (*callback)(void *))
+{
+	struct dhcp_state *state = D_STATE(ifp);
+	struct if_options *ifo = ifp->options;
+	struct dhcp_message *dhcp;
+	struct udp_dhcp_packet *udp;
+	size_t len;
+	ssize_t r;
+	struct in_addr from, to;
+	in_addr_t a = INADDR_ANY;
+	struct timespec tv;
+	int s;
+#ifdef IN_IFF_NOTUSEABLE
+	struct ipv4_addr *ia;
+#endif
+
+	if (!callback)
+		logger(ifp->ctx, LOG_INFO, "%s: sending %s with xid 0x%x",
+		    ifp->name,
+		    ifo->options & DHCPCD_BOOTP ? "BOOTP" : get_dhcp_op(type),
+		    state->xid);
+	else {
+		if (state->interval == 0)
+			state->interval = DHCP_BASE;
+		else {
+			state->interval *= 2;
+			if (state->interval > DHCP_MAX)
+				state->interval = DHCP_MAX;
+		}
+		tv.tv_sec = state->interval + DHCP_RAND_MIN;
+		tv.tv_nsec = (suseconds_t)arc4random_uniform(
+		    (DHCP_RAND_MAX - DHCP_RAND_MIN) * NSEC_PER_SEC);
+		timespecnorm(&tv);
+		logger(ifp->ctx, LOG_INFO,
+		    "%s: sending %s (xid 0x%x), next in %0.1f seconds",
+		    ifp->name,
+		    ifo->options & DHCPCD_BOOTP ? "BOOTP" : get_dhcp_op(type),
+		    state->xid,
+		    timespec_to_double(&tv));
+	}
+
+	if (dhcp_open(ifp) == -1)
+		return;
+
+	if (state->added && !(state->added & STATE_FAKE) &&
+	    state->addr.s_addr != INADDR_ANY &&
+	    state->new != NULL &&
+#ifdef IN_IFF_NOTUSEABLE
+	    ((ia = ipv4_iffindaddr(ifp, &state->addr, NULL)) &&
+	    !(ia->addr_flags & IN_IFF_NOTUSEABLE)) &&
+#endif
+	    (state->new->cookie == htonl(MAGIC_COOKIE) ||
+	    ifp->options->options & DHCPCD_INFORM))
+	{
+		s = dhcp_openudp(ifp);
+		if (s == -1 && errno != EADDRINUSE)
+			logger(ifp->ctx, LOG_ERR,
+			    "%s: dhcp_openudp: %m", ifp->name);
+	} else
+		s = -1;
+
+	/* If we couldn't open a UDP port for our IP address
+	 * then we cannot renew.
+	 * This could happen if our IP was pulled out from underneath us.
+	 * Also, we should not unicast from a BOOTP lease. */
+	if (s == -1 ||
+	    (!(ifo->options & DHCPCD_INFORM) &&
+	    IS_BOOTP(ifp, state->new)))
+	{
+		a = state->addr.s_addr;
+		state->addr.s_addr = INADDR_ANY;
+	}
+	r = make_message(&dhcp, ifp, type);
+	if (r == -1)
+		goto fail;
+	len = (size_t)r;
+	if (a)
+		state->addr.s_addr = a;
+	from.s_addr = dhcp->ciaddr;
+	if (from.s_addr)
+		to.s_addr = state->lease.server.s_addr;
+	else
+		to.s_addr = INADDR_ANY;
+	if (to.s_addr && to.s_addr != INADDR_BROADCAST) {
+		struct sockaddr_in sin;
+
+		memset(&sin, 0, sizeof(sin));
+		sin.sin_family = AF_INET;
+		sin.sin_addr.s_addr = to.s_addr;
+		sin.sin_port = htons(DHCP_SERVER_PORT);
+		r = sendto(s, (uint8_t *)dhcp, len, 0,
+		    (struct sockaddr *)&sin, sizeof(sin));
+		if (r == -1)
+			logger(ifp->ctx, LOG_ERR,
+			    "%s: dhcp_sendpacket: %m", ifp->name);
+	} else {
+		size_t ulen;
+
+		r = 0;
+		udp = dhcp_makeudppacket(&ulen, (uint8_t *)dhcp, len, from, to);
+		if (udp == NULL) {
+			logger(ifp->ctx, LOG_ERR, "dhcp_makeudppacket: %m");
+		} else {
+			r = if_sendrawpacket(ifp, ETHERTYPE_IP,
+			    (uint8_t *)udp, ulen, NULL);
+			free(udp);
+		}
+		/* If we failed to send a raw packet this normally means
+		 * we don't have the ability to work beneath the IP layer
+		 * for this interface.
+		 * As such we remove it from consideration without actually
+		 * stopping the interface. */
+		if (r == -1) {
+			logger(ifp->ctx, LOG_ERR,
+			    "%s: if_sendrawpacket: %m", ifp->name);
+			switch(errno) {
+			case ENETDOWN:
+			case ENETRESET:
+			case ENETUNREACH:
+				break;
+			default:
+				if (!(ifp->ctx->options & DHCPCD_TEST))
+					dhcp_drop(ifp, "FAIL");
+				dhcp_free(ifp);
+				eloop_timeout_delete(ifp->ctx->eloop,
+				    NULL, ifp);
+				callback = NULL;
+			}
+		}
+	}
+	free(dhcp);
+
+fail:
+	if (s != -1)
+		close(s);
+
+	/* Even if we fail to send a packet we should continue as we are
+	 * as our failure timeouts will change out codepath when needed. */
+	if (callback)
+		eloop_timeout_add_tv(ifp->ctx->eloop, &tv, callback, ifp);
+}
+
+static void
+send_inform(void *arg)
+{
+
+	send_message((struct interface *)arg, DHCP_INFORM, send_inform);
+}
+
+static void
+send_discover(void *arg)
+{
+
+	send_message((struct interface *)arg, DHCP_DISCOVER, send_discover);
+}
+
+static void
+send_request(void *arg)
+{
+
+	send_message((struct interface *)arg, DHCP_REQUEST, send_request);
+}
+
+static void
+send_renew(void *arg)
+{
+
+	send_message((struct interface *)arg, DHCP_REQUEST, send_renew);
+}
+
+static void
+send_rebind(void *arg)
+{
+
+	send_message((struct interface *)arg, DHCP_REQUEST, send_rebind);
+}
+
+void
+dhcp_discover(void *arg)
+{
+	struct interface *ifp = arg;
+	struct dhcp_state *state = D_STATE(ifp);
+	struct if_options *ifo = ifp->options;
+
+	rpc_signal_status("Discover");
+	state->state = DHS_DISCOVER;
+	state->xid = dhcp_xid(ifp);
+	state->nak_receive_count = 0;
+	state->failed_address_offer_count = 0;
+	eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
+	if (ifo->fallback)
+		eloop_timeout_add_sec(ifp->ctx->eloop,
+		    ifo->reboot, dhcp_fallback, ifp);
+	else if (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->options & DHCPCD_REQUEST)
+		logger(ifp->ctx, LOG_INFO,
+		    "%s: soliciting a DHCP lease (requesting %s)",
+		    ifp->name, inet_ntoa(ifo->req_addr));
+	else
+		logger(ifp->ctx, LOG_INFO,
+		    "%s: soliciting a %s lease",
+		    ifp->name, ifo->options & DHCPCD_BOOTP ? "BOOTP" : "DHCP");
+	send_discover(ifp);
+}
+
+static void
+dhcp_request(void *arg)
+{
+	struct interface *ifp = arg;
+	struct dhcp_state *state = D_STATE(ifp);
+
+	logger(ifp->ctx, LOG_INFO, "%s: requesting lease of %s",
+		ifp->name, inet_ntoa(state->lease.addr));
+
+	rpc_signal_status("Request");
+	state->state = DHS_REQUEST;
+	state->nak_receive_count = 0;
+	send_request(ifp);
+}
+
+static void
+dhcp_expire(void *arg)
+{
+	struct interface *ifp = arg;
+	struct dhcp_state *state = D_STATE(ifp);
+
+	logger(ifp->ctx, LOG_ERR, "%s: DHCP lease expired", ifp->name);
+	eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
+	dhcp_drop(ifp, "EXPIRE");
+	unlink(state->leasefile);
+	state->interval = 0;
+	dhcp_discover(ifp);
+}
+
+static void
+dhcp_decline(struct interface *ifp)
+{
+
+	send_message(ifp, DHCP_DECLINE, NULL);
+}
+
+static void
+dhcp_renew(void *arg)
+{
+	struct interface *ifp = arg;
+	struct dhcp_state *state = D_STATE(ifp);
+	struct dhcp_lease *lease = &state->lease;
+
+	rpc_signal_status("Renew");
+	logger(ifp->ctx, LOG_INFO, "%s: renewing lease of %s",
+	    ifp->name, inet_ntoa(lease->addr));
+	logger(ifp->ctx, LOG_DEBUG, "%s: rebind in %"PRIu32" seconds,"
+	    " expire in %"PRIu32" seconds",
+	    ifp->name, lease->rebindtime - lease->renewaltime,
+	    lease->leasetime - lease->renewaltime);
+	state->state = DHS_RENEW;
+	state->xid = dhcp_xid(ifp);
+	state->nak_receive_count = 0;
+	send_renew(ifp);
+}
+
+#ifndef IN_IFF_TENTATIVE
+static void
+dhcp_arp_announced(struct arp_state *astate)
+{
+
+	arp_close(astate->iface);
+}
+#endif
+
+static void
+dhcp_rebind(void *arg)
+{
+	struct interface *ifp = arg;
+	struct dhcp_state *state = D_STATE(ifp);
+	struct dhcp_lease *lease = &state->lease;
+
+	rpc_signal_status("Rebind");
+	logger(ifp->ctx, LOG_WARNING,
+	    "%s: failed to renew DHCP, rebinding", ifp->name);
+	logger(ifp->ctx, LOG_DEBUG, "%s: expire in %"PRIu32" seconds",
+	    ifp->name, lease->leasetime - lease->rebindtime);
+	state->state = DHS_REBIND;
+	eloop_timeout_delete(ifp->ctx->eloop, send_renew, ifp);
+	state->lease.server.s_addr = 0;
+	state->nak_receive_count = 0;
+	ifp->options->options &= ~(DHCPCD_CSR_WARNED |
+	    DHCPCD_ROUTER_HOST_ROUTE_WARNED);
+	send_rebind(ifp);
+}
+
+static void
+init_option_iterator(const struct dhcp_message *message,
+		     struct dhcp_option_iterator *iterator)
+{
+	iterator->message = message;
+	iterator->ptr = message->options;
+	iterator->end = iterator->ptr + sizeof(message->options);
+	iterator->extra_option_locations = 0;
+	iterator->extra_option_locations_set = 0;
+}
+
+static int
+iterate_next_option(struct dhcp_option_iterator *iterator,
+		    uint8_t *option, uint8_t *length, const uint8_t **value)
+{
+	uint8_t option_code;
+	uint8_t option_len;
+
+	/* Process special DHO_PAD and DHO_END opcodes. */
+	while (iterator->ptr < iterator->end) {
+		if (*iterator->ptr == DHO_PAD) {
+			iterator->ptr++;
+			continue;
+		}
+
+		if (*iterator->ptr != DHO_END)
+			break;
+
+		if (iterator->extra_option_locations &
+		    OPTION_OVERLOADED_BOOT_FILE) {
+			iterator->extra_option_locations &=
+				~OPTION_OVERLOADED_BOOT_FILE;
+			iterator->ptr = iterator->message->bootfile;
+			iterator->end = iterator->ptr +
+				sizeof(iterator->message->bootfile);
+		} else if (iterator->extra_option_locations &
+			   OPTION_OVERLOADED_SERVER_NAME) {
+			iterator->extra_option_locations &=
+				~OPTION_OVERLOADED_SERVER_NAME;
+			iterator->ptr = iterator->message->servername;
+			iterator->end = iterator->ptr +
+				sizeof(iterator->message->servername);
+		} else
+			return 0;
+	}
+
+	if (iterator->ptr + 2 > iterator->end)
+		return 0;
+
+	option_code = *iterator->ptr++;
+	option_len = *iterator->ptr++;
+	if (iterator->ptr + option_len > iterator->end)
+		return 0;
+
+	if (option_code == DHO_OPTIONSOVERLOADED && option_len > 0 &&
+	    !iterator->extra_option_locations_set) {
+		iterator->extra_option_locations = *iterator->ptr;
+		iterator->extra_option_locations_set = 1;
+	}
+
+	if (option)
+		*option = option_code;
+	if (length)
+		*length = option_len;
+	if (value)
+		*value = iterator->ptr;
+
+	iterator->ptr += option_len;
+
+	return 1;
+}
+
+static void
+merge_option_values(const struct dhcp_message *src,
+		    struct dhcp_message *dst, uint8_t *copy_options)
+{
+	uint8_t supplied_options[OPTION_MASK_SIZE];
+	struct dhcp_option_iterator dst_iterator;
+	struct dhcp_option_iterator src_iterator;
+	uint8_t option;
+	const uint8_t *option_value;
+	uint8_t option_length;
+	uint8_t *out;
+	const uint8_t *out_end;
+	int added_options = 0;
+
+	/* Traverse the destination message for options already supplied. */
+	memset(&supplied_options, 0, sizeof(supplied_options));
+	init_option_iterator(dst, &dst_iterator);
+	while (iterate_next_option(&dst_iterator, &option, NULL, NULL)) {
+		add_option_mask(supplied_options, option);
+	}
+
+	/* We will start merging options at the end of the last block
+	 * the iterator traversed to.  The const cast below is safe since
+	 * this points to data within the (non-const) dst message. */
+	out = (uint8_t *) dst_iterator.ptr;
+	out_end = dst_iterator.end;
+
+	init_option_iterator(src, &src_iterator);
+	while (iterate_next_option(&src_iterator, &option, &option_length,
+				   &option_value)) {
+		if (has_option_mask(supplied_options, option) ||
+		    !has_option_mask(copy_options, option))
+			continue;
+		/* We need space for this option, plus a trailing DHO_END. */
+		if (out + option_length + 3 > out_end) {
+			syslog(LOG_ERR,
+			       "%s: unable to fit option %d (length %d)",
+			       __func__, option, option_length);
+			continue;
+		}
+		*out++ = option;
+		*out++ = option_length;
+		memcpy(out, option_value, option_length);
+		out += option_length;
+		added_options++;
+	}
+
+	if (added_options) {
+		*out++ = DHO_END;
+		syslog(LOG_INFO, "carrying over %d options from original offer",
+		added_options);
+	}
+}
+
+void
+dhcp_bind(struct interface *ifp, struct arp_state *astate)
+{
+	struct dhcp_state *state = D_STATE(ifp);
+	struct if_options *ifo = ifp->options;
+	struct dhcp_lease *lease = &state->lease;
+	uint8_t ipv4ll = 0;
+
+	if (state->state == DHS_BOUND)
+		goto applyaddr;
+	state->reason = NULL;
+	free(state->old);
+	state->old = state->new;
+	state->new = state->offer;
+	state->offer = NULL;
+	get_lease(ifp->ctx, lease, state->new);
+	if (ifo->options & DHCPCD_STATIC) {
+		logger(ifp->ctx, LOG_INFO, "%s: using static address %s/%d",
+		    ifp->name, inet_ntoa(lease->addr),
+		    inet_ntocidr(lease->net));
+		lease->leasetime = ~0U;
+		state->reason = "STATIC";
+	} else if (state->new->cookie != htonl(MAGIC_COOKIE)) {
+		logger(ifp->ctx, LOG_INFO, "%s: using IPv4LL address %s",
+		    ifp->name, inet_ntoa(lease->addr));
+		lease->leasetime = ~0U;
+		state->reason = "IPV4LL";
+		ipv4ll = 1;
+	} else if (ifo->options & DHCPCD_INFORM) {
+		if (ifo->req_addr.s_addr != 0)
+			lease->addr.s_addr = ifo->req_addr.s_addr;
+		else
+			lease->addr.s_addr = state->addr.s_addr;
+		logger(ifp->ctx, LOG_INFO, "%s: received approval for %s",
+		    ifp->name, inet_ntoa(lease->addr));
+		lease->leasetime = ~0U;
+		state->reason = "INFORM";
+	} else {
+		if (lease->frominfo)
+			state->reason = "TIMEOUT";
+		if (lease->leasetime == ~0U) {
+			lease->renewaltime =
+			    lease->rebindtime =
+			    lease->leasetime;
+			logger(ifp->ctx, LOG_INFO, "%s: leased %s for infinity",
+			    ifp->name, inet_ntoa(lease->addr));
+		} else {
+			if (lease->leasetime < DHCP_MIN_LEASE) {
+				logger(ifp->ctx, LOG_WARNING,
+				    "%s: minimum lease is %d seconds",
+				    ifp->name, DHCP_MIN_LEASE);
+				lease->leasetime = DHCP_MIN_LEASE;
+			}
+			if (lease->rebindtime == 0)
+				lease->rebindtime =
+				    (uint32_t)(lease->leasetime * T2);
+			else if (lease->rebindtime >= lease->leasetime) {
+				lease->rebindtime =
+				    (uint32_t)(lease->leasetime * T2);
+				logger(ifp->ctx, LOG_WARNING,
+				    "%s: rebind time greater than lease "
+				    "time, forcing to %"PRIu32" seconds",
+				    ifp->name, lease->rebindtime);
+			}
+			if (lease->renewaltime == 0)
+				lease->renewaltime =
+				    (uint32_t)(lease->leasetime * T1);
+			else if (lease->renewaltime > lease->rebindtime) {
+				lease->renewaltime =
+				    (uint32_t)(lease->leasetime * T1);
+				logger(ifp->ctx, LOG_WARNING,
+				    "%s: renewal time greater than rebind "
+				    "time, forcing to %"PRIu32" seconds",
+				    ifp->name, lease->renewaltime);
+			}
+			logger(ifp->ctx,
+			    lease->addr.s_addr == state->addr.s_addr &&
+			    !(state->added & STATE_FAKE) ?
+			    LOG_DEBUG : LOG_INFO,
+			    "%s: leased %s for %"PRIu32" seconds", ifp->name,
+			    inet_ntoa(lease->addr), lease->leasetime);
+		}
+	}
+	if (ifp->ctx->options & DHCPCD_TEST) {
+		state->reason = "TEST";
+		script_runreason(ifp, state->reason);
+		eloop_exit(ifp->ctx->eloop, EXIT_SUCCESS);
+		return;
+	}
+	if (state->reason == NULL) {
+		if (state->old && !(state->added & STATE_FAKE)) {
+			if (state->old->yiaddr == state->new->yiaddr &&
+			    lease->server.s_addr)
+				state->reason = "RENEW";
+			else
+				state->reason = "REBIND";
+		} else if (state->state == DHS_REBOOT)
+			state->reason = "REBOOT";
+		else
+			state->reason = "BOUND";
+	}
+
+	if (state->old && state->old->yiaddr == state->new->yiaddr &&
+	    (state->state == DHS_REBOOT || state->state == DHS_RENEW ||
+	     state->state == DHS_REBIND)) {
+		/* Some DHCP servers respond to REQUEST with a subset
+		 * of the original requested parameters.  If they were not
+		 * supplied in the response to a renewal, we should assume
+		 * that it's reasonable to transfer them forward from the
+		 * original offer. */
+		merge_option_values(state->old, state->new, ifo->requestmask);
+	}
+
+	if (lease->leasetime == ~0U)
+		lease->renewaltime = lease->rebindtime = lease->leasetime;
+	else {
+		eloop_timeout_add_sec(ifp->ctx->eloop,
+		    (time_t)lease->renewaltime, dhcp_renew, ifp);
+		eloop_timeout_add_sec(ifp->ctx->eloop,
+		    (time_t)lease->rebindtime, dhcp_rebind, ifp);
+		eloop_timeout_add_sec(ifp->ctx->eloop,
+		    (time_t)lease->leasetime, dhcp_expire, ifp);
+		logger(ifp->ctx, LOG_DEBUG,
+		    "%s: renew in %"PRIu32" seconds, rebind in %"PRIu32
+		    " seconds",
+		    ifp->name, lease->renewaltime, lease->rebindtime);
+	}
+	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)
+			logger(ifp->ctx, LOG_ERR,
+			    "%s: write_lease: %m", __func__);
+
+applyaddr:
+	ipv4_applyaddr(ifp);
+	if (ifo->options & DHCPCD_ARP &&
+	    !(ifp->ctx->options & DHCPCD_FORKED))
+	{
+#ifdef IN_IFF_TENTATIVE
+		if (astate)
+			arp_free_but(astate);
+		else if (!ipv4ll)
+			arp_close(ifp);
+#else
+		if (state->added) {
+			if (astate == NULL) {
+				astate = arp_new(ifp, &state->addr);
+				astate->announced_cb =
+				    dhcp_arp_announced;
+			}
+			if (astate) {
+				arp_announce(astate);
+				if (!ipv4ll)
+					arp_free_but(astate);
+			}
+		} else if (!ipv4ll)
+			arp_close(ifp);
+#endif
+	}
+}
+
+static void
+dhcp_timeout(void *arg)
+{
+	struct interface *ifp = arg;
+	struct dhcp_state *state = D_STATE(ifp);
+
+	dhcp_bind(ifp, NULL);
+	state->interval = 0;
+	dhcp_discover(ifp);
+}
+
+struct dhcp_message *
+dhcp_message_new(const struct in_addr *addr, const struct in_addr *mask)
+{
+	struct dhcp_message *dhcp;
+	uint8_t *p;
+
+	dhcp = calloc(1, sizeof(*dhcp));
+	if (dhcp == NULL)
+		return NULL;
+	dhcp->yiaddr = addr->s_addr;
+	p = dhcp->options;
+	if (mask && mask->s_addr != INADDR_ANY) {
+		*p++ = DHO_SUBNETMASK;
+		*p++ = sizeof(mask->s_addr);
+		memcpy(p, &mask->s_addr, sizeof(mask->s_addr));
+		p+= sizeof(mask->s_addr);
+	}
+	*p++ = DHO_END;
+	return dhcp;
+}
+
+static void
+dhcp_static(struct interface *ifp)
+{
+	struct if_options *ifo;
+	struct dhcp_state *state;
+
+	state = D_STATE(ifp);
+	ifo = ifp->options;
+	if (ifo->req_addr.s_addr == INADDR_ANY) {
+		logger(ifp->ctx, LOG_INFO,
+		    "%s: waiting for 3rd party to "
+		    "configure IP address",
+		    ifp->name);
+		state->reason = "3RDPARTY";
+		script_runreason(ifp, state->reason);
+		return;
+	}
+	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, NULL);
+	}
+}
+
+void
+dhcp_inform(struct interface *ifp)
+{
+	struct dhcp_state *state;
+	struct if_options *ifo;
+	struct ipv4_addr *ap;
+
+	state = D_STATE(ifp);
+	ifo = ifp->options;
+	logger(ifp->ctx, LOG_INFO, "%s: informing peers of local address",
+	       ifp->name);
+	if (ifp->ctx->options & DHCPCD_TEST) {
+		state->addr.s_addr = ifo->req_addr.s_addr;
+		state->net.s_addr = ifo->req_mask.s_addr;
+	} else {
+		if (ifo->req_addr.s_addr == INADDR_ANY) {
+			state = D_STATE(ifp);
+			ap = ipv4_iffindaddr(ifp, NULL, NULL);
+			if (ap == NULL) {
+				logger(ifp->ctx, LOG_INFO,
+				    "%s: waiting for 3rd party to "
+				    "configure IP address",
+				    ifp->name);
+				state->reason = "3RDPARTY";
+				script_runreason(ifp, state->reason);
+				return;
+			}
+			state->offer =
+			    dhcp_message_new(&ap->addr, &ap->net);
+		} else
+			state->offer =
+			    dhcp_message_new(&ifo->req_addr, &ifo->req_mask);
+		if (state->offer) {
+			ifo->options |= DHCPCD_STATIC;
+			dhcp_bind(ifp, NULL);
+			ifo->options &= ~DHCPCD_STATIC;
+		}
+	}
+
+	rpc_signal_status("Inform");
+	state->state = DHS_INFORM;
+	state->xid = dhcp_xid(ifp);
+	send_inform(ifp);
+}
+
+void
+dhcp_reboot_newopts(struct interface *ifp, unsigned long long oldopts)
+{
+	struct if_options *ifo;
+	struct dhcp_state *state = D_STATE(ifp);
+
+	if (state == NULL)
+		return;
+	ifo = ifp->options;
+	if ((ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC) &&
+		state->addr.s_addr != ifo->req_addr.s_addr) ||
+	    (oldopts & (DHCPCD_INFORM | DHCPCD_STATIC) &&
+		!(ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC))))
+	{
+		dhcp_drop(ifp, "EXPIRE");
+	}
+}
+
+static void start_unicast_arp(struct interface *ifp);
+
+static void
+dhcp_reboot(struct interface *ifp)
+{
+	struct if_options *ifo;
+	struct dhcp_state *state = D_STATE(ifp);
+
+	if (state == NULL)
+		return;
+	rpc_signal_status("Reboot");
+	ifo = ifp->options;
+	state->state = DHS_REBOOT;
+	state->interval = 0;
+
+	if (ifo->options & DHCPCD_LINK && ifp->carrier == LINK_DOWN) {
+		logger(ifp->ctx, LOG_INFO,
+		    "%s: waiting for carrier", ifp->name);
+		return;
+	}
+	if (ifo->options & DHCPCD_STATIC) {
+		dhcp_static(ifp);
+		return;
+	}
+	if (ifo->options & DHCPCD_UNICAST_ARP) {
+		start_unicast_arp(ifp);
+	}
+	if (ifo->options & DHCPCD_INFORM) {
+		logger(ifp->ctx, LOG_INFO, "%s: informing address of %s",
+		    ifp->name, inet_ntoa(state->lease.addr));
+		dhcp_inform(ifp);
+		return;
+	}
+	if (ifo->reboot == 0 || state->offer == NULL) {
+		dhcp_discover(ifp);
+		return;
+	}
+	if (state->offer->cookie == 0)
+		return;
+
+	logger(ifp->ctx, LOG_INFO, "%s: rebinding lease of %s",
+	    ifp->name, inet_ntoa(state->lease.addr));
+	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->options & DHCPCD_IPV4LL &&
+	    !IN_LINKLOCAL(htonl(state->addr.s_addr)))
+		eloop_timeout_add_sec(ifp->ctx->eloop,
+		    ifo->reboot, ipv4ll_start, ifp);
+
+	if (ifo->options & DHCPCD_LASTLEASE && state->lease.frominfo)
+		eloop_timeout_add_sec(ifp->ctx->eloop,
+		    ifo->reboot, dhcp_timeout, ifp);
+	else if (!(ifo->options & DHCPCD_INFORM))
+		eloop_timeout_add_sec(ifp->ctx->eloop,
+		    ifo->reboot, dhcp_expire, ifp);
+
+	/* Don't bother ARP checking as the server could NAK us first.
+	 * Don't call dhcp_request as that would change the state */
+	send_request(ifp);
+}
+
+void
+dhcp_drop(struct interface *ifp, const char *reason)
+{
+	struct dhcp_state *state;
+#ifdef RELEASE_SLOW
+	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. */
+	if (state == NULL) {
+		eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
+		return;
+	}
+	/* Don't reset DHCP state if we have an IPv4LL address and link is up,
+	 * unless the interface is departing. */
+	if (state->state != DHS_IPV4LL_BOUND ||
+	    ifp->carrier != LINK_UP ||
+	    ifp->options->options & DHCPCD_DEPARTED)
+	{
+		eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
+		dhcp_auth_reset(&state->auth);
+		dhcp_close(ifp);
+	}
+
+	if (ifp->options->options & DHCPCD_RELEASE ||
+	    strcmp(reason, "RELEASE") == 0) {
+		unlink(state->leasefile);
+		if (ifp->carrier != LINK_DOWN &&
+		    state->new != NULL &&
+		    state->new->cookie == htonl(MAGIC_COOKIE))
+		{
+			logger(ifp->ctx, LOG_INFO, "%s: releasing lease of %s",
+			    ifp->name, inet_ntoa(state->lease.addr));
+			state->xid = dhcp_xid(ifp);
+			send_message(ifp, DHCP_RELEASE, NULL);
+#ifdef RELEASE_SLOW
+			/* Give the packet a chance to go */
+			ts.tv_sec = RELEASE_DELAY_S;
+			ts.tv_nsec = RELEASE_DELAY_NS;
+			nanosleep(&ts, NULL);
+#endif
+		}
+	}
+
+	free(state->old);
+	state->old = state->new;
+	state->new = NULL;
+	state->reason = reason;
+	ipv4_applyaddr(ifp);
+	free(state->old);
+	state->old = NULL;
+	state->lease.addr.s_addr = 0;
+	ifp->options->options &= ~(DHCPCD_CSR_WARNED |
+	    DHCPCD_ROUTER_HOST_ROUTE_WARNED);
+}
+
+static void
+log_dhcp1(int lvl, const char *msg,
+    const struct interface *ifp, const struct dhcp_message *dhcp,
+    const struct in_addr *from, int ad)
+{
+	const char *tfrom;
+	char *a,  sname[sizeof(dhcp->servername) * 4];
+	struct in_addr addr;
+	int r;
+
+	if (strcmp(msg, "NAK:") == 0) {
+		a = get_option_string(ifp->ctx, dhcp, DHO_MESSAGE);
+		if (a) {
+			char *tmp;
+			size_t al, tmpl;
+
+			al = strlen(a);
+			tmpl = (al * 4) + 1;
+			tmp = malloc(tmpl);
+			if (tmp == NULL) {
+				logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
+				free(a);
+				return;
+			}
+			print_string(tmp, tmpl, STRING, (uint8_t *)a, al);
+			free(a);
+			a = tmp;
+		}
+	} else if (ad && dhcp->yiaddr != 0) {
+		addr.s_addr = dhcp->yiaddr;
+		a = strdup(inet_ntoa(addr));
+		if (a == NULL) {
+			logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
+			return;
+		}
+	} else
+		a = NULL;
+
+	tfrom = "from";
+	r = get_option_addr(ifp->ctx, &addr, dhcp, DHO_SERVERID);
+	if (dhcp->servername[0] && r == 0) {
+		print_string(sname, sizeof(sname), STRING,
+		    dhcp->servername, strlen((const char *)dhcp->servername));
+		if (a == NULL)
+			logger(ifp->ctx, lvl, "%s: %s %s %s `%s'",
+			    ifp->name, msg, tfrom, inet_ntoa(addr), sname);
+		else
+			logger(ifp->ctx, lvl, "%s: %s %s %s %s `%s'",
+			    ifp->name, msg, a, tfrom, inet_ntoa(addr), sname);
+	} else {
+		if (r != 0) {
+			tfrom = "via";
+			addr = *from;
+		}
+		if (a == NULL)
+			logger(ifp->ctx, lvl, "%s: %s %s %s",
+			    ifp->name, msg, tfrom, inet_ntoa(addr));
+		else
+			logger(ifp->ctx, lvl, "%s: %s %s %s %s",
+			    ifp->name, msg, a, tfrom, inet_ntoa(addr));
+	}
+	free(a);
+}
+
+static void
+log_dhcp(int lvl, const char *msg,
+    const struct interface *ifp, const struct dhcp_message *dhcp,
+    const struct in_addr *from)
+{
+
+	log_dhcp1(lvl, msg, ifp, dhcp, from, 1);
+}
+
+static int
+blacklisted_ip(const struct if_options *ifo, in_addr_t addr)
+{
+	size_t i;
+
+	for (i = 0; i < ifo->blacklist_len; i += 2)
+		if (ifo->blacklist[i] == (addr & ifo->blacklist[i + 1]))
+			return 1;
+	return 0;
+}
+
+static int
+whitelisted_ip(const struct if_options *ifo, in_addr_t addr)
+{
+	size_t i;
+
+	if (ifo->whitelist_len == 0)
+		return -1;
+	for (i = 0; i < ifo->whitelist_len; i += 2)
+		if (ifo->whitelist[i] == (addr & ifo->whitelist[i + 1]))
+			return 1;
+	return 0;
+}
+
+static void
+save_gateway_addr(struct interface *ifp, const uint8_t *gw_hwaddr)
+{
+	struct dhcp_state *state = D_STATE(ifp);
+	memcpy(state->server_info.gw_hwaddr, gw_hwaddr, ifp->hwlen);
+	state->server_info.gw_hwlen = ifp->hwlen;
+}
+
+static void
+dhcp_probe_gw_timeout(struct arp_state *astate)
+{
+	struct dhcp_state *state = D_STATE(astate->iface);
+
+	/* Ignore unicast ARP failures. */
+	if (astate->dest_hwlen)
+		return;
+
+	/* Probegw failure, allow ourselves to fail only once this way */
+	logger(astate->iface->ctx, LOG_ERR,
+	       "%s: Probe gateway %s timed out ",
+	       astate->iface->name, inet_ntoa(astate->addr));
+	astate->iface->options->options &= ~DHCPCD_ARPGW;
+
+	unlink(state->leasefile);
+	if (!state->lease.frominfo)
+		dhcp_decline(astate->iface);
+#ifdef IN_IFF_DUPLICATED
+	ia = ipv4_iffindaddr(astate->iface, &astate->addr, NULL);
+	if (ia)
+		ipv4_deladdr(astate->iface, &ia->addr, &ia->net);
+#endif
+	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);
+}
+
+static void
+dhcp_probe_gw_response(struct arp_state *astate, const struct arp_msg *amsg)
+{
+	/* Verify this is a response for the gateway probe. */
+	if (astate->src_addr.s_addr != 0 &&
+	    amsg &&
+	    amsg->tip.s_addr == astate->src_addr.s_addr &&
+	    amsg->sip.s_addr == astate->addr.s_addr) {
+		if (astate->dest_hwlen) {
+			/* Response to unicast ARP. */
+			rpc_notify_unicast_arp(astate->iface);
+		} else {
+			/* Response to arpgw request. */
+			save_gateway_addr(astate->iface, amsg->sha);
+
+			dhcp_close(astate->iface);
+			eloop_timeout_delete(astate->iface->ctx->eloop,
+					     NULL, astate->iface);
+	#ifdef IN_IFF_TENTATIVE
+			ipv4_finaliseaddr(astate->iface);
+	#else
+			dhcp_bind(astate->iface, NULL);
+	#endif
+		}
+		arp_close(astate->iface);
+	}
+}
+
+static int
+dhcp_probe_gw(struct interface *ifp)
+{
+	struct dhcp_state *state = D_STATE(ifp);
+	struct arp_state *astate;
+	struct in_addr gateway_addr;
+
+	if (get_option_addr(ifp->ctx, &gateway_addr,
+			    state->offer, DHO_ROUTER) == 0) {
+		astate = arp_new(ifp, &gateway_addr);
+		if (astate) {
+			astate->src_addr.s_addr = state->offer->yiaddr;
+			astate->probed_cb = dhcp_probe_gw_timeout;
+			astate->conflicted_cb = dhcp_probe_gw_response;
+			arp_probe(astate);
+			return 1;
+		}
+	}
+	return 0;
+}
+
+static void
+start_unicast_arp(struct interface *ifp)
+{
+	struct dhcp_state *state = D_STATE(ifp);
+	struct in_addr gwa;
+	struct in_addr src_addr;
+	struct arp_state *astate;
+
+	if (!state->offer)
+		return;
+
+	if (!state->lease.frominfo)
+		return;
+
+	if (state->server_info.gw_hwlen != ifp->hwlen)
+		return;
+
+	if (get_option_addr(ifp->ctx, &gwa, state->offer, DHO_ROUTER))
+		return;
+
+	astate = arp_new(ifp, &gwa);
+	if (!astate)
+		return;
+	if (state->offer->yiaddr)
+		astate->src_addr.s_addr = state->offer->yiaddr;
+	else
+		astate->src_addr.s_addr = state->offer->ciaddr;
+	astate->probed_cb = dhcp_probe_gw_timeout;
+	astate->conflicted_cb = dhcp_probe_gw_response;
+	astate->dest_hwlen = state->server_info.gw_hwlen;
+	memcpy(astate->dest_hwaddr, state->server_info.gw_hwaddr,
+	       state->server_info.gw_hwlen);
+
+	arp_probe(astate);
+
+	/* Invalidate our gateway address until the next successful PROBEGW. */
+	state->server_info.gw_hwlen = 0;
+}
+
+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;
+	}
+
+	/* Probe the gateway specified in the lease offer. */
+	if ((ifo->options & DHCPCD_ARPGW) && (dhcp_probe_gw(astate->iface))) {
+		return;
+	}
+
+	dhcp_close(astate->iface);
+	eloop_timeout_delete(astate->iface->ctx->eloop, NULL, astate->iface);
+#ifdef IN_IFF_TENTATIVE
+	ipv4_finaliseaddr(astate->iface);
+	arp_close(astate->iface);
+#else
+	dhcp_bind(astate->iface, astate);
+#endif
+}
+
+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 &&
+	    (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);
+	}
+
+	/* RFC 2131 3.1.5, Client-server interaction
+	 * NULL amsg means IN_IFF_DUPLICATED */
+	if (amsg == NULL || (state->offer &&
+	    (amsg->sip.s_addr == state->offer->yiaddr ||
+	    (amsg->sip.s_addr == 0 &&
+	    amsg->tip.s_addr == state->offer->yiaddr))))
+	{
+#ifdef IN_IFF_DUPLICATED
+		struct ipv4_addr *ia;
+#endif
+
+		if (amsg) {
+			astate->failed.s_addr = state->offer->yiaddr;
+			state->failed.s_addr = state->offer->yiaddr;
+		} else {
+			astate->failed = astate->addr;
+			state->failed = astate->addr;
+		}
+
+		arp_report_conflicted(astate, amsg);
+		unlink(state->leasefile);
+		if (!state->lease.frominfo)
+			dhcp_decline(astate->iface);
+#ifdef IN_IFF_DUPLICATED
+		ia = ipv4_iffindaddr(astate->iface, &astate->addr, NULL);
+		if (ia)
+			ipv4_deladdr(astate->iface, &ia->addr, &ia->net);
+#endif
+		arp_close(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);
+	}
+}
+
+static void
+handle_nak(void *arg)
+{
+	struct interface *ifp = arg;
+	struct dhcp_state *state = D_STATE(ifp);
+
+	logger(ifp->ctx, LOG_INFO, "%s: Handling deferred NAK", ifp->name);
+	if (!(ifp->ctx->options & DHCPCD_TEST)) {
+		dhcp_drop(ifp, "NAK");
+		unlink(state->leasefile);
+	}
+
+	/* If we constantly get NAKS then we should slowly back off */
+	eloop_timeout_add_sec(ifp->ctx->eloop,
+	    state->nakoff, dhcp_discover, ifp);
+	if (state->nakoff == 0)
+		state->nakoff = 1;
+	else {
+		state->nakoff *= 2;
+		if (state->nakoff > NAKOFF_MAX)
+			state->nakoff = NAKOFF_MAX;
+	}
+}
+
+static void
+dhcp_handledhcp(struct interface *ifp, struct dhcp_message **dhcpp,
+    const struct in_addr *from)
+{
+	struct dhcp_state *state = D_STATE(ifp);
+	struct if_options *ifo = ifp->options;
+	struct dhcp_message *dhcp = *dhcpp;
+	struct dhcp_lease *lease = &state->lease;
+	uint8_t type, tmp;
+	const uint8_t *auth;
+	struct in_addr addr;
+	unsigned int i;
+	size_t auth_len;
+	char *msg;
+	struct arp_state *astate;
+	struct ipv4_addr *ia;
+
+	/* We may have found a BOOTP server */
+	if (get_option_uint8(ifp->ctx, &type, dhcp, DHO_MESSAGETYPE) == -1)
+		type = 0;
+	else if (ifo->options & DHCPCD_BOOTP) {
+		logger(ifp->ctx, LOG_DEBUG,
+		    "%s: ignoring DHCP reply (excpecting BOOTP)",
+		    ifp->name);
+		return;
+	}
+
+	logger(ifp->ctx, LOG_INFO, "%s: received %s with xid 0x%x",
+		ifp->name, get_dhcp_op(type), state->xid);
+
+	/* Authenticate the message */
+	auth = get_option(ifp->ctx, dhcp, DHO_AUTHENTICATION, &auth_len);
+	if (auth) {
+		if (dhcp_auth_validate(&state->auth, &ifo->auth,
+		    (uint8_t *)*dhcpp, sizeof(**dhcpp), 4, type,
+		    auth, auth_len) == NULL)
+		{
+			logger(ifp->ctx, LOG_DEBUG,
+			    "%s: dhcp_auth_validate: %m", ifp->name);
+			log_dhcp1(LOG_ERR, "authentication failed",
+			    ifp, dhcp, from, 0);
+			return;
+		}
+		if (state->auth.token)
+			logger(ifp->ctx, LOG_DEBUG,
+			    "%s: validated using 0x%08" PRIu32,
+			    ifp->name, state->auth.token->secretid);
+		else
+			logger(ifp->ctx, LOG_DEBUG,
+			    "%s: accepted reconfigure key", ifp->name);
+	} else if (ifo->auth.options & DHCPCD_AUTH_REQUIRE) {
+		log_dhcp1(LOG_ERR, "no authentication", ifp, dhcp, from, 0);
+		return;
+	} else if (ifo->auth.options & DHCPCD_AUTH_SEND)
+		log_dhcp1(LOG_WARNING, "no authentication",
+		    ifp, dhcp, from, 0);
+
+	/* RFC 3203 */
+	if (type == DHCP_FORCERENEW) {
+		if (from->s_addr == INADDR_ANY ||
+		    from->s_addr == INADDR_BROADCAST)
+		{
+			log_dhcp(LOG_ERR, "discarding Force Renew",
+			    ifp, dhcp, from);
+			return;
+		}
+		if (auth == NULL) {
+			log_dhcp(LOG_ERR, "unauthenticated Force Renew",
+			    ifp, dhcp, from);
+			return;
+		}
+		if (state->state != DHS_BOUND && state->state != DHS_INFORM) {
+			log_dhcp(LOG_DEBUG, "not bound, ignoring Force Renew",
+			    ifp, dhcp, from);
+			return;
+		}
+		log_dhcp(LOG_ERR, "Force Renew from", ifp, dhcp, from);
+		/* The rebind and expire timings are still the same, we just
+		 * enter the renew state early */
+		if (state->state == DHS_BOUND) {
+			eloop_timeout_delete(ifp->ctx->eloop,
+			    dhcp_renew, ifp);
+			dhcp_renew(ifp);
+		} else {
+			eloop_timeout_delete(ifp->ctx->eloop,
+			    send_inform, ifp);
+			dhcp_inform(ifp);
+		}
+		return;
+	}
+
+	if (state->state == DHS_BOUND) {
+		/* Before we supported FORCERENEW we closed off the raw
+		 * port so we effectively ignored all messages.
+		 * As such we'll not log by default here. */
+		//log_dhcp(LOG_DEBUG, "bound, ignoring", iface, dhcp, from);
+		return;
+	}
+
+	/* Ensure it's the right transaction */
+	if (state->xid != ntohl(dhcp->xid)) {
+		logger(ifp->ctx, LOG_DEBUG,
+		    "%s: wrong xid 0x%x (expecting 0x%x) from %s",
+		    ifp->name, ntohl(dhcp->xid), state->xid,
+		    inet_ntoa(*from));
+		return;
+	}
+	/* reset the message counter */
+	state->interval = 0;
+
+	/* Ensure that no reject options are present */
+	for (i = 1; i < 255; i++) {
+		if (has_option_mask(ifo->rejectmask, i) &&
+		    get_option_uint8(ifp->ctx, &tmp, dhcp, (uint8_t)i) == 0)
+		{
+			log_dhcp(LOG_WARNING, "reject DHCP", ifp, dhcp, from);
+			return;
+		}
+	}
+
+	if (type == DHCP_NAK) {
+		if ((msg = get_option_string(ifp->ctx, dhcp, DHO_MESSAGE))) {
+			logger(ifp->ctx, LOG_WARNING, "%s: message: %s",
+			    ifp->name, msg);
+			free(msg);
+		}
+		if (state->state == DHS_INFORM) /* INFORM should not be NAKed */
+			return;
+
+		log_dhcp(LOG_WARNING, "NAK (deferred):", ifp, dhcp, from);
+		rpc_signal_status("NakDefer");
+		if (state->nak_receive_count == 0)
+			eloop_timeout_add_sec(ifp->ctx->eloop,
+					      DHCP_BASE, handle_nak, ifp);
+		state->nak_receive_count++;
+		return;
+	}
+
+	/* Ensure that all required options are present */
+	for (i = 1; i < 255; i++) {
+		if (has_option_mask(ifo->requiremask, i) &&
+		    get_option_uint8(ifp->ctx, &tmp, dhcp, (uint8_t)i) != 0)
+		{
+			/* If we are BOOTP, then ignore the need for serverid.
+			 * To ignore BOOTP, require dhcp_message_type.
+			 * However, nothing really stops BOOTP from providing
+			 * DHCP style options as well so the above isn't
+			 * always true. */
+			if (type == 0 && i == DHO_SERVERID)
+				continue;
+			log_dhcp(LOG_WARNING, "reject DHCP", ifp, dhcp, from);
+			return;
+		}
+	}
+
+	/* DHCP Auto-Configure, RFC 2563 */
+	if (type == DHCP_OFFER && dhcp->yiaddr == 0) {
+		log_dhcp(LOG_WARNING, "no address given", ifp, dhcp, from);
+		if ((msg = get_option_string(ifp->ctx, dhcp, DHO_MESSAGE))) {
+			logger(ifp->ctx, LOG_WARNING,
+			    "%s: message: %s", ifp->name, msg);
+			free(msg);
+		}
+		if ((state->state == DHS_DISCOVER ||
+		    state->state == DHS_IPV4LL_BOUND) &&
+		    get_option_uint8(ifp->ctx, &tmp, dhcp,
+		    DHO_AUTOCONFIGURE) == 0)
+		{
+			switch (tmp) {
+			case 0:
+				log_dhcp(LOG_WARNING, "IPv4LL disabled from",
+				    ifp, dhcp, from);
+				dhcp_drop(ifp, "EXPIRE");
+				arp_close(ifp);
+				eloop_timeout_delete(ifp->ctx->eloop,
+				    NULL, ifp);
+				eloop_timeout_add_sec(ifp->ctx->eloop,
+				    DHCP_MAX, dhcp_discover,
+				    ifp);
+				break;
+			case 1:
+				log_dhcp(LOG_WARNING, "IPv4LL enabled from",
+				    ifp, dhcp, from);
+				eloop_timeout_delete(ifp->ctx->eloop,
+				    NULL, ifp);
+				if (IN_LINKLOCAL(htonl(state->addr.s_addr)))
+					eloop_timeout_add_sec(ifp->ctx->eloop,
+					    DHCP_MAX, dhcp_discover, ifp);
+				else
+					ipv4ll_start(ifp);
+				break;
+			default:
+				logger(ifp->ctx, LOG_ERR,
+				    "%s: unknown auto configuration option %d",
+				    ifp->name, tmp);
+				break;
+			}
+		}
+		return;
+	}
+
+	/* Ensure that the address offered is valid */
+	if ((type == 0 || type == DHCP_OFFER || type == DHCP_ACK) &&
+	    (dhcp->ciaddr == INADDR_ANY || dhcp->ciaddr == INADDR_BROADCAST) &&
+	    (dhcp->yiaddr == INADDR_ANY || dhcp->yiaddr == INADDR_BROADCAST))
+	{
+		rpc_signal_status("IgnoreInvalidOffer");
+		log_dhcp(LOG_WARNING, "reject invalid address",
+		    ifp, dhcp, from);
+		return;
+	}
+
+#ifdef IN_IFF_DUPLICATED
+	ia = ipv4_iffindaddr(ifp, &lease->addr, NULL);
+	if (ia && ia->addr_flags & IN_IFF_DUPLICATED) {
+		log_dhcp(LOG_WARNING, "declined duplicate address",
+		    ifp, dhcp, from);
+		if (type)
+			dhcp_decline(ifp);
+		ipv4_deladdr(ifp, &ia->addr, &ia->net);
+		eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
+		eloop_timeout_add_sec(ifp->ctx->eloop,
+		    DHCP_RAND_MAX, dhcp_discover, ifp);
+		return;
+	}
+#endif
+
+	if ((type == 0 || type == DHCP_OFFER) &&
+	    (state->state == DHS_DISCOVER || state->state == DHS_IPV4LL_BOUND))
+	{
+		if (dhcp->yiaddr == state->failed.s_addr &&
+		    state->failed_address_offer_count == 0) {
+			log_dhcp(LOG_WARNING,
+				 "reject previously declined address",
+				 ifp, dhcp, from);
+			rpc_signal_status("IgnoreFailedOffer");
+			state->failed_address_offer_count++;
+			return;
+		}
+		lease->frominfo = 0;
+		lease->addr.s_addr = dhcp->yiaddr;
+		lease->cookie = dhcp->cookie;
+		if (type == 0 ||
+		    get_option_addr(ifp->ctx,
+		    &lease->server, dhcp, DHO_SERVERID) != 0)
+			lease->server.s_addr = INADDR_ANY;
+		log_dhcp(LOG_INFO, "offered", ifp, dhcp, from);
+		free(state->offer);
+		state->offer = dhcp;
+		*dhcpp = NULL;
+		if (ifp->ctx->options & DHCPCD_TEST) {
+			free(state->old);
+			state->old = state->new;
+			state->new = state->offer;
+			state->offer = NULL;
+			state->reason = "TEST";
+			script_runreason(ifp, state->reason);
+			eloop_exit(ifp->ctx->eloop, EXIT_SUCCESS);
+			return;
+		}
+		eloop_timeout_delete(ifp->ctx->eloop, send_discover, ifp);
+		eloop_timeout_delete(ifp->ctx->eloop, handle_nak, ifp);
+		/* We don't request BOOTP addresses */
+		if (type) {
+			/* We used to ARP check here, but that seems to be in
+			 * violation of RFC2131 where it only describes
+			 * DECLINE after REQUEST.
+			 * It also seems that some MS DHCP servers actually
+			 * ignore DECLINE if no REQUEST, ie we decline a
+			 * DISCOVER. */
+			dhcp_request(ifp);
+			return;
+		}
+	}
+
+	if (type) {
+		if (type == DHCP_OFFER) {
+			log_dhcp(LOG_WARNING, "ignoring offer of",
+			    ifp, dhcp, from);
+			rpc_signal_status("IgnoreAdditionalOffer");
+			return;
+		}
+
+		/* We should only be dealing with acks */
+		if (type != DHCP_ACK) {
+			log_dhcp(LOG_ERR, "not ACK or OFFER",
+			    ifp, dhcp, from);
+			rpc_signal_status("IgnoreNonOffer");
+			return;
+		}
+
+		if (!(ifo->options & DHCPCD_INFORM))
+			log_dhcp(LOG_INFO, "acknowledged", ifp, dhcp, from);
+		else
+		    ifo->options &= ~DHCPCD_STATIC;
+	}
+
+
+	/* No NAK, so reset the backoff
+	 * We don't reset on an OFFER message because the server could
+	 * potentially NAK the REQUEST. */
+	state->nakoff = 0;
+
+	/* BOOTP could have already assigned this above, so check we still
+	 * have a pointer. */
+	if (*dhcpp) {
+		free(state->offer);
+		state->offer = dhcp;
+		*dhcpp = NULL;
+	}
+
+	lease->frominfo = 0;
+	eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
+	astate = NULL;
+
+#ifdef IN_IFF_TENTATIVE
+	addr.s_addr = state->offer->yiaddr;
+	astate = arp_new(ifp, &addr);
+	if (astate) {
+		astate->probed_cb = dhcp_arp_probed;
+		astate->conflicted_cb = dhcp_arp_conflicted;
+		/* No need to start the probe as we'll
+		 * listen to the kernel stating DAD or not and
+		 * that action look look for our ARP state  for
+		 * what to do. */
+	}
+#else
+	if ((ifo->options & DHCPCD_ARP || state->nak_receive_count > 0 ||
+	     dhcp->yiaddr == state->failed.s_addr)
+	    && state->addr.s_addr != state->offer->yiaddr)
+	{
+		addr.s_addr = state->offer->yiaddr;
+		/* If the interface already has the address configured
+		 * then we can't ARP for duplicate detection. */
+		ia = ipv4_findaddr(ifp->ctx, &addr);
+		if (ia == NULL) {
+			astate = arp_new(ifp, &addr);
+			if (astate) {
+				astate->probed_cb = dhcp_arp_probed;
+				astate->conflicted_cb = dhcp_arp_conflicted;
+				arp_probe(astate);
+				rpc_signal_status("ArpSelf");
+			}
+			return;
+		}
+	}
+#endif
+
+	if ((ifo->options & DHCPCD_ARPGW) && (dhcp_probe_gw(ifp))) {
+		rpc_signal_status("ArpGateway");
+		return;
+	}
+
+	dhcp_bind(ifp, astate);
+}
+
+static size_t
+get_udp_data(const uint8_t **data, const uint8_t *udp)
+{
+	struct udp_dhcp_packet p;
+
+	memcpy(&p, udp, sizeof(p));
+	*data = udp + offsetof(struct udp_dhcp_packet, dhcp);
+	return ntohs(p.ip.ip_len) - sizeof(p.ip) - sizeof(p.udp);
+}
+
+static int
+valid_udp_packet(const uint8_t *data, size_t data_len, struct in_addr *from,
+    int noudpcsum)
+{
+	struct udp_dhcp_packet p;
+	uint16_t bytes, udpsum;
+
+	if (data_len < sizeof(p.ip)) {
+		syslog(LOG_WARNING, "packet short than an ip header "
+			"(len=%zd)", data_len);
+		if (from)
+			from->s_addr = INADDR_ANY;
+		errno = EINVAL;
+		return -1;
+	}
+	memcpy(&p, data, MIN(data_len, sizeof(p)));
+	if (from)
+		from->s_addr = p.ip.ip_src.s_addr;
+	if (data_len > sizeof(p)) {
+		syslog(LOG_WARNING, "packet too long (%zd bytes)", data_len);
+		errno = EINVAL;
+		return -1;
+	}
+	if (checksum(&p.ip, sizeof(p.ip)) != 0) {
+		syslog(LOG_WARNING, "packet failed ip header checksum");
+		errno = EINVAL;
+		return -1;
+	}
+
+	bytes = ntohs(p.ip.ip_len);
+	if (data_len < bytes) {
+		syslog(LOG_WARNING, "packet appears truncated "
+			"(len=%zd, ip_len=%zd)", data_len, bytes);
+		errno = EINVAL;
+		return -1;
+	}
+
+	if (noudpcsum == 0) {
+		udpsum = p.udp.uh_sum;
+		p.udp.uh_sum = 0;
+		p.ip.ip_hl = 0;
+		p.ip.ip_v = 0;
+		p.ip.ip_tos = 0;
+		p.ip.ip_len = p.udp.uh_ulen;
+		p.ip.ip_id = 0;
+		p.ip.ip_off = 0;
+		p.ip.ip_ttl = 0;
+		p.ip.ip_sum = 0;
+		if (udpsum && checksum(&p, bytes) != udpsum) {
+			syslog(LOG_WARNING, "packet failed udp checksum");
+			errno = EINVAL;
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+static void
+dhcp_handlepacket(void *arg)
+{
+	struct interface *ifp = arg;
+	struct dhcp_message *dhcp = NULL;
+	const uint8_t *pp;
+	size_t bytes;
+	struct in_addr from;
+	int i, flags;
+	const struct dhcp_state *state = D_CSTATE(ifp);
+
+	/* Need this API due to BPF */
+	flags = 0;
+	while (!(flags & RAW_EOF)) {
+		bytes = (size_t)if_readrawpacket(ifp, ETHERTYPE_IP,
+		    ifp->ctx->packet, udp_dhcp_len, &flags);
+		if ((ssize_t)bytes == -1) {
+			logger(ifp->ctx, LOG_ERR,
+			    "%s: dhcp if_readrawpacket: %m", ifp->name);
+			dhcp_close(ifp);
+			arp_close(ifp);
+			break;
+		}
+		if (valid_udp_packet(ifp->ctx->packet, bytes,
+		    &from, flags & RAW_PARTIALCSUM) == -1)
+		{
+			logger(ifp->ctx, LOG_ERR,
+			    "%s: invalid UDP packet from %s",
+			    ifp->name, inet_ntoa(from));
+			continue;
+		}
+		i = whitelisted_ip(ifp->options, from.s_addr);
+		if (i == 0) {
+			logger(ifp->ctx, LOG_WARNING,
+			    "%s: non whitelisted DHCP packet from %s",
+			    ifp->name, inet_ntoa(from));
+			continue;
+		} else if (i != 1 &&
+		    blacklisted_ip(ifp->options, from.s_addr) == 1)
+		{
+			logger(ifp->ctx, LOG_WARNING,
+			    "%s: blacklisted DHCP packet from %s",
+			    ifp->name, inet_ntoa(from));
+			continue;
+		}
+		if (ifp->flags & IFF_POINTOPOINT &&
+		    state->dst.s_addr != from.s_addr)
+		{
+			logger(ifp->ctx, LOG_WARNING,
+			    "%s: server %s is not destination",
+			    ifp->name, inet_ntoa(from));
+		}
+		bytes = get_udp_data(&pp, ifp->ctx->packet);
+		if (bytes > sizeof(*dhcp)) {
+			logger(ifp->ctx, LOG_ERR,
+			    "%s: packet greater than DHCP size from %s",
+			    ifp->name, inet_ntoa(from));
+			continue;
+		}
+		if (dhcp == NULL) {
+		        dhcp = calloc(1, sizeof(*dhcp));
+			if (dhcp == NULL) {
+				logger(ifp->ctx, LOG_ERR,
+				    "%s: calloc: %m", __func__);
+				break;
+			}
+		}
+		memcpy(dhcp, pp, bytes);
+		if (dhcp->cookie != htonl(MAGIC_COOKIE)) {
+			logger(ifp->ctx, LOG_DEBUG, "%s: bogus cookie from %s",
+			    ifp->name, inet_ntoa(from));
+			continue;
+		}
+		/* Ensure packet is for us */
+		if (ifp->hwlen <= sizeof(dhcp->chaddr) &&
+		    memcmp(dhcp->chaddr, ifp->hwaddr, ifp->hwlen))
+		{
+			char buf[sizeof(dhcp->chaddr) * 3];
+
+			logger(ifp->ctx, LOG_DEBUG,
+			    "%s: xid 0x%x is for hwaddr %s",
+			    ifp->name, ntohl(dhcp->xid),
+			    hwaddr_ntoa(dhcp->chaddr, sizeof(dhcp->chaddr),
+				buf, sizeof(buf)));
+			continue;
+		}
+		dhcp_handledhcp(ifp, &dhcp, &from);
+		if (state->raw_fd == -1)
+			break;
+	}
+	free(dhcp);
+}
+
+static void
+dhcp_handleudp(void *arg)
+{
+	struct dhcpcd_ctx *ctx;
+	uint8_t buffer[sizeof(struct dhcp_message)];
+
+	ctx = arg;
+
+	/* Just read what's in the UDP fd and discard it as we always read
+	 * from the raw fd */
+	if (read(ctx->udp_fd, buffer, sizeof(buffer)) == -1) {
+		logger(ctx, LOG_ERR, "%s: %m", __func__);
+		eloop_event_delete(ctx->eloop, ctx->udp_fd, 0);
+		close(ctx->udp_fd);
+		ctx->udp_fd = -1;
+	}
+}
+
+static int
+dhcp_open(struct interface *ifp)
+{
+	struct dhcp_state *state;
+
+	if (ifp->ctx->packet == NULL) {
+		ifp->ctx->packet = malloc(udp_dhcp_len);
+		if (ifp->ctx->packet == NULL) {
+			logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
+			return -1;
+		}
+	}
+
+	state = D_STATE(ifp);
+	if (state->raw_fd == -1) {
+		state->raw_fd = if_openrawsocket(ifp, ETHERTYPE_IP);
+		if (state->raw_fd == -1) {
+			if (errno == ENOENT) {
+				logger(ifp->ctx, LOG_ERR,
+				    "%s not found", if_pfname);
+				/* May as well disable IPv4 entirely at
+				 * this point as we really need it. */
+				ifp->options->options &= ~DHCPCD_IPV4;
+			} else
+				logger(ifp->ctx, LOG_ERR, "%s: %s: %m",
+				    __func__, ifp->name);
+			return -1;
+		}
+		eloop_event_add(ifp->ctx->eloop,
+		    state->raw_fd, dhcp_handlepacket, ifp, NULL, NULL);
+	}
+	return 0;
+}
+
+int
+dhcp_dump(struct interface *ifp)
+{
+	struct dhcp_state *state;
+
+	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);
+	dhcp_set_leasefile(state->leasefile, sizeof(state->leasefile),
+	    AF_INET, ifp, "");
+	state->new = read_lease(ifp);
+	if (state->new == NULL) {
+		logger(ifp->ctx, LOG_ERR, "%s: %s: %m",
+		    *ifp->name ? ifp->name : state->leasefile, __func__);
+		return -1;
+	}
+	state->reason = "DUMP";
+	return script_runreason(ifp, state->reason);
+
+eexit:
+	logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
+	return -1;
+}
+
+void
+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);
+		free(state->offer);
+		free(state->buffer);
+		free(state->clientid);
+		free(state);
+		ifp->if_data[IF_DATA_DHCP] = NULL;
+	}
+
+	ctx = ifp->ctx;
+	/* If we don't have any more DHCP enabled interfaces,
+	 * close the global socket and release resources */
+	if (ctx->ifaces) {
+		TAILQ_FOREACH(ifp, ctx->ifaces, next) {
+			if (D_STATE(ifp))
+				break;
+		}
+	}
+	if (ifp == NULL) {
+		if (ctx->udp_fd != -1) {
+			eloop_event_delete(ctx->eloop, ctx->udp_fd, 0);
+			close(ctx->udp_fd);
+			ctx->udp_fd = -1;
+		}
+
+		free(ctx->packet);
+		free(ctx->opt_buffer);
+		ctx->packet = NULL;
+		ctx->opt_buffer = NULL;
+	}
+}
+
+static int
+dhcp_init(struct interface *ifp)
+{
+	struct dhcp_state *state;
+	const struct if_options *ifo;
+	uint8_t len;
+	char buf[(sizeof(ifo->clientid) - 1) * 3];
+
+	state = D_STATE(ifp);
+	if (state == NULL) {
+		ifp->if_data[IF_DATA_DHCP] = calloc(1, sizeof(*state));
+		state = D_STATE(ifp);
+		if (state == NULL)
+			return -1;
+		/* 0 is a valid fd, so init to -1 */
+		state->raw_fd = state->arp_fd = -1;
+		TAILQ_INIT(&state->arp_states);
+
+		/* Now is a good time to find IPv4 routes */
+		if_initrt(ifp);
+	}
+
+	state->state = DHS_INIT;
+	state->reason = "PREINIT";
+	state->nakoff = 0;
+	dhcp_set_leasefile(state->leasefile, sizeof(state->leasefile),
+	    AF_INET, ifp, "");
+
+	ifo = ifp->options;
+	/* We need to drop the leasefile so that dhcp_start
+	 * doesn't load it. */
+	if (ifo->options & DHCPCD_REQUEST)
+		unlink(state->leasefile);
+
+	free(state->clientid);
+	state->clientid = NULL;
+
+	if (*ifo->clientid) {
+		state->clientid = malloc((size_t)(ifo->clientid[0] + 1));
+		if (state->clientid == NULL)
+			goto eexit;
+		memcpy(state->clientid, ifo->clientid,
+		    (size_t)(ifo->clientid[0]) + 1);
+	} else if (ifo->options & DHCPCD_CLIENTID) {
+		if (ifo->options & DHCPCD_DUID) {
+			state->clientid = malloc(ifp->ctx->duid_len + 6);
+			if (state->clientid == NULL)
+				goto eexit;
+			state->clientid[0] =(uint8_t)(ifp->ctx->duid_len + 5);
+			state->clientid[1] = 255; /* RFC 4361 */
+			memcpy(state->clientid + 2, ifo->iaid, 4);
+			memcpy(state->clientid + 6, ifp->ctx->duid,
+			    ifp->ctx->duid_len);
+		} else {
+			len = (uint8_t)(ifp->hwlen + 1);
+			state->clientid = malloc((size_t)len + 1);
+			if (state->clientid == NULL)
+				goto eexit;
+			state->clientid[0] = len;
+			state->clientid[1] = (uint8_t)ifp->family;
+			memcpy(state->clientid + 2, ifp->hwaddr,
+			    ifp->hwlen);
+		}
+	}
+
+	if (ifo->options & DHCPCD_DUID)
+		/* Don't bother logging as DUID and IAID are reported
+		 * at device start. */
+		return 0;
+
+	if (ifo->options & DHCPCD_CLIENTID)
+		logger(ifp->ctx, LOG_DEBUG, "%s: using ClientID %s", ifp->name,
+		    hwaddr_ntoa(state->clientid + 1, state->clientid[0],
+			buf, sizeof(buf)));
+	else if (ifp->hwlen)
+		logger(ifp->ctx, LOG_DEBUG, "%s: using hwaddr %s", ifp->name,
+		    hwaddr_ntoa(ifp->hwaddr, ifp->hwlen, buf, sizeof(buf)));
+	return 0;
+
+eexit:
+	logger(ifp->ctx, LOG_ERR, "%s: error making ClientID: %m", __func__);
+	return -1;
+}
+
+static void
+dhcp_start1(void *arg)
+{
+	struct interface *ifp = arg;
+	struct if_options *ifo = ifp->options;
+	struct dhcp_state *state;
+	struct stat st;
+	uint32_t l;
+	int nolease;
+
+	if (!(ifo->options & DHCPCD_IPV4))
+		return;
+
+	/* Listen on *.*.*.*:bootpc so that the kernel never sends an
+	 * ICMP port unreachable message back to the DHCP server */
+	if (ifp->ctx->udp_fd == -1) {
+		ifp->ctx->udp_fd = dhcp_openudp(NULL);
+		if (ifp->ctx->udp_fd == -1) {
+			/* Don't log an error if some other process
+			 * is handling this. */
+			if (errno != EADDRINUSE)
+				logger(ifp->ctx, LOG_ERR,
+				    "%s: dhcp_openudp: %m", __func__);
+		} else
+			eloop_event_add(ifp->ctx->eloop,
+			    ifp->ctx->udp_fd, dhcp_handleudp,
+			    ifp->ctx, NULL, NULL);
+	}
+
+	if (dhcp_init(ifp) == -1) {
+		logger(ifp->ctx, LOG_ERR, "%s: dhcp_init: %m", ifp->name);
+		return;
+	}
+
+	state = D_STATE(ifp);
+	state->start_uptime = uptime();
+	free(state->offer);
+	state->offer = NULL;
+
+	if (state->arping_index < ifo->arping_len) {
+		struct arp_state *astate;
+
+		astate = arp_new(ifp, NULL);
+		if (astate) {
+			astate->probed_cb = dhcp_arp_probed;
+			astate->conflicted_cb = dhcp_arp_conflicted;
+			dhcp_arp_probed(astate);
+		}
+		return;
+	}
+
+	if (ifo->options & DHCPCD_STATIC) {
+		dhcp_static(ifp);
+		return;
+	}
+
+	if (ifo->options & DHCPCD_DHCP && dhcp_open(ifp) == -1)
+		return;
+
+	if (ifo->options & DHCPCD_INFORM) {
+		dhcp_inform(ifp);
+		return;
+	}
+	if (ifp->hwlen == 0 && ifo->clientid[0] == '\0') {
+		logger(ifp->ctx, LOG_WARNING,
+		    "%s: needs a clientid to configure", ifp->name);
+		dhcp_drop(ifp, "FAIL");
+		eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
+		return;
+	}
+	/* We don't want to read the old lease if we NAK an old test */
+	nolease = state->offer && ifp->ctx->options & DHCPCD_TEST;
+	if (!nolease) {
+		state->offer = read_lease(ifp);
+		/* Check the saved lease matches the type we want */
+		if (state->offer) {
+#ifdef IN_IFF_DUPLICATED
+			struct in_addr addr;
+			struct ipv4_addr *ia;
+
+			addr.s_addr = state->offer->yiaddr;
+			ia = ipv4_iffindaddr(ifp, &addr, NULL);
+#endif
+
+			if ((IS_BOOTP(ifp, state->offer) &&
+			    !(ifo->options & DHCPCD_BOOTP)) ||
+#ifdef IN_IFF_DUPLICATED
+			    (ia && ia->addr_flags & IN_IFF_DUPLICATED) ||
+#endif
+			    (!IS_BOOTP(ifp, state->offer) &&
+			    ifo->options & DHCPCD_BOOTP))
+			{
+				free(state->offer);
+				state->offer = NULL;
+			}
+		}
+	}
+	if (state->offer) {
+		get_lease(ifp->ctx, &state->lease, state->offer);
+		state->lease.frominfo = 1;
+		if (state->new == NULL &&
+		    ipv4_iffindaddr(ifp, &state->lease.addr, &state->lease.net))
+		{
+			/* We still have the IP address from the last lease.
+			 * Fake add the address and routes from it so the lease
+			 * can be cleaned up. */
+			state->new = malloc(sizeof(*state->new));
+			if (state->new) {
+				memcpy(state->new, state->offer,
+				    sizeof(*state->new));
+				state->addr = state->lease.addr;
+				state->net = state->lease.net;
+				state->added |= STATE_ADDED | STATE_FAKE;
+				ipv4_buildroutes(ifp->ctx);
+			} else
+				logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
+		}
+		if (state->offer->cookie == 0) {
+			if (state->offer->yiaddr == state->addr.s_addr) {
+				free(state->offer);
+				state->offer = NULL;
+			}
+		} else if (state->lease.leasetime != ~0U &&
+		    stat(state->leasefile, &st) == 0)
+		{
+			time_t now;
+
+			/* Offset lease times and check expiry */
+			now = time(NULL);
+			if (now == -1 ||
+			    (time_t)state->lease.leasetime < now - st.st_mtime)
+			{
+				logger(ifp->ctx, LOG_DEBUG,
+				    "%s: discarding expired lease", ifp->name);
+				free(state->offer);
+				state->offer = NULL;
+				state->lease.addr.s_addr = 0;
+				/* Technically we should discard the lease
+				 * as it's expired, just as DHCPv6 addresses
+				 * would be by the kernel.
+				 * However, this may violate POLA so
+				 * we currently leave it be.
+				 * If we get a totally different lease from
+				 * the DHCP server we'll drop it anyway, as
+				 * we will on any other event which would
+				 * trigger a lease drop.
+				 * This should only happen if dhcpcd stops
+				 * running and the lease expires before
+				 * dhcpcd starts again. */
+#if 0
+				if (state->new)
+					dhcp_drop(ifp, "EXPIRE");
+#endif
+			} else {
+				l = (uint32_t)(now - st.st_mtime);
+				state->lease.leasetime -= l;
+				state->lease.renewaltime -= l;
+				state->lease.rebindtime -= l;
+			}
+		}
+	}
+
+	if (!(ifo->options & DHCPCD_DHCP)) {
+		if (ifo->options & DHCPCD_IPV4LL) {
+			if (state->offer && state->offer->cookie != 0) {
+				free(state->offer);
+				state->offer = NULL;
+			}
+			ipv4ll_start(ifp);
+		}
+		return;
+	}
+
+	if (state->offer == NULL || state->offer->cookie == 0)
+		dhcp_discover(ifp);
+	else
+		dhcp_reboot(ifp);
+}
+
+void
+dhcp_start(struct interface *ifp)
+{
+	struct timespec tv;
+
+	if (!(ifp->options->options & DHCPCD_IPV4))
+		return;
+
+	/* No point in delaying a static configuration */
+	tv.tv_sec = DHCP_MIN_DELAY;
+	tv.tv_nsec = (suseconds_t)arc4random_uniform(
+	    (DHCP_MAX_DELAY - DHCP_MIN_DELAY) * NSEC_PER_SEC);
+	timespecnorm(&tv);
+	logger(ifp->ctx, LOG_DEBUG,
+	    "%s: delaying IPv4 for %0.1f seconds",
+	    ifp->name, timespec_to_double(&tv));
+
+	eloop_timeout_add_tv(ifp->ctx->eloop, &tv, dhcp_start1, ifp);
+}
+
+void
+dhcp_handleifa(int cmd, struct interface *ifp,
+	const struct in_addr *addr,
+	const struct in_addr *net,
+	const struct in_addr *dst,
+	__unused int flags)
+{
+	struct dhcp_state *state;
+	struct if_options *ifo;
+	uint8_t i;
+
+	state = D_STATE(ifp);
+	if (state == NULL)
+		return;
+
+	if (cmd == RTM_DELADDR) {
+		if (state->addr.s_addr == addr->s_addr &&
+		    state->net.s_addr == net->s_addr)
+		{
+			logger(ifp->ctx, LOG_INFO,
+			    "%s: removing IP address %s/%d",
+			    ifp->name, inet_ntoa(state->addr),
+			    inet_ntocidr(state->net));
+			dhcp_drop(ifp, "EXPIRE");
+		}
+		return;
+	}
+
+	if (cmd != RTM_NEWADDR)
+		return;
+
+	ifo = ifp->options;
+	if (ifo->options & DHCPCD_INFORM) {
+		if (state->state != DHS_INFORM)
+			dhcp_inform(ifp);
+		return;
+	}
+
+	if (!(ifo->options & DHCPCD_STATIC))
+		return;
+	if (ifo->req_addr.s_addr != INADDR_ANY)
+		return;
+
+	free(state->old);
+	state->old = state->new;
+	state->new = dhcp_message_new(addr, net);
+	if (state->new == NULL)
+		return;
+	state->dst.s_addr = dst ? dst->s_addr : INADDR_ANY;
+	if (dst) {
+		for (i = 1; i < 255; i++)
+			if (i != DHO_ROUTER && has_option_mask(ifo->dstmask,i))
+				dhcp_message_add_addr(state->new, i, *dst);
+	}
+	state->reason = "STATIC";
+	ipv4_buildroutes(ifp->ctx);
+	script_runreason(ifp, state->reason);
+	if (ifo->options & DHCPCD_INFORM) {
+		state->state = DHS_INFORM;
+		state->xid = dhcp_xid(ifp);
+		state->lease.server.s_addr = dst ? dst->s_addr : INADDR_ANY;
+		state->addr = *addr;
+		state->net = *net;
+		dhcp_inform(ifp);
+	}
+}
diff --git a/dhcpcd-6.8.2/dhcp.h b/dhcpcd-6.8.2/dhcp.h
new file mode 100644
index 0000000..e926b00
--- /dev/null
+++ b/dhcpcd-6.8.2/dhcp.h
@@ -0,0 +1,322 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef DHCP_H
+#define DHCP_H
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+
+#include <limits.h>
+#include <stdint.h>
+
+#include "arp.h"
+#include "auth.h"
+#include "dhcp-common.h"
+
+/* UDP port numbers for DHCP */
+#define DHCP_SERVER_PORT    67
+#define DHCP_CLIENT_PORT    68
+
+#define MAGIC_COOKIE        0x63825363
+#define BROADCAST_FLAG      0x8000
+
+/* DHCP message OP code */
+#define DHCP_BOOTREQUEST    1
+#define DHCP_BOOTREPLY      2
+
+/* DHCP message type */
+#define DHCP_DISCOVER       1
+#define DHCP_OFFER          2
+#define DHCP_REQUEST        3
+#define DHCP_DECLINE        4
+#define DHCP_ACK            5
+#define DHCP_NAK            6
+#define DHCP_RELEASE        7
+#define DHCP_INFORM         8
+#define DHCP_FORCERENEW     9
+
+/* Constants taken from RFC 2131. */
+#define T1			0.5
+#define T2			0.875
+#define DHCP_BASE		4
+#define DHCP_MAX		64
+#define DHCP_RAND_MIN		-1
+#define DHCP_RAND_MAX		1
+
+#ifdef RFC2131_STRICT
+/* Be strictly conformant for section 4.1.1 */
+#  define DHCP_MIN_DELAY	1
+#  define DHCP_MAX_DELAY	10
+#else
+/* or mirror the more modern IPv6RS and DHCPv6 delays */
+#  define DHCP_MIN_DELAY	0
+#  define DHCP_MAX_DELAY	1
+#endif
+
+/* DHCP options */
+enum DHO {
+	DHO_PAD                    = 0,
+	DHO_SUBNETMASK             = 1,
+	DHO_ROUTER                 = 3,
+	DHO_DNSSERVER              = 6,
+	DHO_HOSTNAME               = 12,
+	DHO_DNSDOMAIN              = 15,
+	DHO_MTU                    = 26,
+	DHO_BROADCAST              = 28,
+	DHO_STATICROUTE            = 33,
+	DHO_NISDOMAIN              = 40,
+	DHO_NISSERVER              = 41,
+	DHO_NTPSERVER              = 42,
+	DHO_VENDOR                 = 43,
+	DHO_IPADDRESS              = 50,
+	DHO_LEASETIME              = 51,
+	DHO_OPTIONSOVERLOADED      = 52,
+	DHO_MESSAGETYPE            = 53,
+	DHO_SERVERID               = 54,
+	DHO_PARAMETERREQUESTLIST   = 55,
+	DHO_MESSAGE                = 56,
+	DHO_MAXMESSAGESIZE         = 57,
+	DHO_RENEWALTIME            = 58,
+	DHO_REBINDTIME             = 59,
+	DHO_VENDORCLASSID          = 60,
+	DHO_CLIENTID               = 61,
+	DHO_USERCLASS              = 77,  /* RFC 3004 */
+	DHO_RAPIDCOMMIT            = 80,  /* RFC 4039 */
+	DHO_FQDN                   = 81,
+	DHO_AUTHENTICATION         = 90,  /* RFC 3118 */
+	DHO_AUTOCONFIGURE          = 116, /* RFC 2563 */
+	DHO_DNSSEARCH              = 119, /* RFC 3397 */
+	DHO_CSR                    = 121, /* RFC 3442 */
+	DHO_VIVCO                  = 124, /* RFC 3925 */
+	DHO_VIVSO                  = 125, /* RFC 3925 */
+	DHO_FORCERENEW_NONCE       = 145, /* RFC 6704 */
+	DHO_SIXRD                  = 212, /* RFC 5969 */
+	DHO_MSCSR                  = 249, /* MS code for RFC 3442 */
+	DHO_END                    = 255
+};
+
+/* FQDN values - lsnybble used in flags
+ * hsnybble to create order
+ * and to allow 0x00 to mean disable
+ */
+enum FQDN {
+	FQDN_DISABLE    = 0x00,
+	FQDN_NONE       = 0x18,
+	FQDN_PTR        = 0x20,
+	FQDN_BOTH       = 0x31
+};
+
+/* Sizes for DHCP options */
+#define DHCP_CHADDR_LEN         16
+#define SERVERNAME_LEN          64
+#define BOOTFILE_LEN            128
+#define DHCP_UDP_LEN            (14 + 20 + 8)
+#define DHCP_FIXED_LEN          (DHCP_UDP_LEN + 226)
+#define DHCP_OPTION_LEN         (MTU_MAX - DHCP_FIXED_LEN)
+
+/* Some crappy DHCP servers require the BOOTP minimum length */
+#define BOOTP_MESSAGE_LENTH_MIN 300
+
+/* Flags for the OPTIONSOVERLOADED field. */
+#define OPTION_OVERLOADED_BOOT_FILE 1
+#define OPTION_OVERLOADED_SERVER_NAME 2
+
+/* Don't import common.h as that defines __unused which causes problems
+ * on some Linux systems which define it as part of a structure */
+#if __GNUC__ > 2 || defined(__INTEL_COMPILER)
+# ifndef __packed
+#  define __packed   __attribute__((__packed__))
+# endif
+#else
+# ifndef __packed
+#  define __packed
+# endif
+#endif
+
+struct dhcp_message {
+	uint8_t op;           /* message type */
+	uint8_t hwtype;       /* hardware address type */
+	uint8_t hwlen;        /* hardware address length */
+	uint8_t hwopcount;    /* should be zero in client message */
+	uint32_t xid;            /* transaction id */
+	uint16_t secs;           /* elapsed time in sec. from boot */
+	uint16_t flags;
+	uint32_t ciaddr;         /* (previously allocated) client IP */
+	uint32_t yiaddr;         /* 'your' client IP address */
+	uint32_t siaddr;         /* should be zero in client's messages */
+	uint32_t giaddr;         /* should be zero in client's messages */
+	uint8_t chaddr[DHCP_CHADDR_LEN];  /* client's hardware address */
+	uint8_t servername[SERVERNAME_LEN];    /* server host name */
+	uint8_t bootfile[BOOTFILE_LEN];    /* boot file name */
+	uint32_t cookie;
+	uint8_t options[DHCP_OPTION_LEN]; /* message options - cookie */
+} __packed;
+
+struct dhcp_option_iterator {
+	const struct dhcp_message *message;
+	const uint8_t *ptr;
+	const uint8_t *end;
+	uint8_t extra_option_locations;
+	uint8_t extra_option_locations_set;
+};
+
+struct dhcp_lease {
+	struct in_addr addr;
+	struct in_addr net;
+	struct in_addr brd;
+	uint32_t leasetime;
+	uint32_t renewaltime;
+	uint32_t rebindtime;
+	struct in_addr server;
+	uint8_t frominfo;
+	uint32_t cookie;
+};
+
+/* Extra data about servers stored in the lease file after the dhcp_message */
+struct dhcp_server_info {
+	uint8_t gw_hwlen;
+	unsigned char gw_hwaddr[HWADDR_LEN];
+};
+
+enum DHS {
+	DHS_INIT,
+	DHS_DISCOVER,
+	DHS_REQUEST,
+	DHS_BOUND,
+	DHS_RENEW,
+	DHS_REBIND,
+	DHS_REBOOT,
+	DHS_INFORM,
+	DHS_RENEW_REQUESTED,
+	DHS_IPV4LL_BOUND,
+	DHS_PROBE
+};
+
+struct dhcp_state {
+	enum DHS state;
+	struct dhcp_message *sent;
+	struct dhcp_message *offer;
+	struct dhcp_message *new;
+	struct dhcp_message *old;
+	struct dhcp_lease lease;
+	const char *reason;
+	time_t interval;
+	time_t nakoff;
+	uint32_t xid;
+	int socket;
+
+	int raw_fd;
+	int arp_fd;
+	size_t buffer_size, buffer_len, buffer_pos;
+	unsigned char *buffer;
+
+	struct in_addr addr;
+	struct in_addr net;
+	struct in_addr dst;
+	uint8_t added;
+
+	char leasefile[PATH_MAX];
+	time_t start_uptime;
+
+	unsigned char *clientid;
+
+	struct authstate auth;
+	struct arp_statehead arp_states;
+
+	size_t arping_index;
+
+	struct arp_state *arp_ipv4ll;
+	unsigned int conflicts;
+	int nak_receive_count;
+	int failed_address_offer_count;
+	struct in_addr failed;
+	time_t defend;
+	char randomstate[128];
+	struct dhcp_server_info server_info;
+};
+
+#define D_STATE(ifp)							       \
+	((struct dhcp_state *)(ifp)->if_data[IF_DATA_DHCP])
+#define D_CSTATE(ifp)							       \
+	((const struct dhcp_state *)(ifp)->if_data[IF_DATA_DHCP])
+#define D_STATE_RUNNING(ifp)						       \
+	(D_CSTATE((ifp)) && D_CSTATE((ifp))->new && D_CSTATE((ifp))->reason)
+
+#include "dhcpcd.h"
+#include "if-options.h"
+
+#ifdef INET
+char *decode_rfc3361(const uint8_t *, size_t);
+ssize_t decode_rfc3442(char *, size_t, const uint8_t *p, size_t);
+ssize_t decode_rfc5969(char *, size_t, const uint8_t *p, size_t);
+
+void dhcp_printoptions(const struct dhcpcd_ctx *,
+    const struct dhcp_opt *, size_t);
+int get_option_addr(struct dhcpcd_ctx *,struct in_addr *,
+    const struct dhcp_message *, uint8_t);
+#define IS_BOOTP(i, m) ((m) &&						    \
+	    !IN_LINKLOCAL(htonl((m)->yiaddr)) &&			    \
+	    get_option_uint8((i)->ctx, NULL, (m), DHO_MESSAGETYPE) == -1)
+struct rt_head *get_option_routes(struct interface *,
+    const struct dhcp_message *);
+ssize_t dhcp_env(char **, const char *, const struct dhcp_message *,
+    const struct interface *);
+
+uint32_t dhcp_xid(const struct interface *);
+struct dhcp_message *dhcp_message_new(const struct in_addr *addr,
+    const struct in_addr *mask);
+int dhcp_message_add_addr(struct dhcp_message *, uint8_t, struct in_addr);
+ssize_t make_message(struct dhcp_message **, const struct interface *,
+    uint8_t);
+int valid_dhcp_packet(unsigned char *);
+
+void dhcp_handleifa(int, struct interface *,
+    const struct in_addr *, const struct in_addr *, const struct in_addr *,
+    int);
+
+void dhcp_drop(struct interface *, const char *);
+void dhcp_start(struct interface *);
+void dhcp_stop(struct interface *);
+void dhcp_discover(void *);
+void dhcp_inform(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 *);
+int dhcp_dump(struct interface *);
+#else
+#define dhcp_drop(a, b) {}
+#define dhcp_start(a) {}
+#define dhcp_reboot(a, b) (b = b)
+#define dhcp_reboot_newopts(a, b) (b = b)
+#define dhcp_close(a) {}
+#define dhcp_free(a) {}
+#define dhcp_dump(a) (-1)
+#endif
+
+#endif
diff --git a/dhcpcd-6.8.2/dhcp6.c b/dhcpcd-6.8.2/dhcp6.c
new file mode 100644
index 0000000..ea37fe3
--- /dev/null
+++ b/dhcpcd-6.8.2/dhcp6.c
@@ -0,0 +1,3621 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* TODO: We should decline dupliate addresses detected */
+
+#include <sys/stat.h>
+#include <sys/utsname.h>
+
+#include <netinet/in.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define ELOOP_QUEUE 4
+#include "config.h"
+#include "common.h"
+#include "dhcp.h"
+#include "dhcp6.h"
+#include "duid.h"
+#include "eloop.h"
+#include "if.h"
+#include "if-options.h"
+#include "ipv6nd.h"
+#include "rpc-interface.h"
+#include "script.h"
+
+#ifndef __UNCONST
+#define __UNCONST(a) ((void *)(unsigned long)(const void *)(a))
+#endif
+
+/* DHCPCD Project has been assigned an IANA PEN of 40712 */
+#define DHCPCD_IANA_PEN 40712
+
+/* Unsure if I want this */
+//#define VENDOR_SPLIT
+
+/* Support older systems with different defines */
+#if !defined(IPV6_RECVPKTINFO) && defined(IPV6_PKTINFO)
+#define IPV6_RECVPKTINFO IPV6_PKTINFO
+#endif
+
+struct dhcp6_op {
+	uint16_t type;
+	const char *name;
+};
+
+static const struct dhcp6_op dhcp6_ops[] = {
+	{ DHCP6_SOLICIT, "SOLICIT6" },
+	{ DHCP6_ADVERTISE, "ADVERTISE6" },
+	{ DHCP6_REQUEST, "REQUEST6" },
+	{ DHCP6_REPLY, "REPLY6" },
+	{ DHCP6_RENEW, "RENEW6" },
+	{ DHCP6_REBIND, "REBIND6" },
+	{ DHCP6_CONFIRM, "CONFIRM6" },
+	{ DHCP6_INFORMATION_REQ, "INFORM6" },
+	{ DHCP6_RELEASE, "RELEASE6" },
+	{ DHCP6_RECONFIGURE, "RECONFIURE6" },
+	{ 0, NULL }
+};
+
+struct dhcp_compat {
+	uint8_t dhcp_opt;
+	uint16_t dhcp6_opt;
+};
+
+const struct dhcp_compat dhcp_compats[] = {
+	{ DHO_DNSSERVER,	D6_OPTION_DNS_SERVERS },
+	{ DHO_HOSTNAME,		D6_OPTION_FQDN },
+	{ DHO_DNSDOMAIN,	D6_OPTION_FQDN },
+	{ DHO_NISSERVER,	D6_OPTION_NIS_SERVERS },
+	{ DHO_NTPSERVER,	D6_OPTION_SNTP_SERVERS },
+	{ DHO_RAPIDCOMMIT,	D6_OPTION_RAPID_COMMIT },
+	{ DHO_FQDN,		D6_OPTION_FQDN },
+	{ DHO_VIVCO,		D6_OPTION_VENDOR_CLASS },
+	{ DHO_VIVSO,		D6_OPTION_VENDOR_OPTS },
+	{ DHO_DNSSEARCH,	D6_OPTION_DOMAIN_LIST },
+	{ 0, 0 }
+};
+
+static const char * const dhcp6_statuses[] = {
+	"Success",
+	"Unspecified Failure",
+	"No Addresses Available",
+	"No Binding",
+	"Not On Link",
+	"Use Multicast"
+};
+
+struct dhcp6_ia_addr {
+	struct in6_addr addr;
+	uint32_t pltime;
+	uint32_t vltime;
+} __packed;
+
+struct dhcp6_pd_addr {
+	uint32_t pltime;
+	uint32_t vltime;
+	uint8_t prefix_len;
+	struct in6_addr prefix;
+} __packed;
+
+void
+dhcp6_printoptions(const struct dhcpcd_ctx *ctx,
+    const struct dhcp_opt *opts, size_t opts_len)
+{
+	size_t i, j;
+	const struct dhcp_opt *opt, *opt2;
+	int cols;
+
+	for (i = 0, opt = ctx->dhcp6_opts;
+	    i < ctx->dhcp6_opts_len; i++, opt++)
+	{
+		for (j = 0, opt2 = opts; j < opts_len; j++, opt2++)
+			if (opt2->option == opt->option)
+				break;
+		if (j == opts_len) {
+			cols = printf("%05d %s", opt->option, opt->var);
+			dhcp_print_option_encoding(opt, cols);
+		}
+	}
+	for (i = 0, opt = opts; i < opts_len; i++, opt++) {
+		cols = printf("%05d %s", opt->option, opt->var);
+		dhcp_print_option_encoding(opt, cols);
+	}
+}
+
+static size_t
+dhcp6_makevendor(struct dhcp6_option *o, const struct interface *ifp)
+{
+	const struct if_options *ifo;
+	size_t len, i;
+	uint8_t *p;
+	uint16_t u16;
+	uint32_t u32;
+	ssize_t vlen;
+	const struct vivco *vivco;
+	char vendor[VENDORCLASSID_MAX_LEN];
+
+	ifo = ifp->options;
+	len = sizeof(uint32_t); /* IANA PEN */
+	if (ifo->vivco_en) {
+		for (i = 0, vivco = ifo->vivco;
+		    i < ifo->vivco_len;
+		    i++, vivco++)
+			len += sizeof(uint16_t) + vivco->len;
+		vlen = 0; /* silence bogus gcc warning */
+	} else {
+		vlen = dhcp_vendor(vendor, sizeof(vendor));
+		if (vlen == -1)
+			vlen = 0;
+		else
+			len += sizeof(uint16_t) + (size_t)vlen;
+	}
+
+	if (len > UINT16_MAX) {
+		logger(ifp->ctx, LOG_ERR,
+		    "%s: DHCPv6 Vendor Class too big", ifp->name);
+		return 0;
+	}
+
+	if (o) {
+		o->code = htons(D6_OPTION_VENDOR_CLASS);
+		o->len = htons((uint16_t)len);
+		p = D6_OPTION_DATA(o);
+		u32 = htonl(ifo->vivco_en ? ifo->vivco_en : DHCPCD_IANA_PEN);
+		memcpy(p, &u32, sizeof(u32));
+		p += sizeof(u32);
+		if (ifo->vivco_en) {
+			for (i = 0, vivco = ifo->vivco;
+			    i < ifo->vivco_len;
+			    i++, vivco++)
+			{
+				u16 = htons((uint16_t)vivco->len);
+				memcpy(p, &u16, sizeof(u16));
+				p += sizeof(u16);
+				memcpy(p, vivco->data, vivco->len);
+				p += vivco->len;
+			}
+		} else if (vlen) {
+			u16 = htons((uint16_t)vlen);
+			memcpy(p, &u16, sizeof(u16));
+			p += sizeof(u16);
+			memcpy(p, vendor, (size_t)vlen);
+		}
+	}
+
+	return len;
+}
+
+static const struct dhcp6_option *
+dhcp6_findoption(uint16_t code, const uint8_t *d, size_t len)
+{
+	const struct dhcp6_option *o;
+	size_t ol;
+
+	code = htons(code);
+	for (o = (const struct dhcp6_option *)d;
+	    len >= sizeof(*o);
+	    o = D6_CNEXT_OPTION(o))
+	{
+		ol = sizeof(*o) + ntohs(o->len);
+		if (ol > len) {
+			errno = EINVAL;
+			return NULL;
+		}
+		if (o->code == code)
+			return o;
+		len -= ol;
+	}
+
+	errno = ESRCH;
+	return NULL;
+}
+
+static const uint8_t *
+dhcp6_getoption(struct dhcpcd_ctx *ctx,
+    size_t *os, unsigned int *code, size_t *len,
+    const uint8_t *od, size_t ol, struct dhcp_opt **oopt)
+{
+	const struct dhcp6_option *o;
+	size_t i;
+	struct dhcp_opt *opt;
+
+	if (od) {
+		*os = sizeof(*o);
+		if (ol < *os) {
+			errno = EINVAL;
+			return NULL;
+		}
+		o = (const struct dhcp6_option *)od;
+		*len = ntohs(o->len);
+		if (*len > ol - *os) {
+			errno = EINVAL;
+			return NULL;
+		}
+		*code = ntohs(o->code);
+	} else
+		o = NULL;
+
+	*oopt = NULL;
+	for (i = 0, opt = ctx->dhcp6_opts;
+	    i < ctx->dhcp6_opts_len; i++, opt++)
+	{
+		if (opt->option == *code) {
+			*oopt = opt;
+			break;
+		}
+	}
+
+	if (o)
+		return D6_COPTION_DATA(o);
+	return NULL;
+}
+
+static const struct dhcp6_option *
+dhcp6_getmoption(uint16_t code, const struct dhcp6_message *m, size_t len)
+{
+
+	if (len < sizeof(*m)) {
+		errno = EINVAL;
+		return NULL;
+	}
+	len -= sizeof(*m);
+	return dhcp6_findoption(code,
+	    (const uint8_t *)D6_CFIRST_OPTION(m), len);
+}
+
+static int
+dhcp6_updateelapsed(struct interface *ifp, struct dhcp6_message *m, size_t len)
+{
+	struct dhcp6_state *state;
+	const struct dhcp6_option *co;
+	struct dhcp6_option *o;
+	time_t up;
+	uint16_t u16;
+
+	co = dhcp6_getmoption(D6_OPTION_ELAPSED, m, len);
+	if (co == NULL)
+		return -1;
+
+	o = __UNCONST(co);
+	state = D6_STATE(ifp);
+	up = uptime() - state->start_uptime;
+	if (up < 0 || up > (time_t)UINT16_MAX)
+		up = (time_t)UINT16_MAX;
+	u16 = htons((uint16_t)up);
+	memcpy(D6_OPTION_DATA(o), &u16, sizeof(u16));
+	return 0;
+}
+
+static void
+dhcp6_newxid(const struct interface *ifp, struct dhcp6_message *m)
+{
+	uint32_t xid;
+
+	if (ifp->options->options & DHCPCD_XID_HWADDR &&
+	    ifp->hwlen >= sizeof(xid))
+		/* The lower bits are probably more unique on the network */
+		memcpy(&xid, (ifp->hwaddr + ifp->hwlen) - sizeof(xid),
+		    sizeof(xid));
+	else
+		xid = arc4random();
+
+	m->xid[0] = (xid >> 16) & 0xff;
+	m->xid[1] = (xid >> 8) & 0xff;
+	m->xid[2] = xid & 0xff;
+}
+
+static const struct if_sla *
+dhcp6_findselfsla(struct interface *ifp, const uint8_t *iaid)
+{
+	size_t i, j;
+
+	for (i = 0; i < ifp->options->ia_len; i++) {
+		if (iaid == NULL ||
+		    memcmp(&ifp->options->ia[i].iaid, iaid,
+		    sizeof(ifp->options->ia[i].iaid)) == 0)
+		{
+			for (j = 0; j < ifp->options->ia[i].sla_len; j++) {
+				if (strcmp(ifp->options->ia[i].sla[j].ifname,
+				    ifp->name) == 0)
+					return &ifp->options->ia[i].sla[j];
+			}
+		}
+	}
+	return NULL;
+}
+
+
+#ifndef ffs32
+static int
+ffs32(uint32_t n)
+{
+	int v;
+
+	if (!n)
+		return 0;
+
+	v = 1;
+	if ((n & 0x0000FFFFU) == 0) {
+		n >>= 16;
+		v += 16;
+	}
+	if ((n & 0x000000FFU) == 0) {
+		n >>= 8;
+		v += 8;
+	}
+	if ((n & 0x0000000FU) == 0) {
+		n >>= 4;
+		v += 4;
+	}
+	if ((n & 0x00000003U) == 0) {
+		n >>= 2;
+		v += 2;
+	}
+	if ((n & 0x00000001U) == 0)
+		v += 1;
+
+	return v;
+}
+#endif
+
+static int
+dhcp6_delegateaddr(struct in6_addr *addr, struct interface *ifp,
+    const struct ipv6_addr *prefix, const struct if_sla *sla, struct if_ia *ia)
+{
+	struct dhcp6_state *state;
+	struct if_sla asla;
+	char sabuf[INET6_ADDRSTRLEN];
+	const char *sa;
+
+	state = D6_STATE(ifp);
+	if (state == NULL) {
+		ifp->if_data[IF_DATA_DHCP6] = calloc(1, sizeof(*state));
+		state = D6_STATE(ifp);
+		if (state == NULL) {
+			logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
+			return -1;
+		}
+
+		TAILQ_INIT(&state->addrs);
+		state->state = DH6S_DELEGATED;
+		state->reason = "DELEGATED6";
+	}
+
+	if (sla == NULL || sla->sla_set == 0) {
+		asla.sla = ifp->index;
+		asla.prefix_len = 0;
+		sla = &asla;
+	} else if (sla->prefix_len == 0) {
+		asla.sla = sla->sla;
+		if (asla.sla == 0)
+			asla.prefix_len = prefix->prefix_len;
+		else
+			asla.prefix_len = 0;
+		sla = &asla;
+	}
+	if (sla->prefix_len == 0) {
+		uint32_t sla_max;
+		int bits;
+
+		if (ia->sla_max == 0) {
+			const struct interface *ifi;
+
+			sla_max = 0;
+			TAILQ_FOREACH(ifi, ifp->ctx->ifaces, next) {
+				if (ifi != ifp && ifi->index > sla_max)
+					sla_max = ifi->index;
+			}
+		} else
+			sla_max = ia->sla_max;
+
+		bits = ffs32(sla_max);
+
+		if (prefix->prefix_len + bits > UINT8_MAX)
+			asla.prefix_len = UINT8_MAX;
+		else {
+			asla.prefix_len = (uint8_t)(prefix->prefix_len + bits);
+
+			/* Make a 64 prefix by default, as this maks SLAAC
+			 * possible. Otherwise round up to the nearest octet. */
+			if (asla.prefix_len <= 64)
+				asla.prefix_len = 64;
+			else
+				asla.prefix_len = (uint8_t)ROUNDUP8(asla.prefix_len);
+
+		}
+
+#define BIT(n) (1l << (n))
+#define BIT_MASK(len) (BIT(len) - 1)
+		if (ia->sla_max == 0)
+			/* Work out the real sla_max from our bits used */
+			ia->sla_max = (uint32_t)BIT_MASK(asla.prefix_len -
+			    prefix->prefix_len);
+	}
+
+	if (ipv6_userprefix(&prefix->prefix, prefix->prefix_len,
+		sla->sla, addr, sla->prefix_len) == -1)
+	{
+		sa = inet_ntop(AF_INET6, &prefix->prefix,
+		    sabuf, sizeof(sabuf));
+		logger(ifp->ctx, LOG_ERR,
+		    "%s: invalid prefix %s/%d + %d/%d: %m",
+		    ifp->name, sa, prefix->prefix_len,
+		    sla->sla, sla->prefix_len);
+		return -1;
+	}
+
+	if (prefix->prefix_exclude_len &&
+	    IN6_ARE_ADDR_EQUAL(addr, &prefix->prefix_exclude))
+	{
+		sa = inet_ntop(AF_INET6, &prefix->prefix_exclude,
+		    sabuf, sizeof(sabuf));
+		logger(ifp->ctx, LOG_ERR,
+		    "%s: cannot delegate excluded prefix %s/%d",
+		    ifp->name, sa, prefix->prefix_exclude_len);
+		return -1;
+	}
+
+	return sla->prefix_len;
+}
+
+int
+dhcp6_has_public_addr(const struct interface *ifp)
+{
+	const struct dhcp6_state *state = D6_CSTATE(ifp);
+	const struct ipv6_addr *ia;
+
+	if (state == NULL)
+		return 0;
+	TAILQ_FOREACH(ia, &state->addrs, next) {
+		if (ipv6_publicaddr(ia))
+			return 1;
+	}
+	return 0;
+}
+
+static int
+dhcp6_makemessage(struct interface *ifp)
+{
+	struct dhcp6_state *state;
+	struct dhcp6_message *m;
+	struct dhcp6_option *o, *so, *eo;
+	const struct dhcp6_option *si, *unicast;
+	size_t l, n, len, ml;
+	uint8_t u8, type;
+	uint16_t u16, n_options, auth_len;
+	struct if_options *ifo;
+	const struct dhcp_opt *opt, *opt2;
+	uint8_t IA, *p;
+	const uint8_t *pp;
+	uint32_t u32;
+	const struct ipv6_addr *ap;
+	char hbuf[HOSTNAME_MAX_LEN + 1];
+	const char *hostname;
+	int fqdn;
+	struct dhcp6_ia_addr *iap;
+	struct dhcp6_pd_addr *pdp;
+
+	state = D6_STATE(ifp);
+	if (state->send) {
+		free(state->send);
+		state->send = NULL;
+	}
+
+	ifo = ifp->options;
+	fqdn = ifo->fqdn;
+
+	if (fqdn == FQDN_DISABLE && ifo->options & DHCPCD_HOSTNAME) {
+		/* We're sending the DHCPv4 hostname option, so send FQDN as
+		 * DHCPv6 has no FQDN option and DHCPv4 must not send
+		 * hostname and FQDN according to RFC4702 */
+		fqdn = FQDN_BOTH;
+	}
+	if (fqdn != FQDN_DISABLE) {
+		if (ifo->hostname[0] == '\0')
+			hostname = get_hostname(hbuf, sizeof(hbuf),
+			    ifo->options & DHCPCD_HOSTNAME_SHORT ? 1 : 0);
+		else
+			hostname = ifo->hostname;
+	} else
+		hostname = NULL; /* appearse gcc */
+
+	/* Work out option size first */
+	n_options = 0;
+	len = 0;
+	si = NULL;
+	if (state->state != DH6S_RELEASE) {
+		for (l = 0, opt = ifp->ctx->dhcp6_opts;
+		    l < ifp->ctx->dhcp6_opts_len;
+		    l++, opt++)
+		{
+			for (n = 0, opt2 = ifo->dhcp6_override;
+			    n < ifo->dhcp6_override_len;
+			    n++, opt2++)
+			{
+				if (opt->option == opt2->option)
+					break;
+			}
+			if (n < ifo->dhcp6_override_len)
+			    continue;
+			if (!(opt->type & NOREQ) &&
+			    (opt->type & REQUEST ||
+			    has_option_mask(ifo->requestmask6, opt->option)))
+			{
+				n_options++;
+				len += sizeof(u16);
+			}
+		}
+		for (l = 0, opt = ifo->dhcp6_override;
+		    l < ifo->dhcp6_override_len;
+		    l++, opt++)
+		{
+			if (!(opt->type & NOREQ) &&
+			    (opt->type & REQUEST ||
+			    has_option_mask(ifo->requestmask6, opt->option)))
+			{
+				n_options++;
+				len += sizeof(u16);
+			}
+		}
+		if (dhcp6_findselfsla(ifp, NULL)) {
+			n_options++;
+			len += sizeof(u16);
+		}
+		if (len)
+			len += sizeof(*o);
+
+		if (fqdn != FQDN_DISABLE)
+			len += sizeof(*o) + 1 + encode_rfc1035(hostname, NULL);
+
+		if ((ifo->auth.options & DHCPCD_AUTH_SENDREQUIRE) !=
+		    DHCPCD_AUTH_SENDREQUIRE)
+			len += sizeof(*o); /* Reconfigure Accept */
+	}
+
+	len += sizeof(*state->send);
+	len += sizeof(*o) + ifp->ctx->duid_len;
+	len += sizeof(*o) + sizeof(uint16_t); /* elapsed */
+	len += sizeof(*o) + dhcp6_makevendor(NULL, ifp);
+
+	/* IA */
+	m = NULL;
+	ml = 0;
+	switch(state->state) {
+	case DH6S_REQUEST:
+		m = state->recv;
+		ml = state->recv_len;
+		/* FALLTHROUGH */
+	case DH6S_RELEASE:
+		/* FALLTHROUGH */
+	case DH6S_RENEW:
+		if (m == NULL) {
+			m = state->new;
+			ml = state->new_len;
+		}
+		si = dhcp6_getmoption(D6_OPTION_SERVERID, m, ml);
+		if (si == NULL) {
+			errno = ESRCH;
+			return -1;
+		}
+		len += sizeof(*si) + ntohs(si->len);
+		/* FALLTHROUGH */
+	case DH6S_REBIND:
+		/* FALLTHROUGH */
+	case DH6S_CONFIRM:
+		/* FALLTHROUGH */
+	case DH6S_DISCOVER:
+		if (m == NULL) {
+			m = state->new;
+			ml = state->new_len;
+		}
+		TAILQ_FOREACH(ap, &state->addrs, next) {
+			if (ap->prefix_vltime == 0 &&
+			    !(ap->flags & IPV6_AF_REQUEST))
+				continue;
+			if (ap->ia_type == D6_OPTION_IA_PD) {
+				if (!(ifo->options & DHCPCD_NOPFXDLG)) {
+					len += sizeof(*o) + sizeof(u8) +
+					    sizeof(u32) + sizeof(u32) +
+					    sizeof(ap->prefix);
+					if (ap->prefix_exclude_len)
+						len += sizeof(*o) + 1 +
+						    (uint8_t)((ap->prefix_exclude_len -
+						    ap->prefix_len - 1) / NBBY)
+						    + 1;
+
+				}
+			} else if (!(ifo->options & DHCPCD_PFXDLGONLY))
+				len += sizeof(*o) + sizeof(ap->addr) +
+				    sizeof(u32) + sizeof(u32);
+		}
+		/* FALLTHROUGH */
+	case DH6S_INIT:
+		for (l = 0; l < ifo->ia_len; l++) {
+			if (ifo->ia[l].ia_type == D6_OPTION_IA_PD) {
+				if (ifo->options & DHCPCD_NOPFXDLG)
+					continue;
+			} else if (ifo->options & DHCPCD_PFXDLGONLY)
+				continue;
+			len += sizeof(*o) + (sizeof(u32) * 3);
+		}
+		IA = 1;
+		break;
+	default:
+		IA = 0;
+	}
+
+	if (state->state == DH6S_DISCOVER &&
+	    !(ifp->ctx->options & DHCPCD_TEST) &&
+	    has_option_mask(ifo->requestmask6, D6_OPTION_RAPID_COMMIT))
+		len += sizeof(*o);
+
+	if (m == NULL) {
+		m = state->new;
+		ml = state->new_len;
+	}
+	unicast = NULL;
+	/* Depending on state, get the unicast address */
+	switch(state->state) {
+		break;
+	case DH6S_INIT: /* FALLTHROUGH */
+	case DH6S_DISCOVER:
+		type = DHCP6_SOLICIT;
+		break;
+	case DH6S_REQUEST:
+		type = DHCP6_REQUEST;
+		unicast = dhcp6_getmoption(D6_OPTION_UNICAST, m, ml);
+		break;
+	case DH6S_CONFIRM:
+		type = DHCP6_CONFIRM;
+		break;
+	case DH6S_REBIND:
+		type = DHCP6_REBIND;
+		break;
+	case DH6S_RENEW:
+		type = DHCP6_RENEW;
+		unicast = dhcp6_getmoption(D6_OPTION_UNICAST, m, ml);
+		break;
+	case DH6S_INFORM:
+		type = DHCP6_INFORMATION_REQ;
+		break;
+	case DH6S_RELEASE:
+		type = DHCP6_RELEASE;
+		unicast = dhcp6_getmoption(D6_OPTION_UNICAST, m, ml);
+		break;
+	default:
+		errno = EINVAL;
+		return -1;
+	}
+
+	auth_len = 0;
+	if (ifo->auth.options & DHCPCD_AUTH_SEND) {
+		ssize_t alen = dhcp_auth_encode(&ifo->auth,
+		    state->auth.token, NULL, 0, 6, type, NULL, 0);
+		if (alen != -1 && alen > UINT16_MAX) {
+			errno = ERANGE;
+			alen = -1;
+		}
+		if (alen == -1)
+			logger(ifp->ctx, LOG_ERR,
+			    "%s: dhcp_auth_encode: %m", ifp->name);
+		else if (alen != 0) {
+			auth_len = (uint16_t)alen;
+			len += sizeof(*o) + auth_len;
+		}
+	}
+
+	state->send = malloc(len);
+	if (state->send == NULL)
+		return -1;
+
+	state->send_len = len;
+	state->send->type = type;
+
+	/* If we found a unicast option, copy it to our state for sending */
+	if (unicast && ntohs(unicast->len) == sizeof(state->unicast))
+		memcpy(&state->unicast, D6_COPTION_DATA(unicast),
+		    sizeof(state->unicast));
+	else
+		state->unicast = in6addr_any;
+
+	dhcp6_newxid(ifp, state->send);
+
+	o = D6_FIRST_OPTION(state->send);
+	o->code = htons(D6_OPTION_CLIENTID);
+	o->len = htons((uint16_t)ifp->ctx->duid_len);
+	memcpy(D6_OPTION_DATA(o), ifp->ctx->duid, ifp->ctx->duid_len);
+
+	if (si) {
+		o = D6_NEXT_OPTION(o);
+		memcpy(o, si, sizeof(*si) + ntohs(si->len));
+	}
+
+	o = D6_NEXT_OPTION(o);
+	o->code = htons(D6_OPTION_ELAPSED);
+	o->len = htons(sizeof(uint16_t));
+	p = D6_OPTION_DATA(o);
+	memset(p, 0, sizeof(uint16_t));
+
+	o = D6_NEXT_OPTION(o);
+	dhcp6_makevendor(o, ifp);
+
+	if (state->state == DH6S_DISCOVER &&
+	    !(ifp->ctx->options & DHCPCD_TEST) &&
+	    has_option_mask(ifo->requestmask6, D6_OPTION_RAPID_COMMIT))
+	{
+		o = D6_NEXT_OPTION(o);
+		o->code = htons(D6_OPTION_RAPID_COMMIT);
+		o->len = 0;
+	}
+
+	for (l = 0; IA && l < ifo->ia_len; l++) {
+		if (ifo->ia[l].ia_type == D6_OPTION_IA_PD) {
+			if (ifo->options & DHCPCD_NOPFXDLG)
+				continue;
+		} else if (ifo->options & DHCPCD_PFXDLGONLY)
+			continue;
+		o = D6_NEXT_OPTION(o);
+		o->code = htons(ifo->ia[l].ia_type);
+		o->len = htons(sizeof(u32) + sizeof(u32) + sizeof(u32));
+		p = D6_OPTION_DATA(o);
+		memcpy(p, ifo->ia[l].iaid, sizeof(u32));
+		p += sizeof(u32);
+		memset(p, 0, sizeof(u32) + sizeof(u32));
+		TAILQ_FOREACH(ap, &state->addrs, next) {
+			if (ap->prefix_vltime == 0 &&
+			    !(ap->flags & IPV6_AF_REQUEST))
+				continue;
+			if (memcmp(ifo->ia[l].iaid, ap->iaid, sizeof(u32)))
+				continue;
+			so = D6_NEXT_OPTION(o);
+			if (ap->ia_type == D6_OPTION_IA_PD) {
+				so->code = htons(D6_OPTION_IAPREFIX);
+				so->len = htons(sizeof(ap->prefix) +
+				    sizeof(u32) + sizeof(u32) + sizeof(u8));
+				pdp = (struct dhcp6_pd_addr *)
+				    D6_OPTION_DATA(so);
+				pdp->pltime = htonl(ap->prefix_pltime);
+				pdp->vltime = htonl(ap->prefix_vltime);
+				pdp->prefix_len = ap->prefix_len;
+				pdp->prefix = ap->prefix;
+
+				/* RFC6603 Section 4.2 */
+				if (ap->prefix_exclude_len) {
+					n = (size_t)((ap->prefix_exclude_len -
+					    ap->prefix_len - 1) / NBBY) + 1;
+					eo = D6_NEXT_OPTION(so);
+					eo->code = htons(D6_OPTION_PD_EXCLUDE);
+					eo->len = (uint16_t)(n + 1);
+					p = D6_OPTION_DATA(eo);
+					*p++ = (uint8_t)ap->prefix_exclude_len;
+					pp = ap->prefix_exclude.s6_addr;
+					pp += (size_t)((ap->prefix_len - 1) / NBBY)
+					    + (n - 1);
+					u8 = ap->prefix_len % NBBY;
+					if (u8)
+						n--;
+					while (n-- > 0)
+						*p++ = *pp--;
+					if (u8)
+						*p = (uint8_t)(*pp << u8);
+					u16 = (uint16_t)(ntohs(so->len) +
+					    sizeof(*eo) + eo->len);
+					so->len = htons(u16);
+					eo->len = htons(eo->len);
+				}
+
+				u16 = (uint16_t)(ntohs(o->len) + sizeof(*so)
+				    + ntohs(so->len));
+				o->len = htons(u16);
+			} else {
+				so->code = htons(D6_OPTION_IA_ADDR);
+				so->len = sizeof(ap->addr) +
+				    sizeof(u32) + sizeof(u32);
+				iap = (struct dhcp6_ia_addr *)
+				    D6_OPTION_DATA(so);
+				iap->addr = ap->addr;
+				iap->pltime = htonl(ap->prefix_pltime);
+				iap->vltime = htonl(ap->prefix_vltime);
+				u16 = (uint16_t)(ntohs(o->len) + sizeof(*so)
+				    + so->len);
+				so->len = htons(so->len);
+				o->len = htons(u16);
+			}
+		}
+	}
+
+	if (state->send->type != DHCP6_RELEASE) {
+		if (fqdn != FQDN_DISABLE) {
+			o = D6_NEXT_OPTION(o);
+			o->code = htons(D6_OPTION_FQDN);
+			p = D6_OPTION_DATA(o);
+			switch (fqdn) {
+			case FQDN_BOTH:
+				*p = D6_FQDN_BOTH;
+				break;
+			case FQDN_PTR:
+				*p = D6_FQDN_PTR;
+				break;
+			default:
+				*p = D6_FQDN_NONE;
+				break;
+			}
+			l = encode_rfc1035(hostname, p + 1);
+			if (l == 0)
+				*p = D6_FQDN_NONE;
+			o->len = htons((uint16_t)(l + 1));
+		}
+
+		if ((ifo->auth.options & DHCPCD_AUTH_SENDREQUIRE) !=
+		    DHCPCD_AUTH_SENDREQUIRE)
+		{
+			o = D6_NEXT_OPTION(o);
+			o->code = htons(D6_OPTION_RECONF_ACCEPT);
+			o->len = 0;
+		}
+
+		if (n_options) {
+			o = D6_NEXT_OPTION(o);
+			o->code = htons(D6_OPTION_ORO);
+			o->len = 0;
+			p = D6_OPTION_DATA(o);
+			for (l = 0, opt = ifp->ctx->dhcp6_opts;
+			    l < ifp->ctx->dhcp6_opts_len;
+			    l++, opt++)
+			{
+				for (n = 0, opt2 = ifo->dhcp6_override;
+				    n < ifo->dhcp6_override_len;
+				    n++, opt2++)
+				{
+					if (opt->option == opt2->option)
+						break;
+				}
+				if (n < ifo->dhcp6_override_len)
+				    continue;
+				if (!(opt->type & NOREQ) &&
+				    (opt->type & REQUEST ||
+				    has_option_mask(ifo->requestmask6,
+				        opt->option)))
+				{
+					u16 = htons((uint16_t)opt->option);
+					memcpy(p, &u16, sizeof(u16));
+					p += sizeof(u16);
+					o->len = (uint16_t)(o->len + sizeof(u16));
+				}
+			}
+			for (l = 0, opt = ifo->dhcp6_override;
+			    l < ifo->dhcp6_override_len;
+			    l++, opt++)
+			{
+				if (!(opt->type & NOREQ) &&
+				    (opt->type & REQUEST ||
+				    has_option_mask(ifo->requestmask6,
+				        opt->option)))
+				{
+					u16 = htons((uint16_t)opt->option);
+					memcpy(p, &u16, sizeof(u16));
+					p += sizeof(u16);
+					o->len = (uint16_t)(o->len + sizeof(u16));
+				}
+			}
+			if (dhcp6_findselfsla(ifp, NULL)) {
+				u16 = htons(D6_OPTION_PD_EXCLUDE);
+				memcpy(p, &u16, sizeof(u16));
+				o->len = (uint16_t)(o->len + sizeof(u16));
+			}
+			o->len = htons(o->len);
+		}
+	}
+
+	/* This has to be the last option */
+	if (ifo->auth.options & DHCPCD_AUTH_SEND && auth_len != 0) {
+		o = D6_NEXT_OPTION(o);
+		o->code = htons(D6_OPTION_AUTH);
+		o->len = htons((uint16_t)auth_len);
+		/* data will be filled at send message time */
+	}
+
+	return 0;
+}
+
+static const char *
+dhcp6_get_op(uint16_t type)
+{
+	const struct dhcp6_op *d;
+
+	for (d = dhcp6_ops; d->name; d++)
+		if (d->type == type)
+			return d->name;
+	return NULL;
+}
+
+static void
+dhcp6_freedrop_addrs(struct interface *ifp, int drop,
+    const struct interface *ifd)
+{
+	struct dhcp6_state *state;
+
+	state = D6_STATE(ifp);
+	if (state) {
+		ipv6_freedrop_addrs(&state->addrs, drop, ifd);
+		if (drop)
+			ipv6_buildroutes(ifp->ctx);
+	}
+}
+
+static void dhcp6_delete_delegates(struct interface *ifp)
+{
+	struct interface *ifp0;
+
+	if (ifp->ctx->ifaces) {
+		TAILQ_FOREACH(ifp0, ifp->ctx->ifaces, next) {
+			if (ifp0 != ifp)
+				dhcp6_freedrop_addrs(ifp0, 1, ifp);
+		}
+	}
+}
+
+static ssize_t
+dhcp6_update_auth(struct interface *ifp, struct dhcp6_message *m, size_t len)
+{
+	struct dhcp6_state *state;
+	const struct dhcp6_option *co;
+	struct dhcp6_option *o;
+
+	co = dhcp6_getmoption(D6_OPTION_AUTH, m, len);
+	if (co == NULL)
+		return -1;
+
+	o = __UNCONST(co);
+	state = D6_STATE(ifp);
+
+	return dhcp_auth_encode(&ifp->options->auth, state->auth.token,
+	    (uint8_t *)state->send, state->send_len,
+	    6, state->send->type,
+	    D6_OPTION_DATA(o), ntohs(o->len));
+}
+
+static int
+dhcp6_sendmessage(struct interface *ifp, void (*callback)(void *))
+{
+	struct dhcp6_state *state;
+	struct ipv6_ctx *ctx;
+	struct sockaddr_in6 dst;
+	struct cmsghdr *cm;
+	struct in6_pktinfo pi;
+	struct timespec RTprev;
+	double rnd;
+	time_t ms;
+	uint8_t neg;
+	const char *broad_uni;
+	const struct in6_addr alldhcp = IN6ADDR_LINKLOCAL_ALLDHCP_INIT;
+
+	memset(&dst, 0, sizeof(dst));
+	dst.sin6_family = AF_INET6;
+	dst.sin6_port = htons(DHCP6_SERVER_PORT);
+#ifdef SIN6_LEN
+	dst.sin6_len = sizeof(dst);
+#endif
+
+	state = D6_STATE(ifp);
+	/* We need to ensure we have sufficient scope to unicast the address */
+	/* XXX FIXME: We should check any added addresses we have like from
+	 * a Router Advertisement */
+	if (IN6_IS_ADDR_UNSPECIFIED(&state->unicast) ||
+	    (state->state == DH6S_REQUEST &&
+	    (!IN6_IS_ADDR_LINKLOCAL(&state->unicast) || !ipv6_linklocal(ifp))))
+	{
+		dst.sin6_addr = alldhcp;
+		broad_uni = "broadcasting";
+	} else {
+		dst.sin6_addr = state->unicast;
+		broad_uni = "unicasting";
+	}
+
+	if (!callback)
+		logger(ifp->ctx, LOG_DEBUG,
+		    "%s: %s %s with xid 0x%02x%02x%02x",
+		    ifp->name,
+		    broad_uni,
+		    dhcp6_get_op(state->send->type),
+		    state->send->xid[0],
+		    state->send->xid[1],
+		    state->send->xid[2]);
+	else {
+		if (state->IMD) {
+			/* Some buggy PPP servers close the link too early
+			 * after sending an invalid status in their reply
+			 * which means this host won't see it.
+			 * 1 second grace seems to be the sweet spot. */
+			if (ifp->flags & IFF_POINTOPOINT)
+				state->RT.tv_sec = 1;
+			else
+				state->RT.tv_sec = 0;
+			state->RT.tv_nsec = (suseconds_t)arc4random_uniform(
+			    (uint32_t)(state->IMD * NSEC_PER_SEC));
+			timespecnorm(&state->RT);
+			broad_uni = "delaying";
+			goto logsend;
+		}
+		if (state->RTC == 0) {
+			RTprev.tv_sec = state->IRT;
+			RTprev.tv_nsec = 0;
+			state->RT.tv_sec = RTprev.tv_sec;
+			state->RT.tv_nsec = 0;
+		} else {
+			RTprev = state->RT;
+			timespecadd(&state->RT, &state->RT, &state->RT);
+		}
+
+		rnd = DHCP6_RAND_MIN;
+		rnd += (suseconds_t)arc4random_uniform(
+		    DHCP6_RAND_MAX - DHCP6_RAND_MIN);
+		rnd /= MSEC_PER_SEC;
+		neg = (rnd < 0.0);
+		if (neg)
+			rnd = -rnd;
+		ts_to_ms(ms, &RTprev);
+		ms = (time_t)((double)ms * rnd);
+		ms_to_ts(&RTprev, ms);
+		if (neg)
+			timespecsub(&state->RT, &RTprev, &state->RT);
+		else
+			timespecadd(&state->RT, &RTprev, &state->RT);
+
+		if (state->RT.tv_sec > state->MRT) {
+			RTprev.tv_sec = state->MRT;
+			RTprev.tv_nsec = 0;
+			state->RT.tv_sec = state->MRT;
+			state->RT.tv_nsec = 0;
+			ts_to_ms(ms, &RTprev);
+			ms = (time_t)((double)ms * rnd);
+			ms_to_ts(&RTprev, ms);
+			if (neg)
+				timespecsub(&state->RT, &RTprev, &state->RT);
+			else
+				timespecadd(&state->RT, &RTprev, &state->RT);
+		}
+
+logsend:
+		logger(ifp->ctx, LOG_DEBUG,
+		    "%s: %s %s (xid 0x%02x%02x%02x),"
+		    " next in %0.1f seconds",
+		    ifp->name,
+		    broad_uni,
+		    dhcp6_get_op(state->send->type),
+		    state->send->xid[0],
+		    state->send->xid[1],
+		    state->send->xid[2],
+		    timespec_to_double(&state->RT));
+
+		/* Wait the initial delay */
+		if (state->IMD) {
+			state->IMD = 0;
+			eloop_timeout_add_tv(ifp->ctx->eloop,
+			    &state->RT, callback, ifp);
+			return 0;
+		}
+	}
+
+	/* Update the elapsed time */
+	dhcp6_updateelapsed(ifp, state->send, state->send_len);
+	if (ifp->options->auth.options & DHCPCD_AUTH_SEND &&
+	    dhcp6_update_auth(ifp, state->send, state->send_len) == -1)
+	{
+		logger(ifp->ctx, LOG_ERR,
+		    "%s: dhcp6_updateauth: %m", ifp->name);
+		if (errno != ESRCH)
+			return -1;
+	}
+
+	ctx = ifp->ctx->ipv6;
+	dst.sin6_scope_id = ifp->index;
+	ctx->sndhdr.msg_name = (void *)&dst;
+	ctx->sndhdr.msg_iov[0].iov_base = state->send;
+	ctx->sndhdr.msg_iov[0].iov_len = state->send_len;
+
+	/* Set the outbound interface */
+	cm = CMSG_FIRSTHDR(&ctx->sndhdr);
+	if (cm == NULL) /* unlikely */
+		return -1;
+	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));
+
+	if (sendmsg(ctx->dhcp_fd, &ctx->sndhdr, 0) == -1) {
+		logger(ifp->ctx, LOG_ERR,
+		    "%s: %s: sendmsg: %m", ifp->name, __func__);
+		ifp->options->options &= ~DHCPCD_IPV6;
+		dhcp6_drop(ifp, "EXPIRE6");
+		return -1;
+	}
+
+	state->RTC++;
+	if (callback) {
+		if (state->MRC == 0 || state->RTC < state->MRC)
+			eloop_timeout_add_tv(ifp->ctx->eloop,
+			    &state->RT, callback, ifp);
+		else if (state->MRC != 0 && state->MRCcallback)
+			eloop_timeout_add_tv(ifp->ctx->eloop,
+			    &state->RT, state->MRCcallback, ifp);
+		else
+			logger(ifp->ctx, LOG_WARNING,
+			    "%s: sent %d times with no reply",
+			    ifp->name, state->RTC);
+	}
+	return 0;
+}
+
+static void
+dhcp6_sendinform(void *arg)
+{
+
+	dhcp6_sendmessage(arg, dhcp6_sendinform);
+}
+
+static void
+dhcp6_senddiscover(void *arg)
+{
+
+	dhcp6_sendmessage(arg, dhcp6_senddiscover);
+}
+
+static void
+dhcp6_sendrequest(void *arg)
+{
+
+	dhcp6_sendmessage(arg, dhcp6_sendrequest);
+}
+
+static void
+dhcp6_sendrebind(void *arg)
+{
+
+	dhcp6_sendmessage(arg, dhcp6_sendrebind);
+}
+
+static void
+dhcp6_sendrenew(void *arg)
+{
+
+	dhcp6_sendmessage(arg, dhcp6_sendrenew);
+}
+
+static void
+dhcp6_sendconfirm(void *arg)
+{
+
+	dhcp6_sendmessage(arg, dhcp6_sendconfirm);
+}
+
+/*
+static void
+dhcp6_sendrelease(void *arg)
+{
+
+	dhcp6_sendmessage(arg, dhcp6_sendrelease);
+}
+*/
+
+static void
+dhcp6_startrenew(void *arg)
+{
+	struct interface *ifp;
+	struct dhcp6_state *state;
+
+	ifp = arg;
+	state = D6_STATE(ifp);
+	state->state = DH6S_RENEW;
+	state->start_uptime = uptime();
+	state->RTC = 0;
+	state->IRT = REN_TIMEOUT;
+	state->MRT = REN_MAX_RT;
+	state->MRC = 0;
+
+	if (dhcp6_makemessage(ifp) == -1)
+		logger(ifp->ctx, LOG_ERR,
+		    "%s: dhcp6_makemessage: %m", ifp->name);
+	else
+		dhcp6_sendrenew(ifp);
+}
+
+int
+dhcp6_dadcompleted(const struct interface *ifp)
+{
+	const struct dhcp6_state *state;
+	const struct ipv6_addr *ap;
+
+	state = D6_CSTATE(ifp);
+	TAILQ_FOREACH(ap, &state->addrs, next) {
+		if (ap->flags & IPV6_AF_ADDED &&
+		    !(ap->flags & IPV6_AF_DADCOMPLETED))
+			return 0;
+	}
+	return 1;
+}
+
+static void
+dhcp6_dadcallback(void *arg)
+{
+	struct ipv6_addr *ap = arg;
+	struct interface *ifp;
+	struct dhcp6_state *state;
+	int wascompleted, valid;
+
+	wascompleted = (ap->flags & IPV6_AF_DADCOMPLETED);
+	ap->flags |= IPV6_AF_DADCOMPLETED;
+	if (ap->flags & IPV6_AF_DUPLICATED)
+		/* XXX FIXME
+		 * We should decline the address */
+		logger(ap->iface->ctx, LOG_WARNING, "%s: DAD detected %s",
+		    ap->iface->name, ap->saddr);
+
+	if (!wascompleted) {
+		ifp = ap->iface;
+		state = D6_STATE(ifp);
+		if (state->state == DH6S_BOUND ||
+		    state->state == DH6S_DELEGATED)
+		{
+			struct ipv6_addr *ap2;
+
+			valid = (ap->delegating_iface == NULL);
+			TAILQ_FOREACH(ap2, &state->addrs, next) {
+				if (ap2->flags & IPV6_AF_ADDED &&
+				    !(ap2->flags & IPV6_AF_DADCOMPLETED))
+				{
+					wascompleted = 1;
+					break;
+				}
+			}
+			if (!wascompleted) {
+				logger(ap->iface->ctx, LOG_DEBUG,
+				    "%s: DHCPv6 DAD completed", ifp->name);
+				script_runreason(ifp,
+				    ap->delegating_iface ?
+				    "DELEGATED6" : state->reason);
+				if (valid)
+					dhcpcd_daemonise(ifp->ctx);
+			}
+		}
+	}
+}
+
+static void
+dhcp6_addrequestedaddrs(struct interface *ifp)
+{
+	struct dhcp6_state *state;
+	size_t i;
+	struct if_ia *ia;
+	struct ipv6_addr *a;
+	char iabuf[INET6_ADDRSTRLEN];
+	const char *iap;
+
+	state = D6_STATE(ifp);
+	/* Add any requested prefixes / addresses */
+	for (i = 0; i < ifp->options->ia_len; i++) {
+		ia = &ifp->options->ia[i];
+		if (!((ia->ia_type == D6_OPTION_IA_PD && ia->prefix_len) ||
+		    !IN6_IS_ADDR_UNSPECIFIED(&ia->addr)))
+			continue;
+		a = calloc(1, sizeof(*a));
+		if (a == NULL) {
+			logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
+			return;
+		}
+		a->flags = IPV6_AF_REQUEST;
+		a->iface = ifp;
+		a->dadcallback = dhcp6_dadcallback;
+		memcpy(&a->iaid, &ia->iaid, sizeof(a->iaid));
+		a->ia_type = ia->ia_type;
+		//a->prefix_pltime = 0;
+		//a->prefix_vltime = 0;
+
+		if (ia->ia_type == D6_OPTION_IA_PD) {
+			memcpy(&a->prefix, &ia->addr, sizeof(a->addr));
+			a->prefix_len = ia->prefix_len;
+			iap = inet_ntop(AF_INET6, &a->prefix,
+			    iabuf, sizeof(iabuf));
+		} else {
+			memcpy(&a->addr, &ia->addr, sizeof(a->addr));
+			/*
+			 * RFC 5942 Section 5
+			 * We cannot assume any prefix length, nor tie the
+			 * address to an existing one as it could expire
+			 * before the address.
+			 * As such we just give it a 128 prefix.
+			 */
+			a->prefix_len = 128;
+			ipv6_makeprefix(&a->prefix, &a->addr, a->prefix_len);
+			iap = inet_ntop(AF_INET6, &a->addr,
+			    iabuf, sizeof(iabuf));
+		}
+		snprintf(a->saddr, sizeof(a->saddr),
+		    "%s/%d", iap, a->prefix_len);
+		TAILQ_INSERT_TAIL(&state->addrs, a, next);
+	}
+}
+
+static void
+dhcp6_startdiscover(void *arg)
+{
+	struct interface *ifp;
+	struct dhcp6_state *state;
+
+	rpc_signal_status("Discover6");
+	ifp = arg;
+	dhcp6_delete_delegates(ifp);
+	logger(ifp->ctx, LOG_INFO, "%s: soliciting a DHCPv6 lease", ifp->name);
+	state = D6_STATE(ifp);
+	state->state = DH6S_DISCOVER;
+	state->start_uptime = uptime();
+	state->RTC = 0;
+	state->IMD = SOL_MAX_DELAY;
+	state->IRT = SOL_TIMEOUT;
+	state->MRT = state->sol_max_rt;
+	state->MRC = 0;
+
+	eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
+	free(state->new);
+	state->new = NULL;
+	state->new_len = 0;
+
+	dhcp6_freedrop_addrs(ifp, 0, NULL);
+	unlink(state->leasefile);
+
+	dhcp6_addrequestedaddrs(ifp);
+
+	if (dhcp6_makemessage(ifp) == -1)
+		logger(ifp->ctx, LOG_ERR,
+		    "%s: dhcp6_makemessage: %m", ifp->name);
+	else
+		dhcp6_senddiscover(ifp);
+}
+
+static void
+dhcp6_failconfirm(void *arg)
+{
+	struct interface *ifp;
+
+	ifp = arg;
+	logger(ifp->ctx, LOG_ERR,
+	    "%s: failed to confirm prior address", ifp->name);
+	/* Section 18.1.2 says that we SHOULD use the last known
+	 * IP address(s) and lifetimes if we didn't get a reply.
+	 * I disagree with this. */
+	dhcp6_startdiscover(ifp);
+}
+
+static void
+dhcp6_failrequest(void *arg)
+{
+	struct interface *ifp;
+
+	ifp = arg;
+	logger(ifp->ctx, LOG_ERR, "%s: failed to request address", ifp->name);
+	/* Section 18.1.1 says that client local policy dictates
+	 * what happens if a REQUEST fails.
+	 * Of the possible scenarios listed, moving back to the
+	 * DISCOVER phase makes more sense for us. */
+	dhcp6_startdiscover(ifp);
+}
+
+static void
+dhcp6_failrebind(void *arg)
+{
+	struct interface *ifp;
+
+	ifp = arg;
+	logger(ifp->ctx, LOG_ERR,
+	    "%s: failed to rebind prior delegation", ifp->name);
+	dhcp6_delete_delegates(ifp);
+	/* Section 18.1.2 says that we SHOULD use the last known
+	 * IP address(s) and lifetimes if we didn't get a reply.
+	 * I disagree with this. */
+	dhcp6_startdiscover(ifp);
+}
+
+
+static int
+dhcp6_hasprefixdelegation(struct interface *ifp)
+{
+	size_t i;
+	uint16_t t;
+
+	if (ifp->options->options & DHCPCD_NOPFXDLG)
+		return 0;
+
+	t = 0;
+	for (i = 0; i < ifp->options->ia_len; i++) {
+		if (t && t != ifp->options->ia[i].ia_type) {
+			if (t == D6_OPTION_IA_PD ||
+			    ifp->options->ia[i].ia_type == D6_OPTION_IA_PD)
+				return 2;
+		}
+		t = ifp->options->ia[i].ia_type;
+	}
+	return t == D6_OPTION_IA_PD ? 1 : 0;
+}
+
+static void
+dhcp6_startrebind(void *arg)
+{
+	struct interface *ifp;
+	struct dhcp6_state *state;
+	int pd;
+
+	rpc_signal_status("Rebind6");
+	ifp = arg;
+	eloop_timeout_delete(ifp->ctx->eloop, dhcp6_sendrenew, ifp);
+	state = D6_STATE(ifp);
+	if (state->state == DH6S_RENEW)
+		logger(ifp->ctx, LOG_WARNING,
+		    "%s: failed to renew DHCPv6, rebinding", ifp->name);
+	else
+		logger(ifp->ctx, LOG_INFO,
+		    "%s: rebinding prior DHCPv6 lease", ifp->name);
+	state->state = DH6S_REBIND;
+	state->RTC = 0;
+	state->MRC = 0;
+
+	/* RFC 3633 section 12.1 */
+	pd = dhcp6_hasprefixdelegation(ifp);
+	if (pd) {
+		state->IMD = CNF_MAX_DELAY;
+		state->IRT = CNF_TIMEOUT;
+		state->MRT = CNF_MAX_RT;
+	} else {
+		state->IRT = REB_TIMEOUT;
+		state->MRT = REB_MAX_RT;
+	}
+
+	if (dhcp6_makemessage(ifp) == -1)
+		logger(ifp->ctx, LOG_ERR,
+		    "%s: dhcp6_makemessage: %m", ifp->name);
+	else
+		dhcp6_sendrebind(ifp);
+
+	/* RFC 3633 section 12.1 */
+	if (pd)
+		eloop_timeout_add_sec(ifp->ctx->eloop,
+		    CNF_MAX_RD, dhcp6_failrebind, ifp);
+}
+
+
+static void
+dhcp6_startrequest(struct interface *ifp)
+{
+	struct dhcp6_state *state;
+
+	rpc_signal_status("Request6");
+	eloop_timeout_delete(ifp->ctx->eloop, dhcp6_senddiscover, ifp);
+	state = D6_STATE(ifp);
+	state->state = DH6S_REQUEST;
+	state->RTC = 0;
+	state->IRT = REQ_TIMEOUT;
+	state->MRT = REQ_MAX_RT;
+	state->MRC = REQ_MAX_RC;
+	state->MRCcallback = dhcp6_failrequest;
+
+	if (dhcp6_makemessage(ifp) == -1) {
+		logger(ifp->ctx, LOG_ERR,
+		    "%s: dhcp6_makemessage: %m", ifp->name);
+		return;
+	}
+
+	dhcp6_sendrequest(ifp);
+}
+
+static void
+dhcp6_startconfirm(struct interface *ifp)
+{
+	struct dhcp6_state *state;
+
+	rpc_signal_status("Confirm6");
+	state = D6_STATE(ifp);
+	state->state = DH6S_CONFIRM;
+	state->start_uptime = uptime();
+	state->RTC = 0;
+	state->IMD = CNF_MAX_DELAY;
+	state->IRT = CNF_TIMEOUT;
+	state->MRT = CNF_MAX_RT;
+	state->MRC = 0;
+
+	logger(ifp->ctx, LOG_INFO,
+	    "%s: confirming prior DHCPv6 lease", ifp->name);
+	if (dhcp6_makemessage(ifp) == -1) {
+		logger(ifp->ctx, LOG_ERR,
+		    "%s: dhcp6_makemessage: %m", ifp->name);
+		return;
+	}
+	dhcp6_sendconfirm(ifp);
+	eloop_timeout_add_sec(ifp->ctx->eloop,
+	    CNF_MAX_RD, dhcp6_failconfirm, ifp);
+}
+
+static void
+dhcp6_startinform(void *arg)
+{
+	struct interface *ifp;
+	struct dhcp6_state *state;
+
+	rpc_signal_status("Inform6");
+	ifp = arg;
+	state = D6_STATE(ifp);
+	if (state->new == NULL || ifp->options->options & DHCPCD_DEBUG)
+		logger(ifp->ctx, LOG_INFO,
+		    "%s: requesting DHCPv6 information", ifp->name);
+	state->state = DH6S_INFORM;
+	state->start_uptime = uptime();
+	state->RTC = 0;
+	state->IMD = INF_MAX_DELAY;
+	state->IRT = INF_TIMEOUT;
+	state->MRT = state->inf_max_rt;
+	state->MRC = 0;
+
+	if (dhcp6_makemessage(ifp) == -1)
+		logger(ifp->ctx, LOG_ERR,
+		    "%s: dhcp6_makemessage: %m", ifp->name);
+	else
+		dhcp6_sendinform(ifp);
+}
+
+static void
+dhcp6_startexpire(void *arg)
+{
+	struct interface *ifp;
+
+	rpc_signal_status("Expire6");
+	ifp = arg;
+	eloop_timeout_delete(ifp->ctx->eloop, dhcp6_sendrebind, ifp);
+
+	logger(ifp->ctx, LOG_ERR, "%s: DHCPv6 lease expired", ifp->name);
+	dhcp6_freedrop_addrs(ifp, 1, NULL);
+	dhcp6_delete_delegates(ifp);
+	script_runreason(ifp, "EXPIRE6");
+	if (ipv6nd_hasradhcp(ifp) || dhcp6_hasprefixdelegation(ifp))
+		dhcp6_startdiscover(ifp);
+	else
+		logger(ifp->ctx, LOG_WARNING,
+		    "%s: no advertising IPv6 router wants DHCP", ifp->name);
+}
+
+static void
+dhcp6_startrelease(struct interface *ifp)
+{
+	struct dhcp6_state *state;
+
+	state = D6_STATE(ifp);
+	if (state->state != DH6S_BOUND)
+		return;
+
+	rpc_signal_status("Release6");
+	state->state = DH6S_RELEASE;
+	state->start_uptime = uptime();
+	state->RTC = 0;
+	state->IRT = REL_TIMEOUT;
+	state->MRT = 0;
+	state->MRC = REL_MAX_RC;
+	//state->MRCcallback = dhcp6_failrelease;
+	state->MRCcallback = NULL;
+
+	if (dhcp6_makemessage(ifp) == -1)
+		logger(ifp->ctx, LOG_ERR,
+		    "%s: dhcp6_makemessage: %m", ifp->name);
+	else
+		/* XXX: We should loop a few times
+		 * Luckily RFC3315 section 18.1.6 says this is optional */
+		//dhcp6_sendrelease(ifp);
+		dhcp6_sendmessage(ifp, NULL);
+}
+
+static int
+dhcp6_checkstatusok(const struct interface *ifp,
+    const struct dhcp6_message *m, const uint8_t *p, size_t len)
+{
+	const struct dhcp6_option *o;
+	uint16_t code;
+	char *status;
+
+	if (p)
+		o = dhcp6_findoption(D6_OPTION_STATUS_CODE, p, len);
+	else
+		o = dhcp6_getmoption(D6_OPTION_STATUS_CODE, m, len);
+	if (o == NULL) {
+		//logger(ifp->ctx, LOG_DEBUG, "%s: no status", ifp->name);
+		return 0;
+	}
+
+	len = ntohs(o->len);
+	if (len < sizeof(code)) {
+		logger(ifp->ctx, LOG_ERR, "%s: status truncated", ifp->name);
+		return -1;
+	}
+
+	p = D6_COPTION_DATA(o);
+	memcpy(&code, p, sizeof(code));
+	code = ntohs(code);
+	if (code == D6_STATUS_OK)
+		return 1;
+
+	len -= sizeof(code);
+
+	if (len == 0) {
+		if (code < sizeof(dhcp6_statuses) / sizeof(char *)) {
+			p = (const uint8_t *)dhcp6_statuses[code];
+			len = strlen((const char *)p);
+		} else
+			p = NULL;
+	} else
+		p += sizeof(code);
+
+	status = malloc(len + 1);
+	if (status == NULL) {
+		logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
+		return -1;
+	}
+	if (p)
+		memcpy(status, p, len);
+	status[len] = '\0';
+	logger(ifp->ctx, LOG_ERR, "%s: DHCPv6 REPLY: %s", ifp->name, status);
+	free(status);
+	return -1;
+}
+
+static struct ipv6_addr *
+dhcp6_iffindaddr(struct interface *ifp, const struct in6_addr *addr,
+    short flags)
+{
+	struct dhcp6_state *state;
+	struct ipv6_addr *ap;
+
+	state = D6_STATE(ifp);
+	if (state) {
+		TAILQ_FOREACH(ap, &state->addrs, next) {
+			if (addr == NULL) {
+				if ((ap->flags &
+				    (IPV6_AF_ADDED | IPV6_AF_DADCOMPLETED)) ==
+				    (IPV6_AF_ADDED | IPV6_AF_DADCOMPLETED))
+					return ap;
+			} else if (ap->prefix_vltime &&
+			    IN6_ARE_ADDR_EQUAL(&ap->addr, addr) &&
+			    (!flags || ap->flags & flags))
+				return ap;
+		}
+	}
+	return NULL;
+}
+
+struct ipv6_addr *
+dhcp6_findaddr(struct dhcpcd_ctx *ctx, const struct in6_addr *addr,
+    short flags)
+{
+	struct interface *ifp;
+	struct ipv6_addr *ap;
+
+	TAILQ_FOREACH(ifp, ctx->ifaces, next) {
+		ap = dhcp6_iffindaddr(ifp, addr, flags);
+		if (ap)
+			return ap;
+	}
+	return NULL;
+}
+
+static int
+dhcp6_findna(struct interface *ifp, uint16_t ot, const uint8_t *iaid,
+    const uint8_t *d, size_t l, const struct timespec *acquired)
+{
+	struct dhcp6_state *state;
+	const struct dhcp6_option *o;
+	struct ipv6_addr *a;
+	char iabuf[INET6_ADDRSTRLEN];
+	const char *ia;
+	int i;
+	uint32_t u32;
+	size_t off;
+	const struct dhcp6_ia_addr *iap;
+
+	i = 0;
+	state = D6_STATE(ifp);
+	while ((o = dhcp6_findoption(D6_OPTION_IA_ADDR, d, l))) {
+		off = (size_t)((const uint8_t *)o - d);
+		l -= off;
+		d += off;
+		u32 = ntohs(o->len);
+		l -= sizeof(*o) + u32;
+		d += sizeof(*o) + u32;
+		if (u32 < 24) {
+			errno = EINVAL;
+			logger(ifp->ctx, LOG_ERR,
+			    "%s: IA Address option truncated", ifp->name);
+			continue;
+		}
+		iap = (const struct dhcp6_ia_addr *)D6_COPTION_DATA(o);
+		a = dhcp6_iffindaddr(ifp, &iap->addr, 0);
+		if (a == NULL) {
+			a = calloc(1, sizeof(*a));
+			if (a == NULL) {
+				logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
+				break;
+			}
+			a->iface = ifp;
+			a->flags = IPV6_AF_NEW | IPV6_AF_ONLINK;
+			a->dadcallback = dhcp6_dadcallback;
+			a->ia_type = ot;
+			memcpy(a->iaid, iaid, sizeof(a->iaid));
+			a->addr = iap->addr;
+			a->created = *acquired;
+
+			/*
+			 * RFC 5942 Section 5
+			 * We cannot assume any prefix length, nor tie the
+			 * address to an existing one as it could expire
+			 * before the address.
+			 * As such we just give it a 128 prefix.
+			 */
+			a->prefix_len = 128;
+			ipv6_makeprefix(&a->prefix, &a->addr, a->prefix_len);
+			ia = inet_ntop(AF_INET6, &a->addr,
+			    iabuf, sizeof(iabuf));
+			snprintf(a->saddr, sizeof(a->saddr),
+			    "%s/%d", ia, a->prefix_len);
+
+			TAILQ_INSERT_TAIL(&state->addrs, a, next);
+		} else {
+			if (!(a->flags & IPV6_AF_ONLINK))
+				a->flags |= IPV6_AF_ONLINK | IPV6_AF_NEW;
+			a->flags &= ~IPV6_AF_STALE;
+		}
+		a->acquired = *acquired;
+		a->prefix_pltime = ntohl(iap->pltime);
+		u32 = ntohl(iap->vltime);
+		if (a->prefix_vltime != u32) {
+			a->flags |= IPV6_AF_NEW;
+			a->prefix_vltime = u32;
+		}
+		if (a->prefix_pltime && a->prefix_pltime < state->lowpl)
+		    state->lowpl = a->prefix_pltime;
+		if (a->prefix_vltime && a->prefix_vltime > state->expire)
+		    state->expire = a->prefix_vltime;
+		i++;
+	}
+	return i;
+}
+
+static int
+dhcp6_findpd(struct interface *ifp, const uint8_t *iaid,
+    const uint8_t *d, size_t l, const struct timespec *acquired)
+{
+	struct dhcp6_state *state;
+	const struct dhcp6_option *o, *ex;
+	const uint8_t *p, *op;
+	struct ipv6_addr *a;
+	char iabuf[INET6_ADDRSTRLEN];
+	const char *ia;
+	int i;
+	uint8_t u8, *pw;
+	size_t off;
+	uint16_t ol;
+	const struct dhcp6_pd_addr *pdp;
+
+	i = 0;
+	state = D6_STATE(ifp);
+	while ((o = dhcp6_findoption(D6_OPTION_IAPREFIX, d, l))) {
+		off = (size_t)((const uint8_t *)o - d);
+		l -= off;
+		d += off;
+		ol = ntohs(o->len);
+		l -= sizeof(*o) + ol;
+		d += sizeof(*o) + ol;
+		if (ol < sizeof(*pdp)) {
+			errno = EINVAL;
+			logger(ifp->ctx, LOG_ERR,
+			    "%s: IA Prefix option truncated", ifp->name);
+			continue;
+		}
+
+		pdp = (const struct dhcp6_pd_addr *)D6_COPTION_DATA(o);
+		TAILQ_FOREACH(a, &state->addrs, next) {
+			if (IN6_ARE_ADDR_EQUAL(&a->prefix, &pdp->prefix))
+				break;
+		}
+		if (a == NULL) {
+			a = calloc(1, sizeof(*a));
+			if (a == NULL) {
+				logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
+				break;
+			}
+			a->iface = ifp;
+			a->flags = IPV6_AF_NEW | IPV6_AF_DELEGATEDPFX;
+			a->created = *acquired;
+			a->dadcallback = dhcp6_dadcallback;
+			a->ia_type = D6_OPTION_IA_PD;
+			memcpy(a->iaid, iaid, sizeof(a->iaid));
+			a->prefix = pdp->prefix;
+			a->prefix_len = pdp->prefix_len;
+			ia = inet_ntop(AF_INET6, &a->prefix,
+			    iabuf, sizeof(iabuf));
+			snprintf(a->saddr, sizeof(a->saddr),
+			    "%s/%d", ia, a->prefix_len);
+			TAILQ_INSERT_TAIL(&state->addrs, a, next);
+		} else {
+			if (!(a->flags & IPV6_AF_DELEGATEDPFX))
+				a->flags |= IPV6_AF_NEW | IPV6_AF_DELEGATEDPFX;
+			a->flags &= ~(IPV6_AF_STALE | IPV6_AF_REQUEST);
+			if (a->prefix_vltime != ntohl(pdp->vltime))
+				a->flags |= IPV6_AF_NEW;
+		}
+
+		a->acquired = *acquired;
+		a->prefix_pltime = ntohl(pdp->pltime);
+		a->prefix_vltime = ntohl(pdp->vltime);
+
+		if (a->prefix_pltime && a->prefix_pltime < state->lowpl)
+			state->lowpl = a->prefix_pltime;
+		if (a->prefix_vltime && a->prefix_vltime > state->expire)
+			state->expire = a->prefix_vltime;
+		i++;
+
+		p = D6_COPTION_DATA(o) + sizeof(pdp);
+		ol = (uint16_t)(ol - sizeof(pdp));
+		ex = dhcp6_findoption(D6_OPTION_PD_EXCLUDE, p, ol);
+		a->prefix_exclude_len = 0;
+		memset(&a->prefix_exclude, 0, sizeof(a->prefix_exclude));
+#if 0
+		if (ex == NULL) {
+			struct dhcp6_option *w;
+			uint8_t *wp;
+
+			w = calloc(1, 128);
+			w->len = htons(2);
+			wp = D6_OPTION_DATA(w);
+			*wp++ = 64;
+			*wp++ = 0x78;
+			ex = w;
+		}
+#endif
+		if (ex == NULL)
+			continue;
+		ol = ntohs(ex->len);
+		if (ol < 2) {
+			logger(ifp->ctx, LOG_ERR,
+			    "%s: truncated PD Exclude", ifp->name);
+			continue;
+		}
+		op = D6_COPTION_DATA(ex);
+		a->prefix_exclude_len = *op++;
+		ol--;
+		if (((a->prefix_exclude_len - a->prefix_len - 1) / NBBY) + 1
+		    != ol)
+		{
+			logger(ifp->ctx, LOG_ERR,
+			    "%s: PD Exclude length mismatch", ifp->name);
+			a->prefix_exclude_len = 0;
+			continue;
+		}
+		u8 = a->prefix_len % NBBY;
+		memcpy(&a->prefix_exclude, &a->prefix,
+		    sizeof(a->prefix_exclude));
+		if (u8)
+			ol--;
+		pw = a->prefix_exclude.s6_addr +
+		    (a->prefix_exclude_len / NBBY) - 1;
+		while (ol-- > 0)
+			*pw-- = *op++;
+		if (u8)
+			*pw = (uint8_t)(*pw | (*op >> u8));
+	}
+	return i;
+}
+
+static int
+dhcp6_findia(struct interface *ifp, const struct dhcp6_message *m, size_t l,
+    const char *sfrom, const struct timespec *acquired)
+{
+	struct dhcp6_state *state;
+	const struct if_options *ifo;
+	const struct dhcp6_option *o;
+	const uint8_t *p;
+	int i, e;
+	size_t j;
+	uint32_t u32, renew, rebind;
+	uint16_t code, ol;
+	uint8_t iaid[4];
+	char buf[sizeof(iaid) * 3];
+	struct ipv6_addr *ap, *nap;
+
+	if (l < sizeof(*m)) {
+		/* Should be impossible with guards at packet in
+		 * and reading leases */
+		errno = EINVAL;
+		return -1;
+	}
+
+	ifo = ifp->options;
+	i = e = 0;
+	state = D6_STATE(ifp);
+	TAILQ_FOREACH(ap, &state->addrs, next) {
+		ap->flags |= IPV6_AF_STALE;
+	}
+	l -= sizeof(*m);
+	for (o = D6_CFIRST_OPTION(m); l > sizeof(*o); o = D6_CNEXT_OPTION(o)) {
+		ol = ntohs(o->len);
+		if (sizeof(*o) + ol > l) {
+			errno = EINVAL;
+			logger(ifp->ctx, LOG_ERR,
+			    "%s: option overflow", ifp->name);
+			break;
+		}
+		l -= sizeof(*o) + ol;
+
+		code = ntohs(o->code);
+		switch(code) {
+		case D6_OPTION_IA_TA:
+			u32 = 4;
+			break;
+		case D6_OPTION_IA_NA:
+		case D6_OPTION_IA_PD:
+			u32 = 12;
+			break;
+		default:
+			continue;
+		}
+		if (ol < u32) {
+			errno = EINVAL;
+			logger(ifp->ctx, LOG_ERR,
+			    "%s: IA option truncated", ifp->name);
+			continue;
+		}
+
+		p = D6_COPTION_DATA(o);
+		memcpy(iaid, p, sizeof(iaid));
+		p += sizeof(iaid);
+		ol = (uint16_t)(ol - sizeof(iaid));
+
+		for (j = 0; j < ifo->ia_len; j++) {
+			if (memcmp(&ifo->ia[j].iaid, iaid, sizeof(iaid)) == 0)
+				break;
+		}
+		if (j == ifo->ia_len &&
+		    !(ifo->ia_len == 0 && ifp->ctx->options & DHCPCD_DUMPLEASE))
+		{
+			logger(ifp->ctx, LOG_DEBUG,
+			    "%s: ignoring unrequested IAID %s",
+			    ifp->name,
+			    hwaddr_ntoa(iaid, sizeof(iaid), buf, sizeof(buf)));
+			continue;
+		}
+		if ( j < ifo->ia_len && ifo->ia[j].ia_type != code) {
+			logger(ifp->ctx, LOG_ERR,
+			    "%s: IAID %s: option type mismatch",
+			    ifp->name,
+			    hwaddr_ntoa(iaid, sizeof(iaid), buf, sizeof(buf)));
+			continue;
+		}
+
+		if (code != D6_OPTION_IA_TA) {
+			memcpy(&u32, p, sizeof(u32));
+			renew = ntohl(u32);
+			p += sizeof(u32);
+			ol = (uint16_t)(ol - sizeof(u32));
+			memcpy(&u32, p, sizeof(u32));
+			rebind = ntohl(u32);
+			p += sizeof(u32);
+			ol = (uint16_t)(ol - sizeof(u32));
+		} else
+			renew = rebind = 0; /* appease gcc */
+		if (dhcp6_checkstatusok(ifp, NULL, p, ol) == -1) {
+			e = 1;
+			continue;
+		}
+		if (code == D6_OPTION_IA_PD) {
+			if (!(ifo->options & DHCPCD_NOPFXDLG) &&
+			    dhcp6_findpd(ifp, iaid, p, ol, acquired) == 0)
+			{
+				logger(ifp->ctx, LOG_WARNING,
+				    "%s: %s: DHCPv6 REPLY missing Prefix",
+				    ifp->name, sfrom);
+				continue;
+			}
+		} else if (!(ifo->options & DHCPCD_PFXDLGONLY)) {
+			if (dhcp6_findna(ifp, code, iaid, p, ol, acquired) == 0)
+			{
+				logger(ifp->ctx, LOG_WARNING,
+				    "%s: %s: DHCPv6 REPLY missing IA Address",
+				    ifp->name, sfrom);
+				continue;
+			}
+		}
+		if (code != D6_OPTION_IA_TA) {
+			if (renew > rebind && rebind > 0) {
+				if (sfrom)
+				    logger(ifp->ctx, LOG_WARNING,
+					"%s: T1 (%d) > T2 (%d) from %s",
+					ifp->name, renew, rebind, sfrom);
+				renew = 0;
+				rebind = 0;
+			}
+			if (renew != 0 &&
+			    (renew < state->renew || state->renew == 0))
+				state->renew = renew;
+			if (rebind != 0 &&
+			    (rebind < state->rebind || state->rebind == 0))
+				state->rebind = rebind;
+		}
+		i++;
+	}
+	TAILQ_FOREACH_SAFE(ap, &state->addrs, next, nap) {
+		if (ap->flags & IPV6_AF_STALE) {
+			eloop_q_timeout_delete(ifp->ctx->eloop, 0, NULL, ap);
+			if (ap->flags & IPV6_AF_REQUEST) {
+				ap->prefix_vltime = ap->prefix_pltime = 0;
+			} else {
+				TAILQ_REMOVE(&state->addrs, ap, next);
+				free(ap);
+			}
+		}
+	}
+	if (i == 0 && e)
+		return -1;
+	return i;
+}
+
+static int
+dhcp6_validatelease(struct interface *ifp,
+    const struct dhcp6_message *m, size_t len,
+    const char *sfrom, const struct timespec *acquired)
+{
+	struct dhcp6_state *state;
+	int nia;
+	struct timespec aq;
+
+	if (len <= sizeof(*m)) {
+		logger(ifp->ctx, LOG_ERR,
+		    "%s: DHCPv6 lease truncated", ifp->name);
+		return -1;
+	}
+
+	state = D6_STATE(ifp);
+	if (dhcp6_checkstatusok(ifp, m, NULL, len) == -1)
+		return -1;
+
+	state->renew = state->rebind = state->expire = 0;
+	state->lowpl = ND6_INFINITE_LIFETIME;
+	if (!acquired) {
+		get_monotonic(&aq);
+		acquired = &aq;
+	}
+	nia = dhcp6_findia(ifp, m, len, sfrom, acquired);
+	if (nia == 0) {
+		logger(ifp->ctx, LOG_ERR,
+		    "%s: no useable IA found in lease", ifp->name);
+		return -1;
+	}
+	return nia;
+}
+
+static ssize_t
+dhcp6_writelease(const struct interface *ifp)
+{
+	const struct dhcp6_state *state;
+	int fd;
+	ssize_t bytes;
+
+	state = D6_CSTATE(ifp);
+	logger(ifp->ctx, LOG_DEBUG,
+	    "%s: writing lease `%s'", ifp->name, state->leasefile);
+
+	fd = open(state->leasefile, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+	if (fd == -1) {
+		logger(ifp->ctx, LOG_ERR, "%s: dhcp6_writelease: %m", ifp->name);
+		return -1;
+	}
+	bytes = write(fd, state->new, state->new_len);
+	close(fd);
+	return bytes;
+}
+
+static int
+dhcp6_readlease(struct interface *ifp, int validate)
+{
+	struct dhcp6_state *state;
+	struct stat st;
+	int fd;
+	ssize_t bytes;
+	const struct dhcp6_option *o;
+	struct timespec acquired;
+	time_t now;
+	int retval;
+
+	state = D6_STATE(ifp);
+	if (stat(state->leasefile, &st) == -1)
+		return -1;
+	logger(ifp->ctx, LOG_DEBUG, "%s: reading lease `%s'",
+	    ifp->name, state->leasefile);
+	if (st.st_size > UINT32_MAX) {
+		errno = E2BIG;
+		return -1;
+	}
+	if ((fd = open(state->leasefile, O_RDONLY)) == -1)
+		return -1;
+	if ((state->new = malloc((size_t)st.st_size)) == NULL)
+		return -1;
+	retval = -1;
+	state->new_len = (size_t)st.st_size;
+	bytes = read(fd, state->new, state->new_len);
+	close(fd);
+	if (bytes != (ssize_t)state->new_len)
+		goto ex;
+
+	/* If not validating IA's and if they have expired,
+	 * skip to the auth check. */
+	if (!validate) {
+		fd = 0;
+		goto auth;
+	}
+
+	if ((now = time(NULL)) == -1)
+		goto ex;
+
+	get_monotonic(&acquired);
+	acquired.tv_sec -= now - st.st_mtime;
+
+	/* Check to see if the lease is still valid */
+	fd = dhcp6_validatelease(ifp, state->new, state->new_len, NULL,
+	    &acquired);
+	if (fd == -1)
+		goto ex;
+
+	if (!(ifp->ctx->options & DHCPCD_DUMPLEASE) &&
+	    state->expire != ND6_INFINITE_LIFETIME)
+	{
+		if ((time_t)state->expire < now - st.st_mtime) {
+			logger(ifp->ctx,
+			    LOG_DEBUG,"%s: discarding expired lease",
+			    ifp->name);
+			retval = 0;
+			goto ex;
+		}
+	}
+
+auth:
+
+	retval = 0;
+	/* Authenticate the message */
+	o = dhcp6_getmoption(D6_OPTION_AUTH, state->new, state->new_len);
+	if (o) {
+		if (dhcp_auth_validate(&state->auth, &ifp->options->auth,
+		    (uint8_t *)state->new, state->new_len, 6, state->new->type,
+		    D6_COPTION_DATA(o), ntohs(o->len)) == NULL)
+		{
+			logger(ifp->ctx, LOG_DEBUG,
+			    "%s: dhcp_auth_validate: %m", ifp->name);
+			logger(ifp->ctx, LOG_ERR,
+			    "%s: authentication failed", ifp->name);
+			goto ex;
+		}
+		if (state->auth.token)
+			logger(ifp->ctx, LOG_DEBUG,
+			    "%s: validated using 0x%08" PRIu32,
+			    ifp->name, state->auth.token->secretid);
+		else
+			logger(ifp->ctx, LOG_DEBUG,
+			    "%s: accepted reconfigure key", ifp->name);
+	} else if (ifp->options->auth.options & DHCPCD_AUTH_REQUIRE) {
+		logger(ifp->ctx, LOG_ERR,
+		    "%s: authentication now required", ifp->name);
+		goto ex;
+	}
+
+	return fd;
+
+ex:
+	dhcp6_freedrop_addrs(ifp, 0, NULL);
+	free(state->new);
+	state->new = NULL;
+	state->new_len = 0;
+	if (!(ifp->ctx->options & DHCPCD_DUMPLEASE))
+		unlink(state->leasefile);
+	return retval;
+}
+
+static void
+dhcp6_startinit(struct interface *ifp)
+{
+	struct dhcp6_state *state;
+	int r;
+	uint8_t has_ta, has_non_ta;
+	size_t i;
+
+	state = D6_STATE(ifp);
+	state->state = DH6S_INIT;
+	state->expire = ND6_INFINITE_LIFETIME;
+	state->lowpl = ND6_INFINITE_LIFETIME;
+
+	dhcp6_addrequestedaddrs(ifp);
+	has_ta = has_non_ta = 0;
+	for (i = 0; i < ifp->options->ia_len; i++) {
+		switch (ifp->options->ia[i].ia_type) {
+		case D6_OPTION_IA_TA:
+			has_ta = 1;
+			break;
+		default:
+			has_non_ta = 1;
+		}
+	}
+
+	if (!(ifp->ctx->options & DHCPCD_TEST) &&
+	    !(has_ta && !has_non_ta) &&
+	    ifp->options->reboot != 0)
+	{
+		r = dhcp6_readlease(ifp, 1);
+		if (r == -1) {
+			if (errno != ENOENT)
+				logger(ifp->ctx, LOG_ERR,
+				    "%s: dhcp6_readlease: %s: %m",
+				    ifp->name, state->leasefile);
+		} else if (r != 0) {
+			/* RFC 3633 section 12.1 */
+			if (dhcp6_hasprefixdelegation(ifp))
+				dhcp6_startrebind(ifp);
+			else
+				dhcp6_startconfirm(ifp);
+			return;
+		}
+	}
+	dhcp6_startdiscover(ifp);
+}
+
+static struct ipv6_addr *
+dhcp6_ifdelegateaddr(struct interface *ifp, struct ipv6_addr *prefix,
+    const struct if_sla *sla, struct if_ia *ia, struct interface *ifs)
+{
+	struct dhcp6_state *state;
+	struct in6_addr addr;
+	struct ipv6_addr *a, *ap, *apn;
+	char sabuf[INET6_ADDRSTRLEN];
+	const char *sa;
+	int pfxlen;
+
+	/* RFC6603 Section 4.2 */
+	if (strcmp(ifp->name, ifs->name) == 0) {
+		if (prefix->prefix_exclude_len == 0) {
+			/* Don't spam the log automatically */
+			if (sla)
+				logger(ifp->ctx, LOG_WARNING,
+				    "%s: DHCPv6 server does not support "
+				    "OPTION_PD_EXCLUDE",
+				    ifp->name);
+			return NULL;
+		}
+		pfxlen = prefix->prefix_exclude_len;
+		memcpy(&addr, &prefix->prefix_exclude, sizeof(addr));
+	} else if ((pfxlen = dhcp6_delegateaddr(&addr, ifp, prefix,
+	    sla, ia)) == -1)
+		return NULL;
+
+
+	a = calloc(1, sizeof(*a));
+	if (a == NULL) {
+		logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
+		return NULL;
+	}
+	a->iface = ifp;
+	a->flags = IPV6_AF_NEW | IPV6_AF_ONLINK;
+	a->dadcallback = dhcp6_dadcallback;
+	a->delegating_iface = ifs;
+	memcpy(&a->iaid, &prefix->iaid, sizeof(a->iaid));
+	a->created = a->acquired = prefix->acquired;
+	a->prefix_pltime = prefix->prefix_pltime;
+	a->prefix_vltime = prefix->prefix_vltime;
+	a->prefix = addr;
+	a->prefix_len = (uint8_t)pfxlen;
+
+	/* Wang a 1 at the end as the prefix could be >64
+	 * making SLAAC impossible. */
+	a->addr = a->prefix;
+	a->addr.s6_addr[sizeof(a->addr.s6_addr) - 1] =
+	    (uint8_t)(a->addr.s6_addr[sizeof(a->addr.s6_addr) - 1] + 1);
+
+	state = D6_STATE(ifp);
+	/* Remove any exiting address */
+	TAILQ_FOREACH_SAFE(ap, &state->addrs, next, apn) {
+		if (IN6_ARE_ADDR_EQUAL(&ap->addr, &a->addr)) {
+			TAILQ_REMOVE(&state->addrs, ap, next);
+			/* Keep our flags */
+			a->flags |= ap->flags;
+			a->flags &= ~IPV6_AF_NEW;
+			a->created = ap->created;
+			ipv6_freeaddr(ap);
+		}
+	}
+
+	sa = inet_ntop(AF_INET6, &a->addr, sabuf, sizeof(sabuf));
+	snprintf(a->saddr, sizeof(a->saddr), "%s/%d", sa, a->prefix_len);
+	TAILQ_INSERT_TAIL(&state->addrs, a, next);
+	return a;
+}
+
+static void
+dhcp6_script_try_run(struct interface *ifp, int delegated)
+{
+	struct dhcp6_state *state;
+	struct ipv6_addr *ap;
+	int completed;
+
+	state = D6_STATE(ifp);
+	completed = 1;
+	/* If all addresses have completed DAD run the script */
+	TAILQ_FOREACH(ap, &state->addrs, next) {
+		if (!(ap->flags & IPV6_AF_ADDED))
+			continue;
+		if (ap->flags & IPV6_AF_ONLINK) {
+			if (!(ap->flags & IPV6_AF_DADCOMPLETED) &&
+			    ipv6_iffindaddr(ap->iface, &ap->addr))
+				ap->flags |= IPV6_AF_DADCOMPLETED;
+			if ((ap->flags & IPV6_AF_DADCOMPLETED) == 0 &&
+			    ((delegated && ap->delegating_iface) ||
+			    (!delegated && !ap->delegating_iface)))
+			{
+				completed = 0;
+				break;
+			}
+		}
+	}
+	if (completed) {
+		script_runreason(ifp, delegated ? "DELEGATED6" : state->reason);
+		if (!delegated)
+			dhcpcd_daemonise(ifp->ctx);
+	} else
+		logger(ifp->ctx, LOG_DEBUG,
+		    "%s: waiting for DHCPv6 DAD to complete", ifp->name);
+}
+
+static void
+dhcp6_delegate_prefix(struct interface *ifp)
+{
+	struct if_options *ifo;
+	struct dhcp6_state *state, *ifd_state;
+	struct ipv6_addr *ap;
+	size_t i, j, k;
+	struct if_ia *ia;
+	struct if_sla *sla;
+	struct interface *ifd;
+	uint8_t carrier_warned, abrt;
+
+	ifo = ifp->options;
+	state = D6_STATE(ifp);
+
+	/* Try to load configured interfaces for delegation that do not exist */
+	for (i = 0; i < ifo->ia_len; i++) {
+		ia = &ifo->ia[i];
+		for (j = 0; j < ia->sla_len; j++) {
+			sla = &ia->sla[j];
+			for (k = 0; k < i; j++)
+				if (strcmp(sla->ifname, ia->sla[j].ifname) == 0)
+					break;
+			if (j >= i &&
+			    if_find(ifp->ctx->ifaces, sla->ifname) == NULL)
+			{
+				logger(ifp->ctx, LOG_INFO,
+				    "%s: loading for delegation", sla->ifname);
+				if (dhcpcd_handleinterface(ifp->ctx, 2,
+				    sla->ifname) == -1)
+					logger(ifp->ctx, LOG_ERR,
+					    "%s: interface does not exist"
+					    " for delegation",
+					    sla->ifname);
+			}
+		}
+	}
+
+	TAILQ_FOREACH(ifd, ifp->ctx->ifaces, next) {
+		if (ifd->options->options & DHCPCD_NOPFXDLG)
+			continue;
+		k = 0;
+		carrier_warned = abrt = 0;
+		TAILQ_FOREACH(ap, &state->addrs, next) {
+			if (!(ap->flags & IPV6_AF_DELEGATEDPFX))
+				continue;
+			if (ap->flags & IPV6_AF_NEW) {
+				ap->flags &= ~IPV6_AF_NEW;
+				logger(ifp->ctx, LOG_DEBUG,
+				    "%s: delegated prefix %s",
+				    ifp->name, ap->saddr);
+			}
+			for (i = 0; i < ifo->ia_len; i++) {
+				ia = &ifo->ia[i];
+				if (memcmp(ia->iaid, ap->iaid,
+				    sizeof(ia->iaid)))
+					continue;
+				if (ia->sla_len == 0) {
+					/* no SLA configured, so lets
+					 * automate it */
+					if (ifd->carrier != LINK_UP) {
+						logger(ifp->ctx, LOG_DEBUG,
+						    "%s: has no carrier, cannot"
+						    " delegate addresses",
+						    ifd->name);
+						carrier_warned = 1;
+						break;
+					}
+					if (dhcp6_ifdelegateaddr(ifd, ap,
+					    NULL, ia, ifp))
+						k++;
+				}
+				for (j = 0; j < ia->sla_len; j++) {
+					sla = &ia->sla[j];
+					if (sla->sla_set && sla->sla == 0)
+						ap->flags |=
+						    IPV6_AF_DELEGATEDZERO;
+					if (strcmp(ifd->name, sla->ifname))
+						continue;
+					if (ifd->carrier != LINK_UP) {
+						logger(ifp->ctx, LOG_DEBUG,
+						    "%s: has no carrier, cannot"
+						    " delegate addresses",
+						    ifd->name);
+						carrier_warned = 1;
+						break;
+					}
+					if (dhcp6_ifdelegateaddr(ifd, ap,
+					    sla, ia, ifp))
+						k++;
+				}
+				if (carrier_warned ||abrt)
+					break;
+			}
+			if (carrier_warned || abrt)
+				break;
+		}
+		if (k && !carrier_warned) {
+			ifd_state = D6_STATE(ifd);
+			ipv6_addaddrs(&ifd_state->addrs);
+			if_initrt6(ifd);
+			dhcp6_script_try_run(ifd, 1);
+		}
+	}
+}
+
+static void
+dhcp6_find_delegates1(void *arg)
+{
+
+	dhcp6_find_delegates(arg);
+}
+
+size_t
+dhcp6_find_delegates(struct interface *ifp)
+{
+	struct if_options *ifo;
+	struct dhcp6_state *state;
+	struct ipv6_addr *ap;
+	size_t i, j, k;
+	struct if_ia *ia;
+	struct if_sla *sla;
+	struct interface *ifd;
+
+	k = 0;
+	TAILQ_FOREACH(ifd, ifp->ctx->ifaces, next) {
+		ifo = ifd->options;
+		state = D6_STATE(ifd);
+		if (state == NULL || state->state != DH6S_BOUND)
+			continue;
+		TAILQ_FOREACH(ap, &state->addrs, next) {
+			if (!(ap->flags & IPV6_AF_DELEGATEDPFX))
+				continue;
+			for (i = 0; i < ifo->ia_len; i++) {
+				ia = &ifo->ia[i];
+				if (memcmp(ia->iaid, ap->iaid,
+				    sizeof(ia->iaid)))
+					continue;
+				for (j = 0; j < ia->sla_len; j++) {
+					sla = &ia->sla[j];
+					if (strcmp(ifp->name, sla->ifname))
+						continue;
+					if (ipv6_linklocal(ifp) == NULL) {
+						logger(ifp->ctx, LOG_DEBUG,
+						    "%s: delaying adding"
+						    " delegated addresses for"
+						    " LL address",
+						    ifp->name);
+						ipv6_addlinklocalcallback(ifp,
+						    dhcp6_find_delegates1, ifp);
+						return 1;
+					}
+					if (dhcp6_ifdelegateaddr(ifp, ap,
+					    sla, ia, ifd))
+					    k++;
+				}
+			}
+		}
+	}
+
+	if (k) {
+		logger(ifp->ctx, LOG_INFO,
+		    "%s: adding delegated prefixes", ifp->name);
+		state = D6_STATE(ifp);
+		state->state = DH6S_DELEGATED;
+		ipv6_addaddrs(&state->addrs);
+		if_initrt6(ifp);
+		ipv6_buildroutes(ifp->ctx);
+		dhcp6_script_try_run(ifp, 1);
+	}
+	return k;
+}
+
+static struct interface *
+dhcp6_findpfxdlgif(struct interface *ifp)
+{
+	struct interface *ifn;
+
+	if (ifp->options && ifp->options->options & DHCPCD_PFXDLGONLY)
+		return NULL;
+
+	if (ifp->ctx && ifp->ctx->ifaces) {
+		TAILQ_FOREACH(ifn, ifp->ctx->ifaces, next) {
+			if (strcmp(ifn->name, ifp->name) == 0 &&
+			    ifn->options->options & DHCPCD_PFXDLGONLY)
+				return ifn;
+		}
+	}
+	return NULL;
+}
+
+/* ARGSUSED */
+static void
+dhcp6_handledata(void *arg)
+{
+	struct dhcpcd_ctx *dctx;
+	struct ipv6_ctx *ctx;
+	size_t i, len;
+	ssize_t bytes;
+	struct cmsghdr *cm;
+	struct in6_pktinfo pkt;
+	struct interface *ifp, *ifpx;
+	const char *op;
+	struct dhcp6_message *r;
+	struct dhcp6_state *state;
+	const struct dhcp6_option *o, *auth;
+	const struct dhcp_opt *opt;
+	const struct if_options *ifo;
+	struct ipv6_addr *ap;
+	uint8_t has_new;
+	int error;
+	uint32_t u32;
+
+	dctx = arg;
+	ctx = dctx->ipv6;
+	ctx->rcvhdr.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
+	bytes = recvmsg(ctx->dhcp_fd, &ctx->rcvhdr, 0);
+	if (bytes == -1) {
+		logger(dctx, LOG_ERR, "%s: recvmsg: %m", __func__);
+		close(ctx->dhcp_fd);
+		eloop_event_delete(dctx->eloop, ctx->dhcp_fd, 0);
+		ctx->dhcp_fd = -1;
+		return;
+	}
+	len = (size_t)bytes;
+	ctx->sfrom = inet_ntop(AF_INET6, &ctx->from.sin6_addr,
+	    ctx->ntopbuf, sizeof(ctx->ntopbuf));
+	if (len < sizeof(struct dhcp6_message)) {
+		logger(dctx, LOG_ERR,
+		    "DHCPv6 packet too short from %s", ctx->sfrom);
+		return;
+	}
+
+	pkt.ipi6_ifindex = 0;
+	for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&ctx->rcvhdr);
+	     cm;
+	     cm = (struct cmsghdr *)CMSG_NXTHDR(&ctx->rcvhdr, cm))
+	{
+		if (cm->cmsg_level != IPPROTO_IPV6)
+			continue;
+		switch(cm->cmsg_type) {
+		case IPV6_PKTINFO:
+			if (cm->cmsg_len == CMSG_LEN(sizeof(pkt)))
+				memcpy(&pkt, CMSG_DATA(cm), sizeof(pkt));
+			break;
+		}
+	}
+	if (pkt.ipi6_ifindex == 0) {
+		logger(dctx, LOG_ERR,
+		    "DHCPv6 reply did not contain index from %s", ctx->sfrom);
+		return;
+	}
+
+	TAILQ_FOREACH(ifp, dctx->ifaces, next) {
+		/* Ensure we work on the master interface */
+		if (ifp->index == (unsigned int)pkt.ipi6_ifindex &&
+		    !(ifp->options->options & DHCPCD_PFXDLGONLY))
+			break;
+	}
+	if (ifp == NULL) {
+		logger(dctx, LOG_DEBUG,
+		    "DHCPv6 reply for unexpected interface from %s",
+		    ctx->sfrom);
+		return;
+	}
+
+	r = (struct dhcp6_message *)ctx->rcvhdr.msg_iov[0].iov_base;
+
+	/* Which interface state is the IAID for? */
+	ifpx = dhcp6_findpfxdlgif(ifp);
+	if (ifpx && D6_STATE(ifpx)) {
+		state = D6_STATE(ifpx);
+		if (r->xid[0] == state->send->xid[0] &&
+		    r->xid[1] == state->send->xid[1] &&
+		    r->xid[2] == state->send->xid[2])
+			ifp = ifpx;
+	}
+
+	state = D6_STATE(ifp);
+	if (state == NULL || state->send == NULL) {
+		logger(ifp->ctx, LOG_DEBUG,
+		    "%s: DHCPv6 reply received but not running", ifp->name);
+		return;
+	}
+
+	/* We're already bound and this message is for another machine */
+	/* XXX DELEGATED? */
+	if (r->type != DHCP6_RECONFIGURE &&
+	    (state->state == DH6S_BOUND || state->state == DH6S_INFORMED)) 
+	{
+		logger(ifp->ctx, LOG_DEBUG,
+		    "%s: DHCPv6 reply received but already bound", ifp->name);
+		return;
+	}
+
+	if (r->type != DHCP6_RECONFIGURE &&
+	    (r->xid[0] != state->send->xid[0] ||
+	    r->xid[1] != state->send->xid[1] ||
+	    r->xid[2] != state->send->xid[2]))
+	{
+		logger(dctx, LOG_DEBUG,
+		    "%s: wrong xid 0x%02x%02x%02x"
+		    " (expecting 0x%02x%02x%02x) from %s",
+		    ifp->name,
+		    r->xid[0], r->xid[1], r->xid[2],
+		    state->send->xid[0], state->send->xid[1],
+		    state->send->xid[2],
+		    ctx->sfrom);
+		return;
+	}
+
+	if (dhcp6_getmoption(D6_OPTION_SERVERID, r, len) == NULL) {
+		logger(ifp->ctx, LOG_DEBUG, "%s: no DHCPv6 server ID from %s",
+		    ifp->name, ctx->sfrom);
+		return;
+	}
+
+	o = dhcp6_getmoption(D6_OPTION_CLIENTID, r, len);
+	if (o == NULL || ntohs(o->len) != dctx->duid_len ||
+	    memcmp(D6_COPTION_DATA(o), dctx->duid, dctx->duid_len) != 0)
+	{
+		logger(ifp->ctx, LOG_DEBUG, "%s: incorrect client ID from %s",
+		    ifp->name, ctx->sfrom);
+		return;
+	}
+
+	ifo = ifp->options;
+	for (i = 0, opt = dctx->dhcp6_opts;
+	    i < dctx->dhcp6_opts_len;
+	    i++, opt++)
+	{
+		if (has_option_mask(ifo->requiremask6, opt->option) &&
+		    dhcp6_getmoption((uint16_t)opt->option, r, len) == NULL)
+		{
+			logger(ifp->ctx, LOG_WARNING,
+			    "%s: reject DHCPv6 (no option %s) from %s",
+			    ifp->name, opt->var, ctx->sfrom);
+			return;
+		}
+		if (has_option_mask(ifo->rejectmask6, opt->option) &&
+		    dhcp6_getmoption((uint16_t)opt->option, r, len))
+		{
+			logger(ifp->ctx, LOG_WARNING,
+			    "%s: reject DHCPv6 (option %s) from %s",
+			    ifp->name, opt->var, ctx->sfrom);
+			return;
+		}
+	}
+
+	/* Authenticate the message */
+	auth = dhcp6_getmoption(D6_OPTION_AUTH, r, len);
+	if (auth) {
+		if (dhcp_auth_validate(&state->auth, &ifo->auth,
+		    (uint8_t *)r, len, 6, r->type,
+		    D6_COPTION_DATA(auth), ntohs(auth->len)) == NULL)
+		{
+			logger(ifp->ctx, LOG_DEBUG, "dhcp_auth_validate: %m");
+			logger(ifp->ctx, LOG_ERR,
+			    "%s: authentication failed from %s",
+			    ifp->name, ctx->sfrom);
+			return;
+		}
+		if (state->auth.token)
+			logger(ifp->ctx, LOG_DEBUG,
+			    "%s: validated using 0x%08" PRIu32,
+			    ifp->name, state->auth.token->secretid);
+		else
+			logger(ifp->ctx, LOG_DEBUG,
+			    "%s: accepted reconfigure key", ifp->name);
+	} else if (ifo->auth.options & DHCPCD_AUTH_REQUIRE) {
+		logger(ifp->ctx, LOG_ERR,
+		    "%s: no authentication from %s", ifp->name, ctx->sfrom);
+		return;
+	} else if (ifo->auth.options & DHCPCD_AUTH_SEND)
+		logger(ifp->ctx, LOG_WARNING,
+		    "%s: no authentication from %s", ifp->name, ctx->sfrom);
+
+	op = dhcp6_get_op(r->type);
+	switch(r->type) {
+	case DHCP6_REPLY:
+		switch(state->state) {
+		case DH6S_INFORM:
+			if (dhcp6_checkstatusok(ifp, r, NULL, len) == -1)
+				return;
+			/* RFC4242 */
+			o = dhcp6_getmoption(D6_OPTION_INFO_REFRESH_TIME,
+			    r, len);
+			if (o == NULL || ntohs(o->len) != sizeof(u32))
+				state->renew = IRT_DEFAULT;
+			else {
+				memcpy(&u32, D6_COPTION_DATA(o), sizeof(u32));
+				state->renew = ntohl(u32);
+				if (state->renew < IRT_MINIMUM)
+					state->renew = IRT_MINIMUM;
+			}
+			break;
+		case DH6S_CONFIRM:
+			error = dhcp6_checkstatusok(ifp, r, NULL, len);
+			/* If we got an OK status the chances are that we
+			 * didn't get the IA's returned, so preserve them
+			 * from our saved response */
+			if (error == 1)
+				goto recv;
+			if (error == -1 ||
+			    dhcp6_validatelease(ifp, r, len,
+			    ctx->sfrom, NULL) == -1)
+			{
+				dhcp6_startdiscover(ifp);
+				return;
+			}
+			break;
+		case DH6S_DISCOVER:
+			if (has_option_mask(ifo->requestmask6,
+			    D6_OPTION_RAPID_COMMIT) &&
+			    dhcp6_getmoption(D6_OPTION_RAPID_COMMIT, r, len))
+				state->state = DH6S_REQUEST;
+			else
+				op = NULL;
+		case DH6S_REQUEST: /* FALLTHROUGH */
+		case DH6S_RENEW: /* FALLTHROUGH */
+		case DH6S_REBIND:
+			if (dhcp6_validatelease(ifp, r, len,
+			    ctx->sfrom, NULL) == -1)
+			{
+				/* PD doesn't use CONFIRM, so REBIND could
+				 * throw up an invalid prefix if we
+				 * changed link */
+				if (dhcp6_hasprefixdelegation(ifp))
+					dhcp6_startdiscover(ifp);
+				return;
+			}
+			break;
+		default:
+			op = NULL;
+		}
+		break;
+	case DHCP6_ADVERTISE:
+		if (state->state != DH6S_DISCOVER) {
+			op = NULL;
+			break;
+		}
+		/* RFC7083 */
+		o = dhcp6_getmoption(D6_OPTION_SOL_MAX_RT, r, len);
+		if (o && ntohs(o->len) >= sizeof(u32)) {
+			memcpy(&u32, D6_COPTION_DATA(o), sizeof(u32));
+			u32 = ntohl(u32);
+			if (u32 >= 60 && u32 <= 86400) {
+				logger(ifp->ctx, LOG_DEBUG,
+				    "%s: SOL_MAX_RT %llu -> %d", ifp->name,
+				    (unsigned long long)state->sol_max_rt, u32);
+				state->sol_max_rt = (time_t)u32;
+			} else
+				logger(ifp->ctx, LOG_ERR,
+				    "%s: invalid SOL_MAX_RT %d",
+				    ifp->name, u32);
+		}
+		o = dhcp6_getmoption(D6_OPTION_INF_MAX_RT, r, len);
+		if (o && ntohs(o->len) >= sizeof(u32)) {
+			memcpy(&u32, D6_COPTION_DATA(o), sizeof(u32));
+			u32 = ntohl(u32);
+			if (u32 >= 60 && u32 <= 86400) {
+				logger(ifp->ctx, LOG_DEBUG,
+				    "%s: INF_MAX_RT %llu -> %d",
+				    ifp->name,
+				    (unsigned long long)state->inf_max_rt, u32);
+				state->inf_max_rt = (time_t)u32;
+			} else
+				logger(ifp->ctx, LOG_ERR,
+				    "%s: invalid INF_MAX_RT %d",
+				    ifp->name, u32);
+		}
+		if (dhcp6_validatelease(ifp, r, len, ctx->sfrom, NULL) == -1)
+			return;
+		break;
+	case DHCP6_RECONFIGURE:
+		if (auth == NULL) {
+			logger(ifp->ctx, LOG_ERR,
+			    "%s: unauthenticated %s from %s",
+			    ifp->name, op, ctx->sfrom);
+			return;
+		}
+		logger(ifp->ctx, LOG_INFO, "%s: %s from %s",
+		    ifp->name, op, ctx->sfrom);
+		o = dhcp6_getmoption(D6_OPTION_RECONF_MSG, r, len);
+		if (o == NULL) {
+			logger(ifp->ctx, LOG_ERR,
+			    "%s: missing Reconfigure Message option",
+			    ifp->name);
+			return;
+		}
+		if (ntohs(o->len) != 1) {
+			logger(ifp->ctx, LOG_ERR,
+			    "%s: missing Reconfigure Message type", ifp->name);
+			return;
+		}
+		switch(*D6_COPTION_DATA(o)) {
+		case DHCP6_RENEW:
+			if (state->state != DH6S_BOUND) {
+				logger(ifp->ctx, LOG_ERR,
+				    "%s: not bound, ignoring %s",
+				    ifp->name, op);
+				return;
+			}
+			eloop_timeout_delete(ifp->ctx->eloop,
+			    dhcp6_startrenew, ifp);
+			dhcp6_startrenew(ifp);
+			break;
+		case DHCP6_INFORMATION_REQ:
+			if (state->state != DH6S_INFORMED) {
+				logger(ifp->ctx, LOG_ERR,
+				    "%s: not informed, ignoring %s",
+				    ifp->name, op);
+				return;
+			}
+			eloop_timeout_delete(ifp->ctx->eloop,
+			    dhcp6_sendinform, ifp);
+			dhcp6_startinform(ifp);
+			break;
+		default:
+			logger(ifp->ctx, LOG_ERR,
+			    "%s: unsupported %s type %d",
+			    ifp->name, op, *D6_COPTION_DATA(o));
+			break;
+		}
+		return;
+	default:
+		logger(ifp->ctx, LOG_ERR, "%s: invalid DHCP6 type %s (%d)",
+		    ifp->name, op, r->type);
+		return;
+	}
+	if (op == NULL) {
+		logger(ifp->ctx, LOG_WARNING,
+		    "%s: invalid state for DHCP6 type %s (%d)",
+		    ifp->name, op, r->type);
+		return;
+	}
+
+	if (state->recv_len < (size_t)len) {
+		free(state->recv);
+		state->recv = malloc(len);
+		if (state->recv == NULL) {
+			logger(ifp->ctx, LOG_ERR,
+			    "%s: malloc recv: %m", ifp->name);
+			return;
+		}
+	}
+	memcpy(state->recv, r, len);
+	state->recv_len = len;
+
+	switch(r->type) {
+	case DHCP6_ADVERTISE:
+		if (state->state == DH6S_REQUEST) /* rapid commit */
+			break;
+		ap = TAILQ_FIRST(&state->addrs);
+		logger(ifp->ctx, LOG_INFO, "%s: ADV %s from %s",
+		    ifp->name, ap->saddr, ctx->sfrom);
+		if (ifp->ctx->options & DHCPCD_TEST)
+			break;
+		dhcp6_startrequest(ifp);
+		return;
+	}
+
+recv:
+	has_new = 0;
+	TAILQ_FOREACH(ap, &state->addrs, next) {
+		if (ap->flags & IPV6_AF_NEW) {
+			has_new = 1;
+			break;
+		}
+	}
+	logger(ifp->ctx, has_new ? LOG_INFO : LOG_DEBUG,
+	    "%s: %s received from %s", ifp->name, op, ctx->sfrom);
+
+	state->reason = NULL;
+	eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
+	switch(state->state) {
+	case DH6S_INFORM:
+		state->rebind = 0;
+		state->expire = ND6_INFINITE_LIFETIME;
+		state->lowpl = ND6_INFINITE_LIFETIME;
+		state->reason = "INFORM6";
+		break;
+	case DH6S_REQUEST:
+		if (state->reason == NULL)
+			state->reason = "BOUND6";
+		/* FALLTHROUGH */
+	case DH6S_RENEW:
+		if (state->reason == NULL)
+			state->reason = "RENEW6";
+		/* FALLTHROUGH */
+	case DH6S_REBIND:
+		if (state->reason == NULL)
+			state->reason = "REBIND6";
+		/* FALLTHROUGH */
+	case DH6S_CONFIRM:
+		if (state->reason == NULL)
+			state->reason = "REBOOT6";
+		if (state->renew == 0) {
+			if (state->expire == ND6_INFINITE_LIFETIME)
+				state->renew = ND6_INFINITE_LIFETIME;
+			else if (state->lowpl != ND6_INFINITE_LIFETIME)
+				state->renew = (uint32_t)(state->lowpl * 0.5);
+		}
+		if (state->rebind == 0) {
+			if (state->expire == ND6_INFINITE_LIFETIME)
+				state->rebind = ND6_INFINITE_LIFETIME;
+			else if (state->lowpl != ND6_INFINITE_LIFETIME)
+				state->rebind = (uint32_t)(state->lowpl * 0.8);
+		}
+		break;
+	default:
+		state->reason = "UNKNOWN6";
+		break;
+	}
+
+	if (state->state != DH6S_CONFIRM) {
+		free(state->old);
+		state->old = state->new;
+		state->old_len = state->new_len;
+		state->new = state->recv;
+		state->new_len = state->recv_len;
+		state->recv = NULL;
+		state->recv_len = 0;
+	}
+
+	if (ifp->ctx->options & DHCPCD_TEST)
+		script_runreason(ifp, "TEST");
+	else {
+		if (state->state == DH6S_INFORM)
+			state->state = DH6S_INFORMED;
+		else
+			state->state = DH6S_BOUND;
+		if (state->renew && state->renew != ND6_INFINITE_LIFETIME)
+			eloop_timeout_add_sec(ifp->ctx->eloop,
+			    (time_t)state->renew,
+			    state->state == DH6S_INFORMED ?
+			    dhcp6_startinform : dhcp6_startrenew, ifp);
+		if (state->rebind && state->rebind != ND6_INFINITE_LIFETIME)
+			eloop_timeout_add_sec(ifp->ctx->eloop,
+			    (time_t)state->rebind, dhcp6_startrebind, ifp);
+		if (state->expire != ND6_INFINITE_LIFETIME)
+			eloop_timeout_add_sec(ifp->ctx->eloop,
+			    (time_t)state->expire, dhcp6_startexpire, ifp);
+
+#ifndef PASSIVE_MODE
+		ipv6nd_runignoredra(ifp);
+		ipv6_addaddrs(&state->addrs);
+		dhcp6_delegate_prefix(ifp);
+#else
+		rpc_update_ipv6(ifp);
+#endif  /* PASSIVE_MODE */
+
+		if (state->state == DH6S_INFORMED)
+			logger(ifp->ctx, has_new ? LOG_INFO : LOG_DEBUG,
+			    "%s: refresh in %"PRIu32" seconds",
+			    ifp->name, state->renew);
+		else if (state->renew || state->rebind)
+			logger(ifp->ctx, has_new ? LOG_INFO : LOG_DEBUG,
+			    "%s: renew in %"PRIu32" seconds,"
+			    " rebind in %"PRIu32" seconds",
+			    ifp->name, state->renew, state->rebind);
+		else if (state->expire == 0)
+			logger(ifp->ctx, has_new ? LOG_INFO : LOG_DEBUG,
+			    "%s: will expire", ifp->name);
+		if_initrt6(ifp);
+		ipv6_buildroutes(ifp->ctx);
+		dhcp6_writelease(ifp);
+		dhcp6_script_try_run(ifp, 0);
+	}
+
+	if (ifp->ctx->options & DHCPCD_TEST ||
+	    (ifp->options->options & DHCPCD_INFORM &&
+	    !(ifp->ctx->options & DHCPCD_MASTER)))
+	{
+		eloop_exit(ifp->ctx->eloop, EXIT_SUCCESS);
+	}
+}
+
+static int
+dhcp6_open(struct dhcpcd_ctx *dctx)
+{
+	struct ipv6_ctx *ctx;
+	struct sockaddr_in6 sa;
+	int n;
+
+	memset(&sa, 0, sizeof(sa));
+	sa.sin6_family = AF_INET6;
+	sa.sin6_port = htons(DHCP6_CLIENT_PORT);
+#ifdef BSD
+	sa.sin6_len = sizeof(sa);
+#endif
+
+	ctx = dctx->ipv6;
+#ifdef SOCK_CLOEXEC
+	ctx->dhcp_fd = socket(PF_INET6,
+	    SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
+	    IPPROTO_UDP);
+	if (ctx->dhcp_fd == -1)
+		return -1;
+#else
+	if ((ctx->dhcp_fd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP)) == -1)
+		return -1;
+	if ((n = fcntl(ctx->dhcp_fd, F_GETFD, 0)) == -1 ||
+	    fcntl(ctx->dhcp_fd, F_SETFD, n | FD_CLOEXEC) == -1)
+	{
+		close(ctx->dhcp_fd);
+		ctx->dhcp_fd = -1;
+	        return -1;
+	}
+	if ((n = fcntl(ctx->dhcp_fd, F_GETFL, 0)) == -1 ||
+	    fcntl(ctx->dhcp_fd, F_SETFL, n | O_NONBLOCK) == -1)
+	{
+		close(ctx->dhcp_fd);
+		ctx->dhcp_fd = -1;
+	        return -1;
+	}
+#endif
+
+	n = 1;
+	if (setsockopt(ctx->dhcp_fd, SOL_SOCKET, SO_REUSEADDR,
+	    &n, sizeof(n)) == -1)
+		goto errexit;
+
+	n = 1;
+	if (setsockopt(ctx->dhcp_fd, SOL_SOCKET, SO_BROADCAST,
+	    &n, sizeof(n)) == -1)
+		goto errexit;
+
+#ifdef SO_REUSEPORT
+	n = 1;
+	if (setsockopt(ctx->dhcp_fd, SOL_SOCKET, SO_REUSEPORT,
+	    &n, sizeof(n)) == -1)
+		logger(dctx, LOG_WARNING, "setsockopt: SO_REUSEPORT: %m");
+#endif
+
+	if (bind(ctx->dhcp_fd, (struct sockaddr *)&sa, sizeof(sa)) == -1)
+		goto errexit;
+
+	n = 1;
+	if (setsockopt(ctx->dhcp_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO,
+	    &n, sizeof(n)) == -1)
+		goto errexit;
+
+	eloop_event_add(dctx->eloop, ctx->dhcp_fd,
+	    dhcp6_handledata, dctx, NULL, NULL);
+	return 0;
+
+errexit:
+	close(ctx->dhcp_fd);
+	ctx->dhcp_fd = -1;
+	return -1;
+}
+
+static void
+dhcp6_start1(void *arg)
+{
+	struct interface *ifp = arg;
+	struct if_options *ifo = ifp->options;
+	struct dhcp6_state *state;
+	size_t i;
+	const struct dhcp_compat *dhc;
+
+	state = D6_STATE(ifp);
+	/* Match any DHCPv4 opton to DHCPv6 options if given for easy
+	 * configuration */
+	for (i = 0; i < sizeof(ifo->requestmask6); i++) {
+		if (ifo->requestmask6[i] != '\0')
+			break;
+	}
+	if (i == sizeof(ifo->requestmask6)) {
+		for (dhc = dhcp_compats; dhc->dhcp_opt; dhc++) {
+			if (has_option_mask(ifo->requestmask, dhc->dhcp_opt))
+				add_option_mask(ifo->requestmask6,
+				    dhc->dhcp6_opt);
+		}
+		if (ifo->fqdn != FQDN_DISABLE ||
+		    ifo->options & DHCPCD_HOSTNAME)
+			add_option_mask(ifo->requestmask6, D6_OPTION_FQDN);
+	}
+
+	/* Rapid commit won't wor with Prefix Delegation Exclusion */
+	if (dhcp6_findselfsla(ifp, NULL))
+		del_option_mask(ifo->requestmask6, D6_OPTION_RAPID_COMMIT);
+
+	/* Create a 2nd interface to handle the PD state */
+	if (!(ifo->options & (DHCPCD_PFXDLGONLY | DHCPCD_PFXDLGMIX)) &&
+	    dhcp6_hasprefixdelegation(ifp) > 1)
+	{
+		const char * const argv[] = { ifp->name };
+		struct if_head *ifs;
+		struct interface *ifn;
+
+		ifn = dhcp6_findpfxdlgif(ifp);
+		if (ifn == NULL) {
+			ifs = if_discover(ifp->ctx, -1, UNCONST(argv));
+			if (ifs) {
+				ifn = TAILQ_FIRST(ifs);
+				if (ifn) {
+					logger(ifp->ctx, LOG_INFO,
+					    "%s: creating pseudo interface"
+					    " to handle Prefix Delegation",
+					    ifp->name);
+					ifp->options->options |=
+					    DHCPCD_NOPFXDLG;
+					/*
+					 * Maintain the same lease identifier
+					 * for the pseudo interface for
+					 * obtaining prefix delegation.
+					 */
+					strlcpy(ifn->lease_identifier,
+					        ifp->lease_identifier,
+					        sizeof(ifn->lease_identifier));
+					TAILQ_REMOVE(ifs, ifn, next);
+					TAILQ_INSERT_AFTER(ifp->ctx->ifaces,
+					    ifp, ifn, next);
+					dhcpcd_initstate(ifn,
+					    DHCPCD_PFXDLGONLY);
+					eloop_timeout_add_sec(ifp->ctx->eloop,
+					    0, dhcpcd_startinterface, ifn);
+				}
+				while ((ifn = TAILQ_FIRST(ifs))) {
+					TAILQ_REMOVE(ifs, ifn, next);
+					if_free(ifn);
+				}
+				free(ifs);
+			}
+		}
+	}
+
+	if (state->state == DH6S_INFORM) {
+		add_option_mask(ifo->requestmask6, D6_OPTION_INFO_REFRESH_TIME);
+		dhcp6_startinform(ifp);
+	} else {
+		del_option_mask(ifo->requestmask6, D6_OPTION_INFO_REFRESH_TIME);
+		dhcp6_startinit(ifp);
+	}
+}
+
+int
+dhcp6_start(struct interface *ifp, enum DH6S init_state)
+{
+	struct dhcp6_state *state;
+
+	state = D6_STATE(ifp);
+	if (state) {
+		if (state->state == DH6S_INFORMED &&
+		    init_state == DH6S_INFORM)
+		{
+			dhcp6_startinform(ifp);
+			return 0;
+		}
+		if (init_state == DH6S_INIT &&
+		    ifp->options->options & DHCPCD_DHCP6 &&
+		    (state->state == DH6S_INFORM ||
+		    state->state == DH6S_INFORMED ||
+		    state->state == DH6S_DELEGATED))
+		{
+			/* Change from stateless to stateful */
+			goto gogogo;
+		}
+		/* We're already running DHCP6 */
+		/* XXX: What if the managed flag vanishes from all RA? */
+		return 0;
+	}
+
+	if (!(ifp->options->options & DHCPCD_DHCP6))
+		return 0;
+
+	if (ifp->ctx->ipv6->dhcp_fd == -1 && dhcp6_open(ifp->ctx) == -1)
+		return -1;
+
+	ifp->if_data[IF_DATA_DHCP6] = calloc(1, sizeof(*state));
+	state = D6_STATE(ifp);
+	if (state == NULL)
+		return -1;
+
+	state->sol_max_rt = SOL_MAX_RT;
+	state->inf_max_rt = INF_MAX_RT;
+	TAILQ_INIT(&state->addrs);
+
+gogogo:
+	state->state = init_state;
+	dhcp_set_leasefile(state->leasefile, sizeof(state->leasefile),
+	    AF_INET6, ifp,
+	    ifp->options->options & DHCPCD_PFXDLGONLY ? ".pd" : "");
+	if (ipv6_linklocal(ifp) == NULL) {
+		logger(ifp->ctx, LOG_DEBUG,
+		    "%s: delaying DHCPv6 soliciation for LL address",
+		    ifp->name);
+		ipv6_addlinklocalcallback(ifp, dhcp6_start1, ifp);
+		return 0;
+	}
+
+	dhcp6_start1(ifp);
+	return 0;
+}
+
+void
+dhcp6_reboot(struct interface *ifp)
+{
+	struct dhcp6_state *state;
+
+	state = D6_STATE(ifp);
+	if (state) {
+		switch (state->state) {
+		case DH6S_BOUND:
+			dhcp6_startrebind(ifp);
+			break;
+		case DH6S_INFORMED:
+			dhcp6_startinform(ifp);
+			break;
+		default:
+			dhcp6_startdiscover(ifp);
+			break;
+		}
+	}
+}
+
+static void
+dhcp6_freedrop(struct interface *ifp, int drop, const char *reason)
+{
+	struct interface *ifpx;
+	struct dhcp6_state *state;
+	struct dhcpcd_ctx *ctx;
+	unsigned long long options;
+	int dropdele;
+
+	/*
+	 * As the interface is going away from dhcpcd we need to
+	 * remove the delegated addresses, otherwise we lose track
+	 * of which interface is delegating as we remeber it by pointer.
+	 * So if we need to change this behaviour, we need to change
+	 * how we remember which interface delegated.
+	 *
+	 * XXX The below is no longer true due to the change of the
+	 * default IAID, but do PPP links have stable ethernet
+	 * addresses?
+	 *
+	 * To make it more interesting, on some OS's with PPP links
+	 * there is no guarantee the delegating interface will have
+	 * the same name or index so think very hard before changing
+	 * this.
+	 */
+	if (ifp->options)
+		options = ifp->options->options;
+	else
+		options = 0;
+	dropdele = (options & (DHCPCD_STOPPING | DHCPCD_RELEASE) &&
+	    (options &
+	    (DHCPCD_EXITING | DHCPCD_PERSISTENT)) !=
+	    (DHCPCD_EXITING | DHCPCD_PERSISTENT));
+
+	ifpx = dhcp6_findpfxdlgif(ifp);
+	if (ifpx) {
+		if (options & DHCPCD_EXITING)
+			ifpx->options->options |= DHCPCD_EXITING;
+		dhcp6_freedrop(ifpx, dropdele ? 1 : drop, reason);
+		TAILQ_REMOVE(ifp->ctx->ifaces, ifpx, next);
+		if_free(ifpx);
+	}
+
+	if (ifp->ctx->eloop)
+		eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
+
+	if (dropdele)
+		dhcp6_delete_delegates(ifp);
+
+	state = D6_STATE(ifp);
+	if (state) {
+		dhcp_auth_reset(&state->auth);
+		if (drop && options & DHCPCD_RELEASE) {
+			if (ifp->carrier == LINK_UP)
+				dhcp6_startrelease(ifp);
+			unlink(state->leasefile);
+		}
+		dhcp6_freedrop_addrs(ifp, drop, NULL);
+		free(state->old);
+		state->old = state->new;
+		state->old_len = state->new_len;
+		state->new = NULL;
+		state->new_len = 0;
+		if (drop && state->old &&
+		    (options &
+		    (DHCPCD_EXITING | DHCPCD_PERSISTENT)) !=
+		    (DHCPCD_EXITING | DHCPCD_PERSISTENT))
+		{
+			if (reason == NULL)
+				reason = "STOP6";
+			script_runreason(ifp, reason);
+		}
+		free(state->old);
+		free(state->send);
+		free(state->recv);
+		free(state);
+		ifp->if_data[IF_DATA_DHCP6] = NULL;
+	}
+
+	/* If we don't have any more DHCP6 enabled interfaces,
+	 * close the global socket and release resources */
+	ctx = ifp->ctx;
+	if (ctx->ifaces) {
+		TAILQ_FOREACH(ifp, ctx->ifaces, next) {
+			if (D6_STATE(ifp))
+				break;
+		}
+	}
+	if (ifp == NULL && ctx->ipv6) {
+		if (ctx->ipv6->dhcp_fd != -1) {
+			eloop_event_delete(ctx->eloop, ctx->ipv6->dhcp_fd, 0);
+			close(ctx->ipv6->dhcp_fd);
+			ctx->ipv6->dhcp_fd = -1;
+		}
+	}
+}
+
+void
+dhcp6_drop(struct interface *ifp, const char *reason)
+{
+
+	dhcp6_freedrop(ifp, 1, reason);
+}
+
+void
+dhcp6_free(struct interface *ifp)
+{
+
+	dhcp6_freedrop(ifp, 0, NULL);
+}
+
+void
+dhcp6_handleifa(struct dhcpcd_ctx *ctx, int cmd, const char *ifname,
+    const struct in6_addr *addr, int flags)
+{
+	struct interface *ifp;
+	struct dhcp6_state *state;
+
+	if (ctx->ifaces == NULL)
+		return;
+
+	TAILQ_FOREACH(ifp, ctx->ifaces, next) {
+		state = D6_STATE(ifp);
+		if (state == NULL || strcmp(ifp->name, ifname))
+			continue;
+		ipv6_handleifa_addrs(cmd, &state->addrs, addr, flags);
+	}
+
+}
+
+ssize_t
+dhcp6_env(char **env, const char *prefix, const struct interface *ifp,
+    const struct dhcp6_message *m, size_t len)
+{
+	const struct if_options *ifo;
+	struct dhcp_opt *opt, *vo;
+	const struct dhcp6_option *o;
+	size_t i, n;
+	uint16_t ol, oc;
+	char *pfx;
+	uint32_t en;
+	const struct dhcpcd_ctx *ctx;
+	const struct dhcp6_state *state;
+	const struct ipv6_addr *ap;
+	char *v, *val;
+
+	n = 0;
+	if (m == NULL)
+		goto delegated;
+
+	if (len < sizeof(*m)) {
+		/* Should be impossible with guards at packet in
+		 * and reading leases */
+		errno = EINVAL;
+		return -1;
+	}
+
+	ifo = ifp->options;
+	ctx = ifp->ctx;
+
+	/* Zero our indexes */
+	if (env) {
+		for (i = 0, opt = ctx->dhcp6_opts;
+		    i < ctx->dhcp6_opts_len;
+		    i++, opt++)
+			dhcp_zero_index(opt);
+		for (i = 0, opt = ifp->options->dhcp6_override;
+		    i < ifp->options->dhcp6_override_len;
+		    i++, opt++)
+			dhcp_zero_index(opt);
+		for (i = 0, opt = ctx->vivso;
+		    i < ctx->vivso_len;
+		    i++, opt++)
+			dhcp_zero_index(opt);
+		i = strlen(prefix) + strlen("_dhcp6") + 1;
+		pfx = malloc(i);
+		if (pfx == NULL) {
+			logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
+			return -1;
+		}
+		snprintf(pfx, i, "%s_dhcp6", prefix);
+	} else
+		pfx = NULL;
+
+	/* Unlike DHCP, DHCPv6 options *may* occur more than once.
+	 * There is also no provision for option concatenation unlike DHCP. */
+	for (o = D6_CFIRST_OPTION(m);
+	    len > (ssize_t)sizeof(*o);
+	    o = D6_CNEXT_OPTION(o))
+	{
+		ol = ntohs(o->len);
+		if (sizeof(*o) + ol > len) {
+			errno =	EINVAL;
+			break;
+		}
+		len -= sizeof(*o) + ol;
+		oc = ntohs(o->code);
+		if (has_option_mask(ifo->nomask6, oc))
+			continue;
+		for (i = 0, opt = ifo->dhcp6_override;
+		    i < ifo->dhcp6_override_len;
+		    i++, opt++)
+			if (opt->option == oc)
+				break;
+		if (i == ifo->dhcp6_override_len &&
+		    oc == D6_OPTION_VENDOR_OPTS &&
+		    ol > sizeof(en))
+		{
+			memcpy(&en, D6_COPTION_DATA(o), sizeof(en));
+			en = ntohl(en);
+			vo = vivso_find(en, ifp);
+		} else
+			vo = NULL;
+		if (i == ifo->dhcp6_override_len) {
+			for (i = 0, opt = ctx->dhcp6_opts;
+			    i < ctx->dhcp6_opts_len;
+			    i++, opt++)
+				if (opt->option == oc)
+					break;
+			if (i == ctx->dhcp6_opts_len)
+				opt = NULL;
+		}
+		if (opt) {
+			n += dhcp_envoption(ifp->ctx,
+			    env == NULL ? NULL : &env[n],
+			    pfx, ifp->name,
+			    opt, dhcp6_getoption, D6_COPTION_DATA(o), ol);
+		}
+		if (vo) {
+			n += dhcp_envoption(ifp->ctx,
+			    env == NULL ? NULL : &env[n],
+			    pfx, ifp->name,
+			    vo, dhcp6_getoption,
+			    D6_COPTION_DATA(o) + sizeof(en),
+			    ol - sizeof(en));
+		}
+	}
+	free(pfx);
+
+delegated:
+        /* Needed for Delegated Prefixes */
+	state = D6_CSTATE(ifp);
+	i = 0;
+	TAILQ_FOREACH(ap, &state->addrs, next) {
+		if (ap->delegating_iface) {
+			i += strlen(ap->saddr) + 1;
+		}
+	}
+	if (env && i) {
+		i += strlen(prefix) + strlen("_delegated_dhcp6_prefix=");
+                v = val = env[n] = malloc(i);
+		if (v == NULL) {
+			logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
+			return -1;
+		}
+		v += snprintf(val, i, "%s_delegated_dhcp6_prefix=", prefix);
+		TAILQ_FOREACH(ap, &state->addrs, next) {
+			if (ap->delegating_iface) {
+				/* Can't use stpcpy(3) due to "security" */
+				const char *sap = ap->saddr;
+
+				do
+					*v++ = *sap;
+				while (*++sap != '\0');
+				*v++ = ' ';
+			}
+		}
+		*--v = '\0';
+        }
+	if (i)
+		n++;
+
+	return (ssize_t)n;
+}
+
+int
+dhcp6_dump(struct interface *ifp)
+{
+	struct dhcp6_state *state;
+
+	ifp->if_data[IF_DATA_DHCP6] = state = calloc(1, sizeof(*state));
+	if (state == NULL) {
+		logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
+		return -1;
+	}
+	TAILQ_INIT(&state->addrs);
+	dhcp_set_leasefile(state->leasefile, sizeof(state->leasefile),
+	    AF_INET6, ifp,
+	    ifp->options->options & DHCPCD_PFXDLGONLY ? ".pd" : "");
+	if (dhcp6_readlease(ifp, 0) == -1) {
+		logger(ifp->ctx, LOG_ERR, "%s: %s: %m",
+		    *ifp->name ? ifp->name : state->leasefile, __func__);
+		return -1;
+	}
+	state->reason = "DUMP6";
+	return script_runreason(ifp, state->reason);
+}
diff --git a/dhcpcd-6.8.2/dhcp6.h b/dhcpcd-6.8.2/dhcp6.h
new file mode 100644
index 0000000..41b2213
--- /dev/null
+++ b/dhcpcd-6.8.2/dhcp6.h
@@ -0,0 +1,261 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef DHCP6_H
+#define DHCP6_H
+
+#include "dhcpcd.h"
+
+#define IN6ADDR_LINKLOCAL_ALLDHCP_INIT \
+	{{{ 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+	    0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02 }}}
+
+/* UDP port numbers for DHCP */
+#define DHCP6_CLIENT_PORT	546
+#define DHCP6_SERVER_PORT	547
+
+/* DHCP message type */
+#define DHCP6_SOLICIT		1
+#define DHCP6_ADVERTISE		2
+#define DHCP6_REQUEST		3
+#define DHCP6_CONFIRM		4
+#define DHCP6_RENEW		5
+#define DHCP6_REBIND		6
+#define DHCP6_REPLY		7
+#define DHCP6_RELEASE		8
+#define DHCP6_DECLINE		9
+#define DHCP6_RECONFIGURE	10
+#define DHCP6_INFORMATION_REQ	11
+#define DHCP6_RELAY_FLOW	12
+#define DHCP6_RELAY_REPL	13
+#define DHCP6_RECONFIGURE_REQ	18
+#define DHCP6_RECONFIGURE_REPLY	19
+
+#define D6_OPTION_CLIENTID		1
+#define D6_OPTION_SERVERID		2
+#define D6_OPTION_IA_NA			3
+#define D6_OPTION_IA_TA			4
+#define D6_OPTION_ORO			6
+#define D6_OPTION_IA_ADDR		5
+#define D6_OPTION_PREFERENCE		7
+#define D6_OPTION_ELAPSED		8
+#define D6_OPTION_AUTH			11
+#define D6_OPTION_UNICAST		12
+#define D6_OPTION_STATUS_CODE		13
+#define D6_OPTION_RAPID_COMMIT		14
+#define D6_OPTION_VENDOR_CLASS		16
+#define D6_OPTION_VENDOR_OPTS		17
+#define D6_OPTION_INTERFACE_ID		18
+#define D6_OPTION_RECONF_MSG		19
+#define D6_OPTION_RECONF_ACCEPT		20
+#define D6_OPTION_SIP_SERVERS_NAME	21
+#define D6_OPTION_SIP_SERVERS_ADDRESS	22
+#define D6_OPTION_DNS_SERVERS		23
+#define D6_OPTION_DOMAIN_LIST		24
+#define D6_OPTION_IA_PD			25
+#define D6_OPTION_IAPREFIX		26
+#define D6_OPTION_NIS_SERVERS		27
+#define D6_OPTION_NISP_SERVERS		28
+#define D6_OPTION_NIS_DOMAIN_NAME	29
+#define D6_OPTION_NISP_DOMAIN_NAME	30
+#define D6_OPTION_SNTP_SERVERS		31
+#define D6_OPTION_INFO_REFRESH_TIME	32
+#define D6_OPTION_BCMS_SERVER_D		33
+#define D6_OPTION_BCMS_SERVER_A		34
+#define D6_OPTION_FQDN			39
+#define D6_OPTION_POSIX_TIMEZONE	41
+#define D6_OPTION_TZDB_TIMEZONE		42
+#define D6_OPTION_PD_EXCLUDE		67
+#define D6_OPTION_SOL_MAX_RT		82
+#define D6_OPTION_INF_MAX_RT		83
+
+#define D6_FQDN_PTR	0x00
+#define D6_FQDN_BOTH	0x01
+#define D6_FQDN_NONE	0x04
+
+#include "dhcp.h"
+#include "ipv6.h"
+
+struct dhcp6_message {
+	uint8_t type;
+	uint8_t xid[3];
+	/* followed by options */
+} __packed;
+
+struct dhcp6_option {
+	uint16_t code;
+	uint16_t len;
+	/* followed by data */
+} __packed;
+
+#define D6_STATUS_OK		0
+#define D6_STATUS_FAIL		1
+#define D6_STATUS_NOADDR	2
+#define D6_STATUS_NOBINDING	3
+#define D6_STATUS_NOTONLINK	4
+#define D6_STATUS_USEMULTICAST	5
+
+#define SOL_MAX_DELAY		1
+#define SOL_TIMEOUT		1
+#define SOL_MAX_RT		3600 /* RFC7083 */
+#define REQ_TIMEOUT		1
+#define REQ_MAX_RT		30
+#define REQ_MAX_RC		10
+#define CNF_MAX_DELAY		1
+#define CNF_TIMEOUT		1
+#define CNF_MAX_RT		4
+#define CNF_MAX_RD		10
+#define REN_TIMEOUT		10
+#define REN_MAX_RT		600
+#define REB_TIMEOUT		10
+#define REB_MAX_RT		600
+#define INF_MAX_DELAY		1
+#define INF_TIMEOUT		1
+#define INF_MAX_RT		3600 /* RFC7083 */
+#define REL_TIMEOUT		1
+#define REL_MAX_RC		5
+#define DEC_TIMEOUT		1
+#define DEC_MAX_RC		5
+#define REC_TIMEOUT		2
+#define REC_MAX_RC		8
+#define HOP_COUNT_LIMIT		32
+
+/* RFC4242 3.1 */
+#define IRT_DEFAULT		86400
+#define IRT_MINIMUM		600
+
+#define DHCP6_RAND_MIN		-100
+#define DHCP6_RAND_MAX		100
+
+enum DH6S {
+	DH6S_INIT,
+	DH6S_DISCOVER,
+	DH6S_REQUEST,
+	DH6S_BOUND,
+	DH6S_RENEW,
+	DH6S_REBIND,
+	DH6S_CONFIRM,
+	DH6S_INFORM,
+	DH6S_INFORMED,
+	DH6S_RENEW_REQUESTED,
+	DH6S_PROBE,
+	DH6S_DELEGATED,
+	DH6S_RELEASE
+};
+
+struct dhcp6_state {
+	enum DH6S state;
+	time_t start_uptime;
+
+	/* Message retransmission timings */
+	struct timespec RT;
+	unsigned int IMD;
+	unsigned int RTC;
+	time_t IRT;
+	unsigned int MRC;
+	time_t MRT;
+	void (*MRCcallback)(void *);
+	time_t sol_max_rt;
+	time_t inf_max_rt;
+
+	struct dhcp6_message *send;
+	size_t send_len;
+	struct dhcp6_message *recv;
+	size_t recv_len;
+	struct dhcp6_message *new;
+	size_t new_len;
+	struct dhcp6_message *old;
+	size_t old_len;
+
+	uint32_t renew;
+	uint32_t rebind;
+	uint32_t expire;
+	struct in6_addr unicast;
+	struct ipv6_addrhead addrs;
+	uint32_t lowpl;
+	/* The +3 is for the possible .pd extension for prefix delegation */
+	char leasefile[sizeof(LEASEFILE6) + IF_NAMESIZE + (IF_SSIDSIZE * 4) +3];
+	const char *reason;
+
+	struct authstate auth;
+};
+
+#define D6_STATE(ifp)							       \
+	((struct dhcp6_state *)(ifp)->if_data[IF_DATA_DHCP6])
+#define D6_CSTATE(ifp)							       \
+	((const struct dhcp6_state *)(ifp)->if_data[IF_DATA_DHCP6])
+#define D6_STATE_RUNNING(ifp)						       \
+	(D6_CSTATE((ifp)) &&						       \
+	D6_CSTATE((ifp))->reason && dhcp6_dadcompleted((ifp)))
+
+#define D6_FIRST_OPTION(m)						       \
+    ((struct dhcp6_option *)						       \
+        ((uint8_t *)(m) + sizeof(struct dhcp6_message)))
+#define D6_NEXT_OPTION(o)						       \
+    ((struct dhcp6_option *)						       \
+        (((uint8_t *)o) + sizeof(struct dhcp6_option) + ntohs((o)->len)))
+#define D6_OPTION_DATA(o)						       \
+    ((uint8_t *)(o) + sizeof(struct dhcp6_option))
+#define D6_CFIRST_OPTION(m)						       \
+    ((const struct dhcp6_option *)					       \
+        ((const uint8_t *)(m) + sizeof(struct dhcp6_message)))
+#define D6_CNEXT_OPTION(o)						       \
+    ((const struct dhcp6_option *)					       \
+        (((const uint8_t *)o) + sizeof(struct dhcp6_option) + ntohs((o)->len)))
+#define D6_COPTION_DATA(o)						       \
+    ((const uint8_t *)(o) + sizeof(struct dhcp6_option))
+
+#ifdef INET6
+void dhcp6_printoptions(const struct dhcpcd_ctx *,
+    const struct dhcp_opt *, size_t);
+struct ipv6_addr *dhcp6_findaddr(struct dhcpcd_ctx *, const struct in6_addr *,
+    short);
+size_t dhcp6_find_delegates(struct interface *);
+int dhcp6_has_public_addr(const struct interface *);
+int dhcp6_start(struct interface *, enum DH6S);
+void dhcp6_reboot(struct interface *);
+ssize_t dhcp6_env(char **, const char *, const struct interface *,
+    const struct dhcp6_message *, size_t);
+void dhcp6_free(struct interface *);
+void dhcp6_handleifa(struct dhcpcd_ctx *, int, const char *,
+    const struct in6_addr *addr, int);
+int dhcp6_dadcompleted(const struct interface *);
+void dhcp6_drop(struct interface *, const char *);
+int dhcp6_dump(struct interface *);
+#else
+#define dhcp6_findaddr(a, b, c) (0)
+#define dhcp6_find_delegates(a) {}
+#define dhcp6_start(a, b) (0)
+#define dhcp6_reboot(a) {}
+#define dhcp6_env(a, b, c, d, e) {}
+#define dhcp6_free(a) {}
+#define dhcp6_dadcompleted(a) (0)
+#define dhcp6_drop(a, b) {}
+#define dhcp6_dump(a) (-1)
+#endif
+
+#endif
diff --git a/dhcpcd-6.8.2/dhcpcd-definitions.conf b/dhcpcd-6.8.2/dhcpcd-definitions.conf
new file mode 100644
index 0000000..0e5aa3b
--- /dev/null
+++ b/dhcpcd-6.8.2/dhcpcd-definitions.conf
@@ -0,0 +1,533 @@
+# Copyright (c) 2006-2015 Roy Marples
+# All rights reserved
+
+# DHCP option definitions for dhcpcd(8)
+# These are used to translate DHCP options into shell variables
+# for use in dhcpcd-run-hooks(8)
+# See dhcpcd.conf(5) for details
+
+##############################################################################
+# DHCP RFC2132 options unless otheriwse stated
+define 1	request ipaddress	subnet_mask
+# RFC3442 states that the CSR has to come before all other routes
+# For completeness we also specify static routes then routers
+define 121	rfc3442			classless_static_routes
+# Option 249 is an IANA assigned private number used by Windows DHCP servers
+# to provide the exact same information as option 121, classless static routes
+define 249	rfc3442			ms_classless_static_routes
+define 33	request array ipaddress	static_routes
+define 3	request array ipaddress	routers
+define 2	uint32			time_offset
+define 4	array ipaddress		time_servers
+define 5	array ipaddress		ien116_name_servers
+define 6	array ipaddress		domain_name_servers
+define 7	array ipaddress		log_servers
+define 8	array ipaddress		cookie_servers
+define 9	array ipaddress		lpr_servers
+define 10	array ipaddress		impress_servers
+define 11	array ipaddress		resource_location_servers
+define 12	dname			host_name
+define 13	uint16			boot_size
+define 14	string			merit_dump
+# Technically domain_name is not an array, but many servers expect clients
+# to treat it as one.
+define 15	array dname		domain_name
+define 16	ipaddress		swap_server
+define 17	string			root_path
+define 18	string			extensions_path
+define 19	byte			ip_forwarding
+define 20	byte			non_local_source_routing
+define 21	array ipaddress		policy_filter
+define 22	int16			max_dgram_reassembly
+define 23	uint16			default_ip_ttl
+define 24	uint32			path_mtu_aging_timeout
+define 25	array uint16		path_mtu_plateau_table
+define 26	uint16			interface_mtu
+define 27	byte			all_subnets_local
+define 28	request ipaddress	broadcast_address
+define 29	byte			perform_mask_discovery
+define 30	byte			mask_supplier
+define 31	byte			router_discovery
+define 32	ipaddress		router_solicitation_address
+define 34	byte			trailer_encapsulation
+define 35	uint32			arp_cache_timeout
+define 36	uint16			ieee802_3_encapsulation
+define 37	byte			default_tcp_ttl
+define 38	uint32			tcp_keepalive_interval
+define 39	byte			tcp_keepalive_garbage
+define 40	string			nis_domain
+define 41	array ipaddress		nis_servers
+define 42	array ipaddress		ntp_servers
+define 43	binhex			vendor_encapsulated_options
+define 44	array ipaddress		netbios_name_servers
+define 45	ipaddress		netbios_dd_server
+define 46	byte			netbios_node_type
+define 47	string			netbios_scope
+define 48	array ipaddress		font_servers
+define 49	array ipaddress		x_display_manager
+define 50	ipaddress		dhcp_requested_address
+define 51	request uint32		dhcp_lease_time
+define 52	byte			dhcp_option_overload
+define 53	byte			dhcp_message_type
+define 54	ipaddress		dhcp_server_identifier
+define 55	array byte		dhcp_parameter_request_list
+define 56	string			dhcp_message
+define 57	uint16			dhcp_max_message_size
+define 58	request uint32		dhcp_renewal_time
+define 59	request uint32		dhcp_rebinding_time
+define 60	binhex			vendor_class_identifier
+define 61	binhex			dhcp_client_identifier
+define 64	string			nisplus_domain
+define 65	array ipaddress		nisplus_servers
+define 66	dname			tftp_server_name
+define 67	string			bootfile_name
+define 68	array ipaddress		mobile_ip_home_agent
+define 69	array ipaddress		smtp_server
+define 70	array ipaddress		pop_server
+define 71	array ipaddress		nntp_server
+define 72	array ipaddress		www_server
+define 73	array ipaddress		finger_server
+define 74	array ipaddress		irc_server
+define 75	array ipaddress		streettalk_server
+define 76	array ipaddress		streettalk_directory_assistance_server
+
+# DHCP User Class, RFC3004
+define 77	binhex			user_class
+
+# DHCP SLP Directory Agent, RFC2610
+define 78	embed			slp_agent
+embed		byte			mandatory
+embed		array ipaddress		address
+define 79	embed			slp_service
+embed		byte			mandatory
+embed		ascii			scope_list
+
+# DHCP Rapid Commit, RFC4039
+define 80	norequest flag		rapid_commit
+
+# DHCP Fully Qualified Domain Name, RFC4702
+define 81	embed			fqdn
+embed		byte			flags
+embed		byte			rcode1
+embed		byte			rcode2
+embed		domain			fqdn
+
+# Option 82 is for Relay Agents and DHCP servers
+
+# Options 83 ad 84 are unused, RFC3679
+
+# DHCP Novell Directory Services, RFC2241
+define 85	array ipaddress		nds_servers
+define 86	raw			nds_tree_name
+define 87	raw			nds_context
+
+# DHCP Broadcast and Multicast Control Server, RFC4280
+define 88	array domain		bcms_controller_names
+define 89	array ipaddress		bcms_controller_address
+
+# DHCP Authentication, RFC3118
+define 90	embed			auth
+embed		byte			protocol
+embed		byte			algorithm
+embed		byte			rdm
+embed		binhex:8		replay
+embed		binhex			information
+
+# DHCP Leasequery, RFC4388
+define 91	uint32			client_last_transaction_time
+define 92	array ipaddress		associated_ip
+
+# DHCP Options for Intel Preboot eXecution Environent (PXE), RFC4578
+# Options 93, 94 and 97 are used but of no use to dhcpcd
+
+# Option 95 used by Apple but never published RFC3679
+# Option 96 is unused, RFC3679
+
+# DHCP The Open Group's User Authentication Protocol, RFC2485
+define 98	string			uap_servers
+
+# DHCP Civic Addresses Configuration Information, RFC4776
+define 99	encap			geoconf_civic
+embed		byte			what
+embed		uint16			country_code
+# The rest of this option is not supported
+
+# DHCP Timezone, RFC4883
+define 100	string			posix_timezone
+define 101	string			tzdb_timezone
+
+# Options 102-115 are unused, RFC3679
+
+# DHCP Auto-Configuration, RFC2563
+define 116	byte			auto_configure
+
+# DHCP Name Service Search, RFC2937
+define 117	array uint16		name_service_search
+
+# DHCP Subnet Selection, RFC3011
+define 118	ipaddress		subnet_selection
+
+# DHCP Domain Search, RFC3397
+define 119	array domain		domain_search
+
+# DHCP Session Initiated Protocol Servers, RFC3361
+define 120	rfc3361			sip_server
+
+# Option 121 is defined at the top of this file
+
+# DHCP CableLabs Client, RFC3495
+define 122	encap			tsp
+encap 1		ipaddress		dhcp_server
+encap 2		ipaddress		dhcp_secondary_server
+encap 3		rfc3361			provisioning_server
+encap 4		embed			as_req_as_rep_backoff
+embed		uint32			nominal
+embed		uint32			maximum
+embed		uint32			retry
+encap 5		embed			ap_req_ap_rep_backoff
+embed		uint32			nominal
+embed		uint32			maximum
+embed		uint32			retry
+encap 6		domain			kerberos_realm
+encap 7		byte			ticket_granting_server_utilization
+encap 8		byte			provisioning_timer
+
+# DHCP Coordinate LCI, RFC6225
+# We have no means of expressing 6 bit lengths
+define 123	binhex			geoconf
+
+# DHCP Vendor-Identifying Vendor Options, RFC3925
+define 124	binhex			vivco
+define 125	embed			vivso
+embed		uint32			enterprise_number
+# Vendor options are shared between DHCP/DHCPv6
+# Their code is matched to the enterprise number defined above
+# see the end of this file for an example
+
+# Options 126 and 127 are unused, RFC3679
+
+# DHCP Options for Intel Preboot eXecution Environent (PXE), RFC4578
+# Options 128-135 are used but of no use to dhcpcd
+
+# DHCP PANA Authentication Agent, RFC5192
+define 136	array ipaddress		pana_agent
+
+# DHCP Lost Server, RFC5223
+define 137	domain			lost_server
+
+# DHCP CAPWAP, RFC5417
+define 138	array ipaddress		capwap_ac
+
+# DHCP Mobility Services, RFC5678
+define 139	encap			mos_ip
+encap 1		array ipaddress		is
+encap 2		array ipaddress		cs
+encap 3		array ipaddress		es
+define 140	encap			mos_domain
+encap 1		domain			is
+encap 2		domain			cs
+encap 3		domain			es
+
+# DHCP SIP UA, RFC6011
+define 141	array domain		sip_ua_cs_list
+
+# DHCP ANDSF, RFC6153
+define 142	array ipaddress		andsf
+define 143	array ip6address	andsf6
+
+# DHCP Coordinate LCI, RFC6225
+# We have no means of expressing 6 bit lengths
+define 144	binhex			geoloc
+
+# DHCP FORCERENEW Nonce Capability, RFC6704
+define 145	array byte		forcerenew_nonce_capable
+
+# DHCP RDNSS Selection for MIF Nodes, RFC6731
+define 146	embed			rdnss_selection
+embed		byte			prf
+embed		ipaddress		primary
+embed		ipaddress		secondary
+embed		array domain		domains
+
+# Options 147, 148 and 149 are unused, RFC3942
+
+# DHCP TFTP Server Address, RFC5859
+define 150	array ipaddress		tftp_servers
+
+# Options 151-157 are used for Lease Query, RFC6926 and not for dhcpcd
+# Options 158-174 are unused, RFC3942
+# Options 175-177 are tentativel assigned for Etherboot
+# Options 178-207 are unused, RFC3942
+
+# DHCP PXELINUX, RFC5071
+define 208	binhex			pxelinux_magic
+define 209	string			config_file
+define 210	string			path_prefix
+define 211	uint32			reboot_time
+
+# DHCP IPv6 Rapid Deployment on IPv4 Infrastructures, RFC5969
+define 212	rfc5969			sixrd
+
+# DHCP Access Network Domain Name, RFC5986
+define 213	domain			access_domain
+
+# Options 214-219 are unused, RFC3942
+
+# DHCP Subnet Allocation, RFC6656
+# Option 220 looks specific to Cisco hardware.
+
+# DHCP Virtual Subnet Selection, RFC6607
+define 221	encap			vss
+encap 0		string			nvt
+encap 1		binhex			vpn_id
+encap 255	flag			global
+
+# Web Proxy Auto-Discovery
+define 252  string          wpad_url
+
+# Options 222 and 223 are unused, RFC3942
+# Options 224-254 are reserved for Private Use
+# Option 255 End
+
+##############################################################################
+# DHCPv6 options, RFC3315
+define6 1	binhex			client_id
+define6 2	binhex			server_id
+
+define6 3	norequest index embed	ia_na
+embed		binhex:4		iaid
+embed		uint32			t1
+embed		uint32			t2
+encap 5		option
+encap 13	option
+
+define6 4	norequest index embed	ia_ta
+embed		uint32			iaid
+encap 5		option
+encap 13	option
+
+define6 5	norequest index embed	ia_addr
+embed		ip6address		ia_addr
+embed		uint32			pltime
+embed		uint32			vltime
+encap 13	option
+
+define6 6	array uint16		option_request
+define6 7	byte			preference
+define6 8	uint16			elased_time
+define6 9	binhex			dhcp_relay_msg
+
+# Option 10 is unused
+
+define6 11	embed			auth
+embed		byte			protocol
+embed		byte			algorithm
+embed		byte			rdm
+embed		binhex:8		replay
+embed		binhex			information
+
+define6 12	ip6address		unicast
+
+define6 13	norequest embed		status_code
+embed		uint16			status_code
+embed		string			message
+
+define6 14	norequest flag		rapid_commit
+define6 15	binhex			user_class
+
+define6 16	binhex			vivco
+define6 17	embed			vivso
+embed		uint32			enterprise_number
+# Vendor options are shared between DHCP/DHCPv6
+# Their code is matched to the enterprise number defined above
+# See the end of this file for an example
+
+define6 18	binhex			interface_id
+define6 19	byte			reconfigure_msg
+define6 20	flag			reconfigure_accept
+
+# DHCPv6 Session Initiation Protocol Options, RFC3319
+define6 21	array domain		sip_servers_names
+define6 22	array ip6address	sip_servers_addresses
+
+# DHCPv6 DNS Configuration Options, RFC3646
+define6 23	array ip6address	name_servers
+define6 24	array domain		domain_search
+
+# DHCPv6 Prefix Options, RFC6603
+define6 25	norequest index embed	ia_pd
+embed		binhex:4		iaid
+embed		uint32			t1
+embed		uint32			t2
+encap 26	option
+define6 26	index embed		prefix
+embed		uint32			pltime
+embed		uint32			vltime
+embed		byte			length
+embed		ip6address		prefix
+encap 13	option
+encap 67	option
+
+# DHCPv6 Network Information Service Options, RFC3898
+define6 27	array ip6address	nis_servers
+define6 28	array ip6address	nisp_servers
+define6 29	string			nis_domain_name
+define6 30	string			nisp_domain_name
+
+# DHCPv6 Simple Network Time Protocol Servers Option, RFC4075
+define6 31	array ip6address	sntp_servers
+
+# DHCPv6 Information Refresh Time, RFC4242
+define6 32	uint32			info_refresh_time
+
+# DHCPv6 Broadcast and Multicast Control Server, RFC4280
+define6 33	array domain		bcms_server_d
+define6 34	array ip6address	bcms_server_a
+
+# DHCP Civic Addresses Configuration Information, RFC4776
+define6 36	encap			geoconf_civic
+embed		byte			what
+embed		uint16			country_code
+# The rest of this option is not supported
+
+# DHCP Relay Agent Remote-ID, RFC4649
+define6 37	embed			remote_id
+embed		uint32			enterprise_number
+embed		binhex			remote_id
+
+# DHCP Relay Agent Subscriber-ID, RFC4580
+define6 38	binhex			subscriber_id
+
+# DHCPv6 Fully Qualified Domain Name, RFC4704
+define6 39	embed			fqdn
+embed		byte			flags
+embed		domain			fqdn
+
+# DHCPv6 PANA Authentication Agnet, RC5192
+define6 40	array ip6address	pana_agent
+
+# DHCPv6 Timezone options, RFC4883
+define6 41	string			posix_timezone
+define6 42	string			tzdb_timezone
+
+# DHCPv6 Relay Agent Echo Request
+define6 43	array uint16		ero
+
+# Options 44-48 are used for Lease Query, RFC5007 and not for dhcpcd
+
+# DHCPv6 Home Info Discovery in MIPv6, RFC6610
+define6 49	domain			mip6_hnidf
+define6 50	encap			mip6_vdinf
+encap 71	option
+encap 72	option
+encap 73	option
+
+# DHCPv6 Lost Server, RFC5223
+define6 51	domain			lost_server
+
+# DHCPv6 CAPWAP, RFC5417
+define6 52	array ip6address	capwap_ac
+
+# DHCPv6 Relay-ID, RFC5460
+define6 53	binhex			relay_id
+
+# DHCP Mobility Services, RFC5678
+define6 54	encap			mos_ip
+encap 1		array ip6address	is
+encap 2		array ip6address	cs
+encap 3		array ip6address	es
+define6 55 	encap			mos_domain
+encap 1		domain			is
+encap 2		domain			cs
+encap 3		domain			es
+
+# DHCPv6 Network Time Protocol Server, RFC5908
+define6 56	encap			ntp_server
+encap 1		ip6address		addr
+encap 2		ip6address		mcast_addr
+encap 3		ip6address		fqdn
+
+# DHCPv6 LIS Discovery, RFC5986
+define6 57	domain			access_domain
+
+# DHCPv6 SIP UA, RFC6011
+define6 58	array domain		sip_ua_cs_list
+
+# DHCPv6 Network Boot, RFC5970
+define6 59	string			bootfile_url
+# We presently cannot decode bootfile_param
+define6 60	binhex			bootfile_param
+define6 61	array uint16		architecture_types
+define6 62	embed			nii
+embed		byte			type
+embed		byte			major
+embed		byte			minor
+
+# DHCPv6 Coordinate LCI, RFC6225
+# We have no means of expressing 6 bit lengths
+define6 63	binhex			geoloc
+
+# DHCPv6 AFTR-Name, RFC6334
+define6 64	domain			aftr_name
+
+# DHCPv6 Prefix Exclude Option, RFC6603
+define6 67	embed			pd_exclude
+embed		byte			prefix_len
+embed		binhex			subnetID
+
+# DHCPv6 Home Info Discovery in MIPv6, RFC6610
+define6 69	encap			mip6_idinf
+encap 71	option
+encap 72	option
+encap 73	option
+define6 70	encap			mip6_udinf
+encap 71	option
+encap 72	option
+encap 73	option
+define6	71	embed			mip6_hnp
+embed		byte			prefix_len
+embed		ip6address		prefix
+define6 72	ip6address		mip6_haa
+define6 73	domain			mip6_haf
+
+# DHCPv6 RDNSS Selection for MIF Nodes, RFC6731
+define6 74	embed			rdnss_selection
+embed		ip6address		server
+embed		byte			prf
+embed		array domain		domains
+
+# DHCPv6 Kerberos, RFC6784
+define6 75	string			krb_principal_name
+define6 76	string			krb_realm_name
+define6 78	embed			krb_kdc
+embed		uint16			priority
+embed		uint16			weight
+embed		byte			transport_type
+embed		uint16			port
+embed		ip6address		address
+embed		string			realm_name
+
+# DHCPv6 Client Link-Layer Address, RFC6939
+# Section 7 states that clients MUST ignore the option 79
+
+# DHCPv6 Relay-Triggered Reconfiguraion, RFC6977
+define6 80	ip6address		link_address
+
+# DHCPv6 Radius, RFC7037
+# Section 7 states that clients MUST ignore the option 81
+
+# DHCPv6 SOL_MAX_RT, RFC7083
+define6 82	request uint32		sol_max_rt
+define6	83	request uint32		inf_max_rt
+
+# DHCPv6 Address Selection Policy
+# Currently not supported
+
+# Options 86-65535 are unasssinged
+
+##############################################################################
+# Vendor-Identifying Vendor Options
+# An example:
+#vendopt 12345	encap			frobozzco
+#encap 1	string			maze_location
+#encap 2	byte			grue_probability
diff --git a/dhcpcd-6.8.2/dhcpcd-embedded.c b/dhcpcd-6.8.2/dhcpcd-embedded.c
new file mode 100644
index 0000000..4029747
--- /dev/null
+++ b/dhcpcd-6.8.2/dhcpcd-embedded.c
@@ -0,0 +1,343 @@
+/*
+ * DO NOT EDIT!
+ * Automatically generated from dhcpcd-embedded.conf
+ * Ths allows us to simply generate DHCP structure without any C programming.
+ */
+
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <unistd.h>
+
+const char * const dhcpcd_embedded_conf[] = {
+"define 1 request ipaddress subnet_mask",
+"define 121 rfc3442 classless_static_routes",
+"define 249 rfc3442 ms_classless_static_routes",
+"define 33 request array ipaddress static_routes",
+"define 3 request array ipaddress routers",
+"define 2 uint32 time_offset",
+"define 4 array ipaddress time_servers",
+"define 5 array ipaddress ien116_name_servers",
+"define 6 array ipaddress domain_name_servers",
+"define 7 array ipaddress log_servers",
+"define 8 array ipaddress cookie_servers",
+"define 9 array ipaddress lpr_servers",
+"define 10 array ipaddress impress_servers",
+"define 11 array ipaddress resource_location_servers",
+"define 12 dname host_name",
+"define 13 uint16 boot_size",
+"define 14 string merit_dump",
+"define 15 array dname domain_name",
+"define 16 ipaddress swap_server",
+"define 17 string root_path",
+"define 18 string extensions_path",
+"define 19 byte ip_forwarding",
+"define 20 byte non_local_source_routing",
+"define 21 array ipaddress policy_filter",
+"define 22 int16 max_dgram_reassembly",
+"define 23 uint16 default_ip_ttl",
+"define 24 uint32 path_mtu_aging_timeout",
+"define 25 array uint16 path_mtu_plateau_table",
+"define 26 uint16 interface_mtu",
+"define 27 byte all_subnets_local",
+"define 28 request ipaddress broadcast_address",
+"define 29 byte perform_mask_discovery",
+"define 30 byte mask_supplier",
+"define 31 byte router_discovery",
+"define 32 ipaddress router_solicitation_address",
+"define 34 byte trailer_encapsulation",
+"define 35 uint32 arp_cache_timeout",
+"define 36 uint16 ieee802_3_encapsulation",
+"define 37 byte default_tcp_ttl",
+"define 38 uint32 tcp_keepalive_interval",
+"define 39 byte tcp_keepalive_garbage",
+"define 40 string nis_domain",
+"define 41 array ipaddress nis_servers",
+"define 42 array ipaddress ntp_servers",
+"define 43 string vendor_encapsulated_options",
+"define 44 array ipaddress netbios_name_servers",
+"define 45 ipaddress netbios_dd_server",
+"define 46 byte netbios_node_type",
+"define 47 string netbios_scope",
+"define 48 array ipaddress font_servers",
+"define 49 array ipaddress x_display_manager",
+"define 50 ipaddress dhcp_requested_address",
+"define 51 request uint32 dhcp_lease_time",
+"define 52 byte dhcp_option_overload",
+"define 53 byte dhcp_message_type",
+"define 54 ipaddress dhcp_server_identifier",
+"define 55 array byte dhcp_parameter_request_list",
+"define 56 string dhcp_message",
+"define 57 uint16 dhcp_max_message_size",
+"define 58 request uint32 dhcp_renewal_time",
+"define 59 request uint32 dhcp_rebinding_time",
+"define 60 binhex vendor_class_identifier",
+"define 61 binhex dhcp_client_identifier",
+"define 64 string nisplus_domain",
+"define 65 array ipaddress nisplus_servers",
+"define 66 dname tftp_server_name",
+"define 67 string bootfile_name",
+"define 68 array ipaddress mobile_ip_home_agent",
+"define 69 array ipaddress smtp_server",
+"define 70 array ipaddress pop_server",
+"define 71 array ipaddress nntp_server",
+"define 72 array ipaddress www_server",
+"define 73 array ipaddress finger_server",
+"define 74 array ipaddress irc_server",
+"define 75 array ipaddress streettalk_server",
+"define 76 array ipaddress streettalk_directory_assistance_server",
+"define 77 binhex user_class",
+"define 78 embed slp_agent",
+"embed byte mandatory",
+"embed array ipaddress address",
+"define 79 embed slp_service",
+"embed byte mandatory",
+"embed ascii scope_list",
+"define 80 norequest flag rapid_commit",
+"define 81 embed fqdn",
+"embed byte flags",
+"embed byte rcode1",
+"embed byte rcode2",
+"embed domain fqdn",
+"define 85 array ipaddress nds_servers",
+"define 86 raw nds_tree_name",
+"define 87 raw nds_context",
+"define 88 array domain bcms_controller_names",
+"define 89 array ipaddress bcms_controller_address",
+"define 90 embed auth",
+"embed byte protocol",
+"embed byte algorithm",
+"embed byte rdm",
+"embed binhex:8 replay",
+"embed binhex information",
+"define 91 uint32 client_last_transaction_time",
+"define 92 array ipaddress associated_ip",
+"define 98 string uap_servers",
+"define 99 encap geoconf_civic",
+"embed byte what",
+"embed uint16 country_code",
+"define 100 string posix_timezone",
+"define 101 string tzdb_timezone",
+"define 116 byte auto_configure",
+"define 117 array uint16 name_service_search",
+"define 118 ipaddress subnet_selection",
+"define 119 array domain domain_search",
+"define 120 rfc3361 sip_server",
+"define 122 encap tsp",
+"encap 1 ipaddress dhcp_server",
+"encap 2 ipaddress dhcp_secondary_server",
+"encap 3 rfc3361 provisioning_server",
+"encap 4 embed as_req_as_rep_backoff",
+"embed uint32 nominal",
+"embed uint32 maximum",
+"embed uint32 retry",
+"encap 5 embed ap_req_ap_rep_backoff",
+"embed uint32 nominal",
+"embed uint32 maximum",
+"embed uint32 retry",
+"encap 6 domain kerberos_realm",
+"encap 7 byte ticket_granting_server_utilization",
+"encap 8 byte provisioning_timer",
+"define 123 binhex geoconf",
+"define 124 binhex vivco",
+"define 125 embed vivso",
+"embed uint32 enterprise_number",
+"define 136 array ipaddress pana_agent",
+"define 137 domain lost_server",
+"define 138 array ipaddress capwap_ac",
+"define 139 encap mos_ip",
+"encap 1 array ipaddress is",
+"encap 2 array ipaddress cs",
+"encap 3 array ipaddress es",
+"define 140 encap mos_domain",
+"encap 1 domain is",
+"encap 2 domain cs",
+"encap 3 domain es",
+"define 141 array domain sip_ua_cs_list",
+"define 142 array ipaddress andsf",
+"define 143 array ip6address andsf6",
+"define 144 binhex geoloc",
+"define 145 array byte forcerenew_nonce_capable",
+"define 146 embed rdnss_selection",
+"embed byte prf",
+"embed ipaddress primary",
+"embed ipaddress secondary",
+"embed array domain domains",
+"define 150 array ipaddress tftp_servers",
+"define 208 binhex pxelinux_magic",
+"define 209 string config_file",
+"define 210 string path_prefix",
+"define 211 uint32 reboot_time",
+"define 212 rfc5969 sixrd",
+"define 213 domain access_domain",
+"define 221 encap vss",
+"encap 0 string nvt",
+"encap 1 binhex vpn_id",
+"encap 255 flag global",
+"define 252 string wpad_url",
+"define6 1 binhex client_id",
+"define6 2 binhex server_id",
+"define6 3 norequest index embed ia_na",
+"embed binhex:4 iaid",
+"embed uint32 t1",
+"embed uint32 t2",
+"encap 5 option",
+"encap 13 option",
+"define6 4 norequest index embed ia_ta",
+"embed uint32 iaid",
+"encap 5 option",
+"encap 13 option",
+"define6 5 norequest index embed ia_addr",
+"embed ip6address ia_addr",
+"embed uint32 pltime",
+"embed uint32 vltime",
+"encap 13 option",
+"define6 6 array uint16 option_request",
+"define6 7 byte preference",
+"define6 8 uint16 elased_time",
+"define6 9 binhex dhcp_relay_msg",
+"define6 11 embed auth",
+"embed byte protocol",
+"embed byte algorithm",
+"embed byte rdm",
+"embed binhex:8 replay",
+"embed binhex information",
+"define6 12 ip6address unicast",
+"define6 13 norequest embed status_code",
+"embed uint16 status_code",
+"embed string message",
+"define6 14 norequest flag rapid_commit",
+"define6 15 binhex user_class",
+"define6 16 binhex vivco",
+"define6 17 embed vivso",
+"embed uint32 enterprise_number",
+"define6 18 binhex interface_id",
+"define6 19 byte reconfigure_msg",
+"define6 20 flag reconfigure_accept",
+"define6 21 array domain sip_servers_names",
+"define6 22 array ip6address sip_servers_addresses",
+"define6 23 array ip6address name_servers",
+"define6 24 array domain domain_search",
+"define6 25 norequest index embed ia_pd",
+"embed binhex:4 iaid",
+"embed uint32 t1",
+"embed uint32 t2",
+"encap 26 option",
+"define6 26 index embed prefix",
+"embed uint32 pltime",
+"embed uint32 vltime",
+"embed byte length",
+"embed ip6address prefix",
+"encap 13 option",
+"encap 67 option",
+"define6 27 array ip6address nis_servers",
+"define6 28 array ip6address nisp_servers",
+"define6 29 string nis_domain_name",
+"define6 30 string nisp_domain_name",
+"define6 31 array ip6address sntp_servers",
+"define6 32 uint32 info_refresh_time",
+"define6 33 array domain bcms_server_d",
+"define6 34 array ip6address bcms_server_a",
+"define6 36 encap geoconf_civic",
+"embed byte what",
+"embed uint16 country_code",
+"define6 37 embed remote_id",
+"embed uint32 enterprise_number",
+"embed binhex remote_id",
+"define6 38 binhex subscriber_id",
+"define6 39 embed fqdn",
+"embed byte flags",
+"embed domain fqdn",
+"define6 40 array ip6address pana_agent",
+"define6 41 string posix_timezone",
+"define6 42 string tzdb_timezone",
+"define6 43 array uint16 ero",
+"define6 49 domain mip6_hnidf",
+"define6 50 encap mip6_vdinf",
+"encap 71 option",
+"encap 72 option",
+"encap 73 option",
+"define6 51 domain lost_server",
+"define6 52 array ip6address capwap_ac",
+"define6 53 binhex relay_id",
+"define6 54 encap mos_ip",
+"encap 1 array ip6address is",
+"encap 2 array ip6address cs",
+"encap 3 array ip6address es",
+"define6 55  encap mos_domain",
+"encap 1 domain is",
+"encap 2 domain cs",
+"encap 3 domain es",
+"define6 56 encap ntp_server",
+"encap 1 ip6address addr",
+"encap 2 ip6address mcast_addr",
+"encap 3 ip6address fqdn",
+"define6 57 domain access_domain",
+"define6 58 array domain sip_ua_cs_list",
+"define6 59 string bootfile_url",
+"define6 60 binhex bootfile_param",
+"define6 61 array uint16 architecture_types",
+"define6 62 embed nii",
+"embed byte type",
+"embed byte major",
+"embed byte minor",
+"define6 63 binhex geoloc",
+"define6 64 domain aftr_name",
+"define6 67 embed pd_exclude",
+"embed byte prefix_len",
+"embed binhex subnetID",
+"define6 69 encap mip6_idinf",
+"encap 71 option",
+"encap 72 option",
+"encap 73 option",
+"define6 70 encap mip6_udinf",
+"encap 71 option",
+"encap 72 option",
+"encap 73 option",
+"define6 71 embed mip6_hnp",
+"embed byte prefix_len",
+"embed ip6address prefix",
+"define6 72 ip6address mip6_haa",
+"define6 73 domain mip6_haf",
+"define6 74 embed rdnss_selection",
+"embed ip6address server",
+"embed byte prf",
+"embed array domain domains",
+"define6 75 string krb_principal_name",
+"define6 76 string krb_realm_name",
+"define6 78 embed krb_kdc",
+"embed uint16 priority",
+"embed uint16 weight",
+"embed byte transport_type",
+"embed uint16 port",
+"embed ip6address address",
+"embed string realm_name",
+"define6 80 ip6address link_address",
+"define6 82 request uint32 sol_max_rt",
+"define6 83 request uint32 inf_max_rt",
+NULL
+};
diff --git a/dhcpcd-6.8.2/dhcpcd-embedded.c.in b/dhcpcd-6.8.2/dhcpcd-embedded.c.in
new file mode 100644
index 0000000..fcaa629
--- /dev/null
+++ b/dhcpcd-6.8.2/dhcpcd-embedded.c.in
@@ -0,0 +1,36 @@
+/*
+ * DO NOT EDIT!
+ * Automatically generated from dhcpcd-embedded.conf
+ * Ths allows us to simply generate DHCP structure without any C programming.
+ */
+
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <unistd.h>
+
+const char * const dhcpcd_embedded_conf[] = {
diff --git a/dhcpcd-6.8.2/dhcpcd-embedded.h b/dhcpcd-6.8.2/dhcpcd-embedded.h
new file mode 100644
index 0000000..1a245e4
--- /dev/null
+++ b/dhcpcd-6.8.2/dhcpcd-embedded.h
@@ -0,0 +1,31 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#define INITDEFINES	122
+#define INITDEFINE6S	68
+
+extern const char * const dhcpcd_embedded_conf[];
diff --git a/dhcpcd-6.8.2/dhcpcd-embedded.h.in b/dhcpcd-6.8.2/dhcpcd-embedded.h.in
new file mode 100644
index 0000000..3d15316
--- /dev/null
+++ b/dhcpcd-6.8.2/dhcpcd-embedded.h.in
@@ -0,0 +1,31 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#define INITDEFINES	@INITDEFINES@
+#define INITDEFINE6S	@INITDEFINE6S@
+
+extern const char * const dhcpcd_embedded_conf[];
diff --git a/dhcpcd-6.8.2/dhcpcd-hooks/01-test b/dhcpcd-6.8.2/dhcpcd-hooks/01-test
new file mode 100644
index 0000000..261f7ca
--- /dev/null
+++ b/dhcpcd-6.8.2/dhcpcd-hooks/01-test
@@ -0,0 +1,8 @@
+# Just echo our DHCP options we have
+
+if [ "$reason" = "TEST" ]; then
+	set | grep "^\(interface\|pid\|reason\|profile\|skip_hooks\)=" | sort
+	set | grep "^if\(carrier\|flags\|mtu\|wireless\|ssid\)=" | sort
+	set | grep "^\(new_\|old_\|ra_count=\|ra[0-9]*_\)" | sort
+	exit 0
+fi
diff --git a/dhcpcd-6.8.2/dhcpcd-hooks/02-dump b/dhcpcd-6.8.2/dhcpcd-hooks/02-dump
new file mode 100644
index 0000000..0d515f7
--- /dev/null
+++ b/dhcpcd-6.8.2/dhcpcd-hooks/02-dump
@@ -0,0 +1,8 @@
+# Just echo our DHCP options we have
+
+case "$reason" in
+DUMP|DUMP6)
+	set | sed -ne 's/^new_//p' | sort
+	exit 0
+	;;
+esac
diff --git a/dhcpcd-6.8.2/dhcpcd-hooks/10-mtu b/dhcpcd-6.8.2/dhcpcd-hooks/10-mtu
new file mode 100644
index 0000000..f8657cb
--- /dev/null
+++ b/dhcpcd-6.8.2/dhcpcd-hooks/10-mtu
@@ -0,0 +1,38 @@
+# Configure the MTU for the interface
+
+mtu_dir="$state_dir/mtu"
+
+set_mtu()
+{
+	local mtu=$1
+
+	if [ -w /sys/class/net/$interface/mtu ]; then
+		echo "$mtu" >/sys/class/net/$interface/mtu
+	else
+		ifconfig "$interface" mtu "$mtu"
+	fi
+}
+
+if [ "$reason" = PREINIT -a -e "$mtu_dir/$interface" ]; then
+	rm "$mtu_dir/$interface"
+elif [ -n "$new_interface_mtu" ] && $if_up; then
+	# The smalled MTU dhcpcd can work with is 576
+	if [ "$new_interface_mtu" -ge 576 ]; then
+		if set_mtu "$new_interface_mtu"; then
+			syslog info "MTU set to $new_interface_mtu"
+			# Save the MTU so we can restore it later
+			if [ ! -e "$mtu_dir/$interface" ]; then
+				mkdir -p "$mtu_dir"
+				echo "$ifmtu" > "$mtu_dir/$interface"
+			fi
+		fi
+	fi
+elif [ -e "$mtu_dir/$interface" ]; then
+	if $if_up || $if_down; then
+		# No MTU in this state, so restore the prior MTU
+		mtu=$(cat "$mtu_dir/$interface")
+		syslog info "MTU restored to $mtu"
+		set_mtu "$mtu"
+		rm "$mtu_dir/$interface"
+	fi
+fi
diff --git a/dhcpcd-6.8.2/dhcpcd-hooks/10-wpa_supplicant b/dhcpcd-6.8.2/dhcpcd-hooks/10-wpa_supplicant
new file mode 100644
index 0000000..9eec0c1
--- /dev/null
+++ b/dhcpcd-6.8.2/dhcpcd-hooks/10-wpa_supplicant
@@ -0,0 +1,119 @@
+# Start, reconfigure and stop wpa_supplicant per wireless interface.
+# This is needed because wpa_supplicant lacks hotplugging of any kind
+# and the user should not be expected to have to wire it into their system
+# if the base system doesn't do this itself.
+
+if [ -z "$wpa_supplicant_conf" ]; then
+	for x in \
+		/etc/wpa_supplicant/wpa_supplicant-"$interface".conf \
+		/etc/wpa_supplicant/wpa_supplicant.conf \
+		/etc/wpa_supplicant-"$interface".conf \
+		/etc/wpa_supplicant.conf \
+	; do
+		if [ -s "$x" ]; then
+			wpa_supplicant_conf="$x"
+			break
+		fi
+	done
+fi
+: ${wpa_supplicant_conf:=/etc/wpa_supplicant.conf}
+
+wpa_supplicant_ctrldir()
+{
+	local dir
+
+	dir=$(key_get_value "[[:space:]]*ctrl_interface=" \
+		"$wpa_supplicant_conf")
+	dir=$(trim "$dir")
+	case "$dir" in
+	DIR=*)
+		dir=${dir##DIR=}
+		dir=${dir%%[[:space:]]GROUP=*}
+		dir=$(trim "$dir")
+		;;
+	esac
+	printf %s "$dir"
+}
+
+wpa_supplicant_start()
+{
+	local dir err errn
+
+	# If the carrier is up, don't bother checking anything
+	[ "$ifcarrier" = "up" ] && return 0
+
+	# Pre flight checks
+	if [ ! -s "$wpa_supplicant_conf" ]; then
+		syslog warn \
+			"$wpa_supplicant_conf does not exist"
+		syslog warn "not interacting with wpa_supplicant(8)"
+		return 1
+	fi
+	dir=$(wpa_supplicant_ctrldir)
+	if [ -z "$dir" ]; then
+		syslog warn \
+			"ctrl_interface not defined in $wpa_supplicant_conf"
+		syslog warn "not interacting with wpa_supplicant(8)"
+		return 1
+	fi
+
+	wpa_cli -p "$dir" -i "$interface" status >/dev/null 2>&1 && return 0
+	syslog info "starting wpa_supplicant"
+	driver=${wpa_supplicant_driver:+-D}$wpa_supplicant_driver
+	err=$(wpa_supplicant -B -c"$wpa_supplicant_conf" -i"$interface" \
+	    "$driver" 2>&1)
+	errn=$?
+	if [ $errn != 0 ]; then
+		syslog err "failed to start wpa_supplicant"
+		syslog err "$err"
+	fi
+	return $errn
+}
+
+wpa_supplicant_reconfigure()
+{
+	local dir err errn
+
+	dir=$(wpa_supplicant_ctrldir)
+	[ -z "$dir" ] && return 1
+	if ! wpa_cli -p "$dir" -i "$interface" status >/dev/null 2>&1; then
+		wpa_supplicant_start
+		return $?
+	fi
+	syslog info "reconfiguring wpa_supplicant"
+	err=$(wpa_cli -p "$dir" -i "$interface" reconfigure 2>&1)
+	errn=$?
+	if [ $errn != 0 ]; then
+		syslog err "failed to reconfigure wpa_supplicant"
+		syslog err "$err"
+	fi
+	return $errn
+}
+
+wpa_supplicant_stop()
+{
+	local dir err errn
+
+	dir=$(wpa_supplicant_ctrldir)
+	[ -z "$dir" ] && return 1
+	wpa_cli -p "$dir" -i "$interface" status >/dev/null 2>&1 || return 0
+	syslog info "stopping wpa_supplicant"
+	err=$(wpa_cli -i"$interface" terminate 2>&1)
+	errn=$?
+	if [ $errn != 0 ]; then
+		syslog err "failed to start wpa_supplicant"
+		syslog err "$err"
+	fi
+	return $errn
+}
+
+if [ "$ifwireless" = "1" ] && \
+    type wpa_supplicant >/dev/null 2>&1 && \
+    type wpa_cli >/dev/null 2>&1
+then
+	case "$reason" in
+	PREINIT)	wpa_supplicant_start;;
+	RECONFIGURE)	wpa_supplicant_reconfigure;;
+	DEPARTED)	wpa_supplicant_stop;;
+	esac
+fi
diff --git a/dhcpcd-6.8.2/dhcpcd-hooks/15-timezone b/dhcpcd-6.8.2/dhcpcd-hooks/15-timezone
new file mode 100644
index 0000000..0ccdc45
--- /dev/null
+++ b/dhcpcd-6.8.2/dhcpcd-hooks/15-timezone
@@ -0,0 +1,48 @@
+# Configure timezone
+
+: ${localtime:=/etc/localtime}
+
+set_zoneinfo()
+{
+	local zoneinfo_dir= zone_file=
+
+	[ -z "$new_tzdb_timezone" ] && return 0
+
+	for d in \
+		/usr/share/zoneinfo	\
+		/usr/lib/zoneinfo	\
+		/var/share/zoneinfo	\
+		/var/zoneinfo		\
+	; do
+		if [ -d "$d" ]; then
+			zoneinfo_dir="$d"
+			break
+		fi
+	done
+
+	if [ -z "$zoneinfo_dir" ]; then
+		syslog warning "timezone directory not found"
+		return 1
+	fi
+
+	zone_file="$zoneinfo_dir/$new_tzdb_timezone"
+	if [ ! -e "$zone_file" ]; then
+		syslog warning "no timezone definition for $new_tzdb_timezone"
+		return 1
+	fi
+
+	if copy_file "$zone_file" "$localtime"; then
+		syslog info "timezone changed to $new_tzdb_timezone"
+	fi
+}
+
+# For ease of use, map DHCP6 names onto our DHCP4 names
+case "$reason" in
+BOUND6|RENEW6|REBIND6|REBOOT6|INFORM6)
+	new_tzdb_timezone="$new_dhcp6_tzdb_timezone"
+	;;
+esac
+
+if $if_up; then
+ 	set_zoneinfo
+fi
diff --git a/dhcpcd-6.8.2/dhcpcd-hooks/20-resolv.conf b/dhcpcd-6.8.2/dhcpcd-hooks/20-resolv.conf
new file mode 100644
index 0000000..c9f7bed
--- /dev/null
+++ b/dhcpcd-6.8.2/dhcpcd-hooks/20-resolv.conf
@@ -0,0 +1,164 @@
+# Generate /etc/resolv.conf
+# Support resolvconf(8) if available
+# We can merge other dhcpcd resolv.conf files into one like resolvconf,
+# but resolvconf is preferred as other applications like VPN clients
+# can readily hook into it.
+# Also, resolvconf can configure local nameservers such as bind
+# or dnsmasq. This is important as the libc resolver isn't that powerful.
+
+resolv_conf_dir="$state_dir/resolv.conf"
+NL="
+"
+
+build_resolv_conf()
+{
+	local cf="$state_dir/resolv.conf.$ifname"
+	local interfaces= header= search= srvs= servers= x=
+
+	# Build a list of interfaces
+	interfaces=$(list_interfaces "$resolv_conf_dir")
+
+	# Build the resolv.conf
+	if [ -n "$interfaces" ]; then
+		# Build the header
+		for x in ${interfaces}; do
+			header="$header${header:+, }$x"
+		done
+
+		# Build the search list
+		domain=$(cd "$resolv_conf_dir"; \
+			key_get_value "domain " ${interfaces})
+		search=$(cd "$resolv_conf_dir"; \
+			key_get_value "search " ${interfaces})
+		set -- ${domain}
+		domain="$1"
+		[ -n "$2" ] && search="$search $*"
+		[ -n "$search" ] && search="$(uniqify $search)"
+		[ "$domain" = "$search" ] && search=
+		[ -n "$domain" ] && domain="domain $domain$NL"
+		[ -n "$search" ] && search="search $search$NL"
+
+		# Build the nameserver list
+		srvs=$(cd "$resolv_conf_dir"; \
+			key_get_value "nameserver " ${interfaces})
+		for x in $(uniqify ${srvs}); do
+			servers="${servers}nameserver $x$NL"
+		done
+	fi
+	header="$signature_base${header:+ $from }$header"
+
+	# Assemble resolv.conf using our head and tail files
+	[ -f "$cf" ] && rm -f "$cf"
+	[ -d "$resolv_conf_dir" ] || mkdir -p "$resolv_conf_dir"
+	echo "$header" > "$cf"
+	if [ -f /etc/resolv.conf.head ]; then
+		cat /etc/resolv.conf.head >> "$cf"
+	else
+		echo "# /etc/resolv.conf.head can replace this line" >> "$cf"
+	fi
+	printf %s "$domain$search$servers" >> "$cf"
+	if [ -f /etc/resolv.conf.tail ]; then
+		cat /etc/resolv.conf.tail >> "$cf"
+	else
+		echo "# /etc/resolv.conf.tail can replace this line" >> "$cf"
+	fi
+	if change_file /etc/resolv.conf "$cf"; then
+		chmod 644 /etc/resolv.conf
+	fi
+	rm -f "$cf"
+}
+
+add_resolv_conf()
+{
+	local x= conf="$signature$NL" i=${ra_count:-0} ra= warn=true
+
+	while [ $i -ne 0 ]; do
+		eval ra=\$ra${i}_rdnss
+		new_domain_name_servers="$new_domain_name_servers${new_domain_name_servers:+ }$ra"
+		eval ra=\$ra${i}_dnssl
+		new_domain_search="$new_domain_search${new_domain_search:+ }$ra"
+		i=$(($i - 1))
+	done
+
+	# If we don't have any configuration, remove it
+	if [ -z "$new_domain_name_servers" -a \
+		-z "$new_domain_name" -a \
+		-z "$new_domain_search" ]; then
+		remove_resolv_conf
+		return $?
+	fi
+
+	# Derive a new domain from our various hostname options
+	if [ -z "$new_domain_name" ]; then
+		if [ "$new_dhcp6_fqdn" != "${new_dhcp6_fqdn#*.}" ]; then
+			new_domain_name="${new_dhcp6_fqdn#*.}"
+		elif [ "$new_fqdn" != "${new_fqdn#*.}" ]; then
+			new_domain_name="${new_fqdn#*.}"
+		elif [ "$new_host_name" != "${new_host_name#*.}" ]; then
+			new_domain_name="${new_host_name#*.}"
+		fi
+	fi
+
+	if [ -n "$new_domain_name" ]; then
+		set -- $new_domain_name
+		if valid_domainname "$1"; then
+			conf="${conf}domain $1$NL"
+		else
+			syslog err "Invalid domain name: $1"
+		fi
+		# If there is no search this, make this one
+		if [ -z "$new_domain_search" ]; then
+			new_domain_search="$new_domain_name"
+			[ "$new_domain_name" = "$1" ] && warn=true
+		fi
+	fi
+	if [ -n "$new_domain_search" ]; then
+		if valid_domainname_list $new_domain_search; then
+			conf="${conf}search $new_domain_search$NL"
+		elif ! $warn; then
+			syslog err "Invalid domain name in list:" \
+			    "$new_domain_search"
+		fi
+	fi
+	for x in ${new_domain_name_servers}; do
+		conf="${conf}nameserver $x$NL"
+	done
+	if type resolvconf >/dev/null 2>&1; then
+		[ -n "$ifmetric" ] && export IF_METRIC="$ifmetric"
+		printf %s "$conf" | resolvconf -a "$ifname"
+		return $?
+	fi
+
+	if [ -e "$resolv_conf_dir/$ifname" ]; then
+		rm -f "$resolv_conf_dir/$ifname"
+	fi
+	[ -d "$resolv_conf_dir" ] || mkdir -p "$resolv_conf_dir"
+	printf %s "$conf" > "$resolv_conf_dir/$ifname"
+	build_resolv_conf
+}
+
+remove_resolv_conf()
+{
+	if type resolvconf >/dev/null 2>&1; then
+		resolvconf -d "$ifname" -f
+	else
+		if [ -e "$resolv_conf_dir/$ifname" ]; then
+			rm -f "$resolv_conf_dir/$ifname"
+		fi
+		build_resolv_conf
+	fi
+}
+
+# For ease of use, map DHCP6 names onto our DHCP4 names
+case "$reason" in
+BOUND6|RENEW6|REBIND6|REBOOT6|INFORM6)
+	new_domain_name_servers="$new_dhcp6_name_servers"
+	new_domain_search="$new_dhcp6_domain_search"
+	;;
+esac
+
+if $if_up || [ "$reason" = ROUTERADVERT ]; then
+	add_resolv_conf
+elif $if_down; then
+	remove_resolv_conf
+fi
diff --git a/dhcpcd-6.8.2/dhcpcd-hooks/29-lookup-hostname b/dhcpcd-6.8.2/dhcpcd-hooks/29-lookup-hostname
new file mode 100644
index 0000000..04ad275
--- /dev/null
+++ b/dhcpcd-6.8.2/dhcpcd-hooks/29-lookup-hostname
@@ -0,0 +1,40 @@
+# Lookup the hostname in DNS if not set
+
+lookup_hostname()
+{
+	[ -z "$new_ip_address" ] && return 1
+	local h=
+	# Silly ISC programs love to send error text to stdout
+	if type dig >/dev/null 2>&1; then
+		h=$(dig +short -x $new_ip_address)
+		if [ $? = 0 ]; then
+			echo "$h" | sed 's/\.$//'
+			return 0
+		fi
+	elif type host >/dev/null 2>&1; then
+		h=$(host $new_ip_address)
+		if [ $? = 0 ]; then 
+			echo "$h" \
+			| sed 's/.* domain name pointer \(.*\)./\1/'
+			return 0
+		fi
+	elif type getent >/dev/null 2>&1; then
+		h=$(getent hosts $new_ip_address)
+		if [ $? = 0 ]; then
+			echo "$h" | sed 's/[^ ]* *\([^ ]*\).*/\1/'
+			return 0
+		 fi
+	fi
+	return 1
+}
+
+set_hostname()
+{
+	if [ -z "$new_host_name" -a -z "$new_fqdn_name" ]; then
+		export new_host_name="$(lookup_hostname)"
+	fi
+}
+
+if $if_up; then
+	set_hostname
+fi
diff --git a/dhcpcd-6.8.2/dhcpcd-hooks/30-hostname b/dhcpcd-6.8.2/dhcpcd-hooks/30-hostname
new file mode 100644
index 0000000..616fb82
--- /dev/null
+++ b/dhcpcd-6.8.2/dhcpcd-hooks/30-hostname
@@ -0,0 +1,154 @@
+# Set the hostname from DHCP data if required
+
+# A hostname can either be a short hostname or a FQDN.
+# hostname_fqdn=true
+# hostname_fqdn=false
+# hostname_fqdn=server
+
+# A value of server means just what the server says, don't manipulate it.
+# This could lead to an inconsistent hostname on a DHCPv4 and DHCPv6 network
+# where the DHCPv4 hostname is short and the DHCPv6 has an FQDN.
+# DHCPv6 has no hostname option.
+# RFC4702 section 3.1 says FQDN should be prefered over hostname.
+#
+# As such, the default is hostname_fqdn=true so that a consistent hostname
+# is always assigned.
+: ${hostname_fqdn:=true}
+
+# Some systems don't have hostname(1)
+_hostname()
+{
+	local name=
+
+	if [ -z "$1" ]; then
+		if type hostname >/dev/null 2>&1; then
+			hostname
+		elif [ -r /proc/sys/kernel/hostname ]; then
+			read name </proc/sys/kernel/hostname && echo "$name"
+		elif sysctl kern.hostname >/dev/null 2>&1; then
+			sysctl -n kern.hostname
+		elif sysctl kernel.hostname >/dev/null 2>&1; then
+			sysctl -n kernel.hostname
+		else
+			return 1
+		fi
+		return $?
+	fi
+
+	# Always prefer hostname(1) if we have it
+	if type hostname >/dev/null 2>&1; then
+		hostname "$1"
+	elif [ -w /proc/sys/kernel/hostname ]; then
+		echo "$1" >/proc/sys/kernel/hostname
+	elif sysctl kern.hostname >/dev/null 2>&1; then
+		sysctl -w "kern.hostname=$1"
+	elif sysctl kernel.hostname >/dev/null 2>&1; then
+		sysctl -w "kernel.hostname=$1"
+	else
+		# We know this will fail, but it will now fail
+		# with an error to stdout
+		hostname "$1"
+	fi
+}
+
+need_hostname()
+{
+	local hostname hfqdn=false hshort=false
+
+	case "$force_hostname" in
+	[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|1) return 0;;
+	esac
+
+	hostname="$(_hostname)"
+	case "$hostname" in
+	""|"(none)"|localhost|localhost.localdomain) return 0;;
+	esac
+	
+	case "$hostname_fqdn" in
+	[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|1)	hfqdn=true;;
+	[Ss][Ee][Rr][Vv][Ee][Rr])		;;
+	*)					hshort=true;;
+	esac
+
+	if [ -n "$old_fqdn" ]; then
+		if ${hfqdn} || ! ${hsort}; then
+			[ "$hostname" = "$old_fqdn" ]
+		else
+			[ "$hostname" = "${old_fqdn%%.*}" ]
+		fi
+	elif [ -n "$old_host_name" ]; then
+		if ${hfqdn}; then
+			if [ -n "$old_domain_name" -a \
+			    "$old_host_name" = "${old_host_name#*.}" ]
+			then
+				[ "$hostname" = \
+				    "$old_host_name.$old_domain_name" ]
+			else
+				[ "$hostname" = "$old_host_name" ]
+			fi
+		elif ${hshort}; then
+			[ "$hostname" = "${old_host_name%%.*}" ]
+		else
+			[ "$hostname" = "$old_host_name" ]
+		fi
+	else
+		# No old hostname
+		false
+	fi
+}
+
+try_hostname()
+{
+
+	if valid_domainname "$1"; then
+		_hostname "$1"
+	else
+		syslog err "Invalid hostname: $1"
+	fi
+}
+
+set_hostname()
+{
+	local hfqdn=false hshort=false
+
+	need_hostname || return
+
+	case "$hostname_fqdn" in
+	[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|1)	hfqdn=true;;
+	"")					;;
+	*)					hshort=true;;
+	esac
+
+	if [ -n "$new_fqdn" ]; then
+		if ${hfqdn} || ! ${hshort}; then
+			try_hostname "$new_fqdn"
+		else
+			try_hostname "${new_fqdn%%.*}"
+		fi
+	elif [ -n "$new_host_name" ]; then
+		if ${hfqdn}; then
+			if [ -n "$new_domain_name" -a \
+			    "$new_host_name" = "${new_host_name#*.}" ]
+			then
+				try_hostname "$new_host_name.$new_domain_name"
+			else
+				try_hostname "$new_host_name"
+			fi
+		elif ${hshort}; then
+			try_hostname "${new_host_name%%.*}"
+		else
+			try_hostname "$new_host_name"
+		fi
+	fi
+}
+
+# For ease of use, map DHCP6 names onto our DHCP4 names
+case "$reason" in
+BOUND6|RENEW6|REBIND6|REBOOT6|INFORM6)
+	new_fqdn="$new_dhcp6_fqdn"
+	;;
+esac
+
+if $if_up; then
+	set_hostname
+fi
diff --git a/dhcpcd-6.8.2/dhcpcd-hooks/50-dhcpcd-compat b/dhcpcd-6.8.2/dhcpcd-hooks/50-dhcpcd-compat
new file mode 100644
index 0000000..0d6256e
--- /dev/null
+++ b/dhcpcd-6.8.2/dhcpcd-hooks/50-dhcpcd-compat
@@ -0,0 +1,41 @@
+# Compat enter hook shim for older dhcpcd versions
+
+IPADDR=$new_ip_address
+INTERFACE=$interface
+NETMASK=$new_subnet_mask
+BROADCAST=$new_broadcast_address
+NETWORK=$new_network_number
+DHCPSID=$new_dhcp_server_identifier
+GATEWAYS=$new_routers
+DNSSERVERS=$new_domain_name_servers
+DNSDOMAIN=$new_domain_name
+DNSSEARCH=$new_domain_search
+NISDOMAIN=$new_nis_domain
+NISSERVERS=$new_nis_servers
+NTPSERVERS=$new_ntp_servers
+
+GATEWAY=
+for x in $new_routers; do
+	GATEWAY="$GATEWAY${GATEWAY:+,}$x"
+done
+DNS=
+for x in $new_domain_name_servers; do
+	DNS="$DNS${DNS:+,}$x"
+done
+
+r="down"
+case "$reason" in
+RENEW) r="up";;
+BOUND|INFORM|REBIND|REBOOT|TEST|TIMEOUT|IPV4LL) r="new";;
+esac
+
+if [ "$r" != "down" ]; then
+	rm -f /var/lib/dhcpcd-"$INTERFACE".info
+	for x in IPADDR INTERFACE NETMASK BROADCAST NETWORK DHCPSID GATEWAYS \
+		DNSSERVERS DNSDOMAIN DNSSEARCH NISDOMAIN NISSERVERS \
+		NTPSERVERS GATEWAY DNS; do
+		eval echo "$x=\'\$$x\'" >> /var/lib/dhcpcd-"$INTERFACE".info
+	done
+fi
+
+set -- /var/lib/dhcpcd-"$INTERFACE".info "$r"
diff --git a/dhcpcd-6.8.2/dhcpcd-hooks/50-ntp.conf b/dhcpcd-6.8.2/dhcpcd-hooks/50-ntp.conf
new file mode 100644
index 0000000..551c5be
--- /dev/null
+++ b/dhcpcd-6.8.2/dhcpcd-hooks/50-ntp.conf
@@ -0,0 +1,118 @@
+# Sample dhcpcd hook script for ntp
+# Like our resolv.conf hook script, we store a database of ntp.conf files
+# and merge into /etc/ntp.conf
+
+# You can set the env var NTP_CONF to another file like this
+#   dhcpcd -e NTP_CONF=/usr/pkg/etc/ntpd.conf
+# or by adding this to /etc/dhcpcd.enter-hook
+#   NTP_CONF=/usr/pkg/etc/ntpd.conf
+# to use OpenNTPD instead of the default NTP.
+
+if type invoke-rc.d >/dev/null 2>&1; then
+	# Debian has a seperate file for DHCP config to avoid stamping on
+	# the master.
+	[ -e /var/lib/ntp ] || mkdir /var/lib/ntp
+	: ${ntp_service:=ntp}
+	: ${NTP_DHCP_CONF:=/var/lib/ntp/ntp.conf.dhcp}
+fi
+
+: ${ntp_service:=ntpd}
+: ${ntp_restart_cmd:=service_condcommand $ntp_service restart}
+ntp_conf_dir="$state_dir/ntp.conf"
+
+# If we have installed OpenNTPD but not NTP then prefer it
+# XXX If both exist then update both?
+if [ -z "$NTP_CONF" -a -e /etc/ntpd.conf -a ! -e /etc/ntp.conf ]; then
+	: ${NTP_CONF:=/etc/ntpd.conf}
+else
+	: ${NTP_CONF:=/etc/ntp.conf}
+fi
+
+ntp_conf=${NTP_CONF}
+NL="
+"
+
+build_ntp_conf()
+{
+	local cf="$state_dir/ntp.conf.$ifname"
+	local interfaces= header= srvs= servers= x=
+
+	# Build a list of interfaces
+	interfaces=$(list_interfaces "$ntp_conf_dir")
+
+	if [ -n "$interfaces" ]; then
+		# Build the header
+		for x in ${interfaces}; do
+			header="$header${header:+, }$x"
+		done
+
+		# Build a server list
+		srvs=$(cd "$ntp_conf_dir";
+			key_get_value "server " $interfaces)
+		if [ -n "$srvs" ]; then
+			for x in $(uniqify $srvs); do
+				servers="${servers}server $x$NL"
+			done
+		fi
+	fi
+
+	# Merge our config into ntp.conf
+	[ -e "$cf" ] && rm -f "$cf"
+	[ -d "$ntp_conf_dir" ] || mkdir -p "$ntp_conf_dir"
+
+	if [ -n "$NTP_DHCP_CONF" ]; then
+		[ -e "$ntp_conf" ] && cp "$ntp_conf" "$cf"
+		ntp_conf="$NTP_DHCP_CONF"
+	elif [ -e "$ntp_conf" ]; then
+		remove_markers "$signature_base" "$signature_base_end" \
+			"$ntp_conf" > "$cf"
+	fi
+
+	if [ -n "$servers" ]; then
+		echo "$signature_base${header:+ $from }$header" >> "$cf"
+		printf %s "$servers" >> "$cf"
+		echo "$signature_base_end${header:+ $from }$header" >> "$cf"
+	else
+		[ -e "$ntp_conf" -a -e "$cf" ] || return
+	fi
+
+	# If we changed anything, restart ntpd
+	if change_file "$ntp_conf" "$cf"; then
+		[ -n "$ntp_restart_cmd" ] && eval $ntp_restart_cmd
+	fi
+}
+
+add_ntp_conf()
+{
+	local cf="$ntp_conf_dir/$ifname" x=
+
+	[ -e "$cf" ] && rm "$cf"
+	[ -d "$ntp_conf_dir" ] || mkdir -p "$ntp_conf_dir"
+	if [ -n "$new_ntp_servers" ]; then
+		for x in $new_ntp_servers; do
+			echo "server $x" >> "$cf"
+		done
+	fi
+	build_ntp_conf
+}
+
+remove_ntp_conf()
+{
+	if [ -e "$ntp_conf_dir/$ifname" ]; then
+		rm "$ntp_conf_dir/$ifname"
+	fi
+	build_ntp_conf
+}
+
+# For ease of use, map DHCP6 names onto our DHCP4 names
+case "$reason" in
+BOUND6|RENEW6|REBIND6|REBOOT6|INFORM6)
+	new_ntp_servers="$new_dhcp6_sntp_servers"
+;;
+esac
+
+if $if_up; then
+	add_ntp_conf
+elif $if_down; then
+	remove_ntp_conf
+fi
diff --git a/dhcpcd-6.8.2/dhcpcd-hooks/50-yp.conf b/dhcpcd-6.8.2/dhcpcd-hooks/50-yp.conf
new file mode 100644
index 0000000..2da68eb
--- /dev/null
+++ b/dhcpcd-6.8.2/dhcpcd-hooks/50-yp.conf
@@ -0,0 +1,56 @@
+# Sample dhcpcd hook for ypbind
+# This script is only suitable for the Linux version.
+
+ypbind_pid()
+{
+	[ -s /var/run/ypbind.pid ] && cat /var/run/ypbind.pid
+}
+
+make_yp_conf()
+{
+	[ -z "$new_nis_domain" -a -z "$new_nis_servers" ] && return 0
+	local cf=/etc/yp.conf."$ifname" prefix= x= pid=
+	rm -f "$cf"
+	echo "$signature" > "$cf"
+	if [ -n "$new_nis_domain" ]; then
+		if ! valid_domainname "$new_nis_domain"; then
+			syslog err "Invalid NIS domain name: $new_nis_domain"
+			rm -f "$cf"
+			return 1
+		fi
+		domainname "$new_nis_domain"
+		if [ -n "$new_nis_servers" ]; then
+			prefix="domain $new_nis_domain server "
+		else
+			echo "domain $new_nis_domain broadcast" >> "$cf"
+		fi
+	else
+		prefix="ypserver "
+	fi
+	for x in $new_nis_servers; do
+		echo "$prefix$x" >> "$cf"
+	done
+	save_conf /etc/yp.conf
+	cat "$cf" > /etc/yp.conf
+	rm -f "$cf"
+	pid="$(ypbind_pid)"
+	if [ -n "$pid" ]; then
+		kill -HUP "$pid"
+	fi
+}
+
+restore_yp_conf()
+{
+	[ -n "$old_nis_domain" ] && domainname ""
+	restore_conf /etc/yp.conf || return 0
+	local pid="$(ypbind_pid)"
+	if [ -n "$pid" ]; then
+		kill -HUP "$pid"
+	fi
+}
+
+if $if_up; then
+	make_yp_conf
+elif $if_down; then
+	restore_yp_conf
+fi
diff --git a/dhcpcd-6.8.2/dhcpcd-hooks/50-ypbind.in b/dhcpcd-6.8.2/dhcpcd-hooks/50-ypbind.in
new file mode 100644
index 0000000..a9ebbfa
--- /dev/null
+++ b/dhcpcd-6.8.2/dhcpcd-hooks/50-ypbind.in
@@ -0,0 +1,86 @@
+# Sample dhcpcd hook for ypbind
+# This script is only suitable for the BSD versions.
+
+: ${ypbind_restart_cmd:=service_command ypbind restart}
+: ${ypbind_stop_cmd:=service_condcommand ypbind stop}
+ypbind_dir="$state_dir/ypbind"
+: ${ypdomain_dir:=@YPDOMAIN_DIR@}
+: ${ypdomain_suffix:=@YPDOMAIN_SUFFIX@}
+
+
+best_domain()
+{
+	local i=
+
+	for i in "$ypbind_dir/$interface_order".*; do
+		if [ -f "$i" ]; then
+			cat "$i"
+			return 0
+		fi
+	done
+	return 1
+}
+
+make_yp_binding()
+{
+	[ -d "$ypbind_dir" ] || mkdir -p "$ypbind_dir"
+	echo "$new_nis_domain" >"$ypbind_dir/$ifname"
+
+	if [ -z "$ypdomain_dir" ]; then
+		false
+	else
+		local cf="$ypdomain_dir/$new_nis_domain$ypdomain_suffix"
+		if [ -n "$new_nis_servers" ]; then
+			local ncf="$cf.$ifname" x=
+			rm -f "$ncf"
+			for x in $new_nis_servers; do
+				echo "$x" >>"$ncf"
+			done
+			change_file "$cf" "$ncf"
+		else
+			[ -e "$cf" ] && rm "$cf"
+		fi
+	fi
+
+	local nd="$(best_domain)"
+	if [ $? = 0 -a "$nd" != "$(domainname)" ]; then
+		domainname "$nd"
+		if [ -n "$ypbind_restart_cmd" ]; then
+			eval $ypbind_restart_cmd
+		fi
+	fi
+}
+
+restore_yp_binding()
+{
+
+	rm -f "$ypbind_dir/$ifname"
+	local nd="$(best_domain)"
+	# We need to stop ypbind if there is no best domain
+	# otherwise it will just stall as we cannot set domainname
+	# to blank :/
+	if [ -z "$nd" ]; then
+		if [ -n "$ypbind_stop_cmd" ]; then
+			eval $ypbind_stop_cmd
+		fi
+	elif [ "$nd" != "$(domainname)" ]; then
+		domainname "$nd"
+		if [ -n "$ypbind_restart_cmd" ]; then
+			eval $ypbind_restart_cmd
+		fi
+	fi
+}
+
+if [ "$reason" = PREINIT ]; then
+	rm -f "$ypbind_dir/$interface".*
+elif $if_up || $if_down; then
+	if [ -n "$new_nis_domain" ]; then
+		if valid_domainname "$new_nis_domain"; then
+			make_yp_binding
+		else
+			syslog err "Invalid NIS domain name: $new_nis_domain"
+		fi
+	elif [ -n "$old_nis_domain" ]; then
+		restore_yp_binding
+	fi
+fi
diff --git a/dhcpcd-6.8.2/dhcpcd-hooks/GNUmakefile b/dhcpcd-6.8.2/dhcpcd-hooks/GNUmakefile
new file mode 100644
index 0000000..1f97d8c
--- /dev/null
+++ b/dhcpcd-6.8.2/dhcpcd-hooks/GNUmakefile
@@ -0,0 +1,2 @@
+TOP?=	..
+include ${TOP}/GNUmakefile
diff --git a/dhcpcd-6.8.2/dhcpcd-hooks/Makefile b/dhcpcd-6.8.2/dhcpcd-hooks/Makefile
new file mode 100644
index 0000000..6328509
--- /dev/null
+++ b/dhcpcd-6.8.2/dhcpcd-hooks/Makefile
@@ -0,0 +1,30 @@
+TOP?=	../
+include ${TOP}/Makefile.inc
+include ${TOP}/iconfig.mk
+
+SCRIPTSDIR=	${LIBEXECDIR}/dhcpcd-hooks
+SCRIPTS=	01-test 02-dump
+SCRIPTS+=	10-mtu 10-wpa_supplicant 15-timezone 20-resolv.conf
+SCRIPTS+=	29-lookup-hostname 30-hostname
+SCRIPTS+=	${HOOKSCRIPTS}
+
+50-ypbind: 50-ypbind.in
+	${SED} \
+		-e 's:@YPDOMAIN_DIR@:${YPDOMAIN_DIR}:g' \
+		-e 's:@YPDOMAIN_SUFFIX@:${YPDOMAIN_SUFFIX}:g' \
+		50-ypbind.in > $@
+
+all: ${HOOKSCRIPTS}
+
+clean:
+	rm -f 50-ypbind
+
+proginstall: ${HOOKSCRIPTS}
+	${INSTALL} -d ${DESTDIR}${SCRIPTSDIR}
+	${INSTALL} -m ${NONBINMODE} ${SCRIPTS} ${DESTDIR}${SCRIPTSDIR}
+
+install: proginstall
+
+import: ${HOOKSCRIPTS}
+	${INSTALL} -d /tmp/${DISTPREFIX}/dhcpcd-hooks
+	${INSTALL} -m ${NONBINMODE} ${SCRIPTS} /tmp/${DISTPREFIX}/dhcpcd-hooks
diff --git a/dhcpcd-6.8.2/dhcpcd-run-hooks.8.in b/dhcpcd-6.8.2/dhcpcd-run-hooks.8.in
new file mode 100644
index 0000000..87d85f4
--- /dev/null
+++ b/dhcpcd-6.8.2/dhcpcd-run-hooks.8.in
@@ -0,0 +1,222 @@
+.\" Copyright (c) 2006-2015 Roy Marples
+.\" All rights reserved
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.Dd October 3, 2014
+.Dt DHCPCD-RUN-HOOKS 8
+.Os
+.Sh NAME
+.Nm dhcpcd-run-hooks
+.Nd DHCP client configuration script
+.Sh DESCRIPTION
+.Nm
+is used by
+.Xr dhcpcd 8
+to run any system and user defined hook scripts.
+System hook scripts are found in
+.Pa @HOOKDIR@
+and the user defined hooks are
+.Pa @SYSCONFDIR@/dhcpcd.enter-hook .
+and
+.Pa @SYSCONFDIR@/dhcpcd.exit-hook .
+The default install supplies hook scripts for configuring
+.Pa /etc/resolv.conf
+and the hostname.
+Your distribution may have included other hook scripts to say configure
+ntp or ypbind.
+A test hook is also supplied that simply echos the dhcp variables to the
+console from DISCOVER message.
+.Pp
+Each time
+.Nm
+is invoked,
+.Ev $interface
+is set to the interface that
+.Nm dhcpcd
+is run on and
+.Ev $reason
+is to the reason why
+.Nm
+was invoked.
+DHCP information to be configured is held in variables starting with the word
+new_ and old DHCP information to be removed is held in variables starting with
+the word old_.
+.Nm dhcpcd
+can display the full list of variables it knows how about by using the
+.Fl V , -variables
+argument.
+.Pp
+Here's a list of reasons why
+.Nm
+could be invoked:
+.Bl -tag -width EXPIREXXXEXPIRE6
+.It Dv PREINIT
+dhcpcd is starting up and any pre-initialisation should be done.
+.It Dv CARRIER
+dhcpcd has detected the carrier is up.
+This is generally just a notification and no action need be taken.
+.It Dv NOCARRIER
+dhcpcd lost the carrier.
+The cable may have been unplugged or association to the wireless point lost.
+.It Dv INFORM | Dv INFORM6
+dhcpcd informed a DHCP server about it's address and obtained other
+configuration details.
+.It Dv BOUND | Dv BOUND6
+dhcpcd obtained a new lease from a DHCP server.
+.It Dv RENEW | Dv RENEW6
+dhcpcd renewed it's lease.
+.It Dv REBIND | Dv REBIND6
+dhcpcd has rebound to a new DHCP server.
+.It Dv REBOOT | Dv REBOOT6
+dhcpcd successfully requested a lease from a DHCP server.
+.It Dv DELEGATED6
+dhcpcd assigned a delegated prefix to the interface.
+.It Dv IPV4LL
+dhcpcd failed to contact any DHCP servers but did obtain an IPV4LL address.
+.It Dv STATIC
+dhcpcd has been configured with a static configuration which has not been
+obtained from a DHCP server.
+.It Dv 3RDPARTY
+dhcpcd is monitoring the interface for a 3rd party to give it an IP address.
+.It Dv TIMEOUT
+dhcpcd failed to contact any DHCP servers but was able to use an old lease.
+.It Dv EXPIRE | EXPIRE6
+dhcpcd's lease or state expired and it failed to obtain a new one.
+.It Dv NAK
+dhcpcd received a NAK from the DHCP server.
+This should be treated as EXPIRE.
+.It Dv RECONFIGURE
+dhcpcd has been instructed to reconfigure an interface.
+.It Dv ROUTERADVERT
+dhcpcd has received an IPv6 Router Advertisment, or one has expired.
+.It Dv STOP | Dv STOP6
+dhcpcd stopped running on the interface.
+.It Dv STOPPED
+dhcpcd has stopped entirely.
+.It Dv DEPARTED
+The interface has been removed.
+.It Dv FAIL
+dhcpcd failed to operate on the interface.
+This normally happens when dhcpcd does not support the raw interface, which
+means it cannot work as a DHCP or ZeroConf client.
+Static configuration and DHCP INFORM is still allowed.
+.It Dv DUMP
+dhcpcd has been asked to dump the last lease for the interface.
+.It Dv TEST
+dhcpcd received an OFFER from a DHCP server but will not configure the
+interface.
+This is primarily used to test the variables are filled correctly for the
+script to process them.
+.El
+.Sh ENVIRONMENT
+.Nm dhcpcd
+will clear the environment variables aside from
+.Ev $PATH
+and
+.Ev $RC_SVCNAME .
+The following variables will then be set, along with any protocol supplied
+ones.
+.Bl -tag -width xnew_delegated_dhcp6_prefix
+.It Ev $interface
+the name of the interface.
+.It Ev $reason
+as described above.
+.It Ev $pid
+the pid of
+.Nm dhcpcd .
+.It Ev $ifcarrier
+the link status of
+.Ev $interface :
+.Dv unknown ,
+.Dv up
+or
+.Dv down .
+.It Ev $ifmetric
+.Ev $interface
+preference, lower is better.
+.It Ev $ifwireless
+.Dv 1 if
+.Ev $interface
+is wireless, otherwise
+.Dv 0 .
+.It Ev $ifflags
+.Ev $interface
+flags.
+.It Ev $ifmtu
+.Ev $interface
+MTU.
+.It Ev $ifssid
+the name of the SSID the
+.Ev interface
+is connected to.
+.It Ev $interface_order
+A list of interfaces, in order of preference.
+.It Ev $if_up
+.Dv true
+if the
+.Ev interface
+is up, otherwise
+.Dv false .
+.It Ev $if_down
+.Dv true
+if the
+.Ev interface
+is down, otherwise
+.Dv false .
+.It Ev $if_oneup
+.Dv true
+if any interface is up, otherwise false.
+.It Ev $if_ipwaited
+.Dv true
+if any interface has been assigned an IP address which matches any wait
+requirements specified in
+.Xr dhcpcd.conf 5 .
+.It Ev $profile
+the name of the profile selected from
+.Xr dhcpcd.conf 5 .
+.It Ev $new_delegated_dhcp6_prefix
+space separated list of delegated prefixes.
+.El
+.Sh FILES
+When
+.Nm
+runs, it loads
+.Pa @SYSCONFDIR@/dhcpcd.enter-hook
+and any scripts found in
+.Pa @HOOKDIR@
+in a lexical order and then finally
+.Pa @SYSCONFDIR@/dhcpcd.exit-hook
+.Sh SEE ALSO
+.Xr dhcpcd 8
+.Sh AUTHORS
+.An Roy Marples Aq Mt roy@marples.name
+.Sh BUGS
+Please report them to
+.Lk http://roy.marples.name/projects/dhcpcd
+.Sh SECURITY CONSIDERATIONS
+.Nm dhcpcd
+will validate the content of each option against its encoding.
+For string, ascii, raw or binhex encoding it's up to the user to validate it
+for the intended purpose.
+.Pp
+When used in a shell script, each variable must be quoted correctly.
diff --git a/dhcpcd-6.8.2/dhcpcd-run-hooks.in b/dhcpcd-6.8.2/dhcpcd-run-hooks.in
new file mode 100644
index 0000000..870e8ce
--- /dev/null
+++ b/dhcpcd-6.8.2/dhcpcd-run-hooks.in
@@ -0,0 +1,381 @@
+#!/bin/sh
+# dhcpcd client configuration script 
+
+# Handy variables and functions for our hooks to use
+case "$reason" in
+	ROUTERADVERT)
+		ifsuffix=".ra";;
+	INFORM6|BOUND6|RENEW6|REBIND6|REBOOT6|EXPIRE6|RELEASE6|STOP6)
+		ifsuffix=".dhcp6";;
+	*)
+		ifsuffix=".dhcp";;
+esac
+ifname="$interface$ifsuffix${ifclass+.}$ifclass"
+
+from=from
+signature_base="# Generated by dhcpcd"
+signature="$signature_base $from $ifname"
+signature_base_end="# End of dhcpcd"
+signature_end="$signature_base_end $from $ifname"
+state_dir=@RUNDIR@/dhcpcd
+_detected_init=false
+
+: ${if_up:=false}
+: ${if_down:=false}
+: ${syslog_debug:=false}
+
+# Ensure that all arguments are unique
+uniqify()
+{
+	local result= i=
+	for i do
+		case " $result " in
+			*" $i "*);;
+			*) result="$result $i";;
+		esac
+	done
+	echo "${result# *}"
+}
+
+# List interface config files in a directory.
+# If dhcpcd is running as a single instance then it will have a list of
+# interfaces in the preferred order.
+# Otherwise we just use what we have.
+list_interfaces()
+{
+	local i= x= ifaces=
+	for i in $interface_order; do
+		for x in "$1"/$i.*; do
+			[ -f "$x" ] && ifaces="$ifaces${ifaces:+ }${x##*/}"
+		done
+	done
+	for x in "$1"/*; do
+		[ -f "$x" ] && ifaces="$ifaces${ifaces:+ }${x##*/}"
+	done
+	uniqify $ifaces
+}
+
+# Trim function
+trim()
+{
+	local var="$*"
+
+	var=${var#"${var%%[![:space:]]*}"}
+	var=${var%"${var##*[![:space:]]}"}
+	if [ -z "$var" ]; then
+		# So it seems our shell doesn't support wctype(3) patterns
+		# Fall back to sed
+		var=$(echo "$*" | sed -e 's/^[[:space:]]*//;s/[[:space:]]*$//')
+	fi
+	printf %s "$var"
+}
+
+# We normally use sed to extract values using a key from a list of files
+# but sed may not always be available at the time.
+key_get_value()
+{
+	local key="$1" value= x= line=
+
+	shift
+	if type sed >/dev/null 2>&1; then
+		sed -n "s/^$key//p" $@
+	else
+		for x do
+			while read line; do
+				case "$line" in
+				"$key"*) echo "${line##$key}";;
+				esac
+			done < "$x"
+		done
+	fi
+}
+
+# We normally use sed to remove markers from a configuration file
+# but sed may not always be available at the time.
+remove_markers()
+{
+	local m1="$1" m2="$2" x= line= in_marker=0
+
+	shift; shift
+	if type sed >/dev/null 2>&1; then
+		sed "/^$m1/,/^$m2/d" $@
+	else
+		for x do
+			while read line; do
+				case "$line" in
+				"$m1"*) in_marker=1;;
+				"$m2"*) in_marker=0;;
+				*) [ $in_marker = 0 ] && echo "$line";;
+				esac
+			done < "$x"
+		done
+	fi
+}
+
+# Compare two files.
+comp_file()
+{
+
+	[ -e "$1" ] || return 1
+	[ -e "$2" ] || return 1
+
+	if type cmp >/dev/null 2>&1; then
+		cmp -s "$1" "$2"
+	elif type diff >/dev/null 2>&1; then
+		diff -q "$1" "$2" >/dev/null
+	else
+		# Hopefully we're only working on small text files ...
+		[ "$(cat "$1")" = "$(cat "$2")" ]
+	fi
+}
+
+# Compare two files.
+# If different, replace first with second otherwise remove second.
+change_file()
+{
+
+	if [ -e "$1" ]; then
+		if comp_file "$1" "$2"; then
+			rm -f "$2"
+			return 1
+		fi
+	fi
+	cat "$2" > "$1"
+	rm -f "$2"
+	return 0
+}
+
+# Compare two files.
+# If different, copy or link depending on target type
+copy_file()
+{
+
+	if [ -h "$2" ]; then
+		[ "$(readlink "$2")" = "$1" ] && return 1
+		ln -sf "$1" "$2"
+	else
+		comp_file "$1" "$2" && return 1
+		cat "$1" >"$2"
+	fi
+}
+
+# Save a config file
+save_conf()
+{
+
+	if [ -f "$1" ]; then
+		rm -f "$1-pre.$interface"
+		cat "$1" > "$1-pre.$interface"
+	fi
+}
+
+# Restore a config file
+restore_conf()
+{
+
+	[ -f "$1-pre.$interface" ] || return 1
+	cat "$1-pre.$interface" > "$1"
+	rm -f "$1-pre.$interface"
+}
+
+# Write a syslog entry
+syslog()
+{
+	local lvl="$1"
+
+	if [ "$lvl" = debug ]; then
+		${syslog_debug} || return 0
+	fi
+	[ -n "$lvl" ] && shift
+	[ -n "$*" ] || return 0
+	case "$lvl" in
+	err|error)	echo "$interface: $*" >&2;;
+	*)		echo "$interface: $*";;
+	esac
+	if type logger >/dev/null 2>&1; then
+		logger -i -p daemon."$lvl" -t dhcpcd-run-hooks "$interface: $*"
+	fi
+}
+
+# Check for a valid domain name as per RFC1123 with the exception of
+# allowing - and _ as they seem to be widely used.
+valid_domainname()
+{
+	local name="$1" label
+
+	[ -z "$name" -o ${#name} -gt 255 ] && return 1
+	
+	while [ -n "$name" ]; do
+		label="${name%%.*}"
+		[ -z "$label" -o ${#label} -gt 63 ] && return 1
+		case "$label" in
+		-*|_*|*-|*_)		return 1;;
+		# some sh require - as the first or last character in the class
+		# when matching it
+		*[![:alnum:]_-]*)	return 1;;
+		esac
+		[ "$name" = "${name#*.}" ] && break
+		name="${name#*.}"
+	done
+	return 0	
+}
+
+valid_domainname_list()
+{
+	local name
+
+	for name do
+		valid_domainname "$name" || return $?
+	done
+	return 0
+}
+
+# Check for a valid path
+valid_path()
+{
+
+	case "$@" in
+	*[![:alnum:]#%+-_:\.,@~\\/\[\]=\ ]*) return 1;;
+	esac
+	return 0
+}
+
+# With the advent of alternative init systems, it's possible to have
+# more than one installed. So we need to try and guess what one we're
+# using unless overriden by configure.
+detect_init()
+{
+	_service_exists="@SERVICEEXISTS@"
+	_service_cmd="@SERVICECMD@"
+	_service_status="@SERVICESTATUS@"
+
+	[ -n "$_service_cmd" ] && return 0
+
+	if ${_detected_init}; then
+		[ -n "$_service_cmd" ]
+		return $?
+	fi
+
+	# Detect the running init system.
+	# As systemd and OpenRC can be installed on top of legacy init
+	# systems we try to detect them first.
+	_service_status=
+	if [ -x /bin/systemctl -a -S /run/systemd/private ]; then
+		_service_exists="/bin/systemctl --quiet is-enabled \$1.service"
+		_service_status="/bin/systemctl --quiet is-active \$1.service"
+		_service_cmd="/bin/systemctl \$2 \$1.service"
+	elif [ -x /usr/bin/systemctl -a -S /run/systemd/private ]; then
+		_service_exists="/usr/bin/systemctl --quiet is-enabled \$1.service"
+		_service_status="/usr/bin/systemctl --quiet is-active \$1.service"
+		_service_cmd="/usr/bin/systemctl \$2 \$1.service"
+	elif [ -x /sbin/rc-service -a \
+	    -s /libexec/rc/init.d/softlevel -o -s /run/openrc/softlevel ]
+	then
+		_service_exists="/sbin/rc-service -e \$1"
+		_service_cmd="/sbin/rc-service \$1 -- -D \$2"
+	elif [ -x /usr/sbin/invoke-rc.d ]; then
+		_service_exists="/usr/sbin/invoke-rc.d --query --quiet \$1 start >/dev/null 2>&1 || [ \$? = 104 ]"
+		_service_cmd="/usr/sbin/invoke-rc.d \$1 \$2"
+	elif [ -x /sbin/service ]; then
+		_service_exists="/sbin/service \$1 >/dev/null 2>&1"
+		_service_cmd="/sbin/service \$1 \$2"
+	elif [ -x /bin/sv ]; then
+		_service_exists="/bin/sv status \1 >/dev/null 2>&1"
+		_service_cmd="/bin/sv \$1 \$2"
+	elif [ -x /usr/bin/sv ]; then
+		_service_exists="/usr/bin/sv status \1 >/dev/null 2>&1"
+		_service_cmd="/usr/bin/sv \$1 \$2"
+	elif [ -e /etc/slackware-version -a -d /etc/rc.d ]; then
+		_service_exists="[ -x /etc/rc.d/rc.\$1 ]"
+		_service_cmd="/etc/rc.d/rc.\$1 \$2"
+		_service_status="/etc/rc.d/rc.\$1 status 1>/dev/null 2>&1"
+	else
+		for x in /etc/init.d/rc.d /etc/rc.d /etc/init.d; do
+			if [ -d $x ]; then
+				_service_exists="[ -x $x/\$1 ]"
+				_service_cmd="$x/\$1 \$2"
+				break
+			fi
+		done
+		if [ -e /etc/arch-release ]; then
+			_service_status="[ -e /var/run/daemons/\$1 ]"
+		elif [ "$x" = "/etc/rc.d" -a -e /etc/rc.d/rc.subr ]; then
+			_service_status="$x/\$1 check 1>/dev/null 2>&1"
+		fi
+	fi
+
+	_detected_init=true
+	if [ -z "$_service_cmd" ]; then
+		syslog err "could not detect a useable init system"
+		return 1
+	fi
+	return 0
+}
+
+# Check a system service exists 
+service_exists()
+{
+
+	if [ -z "$_service_exists" ]; then
+		detect_init || return 1
+	fi
+	eval $_service_exists
+}
+
+# Send a command to a system service
+service_cmd()
+{
+
+	if [ -z "$_service_cmd" ]; then
+		detect_init || return 1
+	fi
+	eval $_service_cmd
+}
+
+# Send a command to a system service if it is running
+service_status()
+{
+
+	if [ -z "$_service_cmd" ]; then
+		detect_init || return 1
+	fi
+	if [ -n "$_service_status" ]; then
+		eval $_service_status
+	else
+		service_command $1 status >/dev/null 2>&1
+	fi
+}
+
+# Handy macros for our hooks
+service_command()
+{
+
+	service_exists $1 && service_cmd $1 $2
+}
+service_condcommand()
+{
+
+	service_exists $1 && service_status $1 && service_cmd $1 $2
+}
+
+# We source each script into this one so that scripts run earlier can
+# remove variables from the environment so later scripts don't see them.
+# Thus, the user can create their dhcpcd.enter/exit-hook script to configure
+# /etc/resolv.conf how they want and stop the system scripts ever updating it.
+for hook in \
+	@SYSCONFDIR@/dhcpcd.enter-hook \
+	@HOOKDIR@/* \
+	@SYSCONFDIR@/dhcpcd.exit-hook
+do
+	for skip in $skip_hooks; do
+		case "$hook" in
+			*/*~)				continue 2;;
+			*/"$skip")			continue 2;;
+			*/[0-9][0-9]"-$skip")		continue 2;;
+			*/[0-9][0-9]"-$skip.sh")	continue 2;;
+		esac
+	done
+	if [ -f "$hook" ]; then
+		. "$hook"
+	fi
+done
diff --git a/dhcpcd-6.8.2/dhcpcd.8.in b/dhcpcd-6.8.2/dhcpcd.8.in
new file mode 100644
index 0000000..e815620
--- /dev/null
+++ b/dhcpcd-6.8.2/dhcpcd.8.in
@@ -0,0 +1,743 @@
+.\" Copyright (c) 2006-2015 Roy Marples
+.\" All rights reserved
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.Dd March 17, 2015
+.Dt DHCPCD 8
+.Os
+.Sh NAME
+.Nm dhcpcd
+.Nd a DHCP client
+.Sh SYNOPSIS
+.Nm
+.Op Fl 46ABbDdEGgHJKLMpqTV
+.Op Fl C , Fl Fl nohook Ar hook
+.Op Fl c , Fl Fl script Ar script
+.Op Fl e , Fl Fl env Ar value
+.Op Fl F , Fl Fl fqdn Ar FQDN
+.Op Fl f , Fl Fl config Ar file
+.Op Fl h , Fl Fl hostname Ar hostname
+.Op Fl I , Fl Fl clientid Ar clientid
+.Op Fl i , Fl Fl vendorclassid Ar vendorclassid
+.Op Fl j , Fl Fl logfile Ar logfile
+.Op Fl l , Fl Fl leasetime Ar seconds
+.Op Fl m , Fl Fl metric Ar metric
+.Op Fl O , Fl Fl nooption Ar option
+.Op Fl o , Fl Fl option Ar option
+.Op Fl Q , Fl Fl require Ar option
+.Op Fl r , Fl Fl request Ar address
+.Op Fl S , Fl Fl static Ar value
+.Op Fl s , Fl Fl inform Ar address Ns Op Ar /cidr
+.Op Fl t , Fl Fl timeout Ar seconds
+.Op Fl u , Fl Fl userclass Ar class
+.Op Fl v , Fl Fl vendor Ar code , Ar value
+.Op Fl W , Fl Fl whitelist Ar address Ns Op Ar /cidr
+.Op Fl w
+.Op Fl Fl waitip Op 4 | 6
+.Op Fl y , Fl Fl reboot Ar seconds
+.Op Fl X , Fl Fl blacklist Ar address Ns Op Ar /cidr
+.Op Fl Z , Fl Fl denyinterfaces Ar pattern
+.Op Fl z , Fl Fl allowinterfaces Ar pattern
+.Op interface
+.Op ...
+.Nm
+.Fl n , Fl Fl rebind
+.Op interface
+.Nm
+.Fl k , Fl Fl release
+.Op interface
+.Nm
+.Fl U, Fl Fl dumplease
+.Ar interface
+.Nm
+.Fl Fl version
+.Nm
+.Fl x , Fl Fl exit
+.Op interface
+.Sh DESCRIPTION
+.Nm
+is an implementation of the DHCP client specified in
+.Li RFC 2131 .
+.Nm
+gets the host information
+.Po
+IP address, routes, etc
+.Pc
+from a DHCP server and configures the network
+.Ar interface
+of the
+machine on which it is running.
+.Nm
+then runs the configuration script which writes DNS information to
+.Xr resolvconf 8 ,
+if available, otherwise directly to
+.Pa /etc/resolv.conf .
+If the hostname is currently blank, (null) or localhost, or
+.Va force_hostname
+is YES or TRUE or 1 then
+.Nm
+sets the hostname to the one supplied by the DHCP server.
+.Nm
+then daemonises and waits for the lease renewal time to lapse.
+It will then attempt to renew its lease and reconfigure if the new lease
+changes when the lease beings to expire or the DHCP server sends message
+to renew early.
+.Pp
+If any interface reports a working carrier then
+.Nm
+will try and obtain a lease before forking to the background,
+otherwise it will fork right away.
+This behaviour can be modified with the
+.Fl b , Fl Fl background
+and
+.Fl w , Fl Fl waitip
+options.
+.Pp
+.Nm
+is also an implementation of the BOOTP client specified in
+.Li RFC 951 .
+.Pp
+.Nm
+is also an implementation of the IPv6 Router Solicitor as specified in
+.Li RFC 4861
+and
+.Li RFC 6106 .
+.Pp
+.Nm
+is also an implementation of the IPv6 Privacy Extensions to AutoConf as
+specified in
+.Li RFC 4941 .
+This feature needs to be enabled in the kernel and
+.Nm
+will start using it.
+.Pp
+.Nm
+is also an implemenation of the DHCPv6 client as specified in
+.Li RFC 3315 .
+By default,
+.Nm
+only starts DHCPv6 when instructed to do so by an IPV6 Router Advertisement.
+If no Identity Association is configured,
+then a Non-temporary Address is requested.
+.Ss Local Link configuration
+If
+.Nm
+failed to obtain a lease, it probes for a valid IPv4LL address
+.Po
+aka ZeroConf, aka APIPA
+.Pc .
+Once obtained it restarts the process of looking for a DHCP server to get a
+proper address.
+.Pp
+When using IPv4LL,
+.Nm
+nearly always succeeds and returns an exit code of 0.
+In the rare case it fails, it normally means that there is a reverse ARP proxy
+installed which always defeats IPv4LL probing.
+To disable this behaviour, you can use the
+.Fl L , Fl Fl noipv4ll
+option.
+.Ss Multiple interfaces
+If a list of interfaces are given on the command line, then
+.Nm
+only works with those interfaces, otherwise
+.Nm
+discovers available Ethernet interfaces that can be configured.
+When
+.Nm
+is operating on more than one interface,
+it is called Master mode. and this behaviour can be forced with the
+.Fl M , Fl Fl master
+option so that an individual interface can start
+.Nm
+but only one instance is running.
+The
+.Nm dhcpcd-ui
+project expects dhcpcd to be running this way.
+.Pp
+If a single interface is given then
+.Nm
+only works for that interface and runs as a separate instance.
+The
+.Fl w , Fl Fl waitip
+option is enabled in this instance to maintain compatibility with older
+versions.
+.Pp
+Interfaces are preferred by carrier, DHCP lease/IPv4LL and then lowest metric.
+For systems that support route metrics, each route will be tagged with the
+metric, otherwise
+.Nm
+changes the routes to use the interface with the same route and the lowest
+metric.
+See options below for controlling which interfaces we allow and deny through
+the use of patterns.
+.Pp
+If an interface name is suffixed by an equal-sign, the text following the
+equal sign will be used instead of the interface name as the unique identifier
+for the DHCP lease file.  Doing so allows the caller to specify different
+lease files for the same interface (e.g, when switching the same wireless
+interface between different 802.11 networks).
+.Ss Hooking into events
+.Nm
+runs
+.Pa @SCRIPT@ ,
+or the script specified by the
+.Fl c , Fl Fl script
+option.
+This script runs each script found in
+.Pa @HOOKDIR@
+in a lexical order.
+The default installation supplies the scripts
+.Pa 01-test ,
+.Pa 10-mtu ,
+.Pa 10-wpa_supplicant ,
+.Pa 15-timezone ,
+.Pa 20-resolv.conf
+and
+.Pa 30-hostname .
+You can disable each script by using the
+.Fl C , Fl Fl nohook
+option.
+See
+.Xr dhcpcd-run-hooks 8
+for details on how these scripts work.
+.Nm
+currently ignores the exit code of the script.
+.Ss Fine tuning
+You can fine-tune the behaviour of
+.Nm
+with the following options:
+.Bl -tag -width indent
+.It Fl b , Fl Fl background
+Background immediately.
+This is useful for startup scripts which don't disable link messages for
+carrier status.
+.It Fl c , Fl Fl script Ar script
+Use this
+.Ar script
+instead of the default
+.Pa @SCRIPT@ .
+.It Fl D , Fl Fl duid
+Generate an
+.Li RFC 4361
+compliant clientid.
+This requires persistent storage and not all DHCP servers work with it so it
+is not enabled by default.
+.Nm
+generates the DUID and stores it in
+.Pa @SYSCONFDIR@/dhcpcd.duid .
+This file should not be copied to other hosts.
+.It Fl d , Fl Fl debug
+Echo debug messages to the stderr and syslog.
+.It Fl E , Fl Fl lastlease
+If
+.Nm
+cannot obtain a lease, then try to use the last lease acquired for the
+interface.
+If the
+.Fl p, Fl Fl persistent
+option is not given then the lease is used if it hasn't expired.
+.It Fl e , Fl Fl env Ar value
+Push
+.Ar value
+to the environment for use in
+.Xr dhcpcd-run-hooks 8 .
+For example, you can force the hostname hook to always set the hostname with
+.Fl e
+.Va force_hostname=YES .
+.It Fl g , Fl Fl reconfigure
+.Nm
+will re-apply IP address, routing and run
+.Xr dhcpcd-run-hooks 8
+for each interface.
+This is useful so that a 3rd party such as PPP or VPN can change the routing
+table and / or DNS, etc and then instruct
+.Nm
+to put things back afterwards.
+.Nm
+does not read a new configuration when this happens - you should rebind if you
+need that functionality.
+.It Fl F , Fl Fl fqdn Ar fqdn
+Requests that the DHCP server updates DNS using FQDN instead of just a
+hostname.
+Valid values for
+.Ar fqdn
+are disable, none, ptr and both.
+.Nm
+itself never does any DNS updates.
+.Nm
+encodes the FQDN hostname as specified in
+.Li RFC1035 .
+.It Fl f , Fl Fl config Ar file
+Specify a config to load instead of
+.Pa @SYSCONFDIR@/dhcpcd.conf .
+.Nm
+always processes the config file before any command line options.
+.It Fl h , Fl Fl hostname Ar hostname
+Sends
+.Ar hostname
+to the DHCP server so it can be registered in DNS.
+If
+.Ar hostname
+is an empty string then the current system hostname is sent.
+If
+.Ar hostname
+is a FQDN (ie, contains a .) then it will be encoded as such.
+.It Fl I , Fl Fl clientid Ar clientid
+Send the
+.Ar clientid .
+If the string is of the format 01:02:03 then it is encoded as hex.
+For interfaces whose hardware address is longer than 8 bytes, or if the
+.Ar clientid
+is an empty string then
+.Nm
+sends a default
+.Ar clientid
+of the hardware family and the hardware address.
+.It Fl i , Fl Fl vendorclassid Ar vendorclassid
+Override the DHCPv4
+.Ar vendorclassid
+field sent.
+The default is
+dhcpcd-<version>:<os>:<machine>:<platform>.
+For example
+.D1 dhcpcd-5.5.6:NetBSD-6.99.5:i386:i386
+If not set then none is sent.
+Some badly configured DHCP servers reject unknown vendorclassids.
+To work around it, try and impersonate Windows by using the MSFT vendorclassid.
+.It Fl j , Fl Fl logfile Ar logfile
+Writes to the specified
+.Ar logfile
+rather than
+.Xr syslog 3 .
+The
+.Ar logfile
+is truncated when opened and is reopened when
+.Nm
+receives the
+.Dv SIGUSR2
+signal.
+.It Fl k , Fl Fl release Op Ar interface
+This causes an existing
+.Nm
+process running on the
+.Ar interface
+to release its lease and de-configure the
+.Ar interface .
+If no
+.Ar interface
+is specified then this applies to all interfaces.
+If no interfaces are left running,
+.Nm
+will exit.
+.It Fl l , Fl Fl leasetime Ar seconds
+Request a specific lease time in
+.Ar seconds .
+By default
+.Nm
+does not request any lease time and leaves it in the hands of the
+DHCP server.
+.It Fl M , Fl Fl master
+Start
+.Nm
+in master mode even if only one interface specified on the command line.
+See the Multiple Interfaces section above.
+.It Fl m , Fl Fl metric Ar metric
+Metrics are used to prefer an interface over another one, lowest wins.
+.Nm
+will supply a default metic of 200 +
+.Xr if_nametoindex 3 .
+An extra 100 will be added for wireless interfaces.
+.It Fl n , Fl Fl rebind Op Ar interface
+Notifies
+.Nm
+to reload its configuration and rebind the specified
+.Ar interface .
+If no interface is specified then this applies to all interfaces.
+If
+.Nm
+is not running, then it starts up as normal.
+This may also cause
+.Xr wpa_supplicant 8
+to reload its configuration for each interface as well.
+.It Fl o , Fl Fl option Ar option
+Request the DHCP
+.Ar option
+variable for use in
+.Pa @SCRIPT@ .
+.It Fl p , Fl Fl persistent
+.Nm
+normally de-configures the
+.Ar interface
+and configuration when it exits.
+Sometimes, this isn't desirable if, for example, you have root mounted over
+NFS or SSH clients connect to this host and they need to be notified of
+the host shutting down.
+You can use this option to stop this from happening.
+.It Fl r , Fl Fl request Op Ar address
+Request the
+.Ar address
+in the DHCP DISCOVER message.
+There is no guarantee this is the address the DHCP server will actually give.
+If no
+.Ar address
+is given then the first address currently assigned to the
+.Ar interface
+is used.
+.It Fl s , Fl Fl inform Op Ar address Ns Op Ar /cidr
+Behaves like
+.Fl r , Fl Fl request
+as above, but sends a DHCP INFORM instead of DISCOVER/REQUEST.
+This does not get a lease as such, just notifies the DHCP server of the
+.Ar address
+in use.
+You should also include the optional
+.Ar cidr
+network number in case the address is not already configured on the interface.
+.Nm
+remains running and pretends it has an infinite lease.
+.Nm
+will not de-configure the interface when it exits.
+If
+.Nm
+fails to contact a DHCP server then it returns a failure instead of falling
+back on IPv4LL.
+.It Fl S, Fl Fl static Ar value
+Configures a static
+.Ar value .
+If you set
+.Ic ip_address
+then
+.Nm
+will not attempt to obtain a lease and just use the value for the address with
+an infinite lease time.
+.Pp
+Here is an example which configures a static address, routes and dns.
+.D1 dhcpcd -S ip_address=192.168.0.10/24 \e
+.D1 -S routers=192.168.0.1 \e
+.D1 -S domain_name_servers=192.168.0.1 \e
+.D1 eth0
+.It Fl t , Fl Fl timeout Ar seconds
+Timeout after
+.Ar seconds ,
+instead of the default 30.
+A setting of 0
+.Ar seconds
+causes
+.Nm
+to wait forever to get a lease.
+If
+.Nm
+is working on a single interface then
+.Nm
+will exit when a timeout occurs, otherwise
+.Nm
+will fork into the background.
+.It Fl u , Fl Fl userclass Ar class
+Tags the DHCPv4 message with the userclass
+.Ar class .
+DHCP servers use this to give members of the class DHCP options other than the
+default, without having to know things like hardware address or hostname.
+.It Fl v , Fl Fl vendor Ar code , Ns Ar value
+Add an encapsulated vendor option.
+.Ar code
+should be between 1 and 254 inclusive.
+To add a raw vendor string, omit
+.Ar code
+but keep the comma.
+Examples.
+.Pp
+Set the vendor option 01 with an IP address.
+.D1 dhcpcd \-v 01,192.168.0.2 eth0
+Set the vendor option 02 with a hex code.
+.D1 dhcpcd \-v 02,01:02:03:04:05 eth0
+Set the vendor option 03 with an IP address as a string.
+.D1 dhcpcd \-v 03,\e"192.168.0.2\e" eth0
+Set un-encapsulated vendor option to hello world.
+.D1 dhcpcd \-v ,"hello world" eth0
+.It Fl Fl version
+Display both program version and copyright information.
+.Nm
+then exits before doing any configuration.
+.It Fl w
+Wait for an address to be assigned before forking to the background.
+Does not take an argument, unlike the below option.
+.Fl fl waitip
+option.
+.It Fl Fl waitip Op 4 | 6
+Wait for an address to be assigned before forking to the background.
+4 means wait for an IPv4 address to be assigned.
+6 means wait for an IPv6 address to be assigned.
+If no argument is given,
+.Nm
+will wait for any address protocol to be assigned.
+It is possible to wait for more than one address protocol and
+.Nm
+will only fork to the background when all waiting conditions are satisfied.
+.It Fl x , Fl Fl exit Op Ar interface
+This will signal an existing
+.Nm
+process running on the
+.Ar interface
+to de-configure the
+.Ar interface
+and exit.
+If no interface is specified, then the above is applied to all interfaces.
+.Nm
+then waits until this process has exited.
+.It Fl y , Fl Fl reboot Ar seconds
+Allow
+.Ar reboot
+seconds before moving to the discover phase if we have an old lease to use.
+Allow
+.Ar reboot
+seconds before starting fallback states from the discover phase.
+IPv4LL is started when the first
+.Ar reboot
+timeout is reached.
+The default is 5 seconds.
+A setting of 0 seconds causes
+.Nm
+to skip the reboot phase and go straight into discover.
+This has no effect on DHCPv6 other than skipping the reboot phase.
+.El
+.Ss Restricting behaviour
+.Nm
+will try to do as much as it can by default.
+However, there are sometimes situations where you don't want the things to be
+configured exactly how the the DHCP server wants.
+Here are some options that deal with turning these bits off.
+.Bl -tag -width indent
+.It Fl 4 , Fl Fl ipv4only
+Configure IPv4 only.
+.It Fl 6 , Fl Fl ipv6only
+Configure IPv6 only.
+.It Fl A , Fl Fl noarp
+Don't request or claim the address by ARP.
+This also disables IPv4LL.
+.It Fl B , Fl Fl nobackground
+Don't run in the background when we acquire a lease.
+This is mainly useful for running under the control of another process, such
+as a debugger or a network manager.
+.It Fl C , Fl Fl nohook Ar script
+Don't run this hook script.
+Matches full name, or prefixed with 2 numbers optionally ending with
+.Pa .sh .
+.Pp
+So to stop
+.Nm
+from touching your DNS or MTU settings you would do:-
+.D1 dhcpcd -C resolv.conf -C mtu eth0
+.It Fl G , Fl Fl nogateway
+Don't set any default routes.
+.It Fl H , Fl Fl xidhwaddr
+Use the last four bytes of the hardware address as the DHCP xid instead
+of a randomly generated number.
+.It Fl J , Fl Fl broadcast
+Instructs the DHCP server to broadcast replies back to the client.
+Normally this is only set for non Ethernet interfaces,
+such as FireWire and InfiniBand.
+In most instances,
+.Nm
+will set this automatically.
+.It Fl K , Fl Fl nolink
+Don't receive link messages for carrier status.
+You should only have to use this with buggy device drivers or running
+.Nm
+through a network manager.
+.It Fl L , Fl Fl noipv4ll
+Don't use IPv4LL (aka APIPA, aka Bonjour, aka ZeroConf).
+.It Fl O , Fl Fl nooption Ar option
+Don't request the specified option.
+If no option given, then don't request any options other than those to
+configure the interface and routing.
+.It Fl Q , Fl Fl require Ar option
+Requires the
+.Ar option
+to be present in all DHCP messages, otherwise the message is ignored.
+To enforce that
+.Nm
+only responds to DHCP servers and not BOOTP servers, you can
+.Fl Q
+.Ar dhcp_message_type .
+.It Fl q , Fl Fl quiet
+Quiet
+.Nm
+on the command line, only warnings and errors will be displayed.
+The messages are still logged though.
+.It Fl T, Fl Fl test
+On receipt of DHCP messages just call
+.Pa @SCRIPT@
+with the reason of TEST which echos the DHCP variables found in the message
+to the console.
+The interface configuration isn't touched and neither are any configuration
+files.
+The
+.Ar rapid_commit
+option is not sent in TEST mode so that the server does not lease an address.
+To test INFORM the interface needs to be configured with the desired address
+before starting
+.Nm .
+.It Fl U, Fl Fl dumplease Ar interface
+Dumps the last lease for the
+.Ar interface
+to stdout.
+.Ar interface
+could also be a path to a DHCP wire formatted file.
+Use the
+.Fl 4
+or
+.Fl 6
+flags to specify an address family.
+Pass a 2nd
+.Fl U, Fl Fl dumplease option to dump a secondary lease, such as
+DHCPv6 Prefix Delegation when not being mixed with another IA type.
+.It Fl V, Fl Fl variables
+Display a list of option codes, the associated variable and encoding for use in
+.Xr dhcpcd-run-hooks 8 .
+Variables are prefixed with new_ and old_ unless the option number is -.
+Variables without an option are part of the DHCP message and cannot be
+directly requested.
+.It Fl W, Fl Fl whitelist Ar address Ns Op /cidr
+Only accept packets from
+.Ar address Ns Op /cidr .
+.Fl X, Fl Fl blacklist
+is ignored if
+.Fl W, Fl Fl whitelist
+is set.
+.It Fl X, Fl Fl blacklist Ar address Ns Op Ar /cidr
+Ignore all packets from
+.Ar address Ns Op Ar /cidr .
+.It Fl Z , Fl Fl denyinterfaces Ar pattern
+When discovering interfaces, the interface name must not match
+.Ar pattern
+which is a space or comma separated list of patterns passed to
+.Xr fnmatch 3 .
+.It Fl z , Fl Fl allowinterfaces Ar pattern
+When discovering interfaces, the interface name must match
+.Ar pattern
+which is a space or comma separated list of patterns passed to
+.Xr fnmatch 3 .
+If the same interface is matched in
+.Fl Z , Fl Fl denyinterfaces
+then it is still denied.
+.It Fl Fl nodev
+Don't load any
+.Pa /dev
+management modules.
+.El
+.Sh 3RDPARTY LINK MANAGEMENT
+Some interfaces require configuration by 3rd parties, such as PPP or VPN.
+When an interface configuration in
+.Nm
+is marked as STATIC or INFORM without an address then
+.Nm
+will monitor the interface until an address is added or removed from it and
+act accordingly.
+For point to point interfaces (like PPP), a default route to its
+destination is automatically added to the configuration.
+If the point to point interface is configured for INFORM, then
+.Nm
+unicasts INFORM to the destination, otherwise it defaults to STATIC.
+.Sh NOTES
+.Nm
+requires a Berkley Packet Filter, or BPF device on BSD based systems and a
+Linux Socket Filter, or LPF device on Linux based systems for all IPv4
+configuration.
+.Pp
+If restricting
+.Nm
+to a single interface and optionally address family via the command-line
+then all futher calls to
+.Nm
+to rebind, reconfigure or exit need to include the same restrictive flags
+so that
+.Nm
+knows which process to signal.
+.Sh FILES
+.Bl -ohang
+.It Pa @SYSCONFDIR@/dhcpcd.conf
+Configuration file for dhcpcd.
+If you always use the same options, put them here.
+.It Pa @SYSCONFDIR@/dhcpcd.duid
+Text file that holds the DUID used to identify the host.
+.It Pa @SYSCONFDIR@/dhcpcd.secret
+Text file that holds a secret key known only to the host.
+.It Pa @SCRIPT@
+Bourne shell script that is run to configure or de-configure an interface.
+.It Pa @LIBDIR@/dhcpcd/dev
+.Pa /dev
+management modules.
+.It Pa @HOOKDIR@
+A directory containing bourne shell scripts that are run by the above script.
+Each script can be disabled by using the
+.Fl C , Fl Fl nohook
+option described above.
+.It Pa @DBDIR@/dhcpcd\- Ns Ar interface Ns Ar -ssid Ns .lease
+The actual DHCP message sent by the server.
+We use this when reading the last
+lease and use the files mtime as when it was issued.
+.It Pa @DBDIR@/dhcpcd\- Ns Ar interface Ns Ar -ssid Ns .lease6
+The actual DHCPv6 message sent by the server.
+We use this when reading the last
+lease and use the files mtime as when it was issued.
+.It Pa @DBDIR@/dhcpcd-rdm.monotonic
+Stores the monotonic counter used in the
+.Ar replay
+field in Authentication Options.
+.It Pa @RUNDIR@/dhcpcd.pid
+Stores the PID of
+.Nm
+running on all interfaces.
+.It Pa @RUNDIR@/dhcpcd\- Ns Ar interface Ns .pid
+Stores the PID of
+.Nm
+running on the
+.Ar interface .
+.It Pa @RUNDIR@/dhcpcd.sock
+Control socket to the master daemon.
+.It Pa @RUNDIR@/dhcpcd.unpriv.sock
+Unpriviledged socket to the master daemon, only allows state retrieval.
+Control socket to the master daemon.
+.It Pa @RUNDIR@/dhcpcd\- Ns Ar interface Ns .sock
+Control socket to per interface daemon.
+.El
+.Sh SEE ALSO
+.Xr fnmatch 3 ,
+.Xr if_nametoindex 3 ,
+.Xr dhcpcd.conf 5 ,
+.Xr resolv.conf 5 ,
+.Xr dhcpcd-run-hooks 8 ,
+.Xr resolvconf 8
+.Sh STANDARDS
+RFC\ 951, RFC\ 1534, RFC\ 2104, RFC\ 2131, RFC\ 2132, RFC\ 2563, RFC\ 2855, 
+RFC\ 3004, RFC\ 3118, RFC\ 3203, RFC\ 3315, RFC\ 3361, RFC\ 3633, RFC\ 3396,
+RFC\ 3397, RFC\ 3442, RFC\ 3495, RFC\ 3925, RFC\ 3927, RFC\ 4039, RFC\ 4075,
+RFC\ 4242, RFC\ 4361, RFC\ 4390, RFC\ 4702, RFC\ 4074, RFC\ 4861, RFC\ 4833,
+RFC\ 4941, RFC\ 5227, RFC\ 5942, RFC\ 5969, RFC\ 6106, RFC\ 6334, RFC\ 6603,
+RFC\ 6704, RFC\ 7217.
+.Sh AUTHORS
+.An Roy Marples Aq Mt roy@marples.name
+.Sh BUGS
+Please report them to
+.Lk http://roy.marples.name/projects/dhcpcd
diff --git a/dhcpcd-6.8.2/dhcpcd.c b/dhcpcd-6.8.2/dhcpcd.c
new file mode 100644
index 0000000..28a472c
--- /dev/null
+++ b/dhcpcd-6.8.2/dhcpcd.c
@@ -0,0 +1,1998 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+const char dhcpcd_copyright[] = "Copyright (c) 2006-2015 Roy Marples";
+
+#define _WITH_DPRINTF /* Stop FreeBSD bitching */
+
+#include <sys/file.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <limits.h>
+#include <paths.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+
+#if defined(__ANDROID__)
+#include <sys/capability.h>
+#include <sys/prctl.h>
+#include <private/android_filesystem_config.h>
+#endif  /* __ANDROID__ */
+
+#include "config.h"
+#include "arp.h"
+#include "common.h"
+#include "control.h"
+#include "dev.h"
+#include "dhcpcd.h"
+#include "dhcp6.h"
+#include "duid.h"
+#include "eloop.h"
+#include "if.h"
+#include "if-options.h"
+#include "ipv4.h"
+#include "ipv6.h"
+#include "ipv6nd.h"
+#include "rpc-interface.h"
+#include "script.h"
+
+#ifdef USE_SIGNALS
+const int dhcpcd_handlesigs[] = {
+	SIGTERM,
+	SIGINT,
+	SIGALRM,
+	SIGHUP,
+	SIGUSR1,
+	SIGUSR2,
+	SIGPIPE,
+	0
+};
+
+/* Handling signals needs *some* context */
+static struct dhcpcd_ctx *dhcpcd_ctx;
+#endif
+
+#if defined(USE_SIGNALS) || !defined(THERE_IS_NO_FORK)
+static pid_t
+read_pid(const char *pidfile)
+{
+	FILE *fp;
+	pid_t pid;
+
+	if ((fp = fopen(pidfile, "r")) == NULL) {
+		errno = ENOENT;
+		return 0;
+	}
+	if (fscanf(fp, "%d", &pid) != 1)
+		pid = 0;
+	fclose(fp);
+	return pid;
+}
+
+static int
+write_pid(int fd, pid_t pid)
+{
+
+	if (ftruncate(fd, (off_t)0) == -1)
+		return -1;
+	lseek(fd, (off_t)0, SEEK_SET);
+	return dprintf(fd, "%d\n", (int)pid);
+}
+#endif
+
+static void
+usage(void)
+{
+
+printf("usage: "PACKAGE"\t[-46ABbDdEGgHJKkLnpqTVw]\n"
+	"\t\t[-C, --nohook hook] [-c, --script script]\n"
+	"\t\t[-e, --env value] [-F, --fqdn FQDN] [-f, --config file]\n"
+	"\t\t[-h, --hostname hostname] [-I, --clientid clientid]\n"
+	"\t\t[-i, --vendorclassid vendorclassid] [-l, --leasetime seconds]\n"
+	"\t\t[-m, --metric metric] [-O, --nooption option]\n"
+	"\t\t[-o, --option option] [-Q, --require option]\n"
+	"\t\t[-r, --request address] [-S, --static value]\n"
+	"\t\t[-s, --inform address[/cidr]] [-t, --timeout seconds]\n"
+	"\t\t[-u, --userclass class] [-v, --vendor code, value]\n"
+	"\t\t[-W, --whitelist address[/cidr]] [-y, --reboot seconds]\n"
+	"\t\t[-X, --blacklist address[/cidr]] [-Z, --denyinterfaces pattern]\n"
+	"\t\t[-z, --allowinterfaces pattern] [interface] [...]\n"
+	"       "PACKAGE"\t-k, --release [interface]\n"
+	"       "PACKAGE"\t-U, --dumplease interface\n"
+	"       "PACKAGE"\t--version\n"
+	"       "PACKAGE"\t-x, --exit [interface]\n");
+}
+
+static void
+free_globals(struct dhcpcd_ctx *ctx)
+{
+	struct dhcp_opt *opt;
+
+	if (ctx->ifac) {
+		for (; ctx->ifac > 0; ctx->ifac--)
+			free(ctx->ifav[ctx->ifac - 1]);
+		free(ctx->ifav);
+		ctx->ifav = NULL;
+	}
+	if (ctx->ifdc) {
+		for (; ctx->ifdc > 0; ctx->ifdc--)
+			free(ctx->ifdv[ctx->ifdc - 1]);
+		free(ctx->ifdv);
+		ctx->ifdv = NULL;
+	}
+	if (ctx->ifcc) {
+		for (; ctx->ifcc > 0; ctx->ifcc--)
+			free(ctx->ifcv[ctx->ifcc - 1]);
+		free(ctx->ifcv);
+		ctx->ifcv = NULL;
+	}
+
+#ifdef INET
+	if (ctx->dhcp_opts) {
+		for (opt = ctx->dhcp_opts;
+		    ctx->dhcp_opts_len > 0;
+		    opt++, ctx->dhcp_opts_len--)
+			free_dhcp_opt_embenc(opt);
+		free(ctx->dhcp_opts);
+		ctx->dhcp_opts = NULL;
+	}
+#endif
+#ifdef INET6
+	if (ctx->dhcp6_opts) {
+		for (opt = ctx->dhcp6_opts;
+		    ctx->dhcp6_opts_len > 0;
+		    opt++, ctx->dhcp6_opts_len--)
+			free_dhcp_opt_embenc(opt);
+		free(ctx->dhcp6_opts);
+		ctx->dhcp6_opts = NULL;
+	}
+#endif
+	if (ctx->vivso) {
+		for (opt = ctx->vivso;
+		    ctx->vivso_len > 0;
+		    opt++, ctx->vivso_len--)
+			free_dhcp_opt_embenc(opt);
+		free(ctx->vivso);
+		ctx->vivso = NULL;
+	}
+}
+
+static void
+handle_exit_timeout(void *arg)
+{
+	struct dhcpcd_ctx *ctx;
+
+	ctx = arg;
+	logger(ctx, LOG_ERR, "timed out");
+	if (!(ctx->options & DHCPCD_MASTER)) {
+		eloop_exit(ctx->eloop, EXIT_FAILURE);
+		return;
+	}
+	ctx->options |= DHCPCD_NOWAITIP;
+	dhcpcd_daemonise(ctx);
+}
+
+int
+dhcpcd_oneup(struct dhcpcd_ctx *ctx)
+{
+	const struct interface *ifp;
+
+	TAILQ_FOREACH(ifp, ctx->ifaces, next) {
+		if (D_STATE_RUNNING(ifp) ||
+		    RS_STATE_RUNNING(ifp) ||
+		    D6_STATE_RUNNING(ifp))
+			return 1;
+	}
+	return 0;
+}
+
+int
+dhcpcd_ipwaited(struct dhcpcd_ctx *ctx)
+{
+
+	if (ctx->options & DHCPCD_WAITIP4 &&
+	    !ipv4_addrexists(ctx, NULL))
+		return 0;
+	if (ctx->options & DHCPCD_WAITIP6 &&
+	    !ipv6nd_findaddr(ctx, NULL, 0) &&
+	    !dhcp6_findaddr(ctx, NULL, 0))
+		return 0;
+	if (ctx->options & DHCPCD_WAITIP &&
+	    !(ctx->options & (DHCPCD_WAITIP4 | DHCPCD_WAITIP6)) &&
+	    !ipv4_addrexists(ctx, NULL) &&
+	    !ipv6nd_findaddr(ctx, NULL, 0) &&
+	    !dhcp6_findaddr(ctx, NULL, 0))
+		return 0;
+	return 1;
+}
+
+/* Returns the pid of the child, otherwise 0. */
+pid_t
+dhcpcd_daemonise(struct dhcpcd_ctx *ctx)
+{
+#ifdef THERE_IS_NO_FORK
+	eloop_timeout_delete(ctx->eloop, handle_exit_timeout, ctx);
+	errno = ENOSYS;
+	return 0;
+#else
+	pid_t pid;
+	char buf = '\0';
+	int sidpipe[2], fd;
+
+	if (ctx->options & DHCPCD_DAEMONISE &&
+	    !(ctx->options & (DHCPCD_DAEMONISED | DHCPCD_NOWAITIP)))
+	{
+		if (!dhcpcd_ipwaited(ctx))
+			return 0;
+	}
+
+	eloop_timeout_delete(ctx->eloop, handle_exit_timeout, ctx);
+	if (ctx->options & DHCPCD_DAEMONISED ||
+	    !(ctx->options & DHCPCD_DAEMONISE))
+		return 0;
+	/* Setup a signal pipe so parent knows when to exit. */
+	if (pipe(sidpipe) == -1) {
+		logger(ctx, LOG_ERR, "pipe: %m");
+		return 0;
+	}
+	logger(ctx, LOG_DEBUG, "forking to background");
+	switch (pid = fork()) {
+	case -1:
+		logger(ctx, LOG_ERR, "fork: %m");
+		return 0;
+	case 0:
+		setsid();
+		/* Some polling methods don't survive after forking,
+		 * so ensure we can requeue all our events. */
+		if (eloop_requeue(ctx->eloop) == -1) {
+			logger(ctx, LOG_ERR, "eloop_requeue: %m");
+			eloop_exit(ctx->eloop, EXIT_FAILURE);
+		}
+		/* Notify parent it's safe to exit as we've detached. */
+		close(sidpipe[0]);
+		if (write(sidpipe[1], &buf, 1) == -1)
+			logger(ctx, LOG_ERR, "failed to notify parent: %m");
+		close(sidpipe[1]);
+		if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
+			dup2(fd, STDIN_FILENO);
+			dup2(fd, STDOUT_FILENO);
+			dup2(fd, STDERR_FILENO);
+			close(fd);
+		}
+		break;
+	default:
+		/* Wait for child to detach */
+		close(sidpipe[1]);
+		if (read(sidpipe[0], &buf, 1) == -1)
+			logger(ctx, LOG_ERR, "failed to read child: %m");
+		close(sidpipe[0]);
+		break;
+	}
+	/* Done with the fd now */
+	if (pid != 0) {
+		logger(ctx, LOG_INFO, "forked to background, child pid %d", pid);
+		write_pid(ctx->pid_fd, pid);
+		close(ctx->pid_fd);
+		ctx->pid_fd = -1;
+		ctx->options |= DHCPCD_FORKED;
+		eloop_exit(ctx->eloop, EXIT_SUCCESS);
+		return pid;
+	}
+	ctx->options |= DHCPCD_DAEMONISED;
+	return pid;
+#endif
+}
+
+static void
+dhcpcd_drop(struct interface *ifp, int stop)
+{
+
+	dhcp6_drop(ifp, stop ? NULL : "EXPIRE6");
+	ipv6nd_drop(ifp);
+	ipv6_drop(ifp);
+	dhcp_drop(ifp, stop ? "STOP" : "EXPIRE");
+	arp_close(ifp);
+}
+
+static void
+stop_interface(struct interface *ifp)
+{
+	struct dhcpcd_ctx *ctx;
+
+	ctx = ifp->ctx;
+	logger(ctx, LOG_INFO, "%s: removing interface", ifp->name);
+	ifp->options->options |= DHCPCD_STOPPING;
+
+	dhcpcd_drop(ifp, 1);
+	if (ifp->options->options & DHCPCD_DEPARTED)
+		script_runreason(ifp, "DEPARTED");
+	else
+		script_runreason(ifp, "STOPPED");
+
+	/* Delete all timeouts for the interfaces */
+	eloop_q_timeout_delete(ctx->eloop, 0, NULL, ifp);
+
+	/* Remove the interface from our list */
+	TAILQ_REMOVE(ifp->ctx->ifaces, ifp, next);
+	if_free(ifp);
+
+	if (!(ctx->options & (DHCPCD_MASTER | DHCPCD_TEST)))
+		eloop_exit(ctx->eloop, EXIT_FAILURE);
+}
+
+static void
+configure_interface1(struct interface *ifp)
+{
+	struct if_options *ifo = ifp->options;
+	int ra_global, ra_iface;
+#ifdef INET6
+	size_t i;
+#endif
+
+	/* Do any platform specific configuration */
+	if_conf(ifp);
+
+	/* If we want to release a lease, we can't really persist the
+	 * address either. */
+	if (ifo->options & DHCPCD_RELEASE)
+		ifo->options &= ~DHCPCD_PERSISTENT;
+
+	if (ifp->flags & IFF_POINTOPOINT && !(ifo->options & DHCPCD_INFORM))
+		ifo->options |= DHCPCD_STATIC;
+	if (ifp->flags & IFF_NOARP ||
+	    ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC))
+		ifo->options &= ~(DHCPCD_ARP | DHCPCD_IPV4LL);
+	if (ifp->flags & (IFF_POINTOPOINT | IFF_LOOPBACK) ||
+	    !(ifp->flags & IFF_MULTICAST))
+		ifo->options &= ~DHCPCD_IPV6RS;
+
+	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 | DHCPCD_DHCP6);
+
+	if (ifo->options & DHCPCD_SLAACPRIVATE &&
+	    !(ifp->ctx->options & (DHCPCD_DUMPLEASE | DHCPCD_TEST)))
+		ifo->options |= DHCPCD_IPV6RA_OWN;
+
+	/* If we're a psuedo interface, ensure we disable as much as we can */
+	if (ifp->options->options & DHCPCD_PFXDLGONLY)
+		ifp->options->options &= ~(DHCPCD_IPV4 | DHCPCD_IPV6RS);
+
+	/* We want to disable kernel interface RA as early as possible. */
+	if (ifo->options & DHCPCD_IPV6RS &&
+	    !(ifp->ctx->options & DHCPCD_DUMPLEASE))
+	{
+		/* 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,
+		    ifp->options->options & DHCPCD_IPV6RA_OWN ? 1 : 0);
+		if (ra_global == -1 || ra_iface == -1)
+			ifo->options &= ~DHCPCD_IPV6RS;
+		else if (ra_iface == 0 &&
+		    !(ifp->ctx->options & DHCPCD_TEST))
+			ifo->options |= DHCPCD_IPV6RA_OWN;
+	}
+
+	/* If we haven't specified a ClientID and our hardware address
+	 * length is greater than DHCP_CHADDR_LEN then we enforce a ClientID
+	 * of the hardware address family and the hardware address.
+	 * If there is no hardware address and no ClientID set,
+	 * force a DUID based ClientID. */
+	if (ifp->hwlen > DHCP_CHADDR_LEN)
+		ifo->options |= DHCPCD_CLIENTID;
+	else if (ifp->hwlen == 0 && !(ifo->options & DHCPCD_CLIENTID))
+		ifo->options |= DHCPCD_CLIENTID | DHCPCD_DUID;
+
+	/* Firewire and InfiniBand interfaces require ClientID and
+	 * the broadcast option being set. */
+	switch (ifp->family) {
+	case ARPHRD_IEEE1394:	/* FALLTHROUGH */
+	case ARPHRD_INFINIBAND:
+		ifo->options |= DHCPCD_CLIENTID | DHCPCD_BROADCAST;
+		break;
+	}
+
+	if (!(ifo->options & DHCPCD_IAID)) {
+		/*
+		 * An IAID is for identifying a unqiue interface within
+		 * the client. It is 4 bytes long. Working out a default
+		 * value is problematic.
+		 *
+		 * Interface name and number are not stable
+		 * between different OS's. Some OS's also cannot make
+		 * up their mind what the interface should be called
+		 * (yes, udev, I'm looking at you).
+		 * Also, the name could be longer than 4 bytes.
+		 * Also, with pluggable interfaces the name and index
+		 * could easily get swapped per actual interface.
+		 *
+		 * The MAC address is 6 bytes long, the final 3
+		 * being unique to the manufacturer and the initial 3
+		 * being unique to the organisation which makes it.
+		 * We could use the last 4 bytes of the MAC address
+		 * as the IAID as it's the most stable part given the
+		 * above, but equally it's not guaranteed to be
+		 * unique.
+		 *
+		 * Given the above, and our need to reliably work
+		 * between reboots without persitent storage,
+		 * generating the IAID from the MAC address is the only
+		 * logical default.
+		 *
+		 * dhclient uses the last 4 bytes of the MAC address.
+		 * dibbler uses an increamenting counter.
+		 * wide-dhcpv6 uses 0 or a configured value.
+		 * odhcp6c uses 1.
+		 * Windows 7 uses the first 3 bytes of the MAC address
+		 * and an unknown byte.
+		 * dhcpcd-6.1.0 and earlier used the interface name,
+		 * falling back to interface index if name > 4.
+		 */
+		if (ifp->hwlen >= sizeof(ifo->iaid))
+			memcpy(ifo->iaid,
+			    ifp->hwaddr + ifp->hwlen - sizeof(ifo->iaid),
+			    sizeof(ifo->iaid));
+		else {
+			uint32_t len;
+
+			len = (uint32_t)strlen(ifp->name);
+			if (len <= sizeof(ifo->iaid)) {
+				memcpy(ifo->iaid, ifp->name, len);
+				if (len < sizeof(ifo->iaid))
+					memset(ifo->iaid + len, 0,
+					    sizeof(ifo->iaid) - len);
+			} else {
+				/* IAID is the same size as a uint32_t */
+				len = htonl(ifp->index);
+				memcpy(ifo->iaid, &len, sizeof(len));
+			}
+		}
+		ifo->options |= DHCPCD_IAID;
+	}
+
+#ifdef INET6
+	if (ifo->ia_len == 0 && ifo->options & DHCPCD_IPV6 &&
+	    ifp->name[0] != '\0')
+	{
+		ifo->ia = malloc(sizeof(*ifo->ia));
+		if (ifo->ia == NULL)
+			logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
+		else {
+			ifo->ia_len = 1;
+			ifo->ia->ia_type = D6_OPTION_IA_NA;
+			memcpy(ifo->ia->iaid, ifo->iaid, sizeof(ifo->iaid));
+			memset(&ifo->ia->addr, 0, sizeof(ifo->ia->addr));
+			ifo->ia->sla = NULL;
+			ifo->ia->sla_len = 0;
+		}
+	} else {
+		for (i = 0; i < ifo->ia_len; i++) {
+			if (!ifo->ia[i].iaid_set) {
+				memcpy(&ifo->ia[i].iaid, ifo->iaid,
+				    sizeof(ifo->ia[i].iaid));
+				ifo->ia[i].iaid_set = 1;
+			}
+		}
+	}
+#endif
+
+	/* If we are not sending an authentication option, don't require it */
+	if (!(ifo->auth.options & DHCPCD_AUTH_SEND))
+		ifo->auth.options &= ~DHCPCD_AUTH_REQUIRE;
+}
+
+int
+dhcpcd_selectprofile(struct interface *ifp, const char *profile)
+{
+	struct if_options *ifo;
+	char pssid[PROFILE_LEN];
+
+	if (ifp->ssid_len) {
+		ssize_t r;
+
+		r = print_string(pssid, sizeof(pssid), ESCSTRING,
+		    ifp->ssid, ifp->ssid_len);
+		if (r == -1) {
+			logger(ifp->ctx, LOG_ERR,
+			    "%s: %s: %m", ifp->name, __func__);
+			pssid[0] = '\0';
+		}
+	} else
+		pssid[0] = '\0';
+	ifo = read_config(ifp->ctx, ifp->name, pssid, profile);
+	if (ifo == NULL) {
+		logger(ifp->ctx, LOG_DEBUG, "%s: no profile %s",
+		    ifp->name, profile);
+		return -1;
+	}
+	if (profile != NULL) {
+		strlcpy(ifp->profile, profile, sizeof(ifp->profile));
+		logger(ifp->ctx, LOG_INFO, "%s: selected profile %s",
+		    ifp->name, profile);
+	} else
+		*ifp->profile = '\0';
+
+	free_options(ifp->options);
+	ifp->options = ifo;
+	if (profile)
+		configure_interface1(ifp);
+	return 1;
+}
+
+static void
+configure_interface(struct interface *ifp, int argc, char **argv,
+    unsigned long long options)
+{
+	time_t old;
+
+	old = ifp->options ? ifp->options->mtime : 0;
+	dhcpcd_selectprofile(ifp, NULL);
+	add_options(ifp->ctx, ifp->name, ifp->options, argc, argv);
+	ifp->options->options |= options;
+	configure_interface1(ifp);
+
+	/* If the mtime has changed drop any old lease */
+	if (ifp->options && old != 0 && ifp->options->mtime != old) {
+		logger(ifp->ctx, LOG_WARNING,
+		    "%s: confile file changed, expiring leases", ifp->name);
+		dhcpcd_drop(ifp, 0);
+	}
+}
+
+static void
+dhcpcd_pollup(void *arg)
+{
+	struct interface *ifp = arg;
+	int carrier;
+
+	carrier = if_carrier(ifp); /* will set ifp->flags */
+	if (carrier == LINK_UP && !(ifp->flags & IFF_UP)) {
+		struct timespec tv;
+
+		tv.tv_sec = 0;
+		tv.tv_nsec = IF_POLL_UP * MSEC_PER_NSEC;
+		eloop_timeout_add_tv(ifp->ctx->eloop, &tv, dhcpcd_pollup, ifp);
+		return;
+	}
+
+	dhcpcd_handlecarrier(ifp->ctx, carrier, ifp->flags, ifp->name);
+}
+
+void
+dhcpcd_handlecarrier(struct dhcpcd_ctx *ctx, int carrier, unsigned int flags,
+    const char *ifname)
+{
+	struct interface *ifp;
+
+	ifp = if_find(ctx->ifaces, ifname);
+	if (ifp == NULL || !(ifp->options->options & DHCPCD_LINK))
+		return;
+
+	switch(carrier) {
+	case LINK_UNKNOWN:
+		carrier = if_carrier(ifp); /* will set ifp->flags */
+		break;
+	case LINK_UP:
+		/* we have a carrier! Still need to check for IFF_UP */
+		if (flags & IFF_UP)
+			ifp->flags = flags;
+		else {
+			/* So we need to poll for IFF_UP as there is no
+			 * kernel notification when it's set. */
+			dhcpcd_pollup(ifp);
+			return;
+		}
+		break;
+	default:
+		ifp->flags = flags;
+	}
+
+	/* If we here, we don't need to poll for IFF_UP any longer
+	 * if generated by a kernel event. */
+	eloop_timeout_delete(ifp->ctx->eloop, dhcpcd_pollup, ifp);
+
+	if (carrier == LINK_UNKNOWN) {
+		if (errno != ENOTTY) /* For example a PPP link on BSD */
+			logger(ctx, LOG_ERR, "%s: carrier_status: %m", ifname);
+	} else if (carrier == LINK_DOWN || (ifp->flags & IFF_UP) == 0) {
+		if (ifp->carrier != LINK_DOWN) {
+			if (ifp->carrier == LINK_UP)
+				logger(ctx, LOG_INFO, "%s: carrier lost",
+				    ifp->name);
+			ifp->carrier = LINK_DOWN;
+			script_runreason(ifp, "NOCARRIER");
+#ifdef NOCARRIER_PRESERVE_IP
+			arp_close(ifp);
+			ipv4_buildroutes(ifp->ctx);
+			ipv6nd_expire(ifp, 0);
+#else
+			dhcpcd_drop(ifp, 0);
+#endif
+		}
+	} else if (carrier == LINK_UP && ifp->flags & IFF_UP) {
+		if (ifp->carrier != LINK_UP) {
+			logger(ctx, LOG_INFO, "%s: carrier acquired",
+			    ifp->name);
+			ifp->carrier = LINK_UP;
+#if !defined(__linux__) && !defined(__NetBSD__)
+			/* BSD does not emit RTM_NEWADDR or RTM_CHGADDR when the
+			 * hardware address changes so we have to go
+			 * through the disovery process to work it out. */
+			dhcpcd_handleinterface(ctx, 0, ifp->name);
+#endif
+			if (ifp->wireless) {
+				uint8_t ossid[IF_SSIDSIZE];
+#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))
+					dhcpcd_drop(ifp, 0);
+#endif
+			}
+			dhcpcd_initstate(ifp, 0);
+			script_runreason(ifp, "CARRIER");
+#ifdef NOCARRIER_PRESERVE_IP
+			/* Set any IPv6 Routers we remembered to expire
+			 * faster than they would normally as we
+			 * maybe on a new network. */
+			ipv6nd_expire(ifp, RTR_CARRIER_EXPIRE);
+#endif
+			/* RFC4941 Section 3.5 */
+			if (ifp->options->options & DHCPCD_IPV6RA_OWN)
+				ipv6_gentempifid(ifp);
+			dhcpcd_startinterface(ifp);
+		}
+	}
+}
+
+static void
+warn_iaid_conflict(struct interface *ifp, uint8_t *iaid)
+{
+	struct interface *ifn;
+	size_t i;
+
+	TAILQ_FOREACH(ifn, ifp->ctx->ifaces, next) {
+		if (ifn == ifp)
+			continue;
+		if (ifn->options->options & DHCPCD_PFXDLGONLY)
+			continue;
+		if (memcmp(ifn->options->iaid, iaid,
+		    sizeof(ifn->options->iaid)) == 0)
+			break;
+		for (i = 0; i < ifn->options->ia_len; i++) {
+			if (memcmp(&ifn->options->ia[i].iaid, iaid,
+			    sizeof(ifn->options->ia[i].iaid)) == 0)
+				break;
+		}
+	}
+
+	/* This is only a problem if the interfaces are on the same network. */
+	if (ifn && strcmp(ifp->name, ifn->name))
+		logger(ifp->ctx, LOG_ERR,
+		    "%s: IAID conflicts with one assigned to %s",
+		    ifp->name, ifn->name);
+}
+
+static void
+pre_start(struct interface *ifp)
+{
+
+	/* Add our link-local address before upping the interface
+	 * so our RFC7217 address beats the hwaddr based one.
+	 * This is also a safety check incase it was ripped out
+	 * from under us. */
+	if (ifp->options->options & DHCPCD_IPV6 && ipv6_start(ifp) == -1) {
+		logger(ifp->ctx, LOG_ERR, "%s: ipv6_start: %m", ifp->name);
+		ifp->options->options &= ~DHCPCD_IPV6;
+	}
+}
+
+void
+dhcpcd_startinterface(void *arg)
+{
+	struct interface *ifp = arg;
+	struct if_options *ifo = ifp->options;
+	size_t i;
+	char buf[DUID_LEN * 3];
+	int carrier;
+	struct timespec tv;
+
+	if (ifo->options & DHCPCD_LINK) {
+		switch (ifp->carrier) {
+		case LINK_UP:
+			break;
+		case LINK_DOWN:
+			logger(ifp->ctx, LOG_INFO, "%s: waiting for carrier",
+			    ifp->name);
+			return;
+		case LINK_UNKNOWN:
+			/* No media state available.
+			 * Loop until both IFF_UP and IFF_RUNNING are set */
+			if ((carrier = if_carrier(ifp)) == LINK_UNKNOWN) {
+				tv.tv_sec = 0;
+				tv.tv_nsec = IF_POLL_UP * MSEC_PER_NSEC;
+				eloop_timeout_add_tv(ifp->ctx->eloop,
+				    &tv, dhcpcd_startinterface, ifp);
+			} else
+				dhcpcd_handlecarrier(ifp->ctx, carrier,
+				    ifp->flags, ifp->name);
+			return;
+		}
+	}
+
+	if (ifo->options & (DHCPCD_DUID | DHCPCD_IPV6)) {
+		/* Report client DUID */
+		if (ifp->ctx->duid == NULL) {
+			if (duid_init(ifp) == 0)
+				return;
+			if (!(ifo->options & DHCPCD_PFXDLGONLY))
+				logger(ifp->ctx, LOG_INFO, "DUID %s",
+				    hwaddr_ntoa(ifp->ctx->duid,
+				    ifp->ctx->duid_len,
+				    buf, sizeof(buf)));
+		}
+	}
+
+	if (ifo->options & (DHCPCD_DUID | DHCPCD_IPV6) &&
+	    !(ifo->options & DHCPCD_PFXDLGONLY))
+	{
+		/* Report IAIDs */
+		logger(ifp->ctx, LOG_INFO, "%s: IAID %s", ifp->name,
+		    hwaddr_ntoa(ifo->iaid, sizeof(ifo->iaid),
+		    buf, sizeof(buf)));
+		warn_iaid_conflict(ifp, ifo->iaid);
+		for (i = 0; i < ifo->ia_len; i++) {
+			if (memcmp(ifo->iaid, ifo->ia[i].iaid,
+			    sizeof(ifo->iaid)))
+			{
+				logger(ifp->ctx, LOG_INFO, "%s: IAID %s",
+				    ifp->name, hwaddr_ntoa(ifo->ia[i].iaid,
+				    sizeof(ifo->ia[i].iaid),
+				    buf, sizeof(buf)));
+				warn_iaid_conflict(ifp, ifo->ia[i].iaid);
+			}
+		}
+	}
+
+	if (ifo->options & DHCPCD_IPV6) {
+		if (ifo->options & DHCPCD_IPV6RS &&
+		    !(ifo->options & DHCPCD_INFORM))
+			ipv6nd_startrs(ifp);
+
+		if (ifo->options & DHCPCD_DHCP6)
+			dhcp6_find_delegates(ifp);
+
+		if (!(ifo->options & DHCPCD_IPV6RS) ||
+		    ifo->options & DHCPCD_IA_FORCED)
+		{
+			ssize_t nolease;
+
+			if (ifo->options & DHCPCD_IA_FORCED)
+				nolease = dhcp6_start(ifp, DH6S_INIT);
+			else {
+				nolease = 0;
+				/* Enabling the below doesn't really make
+				 * sense as there is currently no standard
+				 * to push routes via DHCPv6.
+				 * (There is an expired working draft,
+				 * maybe abandoned?)
+				 * You can also get it to work by forcing
+				 * an IA as shown above. */
+#if 0
+				/* With no RS or delegates we might
+				 * as well try and solicit a DHCPv6 address */
+				if (nolease == 0)
+					nolease = dhcp6_start(ifp, DH6S_INIT);
+#endif
+			}
+			if (nolease == -1)
+			        logger(ifp->ctx, LOG_ERR,
+				    "%s: dhcp6_start: %m", ifp->name);
+		}
+	}
+
+	if (ifo->options & DHCPCD_IPV4)
+		dhcp_start(ifp);
+}
+
+static void
+dhcpcd_prestartinterface(void *arg)
+{
+	struct interface *ifp = arg;
+
+	pre_start(ifp);
+	if (if_up(ifp) == -1)
+		logger(ifp->ctx, LOG_ERR, "%s: if_up: %m", ifp->name);
+
+	if (ifp->options->options & DHCPCD_LINK &&
+	    ifp->carrier == LINK_UNKNOWN)
+	{
+		int carrier;
+
+		if ((carrier = if_carrier(ifp)) != LINK_UNKNOWN) {
+			dhcpcd_handlecarrier(ifp->ctx, carrier,
+			    ifp->flags, ifp->name);
+			return;
+		}
+		logger(ifp->ctx, LOG_INFO,
+		    "%s: unknown carrier, waiting for interface flags",
+		    ifp->name);
+	}
+
+	dhcpcd_startinterface(ifp);
+}
+
+static void
+handle_link(void *arg)
+{
+	struct dhcpcd_ctx *ctx;
+
+	ctx = arg;
+	if (if_managelink(ctx) == -1) {
+		logger(ctx, LOG_ERR, "if_managelink: %m");
+		eloop_event_delete(ctx->eloop, ctx->link_fd, 0);
+		close(ctx->link_fd);
+		ctx->link_fd = -1;
+	}
+}
+
+static void
+dhcpcd_initstate1(struct interface *ifp, int argc, char **argv,
+    unsigned long long options)
+{
+	struct if_options *ifo;
+
+	configure_interface(ifp, argc, argv, options);
+	ifo = ifp->options;
+
+	if (ifo->options & DHCPCD_IPV4 && ipv4_init(ifp->ctx) == -1) {
+		logger(ifp->ctx, LOG_ERR, "ipv4_init: %m");
+		ifo->options &= ~DHCPCD_IPV4;
+	}
+	if (ifo->options & DHCPCD_IPV6 && ipv6_init(ifp->ctx) == NULL) {
+		logger(ifp->ctx, LOG_ERR, "ipv6_init: %m");
+		ifo->options &= ~DHCPCD_IPV6RS;
+	}
+
+	/* Add our link-local address before upping the interface
+	 * so our RFC7217 address beats the hwaddr based one.
+	 * This needs to happen before PREINIT incase a hook script
+	 * inadvertently ups the interface. */
+	if (ifo->options & DHCPCD_IPV6 && ipv6_start(ifp) == -1) {
+		logger(ifp->ctx, LOG_ERR, "%s: ipv6_start: %m", ifp->name);
+		ifo->options &= ~DHCPCD_IPV6;
+	}
+}
+
+void
+dhcpcd_initstate(struct interface *ifp, unsigned long long options)
+{
+
+	dhcpcd_initstate1(ifp, ifp->ctx->argc, ifp->ctx->argv, options);
+}
+
+static void
+run_preinit(struct interface *ifp)
+{
+
+	pre_start(ifp);
+	if (ifp->ctx->options & DHCPCD_TEST)
+		return;
+
+	script_runreason(ifp, "PREINIT");
+
+	if (ifp->options->options & DHCPCD_LINK && ifp->carrier != LINK_UNKNOWN)
+		script_runreason(ifp,
+		    ifp->carrier == LINK_UP ? "CARRIER" : "NOCARRIER");
+}
+
+int
+dhcpcd_handleinterface(void *arg, int action, const char *ifname)
+{
+	struct dhcpcd_ctx *ctx;
+	struct if_head *ifs;
+	struct interface *ifp, *iff, *ifn;
+	const char * const argv[] = { ifname };
+	int i;
+
+	ctx = arg;
+	if (action == -1) {
+		ifp = if_find(ctx->ifaces, ifname);
+		if (ifp == NULL) {
+			errno = ESRCH;
+			return -1;
+		}
+		logger(ctx, LOG_DEBUG, "%s: interface departed", ifp->name);
+		ifp->options->options |= DHCPCD_DEPARTED;
+		stop_interface(ifp);
+		return 0;
+	}
+
+	/* If running off an interface list, check it's in it. */
+	if (ctx->ifc && action != 2) {
+		for (i = 0; i < ctx->ifc; i++)
+			if (strcmp(ctx->ifv[i], ifname) == 0)
+				break;
+		if (i >= ctx->ifc)
+			return 0;
+	}
+
+	i = -1;
+	ifs = if_discover(ctx, -1, UNCONST(argv));
+	if (ifs == NULL) {
+		logger(ctx, LOG_ERR, "%s: if_discover: %m", __func__);
+		return -1;
+	}
+	TAILQ_FOREACH_SAFE(ifp, ifs, next, ifn) {
+		if (strcmp(ifp->name, ifname) != 0)
+			continue;
+		i = 0;
+		/* Check if we already have the interface */
+		iff = if_find(ctx->ifaces, ifp->name);
+		if (iff) {
+			logger(ctx, LOG_DEBUG, "%s: interface updated", iff->name);
+			/* The flags and hwaddr could have changed */
+			iff->flags = ifp->flags;
+			iff->hwlen = ifp->hwlen;
+			if (ifp->hwlen != 0)
+				memcpy(iff->hwaddr, ifp->hwaddr, iff->hwlen);
+		} else {
+			logger(ctx, LOG_DEBUG, "%s: interface added", ifp->name);
+			TAILQ_REMOVE(ifs, ifp, next);
+			TAILQ_INSERT_TAIL(ctx->ifaces, ifp, next);
+			dhcpcd_initstate(ifp, 0);
+			run_preinit(ifp);
+			iff = ifp;
+		}
+		if (action > 0)
+			dhcpcd_prestartinterface(iff);
+	}
+
+	/* Free our discovered list */
+	while ((ifp = TAILQ_FIRST(ifs))) {
+		TAILQ_REMOVE(ifs, ifp, next);
+		if_free(ifp);
+	}
+	free(ifs);
+
+	if (i == -1)
+		errno = ENOENT;
+	return i;
+}
+
+void
+dhcpcd_handlehwaddr(struct dhcpcd_ctx *ctx, const char *ifname,
+    const uint8_t *hwaddr, uint8_t hwlen)
+{
+	struct interface *ifp;
+	char buf[sizeof(ifp->hwaddr) * 3];
+
+	ifp = if_find(ctx->ifaces, ifname);
+	if (ifp == NULL)
+		return;
+
+	if (hwlen > sizeof(ifp->hwaddr)) {
+		errno = ENOBUFS;
+		logger(ctx, LOG_ERR, "%s: %s: %m", ifp->name, __func__);
+		return;
+	}
+
+	if (ifp->hwlen == hwlen && memcmp(ifp->hwaddr, hwaddr, hwlen) == 0)
+		return;
+
+	logger(ctx, LOG_INFO, "%s: new hardware address: %s", ifp->name,
+	    hwaddr_ntoa(hwaddr, hwlen, buf, sizeof(buf)));
+	ifp->hwlen = hwlen;
+	memcpy(ifp->hwaddr, hwaddr, hwlen);
+}
+
+void
+dhcpcd_start_interface(struct dhcpcd_ctx *ctx, const char *ifname)
+{
+	struct interface *ifp;
+	ifp = if_find(ctx->ifaces, ifname);
+	if (ifp == NULL)
+	{
+		logger(ctx, LOG_ERR, "start_interface: %s not found",
+		       ifname);
+		return;
+	}
+	dhcpcd_startinterface(ifp);
+}
+
+void
+dhcpcd_stop_interface(struct dhcpcd_ctx *ctx, const char *ifname)
+{
+	struct interface *ifp;
+	ifp = if_find(ctx->ifaces, ifname);
+	if (ifp == NULL)
+	{
+		logger(ctx, LOG_ERR, "stop_interface: %s not found",
+		       ifname);
+		return;
+	}
+	stop_interface(ifp);
+}
+
+void
+dhcpcd_stop_interfaces(struct dhcpcd_ctx *ctx)
+{
+	struct interface *ifp;
+	TAILQ_FOREACH(ifp, ctx->ifaces, next) {
+		stop_interface(ifp);
+	}
+}
+
+void
+dhcpcd_release_ipv4(struct dhcpcd_ctx *ctx, const char *ifname)
+{
+	struct interface *ifp;
+
+	ifp = if_find(ctx->ifaces, ifname);
+	if (ifp == NULL)
+	{
+		logger(ctx, LOG_ERR, "IPv4 release: %s not found",
+		       ifname);
+		return;
+	}
+	dhcp_drop(ifp, "RELEASE");
+}
+
+static void
+if_reboot(struct interface *ifp, int argc, char **argv)
+{
+	unsigned long long oldopts;
+
+	oldopts = ifp->options->options;
+	script_runreason(ifp, "RECONFIGURE");
+	dhcpcd_initstate1(ifp, argc, argv, 0);
+	dhcp_reboot_newopts(ifp, oldopts);
+	dhcp6_reboot(ifp);
+	dhcpcd_prestartinterface(ifp);
+}
+
+static void
+reload_config(struct dhcpcd_ctx *ctx)
+{
+	struct if_options *ifo;
+
+	free_globals(ctx);
+	ifo = read_config(ctx, NULL, NULL, NULL);
+	add_options(ctx, NULL, ifo, ctx->argc, ctx->argv);
+	/* We need to preserve these two options. */
+	if (ctx->options & DHCPCD_MASTER)
+		ifo->options |= DHCPCD_MASTER;
+	if (ctx->options & DHCPCD_DAEMONISED)
+		ifo->options |= DHCPCD_DAEMONISED;
+	ctx->options = ifo->options;
+	free_options(ifo);
+}
+
+static void
+reconf_reboot(struct dhcpcd_ctx *ctx, int action, int argc, char **argv, int oi)
+{
+	struct if_head *ifs;
+	struct interface *ifn, *ifp;
+
+	ifs = if_discover(ctx, argc - oi, argv + oi);
+	if (ifs == NULL) {
+		logger(ctx, LOG_ERR, "%s: if_discover: %m", __func__);
+		return;
+	}
+
+	while ((ifp = TAILQ_FIRST(ifs))) {
+		TAILQ_REMOVE(ifs, ifp, next);
+		ifn = if_find(ctx->ifaces, ifp->name);
+		if (ifn) {
+			if (action)
+				if_reboot(ifn, argc, argv);
+			else
+				ipv4_applyaddr(ifn);
+			if_free(ifp);
+		} else {
+			TAILQ_INSERT_TAIL(ctx->ifaces, ifp, next);
+			dhcpcd_initstate1(ifp, argc, argv, 0);
+			run_preinit(ifp);
+			dhcpcd_prestartinterface(ifp);
+		}
+	}
+	free(ifs);
+}
+
+static void
+stop_all_interfaces(struct dhcpcd_ctx *ctx, int do_release)
+{
+	struct interface *ifp;
+
+	/* drop_dhcp could change the order, so we do it like this. */
+	for (;;) {
+		/* Be sane and drop the last config first,
+		 * skipping any pseudo interfaces */
+		TAILQ_FOREACH_REVERSE(ifp, ctx->ifaces, if_head, next) {
+			if (!(ifp->options->options & DHCPCD_PFXDLGONLY))
+				break;
+		}
+		if (ifp == NULL)
+			break;
+		if (do_release) {
+			ifp->options->options |= DHCPCD_RELEASE;
+			ifp->options->options &= ~DHCPCD_PERSISTENT;
+		}
+		ifp->options->options |= DHCPCD_EXITING;
+		stop_interface(ifp);
+	}
+}
+
+#ifdef USE_SIGNALS
+struct dhcpcd_siginfo dhcpcd_siginfo;
+#define sigmsg "received %s, %s"
+void
+dhcpcd_handle_signal(void *arg)
+{
+	struct dhcpcd_ctx *ctx;
+	struct dhcpcd_siginfo *si;
+	struct interface *ifp;
+	int do_release, exit_code;;
+
+	ctx = dhcpcd_ctx;
+	si = arg;
+	do_release = 0;
+	exit_code = EXIT_FAILURE;
+	switch (si->signo) {
+	case SIGINT:
+		logger(ctx, LOG_INFO, sigmsg, "SIGINT", "stopping");
+		break;
+	case SIGTERM:
+		logger(ctx, LOG_INFO, sigmsg, "SIGTERM", "stopping");
+		exit_code = EXIT_SUCCESS;
+		break;
+	case SIGALRM:
+		logger(ctx, LOG_INFO, sigmsg, "SIGALRM", "releasing");
+		do_release = 1;
+		exit_code = EXIT_SUCCESS;
+		break;
+	case SIGHUP:
+		logger(ctx, LOG_INFO, sigmsg, "SIGHUP", "rebinding");
+		reload_config(ctx);
+		/* Preserve any options passed on the commandline
+		 * when we were started. */
+		reconf_reboot(ctx, 1, ctx->argc, ctx->argv,
+		    ctx->argc - ctx->ifc);
+		return;
+	case SIGUSR1:
+		logger(ctx, LOG_INFO, sigmsg, "SIGUSR1", "reconfiguring");
+		TAILQ_FOREACH(ifp, ctx->ifaces, next) {
+			ipv4_applyaddr(ifp);
+		}
+		return;
+	case SIGUSR2:
+		logger_close(ctx);
+		logger_open(ctx);
+		logger(ctx, LOG_INFO, sigmsg, "SIGUSR2", "reopened logfile");
+		return;
+	case SIGPIPE:
+		logger(ctx, LOG_WARNING, "received SIGPIPE");
+		return;
+	default:
+		logger(ctx, LOG_ERR,
+		    "received signal %d, "
+		    "but don't know what to do with it",
+		    si->signo);
+		return;
+	}
+
+	if (!(ctx->options & DHCPCD_TEST))
+		stop_all_interfaces(ctx, do_release);
+	eloop_exit(ctx->eloop, exit_code);
+}
+
+#ifndef HAVE_KQUEUE
+static void
+handle_signal(int sig, __unused siginfo_t *siginfo, __unused void *context)
+{
+
+	/* So that we can operate safely under a signal we instruct
+	 * eloop to pass a copy of the siginfo structure to handle_signal1
+	 * as the very first thing to do. */
+	dhcpcd_siginfo.signo = sig;
+	eloop_timeout_add_now(dhcpcd_ctx->eloop,
+	    dhcpcd_handle_signal, &dhcpcd_siginfo);
+}
+#endif
+
+static int
+signal_init(sigset_t *oldset)
+{
+	sigset_t newset;
+#ifndef HAVE_KQUEUE
+	int i;
+	struct sigaction sa;
+#endif
+
+	sigfillset(&newset);
+	if (sigprocmask(SIG_SETMASK, &newset, oldset) == -1)
+		return -1;
+
+#ifndef HAVE_KQUEUE
+	memset(&sa, 0, sizeof(sa));
+	sa.sa_sigaction = handle_signal;
+	sa.sa_flags = SA_SIGINFO;
+	sigemptyset(&sa.sa_mask);
+
+	for (i = 0; dhcpcd_handlesigs[i]; i++) {
+		if (sigaction(dhcpcd_handlesigs[i], &sa, NULL) == -1)
+			return -1;
+	}
+#endif
+	return 0;
+}
+#endif
+
+static void
+dhcpcd_getinterfaces(void *arg)
+{
+	struct fd_list *fd = arg;
+	struct interface *ifp;
+	size_t len;
+
+	len = 0;
+	TAILQ_FOREACH(ifp, fd->ctx->ifaces, next) {
+		len++;
+		if (D_STATE_RUNNING(ifp))
+			len++;
+		if (RS_STATE_RUNNING(ifp))
+			len++;
+		if (D6_STATE_RUNNING(ifp))
+			len++;
+	}
+	if (write(fd->fd, &len, sizeof(len)) != sizeof(len))
+		return;
+	eloop_event_delete(fd->ctx->eloop, fd->fd, 1);
+	TAILQ_FOREACH(ifp, fd->ctx->ifaces, next) {
+		if (send_interface(fd, ifp) == -1)
+			logger(ifp->ctx, LOG_ERR,
+			    "send_interface %d: %m", fd->fd);
+	}
+}
+
+int
+dhcpcd_handleargs(struct dhcpcd_ctx *ctx, struct fd_list *fd,
+    int argc, char **argv)
+{
+	struct interface *ifp;
+	int do_exit = 0, do_release = 0, do_reboot = 0;
+	int opt, oi = 0;
+	size_t len, l;
+	char *tmp, *p;
+
+	/* Special commands for our control socket
+	 * as the other end should be blocking until it gets the
+	 * expected reply we should be safely able just to change the
+	 * write callback on the fd */
+	if (strcmp(*argv, "--version") == 0) {
+		return control_queue(fd, UNCONST(VERSION),
+			strlen(VERSION) + 1, 0);
+	} else if (strcmp(*argv, "--getconfigfile") == 0) {
+		return control_queue(fd, UNCONST(fd->ctx->cffile),
+			strlen(fd->ctx->cffile) + 1, 0);
+	} else if (strcmp(*argv, "--getinterfaces") == 0) {
+		eloop_event_add(fd->ctx->eloop, fd->fd, NULL, NULL,
+			dhcpcd_getinterfaces, fd);
+		return 0;
+	} else if (strcmp(*argv, "--listen") == 0) {
+		fd->flags |= FD_LISTEN;
+		return 0;
+	}
+
+	/* Only priviledged users can control dhcpcd via the socket. */
+	if (fd->flags & FD_UNPRIV) {
+		errno = EPERM;
+		return -1;
+	}
+
+	/* Log the command */
+	len = 1;
+	for (opt = 0; opt < argc; opt++)
+		len += strlen(argv[opt]) + 1;
+	tmp = malloc(len);
+	if (tmp == NULL)
+		return -1;
+	p = tmp;
+	for (opt = 0; opt < argc; opt++) {
+		l = strlen(argv[opt]);
+		strlcpy(p, argv[opt], len);
+		len -= l + 1;
+		p += l;
+		*p++ = ' ';
+	}
+	*--p = '\0';
+	logger(ctx, LOG_INFO, "control command: %s", tmp);
+	free(tmp);
+
+	optind = 0;
+	while ((opt = getopt_long(argc, argv, IF_OPTS, cf_options, &oi)) != -1)
+	{
+		switch (opt) {
+		case 'g':
+			/* Assumed if below not set */
+			break;
+		case 'k':
+			do_release = 1;
+			break;
+		case 'n':
+			do_reboot = 1;
+			break;
+		case 'x':
+			do_exit = 1;
+			break;
+		}
+	}
+
+	if (do_release || do_exit) {
+		if (optind == argc) {
+			stop_all_interfaces(ctx, do_release);
+			eloop_exit(ctx->eloop, EXIT_SUCCESS);
+			return 0;
+		}
+		for (oi = optind; oi < argc; oi++) {
+			if ((ifp = if_find(ctx->ifaces, argv[oi])) == NULL)
+				continue;
+			if (do_release) {
+				ifp->options->options |= DHCPCD_RELEASE;
+				ifp->options->options &= ~DHCPCD_PERSISTENT;
+			}
+			ifp->options->options |= DHCPCD_EXITING;
+			stop_interface(ifp);
+		}
+		return 0;
+	}
+
+	reload_config(ctx);
+	/* XXX: Respect initial commandline options? */
+	reconf_reboot(ctx, do_reboot, argc, argv, optind);
+	return 0;
+}
+
+#if defined(__ANDROID__)
+static void
+switch_user(void)
+{
+	gid_t groups[] = { AID_DBUS, AID_INET, AID_SHELL };
+	struct __user_cap_header_struct header;
+	struct __user_cap_data_struct cap;
+
+	setgroups(sizeof(groups)/sizeof(groups[0]), groups);
+
+	prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
+
+	setgid(AID_DHCP);
+	setuid(AID_DHCP);
+	header.version = _LINUX_CAPABILITY_VERSION;
+	header.pid = 0;
+	cap.effective = cap.permitted =
+		(1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) |
+		(1 << CAP_NET_BROADCAST) | (1 << CAP_NET_BIND_SERVICE);
+	cap.inheritable = 0;
+	capset(&header, &cap);
+}
+#endif  /* __ANDROID__ */
+
+int
+main(int argc, char **argv)
+{
+	struct dhcpcd_ctx ctx;
+	struct if_options *ifo;
+	struct interface *ifp;
+	uint16_t family = 0;
+	int opt, oi = 0, i;
+	time_t t;
+	ssize_t len;
+#if defined(USE_SIGNALS) || !defined(THERE_IS_NO_FORK)
+	pid_t pid;
+#endif
+#ifdef USE_SIGNALS
+	int sig;
+	const char *siga;
+#endif
+	char ifn[IF_NAMESIZE];
+
+#if defined(__ANDROID__) && !defined(__BRILLO__)
+	switch_user();
+#endif  /* __ANDROID__ && !__BRILLO__ */
+
+	/* Test for --help and --version */
+	if (argc > 1) {
+		if (strcmp(argv[1], "--help") == 0) {
+			usage();
+			return EXIT_SUCCESS;
+		} else if (strcmp(argv[1], "--version") == 0) {
+			printf(""PACKAGE" "VERSION"\n%s\n", dhcpcd_copyright);
+			return EXIT_SUCCESS;
+		}
+	}
+
+	memset(&ctx, 0, sizeof(ctx));
+#ifdef USE_SIGNALS
+	dhcpcd_ctx = &ctx;
+	sig = 0;
+	siga = NULL;
+#endif
+	closefrom(3);
+
+	ctx.log_fd = -1;
+	logger_open(&ctx);
+	logger_mask(&ctx, LOG_UPTO(LOG_INFO));
+
+	ifo = NULL;
+	ctx.cffile = CONFIG;
+	ctx.pid_fd = ctx.control_fd = ctx.control_unpriv_fd = ctx.link_fd = -1;
+	TAILQ_INIT(&ctx.control_fds);
+#ifdef PLUGIN_DEV
+	ctx.dev_fd = -1;
+#endif
+#ifdef INET
+	ctx.udp_fd = -1;
+#endif
+	i = 0;
+	while ((opt = getopt_long(argc, argv, IF_OPTS, cf_options, &oi)) != -1)
+	{
+		switch (opt) {
+		case '4':
+			family = AF_INET;
+			break;
+		case '6':
+			family = AF_INET6;
+			break;
+		case 'f':
+			ctx.cffile = optarg;
+			break;
+#ifdef USE_SIGNALS
+		case 'g':
+			sig = SIGUSR1;
+			siga = "USR1";
+			break;
+		case 'j':
+			ctx.logfile = strdup(optarg);
+			logger_close(&ctx);
+			logger_open(&ctx);
+			break;
+		case 'k':
+			sig = SIGALRM;
+			siga = "ARLM";
+			break;
+		case 'n':
+			sig = SIGHUP;
+			siga = "HUP";
+			break;
+		case 'x':
+			sig = SIGTERM;
+			siga = "TERM";;
+			break;
+#endif
+		case 'T':
+			i = 1;
+			break;
+		case 'U':
+			if (i == 3)
+				i = 4;
+			else if (i != 4)
+				i = 3;
+			break;
+		case 'V':
+			i = 2;
+			break;
+		case '?':
+			usage();
+			goto exit_failure;
+		}
+	}
+
+	ctx.argv = argv;
+	ctx.argc = argc;
+	ctx.ifc = argc - optind;
+	ctx.ifv = argv + optind;
+
+	ifo = read_config(&ctx, NULL, NULL, NULL);
+	if (ifo == NULL)
+		goto exit_failure;
+	opt = add_options(&ctx, NULL, ifo, argc, argv);
+	if (opt != 1) {
+		if (opt == 0)
+			usage();
+		goto exit_failure;
+	}
+	if (i == 2) {
+		printf("Interface options:\n");
+		if (optind == argc - 1) {
+			free_options(ifo);
+			ifo = read_config(&ctx, argv[optind], NULL, NULL);
+			if (ifo == NULL)
+				goto exit_failure;
+			add_options(&ctx, NULL, ifo, argc, argv);
+		}
+		if_printoptions();
+#ifdef INET
+		if (family == 0 || family == AF_INET) {
+			printf("\nDHCPv4 options:\n");
+			dhcp_printoptions(&ctx,
+			    ifo->dhcp_override, ifo->dhcp_override_len);
+		}
+#endif
+#ifdef INET6
+		if (family == 0 || family == AF_INET6) {
+			printf("\nDHCPv6 options:\n");
+			dhcp6_printoptions(&ctx,
+			    ifo->dhcp6_override, ifo->dhcp6_override_len);
+		}
+#endif
+		goto exit_success;
+	}
+	ctx.options = ifo->options;
+	if (i != 0) {
+		if (i == 1)
+			ctx.options |= DHCPCD_TEST;
+		else
+			ctx.options |= DHCPCD_DUMPLEASE;
+		if (i == 4)
+			ctx.options |= DHCPCD_PFXDLGONLY;
+		ctx.options |= DHCPCD_PERSISTENT;
+		ctx.options &= ~DHCPCD_DAEMONISE;
+	}
+
+#ifdef THERE_IS_NO_FORK
+	ctx.options &= ~DHCPCD_DAEMONISE;
+#endif
+
+	if (ctx.options & DHCPCD_DEBUG)
+		logger_mask(&ctx, LOG_UPTO(LOG_DEBUG));
+	if (ctx.options & DHCPCD_QUIET) {
+		i = open(_PATH_DEVNULL, O_RDWR);
+		if (i == -1)
+			logger(&ctx, LOG_ERR, "%s: open: %m", __func__);
+		else {
+			dup2(i, STDERR_FILENO);
+			close(i);
+		}
+	}
+
+	if (!(ctx.options & (DHCPCD_TEST | DHCPCD_DUMPLEASE))) {
+		/* If we have any other args, we should run as a single dhcpcd
+		 *  instance for that interface. */
+		if (optind == argc - 1 && !(ctx.options & DHCPCD_MASTER)) {
+			const char *per;
+			int intf_len = strlen(argv[optind]);
+			split_interface_lease(argv[optind], &intf_len, NULL);
+			if (intf_len > IF_NAMESIZE) {
+				logger(&ctx, LOG_ERR,
+				    "%s: interface name too long",
+				    argv[optind]);
+				goto exit_failure;
+			}
+			strlcpy(ifn, argv[optind], intf_len + 1);
+			/* Allow a dhcpcd interface per address family */
+			switch(family) {
+			case AF_INET:
+				per = "-4";
+				break;
+			case AF_INET6:
+				per = "-6";
+				break;
+			default:
+				per = "";
+			}
+			snprintf(ctx.pidfile, sizeof(ctx.pidfile),
+			    PIDFILE, "-", ifn, per);
+		} else {
+			snprintf(ctx.pidfile, sizeof(ctx.pidfile),
+			    PIDFILE, "", "", "");
+			ctx.options |= DHCPCD_MASTER;
+		}
+	}
+
+	if (chdir("/") == -1)
+		logger(&ctx, LOG_ERR, "chdir `/': %m");
+
+	/* Freeing allocated addresses from dumping leases can trigger
+	 * eloop removals as well, so init here. */
+	ctx.eloop = eloop_init(&ctx);
+	if (ctx.eloop == NULL) {
+		logger(&ctx, LOG_ERR, "%s: eloop_init: %m", __func__);
+		goto exit_failure;
+	}
+
+	if (ctx.options & DHCPCD_DUMPLEASE) {
+		if (optind != argc - 1) {
+			logger(&ctx, LOG_ERR,
+			    "dumplease requires an interface");
+			goto exit_failure;
+		}
+		i = 0;
+		/* We need to try and find the interface so we can
+		 * load the hardware address to compare automated IAID */
+		ctx.ifaces = if_discover(&ctx, 1, argv + optind);
+		if (ctx.ifaces == NULL) {
+			logger(&ctx, LOG_ERR, "if_discover: %m");
+			goto exit_failure;
+		}
+		ifp = TAILQ_FIRST(ctx.ifaces);
+		if (ifp == NULL) {
+			ifp = calloc(1, sizeof(*ifp));
+			if (ifp == NULL) {
+				logger(&ctx, LOG_ERR, "%s: %m", __func__);
+				goto exit_failure;
+			}
+			strlcpy(ctx.pidfile, argv[optind], sizeof(ctx.pidfile));
+			ifp->ctx = &ctx;
+			TAILQ_INSERT_HEAD(ctx.ifaces, ifp, next);
+			if (family == 0) {
+				if (ctx.pidfile[strlen(ctx.pidfile) - 1] == '6')
+					family = AF_INET6;
+				else
+					family = AF_INET;
+			}
+		}
+		configure_interface(ifp, ctx.argc, ctx.argv, 0);
+		if (ctx.options & DHCPCD_PFXDLGONLY)
+			ifp->options->options |= DHCPCD_PFXDLGONLY;
+		if (family == 0 || family == AF_INET) {
+			if (dhcp_dump(ifp) == -1)
+				i = 1;
+		}
+		if (family == 0 || family == AF_INET6) {
+			if (dhcp6_dump(ifp) == -1)
+				i = 1;
+		}
+		if (i == -1)
+			goto exit_failure;
+		goto exit_success;
+	}
+
+#ifdef USE_SIGNALS
+	if (!(ctx.options & DHCPCD_TEST) &&
+	    (sig == 0 || ctx.ifc != 0))
+	{
+#endif
+		if (ctx.options & DHCPCD_MASTER)
+			i = -1;
+		else
+			i = control_open(&ctx, argv[optind]);
+		if (i == -1)
+			i = control_open(&ctx, NULL);
+		if (i != -1) {
+			logger(&ctx, LOG_INFO,
+			    "sending commands to master dhcpcd process");
+			len = control_send(&ctx, argc, argv);
+			control_close(&ctx);
+			if (len > 0) {
+				logger(&ctx, LOG_DEBUG, "send OK");
+				goto exit_success;
+			} else {
+				logger(&ctx, LOG_ERR,
+				    "failed to send commands");
+				goto exit_failure;
+			}
+		} else {
+			if (errno != ENOENT)
+				logger(&ctx, LOG_ERR, "control_open: %m");
+		}
+#ifdef USE_SIGNALS
+	}
+#endif
+
+	if (geteuid())
+		logger(&ctx, LOG_NOTICE,
+		    PACKAGE " is running with reduced privileges");
+
+#ifdef USE_SIGNALS
+	if (sig != 0) {
+		pid = read_pid(ctx.pidfile);
+		if (pid != 0)
+			logger(&ctx, LOG_INFO, "sending signal %s to pid %d",
+			    siga, pid);
+		if (pid == 0 || kill(pid, sig) != 0) {
+			if (sig != SIGHUP && errno != EPERM)
+				logger(&ctx, LOG_ERR, ""PACKAGE" not running");
+			if (pid != 0 && errno != ESRCH) {
+				logger(&ctx, LOG_ERR, "kill: %m");
+				goto exit_failure;
+			}
+			unlink(ctx.pidfile);
+			if (sig != SIGHUP)
+				goto exit_failure;
+		} else {
+			struct timespec ts;
+
+			if (sig == SIGHUP || sig == SIGUSR1)
+				goto exit_success;
+			/* Spin until it exits */
+			logger(&ctx, LOG_INFO,
+			    "waiting for pid %d to exit", pid);
+			ts.tv_sec = 0;
+			ts.tv_nsec = 100000000; /* 10th of a second */
+			for(i = 0; i < 100; i++) {
+				nanosleep(&ts, NULL);
+				if (read_pid(ctx.pidfile) == 0)
+					goto exit_success;
+			}
+			logger(&ctx, LOG_ERR, "pid %d failed to exit", pid);
+			goto exit_failure;
+		}
+	}
+
+	if (!(ctx.options & DHCPCD_TEST)) {
+		if ((pid = read_pid(ctx.pidfile)) > 0 &&
+		    kill(pid, 0) == 0)
+		{
+			logger(&ctx, LOG_ERR, ""PACKAGE
+			    " already running on pid %d (%s)",
+			    pid, ctx.pidfile);
+			goto exit_failure;
+		}
+
+#if !defined(__ANDROID__)
+		/* Ensure we have the needed directories
+		 * On Android, we assume that these directories have been created
+		 * by calls to mkdir in an init.rc file. */
+		if (mkdir(RUNDIR, 0755) == -1 && errno != EEXIST)
+			logger(&ctx, LOG_ERR, "mkdir `%s': %m", RUNDIR);
+		if (mkdir(DBDIR, 0755) == -1 && errno != EEXIST)
+			logger(&ctx, LOG_ERR, "mkdir `%s': %m", DBDIR);
+#endif /* __ANDROID__ */
+
+		opt = O_WRONLY | O_CREAT | O_NONBLOCK;
+#ifdef O_CLOEXEC
+		opt |= O_CLOEXEC;
+#endif
+		ctx.pid_fd = open(ctx.pidfile, opt, 0664);
+		if (ctx.pid_fd == -1)
+			logger(&ctx, LOG_ERR, "open `%s': %m", ctx.pidfile);
+		else {
+#ifdef LOCK_EX
+			/* Lock the file so that only one instance of dhcpcd
+			 * runs on an interface */
+			if (flock(ctx.pid_fd, LOCK_EX | LOCK_NB) == -1) {
+				logger(&ctx, LOG_ERR, "flock `%s': %m", ctx.pidfile);
+				close(ctx.pid_fd);
+				ctx.pid_fd = -1;
+				goto exit_failure;
+			}
+#endif
+#ifndef O_CLOEXEC
+			if (fcntl(ctx.pid_fd, F_GETFD, &opt) == -1 ||
+			    fcntl(ctx.pid_fd, F_SETFD, opt | FD_CLOEXEC) == -1)
+			{
+				logger(&ctx, LOG_ERR, "fcntl: %m");
+				close(ctx.pid_fd);
+				ctx.pid_fd = -1;
+				goto exit_failure;
+			}
+#endif
+			write_pid(ctx.pid_fd, getpid());
+		}
+	}
+
+	if (ctx.options & DHCPCD_MASTER) {
+		if (control_start(&ctx, NULL) == -1)
+			logger(&ctx, LOG_ERR, "control_start: %m");
+	}
+#else
+	if (control_start(&ctx,
+	    ctx.options & DHCPCD_MASTER ? NULL : argv[optind]) == -1)
+	{
+		logger(&ctx, LOG_ERR, "control_start: %m");
+		goto exit_failure;
+	}
+#endif
+
+	logger(&ctx, LOG_DEBUG, PACKAGE "-" VERSION " starting");
+	ctx.options |= DHCPCD_STARTED;
+#ifdef USE_SIGNALS
+	/* Save signal mask, block and redirect signals to our handler */
+	if (signal_init(&ctx.sigset) == -1) {
+		logger(&ctx, LOG_ERR, "signal_setup: %m");
+		goto exit_failure;
+	}
+#endif
+
+	/* When running dhcpcd against a single interface, we need to retain
+	 * the old behaviour of waiting for an IP address */
+	if (ctx.ifc == 1 && !(ctx.options & DHCPCD_BACKGROUND))
+		ctx.options |= DHCPCD_WAITIP;
+
+	/* RTM_NEWADDR goes through the link socket as well which we
+	 * need for IPv6 DAD, so we check for DHCPCD_LINK in
+	 * dhcpcd_handlecarrier instead.
+	 * We also need to open this before checking for interfaces below
+	 * so that we pickup any new addresses during the discover phase. */
+	ctx.link_fd = if_openlinksocket();
+	if (ctx.link_fd == -1)
+		logger(&ctx, LOG_ERR, "open_link_socket: %m");
+	else
+		eloop_event_add(ctx.eloop, ctx.link_fd,
+		    handle_link, &ctx, NULL, NULL);
+
+	/* Start any dev listening plugin which may want to
+	 * change the interface name provided by the kernel */
+	if ((ctx.options & (DHCPCD_MASTER | DHCPCD_DEV)) ==
+	    (DHCPCD_MASTER | DHCPCD_DEV))
+		dev_start(&ctx);
+
+	if (rpc_init(&ctx) == -1) {
+		/* NB: rpc_init generates a syslog msg */
+		exit(EXIT_FAILURE);
+	}
+	rpc_signal_status("Init");
+
+	ctx.ifaces = if_discover(&ctx, ctx.ifc, ctx.ifv);
+	if (ctx.ifaces == NULL) {
+		logger(&ctx, LOG_ERR, "if_discover: %m");
+		goto exit_failure;
+	}
+	for (i = 0; i < ctx.ifc; i++) {
+		int intf_len = strlen(ctx.ifv[i]);
+		split_interface_lease(ctx.ifv[i], &intf_len, NULL);
+		if (intf_len > IF_NAMESIZE) {
+			logger(&ctx, LOG_ERR,
+			    "%s: interface name too long",
+			    ctx.ifv[i]);
+			continue;
+		}
+		strlcpy(ifn, ctx.ifv[i], intf_len + 1);
+		if (if_find(ctx.ifaces, ifn) == NULL)
+			logger(&ctx, LOG_ERR,
+			    "%s: interface not found or invalid",
+			    ifn);
+	}
+	if (TAILQ_FIRST(ctx.ifaces) == NULL) {
+		if (ctx.ifc == 0)
+			logger(&ctx, LOG_ERR, "no valid interfaces found");
+		else
+			goto exit_failure;
+		if (!(ctx.options & DHCPCD_LINK)) {
+			logger(&ctx, LOG_ERR,
+			    "aborting as link detection is disabled");
+			goto exit_failure;
+		}
+	}
+
+	TAILQ_FOREACH(ifp, ctx.ifaces, next) {
+		dhcpcd_initstate1(ifp, argc, argv, 0);
+	}
+
+	if (ctx.options & DHCPCD_BACKGROUND && dhcpcd_daemonise(&ctx))
+		goto exit_success;
+
+	opt = 0;
+	TAILQ_FOREACH(ifp, ctx.ifaces, next) {
+		run_preinit(ifp);
+		if (ifp->carrier != LINK_DOWN)
+			opt = 1;
+	}
+
+	if (!(ctx.options & DHCPCD_BACKGROUND)) {
+		if (ctx.options & DHCPCD_MASTER)
+			t = ifo->timeout;
+		else if ((ifp = TAILQ_FIRST(ctx.ifaces)))
+			t = ifp->options->timeout;
+		else
+			t = 0;
+		if (opt == 0 &&
+		    ctx.options & DHCPCD_LINK &&
+		    !(ctx.options & DHCPCD_WAITIP))
+		{
+			logger(&ctx, LOG_WARNING,
+			    "no interfaces have a carrier");
+			if (dhcpcd_daemonise(&ctx))
+				goto exit_success;
+		} else if (t > 0 &&
+		    /* Test mode removes the daemonise bit, so check for both */
+		    ctx.options & (DHCPCD_DAEMONISE | DHCPCD_TEST))
+		{
+			eloop_timeout_add_sec(ctx.eloop, t,
+			    handle_exit_timeout, &ctx);
+		}
+	}
+	free_options(ifo);
+	ifo = NULL;
+
+	if_sortinterfaces(&ctx);
+	TAILQ_FOREACH(ifp, ctx.ifaces, next) {
+		eloop_timeout_add_sec(ctx.eloop, 0,
+		    dhcpcd_prestartinterface, ifp);
+	}
+
+	i = eloop_start(ctx.eloop);
+	goto exit1;
+
+exit_success:
+	i = EXIT_SUCCESS;
+	goto exit1;
+
+exit_failure:
+	i = EXIT_FAILURE;
+
+exit1:
+	/* Free memory and close fd's */
+	if (ctx.ifaces) {
+		while ((ifp = TAILQ_FIRST(ctx.ifaces))) {
+			TAILQ_REMOVE(ctx.ifaces, ifp, next);
+			if_free(ifp);
+		}
+		free(ctx.ifaces);
+	}
+	free(ctx.duid);
+	if (ctx.link_fd != -1) {
+		eloop_event_delete(ctx.eloop, ctx.link_fd, 0);
+		close(ctx.link_fd);
+	}
+
+	free_options(ifo);
+	free_globals(&ctx);
+	ipv4_ctxfree(&ctx);
+	ipv6_ctxfree(&ctx);
+	dev_stop(&ctx);
+	if (control_stop(&ctx) == -1)
+		logger(&ctx, LOG_ERR, "control_stop: %m:");
+	if (ctx.pid_fd != -1) {
+		close(ctx.pid_fd);
+		unlink(ctx.pidfile);
+	}
+	eloop_free(ctx.eloop);
+
+	if (ctx.options & DHCPCD_STARTED && !(ctx.options & DHCPCD_FORKED))
+		logger(&ctx, LOG_INFO, PACKAGE " exited");
+	logger_close(&ctx);
+	free(ctx.logfile);
+	return i;
+}
diff --git a/dhcpcd-6.8.2/dhcpcd.conf b/dhcpcd-6.8.2/dhcpcd.conf
new file mode 100644
index 0000000..833c5b6
--- /dev/null
+++ b/dhcpcd-6.8.2/dhcpcd.conf
@@ -0,0 +1,52 @@
+# A sample configuration for dhcpcd.
+# See dhcpcd.conf(5) for details.
+
+# Disabling ARP checking
+noarp
+
+# Disabling link state monitoring
+nolink
+
+# Allow users of this group to interact with dhcpcd via the control socket.
+#controlgroup wheel
+
+# Inform the DHCP server of our hostname for DDNS.
+hostname
+
+# Use the hardware address of the interface for the Client ID.
+clientid
+# or
+# Use the same DUID + IAID as set in DHCPv6 for DHCPv4 ClientID as per RFC4361.
+# Some non-RFC compliant DHCP servers do not reply with this set.
+# In this case, comment out duid and enable clientid above.
+#duid
+
+# Persist interface configuration when dhcpcd exits.
+#persistent
+
+# Rapid commit support.
+# Safe to enable by default because it requires the equivalent option set
+# on the server to actually work.
+#option rapid_commit
+
+# A list of options to request from the DHCP server.
+option domain_name_servers, domain_name, domain_search, host_name, wpad_url
+option classless_static_routes
+# Most distributions have NTP support.
+#option ntp_servers
+# Respect the network MTU.
+# Some interface drivers reset when changing the MTU so disabled by default.
+option interface_mtu
+
+# A ServerID is required by RFC2131.
+require dhcp_server_identifier
+
+# Generate Stable Private IPv6 Addresses instead of hardware based ones
+#slaac private
+
+# A hook script is provided to lookup the hostname if not set by the DHCP
+# server, but it should not be run by default.
+#nohook lookup-hostname
+
+# Disable IPv6 router solicitation
+noipv6rs
diff --git a/dhcpcd-6.8.2/dhcpcd.conf.5.in b/dhcpcd-6.8.2/dhcpcd.conf.5.in
new file mode 100644
index 0000000..905a924
--- /dev/null
+++ b/dhcpcd-6.8.2/dhcpcd.conf.5.in
@@ -0,0 +1,821 @@
+.\" Copyright (c) 2006-2015 Roy Marples
+.\" All rights reserved
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.Dd April 6, 2015
+.Dt DHCPCD.CONF 5
+.Os
+.Sh NAME
+.Nm dhcpcd.conf
+.Nd dhcpcd configuration file
+.Sh DESCRIPTION
+Although
+.Nm dhcpcd
+can do everything from the command line, there are cases where it's just easier
+to do it once in a configuration file.
+Most of the options found in
+.Xr dhcpcd 8
+can be used here.
+The first word on the line is the option and the rest of the line is the value.
+Leading and trailing whitespace for the option and value are trimmed.
+You can escape characters in the value using the \\ character.
+.Pp
+Blank lines and lines starting with # are ignored.
+.Pp
+Here's a list of available options:
+.Bl -tag -width indent
+.It Ic allowinterfaces Ar pattern
+When discovering interfaces, the interface name must match
+.Ar pattern
+which is a space or comma separated list of patterns passed to
+.Xr fnmatch 3 .
+If the same interface is matched in
+.Ic denyinterfaces
+then it is still denied.
+.It Ic denyinterfaces Ar pattern
+When discovering interfaces, the interface name must not match
+.Ar pattern
+which is a space or comma separated list of patterns passed to
+.Xr fnmatch 3 .
+.It Ic arping Ar address Op address
+.Nm dhcpcd
+will arping each address in order before attempting DHCP.
+If an address is found, we will select the replying hardware address as the
+profile, otherwise the ip address.
+Example:
+.Pp
+.D1 interface bge0
+.D1 arping 192.168.0.1
+.Pp
+.D1 profile 192.168.0.1
+.D1 static ip_address=192.168.0.10/24
+.It Ic authprotocol Ar protocol Ar algorithm Ar rdm
+Authenticate DHCP messages.
+See the Supported Authentication Protocols section.
+.It Ic authtoken Ar secretid Ar realm Ar expire Ar key
+Define a shared key for use in authentication.
+.Ar realm can be "" to for use with the
+.Ar delayed
+prptocol.
+.Ar expire
+is the date the token expires and should be formatted "yyy-mm-dd HH:MM".
+You can use the keyword
+.Ar forever
+or
+.Ar 0
+which means the token never expires.
+For the token protocol,
+.Ar secretid
+needs to be 0 and
+.Ar realm
+needs to be "".
+If
+.Nm dhcpcd
+has the error
+.D1 dhcp_auth_encode: Invalid argument
+then it means that
+.Nm dhcpcd
+could not find the correct authentication token in your configuration.
+.It Ic background
+Background immediately.
+This is useful for startup scripts which don't disable link messages for
+carrier status.
+.It Ic blacklist Ar address Ns Op /cidr
+Ignores all packets from
+.Ar address Ns Op /cidr .
+.It Ic whitelist Ar address Ns Op /cidr
+Only accept packets from
+.Ar address Ns Op /cidr .
+.Ic blacklist
+is ignored if
+.Ic whitelist
+is set.
+.It Ic bootp
+Be a BOOTP client.
+Basically, this just doesn't send a DHCP Message Type option and will only
+interact with a BOOTP server.
+All other DHCP options still work.
+.It Ic broadcast
+Instructs the DHCP server to broadcast replies back to the client.
+Normally this is only set for non Ethernet interfaces,
+such as FireWire and InfiniBand.
+In most cases,
+.Nm dhcpcd
+will set this automatically.
+.It Ic controlgroup Ar group
+Sets the group ownership of
+.Pa @RUNDIR@/dhcpcd.sock
+so that users other than root can connect to
+.Nm dhcpcd .
+.It Ic debug
+Echo debug messages to the stderr and syslog.
+.It Ic dev Ar value
+Load the
+.Ar value
+.Pa /dev
+management module.
+.Nm dhcpcd
+will load the first one found to work, if any.
+.It Ic env Ar value
+Push
+.Ar value
+to the environment for use in
+.Xr dhcpcd-run-hooks 8 .
+For example, you can force the hostname hook to always set the hostname with
+.Ic env
+.Va force_hostname=YES .
+Or set which driver
+.Xr wpa_supplicant 8
+should use with
+.Ic env
+.Va wpa_supplicant_driver=nl80211
+.Pp
+If the hostname is set, will be will set to the FQDN if possible as per
+RFC 4702 section 3.1.
+If the FQDN option is missing,
+.Nm dhcpcd
+will still try and set a FQDN from the hostname and domain options for
+consistency.
+To override this, set
+.Ic env
+.Va hostname_fqdn=[YES|NO|SERVER] .
+A value of server means just what the server says, don't manipulate it.
+This could lead to an inconsistent hostname on a DHCPv4 and DHCPv6 network
+where the DHCPv4 hostname is short and the DHCPv6 has an FQDN.
+DHCPv6 has no hostname option.
+.It Ic clientid Ar string
+Send the
+.Ar clientid .
+If the string is of the format 01:02:03 then it is encoded as hex.
+For interfaces whose hardware address is longer than 8 bytes, or if the
+.Ar clientid
+is an empty string then
+.Nm dhcpcd
+sends a default
+.Ar clientid
+of the hardware family and the hardware address.
+.It Ic duid
+Generate an
+.Rs
+.%T "RFC 4361"
+.Re
+compliant DHCP Unique Identifier.
+If persistent storage is available then a DUID-LLT (link local address + time)
+is generated, otherwise DUID-LL is generated (link local address).
+This, plus the IAID will be used as the
+.Ic clientid .
+The DUID-LLT generated will be held in
+.Pa @SYSCONFDIR@/dhcpcd.duid
+and should not be copied to other hosts.
+.It Ic iaid Ar iaid
+Set the Interface Association Identifier to
+.Ar iaid .
+This option must be used in an
+.Ic interface
+block.
+This defaults to the last 4 bytes of the hardware address assigned to the
+interface.
+Each instance of this should be unique within the scope of the client and
+.Nm dhcpcd
+warns if a conflict is detected.
+If there is a conflict, it is only a problem if the conflicted IAIDs are
+used on the same network.
+.It Ic dhcp
+Enable DHCP on the interface, on by default.
+.It Ic dhcp6
+Enable DHCPv6 on the interface, on by default.
+.It Ic ipv4
+Enable IPv4 on the interface, on by default.
+.It Ic ipv6
+Enable IPv6 on the interface, on by default.
+.It Ic persistent
+.Nm dhcpcd
+normally de-configures the interface and configuration when it exits.
+Sometimes, this isn't desirable if, for example, you have root mounted over
+NFS or SSH clients connect to this host and they need to be notified of
+the host shutting down.
+You can use this option to stop this from happening.
+.It Ic fallback Ar profile
+Fallback to using this profile if DHCP fails.
+This allows you to configure a static profile instead of using ZeroConf.
+.It Ic hostname Ar name
+Sends
+.Ar hostname
+to the DHCP server so it can be registered in DNS.
+If
+.Ar hostname
+is an empty string then the current system hostname is sent.
+If
+.Ar hostname
+is a FQDN (ie, contains a .) then it will be encoded as such.
+.It Ic hostname_short
+Sends the short hostname to the DHCP server instead of the FQDN.
+This is useful because DHCP servers will not register the FQDN in their
+DNS if the domain part does not match theirs.
+.Pp
+Also, see the
+.Ic env
+option above to control how the hostname is set on the host.
+.It Ic ia_na Op Ar iaid Op / address
+Request a DHCPv6 Normal Address for
+.Ar iaid .
+.Ar iaid
+defaults to the
+.Ic iaid
+option as described above.
+You can request more than one ia_na by specifying a unique
+.Ar iaid
+for each one.
+.It Ic ia_ta Op Ar iaid
+Request a DHCPv6 Temporary Address for
+.Ar iaid .
+You can request more than one ia_ta by specifying a unique
+.Ar iaid
+for each one.
+.It Ic ia_pd Op Ar iaid Oo / Ar prefix / Ar prefix_len Oc Op Ar interface Op / Ar sla_id Op / Ar prefix_len
+Request a DHCPv6 Delegated Prefix for
+.Ar iaid .
+This option must be used in an
+.Ic interface
+block.
+Unless a
+.Ar sla_id
+of 0 is assigned, a reject route is installed for the Delegated Prefix to
+stop unallocated addresses being resolved upstream.
+If no
+.Ar interface
+is given then we will assign a prefix to every other interface with a
+.Ar sla_id
+equivalent to the interface index assigned by the OS.
+Otherwise addresses are only assigned for each
+.Ar interface
+and
+.Ar sla_id .
+Each assigned address will have a suffix of 1.
+You cannot assign a prefix to the requesting interface unless the
+DHCPv6 server supports
+.Li RFC6603
+Prefix Exclude Option.
+.Nm dhcpcd
+has to be running for all the interfaces it is delegating to.
+A default
+.Ar prefix_len
+of 64 is assumed, unless the maximum
+.Ar sla_id
+does not fit.
+In this case
+.Ar prefix_len
+is increased to the highest multiple of 8 that can accommodate the
+.Ar sla_id .
+.Ar sla_id
+is an integer and is added to the prefix which must fit inside
+.Ar prefix_len
+less the length of the delegated prefix.
+.Ar sla_id can be 0 only if the Delegated Prefix is assigned to one interface.
+You can specify multiple
+.Ar interface /
+.Ar sla_id /
+.Ar prefix_len
+per
+.Ic ia_pd ,
+space separated.
+IPv6RS should be disabled globally when requesting a Prefix Delegation.
+.Pp
+In the following example eth0 is the externally facing interface to be
+configured for both IPv4 and IPv6.
+The DHCPv4 server will provide us with an IPv4 address and a default route.
+The DHCPv6 server is going to provide us with an IPv6 address, a default
+route and a /64 subnet to be delegated to the internal interface.
+The eth1 interface will be automatically configured
+for IPv6 using the first address (::1) from the delegated prefix.
+.Xr rtadvd 8
+can be used with an empty configuration file on eth1 to provide automatic
+IPv6 address configuration for the internal network.
+.Bd -literal -indent
+noipv6rs            # disable routing solicitation
+denyinterfaces eth2 # Don't touch eth2 at all
+interface eth0
+    ipv6rs	    # enable routing solicitation get the
+		    # default IPv6 route
+    ia_na 1	    # request an IPv6 address
+    ia_pd 2 eth1/0  # get a /64 and assign it to eth1
+.Ed
+.It Ic ia_pd_mix
+To be RFC compliant,
+.Nm dhcpcd
+cannot mix Prefix Delegation with other DHCPv6 address types in the same
+session.
+This has a number of issues: additional DHCP traffic and potential collisions
+between options.
+.Ic ia_pd_mix
+enables
+.Li draft-ietf-dhc-dhcpv6-stateful-issues-06
+support so that Prefix Delegation can be mixed with other address types in
+the same session.
+.It Ic ipv4only
+Only configure IPv4.
+.It Ic ipv6only
+Only confgiure IPv6.
+.It Ic fqdn Op disable | ptr | both
+ptr just asks the DHCP server to update the PTR
+record of the host in DNS whereas both also updates the A record.
+disable will disable the FQDN option.
+The default is both.
+.Nm dhcpcd
+itself never does any DNS updates.
+.Nm dhcpcd
+encodes the FQDN hostname as specified in
+.Li RFC1035 .
+.It Ic interface Ar interface
+Subsequent options are only parsed for this
+.Ar interface .
+.It Ic ipv6ra_autoconf
+Generate SLAAC addresses for each Prefix advertised by a
+Router Advertisement message with the Auto flag set.
+On by default.
+.It Ic ipv6ra_noautoconf
+Disables the above option.
+.It Ic ipv6ra_fork
+By default, when
+.Nm dhcpcd
+receives an IPv6 RA,
+.Nm dhcpcd
+will only fork to the background if the RA contains at least one unexpired
+RDNSS option and a valid prefix or no DHCPv6 instruction.
+Set this option so to make
+.Nm dhcpcd
+always fork on an RA.
+.It Ic ipv6ra_own
+Disables kernel IPv6 Router Advertisment processing so dhcpcd can manage
+addresses and routes.
+.It Ic ipv6ra_own_default
+Each time dhcpcd receives an IPv6 Router Adveristment, dhcpcd will manage
+the default route only.
+This allows dhcpcd to prefer an interface for outbound traffic based on metric
+and/or user selection rather than the kernel.
+.It Ic ipv6ra_accept_nopublic
+Some IPv6 routers advertise themselves as a default router without any
+public prefixes or managed addresses.
+Generally, this is incorrect behaviour and
+.Nm dhcpcd
+will ignore the advertisement unless this option is turned on.
+.It Ic ipv6rs
+Enables IPv6 Router Advertisment solicitation.
+This is on by default, but is documented here in the case where it is disabled
+globally but needs to be enabled for one interface.
+.It Ic leasetime Ar seconds
+Request a leasetime of
+.Ar seconds .
+.It Ic logfile Ar logfile
+Writes to the specified
+.Ar logfile
+rather than
+.Xr syslog 3 .
+The
+.Ar logfile
+is truncated when opened and is reopened when
+.Nm dhcpcd
+receives the
+.Dv SIGUSR2
+signal.
+.It Ic metric Ar metric
+Metrics are used to prefer an interface over another one, lowest wins.
+.Nm dhcpcd
+will supply a default metric of 200 +
+.Xr if_nametoindex 3 .
+An extra 100 will be added for wireless interfaces.
+.It Ic noalias
+Any pre-existing IPv4 addresses existing address will be removed from the
+interface when adding a new IPv4 address.
+.It Ic noarp
+Don't send any ARP requests.
+This also disables IPv4LL.
+.It Ic noauthrequired
+Don't require authentication even though we requested it.
+.It Ic nodev
+Don't load
+.Pa /dev
+management modules.
+.It Ic nodhcp
+Don't start DHCP or listen to DHCP messages.
+This is only useful when allowing IPv4LL.
+.It Ic nodhcp6
+Don't start DHCPv6 or listen to DHCPv6 messages.
+Normally DHCPv6 is started by a RA instruction or configuration.
+.It Ic nogateway
+Don't install any default routes.
+.It Ic gateway
+Install a default route if available (default).
+.It Ic nohook Ar script
+Don't run this hook script.
+Matches full name, or prefixed with 2 numbers optionally ending with
+.Pa .sh .
+.Pp
+So to stop
+.Nm dhcpcd
+from touching your DNS or MTU settings you would do:-
+.D1 nohook resolv.conf, mtu
+.It Ic noipv4
+Don't attempt to configure an IPv4 address.
+.It Ic noipv4ll
+Don't attempt to obtain an IPv4LL address if we failed to get one via DHCP.
+See
+.Rs
+.%T "RFC 3927"
+.Re
+.It Ic noipv6
+Don't attmept to configure an IPv6 address.
+.It Ic noipv6rs
+Disable solicitation and receipt of IPv6 Router Advertisements.
+.It Ic nolink
+Don't receive link messages about carrier status.
+You should only set this for buggy interface drivers.
+.It Ic option Ar option
+Requests the
+.Ar option
+from the server.
+It can be a variable to be used in
+.Xr dhcpcd-run-hooks 8
+or the numerical value.
+You can specify more
+.Ar option Ns s
+separated by commas, spaces or more
+.Ic option
+lines.
+Prepend dhcp6_ to
+.Ar option
+to request a DHCPv6 option.
+DHCPv4 options are mapped to DHCPv6 where applicable.
+.It Ic nooption Ar option
+Remove the option from the DHCP message.
+This should only be used when a DHCP server sends a non requested option
+that should not be processed.
+.It Ic destination Ar option
+If
+.Nm
+detects an address added to a point to point interface (PPP, TUN, etc) then
+it will set the listed DHCP options to the destination address of the
+interface.
+.It Ic profile Ar name
+Subsequent options are only parsed for this profile
+.Ar name .
+.It Ic quiet
+Suppress any dhcpcd output to the console, except for errors.
+.It Ic reboot Ar seconds
+Allow
+.Ar reboot
+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
+to skip the REBOOT phase and go straight into DISCOVER.
+This is desirable for mobile users because if you change from network A to
+network B and they use the same subnet and the address from network A isn't
+in use on network B, then the DHCP server will remain silent even if authorative
+which means
+.Nm dhcpcd
+will timeout before moving back to the DISCOVER phase.
+.It Ic release
+.Nm dhcpcd
+will release the lease prior to stopping the interface.
+.It Ic require Ar option
+Requires the
+.Ar option
+to be present in all DHCP messages, otherwise the message is ignored.
+It can be a variable to be used in
+.Xr dhcpcd-run-hooks 8
+or the numerical value.
+You can specify more options separated by commas, spaces or more require lines.
+To enforce that
+.Nm dhcpcd
+only responds to DHCP servers and not BOOTP servers, you can
+.Ic require
+.Ar dhcp_message_type .
+This isn't an exact science though because a BOOTP server can send DHCP like
+options.
+.It Ic reject Ar option
+Reject a DHCP message that contains the
+.Ar option .
+This is useful when you cannot use
+.Ic require
+to select / de-select BOOTP messages.
+.It Ic script Ar script
+Use
+.Ar script
+instead of the default
+.Pa @SCRIPT@ .
+.It Ic ssid Ar ssid
+Subsequent options are only parsed for this wireless
+.Ar ssid .
+.It Ic slaac Op Ar hwaddr | Ar private
+Selects the interface identifier used for SLAAC generated IPv6 addresses.
+If
+.Ar private
+is used, a RFC7217 address is generated.
+.It Ic static Ar value
+Configures a static
+.Ar value .
+If you set
+.Ic ip_address
+then
+.Nm dhcpcd
+will not attempt to obtain a lease and just use the value for the address with
+an infinite lease time.
+.Pp
+Here is an example which configures a static address, routes and dns.
+.D1 interface eth0
+.D1 static ip_address=192.168.0.10/24
+.D1 static routers=192.168.0.1
+.D1 static domain_name_servers=192.168.0.1
+.Pp
+Here is an example for PPP which gives the destination a default route.
+It uses the special destination keyword to insert the destination address
+into the value.
+.D1 interface ppp0
+.D1 static ip_address=
+.D1 destination routers
+.It Ic timeout Ar seconds
+Timeout after
+.Ar seconds ,
+instead of the default 30.
+A setting of 0
+.Ar seconds
+causes
+.Nm dhcpcd
+to wait forever to get a lease.
+If
+.Nm dhcpcd
+is working on a single interface then
+.Nm dhcpcd
+will exit when a timeout occurs, otherwise
+.Nm dhcpcd
+will fork into the background.
+If using IPv4LL then
+.Nm dhcpcd
+start the IPv4LL process after the timeout and then wait a little longer
+before really timing out.
+.It Ic userclass Ar string
+Tag the DHCPv4 messages with the userclass.
+You can specify more than one.
+.It Ic vendor Ar code , Ns Ar value
+Add an encapsulated vendor option.
+.Ar code
+should be between 1 and 254 inclusive.
+To add a raw vendor string, omit
+.Ar code
+but keep the comma.
+Examples.
+.Pp
+Set the vendor option 01 with an IP address.
+.D1 vendor 01,192.168.0.2
+Set the vendor option 02 with a hex code.
+.D1 vendor 02,01:02:03:04:05
+Set the vendor option 03 with an IP address as a string.
+.D1 vendor 03,\e"192.168.0.2\e"
+Set un-encapsulated vendor option to hello world.
+.D1 vendor ,"hello world"
+.It Ic vendorclassid Ar string
+Set the DHCP Vendor Class.
+DHCPv6 has it's own option as shown below.
+The default is
+dhcpcd-<version>:<os>:<machine>:<platform>.
+For example
+.D1 dhcpcd-5.5.6:NetBSD-6.99.5:i386:i386
+If not set then none is sent.
+Some badly configured DHCP servers reject unknown vendorclassids.
+To work around it, try and impersonate Windows by using the MSFT vendorclassid.
+.It Ic vendclass Ar en Ar data
+Add the DHCPv6 Vendor Indetifying Vendor Class with the IANA assigned Enterprise
+Number
+.Ar en
+with the
+.Ar data .
+This option can be set more than once to add more data, but the behaviour,
+as per
+.Xr RFC 3925
+is undefined if the Enterprise Number differs.
+.It Ic waitip Op 4 | 6
+Wait for an address to be assigned before forking to the background.
+4 means wait for an IPv4 address to be assigned.
+6 means wait for an IPv6 address to be assigned.
+If no argument is given,
+.Nm
+will wait for any address protocol to be assigned.
+It is possible to wait for more than one address protocol and
+.Nm
+will only fork to the background when all waiting conditions are satisfied.
+.It Ic xidhwaddr
+Use the last four bytes of the hardware address as the DHCP xid instead
+of a randomly generated number.
+.El
+.Ss Defining new options
+DHCP allows for the use of custom options.
+Each option needs to be started with the
+.Ic define
+or
+.Ic define6
+directive.
+This can optionally be followed by both
+.Ic embed
+or
+.Ic encap
+options.
+Both can be specified more than once and
+.Ic embed
+must come before
+.Ic encap .
+.Bl -tag -width indent
+.It Ic define Ar code Ar type Ar variable
+Defines the DHCP option
+.Ar code
+of
+.Ar type
+with a name of
+.Ar variable
+exported to
+.Xr dhcpcd-run-hooks 8 .
+.It Ic define6 Ar code Ar type Ar variable
+Defines the DHCPv6 option
+.Ar code
+of
+.Ar type
+with a name of
+.Ar variable
+exported to
+.Xr dhcpcd-run-hooks 8 ,
+with a prefix of
+.Va _dhcp6 .
+.It Ic vendopt Ar code Ar type Ar variable
+Defines the Vendor-Identifying Vendor Options.
+The
+.Ar code
+is the IANA Enterprise Number which will unqiuely describe the encapsulated
+options.
+.Ar type
+is normally
+.Ar encap .
+.Ar variable
+names the Vendor option to be exported.
+.It Ic embed Ar type Ar variable
+Defines an embedded variable within the defined option.
+The length is determined by the
+.Ar type .
+If the
+.Ar variable
+is not the same as defined in the parent option,
+it is prefixed with the parent
+.Ar variable
+first with an underscore.
+.It Ic encap Ar code Ar type Ar variable
+Defines an encapsulated variable within the defined option.
+The length is determined by the
+.Ar type .
+If the
+.Ar variable
+is not the same as defined in the parent option,
+it is prefixed with the parent
+.Ar variable
+first with an underscore.
+.El
+.Ss Type prefix
+These keywords come before the type itself, to describe it more fully.
+You can use more than one, but they must appear in the order listed below.
+.Bl -tag -width -indent
+.It Ic request
+Requests the option by default without having to be specified in user
+configuration
+.It Ic norequest
+This option cannot be requested, regardless of user configuration
+.It Ic index
+The option can appear more than once and will be indexed.
+.It Ic array
+The option data is split into a space separated array, each element being
+the same type.
+.El
+.Ss Types to define
+The type directly affects the length of data consumed inside the option.
+Any remaining data is normally discarded.
+Lengths can be specified for string and binhex types, but this is generally
+with other data embedded afterwards in the same option.
+.Bl -tag -width indent
+.It Ic ipaddress
+An IPv4 address, 4 bytes
+.It Ic ip6address
+An IPv6 address, 16 bytes
+.It Ic string Op : Ic length
+A NVT ASCII string of printable characters.
+.It Ic byte
+A byte
+.It Ic int16
+A signed 16bit integer, 2 bytes
+.It Ic uint16
+An unsigned 16bit integer, 2 bytes
+.It Ic int32
+A signed 32bit integer, 4 bytes
+.It Ic uint32
+An unsigned 32bit integer, 4 bytes
+.It Ic flag 
+A fixed value (1) to indicate that the option is present, 0 bytes
+.It Ic domain
+A RFC 3397 encoded string
+.It Ic dname
+A RFC 1035 validated string
+.It Ic binhex Op : Ic length
+Binary data expressed as hexadecimal
+.It Ic embed
+Contains embedded options (implies encap as well)
+.It Ic encap
+Contains encapsulated options (implies embed as well)
+.It Ic option
+References an option from the global definition
+.El
+.Ss Example definition
+.D1 # DHCP option 81, Fully Qualified Domain Name, RFC4702
+.D1 define 81 embed fqdn
+.D1 embed byte flags
+.D1 embed byte rcode1
+.D1 embed byte rcode2
+.D1 embed domain fqdn
+.Pp
+.D1 # DHCP option 125, Vendor Specific Information Option, RFC3925
+.D1 define 125 encap vsio
+.D1 embed uint32 enterprise_number
+.D1 # Options defined for the enterprise number
+.D1 encap 1 ipaddress ipaddress
+.Ss Supported Authentication Protocols
+.Bl -tag -width -indent
+.It Ic token
+Sends and expects the token with the secretid 0 and realm of "" in each message.
+.It Ic delayedrealm
+Delayed Authentication.
+.Nm dhcpcd
+will send an authentication option with no key or MAC.
+The server will see this option, and select a key for
+.Nm , writing the
+.Ar realm
+and
+.Ar secretid
+in it.
+.Nm dhcpcd
+will then look for a non-expired token with a matching realm and secretid.
+This token is used to authenicate all other messages.
+.It Ic delayed
+Same as above, but without a realm.
+.El
+.Ss Supported Authentication Algorithms
+If none specified,
+.Ic hmac-md5
+is the default.
+.Bl -tag -width -indent
+.It Ic hmac-md5
+.El
+.Ss Supported Replay Detection Mechanisms
+If none specified,
+.Ic monotonic
+is the default.
+If this is changed from what was previously used,
+or the means of calculating or storing it is broken then the DHCP server
+will probably have to have its notion of the clients Replay Detection Value
+reset.
+.Bl -tag -width -indent
+.It Ic monocounter
+Read the number in the file
+.Pa @DBDIR@/dhcpcd-rdm.monotonic
+and add one to it.
+.It Ic monotime
+Create a NTP timestamp from the system time.
+.It Ic monotonic
+Same as
+.Ic monotime .
+.El
+.Sh SEE ALSO
+.Xr fnmatch 3 ,
+.Xr if_nametoindex 3 ,
+.Xr dhcpcd 8 ,
+.Xr dhcpcd-run-hooks 8
+.Sh AUTHORS
+.An Roy Marples Aq Mt roy@marples.name
+.Sh BUGS
+Please report them to
+.Lk http://roy.marples.name/projects/dhcpcd
diff --git a/dhcpcd-6.8.2/dhcpcd.h b/dhcpcd-6.8.2/dhcpcd.h
new file mode 100644
index 0000000..b8c961e
--- /dev/null
+++ b/dhcpcd-6.8.2/dhcpcd.h
@@ -0,0 +1,185 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef DHCPCD_H
+#define DHCPCD_H
+
+#include <sys/socket.h>
+#include <net/if.h>
+
+#include "config.h"
+#include "defs.h"
+#include "control.h"
+#include "if-options.h"
+
+#define HWADDR_LEN	20
+#define IF_SSIDSIZE	33
+#define PROFILE_LEN	64
+#define SECRET_LEN	64
+#define LEASE_IDENTIFIER_LEN (PATH_MAX - sizeof(LEASEFILE))
+
+#define LINK_UP		1
+#define LINK_UNKNOWN	0
+#define LINK_DOWN	-1
+
+#define IF_DATA_IPV4	0
+#define IF_DATA_DHCP	1
+#define IF_DATA_IPV6	2
+#define IF_DATA_IPV6ND	3
+#define IF_DATA_DHCP6	4
+#define IF_DATA_MAX	5
+
+/* If the interface does not support carrier status (ie PPP),
+ * dhcpcd can poll it for the relevant flags periodically */
+#define IF_POLL_UP	100	/* milliseconds */
+
+struct interface {
+	struct dhcpcd_ctx *ctx;
+	TAILQ_ENTRY(interface) next;
+	char name[IF_NAMESIZE];
+#ifdef __linux__
+	char alias[IF_NAMESIZE];
+#endif
+	unsigned int index;
+	unsigned int flags;
+	sa_family_t family;
+	unsigned char hwaddr[HWADDR_LEN];
+	uint8_t hwlen;
+	unsigned int metric;
+	int carrier;
+	int wireless;
+	uint8_t ssid[IF_SSIDSIZE];
+	unsigned int ssid_len;
+	char lease_identifier[LEASE_IDENTIFIER_LEN];
+
+	char profile[PROFILE_LEN];
+	struct if_options *options;
+	void *if_data[IF_DATA_MAX];
+};
+TAILQ_HEAD(if_head, interface);
+
+struct dhcpcd_ctx {
+	int pid_fd;
+	char pidfile[sizeof(PIDFILE) + IF_NAMESIZE + 1];
+	const char *cffile;
+	unsigned long long options;
+	char *logfile;
+	int log_fd;
+	int argc;
+	char **argv;
+	int ifac;	/* allowed interfaces */
+	char **ifav;	/* allowed interfaces */
+	int ifdc;	/* denied interfaces */
+	char **ifdv;	/* denied interfaces */
+	int ifc;	/* listed interfaces */
+	char **ifv;	/* listed interfaces */
+	int ifcc;	/* configured interfaces */
+	char **ifcv;	/* configured interfaces */
+	unsigned char *duid;
+	size_t duid_len;
+	int link_fd;
+	struct if_head *ifaces;
+
+#ifdef USE_SIGNALS
+	sigset_t sigset;
+#endif
+	struct eloop_ctx *eloop;
+
+	int control_fd;
+	int control_unpriv_fd;
+	struct fd_list_head control_fds;
+	char control_sock[sizeof(CONTROLSOCKET) + IF_NAMESIZE];
+	gid_t control_group;
+
+	/* DHCP Enterprise options, RFC3925 */
+	struct dhcp_opt *vivso;
+	size_t vivso_len;
+
+#ifdef INET
+	struct dhcp_opt *dhcp_opts;
+	size_t dhcp_opts_len;
+	struct rt_head *ipv4_routes;
+	struct rt_head *ipv4_kroutes;
+
+	int udp_fd;
+	uint8_t *packet;
+
+	/* Our aggregate option buffer.
+	 * We ONLY use this when options are split, which for most purposes is
+	 * practically never. See RFC3396 for details. */
+	uint8_t *opt_buffer;
+#endif
+#ifdef INET6
+	unsigned char secret[SECRET_LEN];
+	size_t secret_len;
+
+	struct dhcp_opt *dhcp6_opts;
+	size_t dhcp6_opts_len;
+	struct ipv6_ctx *ipv6;
+#ifndef __linux__
+	int ra_global;
+#endif
+#endif /* INET6 */
+
+#ifdef PLUGIN_DEV
+	char *dev_load;
+	int dev_fd;
+	struct dev *dev;
+	void *dev_handle;
+#endif
+};
+
+#ifdef USE_SIGNALS
+struct dhcpcd_siginfo {
+	int signo;
+};
+
+extern const int dhcpcd_handlesigs[];
+void dhcpcd_handle_signal(void *);
+#endif
+
+int dhcpcd_oneup(struct dhcpcd_ctx *);
+int dhcpcd_ipwaited(struct dhcpcd_ctx *);
+pid_t dhcpcd_daemonise(struct dhcpcd_ctx *);
+
+int dhcpcd_handleargs(struct dhcpcd_ctx *, struct fd_list *, int, char **);
+void dhcpcd_handlecarrier(struct dhcpcd_ctx *, int, unsigned int, const char *);
+int dhcpcd_handleinterface(void *, int, const char *);
+void dhcpcd_handlehwaddr(struct dhcpcd_ctx *, const char *,
+    const unsigned char *, uint8_t);
+void dhcpcd_dropinterface(struct interface *, const char *);
+int dhcpcd_selectprofile(struct interface *, const char *);
+
+void dhcpcd_startinterface(void *);
+void dhcpcd_initstate(struct interface *, unsigned long long);
+
+void dhcpcd_start_interface(struct dhcpcd_ctx *, const char *);
+void dhcpcd_stop_interface(struct dhcpcd_ctx *, const char *);
+void dhcpcd_release_ipv4(struct dhcpcd_ctx *, const char *);
+void dhcpcd_stop_interfaces(struct dhcpcd_ctx *);
+
+#endif
diff --git a/dhcpcd-6.8.2/duid.c b/dhcpcd-6.8.2/duid.c
new file mode 100644
index 0000000..d24ebc4
--- /dev/null
+++ b/dhcpcd-6.8.2/duid.c
@@ -0,0 +1,165 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#define DUID_TIME_EPOCH 946684800
+#define DUID_LLT	1
+#define DUID_LL		3
+
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#include <net/if.h>
+#include <net/if_arp.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#ifndef ARPHRD_NETROM
+#  define ARPHRD_NETROM	0
+#endif
+
+#include "common.h"
+#include "dhcpcd.h"
+#include "duid.h"
+
+static size_t
+duid_make(unsigned char *d, const struct interface *ifp, uint16_t type)
+{
+	unsigned char *p;
+	uint16_t u16;
+	time_t t;
+	uint32_t u32;
+
+	p = d;
+	u16 = htons(type);
+	memcpy(p, &u16, 2);
+	p += 2;
+	u16 = htons(ifp->family);
+	memcpy(p, &u16, 2);
+	p += 2;
+	if (type == DUID_LLT) {
+		/* time returns seconds from jan 1 1970, but DUID-LLT is
+		 * seconds from jan 1 2000 modulo 2^32 */
+		t = time(NULL) - DUID_TIME_EPOCH;
+		u32 = htonl((uint32_t)t & 0xffffffff);
+		memcpy(p, &u32, 4);
+		p += 4;
+	}
+	/* Finally, add the MAC address of the interface */
+	memcpy(p, ifp->hwaddr, ifp->hwlen);
+	p += ifp->hwlen;
+	return (size_t)(p - d);
+}
+
+#define DUID_STRLEN DUID_LEN * 3
+static size_t
+duid_get(unsigned char *d, const struct interface *ifp)
+{
+	FILE *fp;
+	int x = 0;
+	size_t len = 0;
+	char line[DUID_STRLEN];
+	const struct interface *ifp2;
+
+	/* If we already have a DUID then use it as it's never supposed
+	 * to change once we have one even if the interfaces do */
+	if ((fp = fopen(DUID, "r"))) {
+		while (fgets(line, DUID_STRLEN, fp)) {
+			len = strlen(line);
+			if (len) {
+				if (line[len - 1] == '\n')
+					line[len - 1] = '\0';
+			}
+			len = hwaddr_aton(NULL, line);
+			if (len && len <= DUID_LEN) {
+				hwaddr_aton(d, line);
+				break;
+			}
+			len = 0;
+		}
+		fclose(fp);
+		if (len)
+			return len;
+	} else {
+		if (errno != ENOENT)
+			logger(ifp->ctx, LOG_ERR,
+			    "error reading DUID: %s: %m", DUID);
+	}
+
+	/* No file? OK, lets make one based on our interface */
+	if (ifp->family == ARPHRD_NETROM) {
+		logger(ifp->ctx, LOG_WARNING,
+		    "%s: is a NET/ROM psuedo interface", ifp->name);
+		TAILQ_FOREACH(ifp2, ifp->ctx->ifaces, next) {
+			if (ifp2->family != ARPHRD_NETROM)
+				break;
+		}
+		if (ifp2) {
+			ifp = ifp2;
+			logger(ifp->ctx, LOG_WARNING,
+			    "picked interface %s to generate a DUID",
+			    ifp->name);
+		} else {
+			logger(ifp->ctx, LOG_WARNING,
+			    "no interfaces have a fixed hardware address");
+			return duid_make(d, ifp, DUID_LL);
+		}
+	}
+
+	if (!(fp = fopen(DUID, "w"))) {
+		logger(ifp->ctx, LOG_ERR, "error writing DUID: %s: %m", DUID);
+		return duid_make(d, ifp, DUID_LL);
+	}
+	len = duid_make(d, ifp, DUID_LLT);
+	x = fprintf(fp, "%s\n", hwaddr_ntoa(d, len, line, sizeof(line)));
+	fclose(fp);
+	/* Failed to write the duid? scrub it, we cannot use it */
+	if (x < 1) {
+		logger(ifp->ctx, LOG_ERR, "error writing DUID: %s: %m", DUID);
+		unlink(DUID);
+		return duid_make(d, ifp, DUID_LL);
+	}
+	return len;
+}
+
+size_t duid_init(const struct interface *ifp)
+{
+
+	if (ifp->ctx->duid == NULL) {
+		ifp->ctx->duid = malloc(DUID_LEN);
+		if (ifp->ctx->duid == NULL) {
+			logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
+			return 0;
+		}
+		ifp->ctx->duid_len = duid_get(ifp->ctx->duid, ifp);
+	}
+	return ifp->ctx->duid_len;
+}
diff --git a/dhcpcd-6.8.2/duid.h b/dhcpcd-6.8.2/duid.h
new file mode 100644
index 0000000..0585784
--- /dev/null
+++ b/dhcpcd-6.8.2/duid.h
@@ -0,0 +1,35 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef DUID_H
+#define DUID_H
+
+#define DUID_LEN	128 + 2
+
+size_t duid_init(const struct interface *);
+
+#endif
diff --git a/dhcpcd-6.8.2/eloop.c b/dhcpcd-6.8.2/eloop.c
new file mode 100644
index 0000000..e479ac1
--- /dev/null
+++ b/dhcpcd-6.8.2/eloop.c
@@ -0,0 +1,655 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/time.h>
+
+#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "config.h"
+#include "common.h"
+#include "dhcpcd.h"
+#include "eloop.h"
+
+#if defined(HAVE_KQUEUE)
+#include <sys/event.h>
+#include <fcntl.h>
+#ifdef __NetBSD__
+/* udata is void * except on NetBSD
+ * lengths are int except on NetBSD */
+#define UPTR(x)	((intptr_t)(x))
+#define LENC(x)	(x)
+#else
+#define UPTR(x)	(x)
+#define LENC(x)	((int)(x))
+#endif
+#define eloop_event_setup_fds(ctx)
+#elif defined(HAVE_EPOLL)
+#include <sys/epoll.h>
+#define eloop_event_setup_fds(ctx)
+#else
+#include <poll.h>
+static void
+eloop_event_setup_fds(struct eloop_ctx *ctx)
+{
+	struct eloop_event *e;
+	size_t i;
+
+	i = 0;
+	TAILQ_FOREACH(e, &ctx->events, next) {
+		ctx->fds[i].fd = e->fd;
+		ctx->fds[i].events = 0;
+		if (e->read_cb)
+			ctx->fds[i].events |= POLLIN;
+		if (e->write_cb)
+			ctx->fds[i].events |= POLLOUT;
+		ctx->fds[i].revents = 0;
+		e->pollfd = &ctx->fds[i];
+		i++;
+	}
+}
+#endif
+
+int
+eloop_event_add(struct eloop_ctx *ctx, int fd,
+    void (*read_cb)(void *), void *read_cb_arg,
+    void (*write_cb)(void *), void *write_cb_arg)
+{
+	struct eloop_event *e;
+#if defined(HAVE_KQUEUE)
+	struct kevent ke[2];
+#elif defined(HAVE_EPOLL)
+	struct epoll_event epe;
+#else
+	struct pollfd *nfds;
+#endif
+
+#ifdef HAVE_EPOLL
+	memset(&epe, 0, sizeof(epe));
+	epe.data.fd = fd;
+	epe.events = EPOLLIN;
+	if (write_cb)
+		epe.events |= EPOLLOUT;
+#endif
+
+	/* We should only have one callback monitoring the fd */
+	TAILQ_FOREACH(e, &ctx->events, next) {
+		if (e->fd == fd) {
+			int error;
+
+#if defined(HAVE_KQUEUE)
+			EV_SET(&ke[0], (uintptr_t)fd, EVFILT_READ, EV_ADD,
+			    0, 0, UPTR(e));
+			if (write_cb)
+				EV_SET(&ke[1], (uintptr_t)fd, EVFILT_WRITE,
+				    EV_ADD, 0, 0, UPTR(e));
+			else if (e->write_cb)
+				EV_SET(&ke[1], (uintptr_t)fd, EVFILT_WRITE,
+				    EV_DELETE, 0, 0, UPTR(e));
+			error = kevent(ctx->poll_fd, ke,
+			    e->write_cb || write_cb ? 2 : 1, NULL, 0, NULL);
+#elif defined(HAVE_EPOLL)
+			epe.data.ptr = e;
+			error = epoll_ctl(ctx->poll_fd, EPOLL_CTL_MOD,
+			    fd, &epe);
+#else
+			error = 0;
+#endif
+			if (read_cb) {
+				e->read_cb = read_cb;
+				e->read_cb_arg = read_cb_arg;
+			}
+			if (write_cb) {
+				e->write_cb = write_cb;
+				e->write_cb_arg = write_cb_arg;
+			}
+			eloop_event_setup_fds(ctx);
+			return error;
+		}
+	}
+
+	/* Allocate a new event if no free ones already allocated */
+	if ((e = TAILQ_FIRST(&ctx->free_events))) {
+		TAILQ_REMOVE(&ctx->free_events, e, next);
+	} else {
+		e = malloc(sizeof(*e));
+		if (e == NULL)
+			goto err;
+	}
+
+	/* Ensure we can actually listen to it */
+	ctx->events_len++;
+#if !defined(HAVE_KQUEUE) && !defined(HAVE_EPOLL)
+	if (ctx->events_len > ctx->fds_len) {
+		nfds = realloc(ctx->fds, sizeof(*ctx->fds) * (ctx->fds_len+5));
+		if (nfds == NULL)
+			goto err;
+		ctx->fds_len += 5;
+		ctx->fds = nfds;
+	}
+#endif
+
+	/* Now populate the structure and add it to the list */
+	e->fd = fd;
+	e->read_cb = read_cb;
+	e->read_cb_arg = read_cb_arg;
+	e->write_cb = write_cb;
+	e->write_cb_arg = write_cb_arg;
+
+#if defined(HAVE_KQUEUE)
+	EV_SET(&ke[0], (uintptr_t)fd, EVFILT_READ, EV_ADD, 0, 0, UPTR(e));
+	if (write_cb)
+		EV_SET(&ke[1], (uintptr_t)fd, EVFILT_WRITE,
+		    EV_ADD, 0, 0, UPTR(e));
+	if (kevent(ctx->poll_fd, ke, write_cb ? 2 : 1, NULL, 0, NULL) == -1)
+		goto err;
+#elif defined(HAVE_EPOLL)
+	epe.data.ptr = e;
+	if (epoll_ctl(ctx->poll_fd, EPOLL_CTL_ADD, fd, &epe) == -1)
+		goto err;
+#endif
+
+	/* The order of events should not matter.
+	 * However, some PPP servers love to close the link right after
+	 * sending their final message. So to ensure dhcpcd processes this
+	 * message (which is likely to be that the DHCP addresses are wrong)
+	 * we insert new events at the queue head as the link fd will be
+	 * the first event added. */
+	TAILQ_INSERT_HEAD(&ctx->events, e, next);
+	eloop_event_setup_fds(ctx);
+	return 0;
+
+err:
+	logger(ctx->ctx, LOG_ERR, "%s: %m", __func__);
+	if (e) {
+		ctx->events_len--;
+		TAILQ_INSERT_TAIL(&ctx->free_events, e, next);
+	}
+	return -1;
+}
+
+void
+eloop_event_delete(struct eloop_ctx *ctx, int fd, int write_only)
+{
+	struct eloop_event *e;
+#if defined(HAVE_KQUEUE)
+	struct kevent ke[2];
+#elif defined(HAVE_EPOLL)
+	struct epoll_event epe;
+#endif
+
+	TAILQ_FOREACH(e, &ctx->events, next) {
+		if (e->fd == fd) {
+			if (write_only) {
+				if (e->write_cb) {
+					e->write_cb = NULL;
+					e->write_cb_arg = NULL;
+#if defined(HAVE_KQUEUE)
+					EV_SET(&ke[0], (uintptr_t)fd,
+					    EVFILT_WRITE, EV_DELETE,
+					    0, 0, UPTR(NULL));
+					kevent(ctx->poll_fd, ke, 1, NULL, 0,
+					    NULL);
+#elif defined(HAVE_EPOLL)
+					memset(&epe, 0, sizeof(epe));
+					epe.data.fd = e->fd;
+					epe.data.ptr = e;
+					epe.events = EPOLLIN;
+					epoll_ctl(ctx->poll_fd, EPOLL_CTL_MOD,
+					    fd, &epe);
+#endif
+				}
+
+			} else {
+				TAILQ_REMOVE(&ctx->events, e, next);
+#if defined(HAVE_KQUEUE)
+				EV_SET(&ke[0], (uintptr_t)fd, EVFILT_READ,
+				    EV_DELETE, 0, 0, UPTR(NULL));
+				if (e->write_cb)
+					EV_SET(&ke[1], (uintptr_t)fd,
+					    EVFILT_WRITE, EV_DELETE,
+					    0, 0, UPTR(NULL));
+				kevent(ctx->poll_fd, ke, e->write_cb ? 2 : 1,
+				    NULL, 0, NULL);
+#elif defined(HAVE_EPOLL)
+				/* NULL event is safe because we
+				 * rely on epoll_pwait which as added
+				 * after the delete without event was fixed. */
+				epoll_ctl(ctx->poll_fd, EPOLL_CTL_DEL,
+				    fd, NULL);
+#endif
+				TAILQ_INSERT_TAIL(&ctx->free_events, e, next);
+				ctx->events_len--;
+			}
+			eloop_event_setup_fds(ctx);
+			break;
+		}
+	}
+}
+
+int
+eloop_q_timeout_add_tv(struct eloop_ctx *ctx, int queue,
+    const struct timespec *when, void (*callback)(void *), void *arg)
+{
+	struct timespec now, w;
+	struct eloop_timeout *t, *tt = NULL;
+
+	get_monotonic(&now);
+	timespecadd(&now, when, &w);
+	/* Check for time_t overflow. */
+	if (timespeccmp(&w, &now, <)) {
+		errno = ERANGE;
+		return -1;
+	}
+
+	/* Remove existing timeout if present */
+	TAILQ_FOREACH(t, &ctx->timeouts, next) {
+		if (t->callback == callback && t->arg == arg) {
+			TAILQ_REMOVE(&ctx->timeouts, t, next);
+			break;
+		}
+	}
+
+	if (t == NULL) {
+		/* No existing, so allocate or grab one from the free pool */
+		if ((t = TAILQ_FIRST(&ctx->free_timeouts))) {
+			TAILQ_REMOVE(&ctx->free_timeouts, t, next);
+		} else {
+			t = malloc(sizeof(*t));
+			if (t == NULL) {
+				logger(ctx->ctx, LOG_ERR, "%s: %m", __func__);
+				return -1;
+			}
+		}
+	}
+
+	t->when = w;
+	t->callback = callback;
+	t->arg = arg;
+	t->queue = queue;
+
+	/* The timeout list should be in chronological order,
+	 * soonest first. */
+	TAILQ_FOREACH(tt, &ctx->timeouts, next) {
+		if (timespeccmp(&t->when, &tt->when, <)) {
+			TAILQ_INSERT_BEFORE(tt, t, next);
+			return 0;
+		}
+	}
+	TAILQ_INSERT_TAIL(&ctx->timeouts, t, next);
+	return 0;
+}
+
+int
+eloop_q_timeout_add_sec(struct eloop_ctx *ctx, int queue, time_t when,
+    void (*callback)(void *), void *arg)
+{
+	struct timespec tv;
+
+	tv.tv_sec = when;
+	tv.tv_nsec = 0;
+	return eloop_q_timeout_add_tv(ctx, queue, &tv, callback, arg);
+}
+
+#if !defined(HAVE_KQUEUE)
+int
+eloop_timeout_add_now(struct eloop_ctx *ctx,
+    void (*callback)(void *), void *arg)
+{
+
+	if (ctx->timeout0 != NULL) {
+		logger(ctx->ctx, LOG_WARNING,
+		    "%s: timeout0 already set", __func__);
+		return eloop_q_timeout_add_sec(ctx, 0, 0, callback, arg);
+	}
+
+	ctx->timeout0 = callback;
+	ctx->timeout0_arg = arg;
+	return 0;
+}
+#endif
+
+void
+eloop_q_timeout_delete(struct eloop_ctx *ctx, int queue,
+    void (*callback)(void *), void *arg)
+{
+	struct eloop_timeout *t, *tt;
+
+	TAILQ_FOREACH_SAFE(t, &ctx->timeouts, next, tt) {
+		if ((queue == 0 || t->queue == queue) &&
+		    t->arg == arg &&
+		    (!callback || t->callback == callback))
+		{
+			TAILQ_REMOVE(&ctx->timeouts, t, next);
+			TAILQ_INSERT_TAIL(&ctx->free_timeouts, t, next);
+		}
+	}
+}
+
+void
+eloop_exit(struct eloop_ctx *ctx, int code)
+{
+
+	ctx->exitcode = code;
+	ctx->exitnow = 1;
+}
+
+#if defined(HAVE_KQUEUE) || defined(HAVE_EPOLL)
+static int
+eloop_open(struct eloop_ctx *ctx)
+{
+#if defined(HAVE_KQUEUE1)
+	return (ctx->poll_fd = kqueue1(O_CLOEXEC));
+#elif defined(HAVE_KQUEUE)
+	int i;
+
+	if ((ctx->poll_fd = kqueue()) == -1)
+		return -1;
+	if ((i = fcntl(ctx->poll_fd, F_GETFD, 0)) == -1 ||
+	    fcntl(ctx->poll_fd, F_SETFD, i | FD_CLOEXEC) == -1)
+	{
+		close(ctx->poll_fd);
+		ctx->poll_fd = -1;
+		return -1;
+	}
+
+	return ctx->poll_fd;
+#elif defined (HAVE_EPOLL)
+	return (ctx->poll_fd = epoll_create1(EPOLL_CLOEXEC));
+#endif
+}
+
+int
+eloop_requeue(struct eloop_ctx *ctx)
+{
+	struct eloop_event *e;
+	int error;
+#if defined(HAVE_KQUEUE)
+	size_t i;
+	struct kevent *ke;
+#elif defined(HAVE_EPOLL)
+	struct epoll_event epe;
+#endif
+
+	if (ctx->poll_fd != -1)
+		close(ctx->poll_fd);
+	if (eloop_open(ctx) == -1)
+		return -1;
+#if defined (HAVE_KQUEUE)
+	i = 0;
+	while (dhcpcd_handlesigs[i])
+		i++;
+	TAILQ_FOREACH(e, &ctx->events, next) {
+		i++;
+		if (e->write_cb)
+			i++;
+	}
+
+	if ((ke = malloc(sizeof(*ke) * i)) == NULL)
+		return -1;
+
+	for (i = 0; dhcpcd_handlesigs[i]; i++)
+		EV_SET(&ke[i], (uintptr_t)dhcpcd_handlesigs[i],
+		    EVFILT_SIGNAL, EV_ADD, 0, 0, UPTR(NULL));
+
+	TAILQ_FOREACH(e, &ctx->events, next) {
+		EV_SET(&ke[i], (uintptr_t)e->fd, EVFILT_READ,
+		    EV_ADD, 0, 0, UPTR(e));
+		i++;
+		if (e->write_cb) {
+			EV_SET(&ke[i], (uintptr_t)e->fd, EVFILT_WRITE,
+			    EV_ADD, 0, 0, UPTR(e));
+			i++;
+		}
+	}
+
+	error =  kevent(ctx->poll_fd, ke, LENC(i), NULL, 0, NULL);
+	free(ke);
+
+#elif defined(HAVE_EPOLL)
+
+	error = 0;
+	TAILQ_FOREACH(e, &ctx->events, next) {
+		memset(&epe, 0, sizeof(epe));
+		epe.data.fd = e->fd;
+		epe.events = EPOLLIN;
+		if (e->write_cb)
+			epe.events |= EPOLLOUT;
+		epe.data.ptr = e;
+		if (epoll_ctl(ctx->poll_fd, EPOLL_CTL_ADD, e->fd, &epe) == -1)
+			error = -1;
+	}
+#endif
+
+	return error;
+}
+#endif
+
+struct eloop_ctx *
+eloop_init(struct dhcpcd_ctx *dctx)
+{
+	struct eloop_ctx *ctx;
+	struct timespec now;
+
+	/* Check we have a working monotonic clock. */
+	if (get_monotonic(&now) == -1)
+		return NULL;
+
+	ctx = calloc(1, sizeof(*ctx));
+	if (ctx) {
+		ctx->ctx = dctx;
+		TAILQ_INIT(&ctx->events);
+		TAILQ_INIT(&ctx->free_events);
+		TAILQ_INIT(&ctx->timeouts);
+		TAILQ_INIT(&ctx->free_timeouts);
+		ctx->exitcode = EXIT_FAILURE;
+#if defined(HAVE_KQUEUE) || defined(HAVE_EPOLL)
+		ctx->poll_fd = -1;
+#endif
+		if (eloop_requeue(ctx) == -1) {
+			free(ctx);
+			return NULL;
+		}
+	}
+
+	return ctx;
+}
+
+void eloop_free(struct eloop_ctx *ctx)
+{
+	struct eloop_event *e;
+	struct eloop_timeout *t;
+
+	if (ctx == NULL)
+		return;
+
+	while ((e = TAILQ_FIRST(&ctx->events))) {
+		TAILQ_REMOVE(&ctx->events, e, next);
+		free(e);
+	}
+	while ((e = TAILQ_FIRST(&ctx->free_events))) {
+		TAILQ_REMOVE(&ctx->free_events, e, next);
+		free(e);
+	}
+	while ((t = TAILQ_FIRST(&ctx->timeouts))) {
+		TAILQ_REMOVE(&ctx->timeouts, t, next);
+		free(t);
+	}
+	while ((t = TAILQ_FIRST(&ctx->free_timeouts))) {
+		TAILQ_REMOVE(&ctx->free_timeouts, t, next);
+		free(t);
+	}
+#if defined(HAVE_KQUEUE) || defined(HAVE_EPOLL)
+	close(ctx->poll_fd);
+#else
+	free(ctx->fds);
+#endif
+	free(ctx);
+}
+
+int
+eloop_start(struct eloop_ctx *ctx)
+{
+	int n;
+	struct eloop_event *e;
+	struct eloop_timeout *t;
+	struct timespec now, ts, *tsp;
+	void (*t0)(void *);
+#if defined(HAVE_EPOLL) || !defined(USE_SIGNALS)
+	int timeout;
+#endif
+#if defined(HAVE_KQUEUE)
+	struct kevent ke;
+#elif defined(HAVE_EPOLL)
+	struct epoll_event epe;
+#endif
+
+	for (;;) {
+		if (ctx->exitnow)
+			break;
+
+		/* Run all timeouts first */
+		if (ctx->timeout0) {
+			t0 = ctx->timeout0;
+			ctx->timeout0 = NULL;
+			t0(ctx->timeout0_arg);
+			continue;
+		}
+		if ((t = TAILQ_FIRST(&ctx->timeouts))) {
+			get_monotonic(&now);
+			if (timespeccmp(&now, &t->when, >)) {
+				TAILQ_REMOVE(&ctx->timeouts, t, next);
+				t->callback(t->arg);
+				TAILQ_INSERT_TAIL(&ctx->free_timeouts, t, next);
+				continue;
+			}
+			timespecsub(&t->when, &now, &ts);
+			tsp = &ts;
+		} else
+			/* No timeouts, so wait forever */
+			tsp = NULL;
+
+		if (tsp == NULL && ctx->events_len == 0) {
+			logger(ctx->ctx, LOG_ERR, "nothing to do");
+			break;
+		}
+
+#if defined(HAVE_EPOLL) || !defined(USE_SIGNALS)
+		if (tsp == NULL)
+			timeout = -1;
+		else if (tsp->tv_sec > INT_MAX / 1000 ||
+		    (tsp->tv_sec == INT_MAX / 1000 &&
+		    (tsp->tv_nsec + 999999) / 1000000 > INT_MAX % 1000000))
+			timeout = INT_MAX;
+		else
+			timeout = (int)(tsp->tv_sec * 1000 +
+			    (tsp->tv_nsec + 999999) / 1000000);
+#endif
+
+#if defined(HAVE_KQUEUE)
+		n = kevent(ctx->poll_fd, NULL, 0, &ke, 1, tsp);
+#elif defined(HAVE_EPOLL)
+#ifdef USE_SIGNALS
+		n = epoll_pwait(ctx->poll_fd, &epe, 1, timeout,
+		    &ctx->ctx->sigset);
+#else
+		n = epoll_wait(ctx->poll_fd, &epe, 1, timeout);
+#endif
+#else
+#ifdef USE_SIGNALS
+		n = pollts(ctx->fds, (nfds_t)ctx->events_len, tsp,
+		    &ctx->ctx->sigset);
+#else
+		n = poll(ctx->fds, (nfds_t)ctx->events_len, timeout);
+#endif
+#endif
+		if (n == -1) {
+			if (errno == EINTR)
+				continue;
+			logger(ctx->ctx, LOG_ERR, "poll: %m");
+			break;
+		}
+
+		/* Process any triggered events.
+		 * We go back to the start after calling each callback incase
+		 * the current event or next event is removed. */
+#if defined(HAVE_KQUEUE)
+		if (n) {
+			if (ke.filter == EVFILT_SIGNAL) {
+				struct dhcpcd_siginfo si;
+
+				si.signo = (int)ke.ident;
+				dhcpcd_handle_signal(&si);
+				continue;
+			}
+			e = (struct eloop_event *)ke.udata;
+			if (ke.filter == EVFILT_WRITE) {
+				e->write_cb(e->write_cb_arg);
+				continue;
+			} else if (ke.filter == EVFILT_READ) {
+				e->read_cb(e->read_cb_arg);
+				continue;
+			}
+		}
+#elif defined(HAVE_EPOLL)
+		if (n) {
+			e = (struct eloop_event *)epe.data.ptr;
+			if (epe.events & EPOLLOUT && e->write_cb) {
+				e->write_cb(e->write_cb_arg);
+				continue;
+			}
+			if (epe.events &
+			    (EPOLLIN | EPOLLERR | EPOLLHUP))
+			{
+				e->read_cb(e->read_cb_arg);
+				continue;
+			}
+		}
+#else
+		if (n > 0) {
+			TAILQ_FOREACH(e, &ctx->events, next) {
+				if (e->pollfd->revents & POLLOUT &&
+				    e->write_cb)
+				{
+					e->write_cb(e->write_cb_arg);
+					break;
+				}
+				if (e->pollfd->revents) {
+					e->read_cb(e->read_cb_arg);
+					break;
+				}
+			}
+		}
+#endif
+	}
+
+	return ctx->exitcode;
+}
diff --git a/dhcpcd-6.8.2/eloop.h b/dhcpcd-6.8.2/eloop.h
new file mode 100644
index 0000000..9bb670c
--- /dev/null
+++ b/dhcpcd-6.8.2/eloop.h
@@ -0,0 +1,116 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef ELOOP_H
+#define ELOOP_H
+
+#include <time.h>
+
+#include "config.h"
+
+#ifndef ELOOP_QUEUE
+  #define ELOOP_QUEUE 1
+#endif
+
+/* EXIT_FAILURE is a non zero value and EXIT_SUCCESS is zero.
+ * To add a CONTINUE definition, simply do the opposite of EXIT_FAILURE. */
+#define ELOOP_CONTINUE	-EXIT_FAILURE
+
+struct eloop_event {
+	TAILQ_ENTRY(eloop_event) next;
+	int fd;
+	void (*read_cb)(void *);
+	void *read_cb_arg;
+	void (*write_cb)(void *);
+	void *write_cb_arg;
+#if !defined(HAVE_KQUEUE) && !defined(HAVE_EPOLL)
+	struct pollfd *pollfd;
+#endif
+};
+
+struct eloop_timeout {
+	TAILQ_ENTRY(eloop_timeout) next;
+	struct timespec when;
+	void (*callback)(void *);
+	void *arg;
+	int queue;
+};
+
+struct eloop_ctx {
+	struct dhcpcd_ctx *ctx;
+
+	size_t events_len;
+	TAILQ_HEAD (event_head, eloop_event) events;
+	struct event_head free_events;
+
+	TAILQ_HEAD (timeout_head, eloop_timeout) timeouts;
+	struct timeout_head free_timeouts;
+
+	void (*timeout0)(void *);
+	void *timeout0_arg;
+
+#if defined(HAVE_KQUEUE) || defined(HAVE_EPOLL)
+	int poll_fd;
+#else
+	struct pollfd *fds;
+	size_t fds_len;
+#endif
+
+	int exitnow;
+	int exitcode;
+};
+
+#define eloop_timeout_add_tv(a, b, c, d) \
+    eloop_q_timeout_add_tv(a, ELOOP_QUEUE, b, c, d)
+#define eloop_timeout_add_sec(a, b, c, d) \
+    eloop_q_timeout_add_sec(a, ELOOP_QUEUE, b, c, d)
+#define eloop_timeout_delete(a, b, c) \
+    eloop_q_timeout_delete(a, ELOOP_QUEUE, b, c)
+
+int eloop_event_add(struct eloop_ctx *, int,
+    void (*)(void *), void *,
+    void (*)(void *), void *);
+void eloop_event_delete(struct eloop_ctx *, int, int);
+int eloop_q_timeout_add_sec(struct eloop_ctx *, int queue,
+    time_t, void (*)(void *), void *);
+int eloop_q_timeout_add_tv(struct eloop_ctx *, int queue,
+    const struct timespec *, void (*)(void *), void *);
+#if !defined(HAVE_KQUEUE)
+int eloop_timeout_add_now(struct eloop_ctx *, void (*)(void *), void *);
+#endif
+void eloop_q_timeout_delete(struct eloop_ctx *, int, void (*)(void *), void *);
+struct eloop_ctx * eloop_init(struct dhcpcd_ctx *);
+#if defined(HAVE_KQUEUE) || defined(HAVE_EPOLL)
+int eloop_requeue(struct eloop_ctx *);
+#else
+#define eloop_requeue(a) (0)
+#endif
+void eloop_free(struct eloop_ctx *);
+void eloop_exit(struct eloop_ctx *, int);
+int eloop_start(struct eloop_ctx *);
+
+#endif
diff --git a/dhcpcd-6.8.2/genembedc b/dhcpcd-6.8.2/genembedc
new file mode 100755
index 0000000..5bd7b6f
--- /dev/null
+++ b/dhcpcd-6.8.2/genembedc
@@ -0,0 +1,16 @@
+#!/bin/sh
+set -e
+
+: ${TOOL_SED:=sed}
+CONF=${1:-dhcpcd-definitions.conf}
+
+cat dhcpcd-embedded.c.in
+$TOOL_SED \
+	-e 's/#.*$//' \
+	-e '/^$/d' \
+	-e 's/^/"/g' \
+	-e 's/$/\",/g' \
+	-e 's/ [ ]*/ /g' \
+	-e 's/	[	]*/ /g' \
+	$CONF
+printf "%s\n%s\n" "NULL" "};"
diff --git a/dhcpcd-6.8.2/genembedh b/dhcpcd-6.8.2/genembedh
new file mode 100755
index 0000000..a155cfa
--- /dev/null
+++ b/dhcpcd-6.8.2/genembedh
@@ -0,0 +1,15 @@
+#!/bin/sh
+set -e
+
+: ${TOOL_SED:=sed}
+: ${TOOL_GREP:=grep}
+: ${TOOL_WC:=wc}
+CONF=${1:-dhcpcd-definitions.conf}
+H=${2:-dhcpcd-embedded.h.in}
+
+INITDEFINES=$($TOOL_GREP "^define " $CONF | $TOOL_WC -l)
+INITDEFINE6S=$($TOOL_GREP "^define6 " $CONF | $TOOL_WC -l)
+$TOOL_SED \
+	-e "s/@INITDEFINES@/$INITDEFINES/" \
+	-e "s/@INITDEFINE6S@/$INITDEFINE6S/" \
+	$H
diff --git a/dhcpcd-6.8.2/iconfig.mk b/dhcpcd-6.8.2/iconfig.mk
new file mode 100644
index 0000000..465e02e
--- /dev/null
+++ b/dhcpcd-6.8.2/iconfig.mk
@@ -0,0 +1,7 @@
+# Nasty hack so that make clean works without configure being run
+# Requires gmake4
+TOP?=		.
+_CONFIG_MK!=	test -e ${TOP}/config.mk && \
+		    echo config.mk || echo config-null.mk
+CONFIG_MK?=	${_CONFIG_MK}
+include		${TOP}/${CONFIG_MK}
diff --git a/dhcpcd-6.8.2/if-bsd.c b/dhcpcd-6.8.2/if-bsd.c
new file mode 100644
index 0000000..ec4d4ba
--- /dev/null
+++ b/dhcpcd-6.8.2/if-bsd.c
@@ -0,0 +1,1689 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/utsname.h>
+
+#include <arpa/inet.h>
+#include <net/bpf.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#ifdef __FreeBSD__ /* Needed so that including netinet6/in6_var.h works */
+#  include <net/if_var.h>
+#endif
+#include <net/if_media.h>
+#include <net/route.h>
+#include <netinet/if_ether.h>
+#include <netinet/in.h>
+#include <netinet/in_var.h>
+#include <netinet6/in6_var.h>
+#include <netinet6/nd6.h>
+#ifdef __DragonFly__
+#  include <netproto/802_11/ieee80211_ioctl.h>
+#elif __APPLE__
+  /* FIXME: Add apple includes so we can work out SSID */
+#else
+#  include <net80211/ieee80211.h>
+#  include <net80211/ieee80211_ioctl.h>
+#endif
+
+#include <errno.h>
+#include <fcntl.h>
+#include <fnmatch.h>
+#include <paths.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#if defined(OpenBSD) && OpenBSD >= 201411
+/* OpenBSD dropped the global setting from sysctl but left the #define
+ * which causes a EPERM error when trying to use it.
+ * I think both the error and keeping the define are wrong, so we #undef it. */
+#undef IPV6CTL_ACCEPT_RTADV
+#endif
+
+#include "config.h"
+#include "common.h"
+#include "dhcp.h"
+#include "if.h"
+#include "if-options.h"
+#include "ipv4.h"
+#include "ipv6.h"
+#include "ipv6nd.h"
+
+#include "bpf-filter.h"
+
+#ifndef RT_ROUNDUP
+#define RT_ROUNDUP(a)							      \
+	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
+#define RT_ADVANCE(x, n) (x += RT_ROUNDUP((n)->sa_len))
+#endif
+
+#define COPYOUT(sin, sa) do {						      \
+	if ((sa) && ((sa)->sa_family == AF_INET || (sa)->sa_family == 255))   \
+		(sin) = ((struct sockaddr_in*)(void *)(sa))->sin_addr;	      \
+	} while (0)
+
+#define COPYOUT6(sin, sa) do {						      \
+	if ((sa) && ((sa)->sa_family == AF_INET6 || (sa)->sa_family == 255))  \
+		(sin) = ((struct sockaddr_in6*)(void *)(sa))->sin6_addr;      \
+	} while (0)
+
+#ifndef CLLADDR
+#  define CLLADDR(s) ((const char *)((s)->sdl_data + (s)->sdl_nlen))
+#endif
+
+int
+if_init(__unused struct interface *iface)
+{
+	/* BSD promotes secondary address by default */
+	return 0;
+}
+
+int
+if_conf(__unused struct interface *iface)
+{
+	/* No extra checks needed on BSD */
+	return 0;
+}
+
+int
+if_openlinksocket(void)
+{
+
+#ifdef SOCK_CLOEXEC
+	return socket(PF_ROUTE, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
+#else
+	int s, flags;
+
+	if ((s = socket(PF_ROUTE, SOCK_RAW, 0)) == -1)
+		return -1;
+	if ((flags = fcntl(s, F_GETFD, 0)) == -1 ||
+	    fcntl(s, F_SETFD, flags | FD_CLOEXEC) == -1)
+	{
+		close(s);
+	        return -1;
+	}
+	if ((flags = fcntl(s, F_GETFL, 0)) == -1 ||
+	    fcntl(s, F_SETFL, flags | O_NONBLOCK) == -1)
+	{
+		close(s);
+	        return -1;
+	}
+	return s;
+#endif
+}
+
+#if defined(INET) || defined(INET6)
+static void
+if_linkaddr(struct sockaddr_dl *sdl, const struct interface *ifp)
+{
+
+	memset(sdl, 0, sizeof(*sdl));
+	sdl->sdl_family = AF_LINK;
+	sdl->sdl_len = sizeof(*sdl);
+	sdl->sdl_nlen = sdl->sdl_alen = sdl->sdl_slen = 0;
+	sdl->sdl_index = (unsigned short)ifp->index;
+}
+#endif
+
+static int
+if_getssid1(const char *ifname, uint8_t *ssid)
+{
+	int s, retval = -1;
+#if defined(SIOCG80211NWID)
+	struct ifreq ifr;
+	struct ieee80211_nwid nwid;
+#elif defined(IEEE80211_IOC_SSID)
+	struct ieee80211req ireq;
+	char nwid[IEEE80211_NWID_LEN + 1];
+#endif
+
+	if ((s = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
+		return -1;
+
+#if defined(SIOCG80211NWID) /* NetBSD */
+	memset(&ifr, 0, sizeof(ifr));
+	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+	memset(&nwid, 0, sizeof(nwid));
+	ifr.ifr_data = (void *)&nwid;
+	if (ioctl(s, SIOCG80211NWID, &ifr) == 0) {
+		if (ssid == NULL)
+			retval = nwid.i_len;
+		else if (nwid.i_len > IF_SSIDSIZE) {
+			errno = ENOBUFS;
+			retval = -1;
+		} else {
+			retval = nwid.i_len;
+			memcpy(ssid, nwid.i_nwid, nwid.i_len);
+			ssid[nwid.i_len] = '\0';
+		}
+	}
+#elif defined(IEEE80211_IOC_SSID) /* FreeBSD */
+	memset(&ireq, 0, sizeof(ireq));
+	strlcpy(ireq.i_name, ifname, sizeof(ireq.i_name));
+	ireq.i_type = IEEE80211_IOC_SSID;
+	ireq.i_val = -1;
+	memset(nwid, 0, sizeof(nwid));
+	ireq.i_data = &nwid;
+	if (ioctl(s, SIOCG80211, &ireq) == 0) {
+		if (ssid == NULL)
+			retval = ireq.i_len;
+		else if (ireq.i_len > IF_SSIDSIZE) {
+			errno = ENOBUFS;
+			retval = -1;
+		} else  {
+			retval = ireq.i_len;
+			memcpy(ssid, nwid, ireq.i_len);
+			ssid[ireq.i_len] = '\0';
+		}
+	}
+#endif
+
+	close(s);
+	return retval;
+}
+
+int
+if_getssid(struct interface *ifp)
+{
+	int r;
+
+	r = if_getssid1(ifp->name, ifp->ssid);
+	if (r != -1)
+		ifp->ssid_len = (unsigned int)r;
+	return r;
+}
+
+/*
+ * FreeBSD allows for Virtual Access Points
+ * We need to check if the interface is a Virtual Interface Master
+ * and if so, don't use it.
+ * This check is made by virtue of being a IEEE80211 device but
+ * returning the SSID gives an error.
+ */
+int
+if_vimaster(const char *ifname)
+{
+	int s, r;
+	struct ifmediareq ifmr;
+
+	if ((s = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
+		return -1;
+	memset(&ifmr, 0, sizeof(ifmr));
+	strlcpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name));
+	r = ioctl(s, SIOCGIFMEDIA, &ifmr);
+	close(s);
+	if (r == -1)
+		return -1;
+	if (ifmr.ifm_status & IFM_AVALID &&
+	    IFM_TYPE(ifmr.ifm_active) == IFM_IEEE80211)
+	{
+		if (if_getssid1(ifname, NULL) == -1)
+			return 1;
+	}
+	return 0;
+}
+
+static void
+get_addrs(int type, char *cp, struct sockaddr **sa)
+{
+	int i;
+
+	for (i = 0; i < RTAX_MAX; i++) {
+		if (type & (1 << i)) {
+			sa[i] = (struct sockaddr *)cp;
+			RT_ADVANCE(cp, sa[i]);
+		} else
+			sa[i] = NULL;
+	}
+}
+
+#if defined(INET) || defined(INET6)
+static struct interface *
+if_findsdl(struct dhcpcd_ctx *ctx, struct sockaddr_dl *sdl)
+{
+
+	if (sdl->sdl_nlen) {
+		char ifname[IF_NAMESIZE];
+		memcpy(ifname, sdl->sdl_data, sdl->sdl_nlen);
+		ifname[sdl->sdl_nlen] = '\0';
+		return if_find(ctx->ifaces, ifname);
+	}
+	return NULL;
+}
+#endif
+
+#ifdef INET
+const char *if_pfname = "Berkley Packet Filter";
+
+int
+if_openrawsocket(struct interface *ifp, uint16_t protocol)
+{
+	struct dhcp_state *state;
+	int fd = -1;
+	struct ifreq ifr;
+	int ibuf_len = 0;
+	size_t buf_len;
+	struct bpf_version pv;
+	struct bpf_program pf;
+#ifdef BIOCIMMEDIATE
+	int flags;
+#endif
+#ifdef _PATH_BPF
+	fd = open(_PATH_BPF, O_RDWR | O_CLOEXEC | O_NONBLOCK);
+#else
+	char device[32];
+	int n = 0;
+
+	do {
+		snprintf(device, sizeof(device), "/dev/bpf%d", n++);
+		fd = open(device, O_RDWR | O_CLOEXEC | O_NONBLOCK);
+	} while (fd == -1 && errno == EBUSY);
+#endif
+
+	if (fd == -1)
+		return -1;
+
+	state = D_STATE(ifp);
+
+	memset(&pv, 0, sizeof(pv));
+	if (ioctl(fd, BIOCVERSION, &pv) == -1)
+		goto eexit;
+	if (pv.bv_major != BPF_MAJOR_VERSION ||
+	    pv.bv_minor < BPF_MINOR_VERSION) {
+		logger(ifp->ctx, LOG_ERR, "BPF version mismatch - recompile");
+		goto eexit;
+	}
+
+	memset(&ifr, 0, sizeof(ifr));
+	strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
+	if (ioctl(fd, BIOCSETIF, &ifr) == -1)
+		goto eexit;
+
+	/* Get the required BPF buffer length from the kernel. */
+	if (ioctl(fd, BIOCGBLEN, &ibuf_len) == -1)
+		goto eexit;
+	buf_len = (size_t)ibuf_len;
+	if (state->buffer_size != buf_len) {
+		free(state->buffer);
+		state->buffer = malloc(buf_len);
+		if (state->buffer == NULL)
+			goto eexit;
+		state->buffer_size = buf_len;
+		state->buffer_len = state->buffer_pos = 0;
+	}
+
+#ifdef BIOCIMMEDIATE
+	flags = 1;
+	if (ioctl(fd, BIOCIMMEDIATE, &flags) == -1)
+		goto eexit;
+#endif
+
+	/* Install the DHCP filter */
+	memset(&pf, 0, sizeof(pf));
+	if (protocol == ETHERTYPE_ARP) {
+		pf.bf_insns = UNCONST(arp_bpf_filter);
+		pf.bf_len = arp_bpf_filter_len;
+	} else {
+		pf.bf_insns = UNCONST(dhcp_bpf_filter);
+		pf.bf_len = dhcp_bpf_filter_len;
+	}
+	if (ioctl(fd, BIOCSETF, &pf) == -1)
+		goto eexit;
+
+	return fd;
+
+eexit:
+	free(state->buffer);
+	state->buffer = NULL;
+	close(fd);
+	return -1;
+}
+
+ssize_t
+if_sendrawpacket(const struct interface *ifp, uint16_t protocol,
+    const void *data, size_t len, const uint8_t *dest_hw_addr)
+{
+	struct iovec iov[2];
+	struct ether_header hw;
+	int fd;
+	const struct dhcp_state *state;
+
+	memset(&hw, 0, ETHER_HDR_LEN);
+	if (dest_hw_addr)
+		memcpy(&hw.ether_dhost, dest_hw_addr, ETHER_ADDR_LEN);
+	else
+		memset(&hw.ether_dhost, 0xff, ETHER_ADDR_LEN);
+	hw.ether_type = htons(protocol);
+	iov[0].iov_base = &hw;
+	iov[0].iov_len = ETHER_HDR_LEN;
+	iov[1].iov_base = UNCONST(data);
+	iov[1].iov_len = len;
+	state = D_CSTATE(ifp);
+	if (protocol == ETHERTYPE_ARP)
+		fd = state->arp_fd;
+	else
+		fd = state->raw_fd;
+	return writev(fd, iov, 2);
+}
+
+/* BPF requires that we read the entire buffer.
+ * So we pass the buffer in the API so we can loop on >1 packet. */
+ssize_t
+if_readrawpacket(struct interface *ifp, uint16_t protocol,
+    void *data, size_t len, int *flags)
+{
+	int fd;
+	struct bpf_hdr packet;
+	ssize_t bytes;
+	const unsigned char *payload;
+	struct dhcp_state *state;
+
+	state = D_STATE(ifp);
+	if (protocol == ETHERTYPE_ARP)
+		fd = state->arp_fd;
+	else
+		fd = state->raw_fd;
+
+	*flags = 0;
+	for (;;) {
+		if (state->buffer_len == 0) {
+			bytes = read(fd, state->buffer, state->buffer_size);
+			if (bytes == -1 || bytes == 0)
+				return bytes;
+			state->buffer_len = (size_t)bytes;
+			state->buffer_pos = 0;
+		}
+		bytes = -1;
+		memcpy(&packet, state->buffer + state->buffer_pos,
+		    sizeof(packet));
+		if (packet.bh_caplen != packet.bh_datalen)
+			goto next; /* Incomplete packet, drop. */
+		if (state->buffer_pos + packet.bh_caplen + packet.bh_hdrlen >
+		    state->buffer_len)
+			goto next; /* Packet beyond buffer, drop. */
+		payload = state->buffer + state->buffer_pos +
+		    packet.bh_hdrlen + ETHER_HDR_LEN;
+		bytes = (ssize_t)packet.bh_caplen - ETHER_HDR_LEN;
+		if ((size_t)bytes > len)
+			bytes = (ssize_t)len;
+		memcpy(data, payload, (size_t)bytes);
+next:
+		state->buffer_pos += BPF_WORDALIGN(packet.bh_hdrlen +
+		    packet.bh_caplen);
+		if (state->buffer_pos >= state->buffer_len) {
+			state->buffer_len = state->buffer_pos = 0;
+			*flags |= RAW_EOF;
+		}
+		if (bytes != -1)
+			return bytes;
+	}
+}
+
+int
+if_address(const struct interface *ifp, const struct in_addr *address,
+    const struct in_addr *netmask, const struct in_addr *broadcast,
+    int action)
+{
+	int s, r;
+	struct in_aliasreq ifra;
+
+	if ((s = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
+		return -1;
+
+	memset(&ifra, 0, sizeof(ifra));
+	strlcpy(ifra.ifra_name, ifp->name, sizeof(ifra.ifra_name));
+
+#define ADDADDR(var, addr) do {						      \
+		(var)->sin_family = AF_INET;				      \
+		(var)->sin_len = sizeof(*(var));			      \
+		(var)->sin_addr = *(addr);				      \
+	} while (/*CONSTCOND*/0)
+	ADDADDR(&ifra.ifra_addr, address);
+	ADDADDR(&ifra.ifra_mask, netmask);
+	if (action >= 0 && broadcast)
+		ADDADDR(&ifra.ifra_broadaddr, broadcast);
+#undef ADDADDR
+
+	r = ioctl(s,
+	    action < 0 ? SIOCDIFADDR : SIOCAIFADDR, &ifra);
+	close(s);
+	return r;
+}
+
+static int
+if_copyrt(struct dhcpcd_ctx *ctx, struct rt *rt, struct rt_msghdr *rtm)
+{
+	char *cp;
+	struct sockaddr *sa, *rti_info[RTAX_MAX];
+
+	cp = (char *)(void *)(rtm + 1);
+	sa = (struct sockaddr *)(void *)cp;
+	if (sa->sa_family != AF_INET)
+		return -1;
+	if (~rtm->rtm_addrs & (RTA_DST | RTA_GATEWAY))
+		return -1;
+#ifdef RTF_CLONED
+	if (rtm->rtm_flags & RTF_CLONED)
+		return -1;
+#endif
+#ifdef RTF_LOCAL
+	if (rtm->rtm_flags & RTF_LOCAL)
+		return -1;
+#endif
+#ifdef RTF_BROADCAST
+	if (rtm->rtm_flags & RTF_BROADCAST)
+		return -1;
+#endif
+
+	get_addrs(rtm->rtm_addrs, cp, rti_info);
+	memset(rt, 0, sizeof(*rt));
+	COPYOUT(rt->dest, rti_info[RTAX_DST]);
+	if (rtm->rtm_addrs & RTA_NETMASK)
+		COPYOUT(rt->net, rti_info[RTAX_NETMASK]);
+	else
+		rt->net.s_addr = INADDR_BROADCAST;
+	COPYOUT(rt->gate, rti_info[RTAX_GATEWAY]);
+
+	if (rtm->rtm_index)
+		rt->iface = if_findindex(ctx->ifaces, rtm->rtm_index);
+	else if (rtm->rtm_addrs & RTA_IFP) {
+		struct sockaddr_dl *sdl;
+
+		sdl = (struct sockaddr_dl *)(void *)rti_info[RTAX_IFP];
+		rt->iface = if_findsdl(ctx, sdl);
+	}
+	/* If we don't have an interface and it's a host route, it maybe
+	 * to a local ip via the loopback interface. */
+	if (rt->iface == NULL &&
+	    !(~rtm->rtm_flags & (RTF_HOST | RTF_GATEWAY)))
+	{
+		struct ipv4_addr *ia;
+
+		if ((ia = ipv4_findaddr(ctx, &rt->dest)))
+			rt->iface = ia->iface;
+	}
+
+	return 0;
+}
+
+int
+if_route(unsigned char cmd, const struct rt *rt)
+{
+	const struct dhcp_state *state;
+	union sockunion {
+		struct sockaddr sa;
+		struct sockaddr_in sin;
+		struct sockaddr_dl sdl;
+	} su;
+	struct rtm
+	{
+		struct rt_msghdr hdr;
+		char buffer[sizeof(su) * RTAX_MAX];
+	} rtm;
+	char *bp = rtm.buffer;
+	size_t l;
+	int s, retval;
+
+	if ((s = socket(PF_ROUTE, SOCK_RAW, 0)) == -1)
+		return -1;
+
+#define ADDSU {								      \
+		l = RT_ROUNDUP(su.sa.sa_len);				      \
+		memcpy(bp, &su, l);					      \
+		bp += l;						      \
+	}
+#define ADDADDR(addr) {							      \
+		memset(&su, 0, sizeof(su));				      \
+		su.sin.sin_family = AF_INET;				      \
+		su.sin.sin_len = sizeof(su.sin);			      \
+		(&su.sin)->sin_addr = *addr;				      \
+		ADDSU;							      \
+	}
+
+	if (cmd != RTM_DELETE)
+		state = D_CSTATE(rt->iface);
+	else	/* appease GCC */
+		state = NULL;
+	memset(&rtm, 0, sizeof(rtm));
+	rtm.hdr.rtm_version = RTM_VERSION;
+	rtm.hdr.rtm_seq = 1;
+	rtm.hdr.rtm_type = cmd;
+	rtm.hdr.rtm_addrs = RTA_DST;
+	if (cmd == RTM_ADD || cmd == RTM_CHANGE)
+		rtm.hdr.rtm_addrs |= RTA_GATEWAY;
+	rtm.hdr.rtm_flags = RTF_UP;
+#ifdef RTF_PINNED
+	if (cmd != RTM_ADD)
+		rtm.hdr.rtm_flags |= RTF_PINNED;
+#endif
+
+	if (cmd != RTM_DELETE) {
+		rtm.hdr.rtm_addrs |= RTA_IFA | RTA_IFP;
+		/* None interface subnet routes are static. */
+		if (rt->gate.s_addr != INADDR_ANY ||
+		    rt->net.s_addr != state->net.s_addr ||
+		    rt->dest.s_addr != (state->addr.s_addr & state->net.s_addr))
+			rtm.hdr.rtm_flags |= RTF_STATIC;
+		else {
+#ifdef RTF_CLONING
+			rtm.hdr.rtm_flags |= RTF_CLONING;
+#endif
+#ifdef RTP_CONNECTED
+			rtm.hdr.rtm_priority = RTP_CONNECTED;
+#endif
+		}
+	}
+	if (rt->net.s_addr == htonl(INADDR_BROADCAST) &&
+	    rt->gate.s_addr == htonl(INADDR_ANY))
+	{
+#ifdef RTF_CLONING
+		/* We add a cloning network route for a single host.
+		 * Traffic to the host will generate a cloned route and the
+		 * hardware address will resolve correctly.
+		 * It might be more correct to use RTF_HOST instead of
+		 * RTF_CLONING, and that does work, but some OS generate
+		 * an arp warning diagnostic which we don't want to do. */
+		rtm.hdr.rtm_flags |= RTF_CLONING;
+		rtm.hdr.rtm_addrs |= RTA_NETMASK;
+#else
+		rtm.hdr.rtm_flags |= RTF_HOST;
+#endif
+	} else if (rt->gate.s_addr == htonl(INADDR_LOOPBACK) &&
+	    rt->net.s_addr == htonl(INADDR_BROADCAST))
+	{
+		rtm.hdr.rtm_flags |= RTF_HOST | RTF_GATEWAY;
+		/* Going via lo0 so remove the interface flags */
+		if (cmd == RTM_ADD)
+			rtm.hdr.rtm_addrs &= ~(RTA_IFA | RTA_IFP);
+	} else {
+		rtm.hdr.rtm_addrs |= RTA_NETMASK;
+		if (rtm.hdr.rtm_flags & RTF_STATIC)
+			rtm.hdr.rtm_flags |= RTF_GATEWAY;
+	}
+	if ((cmd == RTM_ADD || cmd == RTM_CHANGE) &&
+	    !(rtm.hdr.rtm_flags & RTF_GATEWAY))
+		rtm.hdr.rtm_addrs |= RTA_IFA | RTA_IFP;
+
+	ADDADDR(&rt->dest);
+	if (rtm.hdr.rtm_addrs & RTA_GATEWAY) {
+#ifdef RTF_CLONING
+		if ((rtm.hdr.rtm_flags & (RTF_HOST | RTF_CLONING) &&
+#else
+		if ((rtm.hdr.rtm_flags & RTF_HOST &&
+#endif
+		    rt->gate.s_addr != htonl(INADDR_LOOPBACK)) ||
+		    !(rtm.hdr.rtm_flags & RTF_STATIC))
+		{
+			if_linkaddr(&su.sdl, rt->iface);
+			ADDSU;
+		} else
+			ADDADDR(&rt->gate);
+	}
+
+	if (rtm.hdr.rtm_addrs & RTA_NETMASK)
+		ADDADDR(&rt->net);
+
+	if ((cmd == RTM_ADD || cmd == RTM_CHANGE) &&
+	    (rtm.hdr.rtm_addrs & (RTA_IFP | RTA_IFA)))
+	{
+		rtm.hdr.rtm_index = (unsigned short)rt->iface->index;
+		if (rtm.hdr.rtm_addrs & RTA_IFP) {
+			if_linkaddr(&su.sdl, rt->iface);
+			ADDSU;
+		}
+
+		if (rtm.hdr.rtm_addrs & RTA_IFA)
+			ADDADDR(&state->addr);
+	}
+
+#undef ADDADDR
+#undef ADDSU
+
+	rtm.hdr.rtm_msglen = (unsigned short)(bp - (char *)&rtm);
+	retval = write(s, &rtm, rtm.hdr.rtm_msglen) == -1 ? -1 : 0;
+	close(s);
+	return retval;
+}
+
+int
+if_initrt(struct interface *ifp)
+{
+	struct rt_msghdr *rtm;
+	int mib[6];
+	size_t needed;
+	char *buf, *p, *end;
+	struct rt rt;
+
+	ipv4_freerts(ifp->ctx->ipv4_kroutes);
+
+	mib[0] = CTL_NET;
+	mib[1] = PF_ROUTE;
+	mib[2] = 0;
+	mib[3] = AF_INET;
+	mib[4] = NET_RT_DUMP;
+	mib[5] = 0;
+
+	if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1)
+		return -1;
+	if (needed == 0)
+		return 0;
+	if ((buf = malloc(needed)) == NULL)
+		return -1;
+	if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1)
+		return -1;
+
+	end = buf + needed;
+	for (p = buf; p < end; p += rtm->rtm_msglen) {
+		rtm = (struct rt_msghdr *)(void *)p;
+		if (if_copyrt(ifp->ctx, &rt, rtm) == 0)
+			ipv4_handlert(ifp->ctx, RTM_ADD, &rt);
+	}
+	free(buf);
+	return 0;
+}
+
+#ifdef SIOCGIFAFLAG_IN
+int
+if_addrflags(const struct in_addr *addr, const struct interface *ifp)
+{
+	int s, flags;
+	struct ifreq ifr;
+	struct sockaddr_in *sin;
+
+	s = socket(PF_INET, SOCK_DGRAM, 0);
+	flags = -1;
+	if (s != -1) {
+		memset(&ifr, 0, sizeof(ifr));
+		strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
+		sin = (struct sockaddr_in *)(void *)&ifr.ifr_addr;
+		sin->sin_family = AF_INET;
+		sin->sin_addr = *addr;
+		if (ioctl(s, SIOCGIFAFLAG_IN, &ifr) != -1)
+			flags = ifr.ifr_addrflags;
+		close(s);
+	}
+	return flags;
+}
+#else
+int
+if_addrflags(__unused const struct in_addr *addr,
+    __unused const struct interface *ifp)
+{
+
+	errno = ENOTSUP;
+	return 0;
+}
+#endif
+#endif /* INET */
+
+#ifdef INET6
+static void
+ifa_scope(struct sockaddr_in6 *sin, unsigned int ifindex)
+{
+
+#ifdef __KAME__
+	/* KAME based systems want to store the scope inside the sin6_addr
+	 * for link local addreses */
+	if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) {
+		uint16_t scope = htons((uint16_t)ifindex);
+		memcpy(&sin->sin6_addr.s6_addr[2], &scope,
+		    sizeof(scope));
+	}
+	sin->sin6_scope_id = 0;
+#else
+	if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr))
+		sin->sin6_scope_id = ifindex;
+	else
+		sin->sin6_scope_id = 0;
+#endif
+}
+
+#ifdef __KAME__
+#define DESCOPE(ia6) do {						      \
+	if (IN6_IS_ADDR_LINKLOCAL((ia6)))				      \
+		(ia6)->s6_addr[2] = (ia6)->s6_addr[3] = '\0';		      \
+	} while (/*CONSTCOND */0)
+#else
+#define DESCOPE(ia6)
+#endif
+
+int
+if_address6(const struct ipv6_addr *a, int action)
+{
+	int s, r;
+	struct in6_aliasreq ifa;
+	struct in6_addr mask;
+
+	if ((s = socket(PF_INET6, SOCK_DGRAM, 0)) == -1)
+		return -1;
+
+	memset(&ifa, 0, sizeof(ifa));
+	strlcpy(ifa.ifra_name, a->iface->name, sizeof(ifa.ifra_name));
+	/*
+	 * We should not set IN6_IFF_TENTATIVE as the kernel should be
+	 * able to work out if it's a new address or not.
+	 *
+	 * We should set IN6_IFF_AUTOCONF, but the kernel won't let us.
+	 * This is probably a safety measure, but still it's not entirely right
+	 * either.
+	 */
+#if 0
+	if (a->autoconf)
+		ifa.ifra_flags |= IN6_IFF_AUTOCONF;
+#endif
+#ifdef IPV6_MANGETEMPADDR
+	if (a->flags & IPV6_AF_TEMPORARY)
+		ifa.ifra_flags |= IN6_IFF_TEMPORARY;
+#endif
+
+#define ADDADDR(v, addr) {						      \
+		(v)->sin6_family = AF_INET6;				      \
+		(v)->sin6_len = sizeof(*v);				      \
+		(v)->sin6_addr = *addr;					      \
+	}
+
+	ADDADDR(&ifa.ifra_addr, &a->addr);
+	ifa_scope(&ifa.ifra_addr, a->iface->index);
+	ipv6_mask(&mask, a->prefix_len);
+	ADDADDR(&ifa.ifra_prefixmask, &mask);
+	ifa.ifra_lifetime.ia6t_vltime = a->prefix_vltime;
+	ifa.ifra_lifetime.ia6t_pltime = a->prefix_pltime;
+#undef ADDADDR
+
+	r = ioctl(s, action < 0 ? SIOCDIFADDR_IN6 : SIOCAIFADDR_IN6, &ifa);
+	close(s);
+	return r;
+}
+
+
+static int
+if_copyrt6(struct dhcpcd_ctx *ctx, struct rt6 *rt, struct rt_msghdr *rtm)
+{
+	char *cp;
+	struct sockaddr *sa, *rti_info[RTAX_MAX];
+
+	cp = (char *)(void *)(rtm + 1);
+	sa = (struct sockaddr *)(void *)cp;
+	if (sa->sa_family != AF_INET6)
+		return -1;
+	if (~rtm->rtm_addrs & (RTA_DST | RTA_GATEWAY))
+		return -1;
+#ifdef RTF_CLONED
+	if (rtm->rtm_flags & (RTF_CLONED | RTF_HOST))
+		return -1;
+#else
+	if (rtm->rtm_flags & RTF_HOST)
+		return -1;
+#endif
+#ifdef RTF_LOCAL
+	if (rtm->rtm_flags & RTF_LOCAL)
+		return -1;
+#endif
+
+	get_addrs(rtm->rtm_addrs, cp, rti_info);
+	memset(rt, 0, sizeof(*rt));
+	rt->flags = (unsigned int)rtm->rtm_flags;
+	COPYOUT6(rt->dest, rti_info[RTAX_DST]);
+	if (rtm->rtm_addrs & RTA_NETMASK) {
+		/*
+		 * We need to zero out the struct beyond sin6_len and
+		 * ensure it's valid.
+		 * I have no idea what the invalid data is for, could be
+		 * a kernel bug or actually used for something.
+		 * Either way it needs to be zeroed out.
+		 */
+		struct sockaddr_in6 *sin6;
+		size_t e, i, len = 0, final = 0;
+
+		sin6 = (struct sockaddr_in6 *)(void *)rti_info[RTAX_NETMASK];
+		rt->net = sin6->sin6_addr;
+		e = sin6->sin6_len - offsetof(struct sockaddr_in6, sin6_addr);
+		if (e > sizeof(struct in6_addr))
+			e = sizeof(struct in6_addr);
+		for (i = 0; i < e; i++) {
+			switch (rt->net.s6_addr[i] & 0xff) {
+			case 0xff:
+				/* We don't really want the length,
+				 * just that it's valid */
+				len++;
+				break;
+			case 0xfe:
+			case 0xfc:
+			case 0xf8:
+			case 0xf0:
+			case 0xe0:
+			case 0xc0:
+			case 0x80:
+				len++;
+				final = 1;
+				break;
+			default:
+				rt->net.s6_addr[i] = 0x00;
+				final = 1;
+				break;
+			}
+			if (final)
+				break;
+		}
+		if (len == 0)
+			i = 0;
+		while (i < sizeof(rt->net.s6_addr))
+			rt->net.s6_addr[i++] = 0x00;
+	} else
+		ipv6_mask(&rt->net, 128);
+	COPYOUT6(rt->gate, rti_info[RTAX_GATEWAY]);
+
+	if (rtm->rtm_index)
+		rt->iface = if_findindex(ctx->ifaces, rtm->rtm_index);
+	else if (rtm->rtm_addrs & RTA_IFP) {
+		struct sockaddr_dl *sdl;
+
+		sdl = (struct sockaddr_dl *)(void *)rti_info[RTAX_IFP];
+		rt->iface = if_findsdl(ctx, sdl);
+	}
+	/* If we don't have an interface and it's a host route, it maybe
+	 * to a local ip via the loopback interface. */
+	if (rt->iface == NULL &&
+	    !(~rtm->rtm_flags & (RTF_HOST | RTF_GATEWAY)))
+	{
+		struct ipv6_addr *ia;
+
+		if ((ia = ipv6_findaddr(ctx, &rt->dest, 0)))
+			rt->iface = ia->iface;
+	}
+
+	return 0;
+}
+
+int
+if_route6(unsigned char cmd, const struct rt6 *rt)
+{
+	union sockunion {
+		struct sockaddr sa;
+		struct sockaddr_in6 sin;
+		struct sockaddr_dl sdl;
+	} su;
+	struct rtm
+	{
+		struct rt_msghdr hdr;
+		char buffer[sizeof(su) * RTAX_MAX];
+	} rtm;
+	char *bp = rtm.buffer;
+	size_t l;
+	int s, retval;
+
+	if ((s = socket(PF_ROUTE, SOCK_RAW, 0)) == -1)
+		return -1;
+
+#define ADDSU {								      \
+		l = RT_ROUNDUP(su.sa.sa_len);				      \
+		memcpy(bp, &su, l);					      \
+		bp += l;						      \
+	}
+#define ADDADDRS(addr, scope) {						      \
+		memset(&su, 0, sizeof(su));				      \
+		su.sin.sin6_family = AF_INET6;				      \
+		su.sin.sin6_len = sizeof(su.sin);			      \
+		(&su.sin)->sin6_addr = *addr;				      \
+		if (scope)						      \
+			ifa_scope(&su.sin, scope);			      \
+		ADDSU;							      \
+	}
+#define ADDADDR(addr) ADDADDRS(addr, 0)
+
+	memset(&rtm, 0, sizeof(rtm));
+	rtm.hdr.rtm_version = RTM_VERSION;
+	rtm.hdr.rtm_seq = 1;
+	rtm.hdr.rtm_type = cmd;
+	rtm.hdr.rtm_flags = RTF_UP | (int)rt->flags;
+#ifdef RTF_PINNED
+	if (rtm.hdr.rtm_type != RTM_ADD)
+		rtm.hdr.rtm_flags |= RTF_PINNED;
+#endif
+	rtm.hdr.rtm_addrs = RTA_DST | RTA_NETMASK;
+	/* None interface subnet routes are static. */
+	if (IN6_IS_ADDR_UNSPECIFIED(&rt->gate)) {
+#ifdef RTF_CLONING
+		rtm.hdr.rtm_flags |= RTF_CLONING;
+#endif
+#ifdef RTP_CONNECTED
+		rtm.hdr.rtm_priority = RTP_CONNECTED;
+#endif
+	} else
+		rtm.hdr.rtm_flags |= RTF_GATEWAY | RTF_STATIC;
+
+	if (cmd == RTM_ADD)
+		rtm.hdr.rtm_addrs |= RTA_GATEWAY;
+	if (cmd == RTM_ADD && !(rtm.hdr.rtm_flags & RTF_REJECT))
+		rtm.hdr.rtm_addrs |= RTA_IFP | RTA_IFA;
+
+	ADDADDR(&rt->dest);
+	if (rtm.hdr.rtm_addrs & RTA_GATEWAY) {
+		if (IN6_IS_ADDR_UNSPECIFIED(&rt->gate)) {
+			if_linkaddr(&su.sdl, rt->iface);
+			ADDSU;
+		} else {
+			ADDADDRS(&rt->gate, rt->iface->index);
+		}
+	}
+
+	if (rtm.hdr.rtm_addrs & RTA_NETMASK)
+		ADDADDR(&rt->net);
+
+	if ((cmd == RTM_ADD || cmd == RTM_CHANGE) &&
+	    (rtm.hdr.rtm_addrs & (RTA_IFP | RTA_IFA)))
+	{
+		rtm.hdr.rtm_index = (unsigned short)rt->iface->index;
+		if (rtm.hdr.rtm_addrs & RTA_IFP) {
+			if_linkaddr(&su.sdl, rt->iface);
+			ADDSU;
+		}
+
+		if (rtm.hdr.rtm_addrs & RTA_IFA) {
+			const struct ipv6_addr *lla;
+
+			lla = ipv6_linklocal(rt->iface);
+			if (lla == NULL) /* unlikely */
+					return -1;
+			ADDADDRS(&lla->addr, rt->iface->index);
+		}
+
+		if (rt->mtu) {
+			rtm.hdr.rtm_inits |= RTV_MTU;
+			rtm.hdr.rtm_rmx.rmx_mtu = rt->mtu;
+		}
+	}
+
+#undef ADDADDR
+#undef ADDSU
+
+	rtm.hdr.rtm_msglen = (unsigned short)(bp - (char *)&rtm);
+	retval = write(s, &rtm, rtm.hdr.rtm_msglen) == -1 ? -1 : 0;
+	close(s);
+	return retval;
+}
+
+int
+if_initrt6(struct interface *ifp)
+{
+	struct rt_msghdr *rtm;
+	int mib[6];
+	size_t needed;
+	char *buf, *p, *end;
+	struct rt6 rt;
+
+	ipv6_freerts(&ifp->ctx->ipv6->kroutes);
+
+	mib[0] = CTL_NET;
+	mib[1] = PF_ROUTE;
+	mib[2] = 0;
+	mib[3] = AF_INET6;
+	mib[4] = NET_RT_DUMP;
+	mib[5] = 0;
+
+	if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1)
+		return -1;
+	if (needed == 0)
+		return 0;
+	if ((buf = malloc(needed)) == NULL)
+		return -1;
+	if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1)
+		return -1;
+
+	end = buf + needed;
+	for (p = buf; p < end; p += rtm->rtm_msglen) {
+		rtm = (struct rt_msghdr *)(void *)p;
+		if (if_copyrt6(ifp->ctx, &rt, rtm) == 0)
+			ipv6_handlert(ifp->ctx, RTM_ADD, &rt);
+	}
+	free(buf);
+	return 0;
+}
+
+int
+if_addrflags6(const struct in6_addr *addr, const struct interface *ifp)
+{
+	int s, flags;
+	struct in6_ifreq ifr6;
+
+	s = socket(PF_INET6, SOCK_DGRAM, 0);
+	flags = -1;
+	if (s != -1) {
+		memset(&ifr6, 0, sizeof(ifr6));
+		strlcpy(ifr6.ifr_name, ifp->name, sizeof(ifr6.ifr_name));
+		ifr6.ifr_addr.sin6_family = AF_INET6;
+		ifr6.ifr_addr.sin6_addr = *addr;
+		ifa_scope(&ifr6.ifr_addr, ifp->index);
+		if (ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) != -1)
+			flags = ifr6.ifr_ifru.ifru_flags6;
+		close(s);
+	}
+	return flags;
+}
+
+int
+if_getlifetime6(struct ipv6_addr *ia)
+{
+	int s, r;
+	struct in6_ifreq ifr6;
+
+	s = socket(PF_INET6, SOCK_DGRAM, 0);
+	r = -1;
+	if (s != -1) {
+		memset(&ifr6, 0, sizeof(ifr6));
+		strlcpy(ifr6.ifr_name, ia->iface->name, sizeof(ifr6.ifr_name));
+		ifr6.ifr_addr.sin6_family = AF_INET6;
+		ifr6.ifr_addr.sin6_addr = ia->addr;
+		ifa_scope(&ifr6.ifr_addr, ia->iface->index);
+		if (ioctl(s, SIOCGIFALIFETIME_IN6, &ifr6) != -1) {
+			time_t t;
+			struct in6_addrlifetime *lifetime;
+
+			t = time(NULL);
+			lifetime = &ifr6.ifr_ifru.ifru_lifetime;
+
+			if (lifetime->ia6t_preferred)
+				ia->prefix_pltime =
+				    (uint32_t)(lifetime->ia6t_preferred -
+				    MIN(t, lifetime->ia6t_preferred));
+			else
+				ia->prefix_pltime = ND6_INFINITE_LIFETIME;
+			if (lifetime->ia6t_expire) {
+				ia->prefix_vltime =
+				    (uint32_t)(lifetime->ia6t_expire -
+				    MIN(t, lifetime->ia6t_expire));
+				/* Calculate the created time */
+				get_monotonic(&ia->created);
+				ia->created.tv_sec -=
+				    lifetime->ia6t_vltime - ia->prefix_vltime;
+			} else
+				ia->prefix_vltime = ND6_INFINITE_LIFETIME;
+
+			r = 0;
+		}
+		close(s);
+	}
+	return r;
+}
+#endif
+
+int
+if_managelink(struct dhcpcd_ctx *ctx)
+{
+	/* route and ifwatchd like a msg buf size of 2048 */
+	char msg[2048], *p, *e, *cp;
+	ssize_t bytes;
+	struct rt_msghdr *rtm;
+	struct if_announcemsghdr *ifan;
+	struct if_msghdr *ifm;
+	struct ifa_msghdr *ifam;
+	struct sockaddr *sa, *rti_info[RTAX_MAX];
+	int len;
+	struct sockaddr_dl sdl;
+	struct interface *ifp;
+#ifdef INET
+	struct rt rt;
+#endif
+#ifdef INET6
+	struct rt6 rt6;
+	struct in6_addr ia6, net6;
+	struct sockaddr_in6 *sin6;
+#endif
+#if (defined(INET) && defined(IN_IFF_TENTATIVE)) || defined(INET6)
+	int ifa_flags;
+#endif
+
+	if ((bytes = read(ctx->link_fd, msg, sizeof(msg))) == -1)
+		return -1;
+	e = msg + bytes;
+	for (p = msg; p < e; p += rtm->rtm_msglen) {
+		rtm = (struct rt_msghdr *)(void *)p;
+		// Ignore messages generated by us
+		if (rtm->rtm_pid == getpid())
+			break;
+		switch(rtm->rtm_type) {
+#ifdef RTM_IFANNOUNCE
+		case RTM_IFANNOUNCE:
+			ifan = (struct if_announcemsghdr *)(void *)p;
+			switch(ifan->ifan_what) {
+			case IFAN_ARRIVAL:
+				dhcpcd_handleinterface(ctx, 1,
+				    ifan->ifan_name);
+				break;
+			case IFAN_DEPARTURE:
+				dhcpcd_handleinterface(ctx, -1,
+				    ifan->ifan_name);
+				break;
+			}
+			break;
+#endif
+		case RTM_IFINFO:
+			ifm = (struct if_msghdr *)(void *)p;
+			ifp = if_findindex(ctx->ifaces, ifm->ifm_index);
+			if (ifp == NULL)
+				break;
+			switch (ifm->ifm_data.ifi_link_state) {
+			case LINK_STATE_DOWN:
+				len = LINK_DOWN;
+				break;
+			case LINK_STATE_UP:
+				len = LINK_UP;
+				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 ...*/
+				len = LINK_UNKNOWN;
+				break;
+			}
+			dhcpcd_handlecarrier(ctx, len,
+			    (unsigned int)ifm->ifm_flags, ifp->name);
+			break;
+		case RTM_ADD:
+		case RTM_CHANGE:
+		case RTM_DELETE:
+			cp = (char *)(void *)(rtm + 1);
+			sa = (struct sockaddr *)(void *)cp;
+			switch (sa->sa_family) {
+#ifdef INET
+			case AF_INET:
+				if (if_copyrt(ctx, &rt, rtm) == 0)
+					ipv4_handlert(ctx, rtm->rtm_type, &rt);
+				break;
+#endif
+#ifdef INET6
+			case AF_INET6:
+				if (~rtm->rtm_addrs & (RTA_DST | RTA_GATEWAY))
+					break;
+				/*
+				 * BSD caches host routes in the
+				 * routing table.
+				 * As such, we should be notified of
+				 * reachability by its existance
+				 * with a hardware address
+				 */
+				if (rtm->rtm_flags & (RTF_HOST)) {
+					get_addrs(rtm->rtm_addrs, cp, rti_info);
+					COPYOUT6(ia6, rti_info[RTAX_DST]);
+					DESCOPE(&ia6);
+					if (rti_info[RTAX_GATEWAY]->sa_family
+					    == AF_LINK)
+						memcpy(&sdl,
+						    rti_info[RTAX_GATEWAY],
+						    sizeof(sdl));
+					else
+						sdl.sdl_alen = 0;
+					ipv6nd_neighbour(ctx, &ia6,
+					    rtm->rtm_type != RTM_DELETE &&
+					    sdl.sdl_alen ?
+					    IPV6ND_REACHABLE : 0);
+					break;
+				}
+
+				if (if_copyrt6(ctx, &rt6, rtm) == 0)
+					ipv6_handlert(ctx, rtm->rtm_type, &rt6);
+				break;
+#endif
+			}
+			break;
+#ifdef RTM_CHGADDR
+		case RTM_CHGADDR:	/* FALLTHROUGH */
+#endif
+		case RTM_DELADDR:	/* FALLTHROUGH */
+		case RTM_NEWADDR:
+			ifam = (struct ifa_msghdr *)(void *)p;
+			ifp = if_findindex(ctx->ifaces, ifam->ifam_index);
+			if (ifp == NULL)
+				break;
+			cp = (char *)(void *)(ifam + 1);
+			get_addrs(ifam->ifam_addrs, cp, rti_info);
+			if (rti_info[RTAX_IFA] == NULL)
+				break;
+			switch (rti_info[RTAX_IFA]->sa_family) {
+			case AF_LINK:
+#ifdef RTM_CHGADDR
+				if (rtm->rtm_type != RTM_CHGADDR)
+					break;
+#else
+				if (rtm->rtm_type != RTM_NEWADDR)
+					break;
+#endif
+				memcpy(&sdl, rti_info[RTAX_IFA],
+				    rti_info[RTAX_IFA]->sa_len);
+				dhcpcd_handlehwaddr(ctx, ifp->name,
+				    (const unsigned char*)CLLADDR(&sdl),
+				    sdl.sdl_alen);
+				break;
+#ifdef INET
+			case AF_INET:
+			case 255: /* FIXME: Why 255? */
+				COPYOUT(rt.dest, rti_info[RTAX_IFA]);
+				COPYOUT(rt.net, rti_info[RTAX_NETMASK]);
+				COPYOUT(rt.gate, rti_info[RTAX_BRD]);
+				if (rtm->rtm_type == RTM_NEWADDR) {
+					ifa_flags = if_addrflags(&rt.dest, ifp);
+					if (ifa_flags == -1)
+						break;
+				} else
+					ifa_flags = 0;
+				ipv4_handleifa(ctx, rtm->rtm_type,
+				    NULL, ifp->name,
+				    &rt.dest, &rt.net, &rt.gate, ifa_flags);
+				break;
+#endif
+#ifdef INET6
+			case AF_INET6:
+				sin6 = (struct sockaddr_in6*)(void *)
+				    rti_info[RTAX_IFA];
+				ia6 = sin6->sin6_addr;
+				DESCOPE(&ia6);
+				sin6 = (struct sockaddr_in6*)(void *)
+				    rti_info[RTAX_NETMASK];
+				net6 = sin6->sin6_addr;
+				DESCOPE(&net6);
+				if (rtm->rtm_type == RTM_NEWADDR) {
+					ifa_flags = if_addrflags6(&ia6, ifp);
+					if (ifa_flags == -1)
+						break;
+				} else
+					ifa_flags = 0;
+				ipv6_handleifa(ctx, rtm->rtm_type, NULL,
+				    ifp->name, &ia6, ipv6_prefixlen(&net6),
+				    ifa_flags);
+				break;
+#endif
+			}
+			break;
+		}
+	}
+	return 0;
+}
+
+#ifndef SYS_NMLN	/* OSX */
+#  define SYS_NMLN 256
+#endif
+#ifndef HW_MACHINE_ARCH
+#  ifdef HW_MODEL	/* OpenBSD */
+#    define HW_MACHINE_ARCH HW_MODEL
+#  endif
+#endif
+int
+if_machinearch(char *str, size_t len)
+{
+	int mib[2] = { CTL_HW, HW_MACHINE_ARCH };
+	char march[SYS_NMLN];
+	size_t marchlen = sizeof(march);
+
+	if (sysctl(mib, sizeof(mib) / sizeof(mib[0]),
+	    march, &marchlen, NULL, 0) != 0)
+		return -1;
+	return snprintf(str, len, ":%s", march);
+}
+
+#ifdef INET6
+#ifdef IPV6CTL_ACCEPT_RTADV
+#define get_inet6_sysctl(code) inet6_sysctl(code, 0, 0)
+#define set_inet6_sysctl(code, val) inet6_sysctl(code, val, 1)
+static int
+inet6_sysctl(int code, int val, int action)
+{
+	int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, 0 };
+	size_t size;
+
+	mib[3] = code;
+	size = sizeof(val);
+	if (action) {
+		if (sysctl(mib, sizeof(mib)/sizeof(mib[0]),
+		    NULL, 0, &val, size) == -1)
+			return -1;
+		return 0;
+	}
+	if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), &val, &size, NULL, 0) == -1)
+		return -1;
+	return val;
+}
+#endif
+
+#ifdef IPV6_MANAGETEMPADDR
+#ifndef IPV6CTL_TEMPVLTIME
+#define get_inet6_sysctlbyname(code) inet6_sysctlbyname(code, 0, 0)
+#define set_inet6_sysctlbyname(code, val) inet6_sysctlbyname(code, val, 1)
+static int
+inet6_sysctlbyname(const char *name, int val, int action)
+{
+	size_t size;
+
+	size = sizeof(val);
+	if (action) {
+		if (sysctlbyname(name, NULL, 0, &val, size) == -1)
+			return -1;
+		return 0;
+	}
+	if (sysctlbyname(name, &val, &size, NULL, 0) == -1)
+		return -1;
+	return val;
+}
+#endif
+
+int
+ip6_use_tempaddr(__unused const char *ifname)
+{
+	int val;
+
+#ifdef IPV6CTL_USETEMPADDR
+	val = get_inet6_sysctl(IPV6CTL_USETEMPADDR);
+#else
+	val = get_inet6_sysctlbyname("net.inet6.ip6.use_tempaddr");
+#endif
+	return val == -1 ? 0 : val;
+}
+
+int
+ip6_temp_preferred_lifetime(__unused const char *ifname)
+{
+	int val;
+
+#ifdef IPV6CTL_TEMPPLTIME
+	val = get_inet6_sysctl(IPV6CTL_TEMPPLTIME);
+#else
+	val = get_inet6_sysctlbyname("net.inet6.ip6.temppltime");
+#endif
+	return val < 0 ? TEMP_PREFERRED_LIFETIME : val;
+}
+
+int
+ip6_temp_valid_lifetime(__unused const char *ifname)
+{
+	int val;
+
+#ifdef IPV6CTL_TEMPVLTIME
+	val = get_inet6_sysctl(IPV6CTL_TEMPVLTIME);
+#else
+	val = get_inet6_sysctlbyname("net.inet6.ip6.tempvltime");
+#endif
+	return val < 0 ? TEMP_VALID_LIFETIME : val;
+}
+#endif
+
+#define del_if_nd6_flag(s, ifname, flag) if_nd6_flag((s), (ifp), (flag), -1)
+#define get_if_nd6_flag(s, ifname, flag) if_nd6_flag((s), (ifp), (flag),  0)
+#define set_if_nd6_flag(s, ifname, flag) if_nd6_flag((s), (ifp), (flag),  1)
+static int
+if_nd6_flag(int s, const struct interface *ifp, unsigned int flag, int set)
+{
+	struct in6_ndireq nd;
+	unsigned int oflags;
+
+	memset(&nd, 0, sizeof(nd));
+	strlcpy(nd.ifname, ifp->name, sizeof(nd.ifname));
+	if (ioctl(s, SIOCGIFINFO_IN6, &nd) == -1)
+		return -1;
+	if (set == 0)
+		return nd.ndi.flags & flag ? 1 : 0;
+
+	oflags = nd.ndi.flags;
+	if (set == -1)
+		nd.ndi.flags &= ~flag;
+	else
+		nd.ndi.flags |= flag;
+	if (oflags == nd.ndi.flags)
+		return 0;
+	return ioctl(s, SIOCSIFINFO_FLAGS, &nd);
+}
+
+static int
+if_raflush(int s)
+{
+	char dummy[IFNAMSIZ + 8];
+
+	strlcpy(dummy, "lo0", sizeof(dummy));
+	if (ioctl(s, SIOCSRTRFLUSH_IN6, (void *)&dummy) == -1 ||
+	    ioctl(s, SIOCSPFXFLUSH_IN6, (void *)&dummy) == -1)
+		return -1;
+	return 0;
+}
+
+#ifdef SIOCIFAFATTACH
+static int
+af_attach(int s, const struct interface *ifp, int af)
+{
+	struct if_afreq ifar;
+
+	strlcpy(ifar.ifar_name, ifp->name, sizeof(ifar.ifar_name));
+	ifar.ifar_af = af;
+	return ioctl(s, SIOCIFAFATTACH, (void *)&ifar);
+}
+#endif
+
+#ifdef SIOCGIFXFLAGS
+static int
+set_ifxflags(int s, const struct interface *ifp, int own)
+{
+	struct ifreq ifr;
+	int flags;
+
+#ifndef IFXF_NOINET6
+	/* No point in removing the no inet6 flag if it doesn't
+	 * exist and we're not owning inet6. */
+	if (! own)
+		return 0;
+#endif
+
+	strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
+	if (ioctl(s, SIOCGIFXFLAGS, (void *)&ifr) == -1)
+		return -1;
+	flags = ifr.ifr_flags;
+#ifdef IFXF_NOINET6
+	flags &= ~IFXF_NOINET6;
+#endif
+	if (own)
+		flags &= ~IFXF_AUTOCONF6;
+	if (ifr.ifr_flags == flags)
+		return 0;
+	ifr.ifr_flags = flags;
+	return ioctl(s, SIOCSIFXFLAGS, (void *)&ifr);
+}
+#endif
+
+static int
+_if_checkipv6(int s, struct dhcpcd_ctx *ctx,
+    const struct interface *ifp, int own)
+{
+	int ra;
+
+	if (ifp) {
+#ifdef ND6_IFF_OVERRIDE_RTADV
+		int override;
+#endif
+
+#ifdef ND6_IFF_IFDISABLED
+		if (del_if_nd6_flag(s, ifp, ND6_IFF_IFDISABLED) == -1) {
+			logger(ifp->ctx, LOG_ERR,
+			    "%s: del_if_nd6_flag: ND6_IFF_IFDISABLED: %m",
+			    ifp->name);
+			return -1;
+		}
+#endif
+
+#ifdef ND6_IFF_PERFORMNUD
+		if (set_if_nd6_flag(s, ifp, ND6_IFF_PERFORMNUD) == -1) {
+			logger(ifp->ctx, LOG_ERR,
+			    "%s: set_if_nd6_flag: ND6_IFF_PERFORMNUD: %m",
+			    ifp->name);
+			return -1;
+		}
+#endif
+
+#ifdef ND6_IFF_AUTO_LINKLOCAL
+		if (own) {
+			int all;
+
+			all = get_if_nd6_flag(s, ifp, ND6_IFF_AUTO_LINKLOCAL);
+			if (all == -1)
+				logger(ifp->ctx, LOG_ERR,
+				    "%s: get_if_nd6_flag: "
+				    "ND6_IFF_AUTO_LINKLOCAL: %m",
+				    ifp->name);
+			else if (all != 0) {
+				logger(ifp->ctx, LOG_DEBUG,
+				    "%s: disabling Kernel IPv6 "
+				    "auto link-local support",
+				    ifp->name);
+				if (del_if_nd6_flag(s, ifp,
+				    ND6_IFF_AUTO_LINKLOCAL) == -1)
+				{
+					logger(ifp->ctx, LOG_ERR,
+					    "%s: del_if_nd6_flag: "
+					    "ND6_IFF_AUTO_LINKLOCAL: %m",
+					    ifp->name);
+					return -1;
+				}
+			}
+		}
+#endif
+
+#ifdef SIOCIFAFATTACH
+		if (af_attach(s, ifp, AF_INET6) == -1) {
+			logger(ifp->ctx, LOG_ERR,
+			    "%s: af_attach: %m", ifp->name);
+			return 1;
+		}
+#endif
+
+#ifdef SIOCGIFXFLAGS
+		if (set_ifxflags(s, ifp, own) == -1) {
+			logger(ifp->ctx, LOG_ERR,
+			    "%s: set_ifxflags: %m", ifp->name);
+			return -1;
+		}
+#endif
+
+#ifdef ND6_IFF_OVERRIDE_RTADV
+		override = get_if_nd6_flag(s, ifp, ND6_IFF_OVERRIDE_RTADV);
+		if (override == -1)
+			logger(ifp->ctx, LOG_ERR,
+			    "%s: get_if_nd6_flag: ND6_IFF_OVERRIDE_RTADV: %m",
+			    ifp->name);
+		else if (override == 0 && own) {
+			if (set_if_nd6_flag(s, ifp, ND6_IFF_OVERRIDE_RTADV)
+			    == -1)
+				logger(ifp->ctx, LOG_ERR,
+				    "%s: set_if_nd6_flag: "
+				    "ND6_IFF_OVERRIDE_RTADV: %m",
+				    ifp->name);
+			else
+				override = 1;
+		}
+#endif
+
+#ifdef ND6_IFF_ACCEPT_RTADV
+		ra = get_if_nd6_flag(s, ifp, ND6_IFF_ACCEPT_RTADV);
+		if (ra == -1)
+			logger(ifp->ctx, LOG_ERR,
+			    "%s: get_if_nd6_flag: ND6_IFF_ACCEPT_RTADV: %m",
+			    ifp->name);
+		else if (ra != 0 && own) {
+			logger(ifp->ctx, LOG_DEBUG,
+			    "%s: disabling Kernel IPv6 RA support",
+			    ifp->name);
+			if (del_if_nd6_flag(s, ifp, ND6_IFF_ACCEPT_RTADV)
+			    == -1)
+				logger(ifp->ctx, LOG_ERR,
+				    "%s: del_if_nd6_flag: "
+				    "ND6_IFF_ACCEPT_RTADV: %m",
+				    ifp->name);
+			else
+				ra = 0;
+		} else if (ra == 0 && !own)
+			logger(ifp->ctx, LOG_WARNING,
+			    "%s: IPv6 kernel autoconf disabled", ifp->name);
+#ifdef ND6_IFF_OVERRIDE_RTADV
+		if (override == 0 && ra)
+			return ctx->ra_global;
+#endif
+		return ra;
+#else
+		return ctx->ra_global;
+#endif
+	}
+
+#ifdef IPV6CTL_ACCEPT_RTADV
+	ra = get_inet6_sysctl(IPV6CTL_ACCEPT_RTADV);
+	if (ra == -1)
+		/* The sysctl probably doesn't exist, but this isn't an
+		 * error as such so just log it and continue */
+		logger(ifp->ctx, errno == ENOENT ? LOG_DEBUG : LOG_WARNING,
+		    "IPV6CTL_ACCEPT_RTADV: %m");
+	else if (ra != 0 && own) {
+		logger(ifp->ctx, LOG_DEBUG, "disabling Kernel IPv6 RA support");
+		if (set_inet6_sysctl(IPV6CTL_ACCEPT_RTADV, 0) == -1) {
+			logger(ifp->ctx, LOG_ERR, "IPV6CTL_ACCEPT_RTADV: %m");
+			return ra;
+		}
+		ra = 0;
+#else
+	ra = 0;
+	if (own) {
+#endif
+		/* Flush the kernel knowledge of advertised routers
+		 * and prefixes so the kernel does not expire prefixes
+		 * and default routes we are trying to own. */
+		if (if_raflush(s) == -1)
+			logger(ctx, LOG_WARNING, "if_raflush: %m");
+	}
+
+	ctx->ra_global = ra;
+	return ra;
+}
+
+int
+if_checkipv6(struct dhcpcd_ctx *ctx, const struct interface *ifp, int own)
+{
+	int s, r;
+
+	if ((s = socket(PF_INET6, SOCK_DGRAM, 0)) == -1)
+		return -1;
+	r = _if_checkipv6(s, ctx, ifp, own);
+	close(s);
+	return r;
+}
+#endif
diff --git a/dhcpcd-6.8.2/if-linux-wext.c b/dhcpcd-6.8.2/if-linux-wext.c
new file mode 100644
index 0000000..860cba9
--- /dev/null
+++ b/dhcpcd-6.8.2/if-linux-wext.c
@@ -0,0 +1,90 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2009-2015 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * THIS IS A NASTY HACK THAT SHOULD NEVER HAVE HAPPENED
+ * Basically we cannot include linux/if.h and net/if.h because
+ * they have conflicting structures.
+ * Sadly, linux/wireless.h includes linux/if.h all the time.
+ * Some kernel-header installs fix this and some do not.
+ * This file solely exists for those who do not.
+ *
+ * We *could* include wireless.h as that is designed for userspace,
+ * but that then depends on the correct version of wireless-tools being
+ * installed which isn't always the case.
+ */
+
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <linux/types.h>
+#include <linux/rtnetlink.h>
+/* Support older kernels */
+#ifdef IFLA_WIRELESS
+# include <linux/if.h>
+# include <linux/wireless.h>
+#else
+# define IFLA_WIRELESS (IFLA_MASTER + 1)
+#endif
+
+#include <string.h>
+#include <unistd.h>
+
+#include "config.h"
+
+/* We can't include if.h or dhcpcd.h because
+ * they would pull in net/if.h, which defeats the purpose of this hack. */
+#define IF_SSIDSIZE 33
+int if_getssid_wext(const char *ifname, uint8_t *ssid);
+
+int
+if_getssid_wext(const char *ifname, uint8_t *ssid)
+{
+#ifdef SIOCGIWESSID
+	int s, retval;
+	struct iwreq iwr;
+
+	if ((s = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
+		return -1;
+	memset(&iwr, 0, sizeof(iwr));
+	strlcpy(iwr.ifr_name, ifname, sizeof(iwr.ifr_name));
+	iwr.u.essid.pointer = ssid;
+	iwr.u.essid.length = IF_SSIDSIZE - 1;
+
+	if (ioctl(s, SIOCGIWESSID, &iwr) == 0) {
+		retval = iwr.u.essid.length;
+		ssid[retval] = '\0';
+	} else
+		retval = -1;
+	close(s);
+	return retval;
+#else
+	/* Stop gcc warning about unused parameters */
+	ifname = ssid;
+	return -1;
+#endif
+}
diff --git a/dhcpcd-6.8.2/if-linux.c b/dhcpcd-6.8.2/if-linux.c
new file mode 100644
index 0000000..e4847c6
--- /dev/null
+++ b/dhcpcd-6.8.2/if-linux.c
@@ -0,0 +1,1818 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <asm/types.h> /* Needed for 2.4 kernels */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/param.h>
+
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
+#include <linux/if_packet.h>
+#include <linux/filter.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+
+#include <arpa/inet.h>
+#include <net/if.h>
+#include <netinet/if_ether.h>
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <net/route.h>
+
+/* Support older kernels */
+#ifndef IFLA_WIRELESS
+# define IFLA_WIRELESS (IFLA_MASTER + 1)
+#endif
+
+/* Linux has these in an enum and there is just no way to work
+ * out of they exist at compile time. Silly silly silly. */
+#define IFLA_AF_SPEC			26
+#define IFLA_INET6_ADDR_GEN_MODE	8
+#define IN6_ADDR_GEN_MODE_NONE		1
+
+/* For some reason, glibc doesn't include newer flags from linux/if.h
+ * However, we cannot include linux/if.h directly as it conflicts
+ * with the glibc version. D'oh! */
+#ifndef IFF_LOWER_UP
+#define IFF_LOWER_UP	0x10000		/* driver signals L1 up		*/
+#endif
+
+#include <errno.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "config.h"
+#include "common.h"
+#include "dev.h"
+#include "dhcp.h"
+#include "if.h"
+#include "ipv4.h"
+#include "ipv6.h"
+#include "ipv6nd.h"
+
+#ifdef HAVE_NL80211_H
+#include <linux/genetlink.h>
+#include <linux/nl80211.h>
+#endif
+int if_getssid_wext(const char *ifname, uint8_t *ssid);
+
+#define bpf_insn		sock_filter
+#define BPF_SKIPTYPE
+#define BPF_ETHCOOK		-ETH_HLEN
+#define BPF_WHOLEPACKET	0x0fffffff /* work around buggy LPF filters */
+
+#include "bpf-filter.h"
+
+/* Broadcast address for IPoIB */
+static const uint8_t ipv4_bcast_addr[] = {
+	0x00, 0xff, 0xff, 0xff,
+	0xff, 0x12, 0x40, 0x1b, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff
+};
+
+#define PROC_INET6	"/proc/net/if_inet6"
+#define PROC_PROMOTE	"/proc/sys/net/ipv4/conf/%s/promote_secondaries"
+#define SYS_LAYER2	"/sys/class/net/%s/device/layer2"
+
+static const char *mproc =
+#if defined(__alpha__)
+	"system type"
+#elif defined(__arm__)
+	"Hardware"
+#elif defined(__avr32__)
+	"cpu family"
+#elif defined(__bfin__)
+	"BOARD Name"
+#elif defined(__cris__)
+	"cpu model"
+#elif defined(__frv__)
+	"System"
+#elif defined(__i386__) || defined(__x86_64__)
+	"vendor_id"
+#elif defined(__ia64__)
+	"vendor"
+#elif defined(__hppa__)
+	"model"
+#elif defined(__m68k__)
+	"MMU"
+#elif defined(__mips__)
+	"system type"
+#elif defined(__powerpc__) || defined(__powerpc64__)
+	"machine"
+#elif defined(__s390__) || defined(__s390x__)
+	"Manufacturer"
+#elif defined(__sh__)
+	"machine"
+#elif defined(sparc) || defined(__sparc__)
+	"cpu"
+#elif defined(__vax__)
+	"cpu"
+#else
+	NULL
+#endif
+	;
+
+int
+if_machinearch(char *str, size_t len)
+{
+	FILE *fp;
+	char buf[256];
+
+	if (mproc == NULL) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	fp = fopen("/proc/cpuinfo", "r");
+	if (fp == NULL)
+		return -1;
+
+	while (fscanf(fp, "%255s : ", buf) != EOF) {
+		if (strncmp(buf, mproc, strlen(mproc)) == 0 &&
+		    fscanf(fp, "%255s", buf) == 1)
+		{
+		        fclose(fp);
+			return snprintf(str, len, ":%s", buf);
+		}
+	}
+	fclose(fp);
+	errno = ESRCH;
+	return -1;
+}
+
+static int
+check_proc_int(const char *path)
+{
+	FILE *fp;
+	int i;
+
+	fp = fopen(path, "r");
+	if (fp == NULL)
+		return -1;
+	if (fscanf(fp, "%d", &i) != 1)
+		i = -1;
+	fclose(fp);
+	return i;
+}
+
+static ssize_t
+write_path(const char *path, const char *val)
+{
+	FILE *fp;
+	ssize_t r;
+
+	fp = fopen(path, "w");
+	if (fp == NULL)
+		return -1;
+	r = fprintf(fp, "%s\n", val);
+	fclose(fp);
+	return r;
+}
+
+int
+if_init(struct interface *ifp)
+{
+	char path[sizeof(PROC_PROMOTE) + IF_NAMESIZE];
+	int n;
+
+	/* We enable promote_secondaries so that we can do this
+	 * add 192.168.1.2/24
+	 * add 192.168.1.3/24
+	 * del 192.168.1.2/24
+	 * and the subnet mask moves onto 192.168.1.3/24
+	 * This matches the behaviour of BSD which makes coding dhcpcd
+	 * a little easier as there's just one behaviour. */
+	snprintf(path, sizeof(path), PROC_PROMOTE, ifp->name);
+	n = check_proc_int(path);
+	if (n == -1)
+		return errno == ENOENT ? 0 : -1;
+	if (n == 1)
+		return 0;
+	return write_path(path, "1") == -1 ? -1 : 0;
+}
+
+int
+if_conf(struct interface *ifp)
+{
+	char path[sizeof(SYS_LAYER2) + IF_NAMESIZE];
+	int n;
+
+	/* Some qeth setups require the use of the broadcast flag. */
+	snprintf(path, sizeof(path), SYS_LAYER2, ifp->name);
+	n = check_proc_int(path);
+	if (n == -1)
+		return errno == ENOENT ? 0 : -1;
+	if (n == 0)
+		ifp->options->options |= DHCPCD_BROADCAST;
+	return 0;
+}
+
+/* XXX work out Virtal Interface Masters */
+int
+if_vimaster(__unused const char *ifname)
+{
+
+	return 0;
+}
+
+static int
+_open_link_socket(struct sockaddr_nl *nl, int flags, int protocol)
+{
+	int fd;
+
+#ifdef SOCK_CLOEXEC
+	if (flags)
+		flags = SOCK_CLOEXEC;
+	fd = socket(AF_NETLINK, SOCK_RAW | flags, protocol);
+	if (fd == -1)
+		return -1;
+#else
+	fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+	if (fd == -1)
+		return -1;
+	if (flags &&
+	    (flags = fcntl(fd, F_GETFD, 0)) == -1 ||
+	    fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
+	{
+		close(fd);
+	        return -1;
+	}
+#endif
+	nl->nl_family = AF_NETLINK;
+	if (bind(fd, (struct sockaddr *)nl, sizeof(*nl)) == -1) {
+		close(fd);
+		return -1;
+	}
+	return fd;
+}
+
+int
+if_openlinksocket(void)
+{
+	struct sockaddr_nl snl;
+
+	memset(&snl, 0, sizeof(snl));
+	snl.nl_groups = RTMGRP_LINK;
+
+#ifdef INET
+	snl.nl_groups |= RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_IFADDR;
+#endif
+#ifdef INET6
+	snl.nl_groups |= RTMGRP_IPV6_ROUTE | RTMGRP_IPV6_IFADDR | RTMGRP_NEIGH;
+#endif
+
+	return _open_link_socket(&snl, 1, NETLINK_ROUTE);
+}
+
+static int
+err_netlink(struct nlmsghdr *nlm)
+{
+	struct nlmsgerr *err;
+	size_t len;
+
+	if (nlm->nlmsg_type != NLMSG_ERROR)
+		return 0;
+	len = nlm->nlmsg_len - sizeof(*nlm);
+	if (len < sizeof(*err)) {
+		errno = EBADMSG;
+		return -1;
+	}
+	err = (struct nlmsgerr *)NLMSG_DATA(nlm);
+	if (err->error == 0)
+		return (int)len;
+	errno = -err->error;
+	return -1;
+}
+
+static int
+get_netlink(struct dhcpcd_ctx *ctx, struct interface *ifp, int fd, int flags,
+    int (*callback)(struct dhcpcd_ctx *, struct interface *, struct nlmsghdr *))
+{
+	char *buf = NULL, *nbuf;
+	ssize_t bytes;
+	size_t buflen;
+	struct nlmsghdr *nlm;
+	struct sockaddr_nl nladdr;
+	socklen_t nladdr_len;
+	int r;
+
+	buflen = 0;
+	r = -1;
+	for (;;) {
+		bytes = recv(fd, NULL, 0,
+		    flags | MSG_PEEK | MSG_DONTWAIT | MSG_TRUNC);
+		if (bytes == -1)
+			goto eexit;
+		if ((size_t)bytes == buflen) {
+			/* Support kernels older than 2.6.22 */
+			if (bytes == 0)
+				bytes = 512;
+			else
+				bytes *= 2;
+		}
+		if (buflen < (size_t)bytes) {
+			/* Alloc 1 more so we work with older kernels */
+			buflen = (size_t)bytes + 1;
+			nbuf = realloc(buf, buflen);
+			if (nbuf == NULL)
+				goto eexit;
+			buf = nbuf;
+		}
+		nladdr_len = sizeof(nladdr);
+		bytes = recvfrom(fd, buf, buflen, flags,
+		    (struct sockaddr *)&nladdr, &nladdr_len);
+		if (bytes == -1 || bytes == 0)
+			goto eexit;
+
+		/* Check sender */
+		if (nladdr_len != sizeof(nladdr)) {
+			errno = EINVAL;
+			goto eexit;
+		}
+		/* Ignore message if it is not from kernel */
+		if (nladdr.nl_pid != 0) {
+			r = 0;
+			continue;
+		}
+
+		for (nlm = (struct nlmsghdr *)(void *)buf;
+		     nlm && NLMSG_OK(nlm, (size_t)bytes);
+		     nlm = NLMSG_NEXT(nlm, bytes))
+		{
+			r = err_netlink(nlm);
+			if (r == -1)
+				goto eexit;
+			if (r)
+				continue;
+			if (callback) {
+				r = callback(ctx, ifp, nlm);
+				if (r != 0)
+					goto eexit;
+			}
+		}
+	}
+
+eexit:
+	free(buf);
+	return r;
+}
+
+#ifdef INET
+static int
+if_copyrt(struct dhcpcd_ctx *ctx, struct rt *rt, struct nlmsghdr *nlm)
+{
+	size_t len;
+	struct rtmsg *rtm;
+	struct rtattr *rta;
+	struct in_addr prefsrc;
+
+	len = nlm->nlmsg_len - sizeof(*nlm);
+	if (len < sizeof(*rtm)) {
+		errno = EBADMSG;
+		return -1;
+	}
+	rtm = (struct rtmsg *)NLMSG_DATA(nlm);
+	if (rtm->rtm_table != RT_TABLE_MAIN || rtm->rtm_family != AF_INET)
+		return -1;
+
+	memset(rt, 0, sizeof(*rt));
+	if (rtm->rtm_type == RTN_UNREACHABLE)
+		rt->flags = RTF_REJECT;
+	if (rtm->rtm_scope == RT_SCOPE_HOST)
+		rt->flags |= RTF_HOST;
+
+	prefsrc.s_addr = INADDR_ANY;
+	rta = (struct rtattr *)RTM_RTA(rtm);
+	len = RTM_PAYLOAD(nlm);
+	while (RTA_OK(rta, len)) {
+		switch (rta->rta_type) {
+		case RTA_DST:
+			memcpy(&rt->dest.s_addr, RTA_DATA(rta),
+			    sizeof(rt->dest.s_addr));
+			break;
+		case RTA_GATEWAY:
+			memcpy(&rt->gate.s_addr, RTA_DATA(rta),
+			    sizeof(rt->gate.s_addr));
+			break;
+		case RTA_PREFSRC:
+			memcpy(&prefsrc.s_addr, RTA_DATA(rta),
+			    sizeof(prefsrc.s_addr));
+			break;
+		case RTA_OIF:
+			rt->iface = if_findindex(ctx->ifaces,
+			    *(unsigned int *)RTA_DATA(rta));
+			break;
+		case RTA_PRIORITY:
+			rt->metric = *(unsigned int *)RTA_DATA(rta);
+			break;
+		}
+		rta = RTA_NEXT(rta, len);
+	}
+
+	inet_cidrtoaddr(rtm->rtm_dst_len, &rt->net);
+	if (rt->iface == NULL && prefsrc.s_addr != INADDR_ANY) {
+		struct ipv4_addr *ap;
+
+		/* For some reason the default route comes back with the
+		 * loopback interface in RTA_OIF? Lets find it by
+		 * preferred source address */
+		if ((ap = ipv4_findaddr(ctx, &prefsrc)))
+			rt->iface = ap->iface;
+	}
+	return 0;
+}
+#endif
+
+#ifdef INET6
+static int
+if_copyrt6(struct dhcpcd_ctx *ctx, struct rt6 *rt, struct nlmsghdr *nlm)
+{
+	size_t len;
+	struct rtmsg *rtm;
+	struct rtattr *rta;
+
+	len = nlm->nlmsg_len - sizeof(*nlm);
+	if (len < sizeof(*rtm)) {
+		errno = EBADMSG;
+		return -1;
+	}
+	rtm = (struct rtmsg *)NLMSG_DATA(nlm);
+	if (rtm->rtm_table != RT_TABLE_MAIN || rtm->rtm_family != AF_INET6)
+		return -1;
+
+	memset(rt, 0, sizeof(*rt));
+	if (rtm->rtm_type == RTN_UNREACHABLE)
+		rt->flags = RTF_REJECT;
+	if (rtm->rtm_scope == RT_SCOPE_HOST)
+		rt->flags |= RTF_HOST;
+	ipv6_mask(&rt->net, rtm->rtm_dst_len);
+
+	rta = (struct rtattr *)RTM_RTA(rtm);
+	len = RTM_PAYLOAD(nlm);
+	while (RTA_OK(rta, len)) {
+		switch (rta->rta_type) {
+		case RTA_DST:
+			memcpy(&rt->dest.s6_addr, RTA_DATA(rta),
+			    sizeof(rt->dest.s6_addr));
+			break;
+		case RTA_GATEWAY:
+			memcpy(&rt->gate.s6_addr, RTA_DATA(rta),
+			    sizeof(rt->gate.s6_addr));
+			break;
+		case RTA_OIF:
+			rt->iface = if_findindex(ctx->ifaces,
+			    *(unsigned int *)RTA_DATA(rta));
+			break;
+		case RTA_PRIORITY:
+			rt->metric = *(unsigned int *)RTA_DATA(rta);
+			break;
+		}
+		rta = RTA_NEXT(rta, len);
+	}
+
+	return 0;
+}
+#endif
+
+/* Work out the maximum pid size */
+static inline long long
+get_max_pid_t()
+{
+
+	if (sizeof(pid_t) == sizeof(short))		return SHRT_MAX;
+	if (sizeof(pid_t) == sizeof(int))		return INT_MAX;
+	if (sizeof(pid_t) == sizeof(long))		return LONG_MAX;
+	if (sizeof(pid_t) == sizeof(long long))		return LLONG_MAX;
+	abort();
+}
+
+static int
+link_route(struct dhcpcd_ctx *ctx, __unused struct interface *ifp,
+    struct nlmsghdr *nlm)
+{
+	size_t len;
+	struct rtmsg *rtm;
+	int cmd;
+#ifdef INET
+	struct rt rt;
+#endif
+#ifdef INET6
+	struct rt6 rt6;
+#endif
+	switch (nlm->nlmsg_type) {
+	case RTM_NEWROUTE:
+		cmd = RTM_ADD;
+		break;
+	case RTM_DELROUTE:
+		cmd = RTM_DELETE;
+		break;
+	default:
+		return 0;
+	}
+
+	len = nlm->nlmsg_len - sizeof(*nlm);
+	if (len < sizeof(*rtm)) {
+		errno = EBADMSG;
+		return -1;
+	}
+
+	/* Ignore messages generated by us.
+	 * For some reason we get messages generated by us
+	 * with a very large value in nlmsg_pid that seems to be
+	 * sequentially changing. Is there a better test for this? */
+	if (nlm->nlmsg_pid > get_max_pid_t())
+		return 1;
+
+	rtm = NLMSG_DATA(nlm);
+	switch (rtm->rtm_family) {
+#ifdef INET
+	case AF_INET:
+		if (if_copyrt(ctx, &rt, nlm) == 0)
+			ipv4_handlert(ctx, cmd, &rt);
+		break;
+#endif
+#ifdef INET6
+	case AF_INET6:
+		if (if_copyrt6(ctx, &rt6, nlm) == 0)
+			ipv6_handlert(ctx, cmd, &rt6);
+		break;
+#endif
+	}
+
+	return 0;
+}
+
+static int
+link_addr(struct dhcpcd_ctx *ctx, struct interface *ifp, struct nlmsghdr *nlm)
+{
+	size_t len;
+	struct rtattr *rta;
+	struct ifaddrmsg *ifa;
+#ifdef INET
+	struct in_addr addr, net, dest;
+#endif
+#ifdef INET6
+	struct in6_addr addr6;
+#endif
+
+	if (nlm->nlmsg_type != RTM_DELADDR && nlm->nlmsg_type != RTM_NEWADDR)
+		return 0;
+
+	len = nlm->nlmsg_len - sizeof(*nlm);
+	if (len < sizeof(*ifa)) {
+		errno = EBADMSG;
+		return -1;
+	}
+	ifa = NLMSG_DATA(nlm);
+	if ((ifp = if_findindex(ctx->ifaces, ifa->ifa_index)) == NULL) {
+		/* We don't know about the interface the address is for
+		 * so it's not really an error */
+		return 1;
+	}
+	rta = (struct rtattr *)IFA_RTA(ifa);
+	len = NLMSG_PAYLOAD(nlm, sizeof(*ifa));
+	switch (ifa->ifa_family) {
+#ifdef INET
+	case AF_INET:
+		addr.s_addr = dest.s_addr = INADDR_ANY;
+		dest.s_addr = INADDR_ANY;
+		inet_cidrtoaddr(ifa->ifa_prefixlen, &net);
+		while (RTA_OK(rta, len)) {
+			switch (rta->rta_type) {
+			case IFA_ADDRESS:
+				if (ifp->flags & IFF_POINTOPOINT) {
+					memcpy(&dest.s_addr, RTA_DATA(rta),
+					       sizeof(addr.s_addr));
+				}
+				break;
+			case IFA_LOCAL:
+				memcpy(&addr.s_addr, RTA_DATA(rta),
+				       sizeof(addr.s_addr));
+				break;
+			}
+			rta = RTA_NEXT(rta, len);
+		}
+		ipv4_handleifa(ctx, nlm->nlmsg_type, NULL, ifp->name,
+		    &addr, &net, &dest, ifa->ifa_flags);
+		break;
+#endif
+#ifdef INET6
+	case AF_INET6:
+		memset(&addr6, 0, sizeof(addr6));
+		while (RTA_OK(rta, len)) {
+			switch (rta->rta_type) {
+			case IFA_ADDRESS:
+				memcpy(&addr6.s6_addr, RTA_DATA(rta),
+				       sizeof(addr6.s6_addr));
+				break;
+			}
+			rta = RTA_NEXT(rta, len);
+		}
+		ipv6_handleifa(ctx, nlm->nlmsg_type, NULL, ifp->name,
+		    &addr6, ifa->ifa_prefixlen, ifa->ifa_flags);
+		break;
+#endif
+	}
+	return 0;
+}
+
+static uint8_t
+l2addr_len(unsigned short if_type)
+{
+
+	switch (if_type) {
+	case ARPHRD_ETHER: /* FALLTHROUGH */
+	case ARPHRD_IEEE802: /*FALLTHROUGH */
+	case ARPHRD_IEEE80211:
+		return 6;
+	case ARPHRD_IEEE1394:
+		return 8;
+	case ARPHRD_INFINIBAND:
+		return 20;
+	}
+
+	/* Impossible */
+	return 0;
+}
+
+static int
+handle_rename(struct dhcpcd_ctx *ctx, unsigned int ifindex, const char *ifname)
+{
+	struct interface *ifp;
+
+	TAILQ_FOREACH(ifp, ctx->ifaces, next) {
+		if (ifp->index == ifindex && strcmp(ifp->name, ifname)) {
+			dhcpcd_handleinterface(ctx, -1, ifp->name);
+			/* Let dev announce the interface for renaming */
+			if (!dev_listening(ctx))
+				dhcpcd_handleinterface(ctx, 1, ifname);
+			return 1;
+		}
+	}
+	return 0;
+}
+
+#ifdef INET6
+static int
+link_neigh(struct dhcpcd_ctx *ctx, __unused struct interface *ifp,
+    struct nlmsghdr *nlm)
+{
+	struct ndmsg *r;
+	struct rtattr *rta;
+	size_t len;
+	struct in6_addr addr6;
+	int flags;
+
+	if (nlm->nlmsg_type != RTM_NEWNEIGH && nlm->nlmsg_type != RTM_DELNEIGH)
+		return 0;
+	if (nlm->nlmsg_len < sizeof(*r))
+		return -1;
+
+	r = NLMSG_DATA(nlm);
+	rta = (struct rtattr *)RTM_RTA(r);
+	len = RTM_PAYLOAD(nlm);
+        if (r->ndm_family == AF_INET6) {
+		flags = 0;
+		if (r->ndm_flags & NTF_ROUTER)
+			flags |= IPV6ND_ROUTER;
+		if (nlm->nlmsg_type == RTM_NEWNEIGH &&
+		    r->ndm_state &
+		    (NUD_REACHABLE | NUD_STALE | NUD_DELAY | NUD_PROBE |
+		     NUD_PERMANENT))
+		        flags |= IPV6ND_REACHABLE;
+		memset(&addr6, 0, sizeof(addr6));
+		while (RTA_OK(rta, len)) {
+			switch (rta->rta_type) {
+			case NDA_DST:
+				memcpy(&addr6.s6_addr, RTA_DATA(rta),
+				       sizeof(addr6.s6_addr));
+				break;
+			}
+			rta = RTA_NEXT(rta, len);
+		}
+		ipv6nd_neighbour(ctx, &addr6, flags);
+	}
+
+	return 0;
+}
+#endif
+
+static int
+link_netlink(struct dhcpcd_ctx *ctx, struct interface *ifp,
+    struct nlmsghdr *nlm)
+{
+	int r;
+	size_t len;
+	struct rtattr *rta, *hwaddr;
+	struct ifinfomsg *ifi;
+	char ifn[IF_NAMESIZE + 1];
+
+	r = link_route(ctx, ifp, nlm);
+	if (r != 0)
+		return r;
+	r = link_addr(ctx, ifp, nlm);
+	if (r != 0)
+		return r;
+#ifdef INET6
+	r = link_neigh(ctx, ifp, nlm);
+	if (r != 0)
+		return r;
+#endif
+
+	if (nlm->nlmsg_type != RTM_NEWLINK && nlm->nlmsg_type != RTM_DELLINK)
+		return 0;
+	len = nlm->nlmsg_len - sizeof(*nlm);
+	if ((size_t)len < sizeof(*ifi)) {
+		errno = EBADMSG;
+		return -1;
+	}
+	ifi = NLMSG_DATA(nlm);
+	if (ifi->ifi_flags & IFF_LOOPBACK)
+		return 0;
+	rta = (struct rtattr *)(void *)((char *)ifi +NLMSG_ALIGN(sizeof(*ifi)));
+	len = NLMSG_PAYLOAD(nlm, sizeof(*ifi));
+	*ifn = '\0';
+	hwaddr = NULL;
+
+	while (RTA_OK(rta, len)) {
+		switch (rta->rta_type) {
+		case IFLA_WIRELESS:
+			/* Ignore wireless messages */
+			if (nlm->nlmsg_type == RTM_NEWLINK &&
+			    ifi->ifi_change == 0)
+				return 0;
+			break;
+		case IFLA_IFNAME:
+			strlcpy(ifn, RTA_DATA(rta), sizeof(ifn));
+			break;
+		case IFLA_ADDRESS:
+			hwaddr = rta;
+			break;
+		}
+		rta = RTA_NEXT(rta, len);
+	}
+
+	if (nlm->nlmsg_type == RTM_DELLINK) {
+		dhcpcd_handleinterface(ctx, -1, ifn);
+		return 0;
+	}
+
+	/* Virtual interfaces may not get a valid hardware address
+	 * at this point.
+	 * To trigger a valid hardware address pickup we need to pretend
+	 * that that don't exist until they have one. */
+	if (ifi->ifi_flags & IFF_MASTER && !hwaddr) {
+		dhcpcd_handleinterface(ctx, -1, ifn);
+		return 0;
+	}
+
+	/* Check for interface name change */
+	if (handle_rename(ctx, (unsigned int)ifi->ifi_index, ifn))
+		return 0;
+
+	/* Check for a new interface */
+	if ((ifp = if_find(ctx->ifaces, ifn)) == NULL) {
+		/* If are listening to a dev manager, let that announce
+		 * the interface rather than the kernel. */
+		if (dev_listening(ctx) < 1)
+			dhcpcd_handleinterface(ctx, 1, ifn);
+		return 0;
+	}
+
+	/* Re-read hardware address and friends */
+	if (!(ifi->ifi_flags & IFF_UP) && hwaddr) {
+		uint8_t l;
+
+		l = l2addr_len(ifi->ifi_type);
+		if (hwaddr->rta_len == RTA_LENGTH(l))
+			dhcpcd_handlehwaddr(ctx, ifn, RTA_DATA(hwaddr), l);
+	}
+
+	dhcpcd_handlecarrier(ctx,
+	    ifi->ifi_flags & IFF_RUNNING ? LINK_UP : LINK_DOWN,
+	    ifi->ifi_flags, ifn);
+	return 0;
+}
+
+int
+if_managelink(struct dhcpcd_ctx *ctx)
+{
+
+	return get_netlink(ctx, NULL,
+	    ctx->link_fd, MSG_DONTWAIT, &link_netlink);
+}
+
+static int
+send_netlink(struct dhcpcd_ctx *ctx, struct interface *ifp,
+    int protocol, struct nlmsghdr *hdr,
+    int (*callback)(struct dhcpcd_ctx *, struct interface *, struct nlmsghdr *))
+{
+	int s, r;
+	struct sockaddr_nl snl;
+	struct iovec iov;
+	struct msghdr msg;
+	static unsigned int seq;
+
+	memset(&snl, 0, sizeof(snl));
+	if ((s = _open_link_socket(&snl, 0, protocol)) == -1)
+		return -1;
+	memset(&iov, 0, sizeof(iov));
+	iov.iov_base = hdr;
+	iov.iov_len = hdr->nlmsg_len;
+	memset(&msg, 0, sizeof(msg));
+	msg.msg_name = &snl;
+	msg.msg_namelen = sizeof(snl);
+	msg.msg_iov = &iov;
+	msg.msg_iovlen = 1;
+	/* Request a reply */
+	hdr->nlmsg_flags |= NLM_F_ACK;
+	hdr->nlmsg_seq = ++seq;
+
+	if (sendmsg(s, &msg, 0) != -1)
+		r = get_netlink(ctx, ifp, s, 0, callback);
+	else
+		r = -1;
+	close(s);
+	return r;
+}
+
+#define NLMSG_TAIL(nmsg)						\
+	((struct rtattr *)(((ptrdiff_t)(nmsg))+NLMSG_ALIGN((nmsg)->nlmsg_len)))
+
+static int
+add_attr_l(struct nlmsghdr *n, unsigned short maxlen, unsigned short type,
+    const void *data, unsigned short alen)
+{
+	unsigned short len = (unsigned short)RTA_LENGTH(alen);
+	struct rtattr *rta;
+
+	if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) {
+		errno = ENOBUFS;
+		return -1;
+	}
+
+	rta = NLMSG_TAIL(n);
+	rta->rta_type = type;
+	rta->rta_len = len;
+	if (alen)
+		memcpy(RTA_DATA(rta), data, alen);
+	n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
+
+	return 0;
+}
+
+static int
+add_attr_32(struct nlmsghdr *n, unsigned short maxlen, unsigned short type,
+    uint32_t data)
+{
+	unsigned short len = RTA_LENGTH(sizeof(data));
+	struct rtattr *rta;
+
+	if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen) {
+		errno = ENOBUFS;
+		return -1;
+	}
+
+	rta = NLMSG_TAIL(n);
+	rta->rta_type = type;
+	rta->rta_len = len;
+	memcpy(RTA_DATA(rta), &data, sizeof(data));
+	n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len;
+
+	return 0;
+}
+
+#ifdef HAVE_NL80211_H
+static struct nlattr *
+nla_next(struct nlattr *nla, size_t *rem)
+{
+
+	*rem -= NLA_ALIGN(nla->nla_len);
+	return (struct nlattr *)(void *)((char *)nla + NLA_ALIGN(nla->nla_len));
+}
+
+#define NLA_TYPE(nla) ((nla)->nla_type & NLA_TYPE_MASK)
+#define NLA_LEN(nla) (unsigned int)((nla)->nla_len - NLA_HDRLEN)
+#define NLA_OK(nla, rem) \
+	((rem) >= sizeof(struct nlattr) && \
+	(nla)->nla_len >= sizeof(struct nlattr) && \
+	(nla)->nla_len <= rem)
+#define NLA_DATA(nla) ((char *)(nla) + NLA_HDRLEN)
+#define NLA_FOR_EACH_ATTR(pos, head, len, rem) \
+	for (pos = head, rem = len; NLA_OK(pos, rem); pos = nla_next(pos, &(rem)))
+
+struct nlmg
+{
+	struct nlmsghdr hdr;
+	struct genlmsghdr ghdr;
+	char buffer[64];
+};
+
+static int
+nla_put_32(struct nlmsghdr *n, unsigned short maxlen,
+    unsigned short type, uint32_t data)
+{
+	unsigned short len;
+	struct nlattr *nla;
+
+	len = NLA_ALIGN(NLA_HDRLEN + sizeof(data));
+	if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen) {
+		errno = ENOBUFS;
+		return -1;
+	}
+
+	nla = (struct nlattr *)NLMSG_TAIL(n);
+	nla->nla_type = type;
+	nla->nla_len = len;
+	memcpy(NLA_DATA(nla), &data, sizeof(data));
+	n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len;
+
+	return 0;
+}
+
+static int
+nla_put_string(struct nlmsghdr *n, unsigned short maxlen,
+    unsigned short type, const char *data)
+{
+	struct nlattr *nla;
+	size_t len, sl;
+
+	sl = strlen(data) + 1;
+	len = NLA_ALIGN(NLA_HDRLEN + sl);
+	if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen) {
+		errno = ENOBUFS;
+		return -1;
+	}
+
+	nla = (struct nlattr *)NLMSG_TAIL(n);
+	nla->nla_type = type;
+	nla->nla_len = (unsigned short)len;
+	memcpy(NLA_DATA(nla), data, sl);
+	n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + (unsigned short)len;
+	return 0;
+}
+
+static int
+gnl_parse(struct nlmsghdr *nlm, struct nlattr *tb[], int maxtype)
+{
+	struct genlmsghdr *ghdr;
+	struct nlattr *head, *nla;
+	size_t len, rem;
+	int type;
+
+	memset(tb, 0, sizeof(*tb) * ((unsigned int)maxtype + 1));
+	ghdr = NLMSG_DATA(nlm);
+	head = (struct nlattr *)(void *)((char *) ghdr + GENL_HDRLEN);
+	len = nlm->nlmsg_len - GENL_HDRLEN - NLMSG_HDRLEN;
+	NLA_FOR_EACH_ATTR(nla, head, len, rem) {
+		type = NLA_TYPE(nla);
+		if (type > maxtype)
+			continue;
+		tb[type] = nla;
+	}
+	return 0;
+}
+
+static int
+_gnl_getfamily(__unused struct dhcpcd_ctx *ctx, __unused struct interface *ifp,
+    struct nlmsghdr *nlm)
+{
+	struct nlattr *tb[CTRL_ATTR_FAMILY_ID + 1];
+	uint16_t family;
+
+	if (gnl_parse(nlm, tb, CTRL_ATTR_FAMILY_ID) == -1)
+		return -1;
+	if (tb[CTRL_ATTR_FAMILY_ID] == NULL) {
+		errno = ENOENT;
+		return -1;
+	}
+	family = *(uint16_t *)(void *)NLA_DATA(tb[CTRL_ATTR_FAMILY_ID]);
+	return (int)family;
+}
+
+static int
+gnl_getfamily(struct dhcpcd_ctx *ctx, const char *name)
+{
+	struct nlmg nlm;
+
+	memset(&nlm, 0, sizeof(nlm));
+	nlm.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct genlmsghdr));
+	nlm.hdr.nlmsg_type = GENL_ID_CTRL;
+	nlm.hdr.nlmsg_flags = NLM_F_REQUEST;
+	nlm.ghdr.cmd = CTRL_CMD_GETFAMILY;
+	nlm.ghdr.version = 1;
+	if (nla_put_string(&nlm.hdr, sizeof(nlm),
+	    CTRL_ATTR_FAMILY_NAME, name) == -1)
+		return -1;
+	return send_netlink(ctx, NULL, NETLINK_GENERIC, &nlm.hdr,
+	    &_gnl_getfamily);
+}
+
+static int
+_if_getssid(__unused struct dhcpcd_ctx *ctx, struct interface *ifp,
+    struct nlmsghdr *nlm)
+{
+	struct nlattr *tb[NL80211_ATTR_SSID + 1];
+
+	if (gnl_parse(nlm, tb, NL80211_ATTR_SSID) == -1)
+		return -1;
+
+	if (tb[NL80211_ATTR_SSID] == NULL) {
+		/* If the SSID is not found then it means that
+		 * we're not associated to an AP. */
+		ifp->ssid_len = 0;
+		goto out;
+	}
+
+	ifp->ssid_len = NLA_LEN(tb[NL80211_ATTR_SSID]);
+	if (ifp->ssid_len > sizeof(ifp->ssid)) {
+		errno = ENOBUFS;
+		ifp->ssid_len = 0;
+		return -1;
+	}
+	memcpy(ifp->ssid, NLA_DATA(tb[NL80211_ATTR_SSID]), ifp->ssid_len);
+
+out:
+	ifp->ssid[ifp->ssid_len] = '\0';
+	return (int)ifp->ssid_len;
+}
+
+static int
+if_getssid_nl80211(struct interface *ifp)
+{
+	int family;
+	struct nlmg nlm;
+
+	errno = 0;
+	family = gnl_getfamily(ifp->ctx, "nl80211");
+	if (family == -1)
+		return -1;
+	memset(&nlm, 0, sizeof(nlm));
+	nlm.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct genlmsghdr));
+	nlm.hdr.nlmsg_type = (unsigned short)family;
+	nlm.hdr.nlmsg_flags = NLM_F_REQUEST;
+	nlm.ghdr.cmd = NL80211_CMD_GET_INTERFACE;
+	nla_put_32(&nlm.hdr, sizeof(nlm), NL80211_ATTR_IFINDEX, ifp->index);
+
+	return send_netlink(ifp->ctx, ifp,
+	    NETLINK_GENERIC, &nlm.hdr, &_if_getssid);
+}
+#endif
+
+int
+if_getssid(struct interface *ifp)
+{
+	int r;
+
+	r = if_getssid_wext(ifp->name, ifp->ssid);
+	if (r != -1)
+		ifp->ssid_len = (unsigned int)r;
+#ifdef HAVE_NL80211_H
+	else if (r == -1)
+		r = if_getssid_nl80211(ifp);
+#endif
+	return r;
+}
+
+struct nlma
+{
+	struct nlmsghdr hdr;
+	struct ifaddrmsg ifa;
+	char buffer[64];
+};
+
+struct nlmr
+{
+	struct nlmsghdr hdr;
+	struct rtmsg rt;
+	char buffer[256];
+};
+
+#ifdef INET
+const char *if_pfname = "Packet Socket";
+
+int
+if_openrawsocket(struct interface *ifp, uint16_t protocol)
+{
+	int s;
+	union sockunion {
+		struct sockaddr sa;
+		struct sockaddr_ll sll;
+		struct sockaddr_storage ss;
+	} su;
+	struct sock_fprog pf;
+#ifdef PACKET_AUXDATA
+	int n;
+#endif
+
+#ifdef SOCK_CLOEXEC
+	if ((s = socket(PF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
+	    htons(protocol))) == -1)
+		return -1;
+#else
+	int flags;
+
+	if ((s = socket(PF_PACKET, SOCK_DGRAM, htons(protocol))) == -1)
+		return -1;
+	if ((flags = fcntl(s, F_GETFD, 0)) == -1 ||
+	    fcntl(s, F_SETFD, flags | FD_CLOEXEC) == -1)
+	{
+		close(s);
+	        return -1;
+	}
+	if ((flags = fcntl(s, F_GETFL, 0)) == -1 ||
+	    fcntl(s, F_SETFL, flags | O_NONBLOCK) == -1)
+	{
+		close(s);
+	        return -1;
+	}
+#endif
+	/* Install the DHCP filter */
+	memset(&pf, 0, sizeof(pf));
+	if (protocol == ETHERTYPE_ARP) {
+		pf.filter = UNCONST(arp_bpf_filter);
+		pf.len = arp_bpf_filter_len;
+	} else {
+		pf.filter = UNCONST(dhcp_bpf_filter);
+		pf.len = dhcp_bpf_filter_len;
+	}
+	if (setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, &pf, sizeof(pf)) != 0)
+		goto eexit;
+#ifdef PACKET_AUXDATA
+	n = 1;
+	if (setsockopt(s, SOL_PACKET, PACKET_AUXDATA, &n, sizeof(n)) != 0) {
+		if (errno != ENOPROTOOPT)
+			goto eexit;
+	}
+#endif
+
+	memset(&su, 0, sizeof(su));
+	su.sll.sll_family = PF_PACKET;
+	su.sll.sll_protocol = htons(protocol);
+	su.sll.sll_ifindex = (int)ifp->index;
+	if (bind(s, &su.sa, sizeof(su.sll)) == -1)
+		goto eexit;
+	return s;
+
+eexit:
+	close(s);
+	return -1;
+}
+
+ssize_t
+if_sendrawpacket(const struct interface *ifp, uint16_t protocol,
+    const void *data, size_t len, const uint8_t *dest_hw_addr)
+{
+	const struct dhcp_state *state;
+	union sockunion {
+		struct sockaddr sa;
+		struct sockaddr_ll sll;
+		struct sockaddr_storage ss;
+	} su;
+	int fd;
+
+	memset(&su, 0, sizeof(su));
+	su.sll.sll_family = AF_PACKET;
+	su.sll.sll_protocol = htons(protocol);
+	su.sll.sll_ifindex = (int)ifp->index;
+	su.sll.sll_hatype = htons(ifp->family);
+	su.sll.sll_halen = (unsigned char)ifp->hwlen;
+	if (ifp->family == ARPHRD_INFINIBAND)
+		memcpy(&su.sll.sll_addr,
+		    &ipv4_bcast_addr, sizeof(ipv4_bcast_addr));
+	else {
+		if (dest_hw_addr)
+			memcpy(&su.sll.sll_addr, dest_hw_addr, ifp->hwlen);
+		else
+			memset(&su.sll.sll_addr, 0xff, ifp->hwlen);
+	}
+	state = D_CSTATE(ifp);
+	if (protocol == ETHERTYPE_ARP)
+		fd = state->arp_fd;
+	else
+		fd = state->raw_fd;
+
+	return sendto(fd, data, len, 0, &su.sa, sizeof(su.sll));
+}
+
+ssize_t
+if_readrawpacket(struct interface *ifp, uint16_t protocol,
+    void *data, size_t len, int *flags)
+{
+	struct iovec iov = {
+		.iov_base = data,
+		.iov_len = len,
+	};
+	struct msghdr msg = {
+		.msg_iov = &iov,
+		.msg_iovlen = 1,
+	};
+	struct dhcp_state *state;
+#ifdef PACKET_AUXDATA
+	unsigned char cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))];
+	struct cmsghdr *cmsg;
+	struct tpacket_auxdata *aux;
+#endif
+
+	ssize_t bytes;
+	int fd = -1;
+
+#ifdef PACKET_AUXDATA
+	msg.msg_control = cmsgbuf;
+	msg.msg_controllen = sizeof(cmsgbuf);
+#endif
+
+	state = D_STATE(ifp);
+	if (protocol == ETHERTYPE_ARP)
+		fd = state->arp_fd;
+	else
+		fd = state->raw_fd;
+	bytes = recvmsg(fd, &msg, 0);
+	if (bytes == -1)
+		return -1;
+	*flags = RAW_EOF; /* We only ever read one packet */
+	if (bytes) {
+#ifdef PACKET_AUXDATA
+		for (cmsg = CMSG_FIRSTHDR(&msg);
+		     cmsg;
+		     cmsg = CMSG_NXTHDR(&msg, cmsg))
+		{
+			if (cmsg->cmsg_level == SOL_PACKET &&
+			    cmsg->cmsg_type == PACKET_AUXDATA) {
+				aux = (void *)CMSG_DATA(cmsg);
+				if (aux->tp_status & TP_STATUS_CSUMNOTREADY)
+					*flags |= RAW_PARTIALCSUM;
+			}
+		}
+#endif
+	}
+	return bytes;
+}
+
+int
+if_address(const struct interface *iface,
+    const struct in_addr *address, const struct in_addr *netmask,
+    const struct in_addr *broadcast, int action)
+{
+	struct nlma nlm;
+	int retval = 0;
+
+	memset(&nlm, 0, sizeof(nlm));
+	nlm.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
+	nlm.hdr.nlmsg_flags = NLM_F_REQUEST;
+	if (action >= 0) {
+		nlm.hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE;
+		nlm.hdr.nlmsg_type = RTM_NEWADDR;
+	} else
+		nlm.hdr.nlmsg_type = RTM_DELADDR;
+	nlm.ifa.ifa_index = iface->index;
+	nlm.ifa.ifa_family = AF_INET;
+	nlm.ifa.ifa_prefixlen = inet_ntocidr(*netmask);
+	/* This creates the aliased interface */
+	add_attr_l(&nlm.hdr, sizeof(nlm), IFA_LABEL,
+	    iface->alias, (unsigned short)(strlen(iface->alias) + 1));
+	add_attr_l(&nlm.hdr, sizeof(nlm), IFA_LOCAL,
+	    &address->s_addr, sizeof(address->s_addr));
+	if (action >= 0 && broadcast)
+		add_attr_l(&nlm.hdr, sizeof(nlm), IFA_BROADCAST,
+		    &broadcast->s_addr, sizeof(broadcast->s_addr));
+
+	if (send_netlink(iface->ctx, NULL, NETLINK_ROUTE, &nlm.hdr, NULL) == -1)
+		retval = -1;
+	return retval;
+}
+
+int
+if_route(unsigned char cmd, const struct rt *rt)
+{
+	struct nlmr nlm;
+	int retval = 0;
+	struct dhcp_state *state;
+
+	memset(&nlm, 0, sizeof(nlm));
+	nlm.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
+	switch (cmd) {
+	case RTM_CHANGE:
+		nlm.hdr.nlmsg_type = RTM_NEWROUTE;
+		nlm.hdr.nlmsg_flags = NLM_F_CREATE | NLM_F_REPLACE;
+		break;
+	case RTM_ADD:
+		nlm.hdr.nlmsg_type = RTM_NEWROUTE;
+		nlm.hdr.nlmsg_flags = NLM_F_CREATE | NLM_F_EXCL;
+		break;
+	case RTM_DELETE:
+		nlm.hdr.nlmsg_type = RTM_DELROUTE;
+		break;
+	}
+	nlm.hdr.nlmsg_flags |= NLM_F_REQUEST;
+	nlm.rt.rtm_family = AF_INET;
+	nlm.rt.rtm_table = RT_TABLE_MAIN;
+
+	state = D_STATE(rt->iface);
+	if (cmd == RTM_DELETE)
+		nlm.rt.rtm_scope = RT_SCOPE_NOWHERE;
+	else {
+		/* We only change route metrics for kernel routes */
+		if (rt->dest.s_addr ==
+		    (state->addr.s_addr & state->net.s_addr) &&
+		    rt->net.s_addr == state->net.s_addr)
+			nlm.rt.rtm_protocol = RTPROT_KERNEL;
+		else
+			nlm.rt.rtm_protocol = RTPROT_BOOT;
+		if (rt->iface->flags & IFF_LOOPBACK)
+			nlm.rt.rtm_scope = RT_SCOPE_HOST;
+		else if (rt->gate.s_addr == INADDR_ANY ||
+		    (rt->gate.s_addr == rt->dest.s_addr &&
+			rt->net.s_addr == INADDR_BROADCAST))
+			nlm.rt.rtm_scope = RT_SCOPE_LINK;
+		else
+			nlm.rt.rtm_scope = RT_SCOPE_UNIVERSE;
+		nlm.rt.rtm_type = RTN_UNICAST;
+	}
+
+	nlm.rt.rtm_dst_len = inet_ntocidr(rt->net);
+	add_attr_l(&nlm.hdr, sizeof(nlm), RTA_DST,
+	    &rt->dest.s_addr, sizeof(rt->dest.s_addr));
+	if (nlm.rt.rtm_protocol == RTPROT_KERNEL) {
+		add_attr_l(&nlm.hdr, sizeof(nlm), RTA_PREFSRC,
+		    &state->addr.s_addr, sizeof(state->addr.s_addr));
+	}
+	/* If a host route then don't add the gateway */
+	if ((cmd == RTM_ADD || cmd == RTM_CHANGE) &&
+	    rt->net.s_addr != INADDR_BROADCAST)
+		add_attr_l(&nlm.hdr, sizeof(nlm), RTA_GATEWAY,
+		    &rt->gate.s_addr, sizeof(rt->gate.s_addr));
+
+	if (rt->gate.s_addr != htonl(INADDR_LOOPBACK))
+		add_attr_32(&nlm.hdr, sizeof(nlm), RTA_OIF, rt->iface->index);
+	if (rt->metric)
+		add_attr_32(&nlm.hdr, sizeof(nlm), RTA_PRIORITY, rt->metric);
+
+	if (send_netlink(rt->iface->ctx, NULL,
+	    NETLINK_ROUTE, &nlm.hdr, NULL) == -1)
+		retval = -1;
+	return retval;
+}
+
+static int
+_if_initrt(struct dhcpcd_ctx *ctx, __unused struct interface *ifp,
+    struct nlmsghdr *nlm)
+{
+	struct rt rt;
+
+	if (if_copyrt(ctx, &rt, nlm) == 0)
+		ipv4_handlert(ctx, RTM_ADD, &rt);
+	return 0;
+}
+
+int
+if_initrt(struct interface *ifp)
+{
+	struct nlmr nlm;
+
+	ipv4_freerts(ifp->ctx->ipv4_kroutes);
+
+	memset(&nlm, 0, sizeof(nlm));
+	nlm.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
+	nlm.hdr.nlmsg_type = RTM_GETROUTE;
+	nlm.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_MATCH;
+	nlm.hdr.nlmsg_flags |= NLM_F_REQUEST;
+	nlm.rt.rtm_family = AF_INET;
+	nlm.rt.rtm_table = RT_TABLE_MAIN;
+	add_attr_32(&nlm.hdr, sizeof(nlm), RTA_OIF, ifp->index);
+
+	return send_netlink(ifp->ctx, ifp,
+	    NETLINK_ROUTE, &nlm.hdr, &_if_initrt);
+}
+
+int
+if_addrflags(__unused const struct in_addr *addr,
+    __unused const struct interface *ifp)
+{
+
+	/* Linux has no support for IPv4 address flags */
+	return 0;
+}
+#endif
+
+#ifdef INET6
+int
+if_address6(const struct ipv6_addr *ap, int action)
+{
+	struct nlma nlm;
+	struct ifa_cacheinfo cinfo;
+	int retval = 0;
+/* IFA_FLAGS is not a define, but is was added at the same time
+ * IFA_F_NOPREFIXROUTE was do use that. */
+#if defined(IFA_F_NOPREFIXROUTE) || defined(IFA_F_MANAGETEMPADDR)
+	uint32_t flags = 0;
+#endif
+
+	memset(&nlm, 0, sizeof(nlm));
+	nlm.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
+	nlm.hdr.nlmsg_flags = NLM_F_REQUEST;
+	if (action >= 0) {
+		nlm.hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE;
+		nlm.hdr.nlmsg_type = RTM_NEWADDR;
+	} else
+		nlm.hdr.nlmsg_type = RTM_DELADDR;
+	nlm.ifa.ifa_index = ap->iface->index;
+	nlm.ifa.ifa_family = AF_INET6;
+	if (ap->addr_flags & IFA_F_TEMPORARY) {
+#ifdef IFA_F_NOPREFIXROUTE
+		flags |= IFA_F_TEMPORARY;
+#else
+		nlm.ifa.ifa_flags |= IFA_F_TEMPORARY;
+#endif
+	}
+#ifdef IFA_F_MANAGETEMPADDR
+	else if (ap->flags & IPV6_AF_AUTOCONF &&
+	    ip6_use_tempaddr(ap->iface->name))
+		flags |= IFA_F_MANAGETEMPADDR;
+#endif
+
+	/* Add as /128 if no IFA_F_NOPREFIXROUTE ? */
+	nlm.ifa.ifa_prefixlen = ap->prefix_len;
+	/* This creates the aliased interface */
+	add_attr_l(&nlm.hdr, sizeof(nlm), IFA_LABEL,
+	    ap->iface->alias, (unsigned short)(strlen(ap->iface->alias) + 1));
+	add_attr_l(&nlm.hdr, sizeof(nlm), IFA_LOCAL,
+	    &ap->addr.s6_addr, sizeof(ap->addr.s6_addr));
+
+	if (action >= 0) {
+		memset(&cinfo, 0, sizeof(cinfo));
+		cinfo.ifa_prefered = ap->prefix_pltime;
+		cinfo.ifa_valid = ap->prefix_vltime;
+		add_attr_l(&nlm.hdr, sizeof(nlm), IFA_CACHEINFO,
+		    &cinfo, sizeof(cinfo));
+	}
+
+#ifdef IFA_F_NOPREFIXROUTE
+	if (!IN6_IS_ADDR_LINKLOCAL(&ap->addr))
+		flags |= IFA_F_NOPREFIXROUTE;
+#endif
+#if defined(IFA_F_NOPREFIXROUTE) || defined(IFA_F_MANAGETEMPADDR)
+	if (flags)
+		add_attr_32(&nlm.hdr, sizeof(nlm), IFA_FLAGS, flags);
+#endif
+
+	if (send_netlink(ap->iface->ctx, NULL, NETLINK_ROUTE, &nlm.hdr,
+	    NULL) == -1)
+		retval = -1;
+	return retval;
+}
+
+static int
+rta_add_attr_32(struct rtattr *rta, unsigned short maxlen,
+    unsigned short type, uint32_t data)
+{
+	unsigned short len = RTA_LENGTH(sizeof(data));
+	struct rtattr *subrta;
+
+	if (RTA_ALIGN(rta->rta_len) + len > maxlen) {
+		errno = ENOBUFS;
+		return -1;
+	}
+
+	subrta = (struct rtattr*)(void *)
+	    (((char*)rta) + RTA_ALIGN(rta->rta_len));
+	subrta->rta_type = type;
+	subrta->rta_len = len;
+	memcpy(RTA_DATA(subrta), &data, sizeof(data));
+	rta->rta_len = (unsigned short)(NLMSG_ALIGN(rta->rta_len) + len);
+	return 0;
+}
+
+int
+if_route6(unsigned char cmd, const struct rt6 *rt)
+{
+	struct nlmr nlm;
+	int retval = 0;
+
+	memset(&nlm, 0, sizeof(nlm));
+	nlm.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
+	switch (cmd) {
+	case RTM_CHANGE:
+		nlm.hdr.nlmsg_type = RTM_NEWROUTE;
+		nlm.hdr.nlmsg_flags = NLM_F_CREATE | NLM_F_REPLACE;
+		break;
+	case RTM_ADD:
+		nlm.hdr.nlmsg_type = RTM_NEWROUTE;
+		nlm.hdr.nlmsg_flags = NLM_F_CREATE | NLM_F_EXCL;
+		break;
+	case RTM_DELETE:
+		nlm.hdr.nlmsg_type = RTM_DELROUTE;
+		break;
+	}
+	nlm.hdr.nlmsg_flags |= NLM_F_REQUEST;
+	nlm.rt.rtm_family = AF_INET6;
+	nlm.rt.rtm_table = RT_TABLE_MAIN;
+
+	if (cmd == RTM_DELETE)
+		nlm.rt.rtm_scope = RT_SCOPE_NOWHERE;
+	else {
+		/* None interface subnet routes are static. */
+		if (rt->iface->flags & IFF_LOOPBACK)
+			nlm.rt.rtm_scope = RT_SCOPE_HOST;
+		else if (IN6_IS_ADDR_UNSPECIFIED(&rt->gate)) {
+			nlm.rt.rtm_protocol = RTPROT_KERNEL;
+			nlm.rt.rtm_scope = RT_SCOPE_LINK;
+		} else
+			nlm.rt.rtm_protocol = RTPROT_BOOT;
+		if (rt->flags & RTF_REJECT)
+			nlm.rt.rtm_type = RTN_UNREACHABLE;
+		else
+			nlm.rt.rtm_type = RTN_UNICAST;
+	}
+
+	nlm.rt.rtm_dst_len = ipv6_prefixlen(&rt->net);
+	add_attr_l(&nlm.hdr, sizeof(nlm), RTA_DST,
+	    &rt->dest.s6_addr, sizeof(rt->dest.s6_addr));
+
+	if (cmd == RTM_ADD && !IN6_IS_ADDR_UNSPECIFIED(&rt->gate))
+		add_attr_l(&nlm.hdr, sizeof(nlm), RTA_GATEWAY,
+		    &rt->gate.s6_addr, sizeof(rt->gate.s6_addr));
+
+	if (!(rt->flags & RTF_REJECT)) {
+		add_attr_32(&nlm.hdr, sizeof(nlm), RTA_OIF, rt->iface->index);
+		if (rt->metric)
+			add_attr_32(&nlm.hdr, sizeof(nlm),
+			    RTA_PRIORITY, rt->metric);
+	}
+	if (cmd == RTM_ADD && rt->mtu) {
+		char metricsbuf[32];
+		struct rtattr *metrics = (void *)metricsbuf;
+
+		metrics->rta_type = RTA_METRICS;
+		metrics->rta_len = RTA_LENGTH(0);
+		rta_add_attr_32(metrics, sizeof(metricsbuf), RTAX_MTU, rt->mtu);
+		add_attr_l(&nlm.hdr, sizeof(nlm), RTA_METRICS,
+		    RTA_DATA(metrics), (unsigned short)RTA_PAYLOAD(metrics));
+	}
+
+	if (send_netlink(rt->iface->ctx, NULL,
+	    NETLINK_ROUTE, &nlm.hdr, NULL) == -1)
+		retval = -1;
+	return retval;
+}
+
+static int
+_if_initrt6(struct dhcpcd_ctx *ctx, __unused struct interface *ifp,
+    struct nlmsghdr *nlm)
+{
+	struct rt6 rt;
+
+	if (if_copyrt6(ctx, &rt, nlm) == 0)
+		ipv6_handlert(ctx, RTM_ADD, &rt);
+	return 0;
+}
+
+int
+if_initrt6(struct interface *ifp)
+{
+	struct nlmr nlm;
+
+	ipv6_freerts(&ifp->ctx->ipv6->kroutes);
+
+	memset(&nlm, 0, sizeof(nlm));
+	nlm.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
+	nlm.hdr.nlmsg_type = RTM_GETROUTE;
+	nlm.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_MATCH;
+	nlm.hdr.nlmsg_flags |= NLM_F_REQUEST;
+	nlm.rt.rtm_family = AF_INET6;
+	nlm.rt.rtm_table = RT_TABLE_MAIN;
+	add_attr_32(&nlm.hdr, sizeof(nlm), RTA_OIF, ifp->index);
+
+	return send_netlink(ifp->ctx, ifp,
+	    NETLINK_ROUTE, &nlm.hdr, &_if_initrt6);
+}
+
+int
+if_addrflags6(const struct in6_addr *addr, const struct interface *ifp)
+{
+	FILE *fp;
+	char *p, ifaddress[33], address[33], name[IF_NAMESIZE + 1];
+	unsigned int ifindex;
+	int prefix, scope, flags, i;
+
+	fp = fopen(PROC_INET6, "r");
+	if (fp == NULL)
+		return -1;
+
+	p = ifaddress;
+	for (i = 0; i < (int)sizeof(addr->s6_addr); i++) {
+		p += snprintf(p, 3, "%.2x", addr->s6_addr[i]);
+	}
+	*p = '\0';
+
+	while (fscanf(fp, "%32[a-f0-9] %x %x %x %x %"TOSTRING(IF_NAMESIZE)"s\n",
+	    address, &ifindex, &prefix, &scope, &flags, name) == 6)
+	{
+		if (strlen(address) != 32) {
+			fclose(fp);
+			errno = ENOTSUP;
+			return -1;
+		}
+		if (strcmp(name, ifp->name) == 0 &&
+		    strcmp(ifaddress, address) == 0)
+		{
+			fclose(fp);
+			return flags;
+		}
+	}
+
+	fclose(fp);
+	errno = ESRCH;
+	return -1;
+}
+
+int
+if_getlifetime6(__unused struct ipv6_addr *ia)
+{
+
+	/* God knows how to work out address lifetimes on Linux */
+	errno = ENOTSUP;
+	return -1;
+}
+
+struct nlml
+{
+	struct nlmsghdr hdr;
+	struct ifinfomsg i;
+	char buffer[32];
+};
+
+static int
+add_attr_8(struct nlmsghdr *n, unsigned short maxlen, unsigned short type,
+    uint8_t data)
+{
+
+	return add_attr_l(n, maxlen, type, &data, sizeof(data));
+}
+
+static struct rtattr *
+add_attr_nest(struct nlmsghdr *n, unsigned short maxlen, unsigned short type)
+{
+	struct rtattr *nest;
+
+	nest = NLMSG_TAIL(n);
+	add_attr_l(n, maxlen, type, NULL, 0);
+	return nest;
+}
+
+static void
+add_attr_nest_end(struct nlmsghdr *n, struct rtattr *nest)
+{
+
+	nest->rta_len = (unsigned short)((char *)NLMSG_TAIL(n) - (char *)nest);
+}
+
+static int
+if_disable_autolinklocal(struct dhcpcd_ctx *ctx, int ifindex)
+{
+	struct nlml nlm;
+	struct rtattr *afs, *afs6;
+
+	memset(&nlm, 0, sizeof(nlm));
+	nlm.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+	nlm.hdr.nlmsg_type = RTM_NEWLINK;
+	nlm.hdr.nlmsg_flags = NLM_F_REQUEST;
+	nlm.i.ifi_family = AF_INET6;
+	nlm.i.ifi_index = ifindex;
+	afs = add_attr_nest(&nlm.hdr, sizeof(nlm), IFLA_AF_SPEC);
+	afs6 = add_attr_nest(&nlm.hdr, sizeof(nlm), AF_INET6);
+	add_attr_8(&nlm.hdr, sizeof(nlm), IFLA_INET6_ADDR_GEN_MODE,
+	    IN6_ADDR_GEN_MODE_NONE);
+	add_attr_nest_end(&nlm.hdr, afs6);
+	add_attr_nest_end(&nlm.hdr, afs);
+
+	return send_netlink(ctx, NULL, NETLINK_ROUTE, &nlm.hdr, NULL);
+}
+
+static const char *prefix = "/proc/sys/net/ipv6/conf";
+
+int
+if_checkipv6(struct dhcpcd_ctx *ctx, const struct interface *ifp, int own)
+{
+	const char *ifname;
+	int ra;
+	char path[256];
+
+	if (ifp == NULL)
+		ifname = "all";
+	else if (own) {
+		if (if_disable_autolinklocal(ctx, (int)ifp->index) == -1)
+			logger(ctx, LOG_DEBUG,
+			    "%s: if_disable_autolinklocal: %m", ifp->name);
+	}
+	if (ifp)
+		ifname = ifp->name;
+
+	snprintf(path, sizeof(path), "%s/%s/autoconf", prefix, ifname);
+	ra = check_proc_int(path);
+	if (ra != 1) {
+		if (!own)
+			logger(ctx, LOG_WARNING,
+			    "%s: IPv6 kernel autoconf disabled", ifname);
+	} else if (ra != -1 && own) {
+		if (write_path(path, "0") == -1) {
+			logger(ctx, LOG_ERR, "write_path: %s: %m", path);
+			return -1;
+		}
+	}
+
+	snprintf(path, sizeof(path), "%s/%s/accept_ra", prefix, ifname);
+	ra = check_proc_int(path);
+	if (ra == -1)
+		/* The sysctl probably doesn't exist, but this isn't an
+		 * error as such so just log it and continue */
+		logger(ctx, errno == ENOENT ? LOG_DEBUG : LOG_WARNING,
+		    "%s: %m", path);
+	else if (ra != 0 && own) {
+		logger(ctx, LOG_DEBUG, "%s: disabling kernel IPv6 RA support",
+		    ifname);
+		if (write_path(path, "0") == -1) {
+			logger(ctx, LOG_ERR, "write_path: %s: %m", path);
+			return ra;
+		}
+		return 0;
+	}
+
+	return ra;
+}
+
+#ifdef IPV6_MANAGETEMPADDR
+int
+ip6_use_tempaddr(const char *ifname)
+{
+	char path[256];
+	int val;
+
+	if (ifname == NULL)
+		ifname = "all";
+	snprintf(path, sizeof(path), "%s/%s/use_tempaddr", prefix, ifname);
+	val = check_proc_int(path);
+	return val == -1 ? 0 : val;
+}
+
+int
+ip6_temp_preferred_lifetime(const char *ifname)
+{
+	char path[256];
+	int val;
+
+	if (ifname == NULL)
+		ifname = "all";
+	snprintf(path, sizeof(path), "%s/%s/temp_prefered_lft", prefix,
+	    ifname);
+	val = check_proc_int(path);
+	return val < 0 ? TEMP_PREFERRED_LIFETIME : val;
+}
+
+int
+ip6_temp_valid_lifetime(const char *ifname)
+{
+	char path[256];
+	int val;
+
+	if (ifname == NULL)
+		ifname = "all";
+	snprintf(path, sizeof(path), "%s/%s/temp_valid_lft", prefix, ifname);
+	val = check_proc_int(path);
+	return val < 0 ? TEMP_VALID_LIFETIME : val;
+}
+#endif /* IPV6_MANAGETEMPADDR */
+#endif /* INET6 */
diff --git a/dhcpcd-6.8.2/if-options.c b/dhcpcd-6.8.2/if-options.c
new file mode 100644
index 0000000..5d32811
--- /dev/null
+++ b/dhcpcd-6.8.2/if-options.c
@@ -0,0 +1,2415 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#define _WITH_GETLINE /* Stop FreeBSD bitching */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <getopt.h>
+#include <grp.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+
+#include "config.h"
+#include "common.h"
+#include "dhcp.h"
+#include "dhcp6.h"
+#include "dhcpcd-embedded.h"
+#include "if.h"
+#include "if-options.h"
+#include "ipv4.h"
+
+/* These options only make sense in the config file, so don't use any
+   valid short options for them */
+#define O_BASE			MAX('z', 'Z') + 1
+#define O_ARPING		O_BASE + 1
+#define O_FALLBACK		O_BASE + 2
+#define O_DESTINATION		O_BASE + 3
+#define O_IPV6RS		O_BASE + 4
+#define O_NOIPV6RS		O_BASE + 5
+#define O_IPV6RA_FORK		O_BASE + 6
+#define O_IPV6RA_OWN		O_BASE + 7
+#define O_IPV6RA_OWN_D		O_BASE + 8
+#define O_NOALIAS		O_BASE + 9
+#define O_IA_NA			O_BASE + 10
+#define O_IA_TA			O_BASE + 11
+#define O_IA_PD			O_BASE + 12
+#define O_HOSTNAME_SHORT	O_BASE + 13
+#define O_DEV			O_BASE + 14
+#define O_NODEV			O_BASE + 15
+#define O_NOIPV4		O_BASE + 16
+#define O_NOIPV6		O_BASE + 17
+#define O_IAID			O_BASE + 18
+#define O_DEFINE		O_BASE + 19
+#define O_DEFINE6		O_BASE + 20
+#define O_EMBED			O_BASE + 21
+#define O_ENCAP			O_BASE + 22
+#define O_VENDOPT		O_BASE + 23
+#define O_VENDCLASS		O_BASE + 24
+#define O_AUTHPROTOCOL		O_BASE + 25
+#define O_AUTHTOKEN		O_BASE + 26
+#define O_AUTHNOTREQUIRED	O_BASE + 27
+#define O_NODHCP		O_BASE + 28
+#define O_NODHCP6		O_BASE + 29
+#define O_DHCP			O_BASE + 30
+#define O_DHCP6			O_BASE + 31
+#define O_IPV4			O_BASE + 32
+#define O_IPV6			O_BASE + 33
+#define O_CONTROLGRP		O_BASE + 34
+#define O_SLAAC			O_BASE + 35
+#define O_GATEWAY		O_BASE + 36
+#define O_PFXDLGMIX		O_BASE + 37
+#define O_IPV6RA_AUTOCONF	O_BASE + 38
+#define O_IPV6RA_NOAUTOCONF	O_BASE + 39
+#define O_REJECT		O_BASE + 40
+#define O_IPV6RA_ACCEPT_NOPUBLIC	O_BASE + 41
+#define O_BOOTP			O_BASE + 42
+
+const struct option cf_options[] = {
+	{"shill-ipv6",      no_argument,       NULL, 'a'},
+	{"background",      no_argument,       NULL, 'b'},
+	{"script",          required_argument, NULL, 'c'},
+	{"debug",           no_argument,       NULL, 'd'},
+	{"env",             required_argument, NULL, 'e'},
+	{"config",          required_argument, NULL, 'f'},
+	{"reconfigure",     no_argument,       NULL, 'g'},
+	{"hostname",        optional_argument, NULL, 'h'},
+	{"vendorclassid",   optional_argument, NULL, 'i'},
+	{"logfile",         required_argument, NULL, 'j'},
+	{"release",         no_argument,       NULL, 'k'},
+	{"leasetime",       required_argument, NULL, 'l'},
+	{"metric",          required_argument, NULL, 'm'},
+	{"rebind",          no_argument,       NULL, 'n'},
+	{"option",          required_argument, NULL, 'o'},
+	{"persistent",      no_argument,       NULL, 'p'},
+	{"quiet",           no_argument,       NULL, 'q'},
+	{"request",         optional_argument, NULL, 'r'},
+	{"inform",          optional_argument, NULL, 's'},
+	{"timeout",         required_argument, NULL, 't'},
+	{"userclass",       required_argument, NULL, 'u'},
+	{"vendor",          required_argument, NULL, 'v'},
+	{"waitip",          optional_argument, NULL, 'w'},
+	{"exit",            no_argument,       NULL, 'x'},
+	{"allowinterfaces", required_argument, NULL, 'z'},
+	{"reboot",          required_argument, NULL, 'y'},
+	{"noarp",           no_argument,       NULL, 'A'},
+	{"nobackground",    no_argument,       NULL, 'B'},
+	{"nohook",          required_argument, NULL, 'C'},
+	{"duid",            no_argument,       NULL, 'D'},
+	{"lastlease",       no_argument,       NULL, 'E'},
+	{"fqdn",            optional_argument, NULL, 'F'},
+	{"nogateway",       no_argument,       NULL, 'G'},
+	{"xidhwaddr",       no_argument,       NULL, 'H'},
+	{"clientid",        optional_argument, NULL, 'I'},
+	{"broadcast",       no_argument,       NULL, 'J'},
+	{"nolink",          no_argument,       NULL, 'K'},
+	{"noipv4ll",        no_argument,       NULL, 'L'},
+	{"master",          no_argument,       NULL, 'M'},
+	{"nooption",        optional_argument, NULL, 'O'},
+	{"unicast",	    no_argument,       NULL, 'P'},
+	{"require",	    required_argument, NULL, 'Q'},
+	{"arpgw",	    no_argument,       NULL, 'R'},
+	{"static",          required_argument, NULL, 'S'},
+	{"test",            no_argument,       NULL, 'T'},
+	{"dumplease",       no_argument,       NULL, 'U'},
+	{"variables",       no_argument,       NULL, 'V'},
+	{"whitelist",       required_argument, NULL, 'W'},
+	{"blacklist",       required_argument, NULL, 'X'},
+	{"denyinterfaces",  required_argument, NULL, 'Z'},
+	{"arping",          required_argument, NULL, O_ARPING},
+	{"destination",     required_argument, NULL, O_DESTINATION},
+	{"fallback",        required_argument, NULL, O_FALLBACK},
+	{"ipv6rs",          no_argument,       NULL, O_IPV6RS},
+	{"noipv6rs",        no_argument,       NULL, O_NOIPV6RS},
+	{"ipv6ra_autoconf", no_argument,       NULL, O_IPV6RA_AUTOCONF},
+	{"ipv6ra_noautoconf", no_argument,     NULL, O_IPV6RA_NOAUTOCONF},
+	{"ipv6ra_fork",     no_argument,       NULL, O_IPV6RA_FORK},
+	{"ipv6ra_own",      no_argument,       NULL, O_IPV6RA_OWN},
+	{"ipv6ra_own_default", no_argument,    NULL, O_IPV6RA_OWN_D},
+	{"ipv6ra_accept_nopublic", no_argument, NULL, O_IPV6RA_ACCEPT_NOPUBLIC},
+	{"ipv4only",        no_argument,       NULL, '4'},
+	{"ipv6only",        no_argument,       NULL, '6'},
+	{"ipv4",            no_argument,       NULL, O_IPV4},
+	{"noipv4",          no_argument,       NULL, O_NOIPV4},
+	{"ipv6",            no_argument,       NULL, O_IPV6},
+	{"noipv6",          no_argument,       NULL, O_NOIPV6},
+	{"noalias",         no_argument,       NULL, O_NOALIAS},
+	{"iaid",            required_argument, NULL, O_IAID},
+	{"ia_na",           no_argument,       NULL, O_IA_NA},
+	{"ia_ta",           no_argument,       NULL, O_IA_TA},
+	{"ia_pd",           no_argument,       NULL, O_IA_PD},
+	{"hostname_short",  no_argument,       NULL, O_HOSTNAME_SHORT},
+	{"dev",             required_argument, NULL, O_DEV},
+	{"nodev",           no_argument,       NULL, O_NODEV},
+	{"define",          required_argument, NULL, O_DEFINE},
+	{"define6",         required_argument, NULL, O_DEFINE6},
+	{"embed",           required_argument, NULL, O_EMBED},
+	{"encap",           required_argument, NULL, O_ENCAP},
+	{"vendopt",         required_argument, NULL, O_VENDOPT},
+	{"vendclass",       required_argument, NULL, O_VENDCLASS},
+	{"authprotocol",    required_argument, NULL, O_AUTHPROTOCOL},
+	{"authtoken",       required_argument, NULL, O_AUTHTOKEN},
+	{"noauthrequired",  no_argument,       NULL, O_AUTHNOTREQUIRED},
+	{"dhcp",            no_argument,       NULL, O_DHCP},
+	{"nodhcp",          no_argument,       NULL, O_NODHCP},
+	{"dhcp6",           no_argument,       NULL, O_DHCP6},
+	{"nodhcp6",         no_argument,       NULL, O_NODHCP6},
+	{"controlgroup",    required_argument, NULL, O_CONTROLGRP},
+	{"slaac",           required_argument, NULL, O_SLAAC},
+	{"gateway",         no_argument,       NULL, O_GATEWAY},
+	{"ia_pd_mix",       no_argument,       NULL, O_PFXDLGMIX},
+	{"reject",          required_argument, NULL, O_REJECT},
+	{"bootp",           no_argument,       NULL, O_BOOTP},
+	{NULL,              0,                 NULL, '\0'}
+};
+
+static char *
+add_environ(struct dhcpcd_ctx *ctx, struct if_options *ifo,
+    const char *value, int uniq)
+{
+	char **newlist;
+	char **lst = ifo->environ;
+	size_t i = 0, l, lv;
+	char *match = NULL, *p, *n;
+
+	match = strdup(value);
+	if (match == NULL) {
+		logger(ctx, LOG_ERR, "%s: %m", __func__);
+		return NULL;
+	}
+	p = strchr(match, '=');
+	if (p == NULL) {
+		logger(ctx, LOG_ERR, "%s: no assignment: %s", __func__, value);
+		free(match);
+		return NULL;
+	}
+	*p++ = '\0';
+	l = strlen(match);
+
+	while (lst && lst[i]) {
+		if (match && strncmp(lst[i], match, l) == 0) {
+			if (uniq) {
+				n = strdup(value);
+				if (n == NULL) {
+					logger(ctx, LOG_ERR,
+					    "%s: %m", __func__);
+					free(match);
+					return NULL;
+				}
+				free(lst[i]);
+				lst[i] = n;
+			} else {
+				/* Append a space and the value to it */
+				l = strlen(lst[i]);
+				lv = strlen(p);
+				n = realloc(lst[i], l + lv + 2);
+				if (n == NULL) {
+					logger(ctx, LOG_ERR,
+					    "%s: %m", __func__);
+					free(match);
+					return NULL;
+				}
+				lst[i] = n;
+				lst[i][l] = ' ';
+				memcpy(lst[i] + l + 1, p, lv);
+				lst[i][l + lv + 1] = '\0';
+			}
+			free(match);
+			return lst[i];
+		}
+		i++;
+	}
+
+	free(match);
+	n = strdup(value);
+	if (n == NULL) {
+		logger(ctx, LOG_ERR, "%s: %m", __func__);
+		return NULL;
+	}
+	newlist = realloc(lst, sizeof(char *) * (i + 2));
+	if (newlist == NULL) {
+		logger(ctx, LOG_ERR, "%s: %m", __func__);
+		free(n);
+		return NULL;
+	}
+	newlist[i] = n;
+	newlist[i + 1] = NULL;
+	ifo->environ = newlist;
+	return newlist[i];
+}
+
+#define parse_string(buf, len, arg) parse_string_hwaddr(buf, len, arg, 0)
+static ssize_t
+parse_string_hwaddr(char *sbuf, size_t slen, const char *str, int clid)
+{
+	size_t l;
+	const char *p;
+	int i, punt_last = 0;
+	char c[4];
+
+	/* If surrounded by quotes then it's a string */
+	if (*str == '"') {
+		str++;
+		l = strlen(str);
+		p = str + l - 1;
+		if (*p == '"')
+			punt_last = 1;
+	} else {
+		l = (size_t)hwaddr_aton(NULL, str);
+		if ((ssize_t) l != -1 && l > 1) {
+			if (l > slen) {
+				errno = ENOBUFS;
+				return -1;
+			}
+			hwaddr_aton((uint8_t *)sbuf, str);
+			return (ssize_t)l;
+		}
+	}
+
+	/* Process escapes */
+	l = 0;
+	/* If processing a string on the clientid, first byte should be
+	 * 0 to indicate a non hardware type */
+	if (clid && *str) {
+		if (sbuf)
+			*sbuf++ = 0;
+		l++;
+	}
+	c[3] = '\0';
+	while (*str) {
+		if (++l > slen && sbuf) {
+			errno = ENOBUFS;
+			return -1;
+		}
+		if (*str == '\\') {
+			str++;
+			switch(*str) {
+			case '\0':
+				break;
+			case 'b':
+				if (sbuf)
+					*sbuf++ = '\b';
+				str++;
+				break;
+			case 'n':
+				if (sbuf)
+					*sbuf++ = '\n';
+				str++;
+				break;
+			case 'r':
+				if (sbuf)
+					*sbuf++ = '\r';
+				str++;
+				break;
+			case 't':
+				if (sbuf)
+					*sbuf++ = '\t';
+				str++;
+				break;
+			case 'x':
+				/* Grab a hex code */
+				c[1] = '\0';
+				for (i = 0; i < 2; i++) {
+					if (isxdigit((unsigned char)*str) == 0)
+						break;
+					c[i] = *str++;
+				}
+				if (c[1] != '\0' && sbuf) {
+					c[2] = '\0';
+					*sbuf++ = (char)strtol(c, NULL, 16);
+				} else
+					l--;
+				break;
+			case '0':
+				/* Grab an octal code */
+				c[2] = '\0';
+				for (i = 0; i < 3; i++) {
+					if (*str < '0' || *str > '7')
+						break;
+					c[i] = *str++;
+				}
+				if (c[2] != '\0' && sbuf) {
+					i = (int)strtol(c, NULL, 8);
+					if (i > 255)
+						i = 255;
+					*sbuf ++= (char)i;
+				} else
+					l--;
+				break;
+			default:
+				if (sbuf)
+					*sbuf++ = *str;
+				str++;
+				break;
+			}
+		} else {
+			if (sbuf)
+				*sbuf++ = *str;
+			str++;
+		}
+	}
+	if (punt_last) {
+		if (sbuf)
+			*--sbuf = '\0';
+		l--;
+	}
+	return (ssize_t)l;
+}
+
+static int
+parse_iaid1(uint8_t *iaid, const char *arg, size_t len, int n)
+{
+	int e;
+	uint32_t narg;
+	ssize_t s;
+
+	narg = (uint32_t)strtou(arg, NULL, 0, 0, UINT32_MAX, &e);
+	if (e == 0) {
+		if (n)
+			narg = htonl(narg);
+		memcpy(iaid, &narg, sizeof(narg));
+		return 0;
+	}
+
+	if ((s = parse_string((char *)iaid, len, arg)) < 1)
+		return -1;
+	if (s < 4)
+		iaid[3] = '\0';
+	if (s < 3)
+		iaid[2] = '\0';
+	if (s < 2)
+		iaid[1] = '\0';
+	return 0;
+}
+
+static int
+parse_iaid(uint8_t *iaid, const char *arg, size_t len)
+{
+
+	return parse_iaid1(iaid, arg, len, 1);
+}
+
+static int
+parse_uint32(uint32_t *i, const char *arg)
+{
+
+	return parse_iaid1((uint8_t *)i, arg, sizeof(uint32_t), 0);
+}
+
+static char **
+splitv(struct dhcpcd_ctx *ctx, int *argc, char **argv, const char *arg)
+{
+	char **n, **v = argv;
+	char *o = strdup(arg), *p, *t, *nt;
+
+	if (o == NULL) {
+		logger(ctx, LOG_ERR, "%s: %m", __func__);
+		return v;
+	}
+	p = o;
+	while ((t = strsep(&p, ", "))) {
+		nt = strdup(t);
+		if (nt == NULL) {
+			logger(ctx, LOG_ERR, "%s: %m", __func__);
+			free(o);
+			return v;
+		}
+		n = realloc(v, sizeof(char *) * ((size_t)(*argc) + 1));
+		if (n == NULL) {
+			logger(ctx, LOG_ERR, "%s: %m", __func__);
+			free(o);
+			free(nt);
+			return v;
+		}
+		v = n;
+		v[(*argc)++] = nt;
+	}
+	free(o);
+	return v;
+}
+
+#ifdef INET
+static int
+parse_addr(struct dhcpcd_ctx *ctx,
+    struct in_addr *addr, struct in_addr *net, const char *arg)
+{
+	char *p;
+	int i;
+
+	if (arg == NULL || *arg == '\0') {
+		if (addr != NULL)
+			addr->s_addr = 0;
+		if (net != NULL)
+			net->s_addr = 0;
+		return 0;
+	}
+	if ((p = strchr(arg, '/')) != NULL) {
+		*p++ = '\0';
+		if (net != NULL &&
+		    (sscanf(p, "%d", &i) != 1 ||
+			inet_cidrtoaddr(i, net) != 0))
+		{
+			logger(ctx, LOG_ERR, "`%s' is not a valid CIDR", p);
+			return -1;
+		}
+	}
+
+	if (addr != NULL && inet_aton(arg, addr) == 0) {
+		logger(ctx, LOG_ERR, "`%s' is not a valid IP address", arg);
+		return -1;
+	}
+	if (p != NULL)
+		*--p = '/';
+	else if (net != NULL && addr != NULL)
+		net->s_addr = ipv4_getnetmask(addr->s_addr);
+	return 0;
+}
+#else
+static int
+parse_addr(struct dhcpcd_ctx *ctx,
+    __unused struct in_addr *addr, __unused struct in_addr *net,
+    __unused const char *arg)
+{
+
+	logger(ctx, LOG_ERR, "No IPv4 support");
+	return -1;
+}
+#endif
+
+static const char *
+set_option_space(struct dhcpcd_ctx *ctx,
+    const char *arg,
+    const struct dhcp_opt **d, size_t *dl,
+    const struct dhcp_opt **od, size_t *odl,
+    struct if_options *ifo,
+    uint8_t *request[], uint8_t *require[], uint8_t *no[], uint8_t *reject[])
+{
+
+#if !defined(INET) && !defined(INET6)
+	/* Satisfy use */
+	ctx = NULL;
+#endif
+
+#ifdef INET6
+	if (strncmp(arg, "dhcp6_", strlen("dhcp6_")) == 0) {
+		*d = ctx->dhcp6_opts;
+		*dl = ctx->dhcp6_opts_len;
+		*od = ifo->dhcp6_override;
+		*odl = ifo->dhcp6_override_len;
+		*request = ifo->requestmask6;
+		*require = ifo->requiremask6;
+		*no = ifo->nomask6;
+		*reject = ifo->rejectmask6;
+		return arg + strlen("dhcp6_");
+	}
+#endif
+
+#ifdef INET
+	*d = ctx->dhcp_opts;
+	*dl = ctx->dhcp_opts_len;
+	*od = ifo->dhcp_override;
+	*odl = ifo->dhcp_override_len;
+#else
+	*d = NULL;
+	*dl = 0;
+	*od = NULL;
+	*odl = 0;
+#endif
+	*request = ifo->requestmask;
+	*require = ifo->requiremask;
+	*no = ifo->nomask;
+	*reject = ifo->rejectmask;
+	return arg;
+}
+
+void
+free_dhcp_opt_embenc(struct dhcp_opt *opt)
+{
+	size_t i;
+	struct dhcp_opt *o;
+
+	free(opt->var);
+
+	for (i = 0, o = opt->embopts; i < opt->embopts_len; i++, o++)
+		free_dhcp_opt_embenc(o);
+	free(opt->embopts);
+	opt->embopts_len = 0;
+	opt->embopts = NULL;
+
+	for (i = 0, o = opt->encopts; i < opt->encopts_len; i++, o++)
+		free_dhcp_opt_embenc(o);
+	free(opt->encopts);
+	opt->encopts_len = 0;
+	opt->encopts = NULL;
+}
+
+static char *
+strwhite(const char *s)
+{
+
+	if (s == NULL)
+		return NULL;
+	while (*s != ' ' && *s != '\t') {
+		if (*s == '\0')
+			return NULL;
+		s++;
+	}
+	return UNCONST(s);
+}
+
+static char *
+strskipwhite(const char *s)
+{
+
+	if (s == NULL)
+		return NULL;
+	while (*s == ' ' || *s == '\t') {
+		if (*s == '\0')
+			return NULL;
+		s++;
+	}
+	return UNCONST(s);
+}
+
+/* Find the end pointer of a string. */
+static char *
+strend(const char *s)
+{
+
+	s = strskipwhite(s);
+	if (s == NULL)
+		return NULL;
+	if (*s != '"')
+		return strchr(s, ' ');
+	s++;
+	for (; *s != '"' ; s++) {
+		if (*s == '\0')
+			return NULL;
+		if (*s == '\\') {
+			if (*(++s) == '\0')
+				return NULL;
+		}
+	}
+	return UNCONST(++s);
+}
+
+static int
+parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo,
+    int opt, const char *arg, struct dhcp_opt **ldop, struct dhcp_opt **edop)
+{
+	int e, i, t;
+	long l;
+	unsigned long u;
+	char *p = NULL, *fp, *np, **nconf;
+	ssize_t s;
+	struct in_addr addr, addr2;
+	in_addr_t *naddr;
+	struct rt *rt;
+	const struct dhcp_opt *d, *od;
+	uint8_t *request, *require, *no, *reject;
+	struct dhcp_opt **dop, *ndop;
+	size_t *dop_len, dl, odl;
+	struct vivco *vivco;
+	struct token *token;
+	struct group *grp;
+#ifdef _REENTRANT
+	struct group grpbuf;
+#endif
+#ifdef INET6
+	size_t sl;
+	struct if_ia *ia;
+	uint8_t iaid[4];
+	struct if_sla *sla, *slap;
+#endif
+
+	dop = NULL;
+	dop_len = NULL;
+#ifdef INET6
+	i = 0;
+#endif
+	switch(opt) {
+	case 'f': /* FALLTHROUGH */
+	case 'g': /* FALLTHROUGH */
+	case 'n': /* FALLTHROUGH */
+	case 'x': /* FALLTHROUGH */
+	case 'T': /* FALLTHROUGH */
+	case 'U': /* FALLTHROUGH */
+	case 'V': /* We need to handle non interface options */
+		break;
+#ifdef INET6
+	case 'a':
+		/* Chromeos hack: configure DHCPv6 option for shill. */
+
+		/* Reallocate ia to add both ia_na and ia_pd. */
+		ia = realloc(ifo->ia, sizeof(*ifo->ia) * (ifo->ia_len + 2));
+		if (ia == NULL) {
+			logger(ctx, LOG_ERR, "%s: %m", __func__);
+			return -1;
+		}
+		ifo->ia = ia;
+
+		/* Setup ia_na option with iaid of 0. */
+		ia = &ifo->ia[ifo->ia_len++];
+		ia->ia_type = D6_OPTION_IA_NA;
+		parse_iaid(ia->iaid, "0", sizeof(ia->iaid));
+		ia->iaid_set = 1;
+		memset(&ia->addr, 0, sizeof(ia->addr));
+		ia->prefix_len = 0;
+		ia->sla_max = 0;
+		ia->sla_len = 0;
+		ia->sla = NULL;
+
+		/* Setup ia_pd option with iaid of 1. */
+		ia = &ifo->ia[ifo->ia_len++];
+		ia->ia_type = D6_OPTION_IA_PD;
+		parse_iaid(ia->iaid, "1", sizeof(ia->iaid));
+		ia->iaid_set = 1;
+		memset(&ia->addr, 0, sizeof(ia->addr));
+		ia->prefix_len = 0;
+		ia->sla_max = 0;
+		ia->sla_len = 0;
+		ia->sla = NULL;
+
+		/* Enable ia option. */
+		ifo->options |= DHCPCD_IA_FORCED;
+		break;
+#endif
+	case 'b':
+		ifo->options |= DHCPCD_BACKGROUND;
+		break;
+	case 'c':
+		free(ifo->script);
+		ifo->script = strdup(arg);
+		if (ifo->script == NULL)
+			logger(ctx, LOG_ERR, "%s: %m", __func__);
+		break;
+	case 'd':
+		ifo->options |= DHCPCD_DEBUG;
+		break;
+	case 'e':
+		add_environ(ctx, ifo, arg, 1);
+		break;
+	case 'h':
+		if (!arg) {
+			ifo->options |= DHCPCD_HOSTNAME;
+			break;
+		}
+		s = parse_string(ifo->hostname, HOSTNAME_MAX_LEN, arg);
+		if (s == -1) {
+			logger(ctx, LOG_ERR, "hostname: %m");
+			return -1;
+		}
+		if (s != 0 && ifo->hostname[0] == '.') {
+			logger(ctx, LOG_ERR, "hostname cannot begin with .");
+			return -1;
+		}
+		ifo->hostname[s] = '\0';
+		if (ifo->hostname[0] == '\0')
+			ifo->options &= ~DHCPCD_HOSTNAME;
+		else
+			ifo->options |= DHCPCD_HOSTNAME;
+		break;
+	case 'i':
+		if (arg)
+			s = parse_string((char *)ifo->vendorclassid + 1,
+			    VENDORCLASSID_MAX_LEN, arg);
+		else
+			s = 0;
+		if (s == -1) {
+			logger(ctx, LOG_ERR, "vendorclassid: %m");
+			return -1;
+		}
+		*ifo->vendorclassid = (uint8_t)s;
+		break;
+	case 'j':
+		/* per interface logging is not supported
+		 * don't want to overide the commandline */
+		if (ifname == NULL && ctx->logfile == NULL) {
+			logger_close(ctx);
+			ctx->logfile = strdup(arg);
+			logger_open(ctx);
+		}
+		break;
+	case 'k':
+		ifo->options |= DHCPCD_RELEASE;
+		break;
+	case 'l':
+		ifo->leasetime = (uint32_t)strtou(arg, NULL,
+		    0, 0, UINT32_MAX, &e);
+		if (e) {
+			logger(ctx, LOG_ERR, "failed to convert leasetime %s", arg);
+			return -1;
+		}
+		break;
+	case 'm':
+		ifo->metric = (int)strtoi(arg, NULL, 0, 0, INT32_MAX, &e);
+		if (e) {
+			logger(ctx, LOG_ERR, "failed to convert metric %s", arg);
+			return -1;
+		}
+		break;
+	case 'o':
+		arg = set_option_space(ctx, arg, &d, &dl, &od, &odl, ifo,
+		    &request, &require, &no, &reject);
+		if (make_option_mask(d, dl, od, odl, request, arg, 1) != 0 ||
+		    make_option_mask(d, dl, od, odl, no, arg, -1) != 0 ||
+		    make_option_mask(d, dl, od, odl, reject, arg, -1) != 0)
+		{
+			logger(ctx, LOG_ERR, "unknown option `%s'", arg);
+			return -1;
+		}
+		break;
+	case O_REJECT:
+		arg = set_option_space(ctx, arg, &d, &dl, &od, &odl, ifo,
+		    &request, &require, &no, &reject);
+		if (make_option_mask(d, dl, od, odl, reject, arg, 1) != 0 ||
+		    make_option_mask(d, dl, od, odl, request, arg, -1) != 0 ||
+		    make_option_mask(d, dl, od, odl, require, arg, -1) != 0)
+		{
+			logger(ctx, LOG_ERR, "unknown option `%s'", arg);
+			return -1;
+		}
+		break;
+	case 'p':
+		ifo->options |= DHCPCD_PERSISTENT;
+		break;
+	case 'q':
+		ifo->options |= DHCPCD_QUIET;
+		break;
+	case 'r':
+		if (parse_addr(ctx, &ifo->req_addr, NULL, arg) != 0)
+			return -1;
+		ifo->options |= DHCPCD_REQUEST;
+		ifo->req_mask.s_addr = 0;
+		break;
+	case 's':
+		if (ifo->options & DHCPCD_IPV6 &&
+		    !(ifo->options & DHCPCD_IPV4))
+		{
+			ifo->options |= DHCPCD_INFORM;
+			break;
+		}
+		if (arg && *arg != '\0') {
+			if (parse_addr(ctx,
+			    &ifo->req_addr, &ifo->req_mask, arg) != 0)
+				return -1;
+		} else {
+			ifo->req_addr.s_addr = 0;
+			ifo->req_mask.s_addr = 0;
+		}
+		ifo->options |= DHCPCD_INFORM | DHCPCD_PERSISTENT;
+		ifo->options &= ~(DHCPCD_ARP | DHCPCD_STATIC);
+		break;
+	case 't':
+		ifo->timeout = (time_t)strtoi(arg, NULL, 0, 0, INT32_MAX, &e);
+		if (e) {
+			logger(ctx, LOG_ERR, "failed to convert timeout");
+			return -1;
+		}
+		break;
+	case 'u':
+		s = USERCLASS_MAX_LEN - ifo->userclass[0] - 1;
+		s = parse_string((char *)ifo->userclass +
+		    ifo->userclass[0] + 2, (size_t)s, arg);
+		if (s == -1) {
+			logger(ctx, LOG_ERR, "userclass: %m");
+			return -1;
+		}
+		if (s != 0) {
+			ifo->userclass[ifo->userclass[0] + 1] = (uint8_t)s;
+			ifo->userclass[0] = (uint8_t)(ifo->userclass[0] + s +1);
+		}
+		break;
+	case 'v':
+		p = strchr(arg, ',');
+		if (!p || !p[1]) {
+			logger(ctx, LOG_ERR, "invalid vendor format: %s", arg);
+			return -1;
+		}
+
+		/* If vendor starts with , then it is not encapsulated */
+		if (p == arg) {
+			arg++;
+			s = parse_string((char *)ifo->vendor + 1,
+			    VENDOR_MAX_LEN, arg);
+			if (s == -1) {
+				logger(ctx, LOG_ERR, "vendor: %m");
+				return -1;
+			}
+			ifo->vendor[0] = (uint8_t)s;
+			ifo->options |= DHCPCD_VENDORRAW;
+			break;
+		}
+
+		/* Encapsulated vendor options */
+		if (ifo->options & DHCPCD_VENDORRAW) {
+			ifo->options &= ~DHCPCD_VENDORRAW;
+			ifo->vendor[0] = 0;
+		}
+
+		/* Strip and preserve the comma */
+		*p = '\0';
+		i = (int)strtoi(arg, NULL, 0, 1, 254, &e);
+		*p = ',';
+		if (e) {
+			logger(ctx, LOG_ERR, "vendor option should be between"
+			    " 1 and 254 inclusive");
+			return -1;
+		}
+
+		arg = p + 1;
+		s = VENDOR_MAX_LEN - ifo->vendor[0] - 2;
+		if (inet_aton(arg, &addr) == 1) {
+			if (s < 6) {
+				s = -1;
+				errno = ENOBUFS;
+			} else {
+				memcpy(ifo->vendor + ifo->vendor[0] + 3,
+				    &addr.s_addr, sizeof(addr.s_addr));
+				s = sizeof(addr.s_addr);
+			}
+		} else {
+			s = parse_string((char *)ifo->vendor +
+			    ifo->vendor[0] + 3, (size_t)s, arg);
+		}
+		if (s == -1) {
+			logger(ctx, LOG_ERR, "vendor: %m");
+			return -1;
+		}
+		if (s != 0) {
+			ifo->vendor[ifo->vendor[0] + 1] = (uint8_t)i;
+			ifo->vendor[ifo->vendor[0] + 2] = (uint8_t)s;
+			ifo->vendor[0] = (uint8_t)(ifo->vendor[0] + s + 2);
+		}
+		break;
+	case 'w':
+		ifo->options |= DHCPCD_WAITIP;
+		if (arg != NULL && arg[0] != '\0') {
+			if (arg[0] == '4' || arg[1] == '4')
+				ifo->options |= DHCPCD_WAITIP4;
+			if (arg[0] == '6' || arg[1] == '6')
+				ifo->options |= DHCPCD_WAITIP6;
+		}
+		break;
+	case 'y':
+		ifo->reboot = (time_t)strtoi(arg, NULL, 0, 0, UINT32_MAX, &e);
+		if (e) {
+			logger(ctx, LOG_ERR, "failed to convert reboot %s", arg);
+			return -1;
+		}
+		break;
+	case 'z':
+		if (ifname == NULL)
+			ctx->ifav = splitv(ctx, &ctx->ifac, ctx->ifav, arg);
+		break;
+	case 'A':
+		ifo->options &= ~DHCPCD_ARP;
+		/* IPv4LL requires ARP */
+		ifo->options &= ~DHCPCD_IPV4LL;
+		break;
+	case 'B':
+		ifo->options &= ~DHCPCD_DAEMONISE;
+		break;
+	case 'C':
+		/* Commas to spaces for shell */
+		while ((p = strchr(arg, ',')))
+			*p = ' ';
+		dl = strlen("skip_hooks=") + strlen(arg) + 1;
+		p = malloc(sizeof(char) * dl);
+		if (p == NULL) {
+			logger(ctx, LOG_ERR, "%s: %m", __func__);
+			return -1;
+		}
+		snprintf(p, dl, "skip_hooks=%s", arg);
+		add_environ(ctx, ifo, p, 0);
+		free(p);
+		break;
+	case 'D':
+		ifo->options |= DHCPCD_CLIENTID | DHCPCD_DUID;
+		break;
+	case 'E':
+		ifo->options |= DHCPCD_LASTLEASE;
+		break;
+	case 'F':
+		if (!arg) {
+			ifo->fqdn = FQDN_BOTH;
+			break;
+		}
+		if (strcmp(arg, "none") == 0)
+			ifo->fqdn = FQDN_NONE;
+		else if (strcmp(arg, "ptr") == 0)
+			ifo->fqdn = FQDN_PTR;
+		else if (strcmp(arg, "both") == 0)
+			ifo->fqdn = FQDN_BOTH;
+		else if (strcmp(arg, "disable") == 0)
+			ifo->fqdn = FQDN_DISABLE;
+		else {
+			logger(ctx, LOG_ERR, "invalid value `%s' for FQDN", arg);
+			return -1;
+		}
+		break;
+	case 'G':
+		ifo->options &= ~DHCPCD_GATEWAY;
+		break;
+	case 'H':
+		ifo->options |= DHCPCD_XID_HWADDR;
+		break;
+	case 'I':
+		/* Strings have a type of 0 */;
+		ifo->clientid[1] = 0;
+		if (arg)
+			s = parse_string_hwaddr((char *)ifo->clientid + 1,
+			    CLIENTID_MAX_LEN, arg, 1);
+		else
+			s = 0;
+		if (s == -1) {
+			logger(ctx, LOG_ERR, "clientid: %m");
+			return -1;
+		}
+		ifo->options |= DHCPCD_CLIENTID;
+		ifo->clientid[0] = (uint8_t)s;
+		break;
+	case 'J':
+		ifo->options |= DHCPCD_BROADCAST;
+		break;
+	case 'K':
+		ifo->options &= ~DHCPCD_LINK;
+		break;
+	case 'L':
+		ifo->options &= ~DHCPCD_IPV4LL;
+		break;
+	case 'M':
+		ifo->options |= DHCPCD_MASTER;
+		break;
+	case 'O':
+		arg = set_option_space(ctx, arg, &d, &dl, &od, &odl, ifo,
+		    &request, &require, &no, &reject);
+		if (make_option_mask(d, dl, od, odl, request, arg, -1) != 0 ||
+		    make_option_mask(d, dl, od, odl, require, arg, -1) != 0 ||
+		    make_option_mask(d, dl, od, odl, no, arg, 1) != 0)
+		{
+			logger(ctx, LOG_ERR, "unknown option `%s'", arg);
+			return -1;
+		}
+		break;
+	case 'P':
+		ifo->options |= DHCPCD_UNICAST_ARP;
+		break;
+	case 'Q':
+		arg = set_option_space(ctx, arg, &d, &dl, &od, &odl, ifo,
+		    &request, &require, &no, &reject);
+		if (make_option_mask(d, dl, od, odl, require, arg, 1) != 0 ||
+		    make_option_mask(d, dl, od, odl, request, arg, 1) != 0 ||
+		    make_option_mask(d, dl, od, odl, no, arg, -1) != 0 ||
+		    make_option_mask(d, dl, od, odl, reject, arg, -1) != 0)
+		{
+			logger(ctx, LOG_ERR, "unknown option `%s'", arg);
+			return -1;
+		}
+		break;
+	case 'R':
+		ifo->options |= DHCPCD_ARPGW;
+		break;
+	case 'S':
+		p = strchr(arg, '=');
+		if (p == NULL) {
+			logger(ctx, LOG_ERR, "static assignment required");
+			return -1;
+		}
+		p++;
+		if (strncmp(arg, "ip_address=", strlen("ip_address=")) == 0) {
+			if (parse_addr(ctx, &ifo->req_addr,
+			    ifo->req_mask.s_addr == 0 ? &ifo->req_mask : NULL,
+			    p) != 0)
+				return -1;
+
+			ifo->options |= DHCPCD_STATIC;
+			ifo->options &= ~DHCPCD_INFORM;
+		} else if (strncmp(arg, "subnet_mask=",
+		    strlen("subnet_mask=")) == 0)
+		{
+			if (parse_addr(ctx, &ifo->req_mask, NULL, p) != 0)
+				return -1;
+		} else if (strncmp(arg, "routes=", strlen("routes=")) == 0 ||
+		    strncmp(arg, "static_routes=",
+		        strlen("static_routes=")) == 0 ||
+		    strncmp(arg, "classless_static_routes=",
+		        strlen("classless_static_routes=")) == 0 ||
+		    strncmp(arg, "ms_classless_static_routes=",
+		        strlen("ms_classless_static_routes=")) == 0)
+		{
+			fp = np = strwhite(p);
+			if (np == NULL) {
+				logger(ctx, LOG_ERR,
+				    "all routes need a gateway");
+				return -1;
+			}
+			*np++ = '\0';
+			np = strskipwhite(np);
+			if (ifo->routes == NULL) {
+				ifo->routes = malloc(sizeof(*ifo->routes));
+				if (ifo->routes == NULL) {
+					logger(ctx, LOG_ERR,
+					    "%s: %m", __func__);
+					return -1;
+				}
+				TAILQ_INIT(ifo->routes);
+			}
+			rt = calloc(1, sizeof(*rt));
+			if (rt == NULL) {
+				logger(ctx, LOG_ERR, "%s: %m", __func__);
+				*fp = ' ';
+				return -1;
+			}
+			if (parse_addr(ctx, &rt->dest, &rt->net, p) == -1 ||
+			    parse_addr(ctx, &rt->gate, NULL, np) == -1)
+			{
+				free(rt);
+				*fp = ' ';
+				return -1;
+			}
+			TAILQ_INSERT_TAIL(ifo->routes, rt, next);
+			*fp = ' ';
+		} else if (strncmp(arg, "routers=", strlen("routers=")) == 0) {
+			if (ifo->routes == NULL) {
+				ifo->routes = malloc(sizeof(*ifo->routes));
+				if (ifo->routes == NULL) {
+					logger(ctx, LOG_ERR,
+					    "%s: %m", __func__);
+					return -1;
+				}
+				TAILQ_INIT(ifo->routes);
+			}
+			rt = calloc(1, sizeof(*rt));
+			if (rt == NULL) {
+				logger(ctx, LOG_ERR, "%s: %m", __func__);
+				return -1;
+			}
+			rt->dest.s_addr = INADDR_ANY;
+			rt->net.s_addr = INADDR_ANY;
+			if (parse_addr(ctx, &rt->gate, NULL, p) == -1) {
+				free(rt);
+				return -1;
+			}
+			TAILQ_INSERT_TAIL(ifo->routes, rt, next);
+		} else {
+			dl = 0;
+			if (ifo->config != NULL) {
+				while (ifo->config[dl] != NULL) {
+					if (strncmp(ifo->config[dl], arg,
+						(size_t)(p - arg)) == 0)
+					{
+						p = strdup(arg);
+						if (p == NULL) {
+							logger(ctx, LOG_ERR,
+							    "%s: %m", __func__);
+							return -1;
+						}
+						free(ifo->config[dl]);
+						ifo->config[dl] = p;
+						return 1;
+					}
+					dl++;
+				}
+			}
+			p = strdup(arg);
+			if (p == NULL) {
+				logger(ctx, LOG_ERR, "%s: %m", __func__);
+				return -1;
+			}
+			nconf = realloc(ifo->config, sizeof(char *) * (dl + 2));
+			if (nconf == NULL) {
+				logger(ctx, LOG_ERR, "%s: %m", __func__);
+				return -1;
+			}
+			ifo->config = nconf;
+			ifo->config[dl] = p;
+			ifo->config[dl + 1] = NULL;
+		}
+		break;
+	case 'W':
+		if (parse_addr(ctx, &addr, &addr2, arg) != 0)
+			return -1;
+		if (strchr(arg, '/') == NULL)
+			addr2.s_addr = INADDR_BROADCAST;
+		naddr = realloc(ifo->whitelist,
+		    sizeof(in_addr_t) * (ifo->whitelist_len + 2));
+		if (naddr == NULL) {
+			logger(ctx, LOG_ERR, "%s: %m", __func__);
+			return -1;
+		}
+		ifo->whitelist = naddr;
+		ifo->whitelist[ifo->whitelist_len++] = addr.s_addr;
+		ifo->whitelist[ifo->whitelist_len++] = addr2.s_addr;
+		break;
+	case 'X':
+		if (parse_addr(ctx, &addr, &addr2, arg) != 0)
+			return -1;
+		if (strchr(arg, '/') == NULL)
+			addr2.s_addr = INADDR_BROADCAST;
+		naddr = realloc(ifo->blacklist,
+		    sizeof(in_addr_t) * (ifo->blacklist_len + 2));
+		if (naddr == NULL) {
+			logger(ctx, LOG_ERR, "%s: %m", __func__);
+			return -1;
+		}
+		ifo->blacklist = naddr;
+		ifo->blacklist[ifo->blacklist_len++] = addr.s_addr;
+		ifo->blacklist[ifo->blacklist_len++] = addr2.s_addr;
+		break;
+	case 'Z':
+		if (ifname == NULL)
+			ctx->ifdv = splitv(ctx, &ctx->ifdc, ctx->ifdv, arg);
+		break;
+	case '4':
+		ifo->options &= ~DHCPCD_IPV6;
+		ifo->options |= DHCPCD_IPV4;
+		break;
+	case '6':
+		ifo->options &= ~DHCPCD_IPV4;
+		ifo->options |= DHCPCD_IPV6;
+		break;
+	case O_IPV4:
+		ifo->options |= DHCPCD_IPV4;
+		break;
+	case O_NOIPV4:
+		ifo->options &= ~DHCPCD_IPV4;
+		break;
+	case O_IPV6:
+		ifo->options |= DHCPCD_IPV6;
+		break;
+	case O_NOIPV6:
+		ifo->options &= ~DHCPCD_IPV6;
+		break;
+#ifdef INET
+	case O_ARPING:
+		while (arg && *arg != '\0') {
+			fp = strwhite(arg);
+			if (fp)
+				*fp++ = '\0';
+			if (parse_addr(ctx, &addr, NULL, arg) != 0)
+				return -1;
+			naddr = realloc(ifo->arping,
+			    sizeof(in_addr_t) * (ifo->arping_len + 1));
+			if (naddr == NULL) {
+				logger(ctx, LOG_ERR, "%s: %m", __func__);
+				return -1;
+			}
+			ifo->arping = naddr;
+			ifo->arping[ifo->arping_len++] = addr.s_addr;
+			arg = strskipwhite(fp);
+		}
+		break;
+	case O_DESTINATION:
+		arg = set_option_space(ctx, arg, &d, &dl, &od, &odl, ifo,
+		    &request, &require, &no, &reject);
+		if (make_option_mask(d, dl, od, odl,
+		    ifo->dstmask, arg, 2) != 0)
+		{
+			if (errno == EINVAL)
+				logger(ctx, LOG_ERR, "option `%s' does not take"
+				    " an IPv4 address", arg);
+			else
+				logger(ctx, LOG_ERR, "unknown option `%s'", arg);
+			return -1;
+		}
+		break;
+	case O_FALLBACK:
+		free(ifo->fallback);
+		ifo->fallback = strdup(arg);
+		if (ifo->fallback == NULL) {
+			logger(ctx, LOG_ERR, "%s: %m", __func__);
+			return -1;
+		}
+		break;
+#endif
+	case O_IAID:
+		if (ifname == NULL) {
+			logger(ctx, LOG_ERR,
+			    "IAID must belong in an interface block");
+			return -1;
+		}
+		if (parse_iaid(ifo->iaid, arg, sizeof(ifo->iaid)) == -1) {
+			logger(ctx, LOG_ERR, "invalid IAID %s", arg);
+			return -1;
+		}
+		ifo->options |= DHCPCD_IAID;
+		break;
+	case O_IPV6RS:
+		ifo->options |= DHCPCD_IPV6RS;
+		break;
+	case O_NOIPV6RS:
+		ifo->options &= ~DHCPCD_IPV6RS;
+		break;
+	case O_IPV6RA_FORK:
+		ifo->options &= ~DHCPCD_IPV6RA_REQRDNSS;
+		break;
+	case O_IPV6RA_OWN:
+		ifo->options |= DHCPCD_IPV6RA_OWN;
+		break;
+	case O_IPV6RA_OWN_D:
+		ifo->options |= DHCPCD_IPV6RA_OWN_DEFAULT;
+		break;
+	case O_IPV6RA_ACCEPT_NOPUBLIC:
+		ifo->options |= DHCPCD_IPV6RA_ACCEPT_NOPUBLIC;
+		break;
+	case O_IPV6RA_AUTOCONF:
+		ifo->options |= DHCPCD_IPV6RA_AUTOCONF;
+		break;
+	case O_IPV6RA_NOAUTOCONF:
+		ifo->options &= ~DHCPCD_IPV6RA_AUTOCONF;
+		break;
+	case O_NOALIAS:
+		ifo->options |= DHCPCD_NOALIAS;
+		break;
+#ifdef INET6
+	case O_IA_NA:
+		i = D6_OPTION_IA_NA;
+		/* FALLTHROUGH */
+	case O_IA_TA:
+		if (i == 0)
+			i = D6_OPTION_IA_TA;
+		/* FALLTHROUGH */
+	case O_IA_PD:
+		if (i == 0) {
+			if (ifname == NULL) {
+				logger(ctx, LOG_ERR,
+				    "IA PD must belong in an interface block");
+				return -1;
+			}
+			i = D6_OPTION_IA_PD;
+		}
+		if (ifname == NULL && arg) {
+			logger(ctx, LOG_ERR,
+			    "IA with IAID must belong in an interface block");
+			return -1;
+		}
+		ifo->options |= DHCPCD_IA_FORCED;
+		fp = strwhite(arg);
+		if (fp) {
+			*fp++ = '\0';
+			fp = strskipwhite(fp);
+		}
+		if (arg) {
+			p = strchr(arg, '/');
+			if (p)
+				*p++ = '\0';
+			if (parse_iaid(iaid, arg, sizeof(iaid)) == -1) {
+				logger(ctx, LOG_ERR, "invalid IAID: %s", arg);
+				return -1;
+			}
+		}
+		ia = NULL;
+		for (sl = 0; sl < ifo->ia_len; sl++) {
+			if ((arg == NULL && !ifo->ia[sl].iaid_set) ||
+			    (ifo->ia[sl].iaid_set &&
+			    ifo->ia[sl].iaid[0] == iaid[0] &&
+			    ifo->ia[sl].iaid[1] == iaid[1] &&
+			    ifo->ia[sl].iaid[2] == iaid[2] &&
+			    ifo->ia[sl].iaid[3] == iaid[3]))
+			{
+			        ia = &ifo->ia[sl];
+				break;
+			}
+		}
+		if (ia && ia->ia_type != (uint16_t)i) {
+			logger(ctx, LOG_ERR, "Cannot mix IA for the same IAID");
+			break;
+		}
+		if (ia == NULL) {
+			ia = realloc(ifo->ia,
+			    sizeof(*ifo->ia) * (ifo->ia_len + 1));
+			if (ia == NULL) {
+				logger(ctx, LOG_ERR, "%s: %m", __func__);
+				return -1;
+			}
+			ifo->ia = ia;
+			ia = &ifo->ia[ifo->ia_len++];
+			ia->ia_type = (uint16_t)i;
+			if (arg) {
+				ia->iaid[0] = iaid[0];
+				ia->iaid[1] = iaid[1];
+				ia->iaid[2] = iaid[2];
+				ia->iaid[3] = iaid[3];
+				ia->iaid_set = 1;
+			} else
+				ia->iaid_set = 0;
+			if (!ia->iaid_set ||
+			    p == NULL ||
+			    ia->ia_type == D6_OPTION_IA_TA)
+			{
+				memset(&ia->addr, 0, sizeof(ia->addr));
+				ia->prefix_len = 0;
+			} else {
+				arg = p;
+				p = strchr(arg, '/');
+				if (p)
+					*p++ = '\0';
+				if (inet_pton(AF_INET6, arg, &ia->addr) == -1) {
+					logger(ctx, LOG_ERR, "%s: %m", arg);
+					memset(&ia->addr, 0, sizeof(ia->addr));
+				}
+				if (p && ia->ia_type == D6_OPTION_IA_PD) {
+					i = (int)strtoi(p, NULL, 0, 8, 120, &e);
+					if (e) {
+						logger(ctx, LOG_ERR,
+						    "%s: failed to convert"
+						    " prefix len",
+						    p);
+						ia->prefix_len = 0;
+					} else
+						ia->prefix_len = (uint8_t)i;
+				}
+			}
+			ia->sla_max = 0;
+			ia->sla_len = 0;
+			ia->sla = NULL;
+		}
+		if (ia->ia_type != D6_OPTION_IA_PD)
+			break;
+		for (p = fp; p; p = fp) {
+			fp = strwhite(p);
+			if (fp) {
+				*fp++ = '\0';
+				fp = strskipwhite(fp);
+			}
+			sla = realloc(ia->sla,
+			    sizeof(*ia->sla) * (ia->sla_len + 1));
+			if (sla == NULL) {
+				logger(ctx, LOG_ERR, "%s: %m", __func__);
+				return -1;
+			}
+			ia->sla = sla;
+			sla = &ia->sla[ia->sla_len++];
+			np = strchr(p, '/');
+			if (np)
+				*np++ = '\0';
+			if (strlcpy(sla->ifname, p,
+			    sizeof(sla->ifname)) >= sizeof(sla->ifname))
+			{
+				logger(ctx, LOG_ERR, "%s: interface name too long",
+				    arg);
+				goto err_sla;
+			}
+			p = np;
+			if (p) {
+				np = strchr(p, '/');
+				if (np)
+					*np++ = '\0';
+				if (*p == '\0')
+					sla->sla_set = 0;
+				else {
+					sla->sla = (uint32_t)strtou(p, NULL,
+					    0, 0, UINT32_MAX, &e);
+					sla->sla_set = 1;
+					if (e) {
+						logger(ctx, LOG_ERR,
+						    "%s: failed to convert sla",
+						    ifname);
+						goto err_sla;
+					}
+				}
+				if (np) {
+					sla->prefix_len = (uint8_t)strtoi(np,
+					    NULL, 0, 0, 128, &e);
+					if (e) {
+						logger(ctx, LOG_ERR, "%s: failed to "
+						    "convert prefix len",
+						    ifname);
+						goto err_sla;
+					}
+				} else
+					sla->prefix_len = 0;
+			} else {
+				sla->sla_set = 0;
+				sla->prefix_len = 0;
+			}
+			/* Sanity check */
+			for (sl = 0; sl < ia->sla_len - 1; sl++) {
+				slap = &ia->sla[sl];
+				if (slap->sla_set != sla->sla_set) {
+					logger(ctx, LOG_WARNING,
+					    "%s: cannot mix automatic "
+					    "and fixed SLA",
+					    sla->ifname);
+					goto err_sla;
+				}
+				if (sla->sla_set == 0 &&
+				    strcmp(slap->ifname, sla->ifname) == 0)
+				{
+					logger(ctx, LOG_WARNING,
+					    "%s: cannot specify the "
+					    "same interface twice with "
+					    "an automatic SLA",
+					    sla->ifname);
+					goto err_sla;
+				}
+				if (slap->sla == 0 || sla->sla == 0) {
+					logger(ctx, LOG_ERR, "%s: cannot"
+					    " assign multiple prefixes"
+					    " with a SLA of 0",
+					    ifname);
+					goto err_sla;
+				}
+			}
+			if (sla->sla_set && sla->sla > ia->sla_max)
+				ia->sla_max = sla->sla;
+		}
+		break;
+err_sla:
+		ia->sla_len--;
+		return -1;
+#endif
+	case O_HOSTNAME_SHORT:
+		ifo->options |= DHCPCD_HOSTNAME | DHCPCD_HOSTNAME_SHORT;
+		break;
+	case O_DEV:
+#ifdef PLUGIN_DEV
+		if (ctx->dev_load)
+			free(ctx->dev_load);
+		ctx->dev_load = strdup(arg);
+#endif
+		break;
+	case O_NODEV:
+		ifo->options &= ~DHCPCD_DEV;
+		break;
+	case O_DEFINE:
+		dop = &ifo->dhcp_override;
+		dop_len = &ifo->dhcp_override_len;
+		/* FALLTHROUGH */
+	case O_DEFINE6:
+		if (dop == NULL) {
+			dop = &ifo->dhcp6_override;
+			dop_len = &ifo->dhcp6_override_len;
+		}
+		/* FALLTHROUGH */
+	case O_VENDOPT:
+		if (dop == NULL) {
+			dop = &ifo->vivso_override;
+			dop_len = &ifo->vivso_override_len;
+		}
+		*edop = *ldop = NULL;
+		/* FALLTHROUGH */
+	case O_EMBED:
+		if (dop == NULL) {
+			if (*edop) {
+				dop = &(*edop)->embopts;
+				dop_len = &(*edop)->embopts_len;
+			} else if (ldop) {
+				dop = &(*ldop)->embopts;
+				dop_len = &(*ldop)->embopts_len;
+			} else {
+				logger(ctx, LOG_ERR,
+				    "embed must be after a define or encap");
+				return -1;
+			}
+		}
+		/* FALLTHROUGH */
+	case O_ENCAP:
+		if (dop == NULL) {
+			if (*ldop == NULL) {
+				logger(ctx, LOG_ERR, "encap must be after a define");
+				return -1;
+			}
+			dop = &(*ldop)->encopts;
+			dop_len = &(*ldop)->encopts_len;
+		}
+
+		/* Shared code for define, define6, embed and encap */
+
+		/* code */
+		if (opt == O_EMBED) /* Embedded options don't have codes */
+			u = 0;
+		else {
+			fp = strwhite(arg);
+			if (fp == NULL) {
+				logger(ctx, LOG_ERR, "invalid syntax: %s", arg);
+				return -1;
+			}
+			*fp++ = '\0';
+			u = (uint32_t)strtou(arg, NULL, 0, 0, UINT32_MAX, &e);
+			if (e) {
+				logger(ctx, LOG_ERR, "invalid code: %s", arg);
+				return -1;
+			}
+			arg = strskipwhite(fp);
+			if (arg == NULL) {
+				logger(ctx, LOG_ERR, "invalid syntax");
+				return -1;
+			}
+		}
+		/* type */
+		fp = strwhite(arg);
+		if (fp)
+			*fp++ = '\0';
+		np = strchr(arg, ':');
+		/* length */
+		if (np) {
+			*np++ = '\0';
+			l = (long)strtou(np, NULL, 0, 0, LONG_MAX, &e);
+			if (e) {
+				logger(ctx, LOG_ERR, "failed to convert length");
+				return -1;
+			}
+		} else
+			l = 0;
+		t = 0;
+		if (strcasecmp(arg, "request") == 0) {
+			t |= REQUEST;
+			arg = strskipwhite(fp);
+			fp = strwhite(arg);
+			if (fp == NULL) {
+				logger(ctx, LOG_ERR, "incomplete request type");
+				return -1;
+			}
+			*fp++ = '\0';
+		} else if (strcasecmp(arg, "norequest") == 0) {
+			t |= NOREQ;
+			arg = strskipwhite(fp);
+			fp = strwhite(arg);
+			if (fp == NULL) {
+				logger(ctx, LOG_ERR, "incomplete request type");
+				return -1;
+			}
+			*fp++ = '\0';
+		}
+		if (strcasecmp(arg, "index") == 0) {
+			t |= INDEX;
+			arg = strskipwhite(fp);
+			fp = strwhite(arg);
+			if (fp == NULL) {
+				logger(ctx, LOG_ERR, "incomplete index type");
+				return -1;
+			}
+			*fp++ = '\0';
+		}
+		if (strcasecmp(arg, "array") == 0) {
+			t |= ARRAY;
+			arg = strskipwhite(fp);
+			fp = strwhite(arg);
+			if (fp == NULL) {
+				logger(ctx, LOG_ERR, "incomplete array type");
+				return -1;
+			}
+			*fp++ = '\0';
+		}
+		if (strcasecmp(arg, "ipaddress") == 0)
+			t |= ADDRIPV4;
+		else if (strcasecmp(arg, "ip6address") == 0)
+			t |= ADDRIPV6;
+		else if (strcasecmp(arg, "string") == 0)
+			t |= STRING;
+		else if (strcasecmp(arg, "byte") == 0)
+			t |= UINT8;
+		else if (strcasecmp(arg, "uint16") == 0)
+			t |= UINT16;
+		else if (strcasecmp(arg, "int16") == 0)
+			t |= SINT16;
+		else if (strcasecmp(arg, "uint32") == 0)
+			t |= UINT32;
+		else if (strcasecmp(arg, "int32") == 0)
+			t |= SINT32;
+		else if (strcasecmp(arg, "flag") == 0)
+			t |= FLAG;
+		else if (strcasecmp(arg, "raw") == 0)
+			t |= STRING | RAW;
+		else if (strcasecmp(arg, "ascii") == 0)
+			t |= STRING | ASCII;
+		else if (strcasecmp(arg, "domain") == 0)
+			t |= STRING | DOMAIN | RFC3397;
+		else if (strcasecmp(arg, "dname") == 0)
+			t |= STRING | DOMAIN;
+		else if (strcasecmp(arg, "binhex") == 0)
+			t |= STRING | BINHEX;
+		else if (strcasecmp(arg, "embed") == 0)
+			t |= EMBED;
+		else if (strcasecmp(arg, "encap") == 0)
+			t |= ENCAP;
+		else if (strcasecmp(arg, "rfc3361") ==0)
+			t |= STRING | RFC3361;
+		else if (strcasecmp(arg, "rfc3442") ==0)
+			t |= STRING | RFC3442;
+		else if (strcasecmp(arg, "rfc5969") == 0)
+			t |= STRING | RFC5969;
+		else if (strcasecmp(arg, "option") == 0)
+			t |= OPTION;
+		else {
+			logger(ctx, LOG_ERR, "unknown type: %s", arg);
+			return -1;
+		}
+		if (l && !(t & (STRING | BINHEX))) {
+			logger(ctx, LOG_WARNING,
+			    "ignoring length for type `%s'", arg);
+			l = 0;
+		}
+		if (t & ARRAY && t & (STRING | BINHEX) &&
+		    !(t & (RFC3397 | DOMAIN)))
+		{
+			logger(ctx, LOG_WARNING, "ignoring array for strings");
+			t &= ~ARRAY;
+		}
+		/* variable */
+		if (!fp) {
+			if (!(t & OPTION)) {
+			        logger(ctx, LOG_ERR,
+				    "type %s requires a variable name", arg);
+				return -1;
+			}
+			np = NULL;
+		} else {
+			arg = strskipwhite(fp);
+			fp = strwhite(arg);
+			if (fp)
+				*fp++ = '\0';
+			np = strdup(arg);
+			if (np == NULL) {
+				logger(ctx, LOG_ERR, "%s: %m", __func__);
+				return -1;
+			}
+		}
+		if (opt != O_EMBED) {
+			for (dl = 0, ndop = *dop; dl < *dop_len; dl++, ndop++)
+			{
+				/* type 0 seems freshly malloced struct
+				 * for us to use */
+				if (ndop->option == u || ndop->type == 0)
+					break;
+			}
+			if (dl == *dop_len)
+				ndop = NULL;
+		} else
+			ndop = NULL;
+		if (ndop == NULL) {
+			if ((ndop = realloc(*dop,
+			    sizeof(**dop) * ((*dop_len) + 1))) == NULL)
+			{
+				logger(ctx, LOG_ERR, "%s: %m", __func__);
+				free(np);
+				return -1;
+			}
+			*dop = ndop;
+			ndop = &(*dop)[(*dop_len)++];
+			ndop->embopts = NULL;
+			ndop->embopts_len = 0;
+			ndop->encopts = NULL;
+			ndop->encopts_len = 0;
+		} else
+			free_dhcp_opt_embenc(ndop);
+		ndop->option = (uint32_t)u; /* could have been 0 */
+		ndop->type = t;
+		ndop->len = (size_t)l;
+		ndop->var = np;
+		/* Save the define for embed and encap options */
+		if (opt == O_DEFINE || opt == O_DEFINE6 || opt == O_VENDOPT)
+			*ldop = ndop;
+		else if (opt == O_ENCAP)
+			*edop = ndop;
+		break;
+	case O_VENDCLASS:
+		fp = strwhite(arg);
+		if (fp)
+			*fp++ = '\0';
+		u = (uint32_t)strtou(arg, NULL, 0, 0, UINT32_MAX, &e);
+		if (e) {
+			logger(ctx, LOG_ERR, "invalid code: %s", arg);
+			return -1;
+		}
+		if (fp) {
+			s = parse_string(NULL, 0, fp);
+			if (s == -1) {
+				logger(ctx, LOG_ERR, "%s: %m", __func__);
+				return -1;
+			}
+			dl = (size_t)s;
+			if (dl + (sizeof(uint16_t) * 2) > UINT16_MAX) {
+				logger(ctx, LOG_ERR, "vendor class is too big");
+				return -1;
+			}
+			np = malloc(dl);
+			if (np == NULL) {
+				logger(ctx, LOG_ERR, "%s: %m", __func__);
+				return -1;
+			}
+			parse_string(np, dl, fp);
+		} else {
+			dl = 0;
+			np = NULL;
+		}
+		vivco = realloc(ifo->vivco, sizeof(*ifo->vivco) *
+		    (ifo->vivco_len + 1));
+		if (vivco == NULL) {
+			logger(ctx, LOG_ERR, "%s: %m", __func__);
+			return -1;
+		}
+		ifo->vivco = vivco;
+		ifo->vivco_en = (uint32_t)u;
+		vivco = &ifo->vivco[ifo->vivco_len++];
+		vivco->len = dl;
+		vivco->data = (uint8_t *)np;
+		break;
+	case O_AUTHPROTOCOL:
+		fp = strwhite(arg);
+		if (fp)
+			*fp++ = '\0';
+		if (strcasecmp(arg, "token") == 0)
+			ifo->auth.protocol = AUTH_PROTO_TOKEN;
+		else if (strcasecmp(arg, "delayed") == 0)
+			ifo->auth.protocol = AUTH_PROTO_DELAYED;
+		else if (strcasecmp(arg, "delayedrealm") == 0)
+			ifo->auth.protocol = AUTH_PROTO_DELAYEDREALM;
+		else {
+			logger(ctx, LOG_ERR, "%s: unsupported protocol", arg);
+			return -1;
+		}
+		arg = strskipwhite(fp);
+		fp = strwhite(arg);
+		if (arg == NULL) {
+			ifo->auth.options |= DHCPCD_AUTH_SEND;
+			ifo->auth.algorithm = AUTH_ALG_HMAC_MD5;
+			ifo->auth.rdm = AUTH_RDM_MONOTONIC;
+			break;
+		}
+		if (fp)
+			*fp++ = '\0';
+		if (strcasecmp(arg, "hmacmd5") == 0 ||
+		    strcasecmp(arg, "hmac-md5") == 0)
+			ifo->auth.algorithm = AUTH_ALG_HMAC_MD5;
+		else {
+			logger(ctx, LOG_ERR, "%s: unsupported algorithm", arg);
+			return 1;
+		}
+		arg = fp;
+		if (arg == NULL) {
+			ifo->auth.options |= DHCPCD_AUTH_SEND;
+			ifo->auth.rdm = AUTH_RDM_MONOTONIC;
+			break;
+		}
+		if (strcasecmp(arg, "monocounter") == 0) {
+			ifo->auth.rdm = AUTH_RDM_MONOTONIC;
+			ifo->auth.options |= DHCPCD_AUTH_RDM_COUNTER;
+		} else if (strcasecmp(arg, "monotonic") ==0 ||
+		    strcasecmp(arg, "monotime") == 0)
+			ifo->auth.rdm = AUTH_RDM_MONOTONIC;
+		else {
+			logger(ctx, LOG_ERR, "%s: unsupported RDM", arg);
+			return -1;
+		}
+		ifo->auth.options |= DHCPCD_AUTH_SEND;
+		break;
+	case O_AUTHTOKEN:
+		fp = strwhite(arg);
+		if (fp == NULL) {
+			logger(ctx, LOG_ERR, "authtoken requires a realm");
+			return -1;
+		}
+		*fp++ = '\0';
+		token = malloc(sizeof(*token));
+		if (token == NULL) {
+			logger(ctx, LOG_ERR, "%s: %m", __func__);
+			free(token);
+			return -1;
+		}
+		if (parse_uint32(&token->secretid, arg) == -1) {
+			logger(ctx, LOG_ERR, "%s: not a number", arg);
+			free(token);
+			return -1;
+		}
+		arg = fp;
+		fp = strend(arg);
+		if (fp == NULL) {
+			logger(ctx, LOG_ERR, "authtoken requies an a key");
+			free(token);
+			return -1;
+		}
+		*fp++ = '\0';
+		s = parse_string(NULL, 0, arg);
+		if (s == -1) {
+			logger(ctx, LOG_ERR, "realm_len: %m");
+			free(token);
+			return -1;
+		}
+		if (s) {
+			token->realm_len = (size_t)s;
+			token->realm = malloc(token->realm_len);
+			if (token->realm == NULL) {
+				free(token);
+				logger(ctx, LOG_ERR, "%s: %m", __func__);
+				return -1;
+			}
+			parse_string((char *)token->realm, token->realm_len,
+			    arg);
+		} else {
+			token->realm_len = 0;
+			token->realm = NULL;
+		}
+		arg = fp;
+		fp = strend(arg);
+		if (fp == NULL) {
+			logger(ctx, LOG_ERR, "authtoken requies an an expiry date");
+			free(token->realm);
+			free(token);
+			return -1;
+		}
+		*fp++ = '\0';
+		if (*arg == '"') {
+			arg++;
+			np = strchr(arg, '"');
+			if (np)
+				*np = '\0';
+		}
+		if (strcmp(arg, "0") == 0 || strcasecmp(arg, "forever") == 0)
+			token->expire =0;
+		else {
+			struct tm tm;
+
+			memset(&tm, 0, sizeof(tm));
+			if (strptime(arg, "%Y-%m-%d %H:%M", &tm) == NULL) {
+				logger(ctx, LOG_ERR, "%s: invalid date time", arg);
+				free(token->realm);
+				free(token);
+				return -1;
+			}
+			if ((token->expire = mktime(&tm)) == (time_t)-1) {
+				logger(ctx, LOG_ERR, "%s: mktime: %m", __func__);
+				free(token->realm);
+				free(token);
+				return -1;
+			}
+		}
+		arg = fp;
+		s = parse_string(NULL, 0, arg);
+		if (s == -1 || s == 0) {
+			logger(ctx, LOG_ERR, s == -1 ? "token_len: %m" : 
+			    "authtoken needs a key");
+			free(token->realm);
+			free(token);
+			return -1;
+		}
+		token->key_len = (size_t)s;
+		token->key = malloc(token->key_len);
+		parse_string((char *)token->key, token->key_len, arg);
+		TAILQ_INSERT_TAIL(&ifo->auth.tokens, token, next);
+		break;
+	case O_AUTHNOTREQUIRED:
+		ifo->auth.options &= ~DHCPCD_AUTH_REQUIRE;
+		break;
+	case O_DHCP:
+		ifo->options |= DHCPCD_DHCP | DHCPCD_IPV4;
+		break;
+	case O_NODHCP:
+		ifo->options &= ~DHCPCD_DHCP;
+		break;
+	case O_DHCP6:
+		ifo->options |= DHCPCD_DHCP6 | DHCPCD_IPV6;
+		break;
+	case O_NODHCP6:
+		ifo->options &= ~DHCPCD_DHCP6;
+		break;
+	case O_CONTROLGRP:
+#ifdef _REENTRANT
+		l = sysconf(_SC_GETGR_R_SIZE_MAX);
+		if (l == -1)
+			dl = 1024;
+		else
+			dl = (size_t)l;
+		p = malloc(dl);
+		if (p == NULL) {
+			logger(ctx, LOG_ERR, "%s: malloc: %m", __func__);
+			return -1;
+		}
+		while ((i = getgrnam_r(arg, &grpbuf, p, (size_t)l, &grp)) ==
+		    ERANGE)
+		{
+			size_t nl = dl * 2;
+			if (nl < dl) {
+				logger(ctx, LOG_ERR, "control_group: out of buffer");
+				free(p);
+				return -1;
+			}
+			dl = nl;
+			np = realloc(p, dl);
+			if (np == NULL) {
+				logger(ctx, LOG_ERR, "control_group: realloc: %m");
+				free(p);
+				return -1;
+			}
+			p = np;
+		}
+		if (i != 0) {
+			errno = i;
+			logger(ctx, LOG_ERR, "getgrnam_r: %m");
+			free(p);
+			return -1;
+		}
+		if (grp == NULL) {
+			logger(ctx, LOG_ERR, "controlgroup: %s: not found", arg);
+			free(p);
+			return -1;
+		}
+		ctx->control_group = grp->gr_gid;
+		free(p);
+#else
+		grp = getgrnam(arg);
+		if (grp == NULL) {
+			logger(ctx, LOG_ERR, "controlgroup: %s: not found", arg);
+			return -1;
+		}
+		ctx->control_group = grp->gr_gid;
+#endif
+		break;
+	case O_GATEWAY:
+		ifo->options |= DHCPCD_GATEWAY;
+		break;
+	case O_SLAAC:
+		if (strcmp(arg, "private") == 0 ||
+		    strcmp(arg, "stableprivate") == 0 ||
+		    strcmp(arg, "stable") == 0)
+			ifo->options |= DHCPCD_SLAACPRIVATE;
+		else
+			ifo->options &= ~DHCPCD_SLAACPRIVATE;
+		break;
+	case O_PFXDLGMIX:
+		ifo->options |= DHCPCD_PFXDLGMIX;
+		break;
+	case O_BOOTP:
+		ifo->options |= DHCPCD_BOOTP;
+		break;
+	default:
+		return 0;
+	}
+
+	return 1;
+}
+
+static int
+parse_config_line(struct dhcpcd_ctx *ctx, const char *ifname,
+    struct if_options *ifo, const char *opt, char *line,
+    struct dhcp_opt **ldop, struct dhcp_opt **edop)
+{
+	unsigned int i;
+
+	for (i = 0; i < sizeof(cf_options) / sizeof(cf_options[0]); i++) {
+		if (!cf_options[i].name ||
+		    strcmp(cf_options[i].name, opt) != 0)
+			continue;
+
+		if (cf_options[i].has_arg == required_argument && !line) {
+			fprintf(stderr,
+			    PACKAGE ": option requires an argument -- %s\n",
+			    opt);
+			return -1;
+		}
+
+		return parse_option(ctx, ifname, ifo, cf_options[i].val, line,
+		    ldop, edop);
+	}
+
+	logger(ctx, LOG_ERR, "unknown option: %s", opt);
+	return -1;
+}
+
+static void
+finish_config(struct if_options *ifo)
+{
+
+	/* Terminate the encapsulated options */
+	if (ifo->vendor[0] && !(ifo->options & DHCPCD_VENDORRAW)) {
+		ifo->vendor[0]++;
+		ifo->vendor[ifo->vendor[0]] = DHO_END;
+		/* We are called twice.
+		 * This should be fixed, but in the meantime, this
+		 * guard should suffice */
+		ifo->options |= DHCPCD_VENDORRAW;
+	}
+}
+
+/* Handy routine to read very long lines in text files.
+ * This means we read the whole line and avoid any nasty buffer overflows.
+ * We strip leading space and avoid comment lines, making the code that calls
+ * us smaller. */
+static char *
+get_line(char ** __restrict buf, size_t * __restrict buflen,
+    FILE * __restrict fp)
+{
+	char *p;
+	ssize_t bytes;
+
+	do {
+		bytes = getline(buf, buflen, fp);
+		if (bytes == -1)
+			return NULL;
+		for (p = *buf; *p == ' ' || *p == '\t'; p++)
+			;
+	} while (*p == '\0' || *p == '\n' || *p == '#' || *p == ';');
+	if ((*buf)[--bytes] == '\n')
+		(*buf)[bytes] = '\0';
+	return p;
+}
+
+struct if_options *
+read_config(struct dhcpcd_ctx *ctx,
+    const char *ifname, const char *ssid, const char *profile)
+{
+	struct if_options *ifo;
+	FILE *fp;
+	struct stat sb;
+	char *line, *buf, *option, *p;
+	size_t buflen;
+	ssize_t vlen;
+	int skip = 0, have_profile = 0;
+#ifndef EMBEDDED_CONFIG
+	const char * const *e;
+	size_t ol;
+#endif
+#if !defined(INET) || !defined(INET6)
+	size_t i;
+	struct dhcp_opt *opt;
+#endif
+	struct dhcp_opt *ldop, *edop;
+
+	/* Seed our default options */
+	ifo = calloc(1, sizeof(*ifo));
+	if (ifo == NULL) {
+		logger(ctx, LOG_ERR, "%s: %m", __func__);
+		return NULL;
+	}
+	ifo->options |= DHCPCD_DAEMONISE | DHCPCD_LINK;
+#ifdef PLUGIN_DEV
+	ifo->options |= DHCPCD_DEV;
+#endif
+#ifdef INET
+	ifo->options |= DHCPCD_IPV4 | DHCPCD_DHCP | DHCPCD_IPV4LL;
+	ifo->options |= DHCPCD_GATEWAY | DHCPCD_ARP;
+#endif
+#ifdef INET6
+	ifo->options |= DHCPCD_IPV6 | DHCPCD_IPV6RS;
+	ifo->options |= DHCPCD_IPV6RA_AUTOCONF | DHCPCD_IPV6RA_REQRDNSS;
+	ifo->options |= DHCPCD_DHCP6;
+#endif
+	ifo->timeout = DEFAULT_TIMEOUT;
+	ifo->reboot = DEFAULT_REBOOT;
+	ifo->metric = -1;
+	ifo->auth.options |= DHCPCD_AUTH_REQUIRE;
+	TAILQ_INIT(&ifo->auth.tokens);
+
+	vlen = dhcp_vendor((char *)ifo->vendorclassid + 1,
+	            sizeof(ifo->vendorclassid) - 1);
+	ifo->vendorclassid[0] = (uint8_t)(vlen == -1 ? 0 : vlen);
+
+	buf = NULL;
+	buflen = 0;
+
+	/* Parse our embedded options file */
+	if (ifname == NULL) {
+		/* Space for initial estimates */
+#if defined(INET) && defined(INITDEFINES)
+		ifo->dhcp_override =
+		    calloc(INITDEFINES, sizeof(*ifo->dhcp_override));
+		if (ifo->dhcp_override == NULL)
+			logger(ctx, LOG_ERR, "%s: %m", __func__);
+		else
+			ifo->dhcp_override_len = INITDEFINES;
+#endif
+
+#if defined(INET6) && defined(INITDEFINE6S)
+		ifo->dhcp6_override =
+		    calloc(INITDEFINE6S, sizeof(*ifo->dhcp6_override));
+		if (ifo->dhcp6_override == NULL)
+			logger(ctx, LOG_ERR, "%s: %m", __func__);
+		else
+			ifo->dhcp6_override_len = INITDEFINE6S;
+#endif
+
+		/* Now load our embedded config */
+#ifdef EMBEDDED_CONFIG
+		fp = fopen(EMBEDDED_CONFIG, "r");
+		if (fp == NULL)
+			logger(ctx, LOG_ERR, "fopen `%s': %m", EMBEDDED_CONFIG);
+
+		while (fp && (line = get_line(&buf, &buflen, fp))) {
+#else
+		buflen = 80;
+		buf = malloc(buflen);
+		if (buf == NULL) {
+			logger(ctx, LOG_ERR, "%s: %m", __func__);
+			return NULL;
+		}
+		ldop = edop = NULL;
+		for (e = dhcpcd_embedded_conf; *e; e++) {
+			ol = strlen(*e) + 1;
+			if (ol > buflen) {
+				buflen = ol;
+				buf = realloc(buf, buflen);
+				if (buf == NULL) {
+					logger(ctx, LOG_ERR, "%s: %m", __func__);
+					free(buf);
+					return NULL;
+				}
+			}
+			memcpy(buf, *e, ol);
+			line = buf;
+#endif
+			option = strsep(&line, " \t");
+			if (line)
+				line = strskipwhite(line);
+			/* Trim trailing whitespace */
+			if (line && *line) {
+				p = line + strlen(line) - 1;
+				while (p != line &&
+				    (*p == ' ' || *p == '\t') &&
+				    *(p - 1) != '\\')
+					*p-- = '\0';
+			}
+			parse_config_line(ctx, NULL, ifo, option, line,
+			    &ldop, &edop);
+
+		}
+
+#ifdef EMBEDDED_CONFIG
+		if (fp)
+			fclose(fp);
+#endif
+#ifdef INET
+		ctx->dhcp_opts = ifo->dhcp_override;
+		ctx->dhcp_opts_len = ifo->dhcp_override_len;
+#else
+		for (i = 0, opt = ifo->dhcp_override;
+		    i < ifo->dhcp_override_len;
+		    i++, opt++)
+			free_dhcp_opt_embenc(opt);
+		free(ifo->dhcp_override);
+#endif
+		ifo->dhcp_override = NULL;
+		ifo->dhcp_override_len = 0;
+
+#ifdef INET6
+		ctx->dhcp6_opts = ifo->dhcp6_override;
+		ctx->dhcp6_opts_len = ifo->dhcp6_override_len;
+#else
+		for (i = 0, opt = ifo->dhcp6_override;
+		    i < ifo->dhcp6_override_len;
+		    i++, opt++)
+			free_dhcp_opt_embenc(opt);
+		free(ifo->dhcp6_override);
+#endif
+		ifo->dhcp6_override = NULL;
+		ifo->dhcp6_override_len = 0;
+
+		ctx->vivso = ifo->vivso_override;
+		ctx->vivso_len = ifo->vivso_override_len;
+		ifo->vivso_override = NULL;
+		ifo->vivso_override_len = 0;
+	}
+
+	/* Parse our options file */
+	fp = fopen(ctx->cffile, "r");
+	if (fp == NULL) {
+		if (strcmp(ctx->cffile, CONFIG))
+			logger(ctx, LOG_ERR, "fopen `%s': %m", ctx->cffile);
+		free(buf);
+		return ifo;
+	}
+	if (stat(ctx->cffile, &sb) == 0)
+		ifo->mtime = sb.st_mtime;
+
+	ldop = edop = NULL;
+	while ((line = get_line(&buf, &buflen, fp))) {
+		option = strsep(&line, " \t");
+		if (line)
+			line = strskipwhite(line);
+		/* Trim trailing whitespace */
+		if (line && *line) {
+			p = line + strlen(line) - 1;
+			while (p != line &&
+			    (*p == ' ' || *p == '\t') &&
+			    *(p - 1) != '\\')
+				*p-- = '\0';
+		}
+		/* Start of an interface block, skip if not ours */
+		if (strcmp(option, "interface") == 0) {
+			char **n;
+
+			if (ifname && line && strcmp(line, ifname) == 0)
+				skip = 0;
+			else
+				skip = 1;
+			if (ifname)
+				continue;
+
+			n = realloc(ctx->ifcv,
+			    sizeof(char *) * ((size_t)ctx->ifcc + 1));
+			if (n == NULL) {
+				logger(ctx, LOG_ERR, "%s: %m", __func__);
+				continue;
+			}
+			ctx->ifcv = n;
+			ctx->ifcv[ctx->ifcc] = strdup(line);
+			if (ctx->ifcv[ctx->ifcc] == NULL) {
+				logger(ctx, LOG_ERR, "%s: %m", __func__);
+				continue;
+			}
+			ctx->ifcc++;
+			logger(ctx, LOG_DEBUG, "allowing interface %s",
+			    ctx->ifcv[ctx->ifcc - 1]);
+			continue;
+		}
+		/* Start of an ssid block, skip if not ours */
+		if (strcmp(option, "ssid") == 0) {
+			if (ssid && line && strcmp(line, ssid) == 0)
+				skip = 0;
+			else
+				skip = 1;
+			continue;
+		}
+		/* Start of a profile block, skip if not ours */
+		if (strcmp(option, "profile") == 0) {
+			if (profile && line && strcmp(line, profile) == 0) {
+				skip = 0;
+				have_profile = 1;
+			} else
+				skip = 1;
+			continue;
+		}
+		/* Skip arping if we have selected a profile but not parsing
+		 * one. */
+		if (profile && !have_profile && strcmp(option, "arping") == 0)
+			continue;
+		if (skip)
+			continue;
+		parse_config_line(ctx, ifname, ifo, option, line, &ldop, &edop);
+	}
+	fclose(fp);
+	free(buf);
+
+	if (profile && !have_profile) {
+		free_options(ifo);
+		errno = ENOENT;
+		return NULL;
+	}
+
+	finish_config(ifo);
+	return ifo;
+}
+
+int
+add_options(struct dhcpcd_ctx *ctx, const char *ifname,
+    struct if_options *ifo, int argc, char **argv)
+{
+	int oi, opt, r;
+
+	if (argc == 0)
+		return 1;
+
+	optind = 0;
+	r = 1;
+	while ((opt = getopt_long(argc, argv, IF_OPTS, cf_options, &oi)) != -1)
+	{
+		r = parse_option(ctx, ifname, ifo, opt, optarg, NULL, NULL);
+		if (r != 1)
+			break;
+	}
+
+	finish_config(ifo);
+	return r;
+}
+
+void
+free_options(struct if_options *ifo)
+{
+	size_t i;
+	struct dhcp_opt *opt;
+	struct vivco *vo;
+	struct token *token;
+
+	if (ifo) {
+		if (ifo->environ) {
+			i = 0;
+			while (ifo->environ[i])
+				free(ifo->environ[i++]);
+			free(ifo->environ);
+		}
+		if (ifo->config) {
+			i = 0;
+			while (ifo->config[i])
+				free(ifo->config[i++]);
+			free(ifo->config);
+		}
+		ipv4_freeroutes(ifo->routes);
+		free(ifo->script);
+		free(ifo->arping);
+		free(ifo->blacklist);
+		free(ifo->fallback);
+
+		for (opt = ifo->dhcp_override;
+		    ifo->dhcp_override_len > 0;
+		    opt++, ifo->dhcp_override_len--)
+			free_dhcp_opt_embenc(opt);
+		free(ifo->dhcp_override);
+		for (opt = ifo->dhcp6_override;
+		    ifo->dhcp6_override_len > 0;
+		    opt++, ifo->dhcp6_override_len--)
+			free_dhcp_opt_embenc(opt);
+		free(ifo->dhcp6_override);
+		for (vo = ifo->vivco;
+		    ifo->vivco_len > 0;
+		    vo++, ifo->vivco_len--)
+			free(vo->data);
+		free(ifo->vivco);
+		for (opt = ifo->vivso_override;
+		    ifo->vivso_override_len > 0;
+		    opt++, ifo->vivso_override_len--)
+			free_dhcp_opt_embenc(opt);
+		free(ifo->vivso_override);
+
+#ifdef INET6
+		for (; ifo->ia_len > 0; ifo->ia_len--)
+			free(ifo->ia[ifo->ia_len - 1].sla);
+#endif
+		free(ifo->ia);
+
+		while ((token = TAILQ_FIRST(&ifo->auth.tokens))) {
+			TAILQ_REMOVE(&ifo->auth.tokens, token, next);
+			if (token->realm_len)
+				free(token->realm);
+			free(token->key);
+			free(token);
+		}
+		free(ifo);
+	}
+}
diff --git a/dhcpcd-6.8.2/if-options.h b/dhcpcd-6.8.2/if-options.h
new file mode 100644
index 0000000..78c4358
--- /dev/null
+++ b/dhcpcd-6.8.2/if-options.h
@@ -0,0 +1,215 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef IF_OPTIONS_H
+#define IF_OPTIONS_H
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in.h>
+
+#include <getopt.h>
+#include <limits.h>
+#include <stdint.h>
+
+#include "auth.h"
+
+/* Don't set any optional arguments here so we retain POSIX
+ * compatibility with getopt */
+#define IF_OPTS "46abc:de:f:gh:i:j:kl:m:no:pqr:s:t:u:v:wxy:z:" \
+		"ABC:DEF:GHI:JKLMO:PQ:RS:TUVW:X:Z:"
+
+#define DEFAULT_TIMEOUT		30
+#define DEFAULT_REBOOT		5
+
+#ifndef HOSTNAME_MAX_LEN
+#define HOSTNAME_MAX_LEN	250	/* 255 - 3 (FQDN) - 2 (DNS enc) */
+#endif
+#define VENDORCLASSID_MAX_LEN	255
+#define CLIENTID_MAX_LEN	48
+#define USERCLASS_MAX_LEN	255
+#define VENDOR_MAX_LEN		255
+
+#define DHCPCD_ARP			(1ULL << 0)
+#define DHCPCD_RELEASE			(1ULL << 1)
+#define DHCPCD_DOMAIN			(1ULL << 2)
+#define DHCPCD_GATEWAY			(1ULL << 3)
+#define DHCPCD_STATIC			(1ULL << 4)
+#define DHCPCD_DEBUG			(1ULL << 5)
+#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)
+#define DHCPCD_DAEMONISE		(1ULL << 14)
+#define DHCPCD_DAEMONISED		(1ULL << 15)
+#define DHCPCD_TEST			(1ULL << 16)
+#define DHCPCD_MASTER			(1ULL << 17)
+#define DHCPCD_HOSTNAME			(1ULL << 18)
+#define DHCPCD_CLIENTID			(1ULL << 19)
+#define DHCPCD_LINK			(1ULL << 20)
+#define DHCPCD_QUIET			(1ULL << 21)
+#define DHCPCD_BACKGROUND		(1ULL << 22)
+#define DHCPCD_VENDORRAW		(1ULL << 23)
+#define DHCPCD_NOWAITIP			(1ULL << 24) /* To force daemonise */
+#define DHCPCD_WAITIP			(1ULL << 25)
+#define DHCPCD_SLAACPRIVATE		(1ULL << 26)
+#define DHCPCD_CSR_WARNED		(1ULL << 27)
+#define DHCPCD_XID_HWADDR		(1ULL << 28)
+#define DHCPCD_BROADCAST		(1ULL << 29)
+#define DHCPCD_DUMPLEASE		(1ULL << 30)
+#define DHCPCD_IPV6RS			(1ULL << 31)
+#define DHCPCD_IPV6RA_REQRDNSS		(1ULL << 32)
+#define DHCPCD_IPV6RA_OWN		(1ULL << 33)
+#define DHCPCD_IPV6RA_OWN_DEFAULT	(1ULL << 34)
+#define DHCPCD_IPV4			(1ULL << 35)
+#define DHCPCD_FORKED			(1ULL << 36)
+#define DHCPCD_IPV6			(1ULL << 37)
+#define DHCPCD_STARTED			(1ULL << 38)
+#define DHCPCD_NOALIAS			(1ULL << 39)
+#define DHCPCD_IA_FORCED		(1ULL << 40)
+#define DHCPCD_STOPPING			(1ULL << 41)
+#define DHCPCD_DEPARTED			(1ULL << 42)
+#define DHCPCD_HOSTNAME_SHORT		(1ULL << 43)
+#define DHCPCD_EXITING			(1ULL << 44)
+#define DHCPCD_WAITIP4			(1ULL << 45)
+#define DHCPCD_WAITIP6			(1ULL << 46)
+#define DHCPCD_DEV			(1ULL << 47)
+#define DHCPCD_IAID			(1ULL << 48)
+#define DHCPCD_DHCP			(1ULL << 49)
+#define DHCPCD_DHCP6			(1ULL << 50)
+#define DHCPCD_NOPFXDLG			(1ULL << 51)
+#define DHCPCD_PFXDLGONLY		(1ULL << 52)
+#define DHCPCD_PFXDLGMIX		(1ULL << 53)
+#define DHCPCD_IPV6RA_AUTOCONF		(1ULL << 54)
+#define DHCPCD_ROUTER_HOST_ROUTE_WARNED	(1ULL << 55)
+#define DHCPCD_IPV6RA_ACCEPT_NOPUBLIC	(1ULL << 56)
+#define DHCPCD_BOOTP			(1ULL << 57)
+#define DHCPCD_ARPGW			(1ULL << 58)
+#define DHCPCD_UNICAST_ARP		(1ULL << 59)
+
+#define DHCPCD_WARNINGS (DHCPCD_CSR_WARNED | \
+		DHCPCD_ROUTER_HOST_ROUTE_WARNED)
+#define DHCPCD_CONF (DHCPCD_NOPFXDLG | DHCPCD_PFXDLGONLY)
+
+extern const struct option cf_options[];
+
+/* The number of bytes it takes to hold a flag for each of the 256 options. */
+#define OPTION_MASK_SIZE (256 / NBBY)
+
+struct if_sla {
+	char ifname[IF_NAMESIZE];
+	uint32_t sla;
+	uint8_t prefix_len;
+	int8_t sla_set;
+};
+
+struct if_ia {
+	uint8_t iaid[4];
+#ifdef INET6
+	uint16_t ia_type;
+	uint8_t iaid_set;
+	struct in6_addr addr;
+	uint8_t prefix_len;
+	uint32_t sla_max;
+	size_t sla_len;
+	struct if_sla *sla;
+#endif
+};
+
+struct vivco {
+	size_t len;
+	uint8_t *data;
+};
+
+struct if_options {
+	time_t mtime;
+	uint8_t iaid[4];
+	int metric;
+	uint8_t requestmask[OPTION_MASK_SIZE];
+	uint8_t requiremask[OPTION_MASK_SIZE];
+	uint8_t nomask[OPTION_MASK_SIZE];
+	uint8_t rejectmask[OPTION_MASK_SIZE];
+	uint8_t requestmask6[(UINT16_MAX + 1) / NBBY];
+	uint8_t requiremask6[(UINT16_MAX + 1) / NBBY];
+	uint8_t nomask6[(UINT16_MAX + 1) / NBBY];
+	uint8_t rejectmask6[(UINT16_MAX + 1) / NBBY];
+	uint8_t dstmask[256 / NBBY];
+	uint32_t leasetime;
+	time_t timeout;
+	time_t reboot;
+	unsigned long long options;
+
+	struct in_addr req_addr;
+	struct in_addr req_mask;
+	struct rt_head *routes;
+	char **config;
+
+	char **environ;
+	char *script;
+
+	char hostname[HOSTNAME_MAX_LEN + 1]; /* We don't store the length */
+	uint8_t fqdn;
+	uint8_t vendorclassid[VENDORCLASSID_MAX_LEN + 2];
+	uint8_t clientid[CLIENTID_MAX_LEN + 2];
+	uint8_t userclass[USERCLASS_MAX_LEN + 2];
+	uint8_t vendor[VENDOR_MAX_LEN + 2];
+
+	size_t blacklist_len;
+	in_addr_t *blacklist;
+	size_t whitelist_len;
+	in_addr_t *whitelist;
+	size_t arping_len;
+	in_addr_t *arping;
+	char *fallback;
+
+	struct if_ia *ia;
+	size_t ia_len;
+
+	struct dhcp_opt *dhcp_override;
+	size_t dhcp_override_len;
+	struct dhcp_opt *dhcp6_override;
+	size_t dhcp6_override_len;
+	uint32_t vivco_en;
+	struct vivco *vivco;
+	size_t vivco_len;
+	struct dhcp_opt *vivso_override;
+	size_t vivso_override_len;
+
+	struct auth auth;
+};
+
+struct if_options *read_config(struct dhcpcd_ctx *,
+    const char *, const char *, const char *);
+int add_options(struct dhcpcd_ctx *, const char *,
+    struct if_options *, int, char **);
+void free_dhcp_opt_embenc(struct dhcp_opt *);
+void free_options(struct if_options *);
+
+#endif
diff --git a/dhcpcd-6.8.2/if-sun.c b/dhcpcd-6.8.2/if-sun.c
new file mode 100644
index 0000000..42082c0
--- /dev/null
+++ b/dhcpcd-6.8.2/if-sun.c
@@ -0,0 +1,183 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/utsname.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "config.h"
+#include "common.h"
+#include "dhcp.h"
+#include "if.h"
+#include "if-options.h"
+#include "ipv4.h"
+#include "ipv6.h"
+#include "ipv6nd.h"
+
+int
+if_init(__unused struct interface *iface)
+{
+
+	return 0;
+}
+
+int
+if_conf(__unused struct interface *iface)
+{
+
+	return 0;
+}
+
+int
+if_openlinksocket(void)
+{
+
+	errno = ENOTSUP;
+	return -1;
+}
+
+int
+if_getssid(const char *ifname, char *ssid)
+{
+
+	errno = ENOTSUP;
+	return -1;
+}
+
+int
+if_vimaster(const char *ifname)
+{
+
+	return 0;
+}
+
+#ifdef INET
+int
+if_openrawsocket(struct interface *ifp, int protocol)
+{
+
+	errno = ENOTSUP;
+	return -1;
+}
+
+ssize_t
+if_sendrawpacket(const struct interface *ifp, int protocol,
+    const void *data, size_t len)
+{
+
+	errno = ENOTSUP;
+	return -1;
+}
+
+ssize_t
+if_readrawpacket(struct interface *ifp, int protocol,
+    void *data, size_t len, int *flags)
+{
+
+	errno = ENOTSUP;
+	return -1;
+}
+
+int
+if_address(const struct interface *iface, const struct in_addr *address,
+    const struct in_addr *netmask, const struct in_addr *broadcast,
+    int action)
+{
+
+	errno = ENOTSUP;
+	return -1;
+}
+
+int
+if_route(const struct rt *rt, int action)
+{
+
+	errno = ENOTSUP;
+	return -1;
+}
+#endif
+
+#ifdef INET6
+int
+if_address6(const struct ipv6_addr *a, int action)
+{
+
+	errno = ENOTSUP;
+	return -1;
+}
+
+int
+if_route6(const struct rt6 *rt, int action)
+{
+
+	errno = ENOTSUP;
+	return -1;
+}
+#endif
+
+#ifdef INET6
+int
+if_addrflags6(const struct in6_addr *addr, const struct interface *ifp)
+{
+
+	errno = ENOTSUP;
+	return -1;
+}
+#endif
+
+int
+if_managelink(struct dhcpcd_ctx *ctx)
+{
+
+	errno = ENOTSUP;
+	return -1;
+}
+
+if_machinearch(char *str, size_t len)
+{
+
+	errno = ENOTSUP;
+	return -1;
+}
+
+#ifdef INET6
+void
+if_rarestore(struct dhcpcd_ctx *ctx)
+{
+
+}
+
+int
+if_checkipv6(struct dhcpcd_ctx *ctx, const char *ifname, int own)
+{
+
+	errno = ENOTSUP;
+	return -1;
+}
+#endif
diff --git a/dhcpcd-6.8.2/if.c b/dhcpcd-6.8.2/if.c
new file mode 100644
index 0000000..ddd03ff
--- /dev/null
+++ b/dhcpcd-6.8.2/if.c
@@ -0,0 +1,721 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#ifdef __FreeBSD__ /* Needed so that including netinet6/in6_var.h works */
+#  include <net/if_var.h>
+#endif
+#ifdef AF_LINK
+#  include <net/if_dl.h>
+#  include <net/if_types.h>
+#  include <netinet/in_var.h>
+#endif
+#ifdef AF_PACKET
+#  include <netpacket/packet.h>
+#endif
+#ifdef SIOCGIFMEDIA
+#  include <net/if_media.h>
+#endif
+#include <net/route.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <ifaddrs.h>
+#include <fnmatch.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "config.h"
+#include "common.h"
+#include "dev.h"
+#include "dhcp.h"
+#include "dhcp6.h"
+#include "if.h"
+#include "if-options.h"
+#include "ipv4.h"
+#include "ipv6nd.h"
+
+#ifdef __QNX__
+/* QNX carries defines for, but does not actually support PF_LINK */
+#undef IFLR_ACTIVE
+#endif
+
+int
+split_interface_lease(const char *ifname, int *interface_name_len,
+			  const char **lease_identifier)
+{
+	int ret = 0;
+	int len;
+	const char *lease_ptr = ifname;
+	const char *p = strchr(ifname, '=');
+
+	if (interface_name_len)
+		len = *interface_name_len;
+	else
+		len = strlen(ifname);
+
+	if (p) {
+		lease_ptr = p + 1;
+		if (len > p - ifname)
+			len = p - ifname;
+		ret = 1;
+	}
+
+	if (interface_name_len)
+		*interface_name_len = len;
+	if (lease_identifier)
+		*lease_identifier = lease_ptr;
+	return ret;
+}
+
+void
+if_free(struct interface *ifp)
+{
+
+	if (ifp == NULL)
+		return;
+	ipv4_free(ifp);
+	dhcp_free(ifp);
+	dhcp6_free(ifp);
+	ipv6nd_free(ifp);
+	ipv6_free(ifp);
+	free_options(ifp->options);
+	free(ifp);
+}
+
+int
+if_carrier(struct interface *iface)
+{
+	int s, r;
+	struct ifreq ifr;
+#ifdef SIOCGIFMEDIA
+	struct ifmediareq ifmr;
+#endif
+
+	if ((s = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
+		return LINK_UNKNOWN;
+	memset(&ifr, 0, sizeof(ifr));
+	strlcpy(ifr.ifr_name, iface->name, sizeof(ifr.ifr_name));
+	if (ioctl(s, SIOCGIFFLAGS, &ifr) == -1) {
+		close(s);
+		return LINK_UNKNOWN;
+	}
+	iface->flags = (unsigned int)ifr.ifr_flags;
+
+#ifdef SIOCGIFMEDIA
+	memset(&ifmr, 0, sizeof(ifmr));
+	strlcpy(ifmr.ifm_name, iface->name, sizeof(ifmr.ifm_name));
+	if (ioctl(s, SIOCGIFMEDIA, &ifmr) != -1 &&
+	    ifmr.ifm_status & IFM_AVALID)
+		r = (ifmr.ifm_status & IFM_ACTIVE) ? LINK_UP : LINK_DOWN;
+	else
+		r = ifr.ifr_flags & IFF_RUNNING ? LINK_UP : LINK_UNKNOWN;
+#else
+	r = ifr.ifr_flags & IFF_RUNNING ? LINK_UP : LINK_DOWN;
+#endif
+	close(s);
+	return r;
+}
+
+int
+if_setflag(struct interface *ifp, short flag)
+{
+	struct ifreq ifr;
+	int s, r;
+
+	if ((s = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
+		return -1;
+	memset(&ifr, 0, sizeof(ifr));
+	strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
+	r = -1;
+	if (ioctl(s, SIOCGIFFLAGS, &ifr) == 0) {
+		if (flag == 0 || (ifr.ifr_flags & flag) == flag)
+			r = 0;
+		else {
+			ifr.ifr_flags |= flag;
+			if (ioctl(s, SIOCSIFFLAGS, &ifr) == 0)
+				r = 0;
+		}
+		ifp->flags = (unsigned int)ifr.ifr_flags;
+	}
+	close(s);
+	return r;
+}
+
+static int
+if_hasconf(struct dhcpcd_ctx *ctx, const char *ifname)
+{
+	int i;
+
+	for (i = 0; i < ctx->ifcc; i++) {
+		if (strcmp(ctx->ifcv[i], ifname) == 0)
+			return 1;
+	}
+	return 0;
+}
+
+static void if_learnaddrs1(struct dhcpcd_ctx *ctx, struct if_head *ifs,
+    struct ifaddrs *ifaddrs)
+{
+	struct ifaddrs *ifa;
+	struct interface *ifp;
+#ifdef INET
+	const struct sockaddr_in *addr, *net, *dst;
+#endif
+#ifdef INET6
+	struct sockaddr_in6 *sin6, *net6;
+#endif
+	int ifa_flags;
+
+
+	for (ifa = ifaddrs; ifa; ifa = ifa->ifa_next) {
+		if (ifa->ifa_addr == NULL)
+			continue;
+		if ((ifp = if_find(ifs, ifa->ifa_name)) == NULL)
+			continue;
+		switch(ifa->ifa_addr->sa_family) {
+#ifdef INET
+		case AF_INET:
+			addr = (const struct sockaddr_in *)
+			    (void *)ifa->ifa_addr;
+			net = (const struct sockaddr_in *)
+			    (void *)ifa->ifa_netmask;
+			if (ifa->ifa_flags & IFF_POINTOPOINT)
+				dst = (const struct sockaddr_in *)
+				    (void *)ifa->ifa_dstaddr;
+			else
+				dst = NULL;
+			ifa_flags = if_addrflags(&addr->sin_addr, ifp);
+			ipv4_handleifa(ctx, RTM_NEWADDR, ifs, ifa->ifa_name,
+				&addr->sin_addr,
+				&net->sin_addr,
+				dst ? &dst->sin_addr : NULL, ifa_flags);
+			break;
+#endif
+#ifdef INET6
+		case AF_INET6:
+			sin6 = (struct sockaddr_in6 *)(void *)ifa->ifa_addr;
+			net6 = (struct sockaddr_in6 *)(void *)ifa->ifa_netmask;
+#ifdef __KAME__
+			if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
+				/* Remove the scope from the address */
+				sin6->sin6_addr.s6_addr[2] =
+				    sin6->sin6_addr.s6_addr[3] = '\0';
+#endif
+			ifa_flags = if_addrflags6(&sin6->sin6_addr, ifp);
+			if (ifa_flags != -1)
+				ipv6_handleifa(ctx, RTM_NEWADDR, ifs,
+				    ifa->ifa_name,
+				    &sin6->sin6_addr,
+				    ipv6_prefixlen(&net6->sin6_addr),
+				    ifa_flags);
+			break;
+#endif
+		}
+	}
+}
+
+struct if_head *
+if_discover(struct dhcpcd_ctx *ctx, int argc, char * const *argv)
+{
+	struct ifaddrs *ifaddrs, *ifa;
+	char *p;
+	int i;
+	struct if_head *ifs;
+	struct interface *ifp;
+	const char *lease_identifier;
+	char ifn[IF_NAMESIZE];
+
+#ifdef __linux__
+	char alias[IF_NAMESIZE];
+#endif
+
+#ifdef AF_LINK
+	const struct sockaddr_dl *sdl;
+#ifdef SIOCGIFPRIORITY
+	struct ifreq ifr;
+	int s_inet;
+#endif
+#ifdef IFLR_ACTIVE
+	struct if_laddrreq iflr;
+	int s_link;
+#endif
+
+#ifdef SIOCGIFPRIORITY
+	if ((s_inet = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
+		return NULL;
+#endif
+#ifdef IFLR_ACTIVE
+	if ((s_link = socket(PF_LINK, SOCK_DGRAM, 0)) == -1) {
+#ifdef SIOCGIFPRIORITY
+		close(s_inet);
+#endif
+		return NULL;
+	}
+	memset(&iflr, 0, sizeof(iflr));
+#endif
+#elif AF_PACKET
+	const struct sockaddr_ll *sll;
+#endif
+
+	if (getifaddrs(&ifaddrs) == -1)
+		return NULL;
+	ifs = malloc(sizeof(*ifs));
+	if (ifs == NULL)
+		return NULL;
+	TAILQ_INIT(ifs);
+
+	for (ifa = ifaddrs; ifa; ifa = ifa->ifa_next) {
+		if (ifa->ifa_addr != NULL) {
+#ifdef AF_LINK
+			if (ifa->ifa_addr->sa_family != AF_LINK)
+				continue;
+#elif AF_PACKET
+			if (ifa->ifa_addr->sa_family != AF_PACKET)
+				continue;
+#endif
+		}
+
+		/* It's possible for an interface to have >1 AF_LINK.
+		 * For our purposes, we use the first one. */
+		TAILQ_FOREACH(ifp, ifs, next) {
+			if (strcmp(ifp->name, ifa->ifa_name) == 0)
+				break;
+		}
+		if (ifp)
+			continue;
+
+		lease_identifier = NULL;
+		if (argc > 0) {
+			for (i = 0; i < argc; i++) {
+				int intf_len = strlen(argv[i]);
+				split_interface_lease(argv[i], &intf_len,
+						      &lease_identifier);
+				if (intf_len > IF_NAMESIZE)
+					continue;
+				strlcpy(ifn, argv[i], intf_len + 1);
+#ifdef __linux__
+				strlcpy(alias, argv[i], intf_len + 1);
+				/* Check the real interface name */
+				p = strchr(ifn, ':');
+				if (p)
+					*p = '\0';
+#endif
+				if (strcmp(ifn, ifa->ifa_name) == 0)
+					break;
+			}
+			if (i == argc)
+				continue;
+		} else {
+			strlcpy(ifn, ifa->ifa_name, sizeof(ifn));
+#ifdef __linux
+			strlcpy(alias, ifa->ifa_name, sizeof(alias));
+#endif
+			/* -1 means we're discovering against a specific
+			 * interface, but we still need the below rules
+			 * to apply. */
+			if (argc == -1 && strcmp(argv[0], ifa->ifa_name) != 0)
+				continue;
+		}
+		p = ifn;
+
+		for (i = 0; i < ctx->ifdc; i++)
+			if (!fnmatch(ctx->ifdv[i], p, 0))
+				break;
+		if (i < ctx->ifdc)
+			continue;
+		for (i = 0; i < ctx->ifac; i++)
+			if (!fnmatch(ctx->ifav[i], p, 0))
+				break;
+		if (ctx->ifac && i == ctx->ifac)
+			continue;
+
+		/* Ensure that the interface name has settled */
+		if (!dev_initialized(ctx, p))
+			continue;
+
+		/* Don't allow loopback or pointopoint unless explicit */
+		if (ifa->ifa_flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) {
+			if ((argc == 0 || argc == -1) &&
+			    ctx->ifac == 0 && !if_hasconf(ctx, p))
+				continue;
+		}
+
+		if (if_vimaster(p) == 1) {
+			logger(ctx, argc ? LOG_ERR : LOG_DEBUG,
+			    "%s: is a Virtual Interface Master, skipping", p);
+			continue;
+		}
+
+		ifp = calloc(1, sizeof(*ifp));
+		if (ifp == NULL) {
+			logger(ctx, LOG_ERR, "%s: %m", __func__);
+			break;
+		}
+		ifp->ctx = ctx;
+#ifdef __linux__
+		strlcpy(ifp->alias, alias, sizeof(ifp->alias));
+#endif
+		strlcpy(ifp->name, p, sizeof(ifp->name));
+		if (lease_identifier) {
+			strlcpy(ifp->lease_identifier, lease_identifier,
+				sizeof(ifp->lease_identifier));
+		}
+		ifp->flags = ifa->ifa_flags;
+		ifp->carrier = if_carrier(ifp);
+
+		if (ifa->ifa_addr != NULL) {
+#ifdef AF_LINK
+			sdl = (const struct sockaddr_dl *)(void *)ifa->ifa_addr;
+
+#ifdef IFLR_ACTIVE
+			/* We need to check for active address */
+			strlcpy(iflr.iflr_name, ifp->name,
+			    sizeof(iflr.iflr_name));
+			memcpy(&iflr.addr, ifa->ifa_addr,
+			    MIN(ifa->ifa_addr->sa_len, sizeof(iflr.addr)));
+			iflr.flags = IFLR_PREFIX;
+			iflr.prefixlen = (unsigned int)sdl->sdl_alen * NBBY;
+			if (ioctl(s_link, SIOCGLIFADDR, &iflr) == -1 ||
+			    !(iflr.flags & IFLR_ACTIVE))
+			{
+				if_free(ifp);
+				continue;
+			}
+#endif
+
+			ifp->index = sdl->sdl_index;
+			switch(sdl->sdl_type) {
+#ifdef IFT_BRIDGE
+			case IFT_BRIDGE: /* FALLTHROUGH */
+#endif
+#ifdef IFT_PPP
+			case IFT_PPP: /* FALLTHROUGH */
+#endif
+#ifdef IFT_PROPVIRTUAL
+			case IFT_PROPVIRTUAL: /* FALLTHROUGH */
+#endif
+#if defined(IFT_BRIDGE) || defined(IFT_PPP) || defined(IFT_PROPVIRTUAL)
+				/* Don't allow unless explicit */
+				if ((argc == 0 || argc == -1) &&
+				    ctx->ifac == 0 &&
+				    !if_hasconf(ctx, ifp->name))
+				{
+					logger(ifp->ctx, LOG_DEBUG,
+					    "%s: ignoring due to"
+					    " interface type and"
+					    " no config",
+					    ifp->name);
+					if_free(ifp);
+					continue;
+				}
+				/* FALLTHROUGH */
+#endif
+#ifdef IFT_L2VLAN
+			case IFT_L2VLAN: /* FALLTHROUGH */
+#endif
+#ifdef IFT_L3IPVLAN
+			case IFT_L3IPVLAN: /* FALLTHROUGH */
+#endif
+			case IFT_ETHER:
+				ifp->family = ARPHRD_ETHER;
+				break;
+#ifdef IFT_IEEE1394
+			case IFT_IEEE1394:
+				ifp->family = ARPHRD_IEEE1394;
+				break;
+#endif
+#ifdef IFT_INFINIBAND
+			case IFT_INFINIBAND:
+				ifp->family = ARPHRD_INFINIBAND;
+				break;
+#endif
+			default:
+				/* Don't allow unless explicit */
+				if ((argc == 0 || argc == -1) &&
+				    ctx->ifac == 0 &&
+				    !if_hasconf(ctx, ifp->name))
+				{
+					if_free(ifp);
+					continue;
+				}
+				logger(ifp->ctx, LOG_WARNING,
+				    "%s: unsupported interface type %.2x",
+				    ifp->name, sdl->sdl_type);
+				/* Pretend it's ethernet */
+				ifp->family = ARPHRD_ETHER;
+				break;
+			}
+			ifp->hwlen = sdl->sdl_alen;
+#ifndef CLLADDR
+#  define CLLADDR(s) ((const char *)((s)->sdl_data + (s)->sdl_nlen))
+#endif
+			memcpy(ifp->hwaddr, CLLADDR(sdl), ifp->hwlen);
+#elif AF_PACKET
+			sll = (const struct sockaddr_ll *)(void *)ifa->ifa_addr;
+			ifp->index = (unsigned int)sll->sll_ifindex;
+			ifp->family = sll->sll_hatype;
+			ifp->hwlen = sll->sll_halen;
+			if (ifp->hwlen != 0)
+				memcpy(ifp->hwaddr, sll->sll_addr, ifp->hwlen);
+#endif
+		}
+#ifdef __linux__
+		/* PPP addresses on Linux don't have hardware addresses */
+		else
+			ifp->index = if_nametoindex(ifp->name);
+#endif
+
+		/* We only work on ethernet by default */
+		if (ifp->family != ARPHRD_ETHER) {
+			if ((argc == 0 || argc == -1) &&
+			    ctx->ifac == 0 && !if_hasconf(ctx, ifp->name))
+			{
+				if_free(ifp);
+				continue;
+			}
+			switch (ifp->family) {
+			case ARPHRD_IEEE1394:
+			case ARPHRD_INFINIBAND:
+#ifdef ARPHRD_LOOPBACK
+			case ARPHRD_LOOPBACK:
+#endif
+#ifdef ARPHRD_PPP
+			case ARPHRD_PPP:
+#endif
+				/* We don't warn for supported families */
+				break;
+
+/* IFT already checked */
+#ifndef AF_LINK
+			default:
+				logger(ifp->ctx, LOG_WARNING,
+				    "%s: unsupported interface family %.2x",
+				    ifp->name, ifp->family);
+				break;
+#endif
+			}
+		}
+
+		/* Handle any platform init for the interface */
+		if (if_init(ifp) == -1) {
+			logger(ifp->ctx, LOG_ERR, "%s: if_init: %m", p);
+			if_free(ifp);
+			continue;
+		}
+
+		/* Ensure that the MTU is big enough for DHCP */
+		if (if_getmtu(ifp->name) < MTU_MIN &&
+		    if_setmtu(ifp->name, MTU_MIN) == -1)
+		{
+			logger(ifp->ctx, LOG_ERR, "%s: set_mtu: %m", p);
+			if_free(ifp);
+			continue;
+		}
+
+#ifdef SIOCGIFPRIORITY
+		/* Respect the interface priority */
+		memset(&ifr, 0, sizeof(ifr));
+		strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
+		if (ioctl(s_inet, SIOCGIFPRIORITY, &ifr) == 0)
+			ifp->metric = ifr.ifr_metric;
+#else
+		/* We reserve the 100 range for virtual interfaces, if and when
+		 * we can work them out. */
+		ifp->metric = 200 + ifp->index;
+		if (if_getssid(ifp) != -1) {
+			ifp->wireless = 1;
+			ifp->metric += 100;
+		}
+#endif
+
+		TAILQ_INSERT_TAIL(ifs, ifp, next);
+	}
+
+	if (!ifs) {
+		logger(ctx, LOG_INFO, "%s: no matching interfaces", __func__);
+		for (ifa = ifaddrs; ifa; ifa = ifa->ifa_next) {
+			logger(ctx, LOG_INFO, "%s: considered %s",
+			       __func__, ifa->ifa_name);
+		}
+	}
+
+	if_learnaddrs1(ctx, ifs, ifaddrs);
+	freeifaddrs(ifaddrs);
+
+#ifdef SIOCGIFPRIORITY
+	close(s_inet);
+#endif
+#ifdef IFLR_ACTIVE
+	close(s_link);
+#endif
+
+	return ifs;
+}
+
+static struct interface *
+if_findindexname(struct if_head *ifaces, unsigned int idx, const char *name)
+{
+
+	if (ifaces != NULL) {
+		struct interface *ifp;
+
+		TAILQ_FOREACH(ifp, ifaces, next) {
+			if ((ifp->options == NULL ||
+			    !(ifp->options->options & DHCPCD_PFXDLGONLY)) &&
+			    ((name && strcmp(ifp->name, name) == 0) ||
+#ifdef __linux__
+			    (name && strcmp(ifp->alias, name) == 0) ||
+#endif
+			    (!name && ifp->index == idx)))
+				return ifp;
+		}
+	}
+
+	errno = ESRCH;
+	return NULL;
+}
+
+struct interface *
+if_find(struct if_head *ifaces, const char *name)
+{
+
+	return if_findindexname(ifaces, 0, name);
+}
+
+struct interface *
+if_findindex(struct if_head *ifaces, unsigned int idx)
+{
+
+	return if_findindexname(ifaces, idx, NULL);
+}
+
+int
+if_domtu(const char *ifname, short int mtu)
+{
+	int s, r;
+	struct ifreq ifr;
+
+	if ((s = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
+		return -1;
+	memset(&ifr, 0, sizeof(ifr));
+	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+	ifr.ifr_mtu = mtu;
+	r = ioctl(s, mtu ? SIOCSIFMTU : SIOCGIFMTU, &ifr);
+	close(s);
+	if (r == -1)
+		return -1;
+	return ifr.ifr_mtu;
+}
+
+/* Interface comparer for working out ordering. */
+static int
+if_cmp(const struct interface *si, const struct interface *ti)
+{
+#ifdef INET
+	int r;
+#endif
+
+	/* Always prefer master interfaces */
+	if (!(si->options->options & DHCPCD_PFXDLGONLY) &&
+	    ti->options->options & DHCPCD_PFXDLGONLY)
+		return -1;
+	if (si->options->options & DHCPCD_PFXDLGONLY &&
+	    !(ti->options->options & DHCPCD_PFXDLGONLY))
+		return 1;
+
+	/* Check carrier status first */
+	if (si->carrier > ti->carrier)
+		return -1;
+	if (si->carrier < ti->carrier)
+		return 1;
+
+	if (D_STATE_RUNNING(si) && !D_STATE_RUNNING(ti))
+		return -1;
+	if (!D_STATE_RUNNING(si) && D_STATE_RUNNING(ti))
+		return 1;
+	if (RS_STATE_RUNNING(si) && !RS_STATE_RUNNING(ti))
+		return -1;
+	if (!RS_STATE_RUNNING(si) && RS_STATE_RUNNING(ti))
+		return 1;
+	if (D6_STATE_RUNNING(si) && !D6_STATE_RUNNING(ti))
+		return -1;
+	if (!D6_STATE_RUNNING(si) && D6_STATE_RUNNING(ti))
+		return 1;
+
+#ifdef INET
+	/* Special attention needed here due to states and IPv4LL. */
+	if ((r = ipv4_ifcmp(si, ti)) != 0)
+		return r;
+#endif
+
+	/* Finally, metric */
+	if (si->metric < ti->metric)
+		return -1;
+	if (si->metric > ti->metric)
+		return 1;
+	return 0;
+}
+
+/* Sort the interfaces into a preferred order - best first, worst last. */
+void
+if_sortinterfaces(struct dhcpcd_ctx *ctx)
+{
+	struct if_head sorted;
+	struct interface *ifp, *ift;
+
+	if (ctx->ifaces == NULL ||
+	    (ifp = TAILQ_FIRST(ctx->ifaces)) == NULL ||
+	    TAILQ_NEXT(ifp, next) == NULL)
+		return;
+
+	TAILQ_INIT(&sorted);
+	TAILQ_REMOVE(ctx->ifaces, ifp, next);
+	TAILQ_INSERT_HEAD(&sorted, ifp, next);
+	while ((ifp = TAILQ_FIRST(ctx->ifaces))) {
+		TAILQ_REMOVE(ctx->ifaces, ifp, next);
+		TAILQ_FOREACH(ift, &sorted, next) {
+			if (if_cmp(ifp, ift) == -1) {
+				TAILQ_INSERT_BEFORE(ift, ifp, next);
+				break;
+			}
+		}
+		if (ift == NULL)
+			TAILQ_INSERT_TAIL(&sorted, ifp, next);
+	}
+	TAILQ_CONCAT(ctx->ifaces, &sorted, next);
+}
diff --git a/dhcpcd-6.8.2/if.h b/dhcpcd-6.8.2/if.h
new file mode 100644
index 0000000..a4c67a6
--- /dev/null
+++ b/dhcpcd-6.8.2/if.h
@@ -0,0 +1,174 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef INTERFACE_H
+#define INTERFACE_H
+
+#include <net/if.h>
+#ifdef __FreeBSD__
+#include <net/if_var.h>
+#endif
+#include <net/route.h>		/* for RTM_ADD et all */
+#include <netinet/in.h>
+#ifdef BSD
+#include <netinet/in_var.h>	/* for IN_IFF_TENTATIVE et all */
+#endif
+
+/* Some systems have route metrics.
+ * OpenBSD route priority is not this. */
+#ifndef HAVE_ROUTE_METRIC
+# if defined(__linux__)
+#  define HAVE_ROUTE_METRIC 1
+# endif
+#endif
+
+/* Some systems have in-built IPv4 DAD.
+ * However, we need them to do DAD at carrier up as well. */
+#ifdef IN_IFF_TENTATIVE
+#  ifdef __NetBSD__
+#    define NOCARRIER_PRESERVE_IP
+#  endif
+#endif
+
+#include "config.h"
+#include "dhcpcd.h"
+#include "ipv4.h"
+#include "ipv6.h"
+
+#define EUI64_ADDR_LEN			8
+#define INFINIBAND_ADDR_LEN		20
+
+/* Linux 2.4 doesn't define this */
+#ifndef ARPHRD_IEEE1394
+#  define ARPHRD_IEEE1394		24
+#endif
+
+/* The BSD's don't define this yet */
+#ifndef ARPHRD_INFINIBAND
+#  define ARPHRD_INFINIBAND		32
+#endif
+
+/* Work out if we have a private address or not
+ * 10/8
+ * 172.16/12
+ * 192.168/16
+ */
+#ifndef IN_PRIVATE
+# define IN_PRIVATE(addr) (((addr & IN_CLASSA_NET) == 0x0a000000) ||	      \
+	    ((addr & 0xfff00000)    == 0xac100000) ||			      \
+	    ((addr & IN_CLASSB_NET) == 0xc0a80000))
+#endif
+
+#define LINKLOCAL_ADDR	0xa9fe0000
+#define LINKLOCAL_MASK	IN_CLASSB_NET
+#define LINKLOCAL_BRDC	(LINKLOCAL_ADDR | ~LINKLOCAL_MASK)
+
+#ifndef IN_LINKLOCAL
+# define IN_LINKLOCAL(addr) ((addr & IN_CLASSB_NET) == LINKLOCAL_ADDR)
+#endif
+
+#define RAW_EOF			1 << 0
+#define RAW_PARTIALCSUM		2 << 0
+
+int if_setflag(struct interface *ifp, short flag);
+#define if_up(ifp) if_setflag((ifp), (IFF_UP | IFF_RUNNING))
+struct if_head *if_discover(struct dhcpcd_ctx *, int, char * const *);
+struct interface *if_find(struct if_head *, const char *);
+struct interface *if_findindex(struct if_head *, unsigned int);
+void if_sortinterfaces(struct dhcpcd_ctx *);
+void if_free(struct interface *);
+int if_domtu(const char *, short int);
+#define if_getmtu(iface) if_domtu(iface, 0)
+#define if_setmtu(iface, mtu) if_domtu(iface, mtu)
+int if_carrier(struct interface *);
+int split_interface_lease(const char *ifname, int *ifname_len,
+			  const char **lease_identifier);
+
+/* The below functions are provided by if-KERNEL.c */
+int if_conf(struct interface *);
+int if_init(struct interface *);
+int if_getssid(struct interface *);
+int if_vimaster(const char *);
+int if_openlinksocket(void);
+int if_managelink(struct dhcpcd_ctx *);
+
+/* dhcpcd uses the same routing flags as BSD.
+ * If the platform doesn't use these flags,
+ * map them in the platform interace file. */
+#ifndef RTM_ADD
+#define RTM_ADD		0x1	/* Add Route */
+#define RTM_DELETE	0x2	/* Delete Route */
+#define RTM_CHANGE	0x3	/* Change Metrics or flags */
+#define RTM_GET		0x4	/* Report Metrics */
+#endif
+
+#ifdef INET
+extern const char *if_pfname;
+int if_openrawsocket(struct interface *, uint16_t);
+ssize_t if_sendrawpacket(const struct interface *,
+    uint16_t, const void *, size_t, const uint8_t *dest_hw_addr);
+ssize_t if_readrawpacket(struct interface *, uint16_t, void *, size_t, int *);
+
+int if_address(const struct interface *,
+    const struct in_addr *, const struct in_addr *,
+    const struct in_addr *, int);
+#define if_addaddress(ifp, addr, net, brd)	\
+	if_address(ifp, addr, net, brd, 1)
+#define if_deladdress(ifp, addr, net)		\
+	if_address(ifp, addr, net, NULL, -1)
+
+int if_addrflags(const struct in_addr *, const struct interface *);
+
+int if_route(unsigned char, const struct rt *rt);
+int if_initrt(struct interface *);
+#endif
+
+#ifdef INET6
+int if_checkipv6(struct dhcpcd_ctx *ctx, const struct interface *, int);
+#ifdef IPV6_MANAGETEMPADDR
+int ip6_use_tempaddr(const char *ifname);
+int ip6_temp_preferred_lifetime(const char *ifname);
+int ip6_temp_valid_lifetime(const char *ifname);
+#else
+#define ip6_use_tempaddr(a) (0)
+#endif
+
+int if_address6(const struct ipv6_addr *, int);
+#define if_addaddress6(a) if_address6(a, 1)
+#define if_deladdress6(a) if_address6(a, -1)
+
+int if_addrflags6(const struct in6_addr *, const struct interface *);
+int if_getlifetime6(struct ipv6_addr *);
+
+int if_route6(unsigned char, const struct rt6 *rt);
+int if_initrt6(struct interface *);
+#else
+#define if_checkipv6(a, b, c) (-1)
+#endif
+
+int if_machinearch(char *, size_t);
+#endif
diff --git a/dhcpcd-6.8.2/ifaddrs.c b/dhcpcd-6.8.2/ifaddrs.c
new file mode 100644
index 0000000..1a27d8f
--- /dev/null
+++ b/dhcpcd-6.8.2/ifaddrs.c
@@ -0,0 +1,150 @@
+/* external/dhcpcd-6.8.2/ifaddrs.c
+** Copied from external/dhcpcd/ifaddrs.c.
+**
+** Copyright 2011, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");.
+** you may not use this file except in compliance with the License..
+** You may obtain a copy of the License at.
+**
+**     http://www.apache.org/licenses/LICENSE-2.0.
+**
+** Unless required by applicable law or agreed to in writing, software.
+** distributed under the License is distributed on an "AS IS" BASIS,.
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied..
+** See the License for the specific language governing permissions and.
+** limitations under the License.
+*/
+
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include "ifaddrs.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <netinet/ether.h>
+#include <netdb.h>
+#include <linux/if_packet.h>
+#include <netinet/if_ether.h>
+#include <linux/if_arp.h>
+#include <netutils/ifc.h>
+
+struct ifaddrs *get_interface(const char *name, sa_family_t family)
+{
+    unsigned addr, flags;
+    int masklen;
+    struct ifaddrs *ifa;
+    struct sockaddr_in *saddr = NULL;
+    struct sockaddr_in *smask = NULL;
+    struct sockaddr_ll *hwaddr = NULL;
+    unsigned char hwbuf[ETH_ALEN];
+
+    if (ifc_get_info(name, &addr, &masklen, &flags))
+        return NULL;
+
+    if ((family == AF_INET) && (addr == 0))
+        return NULL;
+
+    ifa = malloc(sizeof(struct ifaddrs));
+    if (!ifa)
+        return NULL;
+    memset(ifa, 0, sizeof(struct ifaddrs));
+
+    ifa->ifa_name = malloc(strlen(name)+1);
+    if (!ifa->ifa_name) {
+        free(ifa);
+        return NULL;
+    }
+    strcpy(ifa->ifa_name, name);
+    ifa->ifa_flags = flags;
+
+    if (family == AF_INET) {
+        saddr = malloc(sizeof(struct sockaddr_in));
+        if (saddr) {
+            saddr->sin_addr.s_addr = addr;
+            saddr->sin_family = family;
+        }
+        ifa->ifa_addr = (struct sockaddr *)saddr;
+
+        if (masklen != 0) {
+            smask = malloc(sizeof(struct sockaddr_in));
+            if (smask) {
+                smask->sin_addr.s_addr = prefixLengthToIpv4Netmask(masklen);
+                smask->sin_family = family;
+            }
+        }
+        ifa->ifa_netmask = (struct sockaddr *)smask;
+    } else if (family == AF_PACKET) {
+        if (!ifc_get_hwaddr(name, hwbuf)) {
+            hwaddr = malloc(sizeof(struct sockaddr_ll));
+            if (hwaddr) {
+                memset(hwaddr, 0, sizeof(struct sockaddr_ll));
+                hwaddr->sll_family = family;
+                /* hwaddr->sll_protocol = ETHERTYPE_IP; */
+                ifc_get_ifindex(ifa->ifa_name, &hwaddr->sll_ifindex);
+                hwaddr->sll_hatype = ARPHRD_ETHER;
+                hwaddr->sll_halen = ETH_ALEN;
+                memcpy(hwaddr->sll_addr, hwbuf, ETH_ALEN);
+            }
+        }
+        ifa->ifa_addr = (struct sockaddr *)hwaddr;
+        ifa->ifa_netmask = (struct sockaddr *)smask;
+    }
+    return ifa;
+}
+
+int getifaddrs(struct ifaddrs **ifap)
+{
+    DIR *d;
+    struct dirent *de;
+    struct ifaddrs *ifa;
+    struct ifaddrs *ifah = NULL;
+
+    if (!ifap)
+        return -1;
+    *ifap = NULL;
+
+    if (ifc_init())
+       return -1;
+
+    d = opendir("/sys/class/net");
+    if (d == 0)
+        return -1;
+    while ((de = readdir(d))) {
+        if (de->d_name[0] == '.')
+            continue;
+        ifa = get_interface(de->d_name, AF_INET);
+        if (ifa != NULL) {
+            ifa->ifa_next = ifah;
+            ifah = ifa;
+        }
+        ifa = get_interface(de->d_name, AF_PACKET);
+        if (ifa != NULL) {
+            ifa->ifa_next = ifah;
+            ifah = ifa;
+        }
+    }
+    *ifap = ifah;
+    closedir(d);
+    ifc_close();
+    return 0;
+}
+
+void freeifaddrs(struct ifaddrs *ifa)
+{
+    struct ifaddrs *ifp;
+
+    while (ifa) {
+        ifp = ifa;
+        free(ifp->ifa_name);
+        if (ifp->ifa_addr)
+            free(ifp->ifa_addr);
+        if (ifp->ifa_netmask)
+            free(ifp->ifa_netmask);
+        ifa = ifa->ifa_next;
+        free(ifp);
+    }
+}
diff --git a/dhcpcd-6.8.2/ifaddrs.h b/dhcpcd-6.8.2/ifaddrs.h
new file mode 100644
index 0000000..6356653
--- /dev/null
+++ b/dhcpcd-6.8.2/ifaddrs.h
@@ -0,0 +1,34 @@
+/****************************************************************************
+ ****************************************************************************
+ ***
+ ***   This header was generated from a glibc header of the same name.
+ ***   It contains only constants, structures, and macros generated from
+ ***   the original header, and thus, contains no copyrightable information.
+ ***
+ ****************************************************************************
+ ****************************************************************************/
+#ifndef _IFADDRS_H
+#define _IFADDRS_H
+
+#include <sys/socket.h>
+
+struct ifaddrs {
+  struct ifaddrs  *ifa_next;
+  char            *ifa_name;
+  unsigned int     ifa_flags;
+  struct sockaddr *ifa_addr;
+  struct sockaddr *ifa_netmask;
+  union {
+    struct sockaddr *ifu_broadaddr;
+    struct sockaddr *ifu_dstaddr;
+  } ifa_ifu;
+#define ifa_broadaddr ifa_ifu.ifu_broadaddr
+#define ifa_dstaddr   ifa_ifu.ifu_dstaddr
+  void            *ifa_data;
+};
+
+extern int getifaddrs(struct ifaddrs **ifap);
+
+extern void freeifaddrs(struct ifaddrs *ifa);
+
+#endif
diff --git a/dhcpcd-6.8.2/ipv4.c b/dhcpcd-6.8.2/ipv4.c
new file mode 100644
index 0000000..f7b0d22
--- /dev/null
+++ b/dhcpcd-6.8.2/ipv4.c
@@ -0,0 +1,1108 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <net/route.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "config.h"
+#include "arp.h"
+#include "common.h"
+#include "dhcpcd.h"
+#include "dhcp.h"
+#include "if.h"
+#include "if-options.h"
+#include "ipv4.h"
+#include "script.h"
+#ifdef PASSIVE_MODE
+#include "rpc-interface.h"
+#endif
+
+#define IPV4_LOOPBACK_ROUTE
+#if defined(__linux__) || (defined(BSD) && defined(RTF_LOCAL))
+/* Linux has had loopback routes in the local table since 2.2 */
+#undef IPV4_LOOPBACK_ROUTE
+#endif
+
+uint8_t
+inet_ntocidr(struct in_addr address)
+{
+	uint8_t cidr = 0;
+	uint32_t mask = htonl(address.s_addr);
+
+	while (mask) {
+		cidr++;
+		mask <<= 1;
+	}
+	return cidr;
+}
+
+int
+inet_cidrtoaddr(int cidr, struct in_addr *addr)
+{
+	int ocets;
+
+	if (cidr < 1 || cidr > 32) {
+		errno = EINVAL;
+		return -1;
+	}
+	ocets = (cidr + 7) / NBBY;
+
+	addr->s_addr = 0;
+	if (ocets > 0) {
+		memset(&addr->s_addr, 255, (size_t)ocets - 1);
+		memset((unsigned char *)&addr->s_addr + (ocets - 1),
+		    (256 - (1 << (32 - cidr) % NBBY)), 1);
+	}
+
+	return 0;
+}
+
+uint32_t
+ipv4_getnetmask(uint32_t addr)
+{
+	uint32_t dst;
+
+	if (addr == 0)
+		return 0;
+
+	dst = htonl(addr);
+	if (IN_CLASSA(dst))
+		return ntohl(IN_CLASSA_NET);
+	if (IN_CLASSB(dst))
+		return ntohl(IN_CLASSB_NET);
+	if (IN_CLASSC(dst))
+		return ntohl(IN_CLASSC_NET);
+
+	return 0;
+}
+
+struct ipv4_addr *
+ipv4_iffindaddr(struct interface *ifp,
+    const struct in_addr *addr, const struct in_addr *net)
+{
+	struct ipv4_state *state;
+	struct ipv4_addr *ap;
+
+	state = IPV4_STATE(ifp);
+	if (state) {
+		TAILQ_FOREACH(ap, &state->addrs, next) {
+			if ((addr == NULL || ap->addr.s_addr == addr->s_addr) &&
+			    (net == NULL || ap->net.s_addr == net->s_addr))
+				return ap;
+		}
+	}
+	return NULL;
+}
+
+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;
+	struct ipv4_addr *ap;
+
+	TAILQ_FOREACH(ifp, ctx->ifaces, next) {
+		ap = ipv4_iffindaddr(ifp, addr, NULL);
+		if (ap)
+			return ap;
+	}
+	return NULL;
+}
+
+int
+ipv4_addrexists(struct dhcpcd_ctx *ctx, const struct in_addr *addr)
+{
+	struct interface *ifp;
+	struct dhcp_state *state;
+
+	TAILQ_FOREACH(ifp, ctx->ifaces, next) {
+		state = D_STATE(ifp);
+		if (state) {
+			if (addr == NULL) {
+				if (state->addr.s_addr != INADDR_ANY)
+					return 1;
+			} else if (addr->s_addr == state->addr.s_addr)
+				return 1;
+		}
+		if (addr != NULL && ipv4_iffindaddr(ifp, addr, NULL))
+			return 1;
+	}
+	return 0;
+}
+
+void
+ipv4_freeroutes(struct rt_head *rts)
+{
+
+	if (rts) {
+		ipv4_freerts(rts);
+		free(rts);
+	}
+}
+
+int
+ipv4_init(struct dhcpcd_ctx *ctx)
+{
+
+	if (ctx->ipv4_routes == NULL) {
+		ctx->ipv4_routes = malloc(sizeof(*ctx->ipv4_routes));
+		if (ctx->ipv4_routes == NULL)
+			return -1;
+		TAILQ_INIT(ctx->ipv4_routes);
+	}
+	if (ctx->ipv4_kroutes == NULL) {
+		ctx->ipv4_kroutes = malloc(sizeof(*ctx->ipv4_kroutes));
+		if (ctx->ipv4_kroutes == NULL)
+			return -1;
+		TAILQ_INIT(ctx->ipv4_kroutes);
+	}
+	return 0;
+}
+
+/* Interface comparer for working out ordering. */
+int
+ipv4_ifcmp(const struct interface *si, const struct interface *ti)
+{
+	const struct dhcp_state *sis, *tis;
+
+	sis = D_CSTATE(si);
+	tis = D_CSTATE(ti);
+	if (sis && !tis)
+		return -1;
+	if (!sis && tis)
+		return 1;
+	if (!sis && !tis)
+		return 0;
+	/* If one has a lease and the other not, it takes precedence. */
+	if (sis->new && !tis->new)
+		return -1;
+	if (!sis->new && tis->new)
+		return 1;
+	/* Always prefer proper leases */
+	if (!(sis->added & STATE_FAKE) && (sis->added & STATE_FAKE))
+		return -1;
+	if ((sis->added & STATE_FAKE) && !(sis->added & STATE_FAKE))
+		return 1;
+	/* If we are either, they neither have a lease, or they both have.
+	 * We need to check for IPv4LL and make it non-preferred. */
+	if (sis->new && tis->new) {
+		int sill = (sis->new->cookie == htonl(MAGIC_COOKIE));
+		int till = (tis->new->cookie == htonl(MAGIC_COOKIE));
+		if (sill && !till)
+			return -1;
+		if (!sill && till)
+			return 1;
+	}
+	return 0;
+}
+
+static struct rt *
+find_route(struct rt_head *rts, const struct rt *r, const struct rt *srt)
+{
+	struct rt *rt;
+
+	if (rts == NULL)
+		return NULL;
+	TAILQ_FOREACH(rt, rts, next) {
+		if (rt->dest.s_addr == r->dest.s_addr &&
+#ifdef HAVE_ROUTE_METRIC
+		    (srt || (r->iface == NULL || rt->iface == NULL ||
+		    rt->iface->metric == r->iface->metric)) &&
+#endif
+                    (!srt || srt != rt) &&
+		    rt->net.s_addr == r->net.s_addr)
+			return rt;
+	}
+	return NULL;
+}
+
+static void
+desc_route(const char *cmd, const struct rt *rt)
+{
+	char addr[sizeof("000.000.000.000") + 1];
+	struct dhcpcd_ctx *ctx = rt->iface ? rt->iface->ctx : NULL;
+	const char *ifname = rt->iface ? rt->iface->name : NULL;
+
+	strlcpy(addr, inet_ntoa(rt->dest), sizeof(addr));
+	if (rt->net.s_addr == htonl(INADDR_BROADCAST) &&
+	    rt->gate.s_addr == htonl(INADDR_ANY))
+		logger(ctx, LOG_INFO, "%s: %s host route to %s",
+		    ifname, cmd, addr);
+	else if (rt->net.s_addr == htonl(INADDR_BROADCAST))
+		logger(ctx, LOG_INFO, "%s: %s host route to %s via %s",
+		    ifname, cmd, addr, inet_ntoa(rt->gate));
+	else if (rt->gate.s_addr == htonl(INADDR_ANY))
+		logger(ctx, LOG_INFO, "%s: %s route to %s/%d",
+		    ifname, cmd, addr, inet_ntocidr(rt->net));
+	else if (rt->dest.s_addr == htonl(INADDR_ANY) &&
+	    rt->net.s_addr == htonl(INADDR_ANY))
+		logger(ctx, LOG_INFO, "%s: %s default route via %s",
+		    ifname, cmd, inet_ntoa(rt->gate));
+	else
+		logger(ctx, LOG_INFO, "%s: %s route to %s/%d via %s",
+		    ifname, cmd, addr, inet_ntocidr(rt->net),
+		    inet_ntoa(rt->gate));
+}
+
+static struct rt *
+ipv4_findrt(struct dhcpcd_ctx *ctx, const struct rt *rt, int flags)
+{
+	struct rt *r;
+
+	if (ctx->ipv4_kroutes == NULL)
+		return NULL;
+	TAILQ_FOREACH(r, ctx->ipv4_kroutes, next) {
+		if (rt->dest.s_addr == r->dest.s_addr &&
+#ifdef HAVE_ROUTE_METRIC
+		    rt->iface == r->iface &&
+		    (!flags || rt->metric == r->metric) &&
+#else
+		    (!flags || rt->iface == r->iface) &&
+#endif
+		    rt->net.s_addr == r->net.s_addr)
+			return r;
+	}
+	return NULL;
+}
+
+void
+ipv4_freerts(struct rt_head *routes)
+{
+	struct rt *rt;
+
+	while ((rt = TAILQ_FIRST(routes))) {
+		TAILQ_REMOVE(routes, rt, next);
+		free(rt);
+	}
+}
+
+/* If something other than dhcpcd removes a route,
+ * we need to remove it from our internal table. */
+int
+ipv4_handlert(struct dhcpcd_ctx *ctx, int cmd, struct rt *rt)
+{
+	struct rt *f;
+
+	if (ctx->ipv4_kroutes == NULL)
+		return 0;
+
+	f = ipv4_findrt(ctx, rt, 1);
+	switch (cmd) {
+	case RTM_ADD:
+		if (f == NULL) {
+			if ((f = malloc(sizeof(*f))) == NULL)
+				return -1;
+			*f = *rt;
+			TAILQ_INSERT_TAIL(ctx->ipv4_kroutes, f, next);
+		}
+		break;
+	case RTM_DELETE:
+		if (f) {
+			TAILQ_REMOVE(ctx->ipv4_kroutes, f, next);
+			free(f);
+		}
+
+		/* If we manage the route, remove it */
+		if ((f = find_route(ctx->ipv4_routes, rt, NULL))) {
+			desc_route("removing", f);
+			TAILQ_REMOVE(ctx->ipv4_routes, f, next);
+			free(f);
+		}
+		break;
+	}
+	return 0;
+}
+
+#define n_route(a)	 nc_route(NULL, a)
+#define c_route(a, b)	 nc_route(a, b)
+static int
+nc_route(struct rt *ort, struct rt *nrt)
+{
+
+	/* Don't set default routes if not asked to */
+	if (nrt->dest.s_addr == 0 &&
+	    nrt->net.s_addr == 0 &&
+	    !(nrt->iface->options->options & DHCPCD_GATEWAY))
+		return -1;
+
+	desc_route(ort == NULL ? "adding" : "changing", nrt);
+
+	if (ort == NULL) {
+		ort = ipv4_findrt(nrt->iface->ctx, nrt, 0);
+		if (ort &&
+		    ((ort->flags & RTF_REJECT && nrt->flags & RTF_REJECT) ||
+		     (ort->iface == nrt->iface &&
+#ifdef HAVE_ROUTE_METRIC
+		    ort->metric == nrt->metric &&
+#endif
+		    ort->gate.s_addr == nrt->gate.s_addr)))
+			return 0;
+	} else if (ort->flags & STATE_FAKE && !(nrt->flags & STATE_FAKE) &&
+	    ort->iface == nrt->iface &&
+#ifdef HAVE_ROUTE_METRIC
+	    ort->metric == nrt->metric &&
+#endif
+	    ort->dest.s_addr == nrt->dest.s_addr &&
+	    ort->net.s_addr ==  nrt->net.s_addr &&
+	    ort->gate.s_addr == nrt->gate.s_addr)
+		return 0;
+
+#ifdef HAVE_ROUTE_METRIC
+	/* With route metrics, we can safely add the new route before
+	 * deleting the old route. */
+	if (if_route(RTM_ADD, nrt)  == 0) {
+		if (ort && if_route(RTM_DELETE, ort) == -1 && errno != ESRCH)
+			logger(nrt->iface->ctx, LOG_ERR, "if_route (DEL): %m");
+		return 0;
+	}
+
+	/* If the kernel claims the route exists we need to rip out the
+	 * old one first. */
+	if (errno != EEXIST || ort == NULL)
+		goto logerr;
+#endif
+
+	/* No route metrics, we need to delete the old route before
+	 * adding the new one. */
+	if (ort && if_route(RTM_DELETE, ort) == -1 && errno != ESRCH)
+		logger(nrt->iface->ctx, LOG_ERR, "if_route (DEL): %m");
+	if (if_route(RTM_ADD, nrt) == 0)
+		return 0;
+#ifdef HAVE_ROUTE_METRIC
+logerr:
+#endif
+	logger(nrt->iface->ctx, LOG_ERR, "if_route (ADD): %m");
+	return -1;
+}
+
+static int
+d_route(struct rt *rt)
+{
+	int retval;
+
+	desc_route("deleting", rt);
+	retval = if_route(RTM_DELETE, rt);
+	if (retval != 0 && errno != ENOENT && errno != ESRCH)
+		logger(rt->iface->ctx, LOG_ERR,
+		    "%s: if_delroute: %m", rt->iface->name);
+	return retval;
+}
+
+static struct rt_head *
+add_subnet_route(struct rt_head *rt, const struct interface *ifp)
+{
+	const struct dhcp_state *s;
+	struct rt *r;
+
+	if (rt == NULL) /* earlier malloc failed */
+		return NULL;
+
+	s = D_CSTATE(ifp);
+	/* Don't create a subnet route for these addresses */
+	if (s->net.s_addr == INADDR_ANY)
+		return rt;
+#ifndef BSD
+	/* BSD adds a route in this instance */
+	if (s->net.s_addr == INADDR_BROADCAST)
+		return rt;
+#endif
+
+	if ((r = malloc(sizeof(*r))) == NULL) {
+		logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
+		ipv4_freeroutes(rt);
+		return NULL;
+	}
+	r->dest.s_addr = s->addr.s_addr & s->net.s_addr;
+	r->net.s_addr = s->net.s_addr;
+	r->gate.s_addr = INADDR_ANY;
+
+	TAILQ_INSERT_HEAD(rt, r, next);
+	return rt;
+}
+
+#ifdef IPV4_LOOPBACK_ROUTE
+static struct rt_head *
+add_loopback_route(struct rt_head *rt, const struct interface *ifp)
+{
+	struct rt *r;
+	const struct dhcp_state *s;
+
+	if (rt == NULL) /* earlier malloc failed */
+		return NULL;
+
+	s = D_CSTATE(ifp);
+	if (s->addr.s_addr == INADDR_ANY)
+		return rt;
+
+	r = malloc(sizeof(*r));
+	if (r == NULL) {
+		logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
+		ipv4_freeroutes(rt);
+		return NULL;
+	}
+	r->dest.s_addr = s->addr.s_addr;
+	r->net.s_addr = INADDR_BROADCAST;
+	r->gate.s_addr = htonl(INADDR_LOOPBACK);
+	TAILQ_INSERT_HEAD(rt, r, next);
+	return rt;
+}
+#endif
+
+static struct rt_head *
+get_routes(struct interface *ifp)
+{
+	struct rt_head *nrt;
+	struct rt *rt, *r = NULL;
+
+	if (ifp->options->routes && TAILQ_FIRST(ifp->options->routes)) {
+		nrt = malloc(sizeof(*nrt));
+		TAILQ_INIT(nrt);
+		TAILQ_FOREACH(rt, ifp->options->routes, next) {
+			if (rt->gate.s_addr == 0)
+				break;
+			r = malloc(sizeof(*r));
+			if (r == NULL) {
+				logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
+				ipv4_freeroutes(nrt);
+				return NULL;
+			}
+			memcpy(r, rt, sizeof(*r));
+			TAILQ_INSERT_TAIL(nrt, r, next);
+		}
+		return nrt;
+	}
+
+	return get_option_routes(ifp, D_STATE(ifp)->new);
+}
+
+/* Some DHCP servers add set host routes by setting the gateway
+ * to the assigned IP address or the destination address.
+ * We need to change this. */
+static struct rt_head *
+massage_host_routes(struct rt_head *rt, const struct interface *ifp)
+{
+	struct rt *r;
+
+	if (rt) {
+		TAILQ_FOREACH(r, rt, next) {
+			if (r->gate.s_addr == D_CSTATE(ifp)->addr.s_addr ||
+			    r->gate.s_addr == r->dest.s_addr)
+			{
+				r->gate.s_addr = htonl(INADDR_ANY);
+				r->net.s_addr = htonl(INADDR_BROADCAST);
+			}
+		}
+	}
+	return rt;
+}
+
+
+static struct rt_head *
+add_destination_route(struct rt_head *rt, const struct interface *ifp)
+{
+	struct rt *r;
+
+	if (rt == NULL || /* failed a malloc earlier probably */
+	    !(ifp->flags & IFF_POINTOPOINT) ||
+	    !has_option_mask(ifp->options->dstmask, DHO_ROUTER))
+		return rt;
+
+	r = malloc(sizeof(*r));
+	if (r == NULL) {
+		logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
+		ipv4_freeroutes(rt);
+		return NULL;
+	}
+	r->dest.s_addr = INADDR_ANY;
+	r->net.s_addr = INADDR_ANY;
+	r->gate.s_addr = D_CSTATE(ifp)->dst.s_addr;
+	TAILQ_INSERT_HEAD(rt, r, next);
+	return rt;
+}
+
+/* We should check to ensure the routers are on the same subnet
+ * OR supply a host route. If not, warn and add a host route. */
+static struct rt_head *
+add_router_host_route(struct rt_head *rt, const struct interface *ifp)
+{
+	struct rt *rtp, *rtn;
+	const char *cp, *cp2, *cp3, *cplim;
+	struct if_options *ifo;
+	const struct dhcp_state *state;
+
+	if (rt == NULL) /* earlier malloc failed */
+		return NULL;
+
+	TAILQ_FOREACH(rtp, rt, next) {
+		if (rtp->dest.s_addr != INADDR_ANY)
+			continue;
+		/* Scan for a route to match */
+		TAILQ_FOREACH(rtn, rt, next) {
+			if (rtn == rtp)
+				break;
+			/* match host */
+			if (rtn->dest.s_addr == rtp->gate.s_addr)
+				break;
+			/* match subnet */
+			cp = (const char *)&rtp->gate.s_addr;
+			cp2 = (const char *)&rtn->dest.s_addr;
+			cp3 = (const char *)&rtn->net.s_addr;
+			cplim = cp3 + sizeof(rtn->net.s_addr);
+			while (cp3 < cplim) {
+				if ((*cp++ ^ *cp2++) & *cp3++)
+					break;
+			}
+			if (cp3 == cplim)
+				break;
+		}
+		if (rtn != rtp)
+			continue;
+		state = D_CSTATE(ifp);
+		ifo = ifp->options;
+		if (ifp->flags & IFF_NOARP) {
+			if (!(ifo->options & DHCPCD_ROUTER_HOST_ROUTE_WARNED) &&
+			    !(state->added & STATE_FAKE))
+			{
+				ifo->options |= DHCPCD_ROUTER_HOST_ROUTE_WARNED;
+				logger(ifp->ctx, LOG_WARNING,
+				    "%s: forcing router %s through interface",
+				    ifp->name, inet_ntoa(rtp->gate));
+			}
+			rtp->gate.s_addr = 0;
+			continue;
+		}
+		if (!(ifo->options & DHCPCD_ROUTER_HOST_ROUTE_WARNED) &&
+		    !(state->added & STATE_FAKE))
+		{
+			ifo->options |= DHCPCD_ROUTER_HOST_ROUTE_WARNED;
+			logger(ifp->ctx, LOG_WARNING,
+			    "%s: router %s requires a host route",
+			    ifp->name, inet_ntoa(rtp->gate));
+		}
+		rtn = malloc(sizeof(*rtn));
+		if (rtn == NULL) {
+			logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
+			ipv4_freeroutes(rt);
+			return NULL;
+		}
+		rtn->dest.s_addr = rtp->gate.s_addr;
+		rtn->net.s_addr = htonl(INADDR_BROADCAST);
+		rtn->gate.s_addr = htonl(INADDR_ANY);
+		TAILQ_INSERT_BEFORE(rtp, rtn, next);
+	}
+	return rt;
+}
+
+void
+ipv4_buildroutes(struct dhcpcd_ctx *ctx)
+{
+/* Do not modify route table when running in passive mode. */
+#ifndef PASSIVE_MODE
+	struct rt_head *nrs, *dnr;
+	struct rt *or, *rt, *rtn;
+	struct interface *ifp;
+	const struct dhcp_state *state;
+
+	/* We need to have the interfaces in the correct order to ensure
+	 * our routes are managed correctly. */
+	if_sortinterfaces(ctx);
+
+	nrs = malloc(sizeof(*nrs));
+	if (nrs == NULL) {
+		logger(ctx, LOG_ERR, "%s: %m", __func__);
+		return;
+	}
+	TAILQ_INIT(nrs);
+
+	TAILQ_FOREACH(ifp, ctx->ifaces, next) {
+		state = D_CSTATE(ifp);
+		if (state == NULL || state->new == NULL || !state->added)
+			continue;
+		dnr = get_routes(ifp);
+		dnr = massage_host_routes(dnr, ifp);
+		dnr = add_subnet_route(dnr, ifp);
+#ifdef IPV4_LOOPBACK_ROUTE
+		dnr = add_loopback_route(dnr, ifp);
+#endif
+		if (ifp->options->options & DHCPCD_GATEWAY) {
+			dnr = add_router_host_route(dnr, ifp);
+			dnr = add_destination_route(dnr, ifp);
+		}
+		if (dnr == NULL) /* failed to malloc all new routes */
+			continue;
+		TAILQ_FOREACH_SAFE(rt, dnr, next, rtn) {
+			rt->iface = ifp;
+#ifdef HAVE_ROUTE_METRIC
+			rt->metric = ifp->metric;
+#endif
+			rt->flags = state->added & STATE_FAKE;
+			/* Is this route already in our table? */
+			if ((find_route(nrs, rt, NULL)) != NULL)
+				continue;
+			rt->src.s_addr = state->addr.s_addr;
+			/* Do we already manage it? */
+			if ((or = find_route(ctx->ipv4_routes, rt, NULL))) {
+				if (state->added & STATE_FAKE)
+					continue;
+				if (or->flags & STATE_FAKE ||
+				    or->iface != ifp ||
+#ifdef HAVE_ROUTE_METRIC
+				    rt->metric != or->metric ||
+#endif
+				    or->src.s_addr != state->addr.s_addr ||
+				    rt->gate.s_addr != or->gate.s_addr)
+				{
+					if (c_route(or, rt) != 0)
+						continue;
+				}
+				TAILQ_REMOVE(ctx->ipv4_routes, or, next);
+				free(or);
+			} else {
+				if (state->added & STATE_FAKE) {
+					or = ipv4_findrt(ctx, rt, 1);
+					if (or == NULL ||
+					    or->gate.s_addr != rt->gate.s_addr)
+ 						continue;
+				} else {
+					if (n_route(rt) != 0)
+						continue;
+				}
+			}
+			rt->flags |= STATE_ADDED;
+			TAILQ_REMOVE(dnr, rt, next);
+			TAILQ_INSERT_TAIL(nrs, rt, next);
+		}
+		ipv4_freeroutes(dnr);
+	}
+
+	/* Remove old routes we used to manage */
+	if (ctx->ipv4_routes) {
+		TAILQ_FOREACH(rt, ctx->ipv4_routes, next) {
+			if (find_route(nrs, rt, NULL) == NULL &&
+			    (rt->iface->options->options &
+			    (DHCPCD_EXITING | DHCPCD_PERSISTENT)) !=
+			    (DHCPCD_EXITING | DHCPCD_PERSISTENT))
+				d_route(rt);
+		}
+	}
+	ipv4_freeroutes(ctx->ipv4_routes);
+	ctx->ipv4_routes = nrs;
+#endif
+}
+
+int
+ipv4_deladdr(struct interface *ifp,
+    const struct in_addr *addr, const struct in_addr *net)
+{
+	int r = 0;
+#ifndef PASSIVE_MODE
+	struct dhcp_state *dstate;
+	struct ipv4_state *state;
+	struct ipv4_addr *ap;
+
+	logger(ifp->ctx, LOG_DEBUG, "%s: deleting IP address %s/%d",
+	    ifp->name, inet_ntoa(*addr), inet_ntocidr(*net));
+
+	r = if_deladdress(ifp, addr, net);
+	if (r == -1 && errno != EADDRNOTAVAIL && errno != ENXIO &&
+	    errno != ENODEV)
+		logger(ifp->ctx, LOG_ERR, "%s: %s: %m", ifp->name, __func__);
+
+	dstate = D_STATE(ifp);
+	if (dstate->addr.s_addr == addr->s_addr &&
+	    dstate->net.s_addr == net->s_addr)
+	{
+		dstate->added = 0;
+		dstate->addr.s_addr = 0;
+		dstate->net.s_addr = 0;
+	}
+
+	state = IPV4_STATE(ifp);
+	TAILQ_FOREACH(ap, &state->addrs, next) {
+		if (ap->addr.s_addr == addr->s_addr &&
+		    ap->net.s_addr == net->s_addr)
+		{
+			TAILQ_REMOVE(&state->addrs, ap, next);
+			free(ap);
+			break;
+		}
+	}
+#endif
+	return r;
+}
+
+static int
+delete_address(struct interface *ifp)
+{
+	int r;
+	struct if_options *ifo;
+	struct dhcp_state *state;
+
+	state = D_STATE(ifp);
+	ifo = ifp->options;
+	if (ifo->options & DHCPCD_INFORM ||
+	    (ifo->options & DHCPCD_STATIC && ifo->req_addr.s_addr == 0))
+		return 0;
+	r = ipv4_deladdr(ifp, &state->addr, &state->net);
+	return r;
+}
+
+static struct ipv4_state *
+ipv4_getstate(struct interface *ifp)
+{
+	struct ipv4_state *state;
+
+	state = IPV4_STATE(ifp);
+	if (state == NULL) {
+	        ifp->if_data[IF_DATA_IPV4] = malloc(sizeof(*state));
+		state = IPV4_STATE(ifp);
+		if (state == NULL) {
+			logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
+			return NULL;
+		}
+		TAILQ_INIT(&state->addrs);
+		TAILQ_INIT(&state->routes);
+	}
+	return state;
+}
+
+static int
+ipv4_addaddr(struct interface *ifp, const struct dhcp_lease *lease)
+{
+	struct ipv4_state *state;
+	struct ipv4_addr *ia;
+
+	if ((state = ipv4_getstate(ifp)) == NULL) {
+		logger(ifp->ctx, LOG_ERR, "%s: ipv4_getstate: %m", __func__);
+		return -1;
+	}
+	if (ifp->options->options & DHCPCD_NOALIAS) {
+		struct ipv4_addr *ian;
+
+		TAILQ_FOREACH_SAFE(ia, &state->addrs, next, ian) {
+			if (ia->addr.s_addr != lease->addr.s_addr)
+				ipv4_deladdr(ifp, &ia->addr, &ia->net);
+		}
+	}
+
+	if ((ia = malloc(sizeof(*ia))) == NULL) {
+		logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
+		return -1;
+	}
+
+	logger(ifp->ctx, LOG_DEBUG, "%s: adding IP address %s/%d",
+	    ifp->name, inet_ntoa(lease->addr),
+	    inet_ntocidr(lease->net));
+	if (if_addaddress(ifp, &lease->addr, &lease->net, &lease->brd) == -1) {
+		if (errno != EEXIST)
+			logger(ifp->ctx, LOG_ERR, "%s: if_addaddress: %m",
+			    __func__);
+		free(ia);
+		return -1;
+	}
+
+	ia->iface = ifp;
+	ia->addr = lease->addr;
+	ia->net = lease->net;
+#ifdef IN_IFF_TENTATIVE
+	ia->addr_flags = IN_IFF_TENTATIVE;
+#endif
+	TAILQ_INSERT_TAIL(&state->addrs, ia, next);
+	return 0;
+}
+
+static void
+ipv4_finalisert(struct interface *ifp)
+{
+	const struct dhcp_state *state = D_CSTATE(ifp);
+
+	/* Find any freshly added routes, such as the subnet route.
+	 * We do this because we cannot rely on recieving the kernel
+	 * notification right now via our link socket. */
+	if_initrt(ifp);
+	ipv4_buildroutes(ifp->ctx);
+	script_runreason(ifp, state->reason);
+
+	dhcpcd_daemonise(ifp->ctx);
+}
+
+void
+ipv4_finaliseaddr(struct interface *ifp)
+{
+#ifndef PASSIVE_MODE
+	struct dhcp_state *state = D_STATE(ifp);
+	struct dhcp_lease *lease;
+
+	lease = &state->lease;
+
+	/* Delete the old address if different */
+	if (state->addr.s_addr != lease->addr.s_addr &&
+	    state->addr.s_addr != 0 &&
+	    ipv4_iffindaddr(ifp, &lease->addr, NULL))
+		delete_address(ifp);
+
+	state->added = STATE_ADDED;
+	state->defend = 0;
+	state->addr.s_addr = lease->addr.s_addr;
+	state->net.s_addr = lease->net.s_addr;
+	ipv4_finalisert(ifp);
+#endif
+}
+
+void
+ipv4_applyaddr(void *arg)
+{
+#ifdef PASSIVE_MODE
+	rpc_update_ipv4(arg);
+#else
+	struct interface *ifp = arg, *ifn;
+	struct dhcp_state *state = D_STATE(ifp), *nstate;
+	struct dhcp_message *dhcp;
+	struct dhcp_lease *lease;
+	struct if_options *ifo = ifp->options;
+	struct ipv4_addr *ap;
+	int r;
+
+	if (state == NULL)
+		return;
+	dhcp = state->new;
+	lease = &state->lease;
+
+	if (dhcp == NULL) {
+		if ((ifo->options & (DHCPCD_EXITING | DHCPCD_PERSISTENT)) !=
+		    (DHCPCD_EXITING | DHCPCD_PERSISTENT))
+		{
+			if (state->added) {
+				struct in_addr addr;
+
+				addr = state->addr;
+				delete_address(ifp);
+				TAILQ_FOREACH(ifn, ifp->ctx->ifaces, next) {
+					if (ifn == ifp ||
+					    strcmp(ifn->name, ifp->name) == 0)
+						continue;
+					nstate = D_STATE(ifn);
+					if (nstate && !nstate->added &&
+					    nstate->addr.s_addr == addr.s_addr)
+					{
+						if (ifn->options->options &
+						    DHCPCD_ARP)
+						{
+							dhcp_bind(ifn, NULL);
+						} else {
+							ipv4_addaddr(ifn,
+							    &nstate->lease);
+							nstate->added =
+							    STATE_ADDED;
+						}
+						break;
+					}
+				}
+			}
+			ipv4_buildroutes(ifp->ctx);
+			script_runreason(ifp, state->reason);
+		} else
+			ipv4_buildroutes(ifp->ctx);
+		return;
+	}
+
+	/* Ensure only one interface has the address */
+	TAILQ_FOREACH(ifn, ifp->ctx->ifaces, next) {
+		if (ifn == ifp || strcmp(ifn->name, ifp->name) == 0)
+			continue;
+		nstate = D_STATE(ifn);
+		if (nstate && nstate->added &&
+		    nstate->addr.s_addr == lease->addr.s_addr)
+		{
+			if (ifn->metric <= ifp->metric) {
+				logger(ifp->ctx, LOG_INFO,
+				    "%s: preferring %s on %s",
+				    ifp->name,
+				    inet_ntoa(lease->addr),
+				    ifn->name);
+				state->addr.s_addr = lease->addr.s_addr;
+				state->net.s_addr = lease->net.s_addr;
+				ipv4_finalisert(ifp);
+			}
+			logger(ifp->ctx, LOG_INFO, "%s: preferring %s on %s",
+			    ifn->name,
+			    inet_ntoa(lease->addr),
+			    ifp->name);
+			ipv4_deladdr(ifn, &nstate->addr, &nstate->net);
+			nstate->added = 0;
+			break;
+		}
+	}
+
+	/* Does another interface already have the address from a prior boot? */
+	if (ifn == NULL) {
+		TAILQ_FOREACH(ifn, ifp->ctx->ifaces, next) {
+			if (ifn == ifp || strcmp(ifn->name, ifp->name) == 0)
+				continue;
+			ap = ipv4_iffindaddr(ifn, &lease->addr, NULL);
+			if (ap)
+				ipv4_deladdr(ifn, &ap->addr, &ap->net);
+		}
+	}
+
+	/* If the netmask is different, delete the addresss */
+	ap = ipv4_iffindaddr(ifp, &lease->addr, NULL);
+	if (ap && ap->net.s_addr != lease->net.s_addr)
+		ipv4_deladdr(ifp, &ap->addr, &ap->net);
+
+	if (ipv4_iffindaddr(ifp, &lease->addr, &lease->net))
+		logger(ifp->ctx, LOG_DEBUG,
+		    "%s: IP address %s/%d already exists",
+		    ifp->name, inet_ntoa(lease->addr),
+		    inet_ntocidr(lease->net));
+	else {
+		r = ipv4_addaddr(ifp, lease);
+		if (r == -1 && errno != EEXIST)
+			return;
+	}
+
+#ifdef IN_IFF_NOTUSEABLE
+	ap = ipv4_iffindaddr(ifp, &lease->addr, NULL);
+	if (ap == NULL) {
+		logger(ifp->ctx, LOG_ERR, "%s: added address vanished",
+		    ifp->name);
+		return;
+	} else if (ap->addr_flags & IN_IFF_NOTUSEABLE)
+		return;
+#endif
+
+	ipv4_finaliseaddr(ifp);
+
+#endif  /* PASSIVE_MODE */
+}
+
+void
+ipv4_handleifa(struct dhcpcd_ctx *ctx,
+    int cmd, struct if_head *ifs, const char *ifname,
+    const struct in_addr *addr, const struct in_addr *net,
+    const struct in_addr *dst, int flags)
+{
+	struct interface *ifp;
+	struct ipv4_state *state;
+	struct ipv4_addr *ap;
+
+	if (ifs == NULL)
+		ifs = ctx->ifaces;
+	if (ifs == NULL) {
+		errno = ESRCH;
+		return;
+	}
+	if (addr->s_addr == INADDR_ANY) {
+		errno = EINVAL;
+		return;
+	}
+	if ((ifp = if_find(ifs, ifname)) == NULL)
+		return;
+	if ((state = ipv4_getstate(ifp)) == NULL) {
+		errno = ENOENT;
+		return;
+	}
+
+	ap = ipv4_iffindaddr(ifp, addr, net);
+	if (cmd == RTM_NEWADDR) {
+		if (ap == NULL) {
+			if ((ap = malloc(sizeof(*ap))) == NULL) {
+				logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
+				return;
+			}
+			ap->iface = ifp;
+			ap->addr = *addr;
+			ap->net = *net;
+			if (dst)
+				ap->dst.s_addr = dst->s_addr;
+			else
+				ap->dst.s_addr = INADDR_ANY;
+			TAILQ_INSERT_TAIL(&state->addrs, ap, next);
+		}
+		ap->addr_flags = flags;
+	} else if (cmd == RTM_DELADDR) {
+		if (ap) {
+			TAILQ_REMOVE(&state->addrs, ap, next);
+			free(ap);
+		}
+	}
+
+	dhcp_handleifa(cmd, ifp, addr, net, dst, flags);
+	arp_handleifa(cmd, ifp, addr, flags);
+}
+
+void
+ipv4_free(struct interface *ifp)
+{
+	struct ipv4_state *state;
+	struct ipv4_addr *addr;
+
+	if (ifp) {
+		state = IPV4_STATE(ifp);
+		if (state) {
+		        while ((addr = TAILQ_FIRST(&state->addrs))) {
+				TAILQ_REMOVE(&state->addrs, addr, next);
+				free(addr);
+			}
+			ipv4_freerts(&state->routes);
+			free(state);
+		}
+	}
+}
+
+void
+ipv4_ctxfree(struct dhcpcd_ctx *ctx)
+{
+
+	ipv4_freeroutes(ctx->ipv4_routes);
+	ipv4_freeroutes(ctx->ipv4_kroutes);
+}
diff --git a/dhcpcd-6.8.2/ipv4.h b/dhcpcd-6.8.2/ipv4.h
new file mode 100644
index 0000000..cd52c41
--- /dev/null
+++ b/dhcpcd-6.8.2/ipv4.h
@@ -0,0 +1,113 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef IPV4_H
+#define IPV4_H
+
+#include "dhcpcd.h"
+
+#ifdef IN_IFF_TENTATIVE
+#define IN_IFF_NOTUSEABLE \
+        (IN_IFF_TENTATIVE | IN_IFF_DUPLICATED | IN_IFF_DETACHED)
+#endif
+
+struct rt {
+	TAILQ_ENTRY(rt) next;
+	struct in_addr dest;
+	struct in_addr net;
+	struct in_addr gate;
+	const struct interface *iface;
+#ifdef HAVE_ROUTE_METRIC
+	unsigned int metric;
+#endif
+	struct in_addr src;
+	unsigned int flags;
+};
+TAILQ_HEAD(rt_head, rt);
+
+struct ipv4_addr {
+	TAILQ_ENTRY(ipv4_addr) next;
+	struct in_addr addr;
+	struct in_addr net;
+	struct in_addr dst;
+	struct interface *iface;
+	int addr_flags;
+};
+TAILQ_HEAD(ipv4_addrhead, ipv4_addr);
+
+struct ipv4_state {
+	struct ipv4_addrhead addrs;
+	struct rt_head routes;
+};
+
+#define IPV4_STATE(ifp)							       \
+	((struct ipv4_state *)(ifp)->if_data[IF_DATA_IPV4])
+#define IPV4_CSTATE(ifp)						       \
+	((const struct ipv4_state *)(ifp)->if_data[IF_DATA_IPV4])
+
+#ifdef INET
+int ipv4_init(struct dhcpcd_ctx *);
+int ipv4_ifcmp(const struct interface *, const struct interface *);
+uint8_t inet_ntocidr(struct in_addr);
+int inet_cidrtoaddr(int, struct in_addr *);
+uint32_t ipv4_getnetmask(uint32_t);
+int ipv4_addrexists(struct dhcpcd_ctx *, const struct in_addr *);
+
+#define STATE_ADDED		0x01
+#define STATE_FAKE		0x02
+
+void ipv4_buildroutes(struct dhcpcd_ctx *);
+void ipv4_finaliseaddr(struct interface *);
+int ipv4_deladdr(struct interface *ifp, const struct in_addr *,
+    const struct in_addr *);
+void ipv4_applyaddr(void *);
+int ipv4_handlert(struct dhcpcd_ctx *, int, struct rt *);
+void ipv4_freerts(struct rt_head *);
+
+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 *,
+    int);
+
+void ipv4_freeroutes(struct rt_head *);
+
+void ipv4_free(struct interface *);
+void ipv4_ctxfree(struct dhcpcd_ctx *);
+#else
+#define ipv4_init(a) (-1)
+#define ipv4_sortinterfaces(a) {}
+#define ipv4_applyaddr(a) {}
+#define ipv4_freeroutes(a) {}
+#define ipv4_free(a) {}
+#define ipv4_ctxfree(a) {}
+#define ipv4_addrexists(a, b) (0)
+#endif
+
+#endif
diff --git a/dhcpcd-6.8.2/ipv4ll.c b/dhcpcd-6.8.2/ipv4ll.c
new file mode 100644
index 0000000..5f08980
--- /dev/null
+++ b/dhcpcd-6.8.2/ipv4ll.c
@@ -0,0 +1,281 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <errno.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define ELOOP_QUEUE 6
+#include "config.h"
+#include "arp.h"
+#include "common.h"
+#include "dhcp.h"
+#include "eloop.h"
+#include "if.h"
+#include "if-options.h"
+#include "ipv4ll.h"
+
+static struct dhcp_message *
+ipv4ll_make_lease(uint32_t addr)
+{
+	uint32_t u32;
+	struct dhcp_message *dhcp;
+	uint8_t *p;
+
+	dhcp = calloc(1, sizeof(*dhcp));
+	if (dhcp == NULL)
+		return NULL;
+	/* Put some LL options in */
+	dhcp->yiaddr = addr;
+	p = dhcp->options;
+	*p++ = DHO_SUBNETMASK;
+	*p++ = sizeof(u32);
+	u32 = htonl(LINKLOCAL_MASK);
+	memcpy(p, &u32, sizeof(u32));
+	p += sizeof(u32);
+	*p++ = DHO_BROADCAST;
+	*p++ = sizeof(u32);
+	u32 = htonl(LINKLOCAL_BRDC);
+	memcpy(p, &u32, sizeof(u32));
+	p += sizeof(u32);
+	*p++ = DHO_END;
+
+	return dhcp;
+}
+
+static in_addr_t
+ipv4ll_pick_addr(const struct arp_state *astate)
+{
+	in_addr_t addr;
+	struct interface *ifp;
+	const struct dhcp_state *state;
+
+	for (;;) {
+		/* 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 |
+		    ((uint32_t)(random() % 0xFD00) + 0x0100));
+
+		/* No point using a failed address */
+		if (addr == astate->failed.s_addr)
+			continue;
+
+		/* 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 addr;
+}
+
+static void
+ipv4ll_probed(struct arp_state *astate)
+{
+	struct dhcp_state *state = D_STATE(astate->iface);
+
+	if (state->state == DHS_IPV4LL_BOUND) {
+		ipv4_finaliseaddr(astate->iface);
+		return;
+	}
+
+	if (state->state != DHS_BOUND) {
+		struct dhcp_message *offer;
+
+		/* A DHCP lease could have already been offered.
+		 * Backup and replace once the IPv4LL address is bound */
+		offer = state->offer;
+		state->offer = ipv4ll_make_lease(astate->addr.s_addr);
+		if (state->offer == NULL)
+			logger(astate->iface->ctx, LOG_ERR, "%s: %m", __func__);
+		else
+			dhcp_bind(astate->iface, astate);
+		state->offer = offer;
+	}
+}
+
+static void
+ipv4ll_announced(struct arp_state *astate)
+{
+	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)
+{
+
+#ifdef IN_IFF_TENTATIVE
+	ipv4ll_probed(arg);
+#else
+	arp_probe(arg);
+#endif
+}
+
+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 == NULL ||
+	    (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 && 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;
+
+		/* RFC 3927 Section 2.5 */
+		up = uptime();
+		if (state->defend + DEFEND_INTERVAL > up) {
+			logger(astate->iface->ctx, LOG_WARNING,
+			    "%s: IPv4LL %d second defence failed for %s",
+			    astate->iface->name, DEFEND_INTERVAL,
+			    inet_ntoa(state->addr));
+			dhcp_drop(astate->iface, "EXPIRE");
+		} else {
+			logger(astate->iface->ctx, LOG_DEBUG,
+			    "%s: defended IPv4LL address %s",
+			    astate->iface->name, inet_ntoa(state->addr));
+			state->defend = up;
+			return;
+		}
+	}
+
+	arp_cancel(astate);
+	if (++state->conflicts == MAX_CONFLICTS)
+		logger(astate->iface->ctx, LOG_ERR,
+		    "%s: failed to acquire an IPv4LL address",
+		    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
+			memcpy(&seed, ifp->hwaddr + ifp->hwlen - sizeof(seed),
+			    sizeof(seed));
+		initstate(seed, state->randomstate, sizeof(state->randomstate));
+	}
+
+	if ((astate = arp_new(ifp, NULL)) == 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))) {
+		logger(ifp->ctx, 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);
+#ifdef IN_IFF_TENTATIVE
+	ipv4ll_probed(astate);
+#else
+	arp_probe(astate);
+#endif
+}
+
+void
+ipv4ll_stop(struct interface *ifp)
+{
+	struct dhcp_state *state = D_STATE(ifp);
+
+	eloop_timeout_delete(ifp->ctx->eloop, NULL, state->arp_ipv4ll);
+}
diff --git a/dhcpcd-6.8.2/ipv4ll.h b/dhcpcd-6.8.2/ipv4ll.h
new file mode 100644
index 0000000..19349de
--- /dev/null
+++ b/dhcpcd-6.8.2/ipv4ll.h
@@ -0,0 +1,36 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef IPV4LL_H
+#define IPV4LL_H
+
+void ipv4ll_start(void *);
+void ipv4ll_claimed(void *);
+void ipv4ll_handle_failure(void *);
+void ipv4ll_stop(struct interface *);
+
+#endif
diff --git a/dhcpcd-6.8.2/ipv6.c b/dhcpcd-6.8.2/ipv6.c
new file mode 100644
index 0000000..7fe3c32
--- /dev/null
+++ b/dhcpcd-6.8.2/ipv6.c
@@ -0,0 +1,2128 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+
+#include <net/if.h>
+#include <net/route.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
+#ifndef __linux__
+#  ifndef __QNX__
+#    include <sys/endian.h>
+#  endif
+#  include <net/if.h>
+#  ifdef __FreeBSD__ /* Needed so that including netinet6/in6_var.h works */
+#    include <net/if_var.h>
+#  endif
+#  ifndef __sun
+#    include <netinet6/in6_var.h>
+#  endif
+#endif
+
+#include <errno.h>
+#include <ifaddrs.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define ELOOP_QUEUE 7
+#include "common.h"
+#include "if.h"
+#include "dhcpcd.h"
+#include "dhcp6.h"
+#include "eloop.h"
+#include "ipv6.h"
+#include "ipv6nd.h"
+
+#ifdef HAVE_MD5_H
+#  ifndef DEPGEN
+#    include <md5.h>
+#  endif
+#else
+#  include "md5.h"
+#endif
+
+#ifdef SHA2_H
+#  include SHA2_H
+#else
+#  include "sha256.h"
+#endif
+
+#ifndef SHA256_DIGEST_LENGTH
+#  define SHA256_DIGEST_LENGTH		32
+#endif
+
+#ifdef IPV6_POLLADDRFLAG
+#  warning kernel does not report IPv6 address flag changes
+#  warning polling tentative address flags periodically
+#endif
+
+#ifdef __linux__
+   /* Match Linux defines to BSD */
+#  define IN6_IFF_TEMPORARY IFA_F_TEMPORARY
+#  ifdef IFA_F_OPTIMISTIC
+#    define IN6_IFF_TENTATIVE	(IFA_F_TENTATIVE | IFA_F_OPTIMISTIC)
+#  else
+#    define IN6_IFF_TENTATIVE   (IFA_F_TENTATIVE | 0x04)
+#  endif
+#  ifdef IF_F_DADFAILED
+#    define IN6_IFF_DUPLICATED	IFA_F_DADFAILED
+#  else
+#    define IN6_IFF_DUPLICATED	0x08
+#  endif
+#  define IN6_IFF_DETACHED	0
+#endif
+
+#define IN6_IFF_NOTUSEABLE \
+	(IN6_IFF_TENTATIVE | IN6_IFF_DUPLICATED | IN6_IFF_DETACHED)
+
+/* Hackery at it's finest. */
+#ifndef s6_addr32
+#  ifdef __sun
+#    define s6_addr32	_S6_un._S6_u32
+#  else
+#    define s6_addr32	__u6_addr.__u6_addr32
+#  endif
+#endif
+
+
+#ifdef IPV6_MANAGETEMPADDR
+static void ipv6_regentempifid(void *);
+static void ipv6_regentempaddr(void *);
+#else
+#define ipv6_regentempifid(a) {}
+#endif
+
+struct ipv6_ctx *
+ipv6_init(struct dhcpcd_ctx *dhcpcd_ctx)
+{
+	struct ipv6_ctx *ctx;
+
+	if (dhcpcd_ctx->ipv6)
+		return dhcpcd_ctx->ipv6;
+
+	ctx = calloc(1, sizeof(*ctx));
+	if (ctx == NULL)
+		return NULL;
+
+	ctx->routes = malloc(sizeof(*ctx->routes));
+	if (ctx->routes == NULL) {
+		free(ctx);
+		return NULL;
+	}
+	TAILQ_INIT(ctx->routes);
+
+	ctx->ra_routers = malloc(sizeof(*ctx->ra_routers));
+	if (ctx->ra_routers == NULL) {
+		free(ctx->routes);
+		free(ctx);
+		return NULL;
+	}
+	TAILQ_INIT(ctx->ra_routers);
+
+	TAILQ_INIT(&ctx->kroutes);
+
+	ctx->sndhdr.msg_namelen = sizeof(struct sockaddr_in6);
+	ctx->sndhdr.msg_iov = ctx->sndiov;
+	ctx->sndhdr.msg_iovlen = 1;
+	ctx->sndhdr.msg_control = ctx->sndbuf;
+	ctx->sndhdr.msg_controllen = sizeof(ctx->sndbuf);
+	ctx->rcvhdr.msg_name = &ctx->from;
+	ctx->rcvhdr.msg_namelen = sizeof(ctx->from);
+	ctx->rcvhdr.msg_iov = ctx->rcviov;
+	ctx->rcvhdr.msg_iovlen = 1;
+	ctx->rcvhdr.msg_control = ctx->rcvbuf;
+	// controllen is set at recieve
+	//ctx->rcvhdr.msg_controllen = sizeof(ctx->rcvbuf);
+	ctx->rcviov[0].iov_base = ctx->ansbuf;
+	ctx->rcviov[0].iov_len = sizeof(ctx->ansbuf);
+
+	ctx->nd_fd = -1;
+	ctx->dhcp_fd = -1;
+
+	dhcpcd_ctx->ipv6 = ctx;
+
+	return ctx;
+}
+
+ssize_t
+ipv6_printaddr(char *s, size_t sl, const uint8_t *d, const char *ifname)
+{
+	char buf[INET6_ADDRSTRLEN];
+	const char *p;
+	size_t l;
+
+	p = inet_ntop(AF_INET6, d, buf, sizeof(buf));
+	if (p == NULL)
+		return -1;
+
+	l = strlen(p);
+	if (d[0] == 0xfe && (d[1] & 0xc0) == 0x80)
+		l += 1 + strlen(ifname);
+
+	if (s == NULL)
+		return (ssize_t)l;
+
+	if (sl < l) {
+		errno = ENOMEM;
+		return -1;
+	}
+
+	s += strlcpy(s, p, sl);
+	if (d[0] == 0xfe && (d[1] & 0xc0) == 0x80) {
+		*s++ = '%';
+		s += strlcpy(s, ifname, sl);
+	}
+	*s = '\0';
+	return (ssize_t)l;
+}
+
+static ssize_t
+ipv6_readsecret(struct dhcpcd_ctx *ctx)
+{
+	FILE *fp;
+	char line[1024];
+	unsigned char *p;
+	size_t len;
+	uint32_t r;
+	int x;
+
+	if ((fp = fopen(SECRET, "r"))) {
+		len = 0;
+		while (fgets(line, sizeof(line), fp)) {
+			len = strlen(line);
+			if (len) {
+				if (line[len - 1] == '\n')
+					line[len - 1] = '\0';
+			}
+			len = hwaddr_aton(NULL, line);
+			if (len) {
+				ctx->secret_len = hwaddr_aton(ctx->secret,
+				    line);
+				break;
+			}
+			len = 0;
+		}
+		fclose(fp);
+		if (len)
+			return (ssize_t)len;
+	} else {
+		if (errno != ENOENT)
+			logger(ctx, LOG_ERR,
+			    "error reading secret: %s: %m", SECRET);
+	}
+
+	/* Chaining arc4random should be good enough.
+	 * RFC7217 section 5.1 states the key SHOULD be at least 128 bits.
+	 * To attempt and future proof ourselves, we'll generate a key of
+	 * 512 bits (64 bytes). */
+	p = ctx->secret;
+	ctx->secret_len = 0;
+	for (len = 0; len < 512 / NBBY; len += sizeof(r)) {
+		r = arc4random();
+		memcpy(p, &r, sizeof(r));
+		p += sizeof(r);
+		ctx->secret_len += sizeof(r);
+
+	}
+
+	/* Ensure that only the dhcpcd user can read the secret.
+	 * Write permission is also denied as chaning it would remove
+	 * it's stability. */
+	if ((fp = fopen(SECRET, "w")) == NULL ||
+	    chmod(SECRET, S_IRUSR) == -1)
+		goto eexit;
+	x = fprintf(fp, "%s\n",
+	    hwaddr_ntoa(ctx->secret, ctx->secret_len, line, sizeof(line)));
+	fclose(fp);
+	if (x > 0)
+		return (ssize_t)ctx->secret_len;
+
+eexit:
+	logger(ctx, LOG_ERR, "error writing secret: %s: %m", SECRET);
+	unlink(SECRET);
+	ctx->secret_len = 0;
+	return -1;
+}
+
+/* http://www.iana.org/assignments/ipv6-interface-ids/ipv6-interface-ids.xhtml
+ * RFC5453 */
+static const struct reslowhigh {
+	const uint8_t high[8];
+	const uint8_t low[8];
+} reslowhigh[] = {
+	/* RFC4291 + RFC6543 */
+	{ { 0x02, 0x00, 0x5e, 0xff, 0xfe, 0x00, 0x00, 0x00 },
+	  { 0x02, 0x00, 0x5e, 0xff, 0xfe, 0xff, 0xff, 0xff } },
+	/* RFC2526 */
+	{ { 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80 },
+	  { 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } }
+};
+
+static int
+ipv6_reserved(const struct in6_addr *addr)
+{
+	uint64_t id, low, high;
+	size_t i;
+	const struct reslowhigh *r;
+
+	id = be64dec(addr->s6_addr + sizeof(id));
+	if (id == 0) /* RFC4291 */
+		return 1;
+	for (i = 0; i < sizeof(reslowhigh) / sizeof(reslowhigh[0]); i++) {
+		r = &reslowhigh[i];
+		low = be64dec(r->low);
+		high = be64dec(r->high);
+		if (id >= low && id <= high)
+			return 1;
+	}
+	return 0;
+}
+
+/* RFC7217 */
+static int
+ipv6_makestableprivate1(struct in6_addr *addr,
+    const struct in6_addr *prefix, int prefix_len,
+    const unsigned char *netiface, size_t netiface_len,
+    const unsigned char *netid, size_t netid_len,
+    uint32_t *dad_counter,
+    const unsigned char *secret, size_t secret_len)
+{
+	unsigned char buf[2048], *p, digest[SHA256_DIGEST_LENGTH];
+	size_t len, l;
+	SHA256_CTX ctx;
+
+	if (prefix_len < 0 || prefix_len > 120) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	l = (size_t)(ROUNDUP8(prefix_len) / NBBY);
+	len = l + netiface_len + netid_len + sizeof(*dad_counter) + secret_len;
+	if (len > sizeof(buf)) {
+		errno = ENOBUFS;
+		return -1;
+	}
+
+	for (;; (*dad_counter)++) {
+		/* Combine all parameters into one buffer */
+		p = buf;
+		memcpy(p, prefix, l);
+		p += l;
+		memcpy(p, netiface, netiface_len);
+		p += netiface_len;
+		memcpy(p, netid, netid_len);
+		p += netid_len;
+		memcpy(p, dad_counter, sizeof(*dad_counter));
+		p += sizeof(*dad_counter);
+		memcpy(p, secret, secret_len);
+
+		/* Make an address using the digest of the above.
+		 * RFC7217 Section 5.1 states that we shouldn't use MD5.
+		 * Pity as we use that for HMAC-MD5 which is still deemed OK.
+		 * SHA-256 is recommended */
+		SHA256_Init(&ctx);
+		SHA256_Update(&ctx, buf, len);
+		SHA256_Final(digest, &ctx);
+
+		p = addr->s6_addr;
+		memcpy(p, prefix, l);
+		/* RFC7217 section 5.2 says we need to start taking the id from
+		 * the least significant bit */
+		len = sizeof(addr->s6_addr) - l;
+		memcpy(p + l, digest + (sizeof(digest) - len), len);
+
+		/* Ensure that the Interface ID does not match a reserved one,
+		 * if it does then treat it as a DAD failure.
+		 * RFC7217 section 5.2 */
+		if (prefix_len != 64)
+			break;
+		if (!ipv6_reserved(addr))
+			break;
+	}
+
+	return 0;
+}
+
+int
+ipv6_makestableprivate(struct in6_addr *addr,
+    const struct in6_addr *prefix, int prefix_len,
+    const struct interface *ifp,
+    int *dad_counter)
+{
+	uint32_t dad;
+	int r;
+
+	dad = (uint32_t)*dad_counter;
+
+	/* For our implementation, we shall set the hardware address
+	 * as the interface identifier */
+	r = ipv6_makestableprivate1(addr, prefix, prefix_len,
+	    ifp->hwaddr, ifp->hwlen,
+	    ifp->ssid, ifp->ssid_len,
+	    &dad,
+	    ifp->ctx->secret, ifp->ctx->secret_len);
+
+	if (r == 0)
+		*dad_counter = (int)dad;
+	return r;
+}
+
+int
+ipv6_makeaddr(struct in6_addr *addr, const struct interface *ifp,
+    const struct in6_addr *prefix, int prefix_len)
+{
+	const struct ipv6_addr *ap;
+	int dad;
+
+	if (prefix_len < 0 || prefix_len > 120) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	if (ifp->options->options & DHCPCD_SLAACPRIVATE) {
+		if (ifp->ctx->secret_len == 0) {
+			if (ipv6_readsecret(ifp->ctx) == -1)
+				return -1;
+		}
+		dad = 0;
+		if (ipv6_makestableprivate(addr,
+		    prefix, prefix_len, ifp, &dad) == -1)
+			return -1;
+		return dad;
+	}
+
+	if (prefix_len > 64) {
+		errno = EINVAL;
+		return -1;
+	}
+	if ((ap = ipv6_linklocal(ifp)) == NULL) {
+		/* We delay a few functions until we get a local-link address
+		 * so this should never be hit. */
+		errno = ENOENT;
+		return -1;
+	}
+
+	/* Make the address from the first local-link address */
+	memcpy(addr, prefix, sizeof(*prefix));
+	addr->s6_addr32[2] = ap->addr.s6_addr32[2];
+	addr->s6_addr32[3] = ap->addr.s6_addr32[3];
+	return 0;
+}
+
+int
+ipv6_makeprefix(struct in6_addr *prefix, const struct in6_addr *addr, int len)
+{
+	int bytelen, bitlen;
+
+	if (len < 0 || len > 128) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	bytelen = len / NBBY;
+	bitlen = len % NBBY;
+	memcpy(&prefix->s6_addr, &addr->s6_addr, (size_t)bytelen);
+	if (bitlen != 0)
+		prefix->s6_addr[bytelen] =
+		    (uint8_t)(prefix->s6_addr[bytelen] >> (NBBY - bitlen));
+	memset((char *)prefix->s6_addr + bytelen, 0,
+	    sizeof(prefix->s6_addr) - (size_t)bytelen);
+	return 0;
+}
+
+int
+ipv6_mask(struct in6_addr *mask, int len)
+{
+	static const unsigned char masks[NBBY] =
+	    { 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
+	int bytes, bits, i;
+
+	if (len < 0 || len > 128) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	memset(mask, 0, sizeof(*mask));
+	bytes = len / NBBY;
+	bits = len % NBBY;
+	for (i = 0; i < bytes; i++)
+		mask->s6_addr[i] = 0xff;
+	if (bits)
+		mask->s6_addr[bytes] = masks[bits - 1];
+	return 0;
+}
+
+uint8_t
+ipv6_prefixlen(const struct in6_addr *mask)
+{
+	int x = 0, y;
+	const unsigned char *lim, *p;
+
+	lim = (const unsigned char *)mask + sizeof(*mask);
+	for (p = (const unsigned char *)mask; p < lim; x++, p++) {
+		if (*p != 0xff)
+			break;
+	}
+	y = 0;
+	if (p < lim) {
+		for (y = 0; y < NBBY; y++) {
+			if ((*p & (0x80 >> y)) == 0)
+				break;
+		}
+	}
+
+	/*
+	 * when the limit pointer is given, do a stricter check on the
+	 * remaining bits.
+	 */
+	if (p < lim) {
+		if (y != 0 && (*p & (0x00ff >> y)) != 0)
+			return 0;
+		for (p = p + 1; p < lim; p++)
+			if (*p != 0)
+				return 0;
+	}
+
+	return (uint8_t)(x * NBBY + y);
+}
+
+static void
+in6_to_h64(uint64_t *vhigh, uint64_t *vlow, const struct in6_addr *addr)
+{
+
+	*vhigh = be64dec(addr->s6_addr);
+	*vlow = be64dec(addr->s6_addr + 8);
+}
+
+static void
+h64_to_in6(struct in6_addr *addr, uint64_t vhigh, uint64_t vlow)
+{
+
+	be64enc(addr->s6_addr, vhigh);
+	be64enc(addr->s6_addr + 8, vlow);
+}
+
+int
+ipv6_userprefix(
+	const struct in6_addr *prefix,	// prefix from router
+	short prefix_len,		// length of prefix received
+	uint64_t user_number,		// "random" number from user
+	struct in6_addr *result,	// resultant prefix
+	short result_len)		// desired prefix length
+{
+	uint64_t vh, vl, user_low, user_high;
+
+	if (prefix_len < 0 || prefix_len > 120 ||
+	    result_len < 0 || result_len > 120)
+	{
+		errno = EINVAL;
+		return -1;
+	}
+
+	/* Check that the user_number fits inside result_len less prefix_len */
+	if (result_len < prefix_len || user_number > INT_MAX ||
+	    ffs((int)user_number) > result_len - prefix_len)
+	{
+	       errno = ERANGE;
+	       return -1;
+	}
+
+	/* virtually shift user number by dest_len, then split at 64 */
+	if (result_len >= 64) {
+		user_high = user_number << (result_len - 64);
+		user_low = 0;
+	} else {
+		user_high = user_number >> (64 - result_len);
+		user_low = user_number << result_len;
+	}
+
+	/* convert to two 64bit host order values */
+	in6_to_h64(&vh, &vl, prefix);
+
+	vh |= user_high;
+	vl |= user_low;
+
+	/* copy back result */
+	h64_to_in6(result, vh, vl);
+
+	return 0;
+}
+
+#ifdef IPV6_POLLADDRFLAG
+void
+ipv6_checkaddrflags(void *arg)
+{
+	struct ipv6_addr *ap;
+	int ifa_flags;
+
+	ap = arg;
+	ifa_flags = if_addrflags6(&ap->addr, ap->iface);
+	if (ifa_flags == -1)
+		logger(ap->iface->ctx, LOG_ERR,
+		    "%s: if_addrflags6: %m", ap->iface->name);
+	else if (!(ifa_flags & IN6_IFF_TENTATIVE)) {
+		ipv6_handleifa(ap->iface->ctx, RTM_NEWADDR,
+		    ap->iface->ctx->ifaces, ap->iface->name,
+		    &ap->addr, ap->prefix_len, ifa_flags);
+	} else {
+		struct timespec tv;
+
+		ms_to_ts(&tv, RETRANS_TIMER / 2);
+		eloop_timeout_add_tv(ap->iface->ctx->eloop, &tv,
+		    ipv6_checkaddrflags, ap);
+	}
+}
+#endif
+
+
+static void
+ipv6_deleteaddr(struct ipv6_addr *ia)
+{
+#ifndef PASSIVE_MODE
+	struct ipv6_state *state;
+	struct ipv6_addr *ap;
+
+	logger(ia->iface->ctx, LOG_INFO, "%s: deleting address %s",
+	    ia->iface->name, ia->saddr);
+	if (if_deladdress6(ia) == -1 &&
+	    errno != EADDRNOTAVAIL && errno != ENXIO && errno != ENODEV)
+		logger(ia->iface->ctx, LOG_ERR, "if_deladdress6: :%m");
+
+	state = IPV6_STATE(ia->iface);
+	TAILQ_FOREACH(ap, &state->addrs, next) {
+		if (IN6_ARE_ADDR_EQUAL(&ap->addr, &ia->addr)) {
+			TAILQ_REMOVE(&state->addrs, ap, next);
+			ipv6_freeaddr(ap);
+			break;
+		}
+	}
+#endif
+}
+
+int
+ipv6_addaddr(struct ipv6_addr *ap, const struct timespec *now)
+{
+#ifndef PASSIVE_MODE
+	struct interface *ifp;
+	struct ipv6_state *state;
+	struct ipv6_addr *nap;
+	uint32_t pltime, vltime;
+
+	/* Ensure no other interface has this address */
+	TAILQ_FOREACH(ifp, ap->iface->ctx->ifaces, next) {
+		if (ifp == ap->iface || strcmp(ifp->name, ap->iface->name) == 0)
+			continue;
+		state = IPV6_STATE(ifp);
+		if (state == NULL)
+			continue;
+		TAILQ_FOREACH(nap, &state->addrs, next) {
+			if (IN6_ARE_ADDR_EQUAL(&nap->addr, &ap->addr)) {
+				ipv6_deleteaddr(nap);
+				break;
+			}
+		}
+	}
+
+	if (!(ap->flags & IPV6_AF_DADCOMPLETED) &&
+	    ipv6_iffindaddr(ap->iface, &ap->addr))
+		ap->flags |= IPV6_AF_DADCOMPLETED;
+
+	logger(ap->iface->ctx, ap->flags & IPV6_AF_NEW ? LOG_INFO : LOG_DEBUG,
+	    "%s: adding address %s", ap->iface->name, ap->saddr);
+	if (ap->prefix_pltime == ND6_INFINITE_LIFETIME &&
+	    ap->prefix_vltime == ND6_INFINITE_LIFETIME)
+		logger(ap->iface->ctx, LOG_DEBUG,
+		    "%s: pltime infinity, vltime infinity",
+		    ap->iface->name);
+	else if (ap->prefix_pltime == ND6_INFINITE_LIFETIME)
+		logger(ap->iface->ctx, LOG_DEBUG,
+		    "%s: pltime infinity, vltime %"PRIu32" seconds",
+		    ap->iface->name, ap->prefix_vltime);
+	else if (ap->prefix_vltime == ND6_INFINITE_LIFETIME)
+		logger(ap->iface->ctx, LOG_DEBUG,
+		    "%s: pltime %"PRIu32"seconds, vltime infinity",
+		    ap->iface->name, ap->prefix_pltime);
+	else
+		logger(ap->iface->ctx, LOG_DEBUG,
+		    "%s: pltime %"PRIu32" seconds, vltime %"PRIu32" seconds",
+		    ap->iface->name, ap->prefix_pltime, ap->prefix_vltime);
+
+	/* Adjust plftime and vltime based on acquired time */
+	pltime = ap->prefix_pltime;
+	vltime = ap->prefix_vltime;
+	if (timespecisset(&ap->acquired) &&
+	    (ap->prefix_pltime != ND6_INFINITE_LIFETIME ||
+	    ap->prefix_vltime != ND6_INFINITE_LIFETIME))
+	{
+		struct timespec n;
+
+		if (now == NULL) {
+			get_monotonic(&n);
+			now = &n;
+		}
+		timespecsub(now, &ap->acquired, &n);
+		if (ap->prefix_pltime != ND6_INFINITE_LIFETIME)
+			ap->prefix_pltime -= (uint32_t)n.tv_sec;
+		if (ap->prefix_vltime != ND6_INFINITE_LIFETIME)
+			ap->prefix_vltime -= (uint32_t)n.tv_sec;
+	}
+
+	if (if_addaddress6(ap) == -1) {
+		logger(ap->iface->ctx, LOG_ERR, "if_addaddress6: %m");
+#if 0
+		logger(ap->iface->ctx, LOG_DEBUG,
+		    "%s: adj pltime %"PRIu32" seconds, "
+		    "vltime %"PRIu32" seconds",
+		    ap->iface->name, ap->prefix_pltime, ap->prefix_vltime);
+#endif
+		/* Restore real pltime and vltime */
+		ap->prefix_pltime = pltime;
+		ap->prefix_vltime = vltime;
+		return -1;
+	}
+
+#ifdef IPV6_MANAGETEMPADDR
+	/* RFC4941 Section 3.4 */
+	if (ap->flags & IPV6_AF_TEMPORARY &&
+	    ap->prefix_pltime &&
+	    ap->prefix_vltime &&
+	    ap->iface->options->options & DHCPCD_IPV6RA_OWN &&
+	    ip6_use_tempaddr(ap->iface->name))
+		eloop_timeout_add_sec(ap->iface->ctx->eloop,
+		    (time_t)ap->prefix_pltime - REGEN_ADVANCE,
+		    ipv6_regentempaddr, ap);
+#endif
+
+	/* Restore real pltime and vltime */
+	ap->prefix_pltime = pltime;
+	ap->prefix_vltime = vltime;
+
+	ap->flags &= ~IPV6_AF_NEW;
+	ap->flags |= IPV6_AF_ADDED;
+	if (ap->delegating_iface)
+		ap->flags |= IPV6_AF_DELEGATED;
+
+#ifdef IPV6_POLLADDRFLAG
+	eloop_timeout_delete(ap->iface->ctx->eloop,
+		ipv6_checkaddrflags, ap);
+	if (!(ap->flags & IPV6_AF_DADCOMPLETED)) {
+		struct timespec tv;
+
+		ms_to_ts(&tv, RETRANS_TIMER / 2);
+		eloop_timeout_add_tv(ap->iface->ctx->eloop,
+		    &tv, ipv6_checkaddrflags, ap);
+	}
+#endif
+#endif
+
+	return 0;
+}
+
+int
+ipv6_publicaddr(const struct ipv6_addr *ia)
+{
+	return (ia->prefix_pltime &&
+	    (ia->addr.s6_addr[0] & 0xfe) != 0xc &&
+	    !(ia->addr_flags & IN6_IFF_NOTUSEABLE));
+}
+
+struct ipv6_addr *
+ipv6_findaddr(struct dhcpcd_ctx *ctx, const struct in6_addr *addr, short flags)
+{
+	struct ipv6_addr *dap, *nap;
+
+	dap = dhcp6_findaddr(ctx, addr, flags);
+	nap = ipv6nd_findaddr(ctx, addr, flags);
+	if (!dap && !nap)
+		return NULL;
+	if (dap && !nap)
+		return dap;
+	if (nap && !dap)
+		return nap;
+	if (nap->iface->metric < dap->iface->metric)
+		return nap;
+	return dap;
+}
+
+ssize_t
+ipv6_addaddrs(struct ipv6_addrhead *addrs)
+{
+	struct ipv6_addr *ap, *apn, *apf;
+	ssize_t i;
+	struct timespec now;
+
+	i = 0;
+	timespecclear(&now);
+	TAILQ_FOREACH_SAFE(ap, addrs, next, apn) {
+		if (ap->prefix_vltime == 0) {
+			if (ap->flags & IPV6_AF_ADDED) {
+				ipv6_deleteaddr(ap);
+				i++;
+			}
+			eloop_q_timeout_delete(ap->iface->ctx->eloop,
+			    0, NULL, ap);
+			if (ap->flags & IPV6_AF_REQUEST) {
+				ap->flags &= ~IPV6_AF_ADDED;
+			} else {
+				TAILQ_REMOVE(addrs, ap, next);
+				ipv6_freeaddr(ap);
+			}
+		} else if (!(ap->flags & IPV6_AF_STALE) &&
+		    !IN6_IS_ADDR_UNSPECIFIED(&ap->addr))
+		{
+			apf = ipv6_findaddr(ap->iface->ctx,
+			    &ap->addr, IPV6_AF_ADDED);
+			if (apf && apf->iface != ap->iface &&
+			    strcmp(apf->iface->name, ap->iface->name))
+			{
+				if (apf->iface->metric <= ap->iface->metric) {
+					logger(apf->iface->ctx, LOG_INFO,
+					    "%s: preferring %s on %s",
+					    ap->iface->name,
+					    ap->saddr,
+					    apf->iface->name);
+					continue;
+				}
+				logger(apf->iface->ctx, LOG_INFO,
+				    "%s: preferring %s on %s",
+				    apf->iface->name,
+				    ap->saddr,
+				    ap->iface->name);
+				if (if_deladdress6(apf) == -1 &&
+				    errno != EADDRNOTAVAIL && errno != ENXIO)
+					logger(apf->iface->ctx, LOG_ERR,
+					    "if_deladdress6: %m");
+				apf->flags &=
+				    ~(IPV6_AF_ADDED | IPV6_AF_DADCOMPLETED);
+			} else if (apf)
+				apf->flags &= ~IPV6_AF_ADDED;
+			if (ap->flags & IPV6_AF_NEW)
+				i++;
+			if (!timespecisset(&now))
+				get_monotonic(&now);
+			ipv6_addaddr(ap, &now);
+		}
+	}
+
+	return i;
+}
+
+void
+ipv6_freeaddr(struct ipv6_addr *ap)
+{
+
+	eloop_q_timeout_delete(ap->iface->ctx->eloop, 0, NULL, ap);
+	free(ap);
+}
+
+void
+ipv6_freedrop_addrs(struct ipv6_addrhead *addrs, int drop,
+    const struct interface *ifd)
+{
+	struct ipv6_addr *ap, *apn, *apf;
+	struct timespec now;
+
+	timespecclear(&now);
+	TAILQ_FOREACH_SAFE(ap, addrs, next, apn) {
+		if (ifd && ap->delegating_iface != ifd)
+			continue;
+		if (drop != 2)
+			TAILQ_REMOVE(addrs, ap, next);
+		if (drop && ap->flags & IPV6_AF_ADDED &&
+		    (ap->iface->options->options &
+		    (DHCPCD_EXITING | DHCPCD_PERSISTENT)) !=
+		    (DHCPCD_EXITING | DHCPCD_PERSISTENT))
+		{
+			if (drop == 2)
+				TAILQ_REMOVE(addrs, ap, next);
+			/* Find the same address somewhere else */
+			apf = ipv6_findaddr(ap->iface->ctx, &ap->addr, 0);
+			if (apf == NULL ||
+			    (apf->iface != ap->iface &&
+			    strcmp(apf->iface->name, ap->iface->name)))
+				ipv6_deleteaddr(ap);
+			if (!(ap->iface->options->options &
+			    DHCPCD_EXITING) && apf)
+			{
+				if (!timespecisset(&now))
+					get_monotonic(&now);
+				ipv6_addaddr(apf, &now);
+			}
+			if (drop == 2)
+				ipv6_freeaddr(ap);
+		}
+		if (drop != 2)
+			ipv6_freeaddr(ap);
+	}
+}
+
+static struct ipv6_state *
+ipv6_getstate(struct interface *ifp)
+{
+	struct ipv6_state *state;
+
+	state = IPV6_STATE(ifp);
+	if (state == NULL) {
+	        ifp->if_data[IF_DATA_IPV6] = calloc(1, sizeof(*state));
+		state = IPV6_STATE(ifp);
+		if (state == NULL) {
+			logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
+			return NULL;
+		}
+		TAILQ_INIT(&state->addrs);
+		TAILQ_INIT(&state->ll_callbacks);
+
+		/* Regenerate new ids */
+		if (ifp->options &&
+		    ifp->options->options & DHCPCD_IPV6RA_OWN &&
+		    ip6_use_tempaddr(ifp->name))
+			ipv6_regentempifid(ifp);
+	}
+	return state;
+}
+
+void
+ipv6_handleifa(struct dhcpcd_ctx *ctx,
+    int cmd, struct if_head *ifs, const char *ifname,
+    const struct in6_addr *addr, uint8_t prefix_len, int flags)
+{
+	struct interface *ifp;
+	struct ipv6_state *state;
+	struct ipv6_addr *ap;
+	struct ll_callback *cb;
+
+#if 0
+	char buf[INET6_ADDRSTRLEN];
+	inet_ntop(AF_INET6, &addr->s6_addr,
+	    buf, INET6_ADDRSTRLEN);
+	logger(ctx, LOG_DEBUG, "%s: cmd %d addr %s flags %d",
+	    ifname, cmd, buf, flags);
+#endif
+
+	if (ifs == NULL)
+		ifs = ctx->ifaces;
+	if (ifs == NULL) {
+		errno = ESRCH;
+		return;
+	}
+	TAILQ_FOREACH(ifp, ifs, next) {
+		/* Each psuedo interface also stores addresses */
+		if (strcmp(ifp->name, ifname))
+			continue;
+		state = ipv6_getstate(ifp);
+		if (state == NULL)
+			continue;
+
+		if (!IN6_IS_ADDR_LINKLOCAL(addr)) {
+			ipv6nd_handleifa(ctx, cmd, ifname, addr, flags);
+			dhcp6_handleifa(ctx, cmd, ifname, addr, flags);
+		}
+
+		TAILQ_FOREACH(ap, &state->addrs, next) {
+			if (IN6_ARE_ADDR_EQUAL(&ap->addr, addr))
+				break;
+		}
+
+		switch (cmd) {
+		case RTM_DELADDR:
+			if (ap) {
+				TAILQ_REMOVE(&state->addrs, ap, next);
+				ipv6_freeaddr(ap);
+			}
+			break;
+		case RTM_NEWADDR:
+			if (ap == NULL) {
+				char buf[INET6_ADDRSTRLEN];
+				const char *cbp;
+
+				ap = calloc(1, sizeof(*ap));
+				ap->iface = ifp;
+				ap->addr = *addr;
+				ap->prefix_len = prefix_len;
+				ipv6_makeprefix(&ap->prefix, &ap->addr,
+				    ap->prefix_len);
+				cbp = inet_ntop(AF_INET6, &addr->s6_addr,
+				    buf, sizeof(buf));
+				if (cbp)
+					snprintf(ap->saddr, sizeof(ap->saddr),
+					    "%s/%d", cbp, prefix_len);
+				if (if_getlifetime6(ap) == -1) {
+					/* No support or address vanished.
+					 * Either way, just set a deprecated
+					 * infinite time lifetime and continue.
+					 * This is fine because we only want
+					 * to know this when trying to extend
+					 * temporary addresses.
+					 * As we can't extend infinite, we'll
+					 * create a new temporary address. */
+					ap->prefix_pltime = 0;
+					ap->prefix_vltime =
+					    ND6_INFINITE_LIFETIME;
+				}
+				/* This is a minor regression against RFC 4941
+				 * because the kernel only knows when the
+				 * lifetimes were last updated, not when the
+				 * address was initially created.
+				 * Provided dhcpcd is not restarted, this
+				 * won't be a problem.
+				 * If we don't like it, we can always
+				 * pretend lifetimes are infinite and always
+				 * generate a new temporary address on
+				 * restart. */
+				ap->acquired = ap->created;
+				TAILQ_INSERT_TAIL(&state->addrs,
+				    ap, next);
+			}
+			ap->addr_flags = flags;
+#ifdef IPV6_MANAGETEMPADDR
+			if (ap->addr_flags & IN6_IFF_TEMPORARY)
+				ap->flags |= IPV6_AF_TEMPORARY;
+#endif
+			if (IN6_IS_ADDR_LINKLOCAL(&ap->addr)) {
+#ifdef IPV6_POLLADDRFLAG
+				if (ap->addr_flags & IN6_IFF_TENTATIVE) {
+					struct timespec tv;
+
+					ms_to_ts(&tv, RETRANS_TIMER / 2);
+					eloop_timeout_add_tv(
+					    ap->iface->ctx->eloop,
+					    &tv, ipv6_checkaddrflags, ap);
+					break;
+				}
+#endif
+
+				if (!(ap->addr_flags & IN6_IFF_NOTUSEABLE)) {
+					/* Now run any callbacks.
+					 * Typically IPv6RS or DHCPv6 */
+					while ((cb =
+					    TAILQ_FIRST(&state->ll_callbacks)))
+					{
+						TAILQ_REMOVE(
+						    &state->ll_callbacks,
+						    cb, next);
+						cb->callback(cb->arg);
+						free(cb);
+					}
+				}
+			}
+			break;
+		}
+	}
+}
+
+const struct ipv6_addr *
+ipv6_iffindaddr(const struct interface *ifp, const struct in6_addr *addr)
+{
+	const struct ipv6_state *state;
+	const struct ipv6_addr *ap;
+
+	state = IPV6_CSTATE(ifp);
+	if (state) {
+		TAILQ_FOREACH(ap, &state->addrs, next) {
+			if (addr == NULL) {
+				if (IN6_IS_ADDR_LINKLOCAL(&ap->addr) &&
+				    !(ap->addr_flags & IN6_IFF_NOTUSEABLE))
+					return ap;
+			} else {
+				if (IN6_ARE_ADDR_EQUAL(&ap->addr, addr) &&
+				    !(ap->addr_flags & IN6_IFF_TENTATIVE))
+					return ap;
+			}
+		}
+	}
+	return NULL;
+}
+
+int
+ipv6_addlinklocalcallback(struct interface *ifp,
+    void (*callback)(void *), void *arg)
+{
+	struct ipv6_state *state;
+	struct ll_callback *cb;
+
+	state = ipv6_getstate(ifp);
+	TAILQ_FOREACH(cb, &state->ll_callbacks, next) {
+		if (cb->callback == callback && cb->arg == arg)
+			break;
+	}
+	if (cb == NULL) {
+		cb = malloc(sizeof(*cb));
+		if (cb == NULL) {
+			logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
+			return -1;
+		}
+		cb->callback = callback;
+		cb->arg = arg;
+		TAILQ_INSERT_TAIL(&state->ll_callbacks, cb, next);
+	}
+	return 0;
+}
+
+static struct ipv6_addr *
+ipv6_newlinklocal(struct interface *ifp)
+{
+	struct ipv6_addr *ap;
+
+	ap = calloc(1, sizeof(*ap));
+	if (ap != NULL) {
+		ap->iface = ifp;
+		ap->prefix.s6_addr32[0] = htonl(0xfe800000);
+		ap->prefix.s6_addr32[1] = 0;
+		ap->prefix_len = 64;
+		ap->dadcounter = 0;
+		ap->prefix_pltime = ND6_INFINITE_LIFETIME;
+		ap->prefix_vltime = ND6_INFINITE_LIFETIME;
+		ap->flags = IPV6_AF_NEW;
+		ap->addr_flags = IN6_IFF_TENTATIVE;
+	}
+	return ap;
+}
+
+static const uint8_t allzero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+static const uint8_t allone[8] =
+    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+static int
+ipv6_addlinklocal(struct interface *ifp)
+{
+	struct ipv6_state *state;
+	struct ipv6_addr *ap, *ap2;
+	int dadcounter;
+
+	/* Check sanity before malloc */
+	if (!(ifp->options->options & DHCPCD_SLAACPRIVATE)) {
+		switch (ifp->family) {
+		case ARPHRD_ETHER:
+			/* Check for a valid hardware address */
+			if (ifp->hwlen != 6 && ifp->hwlen != 8) {
+				errno = ENOTSUP;
+				return -1;
+			}
+			if (memcmp(ifp->hwaddr, allzero, ifp->hwlen) == 0 ||
+			    memcmp(ifp->hwaddr, allone, ifp->hwlen) == 0)
+			{
+				errno = EINVAL;
+				return -1;
+			}
+			break;
+		default:
+			errno = ENOTSUP;
+			return -1;
+		}
+	}
+
+	state = ipv6_getstate(ifp);
+	if (state == NULL)
+		return -1;
+
+	ap = ipv6_newlinklocal(ifp);
+	if (ap == NULL)
+		return -1;
+
+	if (ifp->options->options & DHCPCD_SLAACPRIVATE) {
+		dadcounter = 0;
+nextslaacprivate:
+		if (ipv6_makestableprivate(&ap->addr,
+			&ap->prefix, ap->prefix_len, ifp, &dadcounter) == -1)
+		{
+			free(ap);
+			return -1;
+		}
+		ap->dadcounter = dadcounter;
+	} else {
+		memcpy(ap->addr.s6_addr, ap->prefix.s6_addr, 8);
+		switch (ifp->family) {
+		case ARPHRD_ETHER:
+			if (ifp->hwlen == 6) {
+				ap->addr.s6_addr[ 8] = ifp->hwaddr[0];
+				ap->addr.s6_addr[ 9] = ifp->hwaddr[1];
+				ap->addr.s6_addr[10] = ifp->hwaddr[2];
+				ap->addr.s6_addr[11] = 0xff;
+				ap->addr.s6_addr[12] = 0xfe;
+				ap->addr.s6_addr[13] = ifp->hwaddr[3];
+				ap->addr.s6_addr[14] = ifp->hwaddr[4];
+				ap->addr.s6_addr[15] = ifp->hwaddr[5];
+			} else if (ifp->hwlen == 8)
+				memcpy(&ap->addr.s6_addr[8], ifp->hwaddr, 8);
+			else {
+				free(ap);
+				errno = ENOTSUP;
+				return -1;
+			}
+			break;
+		}
+
+		/* Sanity check: g bit must not indciate "group" */
+		if (EUI64_GROUP(&ap->addr)) {
+			free(ap);
+			errno = EINVAL;
+			return -1;
+		}
+		EUI64_TO_IFID(&ap->addr);
+	}
+
+	/* Do we already have this address? */
+	TAILQ_FOREACH(ap2, &state->addrs, next) {
+		if (IN6_ARE_ADDR_EQUAL(&ap->addr, &ap2->addr)) {
+			if (ap2->addr_flags & IN6_IFF_DUPLICATED) {
+				if (ifp->options->options &
+				    DHCPCD_SLAACPRIVATE)
+				{
+					dadcounter++;
+					goto nextslaacprivate;
+				}
+				free(ap);
+				errno = EADDRNOTAVAIL;
+				return -1;
+			}
+
+			logger(ap2->iface->ctx, LOG_WARNING,
+			    "%s: waiting for %s to complete",
+			    ap2->iface->name, ap2->saddr);
+			free(ap);
+			errno =	EEXIST;
+			return 0;
+		}
+	}
+
+	inet_ntop(AF_INET6, &ap->addr, ap->saddr, sizeof(ap->saddr));
+	TAILQ_INSERT_TAIL(&state->addrs, ap, next);
+	ipv6_addaddr(ap, NULL);
+	return 1;
+}
+
+/* Ensure the interface has a link-local address */
+int
+ipv6_start(struct interface *ifp)
+{
+	const struct ipv6_state *state;
+	const struct ipv6_addr *ap;
+
+	/* We can't assign a link-locak address to this,
+	 * the ppp process has to. */
+	if (ifp->flags & IFF_POINTOPOINT)
+		return 0;
+
+	state = IPV6_CSTATE(ifp);
+	if (state) {
+		TAILQ_FOREACH(ap, &state->addrs, next) {
+			if (IN6_IS_ADDR_LINKLOCAL(&ap->addr) &&
+			    !(ap->addr_flags & IN6_IFF_DUPLICATED))
+				break;
+		}
+		/* Regenerate new ids */
+		if (ifp->options->options & DHCPCD_IPV6RA_OWN &&
+		    ip6_use_tempaddr(ifp->name))
+			ipv6_regentempifid(ifp);
+	} else
+		ap = NULL;
+
+	if (ap == NULL && ipv6_addlinklocal(ifp) == -1)
+		return -1;
+
+	/* Load existing routes */
+	if_initrt6(ifp);
+	return 0;
+}
+
+void
+ipv6_freedrop(struct interface *ifp, int drop)
+{
+	struct ipv6_state *state;
+	struct ll_callback *cb;
+
+	if (ifp == NULL)
+		return;
+
+	if ((state = IPV6_STATE(ifp)) == NULL)
+		return;
+
+	ipv6_freedrop_addrs(&state->addrs, drop ? 2 : 0, NULL);
+
+	/* Becuase we need to cache the addresses we don't control,
+	 * we only free the state on when NOT dropping addresses. */
+	if (drop == 0) {
+		while ((cb = TAILQ_FIRST(&state->ll_callbacks))) {
+			TAILQ_REMOVE(&state->ll_callbacks, cb, next);
+			free(cb);
+		}
+		free(state);
+		ifp->if_data[IF_DATA_IPV6] = NULL;
+		eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
+	}
+}
+
+void
+ipv6_ctxfree(struct dhcpcd_ctx *ctx)
+{
+
+	if (ctx->ipv6 == NULL)
+		return;
+
+	ipv6_freerts(ctx->ipv6->routes);
+	free(ctx->ipv6->routes);
+	free(ctx->ipv6->ra_routers);
+	ipv6_freerts(&ctx->ipv6->kroutes);
+	free(ctx->ipv6);
+}
+
+int
+ipv6_handleifa_addrs(int cmd,
+    struct ipv6_addrhead *addrs, const struct in6_addr *addr, int flags)
+{
+	struct ipv6_addr *ap, *apn;
+	uint8_t found, alldadcompleted;
+
+	alldadcompleted = 1;
+	found = 0;
+	TAILQ_FOREACH_SAFE(ap, addrs, next, apn) {
+		if (!IN6_ARE_ADDR_EQUAL(addr, &ap->addr)) {
+			if (ap->flags & IPV6_AF_ADDED &&
+			    !(ap->flags & IPV6_AF_DADCOMPLETED))
+				alldadcompleted = 0;
+			continue;
+		}
+		switch (cmd) {
+		case RTM_DELADDR:
+			if (ap->flags & IPV6_AF_ADDED) {
+				logger(ap->iface->ctx, LOG_INFO,
+				    "%s: deleted address %s",
+				    ap->iface->name, ap->saddr);
+				ap->flags &= ~IPV6_AF_ADDED;
+			}
+			break;
+		case RTM_NEWADDR:
+			/* Safety - ignore tentative announcements */
+			if (flags & (IN6_IFF_DETACHED |IN6_IFF_TENTATIVE))
+				break;
+			if ((ap->flags & IPV6_AF_DADCOMPLETED) == 0) {
+				found++;
+				if (flags & IN6_IFF_DUPLICATED)
+					ap->flags |= IPV6_AF_DUPLICATED;
+				else
+					ap->flags &= ~IPV6_AF_DUPLICATED;
+				if (ap->dadcallback)
+					ap->dadcallback(ap);
+				/* We need to set this here in-case the
+				 * dadcallback function checks it */
+				ap->flags |= IPV6_AF_DADCOMPLETED;
+			}
+			break;
+		}
+	}
+
+	return alldadcompleted ? found : 0;
+}
+
+#ifdef IPV6_MANAGETEMPADDR
+static const struct ipv6_addr *
+ipv6_findaddrid(struct dhcpcd_ctx *ctx, uint8_t *addr)
+{
+	const struct interface *ifp;
+	const struct ipv6_state *state;
+	const struct ipv6_addr *ia;
+
+	TAILQ_FOREACH(ifp, ctx->ifaces, next) {
+		if ((state = IPV6_CSTATE(ifp))) {
+			TAILQ_FOREACH(ia, &state->addrs, next) {
+				if (memcmp(&ia->addr.s6_addr[8], addr, 8) == 0)
+					return ia;
+			}
+		}
+	}
+	return NULL;
+}
+
+static const uint8_t nullid[8];
+static const uint8_t anycastid[8] = {
+    0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80 };
+static const uint8_t isatapid[4] = { 0x00, 0x00, 0x5e, 0xfe };
+
+static void
+ipv6_regen_desync(struct interface *ifp, int force)
+{
+	struct ipv6_state *state;
+	time_t max;
+
+	state = IPV6_STATE(ifp);
+
+	/* RFC4941 Section 5 states that DESYNC_FACTOR must never be
+	 * greater than TEMP_VALID_LIFETIME - REGEN_ADVANCE.
+	 * I believe this is an error and it should be never be greateter than
+	 * TEMP_PREFERRED_LIFETIME - REGEN_ADVANCE. */
+	max = ip6_temp_preferred_lifetime(ifp->name) - REGEN_ADVANCE;
+	if (state->desync_factor && !force && state->desync_factor < max)
+		return;
+	if (state->desync_factor == 0)
+		state->desync_factor =
+		    (time_t)arc4random_uniform(MIN(MAX_DESYNC_FACTOR,
+		    (uint32_t)max));
+	max = ip6_temp_preferred_lifetime(ifp->name) -
+	    state->desync_factor - REGEN_ADVANCE;
+	eloop_timeout_add_sec(ifp->ctx->eloop, max, ipv6_regentempifid, ifp);
+}
+
+void
+ipv6_gentempifid(struct interface *ifp)
+{
+	struct ipv6_state *state;
+	MD5_CTX md5;
+	uint8_t seed[16], digest[16];
+	int retry;
+
+	if ((state = IPV6_STATE(ifp)) == NULL)
+		return;
+
+	retry = 0;
+	if (memcmp(nullid, state->randomseed0, sizeof(nullid)) == 0) {
+		uint32_t r;
+
+		r = arc4random();
+		memcpy(seed, &r, sizeof(r));
+		r = arc4random();
+		memcpy(seed + sizeof(r), &r, sizeof(r));
+	} else
+		memcpy(seed, state->randomseed0, sizeof(state->randomseed0));
+
+	memcpy(seed + sizeof(state->randomseed0),
+	    state->randomseed1, sizeof(state->randomseed1));
+
+again:
+	/* RFC4941 Section 3.2.1.1
+	 * Take the left-most 64bits and set bit 6 to zero */
+	MD5Init(&md5);
+	MD5Update(&md5, seed, sizeof(seed));
+	MD5Final(digest, &md5);
+
+	/* RFC4941 Section 3.2.1.1
+	 * Take the left-most 64bits and set bit 6 to zero */
+	memcpy(state->randomid, digest, sizeof(state->randomid));
+	state->randomid[0] = (uint8_t)(state->randomid[0] & ~EUI64_UBIT);
+
+	/* RFC4941 Section 3.2.1.4
+	 * Reject reserved or existing id's */
+	if (memcmp(nullid, state->randomid, sizeof(nullid)) == 0 ||
+	    (memcmp(anycastid, state->randomid, 7) == 0 &&
+	    (anycastid[7] & state->randomid[7]) == anycastid[7]) ||
+	    memcmp(isatapid, state->randomid, sizeof(isatapid)) == 0 ||
+	    ipv6_findaddrid(ifp->ctx, state->randomid))
+	{
+		if (++retry < GEN_TEMPID_RETRY_MAX) {
+			memcpy(seed, digest + 8, 8);
+			goto again;
+		}
+		memset(state->randomid, 0, sizeof(state->randomid));
+	}
+
+	/* RFC4941 Section 3.2.1.6
+	 * Save the right-most 64bits of the digest */
+	memcpy(state->randomseed0, digest + 8,
+	    sizeof(state->randomseed0));
+}
+
+/* RFC4941 Section 3.3.7 */
+static void
+ipv6_tempdadcallback(void *arg)
+{
+	struct ipv6_addr *ia = arg;
+
+	if (ia->flags & IPV6_AF_DUPLICATED) {
+		struct ipv6_addr *ia1;
+		struct timespec tv;
+
+		if (++ia->dadcounter == TEMP_IDGEN_RETRIES) {
+			logger(ia->iface->ctx, LOG_ERR,
+			    "%s: too many duplicate temporary addresses",
+			    ia->iface->name);
+			return;
+		}
+		get_monotonic(&tv);
+		if ((ia1 = ipv6_createtempaddr(ia, &tv)) == NULL)
+			logger(ia->iface->ctx, LOG_ERR,
+			    "ipv6_createtempaddr: %m");
+		else
+			ia1->dadcounter = ia->dadcounter;
+		ipv6_deleteaddr(ia);
+		if (ia1)
+			ipv6_addaddr(ia1, &ia1->acquired);
+	}
+}
+
+struct ipv6_addr *
+ipv6_createtempaddr(struct ipv6_addr *ia0, const struct timespec *now)
+{
+	struct ipv6_state *state;
+	const struct ipv6_state *cstate;
+	int genid;
+	struct in6_addr addr, mask;
+	uint32_t randid[2];
+	const struct interface *ifp;
+	const struct ipv6_addr *ap;
+	struct ipv6_addr *ia;
+	uint32_t i, trylimit;
+	char buf[INET6_ADDRSTRLEN];
+	const char *cbp;
+
+	trylimit = TEMP_IDGEN_RETRIES;
+	state = IPV6_STATE(ia0->iface);
+	genid = 0;
+
+	addr = ia0->addr;
+	ipv6_mask(&mask, ia0->prefix_len);
+	/* clear the old ifid */
+	for (i = 0; i < 4; i++)
+		addr.s6_addr32[i] &= mask.s6_addr32[i];
+
+again:
+	if (memcmp(state->randomid, nullid, sizeof(nullid)) == 0)
+		genid = 1;
+	if (genid) {
+		memcpy(state->randomseed1, &ia0->addr.s6_addr[8],
+		    sizeof(state->randomseed1));
+		ipv6_gentempifid(ia0->iface);
+		if (memcmp(state->randomid, nullid, sizeof(nullid)) == 0) {
+			errno = EFAULT;
+			return NULL;
+		}
+	}
+	memcpy(&randid[0], state->randomid, sizeof(randid[0]));
+	memcpy(&randid[1], state->randomid + sizeof(randid[1]),
+	    sizeof(randid[2]));
+	addr.s6_addr32[2] |= randid[0] & ~mask.s6_addr32[2];
+	addr.s6_addr32[3] |= randid[1] & ~mask.s6_addr32[3];
+
+	/* Ensure we don't already have it */
+	TAILQ_FOREACH(ifp, ia0->iface->ctx->ifaces, next) {
+		cstate = IPV6_CSTATE(ifp);
+		if (cstate) {
+			TAILQ_FOREACH(ap, &cstate->addrs, next) {
+				if (IN6_ARE_ADDR_EQUAL(&ap->addr, &addr)) {
+					if (--trylimit == 0) {
+						errno = EEXIST;
+						return NULL;
+					}
+					genid = 1;
+					goto again;
+				}
+			}
+		}
+	}
+
+	if ((ia = calloc(1, sizeof(*ia))) == NULL)
+		return NULL;
+
+	ia->iface = ia0->iface;
+	ia->addr = addr;
+	/* Must be made tentative, for our DaD to work */
+	ia->addr_flags = IN6_IFF_TENTATIVE;
+	ia->dadcallback = ipv6_tempdadcallback;
+	ia->flags = IPV6_AF_NEW | IPV6_AF_AUTOCONF | IPV6_AF_TEMPORARY;
+	ia->prefix = ia0->prefix;
+	ia->prefix_len = ia0->prefix_len;
+	ia->created = ia->acquired = now ? *now : ia0->acquired;
+
+	/* Ensure desync is still valid */
+	ipv6_regen_desync(ia->iface, 0);
+
+	/* RFC4941 Section 3.3.4 */
+	i = (uint32_t)(ip6_temp_preferred_lifetime(ia0->iface->name) -
+	    state->desync_factor);
+	ia->prefix_pltime = MIN(ia0->prefix_pltime, i);
+	i = (uint32_t)ip6_temp_valid_lifetime(ia0->iface->name);
+	ia->prefix_vltime = MIN(ia0->prefix_vltime, i);
+	if (ia->prefix_pltime <= REGEN_ADVANCE ||
+	    ia->prefix_pltime > ia0->prefix_vltime)
+	{
+		errno =	EINVAL;
+		free(ia);
+		return NULL;
+	}
+
+	cbp = inet_ntop(AF_INET6, &ia->addr, buf, sizeof(buf));
+	if (cbp)
+		snprintf(ia->saddr, sizeof(ia->saddr), "%s/%d",
+		    cbp, ia->prefix_len);
+	else
+		ia->saddr[0] = '\0';
+
+	TAILQ_INSERT_TAIL(&state->addrs, ia, next);
+	return ia;
+}
+
+void
+ipv6_settempstale(struct interface *ifp)
+{
+	struct ipv6_state *state;
+	struct ipv6_addr *ia;
+
+	state = IPV6_STATE(ifp);
+	TAILQ_FOREACH(ia, &state->addrs, next) {
+		if (ia->flags & IPV6_AF_TEMPORARY)
+			ia->flags |= IPV6_AF_STALE;
+	}
+}
+
+struct ipv6_addr *
+ipv6_settemptime(struct ipv6_addr *ia, int flags)
+{
+	struct ipv6_state *state;
+	struct ipv6_addr *ap, *first;
+
+	state = IPV6_STATE(ia->iface);
+	first = NULL;
+	TAILQ_FOREACH_REVERSE(ap, &state->addrs, ipv6_addrhead, next) {
+		if (ap->flags & IPV6_AF_TEMPORARY &&
+		    ap->prefix_pltime &&
+		    IN6_ARE_ADDR_EQUAL(&ia->prefix, &ap->prefix))
+		{
+			time_t max, ext;
+
+			if (flags == 0) {
+				if (ap->prefix_pltime -
+				    (uint32_t)(ia->acquired.tv_sec -
+				    ap->acquired.tv_sec)
+				    < REGEN_ADVANCE)
+					continue;
+
+				return ap;
+			}
+
+			if (!(ap->flags & IPV6_AF_ADDED))
+				ap->flags |= IPV6_AF_NEW | IPV6_AF_AUTOCONF;
+			ap->flags &= ~IPV6_AF_STALE;
+
+			/* RFC4941 Section 3.4
+			 * Deprecated prefix, deprecate the temporary address */
+			if (ia->prefix_pltime == 0) {
+				ap->prefix_pltime = 0;
+				goto valid;
+			}
+
+			/* Ensure desync is still valid */
+			ipv6_regen_desync(ap->iface, 0);
+
+			/* RFC4941 Section 3.3.2
+			 * Extend temporary times, but ensure that they
+			 * never last beyond the system limit. */
+			ext = ia->acquired.tv_sec + (time_t)ia->prefix_pltime;
+			max = ap->created.tv_sec +
+			    ip6_temp_preferred_lifetime(ap->iface->name) -
+			    state->desync_factor;
+			if (ext < max)
+				ap->prefix_pltime = ia->prefix_pltime;
+			else
+				ap->prefix_pltime =
+				    (uint32_t)(max - ia->acquired.tv_sec);
+
+valid:
+			ext = ia->acquired.tv_sec + (time_t)ia->prefix_vltime;
+			max = ap->created.tv_sec +
+			    ip6_temp_valid_lifetime(ap->iface->name);
+			if (ext < max)
+				ap->prefix_vltime = ia->prefix_vltime;
+			else
+				ap->prefix_vltime =
+				    (uint32_t)(max - ia->acquired.tv_sec);
+
+			/* Just extend the latest matching prefix */
+			ap->acquired = ia->acquired;
+
+			/* If extending return the last match as
+			 * it's the most current.
+			 * If deprecating, deprecate any other addresses we
+			 * may have, although this should not be needed */
+			if (ia->prefix_pltime)
+				return ap;
+			if (first == NULL)
+				first = ap;
+		}
+	}
+	return first;
+}
+
+void
+ipv6_addtempaddrs(struct interface *ifp, const struct timespec *now)
+{
+	struct ipv6_state *state;
+	struct ipv6_addr *ia;
+
+	state = IPV6_STATE(ifp);
+	TAILQ_FOREACH(ia, &state->addrs, next) {
+		if (ia->flags & IPV6_AF_TEMPORARY &&
+		    !(ia->flags & IPV6_AF_STALE))
+			ipv6_addaddr(ia, now);
+	}
+}
+
+static void
+ipv6_regentempaddr(void *arg)
+{
+	struct ipv6_addr *ia = arg, *ia1;
+	struct timespec tv;
+
+	logger(ia->iface->ctx, LOG_DEBUG, "%s: regen temp addr %s",
+	    ia->iface->name, ia->saddr);
+	get_monotonic(&tv);
+	ia1 = ipv6_createtempaddr(ia, &tv);
+	if (ia1)
+		ipv6_addaddr(ia1, &tv);
+	else
+		logger(ia->iface->ctx, LOG_ERR, "ipv6_createtempaddr: %m");
+}
+
+static void
+ipv6_regentempifid(void *arg)
+{
+	struct interface *ifp = arg;
+	struct ipv6_state *state;
+
+	state = IPV6_STATE(ifp);
+	if (memcmp(state->randomid, nullid, sizeof(state->randomid)))
+		ipv6_gentempifid(ifp);
+
+	ipv6_regen_desync(ifp, 1);
+}
+#endif /* IPV6_MANAGETEMPADDR */
+
+static struct rt6 *
+find_route6(struct rt6_head *rts, const struct rt6 *r)
+{
+	struct rt6 *rt;
+
+	TAILQ_FOREACH(rt, rts, next) {
+		if (IN6_ARE_ADDR_EQUAL(&rt->dest, &r->dest) &&
+#ifdef HAVE_ROUTE_METRIC
+		    (r->iface == NULL || rt->iface == NULL ||
+		    rt->iface->metric == r->iface->metric) &&
+#endif
+		    IN6_ARE_ADDR_EQUAL(&rt->net, &r->net))
+			return rt;
+	}
+	return NULL;
+}
+
+static void
+desc_route(const char *cmd, const struct rt6 *rt)
+{
+	char destbuf[INET6_ADDRSTRLEN];
+	char gatebuf[INET6_ADDRSTRLEN];
+	const char *ifname, *dest, *gate;
+	struct dhcpcd_ctx *ctx;
+
+	ctx = rt->iface ? rt->iface->ctx : NULL;
+	ifname = rt->iface ? rt->iface->name : "(no iface)";
+	dest = inet_ntop(AF_INET6, &rt->dest, destbuf, INET6_ADDRSTRLEN);
+	gate = inet_ntop(AF_INET6, &rt->gate, gatebuf, INET6_ADDRSTRLEN);
+	if (IN6_ARE_ADDR_EQUAL(&rt->gate, &in6addr_any))
+		logger(ctx, LOG_INFO, "%s: %s route to %s/%d",
+		    ifname, cmd, dest, ipv6_prefixlen(&rt->net));
+	else if (IN6_ARE_ADDR_EQUAL(&rt->dest, &in6addr_any) &&
+	    IN6_ARE_ADDR_EQUAL(&rt->net, &in6addr_any))
+		logger(ctx, LOG_INFO, "%s: %s default route via %s",
+		    ifname, cmd, gate);
+	else
+		logger(ctx, LOG_INFO, "%s: %s%s route to %s/%d via %s",
+		    ifname, cmd,
+		    rt->flags & RTF_REJECT ? " reject" : "",
+		    dest, ipv6_prefixlen(&rt->net), gate);
+}
+
+static struct rt6*
+ipv6_findrt(struct dhcpcd_ctx *ctx, const struct rt6 *rt, int flags)
+{
+	struct rt6 *r;
+
+	TAILQ_FOREACH(r, &ctx->ipv6->kroutes, next) {
+		if (IN6_ARE_ADDR_EQUAL(&rt->dest, &r->dest) &&
+#ifdef HAVE_ROUTE_METRIC
+		    (rt->iface == r->iface ||
+		    (rt->flags & RTF_REJECT && r->flags & RTF_REJECT)) &&
+		    (!flags || rt->metric == r->metric) &&
+#else
+		    (!flags || rt->iface == r->iface ||
+		    (rt->flags & RTF_REJECT && r->flags & RTF_REJECT)) &&
+#endif
+		    IN6_ARE_ADDR_EQUAL(&rt->net, &r->net))
+			return r;
+	}
+	return NULL;
+}
+
+void
+ipv6_freerts(struct rt6_head *routes)
+{
+	struct rt6 *rt;
+
+	while ((rt = TAILQ_FIRST(routes))) {
+		TAILQ_REMOVE(routes, rt, next);
+		free(rt);
+	}
+}
+
+/* If something other than dhcpcd removes a route,
+ * we need to remove it from our internal table. */
+int
+ipv6_handlert(struct dhcpcd_ctx *ctx, int cmd, struct rt6 *rt)
+{
+	struct rt6 *f;
+
+	if (ctx->ipv6 == NULL)
+		return 0;
+
+	f = ipv6_findrt(ctx, rt, 1);
+	switch(cmd) {
+	case RTM_ADD:
+		if (f == NULL) {
+			if ((f = malloc(sizeof(*f))) == NULL)
+				return -1;
+			*f = *rt;
+			TAILQ_INSERT_TAIL(&ctx->ipv6->kroutes, f, next);
+		}
+		break;
+	case RTM_DELETE:
+		if (f) {
+			TAILQ_REMOVE(&ctx->ipv6->kroutes, f, next);
+			free(f);
+		}
+		/* If we manage the route, remove it */
+		if ((f = find_route6(ctx->ipv6->routes, rt))) {
+			desc_route("removing", f);
+			TAILQ_REMOVE(ctx->ipv6->routes, f, next);
+			free(f);
+		}
+		break;
+	}
+	return 0;
+}
+
+#define n_route(a)	 nc_route(NULL, a)
+#define c_route(a, b)	 nc_route(a, b)
+static int
+nc_route(struct rt6 *ort, struct rt6 *nrt)
+{
+
+	/* Don't set default routes if not asked to */
+	if (IN6_IS_ADDR_UNSPECIFIED(&nrt->dest) &&
+	    IN6_IS_ADDR_UNSPECIFIED(&nrt->net) &&
+	    !(nrt->iface->options->options & DHCPCD_GATEWAY))
+		return -1;
+
+	desc_route(ort == NULL ? "adding" : "changing", nrt);
+
+	if (ort == NULL) {
+		ort = ipv6_findrt(nrt->iface->ctx, nrt, 0);
+		if (ort &&
+		    ((ort->flags & RTF_REJECT && nrt->flags & RTF_REJECT) ||
+		     (ort->iface == nrt->iface &&
+#ifdef HAVE_ROUTE_METRIC
+		    ort->metric == nrt->metric &&
+#endif
+		    IN6_ARE_ADDR_EQUAL(&ort->gate, &nrt->gate))))
+			return 0;
+	}
+
+#ifdef HAVE_ROUTE_METRIC
+	/* With route metrics, we can safely add the new route before
+	 * deleting the old route. */
+	if (if_route6(RTM_ADD, nrt) == 0) {
+		if (ort && if_route6(RTM_DELETE, ort) == -1 &&
+		    errno != ESRCH)
+			logger(nrt->iface->ctx, LOG_ERR, "if_route6 (DEL): %m");
+		return 0;
+	}
+
+	/* If the kernel claims the route exists we need to rip out the
+	 * old one first. */
+	if (errno != EEXIST || ort == NULL)
+		goto logerr;
+#endif
+
+	/* No route metrics, we need to delete the old route before
+	 * adding the new one. */
+	if (ort && if_route6(RTM_DELETE, ort) == -1 && errno != ESRCH)
+		logger(nrt->iface->ctx, LOG_ERR, "if_route6: %m");
+	if (if_route6(RTM_ADD, nrt) == 0)
+		return 0;
+#ifdef HAVE_ROUTE_METRIC
+logerr:
+#endif
+	logger(nrt->iface->ctx, LOG_ERR, "if_route6 (ADD): %m");
+	return -1;
+}
+
+static int
+d_route(struct rt6 *rt)
+{
+	int retval;
+
+	desc_route("deleting", rt);
+	retval = if_route6(RTM_DELETE, rt);
+	if (retval != 0 && errno != ENOENT && errno != ESRCH)
+		logger(rt->iface->ctx, LOG_ERR,
+		    "%s: if_delroute6: %m", rt->iface->name);
+	return retval;
+}
+
+static struct rt6 *
+make_route(const struct interface *ifp, const struct ra *rap)
+{
+	struct rt6 *r;
+
+	r = calloc(1, sizeof(*r));
+	if (r == NULL) {
+		logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
+		return NULL;
+	}
+	r->iface = ifp;
+#ifdef HAVE_ROUTE_METRIC
+	r->metric = ifp->metric;
+#endif
+	if (rap)
+		r->mtu = rap->mtu;
+	else
+		r->mtu = 0;
+	return r;
+}
+
+static struct rt6 *
+make_prefix(const struct interface *ifp, const struct ra *rap,
+    const struct ipv6_addr *addr)
+{
+	struct rt6 *r;
+
+	if (addr == NULL || addr->prefix_len > 128) {
+		errno = EINVAL;
+		return NULL;
+	}
+
+	/* There is no point in trying to manage a /128 prefix,
+	 * ones without a lifetime or ones not on link or delegated */
+	if (addr->prefix_len == 128 ||
+	    addr->prefix_vltime == 0 ||
+	    !(addr->flags & (IPV6_AF_ONLINK | IPV6_AF_DELEGATEDPFX)))
+		return NULL;
+
+	/* Don't install a blackhole route when not creating bigger prefixes */
+	if (addr->flags & IPV6_AF_DELEGATEDZERO)
+		return NULL;
+
+	r = make_route(ifp, rap);
+	if (r == NULL)
+		return NULL;
+	r->dest = addr->prefix;
+	ipv6_mask(&r->net, addr->prefix_len);
+	if (addr->flags & IPV6_AF_DELEGATEDPFX) {
+		r->flags |= RTF_REJECT;
+		r->gate = in6addr_loopback;
+	} else
+		r->gate = in6addr_any;
+	return r;
+}
+
+static struct rt6 *
+make_router(const struct ra *rap)
+{
+	struct rt6 *r;
+
+	r = make_route(rap->iface, rap);
+	if (r == NULL)
+		return NULL;
+	r->dest = in6addr_any;
+	r->net = in6addr_any;
+	r->gate = rap->from;
+	return r;
+}
+
+#define RT_IS_DEFAULT(rtp) \
+	(IN6_ARE_ADDR_EQUAL(&((rtp)->dest), &in6addr_any) &&		      \
+	    IN6_ARE_ADDR_EQUAL(&((rtp)->net), &in6addr_any))
+
+static void
+ipv6_build_ra_routes(struct ipv6_ctx *ctx, struct rt6_head *dnr, int expired)
+{
+	struct rt6 *rt;
+	struct ra *rap;
+	const struct ipv6_addr *addr;
+
+	TAILQ_FOREACH(rap, ctx->ra_routers, next) {
+		if (rap->expired != expired)
+			continue;
+		if (rap->iface->options->options & DHCPCD_IPV6RA_OWN) {
+			TAILQ_FOREACH(addr, &rap->addrs, next) {
+				rt = make_prefix(rap->iface, rap, addr);
+				if (rt)
+					TAILQ_INSERT_TAIL(dnr, rt, next);
+			}
+		}
+		if (rap->lifetime && rap->iface->options->options &
+		    (DHCPCD_IPV6RA_OWN | DHCPCD_IPV6RA_OWN_DEFAULT) &&
+		    !rap->no_public_warned)
+		{
+			rt = make_router(rap);
+			if (rt)
+				TAILQ_INSERT_TAIL(dnr, rt, next);
+		}
+	}
+}
+
+static void
+ipv6_build_dhcp_routes(struct dhcpcd_ctx *ctx,
+    struct rt6_head *dnr, enum DH6S dstate)
+{
+	const struct interface *ifp;
+	const struct dhcp6_state *d6_state;
+	const struct ipv6_addr *addr;
+	struct rt6 *rt;
+
+	TAILQ_FOREACH(ifp, ctx->ifaces, next) {
+		d6_state = D6_CSTATE(ifp);
+		if (d6_state && d6_state->state == dstate) {
+			TAILQ_FOREACH(addr, &d6_state->addrs, next) {
+				rt = make_prefix(ifp, NULL, addr);
+				if (rt)
+					TAILQ_INSERT_TAIL(dnr, rt, next);
+			}
+		}
+	}
+}
+
+void
+ipv6_buildroutes(struct dhcpcd_ctx *ctx)
+{
+#ifndef PASSIVE_MODE
+	struct rt6_head dnr, *nrs;
+	struct rt6 *rt, *rtn, *or;
+	uint8_t have_default;
+	unsigned long long o;
+
+	/* We need to have the interfaces in the correct order to ensure
+	 * our routes are managed correctly. */
+	if_sortinterfaces(ctx);
+
+	TAILQ_INIT(&dnr);
+
+	/* First add reachable routers and their prefixes */
+	ipv6_build_ra_routes(ctx->ipv6, &dnr, 0);
+#ifdef HAVE_ROUTE_METRIC
+	have_default = (TAILQ_FIRST(&dnr) != NULL);
+#endif
+
+	/* We have no way of knowing if prefixes added by DHCP are reachable
+	 * or not, so we have to assume they are.
+	 * Add bound before delegated so we can prefer interfaces better */
+	ipv6_build_dhcp_routes(ctx, &dnr, DH6S_BOUND);
+	ipv6_build_dhcp_routes(ctx, &dnr, DH6S_DELEGATED);
+
+#ifdef HAVE_ROUTE_METRIC
+	/* If we have an unreachable router, we really do need to remove the
+	 * route to it beause it could be a lower metric than a reachable
+	 * router. Of course, we should at least have some routers if all
+	 * are unreachable. */
+	if (!have_default)
+#endif
+	/* Add our non-reachable routers and prefixes
+	 * Unsure if this is needed, but it's a close match to kernel
+	 * behaviour */
+	ipv6_build_ra_routes(ctx->ipv6, &dnr, 1);
+
+	nrs = malloc(sizeof(*nrs));
+	if (nrs == NULL) {
+		logger(ctx, LOG_ERR, "%s: %m", __func__);
+		return;
+	}
+	TAILQ_INIT(nrs);
+	have_default = 0;
+
+	TAILQ_FOREACH_SAFE(rt, &dnr, next, rtn) {
+		/* Is this route already in our table? */
+		if (find_route6(nrs, rt) != NULL)
+			continue;
+		//rt->src.s_addr = ifp->addr.s_addr;
+		/* Do we already manage it? */
+		if ((or = find_route6(ctx->ipv6->routes, rt))) {
+			if (or->iface != rt->iface ||
+#ifdef HAVE_ROUTE_METRIC
+			    rt->metric != or->metric ||
+#endif
+		//	    or->src.s_addr != ifp->addr.s_addr ||
+			    !IN6_ARE_ADDR_EQUAL(&rt->gate, &or->gate))
+			{
+				if (c_route(or, rt) != 0)
+					continue;
+			}
+			TAILQ_REMOVE(ctx->ipv6->routes, or, next);
+			free(or);
+		} else {
+			if (n_route(rt) != 0)
+				continue;
+		}
+		if (RT_IS_DEFAULT(rt))
+			have_default = 1;
+		TAILQ_REMOVE(&dnr, rt, next);
+		TAILQ_INSERT_TAIL(nrs, rt, next);
+	}
+
+	/* Free any routes we failed to add/change */
+	while ((rt = TAILQ_FIRST(&dnr))) {
+		TAILQ_REMOVE(&dnr, rt, next);
+		free(rt);
+	}
+
+	/* Remove old routes we used to manage
+	 * If we own the default route, but not RA management itself
+	 * then we need to preserve the last best default route we had */
+	while ((rt = TAILQ_LAST(ctx->ipv6->routes, rt6_head))) {
+		TAILQ_REMOVE(ctx->ipv6->routes, rt, next);
+		if (find_route6(nrs, rt) == NULL) {
+			o = rt->iface->options->options;
+			if (!have_default &&
+			    (o & DHCPCD_IPV6RA_OWN_DEFAULT) &&
+			    !(o & DHCPCD_IPV6RA_OWN) &&
+			    RT_IS_DEFAULT(rt))
+				have_default = 1;
+				/* no need to add it back to our routing table
+				 * as we delete an exiting route when we add
+				 * a new one */
+			else if ((rt->iface->options->options &
+				(DHCPCD_EXITING | DHCPCD_PERSISTENT)) !=
+				(DHCPCD_EXITING | DHCPCD_PERSISTENT))
+				d_route(rt);
+		}
+		free(rt);
+	}
+
+	free(ctx->ipv6->routes);
+	ctx->ipv6->routes = nrs;
+#endif
+}
diff --git a/dhcpcd-6.8.2/ipv6.h b/dhcpcd-6.8.2/ipv6.h
new file mode 100644
index 0000000..a2e3042
--- /dev/null
+++ b/dhcpcd-6.8.2/ipv6.h
@@ -0,0 +1,276 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef IPV6_H
+#define IPV6_H
+
+#include <sys/uio.h>
+#include <netinet/in.h>
+
+#include "config.h"
+#include "dhcpcd.h"
+
+#define ALLROUTERS "ff02::2"
+
+#define ROUNDUP8(a)  (1 + (((a) - 1) |  7))
+#define ROUNDUP16(a) (1 + (((a) - 1) | 16))
+
+#define EUI64_GBIT		0x01
+#define EUI64_UBIT		0x02
+#define EUI64_TO_IFID(in6)	do {(in6)->s6_addr[8] ^= EUI64_UBIT; } while (0)
+#define EUI64_GROUP(in6)	((in6)->s6_addr[8] & EUI64_GBIT)
+
+#ifndef ND6_INFINITE_LIFETIME
+#  define ND6_INFINITE_LIFETIME		((uint32_t)~0)
+#endif
+
+/* RFC4941 constants */
+#define TEMP_VALID_LIFETIME	604800	/* 1 week */
+#define TEMP_PREFERRED_LIFETIME	86400	/* 1 day */
+#define REGEN_ADVANCE		5	/* seconds */
+#define MAX_DESYNC_FACTOR	600	/* 10 minutes */
+
+#define TEMP_IDGEN_RETRIES	3
+#define GEN_TEMPID_RETRY_MAX	5
+
+/* RFC7217 constants */
+#define IDGEN_RETRIES	3
+#define IDGEN_DELAY	1 /* second */
+
+/*
+ * BSD kernels don't inform userland of DAD results.
+ * See the discussion here:
+ *    http://mail-index.netbsd.org/tech-net/2013/03/15/msg004019.html
+ */
+#ifndef __linux__
+/* We guard here to avoid breaking a compile on linux ppc-64 headers */
+#  include <sys/param.h>
+#endif
+#ifdef BSD
+#  define IPV6_POLLADDRFLAG
+#endif
+
+/* This was fixed in NetBSD */
+#if defined(__NetBSD_Version__) && __NetBSD_Version__ >= 699002000
+#  undef IPV6_POLLADDRFLAG
+#endif
+
+/* Linux-3.18 can manage temporary addresses even with RA
+ * processing disabled. */
+//#undef IFA_F_MANAGETEMPADDR
+#if defined(__linux__) && defined(IFA_F_MANAGETEMPADDR)
+#define IPV6_MANAGETEMPADDR
+#endif
+
+/* Some BSDs do not allow userland to set temporary addresses. */
+#if defined(BSD) && defined(IN6_IFF_TEMPORARY)
+#define IPV6_MANAGETEMPADDR
+#endif
+
+struct ipv6_addr {
+	TAILQ_ENTRY(ipv6_addr) next;
+	struct interface *iface;
+	struct in6_addr prefix;
+	uint8_t prefix_len;
+	uint32_t prefix_vltime;
+	uint32_t prefix_pltime;
+	struct timespec created;
+	struct timespec acquired;
+	struct in6_addr addr;
+	int addr_flags;
+	short flags;
+	char saddr[INET6_ADDRSTRLEN];
+	uint8_t iaid[4];
+	uint16_t ia_type;
+	struct interface *delegating_iface;
+	uint8_t prefix_exclude_len;
+	struct in6_addr prefix_exclude;
+
+	void (*dadcallback)(void *);
+	int dadcounter;
+	uint8_t *ns;
+	size_t nslen;
+	int nsprobes;
+};
+TAILQ_HEAD(ipv6_addrhead, ipv6_addr);
+
+#define IPV6_AF_ONLINK		0x0001
+#define	IPV6_AF_NEW		0x0002
+#define IPV6_AF_STALE		0x0004
+#define IPV6_AF_ADDED		0x0008
+#define IPV6_AF_AUTOCONF	0x0010
+#define IPV6_AF_DUPLICATED	0x0020
+#define IPV6_AF_DADCOMPLETED	0x0040
+#define IPV6_AF_DELEGATED	0x0080
+#define IPV6_AF_DELEGATEDPFX	0x0100
+#define IPV6_AF_DELEGATEDZERO	0x0200
+#define IPV6_AF_REQUEST		0x0400
+#ifdef IPV6_MANAGETEMPADDR
+#define IPV6_AF_TEMPORARY	0X0800
+#endif
+
+struct rt6 {
+	TAILQ_ENTRY(rt6) next;
+	struct in6_addr dest;
+	struct in6_addr net;
+	struct in6_addr gate;
+	const struct interface *iface;
+	unsigned int flags;
+#ifdef HAVE_ROUTE_METRIC
+	unsigned int metric;
+#endif
+	unsigned int mtu;
+};
+TAILQ_HEAD(rt6_head, rt6);
+
+struct ll_callback {
+	TAILQ_ENTRY(ll_callback) next;
+	void (*callback)(void *);
+	void *arg;
+};
+TAILQ_HEAD(ll_callback_head, ll_callback);
+
+struct ipv6_state {
+	struct ipv6_addrhead addrs;
+	struct ll_callback_head ll_callbacks;
+
+#ifdef IPV6_MANAGETEMPADDR
+	time_t desync_factor;
+	uint8_t randomseed0[8]; /* upper 64 bits of MD5 digest */
+	uint8_t randomseed1[8]; /* lower 64 bits */
+	uint8_t randomid[8];
+#endif
+};
+
+#define IPV6_STATE(ifp)							       \
+	((struct ipv6_state *)(ifp)->if_data[IF_DATA_IPV6])
+#define IPV6_CSTATE(ifp)						       \
+	((const struct ipv6_state *)(ifp)->if_data[IF_DATA_IPV6])
+
+/* dhcpcd requires CMSG_SPACE to evaluate to a compile time constant. */
+#ifdef __QNX__
+#undef CMSG_SPACE
+#endif
+
+#ifndef ALIGNBYTES
+#define ALIGNBYTES (sizeof(int) - 1)
+#endif
+#ifndef ALIGN
+#define	ALIGN(p) (((unsigned int)(p) + ALIGNBYTES) & ~ALIGNBYTES)
+#endif
+#ifndef CMSG_SPACE
+#define	CMSG_SPACE(len)	(ALIGN(sizeof(struct cmsghdr)) + ALIGN(len))
+#endif
+
+#define IP6BUFLEN	(CMSG_SPACE(sizeof(struct in6_pktinfo)) + \
+			CMSG_SPACE(sizeof(int)))
+
+
+#ifdef INET6
+struct ipv6_ctx {
+	struct sockaddr_in6 from;
+	struct msghdr sndhdr;
+	struct iovec sndiov[2];
+	unsigned char sndbuf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
+	struct msghdr rcvhdr;
+	struct iovec rcviov[2];
+	unsigned char rcvbuf[IP6BUFLEN];
+	unsigned char ansbuf[1500];
+	char ntopbuf[INET6_ADDRSTRLEN];
+	const char *sfrom;
+
+	int nd_fd;
+	struct ra_head *ra_routers;
+	struct rt6_head *routes;
+
+	struct rt6_head kroutes;
+
+	int dhcp_fd;
+};
+
+struct ipv6_ctx *ipv6_init(struct dhcpcd_ctx *);
+ssize_t ipv6_printaddr(char *, size_t, const uint8_t *, const char *);
+int ipv6_makestableprivate(struct in6_addr *addr,
+    const struct in6_addr *prefix, int prefix_len,
+    const struct interface *ifp, int *dad_counter);
+int ipv6_makeaddr(struct in6_addr *, const struct interface *,
+    const struct in6_addr *, int);
+int ipv6_makeprefix(struct in6_addr *, const struct in6_addr *, int);
+int ipv6_mask(struct in6_addr *, int);
+uint8_t ipv6_prefixlen(const struct in6_addr *);
+int ipv6_userprefix( const struct in6_addr *, short prefix_len,
+    uint64_t user_number, struct in6_addr *result, short result_len);
+void ipv6_checkaddrflags(void *);
+int ipv6_addaddr(struct ipv6_addr *, const struct timespec *);
+ssize_t ipv6_addaddrs(struct ipv6_addrhead *addrs);
+void ipv6_freedrop_addrs(struct ipv6_addrhead *, int,
+    const struct interface *);
+void ipv6_handleifa(struct dhcpcd_ctx *ctx, int, struct if_head *,
+    const char *, const struct in6_addr *, uint8_t, int);
+int ipv6_handleifa_addrs(int, struct ipv6_addrhead *,
+    const struct in6_addr *, int);
+int ipv6_publicaddr(const struct ipv6_addr *);
+const struct ipv6_addr *ipv6_iffindaddr(const struct interface *,
+    const struct in6_addr *);
+struct ipv6_addr *ipv6_findaddr(struct dhcpcd_ctx *,
+    const struct in6_addr *, short);
+#define ipv6_linklocal(ifp) ipv6_iffindaddr((ifp), NULL)
+int ipv6_addlinklocalcallback(struct interface *, void (*)(void *), void *);
+void ipv6_freeaddr(struct ipv6_addr *);
+void ipv6_freedrop(struct interface *, int);
+#define ipv6_free(ifp) ipv6_freedrop((ifp), 0)
+#define ipv6_drop(ifp) ipv6_freedrop((ifp), 2)
+
+#ifdef IPV6_MANAGETEMPADDR
+void ipv6_gentempifid(struct interface *);
+void ipv6_settempstale(struct interface *);
+struct ipv6_addr *ipv6_createtempaddr(struct ipv6_addr *,
+    const struct timespec *);
+struct ipv6_addr *ipv6_settemptime(struct ipv6_addr *, int);
+void ipv6_addtempaddrs(struct interface *, const struct timespec *);
+#else
+#define ipv6_gentempifid(a) {}
+#define ipv6_settempstale(a) {}
+#endif
+
+int ipv6_start(struct interface *);
+void ipv6_ctxfree(struct dhcpcd_ctx *);
+int ipv6_handlert(struct dhcpcd_ctx *, int cmd, struct rt6 *);
+void ipv6_freerts(struct rt6_head *);
+void ipv6_buildroutes(struct dhcpcd_ctx *);
+
+#else
+#define ipv6_init(a) (NULL)
+#define ipv6_start(a) (-1)
+#define ipv6_free_ll_callbacks(a) {}
+#define ipv6_free(a) {}
+#define ipv6_drop(a) {}
+#define ipv6_ctxfree(a) {}
+#define ipv6_gentempifid(a) {}
+#endif
+
+#endif
diff --git a/dhcpcd-6.8.2/ipv6nd.c b/dhcpcd-6.8.2/ipv6nd.c
new file mode 100644
index 0000000..89f6782
--- /dev/null
+++ b/dhcpcd-6.8.2/ipv6nd.c
@@ -0,0 +1,1762 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <net/route.h>
+#include <netinet/in.h>
+#include <netinet/ip6.h>
+#include <netinet/icmp6.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define ELOOP_QUEUE 3
+#include "common.h"
+#include "dhcpcd.h"
+#include "dhcp6.h"
+#include "eloop.h"
+#include "if.h"
+#include "ipv6.h"
+#include "ipv6nd.h"
+#include "script.h"
+
+/* Debugging Router Solicitations is a lot of spam, so disable it */
+//#define DEBUG_RS
+
+#ifndef ND_OPT_RDNSS
+#define ND_OPT_RDNSS			25
+struct nd_opt_rdnss {           /* RDNSS option RFC 6106 */
+	uint8_t		nd_opt_rdnss_type;
+	uint8_t		nd_opt_rdnss_len;
+	uint16_t	nd_opt_rdnss_reserved;
+	uint32_t	nd_opt_rdnss_lifetime;
+        /* followed by list of IP prefixes */
+} __packed;
+#endif
+
+#ifndef ND_OPT_DNSSL
+#define ND_OPT_DNSSL			31
+struct nd_opt_dnssl {		/* DNSSL option RFC 6106 */
+	uint8_t		nd_opt_dnssl_type;
+	uint8_t		nd_opt_dnssl_len;
+	uint16_t	nd_opt_dnssl_reserved;
+	uint32_t	nd_opt_dnssl_lifetime;
+	/* followed by list of DNS servers */
+} __packed;
+#endif
+
+/* Impossible options, so we can easily add extras */
+#define _ND_OPT_PREFIX_ADDR	255 + 1
+
+/* Minimal IPv6 MTU */
+#ifndef IPV6_MMTU
+#define IPV6_MMTU 1280
+#endif
+
+#ifndef ND_RA_FLAG_RTPREF_HIGH
+#define ND_RA_FLAG_RTPREF_MASK		0x18
+#define ND_RA_FLAG_RTPREF_HIGH		0x08
+#define ND_RA_FLAG_RTPREF_MEDIUM	0x00
+#define ND_RA_FLAG_RTPREF_LOW		0x18
+#define ND_RA_FLAG_RTPREF_RSV		0x10
+#endif
+
+/* RTPREF_MEDIUM has to be 0! */
+#define RTPREF_HIGH	1
+#define RTPREF_MEDIUM	0
+#define RTPREF_LOW	(-1)
+#define RTPREF_RESERVED	(-2)
+#define RTPREF_INVALID	(-3)	/* internal */
+
+#define MIN_RANDOM_FACTOR	500				/* millisecs */
+#define MAX_RANDOM_FACTOR	1500				/* millisecs */
+#define MIN_RANDOM_FACTOR_U	MIN_RANDOM_FACTOR * 1000	/* usecs */
+#define MAX_RANDOM_FACTOR_U	MAX_RANDOM_FACTOR * 1000	/* usecs */
+
+#if BYTE_ORDER == BIG_ENDIAN
+#define IPV6_ADDR_INT32_ONE     1
+#define IPV6_ADDR_INT16_MLL     0xff02
+#elif BYTE_ORDER == LITTLE_ENDIAN
+#define IPV6_ADDR_INT32_ONE     0x01000000
+#define IPV6_ADDR_INT16_MLL     0x02ff
+#endif
+
+/* Debugging Neighbor Solicitations is a lot of spam, so disable it */
+//#define DEBUG_NS
+//
+
+static void ipv6nd_handledata(void *);
+
+/*
+ * Android ships buggy ICMP6 filter headers.
+ * Supply our own until they fix their shit.
+ * References:
+ *     https://android-review.googlesource.com/#/c/58438/
+ *     http://code.google.com/p/android/issues/original?id=32621&seq=24
+ */
+#ifdef __ANDROID__
+#undef ICMP6_FILTER_WILLPASS
+#undef ICMP6_FILTER_WILLBLOCK
+#undef ICMP6_FILTER_SETPASS
+#undef ICMP6_FILTER_SETBLOCK
+#undef ICMP6_FILTER_SETPASSALL
+#undef ICMP6_FILTER_SETBLOCKALL
+#define ICMP6_FILTER_WILLPASS(type, filterp) \
+	((((filterp)->icmp6_filt[(type) >> 5]) & (1 << ((type) & 31))) == 0)
+#define ICMP6_FILTER_WILLBLOCK(type, filterp) \
+	((((filterp)->icmp6_filt[(type) >> 5]) & (1 << ((type) & 31))) != 0)
+#define ICMP6_FILTER_SETPASS(type, filterp) \
+	((((filterp)->icmp6_filt[(type) >> 5]) &= ~(1 << ((type) & 31))))
+#define ICMP6_FILTER_SETBLOCK(type, filterp) \
+	((((filterp)->icmp6_filt[(type) >> 5]) |=  (1 << ((type) & 31))))
+#define ICMP6_FILTER_SETPASSALL(filterp) \
+	memset(filterp, 0, sizeof(struct icmp6_filter));
+#define ICMP6_FILTER_SETBLOCKALL(filterp) \
+	memset(filterp, 0xff, sizeof(struct icmp6_filter));
+#endif
+
+/* Support older systems with different defines */
+#if !defined(IPV6_RECVHOPLIMIT) && defined(IPV6_HOPLIMIT)
+#define IPV6_RECVHOPLIMIT IPV6_HOPLIMIT
+#endif
+#if !defined(IPV6_RECVPKTINFO) && defined(IPV6_PKTINFO)
+#define IPV6_RECVPKTINFO IPV6_PKTINFO
+#endif
+
+static int
+ipv6nd_open(struct dhcpcd_ctx *dctx)
+{
+	struct ipv6_ctx *ctx;
+	int on;
+	struct icmp6_filter filt;
+
+	ctx = dctx->ipv6;
+	if (ctx->nd_fd != -1)
+		return ctx->nd_fd;
+#ifdef SOCK_CLOEXEC
+	ctx->nd_fd = socket(PF_INET6, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK,
+	    IPPROTO_ICMPV6);
+	if (ctx->nd_fd == -1)
+		return -1;
+#else
+	if ((ctx->nd_fd = socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) == -1)
+		return -1;
+	if ((on = fcntl(ctx->nd_fd, F_GETFD, 0)) == -1 ||
+	    fcntl(ctx->nd_fd, F_SETFD, on | FD_CLOEXEC) == -1)
+	{
+		close(ctx->nd_fd);
+		ctx->nd_fd = -1;
+	        return -1;
+	}
+	if ((on = fcntl(ctx->nd_fd, F_GETFL, 0)) == -1 ||
+	    fcntl(ctx->nd_fd, F_SETFL, on | O_NONBLOCK) == -1)
+	{
+		close(ctx->nd_fd);
+		ctx->nd_fd = -1;
+	        return -1;
+	}
+#endif
+
+	/* RFC4861 4.1 */
+	on = 255;
+	if (setsockopt(ctx->nd_fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
+	    &on, sizeof(on)) == -1)
+		goto eexit;
+
+	on = 1;
+	if (setsockopt(ctx->nd_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO,
+	    &on, sizeof(on)) == -1)
+		goto eexit;
+
+	on = 1;
+	if (setsockopt(ctx->nd_fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT,
+	    &on, sizeof(on)) == -1)
+		goto eexit;
+
+	ICMP6_FILTER_SETBLOCKALL(&filt);
+	ICMP6_FILTER_SETPASS(ND_NEIGHBOR_ADVERT, &filt);
+	ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt);
+	if (setsockopt(ctx->nd_fd, IPPROTO_ICMPV6, ICMP6_FILTER,
+	    &filt, sizeof(filt)) == -1)
+		goto eexit;
+
+	eloop_event_add(dctx->eloop, ctx->nd_fd,
+	    ipv6nd_handledata, dctx, NULL, NULL);
+	return ctx->nd_fd;
+
+eexit:
+	if (ctx->nd_fd != -1) {
+		eloop_event_delete(dctx->eloop, ctx->nd_fd, 0);
+		close(ctx->nd_fd);
+		ctx->nd_fd = -1;
+	}
+	return -1;
+}
+
+static int
+ipv6nd_makersprobe(struct interface *ifp)
+{
+	struct rs_state *state;
+	struct nd_router_solicit *rs;
+	struct nd_opt_hdr *nd;
+
+	state = RS_STATE(ifp);
+	free(state->rs);
+	state->rslen = sizeof(*rs) + (size_t)ROUNDUP8(ifp->hwlen + 2);
+	state->rs = calloc(1, state->rslen);
+	if (state->rs == NULL)
+		return -1;
+	rs = (struct nd_router_solicit *)(void *)state->rs;
+	rs->nd_rs_type = ND_ROUTER_SOLICIT;
+	rs->nd_rs_code = 0;
+	rs->nd_rs_cksum = 0;
+	rs->nd_rs_reserved = 0;
+	nd = (struct nd_opt_hdr *)(state->rs + sizeof(*rs));
+	nd->nd_opt_type = ND_OPT_SOURCE_LINKADDR;
+	nd->nd_opt_len = (uint8_t)((ROUNDUP8(ifp->hwlen + 2)) >> 3);
+	memcpy(nd + 1, ifp->hwaddr, ifp->hwlen);
+	return 0;
+}
+
+static void
+ipv6nd_sendrsprobe(void *arg)
+{
+	struct interface *ifp = arg;
+	struct ipv6_ctx *ctx;
+	struct rs_state *state;
+	struct sockaddr_in6 dst;
+	struct cmsghdr *cm;
+	struct in6_pktinfo pi;
+
+	if (ipv6_linklocal(ifp) == NULL) {
+		logger(ifp->ctx, LOG_DEBUG,
+		    "%s: delaying Router Solicitation for LL address",
+		    ifp->name);
+		ipv6_addlinklocalcallback(ifp, ipv6nd_sendrsprobe, ifp);
+		return;
+	}
+
+	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, ALLROUTERS, &dst.sin6_addr) != 1) {
+		logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
+		return;
+	}
+
+	state = RS_STATE(ifp);
+	ctx = ifp->ctx->ipv6;
+	ctx->sndhdr.msg_name = (void *)&dst;
+	ctx->sndhdr.msg_iov[0].iov_base = state->rs;
+	ctx->sndhdr.msg_iov[0].iov_len = state->rslen;
+
+	/* Set the outbound interface */
+	cm = CMSG_FIRSTHDR(&ctx->sndhdr);
+	if (cm == NULL) /* unlikely */
+		return;
+	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));
+
+	logger(ifp->ctx, LOG_DEBUG,
+	    "%s: sending Router Solicitation", ifp->name);
+	if (sendmsg(ctx->nd_fd, &ctx->sndhdr, 0) == -1) {
+		logger(ifp->ctx, LOG_ERR,
+		    "%s: %s: sendmsg: %m", ifp->name, __func__);
+		ipv6nd_drop(ifp);
+		ifp->options->options &= ~(DHCPCD_IPV6 | DHCPCD_IPV6RS);
+		return;
+	}
+
+	if (state->rsprobes++ < MAX_RTR_SOLICITATIONS)
+		eloop_timeout_add_sec(ifp->ctx->eloop,
+		    RTR_SOLICITATION_INTERVAL, ipv6nd_sendrsprobe, ifp);
+	else {
+		logger(ifp->ctx, LOG_WARNING,
+		    "%s: no IPv6 Routers available", ifp->name);
+		ipv6nd_drop(ifp);
+		dhcp6_drop(ifp, "EXPIRE6");
+	}
+}
+
+void
+ipv6nd_expire(struct interface *ifp, uint32_t seconds)
+{
+	struct ra *rap;
+	struct timespec now;
+
+	get_monotonic(&now);
+
+	TAILQ_FOREACH(rap, ifp->ctx->ipv6->ra_routers, next) {
+		if (rap->iface == ifp) {
+			rap->received = now;
+			rap->expired = seconds ? 0 : 1;
+			if (seconds) {
+				struct ra_opt *rao;
+				struct ipv6_addr *ap;
+
+				rap->lifetime = seconds;
+				TAILQ_FOREACH(ap, &rap->addrs, next) {
+					if (ap->prefix_vltime) {
+						ap->prefix_vltime = seconds;
+						ap->prefix_pltime = seconds / 2;
+					}
+				}
+				ipv6_addaddrs(&rap->addrs);
+				TAILQ_FOREACH(rao, &rap->options, next) {
+					timespecclear(&rao->expire);
+				}
+			}
+		}
+	}
+	if (seconds)
+		ipv6nd_expirera(ifp);
+	else
+		ipv6_buildroutes(ifp->ctx);
+}
+
+static void
+ipv6nd_reachable(struct ra *rap, int flags)
+{
+
+	if (flags & IPV6ND_REACHABLE) {
+		if (rap->lifetime && rap->expired) {
+			logger(rap->iface->ctx, LOG_INFO,
+			    "%s: %s is reachable again",
+			    rap->iface->name, rap->sfrom);
+			rap->expired = 0;
+			ipv6_buildroutes(rap->iface->ctx);
+			/* XXX Not really an RA */
+			script_runreason(rap->iface, "ROUTERADVERT");
+		}
+	} else {
+		if (rap->lifetime && !rap->expired) {
+			logger(rap->iface->ctx, LOG_WARNING,
+			    "%s: %s is unreachable, expiring it",
+			    rap->iface->name, rap->sfrom);
+			rap->expired = 1;
+			ipv6_buildroutes(rap->iface->ctx);
+			/* XXX Not really an RA */
+			script_runreason(rap->iface, "ROUTERADVERT");
+		}
+	}
+}
+
+void
+ipv6nd_neighbour(struct dhcpcd_ctx *ctx, struct in6_addr *addr, int flags)
+{
+	struct ra *rap;
+
+	if (ctx->ipv6) {
+	        TAILQ_FOREACH(rap, ctx->ipv6->ra_routers, next) {
+			if (IN6_ARE_ADDR_EQUAL(&rap->from, addr)) {
+				ipv6nd_reachable(rap, flags);
+				break;
+			}
+		}
+	}
+}
+
+static void
+ipv6nd_free_opts(struct ra *rap)
+{
+	struct ra_opt *rao;
+
+	while ((rao = TAILQ_FIRST(&rap->options))) {
+		TAILQ_REMOVE(&rap->options, rao, next);
+		free(rao->option);
+		free(rao);
+	}
+}
+
+struct ipv6_addr *
+ipv6nd_findaddr(struct dhcpcd_ctx *ctx, const struct in6_addr *addr,
+    short flags)
+{
+	struct ra *rap;
+	struct ipv6_addr *ap;
+
+	if (ctx->ipv6 == NULL)
+		return NULL;
+
+	TAILQ_FOREACH(rap, ctx->ipv6->ra_routers, next) {
+		TAILQ_FOREACH(ap, &rap->addrs, next) {
+			if (addr == NULL) {
+				if ((ap->flags &
+				    (IPV6_AF_ADDED | IPV6_AF_DADCOMPLETED)) ==
+				    (IPV6_AF_ADDED | IPV6_AF_DADCOMPLETED))
+					return ap;
+			} else if (ap->prefix_vltime &&
+			    IN6_ARE_ADDR_EQUAL(&ap->addr, addr) &&
+			    (!flags || ap->flags & flags))
+				return ap;
+		}
+	}
+	return NULL;
+}
+
+void ipv6nd_freedrop_ra(struct ra *rap, int drop)
+{
+
+	eloop_timeout_delete(rap->iface->ctx->eloop, NULL, rap->iface);
+	eloop_timeout_delete(rap->iface->ctx->eloop, NULL, rap);
+	if (!drop)
+		TAILQ_REMOVE(rap->iface->ctx->ipv6->ra_routers, rap, next);
+	ipv6_freedrop_addrs(&rap->addrs, drop, NULL);
+	ipv6nd_free_opts(rap);
+	free(rap->data);
+	free(rap);
+}
+
+ssize_t
+ipv6nd_free(struct interface *ifp)
+{
+	struct rs_state *state;
+	struct ra *rap, *ran;
+	struct dhcpcd_ctx *ctx;
+	ssize_t n;
+
+	state = RS_STATE(ifp);
+	if (state == NULL)
+		return 0;
+
+	free(state->rs);
+	free(state);
+	ifp->if_data[IF_DATA_IPV6ND] = NULL;
+	n = 0;
+	TAILQ_FOREACH_SAFE(rap, ifp->ctx->ipv6->ra_routers, next, ran) {
+		if (rap->iface == ifp) {
+			ipv6nd_free_ra(rap);
+			n++;
+		}
+	}
+
+	/* If we don't have any more IPv6 enabled interfaces,
+	 * close the global socket and release resources */
+	ctx = ifp->ctx;
+	TAILQ_FOREACH(ifp, ctx->ifaces, next) {
+		if (RS_STATE(ifp))
+			break;
+	}
+	if (ifp == NULL) {
+		if (ctx->ipv6->nd_fd != -1) {
+			eloop_event_delete(ctx->eloop, ctx->ipv6->nd_fd, 0);
+			close(ctx->ipv6->nd_fd);
+			ctx->ipv6->nd_fd = -1;
+		}
+	}
+
+	return n;
+}
+
+static int
+rtpref(struct ra *rap)
+{
+
+	switch (rap->flags & ND_RA_FLAG_RTPREF_MASK) {
+	case ND_RA_FLAG_RTPREF_HIGH:
+		return (RTPREF_HIGH);
+	case ND_RA_FLAG_RTPREF_MEDIUM:
+	case ND_RA_FLAG_RTPREF_RSV:
+		return (RTPREF_MEDIUM);
+	case ND_RA_FLAG_RTPREF_LOW:
+		return (RTPREF_LOW);
+	default:
+		logger(rap->iface->ctx, LOG_ERR,
+		    "rtpref: impossible RA flag %x", rap->flags);
+		return (RTPREF_INVALID);
+	}
+	/* NOTREACHED */
+}
+
+static void
+add_router(struct ipv6_ctx *ctx, struct ra *router)
+{
+	struct ra *rap;
+
+	TAILQ_FOREACH(rap, ctx->ra_routers, next) {
+		if (router->iface->metric < rap->iface->metric ||
+		    (router->iface->metric == rap->iface->metric &&
+		    rtpref(router) > rtpref(rap)))
+		{
+			TAILQ_INSERT_BEFORE(rap, router, next);
+			return;
+		}
+	}
+	TAILQ_INSERT_TAIL(ctx->ra_routers, router, next);
+}
+
+static int
+ipv6nd_scriptrun(struct ra *rap)
+{
+	int hasdns, hasaddress, pid;
+	struct ipv6_addr *ap;
+	const struct ra_opt *rao;
+
+	hasaddress = 0;
+	/* If all addresses have completed DAD run the script */
+	TAILQ_FOREACH(ap, &rap->addrs, next) {
+		if ((ap->flags & (IPV6_AF_AUTOCONF | IPV6_AF_ADDED)) ==
+		    (IPV6_AF_AUTOCONF | IPV6_AF_ADDED))
+		{
+			hasaddress = 1;
+			if (!(ap->flags & IPV6_AF_DADCOMPLETED) &&
+			    ipv6_iffindaddr(ap->iface, &ap->addr))
+				ap->flags |= IPV6_AF_DADCOMPLETED;
+			if ((ap->flags & IPV6_AF_DADCOMPLETED) == 0) {
+				logger(ap->iface->ctx, LOG_DEBUG,
+				    "%s: waiting for Router Advertisement"
+				    " DAD to complete",
+				    rap->iface->name);
+				return 0;
+			}
+		}
+	}
+
+	/* If we don't require RDNSS then set hasdns = 1 so we fork */
+	if (!(rap->iface->options->options & DHCPCD_IPV6RA_REQRDNSS))
+		hasdns = 1;
+	else {
+		hasdns = 0;
+		TAILQ_FOREACH(rao, &rap->options, next) {
+			if (rao->type == ND_OPT_RDNSS &&
+			    rao->option &&
+			    timespecisset(&rao->expire))
+			{
+				hasdns = 1;
+				break;
+			}
+		}
+	}
+
+	script_runreason(rap->iface, "ROUTERADVERT");
+	pid = 0;
+	if (hasdns && (hasaddress ||
+	    !(rap->flags & (ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER))))
+		pid = dhcpcd_daemonise(rap->iface->ctx);
+#if 0
+	else if (options & DHCPCD_DAEMONISE &&
+	    !(options & DHCPCD_DAEMONISED) && new_data)
+		logger(rap->iface->ctx, LOG_WARNING,
+		    "%s: did not fork due to an absent"
+		    " RDNSS option in the RA",
+		    ifp->name);
+}
+#endif
+	return pid;
+}
+
+static void
+ipv6nd_addaddr(void *arg)
+{
+	struct ipv6_addr *ap = arg;
+
+	ipv6_addaddr(ap, NULL);
+}
+
+int
+ipv6nd_dadcompleted(const struct interface *ifp)
+{
+	const struct ra *rap;
+	const struct ipv6_addr *ap;
+
+	TAILQ_FOREACH(rap, ifp->ctx->ipv6->ra_routers, next) {
+		if (rap->iface != ifp)
+			continue;
+		TAILQ_FOREACH(ap, &rap->addrs, next) {
+			if (ap->flags & IPV6_AF_AUTOCONF &&
+			    ap->flags & IPV6_AF_ADDED &&
+			    !(ap->flags & IPV6_AF_DADCOMPLETED))
+				return 0;
+		}
+	}
+	return 1;
+}
+
+static void
+ipv6nd_dadcallback(void *arg)
+{
+	struct ipv6_addr *ap = arg, *rapap;
+	struct interface *ifp;
+	struct ra *rap;
+	int wascompleted, found;
+	struct timespec tv;
+	char buf[INET6_ADDRSTRLEN];
+	const char *p;
+	int dadcounter;
+
+	ifp = ap->iface;
+	wascompleted = (ap->flags & IPV6_AF_DADCOMPLETED);
+	ap->flags |= IPV6_AF_DADCOMPLETED;
+	if (ap->flags & IPV6_AF_DUPLICATED) {
+		ap->dadcounter++;
+		logger(ifp->ctx, LOG_WARNING, "%s: DAD detected %s",
+		    ifp->name, ap->saddr);
+
+		/* Try and make another stable private address.
+		 * Because ap->dadcounter is always increamented,
+		 * a different address is generated. */
+		/* XXX Cache DAD counter per prefix/id/ssid? */
+		if (ifp->options->options & DHCPCD_SLAACPRIVATE) {
+			if (ap->dadcounter >= IDGEN_RETRIES) {
+				logger(ifp->ctx, LOG_ERR,
+				    "%s: unable to obtain a"
+				    " stable private address",
+				    ifp->name);
+				goto try_script;
+			}
+			logger(ifp->ctx, LOG_INFO, "%s: deleting address %s",
+				ifp->name, ap->saddr);
+			if (if_deladdress6(ap) == -1 &&
+			    errno != EADDRNOTAVAIL && errno != ENXIO)
+				logger(ifp->ctx, LOG_ERR, "if_deladdress6: %m");
+			dadcounter = ap->dadcounter;
+			if (ipv6_makestableprivate(&ap->addr,
+			    &ap->prefix, ap->prefix_len,
+			    ifp, &dadcounter) == -1)
+			{
+				logger(ifp->ctx, LOG_ERR,
+				    "%s: ipv6_makestableprivate: %m",
+				    ifp->name);
+				return;
+			}
+			ap->dadcounter = dadcounter;
+			ap->flags &= ~(IPV6_AF_ADDED | IPV6_AF_DADCOMPLETED);
+			ap->flags |= IPV6_AF_NEW;
+			p = inet_ntop(AF_INET6, &ap->addr, buf, sizeof(buf));
+			if (p)
+				snprintf(ap->saddr,
+				    sizeof(ap->saddr),
+				    "%s/%d",
+				    p, ap->prefix_len);
+			else
+				ap->saddr[0] = '\0';
+			tv.tv_sec = 0;
+			tv.tv_nsec = (suseconds_t)
+			    arc4random_uniform(IDGEN_DELAY * NSEC_PER_SEC);
+			timespecnorm(&tv);
+			eloop_timeout_add_tv(ifp->ctx->eloop, &tv,
+			    ipv6nd_addaddr, ap);
+			return;
+		}
+	}
+
+try_script:
+	if (!wascompleted) {
+		TAILQ_FOREACH(rap, ifp->ctx->ipv6->ra_routers, next) {
+			if (rap->iface != ifp)
+				continue;
+			wascompleted = 1;
+			found = 0;
+			TAILQ_FOREACH(rapap, &rap->addrs, next) {
+				if (rapap->flags & IPV6_AF_AUTOCONF &&
+				    rapap->flags & IPV6_AF_ADDED &&
+				    (rapap->flags & IPV6_AF_DADCOMPLETED) == 0)
+				{
+					wascompleted = 0;
+					break;
+				}
+				if (rapap == ap)
+					found = 1;
+			}
+
+			if (wascompleted && found) {
+				logger(rap->iface->ctx, LOG_DEBUG,
+				    "%s: Router Advertisement DAD completed",
+				    rap->iface->name);
+				if (ipv6nd_scriptrun(rap))
+					return;
+			}
+		}
+	}
+}
+
+static int
+ipv6nd_ra_has_public_addr(const struct ra *rap)
+{
+	const struct ipv6_addr *ia;
+
+	TAILQ_FOREACH(ia, &rap->addrs, next) {
+		if (ia->flags & IPV6_AF_AUTOCONF &&
+		    ipv6_publicaddr(ia))
+			return 1;
+	}
+	return 0;
+}
+
+static void
+ipv6nd_handlera(struct dhcpcd_ctx *dctx, struct interface *ifp,
+    struct icmp6_hdr *icp, size_t len)
+{
+	struct ipv6_ctx *ctx = dctx->ipv6;
+	size_t olen, l, n;
+	ssize_t r;
+	struct nd_router_advert *nd_ra;
+	struct nd_opt_prefix_info *pi;
+	struct nd_opt_mtu *mtu;
+	struct nd_opt_rdnss *rdnss;
+	struct nd_opt_dnssl *dnssl;
+	uint32_t lifetime, mtuv;
+	uint8_t *p, *op;
+	struct in6_addr addr;
+	char buf[INET6_ADDRSTRLEN];
+	const char *cbp;
+	struct ra *rap;
+	struct nd_opt_hdr *ndo;
+	struct ra_opt *rao;
+	struct ipv6_addr *ap;
+	char *opt, *opt2, *tmp;
+	struct timespec expire;
+	uint8_t new_rap, new_data;
+#ifdef IPV6_MANAGETEMPADDR
+	uint8_t new_ap;
+#endif
+
+	if (len < sizeof(struct nd_router_advert)) {
+		logger(dctx, LOG_ERR,
+		    "IPv6 RA packet too short from %s", ctx->sfrom);
+		return;
+	}
+
+	if (!IN6_IS_ADDR_LINKLOCAL(&ctx->from.sin6_addr)) {
+		logger(dctx, LOG_ERR,
+		    "RA from non local address %s", ctx->sfrom);
+		return;
+	}
+
+	if (ifp == NULL) {
+#ifdef DEBUG_RS
+		logger(dctx, LOG_DEBUG,
+		    "RA for unexpected interface from %s", ctx->sfrom);
+#endif
+		return;
+	}
+	if (!(ifp->options->options & DHCPCD_IPV6RS)) {
+#ifdef DEBUG_RS
+		logger(ifp->ctx, LOG_DEBUG, "%s: unexpected RA from %s",
+		    ifp->name, ctx->sfrom);
+#endif
+		return;
+	}
+
+	/* We could receive a RA before we sent a RS*/
+	if (ipv6_linklocal(ifp) == NULL) {
+#ifdef DEBUG_RS
+		logger(ifp->ctx, LOG_DEBUG,
+		    "%s: received RA from %s (no link-local)",
+		    ifp->name, ctx->sfrom);
+#endif
+		return;
+	}
+
+	if (ipv6_iffindaddr(ifp, &ctx->from.sin6_addr)) {
+		logger(ifp->ctx, LOG_DEBUG,
+		    "%s: ignoring RA from ourself %s", ifp->name, ctx->sfrom);
+		return;
+	}
+
+	TAILQ_FOREACH(rap, ctx->ra_routers, next) {
+		if (ifp == rap->iface &&
+		    IN6_ARE_ADDR_EQUAL(&rap->from, &ctx->from.sin6_addr))
+			break;
+	}
+
+	nd_ra = (struct nd_router_advert *)icp;
+
+	/* We don't want to spam the log with the fact we got an RA every
+	 * 30 seconds or so, so only spam the log if it's different. */
+	if (rap == NULL || (rap->data_len != len ||
+	     memcmp(rap->data, (unsigned char *)icp, rap->data_len) != 0))
+	{
+		if (rap) {
+			free(rap->data);
+			rap->data_len = 0;
+			rap->no_public_warned = 0;
+		}
+		new_data = 1;
+	} else
+		new_data = 0;
+	if (new_data || ifp->options->options & DHCPCD_DEBUG)
+		logger(ifp->ctx, LOG_INFO, "%s: Router Advertisement from %s",
+		    ifp->name, ctx->sfrom);
+
+	if (rap == NULL) {
+		rap = calloc(1, sizeof(*rap));
+		if (rap == NULL) {
+			logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
+			return;
+		}
+		rap->iface = ifp;
+		rap->from = ctx->from.sin6_addr;
+		strlcpy(rap->sfrom, ctx->sfrom, sizeof(rap->sfrom));
+		TAILQ_INIT(&rap->addrs);
+		TAILQ_INIT(&rap->options);
+		new_rap = 1;
+	} else
+		new_rap = 0;
+	if (rap->data_len == 0) {
+		rap->data = malloc(len);
+		if (rap->data == NULL) {
+			logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
+			if (new_rap)
+				free(rap);
+			return;
+		}
+		memcpy(rap->data, icp, len);
+		rap->data_len = len;
+	}
+
+	get_monotonic(&rap->received);
+	rap->flags = nd_ra->nd_ra_flags_reserved;
+	if (new_rap == 0 && rap->lifetime == 0)
+		logger(ifp->ctx, LOG_WARNING, "%s: %s router available",
+		   ifp->name, rap->sfrom);
+	rap->lifetime = ntohs(nd_ra->nd_ra_router_lifetime);
+	if (nd_ra->nd_ra_reachable) {
+		rap->reachable = ntohl(nd_ra->nd_ra_reachable);
+		if (rap->reachable > MAX_REACHABLE_TIME)
+			rap->reachable = 0;
+	}
+	if (nd_ra->nd_ra_retransmit)
+		rap->retrans = ntohl(nd_ra->nd_ra_retransmit);
+	if (rap->lifetime)
+		rap->expired = 0;
+
+	ipv6_settempstale(ifp);
+	TAILQ_FOREACH(ap, &rap->addrs, next) {
+		ap->flags |= IPV6_AF_STALE;
+	}
+
+	len -= sizeof(struct nd_router_advert);
+	p = ((uint8_t *)icp) + sizeof(struct nd_router_advert);
+	lifetime = ~0U;
+	for (; len > 0; p += olen, len -= olen) {
+		if (len < sizeof(struct nd_opt_hdr)) {
+			logger(ifp->ctx, LOG_ERR,
+			    "%s: short option", ifp->name);
+			break;
+		}
+		ndo = (struct nd_opt_hdr *)p;
+		olen = (size_t)ndo->nd_opt_len * 8;
+		if (olen == 0) {
+			logger(ifp->ctx, LOG_ERR,
+			    "%s: zero length option", ifp->name);
+			break;
+		}
+		if (olen > len) {
+			logger(ifp->ctx, LOG_ERR,
+			    "%s: option length exceeds message", ifp->name);
+			break;
+		}
+
+		opt = opt2 = NULL;
+		switch (ndo->nd_opt_type) {
+		case ND_OPT_PREFIX_INFORMATION:
+			pi = (struct nd_opt_prefix_info *)(void *)ndo;
+			if (pi->nd_opt_pi_len != 4) {
+				logger(ifp->ctx, new_data ? LOG_ERR : LOG_DEBUG,
+				    "%s: invalid option len for prefix",
+				    ifp->name);
+				continue;
+			}
+			if (pi->nd_opt_pi_prefix_len > 128) {
+				logger(ifp->ctx, new_data ? LOG_ERR : LOG_DEBUG,
+				    "%s: invalid prefix len",
+				    ifp->name);
+				continue;
+			}
+			if (IN6_IS_ADDR_MULTICAST(&pi->nd_opt_pi_prefix) ||
+			    IN6_IS_ADDR_LINKLOCAL(&pi->nd_opt_pi_prefix))
+			{
+				logger(ifp->ctx, new_data ? LOG_ERR : LOG_DEBUG,
+				    "%s: invalid prefix in RA", ifp->name);
+				continue;
+			}
+			if (ntohl(pi->nd_opt_pi_preferred_time) >
+			    ntohl(pi->nd_opt_pi_valid_time))
+			{
+				logger(ifp->ctx, new_data ? LOG_ERR : LOG_DEBUG,
+				    "%s: pltime > vltime", ifp->name);
+				continue;
+			}
+			TAILQ_FOREACH(ap, &rap->addrs, next)
+				if (ap->prefix_len ==pi->nd_opt_pi_prefix_len &&
+				    IN6_ARE_ADDR_EQUAL(&ap->prefix,
+				    &pi->nd_opt_pi_prefix))
+					break;
+			if (ap == NULL) {
+				if (!(pi->nd_opt_pi_flags_reserved &
+				    ND_OPT_PI_FLAG_AUTO) &&
+				    !(pi->nd_opt_pi_flags_reserved &
+				    ND_OPT_PI_FLAG_ONLINK))
+					continue;
+				ap = calloc(1, sizeof(*ap));
+				if (ap == NULL)
+					break;
+				ap->iface = rap->iface;
+				ap->flags = IPV6_AF_NEW;
+				ap->prefix_len = pi->nd_opt_pi_prefix_len;
+				ap->prefix = pi->nd_opt_pi_prefix;
+				if (pi->nd_opt_pi_flags_reserved &
+				    ND_OPT_PI_FLAG_AUTO &&
+				    ap->iface->options->options &
+				    DHCPCD_IPV6RA_AUTOCONF)
+				{
+					ap->flags |= IPV6_AF_AUTOCONF;
+					ap->dadcounter =
+					    ipv6_makeaddr(&ap->addr, ifp,
+					    &ap->prefix,
+					    pi->nd_opt_pi_prefix_len);
+					if (ap->dadcounter == -1) {
+						free(ap);
+						break;
+					}
+					cbp = inet_ntop(AF_INET6,
+					    &ap->addr,
+					    buf, sizeof(buf));
+					if (cbp)
+						snprintf(ap->saddr,
+						    sizeof(ap->saddr),
+						    "%s/%d",
+						    cbp, ap->prefix_len);
+					else
+						ap->saddr[0] = '\0';
+				} else {
+					memset(&ap->addr, 0, sizeof(ap->addr));
+					ap->saddr[0] = '\0';
+				}
+				ap->dadcallback = ipv6nd_dadcallback;
+				ap->created = ap->acquired = rap->received;
+				TAILQ_INSERT_TAIL(&rap->addrs, ap, next);
+
+#ifdef IPV6_MANAGETEMPADDR
+				/* New address to dhcpcd RA handling.
+				 * If the address already exists and a valid
+				 * temporary address also exists then
+				 * extend the existing one rather than
+				 * create a new one */
+				if (ipv6_iffindaddr(ifp, &ap->addr) &&
+				    ipv6_settemptime(ap, 0))
+					new_ap = 0;
+				else
+					new_ap = 1;
+#endif
+			} else {
+#ifdef IPV6_MANAGETEMPADDR
+				new_ap = 0;
+#endif
+				ap->flags &= ~IPV6_AF_STALE;
+				ap->acquired = rap->received;
+			}
+			if (pi->nd_opt_pi_flags_reserved &
+			    ND_OPT_PI_FLAG_ONLINK)
+				ap->flags |= IPV6_AF_ONLINK;
+			ap->prefix_vltime =
+			    ntohl(pi->nd_opt_pi_valid_time);
+			ap->prefix_pltime =
+			    ntohl(pi->nd_opt_pi_preferred_time);
+			ap->nsprobes = 0;
+			cbp = inet_ntop(AF_INET6, &ap->prefix, buf, sizeof(buf));
+			if (cbp) {
+				l = strlen(cbp);
+				opt = malloc(l + 5);
+				if (opt) {
+					snprintf(opt, l + 5, "%s/%d", cbp,
+					    ap->prefix_len);
+					opt2 = strdup(ap->saddr);
+				}
+			}
+
+#ifdef IPV6_MANAGETEMPADDR
+			/* RFC4941 Section 3.3.3 */
+			if (ap->flags & IPV6_AF_AUTOCONF &&
+			    ap->iface->options->options & DHCPCD_IPV6RA_OWN &&
+			    ip6_use_tempaddr(ap->iface->name))
+			{
+				if (!new_ap) {
+					if (ipv6_settemptime(ap, 1) == NULL)
+						new_ap = 1;
+				}
+				if (new_ap && ap->prefix_pltime) {
+					if (ipv6_createtempaddr(ap,
+					    &ap->acquired) == NULL)
+						logger(ap->iface->ctx, LOG_ERR,
+						    "ipv6_createtempaddr: %m");
+				}
+			}
+#endif
+
+			lifetime = ap->prefix_vltime;
+			break;
+
+		case ND_OPT_MTU:
+			mtu = (struct nd_opt_mtu *)(void *)p;
+			mtuv = ntohl(mtu->nd_opt_mtu_mtu);
+			if (mtuv < IPV6_MMTU) {
+				logger(ifp->ctx, LOG_ERR, "%s: invalid MTU %d",
+				    ifp->name, mtuv);
+				break;
+			}
+			rap->mtu = mtuv;
+			snprintf(buf, sizeof(buf), "%d", mtuv);
+			opt = strdup(buf);
+			break;
+
+		case ND_OPT_RDNSS:
+			rdnss = (struct nd_opt_rdnss *)p;
+			lifetime = ntohl(rdnss->nd_opt_rdnss_lifetime);
+			op = (uint8_t *)ndo;
+			op += offsetof(struct nd_opt_rdnss,
+			    nd_opt_rdnss_lifetime);
+			op += sizeof(rdnss->nd_opt_rdnss_lifetime);
+			l = 0;
+			for (n = (size_t)ndo->nd_opt_len - 1; n > 1; n -= 2,
+			    op += sizeof(addr))
+			{
+				r = ipv6_printaddr(NULL, 0, op, ifp->name);
+				if (r != -1)
+					l += (size_t)r + 1;
+			}
+			op = (uint8_t *)ndo;
+			op += offsetof(struct nd_opt_rdnss,
+			    nd_opt_rdnss_lifetime);
+			op += sizeof(rdnss->nd_opt_rdnss_lifetime);
+			tmp = opt = malloc(l);
+			if (opt == NULL)
+				continue;
+			for (n = (size_t)ndo->nd_opt_len - 1; n > 1; n -= 2,
+			    op += sizeof(addr))
+			{
+				r = ipv6_printaddr(tmp, l, op,
+				    ifp->name);
+				if (r != -1) {
+					l -= ((size_t)r + 1);
+					tmp += (size_t)r;
+					*tmp++ = ' ';
+				}
+			}
+			if (tmp != opt)
+				(*--tmp) = '\0';
+			else
+				*opt = '\0';
+			break;
+
+		case ND_OPT_DNSSL:
+			dnssl = (struct nd_opt_dnssl *)p;
+			lifetime = ntohl(dnssl->nd_opt_dnssl_lifetime);
+			op = p + offsetof(struct nd_opt_dnssl,
+			    nd_opt_dnssl_lifetime);
+			op += sizeof(dnssl->nd_opt_dnssl_lifetime);
+			n = (size_t)(dnssl->nd_opt_dnssl_len - 1) * 8;
+			r = decode_rfc3397(NULL, 0, op, n);
+			if (r < 1) {
+				logger(ifp->ctx, new_data ? LOG_ERR : LOG_DEBUG,
+				    "%s: invalid DNSSL option",
+				    ifp->name);
+				continue;
+			} else {
+				l = (size_t)r + 1;
+				tmp = malloc(l);
+				if (tmp) {
+					decode_rfc3397(tmp, l, op, n);
+					l -= 1;
+					n = (size_t)print_string(NULL, 0,
+					    STRING | ARRAY | DOMAIN,
+					    (const uint8_t *)tmp, l);
+					n++;
+					opt = malloc(n);
+					if (opt) {
+						print_string(opt, n,
+						    STRING | ARRAY | DOMAIN,
+						    (const uint8_t *)tmp, l);
+					} else
+						logger(ifp->ctx, LOG_ERR,
+						    "%s: %m", __func__);
+					free(tmp);
+				}
+			}
+			break;
+
+		default:
+			continue;
+		}
+
+		if (opt == NULL) {
+			logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
+			continue;
+		}
+
+		n = ndo->nd_opt_type;
+extra_opt:
+		TAILQ_FOREACH(rao, &rap->options, next) {
+			if (rao->type == n &&
+			    strcmp(rao->option, opt) == 0)
+				break;
+		}
+		if (lifetime == 0 || *opt == '\0') {
+			if (rao) {
+				TAILQ_REMOVE(&rap->options, rao, next);
+				free(rao->option);
+				free(rao);
+			}
+			free(opt);
+			free(opt2);
+			continue;
+		}
+
+		if (rao == NULL) {
+			rao = malloc(sizeof(*rao));
+			if (rao == NULL) {
+				logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
+				continue;
+			}
+			rao->type = (uint16_t)n;
+			rao->option = opt;
+			TAILQ_INSERT_TAIL(&rap->options, rao, next);
+		} else
+			free(opt);
+		if (lifetime == ~0U)
+			timespecclear(&rao->expire);
+		else {
+			expire.tv_sec = (time_t)lifetime;
+			expire.tv_nsec = 0;
+			timespecadd(&rap->received, &expire, &rao->expire);
+		}
+		if (rao && rao->type == ND_OPT_PREFIX_INFORMATION && opt2) {
+			n = _ND_OPT_PREFIX_ADDR;
+			opt = opt2;
+			opt2 = NULL;
+			goto extra_opt;
+		}
+	}
+
+	if (new_rap)
+		add_router(ifp->ctx->ipv6, rap);
+	if (!ipv6nd_ra_has_public_addr(rap) &&
+	    !(rap->iface->options->options & DHCPCD_IPV6RA_ACCEPT_NOPUBLIC) &&
+	    (!(rap->flags & ND_RA_FLAG_MANAGED) ||
+	    !dhcp6_has_public_addr(rap->iface)))
+	{
+		logger(rap->iface->ctx,
+		    rap->no_public_warned ? LOG_DEBUG : LOG_WARNING,
+		    "%s: ignoring RA from %s"
+		    " (no public prefix, no managed address)",
+		    rap->iface->name, rap->sfrom);
+		rap->no_public_warned = 1;
+		return;
+	}
+	if (ifp->ctx->options & DHCPCD_TEST) {
+		script_runreason(ifp, "TEST");
+		goto handle_flag;
+	}
+	ipv6_addaddrs(&rap->addrs);
+#ifdef IPV6_MANAGETEMPADDR
+	ipv6_addtempaddrs(ifp, &rap->received);
+#endif
+
+	/* Find any freshly added routes, such as the subnet route.
+	 * We do this because we cannot rely on recieving the kernel
+	 * notification right now via our link socket. */
+	if_initrt6(ifp);
+
+	ipv6_buildroutes(ifp->ctx);
+	if (ipv6nd_scriptrun(rap))
+		return;
+
+	eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
+	eloop_timeout_delete(ifp->ctx->eloop, NULL, rap); /* reachable timer */
+
+handle_flag:
+	if (!(ifp->options->options & DHCPCD_DHCP6))
+		goto nodhcp6;
+	if (rap->flags & ND_RA_FLAG_MANAGED) {
+		if (new_data && dhcp6_start(ifp, DH6S_INIT) == -1)
+			logger(ifp->ctx, LOG_ERR,
+			    "dhcp6_start: %s: %m", ifp->name);
+	} else if (rap->flags & ND_RA_FLAG_OTHER) {
+		if (new_data && dhcp6_start(ifp, DH6S_INFORM) == -1)
+			logger(ifp->ctx, LOG_ERR,
+			    "dhcp6_start: %s: %m", ifp->name);
+	} else {
+		if (new_data)
+			logger(ifp->ctx, LOG_DEBUG,
+			    "%s: No DHCPv6 instruction in RA", ifp->name);
+nodhcp6:
+		if (ifp->ctx->options & DHCPCD_TEST) {
+			eloop_exit(ifp->ctx->eloop, EXIT_SUCCESS);
+			return;
+		}
+	}
+
+	/* Expire should be called last as the rap object could be destroyed */
+	ipv6nd_expirera(ifp);
+}
+
+/* Run RA's we ignored becuase they had no public addresses
+ * This should only be called when DHCPv6 applies a public address */
+void
+ipv6nd_runignoredra(struct interface *ifp)
+{
+	struct ra *rap;
+
+	TAILQ_FOREACH(rap, ifp->ctx->ipv6->ra_routers, next) {
+		if (rap->iface == ifp &&
+		    !rap->expired &&
+		    rap->no_public_warned)
+		{
+			rap->no_public_warned = 0;
+			logger(rap->iface->ctx, LOG_INFO,
+			    "%s: applying ignored RA from %s",
+			    rap->iface->name, rap->sfrom);
+			if (ifp->ctx->options & DHCPCD_TEST) {
+				script_runreason(ifp, "TEST");
+				continue;
+			}
+			if (ipv6nd_scriptrun(rap))
+				return;
+			eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
+			eloop_timeout_delete(ifp->ctx->eloop, NULL, rap);
+		}
+	}
+}
+
+int
+ipv6nd_hasra(const struct interface *ifp)
+{
+	const struct ra *rap;
+
+	if (ifp->ctx->ipv6) {
+		TAILQ_FOREACH(rap, ifp->ctx->ipv6->ra_routers, next)
+			if (rap->iface == ifp && !rap->expired)
+				return 1;
+	}
+	return 0;
+}
+
+int
+ipv6nd_hasradhcp(const struct interface *ifp)
+{
+	const struct ra *rap;
+
+	if (ifp->ctx->ipv6) {
+		TAILQ_FOREACH(rap, ifp->ctx->ipv6->ra_routers, next) {
+			if (rap->iface == ifp &&
+			    !rap->expired &&
+			    (rap->flags & (ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER)))
+				return 1;
+		}
+	}
+	return 0;
+}
+
+ssize_t
+ipv6nd_env(char **env, const char *prefix, const struct interface *ifp)
+{
+	size_t i, l, len;
+	const struct ra *rap;
+	const struct ra_opt *rao;
+	char buffer[32];
+	const char *optn;
+	char **pref, **addr, **mtu, **rdnss, **dnssl, ***var, *new;
+
+	i = l = 0;
+	TAILQ_FOREACH(rap, ifp->ctx->ipv6->ra_routers, next) {
+		if (rap->iface != ifp)
+			continue;
+		i++;
+		if (env) {
+			snprintf(buffer, sizeof(buffer),
+			    "ra%zu_from", i);
+			setvar(ifp->ctx, &env, prefix, buffer, rap->sfrom);
+		}
+		l++;
+
+		pref = addr = mtu = rdnss = dnssl = NULL;
+		TAILQ_FOREACH(rao, &rap->options, next) {
+			if (rao->option == NULL)
+				continue;
+			var = NULL;
+			switch(rao->type) {
+			case ND_OPT_PREFIX_INFORMATION:
+				optn = "prefix";
+				var = &pref;
+				break;
+			case _ND_OPT_PREFIX_ADDR:
+				optn = "addr";
+				var = &addr;
+				break;
+			case ND_OPT_MTU:
+				optn = "mtu";
+				var = &mtu;
+				break;
+			case ND_OPT_RDNSS:
+				optn = "rdnss";
+				var = &rdnss;
+				break;
+			case ND_OPT_DNSSL:
+				optn = "dnssl";
+				var = &dnssl;
+				break;
+			default:
+				continue;
+			}
+			if (*var == NULL) {
+				*var = env ? env : &new;
+				l++;
+			} else if (env) {
+				/* With single only options, last one takes
+				 * precedence */
+				if (rao->type == ND_OPT_MTU) {
+					new = strchr(**var, '=');
+					if (new == NULL) {
+						logger(ifp->ctx, LOG_ERR,
+						    "new is null");
+						continue;
+					} else
+						new++;
+					len = (size_t)(new - **var) +
+					    strlen(rao->option) + 1;
+					if (len > strlen(**var))
+						new = realloc(**var, len);
+					else
+						new = **var;
+					if (new) {
+						**var = new;
+						new = strchr(**var, '=');
+						if (new) {
+							len -=
+							    (size_t)
+							    (new - **var);
+							strlcpy(new + 1,
+							    rao->option,
+							    len - 1);
+						} else
+							logger(ifp->ctx,
+							    LOG_ERR,
+							    "new is null");
+					}
+					continue;
+				}
+				len = strlen(rao->option) + 1;
+				new = realloc(**var, strlen(**var) + 1 + len);
+				if (new) {
+					**var = new;
+					new += strlen(new);
+					*new++ = ' ';
+					strlcpy(new, rao->option, len);
+				} else
+					logger(ifp->ctx, LOG_ERR,
+					    "%s: %m", __func__);
+				continue;
+			}
+			if (env) {
+				snprintf(buffer, sizeof(buffer),
+				    "ra%zu_%s", i, optn);
+				setvar(ifp->ctx, &env,
+				    prefix, buffer, rao->option);
+			}
+		}
+	}
+
+	if (env)
+		setvard(ifp->ctx, &env, prefix, "ra_count", i);
+	l++;
+	return (ssize_t)l;
+}
+
+void
+ipv6nd_handleifa(struct dhcpcd_ctx *ctx, int cmd, const char *ifname,
+    const struct in6_addr *addr, int flags)
+{
+	struct ra *rap;
+
+	if (ctx->ipv6 == NULL)
+		return;
+	TAILQ_FOREACH(rap, ctx->ipv6->ra_routers, next) {
+		if (strcmp(rap->iface->name, ifname))
+			continue;
+		ipv6_handleifa_addrs(cmd, &rap->addrs, addr, flags);
+	}
+}
+
+void
+ipv6nd_expirera(void *arg)
+{
+	struct interface *ifp;
+	struct ra *rap, *ran;
+	struct ra_opt *rao, *raon;
+	struct timespec now, lt, expire, next;
+	uint8_t expired, valid, validone;
+
+	ifp = arg;
+	get_monotonic(&now);
+	expired = 0;
+	timespecclear(&next);
+
+	validone = 0;
+	TAILQ_FOREACH_SAFE(rap, ifp->ctx->ipv6->ra_routers, next, ran) {
+		if (rap->iface != ifp)
+			continue;
+		valid = 0;
+		if (rap->lifetime) {
+			lt.tv_sec = (time_t)rap->lifetime;
+			lt.tv_nsec = 0;
+			timespecadd(&rap->received, &lt, &expire);
+			if (rap->lifetime == 0 || timespeccmp(&now, &expire, >))
+			{
+				if (!rap->expired) {
+					logger(ifp->ctx, LOG_WARNING,
+					    "%s: %s: router expired",
+					    ifp->name, rap->sfrom);
+					rap->expired = expired = 1;
+					rap->lifetime = 0;
+				}
+			} else {
+				valid = 1;
+				timespecsub(&expire, &now, &lt);
+				if (!timespecisset(&next) ||
+				    timespeccmp(&next, &lt, >))
+					next = lt;
+			}
+		}
+
+		/* Addresses are expired in ipv6_addaddrs
+		 * so that DHCPv6 addresses can be removed also. */
+		TAILQ_FOREACH_SAFE(rao, &rap->options, next, raon) {
+			if (rap->expired) {
+				switch(rao->type) {
+				case ND_OPT_RDNSS: /* FALLTHROUGH */
+				case ND_OPT_DNSSL:
+					/* RFC6018 end of section 5.2 states
+					 * that if tha RA has a lifetime of 0
+					 * then we should expire these
+					 * options */
+					TAILQ_REMOVE(&rap->options, rao, next);
+					expired = 1;
+					free(rao->option);
+					free(rao);
+					continue;
+				}
+			}
+			if (!timespecisset(&rao->expire))
+				continue;
+			if (timespeccmp(&now, &rao->expire, >)) {
+				/* Expired prefixes are logged above */
+				if (rao->type != ND_OPT_PREFIX_INFORMATION)
+					logger(ifp->ctx, LOG_WARNING,
+					    "%s: %s: expired option %d",
+					    ifp->name, rap->sfrom, rao->type);
+				TAILQ_REMOVE(&rap->options, rao, next);
+				expired = 1;
+				free(rao->option);
+				free(rao);
+				continue;
+			}
+			valid = 1;
+			timespecsub(&rao->expire, &now, &lt);
+			if (!timespecisset(&next) || timespeccmp(&next, &lt, >))
+				next = lt;
+		}
+
+		/* No valid lifetimes are left on the RA, so we might
+		 * as well punt it. */
+		if (!valid && TAILQ_FIRST(&rap->addrs) == NULL)
+			ipv6nd_free_ra(rap);
+		else
+			validone = 1;
+	}
+
+	if (timespecisset(&next))
+		eloop_timeout_add_tv(ifp->ctx->eloop,
+		    &next, ipv6nd_expirera, ifp);
+	if (expired) {
+		ipv6_buildroutes(ifp->ctx);
+		script_runreason(ifp, "ROUTERADVERT");
+	}
+
+	/* No valid routers? Kill any DHCPv6. */
+	if (!validone)
+		dhcp6_drop(ifp, "EXPIRE6");
+}
+
+void
+ipv6nd_drop(struct interface *ifp)
+{
+	struct ra *rap;
+	uint8_t expired = 0;
+	TAILQ_HEAD(rahead, ra) rtrs;
+
+	if (ifp->ctx->ipv6 == NULL)
+		return;
+
+	eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
+	TAILQ_INIT(&rtrs);
+	TAILQ_FOREACH(rap, ifp->ctx->ipv6->ra_routers, next) {
+		if (rap->iface == ifp) {
+			rap->expired = expired = 1;
+			TAILQ_REMOVE(ifp->ctx->ipv6->ra_routers, rap, next);
+			TAILQ_INSERT_TAIL(&rtrs, rap, next);
+		}
+	}
+	if (expired) {
+		while ((rap = TAILQ_FIRST(&rtrs))) {
+			TAILQ_REMOVE(&rtrs, rap, next);
+			ipv6nd_drop_ra(rap);
+		}
+		ipv6_buildroutes(ifp->ctx);
+		if ((ifp->options->options &
+		    (DHCPCD_EXITING | DHCPCD_PERSISTENT)) !=
+		    (DHCPCD_EXITING | DHCPCD_PERSISTENT))
+			script_runreason(ifp, "ROUTERADVERT");
+	}
+}
+
+static void
+ipv6nd_handlena(struct dhcpcd_ctx *dctx, struct interface *ifp,
+    struct icmp6_hdr *icp, size_t len)
+{
+	struct ipv6_ctx *ctx = dctx->ipv6;
+	struct nd_neighbor_advert *nd_na;
+	struct ra *rap;
+	uint32_t is_router, is_solicited;
+	char buf[INET6_ADDRSTRLEN];
+	const char *taddr;
+
+	if (ifp == NULL) {
+#ifdef DEBUG_NS
+		logger(ctx, LOG_DEBUG, "NA for unexpected interface from %s",
+		    dctx->sfrom);
+#endif
+		return;
+	}
+
+	if ((size_t)len < sizeof(struct nd_neighbor_advert)) {
+		logger(ifp->ctx, LOG_ERR, "%s: IPv6 NA too short from %s",
+		    ifp->name, ctx->sfrom);
+		return;
+	}
+
+	nd_na = (struct nd_neighbor_advert *)icp;
+	is_router = nd_na->nd_na_flags_reserved & ND_NA_FLAG_ROUTER;
+	is_solicited = nd_na->nd_na_flags_reserved & ND_NA_FLAG_SOLICITED;
+	taddr = inet_ntop(AF_INET6, &nd_na->nd_na_target,
+	    buf, INET6_ADDRSTRLEN);
+
+	if (IN6_IS_ADDR_MULTICAST(&nd_na->nd_na_target)) {
+		logger(ifp->ctx, LOG_ERR, "%s: NA multicast address %s (%s)",
+		    ifp->name, taddr, ctx->sfrom);
+		return;
+	}
+
+	TAILQ_FOREACH(rap, ctx->ra_routers, next) {
+		if (rap->iface == ifp &&
+		    IN6_ARE_ADDR_EQUAL(&rap->from, &nd_na->nd_na_target))
+			break;
+	}
+	if (rap == NULL) {
+#ifdef DEBUG_NS
+		logger(ifp->ctx, LOG_DEBUG, "%s: unexpected NA from %s for %s",
+		    ifp->name, ctx->sfrom, taddr);
+#endif
+		return;
+	}
+
+#ifdef DEBUG_NS
+	logger(ifp->ctx, LOG_DEBUG, "%s: %sNA for %s from %s",
+	    ifp->name, is_solicited ? "solicited " : "", taddr, ctx->sfrom);
+#endif
+
+	/* Node is no longer a router, so remove it from consideration */
+	if (!is_router && !rap->expired) {
+		logger(ifp->ctx, LOG_INFO, "%s: %s not a router (%s)",
+		    ifp->name, taddr, ctx->sfrom);
+		rap->expired = 1;
+		ipv6_buildroutes(ifp->ctx);
+		script_runreason(ifp, "ROUTERADVERT");
+		return;
+	}
+
+	if (is_solicited && is_router && rap->lifetime) {
+		if (rap->expired) {
+			rap->expired = 0;
+			logger(ifp->ctx, LOG_INFO, "%s: %s reachable (%s)",
+			    ifp->name, taddr, ctx->sfrom);
+			ipv6_buildroutes(ifp->ctx);
+			script_runreason(rap->iface, "ROUTERADVERT"); /* XXX */
+		}
+	}
+}
+
+static void
+ipv6nd_handledata(void *arg)
+{
+	struct dhcpcd_ctx *dctx;
+	struct ipv6_ctx *ctx;
+	ssize_t len;
+	struct cmsghdr *cm;
+	int hoplimit;
+	struct in6_pktinfo pkt;
+	struct icmp6_hdr *icp;
+	struct interface *ifp;
+
+	dctx = arg;
+	ctx = dctx->ipv6;
+	ctx->rcvhdr.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo)) +
+	    CMSG_SPACE(sizeof(int));
+	len = recvmsg(ctx->nd_fd, &ctx->rcvhdr, 0);
+	if (len == -1) {
+		logger(dctx, LOG_ERR, "recvmsg: %m");
+		eloop_event_delete(dctx->eloop, ctx->nd_fd, 0);
+		close(ctx->nd_fd);
+		ctx->nd_fd = -1;
+		return;
+	}
+	ctx->sfrom = inet_ntop(AF_INET6, &ctx->from.sin6_addr,
+	    ctx->ntopbuf, INET6_ADDRSTRLEN);
+	if ((size_t)len < sizeof(struct icmp6_hdr)) {
+		logger(dctx, LOG_ERR, "IPv6 ICMP packet too short from %s",
+		    ctx->sfrom);
+		return;
+	}
+
+	pkt.ipi6_ifindex = 0;
+	hoplimit = 0;
+	for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&ctx->rcvhdr);
+	     cm;
+	     cm = (struct cmsghdr *)CMSG_NXTHDR(&ctx->rcvhdr, cm))
+	{
+		if (cm->cmsg_level != IPPROTO_IPV6)
+			continue;
+		switch(cm->cmsg_type) {
+		case IPV6_PKTINFO:
+			if (cm->cmsg_len == CMSG_LEN(sizeof(pkt)))
+				memcpy(&pkt, CMSG_DATA(cm), sizeof(pkt));
+			break;
+		case IPV6_HOPLIMIT:
+			if (cm->cmsg_len == CMSG_LEN(sizeof(int)))
+				memcpy(&hoplimit, CMSG_DATA(cm), sizeof(int));
+			break;
+		}
+	}
+
+	if (pkt.ipi6_ifindex == 0 || hoplimit == 0) {
+		logger(dctx, LOG_ERR,
+		    "IPv6 RA/NA did not contain index or hop limit from %s",
+		    ctx->sfrom);
+		return;
+	}
+
+	TAILQ_FOREACH(ifp, dctx->ifaces, next) {
+		if (ifp->index == (unsigned int)pkt.ipi6_ifindex &&
+		    !(ifp->options->options & DHCPCD_PFXDLGONLY))
+		{
+			if (!(ifp->options->options & DHCPCD_IPV6))
+				return;
+			break;
+		}
+	}
+
+	icp = (struct icmp6_hdr *)ctx->rcvhdr.msg_iov[0].iov_base;
+	if (icp->icmp6_code == 0) {
+		switch(icp->icmp6_type) {
+			case ND_NEIGHBOR_ADVERT:
+				ipv6nd_handlena(dctx, ifp, icp, (size_t)len);
+				return;
+			case ND_ROUTER_ADVERT:
+				ipv6nd_handlera(dctx, ifp, icp, (size_t)len);
+				return;
+		}
+	}
+
+	logger(dctx, LOG_ERR, "invalid IPv6 type %d or code %d from %s",
+	    icp->icmp6_type, icp->icmp6_code, ctx->sfrom);
+}
+
+static void
+ipv6nd_startrs1(void *arg)
+{
+	struct interface *ifp = arg;
+	struct rs_state *state;
+
+	logger(ifp->ctx, LOG_INFO, "%s: soliciting an IPv6 router", ifp->name);
+	if (ipv6nd_open(ifp->ctx) == -1) {
+		logger(ifp->ctx, LOG_ERR, "%s: ipv6nd_open: %m", __func__);
+		return;
+	}
+
+	state = RS_STATE(ifp);
+	if (state == NULL) {
+		ifp->if_data[IF_DATA_IPV6ND] = calloc(1, sizeof(*state));
+		state = RS_STATE(ifp);
+		if (state == NULL) {
+			logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
+			return;
+		}
+	}
+
+	/* Always make a new probe as the underlying hardware
+	 * address could have changed. */
+	ipv6nd_makersprobe(ifp);
+	if (state->rs == NULL) {
+		logger(ifp->ctx, LOG_ERR,
+		    "%s: ipv6ns_makersprobe: %m", __func__);
+		return;
+	}
+
+	state->rsprobes = 0;
+	ipv6nd_sendrsprobe(ifp);
+}
+
+void
+ipv6nd_startrs(struct interface *ifp)
+{
+	struct timespec tv;
+
+	eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
+	tv.tv_sec = 0;
+	tv.tv_nsec = (suseconds_t)arc4random_uniform(
+	    MAX_RTR_SOLICITATION_DELAY * NSEC_PER_SEC);
+	timespecnorm(&tv);
+	logger(ifp->ctx, LOG_DEBUG,
+	    "%s: delaying IPv6 router solicitation for %0.1f seconds",
+	    ifp->name, timespec_to_double(&tv));
+	eloop_timeout_add_tv(ifp->ctx->eloop, &tv, ipv6nd_startrs1, ifp);
+	return;
+}
diff --git a/dhcpcd-6.8.2/ipv6nd.h b/dhcpcd-6.8.2/ipv6nd.h
new file mode 100644
index 0000000..2ab76df
--- /dev/null
+++ b/dhcpcd-6.8.2/ipv6nd.h
@@ -0,0 +1,121 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef IPV6ND_H
+#define IPV6ND_H
+
+#include <time.h>
+
+#include "config.h"
+#include "dhcpcd.h"
+#include "ipv6.h"
+
+struct ra_opt {
+	TAILQ_ENTRY(ra_opt) next;
+	uint16_t type;
+	struct timespec expire;
+	char *option;
+};
+
+struct ra {
+	TAILQ_ENTRY(ra) next;
+	struct interface *iface;
+	struct in6_addr from;
+	char sfrom[INET6_ADDRSTRLEN];
+	unsigned char *data;
+	size_t data_len;
+	struct timespec received;
+	unsigned char flags;
+	uint32_t lifetime;
+	uint32_t reachable;
+	uint32_t retrans;
+	uint32_t mtu;
+	struct ipv6_addrhead addrs;
+	TAILQ_HEAD(, ra_opt) options;
+	uint8_t expired;
+	uint8_t no_public_warned;
+};
+
+TAILQ_HEAD(ra_head, ra);
+
+struct rs_state {
+	unsigned char *rs;
+	size_t rslen;
+	int rsprobes;
+};
+
+#define RS_STATE(a) ((struct rs_state *)(ifp)->if_data[IF_DATA_IPV6ND])
+#define RS_STATE_RUNNING(a) (ipv6nd_hasra((a)) && ipv6nd_dadcompleted((a)))
+
+#define MAX_RTR_SOLICITATION_DELAY	1	/* seconds */
+#define MAX_UNICAST_SOLICIT		3	/* 3 transmissions */
+#define RTR_SOLICITATION_INTERVAL	4	/* seconds */
+#define MAX_RTR_SOLICITATIONS		3	/* times */
+
+/* On carrier up, expire known routers after RTR_CARRIER_EXPIRE seconds. */
+#define RTR_CARRIER_EXPIRE		\
+    (MAX_RTR_SOLICITATION_DELAY +	\
+    (MAX_RTR_SOLICITATIONS + 1) *	\
+    RTR_SOLICITATION_INTERVAL)
+
+#define MAX_REACHABLE_TIME		3600000	/* milliseconds */
+#define REACHABLE_TIME			30000	/* milliseconds */
+#define RETRANS_TIMER			1000	/* milliseconds */
+#define DELAY_FIRST_PROBE_TIME		5	/* seconds */
+
+#define IPV6ND_REACHABLE		(1 << 0)
+#define IPV6ND_ROUTER			(1 << 1)
+
+#ifdef INET6
+void ipv6nd_startrs(struct interface *);
+ssize_t ipv6nd_env(char **, const char *, const struct interface *);
+struct ipv6_addr *ipv6nd_findaddr(struct dhcpcd_ctx *,
+    const struct in6_addr *, short);
+void ipv6nd_freedrop_ra(struct ra *, int);
+#define ipv6nd_free_ra(ra) ipv6nd_freedrop_ra((ra),  0)
+#define ipv6nd_drop_ra(ra) ipv6nd_freedrop_ra((ra),  1)
+ssize_t ipv6nd_free(struct interface *);
+void ipv6nd_expirera(void *arg);
+int ipv6nd_hasra(const struct interface *);
+int ipv6nd_hasradhcp(const struct interface *);
+void ipv6nd_runignoredra(struct interface *);
+void ipv6nd_handleifa(struct dhcpcd_ctx *, int,
+    const char *, const struct in6_addr *, int);
+int ipv6nd_dadcompleted(const struct interface *);
+void ipv6nd_expire(struct interface *, uint32_t);
+void ipv6nd_drop(struct interface *);
+void ipv6nd_neighbour(struct dhcpcd_ctx *, struct in6_addr *, int);
+#else
+#define ipv6nd_startrs(a) {}
+#define ipv6nd_findaddr(a, b, c) (0)
+#define ipv6nd_free(a) {}
+#define ipv6nd_hasra(a) (0)
+#define ipv6nd_dadcompleted(a) (0)
+#define ipv6nd_drop(a) {}
+#endif
+
+#endif
diff --git a/dhcpcd-6.8.2/rpc-interface.h b/dhcpcd-6.8.2/rpc-interface.h
new file mode 100644
index 0000000..cf4da46
--- /dev/null
+++ b/dhcpcd-6.8.2/rpc-interface.h
@@ -0,0 +1,53 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef RPC_INTERFACE_H
+#define RPC_INTERFACE_H
+
+#include "dhcpcd.h"
+
+/* Initialize RPC interface. Return 0 on success. */
+int rpc_init(struct dhcpcd_ctx *ctx);
+
+/* Tear down RPC interface. */
+void rpc_close(void);
+
+/* Emit signal status to RPC interface. */
+void rpc_signal_status(const char *);
+
+/* Update IPv4 configuration. Return 0 on success. */
+int rpc_update_ipv4(struct interface *ifp);
+
+#ifdef INET6
+/* Update IPv6 configuration. Return 0 on success. */
+int rpc_update_ipv6(struct interface *ifp);
+#endif
+
+/* Emit notification for successful unicast ARP. Return 0 on success. */
+int rpc_notify_unicast_arp(struct interface *ifp);
+
+#endif
diff --git a/dhcpcd-6.8.2/rpc-stub.c b/dhcpcd-6.8.2/rpc-stub.c
new file mode 100644
index 0000000..e2b4ed9
--- /dev/null
+++ b/dhcpcd-6.8.2/rpc-stub.c
@@ -0,0 +1,71 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "rpc-interface.h"
+
+int
+rpc_init(struct dhcpcd_ctx *ctx)
+{
+	/* Stub implementation. */
+	return 0;
+}
+
+void
+rpc_close(void)
+{
+	/* Stub implementation. */
+}
+
+void
+rpc_signal_status(const char *reason)
+{
+	/* Stub implementation. */
+}
+
+int
+rpc_update_ipv4(struct interface *ifp)
+{
+	/* Stub implementation. */
+	return 0;
+}
+
+#ifdef INET6
+int
+rpc_update_ipv6(struct interface *ifp)
+{
+	/* Stub implementation. */
+	return 0;
+}
+#endif
+
+int
+rpc_notify_unicast_arp(struct interface *ifp)
+{
+	/* Stub implementation. */
+	return 0;
+}
+
diff --git a/dhcpcd-6.8.2/script-stub.c b/dhcpcd-6.8.2/script-stub.c
new file mode 100644
index 0000000..ed2a474
--- /dev/null
+++ b/dhcpcd-6.8.2/script-stub.c
@@ -0,0 +1,49 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "common.h"
+#include "script.h"
+
+void
+if_printoptions(void)
+{
+	/* Stub implementation. */
+}
+
+int
+send_interface(struct fd_list *fd, const struct interface *ifp)
+{
+	/* Stub implementation. */
+	return 0;
+}
+
+int
+script_runreason(const struct interface *ifp, const char *reason)
+{
+	/* Stub implementation. */
+	return 0;
+}
diff --git a/dhcpcd-6.8.2/script.c b/dhcpcd-6.8.2/script.c
new file mode 100644
index 0000000..918f700
--- /dev/null
+++ b/dhcpcd-6.8.2/script.c
@@ -0,0 +1,735 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/stat.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <signal.h>
+/* We can't include spawn.h here because it may not exist.
+ * config.h will pull it in, or our compat one. */
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "config.h"
+#include "common.h"
+#include "dhcp.h"
+#include "dhcp6.h"
+#include "if.h"
+#include "if-options.h"
+#include "ipv6nd.h"
+#include "script.h"
+
+#ifdef HAVE_SPAWN_H
+#include <spawn.h>
+#else
+#include "compat/posix_spawn.h"
+#endif
+
+/* Allow the OS to define another script env var name */
+#ifndef RC_SVCNAME
+#define RC_SVCNAME "RC_SVCNAME"
+#endif
+
+#define DEFAULT_PATH	"PATH=/usr/bin:/usr/sbin:/bin:/sbin"
+
+static const char * const if_params[] = {
+	"interface",
+	"reason",
+	"pid",
+	"ifcarrier",
+	"ifmetric",
+	"ifwireless",
+	"ifflags",
+	"ssid",
+	"profile",
+	"interface_order",
+	NULL
+};
+
+void
+if_printoptions(void)
+{
+	const char * const *p;
+
+	for (p = if_params; *p; p++)
+		printf(" -  %s\n", *p);
+}
+
+static int
+exec_script(const struct dhcpcd_ctx *ctx, char *const *argv, char *const *env)
+{
+	pid_t pid;
+	posix_spawnattr_t attr;
+	int i;
+#ifdef USE_SIGNALS
+	short flags;
+	sigset_t defsigs;
+#else
+	UNUSED(ctx);
+#endif
+
+	/* posix_spawn is a safe way of executing another image
+	 * and changing signals back to how they should be. */
+	if (posix_spawnattr_init(&attr) == -1)
+		return -1;
+#ifdef USE_SIGNALS
+	flags = POSIX_SPAWN_SETSIGMASK | POSIX_SPAWN_SETSIGDEF;
+	posix_spawnattr_setflags(&attr, flags);
+	sigemptyset(&defsigs);
+	for (i = 0; dhcpcd_handlesigs[i]; i++)
+		sigaddset(&defsigs, dhcpcd_handlesigs[i]);
+	posix_spawnattr_setsigdefault(&attr, &defsigs);
+	posix_spawnattr_setsigmask(&attr, &ctx->sigset);
+#endif
+	errno = 0;
+	i = posix_spawn(&pid, argv[0], NULL, &attr, argv, env);
+	if (i) {
+		errno = i;
+		return -1;
+	}
+	return pid;
+}
+
+#ifdef INET
+static char *
+make_var(struct dhcpcd_ctx *ctx, const char *prefix, const char *var)
+{
+	size_t len;
+	char *v;
+
+	len = strlen(prefix) + strlen(var) + 2;
+	v = malloc(len);
+	if (v == NULL) {
+		logger(ctx, LOG_ERR, "%s: %m", __func__);
+		return NULL;
+	}
+	snprintf(v, len, "%s_%s", prefix, var);
+	return v;
+}
+
+
+static int
+append_config(struct dhcpcd_ctx *ctx, char ***env, size_t *len,
+    const char *prefix, const char *const *config)
+{
+	size_t i, j, e1;
+	char **ne, *eq, **nep, *p;
+	int ret;
+
+	if (config == NULL)
+		return 0;
+
+	ne = *env;
+	ret = 0;
+	for (i = 0; config[i] != NULL; i++) {
+		eq = strchr(config[i], '=');
+		e1 = (size_t)(eq - config[i] + 1);
+		for (j = 0; j < *len; j++) {
+			if (strncmp(ne[j] + strlen(prefix) + 1,
+				config[i], e1) == 0)
+			{
+				p = make_var(ctx, prefix, config[i]);
+				if (p == NULL) {
+					ret = -1;
+					break;
+				}
+				free(ne[j]);
+				ne[j] = p;
+				break;
+			}
+		}
+		if (j == *len) {
+			j++;
+			p = make_var(ctx, prefix, config[i]);
+			if (p == NULL) {
+				ret = -1;
+				break;
+			}
+			nep = realloc(ne, sizeof(char *) * (j + 1));
+			if (nep == NULL) {
+				logger(ctx, LOG_ERR, "%s: %m", __func__);
+				free(p);
+				ret = -1;
+				break;
+			}
+			ne = nep;
+			ne[j - 1] = p;
+			*len = j;
+		}
+	}
+	*env = ne;
+	return ret;
+}
+#endif
+
+static ssize_t
+arraytostr(const char *const *argv, char **s)
+{
+	const char *const *ap;
+	char *p;
+	size_t len, l;
+
+	if (*argv == NULL)
+		return 0;
+	len = 0;
+	ap = argv;
+	while (*ap)
+		len += strlen(*ap++) + 1;
+	*s = p = malloc(len);
+	if (p == NULL)
+		return -1;
+	ap = argv;
+	while (*ap) {
+		l = strlen(*ap) + 1;
+		memcpy(p, *ap, l);
+		p += l;
+		ap++;
+	}
+	return (ssize_t)len;
+}
+
+static ssize_t
+make_env(const struct interface *ifp, const char *reason, char ***argv)
+{
+	char **env, **nenv, *p;
+	size_t e, elen, l;
+#if defined(INET) || defined(INET6)
+	ssize_t n;
+#endif
+	const struct if_options *ifo = ifp->options;
+	const struct interface *ifp2;
+#ifdef INET
+	int dhcp;
+	const struct dhcp_state *state;
+#endif
+#ifdef INET6
+	const struct dhcp6_state *d6_state;
+	int dhcp6, ra;
+#endif
+
+#ifdef INET
+	dhcp = 0;
+	state = D_STATE(ifp);
+#endif
+#ifdef INET6
+	dhcp6 = ra = 0;
+	d6_state = D6_CSTATE(ifp);
+#endif
+	if (strcmp(reason, "TEST") == 0) {
+		if (1 == 2) {}
+#ifdef INET6
+		else if (d6_state && d6_state->new)
+			dhcp6 = 1;
+		else if (ipv6nd_hasra(ifp))
+			ra = 1;
+#endif
+#ifdef INET
+		else
+			dhcp = 1;
+#endif
+	}
+#ifdef INET6
+	else if (reason[strlen(reason) - 1] == '6')
+		dhcp6 = 1;
+	else if (strcmp(reason, "ROUTERADVERT") == 0)
+		ra = 1;
+#endif
+	else if (strcmp(reason, "PREINIT") == 0 ||
+	    strcmp(reason, "CARRIER") == 0 ||
+	    strcmp(reason, "NOCARRIER") == 0 ||
+	    strcmp(reason, "UNKNOWN") == 0 ||
+	    strcmp(reason, "DEPARTED") == 0 ||
+	    strcmp(reason, "STOPPED") == 0)
+	{
+		/* This space left intentionally blank */
+	}
+#ifdef INET
+	else
+		dhcp = 1;
+#endif
+
+	/* When dumping the lease, we only want to report interface and
+	   reason - the other interface variables are meaningless */
+	if (ifp->ctx->options & DHCPCD_DUMPLEASE)
+		elen = 2;
+	else
+		elen = 13;
+
+#define EMALLOC(i, l) if ((env[(i)] = malloc((l))) == NULL) goto eexit;
+	/* Make our env + space for profile, wireless and debug */
+	env = calloc(1, sizeof(char *) * (elen + 3 + 1));
+	if (env == NULL)
+		goto eexit;
+	e = strlen("interface") + strlen(ifp->name) + 2;
+	EMALLOC(0, e);
+	snprintf(env[0], e, "interface=%s", ifp->name);
+	e = strlen("reason") + strlen(reason) + 2;
+	EMALLOC(1, e);
+	snprintf(env[1], e, "reason=%s", reason);
+	if (ifp->ctx->options & DHCPCD_DUMPLEASE)
+		goto dumplease;
+	e = 20;
+	EMALLOC(2, e);
+	snprintf(env[2], e, "pid=%d", getpid());
+	EMALLOC(3, e);
+	snprintf(env[3], e, "ifcarrier=%s",
+	    ifp->carrier == LINK_UNKNOWN ? "unknown" :
+	    ifp->carrier == LINK_UP ? "up" : "down");
+	EMALLOC(4, e);
+	snprintf(env[4], e, "ifmetric=%d", ifp->metric);
+	EMALLOC(5, e);
+	snprintf(env[5], e, "ifwireless=%d", ifp->wireless);
+	EMALLOC(6, e);
+	snprintf(env[6], e, "ifflags=%u", ifp->flags);
+	EMALLOC(7, e);
+	snprintf(env[7], e, "ifmtu=%d", if_getmtu(ifp->name));
+	l = e = strlen("interface_order=");
+	TAILQ_FOREACH(ifp2, ifp->ctx->ifaces, next) {
+		if (!(ifp2->options->options & DHCPCD_PFXDLGONLY))
+			e += strlen(ifp2->name) + 1;
+	}
+	EMALLOC(8, e);
+	p = env[8];
+	strlcpy(p, "interface_order=", e);
+	e -= l;
+	p += l;
+	TAILQ_FOREACH(ifp2, ifp->ctx->ifaces, next) {
+		if (!(ifp2->options->options & DHCPCD_PFXDLGONLY)) {
+			l = strlcpy(p, ifp2->name, e);
+			p += l;
+			e -= l;
+			*p++ = ' ';
+			e--;
+		}
+	}
+	*--p = '\0';
+	if (strcmp(reason, "STOPPED") == 0) {
+		env[9] = strdup("if_up=false");
+		if (ifo->options & DHCPCD_RELEASE)
+			env[10] = strdup("if_down=true");
+		else
+			env[10] = strdup("if_down=false");
+	} else 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 */
+#ifdef INET
+	    || (dhcp && state && state->new)
+#endif
+#ifdef INET6
+	    || (dhcp6 && d6_state && d6_state->new)
+	    || (ra && ipv6nd_hasra(ifp))
+#endif
+	    )
+	{
+		env[9] = strdup("if_up=true");
+		env[10] = strdup("if_down=false");
+	} else {
+		env[9] = strdup("if_up=false");
+		env[10] = strdup("if_down=true");
+	}
+	if (env[9] == NULL || env[10] == NULL)
+		goto eexit;
+	if (dhcpcd_oneup(ifp->ctx))
+		env[11] = strdup("if_oneup=true");
+	else
+		env[11] = strdup("if_oneup=false");
+	if (env[11] == NULL)
+		goto eexit;
+	if (dhcpcd_ipwaited(ifp->ctx))
+		env[12] = strdup("if_ipwaited=true");
+	else
+		env[12] = strdup("if_ipwaited=false");
+	if (env[12] == NULL)
+		goto eexit;
+	if (ifo->options & DHCPCD_DEBUG) {
+		e = strlen("syslog_debug=true") + 1;
+		EMALLOC(elen, e);
+		snprintf(env[elen++], e, "syslog_debug=true");
+	}
+	if (*ifp->profile) {
+		e = strlen("profile=") + strlen(ifp->profile) + 1;
+		EMALLOC(elen, e);
+		snprintf(env[elen++], e, "profile=%s", ifp->profile);
+	}
+	if (ifp->wireless) {
+		static const char *pfx = "ifssid=";
+		size_t pfx_len;
+		ssize_t psl;
+
+		pfx_len = strlen(pfx);
+		psl = print_string(NULL, 0, ESCSTRING,
+		    (const uint8_t *)ifp->ssid, ifp->ssid_len);
+		if (psl != -1) {
+			EMALLOC(elen, pfx_len + (size_t)psl + 1);
+			memcpy(env[elen], pfx, pfx_len);
+			print_string(env[elen] + pfx_len, (size_t)psl + 1,
+			    ESCSTRING,
+			    (const uint8_t *)ifp->ssid, ifp->ssid_len);
+			elen++;
+		}
+	}
+#ifdef INET
+	if (dhcp && state && state->old) {
+		n = dhcp_env(NULL, NULL, state->old, ifp);
+		if (n == -1)
+			goto eexit;
+		if (n > 0) {
+			nenv = realloc(env, sizeof(char *) *
+			    (elen + (size_t)n + 1));
+			if (nenv == NULL)
+				goto eexit;
+			env = nenv;
+			n = dhcp_env(env + elen, "old", state->old, ifp);
+			if (n == -1)
+				goto eexit;
+			elen += (size_t)n;
+		}
+		if (append_config(ifp->ctx, &env, &elen, "old",
+		    (const char *const *)ifo->config) == -1)
+			goto eexit;
+	}
+#endif
+#ifdef INET6
+	if (dhcp6 && d6_state && ifo->options & DHCPCD_PFXDLGONLY) {
+		nenv = realloc(env, sizeof(char *) * (elen + 2));
+		if (nenv == NULL)
+			goto eexit;
+		env = nenv;
+		env[elen] = strdup("ifclass=pd");
+		if (env[elen] == NULL)
+			goto eexit;
+		elen++;
+	}
+	if (dhcp6 && d6_state && d6_state->old) {
+		n = dhcp6_env(NULL, NULL, ifp,
+		    d6_state->old, d6_state->old_len);
+		if (n > 0) {
+			nenv = realloc(env, sizeof(char *) *
+			    (elen + (size_t)n + 1));
+			if (nenv == NULL)
+				goto eexit;
+			env = nenv;
+			n = dhcp6_env(env + elen, "old", ifp,
+			    d6_state->old, d6_state->old_len);
+			if (n == -1)
+				goto eexit;
+			elen += (size_t)n;
+		}
+	}
+#endif
+
+dumplease:
+#ifdef INET
+	if (dhcp && state && state->new) {
+		n = dhcp_env(NULL, NULL, state->new, ifp);
+		if (n > 0) {
+			nenv = realloc(env, sizeof(char *) *
+			    (elen + (size_t)n + 1));
+			if (nenv == NULL)
+				goto eexit;
+			env = nenv;
+			n = dhcp_env(env + elen, "new",
+			    state->new, ifp);
+			if (n == -1)
+				goto eexit;
+			elen += (size_t)n;
+		}
+		if (append_config(ifp->ctx, &env, &elen, "new",
+		    (const char *const *)ifo->config) == -1)
+			goto eexit;
+	}
+#endif
+#ifdef INET6
+	if (dhcp6 && D6_STATE_RUNNING(ifp)) {
+		n = dhcp6_env(NULL, NULL, ifp,
+		    d6_state->new, d6_state->new_len);
+		if (n > 0) {
+			nenv = realloc(env, sizeof(char *) *
+			    (elen + (size_t)n + 1));
+			if (nenv == NULL)
+				goto eexit;
+			env = nenv;
+			n = dhcp6_env(env + elen, "new", ifp,
+			    d6_state->new, d6_state->new_len);
+			if (n == -1)
+				goto eexit;
+			elen += (size_t)n;
+		}
+	}
+	if (ra) {
+		n = ipv6nd_env(NULL, NULL, ifp);
+		if (n > 0) {
+			nenv = realloc(env, sizeof(char *) *
+			    (elen + (size_t)n + 1));
+			if (nenv == NULL)
+				goto eexit;
+			env = nenv;
+			n = ipv6nd_env(env + elen, NULL, ifp);
+			if (n == -1)
+				goto eexit;
+			elen += (size_t)n;
+		}
+	}
+#endif
+
+	/* Add our base environment */
+	if (ifo->environ) {
+		e = 0;
+		while (ifo->environ[e++])
+			;
+		nenv = realloc(env, sizeof(char *) * (elen + e + 1));
+		if (nenv == NULL)
+			goto eexit;
+		env = nenv;
+		e = 0;
+		while (ifo->environ[e]) {
+			env[elen + e] = strdup(ifo->environ[e]);
+			if (env[elen + e] == NULL)
+				goto eexit;
+			e++;
+		}
+		elen += e;
+	}
+	env[elen] = NULL;
+
+	*argv = env;
+	return (ssize_t)elen;
+
+eexit:
+	logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
+	if (env) {
+		nenv = env;
+		while (*nenv)
+			free(*nenv++);
+		free(env);
+	}
+	return -1;
+}
+
+static int
+send_interface1(struct fd_list *fd, const struct interface *iface,
+    const char *reason)
+{
+	char **env, **ep, *s;
+	size_t elen;
+	int retval;
+
+	if (make_env(iface, reason, &env) == -1)
+		return -1;
+	s = NULL;
+	elen = (size_t)arraytostr((const char *const *)env, &s);
+	if ((ssize_t)elen == -1) {
+		free(s);
+		return -1;
+	}
+	retval = control_queue(fd, s, elen, 1);
+	ep = env;
+	while (*ep)
+		free(*ep++);
+	free(env);
+	return retval;
+}
+
+int
+send_interface(struct fd_list *fd, const struct interface *ifp)
+{
+	const char *reason;
+	int retval = 0;
+#ifdef INET
+	const struct dhcp_state *d;
+#endif
+#ifdef INET6
+	const struct dhcp6_state *d6;
+#endif
+
+	switch (ifp->carrier) {
+	case LINK_UP:
+		reason = "CARRIER";
+		break;
+	case LINK_DOWN:
+		reason = "NOCARRIER";
+		break;
+	default:
+		reason = "UNKNOWN";
+		break;
+	}
+	if (send_interface1(fd, ifp, reason) == -1)
+		retval = -1;
+#ifdef INET
+	if (D_STATE_RUNNING(ifp)) {
+		d = D_CSTATE(ifp);
+		if (send_interface1(fd, ifp, d->reason) == -1)
+			retval = -1;
+	}
+#endif
+
+#ifdef INET6
+	if (RS_STATE_RUNNING(ifp)) {
+		if (send_interface1(fd, ifp, "ROUTERADVERT") == -1)
+			retval = -1;
+	}
+	if (D6_STATE_RUNNING(ifp)) {
+		d6 = D6_CSTATE(ifp);
+		if (send_interface1(fd, ifp, d6->reason) == -1)
+			retval = -1;
+	}
+#endif
+
+	return retval;
+}
+
+int
+script_runreason(const struct interface *ifp, const char *reason)
+{
+	char *argv[2];
+	char **env = NULL, **ep;
+	char *svcname, *path, *bigenv;
+	size_t e, elen = 0;
+	pid_t pid;
+	int status = 0;
+	struct fd_list *fd;
+
+	if (ifp->options->script &&
+	    (ifp->options->script[0] == '\0' ||
+	    strcmp(ifp->options->script, "/dev/null") == 0))
+		return 0;
+
+	argv[0] = ifp->options->script ? ifp->options->script : UNCONST(SCRIPT);
+	argv[1] = NULL;
+	logger(ifp->ctx, LOG_DEBUG, "%s: executing `%s' %s",
+	    ifp->name, argv[0], reason);
+
+	/* Make our env */
+	elen = (size_t)make_env(ifp, reason, &env);
+	if (elen == (size_t)-1) {
+		logger(ifp->ctx, LOG_ERR, "%s: make_env: %m", ifp->name);
+		return -1;
+	}
+	/* Resize for PATH and RC_SVCNAME */
+	svcname = getenv(RC_SVCNAME);
+	ep = realloc(env, sizeof(char *) * (elen + 2 + (svcname ? 1 : 0)));
+	if (ep == NULL) {
+		elen = 0;
+		goto out;
+	}
+	env = ep;
+	/* Add path to it */
+	path = getenv("PATH");
+	if (path) {
+		e = strlen("PATH") + strlen(path) + 2;
+		env[elen] = malloc(e);
+		if (env[elen] == NULL) {
+			elen = 0;
+			goto out;
+		}
+		snprintf(env[elen], e, "PATH=%s", path);
+	} else {
+		env[elen] = strdup(DEFAULT_PATH);
+		if (env[elen] == NULL) {
+			elen = 0;
+			goto out;
+		}
+	}
+	if (svcname) {
+		e = strlen(RC_SVCNAME) + strlen(svcname) + 2;
+		env[++elen] = malloc(e);
+		if (env[elen] == NULL) {
+			elen = 0;
+			goto out;
+		}
+		snprintf(env[elen], e, "%s=%s", RC_SVCNAME, svcname);
+	}
+	env[++elen] = NULL;
+
+	pid = exec_script(ifp->ctx, argv, env);
+	if (pid == -1)
+		logger(ifp->ctx, LOG_ERR, "%s: %s: %m", __func__, argv[0]);
+	else if (pid != 0) {
+		/* Wait for the script to finish */
+		while (waitpid(pid, &status, 0) == -1) {
+			if (errno != EINTR) {
+				logger(ifp->ctx, LOG_ERR, "waitpid: %m");
+				status = 0;
+				break;
+			}
+		}
+		if (WIFEXITED(status)) {
+			if (WEXITSTATUS(status))
+				logger(ifp->ctx, LOG_ERR,
+				    "%s: %s: WEXITSTATUS %d",
+				    __func__, argv[0], WEXITSTATUS(status));
+		} else if (WIFSIGNALED(status))
+			logger(ifp->ctx, LOG_ERR, "%s: %s: %s",
+			    __func__, argv[0], strsignal(WTERMSIG(status)));
+	}
+
+	/* Send to our listeners */
+	bigenv = NULL;
+	status = 0;
+	TAILQ_FOREACH(fd, &ifp->ctx->control_fds, next) {
+		if (!(fd->flags & FD_LISTEN))
+			continue;
+		if (bigenv == NULL) {
+			elen = (size_t)arraytostr((const char *const *)env,
+			    &bigenv);
+			if ((ssize_t)elen == -1) {
+				logger(ifp->ctx, LOG_ERR, "%s: arraytostr: %m",
+				    ifp->name);
+				    break;
+			}
+		}
+		if (control_queue(fd, bigenv, elen, 1) == -1)
+			logger(ifp->ctx, LOG_ERR,
+			    "%s: control_queue: %m", __func__);
+		else
+			status = 1;
+	}
+	if (!status)
+		free(bigenv);
+
+out:
+	/* Cleanup */
+	ep = env;
+	while (*ep)
+		free(*ep++);
+	free(env);
+	if (elen == 0)
+		return -1;
+	return WEXITSTATUS(status);
+}
diff --git a/dhcpcd-6.8.2/script.h b/dhcpcd-6.8.2/script.h
new file mode 100644
index 0000000..d090c5d
--- /dev/null
+++ b/dhcpcd-6.8.2/script.h
@@ -0,0 +1,37 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef SCRIPT_H
+#define SCRIPT_H
+
+#include "control.h"
+
+void if_printoptions(void);
+int send_interface(struct fd_list *, const struct interface *);
+int script_runreason(const struct interface *, const char *);
+
+#endif
diff --git a/dhcpcd-6.8.2/test/GNUmakefile b/dhcpcd-6.8.2/test/GNUmakefile
new file mode 100644
index 0000000..2e838d5
--- /dev/null
+++ b/dhcpcd-6.8.2/test/GNUmakefile
@@ -0,0 +1,7 @@
+# GNU Make does not automagically include .depend
+# Luckily it does read GNUmakefile over Makefile so we can work around it
+
+include Makefile
+ifneq ($(wildcard .depend), )
+include .depend
+endif
diff --git a/dhcpcd-6.8.2/test/Makefile b/dhcpcd-6.8.2/test/Makefile
new file mode 100644
index 0000000..e29a7cd
--- /dev/null
+++ b/dhcpcd-6.8.2/test/Makefile
@@ -0,0 +1,35 @@
+TOP?=	..
+include ${TOP}/iconfig.mk
+
+PROG=		test
+SRCS=		test.c
+SRCS+=		test_hmac_md5.c ../crypt/hmac_md5.c
+
+CFLAGS?=	-O2
+CSTD?=		c99
+CFLAGS+=	-std=${CSTD}
+
+CPPFLAGS+=	-I../crypt
+
+T_COMPAT_SRCS=	${COMPAT_SRCS:compat/%=../compat/%}
+T_MD5_SRC=	${MD5_SRC:crypt/%=../crypt/%}
+OBJS+=		${SRCS:.c=.o} ${T_COMPAT_SRCS:.c=.o} ${T_MD5_SRC:.c=.o}
+
+.c.o:
+	${CC} ${CFLAGS} ${CPPFLAGS} -c $< -o $@
+
+all: ${PROG}
+
+clean:
+	rm -f ${OBJS} ${PROG} ${PROG}.core ${CLEANFILES}
+
+distclean: clean
+	rm -f .depend
+
+.depend: ${SRCS} ${T_COMPAT_SRCS} ${T_CRYPT_SRCS}
+	${CC} ${CPPFLAGS} -MM ${SRCS} ${T_COMPAT_SRCS} ${T_CRYPT_SRCS} > .depend
+
+depend: .depend
+
+${PROG}: ${DEPEND} ${OBJS}
+	${CC} ${LDFLAGS} -o $@ ${OBJS} ${LDADD}
diff --git a/dhcpcd-6.8.2/test/test.c b/dhcpcd-6.8.2/test/test.c
new file mode 100644
index 0000000..fd8d5b4
--- /dev/null
+++ b/dhcpcd-6.8.2/test/test.c
@@ -0,0 +1,38 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2014 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "test.h"
+
+int main(void)
+{
+	int r = 0;
+
+	if (test_hmac_md5())
+		r = -1;
+
+	return r;
+}
diff --git a/dhcpcd-6.8.2/test/test.h b/dhcpcd-6.8.2/test/test.h
new file mode 100644
index 0000000..0ca6182
--- /dev/null
+++ b/dhcpcd-6.8.2/test/test.h
@@ -0,0 +1,32 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2014 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef TEST_H
+
+int test_hmac_md5(void);
+
+#endif
diff --git a/dhcpcd-6.8.2/test/test_hmac_md5.c b/dhcpcd-6.8.2/test/test_hmac_md5.c
new file mode 100644
index 0000000..ddb6875
--- /dev/null
+++ b/dhcpcd-6.8.2/test/test_hmac_md5.c
@@ -0,0 +1,173 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2014 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+
+#include "../crypt/crypt.h"
+#include "test.h"
+
+/* RFC2202 MD5 implementation */
+
+static void
+print_hmac(uint8_t *hmac)
+{
+	int i;
+
+	printf("digest = 0x");
+	for (i = 0; i < 16; i++)
+		printf("%02x", *hmac++);
+	printf("\n");
+}
+
+static void
+hmac_md5_test1(void)
+{
+	uint8_t hmac[16];
+	const uint8_t text[] = "Hi There";
+	uint8_t key[16];
+	int i;
+
+	printf ("HMAC MD5 Test 1:\t\t");
+	for (i = 0; i < 16; i++)
+		key[i] = 0x0b;
+	hmac_md5(text, 8, key, 16, hmac);
+	print_hmac(hmac);
+	printf("\t\texpected result:\t 0x9294727a3638bb1c13f48ef8158bfc9d\n");
+}
+
+static void
+hmac_md5_test2(void)
+{
+	uint8_t hmac[16];
+	const uint8_t text[] = "what do ya want for nothing?";
+	const uint8_t key[] = "Jefe";
+
+	printf("HMAC MD5 Test 2:\t\t");
+	hmac_md5(text, 28, key, 4, hmac);
+	print_hmac(hmac);
+	printf("\t\texpected result:\t 0x750c783e6ab0b503eaa863e10a5db738\n");
+}
+
+static void
+hmac_md5_test3(void)
+{
+	uint8_t hmac[16];
+	uint8_t text[50];
+	uint8_t key[16];
+	int i;
+
+	printf ("HMAC MD5 Test 3:\t\t");
+	for (i = 0; i < 50; i++)
+		text[i] = 0xdd;
+	for (i = 0; i < 16; i++)
+		key[i] = 0xaa;
+	hmac_md5(text, 50, key, 16, hmac);
+	print_hmac(hmac);
+	printf("\t\texpected result:\t 0x56be34521d144c88dbb8c733f0e8b3f6\n");
+}
+
+static void
+hmac_md5_test4(void)
+{
+	uint8_t hmac[16];
+	uint8_t text[50];
+	uint8_t key[25];
+	uint8_t i;
+
+	printf ("HMAC MD5 Test 4:\t\t");
+	for (i = 0; i < 50; i++)
+		text[i] = 0xcd;
+	for (i = 0; i < 25; i++)
+		key[i] = (uint8_t)(i + 1);
+	hmac_md5(text, 50, key, 25, hmac);
+	print_hmac(hmac);
+	printf("\t\texpected result:\t 0x697eaf0aca3a3aea3a75164746ffaa79\n");
+}
+
+static void
+hmac_md5_test5(void)
+{
+	uint8_t hmac[16];
+	const uint8_t text[] = "Test With Truncation";
+	uint8_t key[16];
+	int i;
+
+	printf ("HMAC MD5 Test 5:\t\t");
+	for (i = 0; i < 16; i++)
+		key[i] = 0x0c;
+	hmac_md5(text, 20, key, 16, hmac);
+	print_hmac(hmac);
+	printf("\t\texpected result:\t 0x56461ef2342edc00f9bab995690efd4c\n");
+}
+
+static void
+hmac_md5_test6(void)
+{
+	uint8_t hmac[16];
+	const uint8_t text[] = "Test Using Larger Than Block-Size Key - Hash Key First";
+	uint8_t key[80];
+	int i;
+
+	printf ("HMAC MD5 Test 6:\t\t");
+	for (i = 0; i < 80; i++)
+		key[i] = 0xaa;
+	hmac_md5(text, 54, key, 80, hmac);
+	print_hmac(hmac);
+	printf("\t\texpected result:\t 0x6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd\n");
+}
+
+static void
+hmac_md5_test7(void)
+{
+	uint8_t hmac[16];
+	const uint8_t text[] = "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data";
+	uint8_t key[80];
+	int i;
+
+	printf ("HMAC MD5 Test 7:\t\t");
+	for (i = 0; i < 80; i++)
+		key[i] = 0xaa;
+	hmac_md5(text, 73, key, 80, hmac);
+	print_hmac(hmac);
+	printf("\t\texpected result:\t 0x6f630fad67cda0ee1fb1f562db3aa53e\n");
+}
+
+int test_hmac_md5(void)
+{
+
+	printf ("Starting HMAC MD5 tests...\n\n");
+	hmac_md5_test1();
+	hmac_md5_test2();
+	hmac_md5_test3();
+	hmac_md5_test4();
+	hmac_md5_test5();
+	hmac_md5_test6();
+	hmac_md5_test7();
+	printf("\nConfirm above results visually against RFC 2202.\n");
+	return 0;
+}