Project import
diff --git a/dhcpcd/Android.mk b/dhcpcd/Android.mk
new file mode 100644
index 0000000..4947cbd
--- /dev/null
+++ b/dhcpcd/Android.mk
@@ -0,0 +1,65 @@
+# Copyright 2006 The Android Open Source Project
+LOCAL_PATH:= $(call my-dir)
+
+etc_dir := $(TARGET_OUT)/etc/dhcpcd
+hooks_dir := dhcpcd-hooks
+hooks_target := $(etc_dir)/$(hooks_dir)
+
+dhcpd_cflags := -Wno-error=duplicate-decl-specifier -D_BSD_SOURCE
+# Clang complains about configure.c's comparing array with null.
+dhcpd_cflags += -Wno-tautological-pointer-compare
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := arp.c bind.c common.c control.c dhcp.c dhcpcd.c duid.c \
+	eloop.c if-options.c if-pref.c ipv4ll.c net.c signals.c configure.c \
+	if-linux.c if-linux-wireless.c lpf.c \
+	platform-linux.c compat/closefrom.c ifaddrs.c ipv6rs.c
+
+LOCAL_CFLAGS := $(dhcpd_cflags)
+LOCAL_SHARED_LIBRARIES := libc libcutils libnetutils
+LOCAL_MODULE = dhcpcd
+include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := showlease.c
+LOCAL_SHARED_LIBRARIES := libc
+LOCAL_MODULE = showlease
+LOCAL_MODULE_TAGS := debug
+include $(BUILD_EXECUTABLE)
+
+#include $(CLEAR_VARS)
+#LOCAL_MODULE := dhcpcd.conf
+#LOCAL_MODULE_CLASS := ETC
+#LOCAL_MODULE_PATH := $(etc_dir)
+#LOCAL_SRC_FILES := android.conf
+#include $(BUILD_PREBUILT)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := dhcpcd-run-hooks
+LOCAL_MODULE_CLASS := EXECUTABLES
+LOCAL_MODULE_PATH := $(etc_dir)
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+include $(BUILD_PREBUILT)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := 20-dns.conf
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(hooks_target)
+LOCAL_SRC_FILES := $(hooks_dir)/$(LOCAL_MODULE)
+include $(BUILD_PREBUILT)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := 95-configured
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(hooks_target)
+LOCAL_SRC_FILES := $(hooks_dir)/$(LOCAL_MODULE)
+include $(BUILD_PREBUILT)
+
+# Unit tests.
+include $(CLEAR_VARS)
+LOCAL_MODULE := dhcpcd_test
+LOCAL_CFLAGS := -Wall -Werror -Wunused-parameter
+LOCAL_SRC_FILES := dhcpcd_test.cpp dhcp.c common.c
+LOCAL_CFLAGS := $(dhcpd_cflags)
+LOCAL_MODULE_TAGS := eng tests
+include $(BUILD_NATIVE_TEST)
diff --git a/dhcpcd/CleanSpec.mk b/dhcpcd/CleanSpec.mk
new file mode 100644
index 0000000..b84e1b6
--- /dev/null
+++ b/dhcpcd/CleanSpec.mk
@@ -0,0 +1,49 @@
+# Copyright (C) 2007 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.
+#
+
+# If you don't need to do a full clean build but would like to touch
+# a file or delete some intermediate files, add a clean step to the end
+# of the list.  These steps will only be run once, if they haven't been
+# run before.
+#
+# E.g.:
+#     $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
+#     $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
+#
+# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
+# files that are missing or have been moved.
+#
+# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
+# Use $(OUT_DIR) to refer to the "out" directory.
+#
+# If you need to re-do something that's already mentioned, just copy
+# the command and add it to the bottom of the list.  E.g., if a change
+# that you made last week required touching a file and a change you
+# made today requires touching the same file, just copy the old
+# touch step and add it to the end of the list.
+#
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+
+# For example:
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
+#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
+#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
+
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
diff --git a/dhcpcd/MODULE_LICENSE_BSD_LIKE b/dhcpcd/MODULE_LICENSE_BSD_LIKE
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/dhcpcd/MODULE_LICENSE_BSD_LIKE
diff --git a/dhcpcd/Makefile b/dhcpcd/Makefile
new file mode 100644
index 0000000..3b4dbfd
--- /dev/null
+++ b/dhcpcd/Makefile
@@ -0,0 +1,127 @@
+# dhcpcd Makefile
+
+PROG=		dhcpcd
+SRCS=		arp.c bind.c common.c control.c dhcp.c dhcpcd.c duid.c eloop.c
+SRCS+=		if-options.c if-pref.c ipv4ll.c ipv6rs.c net.c signals.c
+SRCS+=		configure.c
+
+CFLAGS?=	-O2
+CSTD?=		c99
+CFLAGS+=	-std=${CSTD}
+include config.mk
+
+OBJS+=		${SRCS:.c=.o} ${COMPAT_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
+SCRIPTSDIR=	${LIBEXECDIR}
+CLEANFILES+=	dhcpcd-run-hooks
+CLEANFILES+=	.depend
+
+FILES=		dhcpcd.conf
+FILESDIR=	${SYSCONFDIR}
+
+SUBDIRS=	dhcpcd-hooks
+
+SED_DBDIR=		-e 's:@DBDIR@:${DBDIR}: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_SH=	test -e .depend && echo ".depend" || echo ""
+_DEPEND!=	${_DEPEND_SH}
+DEPEND=		${_DEPEND}$(shell ${_DEPEND_SH})
+
+_VERSION_SH=	sed -n 's/\#define VERSION[[:space:]]*"\(.*\)".*/\1/p' defs.h
+_VERSION!=	${_VERSION_SH}
+VERSION=	${_VERSION}$(shell ${_VERSION_SH})
+
+GITREF?=	HEAD
+DISTPREFIX?=	${PROG}-${VERSION}
+DISTFILE?=	${DISTPREFIX}.tar.bz2
+
+CLEANFILES+=	*.tar.bz2
+
+.PHONY:		import import-bsd
+
+.SUFFIXES:	.in
+
+.in:
+	${SED} ${SED_DBDIR} ${SED_HOOKDIR} ${SED_SCRIPT} ${SED_SYS} \
+		${SED_SERVICEEXISTS} ${SED_SERVICECMD} ${SED_SERVICESTATUS} \
+		$< > $@
+
+all: config.h ${PROG} ${SCRIPTS} ${MAN5} ${MAN8}
+
+.c.o:
+	${CC} ${CFLAGS} ${CPPFLAGS} -c $< -o $@
+
+.depend: ${SRCS} ${COMPAT_SRCS}
+	${CC} ${CPPFLAGS} -MM ${SRCS} ${COMPAT_SRCS} > .depend
+
+depend: .depend
+
+${PROG}: ${DEPEND} ${OBJS}
+	${CC} ${LDFLAGS} -o $@ ${OBJS} ${LDADD}
+
+_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}
+
+_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
+
+_confinstall:
+	${INSTALL} -d ${DESTDIR}${SYSCONFDIR}
+	test -e ${DESTDIR}${SYSCONFDIR}/dhcpcd.conf || \
+		${INSTALL} -m ${CONFMODE} dhcpcd.conf ${DESTDIR}${SYSCONFDIR}
+
+install: _proginstall _scriptsinstall _maninstall _confinstall
+	for x in ${SUBDIRS}; do cd $$x; ${MAKE} $@; cd ..; done
+
+clean:
+	rm -f ${OBJS} ${PROG} ${PROG}.core ${CLEANFILES}
+
+distclean: clean
+	rm -f .depend config.h config.mk
+
+dist:
+	git archive --prefix=${DISTPREFIX}/ ${GITREF} | bzip2 > ${DISTFILE}
+
+import:
+	rm -rf /tmp/${DISTPREFIX}
+	${INSTALL} -d /tmp/${DISTPREFIX}
+	cp ${SRCS} dhcpcd.conf *.in /tmp/${DISTPREFIX}
+	cp $$(${CC} ${CPPFLAGS} -MM ${SRCS} | \
+		sed -e 's/^.*\.c //g' -e 's/.*\.c$$//g' -e 's/\\//g' | \
+		tr ' ' '\n' | \
+		sed -e '/^compat\//d' | \
+		sort -u) /tmp/${DISTPREFIX}
+	if test -n "${COMPAT_SRCS}"; then \
+		${INSTALL} -d /tmp/${DISTPREFIX}/compat; \
+		cp ${COMPAT_SRCS} /tmp/${DISTPREFIX}/compat; \
+		cp $$(${CC} ${CPPFLAGS} -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/Makefile.inc b/dhcpcd/Makefile.inc
new file mode 100644
index 0000000..fd7ead4
--- /dev/null
+++ b/dhcpcd/Makefile.inc
@@ -0,0 +1,9 @@
+# System definitions
+
+BINMODE?=	0555
+NONBINMODE?=	0444
+MANMODE?=	${NONBINMODE}
+CONFMODE?=	0644
+
+INSTALL?=	install
+SED?=		sed
diff --git a/dhcpcd/NOTICE b/dhcpcd/NOTICE
new file mode 100644
index 0000000..73598aa
--- /dev/null
+++ b/dhcpcd/NOTICE
@@ -0,0 +1,49 @@
+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.
+
+
+
+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/
diff --git a/dhcpcd/README b/dhcpcd/README
new file mode 100644
index 0000000..32ae27a
--- /dev/null
+++ b/dhcpcd/README
@@ -0,0 +1,80 @@
+dhcpcd - DHCP client daemon
+Copyright (c) 2006-2012 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 are:
+    NetBSD-5.0
+
+We try and detect how dhcpcd should interact with system services during the
+configure stage. If we cannot auto-detect how do to this, or it is wrong then
+you can change this by passing shell commands to --service-exists,
+--servicecmd and optionally --servicestatus.
+
+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
+
+
+Hooks
+-----
+Not all the hooks in dhcpcd-hooks are installed by default.
+By default we install 01-test, 10-mtu, 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
+
+
+Compatibility
+-------------
+dhcpcd-5.0 is only fully command line compatible with dhcpcd-4.0
+For compatibility with older versions, use dhcpcd-4.0
+
+dhcpcd no longer sends a default ClientID for ethernet interfaces.
+This is so we can re-use the address the kernel DHCP client found.
+To retain the old behaviour of sending a default ClientID based on the
+hardware address for interface, simply add the keyword clientid to dhcpcd.conf.
+
+
+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/log/
diff --git a/dhcpcd/android.conf b/dhcpcd/android.conf
new file mode 100755
index 0000000..5f5fd54
--- /dev/null
+++ b/dhcpcd/android.conf
@@ -0,0 +1,10 @@
+# dhcpcd configuration for Android Wi-Fi interface
+# See dhcpcd.conf(5) for details.
+
+# IPv6 RS/RA processing is handled by the kernel. See also http://b/15268738
+noipv6rs
+
+interface wlan0
+# dhcpcd-run-hooks uses these options.
+option subnet_mask, routers, domain_name_servers, domain_name, domain_search
+
diff --git a/dhcpcd/arp.c b/dhcpcd/arp.c
new file mode 100644
index 0000000..1905508
--- /dev/null
+++ b/dhcpcd/arp.c
@@ -0,0 +1,310 @@
+/* 
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2011 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 <syslog.h>
+#include <unistd.h>
+
+#include "arp.h"
+#include "bind.h"
+#include "common.h"
+#include "dhcpcd.h"
+#include "eloop.h"
+#include "if-options.h"
+#include "ipv4ll.h"
+#include "net.h"
+
+#define ARP_LEN								      \
+	(sizeof(struct arphdr) + (2 * sizeof(uint32_t)) + (2 * HWADDR_LEN))
+
+static int
+send_arp(const struct interface *iface, int op, in_addr_t sip, in_addr_t tip)
+{
+	uint8_t arp_buffer[ARP_LEN];
+	struct arphdr ar;
+	size_t len;
+	uint8_t *p;
+	int retval;
+
+	ar.ar_hrd = htons(iface->family);
+	ar.ar_pro = htons(ETHERTYPE_IP);
+	ar.ar_hln = iface->hwlen;
+	ar.ar_pln = sizeof(sip);
+	ar.ar_op = htons(op);
+	memcpy(arp_buffer, &ar, sizeof(ar));
+	p = arp_buffer + sizeof(ar);
+	memcpy(p, iface->hwaddr, iface->hwlen);
+	p += iface->hwlen;
+	memcpy(p, &sip, sizeof(sip));
+	p += sizeof(sip);
+	/* ARP requests should ignore this */
+	retval = iface->hwlen;
+	while (retval--)
+		*p++ = '\0';
+	memcpy(p, &tip, sizeof(tip));
+	p += sizeof(tip);
+	len = p - arp_buffer;
+	retval = send_raw_packet(iface, ETHERTYPE_ARP, arp_buffer, len);
+	return retval;
+}
+
+static void
+handle_arp_failure(struct interface *iface)
+{
+
+	/* If we failed without a magic cookie then we need to try
+	 * and defend our IPv4LL address. */
+	if ((iface->state->offer != NULL &&
+		iface->state->offer->cookie != htonl(MAGIC_COOKIE)) ||
+	    (iface->state->new != NULL &&
+		iface->state->new->cookie != htonl(MAGIC_COOKIE)))
+	{
+		handle_ipv4ll_failure(iface);
+		return;
+	}
+
+	unlink(iface->leasefile);
+	if (!iface->state->lease.frominfo)
+		send_decline(iface);
+	close_sockets(iface);
+	delete_timeout(NULL, iface);
+	if (iface->state->lease.frominfo)
+		start_interface(iface);
+	else
+		add_timeout_sec(DHCP_ARP_FAIL, start_interface, iface);
+}
+
+static void
+handle_arp_packet(void *arg)
+{
+	struct interface *iface = arg;
+	uint8_t arp_buffer[ARP_LEN];
+	struct arphdr ar;
+	uint32_t reply_s;
+	uint32_t reply_t;
+	uint8_t *hw_s, *hw_t;
+	ssize_t bytes;
+	struct if_state *state = iface->state;
+	struct if_options *opts = state->options;
+	const char *hwaddr;
+	struct in_addr ina;
+
+	state->fail.s_addr = 0;
+	for(;;) {
+		bytes = get_raw_packet(iface, ETHERTYPE_ARP,
+		    arp_buffer, sizeof(arp_buffer), NULL);
+		if (bytes == 0 || bytes == -1)
+			return;
+		/* We must have a full ARP header */
+		if ((size_t)bytes < sizeof(ar))
+			continue;
+		memcpy(&ar, arp_buffer, sizeof(ar));
+		/* Protocol must be IP. */
+		if (ar.ar_pro != htons(ETHERTYPE_IP))
+			continue;
+		if (ar.ar_pln != sizeof(reply_s))
+			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 */
+		if (ar.ar_hln == iface->hwlen &&
+		    memcmp(hw_s, iface->hwaddr, iface->hwlen) == 0)
+			continue;
+		/* Copy out the IP addresses */
+		memcpy(&reply_s, hw_s + ar.ar_hln, ar.ar_pln);
+		memcpy(&reply_t, hw_t + ar.ar_hln, ar.ar_pln);
+
+		/* Check for arping */
+		if (state->arping_index &&
+		    state->arping_index <= opts->arping_len &&
+		    (reply_s == opts->arping[state->arping_index - 1] ||
+			(reply_s == 0 &&
+			    reply_t == opts->arping[state->arping_index - 1])))
+		{
+			ina.s_addr = reply_s;
+			hwaddr = hwaddr_ntoa((unsigned char *)hw_s,
+			    (size_t)ar.ar_hln);
+			syslog(LOG_INFO,
+			    "%s: found %s on hardware address %s",
+			    iface->name, inet_ntoa(ina), hwaddr);
+			if (select_profile(iface, hwaddr) == -1 &&
+			    errno == ENOENT)
+				select_profile(iface, inet_ntoa(ina));
+			close_sockets(iface);
+			delete_timeout(NULL, iface);
+			start_interface(iface);
+			return;
+		}
+
+		/* Check for conflict */
+		if (state->offer &&
+		    (reply_s == state->offer->yiaddr ||
+			(reply_s == 0 && reply_t == state->offer->yiaddr)))
+			state->fail.s_addr = state->offer->yiaddr;
+
+		/* Handle IPv4LL conflicts */
+		if (IN_LINKLOCAL(htonl(iface->addr.s_addr)) &&
+		    (reply_s == iface->addr.s_addr ||
+			(reply_s == 0 && reply_t == iface->addr.s_addr)))
+			state->fail.s_addr = iface->addr.s_addr;
+
+		if (state->fail.s_addr) {
+			syslog(LOG_ERR, "%s: hardware address %s claims %s",
+			    iface->name,
+			    hwaddr_ntoa((unsigned char *)hw_s,
+				(size_t)ar.ar_hln),
+			    inet_ntoa(state->fail));
+			errno = EEXIST;
+			handle_arp_failure(iface);
+			return;
+		}
+	}
+}
+
+void
+send_arp_announce(void *arg)
+{
+	struct interface *iface = arg;
+	struct if_state *state = iface->state;
+	struct timeval tv;
+
+	if (state->new == NULL)
+		return;
+	if (iface->arp_fd == -1) {
+		open_socket(iface, ETHERTYPE_ARP);
+		add_event(iface->arp_fd, handle_arp_packet, iface);
+	}
+	if (++state->claims < ANNOUNCE_NUM)	
+		syslog(LOG_DEBUG,
+		    "%s: sending ARP announce (%d of %d), "
+		    "next in %d.00 seconds",
+		    iface->name, state->claims, ANNOUNCE_NUM, ANNOUNCE_WAIT);
+	else
+		syslog(LOG_DEBUG,
+		    "%s: sending ARP announce (%d of %d)",
+		    iface->name, state->claims, ANNOUNCE_NUM);
+	if (send_arp(iface, ARPOP_REQUEST,
+		state->new->yiaddr, state->new->yiaddr) == -1)
+		syslog(LOG_ERR, "send_arp: %m");
+	if (state->claims < ANNOUNCE_NUM) {
+		add_timeout_sec(ANNOUNCE_WAIT, send_arp_announce, iface);
+		return;
+	}
+	if (state->new->cookie != htonl(MAGIC_COOKIE)) {
+		/* We should pretend to be at the end
+		 * of the DHCP negotation cycle unless we rebooted */
+		if (state->interval != 0)
+			state->interval = 64;
+		state->probes = 0;
+		state->claims = 0;
+		tv.tv_sec = state->interval - DHCP_RAND_MIN;
+		tv.tv_usec = arc4random() % (DHCP_RAND_MAX_U - DHCP_RAND_MIN_U);
+		timernorm(&tv);
+		add_timeout_tv(&tv, start_discover, iface);
+	} else {
+		delete_event(iface->arp_fd);
+		close(iface->arp_fd);
+		iface->arp_fd = -1;
+	}
+}
+
+void
+send_arp_probe(void *arg)
+{
+	struct interface *iface = arg;
+	struct if_state *state = iface->state;
+	struct in_addr addr;
+	struct timeval tv;
+	int arping = 0;
+
+	if (state->arping_index < state->options->arping_len) {
+		addr.s_addr = state->options->arping[state->arping_index];
+		arping = 1;
+	} else if (state->offer) {
+		if (state->offer->yiaddr)
+			addr.s_addr = state->offer->yiaddr;
+		else
+			addr.s_addr = state->offer->ciaddr;
+	} else
+		addr.s_addr = iface->addr.s_addr;
+
+	if (iface->arp_fd == -1) {
+		open_socket(iface, ETHERTYPE_ARP);
+		add_event(iface->arp_fd, handle_arp_packet, iface);
+	}
+	if (state->probes == 0) {
+		if (arping)
+			syslog(LOG_INFO, "%s: searching for %s",
+			    iface->name, inet_ntoa(addr));
+		else
+			syslog(LOG_INFO, "%s: checking for %s",
+			    iface->name, inet_ntoa(addr));
+	}
+	if (++state->probes < PROBE_NUM) {
+		tv.tv_sec = PROBE_MIN;
+		tv.tv_usec = arc4random() % (PROBE_MAX_U - PROBE_MIN_U);
+		timernorm(&tv);
+		add_timeout_tv(&tv, send_arp_probe, iface);
+	} else {
+		tv.tv_sec = ANNOUNCE_WAIT;
+		tv.tv_usec = 0;
+		if (arping) {
+			state->probes = 0;
+			if (++state->arping_index < state->options->arping_len)
+				add_timeout_tv(&tv, send_arp_probe, iface);
+			else
+				add_timeout_tv(&tv, start_interface, iface);
+		} else
+			add_timeout_tv(&tv, bind_interface, iface);
+	}
+	syslog(LOG_DEBUG,
+	    "%s: sending ARP probe (%d of %d), next in %0.2f seconds",
+	    iface->name, state->probes ? state->probes : PROBE_NUM, PROBE_NUM,
+	    timeval_to_double(&tv));
+	if (send_arp(iface, ARPOP_REQUEST, 0, addr.s_addr) == -1)
+		syslog(LOG_ERR, "send_arp: %m");
+}
+
+void
+start_arping(struct interface *iface)
+{
+	iface->state->probes = 0;
+	iface->state->arping_index = 0;
+	send_arp_probe(iface);
+}
diff --git a/dhcpcd/arp.h b/dhcpcd/arp.h
new file mode 100644
index 0000000..b97c38b
--- /dev/null
+++ b/dhcpcd/arp.h
@@ -0,0 +1,49 @@
+/* 
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2008 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
+
+/* These are for IPV4LL, RFC 3927.
+ * We put them here as we use the timings for all ARP foo. */
+#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"
+
+void send_arp_announce(void *);
+void send_arp_probe(void *);
+void start_arping(struct interface *);
+#endif
diff --git a/dhcpcd/bind.c b/dhcpcd/bind.c
new file mode 100644
index 0000000..eed64a6
--- /dev/null
+++ b/dhcpcd/bind.c
@@ -0,0 +1,234 @@
+/* 
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2010 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/time.h>
+
+#include <fcntl.h>
+#ifdef BSD
+#  include <paths.h>
+#endif
+#include <signal.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include "arp.h"
+#include "bind.h"
+#include "common.h"
+#include "configure.h"
+#include "dhcpcd.h"
+#include "eloop.h"
+#include "if-options.h"
+#include "net.h"
+#include "signals.h"
+
+#ifndef _PATH_DEVNULL
+#  define _PATH_DEVNULL "/dev/null"
+#endif
+
+/* We do things after aquiring the lease, so ensure we have enough time for them */
+#define DHCP_MIN_LEASE 20
+
+#ifndef THERE_IS_NO_FORK
+pid_t
+daemonise(void)
+{
+	pid_t pid;
+	sigset_t full;
+	sigset_t old;
+	char buf = '\0';
+	int sidpipe[2], fd;
+
+	if (options & DHCPCD_DAEMONISED || !(options & DHCPCD_DAEMONISE))
+		return 0;
+	sigfillset(&full);
+	sigprocmask(SIG_SETMASK, &full, &old);
+	/* Setup a signal pipe so parent knows when to exit. */
+	if (pipe(sidpipe) == -1) {
+		syslog(LOG_ERR, "pipe: %m");
+		return -1;
+	}
+	syslog(LOG_DEBUG, "forking to background");
+	switch (pid = fork()) {
+	case -1:
+		syslog(LOG_ERR, "fork: %m");
+		exit(EXIT_FAILURE);
+		/* NOTREACHED */
+	case 0:
+		setsid();
+		/* Notify parent it's safe to exit as we've detached. */
+		close(sidpipe[0]);
+		if (write(sidpipe[1], &buf, 1) == -1)
+			syslog(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);
+			if (fd > STDERR_FILENO)
+				close(fd);
+		}
+		break;
+	default:
+		signal_reset();
+		/* Wait for child to detach */
+		close(sidpipe[1]);
+		if (read(sidpipe[0], &buf, 1) == -1)
+			syslog(LOG_ERR, "failed to read child: %m");
+		close(sidpipe[0]);
+		break;
+	}
+	/* Done with the fd now */
+	if (pid != 0) {
+		syslog(LOG_INFO, "forked to background, child pid %d",pid);
+		writepid(pidfd, pid);
+		close(pidfd);
+		pidfd = -1;
+		exit(EXIT_SUCCESS);
+	}
+	options |= DHCPCD_DAEMONISED;
+	sigprocmask(SIG_SETMASK, &old, NULL);
+	return pid;
+}
+#endif
+
+void
+bind_interface(void *arg)
+{
+	struct interface *iface = arg;
+	struct if_state *state = iface->state;
+	struct if_options *ifo = state->options;
+	struct dhcp_lease *lease = &state->lease;
+	struct timeval tv;
+
+	/* We're binding an address now - ensure that sockets are closed */
+	close_sockets(iface);
+	state->reason = NULL;
+	delete_timeout(handle_exit_timeout, NULL);
+	if (clock_monotonic)
+		get_monotonic(&lease->boundtime);
+	state->xid = 0;
+	free(state->old);
+	state->old = state->new;
+	state->new = state->offer;
+	state->offer = NULL;
+	get_lease(lease, state->new);
+	if (ifo->options & DHCPCD_STATIC) {
+		syslog(LOG_INFO, "%s: using static address %s",
+		    iface->name, inet_ntoa(lease->addr));
+		lease->leasetime = ~0U;
+		lease->net.s_addr = ifo->req_mask.s_addr;
+		state->reason = "STATIC";
+	} else if (state->new->cookie != htonl(MAGIC_COOKIE)) {
+		syslog(LOG_INFO, "%s: using IPv4LL address %s",
+		    iface->name, inet_ntoa(lease->addr));
+		lease->leasetime = ~0U;
+		state->reason = "IPV4LL";
+	} 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 = iface->addr.s_addr;
+		syslog(LOG_INFO, "%s: received approval for %s", iface->name,
+		    inet_ntoa(lease->addr));
+		lease->leasetime = ~0U;
+		state->reason = "INFORM";
+	} else {
+		if (gettimeofday(&tv, NULL) == 0)
+			lease->leasedfrom = tv.tv_sec;
+		else if (lease->frominfo)
+			state->reason = "TIMEOUT";
+		if (lease->leasetime == ~0U) {
+			lease->renewaltime =
+			    lease->rebindtime =
+			    lease->leasetime;
+			syslog(LOG_INFO, "%s: leased %s for infinity",
+			    iface->name, inet_ntoa(lease->addr));
+		} else {
+			if (lease->leasetime < DHCP_MIN_LEASE) {
+				syslog(LOG_WARNING,
+				    "%s: minimum lease is %d seconds",
+				    iface->name, DHCP_MIN_LEASE);
+				lease->leasetime = DHCP_MIN_LEASE;
+			}
+			if (lease->rebindtime == 0)
+				lease->rebindtime = lease->leasetime * T2;
+			else if (lease->rebindtime >= lease->leasetime) {
+				lease->rebindtime = lease->leasetime * T2;
+				syslog(LOG_ERR,
+				    "%s: rebind time greater than lease "
+				    "time, forcing to %u seconds",
+				    iface->name, lease->rebindtime);
+			}
+			if (lease->renewaltime == 0)
+				lease->renewaltime = lease->leasetime * T1;
+			else if (lease->renewaltime > lease->rebindtime) {
+				lease->renewaltime = lease->leasetime * T1;
+				syslog(LOG_ERR,
+				    "%s: renewal time greater than rebind "
+				    "time, forcing to %u seconds",
+				    iface->name, lease->renewaltime);
+			}
+			syslog(LOG_INFO,
+			    "%s: leased %s for %u seconds", iface->name,
+			    inet_ntoa(lease->addr), lease->leasetime);
+		}
+	}
+	if (options & DHCPCD_TEST) {
+		state->reason = "TEST";
+		run_script(iface);
+		exit(EXIT_SUCCESS);
+	}
+	if (state->reason == NULL) {
+		if (state->old) {
+			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 (lease->leasetime == ~0U)
+		lease->renewaltime = lease->rebindtime = lease->leasetime;
+	else {
+		add_timeout_sec(lease->renewaltime, start_renew, iface);
+		add_timeout_sec(lease->rebindtime, start_rebind, iface);
+		add_timeout_sec(lease->leasetime, start_expire, iface);
+	}
+	ifo->options &= ~ DHCPCD_CSR_WARNED;
+	configure(iface);
+	daemonise();
+	state->state = DHS_BOUND;
+	if (ifo->options & DHCPCD_ARP) {
+		state->claims = 0;
+		send_arp_announce(iface);
+	}
+}
diff --git a/dhcpcd/bind.h b/dhcpcd/bind.h
new file mode 100644
index 0000000..375a0f3
--- /dev/null
+++ b/dhcpcd/bind.h
@@ -0,0 +1,39 @@
+/* 
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2008 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 BIND_H
+#define BIND_H
+
+#include "config.h"
+#ifdef THERE_IS_NO_FORK
+# define daemonise() {}
+#else
+pid_t daemonise(void);
+#endif
+
+void bind_interface(void *);
+#endif
diff --git a/dhcpcd/bpf-filter.h b/dhcpcd/bpf-filter.h
new file mode 100644
index 0000000..b68ee49
--- /dev/null
+++ b/dhcpcd/bpf-filter.h
@@ -0,0 +1,101 @@
+/*
+ * 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 const 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),
+};
+static const size_t 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 const 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),
+};
+static const size_t dhcp_bpf_filter_len =
+    sizeof(dhcp_bpf_filter) / sizeof(dhcp_bpf_filter[0]);
diff --git a/dhcpcd/bpf.c b/dhcpcd/bpf.c
new file mode 100644
index 0000000..1c30c76
--- /dev/null
+++ b/dhcpcd/bpf.c
@@ -0,0 +1,209 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2011 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 <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+
+#include <net/bpf.h>
+#include <net/if.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include "config.h"
+#include "common.h"
+#include "dhcp.h"
+#include "net.h"
+#include "bpf-filter.h"
+
+int
+open_socket(struct interface *iface, int protocol)
+{
+	int fd = -1;
+	int *fdp = NULL;
+	struct ifreq ifr;
+	int buf_len = 0;
+	struct bpf_version pv;
+	struct bpf_program pf;
+#ifdef BIOCIMMEDIATE
+	int flags;
+#endif
+#ifdef _PATH_BPF
+	fd = open(_PATH_BPF, O_RDWR | O_NONBLOCK);
+#else
+	char *device;
+	int n = 0;
+
+	device = xmalloc(sizeof(char) * PATH_MAX);
+	do {
+		snprintf(device, PATH_MAX, "/dev/bpf%d", n++);
+		fd = open(device, O_RDWR | O_NONBLOCK);
+	} while (fd == -1 && errno == EBUSY);
+	free(device);
+#endif
+
+	if (fd == -1)
+		return -1;
+
+	if (ioctl(fd, BIOCVERSION, &pv) == -1)
+		goto eexit;
+	if (pv.bv_major != BPF_MAJOR_VERSION ||
+	    pv.bv_minor < BPF_MINOR_VERSION) {
+		syslog(LOG_ERR, "BPF version mismatch - recompile");
+		goto eexit;
+	}
+
+	memset(&ifr, 0, sizeof(ifr));
+	strlcpy(ifr.ifr_name, iface->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, &buf_len) == -1)
+		goto eexit;
+	if (iface->buffer_size != (size_t)buf_len) {
+		free(iface->buffer);
+		iface->buffer_size = buf_len;
+		iface->buffer = xmalloc(buf_len);
+		iface->buffer_len = iface->buffer_pos = 0;
+	}
+
+#ifdef BIOCIMMEDIATE
+	flags = 1;
+	if (ioctl(fd, BIOCIMMEDIATE, &flags) == -1)
+		goto eexit;
+#endif
+
+	/* Install the DHCP filter */
+	if (protocol == ETHERTYPE_ARP) {
+		pf.bf_insns = UNCONST(arp_bpf_filter);
+		pf.bf_len = arp_bpf_filter_len;
+		fdp = &iface->arp_fd;
+	} else {
+		pf.bf_insns = UNCONST(dhcp_bpf_filter);
+		pf.bf_len = dhcp_bpf_filter_len;
+		fdp = &iface->raw_fd;
+	}
+	if (ioctl(fd, BIOCSETF, &pf) == -1)
+		goto eexit;
+	if (set_cloexec(fd) == -1)
+		goto eexit;
+	if (fdp) {
+		if (*fdp != -1)
+			close(*fdp);
+		*fdp = fd;
+	}
+	return fd;
+
+eexit:
+	free(iface->buffer);
+	iface->buffer = NULL;
+	close(fd);
+	return -1;
+}
+
+ssize_t
+send_raw_packet(const struct interface *iface, int protocol,
+    const void *data, ssize_t len)
+{
+	struct iovec iov[2];
+	struct ether_header hw;
+	int fd;
+
+	memset(&hw, 0, ETHER_HDR_LEN);
+	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;
+	if (protocol == ETHERTYPE_ARP)
+		fd = iface->arp_fd;
+	else
+		fd = iface->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
+get_raw_packet(struct interface *iface, int protocol,
+    void *data, ssize_t len, int *partialcsum)
+{
+	int fd = -1;
+	struct bpf_hdr packet;
+	ssize_t bytes;
+	const unsigned char *payload;
+
+	if (protocol == ETHERTYPE_ARP)
+		fd = iface->arp_fd;
+	else
+		fd = iface->raw_fd;
+
+	if (partialcsum != NULL)
+		*partialcsum = 0; /* Not supported on BSD */
+
+	for (;;) {
+		if (iface->buffer_len == 0) {
+			bytes = read(fd, iface->buffer, iface->buffer_size);
+			if (bytes == -1)
+				return errno == EAGAIN ? 0 : -1;
+			else if ((size_t)bytes < sizeof(packet))
+				return -1;
+			iface->buffer_len = bytes;
+			iface->buffer_pos = 0;
+		}
+		bytes = -1;
+		memcpy(&packet, iface->buffer + iface->buffer_pos,
+		    sizeof(packet));
+		if (packet.bh_caplen != packet.bh_datalen)
+			goto next; /* Incomplete packet, drop. */
+		if (iface->buffer_pos + packet.bh_caplen + packet.bh_hdrlen >
+		    iface->buffer_len)
+			goto next; /* Packet beyond buffer, drop. */
+		payload = iface->buffer + packet.bh_hdrlen + ETHER_HDR_LEN;
+		bytes = packet.bh_caplen - ETHER_HDR_LEN;
+		if (bytes > len)
+			bytes = len;
+		memcpy(data, payload, bytes);
+next:
+		iface->buffer_pos += BPF_WORDALIGN(packet.bh_hdrlen +
+		    packet.bh_caplen);
+		if (iface->buffer_pos >= iface->buffer_len)
+			iface->buffer_len = iface->buffer_pos = 0;
+		if (bytes != -1)
+			return bytes;
+	}
+}
diff --git a/dhcpcd/common.c b/dhcpcd/common.c
new file mode 100644
index 0000000..05b547b
--- /dev/null
+++ b/dhcpcd/common.c
@@ -0,0 +1,301 @@
+/* 
+ * 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.
+ */
+
+/* Needed define to get at getline for glibc and FreeBSD */
+#ifndef _GNU_SOURCE
+#  define _GNU_SOURCE
+#endif
+
+#include <sys/cdefs.h>
+
+#ifdef __APPLE__
+#  include <mach/mach_time.h>
+#  include <mach/kern_return.h>
+#endif
+
+#include <sys/param.h>
+#include <sys/time.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#ifdef BSD
+#  include <paths.h>
+#endif
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "common.h"
+
+#ifndef _PATH_DEVNULL
+#  define _PATH_DEVNULL "/dev/null"
+#endif
+
+int clock_monotonic;
+static char *lbuf;
+static size_t lbuf_len;
+#ifdef DEBUG_MEMORY
+static char lbuf_set;
+#endif
+
+#ifdef DEBUG_MEMORY
+static void
+free_lbuf(void)
+{
+	free(lbuf);
+	lbuf = NULL;
+}
+#endif
+
+/* 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.
+ * As we don't use threads, this API is clean too. */
+char *
+get_line(FILE * __restrict fp)
+{
+	char *p;
+	ssize_t bytes;
+
+#ifdef DEBUG_MEMORY
+	if (lbuf_set == 0) {
+		atexit(free_lbuf);
+		lbuf_set = 1;
+	}
+#endif
+
+	do {
+		bytes = getline(&lbuf, &lbuf_len, fp);
+		if (bytes == -1)
+			return NULL;
+		for (p = lbuf; *p == ' ' || *p == '\t'; p++)
+			;
+	} while (*p == '\0' || *p == '\n' || *p == '#' || *p == ';');
+	if (lbuf[--bytes] == '\n')
+		lbuf[bytes] = '\0';
+	return p;
+}
+
+int
+set_cloexec(int fd)
+{
+	int flags;
+
+	if ((flags = fcntl(fd, F_GETFD, 0)) == -1 ||
+	    fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
+	{
+		syslog(LOG_ERR, "fcntl: %m");
+		return -1;
+	}
+	return 0;
+}
+
+int
+set_nonblock(int fd)
+{
+	int flags;
+
+	if ((flags = fcntl(fd, F_GETFL, 0)) == -1 ||
+	    fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1)
+	{
+		syslog(LOG_ERR, "fcntl: %m");
+		return -1;
+	}
+	return 0;
+}
+
+/* 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 timeval *tp)
+{
+	static int posix_clock_set = 0;
+#if defined(_POSIX_MONOTONIC_CLOCK) && defined(CLOCK_MONOTONIC)
+	struct timespec ts;
+	static clockid_t posix_clock;
+
+	if (!posix_clock_set) {
+		if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
+			posix_clock = CLOCK_MONOTONIC;
+			clock_monotonic = posix_clock_set = 1;
+		}
+	}
+
+	if (clock_monotonic) {
+		if (clock_gettime(posix_clock, &ts) == 0) {
+			tp->tv_sec = ts.tv_sec;
+			tp->tv_usec = ts.tv_nsec / 1000;
+			return 0;
+		}
+	}
+#elif defined(__APPLE__)
+#define NSEC_PER_SEC 1000000000
+	/* 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;
+		tp->tv_sec = nano / NSEC_PER_SEC;
+		rem = nano % NSEC_PER_SEC;
+		if (rem < 0) {
+			tp->tv_sec--;
+			rem += NSEC_PER_SEC;
+		}
+		tp->tv_usec = rem / 1000;
+		return 0;
+	}
+#endif
+
+	/* Something above failed, so fall back to gettimeofday */
+	if (!posix_clock_set) {
+		syslog(LOG_WARNING, NO_MONOTONIC);
+		posix_clock_set = 1;
+	}
+	return gettimeofday(tp, NULL);
+}
+
+ssize_t
+setvar(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 = xmalloc(len);
+	if (prefix)
+		snprintf(**e, len, "%s_%s=%s", prefix, var, value);
+	else
+		snprintf(**e, len, "%s=%s", var, value);
+	(*e)++;
+	return len;
+}
+
+ssize_t
+setvard(char ***e, const char *prefix, const char *var, int value)
+{
+	char buffer[32];
+
+	snprintf(buffer, sizeof(buffer), "%d", value);
+	return setvar(e, prefix, var, buffer);
+}
+
+
+time_t
+uptime(void)
+{
+	struct timeval tv;
+
+	if (get_monotonic(&tv) == -1)
+		return -1;
+	return tv.tv_sec;
+}
+
+int
+writepid(int fd, pid_t pid)
+{
+	char spid[16];
+	ssize_t len;
+
+	if (ftruncate(fd, (off_t)0) == -1)
+		return -1;
+	snprintf(spid, sizeof(spid), "%u\n", pid);
+	len = pwrite(fd, spid, strlen(spid), (off_t)0);
+	if (len != (ssize_t)strlen(spid))
+		return -1;
+	return 0;
+}
+
+void *
+xmalloc(size_t s)
+{
+	void *value = malloc(s);
+
+	if (value != NULL)
+		return value;
+	syslog(LOG_ERR, "memory exhausted (xalloc %zu bytes)", s);
+	exit (EXIT_FAILURE);
+	/* NOTREACHED */
+}
+
+void *
+xzalloc(size_t s)
+{
+	void *value = xmalloc(s);
+
+	memset(value, 0, s);
+	return value;
+}
+
+void *
+xrealloc(void *ptr, size_t s)
+{
+	void *value = realloc(ptr, s);
+
+	if (value != NULL)
+		return value;
+	syslog(LOG_ERR, "memory exhausted (xrealloc %zu bytes)", s);
+	exit(EXIT_FAILURE);
+	/* NOTREACHED */
+}
+
+char *
+xstrdup(const char *str)
+{
+	char *value;
+
+	if (str == NULL)
+		return NULL;
+
+	if ((value = strdup(str)) != NULL)
+		return value;
+
+	syslog(LOG_ERR, "memory exhausted (xstrdup)");
+	exit(EXIT_FAILURE);
+	/* NOTREACHED */
+}
diff --git a/dhcpcd/common.h b/dhcpcd/common.h
new file mode 100644
index 0000000..4fe2444
--- /dev/null
+++ b/dhcpcd/common.h
@@ -0,0 +1,113 @@
+/* 
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2011 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/time.h>
+#include <stdio.h>
+
+#include "config.h"
+#include "defs.h"
+
+#define UNCONST(a)		((void *)(unsigned long)(const void *)(a))
+
+#define timeval_to_double(tv) ((tv)->tv_sec * 1.0 + (tv)->tv_usec * 1.0e-6)
+#define timernorm(tvp)							\
+	do {								\
+		while ((tvp)->tv_usec >= 1000000) {			\
+			(tvp)->tv_sec++;				\
+			(tvp)->tv_usec -= 1000000;			\
+		}							\
+	} while (0 /* CONSTCOND */);
+
+#if __GNUC__ > 2 || defined(__INTEL_COMPILER)
+# define _noreturn __attribute__((__noreturn__))
+# define _packed   __attribute__((__packed__))
+# define _unused   __attribute__((__unused__))
+#else
+# define _noreturn
+# define _packed
+# define _unused
+#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
+
+int set_cloexec(int);
+int set_nonblock(int);
+char *get_line(FILE * __restrict);
+extern int clock_monotonic;
+int get_monotonic(struct timeval *);
+ssize_t setvar(char ***, const char *, const char *, const char *);
+ssize_t setvard(char ***, const char *, const char *, int);
+time_t uptime(void);
+int writepid(int, pid_t);
+void *xrealloc(void *, size_t);
+void *xmalloc(size_t);
+void *xzalloc(size_t);
+char *xstrdup(const char *);
+
+/* Uncomment the #def below to send DHCPCD syslog messages to Android's logcat
+ * instead.  */
+/* #define REDIRECT_SYSLOG_TO_ANDROID_LOGCAT */
+#ifdef REDIRECT_SYSLOG_TO_ANDROID_LOGCAT
+
+#define LOG_TAG "DHCPCD"
+#include <utils/Log.h>
+
+#undef LOG_EMERG
+#undef LOG_ALERT
+#undef LOG_CRIT
+#undef LOG_ERR
+#undef LOG_WARNING
+#undef LOG_NOTICE
+#undef LOG_INFO
+#undef LOG_DEBUG
+
+#define LOG_EMERG   ANDROID_LOG_FATAL
+#define LOG_ALERT   ANDROID_LOG_FATAL
+#define LOG_CRIT    ANDROID_LOG_FATAL
+#define LOG_ERR     ANDROID_LOG_ERROR
+#define LOG_WARNING ANDROID_LOG_WARN
+#define LOG_NOTICE  ANDROID_LOG_WARN
+#define LOG_INFO    ANDROID_LOG_INFO
+#define LOG_DEBUG   ANDROID_LOG_DEBUG
+#define syslog(a, b...) android_printLog(a, LOG_TAG, b)
+
+#endif  /* REDIRECT_SYSLOG_TO_ANDROID_LOGCAT */
+
+#endif
diff --git a/dhcpcd/compat/closefrom.c b/dhcpcd/compat/closefrom.c
new file mode 100644
index 0000000..9d34a53
--- /dev/null
+++ b/dhcpcd/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/compat/closefrom.h b/dhcpcd/compat/closefrom.h
new file mode 100644
index 0000000..b028507
--- /dev/null
+++ b/dhcpcd/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/config.h b/dhcpcd/config.h
new file mode 100644
index 0000000..e9f0af3
--- /dev/null
+++ b/dhcpcd/config.h
@@ -0,0 +1,9 @@
+/* linux */
+#define SYSCONFDIR	"/system/etc/dhcpcd"
+#define SBINDIR		"/system/etc/dhcpcd"
+#define LIBEXECDIR	"/system/etc/dhcpcd"
+#define DBDIR		"/data/misc/dhcp"
+#define RUNDIR		"/data/misc/dhcp"
+#include "compat/closefrom.h"
+
+#include <sys/param.h>
diff --git a/dhcpcd/config.mk b/dhcpcd/config.mk
new file mode 100644
index 0000000..c7a9eca
--- /dev/null
+++ b/dhcpcd/config.mk
@@ -0,0 +1,20 @@
+# linux
+SYSCONFDIR=	/etc
+SBINDIR=	/sbin
+LIBEXECDIR=	/libexec
+DBDIR=		/var/db
+RUNDIR=		/var/run
+LIBDIR=		/lib
+MANDIR=		/usr/share/man
+CC=		gcc
+CPPFLAGS+=	-D_BSD_SOURCE -D_XOPEN_SOURCE=600
+SRCS+=		if-linux.c if-linux-wireless.c lpf.c
+SRCS+=		platform-linux.c
+LDADD+=		-lrt
+COMPAT_SRCS+=	compat/arc4random.c
+COMPAT_SRCS+=	compat/closefrom.c
+COMPAT_SRCS+=	compat/strlcpy.c
+SERVICEEXISTS=	/usr/sbin/invoke-rc.d --query --quiet $$1 start >/dev/null 2>\&1 || [ $$? = 104 ]
+SERVICECMD=	/usr/sbin/invoke-rc.d $$1 $$2
+SERVICESTATUS=	service_command $$1 status >/dev/null 2>\&1
+HOOKSCRIPTS=	50-ntp.conf
diff --git a/dhcpcd/configure.c b/dhcpcd/configure.c
new file mode 100644
index 0000000..fe89532
--- /dev/null
+++ b/dhcpcd/configure.c
@@ -0,0 +1,841 @@
+/* 
+ * 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.
+ */
+
+#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>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include "config.h"
+#include "common.h"
+#include "configure.h"
+#include "dhcp.h"
+#include "if-options.h"
+#include "if-pref.h"
+#include "ipv6rs.h"
+#include "net.h"
+#include "signals.h"
+
+#define DEFAULT_PATH	"PATH=/usr/bin:/usr/sbin:/bin:/sbin"
+
+/* Some systems have route metrics */
+#ifndef HAVE_ROUTE_METRIC
+# ifdef __linux__
+#  define HAVE_ROUTE_METRIC 1
+# endif
+# ifndef HAVE_ROUTE_METRIC
+#  define HAVE_ROUTE_METRIC 0
+# endif
+#endif
+
+static struct rt *routes;
+
+static int
+exec_script(char *const *argv, char *const *env)
+{
+	pid_t pid;
+	sigset_t full;
+	sigset_t old;
+
+	/* OK, we need to block signals */
+	sigfillset(&full);
+	sigprocmask(SIG_SETMASK, &full, &old);
+	signal_reset();
+
+	switch (pid = vfork()) {
+	case -1:
+		syslog(LOG_ERR, "vfork: %m");
+		break;
+	case 0:
+		sigprocmask(SIG_SETMASK, &old, NULL);
+		execve(argv[0], argv, env);
+		syslog(LOG_ERR, "%s: %m", argv[0]);
+		_exit(127);
+		/* NOTREACHED */
+	}
+
+	/* Restore our signals */
+	signal_setup();
+	sigprocmask(SIG_SETMASK, &old, NULL);
+	return pid;
+}
+
+static char *
+make_var(const char *prefix, const char *var)
+{
+	size_t len;
+	char *v;
+
+	len = strlen(prefix) + strlen(var) + 2;
+	v = xmalloc(len);
+	snprintf(v, len, "%s_%s", prefix, var);
+	return v;
+}
+
+
+static void
+append_config(char ***env, ssize_t *len,
+    const char *prefix, const char *const *config)
+{
+	ssize_t i, j, e1;
+	char **ne, *eq;
+
+	if (config == NULL)
+		return;
+
+	ne = *env;
+	for (i = 0; config[i] != NULL; i++) {
+		eq = strchr(config[i], '=');
+		e1 = eq - config[i] + 1;
+		for (j = 0; j < *len; j++) {
+			if (strncmp(ne[j] + strlen(prefix) + 1,
+				config[i], e1) == 0)
+			{
+				free(ne[j]);
+				ne[j] = make_var(prefix, config[i]);
+				break;
+			}
+		}
+		if (j == *len) {
+			j++;
+			ne = xrealloc(ne, sizeof(char *) * (j + 1));
+			ne[j - 1] = make_var(prefix, config[i]);
+			*len = j;
+		}
+	}
+	*env = ne;
+}
+
+static size_t
+arraytostr(const char *const *argv, char **s)
+{
+	const char *const *ap;
+	char *p;
+	size_t len, l;
+
+	len = 0;
+	ap = argv;
+	while (*ap)
+		len += strlen(*ap++) + 1;
+	*s = p = xmalloc(len);
+	ap = argv;
+	while (*ap) {
+		l = strlen(*ap) + 1;
+		memcpy(p, *ap, l);
+		p += l;
+		ap++;
+	}
+	return len;
+}
+
+static ssize_t
+make_env(const struct interface *iface, const char *reason, char ***argv)
+{
+	char **env, *p;
+	ssize_t e, elen, l;
+	const struct if_options *ifo = iface->state->options;
+	const struct interface *ifp;
+	int dhcp, ra;
+
+	dhcp = ra = 0;
+	if (strcmp(reason, "ROUTERADVERT") == 0)
+		ra = 1;
+	else
+		dhcp = 1;
+
+	/* When dumping the lease, we only want to report interface and
+	   reason - the other interface variables are meaningless */
+	if (options & DHCPCD_DUMPLEASE)
+		elen = 2;
+	else
+		elen = 10;
+
+	/* Make our env */
+	env = xmalloc(sizeof(char *) * (elen + 1));
+	e = strlen("interface") + strlen(iface->name) + 2;
+	env[0] = xmalloc(e);
+	snprintf(env[0], e, "interface=%s", iface->name);
+	e = strlen("reason") + strlen(reason) + 2;
+	env[1] = xmalloc(e);
+	snprintf(env[1], e, "reason=%s", reason);
+	if (options & DHCPCD_DUMPLEASE)
+		goto dumplease;
+
+ 	e = 20;
+	env[2] = xmalloc(e);
+	snprintf(env[2], e, "pid=%d", getpid());
+	env[3] = xmalloc(e);
+	snprintf(env[3], e, "ifmetric=%d", iface->metric);
+	env[4] = xmalloc(e);
+	snprintf(env[4], e, "ifwireless=%d", iface->wireless);
+	env[5] = xmalloc(e);
+	snprintf(env[5], e, "ifflags=%u", iface->flags);
+	env[6] = xmalloc(e);
+	snprintf(env[6], e, "ifmtu=%d", get_mtu(iface->name));
+	l = e = strlen("interface_order=");
+	for (ifp = ifaces; ifp; ifp = ifp->next)
+		e += strlen(ifp->name) + 1;
+	p = env[7] = xmalloc(e);
+	strlcpy(p, "interface_order=", e);
+	e -= l;
+	p += l;
+	for (ifp = ifaces; ifp; ifp = ifp->next) {
+		l = strlcpy(p, ifp->name, e);
+		p += l;
+		e -= l;
+		*p++ = ' ';
+		e--;
+	}
+	*--p = '\0';
+	if ((dhcp && iface->state->new) || (ra && iface->ras)) {
+		env[8] = strdup("if_up=true");
+		env[9] = strdup("if_down=false");
+	} else {
+		env[8] = strdup("if_up=false");
+		env[9] = strdup("if_down=true");
+	}
+	if (*iface->state->profile) {
+		e = strlen("profile=") + strlen(iface->state->profile) + 2;
+		env[elen] = xmalloc(e);
+		snprintf(env[elen++], e, "profile=%s", iface->state->profile);
+	}
+	if (iface->wireless) {
+		e = strlen("new_ssid=") + strlen(iface->ssid) + 2;
+		if (iface->state->new != NULL ||
+		    strcmp(iface->state->reason, "CARRIER") == 0)
+		{
+			env = xrealloc(env, sizeof(char *) * (elen + 2));
+			env[elen] = xmalloc(e);
+			snprintf(env[elen++], e, "new_ssid=%s", iface->ssid);
+		}
+		if (iface->state->old != NULL ||
+		    strcmp(iface->state->reason, "NOCARRIER") == 0)
+		{
+			env = xrealloc(env, sizeof(char *) * (elen + 2));
+			env[elen] = xmalloc(e);
+			snprintf(env[elen++], e, "old_ssid=%s", iface->ssid);
+		}
+	}
+	if (dhcp && iface->state->old) {
+		e = configure_env(NULL, NULL, iface->state->old, ifo);
+		if (e > 0) {
+			env = xrealloc(env, sizeof(char *) * (elen + e + 1));
+			elen += configure_env(env + elen, "old",
+			    iface->state->old, ifo);
+		}
+		append_config(&env, &elen, "old",
+		    (const char *const *)ifo->config);
+	}
+
+dumplease:
+	if (dhcp && iface->state->new) {
+		e = configure_env(NULL, NULL, iface->state->new, ifo);
+		if (e > 0) {
+			env = xrealloc(env, sizeof(char *) * (elen + e + 1));
+			elen += configure_env(env + elen, "new",
+			    iface->state->new, ifo);
+		}
+		append_config(&env, &elen, "new",
+		    (const char *const *)ifo->config);
+	}
+	if (ra) {
+		e = ipv6rs_env(NULL, NULL, iface);
+		if (e > 0) {
+			env = xrealloc(env, sizeof(char *) * (elen + e + 1));
+			elen += ipv6rs_env(env + elen, NULL, iface);
+		}
+	}
+
+	/* Add our base environment */
+	if (ifo->environ) {
+		e = 0;
+		while (ifo->environ[e++])
+			;
+		env = xrealloc(env, sizeof(char *) * (elen + e + 1));
+		e = 0;
+		while (ifo->environ[e]) {
+			env[elen + e] = xstrdup(ifo->environ[e]);
+			e++;
+		}
+		elen += e;
+	}
+	env[elen] = '\0';
+
+	*argv = env;
+	return elen;
+}
+
+static int
+send_interface1(int fd, const struct interface *iface, const char *reason)
+{
+	char **env, **ep, *s;
+	ssize_t elen;
+	struct iovec iov[2];
+	int retval;
+
+	retval = 0;
+	make_env(iface, reason, &env);
+	elen = arraytostr((const char *const *)env, &s);
+	iov[0].iov_base = &elen;
+	iov[0].iov_len = sizeof(ssize_t);
+	iov[1].iov_base = s;
+	iov[1].iov_len = elen;
+	retval = writev(fd, iov, 2);
+	ep = env;
+	while (*ep)
+		free(*ep++);
+	free(env);
+	free(s);
+	return retval;
+}
+
+int
+send_interface(int fd, const struct interface *iface)
+{
+	int retval = 0;
+	if (send_interface1(fd, iface, iface->state->reason) == -1)
+		retval = -1;
+	if (iface->ras) {
+		if (send_interface1(fd, iface, "ROUTERADVERT") == -1)
+			retval = -1;
+	}
+	return retval;
+}
+
+int
+run_script_reason(const struct interface *iface, const char *reason)
+{
+	char *const argv[2] = { UNCONST(iface->state->options->script), NULL };
+	char **env = NULL, **ep;
+	char *path, *bigenv;
+	ssize_t e, elen = 0;
+	pid_t pid;
+	int status = 0;
+	const struct fd_list *fd;
+	struct iovec iov[2];
+
+	if (iface->state->options->script == NULL ||
+	    iface->state->options->script[0] == '\0' ||
+	    strcmp(iface->state->options->script, "/dev/null") == 0)
+		return 0;
+
+	if (reason == NULL)
+		reason = iface->state->reason;
+	syslog(LOG_DEBUG, "%s: executing `%s', reason %s",
+	    iface->name, argv[0], reason);
+
+	/* Make our env */
+	elen = make_env(iface, reason, &env);
+	env = xrealloc(env, sizeof(char *) * (elen + 2));
+	/* Add path to it */
+	path = getenv("PATH");
+	if (path) {
+		e = strlen("PATH") + strlen(path) + 2;
+		env[elen] = xmalloc(e);
+		snprintf(env[elen], e, "PATH=%s", path);
+	} else
+		env[elen] = xstrdup(DEFAULT_PATH);
+	env[++elen] = '\0';
+
+	pid = exec_script(argv, env);
+	if (pid == -1)
+		status = -1;
+	else if (pid != 0) {
+		/* Wait for the script to finish */
+		while (waitpid(pid, &status, 0) == -1) {
+			if (errno != EINTR) {
+				syslog(LOG_ERR, "waitpid: %m");
+				status = -1;
+				break;
+			}
+		}
+	}
+
+	/* Send to our listeners */
+	bigenv = NULL;
+	for (fd = fds; fd != NULL; fd = fd->next) {
+		if (fd->listener) {
+			if (bigenv == NULL) {
+				elen = arraytostr((const char *const *)env,
+				    &bigenv);
+				iov[0].iov_base = &elen;
+				iov[0].iov_len = sizeof(ssize_t);
+				iov[1].iov_base = bigenv;
+				iov[1].iov_len = elen;
+			}
+			if (writev(fd->fd, iov, 2) == -1)
+				syslog(LOG_ERR, "writev: %m");
+		}
+	}
+	free(bigenv);
+
+	/* Cleanup */
+	ep = env;
+	while (*ep)
+		free(*ep++);
+	free(env);
+	return status;
+}
+
+static struct rt *
+find_route(struct rt *rts, const struct rt *r, struct rt **lrt,
+    const struct rt *srt)
+{
+	struct rt *rt;
+
+	if (lrt)
+		*lrt = NULL;
+	for (rt = rts; rt; rt = rt->next) {
+		if (rt->dest.s_addr == r->dest.s_addr &&
+#if HAVE_ROUTE_METRIC
+		    (srt || (!rt->iface ||
+			rt->iface->metric == r->iface->metric)) &&
+#endif
+                    (!srt || srt != rt) &&
+		    rt->net.s_addr == r->net.s_addr)
+			return rt;
+		if (lrt)
+			*lrt = rt;
+	}
+	return NULL;
+}
+
+static void
+desc_route(const char *cmd, const struct rt *rt)
+{
+	char addr[sizeof("000.000.000.000") + 1];
+	const char *ifname = rt->iface->name;
+
+	strlcpy(addr, inet_ntoa(rt->dest), sizeof(addr));
+	if (rt->gate.s_addr == INADDR_ANY)
+		syslog(LOG_DEBUG, "%s: %s route to %s/%d", ifname, cmd,
+		    addr, inet_ntocidr(rt->net));
+	else if (rt->gate.s_addr == rt->dest.s_addr &&
+	    rt->net.s_addr == INADDR_BROADCAST)
+		syslog(LOG_DEBUG, "%s: %s host route to %s", ifname, cmd,
+		    addr);
+	else if (rt->dest.s_addr == INADDR_ANY && rt->net.s_addr == INADDR_ANY)
+		syslog(LOG_DEBUG, "%s: %s default route via %s", ifname, cmd,
+		    inet_ntoa(rt->gate));
+	else
+		syslog(LOG_DEBUG, "%s: %s route to %s/%d via %s", ifname, cmd,
+		    addr, inet_ntocidr(rt->net), inet_ntoa(rt->gate));
+}
+
+/* If something other than dhcpcd removes a route,
+ * we need to remove it from our internal table. */
+int
+route_deleted(const struct rt *rt)
+{
+	struct rt *f, *l;
+
+	f = find_route(routes, rt, &l, NULL);
+	if (f == NULL)
+		return 0;
+	desc_route("removing", f);
+	if (l)
+		l->next = f->next;
+	else
+		routes = f->next;
+	free(f);
+	return 1;
+}
+
+static int
+n_route(struct rt *rt)
+{
+	/* Don't set default routes if not asked to */
+	if (rt->dest.s_addr == 0 &&
+	    rt->net.s_addr == 0 &&
+	    !(rt->iface->state->options->options & DHCPCD_GATEWAY))
+		return -1;
+
+	desc_route("adding", rt);
+	if (!add_route(rt))
+		return 0;
+	if (errno == EEXIST) {
+		/* Pretend we added the subnet route */
+		if (rt->dest.s_addr ==
+		    (rt->iface->addr.s_addr & rt->iface->net.s_addr) &&
+		    rt->net.s_addr == rt->iface->net.s_addr &&
+		    rt->gate.s_addr == 0)
+			return 0;
+		else
+			return -1;
+	}
+	syslog(LOG_ERR, "%s: add_route: %m", rt->iface->name);
+	return -1;
+}
+
+static int
+c_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->state->options->options & DHCPCD_GATEWAY))
+		return -1;
+
+	desc_route("changing", nrt);
+	/* We delete and add the route so that we can change metric.
+	 * This also has the nice side effect of flushing ARP entries so
+	 * we don't have to do that manually. */
+	del_route(ort);
+	if (!add_route(nrt))
+		return 0;
+	syslog(LOG_ERR, "%s: add_route: %m", nrt->iface->name);
+	return -1;
+}
+
+static int
+d_route(struct rt *rt)
+{
+	int retval;
+
+	desc_route("deleting", rt);
+	retval = del_route(rt);
+	if (retval != 0 && errno != ENOENT && errno != ESRCH)
+		syslog(LOG_ERR,"%s: del_route: %m", rt->iface->name);
+	return retval;
+}
+
+static struct rt *
+get_subnet_route(struct dhcp_message *dhcp)
+{
+	in_addr_t addr;
+	struct in_addr net;
+	struct rt *rt;
+
+	addr = dhcp->yiaddr;
+	if (addr == 0)
+		addr = dhcp->ciaddr;
+	/* Ensure we have all the needed values */
+	if (get_option_addr(&net, dhcp, DHO_SUBNETMASK) == -1)
+		net.s_addr = get_netmask(addr);
+	if (net.s_addr == INADDR_BROADCAST || net.s_addr == INADDR_ANY)
+		return NULL;
+	rt = malloc(sizeof(*rt));
+	rt->dest.s_addr = addr & net.s_addr;
+	rt->net.s_addr = net.s_addr;
+	rt->gate.s_addr = 0;
+	return rt;
+}
+
+static struct rt *
+add_subnet_route(struct rt *rt, const struct interface *iface)
+{
+	struct rt *r;
+
+	if (iface->net.s_addr == INADDR_BROADCAST ||
+	    iface->net.s_addr == INADDR_ANY ||
+	    (iface->state->options->options &
+	     (DHCPCD_INFORM | DHCPCD_STATIC) &&
+	     iface->state->options->req_addr.s_addr == INADDR_ANY))
+		return rt;
+
+	r = xmalloc(sizeof(*r));
+	r->dest.s_addr = iface->addr.s_addr & iface->net.s_addr;
+	r->net.s_addr = iface->net.s_addr;
+	r->gate.s_addr = 0;
+	r->next = rt;
+	return r;
+}
+
+static struct rt *
+get_routes(const struct interface *iface)
+{
+	struct rt *rt, *nrt = NULL, *r = NULL;
+
+	if (iface->state->options->routes != NULL) {
+		for (rt = iface->state->options->routes;
+		     rt != NULL;
+		     rt = rt->next)
+		{
+			if (rt->gate.s_addr == 0)
+				break;
+			if (r == NULL)
+				r = nrt = xmalloc(sizeof(*r));
+			else {
+				r->next = xmalloc(sizeof(*r));
+				r = r->next;
+			}
+			memcpy(r, rt, sizeof(*r));
+			r->next = NULL;
+		}
+		return nrt;
+	}
+
+	return get_option_routes(iface->state->new,
+	    iface->name, &iface->state->options->options);
+}
+
+/* Some DHCP servers add set host routes by setting the gateway
+ * to the assinged IP address. This differs from our notion of a host route
+ * where the gateway is the destination address, so we fix it. */
+static struct rt *
+massage_host_routes(struct rt *rt, const struct interface *iface)
+{
+	struct rt *r;
+
+	for (r = rt; r; r = r->next)
+		if (r->gate.s_addr == iface->addr.s_addr &&
+		    r->net.s_addr == INADDR_BROADCAST)
+			r->gate.s_addr = r->dest.s_addr;
+	return rt;
+}
+
+static struct rt *
+add_destination_route(struct rt *rt, const struct interface *iface)
+{
+	struct rt *r;
+
+	if (!(iface->flags & IFF_POINTOPOINT) ||
+	    !has_option_mask(iface->state->options->dstmask, DHO_ROUTER))
+		return rt;
+	r = xmalloc(sizeof(*r));
+	r->dest.s_addr = INADDR_ANY;
+	r->net.s_addr = INADDR_ANY;
+	r->gate.s_addr = iface->dst.s_addr;
+	r->next = rt;
+	return r;
+}
+
+/* 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 *
+add_router_host_route(struct rt *rt, const struct interface *ifp)
+{
+	struct rt *rtp, *rtl, *rtn;
+	const char *cp, *cp2, *cp3, *cplim;
+
+	for (rtp = rt, rtl = NULL; rtp; rtl = rtp, rtp = rtp->next) {
+		if (rtp->dest.s_addr != INADDR_ANY)
+			continue;
+		/* Scan for a route to match */
+		for (rtn = rt; rtn != rtp; rtn = rtn->next) {
+			/* 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;
+		if (ifp->flags & IFF_NOARP) {
+			syslog(LOG_WARNING,
+			    "%s: forcing router %s through interface",
+			    ifp->name, inet_ntoa(rtp->gate));
+			rtp->gate.s_addr = 0;
+			continue;
+		}
+		syslog(LOG_WARNING, "%s: router %s requires a host route",
+		    ifp->name, inet_ntoa(rtp->gate));
+		rtn = xmalloc(sizeof(*rtn));
+		rtn->dest.s_addr = rtp->gate.s_addr;
+		rtn->net.s_addr = INADDR_BROADCAST;
+		rtn->gate.s_addr = rtp->gate.s_addr;
+		rtn->next = rtp;
+		if (rtl == NULL)
+			rt = rtn;
+		else
+			rtl->next = rtn;
+	}
+	return rt;
+}
+
+void
+build_routes(void)
+{
+	struct rt *nrs = NULL, *dnr, *or, *rt, *rtn, *rtl, *lrt = NULL;
+	const struct interface *ifp;
+
+	if (avoid_routes) return;
+
+	for (ifp = ifaces; ifp; ifp = ifp->next) {
+		if (ifp->state->new == NULL)
+			continue;
+		dnr = get_routes(ifp);
+		dnr = massage_host_routes(dnr, ifp);
+		dnr = add_subnet_route(dnr, ifp);
+		dnr = add_router_host_route(dnr, ifp);
+		dnr = add_destination_route(dnr, ifp);
+		for (rt = dnr; rt && (rtn = rt->next, 1); lrt = rt, rt = rtn) {
+			rt->iface = ifp;
+			rt->metric = ifp->metric;
+			/* Is this route already in our table? */
+			if ((find_route(nrs, rt, NULL, NULL)) != NULL)
+				continue;
+			rt->src.s_addr = ifp->addr.s_addr;
+			/* Do we already manage it? */
+			if ((or = find_route(routes, rt, &rtl, NULL))) {
+				if (or->iface != ifp ||
+				    or->src.s_addr != ifp->addr.s_addr ||
+				    rt->gate.s_addr != or->gate.s_addr ||
+				    rt->metric != or->metric)
+				{
+					if (c_route(or, rt) != 0)
+						continue;
+				}
+				if (rtl != NULL)
+					rtl->next = or->next;
+				else
+					routes = or->next;
+				free(or);
+			} else {
+				if (n_route(rt) != 0)
+					continue;
+			}
+			if (dnr == rt)
+				dnr = rtn;
+			else if (lrt)
+				lrt->next = rtn;
+			rt->next = nrs;
+			nrs = rt;
+			rt = lrt; /* When we loop this makes lrt correct */
+		}
+		free_routes(dnr);
+	}
+
+	/* Remove old routes we used to manage */
+	for (rt = routes; rt; rt = rt->next) {
+		if (find_route(nrs, rt, NULL, NULL) == NULL)
+			d_route(rt);
+	}
+
+	free_routes(routes);
+	routes = nrs;
+}
+
+static int
+delete_address(struct interface *iface)
+{
+	int retval;
+	struct if_options *ifo;
+
+	ifo = iface->state->options;
+	if (ifo->options & DHCPCD_INFORM ||
+	    (ifo->options & DHCPCD_STATIC && ifo->req_addr.s_addr == 0))
+		return 0;
+	syslog(LOG_DEBUG, "%s: deleting IP address %s/%d",
+	    iface->name,
+	    inet_ntoa(iface->addr),
+	    inet_ntocidr(iface->net));
+	retval = del_address(iface, &iface->addr, &iface->net);
+	if (retval == -1 && errno != EADDRNOTAVAIL) 
+		syslog(LOG_ERR, "del_address: %m");
+	iface->addr.s_addr = 0;
+	iface->net.s_addr = 0;
+	return retval;
+}
+
+int
+configure(struct interface *iface)
+{
+	struct dhcp_message *dhcp = iface->state->new;
+	struct dhcp_lease *lease = &iface->state->lease;
+	struct if_options *ifo = iface->state->options;
+	struct rt *rt;
+
+	/* As we are now adjusting an interface, we need to ensure
+	 * we have them in the right order for routing and configuration. */
+	sort_interfaces();
+
+	if (dhcp == NULL) {
+		if (!(ifo->options & DHCPCD_PERSISTENT)) {
+			build_routes();
+			if (iface->addr.s_addr != 0)
+				delete_address(iface);
+			run_script(iface);
+		}
+		return 0;
+	}
+
+	/* This also changes netmask */
+	if (!(ifo->options & DHCPCD_INFORM) ||
+	    !has_address(iface->name, &lease->addr, &lease->net))
+	{
+		syslog(LOG_DEBUG, "%s: adding IP address %s/%d",
+		    iface->name, inet_ntoa(lease->addr),
+		    inet_ntocidr(lease->net));
+		if (add_address(iface,
+			&lease->addr, &lease->net, &lease->brd) == -1 &&
+		    errno != EEXIST)
+		{
+			syslog(LOG_ERR, "add_address: %m");
+			return -1;
+		}
+	}
+
+	/* Now delete the old address if different */
+	if (iface->addr.s_addr != lease->addr.s_addr &&
+	    iface->addr.s_addr != 0)
+		delete_address(iface);
+
+	iface->addr.s_addr = lease->addr.s_addr;
+	iface->net.s_addr = lease->net.s_addr;
+
+	if (!avoid_routes) {
+		/* We need to delete the subnet route to have our metric or
+		 * prefer the interface. */
+		rt = get_subnet_route(dhcp);
+		if (rt != NULL) {
+			rt->iface = iface;
+			rt->metric = 0;
+			if (!find_route(routes, rt, NULL, NULL))
+				del_route(rt);
+			free(rt);
+		}
+
+		build_routes();
+	}
+
+	if (!iface->state->lease.frominfo &&
+	    !(ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC)))
+		if (write_lease(iface, dhcp) == -1)
+			syslog(LOG_ERR, "write_lease: %m");
+	run_script(iface);
+	return 0;
+}
diff --git a/dhcpcd/configure.h b/dhcpcd/configure.h
new file mode 100644
index 0000000..e125369
--- /dev/null
+++ b/dhcpcd/configure.h
@@ -0,0 +1,40 @@
+/* 
+ * 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 DHCPCONFIG_H
+#define DHCPCONFIG_H
+
+#include "net.h"
+
+int send_interface(int, const struct interface *);
+int run_script_reason(const struct interface *, const char *);
+void build_routes(void);
+int configure(struct interface *);
+int route_deleted(const struct rt *);
+
+#define run_script(ifp) run_script_reason(ifp, (ifp)->state->reason);
+#endif
diff --git a/dhcpcd/control.c b/dhcpcd/control.c
new file mode 100644
index 0000000..24fb354
--- /dev/null
+++ b/dhcpcd/control.c
@@ -0,0 +1,208 @@
+/* 
+ * 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 <linux/socket.h>
+#include <sys/stat.h>
+#include <sys/un.h>
+
+#include <errno.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"
+
+static int fd = -1;
+static char buffer[1024];
+static char *argvp[255];
+
+struct sockaddr_un sun;
+struct fd_list *fds = NULL;
+
+static void
+remove_control_data(void *arg)
+{
+	struct fd_list *l, *last = NULL;
+
+	for (l = fds; l != NULL; l = l->next) {
+		if (l == arg) {
+			close(l->fd);
+			delete_event(l->fd);
+			if (last == NULL)
+				fds = l->next;
+			else
+				last->next = l->next;
+			free(l);
+			break;
+		}
+		last = l;
+	}
+}
+
+static void
+handle_control_data(void *arg)
+{
+	struct fd_list *l = arg;
+	ssize_t bytes;
+	int argc;
+	char *e, *p;
+	char **ap;
+
+	bytes = read(l->fd, buffer, sizeof(buffer) - 1);
+	if (bytes == -1 || bytes == 0) {
+		remove_control_data(l);
+		return;
+	}
+	buffer[bytes] = '\0';
+	p = buffer;
+	e = buffer + bytes;
+	argc = 0;
+	ap = argvp;
+	while (p < e && (size_t)argc < sizeof(argvp)) {
+		argc++;
+		*ap++ = p;
+		p += strlen(p) + 1;
+	}
+	handle_args(l, argc, argvp);
+}
+
+/* ARGSUSED */
+static void
+handle_control(_unused void *arg)
+{
+	struct sockaddr_un run;
+	socklen_t len;
+	struct fd_list *l;
+	int f;
+
+	len = sizeof(run);
+	if ((f = accept(fd, (struct sockaddr *)&run, &len)) == -1)
+		return;
+	l = xmalloc(sizeof(*l));
+	l->fd = f;
+	l->listener = 0;
+	l->next = fds;
+	fds = l;
+	add_event(l->fd, handle_control_data, l);
+}
+
+static int
+make_sock(void)
+{
+	if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
+		return -1;
+	memset(&sun, 0, sizeof(sun));
+	sun.sun_family = AF_UNIX;
+	strlcpy(sun.sun_path, CONTROLSOCKET, sizeof(sun.sun_path));
+	return sizeof(sun.sun_family) + strlen(sun.sun_path) + 1;
+}
+
+int
+start_control(void)
+{
+	int len;
+
+	if ((len = make_sock()) == -1)
+		return -1;
+	unlink(CONTROLSOCKET);
+	if (bind(fd, (struct sockaddr *)&sun, len) == -1 ||
+	    chmod(CONTROLSOCKET,
+		S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP) == -1 ||
+	    set_cloexec(fd) == -1 ||
+	    set_nonblock(fd) == -1 ||
+	    listen(fd, sizeof(fds)) == -1)
+	{
+		close(fd);
+		return -1;
+	}
+	add_event(fd, handle_control, NULL);
+	return fd;
+}
+
+int
+stop_control(void)
+{
+	int retval = 0;
+	struct fd_list *l, *ll;
+
+	delete_event(fd);
+	if (shutdown(fd, SHUT_RDWR) == -1)
+		retval = 1;
+	fd = -1;
+	if (unlink(CONTROLSOCKET) == -1)
+		retval = -1;
+
+	l = fds;
+	while (l != NULL) {
+		ll = l->next;
+		delete_event(l->fd);
+		shutdown(l->fd, SHUT_RDWR);
+		free(l);
+		l = ll;
+	}
+
+	return retval;
+}
+
+int
+open_control(void)
+{
+	int len;
+
+	if ((len = make_sock()) == -1)
+		return -1;
+	return connect(fd, (struct sockaddr *)&sun, len);
+}
+
+int
+send_control(int argc, char * const *argv)
+{
+	char *p = buffer;
+	int i;
+	size_t len;
+
+	if (argc > 255) {
+		errno = ENOBUFS;
+		return -1;
+	}
+	for (i = 0; i < argc; i++) {
+		len = strlen(argv[i]) + 1;
+		if ((p - buffer) + len > sizeof(buffer)) {
+			errno = ENOBUFS;
+			return -1;
+		}
+		memcpy(p, argv[i], len);
+		p += len;
+	}
+	return write(fd, buffer, p - buffer);
+}
diff --git a/dhcpcd/control.h b/dhcpcd/control.h
new file mode 100644
index 0000000..f0faa40
--- /dev/null
+++ b/dhcpcd/control.h
@@ -0,0 +1,45 @@
+/* 
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2008 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"
+
+struct fd_list {
+	int fd;
+	int listener;
+	struct fd_list *next;
+};
+extern struct fd_list *fds;
+
+int start_control(void);
+int stop_control(void);
+int open_control(void);
+int send_control(int, char * const *);
+
+#endif
diff --git a/dhcpcd/defs.h b/dhcpcd/defs.h
new file mode 100644
index 0000000..b4f2380
--- /dev/null
+++ b/dhcpcd/defs.h
@@ -0,0 +1,52 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2012 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			"5.5.6"
+
+#ifndef CONFIG
+# define CONFIG			SYSCONFDIR "/" PACKAGE ".conf"
+#endif
+#ifndef SCRIPT
+# define SCRIPT			LIBEXECDIR "/" PACKAGE "-run-hooks"
+#endif
+#ifndef DUID
+# define DUID			SYSCONFDIR "/" PACKAGE ".duid"
+#endif
+#ifndef LEASEFILE
+# define LEASEFILE		DBDIR "/" PACKAGE "-%s.lease"
+#endif
+#ifndef PIDFILE
+# define PIDFILE		RUNDIR "/" PACKAGE "%s%s.pid"
+#endif
+#ifndef CONTROLSOCKET
+# define CONTROLSOCKET		RUNDIR "/" PACKAGE ".sock"
+#endif
+
+#endif
diff --git a/dhcpcd/dhcp.c b/dhcpcd/dhcp.c
new file mode 100644
index 0000000..b3f7cb1
--- /dev/null
+++ b/dhcpcd/dhcp.c
@@ -0,0 +1,1510 @@
+/* 
+ * 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.
+ */
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include "config.h"
+#include "common.h"
+#include "dhcp.h"
+
+#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 IPV4	(1 << 6)
+#define STRING	(1 << 7)
+#define PAIR	(1 << 8)
+#define ARRAY	(1 << 9)
+#define RFC3361	(1 << 10)
+#define RFC3397	(1 << 11)
+#define RFC3442 (1 << 12)
+#define RFC5969 (1 << 13)
+
+#define IPV4R	IPV4 | REQUEST
+
+#define DAD	"Duplicate address detected"
+
+/* Our aggregate option buffer.
+ * We ONLY use this when options are split, which for most purposes is
+ * practically never. See RFC3396 for details. */
+static uint8_t *opt_buffer;
+
+struct dhcp_opt {
+	uint8_t option;
+	int type;
+	const char *var;
+};
+
+static const struct dhcp_opt const dhcp_opts[] = {
+	{ 1,	IPV4 | REQUEST,	"subnet_mask" },
+		/* RFC 3442 states that the CSR has to come before all other
+		 * routes. For completeness, we also specify static routes,
+	 	 * then routers. */
+	{ 121,  RFC3442,	"classless_static_routes" },
+	{ 249,  RFC3442,	"ms_classless_static_routes" },
+	{ 33,	IPV4 | ARRAY | REQUEST,	"static_routes" },
+	{ 3,	IPV4 | ARRAY | REQUEST,	"routers" },
+	{ 2,	UINT32,		"time_offset" },
+	{ 4,	IPV4 | ARRAY,	"time_servers" },
+	{ 5,	IPV4 | ARRAY,	"ien116_name_servers" },
+        /* Explicitly include DNS in the list of parameters requested in the DNS request.
+         * Without this some DHCP servers may skip the DNS entries in the DHCP replies.*/
+	{ 6,	IPV4 | ARRAY | REQUEST, "domain_name_servers" },
+	{ 7,	IPV4 | ARRAY,	"log_servers" },
+	{ 8,	IPV4 | ARRAY,	"cookie_servers" },
+	{ 9, 	IPV4 | ARRAY,	"lpr_servers" },
+	{ 10,	IPV4 | ARRAY,	"impress_servers" },
+	{ 11,	IPV4 | ARRAY,	"resource_location_servers" },
+	{ 12,	STRING,		"host_name" },
+	{ 13,	UINT16,		"boot_size" },
+	{ 14,	STRING,		"merit_dump" },
+        /* Explicitly include DNS in the list of parameters requested in the DNS request.
+         * Without this some DHCP servers may skip the DNS entries in the DHCP replies.*/
+	{ 15,	STRING | REQUEST, "domain_name" },
+	{ 16,	IPV4,		"swap_server" },
+	{ 17,	STRING,		"root_path" },
+	{ 18,	STRING,		"extensions_path" },
+	{ 19,	UINT8,		"ip_forwarding" },
+	{ 20,	UINT8,		"non_local_source_routing" },
+	{ 21,	IPV4 | ARRAY,	"policy_filter" },
+	{ 22,	SINT16,		"max_dgram_reassembly" },
+	{ 23,	UINT16,		"default_ip_ttl" },
+	{ 24,	UINT32,		"path_mtu_aging_timeout" },
+	{ 25,	UINT16 | ARRAY,	"path_mtu_plateau_table" },
+	{ 26,	UINT16,		"interface_mtu" },
+	{ 27,	UINT8,		"all_subnets_local" },
+	{ 28,	IPV4 | REQUEST,	"broadcast_address" },
+	{ 29,	UINT8,		"perform_mask_discovery" },
+	{ 30,	UINT8,		"mask_supplier" },
+	{ 31,	UINT8,		"router_discovery" },
+	{ 32,	IPV4,		"router_solicitation_address" },
+	{ 34,	UINT8,		"trailer_encapsulation" },
+	{ 35, 	UINT32,		"arp_cache_timeout" },
+	{ 36,	UINT16,		"ieee802_3_encapsulation" },
+	{ 37,	UINT8,		"default_tcp_ttl" },
+	{ 38,	UINT32,		"tcp_keepalive_interval" },
+	{ 39,	UINT8,		"tcp_keepalive_garbage" },
+	{ 40,	STRING,		"nis_domain" },
+	{ 41,	IPV4 | ARRAY,	"nis_servers" },
+	{ 42,	IPV4 | ARRAY,	"ntp_servers" },
+	{ 43,	STRING,		"vendor_encapsulated_options" },
+	{ 44,	IPV4 | ARRAY,	"netbios_name_servers" },
+	{ 45,	IPV4,		"netbios_dd_server" },
+	{ 46,	UINT8,		"netbios_node_type" },
+	{ 47,	STRING,		"netbios_scope" },
+	{ 48,	IPV4 | ARRAY,	"font_servers" },
+	{ 49,	IPV4 | ARRAY,	"x_display_manager" },
+	{ 50, 	IPV4,		"dhcp_requested_address" },
+	{ 51,	UINT32 | REQUEST,	"dhcp_lease_time" },
+	{ 52,	UINT8,		"dhcp_option_overload" },
+	{ 53,	UINT8,		"dhcp_message_type" },
+	{ 54,	IPV4,		"dhcp_server_identifier" },
+	{ 55,	UINT8 | ARRAY,	"dhcp_parameter_request_list" },
+	{ 56,	STRING,		"dhcp_message" },
+	{ 57,	UINT16,		"dhcp_max_message_size" },
+	{ 58,	UINT32 | REQUEST,	"dhcp_renewal_time" },
+	{ 59,	UINT32 | REQUEST,	"dhcp_rebinding_time" },
+	{ 64,	STRING,		"nisplus_domain" },
+	{ 65,	IPV4 | ARRAY,	"nisplus_servers" },
+	{ 66,	STRING,		"tftp_server_name" },
+	{ 67,	STRING,		"bootfile_name" },
+	{ 68,	IPV4 | ARRAY,	"mobile_ip_home_agent" },
+	{ 69,	IPV4 | ARRAY,	"smtp_server" },
+	{ 70,	IPV4 | ARRAY,	"pop_server" },
+	{ 71,	IPV4 | ARRAY,	"nntp_server" },
+	{ 72,	IPV4 | ARRAY,	"www_server" },
+	{ 73,	IPV4 | ARRAY,	"finger_server" },
+	{ 74,	IPV4 | ARRAY,	"irc_server" },
+	{ 75,	IPV4 | ARRAY,	"streettalk_server" },
+	{ 76,	IPV4 | ARRAY,	"streettalk_directory_assistance_server" },
+	{ 77,	STRING,		"user_class" },
+	{ 81,	STRING | RFC3397,	"fqdn_name" },
+	{ 85,	IPV4 | ARRAY,	"nds_servers" },
+	{ 86,	STRING,		"nds_tree_name" },
+	{ 87,	STRING,		"nds_context" },
+	{ 88,	STRING | RFC3397,	"bcms_controller_names" },
+	{ 89,	IPV4 | ARRAY,	"bcms_controller_address" },
+	{ 91,	UINT32,		"client_last_transaction_time" },
+	{ 92,	IPV4 | ARRAY,	"associated_ip" },
+	{ 98,	STRING,		"uap_servers" },
+	{ 112,	IPV4 | ARRAY,	"netinfo_server_address" },
+	{ 113,	STRING,		"netinfo_server_tag" },
+	{ 114,	STRING,		"default_url" },
+	{ 118,	IPV4,		"subnet_selection" },
+	{ 119,	STRING | RFC3397,	"domain_search" },
+	{ 120,	STRING | RFC3361,	"sip_server" },
+	{ 212,  RFC5969,	"sixrd" },
+	{ 0, 0, NULL }
+};
+
+static const char *if_params[] = {
+	"interface",
+	"reason",
+	"pid",
+	"ifmetric",
+	"ifwireless",
+	"ifflags",
+	"profile",
+	"interface_order",
+	NULL
+};
+
+static const char *dhcp_params[] = {
+	"ip_address",
+	"subnet_cidr",
+	"network_number",
+	"ssid",
+	"filename",
+	"server_name",
+	NULL
+};
+
+void
+print_options(void)
+{
+	const struct dhcp_opt *opt;
+	const char **p;
+
+	for (p = if_params; *p; p++)
+		printf(" -  %s\n", *p);
+
+	for (p = dhcp_params; *p; p++)
+		printf("    %s\n", *p);
+
+	for (opt = dhcp_opts; opt->option; opt++)
+		if (opt->var)
+			printf("%03d %s\n", opt->option, opt->var);
+}
+
+int make_option_mask(uint8_t *mask, const char *opts, int add)
+{
+	char *token, *o, *p, *t;
+	const struct dhcp_opt *opt;
+	int match, n;
+
+	o = p = xstrdup(opts);
+	while ((token = strsep(&p, ", "))) {
+		if (*token == '\0')
+			continue;
+		for (opt = dhcp_opts; opt->option; opt++) {
+			if (!opt->var)
+				continue;
+			match = 0;
+			if (strcmp(opt->var, token) == 0)
+				match = 1;
+			else {
+				errno = 0;
+				n = strtol(token, &t, 0);
+				if (errno == 0 && !*t)
+					if (opt->option == n)
+						match = 1;
+			}
+			if (match) {
+				if (add == 2 && !(opt->type & IPV4)) {
+					free(o);
+					errno = EINVAL;
+					return -1;
+				}
+				if (add == 1 || add == 2)
+					add_option_mask(mask,
+					    opt->option);
+				else
+					del_option_mask(mask,
+					    opt->option);
+				break;
+			}
+		}
+		if (!opt->option) {
+			free(o);
+			errno = ENOENT;
+			return -1;
+		}
+	}
+	free(o);
+	return 0;
+}
+
+static int
+valid_length(uint8_t option, int dl, int *type)
+{
+	const struct dhcp_opt *opt;
+	ssize_t sz;
+
+	if (dl == 0)
+		return -1;
+
+	for (opt = dhcp_opts; opt->option; opt++) {
+		if (opt->option != option)
+			continue;
+
+		if (type)
+			*type = opt->type;
+		/* The size of RFC3442 and RFC5969 options is checked at a later
+		 * stage in the code */
+		if (opt->type == 0 ||
+		    opt->type & (STRING | RFC3442 | RFC5969))
+			return 0;
+		/* The code does not use SINT16 / SINT32 together with ARRAY.
+		 * It is however far easier to reason about the code if all
+		 * possible array elements are included, and also does not code
+		 * any additional CPU resources. sizeof(uintXX_t) ==
+		 * sizeof(intXX_t) can be assumed. */
+		sz = 0;
+		if (opt->type & (UINT32 | SINT32 | IPV4))
+			sz = sizeof(uint32_t);
+		else if (opt->type & (UINT16 | SINT16))
+			sz = sizeof(uint16_t);
+		else if (opt->type & UINT8)
+			sz = sizeof(uint8_t);
+		if (opt->type & ARRAY) {
+			/* The result of modulo zero is undefined. There are no
+			 * options defined in this file that do not match one of
+			 * the if-clauses above, so the following is not really
+			 * necessary. However, to avoid confusion and unexpected
+			 * behavior if the defined options are ever extended,
+			 * returning false here seems sensible. */
+			if (!sz) return -1;
+			return (dl % sz == 0) ? 0 : -1;
+		}
+		return (sz == dl) ? 0 : -1;
+	}
+
+	/* unknown option, so let it pass */
+	return 0;
+}
+
+#ifdef DEBUG_MEMORY
+static void
+free_option_buffer(void)
+{
+	free(opt_buffer);
+}
+#endif
+
+#define get_option_raw(dhcp, opt) get_option(dhcp, opt, NULL, NULL)
+static const uint8_t *
+get_option(const struct dhcp_message *dhcp, uint8_t opt, int *len, int *type)
+{
+	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;
+	int bl = 0;
+
+	/* DHCP Options are in TLV format with T and L each being a single
+	 * byte.  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 (!opt_buffer) {
+					opt_buffer = xmalloc(sizeof(*dhcp));
+#ifdef DEBUG_MEMORY
+					atexit(free_option_buffer);
+#endif
+				}
+				if (!bp) 
+					bp = opt_buffer;
+				memcpy(bp, op, ol);
+				bp += ol;
+			}
+			ol = (p + *p < e) ? *p : e - (p + 1);
+			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 &= ~1;
+				p = dhcp->bootfile;
+				e = p + sizeof(dhcp->bootfile);
+			} else if (overl & 2) {
+				/* bit 2 set means parse server name */
+				overl &= ~2;
+				p = dhcp->servername;
+				e = p + sizeof(dhcp->servername);
+			} else
+				goto exit;
+			break;
+		case DHO_OPTIONSOVERLOADED:
+			/* Ensure we only get this option once */
+			if (!overl)
+				overl = 0x80 | p[1];
+			break;
+		}
+		l = *p++;
+		p += l;
+	}
+
+exit:
+	if (valid_length(opt, bl, type) == -1) {
+		errno = EINVAL;
+		return NULL;
+	}
+	if (len)
+		*len = bl;
+	if (bp) {
+		memcpy(bp, op, ol);
+		return (const uint8_t *)opt_buffer;
+	}
+	if (op)
+		return op;
+	errno = ENOENT;
+	return NULL;
+}
+
+int
+get_option_addr(struct in_addr *a, const struct dhcp_message *dhcp,
+    uint8_t option)
+{
+	const uint8_t *p = get_option_raw(dhcp, option);
+
+	if (!p)
+		return -1;
+	memcpy(&a->s_addr, p, sizeof(a->s_addr));
+	return 0;
+}
+
+int
+get_option_uint32(uint32_t *i, const struct dhcp_message *dhcp, uint8_t option)
+{
+	const uint8_t *p = get_option_raw(dhcp, option);
+	uint32_t d;
+
+	if (!p)
+		return -1;
+	memcpy(&d, p, sizeof(d));
+	*i = ntohl(d);
+	return 0;
+}
+
+int
+get_option_uint16(uint16_t *i, const struct dhcp_message *dhcp, uint8_t option)
+{
+	const uint8_t *p = get_option_raw(dhcp, option);
+	uint16_t d;
+
+	if (!p)
+		return -1;
+	memcpy(&d, p, sizeof(d));
+	*i = ntohs(d);
+	return 0;
+}
+
+int
+get_option_uint8(uint8_t *i, const struct dhcp_message *dhcp, uint8_t option)
+{
+	const uint8_t *p = get_option_raw(dhcp, option);
+
+	if (!p)
+		return -1;
+	if (i)
+		*i = *(p);
+	return 0;
+}
+
+/* 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, ssize_t len, int pl, const uint8_t *p)
+{
+	const uint8_t *r, *q = p;
+	int count = 0, l, hops;
+	uint8_t ltype;
+
+	while (q - p < pl) {
+		r = NULL;
+		hops = 0;
+		/* We check we are inside our length again incase
+		 * the data is NOT terminated correctly. */
+		while ((l = *q++) && q - p < pl) {
+			ltype = l & 0xc0;
+			if (ltype == 0x80 || ltype == 0x40)
+				return 0;
+			else if (ltype == 0xc0) { /* pointer */
+				l = (l & 0x3f) << 8;
+				l |= *q++;
+				/* save source of first jump. */
+				if (!r)
+					r = q;
+				hops++;
+				if (hops > 255)
+					return 0;
+				q = p + l;
+				if (q - p >= pl)
+					return 0;
+			} else {
+				/* straightforward name segment, add with '.' */
+				count += l + 1;
+				if (out) {
+					if ((ssize_t)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 - 1) = ' ';
+		if (r)
+			q = r;
+	}
+
+	/* change last space to zero terminator */
+	if (out)
+		*(out - 1) = 0;
+
+	return count;  
+}
+
+static ssize_t
+decode_rfc3442(char *out, ssize_t len, int pl, const uint8_t *p)
+{
+	const uint8_t *e;
+	ssize_t b, bytes = 0, ocets;
+	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 = (cidr + 7) / 8;
+		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 -= b;
+
+		/* Finally, snag the router */
+		memcpy(&addr.s_addr, p, 4);
+		p += 4;
+		b = snprintf(o, len, " %s", inet_ntoa(addr));
+		o += b;
+		len -= b;
+	}
+
+	if (out)
+		return o - out;
+	return bytes;
+}
+
+static struct rt *
+decode_rfc3442_rt(int dl, const uint8_t *data)
+{
+	const uint8_t *p = data;
+	const uint8_t *e;
+	uint8_t cidr;
+	size_t ocets;
+	struct rt *routes = NULL;
+	struct rt *rt = NULL;
+
+	/* Minimum is 5 -first is CIDR and a router length of 4 */
+	if (dl < 5)
+		return NULL;
+
+	e = p + dl;
+	while (p < e) {
+		cidr = *p++;
+		if (cidr > 32) {
+			free_routes(routes);
+			errno = EINVAL;
+			return NULL;
+		}
+
+		if (rt) {
+			rt->next = xzalloc(sizeof(*rt));
+			rt = rt->next;
+		} else {
+			routes = rt = xzalloc(sizeof(*routes));
+		}
+		rt->next = NULL;
+
+		ocets = (cidr + 7) / 8;
+		/* 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;
+}
+
+static char *
+decode_rfc3361(int dl, const uint8_t *data)
+{
+	uint8_t enc;
+	unsigned int l;
+	char *sip = NULL;
+	struct in_addr addr;
+	char *p;
+
+	if (dl < 2) {
+		errno = EINVAL;
+		return 0;
+	}
+
+	enc = *data++;
+	dl--;
+	switch (enc) {
+	case 0:
+		if ((l = decode_rfc3397(NULL, 0, dl, data)) > 0) {
+			sip = xmalloc(l);
+			decode_rfc3397(sip, l, dl, data);
+		}
+		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 = xmalloc(l);
+		while (dl != 0) {
+			memcpy(&addr.s_addr, data, sizeof(addr.s_addr));
+			data += sizeof(addr.s_addr);
+			p += snprintf(p, l - (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. */
+static ssize_t
+decode_rfc5969(char *out, ssize_t len, int pl, const uint8_t *p)
+{
+	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 -= 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 -= b;
+			out += b;
+			bytes += b;
+		} else {
+			bytes += (4 * 4);
+		}
+	}
+	
+	return bytes;
+}
+
+char *
+get_option_string(const struct dhcp_message *dhcp, uint8_t option)
+{
+	int type = 0;
+	int len;
+	const uint8_t *p;
+	char *s;
+
+	p = get_option(dhcp, option, &len, &type);
+	if (!p || *p == '\0')
+		return NULL;
+
+	if (type & RFC3397) {
+		type = decode_rfc3397(NULL, 0, len, p);
+		if (!type) {
+			errno = EINVAL;
+			return NULL;
+		}
+		s = xmalloc(sizeof(char) * type);
+		decode_rfc3397(s, type, len, p);
+		return s;
+	}
+
+	if (type & RFC3361)
+		return decode_rfc3361(len, p);
+
+	s = xmalloc(sizeof(char) * (len + 1));
+	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 *
+get_option_routes(const struct dhcp_message *dhcp,
+    const char *ifname, unsigned long long *opts)
+{
+	const uint8_t *p;
+	const uint8_t *e;
+	struct rt *routes = NULL;
+	struct rt *route = NULL;
+	int len;
+
+	/* If we have CSR's then we MUST use these only */
+	p = get_option(dhcp, DHO_CSR, &len, NULL);
+	/* Check for crappy MS option */
+	if (!p)
+		p = get_option(dhcp, DHO_MSCSR, &len, NULL);
+	if (p) {
+		routes = decode_rfc3442_rt(len, p);
+		if (routes) {
+			if (!(*opts & DHCPCD_CSR_WARNED)) {
+				syslog(LOG_DEBUG,
+				    "%s: using Classless Static Routes",
+				    ifname);
+				*opts |= DHCPCD_CSR_WARNED;
+			}
+			return routes;
+		}
+	}
+
+	/* OK, get our static routes first. */
+	p = get_option(dhcp, DHO_STATICROUTE, &len, NULL);
+	if (p) {
+		e = p + len;
+		while (p < e) {
+			if (route) {
+				route->next = xmalloc(sizeof(*route));
+				route = route->next;
+			} else
+				routes = route = xmalloc(sizeof(*routes));
+			route->next = NULL;
+			memcpy(&route->dest.s_addr, p, 4);
+			p += 4;
+			memcpy(&route->gate.s_addr, p, 4);
+			p += 4;
+			route->net.s_addr = route_netmask(route->dest.s_addr);
+		}
+	}
+
+	/* Now grab our routers */
+	p = get_option(dhcp, DHO_ROUTER, &len, NULL);
+	if (p) {
+		e = p + len;
+		while (p < e) {
+			if (route) {
+				route->next = xzalloc(sizeof(*route));
+				route = route->next;
+			} else
+				routes = route = xzalloc(sizeof(*route));
+			memcpy(&route->gate.s_addr, p, 4);
+			p += 4;
+		}
+	}
+
+	return routes;
+}
+
+static size_t
+encode_rfc1035(const char *src, uint8_t *dst)
+{
+	uint8_t *p = dst;
+	uint8_t *lp = p++;
+
+	if (*src == '\0')
+		return 0;
+	for (; *src; src++) {
+		if (*src == '\0')
+			break;
+		if (*src == '.') {
+			/* Skip the trailing . */
+			if (src[1] == '\0')
+				break;
+			*lp = p - lp - 1;
+			if (*lp == '\0')
+				return p - dst;
+			lp = p++;
+		} else
+			*p++ = (uint8_t)*src;
+	}
+	*lp = p - lp - 1;
+	*p++ = '\0';
+	return p - dst;
+}
+
+#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 = 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 *iface,
+    uint8_t type)
+{
+	struct dhcp_message *dhcp;
+	uint8_t *m, *lp, *p;
+	uint8_t *n_params = NULL;
+	time_t up = uptime() - iface->start_uptime;
+	uint32_t ul;
+	uint16_t sz;
+	size_t len;
+	const char *hp;
+	const struct dhcp_opt *opt;
+	const struct if_options *ifo = iface->state->options;
+	const struct dhcp_lease *lease = &iface->state->lease;
+
+	dhcp = xzalloc(sizeof (*dhcp));
+	m = (uint8_t *)dhcp;
+	p = dhcp->options;
+
+	if ((type == DHCP_INFORM || type == DHCP_RELEASE ||
+		(type == DHCP_REQUEST &&
+		    iface->net.s_addr == lease->net.s_addr &&
+		    (iface->state->new == NULL ||
+			iface->state->new->cookie == htonl(MAGIC_COOKIE)))))
+	{
+		dhcp->ciaddr = iface->addr.s_addr;
+		/* In-case we haven't actually configured the address yet */
+		if (type == DHCP_INFORM && iface->addr.s_addr == 0)
+			dhcp->ciaddr = lease->addr.s_addr;
+	}
+
+	dhcp->op = DHCP_BOOTREQUEST;
+	dhcp->hwtype = iface->family;
+	switch (iface->family) {
+	case ARPHRD_ETHER:
+	case ARPHRD_IEEE802:
+		dhcp->hwlen = iface->hwlen;
+		memcpy(&dhcp->chaddr, &iface->hwaddr, iface->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(up);
+	}
+	dhcp->xid = iface->state->xid;
+	dhcp->cookie = htonl(MAGIC_COOKIE);
+
+	*p++ = DHO_MESSAGETYPE; 
+	*p++ = 1;
+	*p++ = type;
+
+	if (iface->clientid) {
+		*p++ = DHO_CLIENTID;
+		memcpy(p, iface->clientid, iface->clientid[0] + 1);
+		p += iface->clientid[0] + 1;
+	}
+
+	if (lease->addr.s_addr && lease->cookie == htonl(MAGIC_COOKIE)) {
+		if (type == DHCP_DECLINE ||
+		    (type == DHCP_REQUEST &&
+			lease->addr.s_addr != iface->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++ = len;
+		memcpy(p, DAD, len);
+		p += len;
+	}
+
+	if (type == DHCP_DISCOVER && ifo->options & DHCPCD_REQUEST)
+		PUTADDR(DHO_IPADDRESS, ifo->req_addr);
+
+	if (type == DHCP_DISCOVER ||
+	    type == DHCP_INFORM ||
+	    type == DHCP_REQUEST)
+	{
+		*p++ = DHO_MAXMESSAGESIZE;
+		*p++ = 2;
+		sz = get_mtu(iface->name);
+		if (sz < MTU_MIN) {
+			if (set_mtu(iface->name, MTU_MIN) == 0)
+				sz = MTU_MIN;
+		} else if (sz > MTU_MAX) {
+			/* Even though our MTU could be greater than
+			 * MTU_MAX (1500) dhcpcd does not presently
+			 * handle DHCP packets any bigger. */
+			sz = MTU_MAX;
+		}
+		sz = htons(sz);
+		memcpy(p, &sz, 2);
+		p += 2;
+
+		if (ifo->userclass[0]) {
+			*p++ = DHO_USERCLASS;
+			memcpy(p, ifo->userclass, ifo->userclass[0] + 1);
+			p += ifo->userclass[0] + 1;
+		}
+
+		if (ifo->vendorclassid[0]) {
+			*p++ = DHO_VENDORCLASSID;
+			memcpy(p, ifo->vendorclassid,
+			    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;
+			}
+		}
+
+		/* Regardless of RFC2132, we should always send a hostname
+		 * upto the first dot (the short hostname) as otherwise
+		 * confuses some DHCP servers when updating DNS.
+		 * The FQDN option should be used if a FQDN is required. */
+		if (ifo->options & DHCPCD_HOSTNAME && ifo->hostname[0]) {
+			*p++ = DHO_HOSTNAME;
+			hp = strchr(ifo->hostname, '.');
+			if (hp)
+				len = hp - ifo->hostname;
+			else
+				len = strlen(ifo->hostname);
+			*p++ = len;
+			memcpy(p, ifo->hostname, len);
+			p += len;
+		}
+		if (ifo->fqdn != FQDN_DISABLE && ifo->hostname[0]) {
+			/* 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
+			 */
+			*p++ = (ifo->fqdn & 0x09) | 0x04;
+			*p++ = 0; /* from server for PTR RR */
+			*p++ = 0; /* from server for A RR if S=1 */
+			ul = encode_rfc1035(ifo->hostname, p);
+			*lp += ul;
+			p += ul;
+		}
+
+		/* vendor is already encoded correctly, so just add it */
+		if (ifo->vendor[0]) {
+			*p++ = DHO_VENDOR;
+			memcpy(p, ifo->vendor, ifo->vendor[0] + 1);
+			p += ifo->vendor[0] + 1;
+		}
+
+		*p++ = DHO_PARAMETERREQUESTLIST;
+		n_params = p;
+		*p++ = 0;
+		for (opt = dhcp_opts; opt->option; opt++) {
+			if (!(opt->type & REQUEST || 
+				has_option_mask(ifo->requestmask, opt->option)))
+				continue;
+			if (type == DHCP_INFORM &&
+			    (opt->option == DHO_RENEWALTIME ||
+				opt->option == DHO_REBINDTIME))
+				continue;
+			*p++ = opt->option;
+		}
+		*n_params = p - n_params - 1;
+	}
+	*p++ = DHO_END;
+
+#ifdef BOOTP_MESSAGE_LENTH_MIN
+	/* Some crappy DHCP servers think they have to obey the BOOTP minimum
+	 * message length.
+	 * They are wrong, but we should still cater for them. */
+	while (p - m < BOOTP_MESSAGE_LENTH_MIN)
+		*p++ = DHO_PAD;
+#endif
+
+	*message = dhcp;
+	return p - m;
+}
+
+ssize_t
+write_lease(const struct interface *iface, const struct dhcp_message *dhcp)
+{
+	int fd;
+	ssize_t bytes = sizeof(*dhcp);
+	const uint8_t *p = dhcp->options;
+	const uint8_t *e = p + sizeof(dhcp->options);
+	uint8_t l;
+	uint8_t o = 0;
+
+	/* We don't write BOOTP leases */
+	if (is_bootp(dhcp)) {
+		unlink(iface->leasefile);
+		return 0;
+	}
+
+	syslog(LOG_DEBUG, "%s: writing lease `%s'",
+	    iface->name, iface->leasefile);
+
+	fd = open(iface->leasefile, O_WRONLY | O_CREAT | O_TRUNC, 0444);
+#ifdef ANDROID
+	if (fd == -1 && errno == EACCES) {
+		/* the lease file might have been created when dhcpcd was running as root */
+		unlink(iface->leasefile);
+		fd = open(iface->leasefile, O_WRONLY | O_CREAT | O_TRUNC, 0444);
+	}
+#endif
+	if (fd == -1) {
+		syslog(LOG_ERR, "%s: open: %m", iface->name);
+		return -1;
+	}
+
+	/* Only write as much as we need */
+	while (p < e) {
+		o = *p;
+		if (o == DHO_END) {
+			bytes = p - (const uint8_t *)dhcp;
+			break;
+		}
+		p++;
+		if (o != DHO_PAD) {
+			l = *p++;
+			p += l;
+		}
+	}
+	bytes = write(fd, dhcp, bytes);
+	close(fd);
+	return bytes;
+}
+
+struct dhcp_message *
+read_lease(const struct interface *iface)
+{
+	int fd;
+	struct dhcp_message *dhcp;
+	ssize_t bytes;
+
+	fd = open(iface->leasefile, O_RDONLY);
+	if (fd == -1) {
+		if (errno != ENOENT)
+			syslog(LOG_ERR, "%s: open `%s': %m",
+			    iface->name, iface->leasefile);
+		return NULL;
+	}
+	syslog(LOG_DEBUG, "%s: reading lease `%s'",
+	    iface->name, iface->leasefile);
+	dhcp = xmalloc(sizeof(*dhcp));
+	memset(dhcp, 0, sizeof(*dhcp));
+	bytes = read(fd, dhcp, sizeof(*dhcp));
+	close(fd);
+	if (bytes < 0) {
+		free(dhcp);
+		dhcp = NULL;
+	}
+	return dhcp;
+}
+
+static ssize_t
+print_string(char *s, ssize_t len, int dl, const uint8_t *data)
+{
+	uint8_t c;
+	const uint8_t *e, *p;
+	ssize_t bytes = 0;
+	ssize_t r;
+
+	e = data + dl;
+	while (data < e) {
+		c = *data++;
+		if (c == '\0') {
+			/* If rest is all NULL, skip it. */
+			for (p = data; p < e; p++)
+				if (*p != '\0')
+					break;
+			if (p == e)
+				break;
+		}
+		if (!isascii(c) || !isprint(c)) {
+			if (s) {
+				if (len < 5) {
+					errno = ENOBUFS;
+					return -1;
+				}
+				r = snprintf(s, len, "\\%03o", c);
+				len -= r;
+				bytes += r;
+				s += r;
+			} else
+				bytes += 4;
+			continue;
+		}
+		switch (c) {
+		case '"':  /* FALLTHROUGH */
+		case '\'': /* FALLTHROUGH */
+		case '$':  /* FALLTHROUGH */
+		case '`':  /* FALLTHROUGH */
+ 		case '\\': /* FALLTHROUGH */
+		case '|':  /* FALLTHROUGH */
+		case '&':
+			if (s) {
+				if (len < 3) {
+					errno = ENOBUFS;
+					return -1;
+				}
+				*s++ = '\\';
+				len--;
+			}
+			bytes++;
+			break;
+		}
+		if (s) {
+			*s++ = c;
+			len--;
+		}
+		bytes++;
+	}
+
+	/* NULL */
+	if (s)
+		*s = '\0';
+	bytes++;
+	return bytes;
+}
+
+static ssize_t
+print_option(char *s, ssize_t len, int type, int dl, const uint8_t *data)
+{
+	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;
+	ssize_t l;
+	char *tmp;
+
+	if (type & RFC3397) {
+		l = decode_rfc3397(NULL, 0, dl, data);
+		if (l < 1)
+			return l;
+		tmp = xmalloc(l);
+		decode_rfc3397(tmp, l, dl, data);
+		l = print_string(s, len, l - 1, (uint8_t *)tmp);
+		free(tmp);
+		return l;
+	}
+
+	if (type & RFC3361) {
+		if ((tmp = decode_rfc3361(dl, data)) == NULL)
+			return -1;
+		l = strlen(tmp);
+		l = print_string(s, len, l - 1, (uint8_t *)tmp);
+		free(tmp);
+		return l;
+	}
+
+	if (type & RFC3442)
+		return decode_rfc3442(s, len, dl, data);
+
+	if (type & RFC5969)
+		return decode_rfc5969(s, len, dl, data);
+
+	if (type & STRING) {
+		/* Some DHCP servers return NULL strings */
+		if (*data == '\0')
+			return 0;
+		return print_string(s, len, dl, data);
+	}
+
+	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 & IPV4) {
+			l = 16;
+			dl /= 4;
+		} else {
+			errno = EINVAL;
+			return -1;
+		}
+		return (l + 1) * dl;
+	}
+
+	t = data;
+	e = data + dl;
+	while (data < e) {
+		if (data != t) {
+			*s++ = ' ';
+			bytes++;
+			len--;
+		}
+		if (type & UINT8) {
+			l = snprintf(s, len, "%d", *data);
+			data++;
+		} else if (type & UINT16) {
+			memcpy(&u16, data, sizeof(u16));
+			u16 = ntohs(u16);
+			l = snprintf(s, len, "%d", u16);
+			data += sizeof(u16);
+		} else if (type & SINT16) {
+			memcpy(&s16, data, sizeof(s16));
+			s16 = ntohs(s16);
+			l = snprintf(s, len, "%d", s16);
+			data += sizeof(s16);
+		} else if (type & UINT32) {
+			memcpy(&u32, data, sizeof(u32));
+			u32 = ntohl(u32);
+			l = snprintf(s, len, "%d", u32);
+			data += sizeof(u32);
+		} else if (type & SINT32) {
+			memcpy(&s32, data, sizeof(s32));
+			s32 = ntohl(s32);
+			l = snprintf(s, len, "%d", s32);
+			data += sizeof(s32);
+		} else if (type & IPV4) {
+			memcpy(&addr.s_addr, data, sizeof(addr.s_addr));
+			l = snprintf(s, len, "%s", inet_ntoa(addr));
+			data += sizeof(addr.s_addr);
+		} else
+			l = 0;
+		if (len <= l) {
+			bytes += len;
+			break;
+		}
+		len -= l;
+		bytes += l;
+		s += l;
+	}
+
+	return bytes;
+}
+
+ssize_t
+configure_env(char **env, const char *prefix, const struct dhcp_message *dhcp,
+    const struct if_options *ifo)
+{
+	const uint8_t *p;
+	int pl;
+	struct in_addr addr;
+	struct in_addr net;
+	struct in_addr brd;
+	char *val, *v;
+	const struct dhcp_opt *opt;
+	ssize_t len, e = 0;
+	char **ep;
+	char cidr[4];
+	uint8_t overl = 0;
+
+	get_option_uint8(&overl, dhcp, DHO_OPTIONSOVERLOADED);
+
+	if (!env) {
+		for (opt = dhcp_opts; opt->option; opt++) {
+			if (!opt->var)
+				continue;
+			if (has_option_mask(ifo->nomask, opt->option))
+				continue;
+			if (get_option_raw(dhcp, opt->option))
+				e++;
+		}
+		if (dhcp->yiaddr || dhcp->ciaddr)
+			e += 5;
+		if (*dhcp->bootfile && !(overl & 1))
+			e++;
+		if (*dhcp->servername && !(overl & 2))
+			e++;
+		return 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(&ep, prefix, "ip_address", inet_ntoa(addr));
+		if (get_option_addr(&net, dhcp, DHO_SUBNETMASK) == -1) {
+			net.s_addr = get_netmask(addr.s_addr);
+			setvar(&ep, prefix, "subnet_mask", inet_ntoa(net));
+		}
+		snprintf(cidr, sizeof(cidr), "%d", inet_ntocidr(net));
+		setvar(&ep, prefix, "subnet_cidr", cidr);
+		if (get_option_addr(&brd, dhcp, DHO_BROADCAST) == -1) {
+			brd.s_addr = addr.s_addr | ~net.s_addr;
+			setvar(&ep, prefix, "broadcast_address", inet_ntoa(brd));
+		}
+		addr.s_addr = dhcp->yiaddr & net.s_addr;
+		setvar(&ep, prefix, "network_number", inet_ntoa(addr));
+	}
+
+	if (*dhcp->bootfile && !(overl & 1))
+		setvar(&ep, prefix, "filename", (const char *)dhcp->bootfile);
+	if (*dhcp->servername && !(overl & 2))
+		setvar(&ep, prefix, "server_name", (const char *)dhcp->servername);
+
+	for (opt = dhcp_opts; opt->option; opt++) {
+		if (!opt->var)
+			continue;
+		if (has_option_mask(ifo->nomask, opt->option))
+			continue;
+		val = NULL;
+		p = get_option(dhcp, opt->option, &pl, NULL);
+		if (!p)
+			continue;
+		/* We only want the FQDN name */
+		if (opt->option == DHO_FQDN) {
+			p += 3;
+			pl -= 3;
+		}
+		len = print_option(NULL, 0, opt->type, pl, p);
+		if (len < 0)
+			return -1;
+		e = strlen(prefix) + strlen(opt->var) + len + 4;
+		v = val = *ep++ = xmalloc(e);
+		v += snprintf(val, e, "%s_%s=", prefix, opt->var);
+		if (len != 0)
+			print_option(v, len, opt->type, pl, p);
+	}
+
+	return ep - env;
+}
+
+void
+get_lease(struct dhcp_lease *lease, const struct dhcp_message *dhcp)
+{
+	struct timeval now;
+
+	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(&lease->net, dhcp, DHO_SUBNETMASK) == -1)
+		lease->net.s_addr = get_netmask(lease->addr.s_addr);
+	if (get_option_addr(&lease->brd, dhcp, DHO_BROADCAST) == -1)
+		lease->brd.s_addr = lease->addr.s_addr | ~lease->net.s_addr;
+	if (get_option_uint32(&lease->leasetime, dhcp, DHO_LEASETIME) == 0) {
+		/* Ensure that we can use the lease */
+		get_monotonic(&now);
+		if (now.tv_sec + (time_t)lease->leasetime < now.tv_sec)
+			lease->leasetime = ~0U; /* Infinite lease */
+	} else
+		lease->leasetime = ~0U; /* Default to infinite lease */
+	if (get_option_uint32(&lease->renewaltime, dhcp, DHO_RENEWALTIME) != 0)
+		lease->renewaltime = 0;
+	if (get_option_uint32(&lease->rebindtime, dhcp, DHO_REBINDTIME) != 0)
+		lease->rebindtime = 0;
+	if (get_option_addr(&lease->server, dhcp, DHO_SERVERID) != 0)
+		lease->server.s_addr = INADDR_ANY;
+}
diff --git a/dhcpcd/dhcp.h b/dhcpcd/dhcp.h
new file mode 100644
index 0000000..fb27e71
--- /dev/null
+++ b/dhcpcd/dhcp.h
@@ -0,0 +1,204 @@
+/* 
+ * 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 DHCP_H
+#define DHCP_H
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+
+#include <stdint.h>
+
+#include "common.h"
+
+/* Max MTU - defines dhcp option length */
+#define MTU_MAX             1500
+#define MTU_MIN             576
+
+/* 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
+
+/* 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
+#define DHCP_ARP_FAIL		10
+
+/* number of usecs in a second. */
+#define USECS_SECOND		1000000
+/* As we use timevals, we should use the usec part for
+ * greater randomisation. */
+#define DHCP_RAND_MIN_U		DHCP_RAND_MIN * USECS_SECOND
+#define DHCP_RAND_MAX_U		DHCP_RAND_MAX * USECS_SECOND
+#define PROBE_MIN_U		PROBE_MIN * USECS_SECOND
+#define PROBE_MAX_U		PROBE_MAX * USECS_SECOND
+
+/* 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_FQDN                   = 81,
+	DHO_DNSSEARCH              = 119, /* RFC 3397 */
+	DHO_CSR                    = 121, /* RFC 3442 */
+	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
+
+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_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;
+	time_t leasedfrom;
+	struct timeval boundtime;
+	uint8_t frominfo;
+	uint32_t cookie;
+};
+
+#include "dhcpcd.h"
+#include "if-options.h"
+#include "net.h"
+
+#define add_option_mask(var, val) (var[val >> 3] |= 1 << (val & 7))
+#define del_option_mask(var, val) (var[val >> 3] &= ~(1 << (val & 7)))
+#define has_option_mask(var, val) (var[val >> 3] & (1 << (val & 7)))
+int make_option_mask(uint8_t *, const char *, int);
+void print_options(void);
+char *get_option_string(const struct dhcp_message *, uint8_t);
+int get_option_addr(struct in_addr *, const struct dhcp_message *, uint8_t);
+int get_option_uint32(uint32_t *, const struct dhcp_message *, uint8_t);
+int get_option_uint16(uint16_t *, const struct dhcp_message *, uint8_t);
+int get_option_uint8(uint8_t *, const struct dhcp_message *, uint8_t);
+#define is_bootp(m) (m &&						\
+	    !IN_LINKLOCAL(htonl((m)->yiaddr)) &&			\
+	    get_option_uint8(NULL, m, DHO_MESSAGETYPE) == -1)
+struct rt *get_option_routes(const struct dhcp_message *, const char *,
+    unsigned long long *);
+ssize_t decode_rfc3397(char *, ssize_t, int, const uint8_t *);
+ssize_t configure_env(char **, const char *, const struct dhcp_message *,
+    const struct if_options *);
+
+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 *);
+
+ssize_t write_lease(const struct interface *, const struct dhcp_message *);
+struct dhcp_message *read_lease(const struct interface *);
+void get_lease(struct dhcp_lease *, const struct dhcp_message *);
+
+#endif
diff --git a/dhcpcd/dhcpcd-hooks/01-test b/dhcpcd/dhcpcd-hooks/01-test
new file mode 100644
index 0000000..ef7896d
--- /dev/null
+++ b/dhcpcd/dhcpcd-hooks/01-test
@@ -0,0 +1,6 @@
+# Just echo our DHCP options we have
+
+if [ "${reason}" = "TEST" ]; then
+	set | grep "^\(interface\|metric\|pid\|reason\|skip_hooks\)=" | sort
+	set | grep "^\(new_\|old_\)" | sort
+fi
diff --git a/dhcpcd/dhcpcd-hooks/02-dump b/dhcpcd/dhcpcd-hooks/02-dump
new file mode 100644
index 0000000..cbb46ea
--- /dev/null
+++ b/dhcpcd/dhcpcd-hooks/02-dump
@@ -0,0 +1,5 @@
+# Just echo our DHCP options we have
+
+if [ "$reason" = "DUMP" ]; then
+	set | sed -ne 's/^new_//p' | sort
+fi
diff --git a/dhcpcd/dhcpcd-hooks/10-mtu b/dhcpcd/dhcpcd-hooks/10-mtu
new file mode 100644
index 0000000..4265b48
--- /dev/null
+++ b/dhcpcd/dhcpcd-hooks/10-mtu
@@ -0,0 +1,5 @@
+# Configure the MTU for the interface
+
+if [ -n "${new_interface_mtu}" ]; then
+	ifconfig "${interface}" mtu "${new_interface_mtu}"
+fi
diff --git a/dhcpcd/dhcpcd-hooks/20-dns.conf b/dhcpcd/dhcpcd-hooks/20-dns.conf
new file mode 100755
index 0000000..d19c6a9
--- /dev/null
+++ b/dhcpcd/dhcpcd-hooks/20-dns.conf
@@ -0,0 +1,51 @@
+# Set net.<iface>.dnsN properties that contain the
+# DNS server addresses given by the DHCP server.
+
+if [[ $interface == p2p* ]]
+    then
+    intf=p2p
+    else
+    intf=$interface
+fi
+
+set_dns_props()
+{
+    case "${new_domain_name_servers}" in
+    "")   return 0;;
+    esac
+
+    count=1
+    for i in 1 2 3 4; do
+        setprop dhcp.${intf}.dns${i} ""
+    done
+
+    count=1
+    for dnsaddr in ${new_domain_name_servers}; do
+        setprop dhcp.${intf}.dns${count} ${dnsaddr}
+        count=$(($count + 1))
+    done
+
+    separator=" "
+    if [ -z "$new_domain_name" ]; then
+       separator=""
+    else
+        if [ -z "$new_domain_search" ]; then
+            separator=""
+        fi
+    fi
+    setprop dhcp.${interface}.domain "${new_domain_name}$separator${new_domain_search}"
+}
+
+unset_dns_props()
+{
+    for i in 1 2 3 4; do
+        setprop dhcp.${intf}.dns${i} ""
+    done
+
+    setprop dhcp.${interface}.domain ""
+}
+
+case "${reason}" in
+BOUND|INFORM|REBIND|REBOOT|RENEW|TIMEOUT)       set_dns_props;;
+EXPIRE|FAIL|IPV4LL|RELEASE|STOP)                unset_dns_props;;
+esac
diff --git a/dhcpcd/dhcpcd-hooks/20-resolv.conf b/dhcpcd/dhcpcd-hooks/20-resolv.conf
new file mode 100644
index 0000000..628636d
--- /dev/null
+++ b/dhcpcd/dhcpcd-hooks/20-resolv.conf
@@ -0,0 +1,126 @@
+# 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"
+
+build_resolv_conf()
+{
+	local cf="$state_dir/resolv.conf.$interface"
+	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}
+		unset domain
+		if [ -n "$2" ]; then
+			search="$search $@"
+		elif [ -n "$1" ]; then
+			domain="domain $1\n"
+		fi
+		[ -n "$search" ] && search="search $(uniqify $search)\n"
+
+		# Build the nameserver list
+		srvs=$(cd "$resolv_conf_dir"; \
+			key_get_value "nameserver " ${interfaces})
+		for x in $(uniqify ${srvs}); do
+			servers="${servers}nameserver $x\n"
+		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 "$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
+	cat "$cf" > /etc/resolv.conf
+	chmod 644 /etc/resolv.conf
+	rm -f "$cf"
+}
+
+add_resolv_conf()
+{
+	local x= conf="$signature\n"
+
+	# 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
+
+	if [ -n "$new_domain_name" ]; then
+		set -- $new_domain_name
+		new_domain_name="$1"
+		conf="${conf}domain $new_domain_name\n"
+		# Support RFC violating search in domain
+		if [ -z "$new_domain_search" -a -n "$2" ]; then
+			new_domain_search="$@"
+		fi
+	fi
+	if [ -n "$new_domain_search" ]; then
+		conf="${conf}search $new_domain_search\n"
+	fi
+	for x in ${new_domain_name_servers}; do
+		conf="${conf}nameserver $x\n"
+	done
+	if type resolvconf >/dev/null 2>&1; then
+		[ -n "$metric" ] && export IF_METRIC="$metric"
+		printf "$conf" | resolvconf -a "$interface"
+		return $?
+	fi
+
+	if [ -e "$resolv_conf_dir/$interface" ]; then
+		rm -f "$resolv_conf_dir/$interface"
+	fi
+	[ -d "$resolv_conf_dir" ] || mkdir -p "$resolv_conf_dir"
+	printf "$conf" > "$resolv_conf_dir/$interface"
+	build_resolv_conf
+}
+
+remove_resolv_conf()
+{
+	if type resolvconf >/dev/null 2>&1; then
+		resolvconf -d "$interface" -f
+	else
+		if [ -e "$resolv_conf_dir/$interface" ]; then
+			rm -f "$resolv_conf_dir/$interface"
+		fi
+		build_resolv_conf
+	fi
+}
+
+if $if_up; then
+	add_resolv_conf
+elif $if_down; then
+	remove_resolv_conf
+fi
diff --git a/dhcpcd/dhcpcd-hooks/25-static-routes.conf b/dhcpcd/dhcpcd-hooks/25-static-routes.conf
new file mode 100755
index 0000000..c6b7c4a
--- /dev/null
+++ b/dhcpcd/dhcpcd-hooks/25-static-routes.conf
@@ -0,0 +1,61 @@
+# Set dhcp.<iface>.routeN.dest and dhcp.<iface>.routeN.via properties with
+# the static routes provided by the DHCP server.
+
+# CAUTION
+#
+# Placing this in the hooks directory will allow DHCP servers to push static
+# routes to ALL of the interfaces that use the directory.
+#
+# To avoid this, create separate dhcpcd configurations, one for the interfaces
+# that should accept static routes and another for the interfaces that should
+# not accept static routes routes.
+
+# Add this script in the hooks directory only for the interfaces that should
+# accept static routes.
+#
+# Add "nooption classless_static_routes, static_routes" to the dhcpcd.conf
+# file for the interfaces that should not accept static routes. Do not add the
+# script to the hooks directory.
+
+next_set_interface=1
+
+set_route_props_from_list()
+{
+    while [[ $# -ge 2 ]]; do
+        setprop dhcp.${interface}.route${next_set_interface}.dest $1
+        shift
+        setprop dhcp.${interface}.route${next_set_interface}.via $1
+        shift
+        next_set_interface=$(($next_set_interface + 1))
+    done
+}
+
+unset_route_props()
+{
+    next_clear_interface=1
+    while [[ ! -z "$(getprop dhcp.${interface}.route${next_clear_interface}.dest)" ]]; do
+      setprop dhcp.${interface}.route${next_clear_interface}.dest ""
+      setprop dhcp.${interface}.route${next_clear_interface}.via ""
+      next_clear_interface=$(($next_clear_interface + 1))
+    done
+    while [[ ! -z "$(getprop dhcp.${interface}.route${next_clear_interface}.via)" ]]; do
+      setprop dhcp.${interface}.route${next_clear_interface}.dest ""
+      setprop dhcp.${interface}.route${next_clear_interface}.via ""
+      next_clear_interface=$(($next_clear_interface + 1))
+    done
+}
+
+set_route_props()
+{
+    unset_route_props
+    if [[ ! -z "${new_classless_static_routes}" ]]; then
+        set_route_props_from_list ${new_classless_static_routes}
+    else
+        set_route_props_from_list ${new_static_routes}
+    fi
+}
+
+case "${reason}" in
+BOUND|INFORM|REBIND|REBOOT|RENEW|TIMEOUT)       set_route_props;;
+EXPIRE|FAIL|IPV4LL|RELEASE|STOP)                unset_route_props;;
+esac
diff --git a/dhcpcd/dhcpcd-hooks/29-lookup-hostname b/dhcpcd/dhcpcd-hooks/29-lookup-hostname
new file mode 100644
index 0000000..8661fcc
--- /dev/null
+++ b/dhcpcd/dhcpcd-hooks/29-lookup-hostname
@@ -0,0 +1,34 @@
+# 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
+	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/dhcpcd-hooks/30-hostname b/dhcpcd/dhcpcd-hooks/30-hostname
new file mode 100644
index 0000000..87446fb
--- /dev/null
+++ b/dhcpcd/dhcpcd-hooks/30-hostname
@@ -0,0 +1,34 @@
+# Set the hostname from DHCP data if required
+
+need_hostname()
+{
+	local hostname=""
+
+	case "$force_hostname" in
+	[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|1) ;;
+	*) hostname="$(hostname)";;
+	esac
+	case "$hostname" in
+	""|"(none)"|localhost|localhost.localdomain)
+		[ -n "$new_host_name" -o -n "$new_fqdn_name" ];;
+	"$old_host_name"|"$old_fqdn_name")
+		true;;
+	*)
+		false;;
+	esac
+}
+
+set_hostname()
+{
+	if need_hostname; then
+		if [ -n "$new_host_name" ]; then
+			hostname "$new_host_name"
+		elif [ -n "$new_fqdn_name" ]; then
+			hostname "$new_fqdn_name"
+		fi
+	fi
+}
+
+if $if_up; then
+	set_hostname
+fi
diff --git a/dhcpcd/dhcpcd-hooks/50-dhcpcd-compat b/dhcpcd/dhcpcd-hooks/50-dhcpcd-compat
new file mode 100644
index 0000000..651bc08
--- /dev/null
+++ b/dhcpcd/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
+
+x="down"
+case "$reason" in
+RENEW) x="up";;
+BOUND|INFORM|REBIND|REBOOT|TEST|TIMEOUT|IPV4LL) x="new";;
+esac
+
+if [ "$reason" != "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 "$x"
diff --git a/dhcpcd/dhcpcd-hooks/50-ntp.conf b/dhcpcd/dhcpcd-hooks/50-ntp.conf
new file mode 100644
index 0000000..765baa7
--- /dev/null
+++ b/dhcpcd/dhcpcd-hooks/50-ntp.conf
@@ -0,0 +1,98 @@
+# 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 from pkgsrc instead of the system provided ntp.
+
+: ${ntpd_restart_cmd:=service_condcommand ntpd restart}
+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_DHCP_CONF:=/var/lib/ntp/ntp.conf.dhcp}
+fi
+
+ntp_conf_dir="$state_dir/ntp.conf"
+ntp_conf=${NTP_CONF:-/etc/ntp.conf}
+
+build_ntp_conf()
+{
+	local cf="$state_dir/ntp.conf.$interface"
+	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\n"
+			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
+		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 "$search$servers" >> "$cf"
+		echo "$signature_base_end${header:+ $from }$header" >> "$cf"
+	else
+		[ -e "$ntp_conf" ] || return
+	fi
+
+	# If we changed anything, restart ntpd
+	if change_file "$ntp_conf" "$cf"; then
+		[ -n "$ntpd_restart_cmd" ] && eval $ntpd_restart_cmd
+	fi
+}
+
+add_ntp_conf()
+{
+	local cf="$ntp_conf_dir/$interface" 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/$interface" ]; then
+		rm "$ntp_conf_dir/$interface"
+	fi
+	build_ntp_conf
+}
+
+if $if_up; then
+	add_ntp_conf add
+elif $if_down; then
+	remove_ntp_conf del
+fi
diff --git a/dhcpcd/dhcpcd-hooks/50-yp.conf b/dhcpcd/dhcpcd-hooks/50-yp.conf
new file mode 100644
index 0000000..a1f5798
--- /dev/null
+++ b/dhcpcd/dhcpcd-hooks/50-yp.conf
@@ -0,0 +1,51 @@
+# 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."$interface" prefix= x= pid=
+	rm -f "$cf"
+	echo "$signature" > "$cf"
+	if [ -n "$new_nis_domain" ]; then
+		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/dhcpcd-hooks/50-ypbind b/dhcpcd/dhcpcd-hooks/50-ypbind
new file mode 100644
index 0000000..9a1fecc
--- /dev/null
+++ b/dhcpcd/dhcpcd-hooks/50-ypbind
@@ -0,0 +1,74 @@
+# Sample dhcpcd hook for ypbind
+# This script is only suitable for the Linux version.
+
+: ${ypbind_restart_cmd:=service_command ypbind restart}
+: ${ypbind_stop_cmd:=service_condcommand ypbind stop}
+ypbind_dir="$state_dir/ypbind"
+
+best_domain()
+{
+	local i=
+
+	for i in $interfaces; do
+		if [ -e "$ypbind_dir/$i" ]; then
+			cat "$ypbind_dir/$i"
+		fi
+	done
+	return 1
+}
+
+make_yp_binding()
+{
+	[ -d "$ypbind_dir" ] || mkdir -p "$ypbind_dir"
+	echo "$new_nis_domain" >"$ypbind_dir/$interface"
+	local nd="$(best_domain)"
+
+	local cf=/var/yp/binding/"$new_nis_domain".ypservers
+	if [ -n "$new_nis_servers" ]; then
+		local ncf="$cf.$interface" x=
+		rm -f "$ncf"
+		for x in $new_nis_servers; do
+			echo "$x" >>"$ncf"
+		done
+		change_file "$cf" "$ncf"
+	else
+		# Because this is not an if .. fi then we can use $? below
+		[ -e "$cf" ] && rm "$cf"
+	fi
+
+	if [ $? = 0 -o "$nd" != "$(domainname)" ]; then
+		domainname "$nd"
+		if [ -n "$ypbind_restart_cmd" ]; then
+			eval $ypbind_restart_cmd
+		fi
+	fi
+}
+
+restore_yp_binding()
+{
+	rm -f "$ypbind_dir/$interface"
+	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
+		make_yp_binding
+	elif [ -n "$old_nis_domain" ]; then
+		restore_yp_binding
+	fi
+fi
diff --git a/dhcpcd/dhcpcd-hooks/90-NetworkManager b/dhcpcd/dhcpcd-hooks/90-NetworkManager
new file mode 100644
index 0000000..c4d69fe
--- /dev/null
+++ b/dhcpcd/dhcpcd-hooks/90-NetworkManager
@@ -0,0 +1,8 @@
+# Hook for NetworkManager-0.7.0
+# NOTE: NetworkManager will override the script dhcpcd calls, so this hook
+# only makes sense if NetworkManager is patched NOT to override the
+# script dhcpcd would call.
+
+if [ -x /usr/libexec/nm-dhcp-client.action ]; then
+	/usr/libexec/nm-dhcp-client.action
+fi
diff --git a/dhcpcd/dhcpcd-hooks/95-configured b/dhcpcd/dhcpcd-hooks/95-configured
new file mode 100644
index 0000000..fe76c22
--- /dev/null
+++ b/dhcpcd/dhcpcd-hooks/95-configured
@@ -0,0 +1,35 @@
+# This script runs last, after all network configuration
+# has completed. It sets a property to let the framework
+# know that setting up the interface is complete.
+
+if [[ $interface == p2p* ]]
+    then
+    intf=p2p
+    else
+    intf=$interface
+fi
+
+# For debugging:
+setprop dhcp.${intf}.reason "${reason}"
+
+case "${reason}" in
+BOUND|INFORM|REBIND|REBOOT|RENEW|TIMEOUT)
+    setprop dhcp.${intf}.ipaddress  "${new_ip_address}"
+    setprop dhcp.${intf}.gateway    "${new_routers%% *}"
+    setprop dhcp.${intf}.mask       "${new_subnet_mask}"
+    setprop dhcp.${intf}.leasetime  "${new_dhcp_lease_time}"
+    setprop dhcp.${intf}.server     "${new_dhcp_server_identifier}"
+    setprop dhcp.${intf}.vendorInfo "${new_vendor_encapsulated_options}"
+    setprop dhcp.${intf}.mtu        "${new_interface_mtu}"
+
+    setprop dhcp.${intf}.result "ok"
+    ;;
+
+EXPIRE|FAIL|IPV4LL|STOP)
+    setprop dhcp.${intf}.result "failed"
+    ;;
+
+RELEASE)
+    setprop dhcp.${intf}.result "released"
+    ;;
+esac
diff --git a/dhcpcd/dhcpcd-hooks/Makefile b/dhcpcd/dhcpcd-hooks/Makefile
new file mode 100644
index 0000000..7563d2d
--- /dev/null
+++ b/dhcpcd/dhcpcd-hooks/Makefile
@@ -0,0 +1,19 @@
+TOP?=	../
+include ${TOP}/Makefile.inc
+include ${TOP}/config.mk
+
+SCRIPTSDIR=	${LIBEXECDIR}/dhcpcd-hooks
+SCRIPTS=	01-test 02-dump
+SCRIPTS+=	10-mtu 20-resolv.conf 29-lookup-hostname 30-hostname
+SCRIPTS+=	${HOOKSCRIPTS}
+
+all:
+
+install:
+	${INSTALL} -d ${DESTDIR}${SCRIPTSDIR}
+	${INSTALL} -m ${NONBINMODE} ${SCRIPTS} ${DESTDIR}${SCRIPTSDIR}
+
+import:
+	${INSTALL} -d /tmp/${DISTPREFIX}/dhcpcd-hooks
+	${INSTALL} -m ${NONBINMODE} ${SCRIPTS} /tmp/${DISTPREFIX}/dhcpcd-hooks
+
diff --git a/dhcpcd/dhcpcd-run-hooks b/dhcpcd/dhcpcd-run-hooks
new file mode 100755
index 0000000..a39a133
--- /dev/null
+++ b/dhcpcd/dhcpcd-run-hooks
@@ -0,0 +1,31 @@
+#!/system/bin/sh
+# dhcpcd client configuration script 
+
+# Handy variables and functions for our hooks to use
+from="from"
+signature_base="# Generated by dhcpcd"
+signature="${signature_base} ${from} ${interface}"
+signature_base_end="# End of dhcpcd"
+signature_end="${signature_base_end} ${from} ${interface}"
+state_dir="/data/misc/dhcpcd"
+
+# 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 \
+	/system/etc/dhcpcd/dhcpcd.enter-hook \
+	/system/etc/dhcpcd/dhcpcd-hooks/* \
+	/system/etc/dhcpcd/dhcpcd.exit-hook
+do
+	for skip in ${skip_hooks}; do
+		case "${hook}" in
+			*/"${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/dhcpcd-run-hooks.8 b/dhcpcd/dhcpcd-run-hooks.8
new file mode 100644
index 0000000..882b7d5
--- /dev/null
+++ b/dhcpcd/dhcpcd-run-hooks.8
@@ -0,0 +1,137 @@
+.\" Copyright (c) 2006-2010 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 August 24, 2010
+.Dt DHCPCD-RUN-HOOKS 8 SMM
+.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 /libexec/dhcpcd-hooks
+and the user defined hooks are
+.Pa /etc/dhcpcd.enter-hook .
+and
+.Pa /etc/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 PREINIT
+.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 INFORM
+dhcpcd informed a DHCP server about it's address and obtained other
+configuration details.
+.It Dv BOUND
+dhcpcd obtained a new lease from a DHCP server.
+.It Dv RENEW
+dhcpcd renewed it's lease.
+.It Dv REBIND
+dhcpcd has rebound to a new DHCP server.
+.It Dv REBOOT
+dhcpcd successfully requested a lease from a DHCP server.
+.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
+dhcpcd's lease or state expired and it failed to obtain a new one.
+.It Dv RELEASE
+dhcpcd's lease was released back to the DHCP server for re-use.
+.It Dv NAK
+dhcpcd received a NAK from the DHCP server.
+This should be treated as EXPIRE.
+.It Dv NOCARRIER
+dhcpcd lost the carrier.
+The cable may have been unplugged or association to the wireless point lost.
+.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 STOP
+dhcpcd stopped running on the interface.
+.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 FILES
+When
+.Nm
+runs, it loads
+.Pa /etc/dhcpcd.enter-hook
+and any scripts found in
+.Pa /libexec/dhcpcd-hooks
+in a lexical order and then finally
+.Pa /etc/dhcpcd.exit-hook
+.Sh SEE ALSO
+.Xr dhcpcd 8
+.Sh AUTHORS
+.An Roy Marples Aq roy@marples.name
+.Sh BUGS
+Please report them to http://roy.marples.name/projects/dhcpcd
diff --git a/dhcpcd/dhcpcd-run-hooks.8.in b/dhcpcd/dhcpcd-run-hooks.8.in
new file mode 100644
index 0000000..c0dc081
--- /dev/null
+++ b/dhcpcd/dhcpcd-run-hooks.8.in
@@ -0,0 +1,148 @@
+.\" Copyright (c) 2006-2012 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 19, 2012
+.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 ROUTERADVERT
+.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 INFORM
+dhcpcd informed a DHCP server about it's address and obtained other
+configuration details.
+.It Dv BOUND
+dhcpcd obtained a new lease from a DHCP server.
+.It Dv RENEW
+dhcpcd renewed it's lease.
+.It Dv REBIND
+dhcpcd has rebound to a new DHCP server.
+.It Dv REBOOT
+dhcpcd successfully requested a lease from a DHCP server.
+.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
+dhcpcd's lease or state expired and it failed to obtain a new one.
+.It Dv RELEASE
+dhcpcd's lease was released back to the DHCP server for re-use.
+.It Dv NAK
+dhcpcd received a NAK from the DHCP server.
+This should be treated as EXPIRE.
+.It Dv NOCARRIER
+dhcpcd lost the carrier.
+The cable may have been unplugged or association to the wireless point lost.
+.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 STOP
+dhcpcd stopped running on the interface.
+.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.
+.It Dv ROUTERADVERT
+dhcpcd has received an IPv6 Router Advertisment, or one has expired.
+.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 roy@marples.name
+.Sh BUGS
+Please report them to
+.Lk http://roy.marples.name/projects/dhcpcd
+.Sh SECURITY CONSIDERATIONS
+Little validation of DHCP options is done in dhcpcd itself.
+Instead, it is up to the hooks to handle any validation needed.
+To this end, some helper functions are provided, such as valid_domainname as
+used by the
+.Pa 20-resolv.conf
+hook to ensure that the hostname is not set to an invalid value.
+valid_path is also provided, but is currently unused by a stock hook script.
diff --git a/dhcpcd/dhcpcd-run-hooks.in b/dhcpcd/dhcpcd-run-hooks.in
new file mode 100644
index 0000000..2125f9a
--- /dev/null
+++ b/dhcpcd/dhcpcd-run-hooks.in
@@ -0,0 +1,237 @@
+#!/bin/sh
+# dhcpcd client configuration script 
+
+# Handy variables and functions for our hooks to use
+if [ "$reason" = ROUTERADVERT ]; then
+	ifsuffix=":ra"
+else
+	ifsuffix=
+fi
+ifname="$interface$ifsuffix"
+
+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=/var/run/dhcpcd
+
+# 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
+		[ -e "$1/$i" ] && ifaces="$ifaces${ifaces:+ }$i"
+	done
+	for x in "$1"/*; do
+		[ -e "$x" ] || continue
+		for i in $interface_order; do
+			if [ $i = "${x##*/}" ]; then
+				unset x
+				break
+			fi
+		done
+		[ -n "$x" ] && ifaces="$ifaces${ifaces:+ }${x##*/}"
+	done
+	echo "$ifaces"
+}
+
+# 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.
+# If different, replace first with second otherwise remove second.
+change_file()
+{
+	if [ -e "$1" ]; then
+		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
+		if [ $? -eq 0 ]; then
+			rm -f "$2"
+			return 1
+		fi
+	fi
+	cat "$2" > "$1"
+	rm -f "$2"
+	return 0
+}
+
+# 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"
+
+	[ -n "$lvl" ] && shift
+	if [ -n "$*" ]; then
+		if type logger >/dev/null 2>&1; then
+			logger -t dhcpcd -p daemon."$lvl" -is "$interface: $*"
+		fi
+	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;;
+		*[![: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
+}
+
+# Check a system service exists 
+service_exists()
+{
+	@SERVICEEXISTS@
+}
+
+# Send a command to a system service
+service_cmd()
+{
+	@SERVICECMD@
+}
+
+# Send a command to a system service if it is running
+service_status()
+{
+	@SERVICESTATUS@
+}
+
+# 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
+			*/"$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/dhcpcd.8 b/dhcpcd/dhcpcd.8
new file mode 100644
index 0000000..bfeb614
--- /dev/null
+++ b/dhcpcd/dhcpcd.8
@@ -0,0 +1,601 @@
+.\" Copyright (c) 2006-2012 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 June 7, 2012
+.Dt DHCPCD 8
+.Os
+.Sh NAME
+.Nm dhcpcd
+.Nd an RFC 2131 compliant DHCP client
+.Sh SYNOPSIS
+.Nm
+.Op Fl ABbDdEGgHJKkLnpqTVw
+.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 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 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 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.
+.Pp
+.Nm
+is also an implementation of the BOOTP client specified in
+.Li RFC 951 .
+.Pp
+.Nm
+is also an implementation of an IPv6 Router Solicitor as specified in
+.Li RFC 4861
+and
+.Li RFC 6106 .
+.Nm
+can optionally handle address and route management itself,
+and will do so by default if Router Solicitation is disabled in the kernel.
+If
+.Nm
+is managing routes,
+.Nm
+sends Neighbor Solicitions to each advertising router periodically and will
+expire the ones that do not respond.
+.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.
+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
+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.
+.Ss Hooking into DHCP events
+.Nm
+runs
+.Pa /libexec/dhcpcd-run-hooks ,
+or the script specified by the
+.Fl c , Fl Fl script
+option.
+This script runs each script found in
+.Pa /libexec/dhcpcd-hooks
+in a lexical order.
+The default installation supplies the scripts
+.Pa 01-test ,
+.Pa 10-mtu ,
+.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 /libexec/dhcpcd-run-hooks .
+.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 /etc/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 /etc/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
+.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 k , Fl Fl release
+This causes an existing
+.Nm
+process running on the
+.Ar interface
+to release its lease, de-configure the
+.Ar interface
+and then exit.
+.Nm
+then waits until this process has exited.
+.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 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
+Notifies
+.Nm
+to reload its configuration and rebind its interfaces.
+If
+.Nm
+is not running, then it starts up as normal.
+.It Fl o , Fl Fl option Ar option
+Request the DHCP
+.Ar option
+variable for use in
+.Pa /libexec/dhcpcd-run-hooks .
+.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.
+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 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.
+.It Fl u , Fl Fl userclass Ar class
+Tags the DHCP 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 , Fl Fl waitip
+Wait for an address to be assigned before forking to the background.
+.It Fl x , Fl Fl exit
+This will signal an existing
+.Nm
+process running on the
+.Ar interface
+to de-configure the
+.Ar interface
+and exit.
+.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.
+The default is 5 seconds.
+A setting of 0 seconds causes
+.Nm
+to skip the reboot phase and go straight into discover.
+.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 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 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 test
+On receipt of DHCP messages just call
+.Pa /libexec/dhcpcd-run-hooks
+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.
+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.
+.It Fl V, Fl Fl variables
+Display a list of option codes and the associated variable 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.
+.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.
+.Sh FILES
+.Bl -ohang
+.It Pa /etc/dhcpcd.conf
+Configuration file for dhcpcd.
+If you always use the same options, put them here.
+.It Pa /etc/dhcpcd.duid
+Text file that holds the DUID used to identify the host.
+.It Pa /libexec/dhcpcd-run-hooks
+Bourne shell script that is run to configure or de-configure an interface.
+.It Pa /libexec/dhcpcd-hooks
+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 /var/db/dhcpcd\- Ns Ar interface Ns .lease
+The actual DHCP message send by the server.
+We use this when reading the last
+lease and use the files mtime as when it was issued.
+.It Pa /var/run/dhcpcd.pid
+Stores the PID of
+.Nm
+running on all interfaces.
+.It Pa /var/run/dhcpcd\- Ns Ar interface Ns .pid
+Stores the PID of
+.Nm
+running on the
+.Ar interface .
+.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 2131, RFC 2132, RFC 2855, RFC 3004, RFC 3361, RFC 3396,
+RFC 3397, RFC 3442, RFC 3927, RFC 4361, RFC 4390, RFC 4702, RFC 4861, RFC 5969,
+RFC 6106.
+.Sh AUTHORS
+.An Roy Marples Aq roy@marples.name
+.Sh BUGS
+Please report them to
+.Lk http://roy.marples.name/projects/dhcpcd
diff --git a/dhcpcd/dhcpcd.8.in b/dhcpcd/dhcpcd.8.in
new file mode 100644
index 0000000..fc3c04c
--- /dev/null
+++ b/dhcpcd/dhcpcd.8.in
@@ -0,0 +1,586 @@
+.\" Copyright (c) 2006-2012 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 19, 2012
+.Dt DHCPCD 8
+.Os
+.Sh NAME
+.Nm dhcpcd
+.Nd an RFC 2131 compliant DHCP client
+.Sh SYNOPSIS
+.Nm
+.Op Fl ABbDdEGgHJKkLnpqTVw
+.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 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 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 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.
+.Pp
+.Nm
+is also an implementation of the BOOTP client specified in
+.Li RFC 951 .
+.Pp
+.Nm
+is also an implementation of an IPv6 Router Solicitor as specified in
+.Li RFC 6106
+with regard to the RDNSS and DNSSL options.
+.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.
+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
+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.
+.Ss Hooking into DHCP 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 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
+.Ar vendorclassid
+field sent.
+The default is
+dhcpcd <version>.
+If not set then none is sent.
+.It Fl k , Fl Fl release
+This causes an existing
+.Nm
+process running on the
+.Ar interface
+to release its lease, de-configure the
+.Ar interface
+and then exit.
+.Nm
+then waits until this process has exited.
+.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 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
+Notifies
+.Nm
+to reload its configuration and rebind its interfaces.
+If
+.Nm
+is not running, then it starts up as normal.
+.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.
+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 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.
+.It Fl u , Fl Fl userclass Ar class
+Tags the DHCP 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 , Fl Fl waitip
+Wait for an address to be assigned before forking to the background.
+.It Fl x , Fl Fl exit
+This will signal an existing
+.Nm
+process running on the
+.Ar interface
+to de-configure the
+.Ar interface
+and exit.
+.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.
+The default is 5 seconds.
+A setting of 0 seconds causes
+.Nm
+to skip the reboot phase and go straight into discover.
+.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 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 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 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.
+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.
+.It Fl V, Fl Fl variables
+Display a list of option codes and the associated variable 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.
+.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.
+.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 @SCRIPT@
+Bourne shell script that is run to configure or de-configure an interface.
+.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 .lease
+The actual DHCP message send by the server.
+We use this when reading the last
+lease and use the files mtime as when it was issued.
+.It Pa /var/run/dhcpcd.pid
+Stores the PID of
+.Nm
+running on all interfaces.
+.It Pa /var/run/dhcpcd\- Ns Ar interface Ns .pid
+Stores the PID of
+.Nm
+running on the
+.Ar interface .
+.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 2131, RFC 2132, RFC 2855, RFC 3004, RFC 3361, RFC 3396,
+RFC 3397, RFC 3442, RFC 3927, RFC 4361, RFC 4390, RFC 4702, RFC 5969, RFC 6106.
+.Sh AUTHORS
+.An Roy Marples Aq roy@marples.name
+.Sh BUGS
+Please report them to
+.Lk http://roy.marples.name/projects/dhcpcd
diff --git a/dhcpcd/dhcpcd.c b/dhcpcd/dhcpcd.c
new file mode 100644
index 0000000..6eae970
--- /dev/null
+++ b/dhcpcd/dhcpcd.c
@@ -0,0 +1,2206 @@
+/* 
+ * 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.
+ */
+
+const char copyright[] = "Copyright (c) 2006-2012 Roy Marples";
+
+#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 <arpa/inet.h>
+#include <net/route.h>
+
+#ifdef __linux__
+#  include <asm/types.h> /* for systems with broken headers */
+#  include <linux/rtnetlink.h>
+#endif
+
+#include <ctype.h>
+#include <errno.h>
+#include <getopt.h>
+#include <limits.h>
+#include <paths.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <time.h>
+
+#include "arp.h"
+#include "bind.h"
+#include "config.h"
+#include "common.h"
+#include "configure.h"
+#include "control.h"
+#include "dhcpcd.h"
+#include "duid.h"
+#include "eloop.h"
+#include "if-options.h"
+#include "if-pref.h"
+#include "ipv4ll.h"
+#include "ipv6rs.h"
+#include "net.h"
+#include "platform.h"
+#include "signals.h"
+
+#ifdef ANDROID
+#include <sys/capability.h>
+#include <sys/prctl.h>
+#include <cutils/properties.h>
+#include <private/android_filesystem_config.h>
+#endif
+
+/* 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
+
+unsigned long long options = 0;
+int pidfd = -1;
+struct interface *ifaces = NULL;
+int ifac = 0;
+char **ifav = NULL;
+int ifdc = 0;
+char **ifdv = NULL;
+/* If set, avoid routes after a DHCP success */
+int avoid_routes = 0;
+
+static char **margv;
+static int margc;
+static struct if_options *if_options;
+static char **ifv;
+static int ifc;
+static char *cffile;
+static char *pidfile;
+static int linkfd = -1, ipv6rsfd = -1;
+
+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" },
+	{ 0, NULL }
+};
+
+static void send_release(struct interface *);
+
+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 pid_t
+read_pid(void)
+{
+	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 void
+usage(void)
+{
+
+printf("usage: "PACKAGE"\t[-aABbDdEGgHJKkLnpqTVw]\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-v, --version\n"
+	"       "PACKAGE"\t-x, --exit [interface]\n");
+}
+
+static void
+cleanup(void)
+{
+#ifdef DEBUG_MEMORY
+	struct interface *iface;
+	int i;
+
+	free_options(if_options);
+
+	while (ifaces) {
+		iface = ifaces;
+		ifaces = iface->next;
+		free_interface(iface);
+	}
+
+	for (i = 0; i < ifac; i++)
+		free(ifav[i]);
+	free(ifav);
+	for (i = 0; i < ifdc; i++)
+		free(ifdv[i]);
+	free(ifdv);
+#endif
+
+	if (linkfd != -1)
+		close(linkfd);
+	if (pidfd > -1) {
+		if (options & DHCPCD_MASTER) {
+			if (stop_control() == -1)
+				syslog(LOG_ERR, "stop_control: %m");
+		}
+		close(pidfd);
+		unlink(pidfile);
+	}
+#ifdef DEBUG_MEMORY
+	free(pidfile);
+#endif
+}
+
+/* ARGSUSED */
+void
+handle_exit_timeout(_unused void *arg)
+{
+	int timeout;
+
+	syslog(LOG_ERR, "timed out");
+	if (!(options & DHCPCD_TIMEOUT_IPV4LL)) {
+		if (options & DHCPCD_MASTER) {
+			daemonise();
+			return;
+		} else
+			exit(EXIT_FAILURE);
+	}
+	options &= ~DHCPCD_TIMEOUT_IPV4LL;
+	timeout = (PROBE_NUM * PROBE_MAX) + (PROBE_WAIT * 2);
+	syslog(LOG_WARNING, "allowing %d seconds for IPv4LL timeout", timeout);
+	add_timeout_sec(timeout, handle_exit_timeout, NULL);
+}
+
+void
+drop_dhcp(struct interface *iface, const char *reason)
+{
+	free(iface->state->old);
+	iface->state->old = iface->state->new;
+	iface->state->new = NULL;
+	iface->state->reason = reason;
+	configure(iface);
+	free(iface->state->old);
+	iface->state->old = NULL;
+	iface->state->lease.addr.s_addr = 0;
+}
+
+struct interface *
+find_interface(const char *ifname)
+{
+	struct interface *ifp;
+	
+	for (ifp = ifaces; ifp; ifp = ifp->next)
+		if (strcmp(ifp->name, ifname) == 0)
+			return ifp;
+	return NULL;
+}
+
+static void
+stop_interface(struct interface *iface)
+{
+	struct interface *ifp, *ifl = NULL;
+
+	syslog(LOG_INFO, "%s: removing interface", iface->name);
+	if (iface->ras) {
+		ipv6rs_free(iface);
+		iface->ras = NULL;
+		run_script_reason(iface, "ROUTERADVERT");
+	}
+	if (strcmp(iface->state->reason, "RELEASE") != 0)
+		drop_dhcp(iface, "STOP");
+	close_sockets(iface);
+	delete_timeout(NULL, iface);
+	for (ifp = ifaces; ifp; ifp = ifp->next) {
+		if (ifp == iface)
+			break;
+		ifl = ifp;
+	}
+	if (ifl)
+		ifl->next = ifp->next;
+	else
+		ifaces = ifp->next;
+	free_interface(ifp);
+	if (!(options & (DHCPCD_MASTER | DHCPCD_TEST)))
+		exit(EXIT_FAILURE);
+}
+
+static uint32_t
+dhcp_xid(struct interface *iface)
+{
+	uint32_t xid;
+
+	if (iface->state->options->options & DHCPCD_XID_HWADDR &&
+	    iface->hwlen >= sizeof(xid)) 
+		/* The lower bits are probably more unique on the network */
+		memcpy(&xid, (iface->hwaddr + iface->hwlen) - sizeof(xid),
+		    sizeof(xid));
+	else
+		xid = arc4random();
+
+	return xid;
+}
+
+static void
+send_message(struct interface *iface, int type,
+    void (*callback)(void *))
+{
+	struct if_state *state = iface->state;
+	struct if_options *ifo = state->options;
+	struct dhcp_message *dhcp;
+	uint8_t *udp;
+	ssize_t len, r;
+	struct in_addr from, to;
+	in_addr_t a = 0;
+	struct timeval tv;
+
+	if (!callback)
+		syslog(LOG_DEBUG, "%s: sending %s with xid 0x%x",
+		    iface->name, get_dhcp_op(type), state->xid);
+	else {
+		if (state->interval == 0)
+			state->interval = 4;
+		else {
+			state->interval *= 2;
+			if (state->interval > 64)
+				state->interval = 64;
+		}
+		tv.tv_sec = state->interval + DHCP_RAND_MIN;
+		tv.tv_usec = arc4random() % (DHCP_RAND_MAX_U - DHCP_RAND_MIN_U);
+		syslog(LOG_DEBUG,
+		    "%s: sending %s (xid 0x%x), next in %0.2f seconds",
+		    iface->name, get_dhcp_op(type), state->xid,
+		    timeval_to_double(&tv));
+	}
+
+	/* Ensure sockets are open. */
+	open_sockets(iface);
+
+	/* 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 (iface->udp_fd == -1 ||
+	    (!(ifo->options & DHCPCD_INFORM) && is_bootp(iface->state->new)))
+	{
+		a = iface->addr.s_addr;
+		iface->addr.s_addr = 0;
+	}
+	len = make_message(&dhcp, iface, type);
+	if (a)
+		iface->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 = 0;
+	if (to.s_addr && to.s_addr != INADDR_BROADCAST) {
+		r = send_packet(iface, to, (uint8_t *)dhcp, len);
+		if (r == -1) {
+			syslog(LOG_ERR, "%s: send_packet: %m", iface->name);
+			close_sockets(iface);
+		}
+	} else {
+		len = make_udp_packet(&udp, (uint8_t *)dhcp, len, from, to);
+		r = send_raw_packet(iface, ETHERTYPE_IP, udp, len);
+		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) {
+			syslog(LOG_ERR, "%s: send_raw_packet: %m", iface->name);
+			if (!(options & DHCPCD_TEST))
+				drop_dhcp(iface, "FAIL");
+			close_sockets(iface);
+			delete_timeout(NULL, iface);
+			callback = NULL;
+		}
+	}
+	free(dhcp);
+
+	/* 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)
+		add_timeout_tv(&tv, callback, iface);
+}
+
+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
+start_expire(void *arg)
+{
+	struct interface *iface = arg;
+
+	iface->state->interval = 0;
+	if (iface->addr.s_addr == 0) {
+		/* We failed to reboot, so enter discovery. */
+		iface->state->lease.addr.s_addr = 0;
+		start_discover(iface);
+		return;
+	}
+
+	syslog(LOG_ERR, "%s: lease expired", iface->name);
+	delete_timeout(NULL, iface);
+	drop_dhcp(iface, "EXPIRE");
+	unlink(iface->leasefile);
+	if (iface->carrier != LINK_DOWN)
+		start_interface(iface);
+}
+
+static void
+log_dhcp(int lvl, const char *msg,
+    const struct interface *iface, const struct dhcp_message *dhcp,
+    const struct in_addr *from)
+{
+	const char *tfrom;
+	char *a;
+	struct in_addr addr;
+	int r;
+
+	if (strcmp(msg, "NAK:") == 0)
+		a = get_option_string(dhcp, DHO_MESSAGE);
+	else if (dhcp->yiaddr != 0) {
+		addr.s_addr = dhcp->yiaddr;
+		a = xstrdup(inet_ntoa(addr));
+	} else
+		a = NULL;
+
+	tfrom = "from";
+	r = get_option_addr(&addr, dhcp, DHO_SERVERID);
+	if (dhcp->servername[0] && r == 0)
+		syslog(lvl, "%s: %s %s %s %s `%s'", iface->name, msg, a,
+		    tfrom, inet_ntoa(addr), dhcp->servername);
+	else {
+		if (r != 0) {
+			tfrom = "via";
+			addr = *from;
+		}
+		if (a == NULL)
+			syslog(lvl, "%s: %s %s %s",
+			    iface->name, msg, tfrom, inet_ntoa(addr));
+		else
+			syslog(lvl, "%s: %s %s %s %s",
+			    iface->name, msg, a, tfrom, inet_ntoa(addr));
+	}
+	free(a);
+}
+
+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
+handle_dhcp(struct interface *iface, struct dhcp_message **dhcpp, const struct in_addr *from)
+{
+	struct if_state *state = iface->state;
+	struct if_options *ifo = state->options;
+	struct dhcp_message *dhcp = *dhcpp;
+	struct dhcp_lease *lease = &state->lease;
+	uint8_t type, tmp;
+	struct in_addr addr;
+	size_t i;
+
+	/* reset the message counter */
+	state->interval = 0;
+
+	/* We may have found a BOOTP server */
+	if (get_option_uint8(&type, dhcp, DHO_MESSAGETYPE) == -1) 
+		type = 0;
+
+	if (type == DHCP_NAK) {
+		/* For NAK, only check if we require the ServerID */
+		if (has_option_mask(ifo->requiremask, DHO_SERVERID) &&
+		    get_option_addr(&addr, dhcp, DHO_SERVERID) == -1)
+		{
+			log_dhcp(LOG_WARNING, "reject NAK", iface, dhcp, from);
+			return;
+		}
+		/* We should restart on a NAK */
+		log_dhcp(LOG_WARNING, "NAK:", iface, dhcp, from);
+		if (!(options & DHCPCD_TEST)) {
+			drop_dhcp(iface, "NAK");
+			unlink(iface->leasefile);
+		}
+		close_sockets(iface);
+		/* If we constantly get NAKS then we should slowly back off */
+		add_timeout_sec(state->nakoff, start_interface, iface);
+		state->nakoff *= 2;
+		if (state->nakoff > NAKOFF_MAX)
+			state->nakoff = NAKOFF_MAX;
+		return;
+	}
+
+	/* Ensure that all required options are present */
+	for (i = 1; i < 255; i++) {
+		if (has_option_mask(ifo->requiremask, i) &&
+		    get_option_uint8(&tmp, dhcp, i) != 0)
+		{
+			/* If we are bootp, then ignore the need for serverid.
+			 * To ignore bootp, require dhcp_message_type instead. */
+			if (type == 0 && i == DHO_SERVERID)
+				continue;
+			log_dhcp(LOG_WARNING, "reject DHCP", iface, dhcp, from);
+			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))
+	{
+		log_dhcp(LOG_WARNING, "reject invalid address",
+		    iface, dhcp, from);
+		return;
+	}
+
+	/* No NAK, so reset the backoff */
+	state->nakoff = 1;
+
+	if ((type == 0 || type == DHCP_OFFER) &&
+	    state->state == DHS_DISCOVER)
+	{
+		lease->frominfo = 0;
+		lease->addr.s_addr = dhcp->yiaddr;
+		lease->cookie = dhcp->cookie;
+		if (type == 0 ||
+		    get_option_addr(&lease->server, dhcp, DHO_SERVERID) != 0)
+			lease->server.s_addr = INADDR_ANY;
+		log_dhcp(LOG_INFO, "offered", iface, dhcp, from);
+		free(state->offer);
+		state->offer = dhcp;
+		*dhcpp = NULL;
+		if (options & DHCPCD_TEST) {
+			free(state->old);
+			state->old = state->new;
+			state->new = state->offer;
+			state->offer = NULL;
+			state->reason = "TEST";
+			run_script(iface);
+			exit(EXIT_SUCCESS);
+		}
+		delete_timeout(send_discover, iface);
+		/* 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. */
+			start_request(iface);
+			return;
+		}
+	}
+
+	if (type) {
+		if (type == DHCP_OFFER) {
+			log_dhcp(LOG_INFO, "ignoring offer of",
+			    iface, dhcp, from);
+			return;
+		}
+
+		/* We should only be dealing with acks */
+		if (type != DHCP_ACK) {
+			log_dhcp(LOG_ERR, "not ACK or OFFER",
+			    iface, dhcp, from);
+			return;
+		}
+
+		if (!(ifo->options & DHCPCD_INFORM))
+			log_dhcp(LOG_INFO, "acknowledged", iface, dhcp, from);
+	}
+
+	/* 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;
+	delete_timeout(NULL, iface);
+
+	/* We now have an offer, so close the DHCP sockets.
+	 * This allows us to safely ARP when broken DHCP servers send an ACK
+	 * follows by an invalid NAK. */
+	close_sockets(iface);
+
+	if (ifo->options & DHCPCD_ARP &&
+	    iface->addr.s_addr != state->offer->yiaddr)
+	{
+		/* If the interface already has the address configured
+		 * then we can't ARP for duplicate detection. */
+		addr.s_addr = state->offer->yiaddr;
+		if (has_address(iface->name, &addr, NULL) != 1) {
+			state->claims = 0;
+			state->probes = 0;
+			state->conflicts = 0;
+			state->state = DHS_PROBE;
+			send_arp_probe(iface);
+			return;
+		}
+	}
+
+	bind_interface(iface);
+}
+
+static void
+handle_dhcp_packet(void *arg)
+{
+	struct interface *iface = arg;
+	uint8_t *packet;
+	struct dhcp_message *dhcp = NULL;
+	const uint8_t *pp;
+	ssize_t bytes;
+	struct in_addr from;
+	int i, partialcsum = 0;
+
+	/* We loop through until our buffer is empty.
+	 * The benefit is that if we get >1 DHCP packet in our buffer and
+	 * the first one fails for any reason, we can use the next. */
+	packet = xmalloc(udp_dhcp_len);
+	for(;;) {
+		bytes = get_raw_packet(iface, ETHERTYPE_IP,
+		    packet, udp_dhcp_len, &partialcsum);
+		if (bytes == 0 || bytes == -1)
+			break;
+		if (valid_udp_packet(packet, bytes, &from, partialcsum) == -1) {
+			syslog(LOG_ERR, "%s: invalid UDP packet from %s",
+			    iface->name, inet_ntoa(from));
+			continue;
+		}
+		i = whitelisted_ip(iface->state->options, from.s_addr);
+		if (i == 0) {
+			syslog(LOG_WARNING,
+			    "%s: non whitelisted DHCP packet from %s",
+			    iface->name, inet_ntoa(from));
+			continue;
+		} else if (i != 1 &&
+		    blacklisted_ip(iface->state->options, from.s_addr) == 1)
+		{
+			syslog(LOG_WARNING,
+			    "%s: blacklisted DHCP packet from %s",
+			    iface->name, inet_ntoa(from));
+			continue;
+		}
+		if (iface->flags & IFF_POINTOPOINT &&
+		    iface->dst.s_addr != from.s_addr)
+		{
+			syslog(LOG_WARNING,
+			    "%s: server %s is not destination",
+			    iface->name, inet_ntoa(from));
+		}
+		bytes = get_udp_data(&pp, packet);
+		if ((size_t)bytes > sizeof(*dhcp)) {
+			syslog(LOG_ERR,
+			    "%s: packet greater than DHCP size from %s",
+			    iface->name, inet_ntoa(from));
+			continue;
+		}
+		if (!dhcp)
+			dhcp = xzalloc(sizeof(*dhcp));
+		memcpy(dhcp, pp, bytes);
+		if (dhcp->cookie != htonl(MAGIC_COOKIE)) {
+			syslog(LOG_DEBUG, "%s: bogus cookie from %s",
+			    iface->name, inet_ntoa(from));
+			continue;
+		}
+		/* Ensure it's the right transaction */
+		if (iface->state->xid != dhcp->xid) {
+			syslog(LOG_DEBUG,
+			    "%s: wrong xid 0x%x (expecting 0x%x) from %s",
+			    iface->name, dhcp->xid, iface->state->xid,
+			    inet_ntoa(from));
+			continue;
+		}
+		/* Ensure packet is for us */
+		if (iface->hwlen <= sizeof(dhcp->chaddr) &&
+		    memcmp(dhcp->chaddr, iface->hwaddr, iface->hwlen))
+		{
+			syslog(LOG_DEBUG, "%s: xid 0x%x is not for hwaddr %s",
+			    iface->name, dhcp->xid,
+			    hwaddr_ntoa(dhcp->chaddr, sizeof(dhcp->chaddr)));
+			continue;
+		}
+		handle_dhcp(iface, &dhcp, &from);
+		if (iface->raw_fd == -1)
+			break;
+	}
+	free(packet);
+	free(dhcp);
+}
+
+static void
+send_release(struct interface *iface)
+{
+	struct timespec ts;
+
+	if (iface->state->new != NULL &&
+	    iface->state->new->cookie == htonl(MAGIC_COOKIE))
+	{
+		syslog(LOG_INFO, "%s: releasing lease of %s",
+		    iface->name, inet_ntoa(iface->state->lease.addr));
+		iface->state->xid = dhcp_xid(iface);
+		send_message(iface, DHCP_RELEASE, NULL);
+		/* Give the packet a chance to go before dropping the ip */
+		ts.tv_sec = RELEASE_DELAY_S;
+		ts.tv_nsec = RELEASE_DELAY_NS;
+		nanosleep(&ts, NULL);
+		drop_dhcp(iface, "RELEASE");
+	}
+	unlink(iface->leasefile);
+}
+
+void
+send_decline(struct interface *iface)
+{
+	send_message(iface, DHCP_DECLINE, NULL);
+}
+
+static void
+configure_interface1(struct interface *iface)
+{
+	struct if_state *ifs = iface->state;
+	struct if_options *ifo = ifs->options;
+	uint8_t *duid;
+	size_t len = 0, ifl;
+
+	/* Do any platform specific configuration */
+	if_conf(iface);
+
+	if (iface->flags & IFF_POINTOPOINT && !(ifo->options & DHCPCD_INFORM))
+		ifo->options |= DHCPCD_STATIC;
+	if (iface->flags & IFF_NOARP ||
+	    ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC))
+		ifo->options &= ~(DHCPCD_ARP | DHCPCD_IPV4LL);
+	if (!(iface->flags & (IFF_POINTOPOINT | IFF_LOOPBACK | IFF_MULTICAST)))
+		ifo->options &= ~DHCPCD_IPV6RS;
+	if (ifo->options & DHCPCD_LINK && carrier_status(iface) == -1)
+		ifo->options &= ~DHCPCD_LINK;
+	
+	if (ifo->metric != -1)
+		iface->metric = ifo->metric;
+
+	/* 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 (iface->hwlen > DHCP_CHADDR_LEN)
+		ifo->options |= DHCPCD_CLIENTID;
+
+	/* Firewire and InfiniBand interfaces require ClientID and
+	 * the broadcast option being set. */
+	switch (iface->family) {
+	case ARPHRD_IEEE1394:	/* FALLTHROUGH */
+	case ARPHRD_INFINIBAND:
+		ifo->options |= DHCPCD_CLIENTID | DHCPCD_BROADCAST;
+		break;
+	}
+
+	free(iface->clientid);
+	iface->clientid = NULL;
+	if (*ifo->clientid) {
+		iface->clientid = xmalloc(ifo->clientid[0] + 1);
+		memcpy(iface->clientid, ifo->clientid, ifo->clientid[0] + 1);
+	} else if (ifo->options & DHCPCD_CLIENTID) {
+		if (ifo->options & DHCPCD_DUID) {
+			duid = xmalloc(DUID_LEN);
+			if ((len = get_duid(duid, iface)) == 0)
+				syslog(LOG_ERR, "get_duid: %m");
+		}
+		if (len > 0) {
+			iface->clientid = xmalloc(len + 6);
+			iface->clientid[0] = len + 5;
+			iface->clientid[1] = 255; /* RFC 4361 */
+			ifl = strlen(iface->name);
+			if (ifl < 5) {
+				memcpy(iface->clientid + 2, iface->name, ifl);
+				if (ifl < 4)
+					memset(iface->clientid + 2 + ifl,
+					    0, 4 - ifl);
+			} else {
+				ifl = htonl(if_nametoindex(iface->name));
+				memcpy(iface->clientid + 2, &ifl, 4);
+			}
+		} else if (len == 0) {
+			len = iface->hwlen + 1;
+			iface->clientid = xmalloc(len + 1);
+			iface->clientid[0] = len;
+			iface->clientid[1] = iface->family;
+			memcpy(iface->clientid + 2, iface->hwaddr,
+			    iface->hwlen);
+		}
+	}
+	if (ifo->options & DHCPCD_CLIENTID)
+		syslog(LOG_DEBUG, "%s: using ClientID %s", iface->name,
+		    hwaddr_ntoa(iface->clientid + 1, *iface->clientid));
+	else if (iface->hwlen)
+		syslog(LOG_DEBUG, "%s: using hwaddr %s", iface->name,
+		    hwaddr_ntoa(iface->hwaddr, iface->hwlen));
+}
+
+int
+select_profile(struct interface *iface, const char *profile)
+{
+	struct if_options *ifo;
+	int ret;
+
+	ret = 0;
+	ifo = read_config(cffile, iface->name, iface->ssid, profile);
+	if (ifo == NULL) {
+		syslog(LOG_DEBUG, "%s: no profile %s", iface->name, profile);
+		ret = -1;
+		goto exit;
+	}
+	if (profile != NULL) {
+		strlcpy(iface->state->profile, profile,
+		    sizeof(iface->state->profile));
+		syslog(LOG_INFO, "%s: selected profile %s",
+		    iface->name, profile);
+	} else
+		*iface->state->profile = '\0';
+	free_options(iface->state->options);
+	iface->state->options = ifo;
+
+exit:
+	if (profile)
+		configure_interface1(iface);
+	return ret;
+}
+
+static void
+start_fallback(void *arg)
+{
+	struct interface *iface;
+
+	iface = (struct interface *)arg;
+	select_profile(iface, iface->state->options->fallback);
+	start_interface(iface);
+}
+
+static void
+configure_interface(struct interface *iface, int argc, char **argv)
+{
+	select_profile(iface, NULL);
+	add_options(iface->state->options, argc, argv);
+	configure_interface1(iface);
+}
+
+void
+handle_carrier(int action, int flags, const char *ifname)
+{
+	struct interface *iface;
+	int carrier;
+
+	if (!(options & DHCPCD_LINK))
+		return;
+	for (iface = ifaces; iface; iface = iface->next)
+		if (strcmp(iface->name, ifname) == 0)
+			break;
+	if (!iface) {
+		if (options & DHCPCD_LINK)
+			handle_interface(1, ifname);
+		return;
+	}
+	if (!(iface->state->options->options & DHCPCD_LINK))
+		return;
+
+	if (action) {
+		carrier = action == 1 ? 1 : 0;
+		iface->flags = flags;
+	} else
+		carrier = carrier_status(iface);
+
+	if (carrier == -1)
+		syslog(LOG_ERR, "%s: carrier_status: %m", ifname);
+	else if (carrier == 0 || ~iface->flags & IFF_UP) {
+		if (iface->carrier != LINK_DOWN) {
+			iface->carrier = LINK_DOWN;
+			syslog(LOG_INFO, "%s: carrier lost", iface->name);
+			close_sockets(iface);
+			delete_timeouts(iface, start_expire, NULL);
+			if (iface->ras) {
+				ipv6rs_free(iface);
+				iface->ras = NULL;
+				run_script_reason(iface, "ROUTERADVERT");
+			}
+			drop_dhcp(iface, "NOCARRIER");
+		}
+	} else if (carrier == 1 && !(~iface->flags & IFF_UP)) {
+		if (iface->carrier != LINK_UP) {
+			iface->carrier = LINK_UP;
+			syslog(LOG_INFO, "%s: carrier acquired", iface->name);
+			if (iface->wireless)
+				getifssid(iface->name, iface->ssid);
+			configure_interface(iface, margc, margv);
+			iface->state->interval = 0;
+			iface->state->reason = "CARRIER";
+			run_script(iface);
+			start_interface(iface);
+		}
+	}
+}
+
+void
+start_discover(void *arg)
+{
+	struct interface *iface = arg;
+	struct if_options *ifo = iface->state->options;
+	int timeout = ifo->timeout;
+
+	/* If we're rebooting and we're not daemonised then we need
+	 * to shorten the normal timeout to ensure we try correctly
+	 * for a fallback or IPv4LL address. */
+	if (iface->state->state == DHS_REBOOT &&
+	    !(options & DHCPCD_DAEMONISED))
+	{
+		timeout -= ifo->reboot;
+		if (timeout <= 0)
+			timeout = 2;
+	}
+
+	iface->state->state = DHS_DISCOVER;
+	iface->state->xid = dhcp_xid(iface);
+	delete_timeout(NULL, iface);
+	if (ifo->fallback)
+		add_timeout_sec(timeout, start_fallback, iface);
+	else if (ifo->options & DHCPCD_IPV4LL &&
+	    !IN_LINKLOCAL(htonl(iface->addr.s_addr)))
+	{
+		if (IN_LINKLOCAL(htonl(iface->state->fail.s_addr)))
+			add_timeout_sec(RATE_LIMIT_INTERVAL, start_ipv4ll, iface);
+		else
+			add_timeout_sec(timeout, start_ipv4ll, iface);
+	}
+	if (ifo->options & DHCPCD_REQUEST)
+		syslog(LOG_INFO, "%s: broadcasting for a lease (requesting %s)",
+		    iface->name, inet_ntoa(ifo->req_addr));
+	else
+		syslog(LOG_INFO, "%s: broadcasting for a lease", iface->name);
+	send_discover(iface);
+}
+
+void
+start_request(void *arg)
+{
+	struct interface *iface = arg;
+
+	iface->state->state = DHS_REQUEST;
+	send_request(iface);
+}
+
+void
+start_renew(void *arg)
+{
+	struct interface *iface = arg;
+
+	syslog(LOG_INFO, "%s: renewing lease of %s",
+	    iface->name, inet_ntoa(iface->state->lease.addr));
+	iface->state->state = DHS_RENEW;
+	iface->state->xid = dhcp_xid(iface);
+	send_renew(iface);
+}
+
+void
+start_rebind(void *arg)
+{
+	struct interface *iface = arg;
+
+	syslog(LOG_ERR, "%s: failed to renew, attempting to rebind",
+	    iface->name);
+	iface->state->state = DHS_REBIND;
+	delete_timeout(send_renew, iface);
+	iface->state->lease.server.s_addr = 0;
+	send_rebind(iface);
+}
+
+static void
+start_timeout(void *arg)
+{
+	struct interface *iface = arg;
+
+	bind_interface(iface);
+	iface->state->interval = 0;
+	start_discover(iface);
+}
+
+static struct dhcp_message *
+dhcp_message_new(struct in_addr *addr, struct in_addr *mask)
+{
+	struct dhcp_message *dhcp;
+	uint8_t *p;
+
+	dhcp = xzalloc(sizeof(*dhcp));
+	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 int
+handle_3rdparty(struct interface *iface)
+{
+	struct if_options *ifo;
+	struct in_addr addr, net, dst;
+	
+	ifo = iface->state->options;
+	if (ifo->req_addr.s_addr != INADDR_ANY)
+		return 0;
+
+	if (get_address(iface->name, &addr, &net, &dst) == 1)
+		handle_ifa(RTM_NEWADDR, iface->name, &addr, &net, &dst);
+	else {
+		syslog(LOG_INFO,
+		    "%s: waiting for 3rd party to configure IP address",
+		    iface->name);
+		iface->state->reason = "3RDPARTY";
+		run_script(iface);
+	}
+	return 1;
+}
+
+static void
+start_static(struct interface *iface)
+{
+	struct if_options *ifo;
+
+	if (handle_3rdparty(iface))
+		return;
+	ifo = iface->state->options;
+	iface->state->offer =
+	    dhcp_message_new(&ifo->req_addr, &ifo->req_mask);
+	delete_timeout(NULL, iface);
+	bind_interface(iface);
+}
+
+static void
+start_inform(struct interface *iface)
+{
+	if (handle_3rdparty(iface))
+		return;
+
+	if (options & DHCPCD_TEST) {
+		iface->addr.s_addr = iface->state->options->req_addr.s_addr;
+		iface->net.s_addr = iface->state->options->req_mask.s_addr;
+	} else {
+		iface->state->options->options |= DHCPCD_STATIC;
+		start_static(iface);
+	}
+
+	iface->state->state = DHS_INFORM;
+	iface->state->xid = dhcp_xid(iface);
+	send_inform(iface);
+}
+
+void
+start_reboot(struct interface *iface)
+{
+	struct if_options *ifo = iface->state->options;
+
+	if (ifo->options & DHCPCD_LINK && iface->carrier == LINK_DOWN) {
+		syslog(LOG_INFO, "%s: waiting for carrier", iface->name);
+		return;
+	}
+	if (ifo->options & DHCPCD_STATIC) {
+		start_static(iface);
+		return;
+	}
+	if (ifo->reboot == 0 || iface->state->offer == NULL) {
+		start_discover(iface);
+		return;
+	}
+	if (ifo->options & DHCPCD_INFORM) {
+		syslog(LOG_INFO, "%s: informing address of %s",
+		    iface->name, inet_ntoa(iface->state->lease.addr));
+	} else if (iface->state->offer->cookie == 0) {
+		if (ifo->options & DHCPCD_IPV4LL) {
+			iface->state->claims = 0;
+			send_arp_announce(iface);
+		} else
+			start_discover(iface);
+		return;
+	} else {
+		syslog(LOG_INFO, "%s: rebinding lease of %s",
+		    iface->name, inet_ntoa(iface->state->lease.addr));
+	}
+	iface->state->state = DHS_REBOOT;
+	iface->state->xid = dhcp_xid(iface);
+	iface->state->lease.server.s_addr = 0;
+	delete_timeout(NULL, iface);
+	if (ifo->fallback)
+		add_timeout_sec(ifo->reboot, start_fallback, iface);
+	else if (ifo->options & DHCPCD_LASTLEASE &&
+	    iface->state->lease.frominfo)
+		add_timeout_sec(ifo->reboot, start_timeout, iface);
+	else if (!(ifo->options & DHCPCD_INFORM &&
+		options & (DHCPCD_MASTER | DHCPCD_DAEMONISED)))
+		add_timeout_sec(ifo->reboot, start_expire, iface);
+	/* Don't bother ARP checking as the server could NAK us first. */
+	if (ifo->options & DHCPCD_INFORM)
+		send_inform(iface);
+	else
+		send_request(iface);
+}
+
+void
+start_interface(void *arg)
+{
+	struct interface *iface = arg;
+	struct if_options *ifo = iface->state->options;
+	struct stat st;
+	struct timeval now;
+	uint32_t l;
+	int nolease;
+
+	handle_carrier(0, 0, iface->name);
+	if (iface->carrier == LINK_DOWN) {
+		syslog(LOG_INFO, "%s: waiting for carrier", iface->name);
+		return;
+	}
+
+	iface->start_uptime = uptime();
+	free(iface->state->offer);
+	iface->state->offer = NULL;
+
+	if (options & DHCPCD_IPV6RS && ifo->options & DHCPCD_IPV6RS) {
+		if (check_ipv6(iface->name) == 1)
+			ipv6rs_start(iface);
+		else
+			ifo->options &= ~DHCPCD_IPV6RS;
+	}
+
+	if (iface->state->arping_index < ifo->arping_len) {
+		start_arping(iface);
+		return;
+	}
+	if (ifo->options & DHCPCD_STATIC) {
+		start_static(iface);
+		return;
+	}
+	if (ifo->options & DHCPCD_INFORM) {
+		start_inform(iface);
+		return;
+	}
+	if (iface->hwlen == 0 && ifo->clientid[0] == '\0') {
+		syslog(LOG_WARNING, "%s: needs a clientid to configure",
+		    iface->name);
+		drop_dhcp(iface, "FAIL");
+		close_sockets(iface);
+		delete_timeout(NULL, iface);
+		return;
+	}
+	/* We don't want to read the old lease if we NAK an old test */
+	nolease = iface->state->offer && options & DHCPCD_TEST;
+	if (!nolease)
+		iface->state->offer = read_lease(iface);
+	if (iface->state->offer) {
+		get_lease(&iface->state->lease, iface->state->offer);
+		iface->state->lease.frominfo = 1;
+		if (iface->state->offer->cookie == 0) {
+			if (iface->state->offer->yiaddr ==
+			    iface->addr.s_addr)
+			{
+				free(iface->state->offer);
+				iface->state->offer = NULL;
+			}
+		} else if (iface->state->lease.leasetime != ~0U &&
+		    stat(iface->leasefile, &st) == 0)
+		{
+			/* Offset lease times and check expiry */
+			gettimeofday(&now, NULL);
+			if ((time_t)iface->state->lease.leasetime <
+			    (time_t)(now.tv_sec - st.st_mtime))
+			{
+				syslog(LOG_DEBUG,
+				    "%s: discarding expired lease",
+				    iface->name);
+				free(iface->state->offer);
+				iface->state->offer = NULL;
+				iface->state->lease.addr.s_addr = 0;
+			} else {
+				l = now.tv_sec - st.st_mtime;
+				iface->state->lease.leasetime -= l;
+				iface->state->lease.renewaltime -= l;
+				iface->state->lease.rebindtime -= l;
+			}
+		}
+	}
+	if (iface->state->offer == NULL)
+		start_discover(iface);
+	else if (iface->state->offer->cookie == 0 &&
+	    iface->state->options->options & DHCPCD_IPV4LL)
+		start_ipv4ll(iface);
+	else
+		start_reboot(iface);
+}
+
+static void
+init_state(struct interface *iface, int argc, char **argv)
+{
+	struct if_state *ifs;
+
+	if (iface->state)
+		ifs = iface->state;
+	else
+		ifs = iface->state = xzalloc(sizeof(*ifs));
+
+	ifs->state = DHS_INIT;
+	ifs->reason = "PREINIT";
+	ifs->nakoff = 1;
+	configure_interface(iface, argc, argv);
+	if (!(options & DHCPCD_TEST))
+		run_script(iface);
+	/* We need to drop the leasefile so that start_interface
+	 * doesn't load it. */	
+	if (ifs->options->options & DHCPCD_REQUEST)
+		unlink(iface->leasefile);
+
+	if (ifs->options->options & DHCPCD_LINK) {
+		switch (carrier_status(iface)) {
+		case 0:
+			iface->carrier = LINK_DOWN;
+			ifs->reason = "NOCARRIER";
+			break;
+		case 1:
+			iface->carrier = LINK_UP;
+			ifs->reason = "CARRIER";
+			break;
+		default:
+			iface->carrier = LINK_UNKNOWN;
+			return;
+		}
+		if (!(options & DHCPCD_TEST))
+			run_script(iface);
+	} else
+		iface->carrier = LINK_UNKNOWN;
+}
+
+void
+handle_interface(int action, const char *ifname)
+{
+	struct interface *ifs, *ifp, *ifn, *ifl = NULL;
+	const char * const argv[] = { ifname }; 
+	int i;
+
+	if (action == -1) {
+		ifp = find_interface(ifname);
+		if (ifp != NULL)
+			stop_interface(ifp);
+		return;
+	}
+
+	/* If running off an interface list, check it's in it. */
+	if (ifc) {
+		for (i = 0; i < ifc; i++)
+			if (strcmp(ifv[i], ifname) == 0)
+				break;
+		if (i >= ifc)
+			return;
+	}
+
+	ifs = discover_interfaces(-1, UNCONST(argv));
+	for (ifp = ifs; ifp; ifp = ifp->next) {
+		if (strcmp(ifp->name, ifname) != 0)
+			continue;
+		/* Check if we already have the interface */
+		for (ifn = ifaces; ifn; ifn = ifn->next) {
+			if (strcmp(ifn->name, ifp->name) == 0)
+				break;
+			ifl = ifn;
+		}
+		if (ifn) {
+			/* The flags and hwaddr could have changed */
+			ifn->flags = ifp->flags;
+			ifn->hwlen = ifp->hwlen;
+			if (ifp->hwlen != 0)
+				memcpy(ifn->hwaddr, ifp->hwaddr, ifn->hwlen);
+		} else {
+			if (ifl)
+				ifl->next = ifp;
+			else
+				ifaces = ifp;
+		}
+		init_state(ifp, 0, NULL);
+		start_interface(ifp);
+	}
+}
+
+#ifdef RTM_CHGADDR
+void
+handle_hwaddr(const char *ifname, unsigned char *hwaddr, size_t hwlen)
+{
+	struct interface *ifp;
+	struct if_options *ifo;
+
+	for (ifp = ifaces; ifp; ifp = ifp->next)
+		if (strcmp(ifp->name, ifname) == 0 && ifp->hwlen <= hwlen) {
+			ifo = ifp->state->options;
+			if (!(ifo->options &
+			    (DHCPCD_INFORM | DHCPCD_STATIC | DHCPCD_CLIENTID))
+	    		    && ifp->state->new != NULL &&
+			    ifp->state->new->cookie == htonl(MAGIC_COOKIE))
+			{
+				syslog(LOG_INFO,
+				    "%s: expiring for new hardware address",
+				    ifp->name);
+				drop_dhcp(ifp, "EXPIRE");
+			}
+			memcpy(ifp->hwaddr, hwaddr, hwlen);
+			ifp->hwlen = hwlen;
+			if (!(ifo->options &
+			    (DHCPCD_INFORM | DHCPCD_STATIC | DHCPCD_CLIENTID)))
+			{
+				syslog(LOG_DEBUG, "%s: using hwaddr %s",
+				    ifp->name,
+		    		    hwaddr_ntoa(ifp->hwaddr, ifp->hwlen));
+				ifp->state->interval = 0;
+				ifp->state->nakoff = 1;
+				start_interface(ifp);
+			}
+		}
+	free(hwaddr);
+}
+#endif
+
+void
+handle_ifa(int type, const char *ifname,
+    struct in_addr *addr, struct in_addr *net, struct in_addr *dst)
+{
+	struct interface *ifp;
+	struct if_options *ifo;
+	int i;
+
+	if (addr->s_addr == INADDR_ANY)
+		return;
+	for (ifp = ifaces; ifp; ifp = ifp->next)
+		if (strcmp(ifp->name, ifname) == 0)
+			break;
+	if (ifp == NULL)
+		return;
+
+	if (type == RTM_DELADDR) {
+		if (ifp->state->new &&
+		    ifp->state->new->yiaddr == addr->s_addr)
+			syslog(LOG_INFO, "%s: removing IP address %s/%d",
+			    ifp->name, inet_ntoa(ifp->state->lease.addr),
+			    inet_ntocidr(ifp->state->lease.net));
+		return;
+	}
+
+	if (type != RTM_NEWADDR)
+		return;
+
+	ifo = ifp->state->options;
+	if ((ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC)) == 0 ||
+	    ifo->req_addr.s_addr != INADDR_ANY)
+		return;
+
+	free(ifp->state->old);
+	ifp->state->old = ifp->state->new;
+	ifp->state->new = dhcp_message_new(addr, net);
+	ifp->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(ifp->state->new, i, *dst);
+	}
+	ifp->state->reason = "STATIC";
+	build_routes();
+	run_script(ifp);
+	if (ifo->options & DHCPCD_INFORM) {
+		ifp->state->state = DHS_INFORM;
+		ifp->state->xid = dhcp_xid(ifp);
+		ifp->state->lease.server.s_addr =
+		    dst ? dst->s_addr : INADDR_ANY;
+		ifp->addr = *addr;
+		ifp->net = *net;
+		send_inform(ifp);
+	}
+}
+
+/* ARGSUSED */
+static void
+handle_link(_unused void *arg)
+{
+	if (manage_link(linkfd) == -1)
+		syslog(LOG_ERR, "manage_link: %m");
+}
+
+static void
+if_reboot(struct interface *iface, int argc, char **argv)
+{
+	const struct if_options *ifo;
+	int opt;
+	
+	ifo = iface->state->options;
+	opt = ifo->options;
+	configure_interface(iface, argc, argv);
+	ifo = iface->state->options;
+	iface->state->interval = 0;
+	if ((ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC) &&
+		iface->addr.s_addr != ifo->req_addr.s_addr) ||
+	    (opt & (DHCPCD_INFORM | DHCPCD_STATIC) &&
+		!(ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC))))
+	{
+		drop_dhcp(iface, "EXPIRE");
+	} else {
+		free(iface->state->offer);
+		iface->state->offer = NULL;
+	}
+	start_interface(iface);
+}
+
+static void
+reconf_reboot(int action, int argc, char **argv, int oi)
+{
+	struct interface *ifl, *ifn, *ifp, *ifs, *ift;
+	
+	ifs = discover_interfaces(argc - oi, argv + oi);
+	if (ifs == NULL)
+		return;
+
+	for (ifp = ifs; ifp && (ift = ifp->next, 1); ifp = ift) {
+		ifl = NULL;
+		for (ifn = ifaces; ifn; ifn = ifn->next) {
+			if (strcmp(ifn->name, ifp->name) == 0)
+				break;
+			ifl = ifn;
+		}
+		if (ifn) {
+			if (action)
+				if_reboot(ifn, argc, argv);
+			else if (ifn->state->new)
+				configure(ifn);
+			free_interface(ifp);
+		} else {
+			ifp->next = NULL;
+			init_state(ifp, argc, argv);
+			start_interface(ifp);
+			if (ifl)
+				ifl->next = ifp;
+			else
+				ifaces = ifp;
+		}
+	}
+
+	sort_interfaces();
+}
+
+/* ARGSUSED */
+static void
+handle_signal(_unused void *arg)
+{
+	struct interface *ifp, *ifl;
+	struct if_options *ifo;
+	int sig = signal_read();
+	int do_release, do_rebind, i;
+
+	do_rebind = do_release = 0;
+	switch (sig) {
+	case SIGINT:
+		syslog(LOG_INFO, "received SIGINT, stopping");
+		break;
+	case SIGTERM:
+		syslog(LOG_INFO, "received SIGTERM, stopping");
+		break;
+	case SIGALRM:
+#ifdef ANDROID
+		syslog(LOG_INFO, "received SIGALRM, renewing");
+		for (ifp = ifaces; ifp; ifp = ifp->next) {
+			start_renew(ifp);
+		}
+#else
+		syslog(LOG_INFO, "received SIGALRM, rebinding");
+		for (i = 0; i < ifac; i++)
+			free(ifav[i]);
+		free(ifav);
+		ifav = NULL;
+		ifac = 0;
+		for (i = 0; i < ifdc; i++)
+			free(ifdv[i]);
+		free(ifdv);
+		ifdc = 0;
+		ifdv = NULL;
+		ifo = read_config(cffile, NULL, NULL, NULL);
+		add_options(ifo, margc, margv);
+		/* We need to preserve these two options. */
+		if (options & DHCPCD_MASTER)
+			ifo->options |= DHCPCD_MASTER;
+		if (options & DHCPCD_DAEMONISED)
+			ifo->options |= DHCPCD_DAEMONISED;
+		options = ifo->options;
+		free_options(ifo);
+		reconf_reboot(1, ifc, ifv, 0);
+#endif
+		return;
+	case SIGHUP:
+		syslog(LOG_INFO, "received SIGHUP, releasing");
+		do_release = 1;
+		break;
+	case SIGUSR1:
+		syslog(LOG_INFO, "received SIGUSR, reconfiguring");
+		for (ifp = ifaces; ifp; ifp = ifp->next)
+			if (ifp->state->new)
+				configure(ifp);
+		return;
+	case SIGPIPE:
+		syslog(LOG_WARNING, "received SIGPIPE");
+		return;
+	default:
+		syslog(LOG_ERR,
+		    "received signal %d, but don't know what to do with it",
+		    sig);
+		return;
+	}
+
+	if (options & DHCPCD_TEST)
+		exit(EXIT_FAILURE);
+
+	/* As drop_dhcp could re-arrange the order, we do it like this. */
+	for (;;) {
+		/* Be sane and drop the last config first */
+		ifl = NULL;
+		for (ifp = ifaces; ifp; ifp = ifp->next) {
+			if (ifp->next == NULL)
+				break;
+			ifl = ifp;
+		}
+		if (ifp == NULL)
+			break;
+		if (ifp->carrier != LINK_DOWN &&
+		    (do_release ||
+			ifp->state->options->options & DHCPCD_RELEASE))
+			send_release(ifp);
+		stop_interface(ifp);
+	}
+	exit(EXIT_FAILURE);
+}
+
+int
+handle_args(struct fd_list *fd, int argc, char **argv)
+{
+	struct interface *ifp;
+	int do_exit = 0, do_release = 0, do_reboot = 0, do_reconf = 0;
+	int opt, oi = 0;
+	ssize_t len;
+	size_t l;
+	struct iovec iov[2];
+	char *tmp, *p;
+
+	if (fd != NULL) {
+		/* Special commands for our control socket */
+		if (strcmp(*argv, "--version") == 0) {
+			len = strlen(VERSION) + 1;
+			iov[0].iov_base = &len;
+			iov[0].iov_len = sizeof(ssize_t);
+			iov[1].iov_base = UNCONST(VERSION);
+			iov[1].iov_len = len;
+			if (writev(fd->fd, iov, 2) == -1) {
+				syslog(LOG_ERR, "writev: %m");
+				return -1;
+			}
+			return 0;
+		} else if (strcmp(*argv, "--getconfigfile") == 0) {
+			len = strlen(cffile ? cffile : CONFIG) + 1;
+			iov[0].iov_base = &len;
+			iov[0].iov_len = sizeof(ssize_t);
+			iov[1].iov_base = cffile ? cffile : UNCONST(CONFIG);
+			iov[1].iov_len = len;
+			if (writev(fd->fd, iov, 2) == -1) {
+				syslog(LOG_ERR, "writev: %m");
+				return -1;
+			}
+			return 0;
+		} else if (strcmp(*argv, "--getinterfaces") == 0) {
+			len = 0;
+			if (argc == 1) {
+				for (ifp = ifaces; ifp; ifp = ifp->next) {
+					len++;
+					if (ifp->ras)
+						len++;
+				}
+				len = write(fd->fd, &len, sizeof(len));
+				if (len != sizeof(len))
+					return -1;
+				for (ifp = ifaces; ifp; ifp = ifp->next)
+					send_interface(fd->fd, ifp);
+				return 0;
+			}
+			opt = 0;
+			while (argv[++opt] != NULL) {
+				for (ifp = ifaces; ifp; ifp = ifp->next)
+					if (strcmp(argv[opt], ifp->name) == 0) {
+						len++;
+						if (ifp->ras)
+							len++;
+					}
+			}
+			len = write(fd->fd, &len, sizeof(len));
+			if (len != sizeof(len))
+				return -1;
+			opt = 0;
+			while (argv[++opt] != NULL) {
+				for (ifp = ifaces; ifp; ifp = ifp->next)
+					if (strcmp(argv[opt], ifp->name) == 0)
+						send_interface(fd->fd, ifp);
+			}
+			return 0;
+		} else if (strcmp(*argv, "--listen") == 0) {
+			fd->listener = 1;
+			return 0;
+		}
+	}
+
+	/* Log the command */
+	len = 0;
+	for (opt = 0; opt < argc; opt++)
+		len += strlen(argv[opt]) + 1;
+	tmp = p = xmalloc(len + 1);
+	for (opt = 0; opt < argc; opt++) {
+		l = strlen(argv[opt]);
+		strlcpy(p, argv[opt], l + 1);
+		p += l;
+		*p++ = ' ';
+	}
+	*--p = '\0';
+	syslog(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':
+			do_reconf = 1;
+			break;
+		case 'k':
+			do_release = 1;
+			break;
+		case 'n':
+			do_reboot = 1;
+			break;
+		case 'x':
+			do_exit = 1;
+			break;
+		}
+	}
+
+	/* We need at least one interface */
+	if (optind == argc) {
+		syslog(LOG_ERR, "handle_args: no interface");
+		return -1;
+	}
+
+	if (do_release || do_exit) {
+		for (oi = optind; oi < argc; oi++) {
+			for (ifp = ifaces; ifp; ifp = ifp->next)
+				if (strcmp(ifp->name, argv[oi]) == 0)
+					break;
+			if (!ifp)
+				continue;
+			if (do_release)
+				ifp->state->options->options |= DHCPCD_RELEASE;
+			if (ifp->state->options->options & DHCPCD_RELEASE &&
+			    ifp->carrier != LINK_DOWN)
+				send_release(ifp);
+			stop_interface(ifp);
+		}
+		return 0;
+	}
+
+	reconf_reboot(do_reboot, argc, argv, optind);
+	return 0;
+}
+
+void
+open_sockets(struct interface *iface)
+{
+	if (iface->raw_fd == -1) {
+		if (open_socket(iface, ETHERTYPE_IP) == -1)
+			syslog(LOG_ERR, "%s: open_socket: %m", iface->name);
+		else
+			add_event(iface->raw_fd, handle_dhcp_packet, iface);
+	}
+	if (iface->udp_fd == -1 &&
+	    iface->addr.s_addr != 0 &&
+	    iface->state->new != NULL &&
+	    (iface->state->new->cookie == htonl(MAGIC_COOKIE) ||
+	    iface->state->options->options & DHCPCD_INFORM))
+	{
+		if (open_udp_socket(iface) == -1 && errno != EADDRINUSE)
+			syslog(LOG_ERR, "%s: open_udp_socket: %m", iface->name);
+	}
+}
+
+void
+close_sockets(struct interface *iface)
+{
+	if (iface->arp_fd != -1) {
+		delete_event(iface->arp_fd);
+		close(iface->arp_fd);
+		iface->arp_fd = -1;
+	}
+	if (iface->raw_fd != -1) {
+		delete_event(iface->raw_fd);
+		close(iface->raw_fd);
+		iface->raw_fd = -1;
+	}
+	if (iface->udp_fd != -1) {
+		/* we don't listen to events on the udp */
+		close(iface->udp_fd);
+		iface->udp_fd = -1;
+	}
+}
+
+#ifdef ANDROID
+void switchUser(void)
+{
+	gid_t groups[] = { 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 interface *iface;
+	int opt, oi = 0, signal_fd, sig = 0, i, control_fd;
+	size_t len;
+	pid_t pid;
+	struct timespec ts;
+
+#ifdef ANDROID
+	/* Reuse system properties for a p2p interface */
+	char p2p_interface[PROPERTY_KEY_MAX];
+	switchUser();
+#endif
+	closefrom(3);
+	openlog(PACKAGE, LOG_PERROR | LOG_PID, LOG_DAEMON);
+	setlogmask(LOG_UPTO(LOG_INFO));
+
+	/* Test for --help and --version */
+	if (argc > 1) {
+		if (strcmp(argv[1], "--help") == 0) {
+			usage();
+			exit(EXIT_SUCCESS);
+		} else if (strcmp(argv[1], "--version") == 0) {
+			printf(""PACKAGE" "VERSION"\n%s\n", copyright);
+			exit(EXIT_SUCCESS);
+		}
+	}
+
+	i = 0;
+	while ((opt = getopt_long(argc, argv, IF_OPTS, cf_options, &oi)) != -1)
+	{
+		switch (opt) {
+		case 'f':
+			cffile = optarg;
+			break;
+		case 'g':
+			sig = SIGUSR1;
+			break;
+		case 'k':
+			sig = SIGHUP;
+			break;
+		case 'n':
+			sig = SIGALRM;
+			break;
+		case 'x':
+			sig = SIGTERM;
+			break;
+		case 'T':
+			i = 1;
+			break;
+		case 'U':
+			i = 2;
+			break;
+		case 'a':
+			avoid_routes = 1;
+			break;
+		case 'V':
+			print_options();
+			exit(EXIT_SUCCESS);
+		case '?':
+			usage();
+			exit(EXIT_FAILURE);
+		}
+	}
+
+	margv = argv;
+	margc = argc;
+	if_options = read_config(cffile, NULL, NULL, NULL);
+	opt = add_options(if_options, argc, argv);
+	if (opt != 1) {
+		if (opt == 0)
+			usage();
+		exit(EXIT_FAILURE);
+	}
+	options = if_options->options;
+	if (i != 0) {
+		if (i == 1)
+			options |= DHCPCD_TEST;
+		else
+			options |= DHCPCD_DUMPLEASE;
+		options |= DHCPCD_PERSISTENT;
+		options &= ~DHCPCD_DAEMONISE;
+	}
+	
+#ifdef THERE_IS_NO_FORK
+	options &= ~DHCPCD_DAEMONISE;
+#endif
+
+	if (options & DHCPCD_DEBUG)
+		setlogmask(LOG_UPTO(LOG_DEBUG));
+	if (options & DHCPCD_QUIET)
+		close(STDERR_FILENO);
+
+	if (!(options & (DHCPCD_TEST | DHCPCD_DUMPLEASE))) {
+		/* If we have any other args, we should run as a single dhcpcd
+		 *  instance for that interface. */
+		len = strlen(PIDFILE) + IF_NAMESIZE + 2;
+		pidfile = xmalloc(len);
+		if (optind == argc - 1)
+			snprintf(pidfile, len, PIDFILE, "-", argv[optind]);
+		else {
+			snprintf(pidfile, len, PIDFILE, "", "");
+			options |= DHCPCD_MASTER;
+		}
+	}
+
+	if (chdir("/") == -1)
+		syslog(LOG_ERR, "chdir `/': %m");
+	atexit(cleanup);
+
+	if (options & DHCPCD_DUMPLEASE) {
+		if (optind != argc - 1) {
+			syslog(LOG_ERR, "dumplease requires an interface");
+			exit(EXIT_FAILURE);
+		}
+		ifaces = iface = xzalloc(sizeof(*iface));
+		strlcpy(iface->name, argv[optind], sizeof(iface->name));
+		snprintf(iface->leasefile, sizeof(iface->leasefile),
+		    LEASEFILE, iface->name);
+		iface->state = xzalloc(sizeof(*iface->state));
+		iface->state->options = xzalloc(sizeof(*iface->state->options));
+		strlcpy(iface->state->options->script, if_options->script,
+		    sizeof(iface->state->options->script));
+		iface->state->new = read_lease(iface);
+		if (iface->state->new == NULL && errno == ENOENT) {
+			strlcpy(iface->leasefile, argv[optind],
+			    sizeof(iface->leasefile));
+			iface->state->new = read_lease(iface);
+		}
+		if (iface->state->new == NULL) {
+			if (errno == ENOENT)
+				syslog(LOG_ERR, "%s: no lease to dump",
+				    iface->name);
+			exit(EXIT_FAILURE);
+		}
+		iface->state->reason = "DUMP";
+		run_script(iface);
+		exit(EXIT_SUCCESS);
+	}
+
+	if (!(options & (DHCPCD_MASTER | DHCPCD_TEST))) {
+		control_fd = open_control();
+		if (control_fd != -1) {
+			syslog(LOG_INFO,
+			    "sending commands to master dhcpcd process");
+			i = send_control(argc, argv);
+			if (i > 0) {
+				syslog(LOG_DEBUG, "send OK");
+				exit(EXIT_SUCCESS);
+			} else {
+				syslog(LOG_ERR, "failed to send commands");
+				exit(EXIT_FAILURE);
+			}
+		} else {
+			if (errno != ENOENT)
+				syslog(LOG_ERR, "open_control: %m");
+		}
+	}
+
+#ifndef ANDROID
+	/* android runs us as user "dhcp" */
+	if (geteuid())
+		syslog(LOG_WARNING,
+		    PACKAGE " will not work correctly unless run as root");
+#endif
+	if (sig != 0) {
+#ifdef ANDROID
+		char pidpropname[PROPERTY_KEY_MAX];
+		char pidpropval[PROPERTY_VALUE_MAX];
+
+		if (optind != argc - 1) {
+			syslog(LOG_ERR, "Android requires an interface");
+			exit(EXIT_FAILURE);
+		}
+
+		if (strncmp(argv[optind], "p2p", 3) == 0) {
+			strncpy(p2p_interface, "p2p", sizeof(p2p_interface));
+		} else {
+			strncpy(p2p_interface, argv[optind], sizeof(p2p_interface));
+		}
+
+		if (snprintf(pidpropname,
+			     sizeof(pidpropname),
+			     "dhcp.%s.pid", p2p_interface) >= PROPERTY_KEY_MAX)
+			exit(EXIT_FAILURE);
+		property_get(pidpropname, pidpropval, NULL);
+		if (strlen(pidpropval) == 0)
+			exit(EXIT_FAILURE);
+		pid = atoi(pidpropval);
+#else
+		pid = read_pid();
+#endif
+		if (pid != 0)
+			syslog(LOG_INFO, "sending signal %d to pid %d",
+			    sig, pid);
+		if (pid == 0 || kill(pid, sig) != 0) {
+			if (sig != SIGALRM)
+				syslog(LOG_ERR, ""PACKAGE" not running");
+			if (pid != 0 && errno != ESRCH) {
+				syslog(LOG_ERR, "kill: %m");
+				exit(EXIT_FAILURE);
+			}
+			unlink(pidfile);
+			if (sig != SIGALRM)
+				exit(EXIT_FAILURE);
+		} else {
+			if (sig == SIGALRM || sig == SIGUSR1)
+				exit(EXIT_SUCCESS);
+			/* Spin until it exits */
+			syslog(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() == 0)
+					exit(EXIT_SUCCESS);
+			}
+			syslog(LOG_ERR, "pid %d failed to exit", pid);
+			exit(EXIT_FAILURE);
+		}
+	}
+
+	if (!(options & DHCPCD_TEST)) {
+#ifdef ANDROID
+		char pidpropname[PROPERTY_KEY_MAX];
+		char pidpropval[PROPERTY_VALUE_MAX];
+#endif
+#ifndef ANDROID
+		if ((pid = read_pid()) > 0 &&
+		    kill(pid, 0) == 0)
+		{
+			syslog(LOG_ERR, ""PACKAGE
+			    " already running on pid %d (%s)",
+			    pid, pidfile);
+			exit(EXIT_FAILURE);
+		}
+
+		/* Ensure we have the needed directories */
+		if (mkdir(RUNDIR, 0755) == -1 && errno != EEXIST)
+			syslog(LOG_ERR, "mkdir `%s': %m", RUNDIR);
+		if (mkdir(DBDIR, 0755) == -1 && errno != EEXIST)
+			syslog(LOG_ERR, "mkdir `%s': %m", DBDIR);
+#endif
+
+		pidfd = open(pidfile, O_WRONLY | O_CREAT | O_NONBLOCK, 0664);
+		if (pidfd == -1)
+			syslog(LOG_ERR, "open `%s': %m", pidfile);
+		else {
+			/* Lock the file so that only one instance of dhcpcd
+			 * runs on an interface */
+			if (flock(pidfd, LOCK_EX | LOCK_NB) == -1) {
+				syslog(LOG_ERR, "flock `%s': %m", pidfile);
+				exit(EXIT_FAILURE);
+			}
+			if (set_cloexec(pidfd) == -1)
+				exit(EXIT_FAILURE);
+#ifdef ANDROID
+			if (optind != argc - 1) {
+				syslog(LOG_ERR, "Android requires an interface");
+				exit(EXIT_FAILURE);
+			}
+
+			if (strncmp(argv[optind], "p2p", 3) == 0) {
+				strncpy(p2p_interface, "p2p", sizeof(p2p_interface));
+			} else {
+				strncpy(p2p_interface, argv[optind], sizeof(p2p_interface));
+			}
+
+			if (snprintf(pidpropname,
+				     sizeof(pidpropname),
+				     "dhcp.%s.pid", p2p_interface) >= PROPERTY_KEY_MAX)
+				exit(EXIT_FAILURE);
+			if (snprintf(pidpropval, sizeof(pidpropval), "%d", getpid()) >= PROPERTY_VALUE_MAX)
+				exit(EXIT_FAILURE);
+			property_set(pidpropname, pidpropval);
+#else
+			writepid(pidfd, getpid());
+#endif
+		}
+	}
+
+	syslog(LOG_INFO, "version " VERSION " starting");
+
+	if ((signal_fd = signal_init()) == -1)
+		exit(EXIT_FAILURE);
+	if (signal_setup() == -1)
+		exit(EXIT_FAILURE);
+	add_event(signal_fd, handle_signal, NULL);
+
+	if (options & DHCPCD_MASTER) {
+		if (start_control() == -1)
+			syslog(LOG_ERR, "start_control: %m");
+	}
+
+	if (init_sockets() == -1) {
+		syslog(LOG_ERR, "init_socket: %m");
+		exit(EXIT_FAILURE);
+	}
+	if (if_options->options & DHCPCD_LINK) {
+		linkfd = open_link_socket();
+		if (linkfd == -1)
+			syslog(LOG_ERR, "open_link_socket: %m");
+		else
+			add_event(linkfd, handle_link, NULL);
+	}
+
+#if 0
+	if (options & DHCPCD_IPV6RS && disable_rtadv() == -1) {
+		syslog(LOG_ERR, "ipv6rs: %m");
+		options &= ~DHCPCD_IPV6RS;
+	}
+#endif
+
+	if (options & DHCPCD_IPV6RS && !check_ipv6(NULL))
+		options &= ~DHCPCD_IPV6RS;
+	if (options & DHCPCD_IPV6RS) {
+		ipv6rsfd = ipv6rs_open();
+		if (ipv6rsfd == -1) {
+			syslog(LOG_ERR, "ipv6rs: %m");
+			options &= ~DHCPCD_IPV6RS;
+		} else {
+			add_event(ipv6rsfd, ipv6rs_handledata, NULL);
+//			atexit(restore_rtadv);
+		}
+	}
+
+	ifc = argc - optind;
+	ifv = argv + optind;
+
+	/* When running dhcpcd against a single interface, we need to retain
+	 * the old behaviour of waiting for an IP address */
+	if (ifc == 1)
+		options |= DHCPCD_WAITIP;
+
+	ifaces = discover_interfaces(ifc, ifv);
+	for (i = 0; i < ifc; i++) {
+		for (iface = ifaces; iface; iface = iface->next)
+			if (strcmp(iface->name, ifv[i]) == 0)
+				break;
+		if (!iface)
+			syslog(LOG_ERR, "%s: interface not found or invalid",
+			    ifv[i]);
+	}
+	if (!ifaces) {
+		if (ifc == 0)
+			syslog(LOG_ERR, "no valid interfaces found");
+		else
+			exit(EXIT_FAILURE);
+		if (!(options & DHCPCD_LINK)) {
+			syslog(LOG_ERR,
+			    "aborting as link detection is disabled");
+			exit(EXIT_FAILURE);
+		}
+	}
+
+	if (options & DHCPCD_BACKGROUND)
+		daemonise();
+
+	opt = 0;
+	for (iface = ifaces; iface; iface = iface->next) {
+		init_state(iface, argc, argv);
+		if (iface->carrier != LINK_DOWN)
+			opt = 1;
+	}
+
+	if (!(options & DHCPCD_BACKGROUND)) {
+		/* If we don't have a carrier, we may have to wait for a second
+		 * before one becomes available if we brought an interface up */
+		if (opt == 0 &&
+		    options & DHCPCD_LINK &&
+		    options & DHCPCD_WAITUP &&
+		    !(options & DHCPCD_WAITIP))
+		{
+			ts.tv_sec = 1;
+			ts.tv_nsec = 0;
+			nanosleep(&ts, NULL);
+			for (iface = ifaces; iface; iface = iface->next) {
+				handle_carrier(0, 0, iface->name);
+				if (iface->carrier != LINK_DOWN) {
+					opt = 1;
+					break;
+				}
+			}
+		}
+		if (options & DHCPCD_MASTER)
+			i = if_options->timeout;
+		else
+			i = ifaces->state->options->timeout;
+		if (opt == 0 &&
+		    options & DHCPCD_LINK &&
+		    !(options & DHCPCD_WAITIP))
+		{
+			syslog(LOG_WARNING, "no interfaces have a carrier");
+			daemonise();
+		} else if (i > 0) {
+			if (options & DHCPCD_IPV4LL)
+				options |= DHCPCD_TIMEOUT_IPV4LL;
+			add_timeout_sec(i, handle_exit_timeout, NULL);
+		}
+	}
+	free_options(if_options);
+	if_options = NULL;
+
+	sort_interfaces();
+	for (iface = ifaces; iface; iface = iface->next)
+		add_timeout_sec(0, start_interface, iface);
+
+	start_eloop();
+	exit(EXIT_SUCCESS);
+}
diff --git a/dhcpcd/dhcpcd.conf b/dhcpcd/dhcpcd.conf
new file mode 100644
index 0000000..eb625a7
--- /dev/null
+++ b/dhcpcd/dhcpcd.conf
@@ -0,0 +1,23 @@
+# A sample configuration for dhcpcd.
+# See dhcpcd.conf(5) for details.
+
+# Inform the DHCP server of our hostname for DDNS.
+hostname
+# To share the DHCP lease across OSX and Windows a ClientID is needed.
+# Enabling this may get a different lease than the kernel DHCP client.
+# Some upstream DHCP servers may also require a ClientID, such as FRITZ!Box.
+#clientid
+
+# A list of options to request from the DHCP server.
+option domain_name_servers, domain_name, domain_search, host_name
+option classless_static_routes
+# Most distributions have NTP support.
+option ntp_servers
+# Respect the network MTU.
+option interface_mtu
+# A ServerID is required by RFC2131.
+require dhcp_server_identifier
+
+# 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
diff --git a/dhcpcd/dhcpcd.conf.5 b/dhcpcd/dhcpcd.conf.5
new file mode 100644
index 0000000..89cb793
--- /dev/null
+++ b/dhcpcd/dhcpcd.conf.5
@@ -0,0 +1,326 @@
+.\" Copyright (c) 2006-2012 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 May 21, 2012
+.Dt DHCPCD.CONF 5 SMM
+.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 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 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 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 .
+.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 clientid.
+This requires persistent storage and not all DHCP servers work with it so it's
+not enabled by default.
+The duid generated will be held in
+.Pa /etc/dhcpcd.duid
+and should not be copied to other hosts.
+.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 fqdn Op none | ptr | both
+none disables FQDN encoding, ptr just asks the DHCP server to update the PTR
+record of the host in DNS whereas both also updates the A record.
+.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_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.
+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 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 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 noarp
+Don't send any ARP requests.
+This also disables IPv4LL.
+.It Ic nogateway
+Don't install any default routes.
+.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 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 noipv6rs
+Disable solicition 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 options separated by commas, spaces or more option lines.
+.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.
+The default is 5 seconds.
+A setting if 0 seconds causes
+.Nm dhcpcd
+to skip the reboot phase and go straight into discover.
+.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 .
+.It Ic script Ar script
+Use
+.Ar script
+instead of the default
+.Pa /libexec/dhcpcd-run-hooks .
+.It Ic ssid Ar ssid
+Subsequent options are only parsed for this wireless
+.Ar ssid .
+.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
+The default timeout for waiting for a DHCP response is 30 seconds which may
+be too long or too short and can be changed here.
+.It Ic userclass Ar string
+Tag the DHCP 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
+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 waitip
+Wait for an address to be assigned before forking to the background.
+.It Ic xidhwaddr
+Use the last four bytes of the hardware address as the DHCP xid instead
+of a randomly generated number.
+.El
+.Sh SEE ALSO
+.Xr dhcpcd-run-hooks 8 ,
+.Xr dhcpcd 8 ,
+.Xr if_nametoindex 3 ,
+.Xr fnmatch 3
+.Sh AUTHORS
+.An Roy Marples Aq roy@marples.name
+.Sh BUGS
+Please report them to
+.Lk http://roy.marples.name/projects/dhcpcd
diff --git a/dhcpcd/dhcpcd.conf.5.in b/dhcpcd/dhcpcd.conf.5.in
new file mode 100644
index 0000000..9f0ef27
--- /dev/null
+++ b/dhcpcd/dhcpcd.conf.5.in
@@ -0,0 +1,309 @@
+.\" Copyright (c) 2006-2012 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 19, 2012
+.Dt DHCPCD.CONF 5 SMM
+.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 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 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 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 .
+.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 clientid.
+This requires persistent storage and not all DHCP servers work with it so it's
+not enabled by default.
+The duid generated will be held in
+.Pa @SYSCONFDIR@/dhcpcd.duid
+and should not be copied to other hosts.
+.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 fqdn Op none | ptr | both
+none disables FQDN encoding, ptr just asks the DHCP server to update the PTR
+record of the host in DNS whereas both also updates the A record.
+.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_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.
+Set this option so to make
+.Nm dhcpcd
+always fork on an RA.
+.It Ic leasetime Ar seconds
+Request a leasetime of
+.Ar seconds .
+.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 noarp
+Don't send any ARP requests.
+This also disables IPv4LL.
+.It Ic nogateway
+Don't install any default routes.
+.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 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 noipv6rs
+Disable solicition 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 options separated by commas, spaces or more option lines.
+.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.
+The default is 5 seconds.
+A setting if 0 seconds causes
+.Nm dhcpcd
+to skip the reboot phase and go straight into discover.
+.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 .
+.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 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
+The default timeout for waiting for a DHCP response is 30 seconds which may
+be too long or too short and can be changed here.
+.It Ic userclass Ar string
+Tag the DHCP 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
+Change the default vendorclassid sent from dhcpcd-version.
+If not set then none is sent.
+.It Ic waitip
+Wait for an address to be assigned before forking to the background.
+.It Ic xidhwaddr
+Use the last four bytes of the hardware address as the DHCP xid instead
+of a randomly generated number.
+.El
+.Sh SEE ALSO
+.Xr dhcpcd-run-hooks 8 ,
+.Xr dhcpcd 8 ,
+.Xr if_nametoindex 3 ,
+.Xr fnmatch 3
+.Sh AUTHORS
+.An Roy Marples Aq roy@marples.name
+.Sh BUGS
+Please report them to
+.Lk http://roy.marples.name/projects/dhcpcd
diff --git a/dhcpcd/dhcpcd.h b/dhcpcd/dhcpcd.h
new file mode 100644
index 0000000..c2fdfdf
--- /dev/null
+++ b/dhcpcd/dhcpcd.h
@@ -0,0 +1,176 @@
+/* 
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2011 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 <netinet/in.h>
+
+#include <limits.h>
+
+#include "control.h"
+#include "dhcp.h"
+#include "if-options.h"
+
+#define HWADDR_LEN 20
+#define IF_SSIDSIZE 33
+#define PROFILE_LEN 64
+
+enum DHS {
+	DHS_INIT,
+	DHS_DISCOVER,
+	DHS_REQUEST,
+	DHS_BOUND,
+	DHS_RENEW,
+	DHS_REBIND,
+	DHS_REBOOT,
+	DHS_INFORM,
+	DHS_RENEW_REQUESTED,
+	DHS_INIT_IPV4LL,
+	DHS_PROBE
+};
+
+#define LINK_UP 	1
+#define LINK_UNKNOWN	0
+#define LINK_DOWN 	-1
+
+struct if_state {
+	enum DHS state;
+	char profile[PROFILE_LEN];
+	struct if_options *options;
+	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 probes;
+	int claims;
+	int conflicts;
+	time_t defend;
+	struct in_addr fail;
+	size_t arping_index;
+};
+
+struct ra_opt {
+	uint8_t type;
+	struct timeval expire;
+	char *option;
+	struct ra_opt *next;
+};
+
+struct ra {
+	struct in6_addr from;
+	char sfrom[INET6_ADDRSTRLEN];
+	unsigned char *data;
+	ssize_t data_len;
+	struct timeval received;
+	uint32_t lifetime;
+	struct in6_addr prefix;
+	int prefix_len;
+	uint32_t prefix_vltime;
+	uint32_t prefix_pltime;
+	char sprefix[INET6_ADDRSTRLEN];
+	struct ra_opt *options;
+	int expired;
+	struct ra *next;
+};
+
+struct interface {
+	char name[IF_NAMESIZE];
+	struct if_state *state;
+
+	int flags;
+	sa_family_t family;
+	unsigned char hwaddr[HWADDR_LEN];
+	size_t hwlen;
+	int metric;
+	int carrier;
+	int wireless;
+	char ssid[IF_SSIDSIZE];
+
+	int raw_fd;
+	int udp_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;
+
+	char leasefile[PATH_MAX];
+	time_t start_uptime;
+
+	unsigned char *clientid;
+
+	unsigned char *rs;
+	size_t rslen;
+	int rsprobes;
+	struct ra *ras;
+
+	struct interface *next;
+};
+
+extern int pidfd;
+extern unsigned long long options;
+extern int ifac;
+extern char **ifav;
+extern int ifdc;
+extern char **ifdv;
+extern struct interface *ifaces;
+extern int avoid_routes;
+
+struct interface *find_interface(const char *);
+int handle_args(struct fd_list *, int, char **);
+void handle_carrier(int, int, const char *);
+void handle_interface(int, const char *);
+void handle_hwaddr(const char *, unsigned char *, size_t);
+void handle_ifa(int, const char *,
+    struct in_addr *, struct in_addr *, struct in_addr *);
+void handle_exit_timeout(void *);
+void start_interface(void *);
+void start_discover(void *);
+void start_request(void *);
+void start_renew(void *);
+void start_rebind(void *);
+void start_reboot(struct interface *);
+void start_expire(void *);
+void send_decline(struct interface *);
+void open_sockets(struct interface *);
+void close_sockets(struct interface *);
+void drop_dhcp(struct interface *, const char *);
+void drop_interface(struct interface *, const char *);
+int select_profile(struct interface *, const char *);
+
+#endif
diff --git a/dhcpcd/dhcpcd_test.cpp b/dhcpcd/dhcpcd_test.cpp
new file mode 100644
index 0000000..a254d4d
--- /dev/null
+++ b/dhcpcd/dhcpcd_test.cpp
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2014 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_test.cpp - unit tests for dhcpcd
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string>
+
+#include <gtest/gtest.h>
+
+// For convenience.
+#define ARRAYSIZE(x) sizeof((x)) / sizeof((x)[0])
+
+// Regrettably, copy these defines and the dhcp_message structure in from
+// dhcp.h.  This header file is not easily included, since subsequent
+// includes use C++ reserved keywords (like "new") as structure member names.
+extern "C" {
+
+#define DHO_PAD                 0
+#define DHO_DNSDOMAIN           15
+
+/* Max MTU - defines dhcp option length */
+#define MTU_MAX             1500
+
+/* 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
+
+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;
+
+char * get_option_string(const struct dhcp_message *dhcp, uint8_t option);
+
+}
+
+
+static const char kOptionString[] = "hostname";
+
+class DhcpcdGetOptionTest : public ::testing::Test {
+ protected:
+  virtual void SetUp() {
+    memset(dhcpmsgs, 0, ARRAYSIZE(dhcpmsgs) * sizeof(struct dhcp_message));
+    // Technically redundant.
+    memset(&(dhcpmsgs[0].options), DHO_PAD, sizeof(dhcpmsgs[0].options));
+
+    type_index = 0;
+    length_index = 0;
+    value_index = 0;
+  }
+
+  void PopulateTLV() {
+    // May very well write off the end of the first struct dhcp_message,
+    // by design.
+    length_index = type_index + 1;
+    value_index = length_index + 1;
+    dhcpmsgs[0].options[type_index] = DHO_DNSDOMAIN;
+    dhcpmsgs[0].options[length_index] = strlen(kOptionString);
+    memcpy(&(dhcpmsgs[0].options[value_index]),
+           kOptionString, strlen(kOptionString));
+  }
+
+  struct dhcp_message dhcpmsgs[2];
+  volatile size_t type_index;
+  volatile size_t length_index;
+  volatile size_t value_index;
+};
+
+TEST_F(DhcpcdGetOptionTest, OptionNotPresent) {
+  // An entire option block of padding (all zeros).
+  EXPECT_EQ(NULL, ::get_option_string(&(dhcpmsgs[0]), DHO_DNSDOMAIN));
+}
+
+TEST_F(DhcpcdGetOptionTest, TypeIsOffTheEnd) {
+  type_index = sizeof(dhcpmsgs[0].options);
+  PopulateTLV();
+  EXPECT_EQ(NULL, ::get_option_string(&(dhcpmsgs[0]), DHO_DNSDOMAIN));
+}
+
+TEST_F(DhcpcdGetOptionTest, LengthIsOffTheEnd) {
+  type_index = sizeof(dhcpmsgs[0].options) - 1;
+  PopulateTLV();
+  EXPECT_EQ(NULL, ::get_option_string(&(dhcpmsgs[0]), DHO_DNSDOMAIN));
+}
+
+TEST_F(DhcpcdGetOptionTest, ValueIsOffTheEnd) {
+  type_index = sizeof(dhcpmsgs[0].options) - 2;
+  PopulateTLV();
+  EXPECT_EQ(NULL, ::get_option_string(&(dhcpmsgs[0]), DHO_DNSDOMAIN));
+}
+
+TEST_F(DhcpcdGetOptionTest, InsufficientSpaceForValue) {
+  type_index = sizeof(dhcpmsgs[0].options) - 6;
+  PopulateTLV();
+  char* value = ::get_option_string(&(dhcpmsgs[0]), DHO_DNSDOMAIN);
+  EXPECT_TRUE(NULL != value);
+  EXPECT_EQ("host", ::std::string(value));
+  free(value);
+}
+
+TEST_F(DhcpcdGetOptionTest, InsufficientSpaceForContinuedValue) {
+  type_index = sizeof(dhcpmsgs[0].options) - 16;
+  PopulateTLV();
+  type_index = sizeof(dhcpmsgs[0].options) - 6;
+  PopulateTLV();
+  char* value = ::get_option_string(&(dhcpmsgs[0]), DHO_DNSDOMAIN);
+  EXPECT_TRUE(NULL != value);
+  EXPECT_EQ("hostnamehost", ::std::string(value));
+  free(value);
+}
diff --git a/dhcpcd/duid.c b/dhcpcd/duid.c
new file mode 100644
index 0000000..d67e45e
--- /dev/null
+++ b/dhcpcd/duid.c
@@ -0,0 +1,100 @@
+/* 
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2008 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 THIRTY_YEARS_IN_SECONDS    946707779
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "common.h"
+#include "duid.h"
+#include "net.h"
+
+size_t
+get_duid(unsigned char *duid, const struct interface *iface)
+{
+	FILE *f;
+	uint16_t type = 0;
+	uint16_t hw = 0;
+	uint32_t ul;
+	time_t t;
+	int x = 0;
+	unsigned char *p = duid;
+	size_t len = 0;
+	char *line;
+
+	/* 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 ((f = fopen(DUID, "r"))) {
+		while ((line = get_line(f))) {
+			len = hwaddr_aton(NULL, line);
+			if (len && len <= DUID_LEN) {
+				hwaddr_aton(duid, line);
+				break;
+			}
+			len = 0;
+		}
+		fclose(f);
+		if (len)
+			return len;
+	} else {
+		if (errno != ENOENT)
+			return 0;
+	}
+
+	/* No file? OK, lets make one based on our interface */
+	if (!(f = fopen(DUID, "w")))
+		return 0;
+	type = htons(1); /* DUI-D-LLT */
+	memcpy(p, &type, 2);
+	p += 2;
+	hw = htons(iface->family);
+	memcpy(p, &hw, 2);
+	p += 2;
+	/* time returns seconds from jan 1 1970, but DUID-LLT is
+	 * seconds from jan 1 2000 modulo 2^32 */
+	t = time(NULL) - THIRTY_YEARS_IN_SECONDS;
+	ul = htonl(t & 0xffffffff);
+	memcpy(p, &ul, 4);
+	p += 4;
+	/* Finally, add the MAC address of the interface */
+	memcpy(p, iface->hwaddr, iface->hwlen);
+	p += iface->hwlen;
+	len = p - duid;
+	x = fprintf(f, "%s\n", hwaddr_ntoa(duid, len));
+	fclose(f);
+	/* Failed to write the duid? scrub it, we cannot use it */
+	if (x < 1) {
+		len = 0;
+		unlink(DUID);
+	}
+	return len;
+}
diff --git a/dhcpcd/duid.h b/dhcpcd/duid.h
new file mode 100644
index 0000000..98c1bbd
--- /dev/null
+++ b/dhcpcd/duid.h
@@ -0,0 +1,35 @@
+/* 
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2008 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
+
+#include "net.h"
+
+size_t get_duid(unsigned char *duid, const struct interface *iface);
+
+#endif
diff --git a/dhcpcd/eloop.c b/dhcpcd/eloop.c
new file mode 100644
index 0000000..1115d89
--- /dev/null
+++ b/dhcpcd/eloop.c
@@ -0,0 +1,366 @@
+/* 
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2010 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 <poll.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <syslog.h>
+
+#include "common.h"
+#include "eloop.h"
+
+static struct timeval now;
+
+static struct event {
+	int fd;
+	void (*callback)(void *);
+	void *arg;
+	struct event *next;
+} *events;
+static struct event *free_events;
+
+static struct timeout {
+	struct timeval when;
+	void (*callback)(void *);
+	void *arg;
+	int queue;
+	struct timeout *next;
+} *timeouts;
+static struct timeout *free_timeouts;
+
+static struct pollfd *fds;
+static size_t fds_len;
+
+void
+add_event(int fd, void (*callback)(void *), void *arg)
+{
+	struct event *e, *last = NULL;
+
+	/* We should only have one callback monitoring the fd */
+	for (e = events; e; e = e->next) {
+		if (e->fd == fd) {
+			e->callback = callback;
+			e->arg = arg;
+			return;
+		}
+		last = e;
+	}
+
+	/* Allocate a new event if no free ones already allocated */
+	if (free_events) {
+		e = free_events;
+		free_events = e->next;
+	} else
+		e = xmalloc(sizeof(*e));
+	e->fd = fd;
+	e->callback = callback;
+	e->arg = arg;
+	e->next = NULL;
+	if (last)
+		last->next = e;
+	else
+		events = e;
+}
+
+void
+delete_event(int fd)
+{
+	struct event *e, *last = NULL;
+
+	for (e = events; e; e = e->next) {
+		if (e->fd == fd) {
+			if (last)
+				last->next = e->next;
+			else
+				events = e->next;
+			e->next = free_events;
+			free_events = e;
+			break;
+		}
+		last = e;
+	}
+}
+
+void
+add_q_timeout_tv(int queue,
+    const struct timeval *when, void (*callback)(void *), void *arg)
+{
+	struct timeval w;
+	struct timeout *t, *tt = NULL;
+
+	get_monotonic(&now);
+	timeradd(&now, when, &w);
+	/* Check for time_t overflow. */
+	if (timercmp(&w, &now, <)) {
+		errno = ERANGE;
+		return;
+	}
+
+	/* Remove existing timeout if present */
+	for (t = timeouts; t; t = t->next) {
+		if (t->callback == callback && t->arg == arg) {
+			if (tt)
+				tt->next = t->next;
+			else
+				timeouts = t->next;
+			break;
+		}
+		tt = t;
+	}
+
+	if (!t) {
+		/* No existing, so allocate or grab one from the free pool */
+		if (free_timeouts) {
+			t = free_timeouts;
+			free_timeouts = t->next;
+		} else
+			t = xmalloc(sizeof(*t));
+	}
+
+	t->when.tv_sec = w.tv_sec;
+	t->when.tv_usec = w.tv_usec;
+	t->callback = callback;
+	t->arg = arg;
+	t->queue = queue;
+
+	/* The timeout list should be in chronological order,
+	 * soonest first.
+	 * This is the easiest algorithm - check the head, then middle
+	 * and finally the end. */
+	if (!timeouts || timercmp(&t->when, &timeouts->when, <)) {
+		t->next = timeouts;
+		timeouts = t;
+		return;
+	} 
+	for (tt = timeouts; tt->next; tt = tt->next)
+		if (timercmp(&t->when, &tt->next->when, <)) {
+			t->next = tt->next;
+			tt->next = t;
+			return;
+		}
+	tt->next = t;
+	t->next = NULL;
+}
+
+void
+add_q_timeout_sec(int queue, time_t when, void (*callback)(void *), void *arg)
+{
+	struct timeval tv;
+
+	tv.tv_sec = when;
+	tv.tv_usec = 0;
+	add_q_timeout_tv(queue, &tv, callback, arg);
+}
+
+/* This deletes all timeouts for the interface EXCEPT for ones with the
+ * callbacks given. Handy for deleting everything apart from the expire
+ * timeout. */
+static void
+v_delete_q_timeouts(int queue, void *arg, void (*callback)(void *), va_list v)
+{
+	struct timeout *t, *tt, *last = NULL;
+	va_list va;
+	void (*f)(void *);
+
+	for (t = timeouts; t && (tt = t->next, 1); t = tt) {
+		if (t->queue == queue && t->arg == arg &&
+		    t->callback != callback)
+		{
+			va_copy(va, v);
+			while ((f = va_arg(va, void (*)(void *))))
+				if (f == t->callback)
+					break;
+			va_end(va);
+			if (!f) {
+				if (last)
+					last->next = t->next;
+				else
+					timeouts = t->next;
+				t->next = free_timeouts;
+				free_timeouts = t;
+				continue;
+			}
+		}
+		last = t;
+	}
+}
+
+void
+delete_q_timeouts(int queue, void *arg, void (*callback)(void *), ...)
+{
+	va_list va;
+
+	va_start(va, callback);
+	v_delete_q_timeouts(queue, arg, callback, va);
+	va_end(va);
+}
+
+void
+delete_q_timeout(int queue, void (*callback)(void *), void *arg)
+{
+	struct timeout *t, *tt, *last = NULL;
+
+	for (t = timeouts; t && (tt = t->next, 1); t = tt) {
+		if (t->queue == queue && t->arg == arg &&
+		    (!callback || t->callback == callback))
+		{
+			if (last)
+				last->next = t->next;
+			else
+				timeouts = t->next;
+			t->next = free_timeouts;
+			free_timeouts = t;
+			continue;
+		}
+		last = t;
+	}
+}
+
+#ifdef DEBUG_MEMORY
+/* Define this to free all malloced memory.
+ * Normally we don't do this as the OS will do it for us at exit,
+ * but it's handy for debugging other leaks in valgrind. */
+static void
+cleanup(void)
+{
+	struct event *e;
+	struct timeout *t;
+
+	while (events) {
+		e = events->next;
+		free(events);
+		events = e;
+	}
+	while (free_events) {
+		e = free_events->next;
+		free(free_events);
+		free_events = e;
+	}
+	while (timeouts) {
+		t = timeouts->next;
+		free(timeouts);
+		timeouts = t;
+	}
+	while (free_timeouts) {
+		t = free_timeouts->next;
+		free(free_timeouts);
+		free_timeouts = t;
+	}
+	free(fds);
+}
+#endif
+
+_noreturn void
+start_eloop(void)
+{
+	int msecs, n;
+	nfds_t nfds, i;
+	struct event *e;
+	struct timeout *t;
+	struct timeval tv;
+
+#ifdef DEBUG_MEMORY
+	atexit(cleanup);
+#endif
+
+	for (;;) {
+		/* Run all timeouts first.
+		 * When we have one that has not yet occured,
+		 * calculate milliseconds until it does for use in poll. */
+		if (timeouts) {
+			if (timercmp(&now, &timeouts->when, >)) {
+				t = timeouts;
+				timeouts = timeouts->next;
+				t->callback(t->arg);
+				t->next = free_timeouts;
+				free_timeouts = t;
+				continue;
+			}
+			timersub(&timeouts->when, &now, &tv);
+			if (tv.tv_sec > INT_MAX / 1000 ||
+			    (tv.tv_sec == INT_MAX / 1000 &&
+				(tv.tv_usec + 999) / 1000 > INT_MAX % 1000))
+				msecs = INT_MAX;
+			else
+				msecs = tv.tv_sec * 1000 +
+				    (tv.tv_usec + 999) / 1000;
+		} else
+			/* No timeouts, so wait forever. */
+			msecs = -1;
+
+		/* Allocate memory for our pollfds as and when needed.
+		 * We don't bother shrinking it. */
+		nfds = 0;
+		for (e = events; e; e = e->next)
+			nfds++;
+		if (msecs == -1 && nfds == 0) {
+			syslog(LOG_ERR, "nothing to do");
+			exit(EXIT_FAILURE);
+		}
+		if (nfds > fds_len) {
+			free(fds);
+			/* Allocate 5 more than we need for future use */
+			fds_len = nfds + 5;
+			fds = xmalloc(sizeof(*fds) * fds_len);
+		}
+		nfds = 0;
+		for (e = events; e; e = e->next) {
+			fds[nfds].fd = e->fd;
+			fds[nfds].events = POLLIN;
+			fds[nfds].revents = 0;
+			nfds++;
+		}
+		n = poll(fds, nfds, msecs);
+		if (n == -1) {
+			if (errno == EAGAIN || errno == EINTR) {
+				get_monotonic(&now);
+				continue;
+			}
+			syslog(LOG_ERR, "poll: %m");
+			exit(EXIT_FAILURE);
+		}
+
+		/* Get the now time and process any triggered events. */
+		get_monotonic(&now);
+		if (n == 0)
+			continue;
+		for (i = 0; i < nfds; i++) {
+			if (!(fds[i].revents & (POLLIN | POLLHUP)))
+				continue;
+			for (e = events; e; e = e->next) {
+				if (e->fd == fds[i].fd) {
+					e->callback(e->arg);
+					break;
+				}
+			}
+		}
+	}
+}
diff --git a/dhcpcd/eloop.h b/dhcpcd/eloop.h
new file mode 100644
index 0000000..ece43c1
--- /dev/null
+++ b/dhcpcd/eloop.h
@@ -0,0 +1,51 @@
+/* 
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2010 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>
+
+#ifndef ELOOP_QUEUE
+  #define ELOOP_QUEUE 0
+#endif
+
+#define add_timeout_tv(a, b, c) add_q_timeout_tv(ELOOP_QUEUE, a, b, c)
+#define add_timeout_sec(a, b, c) add_q_timeout_sec(ELOOP_QUEUE, a, b, c)
+#define delete_timeout(a, b) delete_q_timeout(ELOOP_QUEUE, a, b)
+#define delete_timeouts(a, ...) delete_q_timeouts(ELOOP_QUEUE, a, __VA_ARGS__)
+
+void add_event(int fd, void (*)(void *), void *);
+void delete_event(int fd);
+void add_q_timeout_sec(int queue, time_t, void (*)(void *), void *);
+void add_q_timeout_tv(int queue, const struct timeval *, void (*)(void *),
+    void *);
+void delete_q_timeout(int, void (*)(void *), void *);
+void delete_q_timeouts(int, void *, void (*)(void *), ...);
+void start_eloop(void);
+
+#endif
diff --git a/dhcpcd/if-bsd.c b/dhcpcd/if-bsd.c
new file mode 100644
index 0000000..c3ffcac
--- /dev/null
+++ b/dhcpcd/if-bsd.c
@@ -0,0 +1,446 @@
+/* 
+ * 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.
+ */
+
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <sys/types.h>
+
+#include <arpa/inet.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/route.h>
+#include <netinet/in.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_ioctl.h>
+#endif
+
+#include <errno.h>
+#include <fnmatch.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include "config.h"
+#include "common.h"
+#include "configure.h"
+#include "dhcp.h"
+#include "if-options.h"
+#include "net.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
+
+/* FIXME: Why do we need to check for sa_family 255 */
+#define COPYOUT(sin, sa)						      \
+	sin.s_addr = ((sa) != NULL) ?					      \
+	    (((struct sockaddr_in *)(void *)sa)->sin_addr).s_addr : 0
+
+static int r_fd = -1;
+static char *link_buf;
+static ssize_t link_buflen;
+
+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;
+}
+
+#ifdef DEBUG_MEMORY
+static void
+cleanup(void)
+{
+
+	free(link_buf);
+}
+#endif
+
+int
+init_sockets(void)
+{
+	if ((socket_afnet = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
+		return -1;
+	set_cloexec(socket_afnet);
+	if ((r_fd = socket(PF_ROUTE, SOCK_RAW, 0)) == -1)
+		return -1;
+	set_cloexec(r_fd);
+	return 0;
+}
+
+int
+getifssid(const char *ifname, char *ssid)
+{
+	int 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 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(socket_afnet, SIOCG80211NWID, &ifr) == 0) {
+		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(socket_afnet, SIOCG80211, &ireq) == 0) {
+		retval = ireq.i_len;
+		memcpy(ssid, nwid, ireq.i_len);
+		ssid[ireq.i_len] = '\0';
+	}
+#endif
+	return retval;
+}
+
+int
+if_address(const struct interface *iface, const struct in_addr *address,
+    const struct in_addr *netmask, const struct in_addr *broadcast,
+    int action)
+{
+	int retval;
+	struct ifaliasreq ifa;
+	union {
+		struct sockaddr *sa;
+		struct sockaddr_in *sin;
+	} _s;
+
+	memset(&ifa, 0, sizeof(ifa));
+	strlcpy(ifa.ifra_name, iface->name, sizeof(ifa.ifra_name));
+
+#define ADDADDR(_var, _addr) {						      \
+		_s.sa = &_var;						      \
+		_s.sin->sin_family = AF_INET;				      \
+		_s.sin->sin_len = sizeof(*_s.sin);			      \
+		memcpy(&_s.sin->sin_addr, _addr, sizeof(_s.sin->sin_addr));   \
+	}
+
+	ADDADDR(ifa.ifra_addr, address);
+	ADDADDR(ifa.ifra_mask, netmask);
+	if (action >= 0 && broadcast) {
+		ADDADDR(ifa.ifra_broadaddr, broadcast);
+	}
+#undef ADDADDR
+
+	if (action < 0)
+		retval = ioctl(socket_afnet, SIOCDIFADDR, &ifa);
+	else
+		retval = ioctl(socket_afnet, SIOCAIFADDR, &ifa);
+	return retval;
+}
+
+/* ARGSUSED4 */
+int
+if_route(const struct rt *rt, int action)
+{
+	union sockunion {
+		struct sockaddr sa;
+		struct sockaddr_in sin;
+#ifdef INET6
+		struct sockaddr_in6 sin6;
+#endif
+		struct sockaddr_dl sdl;
+		struct sockaddr_storage ss;
+	} su;
+	struct rtm 
+	{
+		struct rt_msghdr hdr;
+		char buffer[sizeof(su) * 4];
+	} rtm;
+	char *bp = rtm.buffer;
+	size_t l;
+	int retval = 0;
+
+#define ADDSU(_su) {							      \
+		l = RT_ROUNDUP(_su.sa.sa_len);				      \
+		memcpy(bp, &(_su), l);					      \
+		bp += l;						      \
+	}
+#define ADDADDR(_a) {							      \
+		memset (&su, 0, sizeof(su));				      \
+		su.sin.sin_family = AF_INET;				      \
+		su.sin.sin_len = sizeof(su.sin);			      \
+		memcpy (&su.sin.sin_addr, _a, sizeof(su.sin.sin_addr));	      \
+		ADDSU(su);						      \
+	}
+
+	memset(&rtm, 0, sizeof(rtm));
+	rtm.hdr.rtm_version = RTM_VERSION;
+	rtm.hdr.rtm_seq = 1;
+	if (action == 0)
+		rtm.hdr.rtm_type = RTM_CHANGE;
+	else if (action > 0)
+		rtm.hdr.rtm_type = RTM_ADD;
+	else
+		rtm.hdr.rtm_type = RTM_DELETE;
+	rtm.hdr.rtm_flags = RTF_UP;
+	/* None interface subnet routes are static. */
+	if (rt->gate.s_addr != INADDR_ANY ||
+	    rt->net.s_addr != rt->iface->net.s_addr ||
+	    rt->dest.s_addr != (rt->iface->addr.s_addr & rt->iface->net.s_addr))
+		rtm.hdr.rtm_flags |= RTF_STATIC;
+	rtm.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY;
+	if (rt->dest.s_addr == rt->gate.s_addr &&
+	    rt->net.s_addr == INADDR_BROADCAST)
+		rtm.hdr.rtm_flags |= RTF_HOST;
+	else {
+		rtm.hdr.rtm_addrs |= RTA_NETMASK;
+		if (rtm.hdr.rtm_flags & RTF_STATIC)
+			rtm.hdr.rtm_flags |= RTF_GATEWAY;
+		if (action >= 0)
+			rtm.hdr.rtm_addrs |= RTA_IFA;
+	}
+
+	ADDADDR(&rt->dest);
+	if (rtm.hdr.rtm_flags & RTF_HOST ||
+	    !(rtm.hdr.rtm_flags & RTF_STATIC))
+	{
+		/* Make us a link layer socket for the host gateway */
+		memset(&su, 0, sizeof(su));
+		su.sdl.sdl_len = sizeof(struct sockaddr_dl);
+		link_addr(rt->iface->name, &su.sdl);
+		ADDSU(su);
+	} else
+		ADDADDR(&rt->gate);
+
+	if (rtm.hdr.rtm_addrs & RTA_NETMASK)
+		ADDADDR(&rt->net);
+
+	if (rtm.hdr.rtm_addrs & RTA_IFA)
+		ADDADDR(&rt->iface->addr);
+
+	rtm.hdr.rtm_msglen = l = bp - (char *)&rtm;
+	if (write(r_fd, &rtm, l) == -1)
+		retval = -1;
+	return retval;
+}
+
+int
+open_link_socket(void)
+{
+	int fd;
+
+#ifdef DEBUG_MEMORY
+	if (link_buf == NULL)
+		atexit(cleanup);
+#endif
+
+	fd = socket(PF_ROUTE, SOCK_RAW, 0);
+	if (fd != -1) {
+		set_cloexec(fd);
+		set_nonblock(fd);
+	}
+	return fd;
+}
+
+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;
+#ifdef DEBUG
+			printf ("got %d %d %s\n", i, sa[i]->sa_family,
+			    inet_ntoa(((struct sockaddr_in *)sa[i])->
+				sin_addr));
+#endif
+			RT_ADVANCE(cp, sa[i]);
+		} else
+			sa[i] = NULL;
+	}
+}
+
+int
+manage_link(int fd)
+{
+	char *p, *e, *cp;
+	char ifname[IF_NAMESIZE];
+	ssize_t bytes;
+	struct rt_msghdr *rtm;
+	struct if_announcemsghdr *ifan;
+	struct if_msghdr *ifm;
+	struct ifa_msghdr *ifam;
+	struct rt rt;
+	struct sockaddr *sa, *rti_info[RTAX_MAX];
+	int len;
+#ifdef RTM_CHGADDR
+	struct sockaddr_dl sdl;
+	unsigned char *hwaddr;
+#endif
+
+	for (;;) {
+		if (ioctl(fd, FIONREAD, &len) == -1)
+			return -1;
+		if (link_buflen < len) {
+			p = realloc(link_buf, len);
+			if (p == NULL)
+				return -1;
+			link_buf = p;
+			link_buflen = len;
+		}
+		bytes = read(fd, link_buf, link_buflen);
+		if (bytes == -1) {
+			if (errno == EAGAIN)
+				return 0;
+			if (errno == EINTR)
+				continue;
+			return -1;
+		}
+		e = link_buf + bytes;
+		for (p = link_buf; p < e; p += rtm->rtm_msglen) {
+			rtm = (struct rt_msghdr *)(void *)p;
+			switch(rtm->rtm_type) {
+#ifdef RTM_IFANNOUNCE
+			case RTM_IFANNOUNCE:
+				ifan = (struct if_announcemsghdr *)(void *)p;
+				switch(ifan->ifan_what) {
+				case IFAN_ARRIVAL:
+					handle_interface(1, ifan->ifan_name);
+					break;
+				case IFAN_DEPARTURE:
+					handle_interface(-1, ifan->ifan_name);
+					break;
+				}
+				break;
+#endif
+			case RTM_IFINFO:
+				ifm = (struct if_msghdr *)(void *)p;
+				memset(ifname, 0, sizeof(ifname));
+				if (!(if_indextoname(ifm->ifm_index, ifname)))
+					break;
+				switch (ifm->ifm_data.ifi_link_state) {
+				case LINK_STATE_DOWN:
+					len = -1;
+					break;
+				case LINK_STATE_UP:
+					len = 1;
+					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 = 0;
+					break;
+				}
+				handle_carrier(len, ifm->ifm_flags, ifname);
+				break;
+			case RTM_DELETE:
+				if (~rtm->rtm_addrs &
+				    (RTA_DST | RTA_GATEWAY | RTA_NETMASK))
+					break;
+				if (rtm->rtm_pid == getpid())
+					break;
+				cp = (char *)(void *)(rtm + 1);
+				sa = (struct sockaddr *)(void *)cp;
+				if (sa->sa_family != AF_INET)
+					break;
+				get_addrs(rtm->rtm_addrs, cp, rti_info);
+				rt.iface = NULL;
+				rt.next = NULL;
+				COPYOUT(rt.dest, rti_info[RTAX_DST]);
+				COPYOUT(rt.net, rti_info[RTAX_NETMASK]);
+				COPYOUT(rt.gate, rti_info[RTAX_GATEWAY]);
+				route_deleted(&rt);
+				break;
+#ifdef RTM_CHGADDR
+			case RTM_CHGADDR:	/* FALLTHROUGH */
+#endif
+			case RTM_DELADDR:	/* FALLTHROUGH */
+			case RTM_NEWADDR:
+				ifam = (struct ifa_msghdr *)(void *)p;
+				if (!if_indextoname(ifam->ifam_index, ifname))
+					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) {
+#ifdef RTM_CHGADDR
+				case AF_LINK:
+					if (rtm->rtm_type != RTM_CHGADDR)
+						break;
+					memcpy(&sdl, rti_info[RTAX_IFA],
+					    rti_info[RTAX_IFA]->sa_len);
+					hwaddr = xmalloc(sdl.sdl_alen);
+					memcpy(hwaddr, LLADDR(&sdl),
+					    sdl.sdl_alen);
+					handle_hwaddr(ifname, hwaddr,
+					    sdl.sdl_alen);
+					break;
+#endif
+				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]);
+					handle_ifa(rtm->rtm_type, ifname,
+					    &rt.dest, &rt.net, &rt.gate);
+					break;
+				}
+				break;
+			}
+		}
+	}
+}
diff --git a/dhcpcd/if-linux-wireless.c b/dhcpcd/if-linux-wireless.c
new file mode 100644
index 0000000..f4b649b
--- /dev/null
+++ b/dhcpcd/if-linux-wireless.c
@@ -0,0 +1,90 @@
+/* 
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2009-2010 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 "common.h"
+
+/* We can't include net.h or dhcpcd.h because
+ * they would pull in net/if.h, which defeats the purpose of this hack. */
+#define IF_SSIDSIZE 33
+int getifssid(const char *ifname, char *ssid);
+
+int
+getifssid(const char *ifname, char *ssid)
+{
+#ifdef SIOCGIWESSID
+	int s, retval;
+	struct iwreq iwr;
+
+	if ((s = socket(AF_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 paramters */
+	ifname = ssid;
+	return -1;
+#endif
+}
diff --git a/dhcpcd/if-linux.c b/dhcpcd/if-linux.c
new file mode 100644
index 0000000..3d0bcad
--- /dev/null
+++ b/dhcpcd/if-linux.c
@@ -0,0 +1,597 @@
+/* 
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2011 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/netlink.h>
+#include <linux/rtnetlink.h>
+
+/* Support older kernels */
+#ifndef IFLA_WIRELESS
+# define IFLA_WIRELESS (IFLA_MASTER + 1)
+#endif
+
+#include <errno.h>
+#include <ctype.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "config.h"
+#include "common.h"
+#include "configure.h"
+#include "dhcp.h"
+#include "net.h"
+
+/* ANDROID change, moved this below all includes. */
+/* 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
+/* End of ANDROID change */
+
+static int sock_fd;
+static struct sockaddr_nl sock_nl;
+
+int
+if_init(struct interface *iface)
+{
+	char path[PATH_MAX];
+	FILE *fp;
+	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/sys/net/ipv4/conf/%s/promote_secondaries",
+	    iface->name);
+
+	fp = fopen(path, "w");
+	if (fp == NULL)
+		return errno == ENOENT ? 0 : -1;
+	n = fprintf(fp, "1");
+	fclose(fp);
+	return n == -1 ? -1 : 0;
+}
+
+int
+if_conf(struct interface *iface)
+{
+	char path[PATH_MAX], buf[1];
+	FILE *fp;
+
+	/* Some qeth setups require the use of the broadcast flag. */
+	snprintf(path, sizeof(path),
+	    "/sys/class/net/%s/device/layer2",
+	    iface->name);
+
+	fp = fopen(path, "r");
+	if (fp == NULL)
+		return errno == ENOENT ? 0 : -1;
+	if (fgets(buf, sizeof(buf), fp) != NULL && buf[0] == '0')
+		iface->state->options->options |= DHCPCD_BROADCAST;
+	fclose(fp);
+	return 0;
+}
+
+static int
+_open_link_socket(struct sockaddr_nl *nl)
+{
+	int fd;
+
+	if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1)
+		return -1;
+	nl->nl_family = AF_NETLINK;
+	if (bind(fd, (struct sockaddr *)nl, sizeof(*nl)) == -1)
+		return -1;
+	set_cloexec(fd);
+	return fd;
+}
+
+int
+init_sockets(void)
+{
+	if ((socket_afnet = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
+		return -1;
+	set_cloexec(socket_afnet);
+	sock_fd = _open_link_socket(&sock_nl);
+	set_cloexec(sock_fd);
+	return sock_fd;
+}
+
+int
+open_link_socket(void)
+{
+	struct sockaddr_nl snl;
+
+	memset(&snl, 0, sizeof(snl));
+	snl.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_IFADDR;
+	return _open_link_socket(&snl);
+}
+
+static int
+get_netlink(int fd, int flags,
+    int (*callback)(struct nlmsghdr *))
+{
+	char *buf = NULL, *nbuf;
+	ssize_t buflen = 0, bytes;
+	struct nlmsghdr *nlm;
+	int r = -1;
+
+	for (;;) {
+		bytes = recv(fd, NULL, 0,
+		    flags | MSG_PEEK | MSG_DONTWAIT | MSG_TRUNC);
+		if (bytes == -1) {
+			if (errno == EAGAIN) {
+				r = 0;
+				goto eexit;
+			}
+			if (errno == EINTR)
+				continue;
+			goto eexit;
+		} else if (bytes == buflen) {
+			/* Support kernels older than 2.6.22 */
+			if (bytes == 0)
+				bytes = 512;
+			else
+				bytes *= 2;
+		}
+		if (buflen < bytes) {
+			/* Alloc 1 more so we work with older kernels */
+			buflen = bytes + 1;
+			nbuf = realloc(buf, buflen);
+			if (nbuf == NULL)
+				goto eexit;
+			buf = nbuf;
+		}
+		bytes = recv(fd, buf, buflen, flags);
+		if (bytes == -1) {
+			if (errno == EAGAIN) {
+				r = 0;
+				goto eexit;
+			}
+			if (errno == EINTR)
+				continue;
+			goto eexit;
+		}
+		for (nlm = (struct nlmsghdr *)buf;
+		     NLMSG_OK(nlm, (size_t)bytes);
+		     nlm = NLMSG_NEXT(nlm, bytes))
+		{
+			r = callback(nlm);
+			if (r != 0)
+				goto eexit;
+		}
+	}
+
+eexit:
+	free(buf);
+	return r;
+}
+
+static int
+err_netlink(struct nlmsghdr *nlm)
+{
+	struct nlmsgerr *err;
+	int l;
+
+	if (nlm->nlmsg_type != NLMSG_ERROR)
+		return 0;
+	l = nlm->nlmsg_len - sizeof(*nlm);
+	if ((size_t)l < sizeof(*err)) {
+		errno = EBADMSG;
+		return -1;
+	}
+	err = (struct nlmsgerr *)NLMSG_DATA(nlm);
+	if (err->error == 0)
+		return l;
+	errno = -err->error;
+	return -1;
+}
+
+static int
+link_route(struct nlmsghdr *nlm)
+{
+	int len, idx, metric;
+	struct rtattr *rta;
+	struct rtmsg *rtm;
+	struct rt rt;
+	char ifn[IF_NAMESIZE + 1];
+
+	if (nlm->nlmsg_type != RTM_DELROUTE)
+		return 0;
+
+	len = nlm->nlmsg_len - sizeof(*nlm);
+	if ((size_t)len < sizeof(*rtm)) {
+		errno = EBADMSG;
+		return -1;
+	}
+	rtm = NLMSG_DATA(nlm);
+	if (rtm->rtm_type != RTN_UNICAST ||
+	    rtm->rtm_table != RT_TABLE_MAIN ||
+	    rtm->rtm_family != AF_INET ||
+	    nlm->nlmsg_pid == (uint32_t)getpid())
+		return 1;
+	rta = (struct rtattr *) ((char *)rtm + NLMSG_ALIGN(sizeof(*rtm)));
+	len = NLMSG_PAYLOAD(nlm, sizeof(*rtm));
+	rt.iface = NULL;
+	rt.dest.s_addr = INADDR_ANY;
+	rt.net.s_addr = INADDR_ANY;
+	rt.gate.s_addr = INADDR_ANY;
+	rt.next = NULL;
+	metric = 0;
+	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_OIF:
+			idx = *(int *)RTA_DATA(rta);
+			if (if_indextoname(idx, ifn))
+				rt.iface = find_interface(ifn);
+			break;
+		case RTA_PRIORITY:
+			metric = *(int *)RTA_DATA(rta);
+			break;
+		}
+		rta = RTA_NEXT(rta, len);
+	}
+	if (rt.iface != NULL) {
+		if (metric == rt.iface->metric) {
+			inet_cidrtoaddr(rtm->rtm_dst_len, &rt.net);
+			route_deleted(&rt);
+		}
+	}
+	return 1;
+}
+
+static int
+link_addr(struct nlmsghdr *nlm)
+{
+	int len;
+	struct rtattr *rta;
+	struct ifaddrmsg *ifa;
+	struct in_addr addr, net, dest;
+	char ifn[IF_NAMESIZE + 1];
+	struct interface *iface;
+
+	if (nlm->nlmsg_type != RTM_DELADDR && nlm->nlmsg_type != RTM_NEWADDR)
+		return 0;
+
+	len = nlm->nlmsg_len - sizeof(*nlm);
+	if ((size_t)len < sizeof(*ifa)) {
+		errno = EBADMSG;
+		return -1;
+	}
+	if (nlm->nlmsg_pid == (uint32_t)getpid())
+		return 1;
+	ifa = NLMSG_DATA(nlm);
+	if (if_indextoname(ifa->ifa_index, ifn) == NULL)
+		return -1;
+	iface = find_interface(ifn);
+	if (iface == NULL)
+		return 1;
+	rta = (struct rtattr *) IFA_RTA(ifa);
+	len = NLMSG_PAYLOAD(nlm, sizeof(*ifa));
+	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 (iface->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);
+	}
+	handle_ifa(nlm->nlmsg_type, ifn, &addr, &net, &dest);
+	return 1;
+}
+
+static int
+link_netlink(struct nlmsghdr *nlm)
+{
+	int len;
+	struct rtattr *rta;
+	struct ifinfomsg *ifi;
+	char ifn[IF_NAMESIZE + 1];
+
+	len = link_route(nlm);
+	if (len != 0)
+		return len;
+	len = link_addr(nlm);
+	if (len != 0)
+		return len;
+
+	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 1;
+	rta = (struct rtattr *) ((char *)ifi + NLMSG_ALIGN(sizeof(*ifi)));
+	len = NLMSG_PAYLOAD(nlm, sizeof(*ifi));
+	*ifn = '\0';
+	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 1;
+			break;
+		case IFLA_IFNAME:
+			strlcpy(ifn, RTA_DATA(rta), sizeof(ifn));
+			break;
+		}
+		rta = RTA_NEXT(rta, len);
+	}
+
+	if (nlm->nlmsg_type == RTM_DELLINK) {
+		handle_interface(-1, ifn);
+		return 1;
+	}
+
+	/* Bridge interfaces set IFF_LOWER_UP when they have a valid
+	 * hardware address. To trigger a valid hardware address pickup
+	 * we need to pretend that that don't exist until they have
+	 * IFF_LOWER_UP set. */
+	if (ifi->ifi_flags & IFF_MASTER && !(ifi->ifi_flags & IFF_LOWER_UP)) {
+		handle_interface(-1, ifn);
+		return 1;
+	}
+
+	handle_carrier(ifi->ifi_flags & IFF_RUNNING ? 1 : -1,
+	    ifi->ifi_flags, ifn);
+	return 1;
+}
+
+int
+manage_link(int fd)
+{
+	return get_netlink(fd, MSG_DONTWAIT, &link_netlink);
+}
+
+static int
+send_netlink(struct nlmsghdr *hdr)
+{
+	int r;
+	struct iovec iov;
+	struct msghdr msg;
+	static unsigned int seq;
+
+	memset(&iov, 0, sizeof(iov));
+	iov.iov_base = hdr;
+	iov.iov_len = hdr->nlmsg_len;
+	memset(&msg, 0, sizeof(msg));
+	msg.msg_name = &sock_nl;
+	msg.msg_namelen = sizeof(sock_nl);
+	msg.msg_iov = &iov;
+	msg.msg_iovlen = 1;
+	/* Request a reply */
+	hdr->nlmsg_flags |= NLM_F_ACK;
+	hdr->nlmsg_seq = ++seq;
+
+	if (sendmsg(sock_fd, &msg, 0) != -1)
+		r = get_netlink(sock_fd, 0, &err_netlink);
+	else
+		r = -1;
+	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 int maxlen, int type,
+    const void *data, int alen)
+{
+	int len = 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;
+	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 int maxlen, int type, uint32_t data)
+{
+	int 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;
+}
+
+struct nlma
+{
+	struct nlmsghdr hdr;
+	struct ifaddrmsg ifa; 
+	char buffer[64];
+};
+
+struct nlmr
+{
+	struct nlmsghdr hdr;
+	struct rtmsg rt;
+	char buffer[256];
+};
+
+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;
+
+	nlm = xzalloc(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;
+	if (!(nlm->ifa.ifa_index = if_nametoindex(iface->name))) {
+		free(nlm);
+		errno = ENODEV;
+		return -1;
+	}
+	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->name, strlen(iface->name) + 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(&nlm->hdr) == -1)
+		retval = -1;
+	free(nlm);
+	return retval;
+}
+
+int
+if_route(const struct rt *rt, int action)
+{
+	struct nlmr *nlm;
+	unsigned int ifindex;
+	int retval = 0;
+
+	if (!(ifindex = if_nametoindex(rt->iface->name))) {
+		errno = ENODEV;
+		return -1;
+	}
+
+	nlm = xzalloc(sizeof(*nlm));
+	nlm->hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
+	nlm->hdr.nlmsg_type = RTM_NEWROUTE;
+	if (action == 0)
+		nlm->hdr.nlmsg_flags = NLM_F_REPLACE;
+	else if (action == 1)
+		nlm->hdr.nlmsg_flags = NLM_F_CREATE /*| NLM_F_EXCL*/;
+	else
+		nlm->hdr.nlmsg_type = RTM_DELROUTE;
+	nlm->hdr.nlmsg_flags |= NLM_F_REQUEST;
+	nlm->rt.rtm_family = AF_INET;
+	nlm->rt.rtm_table = RT_TABLE_MAIN;
+
+	if (action == -1 || action == -2)
+		nlm->rt.rtm_scope = RT_SCOPE_NOWHERE;
+	else {
+		nlm->hdr.nlmsg_flags |= NLM_F_CREATE /*| NLM_F_EXCL*/;
+		/* We only change route metrics for kernel routes */
+		if (rt->dest.s_addr ==
+		    (rt->iface->addr.s_addr & rt->iface->net.s_addr) &&
+		    rt->net.s_addr == rt->iface->net.s_addr)
+			nlm->rt.rtm_protocol = RTPROT_KERNEL;
+		else
+			nlm->rt.rtm_protocol = RTPROT_BOOT;
+		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,
+		    &rt->iface->addr.s_addr, sizeof(rt->iface->addr.s_addr));
+	}
+	/* If destination == gateway then don't add the gateway */
+	if (rt->dest.s_addr != rt->gate.s_addr ||
+	    rt->net.s_addr != INADDR_BROADCAST)
+		add_attr_l(&nlm->hdr, sizeof(*nlm), RTA_GATEWAY,
+		    &rt->gate.s_addr, sizeof(rt->gate.s_addr));
+
+	add_attr_32(&nlm->hdr, sizeof(*nlm), RTA_OIF, ifindex);
+	add_attr_32(&nlm->hdr, sizeof(*nlm), RTA_PRIORITY, rt->metric);
+
+	if (send_netlink(&nlm->hdr) == -1)
+		retval = -1;
+	free(nlm);
+	return retval;
+}
diff --git a/dhcpcd/if-options.c b/dhcpcd/if-options.c
new file mode 100644
index 0000000..4fbdf13
--- /dev/null
+++ b/dhcpcd/if-options.c
@@ -0,0 +1,937 @@
+/* 
+ * 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.
+ */
+
+#include <sys/types.h>
+#include <sys/utsname.h>
+
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <getopt.h>
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <time.h>
+
+#include "config.h"
+#include "common.h"
+#include "if-options.h"
+#include "net.h"
+#include "platform.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_NOIPV6RS	O_BASE + 4
+#define O_IPV6_RA_FORK	O_BASE + 5
+
+const struct option cf_options[] = {
+	{"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'},
+	{"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",          no_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'},
+	{"nooption",        optional_argument, NULL, 'O'},
+	{"require",         required_argument, NULL, 'Q'},
+	{"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},
+	{"noipv6rs",        no_argument,       NULL, O_NOIPV6RS},
+	{"ipv6ra_fork",     no_argument,       NULL, O_IPV6_RA_FORK},
+	{NULL,              0,                 NULL, '\0'}
+};
+
+static int
+atoint(const char *s)
+{
+	char *t;
+	long n;
+
+	errno = 0;
+	n = strtol(s, &t, 0);
+	if ((errno != 0 && n == 0) || s == t ||
+	    (errno == ERANGE && (n == LONG_MAX || n == LONG_MIN)))
+	{
+		syslog(LOG_ERR, "`%s' out of range", s);
+		return -1;
+	}
+
+	return (int)n;
+}
+
+static char * 
+add_environ(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;
+
+	match = xstrdup(value);
+	p = strchr(match, '=');
+	if (p)
+		*p++ = '\0';
+	l = strlen(match);
+
+	while (lst && lst[i]) {
+		if (match && strncmp(lst[i], match, l) == 0) {
+			if (uniq) {
+				free(lst[i]);
+				lst[i] = xstrdup(value);
+			} else {
+				/* Append a space and the value to it */
+				l = strlen(lst[i]);
+				lv = strlen(p);
+				lst[i] = xrealloc(lst[i], l + lv + 2);
+				lst[i][l] = ' ';
+				memcpy(lst[i] + l + 1, p, lv);
+				lst[i][l + lv + 1] = '\0';
+			}
+			free(match);
+			return lst[i];
+		}
+		i++;
+	}
+
+	newlist = xrealloc(lst, sizeof(char *) * (i + 2));
+	newlist[i] = xstrdup(value);
+	newlist[i + 1] = NULL;
+	ifo->environ = newlist;
+	free(match);
+	return newlist[i];
+}
+
+#define parse_string(buf, len, arg) parse_string_hwaddr(buf, len, arg, 0)
+static ssize_t
+parse_string_hwaddr(char *sbuf, ssize_t slen, const char *str, int clid)
+{
+	ssize_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 = hwaddr_aton(NULL, str);
+		if (l > 1) {
+			if (l > slen) {
+				errno = ENOBUFS;
+				return -1;
+			}
+			hwaddr_aton((uint8_t *)sbuf, str);
+			return 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) {
+		*sbuf++ = 0;
+		l++;
+	}
+	c[3] = '\0';
+	while (*str) {
+		if (++l > slen) {
+			errno = ENOBUFS;
+			return -1;
+		}
+		if (*str == '\\') {
+			str++;
+			switch(*str) {
+			case '\0':
+				break;
+			case 'b':
+				*sbuf++ = '\b';
+				str++;
+				break;
+			case 'n':
+				*sbuf++ = '\n';
+				str++;
+				break;
+			case 'r':
+				*sbuf++ = '\r';
+				str++;
+				break;
+			case 't':
+				*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') {
+					c[2] = '\0';
+					*sbuf++ = 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') {
+					i = strtol(c, NULL, 8);
+					if (i > 255)
+						i = 255;
+					*sbuf ++= i;
+				} else
+					l--;
+				break;
+			default:
+				*sbuf++ = *str++;
+			}
+		} else
+			*sbuf++ = *str++;
+	}
+	if (punt_last) {
+		*--sbuf = '\0';
+		l--;
+	}
+	return l;
+}
+
+static char **
+splitv(int *argc, char **argv, const char *arg)
+{
+	char **v = argv;
+	char *o = xstrdup(arg), *p, *t;
+
+	p = o;
+	while ((t = strsep(&p, ", "))) {
+		(*argc)++;
+		v = xrealloc(v, sizeof(char *) * ((*argc)));
+		v[(*argc) - 1] = xstrdup(t);
+	}
+	free(o);
+	return v;	
+}
+
+static int
+parse_addr(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))
+		{
+			syslog(LOG_ERR, "`%s' is not a valid CIDR", p);
+			return -1;
+		}
+	} 
+
+	if (addr != NULL && inet_aton(arg, addr) == 0) {
+		syslog(LOG_ERR, "`%s' is not a valid IP address", arg);
+		return -1;
+	}
+	if (p != NULL)
+		*--p = '/';
+	else if (net != NULL)
+		net->s_addr = get_netmask(addr->s_addr);
+	return 0;
+}
+
+static int
+parse_option(struct if_options *ifo, int opt, const char *arg)
+{
+	int i;
+	char *p = NULL, *np;
+	ssize_t s;
+	struct in_addr addr, addr2;
+	struct rt *rt;
+
+	switch(opt) {
+	case 'a': /* FALLTHROUGH */
+	case 'f': /* FALLTHROUGH */
+	case 'g': /* FALLTHROUGH */
+	case 'n': /* FALLTHROUGH */
+	case 'x': /* FALLTHROUGH */
+	case 'T': /* FALLTHROUGH */
+	case 'U': /* We need to handle non interface options */
+		break;
+	case 'b':
+		ifo->options |= DHCPCD_BACKGROUND;
+		break;
+	case 'c':
+		strlcpy(ifo->script, arg, sizeof(ifo->script));
+		break;
+	case 'd':
+		ifo->options |= DHCPCD_DEBUG;
+		break;
+	case 'e':
+		add_environ(ifo, arg, 1);
+		break;
+	case 'h':
+		if (arg) {
+			s = parse_string(ifo->hostname,
+			    HOSTNAME_MAX_LEN, arg);
+			if (s == -1) {
+				syslog(LOG_ERR, "hostname: %m");
+				return -1;
+			}
+			if (s != 0 && ifo->hostname[0] == '.') {
+				syslog(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) {
+			syslog(LOG_ERR, "vendorclassid: %m");
+			return -1;
+		}
+		*ifo->vendorclassid = (uint8_t)s;
+		break;
+	case 'k':
+		ifo->options |= DHCPCD_RELEASE;
+		break;
+	case 'l':
+		if (*arg == '-') {
+			syslog(LOG_ERR,
+			    "leasetime must be a positive value");
+			return -1;
+		}
+		errno = 0;
+		ifo->leasetime = (uint32_t)strtol(arg, NULL, 0);
+		if (errno == EINVAL || errno == ERANGE) {
+			syslog(LOG_ERR, "`%s' out of range", arg);
+			return -1;
+		}
+		break;
+	case 'm':
+		ifo->metric = atoint(arg);
+		if (ifo->metric < 0) {
+			syslog(LOG_ERR, "metric must be a positive value");
+			return -1;
+		}
+		break;
+	case 'o':
+		if (make_option_mask(ifo->requestmask, arg, 1) != 0) {
+			syslog(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(&ifo->req_addr, NULL, arg) != 0)
+			return -1;
+		ifo->options |= DHCPCD_REQUEST;
+		ifo->req_mask.s_addr = 0;
+		break;
+	case 's':
+		if (arg && *arg != '\0') {
+			if (parse_addr(&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 = atoint(arg);
+		if (ifo->timeout < 0) {
+			syslog(LOG_ERR, "timeout must be a positive value");
+			return -1;
+		}
+		break;
+	case 'u':
+		s = USERCLASS_MAX_LEN - ifo->userclass[0] - 1;
+		s = parse_string((char *)ifo->userclass +
+		    ifo->userclass[0] + 2,
+		    s, arg);
+		if (s == -1) {
+			syslog(LOG_ERR, "userclass: %m");
+			return -1;
+		}
+		if (s != 0) {
+			ifo->userclass[ifo->userclass[0] + 1] = s;
+			ifo->userclass[0] += s + 1;
+		}
+		break;
+	case 'v':
+		p = strchr(arg, ',');
+		if (!p || !p[1]) {
+			syslog(LOG_ERR, "invalid vendor format");
+			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) {
+				syslog(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;
+		}
+
+		*p = '\0';
+		i = atoint(arg);
+		arg = p + 1;
+		if (i < 1 || i > 254) {
+			syslog(LOG_ERR, "vendor option should be between"
+			    " 1 and 254 inclusive");
+			return -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));
+		} else {
+			s = parse_string((char *)ifo->vendor +
+			    ifo->vendor[0] + 3, s, arg);
+		}
+		if (s == -1) {
+			syslog(LOG_ERR, "vendor: %m");
+			return -1;
+		}
+		if (s != 0) {
+			ifo->vendor[ifo->vendor[0] + 1] = i;
+			ifo->vendor[ifo->vendor[0] + 2] = s;
+			ifo->vendor[0] += s + 2;
+		}
+		break;
+	case 'w':
+		ifo->options |= DHCPCD_WAITIP;
+		break;
+	case 'y':
+		ifo->reboot = atoint(arg);
+		if (ifo->reboot < 0) {
+			syslog(LOG_ERR, "reboot must be a positive value");
+			return -1;
+		}
+		break;
+	case 'z':
+		ifav = splitv(&ifac, 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 = ' ';
+		s = strlen("skip_hooks=") + strlen(arg) + 1;
+		p = xmalloc(sizeof(char) * s);
+		snprintf(p, s, "skip_hooks=%s", arg);
+		add_environ(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 {
+			syslog(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) {
+			syslog(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 'O':
+		if (make_option_mask(ifo->requestmask, arg, -1) != 0 ||
+		    make_option_mask(ifo->requiremask, arg, -1) != 0 ||
+		    make_option_mask(ifo->nomask, arg, 1) != 0)
+		{
+			syslog(LOG_ERR, "unknown option `%s'", arg);
+			return -1;
+		}
+		break;
+	case 'Q':
+		if (make_option_mask(ifo->requiremask, arg, 1) != 0 ||
+		    make_option_mask(ifo->requestmask, arg, 1) != 0)
+		{
+			syslog(LOG_ERR, "unknown option `%s'", arg);
+			return -1;
+		}
+		break;
+	case 'S':
+		p = strchr(arg, '=');
+		if (p == NULL) {
+			syslog(LOG_ERR, "static assignment required");
+			return -1;
+		}
+		p++;
+		if (strncmp(arg, "ip_address=", strlen("ip_address=")) == 0) {
+			if (parse_addr(&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(&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)
+		{
+			np = strchr(p, ' ');
+			if (np == NULL) {
+				syslog(LOG_ERR, "all routes need a gateway");
+				return -1;
+			}
+			*np++ = '\0';
+			while (*np == ' ')
+				np++;
+			if (ifo->routes == NULL) {
+				rt = ifo->routes = xmalloc(sizeof(*rt));
+			} else {
+				rt = ifo->routes;
+				while (rt->next)
+					rt = rt->next;
+				rt->next = xmalloc(sizeof(*rt));
+				rt = rt->next;
+			}
+			rt->next = NULL;
+			if (parse_addr(&rt->dest, &rt->net, p) == -1 ||
+			    parse_addr(&rt->gate, NULL, np) == -1)
+				return -1;
+		} else if (strncmp(arg, "routers=", strlen("routers=")) == 0) {
+			if (ifo->routes == NULL) {
+				rt = ifo->routes = xzalloc(sizeof(*rt));
+			} else {
+				rt = ifo->routes;
+				while (rt->next)
+					rt = rt->next;
+				rt->next = xmalloc(sizeof(*rt));
+				rt = rt->next;
+			}
+			rt->dest.s_addr = INADDR_ANY;
+			rt->net.s_addr = INADDR_ANY;
+			rt->next = NULL;
+			if (parse_addr(&rt->gate, NULL, p) == -1)
+				return -1;
+		} else {
+			s = 0;
+			if (ifo->config != NULL) {
+				while (ifo->config[s] != NULL) {
+					if (strncmp(ifo->config[s], arg,
+						p - arg) == 0)
+					{
+						free(ifo->config[s]);
+						ifo->config[s] = xstrdup(arg);
+						return 1;
+					}
+					s++;
+				}
+			}
+			ifo->config = xrealloc(ifo->config,
+			    sizeof(char *) * (s + 2));
+			ifo->config[s] = xstrdup(arg);
+			ifo->config[s + 1] = NULL;
+		}
+		break;
+	case 'W':
+		if (parse_addr(&addr, &addr2, arg) != 0)
+			return -1;
+		if (strchr(arg, '/') == NULL)
+			addr2.s_addr = INADDR_BROADCAST;
+		ifo->whitelist = xrealloc(ifo->whitelist,
+		    sizeof(in_addr_t) * (ifo->whitelist_len + 2));
+		ifo->whitelist[ifo->whitelist_len++] = addr.s_addr;
+		ifo->whitelist[ifo->whitelist_len++] = addr2.s_addr;
+		break;
+	case 'X':
+		if (parse_addr(&addr, &addr2, arg) != 0)
+			return -1;
+		if (strchr(arg, '/') == NULL)
+			addr2.s_addr = INADDR_BROADCAST;
+		ifo->blacklist = xrealloc(ifo->blacklist,
+		    sizeof(in_addr_t) * (ifo->blacklist_len + 2));
+		ifo->blacklist[ifo->blacklist_len++] = addr.s_addr;
+		ifo->blacklist[ifo->blacklist_len++] = addr2.s_addr;
+		break;
+	case 'Z':
+		ifdv = splitv(&ifdc, ifdv, arg);
+		break;
+	case O_ARPING:
+		if (parse_addr(&addr, NULL, arg) != 0)
+			return -1;
+		ifo->arping = xrealloc(ifo->arping,
+		    sizeof(in_addr_t) * (ifo->arping_len + 1));
+		ifo->arping[ifo->arping_len++] = addr.s_addr;
+		break;
+	case O_DESTINATION:
+		if (make_option_mask(ifo->dstmask, arg, 2) != 0) {
+			if (errno == EINVAL)
+				syslog(LOG_ERR, "option `%s' does not take"
+				    " an IPv4 address", arg);
+			else
+				syslog(LOG_ERR, "unknown option `%s'", arg);
+			return -1;
+		}
+		break;
+	case O_FALLBACK:
+		free(ifo->fallback);
+		ifo->fallback = xstrdup(arg);
+		break;
+	case O_NOIPV6RS:
+		ifo->options &= ~DHCPCD_IPV6RS;
+		break;
+	case O_IPV6_RA_FORK:
+		ifo->options &= ~DHCPCD_IPV6RA_REQRDNSS;
+		break;
+	default:
+		return 0;
+	}
+
+	return 1;
+}
+
+static int
+parse_config_line(struct if_options *ifo, const char *opt, char *line)
+{
+	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(ifo, cf_options[i].val, line);
+	}
+
+	fprintf(stderr, PACKAGE ": unknown option -- %s\n", opt);
+	return -1;
+}
+
+struct if_options *
+read_config(const char *file,
+    const char *ifname, const char *ssid, const char *profile)
+{
+	struct if_options *ifo;
+	FILE *f;
+	char *line, *option, *p, *platform;
+	int skip = 0, have_profile = 0;
+	struct utsname utn;
+
+	/* Seed our default options */
+	ifo = xzalloc(sizeof(*ifo));
+	ifo->options |= DHCPCD_GATEWAY | DHCPCD_DAEMONISE | DHCPCD_LINK;
+	ifo->options |= DHCPCD_ARP | DHCPCD_IPV4LL;
+#ifndef ANDROID
+	/* On Android, don't enable IPv6 RS processing. This is because we
+	 * already process RAs in the kernel and netd and because we've seen
+	 * dhcpcd crashes when parsing certain RA options.
+	 * See http://b/15268738 and http://b/15779617 . */
+	ifo->options |= DHCPCD_IPV6RS | DHCPCD_IPV6RA_REQRDNSS;
+#endif
+	ifo->timeout = DEFAULT_TIMEOUT;
+	ifo->reboot = DEFAULT_REBOOT;
+	ifo->metric = -1;
+	strlcpy(ifo->script, SCRIPT, sizeof(ifo->script));
+	gethostname(ifo->hostname, HOSTNAME_MAX_LEN);
+	/* Ensure that the hostname is NULL terminated */
+	ifo->hostname[HOSTNAME_MAX_LEN] = '\0';
+	if (strcmp(ifo->hostname, "(none)") == 0 ||
+	    strcmp(ifo->hostname, "localhost") == 0)
+		ifo->hostname[0] = '\0';
+
+	platform = hardware_platform();
+#ifndef ANDROID
+	if (uname(&utn) == 0)
+		ifo->vendorclassid[0] = snprintf((char *)ifo->vendorclassid + 1,
+		    VENDORCLASSID_MAX_LEN,
+	            "%s-%s:%s-%s:%s%s%s", PACKAGE, VERSION,
+		    utn.sysname, utn.release, utn.machine,
+		    platform ? ":" : "", platform ? platform : "");
+	else
+#endif
+		ifo->vendorclassid[0] = snprintf((char *)ifo->vendorclassid + 1,
+		    VENDORCLASSID_MAX_LEN, "%s-%s", PACKAGE, VERSION);
+
+	/* Parse our options file */
+	f = fopen(file ? file : CONFIG, "r");
+	if (f == NULL) {
+		if (file != NULL)
+			syslog(LOG_ERR, "fopen `%s': %m", file);
+		return ifo;
+	}
+
+	while ((line = get_line(f))) {
+		option = strsep(&line, " \t");
+		/* 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) {
+			if (ifname && line && strcmp(line, ifname) == 0)
+				skip = 0;
+			else
+				skip = 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;
+		}
+		if (skip)
+			continue;
+		parse_config_line(ifo, option, line);
+	}
+	fclose(f);
+
+	if (profile && !have_profile) {
+		free_options(ifo);
+		errno = ENOENT;
+		ifo = NULL;
+	}
+
+	/* Terminate the encapsulated options */
+	if (ifo && ifo->vendor[0] && !(ifo->options & DHCPCD_VENDORRAW)) {
+		ifo->vendor[0]++;
+		ifo->vendor[ifo->vendor[0]] = DHO_END;
+	}
+	return ifo;
+}
+
+int
+add_options(struct if_options *ifo, int argc, char **argv)
+{
+	int oi, opt, r = 1;
+
+	optind = 0;
+	while ((opt = getopt_long(argc, argv, IF_OPTS, cf_options, &oi)) != -1)
+	{
+		r = parse_option(ifo, opt, optarg);
+		if (r != 1)
+			break;
+	}
+	/* Terminate the encapsulated options */
+	if (r == 1 && ifo->vendor[0] && !(ifo->options & DHCPCD_VENDORRAW)) {
+		ifo->vendor[0]++;
+		ifo->vendor[ifo->vendor[0]] = DHO_END;
+	}
+	return r;
+}
+
+void
+free_options(struct if_options *ifo)
+{
+	size_t i;
+
+	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);
+		}
+		free_routes(ifo->routes);
+		free(ifo->arping);
+		free(ifo->blacklist);
+		free(ifo->fallback);
+		free(ifo);
+	}
+}
diff --git a/dhcpcd/if-options.h b/dhcpcd/if-options.h
new file mode 100644
index 0000000..45fac33
--- /dev/null
+++ b/dhcpcd/if-options.h
@@ -0,0 +1,125 @@
+/* 
+ * 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 IF_OPTIONS_H
+#define IF_OPTIONS_H
+
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in.h>
+
+#include <getopt.h>
+#include <limits.h>
+
+/* Don't set any optional arguments here so we retain POSIX
+ * compatibility with getopt */
+#define IF_OPTS "abc:de:f:gh:i:kl:m:no:pqr:s:t:u:v:wxy:z:ABC:DEF:GHI:JKLO:Q:S:TUVW:X:Z:"
+
+#define DEFAULT_TIMEOUT		0       /* keep retrying forever... */
+#define DEFAULT_REBOOT		5
+
+#define HOSTNAME_MAX_LEN	250	/* 255 - 3 (FQDN) - 2 (DNS enc) */
+#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_TIMEOUT_IPV4LL		(1ULL << 24)
+#define DHCPCD_WAITIP			(1ULL << 25)
+#define DHCPCD_WAITUP			(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)
+
+extern const struct option cf_options[];
+
+struct if_options {
+	int metric;
+	uint8_t requestmask[256 / 8];
+	uint8_t requiremask[256 / 8];
+	uint8_t nomask[256 / 8];
+	uint8_t dstmask[256 / 8];
+	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 *routes;
+	char **config;
+
+	char **environ;
+	char script[PATH_MAX];
+	
+	char hostname[HOSTNAME_MAX_LEN + 1]; /* We don't store the length */
+	int fqdn;
+	uint8_t vendorclassid[VENDORCLASSID_MAX_LEN + 2];
+	char 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_options *read_config(const char *,
+    const char *, const char *, const char *);
+int add_options(struct if_options *, int, char **);
+void free_options(struct if_options *);
+
+#endif
diff --git a/dhcpcd/if-pref.c b/dhcpcd/if-pref.c
new file mode 100644
index 0000000..6169dbe
--- /dev/null
+++ b/dhcpcd/if-pref.c
@@ -0,0 +1,108 @@
+/* 
+ * 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.
+ */
+
+#include <sys/types.h>
+
+#include "config.h"
+#include "dhcpcd.h"
+#include "if-pref.h"
+#include "net.h"
+
+/* Interface comparer for working out ordering. */
+static int
+ifcmp(struct interface *si, struct interface *ti)
+{
+	int sill, till;
+
+	if (si->state && !ti->state)
+		return -1;
+	if (!si->state && ti->state)
+		return 1;
+	if (!si->state && !ti->state)
+		return 0;
+	/* If one has a lease and the other not, it takes precedence. */
+	if (si->state->new && !ti->state->new)
+		return -1;
+	if (!si->state->new && ti->state->new)
+		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 (si->state->new && ti->state->new) {
+		sill = (si->state->new->cookie == htonl(MAGIC_COOKIE));
+		till = (ti->state->new->cookie == htonl(MAGIC_COOKIE));
+		if (!sill && till)
+			return 1;
+		if (sill && !till)
+			return -1;
+	}
+	/* Then carrier status. */
+	if (si->carrier > ti->carrier)
+		return -1;
+	if (si->carrier < ti->carrier)
+		return 1;
+	/* 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
+sort_interfaces(void)
+{
+	struct interface *sorted, *ifp, *ifn, *ift;
+
+	if (!ifaces || !ifaces->next)
+		return;
+	sorted = ifaces;
+	ifaces = ifaces->next;
+	sorted->next = NULL;
+	for (ifp = ifaces; ifp && (ifn = ifp->next, 1); ifp = ifn) {
+		/* Are we the new head? */
+		if (ifcmp(ifp, sorted) == -1) {
+			ifp->next = sorted;
+			sorted = ifp;
+			continue;
+		}
+		/* Do we fit in the middle? */
+		for (ift = sorted; ift->next; ift = ift->next) {
+			if (ifcmp(ifp, ift->next) == -1) {
+				ifp->next = ift->next;
+				ift->next = ifp;
+				break;
+			}
+		}
+		/* We must be at the end */
+		if (!ift->next) {
+			ift->next = ifp;
+			ifp->next = NULL;
+		}
+	}
+	ifaces = sorted;
+}
diff --git a/dhcpcd/if-pref.h b/dhcpcd/if-pref.h
new file mode 100644
index 0000000..dcedd60
--- /dev/null
+++ b/dhcpcd/if-pref.h
@@ -0,0 +1,34 @@
+/* 
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2008 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_PREF_H
+#define IF_PREF_H
+
+#include "dhcpcd.h"
+
+void sort_interfaces(void);
+#endif
diff --git a/dhcpcd/ifaddrs.c b/dhcpcd/ifaddrs.c
new file mode 100644
index 0000000..c36fd64
--- /dev/null
+++ b/dhcpcd/ifaddrs.c
@@ -0,0 +1,148 @@
+/* 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; */
+                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/ifaddrs.h b/dhcpcd/ifaddrs.h
new file mode 100644
index 0000000..6356653
--- /dev/null
+++ b/dhcpcd/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/ipv4ll.c b/dhcpcd/ipv4ll.c
new file mode 100644
index 0000000..622abb7
--- /dev/null
+++ b/dhcpcd/ipv4ll.c
@@ -0,0 +1,156 @@
+/* 
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2011 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 <syslog.h>
+#include <unistd.h>
+
+#include "arp.h"
+#include "common.h"
+#include "dhcpcd.h"
+#include "eloop.h"
+#include "if-options.h"
+#include "ipv4ll.h"
+#include "net.h"
+
+static struct dhcp_message *
+make_ipv4ll_lease(uint32_t addr)
+{
+	uint32_t u32;
+	struct dhcp_message *dhcp;
+	uint8_t *p;
+
+	dhcp = xzalloc(sizeof(*dhcp));
+	/* 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 struct dhcp_message *
+find_ipv4ll_lease(uint32_t old_addr)
+{
+	uint32_t addr;
+
+	for (;;) {
+		addr = htonl(LINKLOCAL_ADDR |
+		    (((uint32_t)abs((int)arc4random())
+			% 0xFD00) + 0x0100));
+		if (addr != old_addr &&
+		    IN_LINKLOCAL(ntohl(addr)))
+			break;
+	}
+	return make_ipv4ll_lease(addr);
+}
+
+void
+start_ipv4ll(void *arg)
+{
+	struct interface *iface = arg;
+	uint32_t addr;
+
+	delete_timeout(NULL, iface);
+	iface->state->probes = 0;
+	iface->state->claims = 0;
+	if (iface->addr.s_addr) {
+		iface->state->conflicts = 0;
+		if (IN_LINKLOCAL(htonl(iface->addr.s_addr))) {
+			send_arp_announce(iface);
+			return;
+		}
+	}
+
+	if (iface->state->offer == NULL)
+		addr = 0;
+	else {
+		addr = iface->state->offer->yiaddr;
+		free(iface->state->offer);
+	}
+	/* We maybe rebooting an IPv4LL address. */
+	if (!IN_LINKLOCAL(htonl(addr))) {
+		syslog(LOG_INFO, "%s: probing for an IPv4LL address",
+		    iface->name);
+		addr = 0;
+	}
+	if (addr == 0)
+		iface->state->offer = find_ipv4ll_lease(addr);
+	else
+		iface->state->offer = make_ipv4ll_lease(addr);
+	iface->state->lease.frominfo = 0;
+	send_arp_probe(iface);
+}
+
+void
+handle_ipv4ll_failure(void *arg)
+{
+	struct interface *iface = arg;
+	time_t up;
+
+	if (iface->state->fail.s_addr == iface->addr.s_addr) {
+		up = uptime();
+		if (iface->state->defend + DEFEND_INTERVAL > up) {
+			syslog(LOG_DEBUG,
+			    "%s: IPv4LL %d second defence failed",
+			    iface->name, DEFEND_INTERVAL);
+			drop_dhcp(iface, "EXPIRE");
+			iface->state->conflicts = -1;
+		} else {
+			syslog(LOG_DEBUG, "%s: defended IPv4LL address",
+			    iface->name);
+			iface->state->defend = up;
+			return;
+		}
+	}
+
+	close_sockets(iface);
+	free(iface->state->offer);
+	iface->state->offer = NULL;
+	delete_timeout(NULL, iface);
+	if (++iface->state->conflicts > MAX_CONFLICTS) {
+		syslog(LOG_ERR, "%s: failed to acquire an IPv4LL address",
+		    iface->name);
+		iface->state->interval = RATE_LIMIT_INTERVAL / 2;
+		start_discover(iface);
+	} else {
+		add_timeout_sec(PROBE_WAIT, start_ipv4ll, iface);
+	}
+}
diff --git a/dhcpcd/ipv4ll.h b/dhcpcd/ipv4ll.h
new file mode 100644
index 0000000..a5d8e9a
--- /dev/null
+++ b/dhcpcd/ipv4ll.h
@@ -0,0 +1,33 @@
+/* 
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2008 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 start_ipv4ll(void *);
+void handle_ipv4ll_failure(void *);
+#endif
diff --git a/dhcpcd/ipv6rs.c b/dhcpcd/ipv6rs.c
new file mode 100644
index 0000000..df96934
--- /dev/null
+++ b/dhcpcd/ipv6rs.c
@@ -0,0 +1,762 @@
+/* 
+ * 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.
+ */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/ip6.h>
+#include <netinet/icmp6.h>
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+
+#ifdef __linux__
+#  define _LINUX_IN6_H
+#  include <linux/ipv6.h>
+#endif
+
+#define ELOOP_QUEUE 1
+#include "bind.h"
+#include "common.h"
+#include "configure.h"
+#include "dhcpcd.h"
+#include "eloop.h"
+#include "ipv6rs.h"
+
+#define ALLROUTERS "ff02::2"
+#define HOPLIMIT 255
+
+#define ROUNDUP8(a) (1 + (((a) - 1) | 7))
+
+#define RTR_SOLICITATION_INTERVAL       4 /* seconds */
+#define MAX_RTR_SOLICITATIONS           3 /* times */
+
+#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
+
+static int sock;
+static struct sockaddr_in6 allrouters, from;
+static struct msghdr sndhdr;
+static struct iovec sndiov[2];
+static unsigned char *sndbuf;
+static struct msghdr rcvhdr;
+static struct iovec rcviov[2];
+static unsigned char *rcvbuf;
+static unsigned char ansbuf[1500];
+static char ntopbuf[INET6_ADDRSTRLEN];
+
+#if DEBUG_MEMORY
+static void
+ipv6rs_cleanup(void)
+{
+
+	free(sndbuf);
+	free(rcvbuf);
+}
+#endif
+
+int
+ipv6rs_open(void)
+{
+	int on;
+	int len;
+	struct icmp6_filter filt;
+
+	memset(&allrouters, 0, sizeof(allrouters));
+	allrouters.sin6_family = AF_INET6;
+#ifdef SIN6_LEN
+	allrouters.sin6_len = sizeof(allrouters);
+#endif
+	if (inet_pton(AF_INET6, ALLROUTERS, &allrouters.sin6_addr.s6_addr) != 1)
+		return -1;
+	sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
+	if (sock == -1)
+		return -1;
+	on = 1;
+	if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO,
+		&on, sizeof(on)) == -1)
+		return -1;
+
+	on = 1;
+	if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT,
+		&on, sizeof(on)) == -1)
+		return -1;
+
+	ICMP6_FILTER_SETBLOCKALL(&filt);
+	ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt);
+	if (setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER,
+		&filt, sizeof(filt)) == -1)
+		return -1;
+
+#if DEBUG_MEMORY
+	atexit(ipv6rs_cleanup);
+#endif
+
+	len = CMSG_SPACE(sizeof(struct in6_pktinfo)) + CMSG_SPACE(sizeof(int));
+	sndbuf = xzalloc(len);
+	if (sndbuf == NULL)
+		return -1;
+	sndhdr.msg_namelen = sizeof(struct sockaddr_in6);
+	sndhdr.msg_iov = sndiov;
+	sndhdr.msg_iovlen = 1;
+	sndhdr.msg_control = sndbuf;
+	sndhdr.msg_controllen = len;
+	rcvbuf = xzalloc(len);
+	if (rcvbuf == NULL)
+		return -1;
+	rcvhdr.msg_name = &from;
+	rcvhdr.msg_namelen = sizeof(from);
+	rcvhdr.msg_iov = rcviov;
+	rcvhdr.msg_iovlen = 1;
+	rcvhdr.msg_control = rcvbuf;
+	rcvhdr.msg_controllen = len;
+	rcviov[0].iov_base = ansbuf;
+	rcviov[0].iov_len = sizeof(ansbuf);
+	return sock;
+}
+
+static int
+ipv6rs_makeprobe(struct interface *ifp)
+{
+	struct nd_router_solicit *rs;
+	struct nd_opt_hdr *nd;
+
+	free(ifp->rs);
+	ifp->rslen = sizeof(*rs) + ROUNDUP8(ifp->hwlen + 2);
+	ifp->rs = xzalloc(ifp->rslen);
+	if (ifp->rs == NULL)
+		return -1;
+	rs = (struct nd_router_solicit *)ifp->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 *)(ifp->rs + sizeof(*rs));
+	nd->nd_opt_type = ND_OPT_SOURCE_LINKADDR;
+	nd->nd_opt_len = (ROUNDUP8(ifp->hwlen + 2)) >> 3;
+	memcpy(nd + 1, ifp->hwaddr, ifp->hwlen);
+	return 0;
+}
+	
+static void
+ipv6rs_sendprobe(void *arg)
+{
+	struct interface *ifp = arg;
+	struct sockaddr_in6 dst;
+	struct cmsghdr *cm;
+	struct in6_pktinfo pi;
+	int hoplimit = HOPLIMIT;
+
+	dst = allrouters;
+	//dst.sin6_scope_id = ifp->linkid;
+
+	ipv6rs_makeprobe(ifp);
+	sndhdr.msg_name = (caddr_t)&dst;
+	sndhdr.msg_iov[0].iov_base = ifp->rs;
+	sndhdr.msg_iov[0].iov_len = ifp->rslen;
+
+	/* Set the outbound interface */
+	cm = CMSG_FIRSTHDR(&sndhdr);
+	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 = if_nametoindex(ifp->name);
+	memcpy(CMSG_DATA(cm), &pi, sizeof(pi));
+
+	/* Hop limit */
+	cm = CMSG_NXTHDR(&sndhdr, cm);
+	cm->cmsg_level = IPPROTO_IPV6;
+	cm->cmsg_type = IPV6_HOPLIMIT;
+	cm->cmsg_len = CMSG_LEN(sizeof(hoplimit));
+	memcpy(CMSG_DATA(cm), &hoplimit, sizeof(hoplimit));
+
+	syslog(LOG_INFO, "%s: sending IPv6 Router Solicitation", ifp->name);
+	if (sendmsg(sock, &sndhdr, 0) == -1)
+		syslog(LOG_ERR, "%s: sendmsg: %m", ifp->name);
+
+	if (ifp->rsprobes++ < MAX_RTR_SOLICITATIONS)
+		add_timeout_sec(RTR_SOLICITATION_INTERVAL,
+		    ipv6rs_sendprobe, ifp);
+	else
+		syslog(LOG_INFO, "%s: no IPv6 Routers available", ifp->name);
+}
+
+static void
+ipv6rs_sort(struct interface *ifp)
+{
+	struct ra *rap, *sorted, *ran, *rat;
+
+	if (ifp->ras == NULL || ifp->ras->next == NULL)
+		return;
+
+	/* Sort our RA's - most recent first */
+	sorted = ifp->ras;
+	ifp->ras = ifp->ras->next;
+	sorted->next = NULL;
+	for (rap = ifp->ras; rap && (ran = rap->next, 1); rap = ran) {
+		/* Are we the new head? */
+		if (timercmp(&rap->received, &sorted->received, <)) {
+			rap->next = sorted;
+			sorted = rap;
+			continue;
+		}
+		/* Do we fit in the middle? */
+		for (rat = sorted; rat->next; rat = rat->next) {
+			if (timercmp(&rap->received, &rat->next->received, <)) {
+				rap->next = rat->next;
+				rat->next = rap;
+				break;
+			}
+		}
+		/* We must be at the end */
+		if (!rat->next) {
+			rat->next = rap;
+			rap->next = NULL;
+		}
+	}
+}
+
+void
+ipv6rs_handledata(_unused void *arg)
+{
+	ssize_t len, l, n, olen;
+	struct cmsghdr *cm;
+	int hoplimit;
+	struct in6_pktinfo pkt;
+	struct icmp6_hdr *icp;
+	struct interface *ifp;
+	const char *sfrom;
+	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;
+	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, *raol;
+	char *opt;
+	struct timeval expire;
+	int has_dns;
+
+	len = recvmsg(sock, &rcvhdr, 0);
+	if (len == -1) {
+		syslog(LOG_ERR, "recvmsg: %m");
+		return;
+	}
+	sfrom = inet_ntop(AF_INET6, &from.sin6_addr,
+	    ntopbuf, INET6_ADDRSTRLEN);
+	if ((size_t)len < sizeof(struct nd_router_advert)) {
+		syslog(LOG_ERR, "IPv6 RA packet too short from %s", sfrom);
+		return;
+	}
+
+	pkt.ipi6_ifindex = hoplimit = 0;
+	for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&rcvhdr);
+	     cm;
+	     cm = (struct cmsghdr *)CMSG_NXTHDR(&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) {
+		syslog(LOG_ERR,
+		    "IPv6 RA did not contain index or hop limit from %s",
+		    sfrom);
+		return;
+	}
+
+	icp = (struct icmp6_hdr *)rcvhdr.msg_iov[0].iov_base;
+	if (icp->icmp6_type != ND_ROUTER_ADVERT ||
+	    icp->icmp6_code != 0)
+	{
+		syslog(LOG_ERR, "invalid IPv6 type or code from %s", sfrom);
+		return;
+	}
+
+	if (!IN6_IS_ADDR_LINKLOCAL(&from.sin6_addr)) {
+		syslog(LOG_ERR, "RA recieved from non local IPv6 address %s",
+		    sfrom);
+		return;
+	}
+
+	for (ifp = ifaces; ifp; ifp = ifp->next)
+		if (if_nametoindex(ifp->name) == (unsigned int)pkt.ipi6_ifindex)
+			break;
+	if (ifp == NULL) {
+		syslog(LOG_ERR,"received RA for unexpected interface from %s",
+		    sfrom);
+		return;
+	}
+	for (rap = ifp->ras; rap; rap = rap->next) {
+		if (memcmp(rap->from.s6_addr, from.sin6_addr.s6_addr,
+		    sizeof(rap->from.s6_addr)) == 0)
+			break;
+	}
+
+	/* 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 (options & DHCPCD_DEBUG || rap == NULL ||
+	    (rap->expired || rap->data_len != len ||
+	     memcmp(rap->data, (unsigned char *)icp, rap->data_len) != 0))
+	{
+		if (rap) {
+			free(rap->data);
+			rap->data_len = 0;
+		}
+		syslog(LOG_INFO, "%s: Router Advertisement from %s",
+		    ifp->name, sfrom);
+	}
+
+	if (rap == NULL) {
+		rap = xmalloc(sizeof(*rap));
+		rap->next = ifp->ras;
+		rap->options = NULL;
+		ifp->ras = rap;
+		memcpy(rap->from.s6_addr, from.sin6_addr.s6_addr,
+		    sizeof(rap->from.s6_addr));
+		strlcpy(rap->sfrom, sfrom, sizeof(rap->sfrom));
+		rap->data_len = 0;
+	}
+	if (rap->data_len == 0) {
+		rap->data = xmalloc(len);
+		memcpy(rap->data, icp, len);
+		rap->data_len = len;
+	}
+
+	get_monotonic(&rap->received);
+	nd_ra = (struct nd_router_advert *)icp;
+	rap->lifetime = ntohs(nd_ra->nd_ra_router_lifetime);
+	rap->expired = 0;
+
+	len -= sizeof(struct nd_router_advert);
+	p = ((uint8_t *)icp) + sizeof(struct nd_router_advert);
+	olen = 0;
+	lifetime = ~0U;
+	has_dns = 0;
+	for (olen = 0; len > 0; p += olen, len -= olen) {
+		if ((size_t)len < sizeof(struct nd_opt_hdr)) {
+			syslog(LOG_ERR, "%s: Short option", ifp->name);
+			break;
+		}
+		ndo = (struct nd_opt_hdr *)p;
+		olen = ndo->nd_opt_len * 8 ;
+		if (olen == 0) {
+			syslog(LOG_ERR, "%s: zero length option", ifp->name);
+			break;
+		}
+		if (olen > len) {
+			syslog(LOG_ERR,
+			    "%s: Option length exceeds message", ifp->name);
+			break;
+		}
+
+		opt = NULL;
+		switch (ndo->nd_opt_type) {
+		case ND_OPT_PREFIX_INFORMATION:
+			pi = (struct nd_opt_prefix_info *)ndo;
+			if (pi->nd_opt_pi_len != 4) {
+				syslog(LOG_ERR,
+				    "%s: invalid option len for prefix",
+				    ifp->name);
+				break;
+			}
+			if (pi->nd_opt_pi_prefix_len > 128) {
+				syslog(LOG_ERR, "%s: invalid prefix len",
+				    ifp->name);
+				break;
+			}
+			if (IN6_IS_ADDR_MULTICAST(&pi->nd_opt_pi_prefix) ||
+			    IN6_IS_ADDR_LINKLOCAL(&pi->nd_opt_pi_prefix))
+			{
+				syslog(LOG_ERR,
+				    "%s: invalid prefix in RA", ifp->name);
+				break;
+			}
+			opt = xstrdup(inet_ntop(AF_INET6,
+			    pi->nd_opt_pi_prefix.s6_addr,
+			    ntopbuf, INET6_ADDRSTRLEN));
+			if (opt) {
+				rap->prefix_len = pi->nd_opt_pi_prefix_len;
+				rap->prefix_vltime =
+					ntohl(pi->nd_opt_pi_valid_time);
+				rap->prefix_pltime =
+					ntohl(pi->nd_opt_pi_preferred_time);
+			}
+			break;
+
+		case ND_OPT_MTU:
+			mtu = (struct nd_opt_mtu *)p;
+			snprintf(buf, sizeof(buf), "%d",
+			    ntohl(mtu->nd_opt_mtu_mtu));
+			opt = xstrdup(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 = ndo->nd_opt_len - 1; n > 1; n -= 2) {
+				memcpy(&addr.s6_addr, op, sizeof(addr.s6_addr));
+				cbp = inet_ntop(AF_INET6, &addr,
+				    ntopbuf, INET6_ADDRSTRLEN);
+				if (cbp == NULL) {
+					syslog(LOG_ERR,
+					    "%s: invalid RDNSS address",
+					    ifp->name);
+				} else {
+					if (opt) {
+						l = strlen(opt);
+						opt = xrealloc(opt,
+							l + strlen(cbp) + 2);
+						opt[l] = ' ';
+						strcpy(opt + l + 1, cbp);
+					} else
+						opt = xstrdup(cbp);
+					if (lifetime > 0)
+						has_dns = 1;
+				}
+		        	op += sizeof(addr.s6_addr);
+			}
+			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 = (dnssl->nd_opt_dnssl_len - 1) * 8;
+			l = decode_rfc3397(NULL, 0, n, op);
+			if (l < 1) {
+				syslog(LOG_ERR, "%s: invalid DNSSL option",
+				    ifp->name);
+			} else {
+				opt = xmalloc(l);
+				decode_rfc3397(opt, l, n, op);
+			}
+			break;
+		}
+
+		if (opt == NULL)
+			continue;
+		for (raol = NULL, rao = rap->options;
+		    rao;
+		    raol = rao, rao = rao->next)
+		{
+			if (rao->type == ndo->nd_opt_type &&
+			    strcmp(rao->option, opt) == 0)
+				break;
+		}
+		if (lifetime == 0) {
+			if (rao) {
+				if (raol)
+					raol->next = rao->next;
+				else
+					rap->options = rao->next;
+				free(rao->option);
+				free(rao);
+			}
+			continue;
+		}
+
+		if (rao == NULL) {
+			rao = xmalloc(sizeof(*rao));
+			rao->next = rap->options;
+			rap->options = rao;
+			rao->type = ndo->nd_opt_type;
+			rao->option = opt;
+		} else
+			free(opt);
+		if (lifetime == ~0U)
+			timerclear(&rao->expire);
+		else {
+			expire.tv_sec = lifetime;
+			expire.tv_usec = 0;
+			timeradd(&rap->received, &expire, &rao->expire);
+		}
+	}
+
+	ipv6rs_sort(ifp);
+	run_script_reason(ifp, options & DHCPCD_TEST ? "TEST" : "ROUTERADVERT");
+	if (options & DHCPCD_TEST)
+		exit(EXIT_SUCCESS);
+
+	/* If we don't require RDNSS then set has_dns = 1 so we fork */
+	if (!(ifp->state->options->options & DHCPCD_IPV6RA_REQRDNSS))
+		has_dns = 1;
+
+	if (has_dns)
+		delete_q_timeout(0, handle_exit_timeout, NULL);
+	delete_timeout(NULL, ifp);
+	ipv6rs_expire(ifp);
+	if (has_dns)
+		daemonise();
+	else if (options & DHCPCD_DAEMONISE && !(options & DHCPCD_DAEMONISED))
+		syslog(LOG_WARNING,
+		    "%s: did not fork due to an absent RDNSS option in the RA",
+		    ifp->name);
+}
+
+ssize_t
+ipv6rs_env(char **env, const char *prefix, const struct interface *ifp)
+{
+	ssize_t l;
+	struct timeval now;
+	const struct ra *rap;
+	const struct ra_opt *rao;
+	int i;
+	char buffer[32], buffer2[32];
+	const char *optn;
+	
+	l = 0;
+	get_monotonic(&now);
+	for (rap = ifp->ras, i = 1; rap; rap = rap->next, i++) {
+		if (env) {
+			snprintf(buffer, sizeof(buffer),
+			    "ra%d_from", i);
+			setvar(&env, prefix, buffer, rap->sfrom);
+		}
+		l++;
+
+		for (rao = rap->options; rao; rao = rao->next) {
+			if (rao->option == NULL)
+				continue;
+			if (env == NULL) {
+				switch (rao->type) {
+				case ND_OPT_PREFIX_INFORMATION:
+					l += 4;
+					break;
+				default:
+					l++;
+				}
+				continue;
+			}
+			switch (rao->type) {
+			case ND_OPT_PREFIX_INFORMATION:
+				optn = "prefix";
+				break;
+			case ND_OPT_MTU:
+				optn = "mtu";
+				break;
+			case ND_OPT_RDNSS:
+				optn = "rdnss";
+				break;
+			case ND_OPT_DNSSL:
+				optn = "dnssl";
+				break;
+			default:
+				continue;
+			}
+			snprintf(buffer, sizeof(buffer), "ra%d_%s", i, optn);
+			setvar(&env, prefix, buffer, rao->option);
+			l++;
+			switch (rao->type) {
+			case ND_OPT_PREFIX_INFORMATION:
+				snprintf(buffer, sizeof(buffer),
+				    "ra%d_prefix_len", i);
+				snprintf(buffer2, sizeof(buffer2),
+				    "%d", rap->prefix_len);
+				setvar(&env, prefix, buffer, buffer2);
+
+				snprintf(buffer, sizeof(buffer),
+				    "ra%d_prefix_vltime", i);
+				snprintf(buffer2, sizeof(buffer2),
+				    "%d", rap->prefix_vltime);
+				setvar(&env, prefix, buffer, buffer2);
+
+				snprintf(buffer, sizeof(buffer),
+				    "ra%d_prefix_pltime", i);
+				snprintf(buffer2, sizeof(buffer2),
+				    "%d", rap->prefix_pltime);
+				setvar(&env, prefix, buffer, buffer2);
+				l += 3;
+				break;
+			}
+		
+		}
+	}
+
+	if (env)
+		setvard(&env, prefix, "ra_count", i - 1);
+	l++;
+	return l;
+}
+
+static void
+ipv6rs_free_opts(struct ra *rap)
+{
+	struct ra_opt *rao, *raon;
+
+	for (rao = rap->options; rao && (raon = rao->next, 1); rao = raon) {
+		free(rao->option);
+		free(rao);
+	}
+}
+
+void
+ipv6rs_free(struct interface *ifp)
+{
+	struct ra *rap, *ran;
+
+	free(ifp->rs);
+	ifp->rs = NULL;
+	for (rap = ifp->ras; rap && (ran = rap->next, 1); rap = ran) {
+		ipv6rs_free_opts(rap);
+		free(rap->data);
+		free(rap);
+	}
+	ifp->ras = NULL;
+}
+
+void
+ipv6rs_expire(void *arg)
+{
+	struct interface *ifp;
+	struct ra *rap, *ran, *ral;
+	struct ra_opt *rao, *raol, *raon;
+	struct timeval now, lt, expire, next;
+	int expired;
+	uint32_t expire_secs;
+
+	ifp = arg;
+	get_monotonic(&now);
+	expired = 0;
+	expire_secs = ~0U;
+	timerclear(&next);
+
+	for (rap = ifp->ras, ral = NULL;
+	    rap && (ran = rap->next, 1);
+	    ral = rap, rap = ran)
+	{
+		lt.tv_sec = rap->lifetime;
+		lt.tv_usec = 0;
+		timeradd(&rap->received, &lt, &expire);
+		if (timercmp(&now, &expire, >)) {
+			syslog(LOG_INFO, "%s: %s: expired Router Advertisement",
+			    ifp->name, rap->sfrom);
+			rap->expired = expired = 1;
+			if (ral)
+				ral->next = ran;
+			else
+				ifp->ras = ran;
+			ipv6rs_free_opts(rap);
+			free(rap);
+			continue;
+		}
+		timersub(&expire, &now, &lt);
+		if (!timerisset(&next) || timercmp(&next, &lt, >))
+			next = lt;
+		
+		for (rao = rap->options, raol = NULL;
+		    rao && (raon = rao->next);
+		    raol = rao, rao = raon)
+		{
+			if (!timerisset(&rao->expire))
+				continue;
+			if (timercmp(&now, &rao->expire, >)) {
+				syslog(LOG_INFO,
+				    "%s: %s: expired option %d",
+				    ifp->name, rap->sfrom, rao->type);
+				rap->expired = expired = 1;
+				if (raol)
+					raol = raon;
+				else
+					rap->options = raon;
+				continue;
+			}
+			timersub(&rao->expire, &now, &lt);
+			if (!timerisset(&next) || timercmp(&next, &lt, >))
+				next = lt;
+		}
+	}
+
+	if (timerisset(&next))
+		add_timeout_tv(&next, ipv6rs_expire, ifp);
+	if (expired)
+		run_script_reason(ifp, "ROUTERADVERT");
+}
+
+int
+ipv6rs_start(struct interface *ifp)
+{
+
+	delete_timeout(NULL, ifp);
+
+	/* Always make a new probe as the underlying hardware
+	 * address could have changed. */
+	ipv6rs_makeprobe(ifp);
+	if (ifp->rs == NULL)
+		return -1;
+
+	ifp->rsprobes = 0;
+	ipv6rs_sendprobe(ifp);
+	return 0;
+}
diff --git a/dhcpcd/ipv6rs.h b/dhcpcd/ipv6rs.h
new file mode 100644
index 0000000..ae18d3a
--- /dev/null
+++ b/dhcpcd/ipv6rs.h
@@ -0,0 +1,40 @@
+/* 
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2011 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 IPV6RS_H
+#define IPV6RS_H
+
+#ifndef ICMP6_FILTER
+#define ICMP6_FILTER	1
+#endif
+int ipv6rs_open(void);
+void ipv6rs_handledata(void *);
+int ipv6rs_start(struct interface *);
+ssize_t ipv6rs_env(char **, const char *, const struct interface *);
+void ipv6rs_free(struct interface *ifp);
+void ipv6rs_expire(void *arg);
+#endif
diff --git a/dhcpcd/lpf.c b/dhcpcd/lpf.c
new file mode 100644
index 0000000..853d0a3
--- /dev/null
+++ b/dhcpcd/lpf.c
@@ -0,0 +1,214 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2011 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 <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#ifdef __linux__
+# include <asm/types.h> /* needed for 2.4 kernels for the below header */
+# include <linux/filter.h>
+# include <linux/if_packet.h>
+# define bpf_insn		sock_filter
+# define BPF_SKIPTYPE
+# define BPF_ETHCOOK		-ETH_HLEN
+# define BPF_WHOLEPACKET	0x0fffffff /* work around buggy LPF filters */
+#endif
+
+#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 "dhcp.h"
+#include "net.h"
+#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
+};
+
+int
+open_socket(struct interface *iface, int protocol)
+{
+	int s;
+	union sockunion {
+		struct sockaddr sa;
+		struct sockaddr_in sin;
+		struct sockaddr_ll sll;
+		struct sockaddr_storage ss;
+	} su;
+	struct sock_fprog pf;
+	int *fd;
+#ifdef PACKET_AUXDATA
+	int n;
+#endif
+
+	if ((s = socket(PF_PACKET, SOCK_DGRAM, htons(protocol))) == -1)
+		return -1;
+
+	memset(&su, 0, sizeof(su));
+	su.sll.sll_family = PF_PACKET;
+	su.sll.sll_protocol = htons(protocol);
+	if (!(su.sll.sll_ifindex = if_nametoindex(iface->name))) {
+		errno = ENOENT;
+		goto eexit;
+	}
+	/* 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
+	if (set_cloexec(s) == -1)
+		goto eexit;
+	if (set_nonblock(s) == -1)
+		goto eexit;
+	if (bind(s, &su.sa, sizeof(su)) == -1)
+		goto eexit;
+	if (protocol == ETHERTYPE_ARP)
+		fd = &iface->arp_fd;
+	else
+		fd = &iface->raw_fd;
+	if (*fd != -1)
+		close(*fd);
+	*fd = s;
+	return s;
+
+eexit:
+	close(s);
+	return -1;
+}
+
+ssize_t
+send_raw_packet(const struct interface *iface, int protocol,
+    const void *data, ssize_t len)
+{
+	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);
+	if (!(su.sll.sll_ifindex = if_nametoindex(iface->name))) {
+		errno = ENOENT;
+		return -1;
+	}
+	su.sll.sll_hatype = htons(iface->family);
+	su.sll.sll_halen = iface->hwlen;
+	if (iface->family == ARPHRD_INFINIBAND)
+		memcpy(&su.sll.sll_addr,
+		    &ipv4_bcast_addr, sizeof(ipv4_bcast_addr));
+	else
+		memset(&su.sll.sll_addr, 0xff, iface->hwlen);
+	if (protocol == ETHERTYPE_ARP)
+		fd = iface->arp_fd;
+	else
+		fd = iface->raw_fd;
+
+	return sendto(fd, data, len, 0, &su.sa, sizeof(su));
+}
+
+ssize_t
+get_raw_packet(struct interface *iface, int protocol,
+    void *data, ssize_t len, int *partialcsum)
+{
+	struct iovec iov = {
+		.iov_base = data,
+		.iov_len = len,
+	};
+	struct msghdr msg = {
+		.msg_iov = &iov,
+		.msg_iovlen = 1,
+	};
+#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
+
+	if (protocol == ETHERTYPE_ARP)
+		fd = iface->arp_fd;
+	else
+		fd = iface->raw_fd;
+	bytes = recvmsg(fd, &msg, 0);
+	if (bytes == -1)
+		return errno == EAGAIN ? 0 : -1;
+	if (partialcsum != NULL) {
+		*partialcsum = 0;
+#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);
+				*partialcsum = aux->tp_status &
+				    TP_STATUS_CSUMNOTREADY;
+			}
+		}
+#endif
+	}
+	return bytes;
+}
diff --git a/dhcpcd/mk/cc.mk b/dhcpcd/mk/cc.mk
new file mode 100644
index 0000000..fcf0535
--- /dev/null
+++ b/dhcpcd/mk/cc.mk
@@ -0,0 +1,28 @@
+# Copyright 2008 Roy Marples <roy@marples.name>
+
+# Setup some good default CFLAGS
+CFLAGS?=	-Os
+
+# Default to using the C99 standard
+CSTD?=		c99
+_CSTD_SH=	if test -n "${CSTD}"; then echo "-std=${CSTD}"; else echo ""; fi
+_CSTD!=		${_CSTD_SH}
+CFLAGS+=	${_CSTD}$(shell ${_CSTD_SH})
+
+# Try and use some good cc flags if we're building from git
+_CCFLAGS=	-pedantic -Wall -Wunused -Wimplicit -Wshadow -Wformat=2 \
+		-Wmissing-declarations -Wno-missing-prototypes -Wwrite-strings \
+		-Wbad-function-cast -Wnested-externs -Wcomment -Winline \
+		-Wchar-subscripts -Wcast-align -Wno-format-nonliteral \
+		-Wdeclaration-after-statement -Wsequence-point -Wextra
+_CC_FLAGS_SH=	if ! test -d .git; then echo ""; else for f in ${_CCFLAGS}; do \
+		if ${CC} $$f -S -o /dev/null -xc /dev/null >/dev/null 2>&1; \
+		then printf "%s" "$$f "; fi \
+		done; fi
+_CC_FLAGS!=	${_CC_FLAGS_SH}
+CFLAGS+=	${_CC_FLAGS}$(shell ${_CC_FLAGS_SH})
+
+_GGDB_SH=	if test "${DEBUG}" = "yes"; then echo "-ggdb -DDEBUG"; else echo ""; fi
+_GGDB!=		${_GGDB_SH}
+GGDB=		${_GGDB}$(shell ${_GGDB_SH})
+CFLAGS+=	${GGDB}
diff --git a/dhcpcd/mk/depend.mk b/dhcpcd/mk/depend.mk
new file mode 100644
index 0000000..a4d717a
--- /dev/null
+++ b/dhcpcd/mk/depend.mk
@@ -0,0 +1,11 @@
+# This only works for make implementations that always include a .depend if
+# it exists. Only GNU make does not do this.
+
+# Copyright 2008 Roy Marples <roy@marples.name>
+
+CLEANFILES+=	.depend
+
+.depend: ${SRCS}
+	${CC} ${CFLAGS} -MM ${SRCS} > .depend
+
+depend: .depend
diff --git a/dhcpcd/mk/dist.mk b/dhcpcd/mk/dist.mk
new file mode 100644
index 0000000..c4c1947
--- /dev/null
+++ b/dhcpcd/mk/dist.mk
@@ -0,0 +1,31 @@
+# rules to make a distribution tarball from a svn repo
+# Copyright 2008-2009 Roy Marples <roy@marples.name>
+
+GITREF?=	HEAD
+DISTPREFIX?=	${PROG}-${VERSION}
+DISTFILE?=	${DISTPREFIX}.tar.bz2
+
+CLEANFILES+=	*.tar.bz2
+
+_VERSION_SH=	sed -n 's/\#define VERSION[[:space:]]*"\(.*\)".*/\1/p' config.h
+_VERSION!=	${_VERSION_SH}
+VERSION=	${_VERSION}$(shell ${_VERSION_SH})
+
+_SNAP_SH=	date -u +%Y%m%d%H%M
+_SNAP!=		${_SNAP_SH}
+SNAP=		${_SNAP}$(shell ${_SNAP_SH})
+SNAPDIR=	${DISTPREFIX}-${SNAP}
+SNAPFILE=	${SNAPDIR}.tar.bz2
+
+dist:
+	git archive --prefix=${DISTPREFIX}/ ${GITREF} | bzip2 > ${DISTFILE}
+
+snapshot:
+	mkdir /tmp/${SNAPDIR}
+	cp -RPp * /tmp/${SNAPDIR}
+	(cd /tmp/${SNAPDIR}; make clean)
+	tar -cvjpf ${SNAPFILE} -C /tmp ${SNAPDIR}
+	rm -rf /tmp/${SNAPDIR}
+	ls -l ${SNAPFILE}
+
+snap: snapshot
diff --git a/dhcpcd/mk/files.mk b/dhcpcd/mk/files.mk
new file mode 100644
index 0000000..0682b03
--- /dev/null
+++ b/dhcpcd/mk/files.mk
@@ -0,0 +1,9 @@
+# Quick and dirty files
+# Copyright 2008 Roy Marples <roy@marples.name>
+
+FILESDIR?=	${BINDIR}
+FILESMODE?=	${NONBINMODE}
+
+_filesinstall:
+	${INSTALL} -d ${DESTDIR}${FILESDIR}
+	${INSTALL} -m ${FILESMODE} ${FILES} ${DESTDIR}${FILESDIR}
diff --git a/dhcpcd/mk/man.mk b/dhcpcd/mk/man.mk
new file mode 100644
index 0000000..f1570bb
--- /dev/null
+++ b/dhcpcd/mk/man.mk
@@ -0,0 +1,25 @@
+# rules to install manpages
+# Copyright 2008 Roy Marples <roy@marples.name>
+
+_MANPREFIX_SH=	if [ -n "${PREFIX}" ]; then echo "${PREFIX}"; else echo "/usr/share"; fi
+_MANPREFIX!=	${_MANPREFIX_SH}
+MANPREFIX?=	${_MANPREFIX}$(shell ${_MANPREFIX_SH})
+
+MANDIR?=	${MANPREFIX}/man/man
+MANMODE?=	0444
+
+_MAN5_SH=	for man in ${MAN}; do case $$man in *.5) echo $$man;; esac; done
+_MAN5!=		${_MAN5_SH}
+MAN5=		${_MAN5}$(shell ${_MAN5_SH})
+
+_MAN8_SH=	for man in ${MAN}; do case $$man in *.8) echo $$man;; esac; done
+_MAN8!=		${_MAN8_SH}
+MAN8=		${_MAN8}$(shell ${_MAN8_SH})
+
+_man: ${MAN}
+
+_maninstall: _man
+	${INSTALL} -d ${DESTDIR}${MANDIR}5
+	${INSTALL} -m ${MANMODE} ${MAN5} ${DESTDIR}${MANDIR}5
+	${INSTALL} -d ${DESTDIR}${MANDIR}8
+	${INSTALL} -m ${MANMODE} ${MAN8} ${DESTDIR}${MANDIR}8
diff --git a/dhcpcd/mk/os-BSD.mk b/dhcpcd/mk/os-BSD.mk
new file mode 100644
index 0000000..f9d3397
--- /dev/null
+++ b/dhcpcd/mk/os-BSD.mk
@@ -0,0 +1,5 @@
+# Setup OS specific variables
+# Copyright 2008 Roy Marples <roy@marples.name>
+
+SRC_PF=		bpf.c
+SRC_IF=		if-bsd.c
diff --git a/dhcpcd/mk/os-Darwin.mk b/dhcpcd/mk/os-Darwin.mk
new file mode 100644
index 0000000..f2c3104
--- /dev/null
+++ b/dhcpcd/mk/os-Darwin.mk
@@ -0,0 +1,5 @@
+# Setup OS specific variables
+# Copyright 2008 Roy Marples <roy@marples.name>
+
+include ${MK}/os-BSD.mk
+LINK_RPATH=	--rpath
diff --git a/dhcpcd/mk/os-Linux.mk b/dhcpcd/mk/os-Linux.mk
new file mode 100644
index 0000000..2d316b1
--- /dev/null
+++ b/dhcpcd/mk/os-Linux.mk
@@ -0,0 +1,8 @@
+# Setup OS specific variables
+# Copyright 2008 Roy Marples <roy@marples.name>
+
+SRC_PF=		lpf.c
+SRC_IF=		if-linux.c
+
+CPPFLAGS+=	-D_BSD_SOURCE -D_XOPEN_SOURCE=600
+LIBRT=		-lrt
diff --git a/dhcpcd/mk/os.mk b/dhcpcd/mk/os.mk
new file mode 100644
index 0000000..f3426e4
--- /dev/null
+++ b/dhcpcd/mk/os.mk
@@ -0,0 +1,7 @@
+# Setup OS specific variables
+# Copyright 2008 Roy Marples <roy@marples.name>
+
+_OS_SH=	case `uname -s` in Linux) echo "Linux";; Darwin) echo "Darwin";;  *) echo "BSD";; esac
+_OS!=		${_OS_SH}
+OS=		${_OS}$(shell ${_OS_SH})
+include ${MK}/os-${OS}.mk
diff --git a/dhcpcd/mk/prog.mk b/dhcpcd/mk/prog.mk
new file mode 100644
index 0000000..d970b2d
--- /dev/null
+++ b/dhcpcd/mk/prog.mk
@@ -0,0 +1,68 @@
+# rules to build a program 
+# based on FreeBSD's bsd.prog.mk
+
+# Copyright 2008 Roy Marples <roy@marples.name>
+
+include ${MK}/cc.mk
+
+OBJS+=		${SRCS:.c=.o}
+
+# If building for /, ensure we use the libc in / if different from
+# the default one in /usr/lib
+LINK_RPATH?=		-Wl,-rpath
+_RPATH_SH=		if test "${PREFIX}" = "" -o "${PREIX}" = "/"; then \
+				echo "${LINK_RPATH}=${PREFIX}/${LIBNAME}"; \
+			else \
+				echo ""; \
+			fi
+_RPATH!=		${_RPATH_SH}
+LDFLAGS+=		${_RPATH}$(shell ${_RPATH_SH})
+
+# If building for /, ensure we use the linker in /libexec if different from
+# the default one in /usr/libexec
+_DYNLINK_SH=		if test "${PREFIX}" = "" -o "${PREFIX}" = "/" && test -e /libexec/ld.elf_so; then \
+				echo "-Wl,-dynamic-linker=/libexec/ld.elf_so"; \
+			else \
+				echo ""; \
+			fi
+_DYNLINK!=		${_DYNLINK_SH}
+LDFLAGS+=		${_DYNLINK}$(shell ${_DYNLINK_SH})
+
+all: ${PROG} ${SCRIPTS} _man
+
+.c.o:
+	${CC} ${CFLAGS} ${CPPFLAGS} -c $< -o $@
+
+${PROG}: ${OBJS}
+	${CC} ${LDFLAGS} -o $@ ${OBJS} ${LDADD}
+
+# We could save about 600 bytes by building it like this
+# instead of the more traditional method above
+small: ${SRCS}
+	echo "" > _${PROG}.c
+	for src in ${SRCS}; do echo "#include \"$$src\"" >> _${PROG}.c; done
+	${CC} ${CFLAGS} ${CPPFLAGS} -c _${PROG}.c -o _${PROG}.o
+	${CC} ${LDFLAGS} -o ${PROG} _${PROG}.o ${LDADD}
+
+_proginstall: ${PROG}
+	${INSTALL} -d ${DESTDIR}${BINDIR}
+	${INSTALL} -m ${BINMODE} ${PROG} ${DESTDIR}${BINDIR}
+	${INSTALL} -d ${DESTDIR}${DBDIR}
+
+include ${MK}/depend.mk
+include ${MK}/files.mk
+include ${MK}/scripts.mk
+include ${MK}/man.mk
+include ${MK}/dist.mk
+
+install: _proginstall _scriptsinstall _filesinstall _maninstall
+	for x in ${SUBDIRS}; do cd $$x; ${MAKE} $@; cd ..; done
+
+clean:
+	rm -f ${OBJS} ${PROG} _${PROG}.c _${PROG}.o ${PROG}.core ${CLEANFILES}
+
+LINTFLAGS?=	-hx
+LINTFLAGS+=	-X 159,247,352
+
+lint: ${SRCS:.c=.c}
+	${LINT} ${LINTFLAGS} ${CFLAGS:M-[DIU]*} $^ ${.ALLSRC}
diff --git a/dhcpcd/mk/scripts.mk b/dhcpcd/mk/scripts.mk
new file mode 100644
index 0000000..d295163
--- /dev/null
+++ b/dhcpcd/mk/scripts.mk
@@ -0,0 +1,9 @@
+# Quick and dirty scripts
+# Copyright 2008 Roy Marples <roy@marples.name>
+
+SCRIPTSDIR?=	${BINDIR}
+SCRIPTSMODE?=	${BINMODE}
+
+_scriptsinstall: ${SCRIPTS}
+	${INSTALL} -d ${DESTDIR}${SCRIPTSDIR}
+	${INSTALL} -m ${SCRIPTSMODE} ${SCRIPTS} ${DESTDIR}${SCRIPTSDIR}
diff --git a/dhcpcd/mk/sys.mk b/dhcpcd/mk/sys.mk
new file mode 100644
index 0000000..81882ab
--- /dev/null
+++ b/dhcpcd/mk/sys.mk
@@ -0,0 +1,14 @@
+# Simple defaults
+
+BINDIR?=	${PREFIX}/usr/bin
+BINMODE?=	0755
+NONBINMODE?=	0644
+
+SYSCONFDIR?=	${PREFIX}/etc
+
+INSTALL?=	install
+SED?=		sed
+
+_LIBNAME_SH=		case `readlink /lib` in "") echo "lib";; *) basename `readlink /lib`;; esac
+_LIBNAME!=		${_LIBNAME_SH}
+LIBNAME?=		${_LIBNAME}$(shell ${_LIBNAME_SH})
diff --git a/dhcpcd/net.c b/dhcpcd/net.c
new file mode 100644
index 0000000..1a9780d
--- /dev/null
+++ b/dhcpcd/net.c
@@ -0,0 +1,810 @@
+/* 
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2011 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 <sys/ioctl.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#include <arpa/inet.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#ifdef AF_LINK
+#  include <net/if_dl.h>
+#  include <net/if_types.h>
+#endif
+#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
+#ifdef AF_PACKET
+#  include <netpacket/packet.h>
+#endif
+#ifdef SIOCGIFMEDIA
+#  include <net/if_media.h>
+#endif
+
+#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 <syslog.h>
+#include <unistd.h>
+
+#include "config.h"
+#include "common.h"
+#include "dhcp.h"
+#include "if-options.h"
+#include "ipv6rs.h"
+#include "net.h"
+#include "signals.h"
+
+static char hwaddr_buffer[(HWADDR_LEN * 3) + 1];
+
+int socket_afnet = -1;
+
+#if defined(__FreeBSD__) && defined(DEBUG_MEMORY)
+/* FreeBSD does not zero the struct, causing valgrind errors */
+unsigned int
+if_nametoindex(const char *ifname)
+{
+	struct ifreq ifr;
+
+	memset(&ifr, 0, sizeof(ifr));
+	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+	if (ioctl(socket_afnet, SIOCGIFINDEX, &ifr) != -1)
+		return ifr.ifr_index;
+	return 0;
+}
+#endif
+
+int
+inet_ntocidr(struct in_addr address)
+{
+	int 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) / 8;
+
+	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) % 8)), 1);
+	}
+
+	return 0;
+}
+
+uint32_t
+get_netmask(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;
+}
+
+char *
+hwaddr_ntoa(const unsigned char *hwaddr, size_t hwlen)
+{
+	char *p = hwaddr_buffer;
+	size_t i;
+
+	for (i = 0; i < hwlen && i < HWADDR_LEN; i++) {
+		if (i > 0)
+			*p ++= ':';
+		p += snprintf(p, 3, "%.2x", hwaddr[i]);
+	}
+
+	*p ++= '\0';
+
+	return hwaddr_buffer;
+}
+
+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;
+}
+
+struct interface *
+init_interface(const char *ifname)
+{
+	struct ifreq ifr;
+	struct interface *iface = NULL;
+
+	memset(&ifr, 0, sizeof(ifr));
+	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+	if (ioctl(socket_afnet, SIOCGIFFLAGS, &ifr) == -1)
+		goto eexit;
+
+	iface = xzalloc(sizeof(*iface));
+	strlcpy(iface->name, ifname, sizeof(iface->name));
+	iface->flags = ifr.ifr_flags;
+	/* We reserve the 100 range for virtual interfaces, if and when
+	 * we can work them out. */
+	iface->metric = 200 + if_nametoindex(iface->name);
+	if (getifssid(ifname, iface->ssid) != -1) {
+		iface->wireless = 1;
+		iface->metric += 100;
+	}
+
+	if (ioctl(socket_afnet, SIOCGIFMTU, &ifr) == -1)
+		goto eexit;
+	/* Ensure that the MTU is big enough for DHCP */
+	if (ifr.ifr_mtu < MTU_MIN) {
+		ifr.ifr_mtu = MTU_MIN;
+		strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+		if (ioctl(socket_afnet, SIOCSIFMTU, &ifr) == -1)
+			goto eexit;
+	}
+
+	snprintf(iface->leasefile, sizeof(iface->leasefile),
+	    LEASEFILE, ifname);
+	/* 0 is a valid fd, so init to -1 */
+	iface->raw_fd = -1;
+	iface->udp_fd = -1;
+	iface->arp_fd = -1;
+	goto exit;
+
+eexit:
+	free(iface);
+	iface = NULL;
+exit:
+	return iface;
+}
+
+void
+free_interface(struct interface *iface)
+{
+	if (!iface)
+		return;
+	ipv6rs_free(iface);
+	if (iface->state) {
+		free_options(iface->state->options);
+		free(iface->state->old);
+		free(iface->state->new);
+		free(iface->state->offer);
+		free(iface->state);
+	}
+	free(iface->buffer);
+	free(iface->clientid);
+	free(iface);
+}
+
+int
+carrier_status(struct interface *iface)
+{
+	int ret;
+	struct ifreq ifr;
+#ifdef SIOCGIFMEDIA
+	struct ifmediareq ifmr;
+#endif
+#ifdef __linux__
+	char *p;
+#endif
+
+	memset(&ifr, 0, sizeof(ifr));
+	strlcpy(ifr.ifr_name, iface->name, sizeof(ifr.ifr_name));
+#ifdef __linux__
+	/* We can only test the real interface up */
+	if ((p = strchr(ifr.ifr_name, ':')))
+		*p = '\0';
+#endif
+
+	if (ioctl(socket_afnet, SIOCGIFFLAGS, &ifr) == -1)
+		return -1;
+	iface->flags = ifr.ifr_flags;
+
+	ret = -1;
+#ifdef SIOCGIFMEDIA
+	memset(&ifmr, 0, sizeof(ifmr));
+	strlcpy(ifmr.ifm_name, iface->name, sizeof(ifmr.ifm_name));
+	if (ioctl(socket_afnet, SIOCGIFMEDIA, &ifmr) != -1 &&
+	    ifmr.ifm_status & IFM_AVALID)
+		ret = (ifmr.ifm_status & IFM_ACTIVE) ? 1 : 0;
+#endif
+	if (ret == -1)
+		ret = (ifr.ifr_flags & IFF_RUNNING) ? 1 : 0;
+	return ret;
+}
+
+int
+up_interface(struct interface *iface)
+{
+	struct ifreq ifr;
+	int retval = -1;
+#ifdef __linux__
+	char *p;
+#endif
+
+	memset(&ifr, 0, sizeof(ifr));
+	strlcpy(ifr.ifr_name, iface->name, sizeof(ifr.ifr_name));
+#ifdef __linux__
+	/* We can only bring the real interface up */
+	if ((p = strchr(ifr.ifr_name, ':')))
+		*p = '\0';
+#endif
+	if (ioctl(socket_afnet, SIOCGIFFLAGS, &ifr) == 0) {
+		if ((ifr.ifr_flags & IFF_UP))
+			retval = 0;
+		else {
+			ifr.ifr_flags |= IFF_UP;
+			if (ioctl(socket_afnet, SIOCSIFFLAGS, &ifr) == 0)
+				retval = 0;
+		}
+		iface->flags = ifr.ifr_flags;
+	}
+	return retval;
+}
+
+struct interface *
+discover_interfaces(int argc, char * const *argv)
+{
+	struct ifaddrs *ifaddrs, *ifa;
+	char *p;
+	int i, sdl_type;
+	struct interface *ifp, *ifs, *ifl;
+#ifdef __linux__
+	char ifn[IF_NAMESIZE];
+#endif
+#ifdef AF_LINK
+	const struct sockaddr_dl *sdl;
+#ifdef IFLR_ACTIVE
+	struct if_laddrreq iflr;
+	int socket_aflink;
+
+	socket_aflink = socket(AF_LINK, SOCK_DGRAM, 0);
+	if (socket_aflink == -1)
+		return NULL;
+	memset(&iflr, 0, sizeof(iflr));
+#endif
+#elif AF_PACKET
+	const struct sockaddr_ll *sll;
+#endif
+
+	if (getifaddrs(&ifaddrs) == -1)
+		return NULL;
+
+	ifs = ifl = NULL;
+	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. */
+		for (ifp = ifs; ifp; ifp = ifp->next)
+			if (strcmp(ifp->name, ifa->ifa_name) == 0)
+				break;
+		if (ifp)
+			continue;
+		if (argc > 0) {
+			for (i = 0; i < argc; i++) {
+#ifdef __linux__
+				/* Check the real interface name */
+				strlcpy(ifn, argv[i], sizeof(ifn));
+				p = strchr(ifn, ':');
+				if (p)
+					*p = '\0';
+				if (strcmp(ifn, ifa->ifa_name) == 0)
+					break;
+#else
+				if (strcmp(argv[i], ifa->ifa_name) == 0)
+					break;
+#endif
+			}
+			if (i == argc)
+				continue;
+			p = argv[i];
+		} else {
+			/* -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;
+			for (i = 0; i < ifdc; i++)
+				if (!fnmatch(ifdv[i], ifa->ifa_name, 0))
+					break;
+			if (i < ifdc)
+				continue;
+			for (i = 0; i < ifac; i++)
+				if (!fnmatch(ifav[i], ifa->ifa_name, 0))
+					break;
+			if (ifac && i == ifac)
+				continue;
+			p = ifa->ifa_name;
+		}
+		if ((ifp = init_interface(p)) == NULL)
+			continue;
+
+		/* Bring the interface up if not already */
+		if (!(ifp->flags & IFF_UP)
+#ifdef SIOCGIFMEDIA
+		    && carrier_status(ifp) != -1
+#endif
+		   )
+		{
+			if (up_interface(ifp) == 0)
+				options |= DHCPCD_WAITUP;
+			else
+				syslog(LOG_ERR, "%s: up_interface: %m", ifp->name);
+		}
+
+		sdl_type = 0;
+		/* Don't allow loopback unless explicit */
+		if (ifp->flags & IFF_LOOPBACK) {
+			if (argc == 0 && ifac == 0) {
+				free_interface(ifp);
+				continue;
+			}
+		} else 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 = sdl->sdl_alen * NBBY;
+			if (ioctl(socket_aflink, SIOCGLIFADDR, &iflr) == -1 ||
+			    !(iflr.flags & IFLR_ACTIVE))
+			{
+				free_interface(ifp);
+				continue;
+			}
+#endif
+
+			sdl_type = sdl->sdl_type;
+			switch(sdl->sdl_type) {
+			case IFT_BRIDGE: /* FALLTHROUGH */
+			case IFT_L2VLAN: /* FALLTHOUGH */
+			case IFT_L3IPVLAN: /* FALLTHROUGH */
+			case IFT_ETHER:
+				ifp->family = ARPHRD_ETHER;
+				break;
+			case IFT_IEEE1394:
+				ifp->family = ARPHRD_IEEE1394;
+				break;
+#ifdef IFT_INFINIBAND
+			case IFT_INFINIBAND:
+				ifp->family = ARPHRD_INFINIBAND;
+				break;
+#endif
+			}
+			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->family = sdl_type = sll->sll_hatype;
+			ifp->hwlen = sll->sll_halen;
+			if (ifp->hwlen != 0)
+				memcpy(ifp->hwaddr, sll->sll_addr, ifp->hwlen);
+#endif
+		}
+
+		/* We only work on ethernet by default */
+		if (!(ifp->flags & IFF_POINTOPOINT) &&
+		    ifp->family != ARPHRD_ETHER)
+		{
+			if (argc == 0 && ifac == 0) {
+				free_interface(ifp);
+				continue;
+			}
+			switch (ifp->family) {
+			case ARPHRD_IEEE1394: /* FALLTHROUGH */
+			case ARPHRD_INFINIBAND:
+				/* We don't warn for supported families */
+				break;
+			default:
+				syslog(LOG_WARNING,
+				    "%s: unsupported interface type %.2x"
+				    ", falling back to ethernet",
+				    ifp->name, sdl_type);
+				ifp->family = ARPHRD_ETHER;
+				break;
+			}
+		}
+
+		/* Handle any platform init for the interface */
+		if (if_init(ifp) == -1) {
+			syslog(LOG_ERR, "%s: if_init: %m", p);
+			free_interface(ifp);
+			continue;
+		}
+
+		if (ifl)
+			ifl->next = ifp; 
+		else
+			ifs = ifp;
+		ifl = ifp;
+	}
+	freeifaddrs(ifaddrs);
+
+#ifdef IFLR_ACTIVE
+	close(socket_aflink);
+#endif
+
+	return ifs;
+}
+
+int
+do_address(const char *ifname,
+    struct in_addr *addr, struct in_addr *net, struct in_addr *dst, int act)
+{
+	struct ifaddrs *ifaddrs, *ifa;
+	const struct sockaddr_in *a, *n, *d;
+	int retval;
+
+	if (getifaddrs(&ifaddrs) == -1)
+		return -1;
+
+	retval = 0;
+	for (ifa = ifaddrs; ifa; ifa = ifa->ifa_next) {
+		if (ifa->ifa_addr == NULL ||
+		    ifa->ifa_addr->sa_family != AF_INET ||
+		    strcmp(ifa->ifa_name, ifname) != 0)
+			continue;
+		a = (const struct sockaddr_in *)(void *)ifa->ifa_addr;
+		n = (const struct sockaddr_in *)(void *)ifa->ifa_netmask;
+		if (ifa->ifa_flags & IFF_POINTOPOINT)
+			d = (const struct sockaddr_in *)(void *)
+			    ifa->ifa_dstaddr;
+		else
+			d = NULL;
+		if (act == 1) {
+			addr->s_addr = a->sin_addr.s_addr;
+			net->s_addr = n->sin_addr.s_addr;
+			if (dst) {
+				/* TODO: Fix getifaddrs() */
+				if ((ifa->ifa_flags & IFF_POINTOPOINT) && d)
+					dst->s_addr = d->sin_addr.s_addr;
+				else
+					dst->s_addr = INADDR_ANY;
+			}
+			retval = 1;
+			break;
+		}
+		if (addr->s_addr == a->sin_addr.s_addr &&
+		    (net == NULL || net->s_addr == n->sin_addr.s_addr))
+		{
+			retval = 1;
+			break;
+		}
+	}
+	freeifaddrs(ifaddrs);
+	return retval;
+}
+
+int
+do_mtu(const char *ifname, short int mtu)
+{
+	struct ifreq ifr;
+	int r;
+
+	memset(&ifr, 0, sizeof(ifr));
+	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+	ifr.ifr_mtu = mtu;
+	r = ioctl(socket_afnet, mtu ? SIOCSIFMTU : SIOCGIFMTU, &ifr);
+	if (r == -1)
+		return -1;
+	return ifr.ifr_mtu;
+}
+
+void
+free_routes(struct rt *routes)
+{
+	struct rt *r;
+
+	while (routes) {
+		r = routes->next;
+		free(routes);
+		routes = r;
+	}
+}
+
+int
+open_udp_socket(struct interface *iface)
+{
+	int s;
+	struct sockaddr_in sin;
+	int n;
+#ifdef SO_BINDTODEVICE
+	struct ifreq ifr;
+	char *p;
+#endif
+
+	if ((s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
+		return -1;
+
+	n = 1;
+	if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n)) == -1)
+		goto eexit;
+#ifdef SO_BINDTODEVICE
+	memset(&ifr, 0, sizeof(ifr));
+	strlcpy(ifr.ifr_name, iface->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
+	/* As we don't use this socket for receiving, set the
+	 * receive buffer to 1 */
+	n = 1;
+	if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &n, sizeof(n)) == -1)
+		goto eexit;
+	memset(&sin, 0, sizeof(sin));
+	sin.sin_family = AF_INET;
+	sin.sin_port = htons(DHCP_CLIENT_PORT);
+	sin.sin_addr.s_addr = iface->addr.s_addr;
+	if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) == -1)
+		goto eexit;
+
+	iface->udp_fd = s;
+	set_cloexec(s);
+	return 0;
+
+eexit:
+	close(s);
+	return -1;
+}
+
+ssize_t
+send_packet(const struct interface *iface, struct in_addr to,
+    const uint8_t *data, ssize_t len)
+{
+	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);
+	return sendto(iface->udp_fd, data, len, 0,
+	    (struct sockaddr *)&sin, sizeof(sin));
+}
+
+struct udp_dhcp_packet
+{
+	struct ip ip;
+	struct udphdr udp;
+	struct dhcp_message dhcp;
+};
+const size_t udp_dhcp_len = sizeof(struct udp_dhcp_packet);
+
+static uint16_t
+checksum(const void *data, uint16_t len)
+{
+	const uint8_t *addr = data;
+	uint32_t sum = 0;
+
+	while (len > 1) {
+		sum += addr[0] * 256 + addr[1];
+		addr += 2;
+		len -= 2;
+	}
+
+	if (len == 1)
+		sum += *addr * 256;
+
+	sum = (sum >> 16) + (sum & 0xffff);
+	sum += (sum >> 16);
+
+	sum = htons(sum);
+
+	return ~sum;
+}
+
+ssize_t
+make_udp_packet(uint8_t **packet, 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 = xzalloc(sizeof(*udpp));
+	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(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 = arc4random() & UINT16_MAX;
+	ip->ip_ttl = IPDEFTTL;
+	ip->ip_len = htons(sizeof(*ip) + sizeof(*udp) + length);
+	ip->ip_sum = checksum(ip, sizeof(*ip));
+
+	*packet = (uint8_t *)udpp;
+	return sizeof(*ip) + sizeof(*udp) + length;
+}
+
+ssize_t
+get_udp_data(const uint8_t **data, const uint8_t *udp)
+{
+	struct udp_dhcp_packet packet;
+
+	memcpy(&packet, udp, sizeof(packet));
+	*data = udp + offsetof(struct udp_dhcp_packet, dhcp);
+	return ntohs(packet.ip.ip_len) -
+	    sizeof(packet.ip) -
+	    sizeof(packet.udp);
+}
+
+int
+valid_udp_packet(const uint8_t *data, size_t data_len, struct in_addr *from,
+    int noudpcsum)
+{
+	struct udp_dhcp_packet packet;
+	uint16_t bytes, udpsum;
+
+	if (data_len < sizeof(packet.ip)) {
+		if (from)
+			from->s_addr = INADDR_ANY;
+		errno = EINVAL;
+		return -1;
+	}
+	memcpy(&packet, data, MIN(data_len, sizeof(packet)));
+	if (from)
+		from->s_addr = packet.ip.ip_src.s_addr;
+	if (data_len > sizeof(packet)) {
+		errno = EINVAL;
+		return -1;
+	}
+	if (checksum(&packet.ip, sizeof(packet.ip)) != 0) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	bytes = ntohs(packet.ip.ip_len);
+	if (data_len < bytes) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	if (noudpcsum == 0) {
+		udpsum = packet.udp.uh_sum;
+		packet.udp.uh_sum = 0;
+		packet.ip.ip_hl = 0;
+		packet.ip.ip_v = 0;
+		packet.ip.ip_tos = 0;
+		packet.ip.ip_len = packet.udp.uh_ulen;
+		packet.ip.ip_id = 0;
+		packet.ip.ip_off = 0;
+		packet.ip.ip_ttl = 0;
+		packet.ip.ip_sum = 0;
+		if (udpsum && checksum(&packet, bytes) != udpsum) {
+			errno = EINVAL;
+			return -1;
+		}
+	}
+
+	return 0;
+}
diff --git a/dhcpcd/net.h b/dhcpcd/net.h
new file mode 100644
index 0000000..f181798
--- /dev/null
+++ b/dhcpcd/net.h
@@ -0,0 +1,152 @@
+/* 
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2011 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 <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
+#include <limits.h>
+
+#include "config.h"
+#include "dhcp.h"
+#include "dhcpcd.h"
+
+#ifndef DUID_LEN
+#  define DUID_LEN			128 + 2
+#endif
+
+#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
+
+struct rt {
+	struct in_addr dest;
+	struct in_addr net;
+	struct in_addr gate;
+	const struct interface *iface;
+	int metric;
+	struct in_addr src;
+	struct rt *next;
+};
+
+extern int socket_afnet;
+
+uint32_t get_netmask(uint32_t);
+char *hwaddr_ntoa(const unsigned char *, size_t);
+size_t hwaddr_aton(unsigned char *, const char *);
+
+int getifssid(const char *, char *);
+struct interface *init_interface(const char *);
+struct interface *discover_interfaces(int, char * const *);
+void free_interface(struct interface *);
+int do_mtu(const char *, short int);
+#define get_mtu(iface) do_mtu(iface, 0)
+#define set_mtu(iface, mtu) do_mtu(iface, mtu)
+
+int inet_ntocidr(struct in_addr);
+int inet_cidrtoaddr(int, struct in_addr *);
+
+int up_interface(struct interface *);
+int if_conf(struct interface *);
+int if_init(struct interface *);
+
+int do_address(const char *,
+    struct in_addr *, struct in_addr *, struct in_addr *, int);
+int if_address(const struct interface *,
+    const struct in_addr *, const struct in_addr *,
+    const struct in_addr *, int);
+#define add_address(iface, addr, net, brd)				      \
+	if_address(iface, addr, net, brd, 1)
+#define del_address(iface, addr, net)					      \
+	if_address(iface, addr, net, NULL, -1)
+#define has_address(iface, addr, net)					      \
+	do_address(iface, addr, net, NULL, 0)
+#define get_address(iface, addr, net, dst)				      \
+	do_address(iface, addr, net, dst, 1)
+
+int if_route(const struct rt *rt, int);
+#define add_route(rt) if_route(rt, 1)
+#define change_route(rt) if_route(rt, 0)
+#define del_route(rt) if_route(rt, -1)
+#define del_src_route(rt) if_route(rt, -2);
+void free_routes(struct rt *);
+
+int open_udp_socket(struct interface *);
+extern const size_t udp_dhcp_len;
+ssize_t make_udp_packet(uint8_t **, const uint8_t *, size_t,
+    struct in_addr, struct in_addr);
+ssize_t get_udp_data(const uint8_t **, const uint8_t *);
+int valid_udp_packet(const uint8_t *, size_t, struct in_addr *, int);
+
+int open_socket(struct interface *, int);
+ssize_t send_packet(const struct interface *, struct in_addr, 
+    const uint8_t *, ssize_t);
+ssize_t send_raw_packet(const struct interface *, int,
+    const void *, ssize_t);
+ssize_t get_raw_packet(struct interface *, int, void *, ssize_t, int *);
+
+int init_sockets(void);
+int open_link_socket(void);
+int manage_link(int);
+int carrier_status(struct interface *);
+#endif
diff --git a/dhcpcd/platform-bsd.c b/dhcpcd/platform-bsd.c
new file mode 100644
index 0000000..afa4384
--- /dev/null
+++ b/dhcpcd/platform-bsd.c
@@ -0,0 +1,89 @@
+/* 
+ * 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.
+ */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+#include <sys/utsname.h>
+#include <netinet/in.h>
+
+#include <syslog.h>
+
+#include "platform.h"
+
+#ifndef SYS_NMLN	/* OSX */
+#  define SYS_NMLN 256
+#endif
+
+static char march[SYS_NMLN];
+
+char *
+hardware_platform(void)
+{
+	int mib[2] = { CTL_HW, HW_MACHINE_ARCH };
+	size_t len = sizeof(march);
+
+	if (sysctl(mib, sizeof(mib) / sizeof(mib[0]),
+		march, &len, NULL, 0) != 0)
+		return NULL;
+	return march;
+}
+
+static int
+inet6_sysctl(int code)
+{
+	int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, 0 };
+	int val;
+	size_t size;
+
+	mib[3] = code;
+	size = sizeof(val);
+	if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), &val, &size, NULL, 0) == -1)
+		return -1;
+	return val;
+}
+
+int
+check_ipv6(const char *ifname)
+{
+
+	/* BSD doesn't support these values per iface, so just reutrn 1 */
+	if (ifname)
+		return 1;
+
+	if (inet6_sysctl(IPV6CTL_ACCEPT_RTADV) != 1) {
+		syslog(LOG_WARNING,
+		    "Kernel is not configured to accept IPv6 RAs");
+		return 0;
+	}
+	if (inet6_sysctl(IPV6CTL_FORWARDING) != 0) {
+		syslog(LOG_WARNING,
+		    "Kernel is configured as a router, not a host");
+		return 0;
+	}
+	return 1;
+}
diff --git a/dhcpcd/platform-linux.c b/dhcpcd/platform-linux.c
new file mode 100644
index 0000000..119ec50
--- /dev/null
+++ b/dhcpcd/platform-linux.c
@@ -0,0 +1,153 @@
+/* 
+ * 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.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+
+#include "common.h"
+#include "platform.h"
+
+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
+	;
+
+char *
+hardware_platform(void)
+{
+	FILE *fp;
+	char *buf, *p;
+
+	if (mproc == NULL) {
+		errno = EINVAL;
+		return NULL;
+	}
+
+	fp = fopen("/proc/cpuinfo", "r");
+	if (fp == NULL)
+		return NULL;
+
+	p = NULL;
+	while ((buf = get_line(fp))) {
+		if (strncmp(buf, mproc, strlen(mproc)) == 0) {
+			p = strchr(buf, ':');
+			if (p != NULL && ++p != NULL) {
+				while (*p == ' ')
+					p++;
+				break;
+			}
+		}
+	}
+	fclose(fp);
+
+	if (p == NULL)
+		errno = ESRCH;
+	return p;
+}
+
+static int
+check_proc_int(const char *path)
+{
+	FILE *fp;
+	char *buf;
+
+	fp = fopen(path, "r");
+	if (fp == NULL)
+		return -1;
+	buf = get_line(fp);
+	fclose(fp);
+	if (buf == NULL)
+		return -1;
+	return atoi(buf);
+}
+
+static const char *prefix = "/proc/sys/net/ipv6/conf";
+
+int
+check_ipv6(const char *ifname)
+{
+	int r;
+	char path[256];
+
+	if (ifname == NULL)
+		ifname = "all";
+
+	snprintf(path, sizeof(path), "%s/%s/accept_ra", prefix, ifname);
+	r = check_proc_int(path);
+	if (r != 1 && r != 2) {
+		syslog(LOG_WARNING,
+		    "%s: not configured to accept IPv6 RAs", ifname);
+		return 0;
+	}
+
+	if (r != 2) {
+		snprintf(path, sizeof(path), "%s/%s/forwarding",
+		    prefix, ifname);
+		if (check_proc_int(path) != 0) {
+			syslog(LOG_WARNING,
+			    "%s: configured as a router, not a host", ifname);
+			return 0;
+		}
+	}
+	return 1;
+}
diff --git a/dhcpcd/platform.h b/dhcpcd/platform.h
new file mode 100644
index 0000000..08ec368
--- /dev/null
+++ b/dhcpcd/platform.h
@@ -0,0 +1,34 @@
+/* 
+ * 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 PLATFORM_H
+#define PLATFORM_H
+
+char *hardware_platform(void);
+int check_ipv6(const char *);
+
+#endif
diff --git a/dhcpcd/showlease.c b/dhcpcd/showlease.c
new file mode 100644
index 0000000..1257337
--- /dev/null
+++ b/dhcpcd/showlease.c
@@ -0,0 +1,355 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "dhcp.h"
+#include "config.h"
+
+#ifndef DEFAULT_LEASETIME
+#define DEFAULT_LEASETIME	3600	/* 1 hour */
+#endif
+
+#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 IPV4	(1 << 6)
+#define STRING	(1 << 7)
+#define PAIR	(1 << 8)
+#define ARRAY	(1 << 9)
+#define RFC3361	(1 << 10)
+#define RFC3397	(1 << 11)
+#define RFC3442 (1 << 12)
+
+struct dhcp_opt {
+	uint8_t option;
+	int type;
+	const char *var;
+};
+
+static const struct dhcp_opt const dhcp_opts[] = {
+	{ 1,	IPV4 | REQUEST,	"subnet_mask" },
+	{ 2,	UINT32,		"time_offset" },
+	{ 3,	IPV4 | ARRAY | REQUEST,	"routers" },
+	{ 4,	IPV4 | ARRAY,	"time_servers" },
+	{ 5,	IPV4 | ARRAY,	"ien116_name_servers" },
+	{ 6,	IPV4 | ARRAY,	"domain_name_servers" },
+	{ 7,	IPV4 | ARRAY,	"log_servers" },
+	{ 8,	IPV4 | ARRAY,	"cookie_servers" },
+	{ 9, 	IPV4 | ARRAY,	"lpr_servers" },
+	{ 10,	IPV4 | ARRAY,	"impress_servers" },
+	{ 11,	IPV4 | ARRAY,	"resource_location_servers" },
+	{ 12,	STRING,		"host_name" },
+	{ 13,	UINT16,		"boot_size" },
+	{ 14,	STRING,		"merit_dump" },
+	{ 15,	STRING,		"domain_name" },
+	{ 16,	IPV4,		"swap_server" },
+	{ 17,	STRING,		"root_path" },
+	{ 18,	STRING,		"extensions_path" },
+	{ 19,	UINT8,		"ip_forwarding" },
+	{ 20,	UINT8,		"non_local_source_routing" },
+	{ 21,	IPV4 | ARRAY,	"policy_filter" },
+	{ 22,	SINT16,		"max_dgram_reassembly" },
+	{ 23,	UINT16,		"default_ip_ttl" },
+	{ 24,	UINT32,		"path_mtu_aging_timeout" },
+	{ 25,	UINT16 | ARRAY,	"path_mtu_plateau_table" },
+	{ 26,	UINT16,		"interface_mtu" },
+	{ 27,	UINT8,		"all_subnets_local" },
+	{ 28,	IPV4 | REQUEST,	"broadcast_address" },
+	{ 29,	UINT8,		"perform_mask_discovery" },
+	{ 30,	UINT8,		"mask_supplier" },
+	{ 31,	UINT8,		"router_discovery" },
+	{ 32,	IPV4,		"router_solicitation_address" },
+	{ 33,	IPV4 | ARRAY | REQUEST,	"static_routes" },
+	{ 34,	UINT8,		"trailer_encapsulation" },
+	{ 35, 	UINT32,		"arp_cache_timeout" },
+	{ 36,	UINT16,		"ieee802_3_encapsulation" },
+	{ 37,	UINT8,		"default_tcp_ttl" },
+	{ 38,	UINT32,		"tcp_keepalive_interval" },
+	{ 39,	UINT8,		"tcp_keepalive_garbage" },
+	{ 40,	STRING,		"nis_domain" },
+	{ 41,	IPV4 | ARRAY,	"nis_servers" },
+	{ 42,	IPV4 | ARRAY,	"ntp_servers" },
+	{ 43,	STRING,		"vendor_encapsulated_options" },
+	{ 44,	IPV4 | ARRAY,	"netbios_name_servers" },
+	{ 45,	IPV4,		"netbios_dd_server" },
+	{ 46,	UINT8,		"netbios_node_type" },
+	{ 47,	STRING,		"netbios_scope" },
+	{ 48,	IPV4 | ARRAY,	"font_servers" },
+	{ 49,	IPV4 | ARRAY,	"x_display_manager" },
+	{ 50, 	IPV4,		"dhcp_requested_address" },
+	{ 51,	UINT32 | REQUEST,	"dhcp_lease_time" },
+	{ 52,	UINT8,		"dhcp_option_overload" },
+	{ 53,	UINT8,		"dhcp_message_type" },
+	{ 54,	IPV4,		"dhcp_server_identifier" },
+	{ 55,	UINT8 | ARRAY,	"dhcp_parameter_request_list" },
+	{ 56,	STRING,		"dhcp_message" },
+	{ 57,	UINT16,		"dhcp_max_message_size" },
+	{ 58,	UINT32 | REQUEST,	"dhcp_renewal_time" },
+	{ 59,	UINT32 | REQUEST,	"dhcp_rebinding_time" },
+	{ 64,	STRING,		"nisplus_domain" },
+	{ 65,	IPV4 | ARRAY,	"nisplus_servers" },
+	{ 66,	STRING,		"tftp_server_name" },
+	{ 67,	STRING,		"bootfile_name" },
+	{ 68,	IPV4 | ARRAY,	"mobile_ip_home_agent" },
+	{ 69,	IPV4 | ARRAY,	"smtp_server" },
+	{ 70,	IPV4 | ARRAY,	"pop_server" },
+	{ 71,	IPV4 | ARRAY,	"nntp_server" },
+	{ 72,	IPV4 | ARRAY,	"www_server" },
+	{ 73,	IPV4 | ARRAY,	"finger_server" },
+	{ 74,	IPV4 | ARRAY,	"irc_server" },
+	{ 75,	IPV4 | ARRAY,	"streettalk_server" },
+	{ 76,	IPV4 | ARRAY,	"streettalk_directory_assistance_server" },
+	{ 77,	STRING,		"user_class" },
+	{ 85,	IPV4 | ARRAY,	"nds_servers" },
+	{ 86,	STRING,		"nds_tree_name" },
+	{ 87,	STRING,		"nds_context" },
+	{ 88,	STRING | RFC3397,	"bcms_controller_names" },
+	{ 89,	IPV4 | ARRAY,	"bcms_controller_address" },
+	{ 91,	UINT32,		"client_last_transaction_time" },
+	{ 92,	IPV4 | ARRAY,	"associated_ip" },
+	{ 98,	STRING,		"uap_servers" },
+	{ 112,	IPV4 | ARRAY,	"netinfo_server_address" },
+	{ 113,	STRING,		"netinfo_server_tag" },
+	{ 114,	STRING,		"default_url" },
+	{ 118,	IPV4,		"subnet_selection" },
+	{ 119,	STRING | RFC3397,	"domain_search" },
+	{ 121,  RFC3442 | REQUEST,	"classless_static_routes" },
+	{ 249,  RFC3442,	"ms-classless_static_routes" },
+	{ 0, 0, NULL }
+};
+
+struct dhcp_message *
+get_lease_from_file(const char *leasefile)
+{
+	int fd;
+	struct dhcp_message *dhcp;
+	ssize_t bytes;
+
+	fd = open(leasefile, O_RDONLY);
+	if (fd == -1)
+		return NULL;
+	dhcp = malloc(sizeof(*dhcp));
+	memset(dhcp, 0, sizeof(*dhcp));
+	bytes = read(fd, dhcp, sizeof(*dhcp));
+	close(fd);
+	if (bytes < 0) {
+		free(dhcp);
+		dhcp = NULL;
+	}
+	return dhcp;
+}
+
+static uint8_t *dhcp_opt_buffer = NULL;
+
+static int
+valid_length(uint8_t option, int dl, int *type)
+{
+	const struct dhcp_opt *opt;
+	ssize_t sz;
+
+	if (dl == 0)
+		return -1;
+
+	for (opt = dhcp_opts; opt->option; opt++) {
+		if (opt->option != option)
+			continue;
+
+		if (type)
+			*type = opt->type;
+
+		if (opt->type == 0 || opt->type & STRING || opt->type & RFC3442)
+			return 0;
+
+		sz = 0;
+		if (opt->type & UINT32 || opt->type & IPV4)
+			sz = sizeof(uint32_t);
+		if (opt->type & UINT16)
+			sz = sizeof(uint16_t);
+		if (opt->type & UINT8)
+			sz = sizeof(uint8_t);
+		if (opt->type & IPV4 || opt->type & ARRAY)
+			return dl % sz;
+		return (dl == sz ? 0 : -1);
+	}
+
+	/* unknown option, so let it pass */
+	return 0;
+}
+
+static void
+free_option_buffer(void)
+{
+	free(dhcp_opt_buffer);
+}
+
+
+#define get_option_raw(dhcp, opt) get_option(dhcp, opt, NULL, NULL)
+static const uint8_t *
+get_option(const struct dhcp_message *dhcp, uint8_t opt, int *len, int *type)
+{
+	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;
+	int bl = 0;
+
+	while (p < e) {
+		o = *p++;
+		if (o == opt) {
+			if (op) {
+				if (!dhcp_opt_buffer) {
+					dhcp_opt_buffer = malloc(sizeof(struct dhcp_message));
+					atexit(free_option_buffer);
+				}
+				if (!bp) 
+					bp = dhcp_opt_buffer;
+				memcpy(bp, op, ol);
+				bp += ol;
+			}
+			ol = *p;
+			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 &= ~1;
+				p = dhcp->bootfile;
+				e = p + sizeof(dhcp->bootfile);
+			} else if (overl & 2) {
+				/* bit 2 set means parse server name */
+				overl &= ~2;
+				p = dhcp->servername;
+				e = p + sizeof(dhcp->servername);
+			} else
+				goto exit;
+			break;
+		case DHO_OPTIONSOVERLOADED:
+			/* Ensure we only get this option once */
+			if (!overl)
+				overl = p[1];
+			break;
+		}
+		l = *p++;
+		p += l;
+	}
+
+exit:
+	if (valid_length(o, bl, type) == -1) {
+		errno = EINVAL;
+		return NULL;
+	}
+	if (len)
+		*len = bl;
+	if (bp) {
+		memcpy(bp, op, ol);
+		return (const uint8_t *)&dhcp_opt_buffer;
+	}
+	if (op)
+		return op;
+	errno = ENOENT;
+	return NULL;
+}
+
+int
+get_option_addr32(uint32_t *a, const struct dhcp_message *dhcp, uint8_t option)
+{
+	const uint8_t *p = get_option_raw(dhcp, option);
+
+	if (!p)
+		return -1;
+	memcpy(a, p, sizeof(*a));
+	return 0;
+}
+
+int
+get_option_uint32(uint32_t *i, const struct dhcp_message *dhcp, uint8_t option)
+{
+	uint32_t a;
+
+	if (get_option_addr32(&a, dhcp, option) == -1)
+		return -1;
+
+	*i = ntohl(a);
+	return 0;
+}
+
+uint32_t
+get_netmask(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;
+}
+
+void showlease(struct dhcp_lease *lease)
+{
+    printf("addr:      %s\n", inet_ntoa(lease->addr));
+    printf("net:       %s\n", inet_ntoa(lease->net));
+    printf("leasetime: %d\n", lease->leasetime);
+    printf("renew:     %d\n", lease->renewaltime);
+    printf("rebind:    %d\n", lease->rebindtime);
+    printf("server:    %s\n", inet_ntoa(lease->server));
+}
+#define MAX_LEASETIME 2147460
+
+int
+main(int argc, char *argv[])
+{
+    struct dhcp_message *dhcp;
+    struct dhcp_lease *lease;
+    char leasefile[PATH_MAX];
+
+    if (argc < 2) {
+        fprintf(stderr, "Usage: %s <interface>\n", argv[0]);
+        exit(1);
+    }
+    snprintf(leasefile, PATH_MAX, LEASEFILE, argv[1]);
+    if ((dhcp = get_lease_from_file(leasefile)) == NULL) {
+        fprintf(stderr, "Couldn't read lease file: %s\n", strerror(errno));
+        exit(1);
+    }
+    lease = malloc(sizeof(*lease));
+    lease->frominfo = 0;
+    lease->addr.s_addr = dhcp->yiaddr;
+
+    if (get_option_addr32(&lease->net.s_addr, dhcp, DHO_SUBNETMASK) == -1)
+        lease->net.s_addr = get_netmask(dhcp->yiaddr);
+    if (get_option_uint32(&lease->leasetime, dhcp, DHO_LEASETIME) != 0)
+        lease->leasetime = DEFAULT_LEASETIME;
+    get_option_addr32(&lease->server.s_addr, dhcp, DHO_SERVERID);
+    /* Dm: limit lease time value to avoid negative numbers when
+       converting to milliseconds */		
+    if ((lease->leasetime != ~0U) && (lease->leasetime > MAX_LEASETIME))
+        lease->leasetime = MAX_LEASETIME;
+    if (get_option_uint32(&lease->renewaltime, dhcp, DHO_RENEWALTIME) != 0)
+        lease->renewaltime = 0;
+    if (get_option_uint32(&lease->rebindtime, dhcp, DHO_REBINDTIME) != 0)
+        lease->rebindtime = 0;
+    showlease(lease);
+    free(lease);
+    return 0;
+}
diff --git a/dhcpcd/signals.c b/dhcpcd/signals.c
new file mode 100644
index 0000000..fd3b0c3
--- /dev/null
+++ b/dhcpcd/signals.c
@@ -0,0 +1,124 @@
+/* 
+ * 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 <sys/socket.h>
+
+#include <errno.h>
+#include <signal.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include "common.h"
+#include "signals.h"
+
+static int signal_pipe[2];
+
+static const int handle_sigs[] = {
+	SIGALRM,
+	SIGHUP,
+	SIGINT,
+	SIGPIPE,
+	SIGTERM,
+	SIGUSR1,
+};
+
+static void
+signal_handler(int sig)
+{
+	int serrno = errno;
+
+	if (write(signal_pipe[1], &sig, sizeof(sig)) != sizeof(sig))
+		syslog(LOG_ERR, "failed to write signal %d: %m", sig);
+	/* Restore errno */
+	errno = serrno;
+}
+
+/* Read a signal from the signal pipe. Returns 0 if there is
+ * no signal, -1 on error (and sets errno appropriately), and
+ * your signal on success */
+int
+signal_read(void)
+{
+	int sig = -1;
+	char buf[16];
+	ssize_t bytes;
+
+	memset(buf, 0, sizeof(buf));
+	bytes = read(signal_pipe[0], buf, sizeof(buf));
+	if (bytes >= 0 && (size_t)bytes >= sizeof(sig))
+		memcpy(&sig, buf, sizeof(sig));
+	return sig;
+}
+
+/* Call this before doing anything else. Sets up the socket pair
+ * and installs the signal handler */
+int
+signal_init(void)
+{
+	if (pipe(signal_pipe) == -1)
+		return -1;
+	/* Don't block on read */
+	if (set_nonblock(signal_pipe[0]) == -1)
+		return -1;
+	/* Stop any scripts from inheriting us */
+	if (set_cloexec(signal_pipe[0]) == -1)
+		return -1;
+	if (set_cloexec(signal_pipe[1]) == -1)
+		return -1;
+	return signal_pipe[0];
+}
+
+static int
+signal_handle(void (*func)(int))
+{
+	unsigned int i;
+	struct sigaction sa;
+
+	memset(&sa, 0, sizeof(sa));
+	sa.sa_handler = func;
+	sigemptyset(&sa.sa_mask);
+
+	for (i = 0; i < sizeof(handle_sigs) / sizeof(handle_sigs[0]); i++)
+		if (sigaction(handle_sigs[i], &sa, NULL) == -1)
+			return -1;
+	return 0;
+}
+
+int
+signal_setup(void)
+{
+	return signal_handle(signal_handler);
+}
+
+int
+signal_reset(void)
+{
+	return signal_handle(SIG_DFL);
+}
+
diff --git a/dhcpcd/signals.h b/dhcpcd/signals.h
new file mode 100644
index 0000000..7098cfb
--- /dev/null
+++ b/dhcpcd/signals.h
@@ -0,0 +1,36 @@
+/* 
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2008 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 SIGNAL_H
+#define SIGNAL_H
+
+int signal_init(void);
+int signal_setup(void);
+int signal_reset(void);
+int signal_read(void);
+
+#endif