[rtems-libbsd commit] dhclient: New files

Joel Sherrill joel at rtems.org
Thu Sep 6 18:04:08 UTC 2012


Module:    rtems-libbsd
Branch:    master
Commit:    e1fc84b98d2d1a12c7c5e25ede00ae62e7bd5beb
Changeset: http://git.rtems.org/rtems-libbsd/commit/?id=e1fc84b98d2d1a12c7c5e25ede00ae62e7bd5beb

Author:    Joel Sherrill <joel.sherrill at oarcorp.com>
Date:      Thu Sep  6 13:08:06 2012 -0500

dhclient: New files

---

 freebsd-userspace/Makefile                         |   18 +
 freebsd-userspace/commands/sbin/dhclient/alloc.c   |   79 +
 freebsd-userspace/commands/sbin/dhclient/bpf.c     |  416 +++
 freebsd-userspace/commands/sbin/dhclient/clparse.c |  943 +++++++
 freebsd-userspace/commands/sbin/dhclient/conflex.c |  529 ++++
 freebsd-userspace/commands/sbin/dhclient/convert.c |  117 +
 .../commands/sbin/dhclient/dhclient-script         |  384 +++
 .../commands/sbin/dhclient/dhclient-script.8       |  297 +++
 .../commands/sbin/dhclient/dhclient.8              |  191 ++
 .../commands/sbin/dhclient/dhclient.c              | 2669 ++++++++++++++++++++
 .../commands/sbin/dhclient/dhclient.conf           |   39 +
 .../commands/sbin/dhclient/dhclient.conf.5         |  544 ++++
 .../commands/sbin/dhclient/dhclient.leases.5       |   95 +
 .../commands/sbin/dhclient/dhcp-options.5          |  606 +++++
 freebsd-userspace/commands/sbin/dhclient/dhcp.h    |  183 ++
 freebsd-userspace/commands/sbin/dhclient/dhcpd.h   |  440 ++++
 .../commands/sbin/dhclient/dhctoken.h              |  136 +
 .../commands/sbin/dhclient/dispatch.c              |  507 ++++
 freebsd-userspace/commands/sbin/dhclient/errwarn.c |  237 ++
 freebsd-userspace/commands/sbin/dhclient/hash.c    |  122 +
 freebsd-userspace/commands/sbin/dhclient/inet.c    |  121 +
 freebsd-userspace/commands/sbin/dhclient/options.c |  720 ++++++
 freebsd-userspace/commands/sbin/dhclient/packet.c  |  267 ++
 freebsd-userspace/commands/sbin/dhclient/parse.c   |  580 +++++
 freebsd-userspace/commands/sbin/dhclient/privsep.c |  238 ++
 freebsd-userspace/commands/sbin/dhclient/privsep.h |   47 +
 freebsd-userspace/commands/sbin/dhclient/tables.c  |  446 ++++
 freebsd-userspace/commands/sbin/dhclient/tree.c    |   59 +
 freebsd-userspace/commands/sbin/dhclient/tree.h    |   66 +
 29 files changed, 11096 insertions(+), 0 deletions(-)

diff --git a/freebsd-userspace/Makefile b/freebsd-userspace/Makefile
index 9869d8c..8e5cc2f 100644
--- a/freebsd-userspace/Makefile
+++ b/freebsd-userspace/Makefile
@@ -89,6 +89,24 @@ C_FILES += commands/sbin/ping6/ping6.c
 # route command sources
 C_FILES += commands/sbin/route/route.c
 
+# dhclient command sources
+C_FILES += commands/sbin/dhclient/alloc.c
+C_FILES += commands/sbin/dhclient/bpf.c
+C_FILES += commands/sbin/dhclient/clparse.c
+C_FILES += commands/sbin/dhclient/conflex.c
+C_FILES += commands/sbin/dhclient/convert.c
+C_FILES += commands/sbin/dhclient/dhclient.c
+C_FILES += commands/sbin/dhclient/dispatch.c
+C_FILES += commands/sbin/dhclient/errwarn.c
+C_FILES += commands/sbin/dhclient/hash.c
+C_FILES += commands/sbin/dhclient/inet.c
+C_FILES += commands/sbin/dhclient/options.c
+C_FILES += commands/sbin/dhclient/packet.c
+C_FILES += commands/sbin/dhclient/parse.c
+C_FILES += commands/sbin/dhclient/privsep.c
+C_FILES += commands/sbin/dhclient/tables.c
+C_FILES += commands/sbin/dhclient/tree.c
+
 C_O_FILES = $(C_FILES:%.c=%.o)
 C_D_FILES = $(C_FILES:%.c=%.d)
 
diff --git a/freebsd-userspace/commands/sbin/dhclient/alloc.c b/freebsd-userspace/commands/sbin/dhclient/alloc.c
new file mode 100644
index 0000000..cd60cec
--- /dev/null
+++ b/freebsd-userspace/commands/sbin/dhclient/alloc.c
@@ -0,0 +1,79 @@
+/*	$OpenBSD: alloc.c,v 1.9 2004/05/04 20:28:40 deraadt Exp $	*/
+
+/* Memory allocation... */
+
+/*
+ * Copyright (c) 1995, 1996, 1998 The Internet Software Consortium.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of The Internet Software Consortium nor the names
+ *    of its contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM 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 INTERNET SOFTWARE CONSORTIUM 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 software has been written for the Internet Software Consortium
+ * by Ted Lemon <mellon at fugue.com> in cooperation with Vixie
+ * Enterprises.  To learn more about the Internet Software Consortium,
+ * see ``http://www.vix.com/isc''.  To learn more about Vixie
+ * Enterprises, see ``http://www.vix.com''.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "dhcpd.h"
+
+struct string_list *
+new_string_list(size_t size)
+{
+	struct string_list *rval;
+
+	rval = calloc(1, sizeof(struct string_list) + size);
+	if (rval != NULL)
+		rval->string = ((char *)rval) + sizeof(struct string_list);
+	return (rval);
+}
+
+struct hash_table *
+new_hash_table(int count)
+{
+	struct hash_table *rval;
+
+	rval = calloc(1, sizeof(struct hash_table) -
+	    (DEFAULT_HASH_SIZE * sizeof(struct hash_bucket *)) +
+	    (count * sizeof(struct hash_bucket *)));
+	if (rval == NULL)
+		return (NULL);
+	rval->hash_count = count;
+	return (rval);
+}
+
+struct hash_bucket *
+new_hash_bucket(void)
+{
+	struct hash_bucket *rval = calloc(1, sizeof(struct hash_bucket));
+
+	return (rval);
+}
diff --git a/freebsd-userspace/commands/sbin/dhclient/bpf.c b/freebsd-userspace/commands/sbin/dhclient/bpf.c
new file mode 100644
index 0000000..7f87ddf
--- /dev/null
+++ b/freebsd-userspace/commands/sbin/dhclient/bpf.c
@@ -0,0 +1,416 @@
+/*	$OpenBSD: bpf.c,v 1.13 2004/05/05 14:28:58 deraadt Exp $	*/
+
+/* BPF socket interface code, originally contributed by Archie Cobbs. */
+
+/*
+ * Copyright (c) 1995, 1996, 1998, 1999
+ * The Internet Software Consortium.    All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of The Internet Software Consortium nor the names
+ *    of its contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM 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 INTERNET SOFTWARE CONSORTIUM 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 software has been written for the Internet Software Consortium
+ * by Ted Lemon <mellon at fugue.com> in cooperation with Vixie
+ * Enterprises.  To learn more about the Internet Software Consortium,
+ * see ``http://www.vix.com/isc''.  To learn more about Vixie
+ * Enterprises, see ``http://www.vix.com''.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "dhcpd.h"
+#include <sys/ioctl.h>
+#include <sys/uio.h>
+
+#ifdef __rtems__
+#include <freebsd/net/bpf.h>
+#include <freebsd/netinet/in_systm.h>
+#else
+#include <net/bpf.h>
+#include <netinet/in_systm.h>
+#endif
+#include <netinet/ip.h>
+#include <netinet/udp.h>
+#include <netinet/if_ether.h>
+
+#define BPF_FORMAT "/dev/bpf%d"
+
+/*
+ * Called by get_interface_list for each interface that's discovered.
+ * Opens a packet filter for each interface and adds it to the select
+ * mask.
+ */
+int
+if_register_bpf(struct interface_info *info)
+{
+	char filename[50];
+	int sock, b;
+
+	/* Open a BPF device */
+	for (b = 0; 1; b++) {
+		snprintf(filename, sizeof(filename), BPF_FORMAT, b);
+		sock = open(filename, O_RDWR, 0);
+		if (sock < 0) {
+			if (errno == EBUSY)
+				continue;
+			else
+				error("Can't find free bpf: %m");
+		} else
+			break;
+	}
+
+	/* Set the BPF device to point at this interface. */
+	if (ioctl(sock, BIOCSETIF, info->ifp) < 0)
+		error("Can't attach interface %s to bpf device %s: %m",
+		    info->name, filename);
+
+	return (sock);
+}
+
+void
+if_register_send(struct interface_info *info)
+{
+	int sock, on = 1;
+
+	/*
+	 * If we're using the bpf API for sending and receiving, we
+	 * don't need to register this interface twice.
+	 */
+	info->wfdesc = info->rfdesc;
+
+	/*
+	 * Use raw socket for unicast send.
+	 */
+	if ((sock = socket(AF_INET, SOCK_RAW, IPPROTO_UDP)) == -1)
+		error("socket(SOCK_RAW): %m");
+	if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, &on,
+	    sizeof(on)) == -1)
+		error("setsockopt(IP_HDRINCL): %m");
+	info->ufdesc = sock;
+}
+
+/*
+ * Packet filter program...
+ *
+ * XXX: Changes to the filter program may require changes to the
+ * constant offsets used in if_register_send to patch the BPF program!
+ */
+struct bpf_insn dhcp_bpf_filter[] = {
+	/* 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),
+
+	/* Make sure it's a UDP packet... */
+	BPF_STMT(BPF_LD + BPF_B + BPF_ABS, 23),
+	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_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 4, 0),
+
+	/* Get the IP header length... */
+	BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, 14),
+
+	/* Make sure it's to the right port... */
+	BPF_STMT(BPF_LD + BPF_H + BPF_IND, 16),
+	BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 67, 0, 1),		/* patch */
+
+	/* If we passed all the tests, ask for the whole packet. */
+	BPF_STMT(BPF_RET+BPF_K, (u_int)-1),
+
+	/* Otherwise, drop it. */
+	BPF_STMT(BPF_RET+BPF_K, 0),
+};
+
+int dhcp_bpf_filter_len = sizeof(dhcp_bpf_filter) / sizeof(struct bpf_insn);
+
+/*
+ * Packet write filter program:
+ * 'ip and udp and src port bootps and dst port (bootps or bootpc)'
+ */
+struct bpf_insn dhcp_bpf_wfilter[] = {
+	BPF_STMT(BPF_LD + BPF_B + BPF_IND, 14),
+	BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, (IPVERSION << 4) + 5, 0, 12),
+
+	/* 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, 10),
+
+	/* Make sure it's a UDP packet... */
+	BPF_STMT(BPF_LD + BPF_B + BPF_ABS, 23),
+	BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 8),
+
+	/* Make sure this isn't a fragment... */
+	BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 20),
+	BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 6, 0),	/* patched */
+
+	/* Get the IP header length... */
+	BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, 14),
+
+	/* Make sure it's from the right port... */
+	BPF_STMT(BPF_LD + BPF_H + BPF_IND, 14),
+	BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 68, 0, 3),
+
+	/* Make sure it is to the right ports ... */
+	BPF_STMT(BPF_LD + BPF_H + BPF_IND, 16),
+	BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 67, 0, 1),
+
+	/* If we passed all the tests, ask for the whole packet. */
+	BPF_STMT(BPF_RET+BPF_K, (u_int)-1),
+
+	/* Otherwise, drop it. */
+	BPF_STMT(BPF_RET+BPF_K, 0),
+};
+
+int dhcp_bpf_wfilter_len = sizeof(dhcp_bpf_wfilter) / sizeof(struct bpf_insn);
+
+void
+if_register_receive(struct interface_info *info)
+{
+	struct bpf_version v;
+	struct bpf_program p;
+	int flag = 1, sz;
+
+	/* Open a BPF device and hang it on this interface... */
+	info->rfdesc = if_register_bpf(info);
+
+	/* Make sure the BPF version is in range... */
+	if (ioctl(info->rfdesc, BIOCVERSION, &v) < 0)
+		error("Can't get BPF version: %m");
+
+	if (v.bv_major != BPF_MAJOR_VERSION ||
+	    v.bv_minor < BPF_MINOR_VERSION)
+		error("Kernel BPF version out of range - recompile dhcpd!");
+
+	/*
+	 * Set immediate mode so that reads return as soon as a packet
+	 * comes in, rather than waiting for the input buffer to fill
+	 * with packets.
+	 */
+	if (ioctl(info->rfdesc, BIOCIMMEDIATE, &flag) < 0)
+		error("Can't set immediate mode on bpf device: %m");
+
+	/* Get the required BPF buffer length from the kernel. */
+	if (ioctl(info->rfdesc, BIOCGBLEN, &sz) < 0)
+		error("Can't get bpf buffer length: %m");
+	info->rbuf_max = sz;
+	info->rbuf = malloc(info->rbuf_max);
+	if (!info->rbuf)
+		error("Can't allocate %lu bytes for bpf input buffer.",
+		    (unsigned long)info->rbuf_max);
+	info->rbuf_offset = 0;
+	info->rbuf_len = 0;
+
+	/* Set up the bpf filter program structure. */
+	p.bf_len = dhcp_bpf_filter_len;
+	p.bf_insns = dhcp_bpf_filter;
+
+	/* Patch the server port into the BPF program...
+	 *
+	 * XXX: changes to filter program may require changes to the
+	 * insn number(s) used below!
+	 */
+	dhcp_bpf_filter[8].k = LOCAL_PORT;
+
+	if (ioctl(info->rfdesc, BIOCSETF, &p) < 0)
+		error("Can't install packet filter program: %m");
+
+	/* Set up the bpf write filter program structure. */
+	p.bf_len = dhcp_bpf_wfilter_len;
+	p.bf_insns = dhcp_bpf_wfilter;
+
+	if (dhcp_bpf_wfilter[7].k == 0x1fff)
+		dhcp_bpf_wfilter[7].k = htons(IP_MF|IP_OFFMASK);
+
+	if (ioctl(info->rfdesc, BIOCSETWF, &p) < 0)
+		error("Can't install write filter program: %m");
+
+	if (ioctl(info->rfdesc, BIOCLOCK, NULL) < 0)
+		error("Cannot lock bpf");
+}
+
+ssize_t
+send_packet(struct interface_info *interface, struct dhcp_packet *raw,
+    size_t len, struct in_addr from, struct sockaddr_in *to,
+    struct hardware *hto)
+{
+	unsigned char buf[256];
+	struct iovec iov[2];
+	struct msghdr msg;
+	int result, bufp = 0;
+
+	/* Assemble the headers... */
+	if (to->sin_addr.s_addr == INADDR_BROADCAST)
+		assemble_hw_header(interface, buf, &bufp, hto);
+	assemble_udp_ip_header(buf, &bufp, from.s_addr,
+	    to->sin_addr.s_addr, to->sin_port, (unsigned char *)raw, len);
+
+	iov[0].iov_base = (char *)buf;
+	iov[0].iov_len = bufp;
+	iov[1].iov_base = (char *)raw;
+	iov[1].iov_len = len;
+
+	/* Fire it off */
+	if (to->sin_addr.s_addr == INADDR_BROADCAST)
+		result = writev(interface->wfdesc, iov, 2);
+	else {
+		memset(&msg, 0, sizeof(msg));
+		msg.msg_name = (struct sockaddr *)to;
+		msg.msg_namelen = sizeof(*to);
+		msg.msg_iov = iov;
+		msg.msg_iovlen = 2;
+		result = sendmsg(interface->ufdesc, &msg, 0);
+	}
+
+	if (result < 0)
+		warning("send_packet: %m");
+	return (result);
+}
+
+ssize_t
+receive_packet(struct interface_info *interface, unsigned char *buf,
+    size_t len, struct sockaddr_in *from, struct hardware *hfrom)
+{
+	int length = 0, offset = 0;
+	struct bpf_hdr hdr;
+
+	/*
+	 * All this complexity is because BPF doesn't guarantee that
+	 * only one packet will be returned at a time.  We're getting
+	 * what we deserve, though - this is a terrible abuse of the BPF
+	 * interface.  Sigh.
+	 */
+
+	/* Process packets until we get one we can return or until we've
+	 * done a read and gotten nothing we can return...
+	 */
+	do {
+		/* If the buffer is empty, fill it. */
+		if (interface->rbuf_offset >= interface->rbuf_len) {
+			length = read(interface->rfdesc, interface->rbuf,
+			    interface->rbuf_max);
+			if (length <= 0)
+				return (length);
+			interface->rbuf_offset = 0;
+			interface->rbuf_len = length;
+		}
+
+		/*
+		 * If there isn't room for a whole bpf header, something
+		 * went wrong, but we'll ignore it and hope it goes
+		 * away... XXX
+		 */
+		if (interface->rbuf_len - interface->rbuf_offset <
+		    sizeof(hdr)) {
+			interface->rbuf_offset = interface->rbuf_len;
+			continue;
+		}
+
+		/* Copy out a bpf header... */
+		memcpy(&hdr, &interface->rbuf[interface->rbuf_offset],
+		    sizeof(hdr));
+
+		/*
+		 * If the bpf header plus data doesn't fit in what's
+		 * left of the buffer, stick head in sand yet again...
+		 */
+		if (interface->rbuf_offset + hdr.bh_hdrlen + hdr.bh_caplen >
+		    interface->rbuf_len) {
+			interface->rbuf_offset = interface->rbuf_len;
+			continue;
+		}
+
+		/* Skip over the BPF header... */
+		interface->rbuf_offset += hdr.bh_hdrlen;
+
+		/*
+		 * If the captured data wasn't the whole packet, or if
+		 * the packet won't fit in the input buffer, all we can
+		 * do is drop it.
+		 */
+		if (hdr.bh_caplen != hdr.bh_datalen) {
+			interface->rbuf_offset =
+			    BPF_WORDALIGN(interface->rbuf_offset +
+			    hdr.bh_caplen);
+			continue;
+		}
+
+		/* Decode the physical header... */
+		offset = decode_hw_header(interface->rbuf,
+		    interface->rbuf_offset, hfrom);
+
+		/*
+		 * If a physical layer checksum failed (dunno of any
+		 * physical layer that supports this, but WTH), skip
+		 * this packet.
+		 */
+		if (offset < 0) {
+			interface->rbuf_offset =
+			    BPF_WORDALIGN(interface->rbuf_offset +
+			    hdr.bh_caplen);
+			continue;
+		}
+		interface->rbuf_offset += offset;
+		hdr.bh_caplen -= offset;
+
+		/* Decode the IP and UDP headers... */
+		offset = decode_udp_ip_header(interface->rbuf,
+		    interface->rbuf_offset, from, NULL, hdr.bh_caplen);
+
+		/* If the IP or UDP checksum was bad, skip the packet... */
+		if (offset < 0) {
+			interface->rbuf_offset =
+			    BPF_WORDALIGN(interface->rbuf_offset +
+			    hdr.bh_caplen);
+			continue;
+		}
+		interface->rbuf_offset += offset;
+		hdr.bh_caplen -= offset;
+
+		/*
+		 * If there's not enough room to stash the packet data,
+		 * we have to skip it (this shouldn't happen in real
+		 * life, though).
+		 */
+		if (hdr.bh_caplen > len) {
+			interface->rbuf_offset =
+			    BPF_WORDALIGN(interface->rbuf_offset +
+			    hdr.bh_caplen);
+			continue;
+		}
+
+		/* Copy out the data in the packet... */
+		memcpy(buf, interface->rbuf + interface->rbuf_offset,
+		    hdr.bh_caplen);
+		interface->rbuf_offset =
+		    BPF_WORDALIGN(interface->rbuf_offset +
+		    hdr.bh_caplen);
+		return (hdr.bh_caplen);
+	} while (!length);
+	return (0);
+}
diff --git a/freebsd-userspace/commands/sbin/dhclient/clparse.c b/freebsd-userspace/commands/sbin/dhclient/clparse.c
new file mode 100644
index 0000000..5d7084e
--- /dev/null
+++ b/freebsd-userspace/commands/sbin/dhclient/clparse.c
@@ -0,0 +1,943 @@
+/*	$OpenBSD: clparse.c,v 1.18 2004/09/15 18:15:18 henning Exp $	*/
+
+/* Parser for dhclient config and lease files... */
+
+/*
+ * Copyright (c) 1997 The Internet Software Consortium.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of The Internet Software Consortium nor the names
+ *    of its contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM 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 INTERNET SOFTWARE CONSORTIUM 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 software has been written for the Internet Software Consortium
+ * by Ted Lemon <mellon at fugue.com> in cooperation with Vixie
+ * Enterprises.  To learn more about the Internet Software Consortium,
+ * see ``http://www.vix.com/isc''.  To learn more about Vixie
+ * Enterprises, see ``http://www.vix.com''.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "dhcpd.h"
+#include "dhctoken.h"
+
+struct client_config top_level_config;
+struct interface_info *dummy_interfaces;
+extern struct interface_info *ifi;
+
+char client_script_name[] = "/sbin/dhclient-script";
+
+/*
+ * client-conf-file :== client-declarations EOF
+ * client-declarations :== <nil>
+ *			 | client-declaration
+ *			 | client-declarations client-declaration
+ */
+int
+read_client_conf(void)
+{
+	FILE			*cfile;
+	char			*val;
+	int			 token;
+	struct client_config	*config;
+
+	new_parse(path_dhclient_conf);
+
+	/* Set up the initial dhcp option universe. */
+	initialize_universes();
+
+	/* Initialize the top level client configuration. */
+	memset(&top_level_config, 0, sizeof(top_level_config));
+
+	/* Set some defaults... */
+	top_level_config.timeout = 60;
+	top_level_config.select_interval = 0;
+	top_level_config.reboot_timeout = 10;
+	top_level_config.retry_interval = 300;
+	top_level_config.backoff_cutoff = 15;
+	top_level_config.initial_interval = 3;
+	top_level_config.bootp_policy = ACCEPT;
+	top_level_config.script_name = client_script_name;
+	top_level_config.requested_options
+	    [top_level_config.requested_option_count++] = DHO_SUBNET_MASK;
+	top_level_config.requested_options
+	    [top_level_config.requested_option_count++] = DHO_BROADCAST_ADDRESS;
+	top_level_config.requested_options
+	    [top_level_config.requested_option_count++] = DHO_TIME_OFFSET;
+	top_level_config.requested_options
+	    [top_level_config.requested_option_count++] = DHO_CLASSLESS_ROUTES;
+	top_level_config.requested_options
+	    [top_level_config.requested_option_count++] = DHO_ROUTERS;
+	top_level_config.requested_options
+	    [top_level_config.requested_option_count++] = DHO_DOMAIN_NAME;
+	top_level_config.requested_options
+	    [top_level_config.requested_option_count++] =
+	    DHO_DOMAIN_NAME_SERVERS;
+	top_level_config.requested_options
+	    [top_level_config.requested_option_count++] = DHO_HOST_NAME;
+
+	if ((cfile = fopen(path_dhclient_conf, "r")) != NULL) {
+		do {
+			token = peek_token(&val, cfile);
+			if (token == EOF)
+				break;
+			parse_client_statement(cfile, NULL, &top_level_config);
+		} while (1);
+		token = next_token(&val, cfile); /* Clear the peek buffer */
+		fclose(cfile);
+	}
+
+	/*
+	 * Set up state and config structures for clients that don't
+	 * have per-interface configuration declarations.
+	 */
+	config = NULL;
+	if (!ifi->client) {
+		ifi->client = malloc(sizeof(struct client_state));
+		if (!ifi->client)
+			error("no memory for client state.");
+		memset(ifi->client, 0, sizeof(*(ifi->client)));
+	}
+	if (!ifi->client->config) {
+		if (!config) {
+			config = malloc(sizeof(struct client_config));
+			if (!config)
+				error("no memory for client config.");
+			memcpy(config, &top_level_config,
+				sizeof(top_level_config));
+		}
+		ifi->client->config = config;
+	}
+
+	return (!warnings_occurred);
+}
+
+/*
+ * lease-file :== client-lease-statements EOF
+ * client-lease-statements :== <nil>
+ *		     | client-lease-statements LEASE client-lease-statement
+ */
+void
+read_client_leases(void)
+{
+	FILE	*cfile;
+	char	*val;
+	int	 token;
+
+	new_parse(path_dhclient_db);
+
+	/* Open the lease file.   If we can't open it, just return -
+	   we can safely trust the server to remember our state. */
+	if ((cfile = fopen(path_dhclient_db, "r")) == NULL)
+		return;
+	do {
+		token = next_token(&val, cfile);
+		if (token == EOF)
+			break;
+		if (token != LEASE) {
+			warning("Corrupt lease file - possible data loss!");
+			skip_to_semi(cfile);
+			break;
+		} else
+			parse_client_lease_statement(cfile, 0);
+
+	} while (1);
+	fclose(cfile);
+}
+
+/*
+ * client-declaration :==
+ *	SEND option-decl |
+ *	DEFAULT option-decl |
+ *	SUPERSEDE option-decl |
+ *	PREPEND option-decl |
+ *	APPEND option-decl |
+ *	hardware-declaration |
+ *	REQUEST option-list |
+ *	REQUIRE option-list |
+ *	TIMEOUT number |
+ *	RETRY number |
+ *	REBOOT number |
+ *	SELECT_TIMEOUT number |
+ *	SCRIPT string |
+ *	interface-declaration |
+ *	LEASE client-lease-statement |
+ *	ALIAS client-lease-statement
+ */
+void
+parse_client_statement(FILE *cfile, struct interface_info *ip,
+    struct client_config *config)
+{
+	int		 token;
+	char		*val;
+	struct option	*option;
+
+	switch (next_token(&val, cfile)) {
+	case SEND:
+		parse_option_decl(cfile, &config->send_options[0]);
+		return;
+	case DEFAULT:
+		option = parse_option_decl(cfile, &config->defaults[0]);
+		if (option)
+			config->default_actions[option->code] = ACTION_DEFAULT;
+		return;
+	case SUPERSEDE:
+		option = parse_option_decl(cfile, &config->defaults[0]);
+		if (option)
+			config->default_actions[option->code] =
+			    ACTION_SUPERSEDE;
+		return;
+	case APPEND:
+		option = parse_option_decl(cfile, &config->defaults[0]);
+		if (option)
+			config->default_actions[option->code] = ACTION_APPEND;
+		return;
+	case PREPEND:
+		option = parse_option_decl(cfile, &config->defaults[0]);
+		if (option)
+			config->default_actions[option->code] = ACTION_PREPEND;
+		return;
+	case MEDIA:
+		parse_string_list(cfile, &config->media, 1);
+		return;
+	case HARDWARE:
+		if (ip)
+			parse_hardware_param(cfile, &ip->hw_address);
+		else {
+			parse_warn("hardware address parameter %s",
+				    "not allowed here.");
+			skip_to_semi(cfile);
+		}
+		return;
+	case REQUEST:
+		config->requested_option_count =
+			parse_option_list(cfile, config->requested_options);
+		return;
+	case REQUIRE:
+		memset(config->required_options, 0,
+		    sizeof(config->required_options));
+		parse_option_list(cfile, config->required_options);
+		return;
+	case TIMEOUT:
+		parse_lease_time(cfile, &config->timeout);
+		return;
+	case RETRY:
+		parse_lease_time(cfile, &config->retry_interval);
+		return;
+	case SELECT_TIMEOUT:
+		parse_lease_time(cfile, &config->select_interval);
+		return;
+	case REBOOT:
+		parse_lease_time(cfile, &config->reboot_timeout);
+		return;
+	case BACKOFF_CUTOFF:
+		parse_lease_time(cfile, &config->backoff_cutoff);
+		return;
+	case INITIAL_INTERVAL:
+		parse_lease_time(cfile, &config->initial_interval);
+		return;
+	case SCRIPT:
+		config->script_name = parse_string(cfile);
+		return;
+	case INTERFACE:
+		if (ip)
+			parse_warn("nested interface declaration.");
+		parse_interface_declaration(cfile, config);
+		return;
+	case LEASE:
+		parse_client_lease_statement(cfile, 1);
+		return;
+	case ALIAS:
+		parse_client_lease_statement(cfile, 2);
+		return;
+	case REJECT:
+		parse_reject_statement(cfile, config);
+		return;
+	default:
+		parse_warn("expecting a statement.");
+		skip_to_semi(cfile);
+		break;
+	}
+	token = next_token(&val, cfile);
+	if (token != SEMI) {
+		parse_warn("semicolon expected.");
+		skip_to_semi(cfile);
+	}
+}
+
+int
+parse_X(FILE *cfile, u_int8_t *buf, int max)
+{
+	int	 token;
+	char	*val;
+	int	 len;
+
+	token = peek_token(&val, cfile);
+	if (token == NUMBER_OR_NAME || token == NUMBER) {
+		len = 0;
+		do {
+			token = next_token(&val, cfile);
+			if (token != NUMBER && token != NUMBER_OR_NAME) {
+				parse_warn("expecting hexadecimal constant.");
+				skip_to_semi(cfile);
+				return (0);
+			}
+			convert_num(&buf[len], val, 16, 8);
+			if (len++ > max) {
+				parse_warn("hexadecimal constant too long.");
+				skip_to_semi(cfile);
+				return (0);
+			}
+			token = peek_token(&val, cfile);
+			if (token == COLON)
+				token = next_token(&val, cfile);
+		} while (token == COLON);
+		val = (char *)buf;
+	} else if (token == STRING) {
+		token = next_token(&val, cfile);
+		len = strlen(val);
+		if (len + 1 > max) {
+			parse_warn("string constant too long.");
+			skip_to_semi(cfile);
+			return (0);
+		}
+		memcpy(buf, val, len + 1);
+	} else {
+		parse_warn("expecting string or hexadecimal data");
+		skip_to_semi(cfile);
+		return (0);
+	}
+	return (len);
+}
+
+/*
+ * option-list :== option_name |
+ *		   option_list COMMA option_name
+ */
+int
+parse_option_list(FILE *cfile, u_int8_t *list)
+{
+	int	 ix, i;
+	int	 token;
+	char	*val;
+
+	ix = 0;
+	do {
+		token = next_token(&val, cfile);
+		if (!is_identifier(token)) {
+			parse_warn("expected option name.");
+			skip_to_semi(cfile);
+			return (0);
+		}
+		for (i = 0; i < 256; i++)
+			if (!strcasecmp(dhcp_options[i].name, val))
+				break;
+
+		if (i == 256) {
+			parse_warn("%s: unexpected option name.", val);
+			skip_to_semi(cfile);
+			return (0);
+		}
+		list[ix++] = i;
+		if (ix == 256) {
+			parse_warn("%s: too many options.", val);
+			skip_to_semi(cfile);
+			return (0);
+		}
+		token = next_token(&val, cfile);
+	} while (token == COMMA);
+	if (token != SEMI) {
+		parse_warn("expecting semicolon.");
+		skip_to_semi(cfile);
+		return (0);
+	}
+	return (ix);
+}
+
+/*
+ * interface-declaration :==
+ *	INTERFACE string LBRACE client-declarations RBRACE
+ */
+void
+parse_interface_declaration(FILE *cfile, struct client_config *outer_config)
+{
+	int			 token;
+	char			*val;
+	struct interface_info	*ip;
+
+	token = next_token(&val, cfile);
+	if (token != STRING) {
+		parse_warn("expecting interface name (in quotes).");
+		skip_to_semi(cfile);
+		return;
+	}
+
+	ip = interface_or_dummy(val);
+
+	if (!ip->client)
+		make_client_state(ip);
+
+	if (!ip->client->config)
+		make_client_config(ip, outer_config);
+
+	token = next_token(&val, cfile);
+	if (token != LBRACE) {
+		parse_warn("expecting left brace.");
+		skip_to_semi(cfile);
+		return;
+	}
+
+	do {
+		token = peek_token(&val, cfile);
+		if (token == EOF) {
+			parse_warn("unterminated interface declaration.");
+			return;
+		}
+		if (token == RBRACE)
+			break;
+		parse_client_statement(cfile, ip, ip->client->config);
+	} while (1);
+	token = next_token(&val, cfile);
+}
+
+struct interface_info *
+interface_or_dummy(char *name)
+{
+	struct interface_info	*ip;
+
+	/* Find the interface (if any) that matches the name. */
+	if (!strcmp(ifi->name, name))
+		return (ifi);
+
+	/* If it's not a real interface, see if it's on the dummy list. */
+	for (ip = dummy_interfaces; ip; ip = ip->next)
+		if (!strcmp(ip->name, name))
+			return (ip);
+
+	/*
+	 * If we didn't find an interface, make a dummy interface as a
+	 * placeholder.
+	 */
+	ip = malloc(sizeof(*ip));
+	if (!ip)
+		error("Insufficient memory to record interface %s", name);
+	memset(ip, 0, sizeof(*ip));
+	strlcpy(ip->name, name, IFNAMSIZ);
+	ip->next = dummy_interfaces;
+	dummy_interfaces = ip;
+	return (ip);
+}
+
+void
+make_client_state(struct interface_info *ip)
+{
+	ip->client = malloc(sizeof(*(ip->client)));
+	if (!ip->client)
+		error("no memory for state on %s", ip->name);
+	memset(ip->client, 0, sizeof(*(ip->client)));
+}
+
+void
+make_client_config(struct interface_info *ip, struct client_config *config)
+{
+	ip->client->config = malloc(sizeof(struct client_config));
+	if (!ip->client->config)
+		error("no memory for config for %s", ip->name);
+	memset(ip->client->config, 0, sizeof(*(ip->client->config)));
+	memcpy(ip->client->config, config, sizeof(*config));
+}
+
+/*
+ * client-lease-statement :==
+ *	RBRACE client-lease-declarations LBRACE
+ *
+ *	client-lease-declarations :==
+ *		<nil> |
+ *		client-lease-declaration |
+ *		client-lease-declarations client-lease-declaration
+ */
+void
+parse_client_lease_statement(FILE *cfile, int is_static)
+{
+	struct client_lease	*lease, *lp, *pl;
+	struct interface_info	*ip;
+	int			 token;
+	char			*val;
+
+	token = next_token(&val, cfile);
+	if (token != LBRACE) {
+		parse_warn("expecting left brace.");
+		skip_to_semi(cfile);
+		return;
+	}
+
+	lease = malloc(sizeof(struct client_lease));
+	if (!lease)
+		error("no memory for lease.");
+	memset(lease, 0, sizeof(*lease));
+	lease->is_static = is_static;
+
+	ip = NULL;
+
+	do {
+		token = peek_token(&val, cfile);
+		if (token == EOF) {
+			parse_warn("unterminated lease declaration.");
+			return;
+		}
+		if (token == RBRACE)
+			break;
+		parse_client_lease_declaration(cfile, lease, &ip);
+	} while (1);
+	token = next_token(&val, cfile);
+
+	/* If the lease declaration didn't include an interface
+	 * declaration that we recognized, it's of no use to us.
+	 */
+	if (!ip) {
+		free_client_lease(lease);
+		return;
+	}
+
+	/* Make sure there's a client state structure... */
+	if (!ip->client)
+		make_client_state(ip);
+
+	/* If this is an alias lease, it doesn't need to be sorted in. */
+	if (is_static == 2) {
+		ip->client->alias = lease;
+		return;
+	}
+
+	/*
+	 * The new lease may supersede a lease that's not the active
+	 * lease but is still on the lease list, so scan the lease list
+	 * looking for a lease with the same address, and if we find it,
+	 * toss it.
+	 */
+	pl = NULL;
+	for (lp = ip->client->leases; lp; lp = lp->next) {
+		if (lp->address.len == lease->address.len &&
+		    !memcmp(lp->address.iabuf, lease->address.iabuf,
+		    lease->address.len)) {
+			if (pl)
+				pl->next = lp->next;
+			else
+				ip->client->leases = lp->next;
+			free_client_lease(lp);
+			break;
+		}
+	}
+
+	/*
+	 * If this is a preloaded lease, just put it on the list of
+	 * recorded leases - don't make it the active lease.
+	 */
+	if (is_static) {
+		lease->next = ip->client->leases;
+		ip->client->leases = lease;
+		return;
+	}
+
+	/*
+	 * The last lease in the lease file on a particular interface is
+	 * the active lease for that interface.    Of course, we don't
+	 * know what the last lease in the file is until we've parsed
+	 * the whole file, so at this point, we assume that the lease we
+	 * just parsed is the active lease for its interface.   If
+	 * there's already an active lease for the interface, and this
+	 * lease is for the same ip address, then we just toss the old
+	 * active lease and replace it with this one.   If this lease is
+	 * for a different address, then if the old active lease has
+	 * expired, we dump it; if not, we put it on the list of leases
+	 * for this interface which are still valid but no longer
+	 * active.
+	 */
+	if (ip->client->active) {
+		if (ip->client->active->expiry < cur_time)
+			free_client_lease(ip->client->active);
+		else if (ip->client->active->address.len ==
+		    lease->address.len &&
+		    !memcmp(ip->client->active->address.iabuf,
+		    lease->address.iabuf, lease->address.len))
+			free_client_lease(ip->client->active);
+		else {
+			ip->client->active->next = ip->client->leases;
+			ip->client->leases = ip->client->active;
+		}
+	}
+	ip->client->active = lease;
+
+	/* Phew. */
+}
+
+/*
+ * client-lease-declaration :==
+ *	BOOTP |
+ *	INTERFACE string |
+ *	FIXED_ADDR ip_address |
+ *	FILENAME string |
+ *	SERVER_NAME string |
+ *	OPTION option-decl |
+ *	RENEW time-decl |
+ *	REBIND time-decl |
+ *	EXPIRE time-decl
+ */
+void
+parse_client_lease_declaration(FILE *cfile, struct client_lease *lease,
+    struct interface_info **ipp)
+{
+	int			 token;
+	char			*val;
+	struct interface_info	*ip;
+
+	switch (next_token(&val, cfile)) {
+	case BOOTP:
+		lease->is_bootp = 1;
+		break;
+	case INTERFACE:
+		token = next_token(&val, cfile);
+		if (token != STRING) {
+			parse_warn("expecting interface name (in quotes).");
+			skip_to_semi(cfile);
+			break;
+		}
+		ip = interface_or_dummy(val);
+		*ipp = ip;
+		break;
+	case FIXED_ADDR:
+		if (!parse_ip_addr(cfile, &lease->address))
+			return;
+		break;
+	case MEDIUM:
+		parse_string_list(cfile, &lease->medium, 0);
+		return;
+	case FILENAME:
+		lease->filename = parse_string(cfile);
+		return;
+	case SERVER_NAME:
+		lease->server_name = parse_string(cfile);
+		return;
+	case RENEW:
+		lease->renewal = parse_date(cfile);
+		return;
+	case REBIND:
+		lease->rebind = parse_date(cfile);
+		return;
+	case EXPIRE:
+		lease->expiry = parse_date(cfile);
+		return;
+	case OPTION:
+		parse_option_decl(cfile, lease->options);
+		return;
+	default:
+		parse_warn("expecting lease declaration.");
+		skip_to_semi(cfile);
+		break;
+	}
+	token = next_token(&val, cfile);
+	if (token != SEMI) {
+		parse_warn("expecting semicolon.");
+		skip_to_semi(cfile);
+	}
+}
+
+struct option *
+parse_option_decl(FILE *cfile, struct option_data *options)
+{
+	char		*val;
+	int		 token;
+	u_int8_t	 buf[4];
+	u_int8_t	 hunkbuf[1024];
+	int		 hunkix = 0;
+	char		*vendor;
+	char		*fmt;
+	struct universe	*universe;
+	struct option	*option;
+	struct iaddr	 ip_addr;
+	u_int8_t	*dp;
+	int		 len;
+	int		 nul_term = 0;
+
+	token = next_token(&val, cfile);
+	if (!is_identifier(token)) {
+		parse_warn("expecting identifier after option keyword.");
+		if (token != SEMI)
+			skip_to_semi(cfile);
+		return (NULL);
+	}
+	if ((vendor = strdup(val)) == NULL)
+		error("no memory for vendor information.");
+
+	token = peek_token(&val, cfile);
+	if (token == DOT) {
+		/* Go ahead and take the DOT token... */
+		token = next_token(&val, cfile);
+
+		/* The next token should be an identifier... */
+		token = next_token(&val, cfile);
+		if (!is_identifier(token)) {
+			parse_warn("expecting identifier after '.'");
+			if (token != SEMI)
+				skip_to_semi(cfile);
+			return (NULL);
+		}
+
+		/* Look up the option name hash table for the specified
+		   vendor. */
+		universe = ((struct universe *)hash_lookup(&universe_hash,
+		    (unsigned char *)vendor, 0));
+		/* If it's not there, we can't parse the rest of the
+		   declaration. */
+		if (!universe) {
+			parse_warn("no vendor named %s.", vendor);
+			skip_to_semi(cfile);
+			return (NULL);
+		}
+	} else {
+		/* Use the default hash table, which contains all the
+		   standard dhcp option names. */
+		val = vendor;
+		universe = &dhcp_universe;
+	}
+
+	/* Look up the actual option info... */
+	option = (struct option *)hash_lookup(universe->hash,
+	    (unsigned char *)val, 0);
+
+	/* If we didn't get an option structure, it's an undefined option. */
+	if (!option) {
+		if (val == vendor)
+			parse_warn("no option named %s", val);
+		else
+			parse_warn("no option named %s for vendor %s",
+				    val, vendor);
+		skip_to_semi(cfile);
+		return (NULL);
+	}
+
+	/* Free the initial identifier token. */
+	free(vendor);
+
+	/* Parse the option data... */
+	do {
+		for (fmt = option->format; *fmt; fmt++) {
+			if (*fmt == 'A')
+				break;
+			switch (*fmt) {
+			case 'X':
+				len = parse_X(cfile, &hunkbuf[hunkix],
+				    sizeof(hunkbuf) - hunkix);
+				hunkix += len;
+				break;
+			case 't': /* Text string... */
+				token = next_token(&val, cfile);
+				if (token != STRING) {
+					parse_warn("expecting string.");
+					skip_to_semi(cfile);
+					return (NULL);
+				}
+				len = strlen(val);
+				if (hunkix + len + 1 > sizeof(hunkbuf)) {
+					parse_warn("option data buffer %s",
+					    "overflow");
+					skip_to_semi(cfile);
+					return (NULL);
+				}
+				memcpy(&hunkbuf[hunkix], val, len + 1);
+				nul_term = 1;
+				hunkix += len;
+				break;
+			case 'I': /* IP address. */
+				if (!parse_ip_addr(cfile, &ip_addr))
+					return (NULL);
+				len = ip_addr.len;
+				dp = ip_addr.iabuf;
+alloc:
+				if (hunkix + len > sizeof(hunkbuf)) {
+					parse_warn("option data buffer "
+					    "overflow");
+					skip_to_semi(cfile);
+					return (NULL);
+				}
+				memcpy(&hunkbuf[hunkix], dp, len);
+				hunkix += len;
+				break;
+			case 'L':	/* Unsigned 32-bit integer... */
+			case 'l':	/* Signed 32-bit integer... */
+				token = next_token(&val, cfile);
+				if (token != NUMBER) {
+need_number:
+					parse_warn("expecting number.");
+					if (token != SEMI)
+						skip_to_semi(cfile);
+					return (NULL);
+				}
+				convert_num(buf, val, 0, 32);
+				len = 4;
+				dp = buf;
+				goto alloc;
+			case 's':	/* Signed 16-bit integer. */
+			case 'S':	/* Unsigned 16-bit integer. */
+				token = next_token(&val, cfile);
+				if (token != NUMBER)
+					goto need_number;
+				convert_num(buf, val, 0, 16);
+				len = 2;
+				dp = buf;
+				goto alloc;
+			case 'b':	/* Signed 8-bit integer. */
+			case 'B':	/* Unsigned 8-bit integer. */
+				token = next_token(&val, cfile);
+				if (token != NUMBER)
+					goto need_number;
+				convert_num(buf, val, 0, 8);
+				len = 1;
+				dp = buf;
+				goto alloc;
+			case 'f': /* Boolean flag. */
+				token = next_token(&val, cfile);
+				if (!is_identifier(token)) {
+					parse_warn("expecting identifier.");
+bad_flag:
+					if (token != SEMI)
+						skip_to_semi(cfile);
+					return (NULL);
+				}
+				if (!strcasecmp(val, "true") ||
+				    !strcasecmp(val, "on"))
+					buf[0] = 1;
+				else if (!strcasecmp(val, "false") ||
+				    !strcasecmp(val, "off"))
+					buf[0] = 0;
+				else {
+					parse_warn("expecting boolean.");
+					goto bad_flag;
+				}
+				len = 1;
+				dp = buf;
+				goto alloc;
+			default:
+				warning("Bad format %c in parse_option_param.",
+				    *fmt);
+				skip_to_semi(cfile);
+				return (NULL);
+			}
+		}
+		token = next_token(&val, cfile);
+	} while (*fmt == 'A' && token == COMMA);
+
+	if (token != SEMI) {
+		parse_warn("semicolon expected.");
+		skip_to_semi(cfile);
+		return (NULL);
+	}
+
+	options[option->code].data = malloc(hunkix + nul_term);
+	if (!options[option->code].data)
+		error("out of memory allocating option data.");
+	memcpy(options[option->code].data, hunkbuf, hunkix + nul_term);
+	options[option->code].len = hunkix;
+	return (option);
+}
+
+void
+parse_string_list(FILE *cfile, struct string_list **lp, int multiple)
+{
+	int			 token;
+	char			*val;
+	struct string_list	*cur, *tmp;
+
+	/* Find the last medium in the media list. */
+	if (*lp)
+		for (cur = *lp; cur->next; cur = cur->next)
+			;	/* nothing */
+	else
+		cur = NULL;
+
+	do {
+		token = next_token(&val, cfile);
+		if (token != STRING) {
+			parse_warn("Expecting media options.");
+			skip_to_semi(cfile);
+			return;
+		}
+
+		tmp = new_string_list(strlen(val) + 1);
+		if (tmp == NULL)
+			error("no memory for string list entry.");
+		strlcpy(tmp->string, val, strlen(val) + 1);
+		tmp->next = NULL;
+
+		/* Store this medium at the end of the media list. */
+		if (cur)
+			cur->next = tmp;
+		else
+			*lp = tmp;
+		cur = tmp;
+
+		token = next_token(&val, cfile);
+	} while (multiple && token == COMMA);
+
+	if (token != SEMI) {
+		parse_warn("expecting semicolon.");
+		skip_to_semi(cfile);
+	}
+}
+
+void
+parse_reject_statement(FILE *cfile, struct client_config *config)
+{
+	int			 token;
+	char			*val;
+	struct iaddr		 addr;
+	struct iaddrlist	*list;
+
+	do {
+		if (!parse_ip_addr(cfile, &addr)) {
+			parse_warn("expecting IP address.");
+			skip_to_semi(cfile);
+			return;
+		}
+
+		list = malloc(sizeof(struct iaddrlist));
+		if (!list)
+			error("no memory for reject list!");
+
+		list->addr = addr;
+		list->next = config->reject_list;
+		config->reject_list = list;
+
+		token = next_token(&val, cfile);
+	} while (token == COMMA);
+
+	if (token != SEMI) {
+		parse_warn("expecting semicolon.");
+		skip_to_semi(cfile);
+	}
+}
diff --git a/freebsd-userspace/commands/sbin/dhclient/conflex.c b/freebsd-userspace/commands/sbin/dhclient/conflex.c
new file mode 100644
index 0000000..3c8932d
--- /dev/null
+++ b/freebsd-userspace/commands/sbin/dhclient/conflex.c
@@ -0,0 +1,529 @@
+/*	$OpenBSD: conflex.c,v 1.7 2004/09/15 19:02:38 deraadt Exp $	*/
+
+/* Lexical scanner for dhcpd config file... */
+
+/*
+ * Copyright (c) 1995, 1996, 1997 The Internet Software Consortium.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of The Internet Software Consortium nor the names
+ *    of its contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM 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 INTERNET SOFTWARE CONSORTIUM 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 software has been written for the Internet Software Consortium
+ * by Ted Lemon <mellon at fugue.com> in cooperation with Vixie
+ * Enterprises.  To learn more about the Internet Software Consortium,
+ * see ``http://www.vix.com/isc''.  To learn more about Vixie
+ * Enterprises, see ``http://www.vix.com''.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <ctype.h>
+
+#include "dhcpd.h"
+#include "dhctoken.h"
+
+int lexline;
+int lexchar;
+char *token_line;
+char *prev_line;
+char *cur_line;
+char *tlname;
+int eol_token;
+
+static char line1[81];
+static char line2[81];
+static int lpos;
+static int line;
+static int tlpos;
+static int tline;
+static int token;
+static int ugflag;
+static char *tval;
+static char tokbuf[1500];
+
+static int get_char(FILE *);
+static int get_token(FILE *);
+static void skip_to_eol(FILE *);
+static int read_string(FILE *);
+static int read_number(int, FILE *);
+static int read_num_or_name(int, FILE *);
+static int intern(char *, int);
+
+void
+new_parse(char *name)
+{
+	tlname = name;
+	lpos = line = 1;
+	cur_line = line1;
+	prev_line = line2;
+	token_line = cur_line;
+	cur_line[0] = prev_line[0] = 0;
+	warnings_occurred = 0;
+}
+
+static int
+get_char(FILE *cfile)
+{
+	int c = getc(cfile);
+	if (!ugflag) {
+		if (c == '\n') {
+			if (cur_line == line1) {
+				cur_line = line2;
+				prev_line = line1;
+			} else {
+				cur_line = line2;
+				prev_line = line1;
+			}
+			line++;
+			lpos = 1;
+			cur_line[0] = 0;
+		} else if (c != EOF) {
+			if (lpos < sizeof(line1)) {
+				cur_line[lpos - 1] = c;
+				cur_line[lpos] = 0;
+			}
+			lpos++;
+		}
+	} else
+		ugflag = 0;
+	return (c);
+}
+
+static int
+get_token(FILE *cfile)
+{
+	int		c, ttok;
+	static char	tb[2];
+	int		l, p;
+
+	do {
+		l = line;
+		p = lpos;
+
+		c = get_char(cfile);
+
+		if (!(c == '\n' && eol_token) && isascii(c) && isspace(c))
+			continue;
+		if (c == '#') {
+			skip_to_eol(cfile);
+			continue;
+		}
+		if (c == '"') {
+			lexline = l;
+			lexchar = p;
+			ttok = read_string(cfile);
+			break;
+		}
+		if ((isascii(c) && isdigit(c)) || c == '-') {
+			lexline = l;
+			lexchar = p;
+			ttok = read_number(c, cfile);
+			break;
+		} else if (isascii(c) && isalpha(c)) {
+			lexline = l;
+			lexchar = p;
+			ttok = read_num_or_name(c, cfile);
+			break;
+		} else {
+			lexline = l;
+			lexchar = p;
+			tb[0] = c;
+			tb[1] = 0;
+			tval = tb;
+			ttok = c;
+			break;
+		}
+	} while (1);
+	return (ttok);
+}
+
+int
+next_token(char **rval, FILE *cfile)
+{
+	int	rv;
+
+	if (token) {
+		if (lexline != tline)
+			token_line = cur_line;
+		lexchar = tlpos;
+		lexline = tline;
+		rv = token;
+		token = 0;
+	} else {
+		rv = get_token(cfile);
+		token_line = cur_line;
+	}
+	if (rval)
+		*rval = tval;
+
+	return (rv);
+}
+
+int
+peek_token(char **rval, FILE *cfile)
+{
+	int	x;
+
+	if (!token) {
+		tlpos = lexchar;
+		tline = lexline;
+		token = get_token(cfile);
+		if (lexline != tline)
+			token_line = prev_line;
+		x = lexchar;
+		lexchar = tlpos;
+		tlpos = x;
+		x = lexline;
+		lexline = tline;
+		tline = x;
+	}
+	if (rval)
+		*rval = tval;
+
+	return (token);
+}
+
+static void
+skip_to_eol(FILE *cfile)
+{
+	int	c;
+
+	do {
+		c = get_char(cfile);
+		if (c == EOF)
+			return;
+		if (c == '\n')
+			return;
+	} while (1);
+}
+
+static int
+read_string(FILE *cfile)
+{
+	int	i, c, bs = 0;
+
+	for (i = 0; i < sizeof(tokbuf); i++) {
+		c = get_char(cfile);
+		if (c == EOF) {
+			parse_warn("eof in string constant");
+			break;
+		}
+		if (bs) {
+			bs = 0;
+			i--;
+			tokbuf[i] = c;
+		} else if (c == '\\')
+			bs = 1;
+		else if (c == '"')
+			break;
+		else
+			tokbuf[i] = c;
+	}
+	/*
+	 * Normally, I'd feel guilty about this, but we're talking about
+	 * strings that'll fit in a DHCP packet here...
+	 */
+	if (i == sizeof(tokbuf)) {
+		parse_warn("string constant larger than internal buffer");
+		i--;
+	}
+	tokbuf[i] = 0;
+	tval = tokbuf;
+	return (STRING);
+}
+
+static int
+read_number(int c, FILE *cfile)
+{
+	int	seenx = 0, i = 0, token = NUMBER;
+
+	tokbuf[i++] = c;
+	for (; i < sizeof(tokbuf); i++) {
+		c = get_char(cfile);
+		if (!seenx && c == 'x')
+			seenx = 1;
+		else if (!isascii(c) || !isxdigit(c)) {
+			ungetc(c, cfile);
+			ugflag = 1;
+			break;
+		}
+		tokbuf[i] = c;
+	}
+	if (i == sizeof(tokbuf)) {
+		parse_warn("numeric token larger than internal buffer");
+		i--;
+	}
+	tokbuf[i] = 0;
+	tval = tokbuf;
+
+	return (token);
+}
+
+static int
+read_num_or_name(int c, FILE *cfile)
+{
+	int	i = 0;
+	int	rv = NUMBER_OR_NAME;
+
+	tokbuf[i++] = c;
+	for (; i < sizeof(tokbuf); i++) {
+		c = get_char(cfile);
+		if (!isascii(c) || (c != '-' && c != '_' && !isalnum(c))) {
+			ungetc(c, cfile);
+			ugflag = 1;
+			break;
+		}
+		if (!isxdigit(c))
+			rv = NAME;
+		tokbuf[i] = c;
+	}
+	if (i == sizeof(tokbuf)) {
+		parse_warn("token larger than internal buffer");
+		i--;
+	}
+	tokbuf[i] = 0;
+	tval = tokbuf;
+
+	return (intern(tval, rv));
+}
+
+static int
+intern(char *atom, int dfv)
+{
+	if (!isascii(atom[0]))
+		return (dfv);
+
+	switch (tolower(atom[0])) {
+	case 'a':
+		if (!strcasecmp(atom + 1, "lways-reply-rfc1048"))
+			return (ALWAYS_REPLY_RFC1048);
+		if (!strcasecmp(atom + 1, "ppend"))
+			return (APPEND);
+		if (!strcasecmp(atom + 1, "llow"))
+			return (ALLOW);
+		if (!strcasecmp(atom + 1, "lias"))
+			return (ALIAS);
+		if (!strcasecmp(atom + 1, "bandoned"))
+			return (ABANDONED);
+		if (!strcasecmp(atom + 1, "uthoritative"))
+			return (AUTHORITATIVE);
+		break;
+	case 'b':
+		if (!strcasecmp(atom + 1, "ackoff-cutoff"))
+			return (BACKOFF_CUTOFF);
+		if (!strcasecmp(atom + 1, "ootp"))
+			return (BOOTP);
+		if (!strcasecmp(atom + 1, "ooting"))
+			return (BOOTING);
+		if (!strcasecmp(atom + 1, "oot-unknown-clients"))
+			return (BOOT_UNKNOWN_CLIENTS);
+	case 'c':
+		if (!strcasecmp(atom + 1, "lass"))
+			return (CLASS);
+		if (!strcasecmp(atom + 1, "iaddr"))
+			return (CIADDR);
+		if (!strcasecmp(atom + 1, "lient-identifier"))
+			return (CLIENT_IDENTIFIER);
+		if (!strcasecmp(atom + 1, "lient-hostname"))
+			return (CLIENT_HOSTNAME);
+		break;
+	case 'd':
+		if (!strcasecmp(atom + 1, "omain"))
+			return (DOMAIN);
+		if (!strcasecmp(atom + 1, "eny"))
+			return (DENY);
+		if (!strncasecmp(atom + 1, "efault", 6)) {
+			if (!atom[7])
+				return (DEFAULT);
+			if (!strcasecmp(atom + 7, "-lease-time"))
+				return (DEFAULT_LEASE_TIME);
+			break;
+		}
+		if (!strncasecmp(atom + 1, "ynamic-bootp", 12)) {
+			if (!atom[13])
+				return (DYNAMIC_BOOTP);
+			if (!strcasecmp(atom + 13, "-lease-cutoff"))
+				return (DYNAMIC_BOOTP_LEASE_CUTOFF);
+			if (!strcasecmp(atom + 13, "-lease-length"))
+				return (DYNAMIC_BOOTP_LEASE_LENGTH);
+			break;
+		}
+		break;
+	case 'e':
+		if (!strcasecmp(atom + 1, "thernet"))
+			return (ETHERNET);
+		if (!strcasecmp(atom + 1, "nds"))
+			return (ENDS);
+		if (!strcasecmp(atom + 1, "xpire"))
+			return (EXPIRE);
+		break;
+	case 'f':
+		if (!strcasecmp(atom + 1, "ilename"))
+			return (FILENAME);
+		if (!strcasecmp(atom + 1, "ixed-address"))
+			return (FIXED_ADDR);
+		if (!strcasecmp(atom + 1, "ddi"))
+			return (FDDI);
+		break;
+	case 'g':
+		if (!strcasecmp(atom + 1, "iaddr"))
+			return (GIADDR);
+		if (!strcasecmp(atom + 1, "roup"))
+			return (GROUP);
+		if (!strcasecmp(atom + 1, "et-lease-hostnames"))
+			return (GET_LEASE_HOSTNAMES);
+		break;
+	case 'h':
+		if (!strcasecmp(atom + 1, "ost"))
+			return (HOST);
+		if (!strcasecmp(atom + 1, "ardware"))
+			return (HARDWARE);
+		if (!strcasecmp(atom + 1, "ostname"))
+			return (HOSTNAME);
+		break;
+	case 'i':
+		if (!strcasecmp(atom + 1, "nitial-interval"))
+			return (INITIAL_INTERVAL);
+		if (!strcasecmp(atom + 1, "nterface"))
+			return (INTERFACE);
+		break;
+	case 'l':
+		if (!strcasecmp(atom + 1, "ease"))
+			return (LEASE);
+		break;
+	case 'm':
+		if (!strcasecmp(atom + 1, "ax-lease-time"))
+			return (MAX_LEASE_TIME);
+		if (!strncasecmp(atom + 1, "edi", 3)) {
+			if (!strcasecmp(atom + 4, "a"))
+				return (MEDIA);
+			if (!strcasecmp(atom + 4, "um"))
+				return (MEDIUM);
+			break;
+		}
+		break;
+	case 'n':
+		if (!strcasecmp(atom + 1, "ameserver"))
+			return (NAMESERVER);
+		if (!strcasecmp(atom + 1, "etmask"))
+			return (NETMASK);
+		if (!strcasecmp(atom + 1, "ext-server"))
+			return (NEXT_SERVER);
+		if (!strcasecmp(atom + 1, "ot"))
+			return (TOKEN_NOT);
+		break;
+	case 'o':
+		if (!strcasecmp(atom + 1, "ption"))
+			return (OPTION);
+		if (!strcasecmp(atom + 1, "ne-lease-per-client"))
+			return (ONE_LEASE_PER_CLIENT);
+		break;
+	case 'p':
+		if (!strcasecmp(atom + 1, "repend"))
+			return (PREPEND);
+		if (!strcasecmp(atom + 1, "acket"))
+			return (PACKET);
+		break;
+	case 'r':
+		if (!strcasecmp(atom + 1, "ange"))
+			return (RANGE);
+		if (!strcasecmp(atom + 1, "equest"))
+			return (REQUEST);
+		if (!strcasecmp(atom + 1, "equire"))
+			return (REQUIRE);
+		if (!strcasecmp(atom + 1, "etry"))
+			return (RETRY);
+		if (!strcasecmp(atom + 1, "enew"))
+			return (RENEW);
+		if (!strcasecmp(atom + 1, "ebind"))
+			return (REBIND);
+		if (!strcasecmp(atom + 1, "eboot"))
+			return (REBOOT);
+		if (!strcasecmp(atom + 1, "eject"))
+			return (REJECT);
+		break;
+	case 's':
+		if (!strcasecmp(atom + 1, "earch"))
+			return (SEARCH);
+		if (!strcasecmp(atom + 1, "tarts"))
+			return (STARTS);
+		if (!strcasecmp(atom + 1, "iaddr"))
+			return (SIADDR);
+		if (!strcasecmp(atom + 1, "ubnet"))
+			return (SUBNET);
+		if (!strcasecmp(atom + 1, "hared-network"))
+			return (SHARED_NETWORK);
+		if (!strcasecmp(atom + 1, "erver-name"))
+			return (SERVER_NAME);
+		if (!strcasecmp(atom + 1, "erver-identifier"))
+			return (SERVER_IDENTIFIER);
+		if (!strcasecmp(atom + 1, "elect-timeout"))
+			return (SELECT_TIMEOUT);
+		if (!strcasecmp(atom + 1, "end"))
+			return (SEND);
+		if (!strcasecmp(atom + 1, "cript"))
+			return (SCRIPT);
+		if (!strcasecmp(atom + 1, "upersede"))
+			return (SUPERSEDE);
+		break;
+	case 't':
+		if (!strcasecmp(atom + 1, "imestamp"))
+			return (TIMESTAMP);
+		if (!strcasecmp(atom + 1, "imeout"))
+			return (TIMEOUT);
+		if (!strcasecmp(atom + 1, "oken-ring"))
+			return (TOKEN_RING);
+		break;
+	case 'u':
+		if (!strncasecmp(atom + 1, "se", 2)) {
+			if (!strcasecmp(atom + 3, "r-class"))
+				return (USER_CLASS);
+			if (!strcasecmp(atom + 3, "-host-decl-names"))
+				return (USE_HOST_DECL_NAMES);
+			if (!strcasecmp(atom + 3,
+					 "-lease-addr-for-default-route"))
+				return (USE_LEASE_ADDR_FOR_DEFAULT_ROUTE);
+			break;
+		}
+		if (!strcasecmp(atom + 1, "id"))
+			return (UID);
+		if (!strcasecmp(atom + 1, "nknown-clients"))
+			return (UNKNOWN_CLIENTS);
+		break;
+	case 'v':
+		if (!strcasecmp(atom + 1, "endor-class"))
+			return (VENDOR_CLASS);
+		break;
+	case 'y':
+		if (!strcasecmp(atom + 1, "iaddr"))
+			return (YIADDR);
+		break;
+	}
+	return (dfv);
+}
diff --git a/freebsd-userspace/commands/sbin/dhclient/convert.c b/freebsd-userspace/commands/sbin/dhclient/convert.c
new file mode 100644
index 0000000..adca092
--- /dev/null
+++ b/freebsd-userspace/commands/sbin/dhclient/convert.c
@@ -0,0 +1,117 @@
+/*	$OpenBSD: convert.c,v 1.5 2004/02/07 11:35:59 henning Exp $	*/
+
+/*
+ * Safe copying of option values into and out of the option buffer,
+ * which can't be assumed to be aligned.
+ */
+
+/*
+ * Copyright (c) 1995, 1996 The Internet Software Consortium.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of The Internet Software Consortium nor the names
+ *    of its contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM 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 INTERNET SOFTWARE CONSORTIUM 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 software has been written for the Internet Software Consortium
+ * by Ted Lemon <mellon at fugue.com> in cooperation with Vixie
+ * Enterprises.  To learn more about the Internet Software Consortium,
+ * see ``http://www.vix.com/isc''.  To learn more about Vixie
+ * Enterprises, see ``http://www.vix.com''.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "dhcpd.h"
+
+u_int32_t
+getULong(unsigned char *buf)
+{
+	u_int32_t ibuf;
+
+	memcpy(&ibuf, buf, sizeof(ibuf));
+	return (ntohl(ibuf));
+}
+
+int32_t
+getLong(unsigned char *(buf))
+{
+	int32_t ibuf;
+
+	memcpy(&ibuf, buf, sizeof(ibuf));
+	return (ntohl(ibuf));
+}
+
+u_int16_t
+getUShort(unsigned char *buf)
+{
+	u_int16_t ibuf;
+
+	memcpy(&ibuf, buf, sizeof(ibuf));
+	return (ntohs(ibuf));
+}
+
+int16_t
+getShort(unsigned char *buf)
+{
+	int16_t ibuf;
+
+	memcpy(&ibuf, buf, sizeof(ibuf));
+	return (ntohs(ibuf));
+}
+
+void
+putULong(unsigned char *obuf, u_int32_t val)
+{
+	u_int32_t tmp = htonl(val);
+
+	memcpy(obuf, &tmp, sizeof(tmp));
+}
+
+void
+putLong(unsigned char *obuf, int32_t val)
+{
+	int32_t tmp = htonl(val);
+
+	memcpy(obuf, &tmp, sizeof(tmp));
+}
+
+void
+putUShort(unsigned char *obuf, unsigned int val)
+{
+	u_int16_t tmp = htons(val);
+
+	memcpy(obuf, &tmp, sizeof(tmp));
+}
+
+void
+putShort(unsigned char *obuf, int val)
+{
+	int16_t tmp = htons(val);
+
+	memcpy(obuf, &tmp, sizeof(tmp));
+}
diff --git a/freebsd-userspace/commands/sbin/dhclient/dhclient-script b/freebsd-userspace/commands/sbin/dhclient/dhclient-script
new file mode 100644
index 0000000..c457bf4
--- /dev/null
+++ b/freebsd-userspace/commands/sbin/dhclient/dhclient-script
@@ -0,0 +1,384 @@
+#!/bin/sh
+#
+# $OpenBSD: dhclient-script,v 1.6 2004/05/06 18:22:41 claudio Exp $
+# $FreeBSD$
+#
+# Copyright (c) 2003 Kenneth R Westerback <krw at openbsd.org>
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+#
+
+ARP=/usr/sbin/arp
+HOSTNAME=/bin/hostname
+IFCONFIG='/sbin/ifconfig -n'
+
+LOCALHOST=127.0.0.1
+
+if [ -x /usr/bin/logger ]; then
+	LOGGER="/usr/bin/logger -s -p user.notice -t dhclient"
+else
+	LOGGER=echo
+fi
+
+#
+# Helper functions that implement common actions.
+#
+
+check_hostname() {
+	current_hostname=`$HOSTNAME`
+	if [ -z "$current_hostname" ]; then
+		$LOGGER "New Hostname ($interface): $new_host_name"
+		$HOSTNAME $new_host_name
+	elif [ "$current_hostname" = "$old_host_name" -a \
+	       "$new_host_name" != "$old_host_name" ]; then
+		$LOGGER "New Hostname ($interface): $new_host_name"
+		$HOSTNAME $new_host_name
+	fi
+}
+
+arp_flush() {
+	arp -an -i $interface | \
+		sed -n -e 's/^.*(\(.*\)) at .*$/arp -d \1/p' | \
+		sh >/dev/null 2>&1
+}
+
+delete_old_address() {
+	eval "$IFCONFIG $interface inet -alias $old_ip_address $medium"
+}
+
+add_new_address() {
+	eval "$IFCONFIG $interface \
+		inet $new_ip_address \
+		netmask $new_subnet_mask \
+		broadcast $new_broadcast_address \
+		$medium"
+
+	$LOGGER "New IP Address ($interface): $new_ip_address"
+	$LOGGER "New Subnet Mask ($interface): $new_subnet_mask"
+	$LOGGER "New Broadcast Address ($interface): $new_broadcast_address"
+	$LOGGER "New Routers ($interface): $new_routers"
+}
+
+delete_old_alias() {
+	if [ -n "$alias_ip_address" ]; then
+		$IFCONFIG $interface inet -alias $alias_ip_address > /dev/null 2>&1
+		#route delete $alias_ip_address $LOCALHOST > /dev/null 2>&1
+	fi
+}
+
+add_new_alias() {
+	if [ -n "$alias_ip_address" ]; then
+		$IFCONFIG $interface inet alias $alias_ip_address netmask \
+		    $alias_subnet_mask
+		#route add $alias_ip_address $LOCALHOST
+	fi
+}
+
+fill_classless_routes() {
+	set $1
+	while [ $# -ge 5 ]; do
+		if [ $1 -eq 0 ]; then
+			route="default"
+		elif [ $1 -le 8 ]; then
+			route="$2.0.0.0/$1"
+			shift
+		elif [ $1 -le 16 ]; then
+			route="$2.$3.0.0/$1"
+			shift; shift
+		elif [ $1 -le 24 ]; then
+			route="$2.$3.$4.0/$1"
+			shift; shift; shift
+		else
+			route="$2.$3.$4.$5/$1"
+			shift; shift; shift; shift
+		fi
+		shift
+		router="$1.$2.$3.$4"
+		classless_routes="$classless_routes $route $router"
+		shift; shift; shift; shift
+	done
+}
+
+delete_old_routes() {
+	#route delete "$old_ip_address" $LOCALHOST >/dev/null 2>&1
+	if [ -n "$old_classless_routes" ]; then
+		fill_classless_routes "$old_classless_routes"
+		set $classless_routes
+		while [ $# -gt 1 ]; do
+			route delete "$1" "$2"
+			shift; shift
+		done
+		return 0;
+	fi
+
+	# If we supported multiple default routes, we'd be removing each
+	# one here.  We don't so just delete the default route if it's
+	# through our interface.
+	if is_default_interface; then
+		route delete default >/dev/null 2>&1
+	fi
+
+	if [ -n "$old_static_routes" ]; then
+		set $old_static_routes
+		while [ $# -gt 1 ]; do
+			route delete "$1" "$2"
+			shift; shift
+		done
+	fi
+
+	arp_flush
+}
+
+add_new_routes() {
+	#route add $new_ip_address $LOCALHOST >/dev/null 2>&1
+
+	# RFC 3442: If the DHCP server returns both a Classless Static
+	# Routes option and a Router option, the DHCP client MUST ignore
+	# the Router option.
+	#
+	# DHCP clients that support this option (Classless Static Routes)
+	# MUST NOT install the routes specified in the Static Routes
+	# option (option code 33) if both a Static Routes option and the
+	# Classless Static Routes option are provided.
+
+	if [ -n "$new_classless_routes" ]; then
+		fill_classless_routes "$new_classless_routes"
+		$LOGGER "New Classless Static Routes ($interface): $classless_routes"
+		set $classless_routes
+		while [ $# -gt 1 ]; do
+			if [ "0.0.0.0" = "$2" ]; then
+				route add "$1" -iface "$interface"
+			else
+				route add "$1" "$2"
+			fi
+			shift; shift
+		done
+		return
+	fi
+
+	for router in $new_routers; do
+		if is_default_interface; then
+
+			if [ "$new_ip_address" = "$router" ]; then
+				route add default -iface $router >/dev/null 2>&1
+			else
+				route add default $router >/dev/null 2>&1
+			fi
+		fi
+		# 2nd and subsequent default routers error out, so explicitly
+		# stop processing the list after the first one.
+		break
+	done
+
+	if [ -n "$new_static_routes" ]; then
+		$LOGGER "New Static Routes ($interface): $new_static_routes"
+		set $new_static_routes
+		while [ $# -gt 1 ]; do
+			route add $1 $2
+			shift; shift
+		done
+	fi
+}
+
+add_new_resolv_conf() {
+	# XXX Old code did not create/update resolv.conf unless both
+	# $new_domain_name and $new_domain_name_servers were provided.  PR
+	# #3135 reported some ISP's only provide $new_domain_name_servers and
+	# thus broke the script. This code creates the resolv.conf if either
+	# are provided.
+
+	local tmpres=/var/run/resolv.conf.${interface}
+	rm -f $tmpres
+
+	if [ -n "$new_domain_name" ]; then
+		echo "search $new_domain_name" >>$tmpres
+	fi
+
+	if [ -n "$new_domain_name_servers" ]; then
+		for nameserver in $new_domain_name_servers; do
+			echo "nameserver $nameserver" >>$tmpres
+		done
+	fi
+
+	if [ -f $tmpres ]; then
+		if [ -f /etc/resolv.conf.tail ]; then
+			cat /etc/resolv.conf.tail >>$tmpres
+		fi
+
+		# When resolv.conf is not changed actually, we don't
+		# need to update it.
+		# If /usr is not mounted yet, we cannot use cmp, then
+		# the following test fails.  In such case, we simply
+		# ignore an error and do update resolv.conf.
+		if cmp -s $tmpres /etc/resolv.conf; then
+			rm -f $tmpres
+			return 0
+		fi 2>/dev/null
+
+		# In case (e.g. during OpenBSD installs) /etc/resolv.conf
+		# is a symbolic link, take care to preserve the link and write
+		# the new data in the correct location.
+
+		if [ -f /etc/resolv.conf ]; then
+			cat /etc/resolv.conf > /etc/resolv.conf.save
+		fi
+		cat $tmpres > /etc/resolv.conf
+		rm -f $tmpres
+
+		# Try to ensure correct ownership and permissions.
+		chown -RL root:wheel /etc/resolv.conf
+		chmod -RL 644 /etc/resolv.conf
+
+		return 0
+	fi
+
+	return 1
+}
+
+# Must be used on exit.   Invokes the local dhcp client exit hooks, if any.
+exit_with_hooks() {
+	exit_status=$1
+	if [ -f /etc/dhclient-exit-hooks ]; then
+		. /etc/dhclient-exit-hooks
+	fi
+	# probably should do something with exit status of the local script
+	exit $exit_status
+}
+
+# Get the interface with the current ipv4 default route on it using only
+# commands that are available prior to /usr being mounted.
+is_default_interface()
+{
+	routeget="`route -n get -inet default`"
+	oldifs="$IFS"
+	IFS="
+"
+	defif=
+	for line in $routeget ; do
+		case $line in
+		*interface:*)
+			defif=${line##*: }
+			;;
+		esac
+	done
+	IFS=${oldifs}
+
+	if [ -z "$defif" -o "$defif" = "$interface" ]; then
+		return 0
+	else
+		return 1
+	fi
+}
+
+#
+# Start of active code.
+#
+
+# Invoke the local dhcp client enter hooks, if they exist.
+if [ -f /etc/dhclient-enter-hooks ]; then
+	exit_status=0
+	. /etc/dhclient-enter-hooks
+	# allow the local script to abort processing of this state
+	# local script must set exit_status variable to nonzero.
+	if [ $exit_status -ne 0 ]; then
+		exit $exit_status
+	fi
+fi
+
+case $reason in
+MEDIUM)
+	eval "$IFCONFIG $interface $medium"
+	eval "$IFCONFIG $interface inet -alias 0.0.0.0 $medium" >/dev/null 2>&1
+	sleep 1
+	;;
+
+PREINIT)
+	delete_old_alias
+	$IFCONFIG $interface inet alias 0.0.0.0 netmask 0.0.0.0 broadcast 255.255.255.255 up
+	;;
+
+ARPCHECK|ARPSEND)
+	;;
+
+BOUND|RENEW|REBIND|REBOOT)
+	check_hostname
+	if [ -n "$old_ip_address" ]; then
+		if [ "$old_ip_address" != "$alias_ip_address" ]; then
+			delete_old_alias
+		fi
+		if [ "$old_ip_address" != "$new_ip_address" ]; then
+			delete_old_address
+			delete_old_routes
+		fi
+	fi
+	if [ "$reason" = BOUND ] || \
+	   [ "$reason" = REBOOT ] || \
+	   [ -z "$old_ip_address" ] || \
+	   [ "$old_ip_address" != "$new_ip_address" ]; then
+		add_new_address
+		add_new_routes
+	fi
+	if [ "$new_ip_address" != "$alias_ip_address" ]; then
+		add_new_alias
+	fi
+	if is_default_interface; then
+		add_new_resolv_conf
+	fi
+	;;
+
+EXPIRE|FAIL)
+	delete_old_alias
+	if [ -n "$old_ip_address" ]; then
+		delete_old_address
+		delete_old_routes
+	fi
+	if [ -x $ARP ]; then
+		$ARP -d -a -i $interface
+	fi
+	# XXX Why add alias we just deleted above?
+	add_new_alias
+	if is_default_interface; then
+		if [ -f /etc/resolv.conf.save ]; then
+			cat /etc/resolv.conf.save > /etc/resolv.conf
+		fi
+	fi
+	;;
+
+TIMEOUT)
+	delete_old_alias
+	add_new_address
+	sleep 1
+	if [ -n "$new_routers" ]; then
+		$LOGGER "New Routers ($interface): $new_routers"
+		set "$new_routers"
+		if ping -q -c 1 -t 1 "$1"; then
+			if [ "$new_ip_address" != "$alias_ip_address" ]; then
+				add_new_alias
+			fi
+			add_new_routes
+			if ! is_default_interface; then
+				exit_with_hooks 0
+			fi
+			if add_new_resolv_conf; then
+				exit_with_hooks 0
+			fi
+		fi
+	fi
+	eval "$IFCONFIG $interface inet -alias $new_ip_address $medium"
+	delete_old_routes
+	exit_with_hooks 1
+	;;
+esac
+
+exit_with_hooks 0
diff --git a/freebsd-userspace/commands/sbin/dhclient/dhclient-script.8 b/freebsd-userspace/commands/sbin/dhclient/dhclient-script.8
new file mode 100644
index 0000000..89d43cb
--- /dev/null
+++ b/freebsd-userspace/commands/sbin/dhclient/dhclient-script.8
@@ -0,0 +1,297 @@
+.\"	$OpenBSD: dhclient-script.8,v 1.2 2004/04/09 18:30:15 jmc Exp $
+.\"
+.\" Copyright (c) 1997 The Internet Software Consortium.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of The Internet Software Consortium nor the names
+.\"    of its contributors may be used to endorse or promote products derived
+.\"    from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM 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 INTERNET SOFTWARE CONSORTIUM 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 software has been written for the Internet Software Consortium
+.\" by Ted Lemon <mellon at fugue.com> in cooperation with Vixie
+.\" Enterprises.  To learn more about the Internet Software Consortium,
+.\" see ``http://www.isc.org/isc''.  To learn more about Vixie
+.\" Enterprises, see ``http://www.vix.com''.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd September 6, 2010
+.Dt DHCLIENT-SCRIPT 8
+.Os
+.Sh NAME
+.Nm dhclient-script
+.Nd DHCP client network configuration script
+.Sh DESCRIPTION
+The DHCP client network configuration script is invoked from time to
+time by
+.Xr dhclient 8 .
+This script is used by the DHCP client to set each interface's initial
+configuration prior to requesting an address, to test the address once it
+has been offered, and to set the interface's final configuration once a
+lease has been acquired.
+If no lease is acquired, the script is used to test predefined leases, if
+any, and also called once if no valid lease can be identified.
+.Pp
+.\" No standard client script exists for some operating systems, even though
+.\" the actual client may work, so a pioneering user may well need to create
+.\" a new script or modify an existing one.
+In general, customizations specific to a particular computer should be done
+in the
+.Pa /etc/dhclient.conf
+file.
+.Sh OPERATION
+When
+.Xr dhclient 8
+needs to invoke the client configuration script, it sets up a number of
+environment variables and runs
+.Nm .
+In all cases,
+.Va $reason
+is set to the name of the reason why the script has been invoked.
+The following reasons are currently defined:
+.Li MEDIUM , PREINIT , ARPCHECK , ARPSEND , BOUND , RENEW , REBIND , REBOOT ,
+.Li EXPIRE , FAIL
+and
+.Li TIMEOUT .
+.Bl -tag -width ".Li ARPCHECK"
+.It Li MEDIUM
+The DHCP client is requesting that an interface's media type be set.
+The interface name is passed in
+.Va $interface ,
+and the media type is passed in
+.Va $medium .
+.It Li PREINIT
+The DHCP client is requesting that an interface be configured as
+required in order to send packets prior to receiving an actual address.
+.\" For clients which use the BSD socket library,
+This means configuring the interface with an IP address of 0.0.0.0
+and a broadcast address of 255.255.255.255.
+.\" For other clients, it may be possible to simply configure the interface up
+.\" without actually giving it an IP address at all.
+The interface name is passed in
+.Va $interface ,
+and the media type in
+.Va $medium .
+.Pp
+If an IP alias has been declared in
+.Xr dhclient.conf 5 ,
+its address will be passed in
+.Va $alias_ip_address ,
+and that IP alias should be deleted from the interface,
+along with any routes to it.
+.It Li ARPSEND
+The DHCP client is requesting that an address that has been offered to
+it be checked to see if somebody else is using it, by sending an ARP
+request for that address.
+It is not clear how to implement this, so no examples exist yet.
+The IP address to check is passed in
+.Va $new_ip_address ,
+and the interface name is passed in
+.Va $interface .
+.It Li ARPCHECK
+The DHCP client wants to know if a response to the ARP request sent
+using
+.Li ARPSEND
+has been received.
+If one has, the script should exit with a nonzero status, indicating that
+the offered address has already been requested and should be declined.
+The
+.Va $new_ip_address
+and
+.Va $interface
+variables are set as with
+.Li ARPSEND .
+.It Li BOUND
+The DHCP client has done an initial binding to a new address.
+The new IP address is passed in
+.Va $new_ip_address ,
+and the interface name is passed in
+.Va $interface .
+The media type is passed in
+.Va $medium .
+Any options acquired from the server are passed using the option name
+described in
+.Xr dhcp-options 5 ,
+except that dashes
+.Pq Ql -
+are replaced by underscores
+.Pq Ql _
+in order to make valid shell variables, and the variable names start with
+.Dq Li new_ .
+So for example, the new subnet mask would be passed in
+.Va $new_subnet_mask .
+.Pp
+When a binding has been completed, a lot of network parameters are
+likely to need to be set up.
+A new
+.Pa /etc/resolv.conf
+needs to be created, using the values of
+.Va $new_domain_name
+and
+.Va $new_domain_name_servers
+(which may list more than one server, separated by spaces).
+A default route should be set using
+.Va $new_routers ,
+and static routes may need to be set up using
+.Va $new_static_routes .
+.Pp
+If an IP alias has been declared, it must be set up here.
+The alias IP address will be written as
+.Va $alias_ip_address ,
+and other DHCP options that are set for the alias (e.g., subnet mask)
+will be passed in variables named as described previously except starting with
+.Dq Li $alias_
+instead of
+.Dq Li $new_ .
+Care should be taken that the alias IP address not be used if it is identical
+to the bound IP address
+.Pq Va $new_ip_address ,
+since the other alias parameters may be incorrect in this case.
+.It Li RENEW
+When a binding has been renewed, the script is called as in
+.Li BOUND ,
+except that in addition to all the variables starting with
+.Dq Li $new_ ,
+there is another set of variables starting with
+.Dq Li $old_ .
+Persistent settings that may have changed need to be deleted - for example,
+if a local route to the bound address is being configured, the old local
+route should be deleted.
+If the default route has changed, the old default route should be deleted.
+If the static routes have changed, the old ones should be deleted.
+Otherwise, processing can be done as with
+.Li BOUND .
+.It Li REBIND
+The DHCP client has rebound to a new DHCP server.
+This can be handled as with
+.Li RENEW ,
+except that if the IP address has changed,
+the ARP table should be cleared.
+.It Li REBOOT
+The DHCP client has successfully reacquired its old address after a reboot.
+This can be processed as with
+.Li BOUND .
+.It Li EXPIRE
+The DHCP client has failed to renew its lease or acquire a new one,
+and the lease has expired.
+The IP address must be relinquished, and all related parameters should be
+deleted, as in
+.Li RENEW
+and
+.Li REBIND .
+.It Li FAIL
+The DHCP client has been unable to contact any DHCP servers, and any
+leases that have been tested have not proved to be valid.
+The parameters from the last lease tested should be deconfigured.
+This can be handled in the same way as
+.Li EXPIRE .
+.It Li TIMEOUT
+The DHCP client has been unable to contact any DHCP servers.
+However, an old lease has been identified, and its parameters have
+been passed in as with
+.Li BOUND .
+The client configuration script should test these parameters and,
+if it has reason to believe they are valid, should exit with a value of zero.
+If not, it should exit with a nonzero value.
+.El
+.Pp
+Before taking action according to
+.Va $reason ,
+.Nm
+will check for the existence of
+.Pa /etc/dhclient-enter-hooks .
+If found, it will be sourced
+.Pq see Xr sh 1 .
+After taking action according to
+.Va $reason ,
+.Nm
+will check for the existence of
+.Pa /etc/dhclient-exit-hooks .
+If found, it will be sourced
+.Pq see Xr sh 1 .
+These hooks scripts can be used to dynamically modify the enviornment at
+appropriate times during the DHCP negotiations.
+For example, if the administrator wishes to disable alias IP numbers on
+the DHCP interface, they might want to put the following in
+.Pa /etc/dhclient-enter-hooks :
+.Bd -literal -offset indent
+[ ."$reason" = .PREINIT ] && ifconfig $interface 0.0.0.0
+.Ed
+.Pp
+The usual way to test a lease is to set up the network as with
+.Li REBIND
+(since this may be called to test more than one lease) and then ping
+the first router defined in
+.Va $routers .
+If a response is received, the lease must be valid for the network to
+which the interface is currently connected.
+It would be more complete to try to ping all of the routers listed in
+.Va $new_routers ,
+as well as those listed in
+.Va $new_static_routes ,
+but current scripts do not do this.
+.\" .Sh FILES
+.\" Each operating system should generally have its own script file,
+.\" although the script files for similar operating systems may be similar
+.\" or even identical.
+.\" The script files included in the Internet Software Consortium DHCP
+.\" distribution appear in the distribution tree under client/scripts,
+.\" and bear the names of the operating systems on which they are intended
+.\" to work.
+.Sh SEE ALSO
+.Xr sh 1 ,
+.Xr dhclient.conf 5 ,
+.Xr dhclient.leases 5 ,
+.Xr dhclient 8 ,
+.Xr dhcpd 8 ,
+.Xr dhcrelay 8
+.Sh AUTHORS
+.An -nosplit
+The original version of
+.Nm
+was written for the Internet Software Consortium by
+.An Ted Lemon Aq mellon at fugue.com
+in cooperation with Vixie Enterprises.
+.Pp
+The
+.Ox
+implementation of
+.Nm
+was written by
+.An Kenneth R. Westerback Aq krw at openbsd.org .
+.Sh BUGS
+If more than one interface is being used, there is no obvious way to
+avoid clashes between server-supplied configuration parameters - for
+example, the stock
+.Nm
+rewrites
+.Pa /etc/resolv.conf .
+If more than one interface is being configured,
+.Pa /etc/resolv.conf
+will be repeatedly initialized to the values provided by one server, and then
+the other.
+Assuming the information provided by both servers is valid, this should not
+cause any real problems, but it could be confusing.
diff --git a/freebsd-userspace/commands/sbin/dhclient/dhclient.8 b/freebsd-userspace/commands/sbin/dhclient/dhclient.8
new file mode 100644
index 0000000..58f5ddd
--- /dev/null
+++ b/freebsd-userspace/commands/sbin/dhclient/dhclient.8
@@ -0,0 +1,191 @@
+.\" $OpenBSD: dhclient.8,v 1.3 2004/04/09 18:30:15 jmc Exp $
+.\"
+.\" Copyright (c) 1997 The Internet Software Consortium.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of The Internet Software Consortium nor the names
+.\"    of its contributors may be used to endorse or promote products derived
+.\"    from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM 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 INTERNET SOFTWARE CONSORTIUM 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 software has been written for the Internet Software Consortium
+.\" by Ted Lemon <mellon at fugue.com> in cooperation with Vixie
+.\" Enterprises.  To learn more about the Internet Software Consortium,
+.\" see ``http://www.isc.org/isc''.  To learn more about Vixie
+.\" Enterprises, see ``http://www.vix.com''.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd August 13, 2007
+.Dt DHCLIENT 8
+.Os
+.Sh NAME
+.Nm dhclient
+.Nd "Dynamic Host Configuration Protocol (DHCP) client"
+.Sh SYNOPSIS
+.Nm
+.Op Fl bdqu
+.Op Fl c Ar file
+.Op Fl l Ar file
+.Ar interface
+.Sh DESCRIPTION
+The
+.Nm
+utility provides a means for configuring network interfaces using DHCP, BOOTP,
+or if these protocols fail, by statically assigning an address.
+.Pp
+The name of the network interface that
+.Nm
+should attempt to
+configure must be specified on the command line.
+.Pp
+The options are as follows:
+.Bl -tag -width ".Fl c Ar file"
+.It Fl b
+Forces
+.Nm
+to immediately move to the background.
+.It Fl c Ar file
+Specify an alternate location,
+.Ar file ,
+for the configuration file.
+.It Fl d
+Forces
+.Nm
+to always run as a foreground process.
+By default,
+.Nm
+runs in the foreground until it has configured the interface, and then
+will revert to running in the background.
+.It Fl l Ar file
+Specify an alternate location,
+.Ar file ,
+for the leases file.
+.It Fl q
+Forces
+.Nm
+to be less verbose on startup.
+.It Fl u
+Forces
+.Nm
+to reject leases with unknown options in them.
+The default behaviour is to accept such lease offers.
+.El
+.Pp
+The DHCP protocol allows a host to contact a central server which
+maintains a list of IP addresses which may be assigned on one or more
+subnets.
+A DHCP client may request an address from this pool, and
+then use it on a temporary basis for communication on the network.
+The DHCP protocol also provides a mechanism whereby a client can learn
+important details about the network to which it is attached, such as
+the location of a default router, the location of a name server, and
+so on.
+.Pp
+On startup,
+.Nm
+reads
+.Pa /etc/dhclient.conf
+for configuration instructions.
+It then gets a list of all the
+network interfaces that are configured in the current system.
+It then attempts to configure each interface with DHCP.
+.Pp
+In order to keep track of leases across system reboots and server
+restarts,
+.Nm
+keeps a list of leases it has been assigned in the
+.Pa /var/db/dhclient.leases. Ns Ar IFNAME
+file.
+.Ar IFNAME
+represents the network interface of the DHCP client
+(e.g.,
+.Li em0 ) ,
+one for each interface.
+On startup, after reading the
+.Xr dhclient.conf 5
+file,
+.Nm
+reads the leases file to refresh its memory about what leases it has been
+assigned.
+.Pp
+Old leases are kept around in case the DHCP server is unavailable when
+.Nm
+is first invoked (generally during the initial system boot
+process).
+In that event, old leases from the
+.Pa dhclient.leases. Ns Ar IFNAME
+file which have not yet expired are tested, and if they are determined to
+be valid, they are used until either they expire or the DHCP server
+becomes available.
+.Pp
+A mobile host which may sometimes need to access a network on which no
+DHCP server exists may be preloaded with a lease for a fixed
+address on that network.
+When all attempts to contact a DHCP server have failed,
+.Nm
+will try to validate the static lease, and if it
+succeeds, it will use that lease until it is restarted.
+.Pp
+A mobile host may also travel to some networks on which DHCP is not
+available but BOOTP is.
+In that case, it may be advantageous to
+arrange with the network administrator for an entry on the BOOTP
+database, so that the host can boot quickly on that network rather
+than cycling through the list of old leases.
+.Sh NOTES
+You must have the Berkeley Packet Filter (BPF) configured in your kernel.
+The
+.Nm
+utility
+requires at least one
+.Pa /dev/bpf*
+device for each broadcast network interface that is attached to your system.
+See
+.Xr bpf 4
+for more information.
+.Sh FILES
+.Bl -tag -width ".Pa /var/db/dhclient.leases. Ns Ar IFNAME" -compact
+.It Pa /etc/dhclient.conf
+DHCP client configuration file
+.It Pa /var/db/dhclient.leases. Ns Ar IFNAME
+database of acquired leases
+.El
+.Sh SEE ALSO
+.Xr dhclient.conf 5 ,
+.Xr dhclient.leases 5 ,
+.Xr dhclient-script 8
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm
+utility
+was written by
+.An Ted Lemon Aq mellon at fugue.com
+and
+.An Elliot Poger Aq elliot at poger.com .
+.Pp
+The current implementation was reworked by
+.An Henning Brauer Aq henning at openbsd.org .
diff --git a/freebsd-userspace/commands/sbin/dhclient/dhclient.c b/freebsd-userspace/commands/sbin/dhclient/dhclient.c
new file mode 100644
index 0000000..f3c1259
--- /dev/null
+++ b/freebsd-userspace/commands/sbin/dhclient/dhclient.c
@@ -0,0 +1,2669 @@
+/*	$OpenBSD: dhclient.c,v 1.63 2005/02/06 17:10:13 krw Exp $	*/
+
+/*
+ * Copyright 2004 Henning Brauer <henning at openbsd.org>
+ * Copyright (c) 1995, 1996, 1997, 1998, 1999
+ * The Internet Software Consortium.    All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of The Internet Software Consortium nor the names
+ *    of its contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM 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 INTERNET SOFTWARE CONSORTIUM 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 software has been written for the Internet Software Consortium
+ * by Ted Lemon <mellon at fugue.com> in cooperation with Vixie
+ * Enterprises.  To learn more about the Internet Software Consortium,
+ * see ``http://www.vix.com/isc''.  To learn more about Vixie
+ * Enterprises, see ``http://www.vix.com''.
+ *
+ * This client was substantially modified and enhanced by Elliot Poger
+ * for use on Linux while he was working on the MosquitoNet project at
+ * Stanford.
+ *
+ * The current version owes much to Elliot's Linux enhancements, but
+ * was substantially reorganized and partially rewritten by Ted Lemon
+ * so as to use the same networking framework that the Internet Software
+ * Consortium DHCP server uses.   Much system-specific configuration code
+ * was moved into a shell script so that as support for more operating
+ * systems is added, it will not be necessary to port and maintain
+ * system-specific configuration code to these operating systems - instead,
+ * the shell script can invoke the native tools to accomplish the same
+ * purpose.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "dhcpd.h"
+#include "privsep.h"
+
+#ifdef __rtems__
+#include <freebsd/net80211/ieee80211_freebsd.h>
+#else
+#include <net80211/ieee80211_freebsd.h>
+#endif
+
+#ifndef _PATH_VAREMPTY
+#define	_PATH_VAREMPTY	"/var/empty"
+#endif
+
+#define	PERIOD 0x2e
+#define	hyphenchar(c) ((c) == 0x2d)
+#define	bslashchar(c) ((c) == 0x5c)
+#define	periodchar(c) ((c) == PERIOD)
+#define	asterchar(c) ((c) == 0x2a)
+#define	alphachar(c) (((c) >= 0x41 && (c) <= 0x5a) || \
+	    ((c) >= 0x61 && (c) <= 0x7a))
+#define	digitchar(c) ((c) >= 0x30 && (c) <= 0x39)
+#define	whitechar(c) ((c) == ' ' || (c) == '\t')
+
+#define	borderchar(c) (alphachar(c) || digitchar(c))
+#define	middlechar(c) (borderchar(c) || hyphenchar(c))
+#define	domainchar(c) ((c) > 0x20 && (c) < 0x7f)
+
+#define	CLIENT_PATH "PATH=/usr/bin:/usr/sbin:/bin:/sbin"
+
+time_t cur_time;
+time_t default_lease_time = 43200; /* 12 hours... */
+
+char *path_dhclient_conf = _PATH_DHCLIENT_CONF;
+char *path_dhclient_db = NULL;
+
+int log_perror = 1;
+int privfd;
+int nullfd = -1;
+
+struct iaddr iaddr_broadcast = { 4, { 255, 255, 255, 255 } };
+struct in_addr inaddr_any;
+struct sockaddr_in sockaddr_broadcast;
+
+/*
+ * ASSERT_STATE() does nothing now; it used to be
+ * assert (state_is == state_shouldbe).
+ */
+#define ASSERT_STATE(state_is, state_shouldbe) {}
+
+#define TIME_MAX 2147483647
+
+int		log_priority;
+int		no_daemon;
+int		unknown_ok = 1;
+int		routefd;
+
+struct interface_info	*ifi;
+
+int		 findproto(char *, int);
+struct sockaddr	*get_ifa(char *, int);
+void		 routehandler(struct protocol *);
+void		 usage(void);
+int		 check_option(struct client_lease *l, int option);
+int		 check_classless_option(unsigned char *data, int len);
+int		 ipv4addrs(char * buf);
+int		 res_hnok(const char *dn);
+int		 check_search(const char *srch);
+char		*option_as_string(unsigned int code, unsigned char *data, int len);
+int		 fork_privchld(int, int);
+
+#define	ROUNDUP(a) \
+	    ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
+#define	ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
+
+static time_t	scripttime;
+
+int
+findproto(char *cp, int n)
+{
+	struct sockaddr *sa;
+	int i;
+
+	if (n == 0)
+		return -1;
+	for (i = 1; i; i <<= 1) {
+		if (i & n) {
+			sa = (struct sockaddr *)cp;
+			switch (i) {
+			case RTA_IFA:
+			case RTA_DST:
+			case RTA_GATEWAY:
+			case RTA_NETMASK:
+				if (sa->sa_family == AF_INET)
+					return AF_INET;
+				if (sa->sa_family == AF_INET6)
+					return AF_INET6;
+				break;
+			case RTA_IFP:
+				break;
+			}
+			ADVANCE(cp, sa);
+		}
+	}
+	return (-1);
+}
+
+struct sockaddr *
+get_ifa(char *cp, int n)
+{
+	struct sockaddr *sa;
+	int i;
+
+	if (n == 0)
+		return (NULL);
+	for (i = 1; i; i <<= 1)
+		if (i & n) {
+			sa = (struct sockaddr *)cp;
+			if (i == RTA_IFA)
+				return (sa);
+			ADVANCE(cp, sa);
+		}
+
+	return (NULL);
+}
+
+struct iaddr defaddr = { 4 };
+uint8_t curbssid[6];
+
+static void
+disassoc(void *arg)
+{
+	struct interface_info *ifi = arg;
+
+	/*
+	 * Clear existing state.
+	 */
+	if (ifi->client->active != NULL) {
+		script_init("EXPIRE", NULL);
+		script_write_params("old_",
+		    ifi->client->active);
+		if (ifi->client->alias)
+			script_write_params("alias_",
+				ifi->client->alias);
+		script_go();
+	}
+	ifi->client->state = S_INIT;
+}
+
+/* ARGSUSED */
+void
+routehandler(struct protocol *p)
+{
+	char msg[2048], *addr;
+	struct rt_msghdr *rtm;
+	struct if_msghdr *ifm;
+	struct ifa_msghdr *ifam;
+	struct if_announcemsghdr *ifan;
+	struct ieee80211_join_event *jev;
+	struct client_lease *l;
+	time_t t = time(NULL);
+	struct sockaddr *sa;
+	struct iaddr a;
+	ssize_t n;
+
+	n = read(routefd, &msg, sizeof(msg));
+	rtm = (struct rt_msghdr *)msg;
+	if (n < sizeof(rtm->rtm_msglen) || n < rtm->rtm_msglen ||
+	    rtm->rtm_version != RTM_VERSION)
+		return;
+
+	switch (rtm->rtm_type) {
+	case RTM_NEWADDR:
+	case RTM_DELADDR:
+		ifam = (struct ifa_msghdr *)rtm;
+
+		if (ifam->ifam_index != ifi->index)
+			break;
+		if (findproto((char *)(ifam + 1), ifam->ifam_addrs) != AF_INET)
+			break;
+		if (scripttime == 0 || t < scripttime + 10)
+			break;
+
+		sa = get_ifa((char *)(ifam + 1), ifam->ifam_addrs);
+		if (sa == NULL)
+			break;
+
+		if ((a.len = sizeof(struct in_addr)) > sizeof(a.iabuf))
+			error("king bula sez: len mismatch");
+		memcpy(a.iabuf, &((struct sockaddr_in *)sa)->sin_addr, a.len);
+		if (addr_eq(a, defaddr))
+			break;
+
+		for (l = ifi->client->active; l != NULL; l = l->next)
+			if (addr_eq(a, l->address))
+				break;
+
+		if (l == NULL)	/* added/deleted addr is not the one we set */
+			break;
+
+		addr = inet_ntoa(((struct sockaddr_in *)sa)->sin_addr);
+		if (rtm->rtm_type == RTM_NEWADDR)  {
+			/*
+			 * XXX: If someone other than us adds our address,
+			 * should we assume they are taking over from us,
+			 * delete the lease record, and exit without modifying
+			 * the interface?
+			 */
+			warning("My address (%s) was re-added", addr);
+		} else {
+			warning("My address (%s) was deleted, dhclient exiting",
+			    addr);
+			goto die;
+		}
+		break;
+	case RTM_IFINFO:
+		ifm = (struct if_msghdr *)rtm;
+		if (ifm->ifm_index != ifi->index)
+			break;
+		if ((rtm->rtm_flags & RTF_UP) == 0) {
+			warning("Interface %s is down, dhclient exiting",
+			    ifi->name);
+			goto die;
+		}
+		break;
+	case RTM_IFANNOUNCE:
+		ifan = (struct if_announcemsghdr *)rtm;
+		if (ifan->ifan_what == IFAN_DEPARTURE &&
+		    ifan->ifan_index == ifi->index) {
+			warning("Interface %s is gone, dhclient exiting",
+			    ifi->name);
+			goto die;
+		}
+		break;
+	case RTM_IEEE80211:
+		ifan = (struct if_announcemsghdr *)rtm;
+		if (ifan->ifan_index != ifi->index)
+			break;
+		switch (ifan->ifan_what) {
+		case RTM_IEEE80211_ASSOC:
+		case RTM_IEEE80211_REASSOC:
+			/*
+			 * Use assoc/reassoc event to kick state machine
+			 * in case we roam.  Otherwise fall back to the
+			 * normal state machine just like a wired network.
+			 */
+			jev = (struct ieee80211_join_event *) &ifan[1];
+			if (memcmp(curbssid, jev->iev_addr, 6)) {
+				disassoc(ifi);
+				state_reboot(ifi);
+			}
+			memcpy(curbssid, jev->iev_addr, 6);
+			break;
+		}
+		break;
+	default:
+		break;
+	}
+	return;
+
+die:
+	script_init("FAIL", NULL);
+	if (ifi->client->alias)
+		script_write_params("alias_", ifi->client->alias);
+	script_go();
+	exit(1);
+}
+
+int
+main(int argc, char *argv[])
+{
+	extern char		*__progname;
+	int			 ch, fd, quiet = 0, i = 0;
+	int			 pipe_fd[2];
+	int			 immediate_daemon = 0;
+	struct passwd		*pw;
+
+	/* Initially, log errors to stderr as well as to syslogd. */
+	openlog(__progname, LOG_PID | LOG_NDELAY, DHCPD_LOG_FACILITY);
+	setlogmask(LOG_UPTO(LOG_DEBUG));
+
+	while ((ch = getopt(argc, argv, "bc:dl:qu")) != -1)
+		switch (ch) {
+		case 'b':
+			immediate_daemon = 1;
+			break;
+		case 'c':
+			path_dhclient_conf = optarg;
+			break;
+		case 'd':
+			no_daemon = 1;
+			break;
+		case 'l':
+			path_dhclient_db = optarg;
+			break;
+		case 'q':
+			quiet = 1;
+			break;
+		case 'u':
+			unknown_ok = 0;
+			break;
+		default:
+			usage();
+		}
+
+	argc -= optind;
+	argv += optind;
+
+	if (argc != 1)
+		usage();
+
+	if ((ifi = calloc(1, sizeof(struct interface_info))) == NULL)
+		error("calloc");
+	if (strlcpy(ifi->name, argv[0], IFNAMSIZ) >= IFNAMSIZ)
+		error("Interface name too long");
+	if (path_dhclient_db == NULL && asprintf(&path_dhclient_db, "%s.%s",
+	    _PATH_DHCLIENT_DB, ifi->name) == -1)
+		error("asprintf");
+
+	if (quiet)
+		log_perror = 0;
+
+	tzset();
+	time(&cur_time);
+
+	memset(&sockaddr_broadcast, 0, sizeof(sockaddr_broadcast));
+	sockaddr_broadcast.sin_family = AF_INET;
+	sockaddr_broadcast.sin_port = htons(REMOTE_PORT);
+	sockaddr_broadcast.sin_addr.s_addr = INADDR_BROADCAST;
+	sockaddr_broadcast.sin_len = sizeof(sockaddr_broadcast);
+	inaddr_any.s_addr = INADDR_ANY;
+
+	read_client_conf();
+
+	if (!interface_link_status(ifi->name)) {
+		fprintf(stderr, "%s: no link ...", ifi->name);
+		fflush(stderr);
+		sleep(1);
+		while (!interface_link_status(ifi->name)) {
+			fprintf(stderr, ".");
+			fflush(stderr);
+			if (++i > 10) {
+				fprintf(stderr, " giving up\n");
+				exit(1);
+			}
+			sleep(1);
+		}
+		fprintf(stderr, " got link\n");
+	}
+
+	if ((nullfd = open(_PATH_DEVNULL, O_RDWR, 0)) == -1)
+		error("cannot open %s: %m", _PATH_DEVNULL);
+
+	if ((pw = getpwnam("_dhcp")) == NULL) {
+		warning("no such user: _dhcp, falling back to \"nobody\"");
+		if ((pw = getpwnam("nobody")) == NULL)
+			error("no such user: nobody");
+	}
+
+	if (pipe(pipe_fd) == -1)
+		error("pipe");
+
+	fork_privchld(pipe_fd[0], pipe_fd[1]);
+
+	close(pipe_fd[0]);
+	privfd = pipe_fd[1];
+
+	if ((fd = open(path_dhclient_db, O_RDONLY|O_EXLOCK|O_CREAT, 0)) == -1)
+		error("can't open and lock %s: %m", path_dhclient_db);
+	read_client_leases();
+	rewrite_client_leases();
+	close(fd);
+
+	priv_script_init("PREINIT", NULL);
+	if (ifi->client->alias)
+		priv_script_write_params("alias_", ifi->client->alias);
+	priv_script_go();
+
+	if ((routefd = socket(PF_ROUTE, SOCK_RAW, 0)) != -1)
+		add_protocol("AF_ROUTE", routefd, routehandler, ifi);
+
+	/* set up the interface */
+	discover_interfaces(ifi);
+
+	if (chroot(_PATH_VAREMPTY) == -1)
+		error("chroot");
+	if (chdir("/") == -1)
+		error("chdir(\"/\")");
+
+	if (setgroups(1, &pw->pw_gid) ||
+	    setegid(pw->pw_gid) || setgid(pw->pw_gid) ||
+	    seteuid(pw->pw_uid) || setuid(pw->pw_uid))
+		error("can't drop privileges: %m");
+
+	endpwent();
+
+	setproctitle("%s", ifi->name);
+
+	if (immediate_daemon)
+		go_daemon();
+
+	ifi->client->state = S_INIT;
+	state_reboot(ifi);
+
+	bootp_packet_handler = do_packet;
+
+	dispatch();
+
+	/* not reached */
+	return (0);
+}
+
+void
+usage(void)
+{
+	extern char	*__progname;
+
+	fprintf(stderr, "usage: %s [-bdqu] ", __progname);
+	fprintf(stderr, "[-c conffile] [-l leasefile] interface\n");
+	exit(1);
+}
+
+/*
+ * Individual States:
+ *
+ * Each routine is called from the dhclient_state_machine() in one of
+ * these conditions:
+ * -> entering INIT state
+ * -> recvpacket_flag == 0: timeout in this state
+ * -> otherwise: received a packet in this state
+ *
+ * Return conditions as handled by dhclient_state_machine():
+ * Returns 1, sendpacket_flag = 1: send packet, reset timer.
+ * Returns 1, sendpacket_flag = 0: just reset the timer (wait for a milestone).
+ * Returns 0: finish the nap which was interrupted for no good reason.
+ *
+ * Several per-interface variables are used to keep track of the process:
+ *   active_lease: the lease that is being used on the interface
+ *                 (null pointer if not configured yet).
+ *   offered_leases: leases corresponding to DHCPOFFER messages that have
+ *                   been sent to us by DHCP servers.
+ *   acked_leases: leases corresponding to DHCPACK messages that have been
+ *                 sent to us by DHCP servers.
+ *   sendpacket: DHCP packet we're trying to send.
+ *   destination: IP address to send sendpacket to
+ * In addition, there are several relevant per-lease variables.
+ *   T1_expiry, T2_expiry, lease_expiry: lease milestones
+ * In the active lease, these control the process of renewing the lease;
+ * In leases on the acked_leases list, this simply determines when we
+ * can no longer legitimately use the lease.
+ */
+
+void
+state_reboot(void *ipp)
+{
+	struct interface_info *ip = ipp;
+
+	/* If we don't remember an active lease, go straight to INIT. */
+	if (!ip->client->active || ip->client->active->is_bootp) {
+		state_init(ip);
+		return;
+	}
+
+	/* We are in the rebooting state. */
+	ip->client->state = S_REBOOTING;
+
+	/* make_request doesn't initialize xid because it normally comes
+	   from the DHCPDISCOVER, but we haven't sent a DHCPDISCOVER,
+	   so pick an xid now. */
+	ip->client->xid = arc4random();
+
+	/* Make a DHCPREQUEST packet, and set appropriate per-interface
+	   flags. */
+	make_request(ip, ip->client->active);
+	ip->client->destination = iaddr_broadcast;
+	ip->client->first_sending = cur_time;
+	ip->client->interval = ip->client->config->initial_interval;
+
+	/* Zap the medium list... */
+	ip->client->medium = NULL;
+
+	/* Send out the first DHCPREQUEST packet. */
+	send_request(ip);
+}
+
+/*
+ * Called when a lease has completely expired and we've
+ * been unable to renew it.
+ */
+void
+state_init(void *ipp)
+{
+	struct interface_info *ip = ipp;
+
+	ASSERT_STATE(state, S_INIT);
+
+	/* Make a DHCPDISCOVER packet, and set appropriate per-interface
+	   flags. */
+	make_discover(ip, ip->client->active);
+	ip->client->xid = ip->client->packet.xid;
+	ip->client->destination = iaddr_broadcast;
+	ip->client->state = S_SELECTING;
+	ip->client->first_sending = cur_time;
+	ip->client->interval = ip->client->config->initial_interval;
+
+	/* Add an immediate timeout to cause the first DHCPDISCOVER packet
+	   to go out. */
+	send_discover(ip);
+}
+
+/*
+ * state_selecting is called when one or more DHCPOFFER packets
+ * have been received and a configurable period of time has passed.
+ */
+void
+state_selecting(void *ipp)
+{
+	struct interface_info *ip = ipp;
+	struct client_lease *lp, *next, *picked;
+
+	ASSERT_STATE(state, S_SELECTING);
+
+	/* Cancel state_selecting and send_discover timeouts, since either
+	   one could have got us here. */
+	cancel_timeout(state_selecting, ip);
+	cancel_timeout(send_discover, ip);
+
+	/* We have received one or more DHCPOFFER packets.   Currently,
+	   the only criterion by which we judge leases is whether or
+	   not we get a response when we arp for them. */
+	picked = NULL;
+	for (lp = ip->client->offered_leases; lp; lp = next) {
+		next = lp->next;
+
+		/* Check to see if we got an ARPREPLY for the address
+		   in this particular lease. */
+		if (!picked) {
+			script_init("ARPCHECK", lp->medium);
+			script_write_params("check_", lp);
+
+			/* If the ARPCHECK code detects another
+			   machine using the offered address, it exits
+			   nonzero.  We need to send a DHCPDECLINE and
+			   toss the lease. */
+			if (script_go()) {
+				make_decline(ip, lp);
+				send_decline(ip);
+				goto freeit;
+			}
+			picked = lp;
+			picked->next = NULL;
+		} else {
+freeit:
+			free_client_lease(lp);
+		}
+	}
+	ip->client->offered_leases = NULL;
+
+	/* If we just tossed all the leases we were offered, go back
+	   to square one. */
+	if (!picked) {
+		ip->client->state = S_INIT;
+		state_init(ip);
+		return;
+	}
+
+	/* If it was a BOOTREPLY, we can just take the address right now. */
+	if (!picked->options[DHO_DHCP_MESSAGE_TYPE].len) {
+		ip->client->new = picked;
+
+		/* Make up some lease expiry times
+		   XXX these should be configurable. */
+		ip->client->new->expiry = cur_time + 12000;
+		ip->client->new->renewal += cur_time + 8000;
+		ip->client->new->rebind += cur_time + 10000;
+
+		ip->client->state = S_REQUESTING;
+
+		/* Bind to the address we received. */
+		bind_lease(ip);
+		return;
+	}
+
+	/* Go to the REQUESTING state. */
+	ip->client->destination = iaddr_broadcast;
+	ip->client->state = S_REQUESTING;
+	ip->client->first_sending = cur_time;
+	ip->client->interval = ip->client->config->initial_interval;
+
+	/* Make a DHCPREQUEST packet from the lease we picked. */
+	make_request(ip, picked);
+	ip->client->xid = ip->client->packet.xid;
+
+	/* Toss the lease we picked - we'll get it back in a DHCPACK. */
+	free_client_lease(picked);
+
+	/* Add an immediate timeout to send the first DHCPREQUEST packet. */
+	send_request(ip);
+}
+
+/* state_requesting is called when we receive a DHCPACK message after
+   having sent out one or more DHCPREQUEST packets. */
+
+void
+dhcpack(struct packet *packet)
+{
+	struct interface_info *ip = packet->interface;
+	struct client_lease *lease;
+
+	/* If we're not receptive to an offer right now, or if the offer
+	   has an unrecognizable transaction id, then just drop it. */
+	if (packet->interface->client->xid != packet->raw->xid ||
+	    (packet->interface->hw_address.hlen != packet->raw->hlen) ||
+	    (memcmp(packet->interface->hw_address.haddr,
+	    packet->raw->chaddr, packet->raw->hlen)))
+		return;
+
+	if (ip->client->state != S_REBOOTING &&
+	    ip->client->state != S_REQUESTING &&
+	    ip->client->state != S_RENEWING &&
+	    ip->client->state != S_REBINDING)
+		return;
+
+	note("DHCPACK from %s", piaddr(packet->client_addr));
+
+	lease = packet_to_lease(packet);
+	if (!lease) {
+		note("packet_to_lease failed.");
+		return;
+	}
+
+	ip->client->new = lease;
+
+	/* Stop resending DHCPREQUEST. */
+	cancel_timeout(send_request, ip);
+
+	/* Figure out the lease time. */
+	if (ip->client->new->options[DHO_DHCP_LEASE_TIME].data)
+		ip->client->new->expiry = getULong(
+		    ip->client->new->options[DHO_DHCP_LEASE_TIME].data);
+	else
+		ip->client->new->expiry = default_lease_time;
+	/* A number that looks negative here is really just very large,
+	   because the lease expiry offset is unsigned. */
+	if (ip->client->new->expiry < 0)
+		ip->client->new->expiry = TIME_MAX;
+	/* XXX should be fixed by resetting the client state */
+	if (ip->client->new->expiry < 60)
+		ip->client->new->expiry = 60;
+
+	/* Take the server-provided renewal time if there is one;
+	   otherwise figure it out according to the spec. */
+	if (ip->client->new->options[DHO_DHCP_RENEWAL_TIME].len)
+		ip->client->new->renewal = getULong(
+		    ip->client->new->options[DHO_DHCP_RENEWAL_TIME].data);
+	else
+		ip->client->new->renewal = ip->client->new->expiry / 2;
+
+	/* Same deal with the rebind time. */
+	if (ip->client->new->options[DHO_DHCP_REBINDING_TIME].len)
+		ip->client->new->rebind = getULong(
+		    ip->client->new->options[DHO_DHCP_REBINDING_TIME].data);
+	else
+		ip->client->new->rebind = ip->client->new->renewal +
+		    ip->client->new->renewal / 2 + ip->client->new->renewal / 4;
+
+	ip->client->new->expiry += cur_time;
+	/* Lease lengths can never be negative. */
+	if (ip->client->new->expiry < cur_time)
+		ip->client->new->expiry = TIME_MAX;
+	ip->client->new->renewal += cur_time;
+	if (ip->client->new->renewal < cur_time)
+		ip->client->new->renewal = TIME_MAX;
+	ip->client->new->rebind += cur_time;
+	if (ip->client->new->rebind < cur_time)
+		ip->client->new->rebind = TIME_MAX;
+
+	bind_lease(ip);
+}
+
+void
+bind_lease(struct interface_info *ip)
+{
+	/* Remember the medium. */
+	ip->client->new->medium = ip->client->medium;
+
+	/* Write out the new lease. */
+	write_client_lease(ip, ip->client->new, 0);
+
+	/* Run the client script with the new parameters. */
+	script_init((ip->client->state == S_REQUESTING ? "BOUND" :
+	    (ip->client->state == S_RENEWING ? "RENEW" :
+	    (ip->client->state == S_REBOOTING ? "REBOOT" : "REBIND"))),
+	    ip->client->new->medium);
+	if (ip->client->active && ip->client->state != S_REBOOTING)
+		script_write_params("old_", ip->client->active);
+	script_write_params("new_", ip->client->new);
+	if (ip->client->alias)
+		script_write_params("alias_", ip->client->alias);
+	script_go();
+
+	/* Replace the old active lease with the new one. */
+	if (ip->client->active)
+		free_client_lease(ip->client->active);
+	ip->client->active = ip->client->new;
+	ip->client->new = NULL;
+
+	/* Set up a timeout to start the renewal process. */
+	add_timeout(ip->client->active->renewal, state_bound, ip);
+
+	note("bound to %s -- renewal in %d seconds.",
+	    piaddr(ip->client->active->address),
+	    (int)(ip->client->active->renewal - cur_time));
+	ip->client->state = S_BOUND;
+	reinitialize_interfaces();
+	go_daemon();
+}
+
+/*
+ * state_bound is called when we've successfully bound to a particular
+ * lease, but the renewal time on that lease has expired.   We are
+ * expected to unicast a DHCPREQUEST to the server that gave us our
+ * original lease.
+ */
+void
+state_bound(void *ipp)
+{
+	struct interface_info *ip = ipp;
+
+	ASSERT_STATE(state, S_BOUND);
+
+	/* T1 has expired. */
+	make_request(ip, ip->client->active);
+	ip->client->xid = ip->client->packet.xid;
+
+	if (ip->client->active->options[DHO_DHCP_SERVER_IDENTIFIER].len == 4) {
+		memcpy(ip->client->destination.iabuf, ip->client->active->
+		    options[DHO_DHCP_SERVER_IDENTIFIER].data, 4);
+		ip->client->destination.len = 4;
+	} else
+		ip->client->destination = iaddr_broadcast;
+
+	ip->client->first_sending = cur_time;
+	ip->client->interval = ip->client->config->initial_interval;
+	ip->client->state = S_RENEWING;
+
+	/* Send the first packet immediately. */
+	send_request(ip);
+}
+
+void
+bootp(struct packet *packet)
+{
+	struct iaddrlist *ap;
+
+	if (packet->raw->op != BOOTREPLY)
+		return;
+
+	/* If there's a reject list, make sure this packet's sender isn't
+	   on it. */
+	for (ap = packet->interface->client->config->reject_list;
+	    ap; ap = ap->next) {
+		if (addr_eq(packet->client_addr, ap->addr)) {
+			note("BOOTREPLY from %s rejected.", piaddr(ap->addr));
+			return;
+		}
+	}
+	dhcpoffer(packet);
+}
+
+void
+dhcp(struct packet *packet)
+{
+	struct iaddrlist *ap;
+	void (*handler)(struct packet *);
+	char *type;
+
+	switch (packet->packet_type) {
+	case DHCPOFFER:
+		handler = dhcpoffer;
+		type = "DHCPOFFER";
+		break;
+	case DHCPNAK:
+		handler = dhcpnak;
+		type = "DHCPNACK";
+		break;
+	case DHCPACK:
+		handler = dhcpack;
+		type = "DHCPACK";
+		break;
+	default:
+		return;
+	}
+
+	/* If there's a reject list, make sure this packet's sender isn't
+	   on it. */
+	for (ap = packet->interface->client->config->reject_list;
+	    ap; ap = ap->next) {
+		if (addr_eq(packet->client_addr, ap->addr)) {
+			note("%s from %s rejected.", type, piaddr(ap->addr));
+			return;
+		}
+	}
+	(*handler)(packet);
+}
+
+void
+dhcpoffer(struct packet *packet)
+{
+	struct interface_info *ip = packet->interface;
+	struct client_lease *lease, *lp;
+	int i;
+	int arp_timeout_needed, stop_selecting;
+	char *name = packet->options[DHO_DHCP_MESSAGE_TYPE].len ?
+	    "DHCPOFFER" : "BOOTREPLY";
+
+	/* If we're not receptive to an offer right now, or if the offer
+	   has an unrecognizable transaction id, then just drop it. */
+	if (ip->client->state != S_SELECTING ||
+	    packet->interface->client->xid != packet->raw->xid ||
+	    (packet->interface->hw_address.hlen != packet->raw->hlen) ||
+	    (memcmp(packet->interface->hw_address.haddr,
+	    packet->raw->chaddr, packet->raw->hlen)))
+		return;
+
+	note("%s from %s", name, piaddr(packet->client_addr));
+
+
+	/* If this lease doesn't supply the minimum required parameters,
+	   blow it off. */
+	for (i = 0; ip->client->config->required_options[i]; i++) {
+		if (!packet->options[ip->client->config->
+		    required_options[i]].len) {
+			note("%s isn't satisfactory.", name);
+			return;
+		}
+	}
+
+	/* If we've already seen this lease, don't record it again. */
+	for (lease = ip->client->offered_leases;
+	    lease; lease = lease->next) {
+		if (lease->address.len == sizeof(packet->raw->yiaddr) &&
+		    !memcmp(lease->address.iabuf,
+		    &packet->raw->yiaddr, lease->address.len)) {
+			debug("%s already seen.", name);
+			return;
+		}
+	}
+
+	lease = packet_to_lease(packet);
+	if (!lease) {
+		note("packet_to_lease failed.");
+		return;
+	}
+
+	/* If this lease was acquired through a BOOTREPLY, record that
+	   fact. */
+	if (!packet->options[DHO_DHCP_MESSAGE_TYPE].len)
+		lease->is_bootp = 1;
+
+	/* Record the medium under which this lease was offered. */
+	lease->medium = ip->client->medium;
+
+	/* Send out an ARP Request for the offered IP address. */
+	script_init("ARPSEND", lease->medium);
+	script_write_params("check_", lease);
+	/* If the script can't send an ARP request without waiting,
+	   we'll be waiting when we do the ARPCHECK, so don't wait now. */
+	if (script_go())
+		arp_timeout_needed = 0;
+	else
+		arp_timeout_needed = 2;
+
+	/* Figure out when we're supposed to stop selecting. */
+	stop_selecting =
+	    ip->client->first_sending + ip->client->config->select_interval;
+
+	/* If this is the lease we asked for, put it at the head of the
+	   list, and don't mess with the arp request timeout. */
+	if (lease->address.len == ip->client->requested_address.len &&
+	    !memcmp(lease->address.iabuf,
+	    ip->client->requested_address.iabuf,
+	    ip->client->requested_address.len)) {
+		lease->next = ip->client->offered_leases;
+		ip->client->offered_leases = lease;
+	} else {
+		/* If we already have an offer, and arping for this
+		   offer would take us past the selection timeout,
+		   then don't extend the timeout - just hope for the
+		   best. */
+		if (ip->client->offered_leases &&
+		    (cur_time + arp_timeout_needed) > stop_selecting)
+			arp_timeout_needed = 0;
+
+		/* Put the lease at the end of the list. */
+		lease->next = NULL;
+		if (!ip->client->offered_leases)
+			ip->client->offered_leases = lease;
+		else {
+			for (lp = ip->client->offered_leases; lp->next;
+			    lp = lp->next)
+				;	/* nothing */
+			lp->next = lease;
+		}
+	}
+
+	/* If we're supposed to stop selecting before we've had time
+	   to wait for the ARPREPLY, add some delay to wait for
+	   the ARPREPLY. */
+	if (stop_selecting - cur_time < arp_timeout_needed)
+		stop_selecting = cur_time + arp_timeout_needed;
+
+	/* If the selecting interval has expired, go immediately to
+	   state_selecting().  Otherwise, time out into
+	   state_selecting at the select interval. */
+	if (stop_selecting <= 0)
+		state_selecting(ip);
+	else {
+		add_timeout(stop_selecting, state_selecting, ip);
+		cancel_timeout(send_discover, ip);
+	}
+}
+
+/* Allocate a client_lease structure and initialize it from the parameters
+   in the specified packet. */
+
+struct client_lease *
+packet_to_lease(struct packet *packet)
+{
+	struct client_lease *lease;
+	int i;
+
+	lease = malloc(sizeof(struct client_lease));
+
+	if (!lease) {
+		warning("dhcpoffer: no memory to record lease.");
+		return (NULL);
+	}
+
+	memset(lease, 0, sizeof(*lease));
+
+	/* Copy the lease options. */
+	for (i = 0; i < 256; i++) {
+		if (packet->options[i].len) {
+			lease->options[i].data =
+			    malloc(packet->options[i].len + 1);
+			if (!lease->options[i].data) {
+				warning("dhcpoffer: no memory for option %d", i);
+				free_client_lease(lease);
+				return (NULL);
+			} else {
+				memcpy(lease->options[i].data,
+				    packet->options[i].data,
+				    packet->options[i].len);
+				lease->options[i].len =
+				    packet->options[i].len;
+				lease->options[i].data[lease->options[i].len] =
+				    0;
+			}
+			if (!check_option(lease,i)) {
+				/* ignore a bogus lease offer */
+				warning("Invalid lease option - ignoring offer");
+				free_client_lease(lease);
+				return (NULL);
+			}
+		}
+	}
+
+	lease->address.len = sizeof(packet->raw->yiaddr);
+	memcpy(lease->address.iabuf, &packet->raw->yiaddr, lease->address.len);
+
+	/* If the server name was filled out, copy it.
+	   Do not attempt to validate the server name as a host name.
+	   RFC 2131 merely states that sname is NUL-terminated (which do
+	   do not assume) and that it is the server's host name.  Since
+	   the ISC client and server allow arbitrary characters, we do
+	   as well. */
+	if ((!packet->options[DHO_DHCP_OPTION_OVERLOAD].len ||
+	    !(packet->options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 2)) &&
+	    packet->raw->sname[0]) {
+		lease->server_name = malloc(DHCP_SNAME_LEN + 1);
+		if (!lease->server_name) {
+			warning("dhcpoffer: no memory for server name.");
+			free_client_lease(lease);
+			return (NULL);
+		}
+		memcpy(lease->server_name, packet->raw->sname, DHCP_SNAME_LEN);
+		lease->server_name[DHCP_SNAME_LEN]='\0';
+	}
+
+	/* Ditto for the filename. */
+	if ((!packet->options[DHO_DHCP_OPTION_OVERLOAD].len ||
+	    !(packet->options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 1)) &&
+	    packet->raw->file[0]) {
+		/* Don't count on the NUL terminator. */
+		lease->filename = malloc(DHCP_FILE_LEN + 1);
+		if (!lease->filename) {
+			warning("dhcpoffer: no memory for filename.");
+			free_client_lease(lease);
+			return (NULL);
+		}
+		memcpy(lease->filename, packet->raw->file, DHCP_FILE_LEN);
+		lease->filename[DHCP_FILE_LEN]='\0';
+	}
+	return lease;
+}
+
+void
+dhcpnak(struct packet *packet)
+{
+	struct interface_info *ip = packet->interface;
+
+	/* If we're not receptive to an offer right now, or if the offer
+	   has an unrecognizable transaction id, then just drop it. */
+	if (packet->interface->client->xid != packet->raw->xid ||
+	    (packet->interface->hw_address.hlen != packet->raw->hlen) ||
+	    (memcmp(packet->interface->hw_address.haddr,
+	    packet->raw->chaddr, packet->raw->hlen)))
+		return;
+
+	if (ip->client->state != S_REBOOTING &&
+	    ip->client->state != S_REQUESTING &&
+	    ip->client->state != S_RENEWING &&
+	    ip->client->state != S_REBINDING)
+		return;
+
+	note("DHCPNAK from %s", piaddr(packet->client_addr));
+
+	if (!ip->client->active) {
+		note("DHCPNAK with no active lease.\n");
+		return;
+	}
+
+	free_client_lease(ip->client->active);
+	ip->client->active = NULL;
+
+	/* Stop sending DHCPREQUEST packets... */
+	cancel_timeout(send_request, ip);
+
+	ip->client->state = S_INIT;
+	state_init(ip);
+}
+
+/* Send out a DHCPDISCOVER packet, and set a timeout to send out another
+   one after the right interval has expired.  If we don't get an offer by
+   the time we reach the panic interval, call the panic function. */
+
+void
+send_discover(void *ipp)
+{
+	struct interface_info *ip = ipp;
+	int interval, increase = 1;
+
+	/* Figure out how long it's been since we started transmitting. */
+	interval = cur_time - ip->client->first_sending;
+
+	/* If we're past the panic timeout, call the script and tell it
+	   we haven't found anything for this interface yet. */
+	if (interval > ip->client->config->timeout) {
+		state_panic(ip);
+		return;
+	}
+
+	/* If we're selecting media, try the whole list before doing
+	   the exponential backoff, but if we've already received an
+	   offer, stop looping, because we obviously have it right. */
+	if (!ip->client->offered_leases &&
+	    ip->client->config->media) {
+		int fail = 0;
+again:
+		if (ip->client->medium) {
+			ip->client->medium = ip->client->medium->next;
+			increase = 0;
+		}
+		if (!ip->client->medium) {
+			if (fail)
+				error("No valid media types for %s!", ip->name);
+			ip->client->medium = ip->client->config->media;
+			increase = 1;
+		}
+
+		note("Trying medium \"%s\" %d", ip->client->medium->string,
+		    increase);
+		script_init("MEDIUM", ip->client->medium);
+		if (script_go())
+			goto again;
+	}
+
+	/*
+	 * If we're supposed to increase the interval, do so.  If it's
+	 * currently zero (i.e., we haven't sent any packets yet), set
+	 * it to one; otherwise, add to it a random number between zero
+	 * and two times itself.  On average, this means that it will
+	 * double with every transmission.
+	 */
+	if (increase) {
+		if (!ip->client->interval)
+			ip->client->interval =
+			    ip->client->config->initial_interval;
+		else {
+			ip->client->interval += (arc4random() >> 2) %
+			    (2 * ip->client->interval);
+		}
+
+		/* Don't backoff past cutoff. */
+		if (ip->client->interval >
+		    ip->client->config->backoff_cutoff)
+			ip->client->interval =
+				((ip->client->config->backoff_cutoff / 2)
+				 + ((arc4random() >> 2) %
+				    ip->client->config->backoff_cutoff));
+	} else if (!ip->client->interval)
+		ip->client->interval =
+			ip->client->config->initial_interval;
+
+	/* If the backoff would take us to the panic timeout, just use that
+	   as the interval. */
+	if (cur_time + ip->client->interval >
+	    ip->client->first_sending + ip->client->config->timeout)
+		ip->client->interval =
+			(ip->client->first_sending +
+			 ip->client->config->timeout) - cur_time + 1;
+
+	/* Record the number of seconds since we started sending. */
+	if (interval < 65536)
+		ip->client->packet.secs = htons(interval);
+	else
+		ip->client->packet.secs = htons(65535);
+	ip->client->secs = ip->client->packet.secs;
+
+	note("DHCPDISCOVER on %s to %s port %d interval %d",
+	    ip->name, inet_ntoa(sockaddr_broadcast.sin_addr),
+	    ntohs(sockaddr_broadcast.sin_port),
+	    (int)ip->client->interval);
+
+	/* Send out a packet. */
+	(void)send_packet(ip, &ip->client->packet, ip->client->packet_length,
+	    inaddr_any, &sockaddr_broadcast, NULL);
+
+	add_timeout(cur_time + ip->client->interval, send_discover, ip);
+}
+
+/*
+ * state_panic gets called if we haven't received any offers in a preset
+ * amount of time.   When this happens, we try to use existing leases
+ * that haven't yet expired, and failing that, we call the client script
+ * and hope it can do something.
+ */
+void
+state_panic(void *ipp)
+{
+	struct interface_info *ip = ipp;
+	struct client_lease *loop = ip->client->active;
+	struct client_lease *lp;
+
+	note("No DHCPOFFERS received.");
+
+	/* We may not have an active lease, but we may have some
+	   predefined leases that we can try. */
+	if (!ip->client->active && ip->client->leases)
+		goto activate_next;
+
+	/* Run through the list of leases and see if one can be used. */
+	while (ip->client->active) {
+		if (ip->client->active->expiry > cur_time) {
+			note("Trying recorded lease %s",
+			    piaddr(ip->client->active->address));
+			/* Run the client script with the existing
+			   parameters. */
+			script_init("TIMEOUT",
+			    ip->client->active->medium);
+			script_write_params("new_", ip->client->active);
+			if (ip->client->alias)
+				script_write_params("alias_",
+				    ip->client->alias);
+
+			/* If the old lease is still good and doesn't
+			   yet need renewal, go into BOUND state and
+			   timeout at the renewal time. */
+			if (!script_go()) {
+				if (cur_time <
+				    ip->client->active->renewal) {
+					ip->client->state = S_BOUND;
+					note("bound: renewal in %d seconds.",
+					    (int)(ip->client->active->renewal -
+					    cur_time));
+					add_timeout(
+					    ip->client->active->renewal,
+					    state_bound, ip);
+				} else {
+					ip->client->state = S_BOUND;
+					note("bound: immediate renewal.");
+					state_bound(ip);
+				}
+				reinitialize_interfaces();
+				go_daemon();
+				return;
+			}
+		}
+
+		/* If there are no other leases, give up. */
+		if (!ip->client->leases) {
+			ip->client->leases = ip->client->active;
+			ip->client->active = NULL;
+			break;
+		}
+
+activate_next:
+		/* Otherwise, put the active lease at the end of the
+		   lease list, and try another lease.. */
+		for (lp = ip->client->leases; lp->next; lp = lp->next)
+			;
+		lp->next = ip->client->active;
+		if (lp->next)
+			lp->next->next = NULL;
+		ip->client->active = ip->client->leases;
+		ip->client->leases = ip->client->leases->next;
+
+		/* If we already tried this lease, we've exhausted the
+		   set of leases, so we might as well give up for
+		   now. */
+		if (ip->client->active == loop)
+			break;
+		else if (!loop)
+			loop = ip->client->active;
+	}
+
+	/* No leases were available, or what was available didn't work, so
+	   tell the shell script that we failed to allocate an address,
+	   and try again later. */
+	note("No working leases in persistent database - sleeping.\n");
+	script_init("FAIL", NULL);
+	if (ip->client->alias)
+		script_write_params("alias_", ip->client->alias);
+	script_go();
+	ip->client->state = S_INIT;
+	add_timeout(cur_time + ip->client->config->retry_interval, state_init,
+	    ip);
+	go_daemon();
+}
+
+void
+send_request(void *ipp)
+{
+	struct interface_info *ip = ipp;
+	struct sockaddr_in destination;
+	struct in_addr from;
+	int interval;
+
+	/* Figure out how long it's been since we started transmitting. */
+	interval = cur_time - ip->client->first_sending;
+
+	/* If we're in the INIT-REBOOT or REQUESTING state and we're
+	   past the reboot timeout, go to INIT and see if we can
+	   DISCOVER an address... */
+	/* XXX In the INIT-REBOOT state, if we don't get an ACK, it
+	   means either that we're on a network with no DHCP server,
+	   or that our server is down.  In the latter case, assuming
+	   that there is a backup DHCP server, DHCPDISCOVER will get
+	   us a new address, but we could also have successfully
+	   reused our old address.  In the former case, we're hosed
+	   anyway.  This is not a win-prone situation. */
+	if ((ip->client->state == S_REBOOTING ||
+	    ip->client->state == S_REQUESTING) &&
+	    interval > ip->client->config->reboot_timeout) {
+cancel:
+		ip->client->state = S_INIT;
+		cancel_timeout(send_request, ip);
+		state_init(ip);
+		return;
+	}
+
+	/* If we're in the reboot state, make sure the media is set up
+	   correctly. */
+	if (ip->client->state == S_REBOOTING &&
+	    !ip->client->medium &&
+	    ip->client->active->medium ) {
+		script_init("MEDIUM", ip->client->active->medium);
+
+		/* If the medium we chose won't fly, go to INIT state. */
+		if (script_go())
+			goto cancel;
+
+		/* Record the medium. */
+		ip->client->medium = ip->client->active->medium;
+	}
+
+	/* If the lease has expired, relinquish the address and go back
+	   to the INIT state. */
+	if (ip->client->state != S_REQUESTING &&
+	    cur_time > ip->client->active->expiry) {
+		/* Run the client script with the new parameters. */
+		script_init("EXPIRE", NULL);
+		script_write_params("old_", ip->client->active);
+		if (ip->client->alias)
+			script_write_params("alias_", ip->client->alias);
+		script_go();
+
+		/* Now do a preinit on the interface so that we can
+		   discover a new address. */
+		script_init("PREINIT", NULL);
+		if (ip->client->alias)
+			script_write_params("alias_", ip->client->alias);
+		script_go();
+
+		ip->client->state = S_INIT;
+		state_init(ip);
+		return;
+	}
+
+	/* Do the exponential backoff... */
+	if (!ip->client->interval)
+		ip->client->interval = ip->client->config->initial_interval;
+	else
+		ip->client->interval += ((arc4random() >> 2) %
+		    (2 * ip->client->interval));
+
+	/* Don't backoff past cutoff. */
+	if (ip->client->interval >
+	    ip->client->config->backoff_cutoff)
+		ip->client->interval =
+		    ((ip->client->config->backoff_cutoff / 2) +
+		    ((arc4random() >> 2) % ip->client->interval));
+
+	/* If the backoff would take us to the expiry time, just set the
+	   timeout to the expiry time. */
+	if (ip->client->state != S_REQUESTING &&
+	    cur_time + ip->client->interval >
+	    ip->client->active->expiry)
+		ip->client->interval =
+		    ip->client->active->expiry - cur_time + 1;
+
+	/* If the lease T2 time has elapsed, or if we're not yet bound,
+	   broadcast the DHCPREQUEST rather than unicasting. */
+	memset(&destination, 0, sizeof(destination));
+	if (ip->client->state == S_REQUESTING ||
+	    ip->client->state == S_REBOOTING ||
+	    cur_time > ip->client->active->rebind)
+		destination.sin_addr.s_addr = INADDR_BROADCAST;
+	else
+		memcpy(&destination.sin_addr.s_addr,
+		    ip->client->destination.iabuf,
+		    sizeof(destination.sin_addr.s_addr));
+	destination.sin_port = htons(REMOTE_PORT);
+	destination.sin_family = AF_INET;
+	destination.sin_len = sizeof(destination);
+
+	if (ip->client->state != S_REQUESTING)
+		memcpy(&from, ip->client->active->address.iabuf,
+		    sizeof(from));
+	else
+		from.s_addr = INADDR_ANY;
+
+	/* Record the number of seconds since we started sending. */
+	if (ip->client->state == S_REQUESTING)
+		ip->client->packet.secs = ip->client->secs;
+	else {
+		if (interval < 65536)
+			ip->client->packet.secs = htons(interval);
+		else
+			ip->client->packet.secs = htons(65535);
+	}
+
+	note("DHCPREQUEST on %s to %s port %d", ip->name,
+	    inet_ntoa(destination.sin_addr), ntohs(destination.sin_port));
+
+	/* Send out a packet. */
+	(void) send_packet(ip, &ip->client->packet, ip->client->packet_length,
+	    from, &destination, NULL);
+
+	add_timeout(cur_time + ip->client->interval, send_request, ip);
+}
+
+void
+send_decline(void *ipp)
+{
+	struct interface_info *ip = ipp;
+
+	note("DHCPDECLINE on %s to %s port %d", ip->name,
+	    inet_ntoa(sockaddr_broadcast.sin_addr),
+	    ntohs(sockaddr_broadcast.sin_port));
+
+	/* Send out a packet. */
+	(void) send_packet(ip, &ip->client->packet, ip->client->packet_length,
+	    inaddr_any, &sockaddr_broadcast, NULL);
+}
+
+void
+make_discover(struct interface_info *ip, struct client_lease *lease)
+{
+	unsigned char discover = DHCPDISCOVER;
+	struct tree_cache *options[256];
+	struct tree_cache option_elements[256];
+	int i;
+
+	memset(option_elements, 0, sizeof(option_elements));
+	memset(options, 0, sizeof(options));
+	memset(&ip->client->packet, 0, sizeof(ip->client->packet));
+
+	/* Set DHCP_MESSAGE_TYPE to DHCPDISCOVER */
+	i = DHO_DHCP_MESSAGE_TYPE;
+	options[i] = &option_elements[i];
+	options[i]->value = &discover;
+	options[i]->len = sizeof(discover);
+	options[i]->buf_size = sizeof(discover);
+	options[i]->timeout = 0xFFFFFFFF;
+
+	/* Request the options we want */
+	i  = DHO_DHCP_PARAMETER_REQUEST_LIST;
+	options[i] = &option_elements[i];
+	options[i]->value = ip->client->config->requested_options;
+	options[i]->len = ip->client->config->requested_option_count;
+	options[i]->buf_size =
+		ip->client->config->requested_option_count;
+	options[i]->timeout = 0xFFFFFFFF;
+
+	/* If we had an address, try to get it again. */
+	if (lease) {
+		ip->client->requested_address = lease->address;
+		i = DHO_DHCP_REQUESTED_ADDRESS;
+		options[i] = &option_elements[i];
+		options[i]->value = lease->address.iabuf;
+		options[i]->len = lease->address.len;
+		options[i]->buf_size = lease->address.len;
+		options[i]->timeout = 0xFFFFFFFF;
+	} else
+		ip->client->requested_address.len = 0;
+
+	/* Send any options requested in the config file. */
+	for (i = 0; i < 256; i++)
+		if (!options[i] &&
+		    ip->client->config->send_options[i].data) {
+			options[i] = &option_elements[i];
+			options[i]->value =
+			    ip->client->config->send_options[i].data;
+			options[i]->len =
+			    ip->client->config->send_options[i].len;
+			options[i]->buf_size =
+			    ip->client->config->send_options[i].len;
+			options[i]->timeout = 0xFFFFFFFF;
+		}
+		
+	/* send host name if not set via config file. */
+	char hostname[_POSIX_HOST_NAME_MAX+1];
+	if (!options[DHO_HOST_NAME]) {
+		if (gethostname(hostname, sizeof(hostname)) == 0) {
+			size_t len;
+			char* posDot = strchr(hostname, '.');
+			if (posDot != NULL)
+				len = posDot - hostname;
+			else
+				len = strlen(hostname);
+			options[DHO_HOST_NAME] = &option_elements[DHO_HOST_NAME];
+			options[DHO_HOST_NAME]->value = hostname;
+			options[DHO_HOST_NAME]->len = len;
+			options[DHO_HOST_NAME]->buf_size = len;
+			options[DHO_HOST_NAME]->timeout = 0xFFFFFFFF;
+		}
+	}
+
+	/* set unique client identifier */
+	char client_ident[sizeof(struct hardware)];
+	if (!options[DHO_DHCP_CLIENT_IDENTIFIER]) {
+		int hwlen = (ip->hw_address.hlen < sizeof(client_ident)-1) ?
+				ip->hw_address.hlen : sizeof(client_ident)-1;
+		client_ident[0] = ip->hw_address.htype;
+		memcpy(&client_ident[1], ip->hw_address.haddr, hwlen); 
+		options[DHO_DHCP_CLIENT_IDENTIFIER] = &option_elements[DHO_DHCP_CLIENT_IDENTIFIER];
+		options[DHO_DHCP_CLIENT_IDENTIFIER]->value = client_ident;
+		options[DHO_DHCP_CLIENT_IDENTIFIER]->len = hwlen+1;
+		options[DHO_DHCP_CLIENT_IDENTIFIER]->buf_size = hwlen+1;
+		options[DHO_DHCP_CLIENT_IDENTIFIER]->timeout = 0xFFFFFFFF;
+	}
+
+	/* Set up the option buffer... */
+	ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0,
+	    options, 0, 0, 0, NULL, 0);
+	if (ip->client->packet_length < BOOTP_MIN_LEN)
+		ip->client->packet_length = BOOTP_MIN_LEN;
+
+	ip->client->packet.op = BOOTREQUEST;
+	ip->client->packet.htype = ip->hw_address.htype;
+	ip->client->packet.hlen = ip->hw_address.hlen;
+	ip->client->packet.hops = 0;
+	ip->client->packet.xid = arc4random();
+	ip->client->packet.secs = 0; /* filled in by send_discover. */
+	ip->client->packet.flags = 0;
+
+	memset(&(ip->client->packet.ciaddr),
+	    0, sizeof(ip->client->packet.ciaddr));
+	memset(&(ip->client->packet.yiaddr),
+	    0, sizeof(ip->client->packet.yiaddr));
+	memset(&(ip->client->packet.siaddr),
+	    0, sizeof(ip->client->packet.siaddr));
+	memset(&(ip->client->packet.giaddr),
+	    0, sizeof(ip->client->packet.giaddr));
+	memcpy(ip->client->packet.chaddr,
+	    ip->hw_address.haddr, ip->hw_address.hlen);
+}
+
+
+void
+make_request(struct interface_info *ip, struct client_lease * lease)
+{
+	unsigned char request = DHCPREQUEST;
+	struct tree_cache *options[256];
+	struct tree_cache option_elements[256];
+	int i;
+
+	memset(options, 0, sizeof(options));
+	memset(&ip->client->packet, 0, sizeof(ip->client->packet));
+
+	/* Set DHCP_MESSAGE_TYPE to DHCPREQUEST */
+	i = DHO_DHCP_MESSAGE_TYPE;
+	options[i] = &option_elements[i];
+	options[i]->value = &request;
+	options[i]->len = sizeof(request);
+	options[i]->buf_size = sizeof(request);
+	options[i]->timeout = 0xFFFFFFFF;
+
+	/* Request the options we want */
+	i = DHO_DHCP_PARAMETER_REQUEST_LIST;
+	options[i] = &option_elements[i];
+	options[i]->value = ip->client->config->requested_options;
+	options[i]->len = ip->client->config->requested_option_count;
+	options[i]->buf_size =
+		ip->client->config->requested_option_count;
+	options[i]->timeout = 0xFFFFFFFF;
+
+	/* If we are requesting an address that hasn't yet been assigned
+	   to us, use the DHCP Requested Address option. */
+	if (ip->client->state == S_REQUESTING) {
+		/* Send back the server identifier... */
+		i = DHO_DHCP_SERVER_IDENTIFIER;
+		options[i] = &option_elements[i];
+		options[i]->value = lease->options[i].data;
+		options[i]->len = lease->options[i].len;
+		options[i]->buf_size = lease->options[i].len;
+		options[i]->timeout = 0xFFFFFFFF;
+	}
+	if (ip->client->state == S_REQUESTING ||
+	    ip->client->state == S_REBOOTING) {
+		ip->client->requested_address = lease->address;
+		i = DHO_DHCP_REQUESTED_ADDRESS;
+		options[i] = &option_elements[i];
+		options[i]->value = lease->address.iabuf;
+		options[i]->len = lease->address.len;
+		options[i]->buf_size = lease->address.len;
+		options[i]->timeout = 0xFFFFFFFF;
+	} else
+		ip->client->requested_address.len = 0;
+
+	/* Send any options requested in the config file. */
+	for (i = 0; i < 256; i++)
+		if (!options[i] &&
+		    ip->client->config->send_options[i].data) {
+			options[i] = &option_elements[i];
+			options[i]->value =
+			    ip->client->config->send_options[i].data;
+			options[i]->len =
+			    ip->client->config->send_options[i].len;
+			options[i]->buf_size =
+			    ip->client->config->send_options[i].len;
+			options[i]->timeout = 0xFFFFFFFF;
+		}
+		
+	/* send host name if not set via config file. */
+	char hostname[_POSIX_HOST_NAME_MAX+1];
+	if (!options[DHO_HOST_NAME]) {
+		if (gethostname(hostname, sizeof(hostname)) == 0) {
+			size_t len;
+			char* posDot = strchr(hostname, '.');
+			if (posDot != NULL)
+				len = posDot - hostname;
+			else
+				len = strlen(hostname);
+			options[DHO_HOST_NAME] = &option_elements[DHO_HOST_NAME];
+			options[DHO_HOST_NAME]->value = hostname;
+			options[DHO_HOST_NAME]->len = len;
+			options[DHO_HOST_NAME]->buf_size = len;
+			options[DHO_HOST_NAME]->timeout = 0xFFFFFFFF;
+		}
+	}
+
+	/* set unique client identifier */
+	char client_ident[sizeof(struct hardware)];
+	if (!options[DHO_DHCP_CLIENT_IDENTIFIER]) {
+		int hwlen = (ip->hw_address.hlen < sizeof(client_ident)-1) ?
+				ip->hw_address.hlen : sizeof(client_ident)-1;
+		client_ident[0] = ip->hw_address.htype;
+		memcpy(&client_ident[1], ip->hw_address.haddr, hwlen); 
+		options[DHO_DHCP_CLIENT_IDENTIFIER] = &option_elements[DHO_DHCP_CLIENT_IDENTIFIER];
+		options[DHO_DHCP_CLIENT_IDENTIFIER]->value = client_ident;
+		options[DHO_DHCP_CLIENT_IDENTIFIER]->len = hwlen+1;
+		options[DHO_DHCP_CLIENT_IDENTIFIER]->buf_size = hwlen+1;
+		options[DHO_DHCP_CLIENT_IDENTIFIER]->timeout = 0xFFFFFFFF;
+	}
+
+	/* Set up the option buffer... */
+	ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0,
+	    options, 0, 0, 0, NULL, 0);
+	if (ip->client->packet_length < BOOTP_MIN_LEN)
+		ip->client->packet_length = BOOTP_MIN_LEN;
+
+	ip->client->packet.op = BOOTREQUEST;
+	ip->client->packet.htype = ip->hw_address.htype;
+	ip->client->packet.hlen = ip->hw_address.hlen;
+	ip->client->packet.hops = 0;
+	ip->client->packet.xid = ip->client->xid;
+	ip->client->packet.secs = 0; /* Filled in by send_request. */
+
+	/* If we own the address we're requesting, put it in ciaddr;
+	   otherwise set ciaddr to zero. */
+	if (ip->client->state == S_BOUND ||
+	    ip->client->state == S_RENEWING ||
+	    ip->client->state == S_REBINDING) {
+		memcpy(&ip->client->packet.ciaddr,
+		    lease->address.iabuf, lease->address.len);
+		ip->client->packet.flags = 0;
+	} else {
+		memset(&ip->client->packet.ciaddr, 0,
+		    sizeof(ip->client->packet.ciaddr));
+		ip->client->packet.flags = 0;
+	}
+
+	memset(&ip->client->packet.yiaddr, 0,
+	    sizeof(ip->client->packet.yiaddr));
+	memset(&ip->client->packet.siaddr, 0,
+	    sizeof(ip->client->packet.siaddr));
+	memset(&ip->client->packet.giaddr, 0,
+	    sizeof(ip->client->packet.giaddr));
+	memcpy(ip->client->packet.chaddr,
+	    ip->hw_address.haddr, ip->hw_address.hlen);
+}
+
+void
+make_decline(struct interface_info *ip, struct client_lease *lease)
+{
+	struct tree_cache *options[256], message_type_tree;
+	struct tree_cache requested_address_tree;
+	struct tree_cache server_id_tree, client_id_tree;
+	unsigned char decline = DHCPDECLINE;
+	int i;
+
+	memset(options, 0, sizeof(options));
+	memset(&ip->client->packet, 0, sizeof(ip->client->packet));
+
+	/* Set DHCP_MESSAGE_TYPE to DHCPDECLINE */
+	i = DHO_DHCP_MESSAGE_TYPE;
+	options[i] = &message_type_tree;
+	options[i]->value = &decline;
+	options[i]->len = sizeof(decline);
+	options[i]->buf_size = sizeof(decline);
+	options[i]->timeout = 0xFFFFFFFF;
+
+	/* Send back the server identifier... */
+	i = DHO_DHCP_SERVER_IDENTIFIER;
+	options[i] = &server_id_tree;
+	options[i]->value = lease->options[i].data;
+	options[i]->len = lease->options[i].len;
+	options[i]->buf_size = lease->options[i].len;
+	options[i]->timeout = 0xFFFFFFFF;
+
+	/* Send back the address we're declining. */
+	i = DHO_DHCP_REQUESTED_ADDRESS;
+	options[i] = &requested_address_tree;
+	options[i]->value = lease->address.iabuf;
+	options[i]->len = lease->address.len;
+	options[i]->buf_size = lease->address.len;
+	options[i]->timeout = 0xFFFFFFFF;
+
+	/* Send the uid if the user supplied one. */
+	i = DHO_DHCP_CLIENT_IDENTIFIER;
+	if (ip->client->config->send_options[i].len) {
+		options[i] = &client_id_tree;
+		options[i]->value = ip->client->config->send_options[i].data;
+		options[i]->len = ip->client->config->send_options[i].len;
+		options[i]->buf_size = ip->client->config->send_options[i].len;
+		options[i]->timeout = 0xFFFFFFFF;
+	}
+
+
+	/* Set up the option buffer... */
+	ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0,
+	    options, 0, 0, 0, NULL, 0);
+	if (ip->client->packet_length < BOOTP_MIN_LEN)
+		ip->client->packet_length = BOOTP_MIN_LEN;
+
+	ip->client->packet.op = BOOTREQUEST;
+	ip->client->packet.htype = ip->hw_address.htype;
+	ip->client->packet.hlen = ip->hw_address.hlen;
+	ip->client->packet.hops = 0;
+	ip->client->packet.xid = ip->client->xid;
+	ip->client->packet.secs = 0; /* Filled in by send_request. */
+	ip->client->packet.flags = 0;
+
+	/* ciaddr must always be zero. */
+	memset(&ip->client->packet.ciaddr, 0,
+	    sizeof(ip->client->packet.ciaddr));
+	memset(&ip->client->packet.yiaddr, 0,
+	    sizeof(ip->client->packet.yiaddr));
+	memset(&ip->client->packet.siaddr, 0,
+	    sizeof(ip->client->packet.siaddr));
+	memset(&ip->client->packet.giaddr, 0,
+	    sizeof(ip->client->packet.giaddr));
+	memcpy(ip->client->packet.chaddr,
+	    ip->hw_address.haddr, ip->hw_address.hlen);
+}
+
+void
+free_client_lease(struct client_lease *lease)
+{
+	int i;
+
+	if (lease->server_name)
+		free(lease->server_name);
+	if (lease->filename)
+		free(lease->filename);
+	for (i = 0; i < 256; i++) {
+		if (lease->options[i].len)
+			free(lease->options[i].data);
+	}
+	free(lease);
+}
+
+FILE *leaseFile;
+
+void
+rewrite_client_leases(void)
+{
+	struct client_lease *lp;
+
+	if (!leaseFile) {
+		leaseFile = fopen(path_dhclient_db, "w");
+		if (!leaseFile)
+			error("can't create %s: %m", path_dhclient_db);
+	} else {
+		fflush(leaseFile);
+		rewind(leaseFile);
+	}
+
+	for (lp = ifi->client->leases; lp; lp = lp->next)
+		write_client_lease(ifi, lp, 1);
+	if (ifi->client->active)
+		write_client_lease(ifi, ifi->client->active, 1);
+
+	fflush(leaseFile);
+	ftruncate(fileno(leaseFile), ftello(leaseFile));
+	fsync(fileno(leaseFile));
+}
+
+void
+write_client_lease(struct interface_info *ip, struct client_lease *lease,
+    int rewrite)
+{
+	static int leases_written;
+	struct tm *t;
+	int i;
+
+	if (!rewrite) {
+		if (leases_written++ > 20) {
+			rewrite_client_leases();
+			leases_written = 0;
+		}
+	}
+
+	/* If the lease came from the config file, we don't need to stash
+	   a copy in the lease database. */
+	if (lease->is_static)
+		return;
+
+	if (!leaseFile) {	/* XXX */
+		leaseFile = fopen(path_dhclient_db, "w");
+		if (!leaseFile)
+			error("can't create %s: %m", path_dhclient_db);
+	}
+
+	fprintf(leaseFile, "lease {\n");
+	if (lease->is_bootp)
+		fprintf(leaseFile, "  bootp;\n");
+	fprintf(leaseFile, "  interface \"%s\";\n", ip->name);
+	fprintf(leaseFile, "  fixed-address %s;\n", piaddr(lease->address));
+	if (lease->filename)
+		fprintf(leaseFile, "  filename \"%s\";\n", lease->filename);
+	if (lease->server_name)
+		fprintf(leaseFile, "  server-name \"%s\";\n",
+		    lease->server_name);
+	if (lease->medium)
+		fprintf(leaseFile, "  medium \"%s\";\n", lease->medium->string);
+	for (i = 0; i < 256; i++)
+		if (lease->options[i].len)
+			fprintf(leaseFile, "  option %s %s;\n",
+			    dhcp_options[i].name,
+			    pretty_print_option(i, lease->options[i].data,
+			    lease->options[i].len, 1, 1));
+
+	t = gmtime(&lease->renewal);
+	fprintf(leaseFile, "  renew %d %d/%d/%d %02d:%02d:%02d;\n",
+	    t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
+	    t->tm_hour, t->tm_min, t->tm_sec);
+	t = gmtime(&lease->rebind);
+	fprintf(leaseFile, "  rebind %d %d/%d/%d %02d:%02d:%02d;\n",
+	    t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
+	    t->tm_hour, t->tm_min, t->tm_sec);
+	t = gmtime(&lease->expiry);
+	fprintf(leaseFile, "  expire %d %d/%d/%d %02d:%02d:%02d;\n",
+	    t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
+	    t->tm_hour, t->tm_min, t->tm_sec);
+	fprintf(leaseFile, "}\n");
+	fflush(leaseFile);
+}
+
+void
+script_init(char *reason, struct string_list *medium)
+{
+	size_t		 len, mediumlen = 0;
+	struct imsg_hdr	 hdr;
+	struct buf	*buf;
+	int		 errs;
+
+	if (medium != NULL && medium->string != NULL)
+		mediumlen = strlen(medium->string);
+
+	hdr.code = IMSG_SCRIPT_INIT;
+	hdr.len = sizeof(struct imsg_hdr) +
+	    sizeof(size_t) + mediumlen +
+	    sizeof(size_t) + strlen(reason);
+
+	if ((buf = buf_open(hdr.len)) == NULL)
+		error("buf_open: %m");
+
+	errs = 0;
+	errs += buf_add(buf, &hdr, sizeof(hdr));
+	errs += buf_add(buf, &mediumlen, sizeof(mediumlen));
+	if (mediumlen > 0)
+		errs += buf_add(buf, medium->string, mediumlen);
+	len = strlen(reason);
+	errs += buf_add(buf, &len, sizeof(len));
+	errs += buf_add(buf, reason, len);
+
+	if (errs)
+		error("buf_add: %m");
+
+	if (buf_close(privfd, buf) == -1)
+		error("buf_close: %m");
+}
+
+void
+priv_script_init(char *reason, char *medium)
+{
+	struct interface_info *ip = ifi;
+
+	if (ip) {
+		ip->client->scriptEnvsize = 100;
+		if (ip->client->scriptEnv == NULL)
+			ip->client->scriptEnv =
+			    malloc(ip->client->scriptEnvsize * sizeof(char *));
+		if (ip->client->scriptEnv == NULL)
+			error("script_init: no memory for environment");
+
+		ip->client->scriptEnv[0] = strdup(CLIENT_PATH);
+		if (ip->client->scriptEnv[0] == NULL)
+			error("script_init: no memory for environment");
+
+		ip->client->scriptEnv[1] = NULL;
+
+		script_set_env(ip->client, "", "interface", ip->name);
+
+		if (medium)
+			script_set_env(ip->client, "", "medium", medium);
+
+		script_set_env(ip->client, "", "reason", reason);
+	}
+}
+
+void
+priv_script_write_params(char *prefix, struct client_lease *lease)
+{
+	struct interface_info *ip = ifi;
+	u_int8_t dbuf[1500], *dp = NULL;
+	int i, len;
+	char tbuf[128];
+
+	script_set_env(ip->client, prefix, "ip_address",
+	    piaddr(lease->address));
+
+	if (ip->client->config->default_actions[DHO_SUBNET_MASK] ==
+	    ACTION_SUPERSEDE) {
+		dp = ip->client->config->defaults[DHO_SUBNET_MASK].data;
+		len = ip->client->config->defaults[DHO_SUBNET_MASK].len;
+	} else {
+		dp = lease->options[DHO_SUBNET_MASK].data;
+		len = lease->options[DHO_SUBNET_MASK].len;
+	}
+	if (len && (len < sizeof(lease->address.iabuf))) {
+		struct iaddr netmask, subnet, broadcast;
+
+		memcpy(netmask.iabuf, dp, len);
+		netmask.len = len;
+		subnet = subnet_number(lease->address, netmask);
+		if (subnet.len) {
+			script_set_env(ip->client, prefix, "network_number",
+			    piaddr(subnet));
+			if (!lease->options[DHO_BROADCAST_ADDRESS].len) {
+				broadcast = broadcast_addr(subnet, netmask);
+				if (broadcast.len)
+					script_set_env(ip->client, prefix,
+					    "broadcast_address",
+					    piaddr(broadcast));
+			}
+		}
+	}
+
+	if (lease->filename)
+		script_set_env(ip->client, prefix, "filename", lease->filename);
+	if (lease->server_name)
+		script_set_env(ip->client, prefix, "server_name",
+		    lease->server_name);
+	for (i = 0; i < 256; i++) {
+		len = 0;
+
+		if (ip->client->config->defaults[i].len) {
+			if (lease->options[i].len) {
+				switch (
+				    ip->client->config->default_actions[i]) {
+				case ACTION_DEFAULT:
+					dp = lease->options[i].data;
+					len = lease->options[i].len;
+					break;
+				case ACTION_SUPERSEDE:
+supersede:
+					dp = ip->client->
+						config->defaults[i].data;
+					len = ip->client->
+						config->defaults[i].len;
+					break;
+				case ACTION_PREPEND:
+					len = ip->client->
+					    config->defaults[i].len +
+					    lease->options[i].len;
+					if (len >= sizeof(dbuf)) {
+						warning("no space to %s %s",
+						    "prepend option",
+						    dhcp_options[i].name);
+						goto supersede;
+					}
+					dp = dbuf;
+					memcpy(dp,
+						ip->client->
+						config->defaults[i].data,
+						ip->client->
+						config->defaults[i].len);
+					memcpy(dp + ip->client->
+						config->defaults[i].len,
+						lease->options[i].data,
+						lease->options[i].len);
+					dp[len] = '\0';
+					break;
+				case ACTION_APPEND:
+					/*
+					 * When we append, we assume that we're
+					 * appending to text.  Some MS servers
+					 * include a NUL byte at the end of
+					 * the search string provided.
+					 */
+					len = ip->client->
+					    config->defaults[i].len +
+					    lease->options[i].len;
+					if (len >= sizeof(dbuf)) {
+						warning("no space to %s %s",
+						    "append option",
+						    dhcp_options[i].name);
+						goto supersede;
+					}
+					memcpy(dbuf,
+						lease->options[i].data,
+						lease->options[i].len);
+					for (dp = dbuf + lease->options[i].len;
+					    dp > dbuf; dp--, len--)
+						if (dp[-1] != '\0')
+							break;
+					memcpy(dp,
+						ip->client->
+						config->defaults[i].data,
+						ip->client->
+						config->defaults[i].len);
+					dp = dbuf;
+					dp[len] = '\0';
+				}
+			} else {
+				dp = ip->client->
+					config->defaults[i].data;
+				len = ip->client->
+					config->defaults[i].len;
+			}
+		} else if (lease->options[i].len) {
+			len = lease->options[i].len;
+			dp = lease->options[i].data;
+		} else {
+			len = 0;
+		}
+		if (len) {
+			char name[256];
+
+			if (dhcp_option_ev_name(name, sizeof(name),
+			    &dhcp_options[i]))
+				script_set_env(ip->client, prefix, name,
+				    pretty_print_option(i, dp, len, 0, 0));
+		}
+	}
+	snprintf(tbuf, sizeof(tbuf), "%d", (int)lease->expiry);
+	script_set_env(ip->client, prefix, "expiry", tbuf);
+}
+
+void
+script_write_params(char *prefix, struct client_lease *lease)
+{
+	size_t		 fn_len = 0, sn_len = 0, pr_len = 0;
+	struct imsg_hdr	 hdr;
+	struct buf	*buf;
+	int		 errs, i;
+
+	if (lease->filename != NULL)
+		fn_len = strlen(lease->filename);
+	if (lease->server_name != NULL)
+		sn_len = strlen(lease->server_name);
+	if (prefix != NULL)
+		pr_len = strlen(prefix);
+
+	hdr.code = IMSG_SCRIPT_WRITE_PARAMS;
+	hdr.len = sizeof(hdr) + sizeof(struct client_lease) +
+	    sizeof(size_t) + fn_len + sizeof(size_t) + sn_len +
+	    sizeof(size_t) + pr_len;
+
+	for (i = 0; i < 256; i++)
+		hdr.len += sizeof(int) + lease->options[i].len;
+
+	scripttime = time(NULL);
+
+	if ((buf = buf_open(hdr.len)) == NULL)
+		error("buf_open: %m");
+
+	errs = 0;
+	errs += buf_add(buf, &hdr, sizeof(hdr));
+	errs += buf_add(buf, lease, sizeof(struct client_lease));
+	errs += buf_add(buf, &fn_len, sizeof(fn_len));
+	errs += buf_add(buf, lease->filename, fn_len);
+	errs += buf_add(buf, &sn_len, sizeof(sn_len));
+	errs += buf_add(buf, lease->server_name, sn_len);
+	errs += buf_add(buf, &pr_len, sizeof(pr_len));
+	errs += buf_add(buf, prefix, pr_len);
+
+	for (i = 0; i < 256; i++) {
+		errs += buf_add(buf, &lease->options[i].len,
+		    sizeof(lease->options[i].len));
+		errs += buf_add(buf, lease->options[i].data,
+		    lease->options[i].len);
+	}
+
+	if (errs)
+		error("buf_add: %m");
+
+	if (buf_close(privfd, buf) == -1)
+		error("buf_close: %m");
+}
+
+int
+script_go(void)
+{
+	struct imsg_hdr	 hdr;
+	struct buf	*buf;
+	int		 ret;
+
+	hdr.code = IMSG_SCRIPT_GO;
+	hdr.len = sizeof(struct imsg_hdr);
+
+	if ((buf = buf_open(hdr.len)) == NULL)
+		error("buf_open: %m");
+
+	if (buf_add(buf, &hdr, sizeof(hdr)))
+		error("buf_add: %m");
+
+	if (buf_close(privfd, buf) == -1)
+		error("buf_close: %m");
+
+	bzero(&hdr, sizeof(hdr));
+	buf_read(privfd, &hdr, sizeof(hdr));
+	if (hdr.code != IMSG_SCRIPT_GO_RET)
+		error("unexpected msg type %u", hdr.code);
+	if (hdr.len != sizeof(hdr) + sizeof(int))
+		error("received corrupted message");
+	buf_read(privfd, &ret, sizeof(ret));
+
+	scripttime = time(NULL);
+
+	return (ret);
+}
+
+int
+priv_script_go(void)
+{
+	char *scriptName, *argv[2], **envp, *epp[3], reason[] = "REASON=NBI";
+	static char client_path[] = CLIENT_PATH;
+	struct interface_info *ip = ifi;
+	int pid, wpid, wstatus;
+
+	scripttime = time(NULL);
+
+	if (ip) {
+		scriptName = ip->client->config->script_name;
+		envp = ip->client->scriptEnv;
+	} else {
+		scriptName = top_level_config.script_name;
+		epp[0] = reason;
+		epp[1] = client_path;
+		epp[2] = NULL;
+		envp = epp;
+	}
+
+	argv[0] = scriptName;
+	argv[1] = NULL;
+
+	pid = fork();
+	if (pid < 0) {
+		error("fork: %m");
+		wstatus = 0;
+	} else if (pid) {
+		do {
+			wpid = wait(&wstatus);
+		} while (wpid != pid && wpid > 0);
+		if (wpid < 0) {
+			error("wait: %m");
+			wstatus = 0;
+		}
+	} else {
+		execve(scriptName, argv, envp);
+		error("execve (%s, ...): %m", scriptName);
+	}
+
+	if (ip)
+		script_flush_env(ip->client);
+
+	return (wstatus & 0xff);
+}
+
+void
+script_set_env(struct client_state *client, const char *prefix,
+    const char *name, const char *value)
+{
+	int i, j, namelen;
+
+	namelen = strlen(name);
+
+	for (i = 0; client->scriptEnv[i]; i++)
+		if (strncmp(client->scriptEnv[i], name, namelen) == 0 &&
+		    client->scriptEnv[i][namelen] == '=')
+			break;
+
+	if (client->scriptEnv[i])
+		/* Reuse the slot. */
+		free(client->scriptEnv[i]);
+	else {
+		/* New variable.  Expand if necessary. */
+		if (i >= client->scriptEnvsize - 1) {
+			char **newscriptEnv;
+			int newscriptEnvsize = client->scriptEnvsize + 50;
+
+			newscriptEnv = realloc(client->scriptEnv,
+			    newscriptEnvsize);
+			if (newscriptEnv == NULL) {
+				free(client->scriptEnv);
+				client->scriptEnv = NULL;
+				client->scriptEnvsize = 0;
+				error("script_set_env: no memory for variable");
+			}
+			client->scriptEnv = newscriptEnv;
+			client->scriptEnvsize = newscriptEnvsize;
+		}
+		/* need to set the NULL pointer at end of array beyond
+		   the new slot. */
+		client->scriptEnv[i + 1] = NULL;
+	}
+	/* Allocate space and format the variable in the appropriate slot. */
+	client->scriptEnv[i] = malloc(strlen(prefix) + strlen(name) + 1 +
+	    strlen(value) + 1);
+	if (client->scriptEnv[i] == NULL)
+		error("script_set_env: no memory for variable assignment");
+
+	/* No `` or $() command substitution allowed in environment values! */
+	for (j=0; j < strlen(value); j++)
+		switch (value[j]) {
+		case '`':
+		case '$':
+			error("illegal character (%c) in value '%s'", value[j],
+			    value);
+			/* not reached */
+		}
+	snprintf(client->scriptEnv[i], strlen(prefix) + strlen(name) +
+	    1 + strlen(value) + 1, "%s%s=%s", prefix, name, value);
+}
+
+void
+script_flush_env(struct client_state *client)
+{
+	int i;
+
+	for (i = 0; client->scriptEnv[i]; i++) {
+		free(client->scriptEnv[i]);
+		client->scriptEnv[i] = NULL;
+	}
+	client->scriptEnvsize = 0;
+}
+
+int
+dhcp_option_ev_name(char *buf, size_t buflen, struct option *option)
+{
+	int i;
+
+	for (i = 0; option->name[i]; i++) {
+		if (i + 1 == buflen)
+			return 0;
+		if (option->name[i] == '-')
+			buf[i] = '_';
+		else
+			buf[i] = option->name[i];
+	}
+
+	buf[i] = 0;
+	return 1;
+}
+
+void
+go_daemon(void)
+{
+	static int state = 0;
+
+	if (no_daemon || state)
+		return;
+
+	state = 1;
+
+	/* Stop logging to stderr... */
+	log_perror = 0;
+
+	if (daemon(1, 0) == -1)
+		error("daemon");
+
+	/* we are chrooted, daemon(3) fails to open /dev/null */
+	if (nullfd != -1) {
+		dup2(nullfd, STDIN_FILENO);
+		dup2(nullfd, STDOUT_FILENO);
+		dup2(nullfd, STDERR_FILENO);
+		close(nullfd);
+		nullfd = -1;
+	}
+}
+
+int
+check_option(struct client_lease *l, int option)
+{
+	char *opbuf;
+	char *sbuf;
+
+	/* we use this, since this is what gets passed to dhclient-script */
+
+	opbuf = pretty_print_option(option, l->options[option].data,
+	    l->options[option].len, 0, 0);
+
+	sbuf = option_as_string(option, l->options[option].data,
+	    l->options[option].len);
+
+	switch (option) {
+	case DHO_SUBNET_MASK:
+	case DHO_TIME_SERVERS:
+	case DHO_NAME_SERVERS:
+	case DHO_ROUTERS:
+	case DHO_DOMAIN_NAME_SERVERS:
+	case DHO_LOG_SERVERS:
+	case DHO_COOKIE_SERVERS:
+	case DHO_LPR_SERVERS:
+	case DHO_IMPRESS_SERVERS:
+	case DHO_RESOURCE_LOCATION_SERVERS:
+	case DHO_SWAP_SERVER:
+	case DHO_BROADCAST_ADDRESS:
+	case DHO_NIS_SERVERS:
+	case DHO_NTP_SERVERS:
+	case DHO_NETBIOS_NAME_SERVERS:
+	case DHO_NETBIOS_DD_SERVER:
+	case DHO_FONT_SERVERS:
+	case DHO_DHCP_SERVER_IDENTIFIER:
+	case DHO_NISPLUS_SERVERS:
+	case DHO_MOBILE_IP_HOME_AGENT:
+	case DHO_SMTP_SERVER:
+	case DHO_POP_SERVER:
+	case DHO_NNTP_SERVER:
+	case DHO_WWW_SERVER:
+	case DHO_FINGER_SERVER:
+	case DHO_IRC_SERVER:
+	case DHO_STREETTALK_SERVER:
+	case DHO_STREETTALK_DA_SERVER:
+		if (!ipv4addrs(opbuf)) {
+			warning("Invalid IP address in option: %s", opbuf);
+			return (0);
+		}
+		return (1)  ;
+	case DHO_HOST_NAME:
+	case DHO_NIS_DOMAIN:
+	case DHO_NISPLUS_DOMAIN:
+	case DHO_TFTP_SERVER_NAME:
+		if (!res_hnok(sbuf)) {
+			warning("Bogus Host Name option %d: %s (%s)", option,
+			    sbuf, opbuf);
+			l->options[option].len = 0;
+			free(l->options[option].data);
+		}
+		return (1);
+	case DHO_DOMAIN_NAME:
+		if (!res_hnok(sbuf)) {
+			if (!check_search(sbuf)) {
+				warning("Bogus domain search list %d: %s (%s)",
+				    option, sbuf, opbuf);
+				l->options[option].len = 0;
+				free(l->options[option].data);
+			}
+		}
+		return (1);
+	case DHO_PAD:
+	case DHO_TIME_OFFSET:
+	case DHO_BOOT_SIZE:
+	case DHO_MERIT_DUMP:
+	case DHO_ROOT_PATH:
+	case DHO_EXTENSIONS_PATH:
+	case DHO_IP_FORWARDING:
+	case DHO_NON_LOCAL_SOURCE_ROUTING:
+	case DHO_POLICY_FILTER:
+	case DHO_MAX_DGRAM_REASSEMBLY:
+	case DHO_DEFAULT_IP_TTL:
+	case DHO_PATH_MTU_AGING_TIMEOUT:
+	case DHO_PATH_MTU_PLATEAU_TABLE:
+	case DHO_INTERFACE_MTU:
+	case DHO_ALL_SUBNETS_LOCAL:
+	case DHO_PERFORM_MASK_DISCOVERY:
+	case DHO_MASK_SUPPLIER:
+	case DHO_ROUTER_DISCOVERY:
+	case DHO_ROUTER_SOLICITATION_ADDRESS:
+	case DHO_STATIC_ROUTES:
+	case DHO_TRAILER_ENCAPSULATION:
+	case DHO_ARP_CACHE_TIMEOUT:
+	case DHO_IEEE802_3_ENCAPSULATION:
+	case DHO_DEFAULT_TCP_TTL:
+	case DHO_TCP_KEEPALIVE_INTERVAL:
+	case DHO_TCP_KEEPALIVE_GARBAGE:
+	case DHO_VENDOR_ENCAPSULATED_OPTIONS:
+	case DHO_NETBIOS_NODE_TYPE:
+	case DHO_NETBIOS_SCOPE:
+	case DHO_X_DISPLAY_MANAGER:
+	case DHO_DHCP_REQUESTED_ADDRESS:
+	case DHO_DHCP_LEASE_TIME:
+	case DHO_DHCP_OPTION_OVERLOAD:
+	case DHO_DHCP_MESSAGE_TYPE:
+	case DHO_DHCP_PARAMETER_REQUEST_LIST:
+	case DHO_DHCP_MESSAGE:
+	case DHO_DHCP_MAX_MESSAGE_SIZE:
+	case DHO_DHCP_RENEWAL_TIME:
+	case DHO_DHCP_REBINDING_TIME:
+	case DHO_DHCP_CLASS_IDENTIFIER:
+	case DHO_DHCP_CLIENT_IDENTIFIER:
+	case DHO_BOOTFILE_NAME:
+	case DHO_DHCP_USER_CLASS_ID:
+	case DHO_END:
+		return (1);
+	case DHO_CLASSLESS_ROUTES:
+		return (check_classless_option(l->options[option].data,
+		    l->options[option].len));
+	default:
+		warning("unknown dhcp option value 0x%x", option);
+		return (unknown_ok);
+	}
+}
+
+/* RFC 3442 The Classless Static Routes option checks */
+int
+check_classless_option(unsigned char *data, int len)
+{
+	int i = 0;
+	unsigned char width;
+	in_addr_t addr, mask;
+
+	if (len < 5) {
+		warning("Too small length: %d", len);
+		return (0);
+	}
+	while(i < len) {
+		width = data[i++];
+		if (width == 0) {
+			i += 4;
+			continue;
+		} else if (width < 9) {
+			addr =  (in_addr_t)(data[i] 	<< 24);
+			i += 1;
+		} else if (width < 17) {
+			addr =  (in_addr_t)(data[i] 	<< 24) +
+				(in_addr_t)(data[i + 1]	<< 16);
+			i += 2;
+		} else if (width < 25) {
+			addr =  (in_addr_t)(data[i] 	<< 24) +
+				(in_addr_t)(data[i + 1]	<< 16) +
+				(in_addr_t)(data[i + 2]	<< 8);
+			i += 3;
+		} else if (width < 33) {
+			addr =  (in_addr_t)(data[i] 	<< 24) +
+				(in_addr_t)(data[i + 1]	<< 16) +
+				(in_addr_t)(data[i + 2]	<< 8)  +
+				data[i + 3];
+			i += 4;
+		} else {
+			warning("Incorrect subnet width: %d", width);
+			return (0);
+		}
+		mask = (in_addr_t)(~0) << (32 - width);
+		addr = ntohl(addr);
+		mask = ntohl(mask);
+
+		/*
+		 * From RFC 3442:
+		 * ... After deriving a subnet number and subnet mask
+		 * from each destination descriptor, the DHCP client
+		 * MUST zero any bits in the subnet number where the
+		 * corresponding bit in the mask is zero...
+		 */
+		if ((addr & mask) != addr) {
+			addr &= mask;
+			data[i - 1] = (unsigned char)(
+				(addr >> (((32 - width)/8)*8)) & 0xFF);
+		} 
+		i += 4;
+	}
+	if (i > len) {
+		warning("Incorrect data length: %d (must be %d)", len, i);
+		return (0);
+	}
+	return (1);
+}
+
+int
+res_hnok(const char *dn)
+{
+	int pch = PERIOD, ch = *dn++;
+
+	while (ch != '\0') {
+		int nch = *dn++;
+
+		if (periodchar(ch)) {
+			;
+		} else if (periodchar(pch)) {
+			if (!borderchar(ch))
+				return (0);
+		} else if (periodchar(nch) || nch == '\0') {
+			if (!borderchar(ch))
+				return (0);
+		} else {
+			if (!middlechar(ch))
+				return (0);
+		}
+		pch = ch, ch = nch;
+	}
+	return (1);
+}
+
+int
+check_search(const char *srch)
+{
+        int pch = PERIOD, ch = *srch++;
+	int domains = 1;
+
+	/* 256 char limit re resolv.conf(5) */
+	if (strlen(srch) > 256)
+		return (0);
+
+	while (whitechar(ch))
+		ch = *srch++;
+
+        while (ch != '\0') {
+                int nch = *srch++;
+
+                if (periodchar(ch) || whitechar(ch)) {
+                        ;
+                } else if (periodchar(pch)) {
+                        if (!borderchar(ch))
+                                return (0);
+                } else if (periodchar(nch) || nch == '\0') {
+                        if (!borderchar(ch))
+                                return (0);
+                } else {
+                        if (!middlechar(ch))
+                                return (0);
+                }
+		if (!whitechar(ch)) {
+			pch = ch;
+		} else {
+			while (whitechar(nch)) {
+				nch = *srch++;
+			}
+			if (nch != '\0')
+				domains++;
+			pch = PERIOD;
+		}
+		ch = nch;
+        }
+	/* 6 domain limit re resolv.conf(5) */
+	if (domains > 6)
+		return (0);
+        return (1);
+}
+
+/* Does buf consist only of dotted decimal ipv4 addrs?
+ * return how many if so,
+ * otherwise, return 0
+ */
+int
+ipv4addrs(char * buf)
+{
+	struct in_addr jnk;
+	int count = 0;
+
+	while (inet_aton(buf, &jnk) == 1){
+		count++;
+		while (periodchar(*buf) || digitchar(*buf))
+			buf++;
+		if (*buf == '\0')
+			return (count);
+		while (*buf ==  ' ')
+			buf++;
+	}
+	return (0);
+}
+
+
+char *
+option_as_string(unsigned int code, unsigned char *data, int len)
+{
+	static char optbuf[32768]; /* XXX */
+	char *op = optbuf;
+	int opleft = sizeof(optbuf);
+	unsigned char *dp = data;
+
+	if (code > 255)
+		error("option_as_string: bad code %d", code);
+
+	for (; dp < data + len; dp++) {
+		if (!isascii(*dp) || !isprint(*dp)) {
+			if (dp + 1 != data + len || *dp != 0) {
+				snprintf(op, opleft, "\\%03o", *dp);
+				op += 4;
+				opleft -= 4;
+			}
+		} else if (*dp == '"' || *dp == '\'' || *dp == '$' ||
+		    *dp == '`' || *dp == '\\') {
+			*op++ = '\\';
+			*op++ = *dp;
+			opleft -= 2;
+		} else {
+			*op++ = *dp;
+			opleft--;
+		}
+	}
+	if (opleft < 1)
+		goto toobig;
+	*op = 0;
+	return optbuf;
+toobig:
+	warning("dhcp option too large");
+	return "<error>";
+}
+
+int
+fork_privchld(int fd, int fd2)
+{
+	struct pollfd pfd[1];
+	int nfds;
+
+	switch (fork()) {
+	case -1:
+		error("cannot fork");
+	case 0:
+		break;
+	default:
+		return (0);
+	}
+
+	setproctitle("%s [priv]", ifi->name);
+
+	setsid();
+	dup2(nullfd, STDIN_FILENO);
+	dup2(nullfd, STDOUT_FILENO);
+	dup2(nullfd, STDERR_FILENO);
+	close(nullfd);
+	close(fd2);
+
+	for (;;) {
+		pfd[0].fd = fd;
+		pfd[0].events = POLLIN;
+		if ((nfds = poll(pfd, 1, INFTIM)) == -1)
+			if (errno != EINTR)
+				error("poll error");
+
+		if (nfds == 0 || !(pfd[0].revents & POLLIN))
+			continue;
+
+		dispatch_imsg(fd);
+	}
+}
diff --git a/freebsd-userspace/commands/sbin/dhclient/dhclient.conf b/freebsd-userspace/commands/sbin/dhclient/dhclient.conf
new file mode 100644
index 0000000..7eaeeb8
--- /dev/null
+++ b/freebsd-userspace/commands/sbin/dhclient/dhclient.conf
@@ -0,0 +1,39 @@
+# $FreeBSD$
+
+send host-name "andare.fugue.com";
+send dhcp-client-identifier 1:0:a0:24:ab:fb:9c;
+send dhcp-lease-time 3600;
+supersede domain-name "fugue.com home.vix.com";
+prepend domain-name-servers 127.0.0.1;
+request subnet-mask, broadcast-address, time-offset,
+	classless-routes, routers, domain-name,
+	domain-name-servers, host-name;
+require subnet-mask, domain-name-servers;
+timeout 60;
+retry 60;
+reboot 10;
+select-timeout 5;
+initial-interval 2;
+script "/etc/dhclient-script";
+media "-link0 -link1 -link2", "link0 link1";
+reject 192.33.137.209;
+
+alias {
+  interface "ep0";
+  fixed-address 192.5.5.213;
+  option subnet-mask 255.255.255.255;
+}
+
+lease {
+  interface "ep0";
+  fixed-address 192.33.137.200;
+  medium "link0 link1";
+  option host-name "andare.swiftmedia.com";
+  option subnet-mask 255.255.255.0;
+  option broadcast-address 192.33.137.255;
+  option routers 192.33.137.250;
+  option domain-name-servers 127.0.0.1;
+  renew 2 2000/1/12 00:00:01;
+  rebind 2 2000/1/12 00:00:01;
+  expire 2 2000/1/12 00:00:01;
+}
diff --git a/freebsd-userspace/commands/sbin/dhclient/dhclient.conf.5 b/freebsd-userspace/commands/sbin/dhclient/dhclient.conf.5
new file mode 100644
index 0000000..167239e
--- /dev/null
+++ b/freebsd-userspace/commands/sbin/dhclient/dhclient.conf.5
@@ -0,0 +1,544 @@
+.\"	$OpenBSD: dhclient.conf.5,v 1.5 2004/11/01 23:10:18 henning Exp $
+.\"
+.\" Copyright (c) 1997 The Internet Software Consortium.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of The Internet Software Consortium nor the names
+.\"    of its contributors may be used to endorse or promote products derived
+.\"    from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM 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 INTERNET SOFTWARE CONSORTIUM 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 software has been written for the Internet Software Consortium
+.\" by Ted Lemon <mellon at fugue.com> in cooperation with Vixie
+.\" Enterprises.  To learn more about the Internet Software Consortium,
+.\" see ``http://www.isc.org/isc''.  To learn more about Vixie
+.\" Enterprises, see ``http://www.vix.com''.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd January 1, 1997
+.Dt DHCLIENT.CONF 5
+.Os
+.Sh NAME
+.Nm dhclient.conf
+.Nd DHCP client configuration file
+.Sh DESCRIPTION
+The
+.Nm
+file contains configuration information for
+.Xr dhclient 8 ,
+the Internet Software Consortium DHCP Client.
+.Pp
+The
+.Nm
+file is a free-form ASCII text file.
+It is parsed by the recursive-descent parser built into
+.Xr dhclient 8 .
+The file may contain extra tabs and newlines for formatting purposes.
+Keywords in the file are case-insensitive.
+Comments may be placed anywhere within the file (except within quotes).
+Comments begin with the
+.Ql #
+character and end at the end of the line.
+.Pp
+The
+.Nm
+file can be used to configure the behaviour of the client in a wide variety
+of ways: protocol timing, information requested from the server, information
+required of the server, defaults to use if the server does not provide
+certain information, values with which to override information provided by
+the server, or values to prepend or append to information provided by the
+server.
+The configuration file can also be preinitialized with addresses to
+use on networks that do not have DHCP servers.
+.Sh PROTOCOL TIMING
+The timing behaviour of the client need not be configured by the user.
+If no timing configuration is provided by the user, a fairly
+reasonable timing behaviour will be used by default - one which
+results in fairly timely updates without placing an inordinate load on
+the server.
+.Pp
+The following statements can be used to adjust the timing behaviour of
+the DHCP client if required, however:
+.Bl -tag -width indent
+.It Ic timeout Ar time ;
+The
+.Ic timeout
+statement determines the amount of time that must pass between the
+time that the client begins to try to determine its address and the
+time that it decides that it is not going to be able to contact a server.
+By default, this timeout is sixty seconds.
+After the timeout has passed, if there are any static leases defined in the
+configuration file, or any leases remaining in the lease database that
+have not yet expired, the client will loop through these leases
+attempting to validate them, and if it finds one that appears to be
+valid, it will use that lease's address.
+If there are no valid static leases or unexpired leases in the lease database,
+the client will restart the protocol after the defined retry interval.
+.It Ic retry Ar time ;
+The
+.Ic retry
+statement determines the time that must pass after the client has
+determined that there is no DHCP server present before it tries again
+to contact a DHCP server.
+By default, this is five minutes.
+.It Ic select-timeout Ar time ;
+It is possible (some might say desirable) for there to be more than
+one DHCP server serving any given network.
+In this case, it is possible that a client may be sent more than one offer
+in response to its initial lease discovery message.
+It may be that one of these offers is preferable to the other
+(e.g., one offer may have the address the client previously used,
+and the other may not).
+.Pp
+The
+.Ic select-timeout
+is the time after the client sends its first lease discovery request
+at which it stops waiting for offers from servers, assuming that it
+has received at least one such offer.
+If no offers have been received by the time the
+.Ic select-timeout
+has expired, the client will accept the first offer that arrives.
+.Pp
+By default, the
+.Ic select-timeout
+is zero seconds - that is, the client will take the first offer it sees.
+.It Ic reboot Ar time ;
+When the client is restarted, it first tries to reacquire the last
+address it had.
+This is called the INIT-REBOOT state.
+If it is still attached to the same network it was attached to when it last
+ran, this is the quickest way to get started.
+The
+.Ic reboot
+statement sets the time that must elapse after the client first tries
+to reacquire its old address before it gives up and tries to discover
+a new address.
+By default, the reboot timeout is ten seconds.
+.It Ic backoff-cutoff Ar time ;
+The client uses an exponential backoff algorithm with some randomness,
+so that if many clients try to configure themselves at the same time,
+they will not make their requests in lockstep.
+The
+.Ic backoff-cutoff
+statement determines the maximum amount of time that the client is
+allowed to back off.
+It defaults to two minutes.
+.It Ic initial-interval Ar time ;
+The
+.Ic initial-interval
+statement sets the amount of time between the first attempt to reach a
+server and the second attempt to reach a server.
+Each time a message is sent, the interval between messages is incremented by
+twice the current interval multiplied by a random number between zero and one.
+If it is greater than the
+.Ic backoff-cutoff
+amount, it is set to that
+amount.
+It defaults to ten seconds.
+.El
+.Sh LEASE REQUIREMENTS AND REQUESTS
+The DHCP protocol allows the client to request that the server send it
+specific information, and not send it other information that it is not
+prepared to accept.
+The protocol also allows the client to reject offers from servers if they
+do not contain information the client needs, or if the information provided
+is not satisfactory.
+.Pp
+There is a variety of data contained in offers that DHCP servers send
+to DHCP clients.
+The data that can be specifically requested is what are called
+.Em DHCP Options .
+DHCP Options are defined in
+.Xr dhcp-options 5 .
+.Bl -tag -width indent
+.It Ic request Oo Ar option Oc Oo , Ar ... option Oc ;
+The
+.Ic request
+statement causes the client to request that any server responding to the
+client send the client its values for the specified options.
+Only the option names should be specified in the request statement - not
+option parameters.
+.It Ic require Oo Ar option Oc Oo , Ar ... option Oc ;
+The
+.Ic require
+statement lists options that must be sent in order for an offer to be accepted.
+Offers that do not contain all the listed options will be ignored.
+.It Ic send No { Oo Ar option declaration Oc Oo , Ar ... option declaration Oc }
+The
+.Ic send
+statement causes the client to send the specified options to the server with
+the specified values.
+These are full option declarations as described in
+.Xr dhcp-options 5 .
+Options that are always sent in the DHCP protocol should not be specified
+here, except that the client can specify a
+.Ar dhcp-lease-time
+option other than the default requested lease time, which is two hours.
+The other obvious use for this statement is to send information to the server
+that will allow it to differentiate between this client and other
+clients or kinds of clients.
+.El
+.Sh OPTION MODIFIERS
+In some cases, a client may receive option data from the server which
+is not really appropriate for that client, or may not receive
+information that it needs, and for which a useful default value exists.
+It may also receive information which is useful, but which needs to be
+supplemented with local information.
+To handle these needs, several option modifiers are available.
+.Bl -tag -width indent
+.It Xo
+.Ic default No { Op Ar option declaration
+.Oo , Ar ... option declaration Oc }
+.Xc
+If for some set of options the client should use the value supplied by
+the server, but needs to use some default value if no value was supplied
+by the server, these values can be defined in the
+.Ic default
+statement.
+.It Xo
+.Ic supersede No { Op Ar option declaration
+.Oo , Ar ... option declaration Oc }
+.Xc
+If for some set of options the client should always use its own value
+rather than any value supplied by the server, these values can be defined
+in the
+.Ic supersede
+statement.
+.It Xo
+.Ic prepend No { Op Ar option declaration
+.Oo , Ar ... option declaration Oc }
+.Xc
+If for some set of options the client should use a value you supply,
+and then use the values supplied by the server, if any,
+these values can be defined in the
+.Ic prepend
+statement.
+The
+.Ic prepend
+statement can only be used for options which allow more than one value to
+be given.
+This restriction is not enforced - if violated, the results are unpredictable.
+.It Xo
+.Ic append No { Op Ar option declaration
+.Oo , Ar ... option declaration Oc }
+.Xc
+If for some set of options the client should first use the values
+supplied by the server, if any, and then use values you supply, these
+values can be defined in the
+.Ic append
+statement.
+The
+.Ic append
+statement can only be used for options which allow more than one value to
+be given.
+This restriction is not enforced - if you ignore it,
+the behaviour will be unpredictable.
+.El
+.Sh LEASE DECLARATIONS
+The lease declaration:
+.Pp
+.D1 Ic lease No { Ar lease-declaration Oo Ar ... lease-declaration Oc }
+.Pp
+The DHCP client may decide after some period of time (see
+.Sx PROTOCOL TIMING )
+that it is not going to succeed in contacting a server.
+At that time, it consults its own database of old leases and tests each one
+that has not yet timed out by pinging the listed router for that lease to
+see if that lease could work.
+It is possible to define one or more
+.Em fixed
+leases in the client configuration file for networks where there is no DHCP
+or BOOTP service, so that the client can still automatically configure its
+address.
+This is done with the
+.Ic lease
+statement.
+.Pp
+NOTE: the lease statement is also used in the
+.Pa dhclient.leases
+file in order to record leases that have been received from DHCP servers.
+Some of the syntax for leases as described below is only needed in the
+.Pa dhclient.leases
+file.
+Such syntax is documented here for completeness.
+.Pp
+A lease statement consists of the
+.Ic lease
+keyword, followed by a left
+curly brace, followed by one or more lease declaration statements,
+followed by a right curly brace.
+The following lease declarations are possible:
+.Bl -tag -width indent
+.It Ic bootp ;
+The
+.Ic bootp
+statement is used to indicate that the lease was acquired using the
+BOOTP protocol rather than the DHCP protocol.
+It is never necessary to specify this in the client configuration file.
+The client uses this syntax in its lease database file.
+.It Ic interface Qq Ar string ;
+The
+.Ic interface
+lease statement is used to indicate the interface on which the lease is valid.
+If set, this lease will only be tried on a particular interface.
+When the client receives a lease from a server, it always records the
+interface number on which it received that lease.
+If predefined leases are specified in the
+.Nm
+file, the interface should also be specified, although this is not required.
+.It Ic fixed-address Ar ip-address ;
+The
+.Ic fixed-address
+statement is used to set the IP address of a particular lease.
+This is required for all lease statements.
+The IP address must be specified as a dotted quad (e.g.,
+.Li 12.34.56.78 ) .
+.It Ic filename Qq Ar string ;
+The
+.Ic filename
+statement specifies the name of the boot filename to use.
+This is not used by the standard client configuration script, but is
+included for completeness.
+.It Ic server-name Qq Ar string ;
+The
+.Ic server-name
+statement specifies the name of the boot server name to use.
+This is also not used by the standard client configuration script.
+.It Ic option Ar option-declaration ;
+The
+.Ic option
+statement is used to specify the value of an option supplied by the server,
+or, in the case of predefined leases declared in
+.Nm ,
+the value that the user wishes the client configuration script to use if the
+predefined lease is used.
+.It Ic script Qq Ar script-name ;
+The
+.Ic script
+statement is used to specify the pathname of the DHCP client configuration
+script.
+This script is used by the DHCP client to set each interface's initial
+configuration prior to requesting an address, to test the address once it
+has been offered, and to set the interface's final configuration once a
+lease has been acquired.
+If no lease is acquired, the script is used to test predefined leases, if
+any, and also called once if no valid lease can be identified.
+For more information, see
+.Xr dhclient.leases 5 .
+.It Ic medium Qq Ar "media setup" ;
+The
+.Ic medium
+statement can be used on systems where network interfaces cannot
+automatically determine the type of network to which they are connected.
+The
+.Ar "media setup"
+string is a system-dependent parameter which is passed
+to the DHCP client configuration script when initializing the interface.
+On
+.Ux
+and
+.Ux Ns -like
+systems, the argument is passed on the
+.Xr ifconfig 8
+command line
+when configuring the interface.
+.Pp
+The DHCP client automatically declares this parameter if it used a
+media type (see the
+.Ic media
+statement) when configuring the interface in order to obtain a lease.
+This statement should be used in predefined leases only if the network
+interface requires media type configuration.
+.It Ic renew Ar date ;
+.It Ic rebind Ar date ;
+.It Ic expire Ar date ;
+The
+.Ic renew
+statement defines the time at which the DHCP client should begin trying to
+contact its server to renew a lease that it is using.
+The
+.Ic rebind
+statement defines the time at which the DHCP client should begin to try to
+contact
+.Em any
+DHCP server in order to renew its lease.
+The
+.Ic expire
+statement defines the time at which the DHCP client must stop using a lease
+if it has not been able to contact a server in order to renew it.
+.El
+.Pp
+These declarations are automatically set in leases acquired by the
+DHCP client, but must also be configured in predefined leases - a
+predefined lease whose expiry time has passed will not be used by the
+DHCP client.
+.Pp
+Dates are specified as follows:
+.Bd -ragged -offset indent
+.Ar <weekday>
+.Sm off
+.Ar <year> No / Ar <month> No / Ar <day>
+.Ar <hour> : <minute> : <second>
+.Sm on
+.Ed
+.Pp
+The weekday is present to make it easy for a human to tell when a
+lease expires - it is specified as a number from zero to six, with zero
+being Sunday.
+When declaring a predefined lease, it can always be specified as zero.
+The year is specified with the century, so it should generally be four
+digits except for really long leases.
+The month is specified as a number starting with 1 for January.
+The day of the month is likewise specified starting with 1.
+The hour is a number between 0 and 23,
+the minute a number between 0 and 59,
+and the second also a number between 0 and 59.
+.Sh ALIAS DECLARATIONS
+.Ic alias No { Ar declarations ... No }
+.Pp
+Some DHCP clients running TCP/IP roaming protocols may require that in
+addition to the lease they may acquire via DHCP, their interface also
+be configured with a predefined IP alias so that they can have a
+permanent IP address even while roaming.
+The Internet Software Consortium DHCP client does not support roaming with
+fixed addresses directly, but in order to facilitate such experimentation,
+the DHCP client can be set up to configure an IP alias using the
+.Ic alias
+declaration.
+.Pp
+The
+.Ic alias
+declaration resembles a lease declaration, except that options other than
+the subnet-mask option are ignored by the standard client configuration
+script, and expiry times are ignored.
+A typical alias declaration includes an interface declaration, a fixed-address
+declaration for the IP alias address, and a subnet-mask option declaration.
+A medium statement should never be included in an alias declaration.
+.Sh OTHER DECLARATIONS
+.Bl -tag -width indent
+.It Ic reject Ar ip-address ;
+The
+.Ic reject
+statement causes the DHCP client to reject offers from servers who use
+the specified address as a server identifier.
+This can be used to avoid being configured by rogue or misconfigured DHCP
+servers, although it should be a last resort - better to track down
+the bad DHCP server and fix it.
+.It Ic interface Qo Ar name Qc { Ar declarations ... No }
+A client with more than one network interface may require different
+behaviour depending on which interface is being configured.
+All timing parameters and declarations other than lease and alias
+declarations can be enclosed in an interface declaration, and those
+parameters will then be used only for the interface that matches the
+specified name.
+Interfaces for which there is no interface declaration will use the
+parameters declared outside of any interface declaration,
+or the default settings.
+.It Ic media Qo Ar "media setup" Qc Oo , Qo Ar "media setup" Qc , Ar ... Oc ;
+The
+.Ic media
+statement defines one or more media configuration parameters which may
+be tried while attempting to acquire an IP address.
+The DHCP client will cycle through each media setup string on the list,
+configuring the interface using that setup and attempting to boot,
+and then trying the next one.
+This can be used for network interfaces which are not capable of sensing
+the media type unaided - whichever media type succeeds in getting a request
+to the server and hearing the reply is probably right (no guarantees).
+.Pp
+The media setup is only used for the initial phase of address
+acquisition (the DHCPDISCOVER and DHCPOFFER packets).
+Once an address has been acquired, the DHCP client will record it in its
+lease database and will record the media type used to acquire the address.
+Whenever the client tries to renew the lease, it will use that same media type.
+The lease must expire before the client will go back to cycling through media
+types.
+.El
+.Sh EXAMPLES
+The following configuration file is used on a laptop
+which has an IP alias of
+.Li 192.5.5.213 ,
+and has one interface,
+.Li ep0
+(a 3Com 3C589C).
+Booting intervals have been shortened somewhat from the default, because
+the client is known to spend most of its time on networks with little DHCP
+activity.
+The laptop does roam to multiple networks.
+.Bd -literal -offset indent
+timeout 60;
+retry 60;
+reboot 10;
+select-timeout 5;
+initial-interval 2;
+reject 192.33.137.209;
+
+interface "ep0" {
+    send host-name "andare.fugue.com";
+    send dhcp-client-identifier 1:0:a0:24:ab:fb:9c;
+    send dhcp-lease-time 3600;
+    supersede domain-name "fugue.com rc.vix.com home.vix.com";
+    prepend domain-name-servers 127.0.0.1;
+    request subnet-mask, broadcast-address, time-offset, routers,
+	    domain-name, domain-name-servers, host-name;
+    require subnet-mask, domain-name-servers;
+    script "/etc/dhclient-script";
+    media "media 10baseT/UTP", "media 10base2/BNC";
+}
+
+alias {
+  interface "ep0";
+  fixed-address 192.5.5.213;
+  option subnet-mask 255.255.255.255;
+}
+.Ed
+.Pp
+This is a very complicated
+.Nm
+file - in general, yours should be much simpler.
+In many cases, it is sufficient to just create an empty
+.Nm
+file - the defaults are usually fine.
+.Sh SEE ALSO
+.Xr dhclient.leases 5 ,
+.Xr dhcpd.conf 5 ,
+.Xr dhcp-options 5 ,
+.Xr dhclient 8 ,
+.Xr dhcpd 8
+.Rs
+.%R "RFC 2132, RFC 2131"
+.Re
+.Sh AUTHORS
+.An -nosplit
+The
+.Xr dhclient 8
+utility
+was written by
+.An Ted Lemon Aq mellon at vix.com
+under a contract with Vixie Labs.
+.Pp
+The current implementation was reworked by
+.An Henning Brauer Aq henning at openbsd.org .
diff --git a/freebsd-userspace/commands/sbin/dhclient/dhclient.leases.5 b/freebsd-userspace/commands/sbin/dhclient/dhclient.leases.5
new file mode 100644
index 0000000..b1f0f3d
--- /dev/null
+++ b/freebsd-userspace/commands/sbin/dhclient/dhclient.leases.5
@@ -0,0 +1,95 @@
+.\"	$OpenBSD: dhclient.leases.5,v 1.4 2004/04/15 08:59:47 jmc Exp $
+.\"
+.\" Copyright (c) 1997 The Internet Software Consortium.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of The Internet Software Consortium nor the names
+.\"    of its contributors may be used to endorse or promote products derived
+.\"    from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM 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 INTERNET SOFTWARE CONSORTIUM 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 software has been written for the Internet Software Consortium
+.\" by Ted Lemon <mellon at fugue.com> in cooperation with Vixie
+.\" Enterprises.  To learn more about the Internet Software Consortium,
+.\" see ``http://www.isc.org/isc''.  To learn more about Vixie
+.\" Enterprises, see ``http://www.vix.com''.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd January 1, 1997
+.Dt DHCLIENT.LEASES 5
+.Os
+.Sh NAME
+.Nm dhclient.leases
+.Nd DHCP client lease database
+.Sh DESCRIPTION
+The Internet Software Consortium DHCP client keeps a persistent
+database of leases that it has acquired that are still valid.
+The database is a free-form ASCII file containing one valid declaration
+per lease.
+If more than one declaration appears for a given lease,
+the last one in the file is used.
+The file is written as a log, so this is not an unusual occurrence.
+.Pp
+The lease file is named
+.Pa dhclient.leases. Ns Ar IFNAME ,
+where
+.Ar IFNAME
+represents the network interface the DHCP client acquired the lease on.
+For example, if
+.Xr dhclient 8
+is configured for the
+.Li em0
+network device,
+the lease file will be named
+.Pa dhclient.leases.em0 .
+.Pp
+The format of the lease declarations is described in
+.Xr dhclient.conf 5 .
+.Sh FILES
+.Bl -tag -width ".Pa /var/db/dhclient.leases. Ns Ar IFNAME"
+.It Pa /var/db/dhclient.leases. Ns Ar IFNAME
+Current lease file.
+.El
+.Sh SEE ALSO
+.Xr dhclient.conf 5 ,
+.Xr dhcpd.conf 5 ,
+.Xr dhcp-options 5 ,
+.Xr dhclient 8 ,
+.Xr dhcpd 8
+.Rs
+.%R "RFC 2132, RFC 2131"
+.Re
+.Sh AUTHORS
+.An -nosplit
+The
+.Xr dhclient 8
+utility
+was written by
+.An Ted Lemon Aq mellon at vix.com
+under a contract with Vixie Labs.
+.Pp
+The current implementation was reworked by
+.An Henning Brauer Aq henning at openbsd.org .
diff --git a/freebsd-userspace/commands/sbin/dhclient/dhcp-options.5 b/freebsd-userspace/commands/sbin/dhclient/dhcp-options.5
new file mode 100644
index 0000000..3735606
--- /dev/null
+++ b/freebsd-userspace/commands/sbin/dhclient/dhcp-options.5
@@ -0,0 +1,606 @@
+.\"	$OpenBSD: dhcp-options.5,v 1.5 2005/03/02 15:30:42 jmc Exp $
+.\"
+.\" Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of The Internet Software Consortium nor the names
+.\"    of its contributors may be used to endorse or promote products derived
+.\"    from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM 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 INTERNET SOFTWARE CONSORTIUM 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 software has been written for the Internet Software Consortium
+.\" by Ted Lemon <mellon at fugue.com> in cooperation with Vixie
+.\" Enterprises.  To learn more about the Internet Software Consortium,
+.\" see ``http://www.isc.org/isc''.  To learn more about Vixie
+.\" Enterprises, see ``http://www.vix.com''.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd January 1, 1995
+.Dt DHCP-OPTIONS 5
+.Os
+.Sh NAME
+.Nm dhcp-options
+.Nd Dynamic Host Configuration Protocol options
+.Sh DESCRIPTION
+The Dynamic Host Configuration protocol allows the client to receive
+.Ic options
+from the DHCP server describing the network configuration and various
+services that are available on the network.
+When configuring
+.Xr dhcpd 8
+or
+.Xr dhclient 8 ,
+options must often be declared.
+The syntax for declaring options, and the names and formats of the options
+that can be declared, are documented here.
+.Sh REFERENCE: OPTION STATEMENTS
+DHCP
+.Ic option
+statements always start with the
+.Ic option
+keyword, followed by an option name, followed by option data.
+The option names and data formats are described below.
+It is not necessary to exhaustively specify all DHCP options -
+only those options which are needed by clients must be specified.
+.Pp
+Option data comes in a variety of formats, as defined below:
+.Pp
+The
+.Ar ip-address
+data type can be entered either as an explicit IP address
+(e.g.,
+.Li 239.254.197.10 )
+or as a domain name (e.g.,
+.Li haagen.isc.org ) .
+A domain name must resolve to a single IP address.
+.Pp
+The
+.Ar int32
+data type specifies a signed 32-bit integer.
+The
+.Ar uint32
+data type specifies an unsigned 32-bit integer.
+The
+.Ar int16
+and
+.Ar uint16
+data types specify signed and unsigned 16-bit integers.
+The
+.Ar int8
+and
+.Ar uint8
+data types specify signed and unsigned 8-bit integers.
+Unsigned 8-bit integers are also sometimes referred to as octets.
+.Pp
+The
+.Ar string
+data type specifies an
+.Tn NVT
+.Pq Network Virtual Terminal
+.Tn ASCII
+string, which must be enclosed in double quotes - for example,
+to specify a domain-name option, the syntax would be
+.Pp
+.Dl option domain-name \&"isc.org";
+.Pp
+The
+.Ar flag
+data type specifies a boolean value.
+Booleans can be either
+.Li true
+or
+.Li false
+(or
+.Li on
+or
+.Li off ,
+if that makes more sense to you).
+.Pp
+The
+.Ar data-string
+data type specifies either an
+.Tn NVT ASCII
+string enclosed in double quotes, or a series of octets specified in
+hexadecimal, separated by colons.
+For example:
+.Pp
+.Dl option dhcp-client-identifier \&"CLIENT-FOO";
+or
+.Dl option dhcp-client-identifier 43:4c:49:45:54:2d:46:4f:4f;
+.Pp
+The documentation for the various options mentioned below is taken
+from the IETF draft document on DHCP options, RFC 2132.
+Options which are not listed by name may be defined by the name
+.Li option- Ns Ar nnn ,
+where
+.Ar nnn
+is the decimal number of the option code.
+These options may be followed either by a string, enclosed in quotes, or by
+a series of octets, expressed as two-digit hexadecimal numbers separated
+by colons.
+For example:
+.Bd -literal -offset indent
+option option-133 "my-option-133-text";
+option option-129 1:54:c9:2b:47;
+.Ed
+.Pp
+Because
+.Xr dhcpd 8
+does not know the format of these undefined option codes,
+no checking is done to ensure the correctness of the entered data.
+.Pp
+The standard options are:
+.Ss RFC 1497 Vendor Extensions
+.Bl -tag -width indent
+.It Ic option subnet-mask Ar ip-address ;
+The
+.Ic subnet-mask
+option specifies the client's subnet mask as per RFC 950.
+If no subnet-mask option is provided anywhere in scope, as a last resort
+.Xr dhcpd 8
+will use the subnet mask from the subnet declaration for the network on
+which an address is being assigned.
+However,
+.Em any
+subnet-mask option declaration that is in scope for the address being
+assigned will override the subnet mask specified in the subnet declaration.
+.It Ic option time-offset Ar int32 ;
+The
+.Ic time-offset
+option specifies the offset of the client's subnet in seconds from
+Coordinated Universal Time (UTC).
+.It Xo
+.Ic option routers Ar ip-address
+.Oo , Ar ip-address ... Oc ;
+.Xc
+The
+.Ic routers
+option specifies a list of IP addresses for routers on the client's subnet.
+Routers should be listed in order of preference.
+.It Xo
+.Ic option time-servers Ar ip-address
+.Oo , Ar ip-address ... Oc ;
+.Xc
+The
+.Ic time-server
+option specifies a list of RFC 868 time servers available to the client.
+Servers should be listed in order of preference.
+.It Xo
+.Ic option ien116-name-servers Ar ip-address
+.Oo , Ar ip-address ... Oc ;
+.Xc
+The
+.Ic ien116-name-servers
+option specifies a list of IEN 116 name servers available to the client.
+Servers should be listed in order of preference.
+.It Xo
+.Ic option domain-name-servers Ar ip-address
+.Oo , Ar ip-address ... Oc ;
+.Xc
+The
+.Ic domain-name-servers
+option specifies a list of Domain Name System (STD 13, RFC 1035) name servers
+available to the client.
+Servers should be listed in order of preference.
+.It Xo
+.Ic option log-servers Ar ip-address
+.Oo , Ar ip-address ... Oc ;
+.Xc
+The
+.Ic log-servers
+option specifies a list of MIT-LCS UDP log servers available to the client.
+Servers should be listed in order of preference.
+.It Xo
+.Ic option cookie-servers Ar ip-address
+.Oo , Ar ip-address ... Oc ;
+.Xc
+The
+.Ic cookie-servers
+option specifies a list of RFC 865 cookie servers available to the client.
+Servers should be listed in order of preference.
+.It Xo
+.Ic option lpr-servers Ar ip-address
+.Oo , Ar ip-address ... Oc ;
+.Xc
+The
+.Ic lpr-servers
+option specifies a list of RFC 1179 line printer servers available to the
+client.
+Servers should be listed in order of preference.
+.It Xo
+.Ic option impress-servers Ar ip-address
+.Oo , Ar ip-address ... Oc ;
+.Xc
+The
+.Ic impress-servers
+option specifies a list of Imagen Impress servers available to the client.
+Servers should be listed in order of preference.
+.It Xo
+.Ic option resource-location-servers Ar ip-address
+.Oo , Ar ip-address ... Oc ;
+.Xc
+This option specifies a list of RFC 887 Resource Location servers available
+to the client.
+Servers should be listed in order of preference.
+.It Ic option host-name Ar string ;
+This option specifies the name of the client.
+The name may or may not be qualified with the local domain name
+(it is preferable to use the
+.Ic domain-name
+option to specify the domain name).
+See RFC 1035 for character set restrictions.
+.It Ic option boot-size Ar uint16 ;
+This option specifies the length in 512-octet blocks of the default
+boot image for the client.
+.It Ic option merit-dump Ar string ;
+This option specifies the pathname of a file to which the client's
+core image should be dumped in the event the client crashes.
+The path is formatted as a character string consisting of characters from
+the
+.Tn NVT ASCII
+character set.
+.It Ic option domain-name Ar string ;
+This option specifies the domain name that the client should use when
+resolving hostnames via the Domain Name System.
+.It Ic option swap-server Ar ip-address ;
+This specifies the IP address of the client's swap server.
+.It Ic option root-path Ar string ;
+This option specifies the pathname that contains the client's root disk.
+The path is formatted as a character string consisting of characters from
+the
+.Tn NVT ASCII
+character set.
+.El
+.Ss IP Layer Parameters per Host
+.Bl -tag -width indent
+.It Ic option ip-forwarding Ar flag ;
+This option specifies whether the client should configure its IP layer
+for packet forwarding.
+A value of 0 means disable IP forwarding, and a value of 1 means enable
+IP forwarding.
+.It Ic option non-local-source-routing Ar flag ;
+This option specifies whether the client should configure its IP
+layer to allow forwarding of datagrams with non-local source routes
+(see Section 3.3.5 of [4] for a discussion of this topic).
+A value of 0 means disallow forwarding of such datagrams, and a value of 1
+means allow forwarding.
+.It Xo
+.Ic option policy-filter Ar ip-address ip-address
+.Oo , Ar ip-address ip-address ... Oc ;
+.Xc
+This option specifies policy filters for non-local source routing.
+The filters consist of a list of IP addresses and masks which specify
+destination/mask pairs with which to filter incoming source routes.
+.Pp
+Any source-routed datagram whose next-hop address does not match one
+of the filters should be discarded by the client.
+.Pp
+See STD 3 (RFC 1122) for further information.
+.It Ic option max-dgram-reassembly Ar uint16 ;
+This option specifies the maximum size datagram that the client should be
+prepared to reassemble.
+The minimum legal value is 576.
+.It Ic option default-ip-ttl Ar uint8 ;
+This option specifies the default time-to-live that the client should
+use on outgoing datagrams.
+.It Ic option path-mtu-aging-timeout Ar uint32 ;
+This option specifies the timeout (in seconds) to use when aging Path
+MTU values discovered by the mechanism defined in RFC 1191.
+.It Xo
+.Ic option path-mtu-plateau-table Ar uint16
+.Oo , Ar uint16 ... Oc ;
+.Xc
+This option specifies a table of MTU sizes to use when performing
+Path MTU Discovery as defined in RFC 1191.
+The table is formatted as a list of 16-bit unsigned integers,
+ordered from smallest to largest.
+The minimum MTU value cannot be smaller than 68.
+.El
+.Ss IP Layer Parameters per Interface
+.Bl -tag -width indent
+.It Ic option interface-mtu Ar uint16 ;
+This option specifies the MTU to use on this interface.
+The minimum legal value for the MTU is 68.
+.It Ic option all-subnets-local Ar flag ;
+This option specifies whether or not the client may assume that all subnets
+of the IP network to which the client is connected use the same MTU as the
+subnet of that network to which the client is directly connected.
+A value of 1 indicates that all subnets share the same MTU.
+A value of 0 means that the client should assume that some subnets of the
+directly connected network may have smaller MTUs.
+.It Ic option broadcast-address Ar ip-address ;
+This option specifies the broadcast address in use on the client's subnet.
+Legal values for broadcast addresses are specified in section 3.2.1.3 of
+STD 3 (RFC 1122).
+.It Ic option perform-mask-discovery Ar flag ;
+This option specifies whether or not the client should perform subnet mask
+discovery using ICMP.
+A value of 0 indicates that the client should not perform mask discovery.
+A value of 1 means that the client should perform mask discovery.
+.It Ic option mask-supplier Ar flag ;
+This option specifies whether or not the client should respond to subnet mask
+requests using ICMP.
+A value of 0 indicates that the client should not respond.
+A value of 1 means that the client should respond.
+.It Ic option router-discovery Ar flag ;
+This option specifies whether or not the client should solicit routers using
+the Router Discovery mechanism defined in RFC 1256.
+A value of 0 indicates that the client should not perform router discovery.
+A value of 1 means that the client should perform router discovery.
+.It Ic option router-solicitation-address Ar ip-address ;
+This option specifies the address to which the client should transmit
+router solicitation requests.
+.It Xo
+.Ic option static-routes Ar ip-address ip-address
+.Oo , Ar ip-address ip-address ... Oc ;
+.Xc
+This option specifies a list of static routes that the client should
+install in its routing cache.
+If multiple routes to the same destination are specified, they are listed
+in descending order of priority.
+.Pp
+The routes consist of a list of IP address pairs.
+The first address is the destination address,
+and the second address is the router for the destination.
+.Pp
+The default route (0.0.0.0) is an illegal destination for a static route.
+To specify the default route, use the
+.Ic routers
+option.
+.El
+.Ss Link Layer Parameters per Interface
+.Bl -tag -width indent
+.It Ic option trailer-encapsulation Ar flag ;
+This option specifies whether or not the client should negotiate the
+use of trailers (RFC 893 [14]) when using the ARP protocol.
+A value of 0 indicates that the client should not attempt to use trailers.
+A value of 1 means that the client should attempt to use trailers.
+.It Ic option arp-cache-timeout Ar uint32 ;
+This option specifies the timeout in seconds for ARP cache entries.
+.It Ic option ieee802-3-encapsulation Ar flag ;
+This option specifies whether or not the client should use Ethernet
+Version 2 (RFC 894) or IEEE 802.3 (RFC 1042) encapsulation if the
+interface is an Ethernet.
+A value of 0 indicates that the client should use RFC 894 encapsulation.
+A value of 1 means that the client should use RFC 1042 encapsulation.
+.El
+.Ss TCP Parameters
+.Bl -tag -width indent
+.It Ic option default-tcp-ttl Ar uint8 ;
+This option specifies the default TTL that the client should use when
+sending TCP segments.
+The minimum value is 1.
+.It Ic option tcp-keepalive-interval Ar uint32 ;
+This option specifies the interval (in seconds) that the client TCP
+should wait before sending a keepalive message on a TCP connection.
+The time is specified as a 32-bit unsigned integer.
+A value of zero indicates that the client should not generate keepalive
+messages on connections unless specifically requested by an application.
+.It Ic option tcp-keepalive-garbage Ar flag ;
+This option specifies whether or not the client should send TCP keepalive
+messages with an octet of garbage for compatibility with older implementations.
+A value of 0 indicates that a garbage octet should not be sent.
+A value of 1 indicates that a garbage octet should be sent.
+.El
+.Ss Application and Service Parameters
+.Bl -tag -width indent
+.It Ic option nis-domain Ar string ;
+This option specifies the name of the client's NIS (Sun Network Information
+Services) domain.
+The domain is formatted as a character string consisting of characters
+from the
+.Tn NVT ASCII
+character set.
+.It Xo
+.Ic option nis-servers Ar ip-address
+.Oo , Ar ip-address ... Oc ;
+.Xc
+This option specifies a list of IP addresses indicating NIS servers
+available to the client.
+Servers should be listed in order of preference.
+.It Xo
+.Ic option ntp-servers Ar ip-address
+.Oo , Ar ip-address ... Oc ;
+.Xc
+This option specifies a list of IP addresses indicating NTP (RFC 1305)
+servers available to the client.
+Servers should be listed in order of preference.
+.It Xo
+.Ic option netbios-name-servers Ar ip-address
+.Oo , Ar ip-address ... Oc ;
+.Xc
+The NetBIOS name server (NBNS) option specifies a list of RFC 1001/1002
+NBNS name servers listed in order of preference.
+NetBIOS Name Service is currently more commonly referred to as WINS.
+WINS servers can be specified using the
+.Ic netbios-name-servers
+option.
+.It Xo
+.Ic option netbios-dd-server Ar ip-address
+.Oo , Ar ip-address ... Oc ;
+.Xc
+The NetBIOS datagram distribution server (NBDD) option specifies a
+list of RFC 1001/1002 NBDD servers listed in order of preference.
+.It Ic option netbios-node-type Ar uint8 ;
+The NetBIOS node type option allows NetBIOS over TCP/IP clients which
+are configurable to be configured as described in RFC 1001/1002.
+The value is specified as a single octet which identifies the client type.
+.Pp
+Possible node types are:
+.Bl -tag -width indent
+.It 1
+B-node: Broadcast - no WINS
+.It 2
+P-node: Peer - WINS only
+.It 4
+M-node: Mixed - broadcast, then WINS
+.It 8
+H-node: Hybrid - WINS, then broadcast
+.El
+.It Ic option netbios-scope Ar string ;
+The NetBIOS scope option specifies the NetBIOS over TCP/IP scope
+parameter for the client as specified in RFC 1001/1002.
+See RFC 1001, RFC 1002, and RFC 1035 for character-set restrictions.
+.It Xo
+.Ic option font-servers Ar ip-address
+.Oo , Ar ip-address ... Oc ;
+.Xc
+This option specifies a list of X Window System Font servers available
+to the client.
+Servers should be listed in order of preference.
+.It Xo
+.Ic option x-display-manager Ar ip-address
+.Oo , Ar ip-address ... Oc ;
+.Xc
+This option specifies a list of systems that are running the X Window
+System Display Manager and are available to the client.
+Addresses should be listed in order of preference.
+.It Ic option dhcp-client-identifier Ar data-string ;
+This option can be used to specify a DHCP client identifier in a
+host declaration, so that
+.Xr dhcpd 8
+can find the host record by matching against the client identifier.
+.It Ic option nisplus-domain Ar string ;
+This option specifies the name of the client's NIS+ domain.
+The domain is formatted as a character string consisting of characters
+from the
+.Tn NVT ASCII
+character set.
+.It Xo
+.Ic option nisplus-servers Ar ip-address
+.Oo , Ar ip-address ... Oc ;
+.Xc
+This option specifies a list of IP addresses indicating NIS+ servers
+available to the client.
+Servers should be listed in order of preference.
+.It Ic option tftp-server-name Ar string ;
+This option is used to identify a TFTP server and, if supported by the
+client, should have the same effect as the
+.Ic server-name
+declaration.
+BOOTP clients are unlikely to support this option.
+Some DHCP clients will support it, and others actually require it.
+.It Ic option bootfile-name Ar string ;
+This option is used to identify a bootstrap file.
+If supported by the client, it should have the same effect as the
+.Ic filename
+declaration.
+BOOTP clients are unlikely to support this option.
+Some DHCP clients will support it, and others actually require it.
+.It Xo
+.Ic option mobile-ip-home-agent Ar ip-address
+.Oo , Ar ip-address ... Oc ;
+.Xc
+This option specifies a list of IP addresses indicating mobile IP
+home agents available to the client.
+Agents should be listed in order of preference, although normally there
+will be only one such agent.
+.It Xo
+.Ic option smtp-server Ar ip-address
+.Oo , Ar ip-address ... Oc ;
+.Xc
+The
+.Ic smtp-server
+option specifies a list of SMTP servers available to the client.
+Servers should be listed in order of preference.
+.It Xo
+.Ic option pop-server Ar ip-address
+.Oo , Ar ip-address ... Oc ;
+.Xc
+The
+.Ic pop-server
+option specifies a list of POP3 servers available to the client.
+Servers should be listed in order of preference.
+.It Xo
+.Ic option nntp-server Ar ip-address
+.Oo , Ar ip-address ... Oc ;
+.Xc
+The
+.Ic nntp-server
+option specifies a list of NNTP servers available to the client.
+Servers should be listed in order of preference.
+.It Xo
+.Ic option www-server Ar ip-address
+.Oo , Ar ip-address ... Oc ;
+.Xc
+The
+.Ic www-server
+option specifies a list of WWW servers available to the client.
+Servers should be listed in order of preference.
+.It Xo
+.Ic option finger-server Ar ip-address
+.Oo , Ar ip-address ... Oc ;
+.Xc
+The
+.Ic finger-server
+option specifies a list of
+.Xr finger 1
+servers available to the client.
+Servers should be listed in order of preference.
+.It Xo
+.Ic option irc-server Ar ip-address
+.Oo , Ar ip-address ... Oc ;
+.Xc
+The
+.Ic irc-server
+option specifies a list of IRC servers available to the client.
+Servers should be listed in order of preference.
+.It Xo
+.Ic option streettalk-server Ar ip-address
+.Oo , Ar ip-address ... Oc ;
+.Xc
+The
+.Ic streettalk-server
+option specifies a list of StreetTalk servers available to the client.
+Servers should be listed in order of preference.
+.It Xo
+.Ic option streettalk-directory-assistance-server Ar ip-address
+.Oo , Ar ip-address ... Oc ;
+.Xc
+The StreetTalk Directory Assistance (STDA) server option specifies a
+list of STDA servers available to the client.
+Servers should be listed in order of preference.
+.El
+.Sh SEE ALSO
+.Xr dhclient.conf 5 ,
+.Xr dhcpd.conf 5 ,
+.Xr dhcpd.leases 5 ,
+.Xr dhclient 8 ,
+.Xr dhcpd 8
+.Rs
+.%R "RFC 2131, RFC 2132"
+.Re
+.Sh AUTHORS
+.An -nosplit
+The
+.Xr dhcpd 8
+utility
+was written by
+.An Ted Lemon Aq mellon at vix.com
+under a contract with Vixie Labs.
+.Pp
+The current implementation was reworked by
+.An Henning Brauer Aq henning at openbsd.org .
diff --git a/freebsd-userspace/commands/sbin/dhclient/dhcp.h b/freebsd-userspace/commands/sbin/dhclient/dhcp.h
new file mode 100644
index 0000000..e4fa9d1
--- /dev/null
+++ b/freebsd-userspace/commands/sbin/dhclient/dhcp.h
@@ -0,0 +1,183 @@
+/*	$OpenBSD: dhcp.h,v 1.5 2004/05/04 15:49:49 deraadt Exp $	*/
+/*	$FreeBSD$	*/
+
+/* Protocol structures... */
+
+/*
+ * Copyright (c) 1995, 1996 The Internet Software Consortium.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of The Internet Software Consortium nor the names
+ *    of its contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM 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 INTERNET SOFTWARE CONSORTIUM 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 software has been written for the Internet Software Consortium
+ * by Ted Lemon <mellon at fugue.com> in cooperation with Vixie
+ * Enterprises.  To learn more about the Internet Software Consortium,
+ * see ``http://www.vix.com/isc''.  To learn more about Vixie
+ * Enterprises, see ``http://www.vix.com''.
+ */
+
+#define DHCP_UDP_OVERHEAD	(14 + /* Ethernet header */	\
+				 20 + /* IP header */		\
+				 8)   /* UDP header */
+#define DHCP_SNAME_LEN		64
+#define DHCP_FILE_LEN		128
+#define DHCP_FIXED_NON_UDP	236
+#define DHCP_FIXED_LEN		(DHCP_FIXED_NON_UDP + DHCP_UDP_OVERHEAD)
+						/* Everything but options. */
+#define DHCP_MTU_MAX		1500
+#define DHCP_OPTION_LEN		(DHCP_MTU_MAX - DHCP_FIXED_LEN)
+
+#define BOOTP_MIN_LEN		300
+#define DHCP_MIN_LEN		548
+
+struct dhcp_packet {
+	u_int8_t  op;		/* Message opcode/type */
+	u_int8_t  htype;	/* Hardware addr type (see net/if_types.h) */
+	u_int8_t  hlen;		/* Hardware addr length */
+	u_int8_t  hops;		/* Number of relay agent hops from client */
+	u_int32_t xid;		/* Transaction ID */
+	u_int16_t secs;		/* Seconds since client started looking */
+	u_int16_t flags;	/* Flag bits */
+	struct in_addr ciaddr;	/* Client IP address (if already in use) */
+	struct in_addr yiaddr;	/* Client IP address */
+	struct in_addr siaddr;	/* IP address of next server to talk to */
+	struct in_addr giaddr;	/* DHCP relay agent IP address */
+	unsigned char chaddr[16];	/* Client hardware address */
+	char sname[DHCP_SNAME_LEN];	/* Server name */
+	char file[DHCP_FILE_LEN];	/* Boot filename */
+	unsigned char options[DHCP_OPTION_LEN];
+				/* Optional parameters
+				   (actual length dependent on MTU). */
+};
+
+/* BOOTP (rfc951) message types */
+#define BOOTREQUEST	1
+#define BOOTREPLY	2
+
+/* Possible values for flags field... */
+#define BOOTP_BROADCAST 32768L
+
+/* Possible values for hardware type (htype) field... */
+#define HTYPE_ETHER	1		/* Ethernet			*/
+#define HTYPE_IEEE802	6		/* IEEE 802.2 Token Ring...	*/
+#define HTYPE_FDDI	8		/* FDDI...			*/
+
+/* Magic cookie validating dhcp options field (and bootp vendor
+   extensions field). */
+#define DHCP_OPTIONS_COOKIE	"\143\202\123\143"
+
+/* DHCP Option codes: */
+
+#define DHO_PAD				0
+#define DHO_SUBNET_MASK			1
+#define DHO_TIME_OFFSET			2
+#define DHO_ROUTERS			3
+#define DHO_TIME_SERVERS		4
+#define DHO_NAME_SERVERS		5
+#define DHO_DOMAIN_NAME_SERVERS		6
+#define DHO_LOG_SERVERS			7
+#define DHO_COOKIE_SERVERS		8
+#define DHO_LPR_SERVERS			9
+#define DHO_IMPRESS_SERVERS		10
+#define DHO_RESOURCE_LOCATION_SERVERS	11
+#define DHO_HOST_NAME			12
+#define DHO_BOOT_SIZE			13
+#define DHO_MERIT_DUMP			14
+#define DHO_DOMAIN_NAME			15
+#define DHO_SWAP_SERVER			16
+#define DHO_ROOT_PATH			17
+#define DHO_EXTENSIONS_PATH		18
+#define DHO_IP_FORWARDING		19
+#define DHO_NON_LOCAL_SOURCE_ROUTING	20
+#define DHO_POLICY_FILTER		21
+#define DHO_MAX_DGRAM_REASSEMBLY	22
+#define DHO_DEFAULT_IP_TTL		23
+#define DHO_PATH_MTU_AGING_TIMEOUT	24
+#define DHO_PATH_MTU_PLATEAU_TABLE	25
+#define DHO_INTERFACE_MTU		26
+#define DHO_ALL_SUBNETS_LOCAL		27
+#define DHO_BROADCAST_ADDRESS		28
+#define DHO_PERFORM_MASK_DISCOVERY	29
+#define DHO_MASK_SUPPLIER		30
+#define DHO_ROUTER_DISCOVERY		31
+#define DHO_ROUTER_SOLICITATION_ADDRESS	32
+#define DHO_STATIC_ROUTES		33
+#define DHO_TRAILER_ENCAPSULATION	34
+#define DHO_ARP_CACHE_TIMEOUT		35
+#define DHO_IEEE802_3_ENCAPSULATION	36
+#define DHO_DEFAULT_TCP_TTL		37
+#define DHO_TCP_KEEPALIVE_INTERVAL	38
+#define DHO_TCP_KEEPALIVE_GARBAGE	39
+#define DHO_NIS_DOMAIN			40
+#define DHO_NIS_SERVERS			41
+#define DHO_NTP_SERVERS			42
+#define DHO_VENDOR_ENCAPSULATED_OPTIONS	43
+#define DHO_NETBIOS_NAME_SERVERS	44
+#define DHO_NETBIOS_DD_SERVER		45
+#define DHO_NETBIOS_NODE_TYPE		46
+#define DHO_NETBIOS_SCOPE		47
+#define DHO_FONT_SERVERS		48
+#define DHO_X_DISPLAY_MANAGER		49
+#define DHO_DHCP_REQUESTED_ADDRESS	50
+#define DHO_DHCP_LEASE_TIME		51
+#define DHO_DHCP_OPTION_OVERLOAD	52
+#define DHO_DHCP_MESSAGE_TYPE		53
+#define DHO_DHCP_SERVER_IDENTIFIER	54
+#define DHO_DHCP_PARAMETER_REQUEST_LIST	55
+#define DHO_DHCP_MESSAGE		56
+#define DHO_DHCP_MAX_MESSAGE_SIZE	57
+#define DHO_DHCP_RENEWAL_TIME		58
+#define DHO_DHCP_REBINDING_TIME		59
+#define DHO_DHCP_CLASS_IDENTIFIER	60
+#define DHO_DHCP_CLIENT_IDENTIFIER	61
+#define	DHO_NISPLUS_DOMAIN		64
+#define	DHO_NISPLUS_SERVERS		65
+#define	DHO_TFTP_SERVER_NAME		66
+#define	DHO_BOOTFILE_NAME		67
+#define	DHO_MOBILE_IP_HOME_AGENT	68
+#define DHO_SMTP_SERVER			69
+#define DHO_POP_SERVER			70
+#define DHO_NNTP_SERVER			71
+#define DHO_WWW_SERVER			72
+#define DHO_FINGER_SERVER		73
+#define DHO_IRC_SERVER			74
+#define	DHO_STREETTALK_SERVER		75
+#define	DHO_STREETTALK_DA_SERVER	76
+#define DHO_DHCP_USER_CLASS_ID		77
+#define DHO_CLASSLESS_ROUTES		121
+#define DHO_END				255
+
+/* DHCP message types. */
+#define DHCPDISCOVER	1
+#define DHCPOFFER	2
+#define DHCPREQUEST	3
+#define DHCPDECLINE	4
+#define DHCPACK		5
+#define DHCPNAK		6
+#define DHCPRELEASE	7
+#define DHCPINFORM	8
diff --git a/freebsd-userspace/commands/sbin/dhclient/dhcpd.h b/freebsd-userspace/commands/sbin/dhclient/dhcpd.h
new file mode 100644
index 0000000..bd4c9c0
--- /dev/null
+++ b/freebsd-userspace/commands/sbin/dhclient/dhcpd.h
@@ -0,0 +1,440 @@
+/*	$OpenBSD: dhcpd.h,v 1.33 2004/05/06 22:29:15 deraadt Exp $	*/
+
+/*
+ * Copyright (c) 2004 Henning Brauer <henning at openbsd.org>
+ * Copyright (c) 1995, 1996, 1997, 1998, 1999
+ * The Internet Software Consortium.    All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of The Internet Software Consortium nor the names
+ *    of its contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM 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 INTERNET SOFTWARE CONSORTIUM 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 software has been written for the Internet Software Consortium
+ * by Ted Lemon <mellon at fugue.com> in cooperation with Vixie
+ * Enterprises.  To learn more about the Internet Software Consortium,
+ * see ``http://www.vix.com/isc''.  To learn more about Vixie
+ * Enterprises, see ``http://www.vix.com''.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/un.h>
+#include <sys/wait.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/route.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <netdb.h>
+#include <paths.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "dhcp.h"
+#include "tree.h"
+
+#define	LOCAL_PORT	68
+#define	REMOTE_PORT	67
+
+struct option_data {
+	int		 len;
+	u_int8_t	*data;
+};
+
+struct string_list {
+	struct string_list	*next;
+	char			*string;
+};
+
+struct iaddr {
+	int len;
+	unsigned char iabuf[16];
+};
+
+struct iaddrlist {
+	struct iaddrlist *next;
+	struct iaddr addr;
+};
+
+struct packet {
+	struct dhcp_packet	*raw;
+	int			 packet_length;
+	int			 packet_type;
+	int			 options_valid;
+	int			 client_port;
+	struct iaddr		 client_addr;
+	struct interface_info	*interface;
+	struct hardware		*haddr;
+	struct option_data	 options[256];
+};
+
+struct hardware {
+	u_int8_t htype;
+	u_int8_t hlen;
+	u_int8_t haddr[16];
+};
+
+struct client_lease {
+	struct client_lease	*next;
+	time_t			 expiry, renewal, rebind;
+	struct iaddr		 address;
+	char			*server_name;
+	char			*filename;
+	struct string_list	*medium;
+	unsigned int		 is_static : 1;
+	unsigned int		 is_bootp : 1;
+	struct option_data	 options[256];
+};
+
+/* Possible states in which the client can be. */
+enum dhcp_state {
+	S_REBOOTING,
+	S_INIT,
+	S_SELECTING,
+	S_REQUESTING,
+	S_BOUND,
+	S_RENEWING,
+	S_REBINDING
+};
+
+struct client_config {
+	struct option_data	defaults[256];
+	enum {
+		ACTION_DEFAULT,
+		ACTION_SUPERSEDE,
+		ACTION_PREPEND,
+		ACTION_APPEND
+	} default_actions[256];
+
+	struct option_data	 send_options[256];
+	u_int8_t		 required_options[256];
+	u_int8_t		 requested_options[256];
+	int			 requested_option_count;
+	time_t			 timeout;
+	time_t			 initial_interval;
+	time_t			 retry_interval;
+	time_t			 select_interval;
+	time_t			 reboot_timeout;
+	time_t			 backoff_cutoff;
+	struct string_list	*media;
+	char			*script_name;
+	enum { IGNORE, ACCEPT, PREFER }
+				 bootp_policy;
+	struct string_list	*medium;
+	struct iaddrlist	*reject_list;
+};
+
+struct client_state {
+	struct client_lease	 *active;
+	struct client_lease	 *new;
+	struct client_lease	 *offered_leases;
+	struct client_lease	 *leases;
+	struct client_lease	 *alias;
+	enum dhcp_state		  state;
+	struct iaddr		  destination;
+	u_int32_t		  xid;
+	u_int16_t		  secs;
+	time_t			  first_sending;
+	time_t			  interval;
+	struct string_list	 *medium;
+	struct dhcp_packet	  packet;
+	int			  packet_length;
+	struct iaddr		  requested_address;
+	struct client_config	 *config;
+	char			**scriptEnv;
+	int			  scriptEnvsize;
+	struct string_list	 *env;
+	int			  envc;
+};
+
+struct interface_info {
+	struct interface_info	*next;
+	struct hardware		 hw_address;
+	struct in_addr		 primary_address;
+	char			 name[IFNAMSIZ];
+	int			 rfdesc;
+	int			 wfdesc;
+	int			 ufdesc;
+	unsigned char		*rbuf;
+	size_t			 rbuf_max;
+	size_t			 rbuf_offset;
+	size_t			 rbuf_len;
+	struct ifreq		*ifp;
+	struct client_state	*client;
+	int			 noifmedia;
+	int			 errors;
+	int			 dead;
+	u_int16_t		 index;
+};
+
+struct timeout {
+	struct timeout	*next;
+	time_t		 when;
+	void		 (*func)(void *);
+	void		*what;
+};
+
+struct protocol {
+	struct protocol	*next;
+	int fd;
+	void (*handler)(struct protocol *);
+	void *local;
+};
+
+#define DEFAULT_HASH_SIZE 97
+
+struct hash_bucket {
+	struct hash_bucket *next;
+	unsigned char *name;
+	int len;
+	unsigned char *value;
+};
+
+struct hash_table {
+	int hash_count;
+	struct hash_bucket *buckets[DEFAULT_HASH_SIZE];
+};
+
+/* Default path to dhcpd config file. */
+#define	_PATH_DHCLIENT_CONF	"/etc/dhclient.conf"
+#define	_PATH_DHCLIENT_DB	"/var/db/dhclient.leases"
+#define	DHCPD_LOG_FACILITY	LOG_DAEMON
+
+#define	MAX_TIME 0x7fffffff
+#define	MIN_TIME 0
+
+/* External definitions... */
+
+/* options.c */
+int cons_options(struct packet *, struct dhcp_packet *, int,
+    struct tree_cache **, int, int, int, u_int8_t *, int);
+char *pretty_print_option(unsigned int,
+    unsigned char *, int, int, int);
+void do_packet(struct interface_info *, struct dhcp_packet *,
+    int, unsigned int, struct iaddr, struct hardware *);
+
+/* errwarn.c */
+extern int warnings_occurred;
+void error(char *, ...) __attribute__ ((__format__ (__printf__, 1, 2)));
+int warning(char *, ...) __attribute__ ((__format__ (__printf__, 1, 2)));
+int note(char *, ...) __attribute__ ((__format__ (__printf__, 1, 2)));
+int debug(char *, ...) __attribute__ ((__format__ (__printf__, 1, 2)));
+int parse_warn(char *, ...) __attribute__ ((__format__ (__printf__, 1, 2)));
+
+/* conflex.c */
+extern int lexline, lexchar;
+extern char *token_line, *tlname;
+extern char comments[4096];
+extern int comment_index;
+extern int eol_token;
+void new_parse(char *);
+int next_token(char **, FILE *);
+int peek_token(char **, FILE *);
+
+/* parse.c */
+void skip_to_semi(FILE *);
+int parse_semi(FILE *);
+char *parse_string(FILE *);
+int parse_ip_addr(FILE *, struct iaddr *);
+void parse_hardware_param(FILE *, struct hardware *);
+void parse_lease_time(FILE *, time_t *);
+unsigned char *parse_numeric_aggregate(FILE *, unsigned char *, int *,
+    int, int, int);
+void convert_num(unsigned char *, char *, int, int);
+time_t parse_date(FILE *);
+
+/* tree.c */
+pair cons(caddr_t, pair);
+
+/* alloc.c */
+struct string_list	*new_string_list(size_t size);
+struct hash_table	*new_hash_table(int);
+struct hash_bucket	*new_hash_bucket(void);
+
+/* bpf.c */
+int if_register_bpf(struct interface_info *);
+void if_register_send(struct interface_info *);
+void if_register_receive(struct interface_info *);
+ssize_t send_packet(struct interface_info *, struct dhcp_packet *, size_t,
+    struct in_addr, struct sockaddr_in *, struct hardware *);
+ssize_t receive_packet(struct interface_info *, unsigned char *, size_t,
+    struct sockaddr_in *, struct hardware *);
+
+/* dispatch.c */
+extern void (*bootp_packet_handler)(struct interface_info *,
+    struct dhcp_packet *, int, unsigned int, struct iaddr, struct hardware *);
+void discover_interfaces(struct interface_info *);
+void reinitialize_interfaces(void);
+void dispatch(void);
+void got_one(struct protocol *);
+void add_timeout(time_t, void (*)(void *), void *);
+void cancel_timeout(void (*)(void *), void *);
+void add_protocol(char *, int, void (*)(struct protocol *), void *);
+void remove_protocol(struct protocol *);
+int interface_link_status(char *);
+
+/* hash.c */
+struct hash_table *new_hash(void);
+void add_hash(struct hash_table *, unsigned char *, int, unsigned char *);
+unsigned char *hash_lookup(struct hash_table *, unsigned char *, int);
+
+/* tables.c */
+extern struct option dhcp_options[256];
+extern unsigned char dhcp_option_default_priority_list[];
+extern int sizeof_dhcp_option_default_priority_list;
+extern struct hash_table universe_hash;
+extern struct universe dhcp_universe;
+void initialize_universes(void);
+
+/* convert.c */
+u_int32_t getULong(unsigned char *);
+int32_t getLong(unsigned char *);
+u_int16_t getUShort(unsigned char *);
+int16_t getShort(unsigned char *);
+void putULong(unsigned char *, u_int32_t);
+void putLong(unsigned char *, int32_t);
+void putUShort(unsigned char *, unsigned int);
+void putShort(unsigned char *, int);
+
+/* inet.c */
+struct iaddr subnet_number(struct iaddr, struct iaddr);
+struct iaddr broadcast_addr(struct iaddr, struct iaddr);
+int addr_eq(struct iaddr, struct iaddr);
+char *piaddr(struct iaddr);
+
+/* dhclient.c */
+extern char *path_dhclient_conf;
+extern char *path_dhclient_db;
+extern time_t cur_time;
+extern int log_priority;
+extern int log_perror;
+
+extern struct client_config top_level_config;
+
+void dhcpoffer(struct packet *);
+void dhcpack(struct packet *);
+void dhcpnak(struct packet *);
+
+void send_discover(void *);
+void send_request(void *);
+void send_decline(void *);
+
+void state_reboot(void *);
+void state_init(void *);
+void state_selecting(void *);
+void state_requesting(void *);
+void state_bound(void *);
+void state_panic(void *);
+
+void bind_lease(struct interface_info *);
+
+void make_discover(struct interface_info *, struct client_lease *);
+void make_request(struct interface_info *, struct client_lease *);
+void make_decline(struct interface_info *, struct client_lease *);
+
+void free_client_lease(struct client_lease *);
+void rewrite_client_leases(void);
+void write_client_lease(struct interface_info *, struct client_lease *, int);
+
+void	 priv_script_init(char *, char *);
+void	 priv_script_write_params(char *, struct client_lease *);
+int	 priv_script_go(void);
+
+void script_init(char *, struct string_list *);
+void script_write_params(char *, struct client_lease *);
+int script_go(void);
+void client_envadd(struct client_state *,
+    const char *, const char *, const char *, ...);
+void script_set_env(struct client_state *, const char *, const char *,
+    const char *);
+void script_flush_env(struct client_state *);
+int dhcp_option_ev_name(char *, size_t, struct option *);
+
+struct client_lease *packet_to_lease(struct packet *);
+void go_daemon(void);
+void client_location_changed(void);
+
+void bootp(struct packet *);
+void dhcp(struct packet *);
+
+/* packet.c */
+void assemble_hw_header(struct interface_info *, unsigned char *,
+    int *, struct hardware *);
+void assemble_udp_ip_header(unsigned char *, int *, u_int32_t, u_int32_t,
+    unsigned int, unsigned char *, int);
+ssize_t decode_hw_header(unsigned char *, int, struct hardware *);
+ssize_t decode_udp_ip_header(unsigned char *, int, struct sockaddr_in *,
+    unsigned char *, int);
+
+/* ethernet.c */
+void assemble_ethernet_header(struct interface_info *, unsigned char *,
+    int *, struct hardware *);
+ssize_t decode_ethernet_header(struct interface_info *, unsigned char *,
+    int, struct hardware *);
+
+/* clparse.c */
+int read_client_conf(void);
+void read_client_leases(void);
+void parse_client_statement(FILE *, struct interface_info *,
+    struct client_config *);
+int parse_X(FILE *, u_int8_t *, int);
+int parse_option_list(FILE *, u_int8_t *);
+void parse_interface_declaration(FILE *, struct client_config *);
+struct interface_info *interface_or_dummy(char *);
+void make_client_state(struct interface_info *);
+void make_client_config(struct interface_info *, struct client_config *);
+void parse_client_lease_statement(FILE *, int);
+void parse_client_lease_declaration(FILE *, struct client_lease *,
+    struct interface_info **);
+struct option *parse_option_decl(FILE *, struct option_data *);
+void parse_string_list(FILE *, struct string_list **, int);
+void parse_reject_statement(FILE *, struct client_config *);
+
+/* privsep.c */
+struct buf	*buf_open(size_t);
+int		 buf_add(struct buf *, void *, size_t);
+int		 buf_close(int, struct buf *);
+ssize_t		 buf_read(int, void *, size_t);
+void		 dispatch_imsg(int);
diff --git a/freebsd-userspace/commands/sbin/dhclient/dhctoken.h b/freebsd-userspace/commands/sbin/dhclient/dhctoken.h
new file mode 100644
index 0000000..7b23242
--- /dev/null
+++ b/freebsd-userspace/commands/sbin/dhclient/dhctoken.h
@@ -0,0 +1,136 @@
+/*	$OpenBSD: dhctoken.h,v 1.2 2004/02/04 12:16:56 henning Exp $	*/
+
+/* Tokens for config file lexer and parser. */
+
+/*
+ * Copyright (c) 1995, 1996, 1997, 1998, 1999
+ * The Internet Software Consortium.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of The Internet Software Consortium nor the names
+ *    of its contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM 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 INTERNET SOFTWARE CONSORTIUM 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 software has been written for the Internet Software Consortium
+ * by Ted Lemon <mellon at fugue.com> in cooperation with Vixie
+ * Enterprises.  To learn more about the Internet Software Consortium,
+ * see ``http://www.vix.com/isc''.  To learn more about Vixie
+ * Enterprises, see ``http://www.vix.com''.
+ */
+
+#define SEMI ';'
+#define DOT '.'
+#define COLON ':'
+#define COMMA ','
+#define SLASH '/'
+#define LBRACE '{'
+#define RBRACE '}'
+
+#define FIRST_TOKEN	HOST
+#define HOST		256
+#define HARDWARE	257
+#define FILENAME	258
+#define FIXED_ADDR	259
+#define OPTION		260
+#define ETHERNET	261
+#define STRING		262
+#define NUMBER		263
+#define NUMBER_OR_NAME	264
+#define NAME		265
+#define TIMESTAMP	266
+#define STARTS		267
+#define ENDS		268
+#define UID		269
+#define CLASS		270
+#define LEASE		271
+#define RANGE		272
+#define PACKET		273
+#define CIADDR		274
+#define YIADDR		275
+#define SIADDR		276
+#define GIADDR		277
+#define SUBNET		278
+#define NETMASK		279
+#define DEFAULT_LEASE_TIME 280
+#define MAX_LEASE_TIME	281
+#define VENDOR_CLASS	282
+#define USER_CLASS	283
+#define SHARED_NETWORK	284
+#define SERVER_NAME	285
+#define DYNAMIC_BOOTP	286
+#define SERVER_IDENTIFIER 287
+#define DYNAMIC_BOOTP_LEASE_CUTOFF 288
+#define DYNAMIC_BOOTP_LEASE_LENGTH 289
+#define BOOT_UNKNOWN_CLIENTS 290
+#define NEXT_SERVER	291
+#define TOKEN_RING	292
+#define GROUP		293
+#define ONE_LEASE_PER_CLIENT 294
+#define GET_LEASE_HOSTNAMES 295
+#define USE_HOST_DECL_NAMES 296
+#define SEND		297
+#define CLIENT_IDENTIFIER 298
+#define REQUEST		299
+#define REQUIRE		300
+#define TIMEOUT		301
+#define RETRY		302
+#define SELECT_TIMEOUT	303
+#define SCRIPT		304
+#define INTERFACE	305
+#define RENEW		306
+#define	REBIND		307
+#define EXPIRE		308
+#define UNKNOWN_CLIENTS	309
+#define	ALLOW		310
+#define BOOTP		311
+#define DENY		312
+#define BOOTING		313
+#define DEFAULT		314
+#define MEDIA		315
+#define MEDIUM		316
+#define ALIAS		317
+#define REBOOT		318
+#define ABANDONED	319
+#define	BACKOFF_CUTOFF	320
+#define	INITIAL_INTERVAL 321
+#define NAMESERVER	322
+#define	DOMAIN		323
+#define SEARCH		324
+#define SUPERSEDE	325
+#define APPEND		326
+#define PREPEND		327
+#define HOSTNAME	328
+#define CLIENT_HOSTNAME	329
+#define REJECT		330
+#define FDDI		331
+#define USE_LEASE_ADDR_FOR_DEFAULT_ROUTE 332
+#define AUTHORITATIVE	333
+#define TOKEN_NOT	334
+#define ALWAYS_REPLY_RFC1048 335
+
+#define is_identifier(x)	((x) >= FIRST_TOKEN &&	\
+				 (x) != STRING &&	\
+				 (x) != NUMBER &&	\
+				 (x) != EOF)
diff --git a/freebsd-userspace/commands/sbin/dhclient/dispatch.c b/freebsd-userspace/commands/sbin/dhclient/dispatch.c
new file mode 100644
index 0000000..b04d488
--- /dev/null
+++ b/freebsd-userspace/commands/sbin/dhclient/dispatch.c
@@ -0,0 +1,507 @@
+/*	$OpenBSD: dispatch.c,v 1.31 2004/09/21 04:07:03 david Exp $	*/
+
+/*
+ * Copyright 2004 Henning Brauer <henning at openbsd.org>
+ * Copyright (c) 1995, 1996, 1997, 1998, 1999
+ * The Internet Software Consortium.   All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of The Internet Software Consortium nor the names
+ *    of its contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM 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 INTERNET SOFTWARE CONSORTIUM 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 software has been written for the Internet Software Consortium
+ * by Ted Lemon <mellon at fugue.com> in cooperation with Vixie
+ * Enterprises.  To learn more about the Internet Software Consortium,
+ * see ``http://www.vix.com/isc''.  To learn more about Vixie
+ * Enterprises, see ``http://www.vix.com''.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "dhcpd.h"
+
+#include <sys/ioctl.h>
+
+#ifdef __rtems__
+#include <freebsd/net/if_media.h>
+#else
+#include <net/if_media.h>
+#endif
+#include <ifaddrs.h>
+#include <poll.h>
+
+struct protocol *protocols;
+struct timeout *timeouts;
+static struct timeout *free_timeouts;
+static int interfaces_invalidated;
+void (*bootp_packet_handler)(struct interface_info *,
+    struct dhcp_packet *, int, unsigned int,
+    struct iaddr, struct hardware *);
+
+static int interface_status(struct interface_info *ifinfo);
+
+/*
+ * Use getifaddrs() to get a list of all the attached interfaces.  For
+ * each interface that's of type INET and not the loopback interface,
+ * register that interface with the network I/O software, figure out
+ * what subnet it's on, and add it to the list of interfaces.
+ */
+void
+discover_interfaces(struct interface_info *iface)
+{
+	struct ifaddrs *ifap, *ifa;
+	struct sockaddr_in foo;
+	struct ifreq *tif;
+
+	if (getifaddrs(&ifap) != 0)
+		error("getifaddrs failed");
+
+	for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
+		if ((ifa->ifa_flags & IFF_LOOPBACK) ||
+		    (ifa->ifa_flags & IFF_POINTOPOINT) ||
+		    (!(ifa->ifa_flags & IFF_UP)))
+			continue;
+
+		if (strcmp(iface->name, ifa->ifa_name))
+			continue;
+
+		/*
+		 * If we have the capability, extract link information
+		 * and record it in a linked list.
+		 */
+		if (ifa->ifa_addr->sa_family == AF_LINK) {
+			struct sockaddr_dl *foo =
+			    (struct sockaddr_dl *)ifa->ifa_addr;
+
+			iface->index = foo->sdl_index;
+			iface->hw_address.hlen = foo->sdl_alen;
+			iface->hw_address.htype = HTYPE_ETHER; /* XXX */
+			memcpy(iface->hw_address.haddr,
+			    LLADDR(foo), foo->sdl_alen);
+		} else if (ifa->ifa_addr->sa_family == AF_INET) {
+			struct iaddr addr;
+
+			memcpy(&foo, ifa->ifa_addr, sizeof(foo));
+			if (foo.sin_addr.s_addr == htonl(INADDR_LOOPBACK))
+				continue;
+			if (!iface->ifp) {
+				int len = IFNAMSIZ + ifa->ifa_addr->sa_len;
+				if ((tif = malloc(len)) == NULL)
+					error("no space to remember ifp");
+				strlcpy(tif->ifr_name, ifa->ifa_name, IFNAMSIZ);
+				memcpy(&tif->ifr_addr, ifa->ifa_addr,
+				    ifa->ifa_addr->sa_len);
+				iface->ifp = tif;
+				iface->primary_address = foo.sin_addr;
+			}
+			addr.len = 4;
+			memcpy(addr.iabuf, &foo.sin_addr.s_addr, addr.len);
+		}
+	}
+
+	if (!iface->ifp)
+		error("%s: not found", iface->name);
+
+	/* Register the interface... */
+	if_register_receive(iface);
+	if_register_send(iface);
+	add_protocol(iface->name, iface->rfdesc, got_one, iface);
+	freeifaddrs(ifap);
+}
+
+void
+reinitialize_interfaces(void)
+{
+	interfaces_invalidated = 1;
+}
+
+/*
+ * Wait for packets to come in using poll().  When a packet comes in,
+ * call receive_packet to receive the packet and possibly strip hardware
+ * addressing information from it, and then call through the
+ * bootp_packet_handler hook to try to do something with it.
+ */
+void
+dispatch(void)
+{
+	int count, live_interfaces, i, to_msec, nfds = 0;
+	struct protocol *l;
+	struct pollfd *fds;
+	time_t howlong;
+
+	for (l = protocols; l; l = l->next)
+		nfds++;
+
+	fds = malloc(nfds * sizeof(struct pollfd));
+	if (fds == NULL)
+		error("Can't allocate poll structures.");
+
+	do {
+		/*
+		 * Call any expired timeouts, and then if there's still
+		 * a timeout registered, time out the select call then.
+		 */
+another:
+		if (timeouts) {
+			struct timeout *t;
+
+			if (timeouts->when <= cur_time) {
+				t = timeouts;
+				timeouts = timeouts->next;
+				(*(t->func))(t->what);
+				t->next = free_timeouts;
+				free_timeouts = t;
+				goto another;
+			}
+
+			/*
+			 * Figure timeout in milliseconds, and check for
+			 * potential overflow, so we can cram into an
+			 * int for poll, while not polling with a
+			 * negative timeout and blocking indefinitely.
+			 */
+			howlong = timeouts->when - cur_time;
+			if (howlong > INT_MAX / 1000)
+				howlong = INT_MAX / 1000;
+			to_msec = howlong * 1000;
+		} else
+			to_msec = -1;
+
+		/* Set up the descriptors to be polled. */
+		live_interfaces = 0;
+		for (i = 0, l = protocols; l; l = l->next) {
+			struct interface_info *ip = l->local;
+
+			if (ip == NULL || ip->dead)
+				continue;
+			fds[i].fd = l->fd;
+			fds[i].events = POLLIN;
+			fds[i].revents = 0;
+			i++;
+			if (l->handler == got_one)
+				live_interfaces++;
+		}
+		if (live_interfaces == 0)
+			error("No live interfaces to poll on - exiting.");
+
+		/* Wait for a packet or a timeout... XXX */
+		count = poll(fds, nfds, to_msec);
+
+		/* Not likely to be transitory... */
+		if (count == -1) {
+			if (errno == EAGAIN || errno == EINTR) {
+				time(&cur_time);
+				continue;
+			} else
+				error("poll: %m");
+		}
+
+		/* Get the current time... */
+		time(&cur_time);
+
+		i = 0;
+		for (l = protocols; l; l = l->next) {
+			struct interface_info *ip;
+			ip = l->local;
+			if ((fds[i].revents & (POLLIN | POLLHUP))) {
+				fds[i].revents = 0;
+				if (ip && (l->handler != got_one ||
+				    !ip->dead))
+					(*(l->handler))(l);
+				if (interfaces_invalidated)
+					break;
+			}
+			i++;
+		}
+		interfaces_invalidated = 0;
+	} while (1);
+}
+
+
+void
+got_one(struct protocol *l)
+{
+	struct sockaddr_in from;
+	struct hardware hfrom;
+	struct iaddr ifrom;
+	ssize_t result;
+	union {
+		/*
+		 * Packet input buffer.  Must be as large as largest
+		 * possible MTU.
+		 */
+		unsigned char packbuf[4095];
+		struct dhcp_packet packet;
+	} u;
+	struct interface_info *ip = l->local;
+
+	if ((result = receive_packet(ip, u.packbuf, sizeof(u), &from,
+	    &hfrom)) == -1) {
+		warning("receive_packet failed on %s: %s", ip->name,
+		    strerror(errno));
+		ip->errors++;
+		if ((!interface_status(ip)) ||
+		    (ip->noifmedia && ip->errors > 20)) {
+			/* our interface has gone away. */
+			warning("Interface %s no longer appears valid.",
+			    ip->name);
+			ip->dead = 1;
+			interfaces_invalidated = 1;
+			close(l->fd);
+			remove_protocol(l);
+			free(ip);
+		}
+		return;
+	}
+	if (result == 0)
+		return;
+
+	if (bootp_packet_handler) {
+		ifrom.len = 4;
+		memcpy(ifrom.iabuf, &from.sin_addr, ifrom.len);
+
+		(*bootp_packet_handler)(ip, &u.packet, result,
+		    from.sin_port, ifrom, &hfrom);
+	}
+}
+
+int
+interface_status(struct interface_info *ifinfo)
+{
+	char *ifname = ifinfo->name;
+	int ifsock = ifinfo->rfdesc;
+	struct ifreq ifr;
+	struct ifmediareq ifmr;
+
+	/* get interface flags */
+	memset(&ifr, 0, sizeof(ifr));
+	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+	if (ioctl(ifsock, SIOCGIFFLAGS, &ifr) < 0) {
+		syslog(LOG_ERR, "ioctl(SIOCGIFFLAGS) on %s: %m", ifname);
+		goto inactive;
+	}
+
+	/*
+	 * if one of UP and RUNNING flags is dropped,
+	 * the interface is not active.
+	 */
+	if ((ifr.ifr_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
+		goto inactive;
+
+	/* Next, check carrier on the interface, if possible */
+	if (ifinfo->noifmedia)
+		goto active;
+	memset(&ifmr, 0, sizeof(ifmr));
+	strlcpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name));
+	if (ioctl(ifsock, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
+		if (errno != EINVAL) {
+			syslog(LOG_DEBUG, "ioctl(SIOCGIFMEDIA) on %s: %m",
+			    ifname);
+
+			ifinfo->noifmedia = 1;
+			goto active;
+		}
+		/*
+		 * EINVAL (or ENOTTY) simply means that the interface
+		 * does not support the SIOCGIFMEDIA ioctl. We regard it alive.
+		 */
+		ifinfo->noifmedia = 1;
+		goto active;
+	}
+	if (ifmr.ifm_status & IFM_AVALID) {
+		switch (ifmr.ifm_active & IFM_NMASK) {
+		case IFM_ETHER:
+		case IFM_IEEE80211:
+			if (ifmr.ifm_status & IFM_ACTIVE)
+				goto active;
+			else
+				goto inactive;
+			break;
+		default:
+			goto inactive;
+		}
+	}
+inactive:
+	return (0);
+active:
+	return (1);
+}
+
+void
+add_timeout(time_t when, void (*where)(void *), void *what)
+{
+	struct timeout *t, *q;
+
+	/* See if this timeout supersedes an existing timeout. */
+	t = NULL;
+	for (q = timeouts; q; q = q->next) {
+		if (q->func == where && q->what == what) {
+			if (t)
+				t->next = q->next;
+			else
+				timeouts = q->next;
+			break;
+		}
+		t = q;
+	}
+
+	/* If we didn't supersede a timeout, allocate a timeout
+	   structure now. */
+	if (!q) {
+		if (free_timeouts) {
+			q = free_timeouts;
+			free_timeouts = q->next;
+			q->func = where;
+			q->what = what;
+		} else {
+			q = malloc(sizeof(struct timeout));
+			if (!q)
+				error("Can't allocate timeout structure!");
+			q->func = where;
+			q->what = what;
+		}
+	}
+
+	q->when = when;
+
+	/* Now sort this timeout into the timeout list. */
+
+	/* Beginning of list? */
+	if (!timeouts || timeouts->when > q->when) {
+		q->next = timeouts;
+		timeouts = q;
+		return;
+	}
+
+	/* Middle of list? */
+	for (t = timeouts; t->next; t = t->next) {
+		if (t->next->when > q->when) {
+			q->next = t->next;
+			t->next = q;
+			return;
+		}
+	}
+
+	/* End of list. */
+	t->next = q;
+	q->next = NULL;
+}
+
+void
+cancel_timeout(void (*where)(void *), void *what)
+{
+	struct timeout *t, *q;
+
+	/* Look for this timeout on the list, and unlink it if we find it. */
+	t = NULL;
+	for (q = timeouts; q; q = q->next) {
+		if (q->func == where && q->what == what) {
+			if (t)
+				t->next = q->next;
+			else
+				timeouts = q->next;
+			break;
+		}
+		t = q;
+	}
+
+	/* If we found the timeout, put it on the free list. */
+	if (q) {
+		q->next = free_timeouts;
+		free_timeouts = q;
+	}
+}
+
+/* Add a protocol to the list of protocols... */
+void
+add_protocol(char *name, int fd, void (*handler)(struct protocol *),
+    void *local)
+{
+	struct protocol *p;
+
+	p = malloc(sizeof(*p));
+	if (!p)
+		error("can't allocate protocol struct for %s", name);
+
+	p->fd = fd;
+	p->handler = handler;
+	p->local = local;
+	p->next = protocols;
+	protocols = p;
+}
+
+void
+remove_protocol(struct protocol *proto)
+{
+	struct protocol *p, *next, *prev;
+
+	prev = NULL;
+	for (p = protocols; p; p = next) {
+		next = p->next;
+		if (p == proto) {
+			if (prev)
+				prev->next = p->next;
+			else
+				protocols = p->next;
+			free(p);
+		}
+	}
+}
+
+int
+interface_link_status(char *ifname)
+{
+	struct ifmediareq ifmr;
+	int sock;
+
+	if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
+		error("Can't create socket");
+
+	memset(&ifmr, 0, sizeof(ifmr));
+	strlcpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name));
+	if (ioctl(sock, SIOCGIFMEDIA, (caddr_t)&ifmr) == -1) {
+		/* EINVAL -> link state unknown. treat as active */
+		if (errno != EINVAL)
+			syslog(LOG_DEBUG, "ioctl(SIOCGIFMEDIA) on %s: %m",
+			    ifname);
+		close(sock);
+		return (1);
+	}
+	close(sock);
+
+	if (ifmr.ifm_status & IFM_AVALID) {
+		switch (ifmr.ifm_active & IFM_NMASK) {
+		case IFM_ETHER:
+		case IFM_IEEE80211:
+			if (ifmr.ifm_status & IFM_ACTIVE)
+				return (1);
+			else
+				return (0);
+		}
+	}
+	return (1);
+}
diff --git a/freebsd-userspace/commands/sbin/dhclient/errwarn.c b/freebsd-userspace/commands/sbin/dhclient/errwarn.c
new file mode 100644
index 0000000..de34583
--- /dev/null
+++ b/freebsd-userspace/commands/sbin/dhclient/errwarn.c
@@ -0,0 +1,237 @@
+/*	$OpenBSD: errwarn.c,v 1.7 2004/05/04 22:23:01 mickey Exp $	*/
+
+/* Errors and warnings... */
+
+/*
+ * Copyright (c) 1996 The Internet Software Consortium.
+ * All Rights Reserved.
+ * Copyright (c) 1995 RadioMail Corporation.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of RadioMail Corporation, the Internet Software
+ *    Consortium nor the names of its contributors may be used to endorse
+ *    or promote products derived from this software without specific
+ *    prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY RADIOMAIL CORPORATION, THE INTERNET
+ * SOFTWARE CONSORTIUM 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 RADIOMAIL CORPORATION 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 software was written for RadioMail Corporation by Ted Lemon
+ * under a contract with Vixie Enterprises.   Further modifications have
+ * been made for the Internet Software Consortium under a contract
+ * with Vixie Laboratories.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+
+#include "dhcpd.h"
+
+static void do_percentm(char *obuf, size_t size, char *ibuf);
+
+static char mbuf[1024];
+static char fbuf[1024];
+
+int warnings_occurred;
+
+/*
+ * Log an error message, then exit.
+ */
+void
+error(char *fmt, ...)
+{
+	va_list list;
+
+	do_percentm(fbuf, sizeof(fbuf), fmt);
+
+	va_start(list, fmt);
+	vsnprintf(mbuf, sizeof(mbuf), fbuf, list);
+	va_end(list);
+
+#ifndef DEBUG
+	syslog(log_priority | LOG_ERR, "%s", mbuf);
+#endif
+
+	/* Also log it to stderr? */
+	if (log_perror) {
+		write(2, mbuf, strlen(mbuf));
+		write(2, "\n", 1);
+	}
+
+	syslog(LOG_CRIT, "exiting.");
+	if (log_perror) {
+		fprintf(stderr, "exiting.\n");
+		fflush(stderr);
+	}
+	exit(1);
+}
+
+/*
+ * Log a warning message...
+ */
+int
+warning(char *fmt, ...)
+{
+	va_list list;
+
+	do_percentm(fbuf, sizeof(fbuf), fmt);
+
+	va_start(list, fmt);
+	vsnprintf(mbuf, sizeof(mbuf), fbuf, list);
+	va_end(list);
+
+#ifndef DEBUG
+	syslog(log_priority | LOG_ERR, "%s", mbuf);
+#endif
+
+	if (log_perror) {
+		write(2, mbuf, strlen(mbuf));
+		write(2, "\n", 1);
+	}
+
+	return (0);
+}
+
+/*
+ * Log a note...
+ */
+int
+note(char *fmt, ...)
+{
+	va_list list;
+
+	do_percentm(fbuf, sizeof(fbuf), fmt);
+
+	va_start(list, fmt);
+	vsnprintf(mbuf, sizeof(mbuf), fbuf, list);
+	va_end(list);
+
+#ifndef DEBUG
+	syslog(log_priority | LOG_INFO, "%s", mbuf);
+#endif
+
+	if (log_perror) {
+		write(2, mbuf, strlen(mbuf));
+		write(2, "\n", 1);
+	}
+
+	return (0);
+}
+
+/*
+ * Log a debug message...
+ */
+int
+debug(char *fmt, ...)
+{
+	va_list list;
+
+	do_percentm(fbuf, sizeof(fbuf), fmt);
+
+	va_start(list, fmt);
+	vsnprintf(mbuf, sizeof(mbuf), fbuf, list);
+	va_end(list);
+
+#ifndef DEBUG
+	syslog(log_priority | LOG_DEBUG, "%s", mbuf);
+#endif
+
+	if (log_perror) {
+		write(2, mbuf, strlen(mbuf));
+		write(2, "\n", 1);
+	}
+
+	return (0);
+}
+
+/*
+ * Find %m in the input string and substitute an error message string.
+ */
+static void
+do_percentm(char *obuf, size_t size, char *ibuf)
+{
+	char ch;
+	char *s = ibuf;
+	char *t = obuf;
+	size_t prlen;
+	size_t fmt_left;
+	int saved_errno = errno;
+
+	/*
+	 * We wouldn't need this mess if printf handled %m, or if
+	 * strerror() had been invented before syslog().
+	 */
+	for (fmt_left = size; (ch = *s); ++s) {
+		if (ch == '%' && s[1] == 'm') {
+			++s;
+			prlen = snprintf(t, fmt_left, "%s",
+			    strerror(saved_errno));
+			if (prlen >= fmt_left)
+				prlen = fmt_left - 1;
+			t += prlen;
+			fmt_left -= prlen;
+		} else {
+			if (fmt_left > 1) {
+				*t++ = ch;
+				fmt_left--;
+			}
+		}
+	}
+	*t = '\0';
+}
+
+int
+parse_warn(char *fmt, ...)
+{
+	va_list list;
+	static char spaces[] =
+	    "                                        "
+	    "                                        "; /* 80 spaces */
+
+	do_percentm(mbuf, sizeof(mbuf), fmt);
+	snprintf(fbuf, sizeof(fbuf), "%s line %d: %s", tlname, lexline, mbuf);
+	va_start(list, fmt);
+	vsnprintf(mbuf, sizeof(mbuf), fbuf, list);
+	va_end(list);
+
+#ifndef DEBUG
+	syslog(log_priority | LOG_ERR, "%s", mbuf);
+	syslog(log_priority | LOG_ERR, "%s", token_line);
+	if (lexline < 81)
+		syslog(log_priority | LOG_ERR,
+		    "%s^", &spaces[sizeof(spaces) - lexchar]);
+#endif
+
+	if (log_perror) {
+		write(2, mbuf, strlen(mbuf));
+		write(2, "\n", 1);
+		write(2, token_line, strlen(token_line));
+		write(2, "\n", 1);
+		write(2, spaces, lexchar - 1);
+		write(2, "^\n", 2);
+	}
+
+	warnings_occurred = 1;
+
+	return (0);
+}
diff --git a/freebsd-userspace/commands/sbin/dhclient/hash.c b/freebsd-userspace/commands/sbin/dhclient/hash.c
new file mode 100644
index 0000000..040236a
--- /dev/null
+++ b/freebsd-userspace/commands/sbin/dhclient/hash.c
@@ -0,0 +1,122 @@
+/*	$OpenBSD: hash.c,v 1.9 2004/05/10 15:30:47 deraadt Exp $	*/
+
+/* Routines for manipulating hash tables... */
+
+/*
+ * Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of The Internet Software Consortium nor the names
+ *    of its contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM 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 INTERNET SOFTWARE CONSORTIUM 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 software has been written for the Internet Software Consortium
+ * by Ted Lemon <mellon at fugue.com> in cooperation with Vixie
+ * Enterprises.  To learn more about the Internet Software Consortium,
+ * see ``http://www.vix.com/isc''.  To learn more about Vixie
+ * Enterprises, see ``http://www.vix.com''.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "dhcpd.h"
+
+static int do_hash(unsigned char *, int, int);
+
+struct hash_table *
+new_hash(void)
+{
+	struct hash_table *rv = new_hash_table(DEFAULT_HASH_SIZE);
+
+	if (!rv)
+		return (rv);
+	memset(&rv->buckets[0], 0,
+	    DEFAULT_HASH_SIZE * sizeof(struct hash_bucket *));
+	return (rv);
+}
+
+static int
+do_hash(unsigned char *name, int len, int size)
+{
+	unsigned char *s = name;
+	int accum = 0, i = len;
+
+	while (i--) {
+		/* Add the character in... */
+		accum += *s++;
+		/* Add carry back in... */
+		while (accum > 255)
+			accum = (accum & 255) + (accum >> 8);
+	}
+	return (accum % size);
+}
+
+void add_hash(struct hash_table *table, unsigned char *name, int len,
+    unsigned char *pointer)
+{
+	struct hash_bucket *bp;
+	int hashno;
+
+	if (!table)
+		return;
+	if (!len)
+		len = strlen((char *)name);
+
+	hashno = do_hash(name, len, table->hash_count);
+	bp = new_hash_bucket();
+
+	if (!bp) {
+		warning("Can't add %s to hash table.", name);
+		return;
+	}
+	bp->name = name;
+	bp->value = pointer;
+	bp->next = table->buckets[hashno];
+	bp->len = len;
+	table->buckets[hashno] = bp;
+}
+
+unsigned char *
+hash_lookup(struct hash_table *table, unsigned char *name, int len)
+{
+	struct hash_bucket *bp;
+	int hashno;
+
+	if (!table)
+		return (NULL);
+
+	if (!len)
+		len = strlen((char *)name);
+
+	hashno = do_hash(name, len, table->hash_count);
+
+	for (bp = table->buckets[hashno]; bp; bp = bp->next)
+		if (len == bp->len && !memcmp(bp->name, name, len))
+			return (bp->value);
+
+	return (NULL);
+}
diff --git a/freebsd-userspace/commands/sbin/dhclient/inet.c b/freebsd-userspace/commands/sbin/dhclient/inet.c
new file mode 100644
index 0000000..4b7b1ce
--- /dev/null
+++ b/freebsd-userspace/commands/sbin/dhclient/inet.c
@@ -0,0 +1,121 @@
+/*	$OpenBSD: inet.c,v 1.7 2004/05/04 21:48:16 deraadt Exp $	*/
+
+/*
+ * Subroutines to manipulate internet addresses in a safely portable
+ * way...
+ */
+
+/*
+ * Copyright (c) 1996 The Internet Software Consortium.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of The Internet Software Consortium nor the names
+ *    of its contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM 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 INTERNET SOFTWARE CONSORTIUM 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 software has been written for the Internet Software Consortium
+ * by Ted Lemon <mellon at fugue.com> in cooperation with Vixie
+ * Enterprises.  To learn more about the Internet Software Consortium,
+ * see ``http://www.vix.com/isc''.  To learn more about Vixie
+ * Enterprises, see ``http://www.vix.com''.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "dhcpd.h"
+
+/*
+ * Return just the network number of an internet address...
+ */
+struct iaddr
+subnet_number(struct iaddr addr, struct iaddr mask)
+{
+	struct iaddr rv;
+	int i;
+
+	rv.len = 0;
+
+	/* Both addresses must have the same length... */
+	if (addr.len != mask.len)
+		return (rv);
+
+	rv.len = addr.len;
+	for (i = 0; i < rv.len; i++)
+		rv.iabuf[i] = addr.iabuf[i] & mask.iabuf[i];
+	return (rv);
+}
+
+/*
+ * Given a subnet number and netmask, return the address on that subnet
+ * for which the host portion of the address is all ones (the standard
+ * broadcast address).
+ */
+struct iaddr
+broadcast_addr(struct iaddr subnet, struct iaddr mask)
+{
+	struct iaddr rv;
+	int i;
+
+	if (subnet.len != mask.len) {
+		rv.len = 0;
+		return (rv);
+	}
+
+	for (i = 0; i < subnet.len; i++)
+		rv.iabuf[i] = subnet.iabuf[i] | (~mask.iabuf[i] & 255);
+	rv.len = subnet.len;
+
+	return (rv);
+}
+
+int
+addr_eq(struct iaddr addr1, struct iaddr addr2)
+{
+	if (addr1.len != addr2.len)
+		return (0);
+	return (memcmp(addr1.iabuf, addr2.iabuf, addr1.len) == 0);
+}
+
+char *
+piaddr(struct iaddr addr)
+{
+	static char pbuf[32];
+	struct in_addr a;
+	char *s;
+
+	memcpy(&a, &(addr.iabuf), sizeof(struct in_addr));
+
+	if (addr.len == 0)
+		strlcpy(pbuf, "<null address>", sizeof(pbuf));
+	else {
+		s = inet_ntoa(a);
+		if (s != NULL)
+			strlcpy(pbuf, s, sizeof(pbuf));
+		else
+			strlcpy(pbuf, "<invalid address>", sizeof(pbuf));
+	}
+	return (pbuf);
+}
diff --git a/freebsd-userspace/commands/sbin/dhclient/options.c b/freebsd-userspace/commands/sbin/dhclient/options.c
new file mode 100644
index 0000000..09aa4d8
--- /dev/null
+++ b/freebsd-userspace/commands/sbin/dhclient/options.c
@@ -0,0 +1,720 @@
+/*	$OpenBSD: options.c,v 1.15 2004/12/26 03:17:07 deraadt Exp $	*/
+
+/* DHCP options parsing and reassembly. */
+
+/*
+ * Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of The Internet Software Consortium nor the names
+ *    of its contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM 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 INTERNET SOFTWARE CONSORTIUM 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 software has been written for the Internet Software Consortium
+ * by Ted Lemon <mellon at fugue.com> in cooperation with Vixie
+ * Enterprises.  To learn more about the Internet Software Consortium,
+ * see ``http://www.vix.com/isc''.  To learn more about Vixie
+ * Enterprises, see ``http://www.vix.com''.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <ctype.h>
+
+#define DHCP_OPTION_DATA
+#include "dhcpd.h"
+
+int bad_options = 0;
+int bad_options_max = 5;
+
+void	parse_options(struct packet *);
+void	parse_option_buffer(struct packet *, unsigned char *, int);
+int	store_options(unsigned char *, int, struct tree_cache **,
+	    unsigned char *, int, int, int, int);
+
+
+/*
+ * Parse all available options out of the specified packet.
+ */
+void
+parse_options(struct packet *packet)
+{
+	/* Initially, zero all option pointers. */
+	memset(packet->options, 0, sizeof(packet->options));
+
+	/* If we don't see the magic cookie, there's nothing to parse. */
+	if (memcmp(packet->raw->options, DHCP_OPTIONS_COOKIE, 4)) {
+		packet->options_valid = 0;
+		return;
+	}
+
+	/*
+	 * Go through the options field, up to the end of the packet or
+	 * the End field.
+	 */
+	parse_option_buffer(packet, &packet->raw->options[4],
+	    packet->packet_length - DHCP_FIXED_NON_UDP - 4);
+
+	/*
+	 * If we parsed a DHCP Option Overload option, parse more
+	 * options out of the buffer(s) containing them.
+	 */
+	if (packet->options_valid &&
+	    packet->options[DHO_DHCP_OPTION_OVERLOAD].data) {
+		if (packet->options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 1)
+			parse_option_buffer(packet,
+			    (unsigned char *)packet->raw->file,
+			    sizeof(packet->raw->file));
+		if (packet->options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 2)
+			parse_option_buffer(packet,
+			    (unsigned char *)packet->raw->sname,
+			    sizeof(packet->raw->sname));
+	}
+}
+
+/*
+ * Parse options out of the specified buffer, storing addresses of
+ * option values in packet->options and setting packet->options_valid if
+ * no errors are encountered.
+ */
+void
+parse_option_buffer(struct packet *packet,
+    unsigned char *buffer, int length)
+{
+	unsigned char *s, *t, *end = buffer + length;
+	int len, code;
+
+	for (s = buffer; *s != DHO_END && s < end; ) {
+		code = s[0];
+
+		/* Pad options don't have a length - just skip them. */
+		if (code == DHO_PAD) {
+			s++;
+			continue;
+		}
+		if (s + 2 > end) {
+			len = 65536;
+			goto bogus;
+		}
+
+		/*
+		 * All other fields (except end, see above) have a
+		 * one-byte length.
+		 */
+		len = s[1];
+
+		/*
+		 * If the length is outrageous, silently skip the rest,
+		 * and mark the packet bad. Unfortunately some crappy
+		 * dhcp servers always seem to give us garbage on the
+		 * end of a packet. so rather than keep refusing, give
+		 * up and try to take one after seeing a few without
+		 * anything good.
+		 */
+		if (s + len + 2 > end) {
+		    bogus:
+			bad_options++;
+			warning("option %s (%d) %s.",
+			    dhcp_options[code].name, len,
+			    "larger than buffer");
+			if (bad_options == bad_options_max) {
+				packet->options_valid = 1;
+				bad_options = 0;
+				warning("Many bogus options seen in offers. "
+				    "Taking this offer in spite of bogus "
+				    "options - hope for the best!");
+			} else {
+				warning("rejecting bogus offer.");
+				packet->options_valid = 0;
+			}
+			return;
+		}
+		/*
+		 * If we haven't seen this option before, just make
+		 * space for it and copy it there.
+		 */
+		if (!packet->options[code].data) {
+			if (!(t = calloc(1, len + 1)))
+				error("Can't allocate storage for option %s.",
+				    dhcp_options[code].name);
+			/*
+			 * Copy and NUL-terminate the option (in case
+			 * it's an ASCII string.
+			 */
+			memcpy(t, &s[2], len);
+			t[len] = 0;
+			packet->options[code].len = len;
+			packet->options[code].data = t;
+		} else {
+			/*
+			 * If it's a repeat, concatenate it to whatever
+			 * we last saw.   This is really only required
+			 * for clients, but what the heck...
+			 */
+			t = calloc(1, len + packet->options[code].len + 1);
+			if (!t)
+				error("Can't expand storage for option %s.",
+				    dhcp_options[code].name);
+			memcpy(t, packet->options[code].data,
+				packet->options[code].len);
+			memcpy(t + packet->options[code].len,
+				&s[2], len);
+			packet->options[code].len += len;
+			t[packet->options[code].len] = 0;
+			free(packet->options[code].data);
+			packet->options[code].data = t;
+		}
+		s += len + 2;
+	}
+	packet->options_valid = 1;
+}
+
+/*
+ * cons options into a big buffer, and then split them out into the
+ * three separate buffers if needed.  This allows us to cons up a set of
+ * vendor options using the same routine.
+ */
+int
+cons_options(struct packet *inpacket, struct dhcp_packet *outpacket,
+    int mms, struct tree_cache **options,
+    int overload, /* Overload flags that may be set. */
+    int terminate, int bootpp, u_int8_t *prl, int prl_len)
+{
+	unsigned char priority_list[300], buffer[4096];
+	int priority_len, main_buffer_size, mainbufix, bufix;
+	int option_size, length;
+
+	/*
+	 * If the client has provided a maximum DHCP message size, use
+	 * that; otherwise, if it's BOOTP, only 64 bytes; otherwise use
+	 * up to the minimum IP MTU size (576 bytes).
+	 *
+	 * XXX if a BOOTP client specifies a max message size, we will
+	 * honor it.
+	 */
+	if (!mms &&
+	    inpacket &&
+	    inpacket->options[DHO_DHCP_MAX_MESSAGE_SIZE].data &&
+	    (inpacket->options[DHO_DHCP_MAX_MESSAGE_SIZE].len >=
+	    sizeof(u_int16_t)))
+		mms = getUShort(
+		    inpacket->options[DHO_DHCP_MAX_MESSAGE_SIZE].data);
+
+	if (mms)
+		main_buffer_size = mms - DHCP_FIXED_LEN;
+	else if (bootpp)
+		main_buffer_size = 64;
+	else
+		main_buffer_size = 576 - DHCP_FIXED_LEN;
+
+	if (main_buffer_size > sizeof(buffer))
+		main_buffer_size = sizeof(buffer);
+
+	/* Preload the option priority list with mandatory options. */
+	priority_len = 0;
+	priority_list[priority_len++] = DHO_DHCP_MESSAGE_TYPE;
+	priority_list[priority_len++] = DHO_DHCP_SERVER_IDENTIFIER;
+	priority_list[priority_len++] = DHO_DHCP_LEASE_TIME;
+	priority_list[priority_len++] = DHO_DHCP_MESSAGE;
+
+	/*
+	 * If the client has provided a list of options that it wishes
+	 * returned, use it to prioritize.  Otherwise, prioritize based
+	 * on the default priority list.
+	 */
+	if (inpacket &&
+	    inpacket->options[DHO_DHCP_PARAMETER_REQUEST_LIST].data) {
+		int prlen =
+		    inpacket->options[DHO_DHCP_PARAMETER_REQUEST_LIST].len;
+		if (prlen + priority_len > sizeof(priority_list))
+			prlen = sizeof(priority_list) - priority_len;
+
+		memcpy(&priority_list[priority_len],
+		    inpacket->options[DHO_DHCP_PARAMETER_REQUEST_LIST].data,
+		    prlen);
+		priority_len += prlen;
+		prl = priority_list;
+	} else if (prl) {
+		if (prl_len + priority_len > sizeof(priority_list))
+			prl_len = sizeof(priority_list) - priority_len;
+
+		memcpy(&priority_list[priority_len], prl, prl_len);
+		priority_len += prl_len;
+		prl = priority_list;
+	} else {
+		memcpy(&priority_list[priority_len],
+		    dhcp_option_default_priority_list,
+		    sizeof_dhcp_option_default_priority_list);
+		priority_len += sizeof_dhcp_option_default_priority_list;
+	}
+
+	/* Copy the options into the big buffer... */
+	option_size = store_options(
+	    buffer,
+	    (main_buffer_size - 7 + ((overload & 1) ? DHCP_FILE_LEN : 0) +
+		((overload & 2) ? DHCP_SNAME_LEN : 0)),
+	    options, priority_list, priority_len, main_buffer_size,
+	    (main_buffer_size + ((overload & 1) ? DHCP_FILE_LEN : 0)),
+	    terminate);
+
+	/* Put the cookie up front... */
+	memcpy(outpacket->options, DHCP_OPTIONS_COOKIE, 4);
+	mainbufix = 4;
+
+	/*
+	 * If we're going to have to overload, store the overload option
+	 * at the beginning.  If we can, though, just store the whole
+	 * thing in the packet's option buffer and leave it at that.
+	 */
+	if (option_size <= main_buffer_size - mainbufix) {
+		memcpy(&outpacket->options[mainbufix],
+		    buffer, option_size);
+		mainbufix += option_size;
+		if (mainbufix < main_buffer_size)
+			outpacket->options[mainbufix++] = DHO_END;
+		length = DHCP_FIXED_NON_UDP + mainbufix;
+	} else {
+		outpacket->options[mainbufix++] = DHO_DHCP_OPTION_OVERLOAD;
+		outpacket->options[mainbufix++] = 1;
+		if (option_size >
+		    main_buffer_size - mainbufix + DHCP_FILE_LEN)
+			outpacket->options[mainbufix++] = 3;
+		else
+			outpacket->options[mainbufix++] = 1;
+
+		memcpy(&outpacket->options[mainbufix],
+		    buffer, main_buffer_size - mainbufix);
+		bufix = main_buffer_size - mainbufix;
+		length = DHCP_FIXED_NON_UDP + mainbufix;
+		if (overload & 1) {
+			if (option_size - bufix <= DHCP_FILE_LEN) {
+				memcpy(outpacket->file,
+				    &buffer[bufix], option_size - bufix);
+				mainbufix = option_size - bufix;
+				if (mainbufix < DHCP_FILE_LEN)
+					outpacket->file[mainbufix++] = (char)DHO_END;
+				while (mainbufix < DHCP_FILE_LEN)
+					outpacket->file[mainbufix++] = (char)DHO_PAD;
+			} else {
+				memcpy(outpacket->file,
+				    &buffer[bufix], DHCP_FILE_LEN);
+				bufix += DHCP_FILE_LEN;
+			}
+		}
+		if ((overload & 2) && option_size < bufix) {
+			memcpy(outpacket->sname,
+			    &buffer[bufix], option_size - bufix);
+
+			mainbufix = option_size - bufix;
+			if (mainbufix < DHCP_SNAME_LEN)
+				outpacket->file[mainbufix++] = (char)DHO_END;
+			while (mainbufix < DHCP_SNAME_LEN)
+				outpacket->file[mainbufix++] = (char)DHO_PAD;
+		}
+	}
+	return (length);
+}
+
+/*
+ * Store all the requested options into the requested buffer.
+ */
+int
+store_options(unsigned char *buffer, int buflen, struct tree_cache **options,
+    unsigned char *priority_list, int priority_len, int first_cutoff,
+    int second_cutoff, int terminate)
+{
+	int bufix = 0, option_stored[256], i, ix, tto;
+
+	/* Zero out the stored-lengths array. */
+	memset(option_stored, 0, sizeof(option_stored));
+
+	/*
+	 * Copy out the options in the order that they appear in the
+	 * priority list...
+	 */
+	for (i = 0; i < priority_len; i++) {
+		/* Code for next option to try to store. */
+		int code = priority_list[i];
+		int optstart;
+
+		/*
+		 * Number of bytes left to store (some may already have
+		 * been stored by a previous pass).
+		 */
+		int length;
+
+		/* If no data is available for this option, skip it. */
+		if (!options[code]) {
+			continue;
+		}
+
+		/*
+		 * The client could ask for things that are mandatory,
+		 * in which case we should avoid storing them twice...
+		 */
+		if (option_stored[code])
+			continue;
+		option_stored[code] = 1;
+
+		/* We should now have a constant length for the option. */
+		length = options[code]->len;
+
+		/* Do we add a NUL? */
+		if (terminate && dhcp_options[code].format[0] == 't') {
+			length++;
+			tto = 1;
+		} else
+			tto = 0;
+
+		/* Try to store the option. */
+
+		/*
+		 * If the option's length is more than 255, we must
+		 * store it in multiple hunks.   Store 255-byte hunks
+		 * first.  However, in any case, if the option data will
+		 * cross a buffer boundary, split it across that
+		 * boundary.
+		 */
+		ix = 0;
+
+		optstart = bufix;
+		while (length) {
+			unsigned char incr = length > 255 ? 255 : length;
+
+			/*
+			 * If this hunk of the buffer will cross a
+			 * boundary, only go up to the boundary in this
+			 * pass.
+			 */
+			if (bufix < first_cutoff &&
+			    bufix + incr > first_cutoff)
+				incr = first_cutoff - bufix;
+			else if (bufix < second_cutoff &&
+			    bufix + incr > second_cutoff)
+				incr = second_cutoff - bufix;
+
+			/*
+			 * If this option is going to overflow the
+			 * buffer, skip it.
+			 */
+			if (bufix + 2 + incr > buflen) {
+				bufix = optstart;
+				break;
+			}
+
+			/* Everything looks good - copy it in! */
+			buffer[bufix] = code;
+			buffer[bufix + 1] = incr;
+			if (tto && incr == length) {
+				memcpy(buffer + bufix + 2,
+				    options[code]->value + ix, incr - 1);
+				buffer[bufix + 2 + incr - 1] = 0;
+			} else
+				memcpy(buffer + bufix + 2,
+				    options[code]->value + ix, incr);
+			length -= incr;
+			ix += incr;
+			bufix += 2 + incr;
+		}
+	}
+	return (bufix);
+}
+
+/*
+ * Format the specified option so that a human can easily read it.
+ */
+char *
+pretty_print_option(unsigned int code, unsigned char *data, int len,
+    int emit_commas, int emit_quotes)
+{
+	static char optbuf[32768]; /* XXX */
+	int hunksize = 0, numhunk = -1, numelem = 0;
+	char fmtbuf[32], *op = optbuf;
+	int i, j, k, opleft = sizeof(optbuf);
+	unsigned char *dp = data;
+	struct in_addr foo;
+	char comma;
+
+	/* Code should be between 0 and 255. */
+	if (code > 255)
+		error("pretty_print_option: bad code %d", code);
+
+	if (emit_commas)
+		comma = ',';
+	else
+		comma = ' ';
+
+	/* Figure out the size of the data. */
+	for (i = 0; dhcp_options[code].format[i]; i++) {
+		if (!numhunk) {
+			warning("%s: Excess information in format string: %s",
+			    dhcp_options[code].name,
+			    &(dhcp_options[code].format[i]));
+			break;
+		}
+		numelem++;
+		fmtbuf[i] = dhcp_options[code].format[i];
+		switch (dhcp_options[code].format[i]) {
+		case 'A':
+			--numelem;
+			fmtbuf[i] = 0;
+			numhunk = 0;
+			break;
+		case 'X':
+			for (k = 0; k < len; k++)
+				if (!isascii(data[k]) ||
+				    !isprint(data[k]))
+					break;
+			if (k == len) {
+				fmtbuf[i] = 't';
+				numhunk = -2;
+			} else {
+				fmtbuf[i] = 'x';
+				hunksize++;
+				comma = ':';
+				numhunk = 0;
+			}
+			fmtbuf[i + 1] = 0;
+			break;
+		case 't':
+			fmtbuf[i] = 't';
+			fmtbuf[i + 1] = 0;
+			numhunk = -2;
+			break;
+		case 'I':
+		case 'l':
+		case 'L':
+			hunksize += 4;
+			break;
+		case 's':
+		case 'S':
+			hunksize += 2;
+			break;
+		case 'b':
+		case 'B':
+		case 'f':
+			hunksize++;
+			break;
+		case 'e':
+			break;
+		default:
+			warning("%s: garbage in format string: %s",
+			    dhcp_options[code].name,
+			    &(dhcp_options[code].format[i]));
+			break;
+		}
+	}
+
+	/* Check for too few bytes... */
+	if (hunksize > len) {
+		warning("%s: expecting at least %d bytes; got %d",
+		    dhcp_options[code].name, hunksize, len);
+		return ("<error>");
+	}
+	/* Check for too many bytes... */
+	if (numhunk == -1 && hunksize < len)
+		warning("%s: %d extra bytes",
+		    dhcp_options[code].name, len - hunksize);
+
+	/* If this is an array, compute its size. */
+	if (!numhunk)
+		numhunk = len / hunksize;
+	/* See if we got an exact number of hunks. */
+	if (numhunk > 0 && numhunk * hunksize < len)
+		warning("%s: %d extra bytes at end of array",
+		    dhcp_options[code].name, len - numhunk * hunksize);
+
+	/* A one-hunk array prints the same as a single hunk. */
+	if (numhunk < 0)
+		numhunk = 1;
+
+	/* Cycle through the array (or hunk) printing the data. */
+	for (i = 0; i < numhunk; i++) {
+		for (j = 0; j < numelem; j++) {
+			int opcount;
+			switch (fmtbuf[j]) {
+			case 't':
+				if (emit_quotes) {
+					*op++ = '"';
+					opleft--;
+				}
+				for (; dp < data + len; dp++) {
+					if (!isascii(*dp) ||
+					    !isprint(*dp)) {
+						if (dp + 1 != data + len ||
+						    *dp != 0) {
+							snprintf(op, opleft,
+							    "\\%03o", *dp);
+							op += 4;
+							opleft -= 4;
+						}
+					} else if (*dp == '"' ||
+					    *dp == '\'' ||
+					    *dp == '$' ||
+					    *dp == '`' ||
+					    *dp == '\\') {
+						*op++ = '\\';
+						*op++ = *dp;
+						opleft -= 2;
+					} else {
+						*op++ = *dp;
+						opleft--;
+					}
+				}
+				if (emit_quotes) {
+					*op++ = '"';
+					opleft--;
+				}
+
+				*op = 0;
+				break;
+			case 'I':
+				foo.s_addr = htonl(getULong(dp));
+				opcount = strlcpy(op, inet_ntoa(foo), opleft);
+				if (opcount >= opleft)
+					goto toobig;
+				opleft -= opcount;
+				dp += 4;
+				break;
+			case 'l':
+				opcount = snprintf(op, opleft, "%ld",
+				    (long)getLong(dp));
+				if (opcount >= opleft || opcount == -1)
+					goto toobig;
+				opleft -= opcount;
+				dp += 4;
+				break;
+			case 'L':
+				opcount = snprintf(op, opleft, "%ld",
+				    (unsigned long)getULong(dp));
+				if (opcount >= opleft || opcount == -1)
+					goto toobig;
+				opleft -= opcount;
+				dp += 4;
+				break;
+			case 's':
+				opcount = snprintf(op, opleft, "%d",
+				    getShort(dp));
+				if (opcount >= opleft || opcount == -1)
+					goto toobig;
+				opleft -= opcount;
+				dp += 2;
+				break;
+			case 'S':
+				opcount = snprintf(op, opleft, "%d",
+				    getUShort(dp));
+				if (opcount >= opleft || opcount == -1)
+					goto toobig;
+				opleft -= opcount;
+				dp += 2;
+				break;
+			case 'b':
+				opcount = snprintf(op, opleft, "%d",
+				    *(char *)dp++);
+				if (opcount >= opleft || opcount == -1)
+					goto toobig;
+				opleft -= opcount;
+				break;
+			case 'B':
+				opcount = snprintf(op, opleft, "%d", *dp++);
+				if (opcount >= opleft || opcount == -1)
+					goto toobig;
+				opleft -= opcount;
+				break;
+			case 'x':
+				opcount = snprintf(op, opleft, "%x", *dp++);
+				if (opcount >= opleft || opcount == -1)
+					goto toobig;
+				opleft -= opcount;
+				break;
+			case 'f':
+				opcount = strlcpy(op,
+				    *dp++ ? "true" : "false", opleft);
+				if (opcount >= opleft)
+					goto toobig;
+				opleft -= opcount;
+				break;
+			default:
+				warning("Unexpected format code %c", fmtbuf[j]);
+			}
+			op += strlen(op);
+			opleft -= strlen(op);
+			if (opleft < 1)
+				goto toobig;
+			if (j + 1 < numelem && comma != ':') {
+				*op++ = ' ';
+				opleft--;
+			}
+		}
+		if (i + 1 < numhunk) {
+			*op++ = comma;
+			opleft--;
+		}
+		if (opleft < 1)
+			goto toobig;
+
+	}
+	return (optbuf);
+ toobig:
+	warning("dhcp option too large");
+	return ("<error>");
+}
+
+void
+do_packet(struct interface_info *interface, struct dhcp_packet *packet,
+    int len, unsigned int from_port, struct iaddr from, struct hardware *hfrom)
+{
+	struct packet tp;
+	int i;
+
+	if (packet->hlen > sizeof(packet->chaddr)) {
+		note("Discarding packet with invalid hlen.");
+		return;
+	}
+
+	memset(&tp, 0, sizeof(tp));
+	tp.raw = packet;
+	tp.packet_length = len;
+	tp.client_port = from_port;
+	tp.client_addr = from;
+	tp.interface = interface;
+	tp.haddr = hfrom;
+
+	parse_options(&tp);
+	if (tp.options_valid &&
+	    tp.options[DHO_DHCP_MESSAGE_TYPE].data)
+		tp.packet_type = tp.options[DHO_DHCP_MESSAGE_TYPE].data[0];
+	if (tp.packet_type)
+		dhcp(&tp);
+	else
+		bootp(&tp);
+
+	/* Free the data associated with the options. */
+	for (i = 0; i < 256; i++)
+		if (tp.options[i].len && tp.options[i].data)
+			free(tp.options[i].data);
+}
diff --git a/freebsd-userspace/commands/sbin/dhclient/packet.c b/freebsd-userspace/commands/sbin/dhclient/packet.c
new file mode 100644
index 0000000..2e90cc8
--- /dev/null
+++ b/freebsd-userspace/commands/sbin/dhclient/packet.c
@@ -0,0 +1,267 @@
+/*	$OpenBSD: packet.c,v 1.9 2004/05/04 18:58:50 deraadt Exp $	*/
+
+/* Packet assembly code, originally contributed by Archie Cobbs. */
+
+/*
+ * Copyright (c) 1995, 1996, 1999 The Internet Software Consortium.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of The Internet Software Consortium nor the names
+ *    of its contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM 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 INTERNET SOFTWARE CONSORTIUM 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 software has been written for the Internet Software Consortium
+ * by Ted Lemon <mellon at fugue.com> in cooperation with Vixie
+ * Enterprises.  To learn more about the Internet Software Consortium,
+ * see ``http://www.vix.com/isc''.  To learn more about Vixie
+ * Enterprises, see ``http://www.vix.com''.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "dhcpd.h"
+
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/udp.h>
+#include <netinet/if_ether.h>
+
+#define ETHER_HEADER_SIZE (ETHER_ADDR_LEN * 2 + sizeof(u_int16_t))
+
+u_int32_t	checksum(unsigned char *, unsigned, u_int32_t);
+u_int32_t	wrapsum(u_int32_t);
+
+void	assemble_ethernet_header(struct interface_info *, unsigned char *,
+	    int *, struct hardware *);
+ssize_t	decode_ethernet_header(struct interface_info *, unsigned char *,
+	    int bufix, struct hardware *);
+
+u_int32_t
+checksum(unsigned char *buf, unsigned nbytes, u_int32_t sum)
+{
+	int i;
+
+	/* Checksum all the pairs of bytes first... */
+	for (i = 0; i < (nbytes & ~1U); i += 2) {
+		sum += (u_int16_t)ntohs(*((u_int16_t *)(buf + i)));
+		if (sum > 0xFFFF)
+			sum -= 0xFFFF;
+	}
+
+	/*
+	 * If there's a single byte left over, checksum it, too.
+	 * Network byte order is big-endian, so the remaining byte is
+	 * the high byte.
+	 */
+	if (i < nbytes) {
+		sum += buf[i] << 8;
+		if (sum > 0xFFFF)
+			sum -= 0xFFFF;
+	}
+
+	return (sum);
+}
+
+u_int32_t
+wrapsum(u_int32_t sum)
+{
+	sum = ~sum & 0xFFFF;
+	return (htons(sum));
+}
+
+void
+assemble_hw_header(struct interface_info *interface, unsigned char *buf,
+    int *bufix, struct hardware *to)
+{
+	struct ether_header eh;
+
+	if (to != NULL && to->hlen == 6) /* XXX */
+		memcpy(eh.ether_dhost, to->haddr, sizeof(eh.ether_dhost));
+	else
+		memset(eh.ether_dhost, 0xff, sizeof(eh.ether_dhost));
+	if (interface->hw_address.hlen == sizeof(eh.ether_shost))
+		memcpy(eh.ether_shost, interface->hw_address.haddr,
+		    sizeof(eh.ether_shost));
+	else
+		memset(eh.ether_shost, 0x00, sizeof(eh.ether_shost));
+
+	eh.ether_type = htons(ETHERTYPE_IP);
+
+	memcpy(&buf[*bufix], &eh, ETHER_HEADER_SIZE);
+	*bufix += ETHER_HEADER_SIZE;
+}
+
+void
+assemble_udp_ip_header(unsigned char *buf, int *bufix, u_int32_t from,
+    u_int32_t to, unsigned int port, unsigned char *data, int len)
+{
+	struct ip ip;
+	struct udphdr udp;
+
+	ip.ip_v = 4;
+	ip.ip_hl = 5;
+	ip.ip_tos = IPTOS_LOWDELAY;
+	ip.ip_len = htons(sizeof(ip) + sizeof(udp) + len);
+	ip.ip_id = 0;
+	ip.ip_off = 0;
+	ip.ip_ttl = 16;
+	ip.ip_p = IPPROTO_UDP;
+	ip.ip_sum = 0;
+	ip.ip_src.s_addr = from;
+	ip.ip_dst.s_addr = to;
+
+	ip.ip_sum = wrapsum(checksum((unsigned char *)&ip, sizeof(ip), 0));
+
+	/*
+	 * While the BPF -- used for broadcasts -- expects a "true" IP header
+	 * with all the bytes in network byte order, the raw socket interface
+	 * which is used for unicasts expects the ip_len field to be in host
+	 * byte order.  In both cases, the checksum has to be correct, so this
+	 * is as good a place as any to turn the bytes around again.
+	 */
+	if (to != INADDR_BROADCAST)
+		ip.ip_len = ntohs(ip.ip_len);
+
+	memcpy(&buf[*bufix], &ip, sizeof(ip));
+	*bufix += sizeof(ip);
+
+	udp.uh_sport = htons(LOCAL_PORT);	/* XXX */
+	udp.uh_dport = port;			/* XXX */
+	udp.uh_ulen = htons(sizeof(udp) + len);
+	memset(&udp.uh_sum, 0, sizeof(udp.uh_sum));
+
+	udp.uh_sum = wrapsum(checksum((unsigned char *)&udp, sizeof(udp),
+	    checksum(data, len, checksum((unsigned char *)&ip.ip_src,
+	    2 * sizeof(ip.ip_src),
+	    IPPROTO_UDP + (u_int32_t)ntohs(udp.uh_ulen)))));
+
+	memcpy(&buf[*bufix], &udp, sizeof(udp));
+	*bufix += sizeof(udp);
+}
+
+ssize_t
+decode_hw_header(unsigned char *buf, int bufix, struct hardware *from)
+{
+	struct ether_header eh;
+
+	memcpy(&eh, buf + bufix, ETHER_HEADER_SIZE);
+
+	memcpy(from->haddr, eh.ether_shost, sizeof(eh.ether_shost));
+	from->htype = ARPHRD_ETHER;
+	from->hlen = sizeof(eh.ether_shost);
+
+	return (sizeof(eh));
+}
+
+ssize_t
+decode_udp_ip_header(unsigned char *buf, int bufix, struct sockaddr_in *from,
+    unsigned char *data, int buflen)
+{
+	struct ip *ip;
+	struct udphdr *udp;
+	u_int32_t ip_len = (buf[bufix] & 0xf) << 2;
+	u_int32_t sum, usum;
+	static int ip_packets_seen;
+	static int ip_packets_bad_checksum;
+	static int udp_packets_seen;
+	static int udp_packets_bad_checksum;
+	static int udp_packets_length_checked;
+	static int udp_packets_length_overflow;
+	int len = 0;
+
+	ip = (struct ip *)(buf + bufix);
+	udp = (struct udphdr *)(buf + bufix + ip_len);
+
+	/* Check the IP header checksum - it should be zero. */
+	ip_packets_seen++;
+	if (wrapsum(checksum(buf + bufix, ip_len, 0)) != 0) {
+		ip_packets_bad_checksum++;
+		if (ip_packets_seen > 4 &&
+		    (ip_packets_seen / ip_packets_bad_checksum) < 2) {
+			note("%d bad IP checksums seen in %d packets",
+			    ip_packets_bad_checksum, ip_packets_seen);
+			ip_packets_seen = ip_packets_bad_checksum = 0;
+		}
+		return (-1);
+	}
+
+	if (ntohs(ip->ip_len) != buflen)
+		debug("ip length %d disagrees with bytes received %d.",
+		    ntohs(ip->ip_len), buflen);
+
+	memcpy(&from->sin_addr, &ip->ip_src, 4);
+
+	/*
+	 * Compute UDP checksums, including the ``pseudo-header'', the
+	 * UDP header and the data.   If the UDP checksum field is zero,
+	 * we're not supposed to do a checksum.
+	 */
+	if (!data) {
+		data = buf + bufix + ip_len + sizeof(*udp);
+		len = ntohs(udp->uh_ulen) - sizeof(*udp);
+		udp_packets_length_checked++;
+		if (len + data > buf + bufix + buflen) {
+			udp_packets_length_overflow++;
+			if (udp_packets_length_checked > 4 &&
+			    (udp_packets_length_checked /
+			    udp_packets_length_overflow) < 2) {
+				note("%d udp packets in %d too long - dropped",
+				    udp_packets_length_overflow,
+				    udp_packets_length_checked);
+				udp_packets_length_overflow =
+				    udp_packets_length_checked = 0;
+			}
+			return (-1);
+		}
+		if (len + data != buf + bufix + buflen)
+			debug("accepting packet with data after udp payload.");
+	}
+
+	usum = udp->uh_sum;
+	udp->uh_sum = 0;
+
+	sum = wrapsum(checksum((unsigned char *)udp, sizeof(*udp),
+	    checksum(data, len, checksum((unsigned char *)&ip->ip_src,
+	    2 * sizeof(ip->ip_src),
+	    IPPROTO_UDP + (u_int32_t)ntohs(udp->uh_ulen)))));
+
+	udp_packets_seen++;
+	if (usum && usum != sum) {
+		udp_packets_bad_checksum++;
+		if (udp_packets_seen > 4 &&
+		    (udp_packets_seen / udp_packets_bad_checksum) < 2) {
+			note("%d bad udp checksums in %d packets",
+			    udp_packets_bad_checksum, udp_packets_seen);
+			udp_packets_seen = udp_packets_bad_checksum = 0;
+		}
+		return (-1);
+	}
+
+	memcpy(&from->sin_port, &udp->uh_sport, sizeof(udp->uh_sport));
+
+	return (ip_len + sizeof(*udp));
+}
diff --git a/freebsd-userspace/commands/sbin/dhclient/parse.c b/freebsd-userspace/commands/sbin/dhclient/parse.c
new file mode 100644
index 0000000..6a54fd0
--- /dev/null
+++ b/freebsd-userspace/commands/sbin/dhclient/parse.c
@@ -0,0 +1,580 @@
+/*	$OpenBSD: parse.c,v 1.11 2004/05/05 23:07:47 deraadt Exp $	*/
+
+/* Common parser code for dhcpd and dhclient. */
+
+/*
+ * Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of The Internet Software Consortium nor the names
+ *    of its contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM 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 INTERNET SOFTWARE CONSORTIUM 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 software has been written for the Internet Software Consortium
+ * by Ted Lemon <mellon at fugue.com> in cooperation with Vixie
+ * Enterprises.  To learn more about the Internet Software Consortium,
+ * see ``http://www.vix.com/isc''.  To learn more about Vixie
+ * Enterprises, see ``http://www.vix.com''.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "dhcpd.h"
+#include "dhctoken.h"
+
+/* Skip to the semicolon ending the current statement.   If we encounter
+ * braces, the matching closing brace terminates the statement.   If we
+ * encounter a right brace but haven't encountered a left brace, return
+ * leaving the brace in the token buffer for the caller.   If we see a
+ * semicolon and haven't seen a left brace, return.   This lets us skip
+ * over:
+ *
+ *	statement;
+ *	statement foo bar { }
+ *	statement foo bar { statement { } }
+ *	statement}
+ *
+ *	...et cetera.
+ */
+void
+skip_to_semi(FILE *cfile)
+{
+	int brace_count = 0, token;
+	char *val;
+
+	do {
+		token = peek_token(&val, cfile);
+		if (token == RBRACE) {
+			if (brace_count) {
+				token = next_token(&val, cfile);
+				if (!--brace_count)
+					return;
+			} else
+				return;
+		} else if (token == LBRACE) {
+			brace_count++;
+		} else if (token == SEMI && !brace_count) {
+			token = next_token(&val, cfile);
+			return;
+		} else if (token == '\n') {
+			/*
+			 * EOL only happens when parsing
+			 * /etc/resolv.conf, and we treat it like a
+			 * semicolon because the resolv.conf file is
+			 * line-oriented.
+			 */
+			token = next_token(&val, cfile);
+			return;
+		}
+		token = next_token(&val, cfile);
+	} while (token != EOF);
+}
+
+int
+parse_semi(FILE *cfile)
+{
+	int token;
+	char *val;
+
+	token = next_token(&val, cfile);
+	if (token != SEMI) {
+		parse_warn("semicolon expected.");
+		skip_to_semi(cfile);
+		return (0);
+	}
+	return (1);
+}
+
+/*
+ * string-parameter :== STRING SEMI
+ */
+char *
+parse_string(FILE *cfile)
+{
+	char *val, *s;
+	int token;
+
+	token = next_token(&val, cfile);
+	if (token != STRING) {
+		parse_warn("filename must be a string");
+		skip_to_semi(cfile);
+		return (NULL);
+	}
+	s = malloc(strlen(val) + 1);
+	if (!s)
+		error("no memory for string %s.", val);
+	strlcpy(s, val, strlen(val) + 1);
+
+	if (!parse_semi(cfile))
+		return (NULL);
+	return (s);
+}
+
+int
+parse_ip_addr(FILE *cfile, struct iaddr *addr)
+{
+	addr->len = 4;
+	if (parse_numeric_aggregate(cfile, addr->iabuf,
+	    &addr->len, DOT, 10, 8))
+		return (1);
+	return (0);
+}
+
+/*
+ * hardware-parameter :== HARDWARE ETHERNET csns SEMI
+ * csns :== NUMBER | csns COLON NUMBER
+ */
+void
+parse_hardware_param(FILE *cfile, struct hardware *hardware)
+{
+	unsigned char *t;
+	int token, hlen;
+	char *val;
+
+	token = next_token(&val, cfile);
+	switch (token) {
+	case ETHERNET:
+		hardware->htype = HTYPE_ETHER;
+		break;
+	case TOKEN_RING:
+		hardware->htype = HTYPE_IEEE802;
+		break;
+	case FDDI:
+		hardware->htype = HTYPE_FDDI;
+		break;
+	default:
+		parse_warn("expecting a network hardware type");
+		skip_to_semi(cfile);
+		return;
+	}
+
+	/*
+	 * Parse the hardware address information.   Technically, it
+	 * would make a lot of sense to restrict the length of the data
+	 * we'll accept here to the length of a particular hardware
+	 * address type.   Unfortunately, there are some broken clients
+	 * out there that put bogus data in the chaddr buffer, and we
+	 * accept that data in the lease file rather than simply failing
+	 * on such clients.   Yuck.
+	 */
+	hlen = 0;
+	t = parse_numeric_aggregate(cfile, NULL, &hlen, COLON, 16, 8);
+	if (!t)
+		return;
+	if (hlen > sizeof(hardware->haddr)) {
+		free(t);
+		parse_warn("hardware address too long");
+	} else {
+		hardware->hlen = hlen;
+		memcpy((unsigned char *)&hardware->haddr[0], t,
+		    hardware->hlen);
+		if (hlen < sizeof(hardware->haddr))
+			memset(&hardware->haddr[hlen], 0,
+			    sizeof(hardware->haddr) - hlen);
+		free(t);
+	}
+
+	token = next_token(&val, cfile);
+	if (token != SEMI) {
+		parse_warn("expecting semicolon.");
+		skip_to_semi(cfile);
+	}
+}
+
+/*
+ * lease-time :== NUMBER SEMI
+ */
+void
+parse_lease_time(FILE *cfile, time_t *timep)
+{
+	char *val;
+	int token;
+
+	token = next_token(&val, cfile);
+	if (token != NUMBER) {
+		parse_warn("Expecting numeric lease time");
+		skip_to_semi(cfile);
+		return;
+	}
+	convert_num((unsigned char *)timep, val, 10, 32);
+	/* Unswap the number - convert_num returns stuff in NBO. */
+	*timep = ntohl(*timep); /* XXX */
+
+	parse_semi(cfile);
+}
+
+/*
+ * No BNF for numeric aggregates - that's defined by the caller.  What
+ * this function does is to parse a sequence of numbers separated by the
+ * token specified in separator.  If max is zero, any number of numbers
+ * will be parsed; otherwise, exactly max numbers are expected.  Base
+ * and size tell us how to internalize the numbers once they've been
+ * tokenized.
+ */
+unsigned char *
+parse_numeric_aggregate(FILE *cfile, unsigned char *buf, int *max,
+    int separator, int base, int size)
+{
+	unsigned char *bufp = buf, *s = NULL;
+	int token, count = 0;
+	char *val, *t;
+	pair c = NULL;
+
+	if (!bufp && *max) {
+		bufp = malloc(*max * size / 8);
+		if (!bufp)
+			error("can't allocate space for numeric aggregate");
+	} else
+		s = bufp;
+
+	do {
+		if (count) {
+			token = peek_token(&val, cfile);
+			if (token != separator) {
+				if (!*max)
+					break;
+				if (token != RBRACE && token != LBRACE)
+					token = next_token(&val, cfile);
+				parse_warn("too few numbers.");
+				if (token != SEMI)
+					skip_to_semi(cfile);
+				return (NULL);
+			}
+			token = next_token(&val, cfile);
+		}
+		token = next_token(&val, cfile);
+
+		if (token == EOF) {
+			parse_warn("unexpected end of file");
+			break;
+		}
+
+		/* Allow NUMBER_OR_NAME if base is 16. */
+		if (token != NUMBER &&
+		    (base != 16 || token != NUMBER_OR_NAME)) {
+			parse_warn("expecting numeric value.");
+			skip_to_semi(cfile);
+			return (NULL);
+		}
+		/*
+		 * If we can, convert the number now; otherwise, build a
+		 * linked list of all the numbers.
+		 */
+		if (s) {
+			convert_num(s, val, base, size);
+			s += size / 8;
+		} else {
+			t = malloc(strlen(val) + 1);
+			if (!t)
+				error("no temp space for number.");
+			strlcpy(t, val, strlen(val) + 1);
+			c = cons(t, c);
+		}
+	} while (++count != *max);
+
+	/* If we had to cons up a list, convert it now. */
+	if (c) {
+		bufp = malloc(count * size / 8);
+		if (!bufp)
+			error("can't allocate space for numeric aggregate.");
+		s = bufp + count - size / 8;
+		*max = count;
+	}
+	while (c) {
+		pair cdr = c->cdr;
+		convert_num(s, (char *)c->car, base, size);
+		s -= size / 8;
+		/* Free up temp space. */
+		free(c->car);
+		free(c);
+		c = cdr;
+	}
+	return (bufp);
+}
+
+void
+convert_num(unsigned char *buf, char *str, int base, int size)
+{
+	int negative = 0, tval, max;
+	u_int32_t val = 0;
+	char *ptr = str;
+
+	if (*ptr == '-') {
+		negative = 1;
+		ptr++;
+	}
+
+	/* If base wasn't specified, figure it out from the data. */
+	if (!base) {
+		if (ptr[0] == '0') {
+			if (ptr[1] == 'x') {
+				base = 16;
+				ptr += 2;
+			} else if (isascii(ptr[1]) && isdigit(ptr[1])) {
+				base = 8;
+				ptr += 1;
+			} else
+				base = 10;
+		} else
+			base = 10;
+	}
+
+	do {
+		tval = *ptr++;
+		/* XXX assumes ASCII... */
+		if (tval >= 'a')
+			tval = tval - 'a' + 10;
+		else if (tval >= 'A')
+			tval = tval - 'A' + 10;
+		else if (tval >= '0')
+			tval -= '0';
+		else {
+			warning("Bogus number: %s.", str);
+			break;
+		}
+		if (tval >= base) {
+			warning("Bogus number: %s: digit %d not in base %d",
+			    str, tval, base);
+			break;
+		}
+		val = val * base + tval;
+	} while (*ptr);
+
+	if (negative)
+		max = (1 << (size - 1));
+	else
+		max = (1 << (size - 1)) + ((1 << (size - 1)) - 1);
+	if (val > max) {
+		switch (base) {
+		case 8:
+			warning("value %s%o exceeds max (%d) for precision.",
+			    negative ? "-" : "", val, max);
+			break;
+		case 16:
+			warning("value %s%x exceeds max (%d) for precision.",
+			    negative ? "-" : "", val, max);
+			break;
+		default:
+			warning("value %s%u exceeds max (%d) for precision.",
+			    negative ? "-" : "", val, max);
+			break;
+		}
+	}
+
+	if (negative)
+		switch (size) {
+		case 8:
+			*buf = -(unsigned long)val;
+			break;
+		case 16:
+			putShort(buf, -(unsigned long)val);
+			break;
+		case 32:
+			putLong(buf, -(unsigned long)val);
+			break;
+		default:
+			warning("Unexpected integer size: %d", size);
+			break;
+		}
+	else
+		switch (size) {
+		case 8:
+			*buf = (u_int8_t)val;
+			break;
+		case 16:
+			putUShort(buf, (u_int16_t)val);
+			break;
+		case 32:
+			putULong(buf, val);
+			break;
+		default:
+			warning("Unexpected integer size: %d", size);
+			break;
+		}
+}
+
+/*
+ * date :== NUMBER NUMBER SLASH NUMBER SLASH NUMBER
+ *		NUMBER COLON NUMBER COLON NUMBER SEMI
+ *
+ * Dates are always in GMT; first number is day of week; next is
+ * year/month/day; next is hours:minutes:seconds on a 24-hour
+ * clock.
+ */
+time_t
+parse_date(FILE *cfile)
+{
+	static int months[11] = { 31, 59, 90, 120, 151, 181,
+	    212, 243, 273, 304, 334 };
+	int guess, token;
+	struct tm tm;
+	char *val;
+
+	/* Day of week... */
+	token = next_token(&val, cfile);
+	if (token != NUMBER) {
+		parse_warn("numeric day of week expected.");
+		if (token != SEMI)
+			skip_to_semi(cfile);
+		return (0);
+	}
+	tm.tm_wday = atoi(val);
+
+	/* Year... */
+	token = next_token(&val, cfile);
+	if (token != NUMBER) {
+		parse_warn("numeric year expected.");
+		if (token != SEMI)
+			skip_to_semi(cfile);
+		return (0);
+	}
+	tm.tm_year = atoi(val);
+	if (tm.tm_year > 1900)
+		tm.tm_year -= 1900;
+
+	/* Slash separating year from month... */
+	token = next_token(&val, cfile);
+	if (token != SLASH) {
+		parse_warn("expected slash separating year from month.");
+		if (token != SEMI)
+			skip_to_semi(cfile);
+		return (0);
+	}
+
+	/* Month... */
+	token = next_token(&val, cfile);
+	if (token != NUMBER) {
+		parse_warn("numeric month expected.");
+		if (token != SEMI)
+			skip_to_semi(cfile);
+		return (0);
+	}
+	tm.tm_mon = atoi(val) - 1;
+
+	/* Slash separating month from day... */
+	token = next_token(&val, cfile);
+	if (token != SLASH) {
+		parse_warn("expected slash separating month from day.");
+		if (token != SEMI)
+			skip_to_semi(cfile);
+		return (0);
+	}
+
+	/* Month... */
+	token = next_token(&val, cfile);
+	if (token != NUMBER) {
+		parse_warn("numeric day of month expected.");
+		if (token != SEMI)
+			skip_to_semi(cfile);
+		return (0);
+	}
+	tm.tm_mday = atoi(val);
+
+	/* Hour... */
+	token = next_token(&val, cfile);
+	if (token != NUMBER) {
+		parse_warn("numeric hour expected.");
+		if (token != SEMI)
+			skip_to_semi(cfile);
+		return (0);
+	}
+	tm.tm_hour = atoi(val);
+
+	/* Colon separating hour from minute... */
+	token = next_token(&val, cfile);
+	if (token != COLON) {
+		parse_warn("expected colon separating hour from minute.");
+		if (token != SEMI)
+			skip_to_semi(cfile);
+		return (0);
+	}
+
+	/* Minute... */
+	token = next_token(&val, cfile);
+	if (token != NUMBER) {
+		parse_warn("numeric minute expected.");
+		if (token != SEMI)
+			skip_to_semi(cfile);
+		return (0);
+	}
+	tm.tm_min = atoi(val);
+
+	/* Colon separating minute from second... */
+	token = next_token(&val, cfile);
+	if (token != COLON) {
+		parse_warn("expected colon separating hour from minute.");
+		if (token != SEMI)
+			skip_to_semi(cfile);
+		return (0);
+	}
+
+	/* Minute... */
+	token = next_token(&val, cfile);
+	if (token != NUMBER) {
+		parse_warn("numeric minute expected.");
+		if (token != SEMI)
+			skip_to_semi(cfile);
+		return (0);
+	}
+	tm.tm_sec = atoi(val);
+	tm.tm_isdst = 0;
+
+	/* XXX: We assume that mktime does not use tm_yday. */
+	tm.tm_yday = 0;
+
+	/* Make sure the date ends in a semicolon... */
+	token = next_token(&val, cfile);
+	if (token != SEMI) {
+		parse_warn("semicolon expected.");
+		skip_to_semi(cfile);
+		return (0);
+	}
+
+	/* Guess the time value... */
+	guess = ((((((365 * (tm.tm_year - 70) +	/* Days in years since '70 */
+		    (tm.tm_year - 69) / 4 +	/* Leap days since '70 */
+		    (tm.tm_mon			/* Days in months this year */
+		    ? months[tm.tm_mon - 1]
+		    : 0) +
+		    (tm.tm_mon > 1 &&		/* Leap day this year */
+		    !((tm.tm_year - 72) & 3)) +
+		    tm.tm_mday - 1) * 24) +	/* Day of month */
+		    tm.tm_hour) * 60) +
+		    tm.tm_min) * 60) + tm.tm_sec;
+
+	/*
+	 * This guess could be wrong because of leap seconds or other
+	 * weirdness we don't know about that the system does.   For
+	 * now, we're just going to accept the guess, but at some point
+	 * it might be nice to do a successive approximation here to get
+	 * an exact value.   Even if the error is small, if the server
+	 * is restarted frequently (and thus the lease database is
+	 * reread), the error could accumulate into something
+	 * significant.
+	 */
+	return (guess);
+}
diff --git a/freebsd-userspace/commands/sbin/dhclient/privsep.c b/freebsd-userspace/commands/sbin/dhclient/privsep.c
new file mode 100644
index 0000000..b42572f
--- /dev/null
+++ b/freebsd-userspace/commands/sbin/dhclient/privsep.c
@@ -0,0 +1,238 @@
+/*	$OpenBSD: privsep.c,v 1.7 2004/05/10 18:34:42 deraadt Exp $ */
+
+/*
+ * Copyright (c) 2004 Henning Brauer <henning at openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE, ABUSE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "dhcpd.h"
+#include "privsep.h"
+
+struct buf *
+buf_open(size_t len)
+{
+	struct buf	*buf;
+
+	if ((buf = calloc(1, sizeof(struct buf))) == NULL)
+		return (NULL);
+	if ((buf->buf = malloc(len)) == NULL) {
+		free(buf);
+		return (NULL);
+	}
+	buf->size = len;
+
+	return (buf);
+}
+
+int
+buf_add(struct buf *buf, void *data, size_t len)
+{
+	if (buf->wpos + len > buf->size)
+		return (-1);
+
+	memcpy(buf->buf + buf->wpos, data, len);
+	buf->wpos += len;
+	return (0);
+}
+
+int
+buf_close(int sock, struct buf *buf)
+{
+	ssize_t	n;
+
+	do {
+		n = write(sock, buf->buf + buf->rpos, buf->size - buf->rpos);
+		if (n != -1)
+			buf->rpos += n;
+		if (n == 0) {			/* connection closed */
+			errno = 0;
+			return (-1);
+		}
+	} while (n == -1 && (errno == EAGAIN || errno == EINTR));
+
+	if (buf->rpos < buf->size)
+		error("short write: wanted %lu got %ld bytes",
+		    (unsigned long)buf->size, (long)buf->rpos);
+
+	free(buf->buf);
+	free(buf);
+	return (n);
+}
+
+ssize_t
+buf_read(int sock, void *buf, size_t nbytes)
+{
+	ssize_t	n, r = 0;
+	char *p = buf;
+
+	do {
+		n = read(sock, p, nbytes);
+		if (n == 0)
+			error("connection closed");
+		if (n != -1) {
+			r += n;
+			p += n;
+			nbytes -= n;
+		}
+	} while (n == -1 && (errno == EINTR || errno == EAGAIN));
+
+	if (n == -1)
+		error("buf_read: %m");
+
+	if (r < nbytes)
+		error("short read: wanted %lu got %ld bytes",
+		    (unsigned long)nbytes, (long)r);
+
+	return (r);
+}
+
+void
+dispatch_imsg(int fd)
+{
+	struct imsg_hdr		 hdr;
+	char			*medium, *reason, *filename,
+				*servername, *prefix;
+	size_t			 medium_len, reason_len, filename_len,
+				 servername_len, prefix_len, totlen;
+	struct client_lease	 lease;
+	int			 ret, i, optlen;
+	struct buf		*buf;
+
+	buf_read(fd, &hdr, sizeof(hdr));
+
+	switch (hdr.code) {
+	case IMSG_SCRIPT_INIT:
+		if (hdr.len < sizeof(hdr) + sizeof(size_t))
+			error("corrupted message received");
+		buf_read(fd, &medium_len, sizeof(medium_len));
+		if (hdr.len < medium_len + sizeof(size_t) + sizeof(hdr)
+		    + sizeof(size_t) || medium_len == SIZE_T_MAX)
+			error("corrupted message received");
+		if (medium_len > 0) {
+			if ((medium = calloc(1, medium_len + 1)) == NULL)
+				error("%m");
+			buf_read(fd, medium, medium_len);
+		} else
+			medium = NULL;
+
+		buf_read(fd, &reason_len, sizeof(reason_len));
+		if (hdr.len < medium_len + reason_len + sizeof(hdr) ||
+		    reason_len == SIZE_T_MAX)
+			error("corrupted message received");
+		if (reason_len > 0) {
+			if ((reason = calloc(1, reason_len + 1)) == NULL)
+				error("%m");
+			buf_read(fd, reason, reason_len);
+		} else
+			reason = NULL;
+
+		priv_script_init(reason, medium);
+		free(reason);
+		free(medium);
+		break;
+	case IMSG_SCRIPT_WRITE_PARAMS:
+		bzero(&lease, sizeof lease);
+		totlen = sizeof(hdr) + sizeof(lease) + sizeof(size_t);
+		if (hdr.len < totlen)
+			error("corrupted message received");
+		buf_read(fd, &lease, sizeof(lease));
+
+		buf_read(fd, &filename_len, sizeof(filename_len));
+		totlen += filename_len + sizeof(size_t);
+		if (hdr.len < totlen || filename_len == SIZE_T_MAX)
+			error("corrupted message received");
+		if (filename_len > 0) {
+			if ((filename = calloc(1, filename_len + 1)) == NULL)
+				error("%m");
+			buf_read(fd, filename, filename_len);
+		} else
+			filename = NULL;
+
+		buf_read(fd, &servername_len, sizeof(servername_len));
+		totlen += servername_len + sizeof(size_t);
+		if (hdr.len < totlen || servername_len == SIZE_T_MAX)
+			error("corrupted message received");
+		if (servername_len > 0) {
+			if ((servername =
+			    calloc(1, servername_len + 1)) == NULL)
+				error("%m");
+			buf_read(fd, servername, servername_len);
+		} else
+			servername = NULL;
+
+		buf_read(fd, &prefix_len, sizeof(prefix_len));
+		totlen += prefix_len;
+		if (hdr.len < totlen || prefix_len == SIZE_T_MAX)
+			error("corrupted message received");
+		if (prefix_len > 0) {
+			if ((prefix = calloc(1, prefix_len + 1)) == NULL)
+				error("%m");
+			buf_read(fd, prefix, prefix_len);
+		} else
+			prefix = NULL;
+
+		for (i = 0; i < 256; i++) {
+			totlen += sizeof(optlen);
+			if (hdr.len < totlen)
+				error("corrupted message received");
+			buf_read(fd, &optlen, sizeof(optlen));
+			lease.options[i].data = NULL;
+			lease.options[i].len = optlen;
+			if (optlen > 0) {
+				totlen += optlen;
+				if (hdr.len < totlen || optlen == SIZE_T_MAX)
+					error("corrupted message received");
+				lease.options[i].data =
+				    calloc(1, optlen + 1);
+				if (lease.options[i].data == NULL)
+				    error("%m");
+				buf_read(fd, lease.options[i].data, optlen);
+			}
+		}
+		lease.server_name = servername;
+		lease.filename = filename;
+
+		priv_script_write_params(prefix, &lease);
+
+		free(servername);
+		free(filename);
+		free(prefix);
+		for (i = 0; i < 256; i++)
+			if (lease.options[i].len > 0)
+				free(lease.options[i].data);
+		break;
+	case IMSG_SCRIPT_GO:
+		if (hdr.len != sizeof(hdr))
+			error("corrupted message received");
+
+		ret = priv_script_go();
+
+		hdr.code = IMSG_SCRIPT_GO_RET;
+		hdr.len = sizeof(struct imsg_hdr) + sizeof(int);
+		if ((buf = buf_open(hdr.len)) == NULL)
+			error("buf_open: %m");
+		if (buf_add(buf, &hdr, sizeof(hdr)))
+			error("buf_add: %m");
+		if (buf_add(buf, &ret, sizeof(ret)))
+			error("buf_add: %m");
+		if (buf_close(fd, buf) == -1)
+			error("buf_close: %m");
+		break;
+	default:
+		error("received unknown message, code %d", hdr.code);
+	}
+}
diff --git a/freebsd-userspace/commands/sbin/dhclient/privsep.h b/freebsd-userspace/commands/sbin/dhclient/privsep.h
new file mode 100644
index 0000000..f30284e
--- /dev/null
+++ b/freebsd-userspace/commands/sbin/dhclient/privsep.h
@@ -0,0 +1,47 @@
+/*	$OpenBSD: privsep.h,v 1.2 2004/05/04 18:51:18 henning Exp $ */
+
+/*
+ * Copyright (c) 2004 Henning Brauer <henning at openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE, ABUSE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+
+#include <poll.h>
+#include <pwd.h>
+
+struct buf {
+	u_char			*buf;
+	size_t			 size;
+	size_t			 wpos;
+	size_t			 rpos;
+};
+
+enum imsg_code {
+	IMSG_NONE,
+	IMSG_SCRIPT_INIT,
+	IMSG_SCRIPT_WRITE_PARAMS,
+	IMSG_SCRIPT_GO,
+	IMSG_SCRIPT_GO_RET
+};
+
+struct imsg_hdr {
+	enum imsg_code	code;
+	size_t		len;
+};
+
+struct buf	*buf_open(size_t);
+int		 buf_add(struct buf *, void *, size_t);
+int		 buf_close(int, struct buf *);
+ssize_t		 buf_read(int sock, void *, size_t);
diff --git a/freebsd-userspace/commands/sbin/dhclient/tables.c b/freebsd-userspace/commands/sbin/dhclient/tables.c
new file mode 100644
index 0000000..81a9acc
--- /dev/null
+++ b/freebsd-userspace/commands/sbin/dhclient/tables.c
@@ -0,0 +1,446 @@
+/*	$OpenBSD: tables.c,v 1.4 2004/05/04 20:28:40 deraadt Exp $	*/
+
+/* Tables of information... */
+
+/*
+ * Copyright (c) 1995, 1996 The Internet Software Consortium.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of The Internet Software Consortium nor the names
+ *    of its contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM 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 INTERNET SOFTWARE CONSORTIUM 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 software has been written for the Internet Software Consortium
+ * by Ted Lemon <mellon at fugue.com> in cooperation with Vixie
+ * Enterprises.  To learn more about the Internet Software Consortium,
+ * see ``http://www.vix.com/isc''.  To learn more about Vixie
+ * Enterprises, see ``http://www.vix.com''.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "dhcpd.h"
+
+/*
+ * DHCP Option names, formats and codes, from RFC1533.
+ *
+ * Format codes:
+ *
+ * e - end of data
+ * I - IP address
+ * l - 32-bit signed integer
+ * L - 32-bit unsigned integer
+ * s - 16-bit signed integer
+ * S - 16-bit unsigned integer
+ * b - 8-bit signed integer
+ * B - 8-bit unsigned integer
+ * t - ASCII text
+ * f - flag (true or false)
+ * A - array of whatever precedes (e.g., IA means array of IP addresses)
+ */
+
+struct universe dhcp_universe;
+struct option dhcp_options[256] = {
+	{ "pad", "",					&dhcp_universe, 0 },
+	{ "subnet-mask", "I",				&dhcp_universe, 1 },
+	{ "time-offset", "l",				&dhcp_universe, 2 },
+	{ "routers", "IA",				&dhcp_universe, 3 },
+	{ "time-servers", "IA",				&dhcp_universe, 4 },
+	{ "ien116-name-servers", "IA",			&dhcp_universe, 5 },
+	{ "domain-name-servers", "IA",			&dhcp_universe, 6 },
+	{ "log-servers", "IA",				&dhcp_universe, 7 },
+	{ "cookie-servers", "IA",			&dhcp_universe, 8 },
+	{ "lpr-servers", "IA",				&dhcp_universe, 9 },
+	{ "impress-servers", "IA",			&dhcp_universe, 10 },
+	{ "resource-location-servers", "IA",		&dhcp_universe, 11 },
+	{ "host-name", "t",				&dhcp_universe, 12 },
+	{ "boot-size", "S",				&dhcp_universe, 13 },
+	{ "merit-dump", "t",				&dhcp_universe, 14 },
+	{ "domain-name", "t",				&dhcp_universe, 15 },
+	{ "swap-server", "I",				&dhcp_universe, 16 },
+	{ "root-path", "t",				&dhcp_universe, 17 },
+	{ "extensions-path", "t",			&dhcp_universe, 18 },
+	{ "ip-forwarding", "f",				&dhcp_universe, 19 },
+	{ "non-local-source-routing", "f",		&dhcp_universe, 20 },
+	{ "policy-filter", "IIA",			&dhcp_universe, 21 },
+	{ "max-dgram-reassembly", "S",			&dhcp_universe, 22 },
+	{ "default-ip-ttl", "B",			&dhcp_universe, 23 },
+	{ "path-mtu-aging-timeout", "L",		&dhcp_universe, 24 },
+	{ "path-mtu-plateau-table", "SA",		&dhcp_universe, 25 },
+	{ "interface-mtu", "S",				&dhcp_universe, 26 },
+	{ "all-subnets-local", "f",			&dhcp_universe, 27 },
+	{ "broadcast-address", "I",			&dhcp_universe, 28 },
+	{ "perform-mask-discovery", "f",		&dhcp_universe, 29 },
+	{ "mask-supplier", "f",				&dhcp_universe, 30 },
+	{ "router-discovery", "f",			&dhcp_universe, 31 },
+	{ "router-solicitation-address", "I",		&dhcp_universe, 32 },
+	{ "static-routes", "IIA",			&dhcp_universe, 33 },
+	{ "trailer-encapsulation", "f",			&dhcp_universe, 34 },
+	{ "arp-cache-timeout", "L",			&dhcp_universe, 35 },
+	{ "ieee802-3-encapsulation", "f",		&dhcp_universe, 36 },
+	{ "default-tcp-ttl", "B",			&dhcp_universe, 37 },
+	{ "tcp-keepalive-interval", "L",		&dhcp_universe, 38 },
+	{ "tcp-keepalive-garbage", "f",			&dhcp_universe, 39 },
+	{ "nis-domain", "t",				&dhcp_universe, 40 },
+	{ "nis-servers", "IA",				&dhcp_universe, 41 },
+	{ "ntp-servers", "IA",				&dhcp_universe, 42 },
+	{ "vendor-encapsulated-options", "X",		&dhcp_universe, 43 },
+	{ "netbios-name-servers", "IA",			&dhcp_universe, 44 },
+	{ "netbios-dd-server", "IA",			&dhcp_universe, 45 },
+	{ "netbios-node-type", "B",			&dhcp_universe, 46 },
+	{ "netbios-scope", "t",				&dhcp_universe, 47 },
+	{ "font-servers", "IA",				&dhcp_universe, 48 },
+	{ "x-display-manager", "IA",			&dhcp_universe, 49 },
+	{ "dhcp-requested-address", "I",		&dhcp_universe, 50 },
+	{ "dhcp-lease-time", "L",			&dhcp_universe, 51 },
+	{ "dhcp-option-overload", "B",			&dhcp_universe, 52 },
+	{ "dhcp-message-type", "B",			&dhcp_universe, 53 },
+	{ "dhcp-server-identifier", "I",		&dhcp_universe, 54 },
+	{ "dhcp-parameter-request-list", "BA",		&dhcp_universe, 55 },
+	{ "dhcp-message", "t",				&dhcp_universe, 56 },
+	{ "dhcp-max-message-size", "S",			&dhcp_universe, 57 },
+	{ "dhcp-renewal-time", "L",			&dhcp_universe, 58 },
+	{ "dhcp-rebinding-time", "L",			&dhcp_universe, 59 },
+	{ "dhcp-class-identifier", "t",			&dhcp_universe, 60 },
+	{ "dhcp-client-identifier", "X",		&dhcp_universe, 61 },
+	{ "option-62", "X",				&dhcp_universe, 62 },
+	{ "option-63", "X",				&dhcp_universe, 63 },
+	{ "nisplus-domain", "t",			&dhcp_universe, 64 },
+	{ "nisplus-servers", "IA",			&dhcp_universe, 65 },
+	{ "tftp-server-name", "t",			&dhcp_universe, 66 },
+	{ "bootfile-name", "t",				&dhcp_universe, 67 },
+	{ "mobile-ip-home-agent", "IA",			&dhcp_universe, 68 },
+	{ "smtp-server", "IA",				&dhcp_universe, 69 },
+	{ "pop-server", "IA",				&dhcp_universe, 70 },
+	{ "nntp-server", "IA",				&dhcp_universe, 71 },
+	{ "www-server", "IA",				&dhcp_universe, 72 },
+	{ "finger-server", "IA",			&dhcp_universe, 73 },
+	{ "irc-server", "IA",				&dhcp_universe, 74 },
+	{ "streettalk-server", "IA",			&dhcp_universe, 75 },
+	{ "streettalk-directory-assistance-server", "IA", &dhcp_universe, 76 },
+	{ "user-class", "t",				&dhcp_universe, 77 },
+	{ "option-78", "X",				&dhcp_universe, 78 },
+	{ "option-79", "X",				&dhcp_universe, 79 },
+	{ "option-80", "X",				&dhcp_universe, 80 },
+	{ "option-81", "X",				&dhcp_universe, 81 },
+	{ "option-82", "X",				&dhcp_universe, 82 },
+	{ "option-83", "X",				&dhcp_universe, 83 },
+	{ "option-84", "X",				&dhcp_universe, 84 },
+	{ "nds-servers", "IA",				&dhcp_universe, 85 },
+	{ "nds-tree-name", "X",				&dhcp_universe, 86 },
+	{ "nds-context", "X",				&dhcp_universe, 87 },
+	{ "option-88", "X",				&dhcp_universe, 88 },
+	{ "option-89", "X",				&dhcp_universe, 89 },
+	{ "option-90", "X",				&dhcp_universe, 90 },
+	{ "option-91", "X",				&dhcp_universe, 91 },
+	{ "option-92", "X",				&dhcp_universe, 92 },
+	{ "option-93", "X",				&dhcp_universe, 93 },
+	{ "option-94", "X",				&dhcp_universe, 94 },
+	{ "option-95", "X",				&dhcp_universe, 95 },
+	{ "option-96", "X",				&dhcp_universe, 96 },
+	{ "option-97", "X",				&dhcp_universe, 97 },
+	{ "option-98", "X",				&dhcp_universe, 98 },
+	{ "option-99", "X",				&dhcp_universe, 99 },
+	{ "option-100", "X",				&dhcp_universe, 100 },
+	{ "option-101", "X",				&dhcp_universe, 101 },
+	{ "option-102", "X",				&dhcp_universe, 102 },
+	{ "option-103", "X",				&dhcp_universe, 103 },
+	{ "option-104", "X",				&dhcp_universe, 104 },
+	{ "option-105", "X",				&dhcp_universe, 105 },
+	{ "option-106", "X",				&dhcp_universe, 106 },
+	{ "option-107", "X",				&dhcp_universe, 107 },
+	{ "option-108", "X",				&dhcp_universe, 108 },
+	{ "option-109", "X",				&dhcp_universe, 109 },
+	{ "option-110", "X",				&dhcp_universe, 110 },
+	{ "option-111", "X",				&dhcp_universe, 111 },
+	{ "option-112", "X",				&dhcp_universe, 112 },
+	{ "option-113", "X",				&dhcp_universe, 113 },
+	{ "option-114", "X",				&dhcp_universe, 114 },
+	{ "option-115", "X",				&dhcp_universe, 115 },
+	{ "option-116", "X",				&dhcp_universe, 116 },
+	{ "option-117", "X",				&dhcp_universe, 117 },
+	{ "option-118", "X",				&dhcp_universe, 118 },
+	{ "option-119", "X",				&dhcp_universe, 119 },
+	{ "option-120", "X",				&dhcp_universe, 120 },
+	{ "classless-routes", "BA",			&dhcp_universe, 121 },
+	{ "option-122", "X",				&dhcp_universe, 122 },
+	{ "option-123", "X",				&dhcp_universe, 123 },
+	{ "option-124", "X",				&dhcp_universe, 124 },
+	{ "option-125", "X",				&dhcp_universe, 125 },
+	{ "option-126", "X",				&dhcp_universe, 126 },
+	{ "option-127", "X",				&dhcp_universe, 127 },
+	{ "option-128", "X",				&dhcp_universe, 128 },
+	{ "option-129", "X",				&dhcp_universe, 129 },
+	{ "option-130", "X",				&dhcp_universe, 130 },
+	{ "option-131", "X",				&dhcp_universe, 131 },
+	{ "option-132", "X",				&dhcp_universe, 132 },
+	{ "option-133", "X",				&dhcp_universe, 133 },
+	{ "option-134", "X",				&dhcp_universe, 134 },
+	{ "option-135", "X",				&dhcp_universe, 135 },
+	{ "option-136", "X",				&dhcp_universe, 136 },
+	{ "option-137", "X",				&dhcp_universe, 137 },
+	{ "option-138", "X",				&dhcp_universe, 138 },
+	{ "option-139", "X",				&dhcp_universe, 139 },
+	{ "option-140", "X",				&dhcp_universe, 140 },
+	{ "option-141", "X",				&dhcp_universe, 141 },
+	{ "option-142", "X",				&dhcp_universe, 142 },
+	{ "option-143", "X",				&dhcp_universe, 143 },
+	{ "option-144", "X",				&dhcp_universe, 144 },
+	{ "option-145", "X",				&dhcp_universe, 145 },
+	{ "option-146", "X",				&dhcp_universe, 146 },
+	{ "option-147", "X",				&dhcp_universe, 147 },
+	{ "option-148", "X",				&dhcp_universe, 148 },
+	{ "option-149", "X",				&dhcp_universe, 149 },
+	{ "option-150", "X",				&dhcp_universe, 150 },
+	{ "option-151", "X",				&dhcp_universe, 151 },
+	{ "option-152", "X",				&dhcp_universe, 152 },
+	{ "option-153", "X",				&dhcp_universe, 153 },
+	{ "option-154", "X",				&dhcp_universe, 154 },
+	{ "option-155", "X",				&dhcp_universe, 155 },
+	{ "option-156", "X",				&dhcp_universe, 156 },
+	{ "option-157", "X",				&dhcp_universe, 157 },
+	{ "option-158", "X",				&dhcp_universe, 158 },
+	{ "option-159", "X",				&dhcp_universe, 159 },
+	{ "option-160", "X",				&dhcp_universe, 160 },
+	{ "option-161", "X",				&dhcp_universe, 161 },
+	{ "option-162", "X",				&dhcp_universe, 162 },
+	{ "option-163", "X",				&dhcp_universe, 163 },
+	{ "option-164", "X",				&dhcp_universe, 164 },
+	{ "option-165", "X",				&dhcp_universe, 165 },
+	{ "option-166", "X",				&dhcp_universe, 166 },
+	{ "option-167", "X",				&dhcp_universe, 167 },
+	{ "option-168", "X",				&dhcp_universe, 168 },
+	{ "option-169", "X",				&dhcp_universe, 169 },
+	{ "option-170", "X",				&dhcp_universe, 170 },
+	{ "option-171", "X",				&dhcp_universe, 171 },
+	{ "option-172", "X",				&dhcp_universe, 172 },
+	{ "option-173", "X",				&dhcp_universe, 173 },
+	{ "option-174", "X",				&dhcp_universe, 174 },
+	{ "option-175", "X",				&dhcp_universe, 175 },
+	{ "option-176", "X",				&dhcp_universe, 176 },
+	{ "option-177", "X",				&dhcp_universe, 177 },
+	{ "option-178", "X",				&dhcp_universe, 178 },
+	{ "option-179", "X",				&dhcp_universe, 179 },
+	{ "option-180", "X",				&dhcp_universe, 180 },
+	{ "option-181", "X",				&dhcp_universe, 181 },
+	{ "option-182", "X",				&dhcp_universe, 182 },
+	{ "option-183", "X",				&dhcp_universe, 183 },
+	{ "option-184", "X",				&dhcp_universe, 184 },
+	{ "option-185", "X",				&dhcp_universe, 185 },
+	{ "option-186", "X",				&dhcp_universe, 186 },
+	{ "option-187", "X",				&dhcp_universe, 187 },
+	{ "option-188", "X",				&dhcp_universe, 188 },
+	{ "option-189", "X",				&dhcp_universe, 189 },
+	{ "option-190", "X",				&dhcp_universe, 190 },
+	{ "option-191", "X",				&dhcp_universe, 191 },
+	{ "option-192", "X",				&dhcp_universe, 192 },
+	{ "option-193", "X",				&dhcp_universe, 193 },
+	{ "option-194", "X",				&dhcp_universe, 194 },
+	{ "option-195", "X",				&dhcp_universe, 195 },
+	{ "option-196", "X",				&dhcp_universe, 196 },
+	{ "option-197", "X",				&dhcp_universe, 197 },
+	{ "option-198", "X",				&dhcp_universe, 198 },
+	{ "option-199", "X",				&dhcp_universe, 199 },
+	{ "option-200", "X",				&dhcp_universe, 200 },
+	{ "option-201", "X",				&dhcp_universe, 201 },
+	{ "option-202", "X",				&dhcp_universe, 202 },
+	{ "option-203", "X",				&dhcp_universe, 203 },
+	{ "option-204", "X",				&dhcp_universe, 204 },
+	{ "option-205", "X",				&dhcp_universe, 205 },
+	{ "option-206", "X",				&dhcp_universe, 206 },
+	{ "option-207", "X",				&dhcp_universe, 207 },
+	{ "option-208", "X",				&dhcp_universe, 208 },
+	{ "option-209", "X",				&dhcp_universe, 209 },
+	{ "option-210", "X",				&dhcp_universe, 210 },
+	{ "option-211", "X",				&dhcp_universe, 211 },
+	{ "option-212", "X",				&dhcp_universe, 212 },
+	{ "option-213", "X",				&dhcp_universe, 213 },
+	{ "option-214", "X",				&dhcp_universe, 214 },
+	{ "option-215", "X",				&dhcp_universe, 215 },
+	{ "option-216", "X",				&dhcp_universe, 216 },
+	{ "option-217", "X",				&dhcp_universe, 217 },
+	{ "option-218", "X",				&dhcp_universe, 218 },
+	{ "option-219", "X",				&dhcp_universe, 219 },
+	{ "option-220", "X",				&dhcp_universe, 220 },
+	{ "option-221", "X",				&dhcp_universe, 221 },
+	{ "option-222", "X",				&dhcp_universe, 222 },
+	{ "option-223", "X",				&dhcp_universe, 223 },
+	{ "option-224", "X",				&dhcp_universe, 224 },
+	{ "option-225", "X",				&dhcp_universe, 225 },
+	{ "option-226", "X",				&dhcp_universe, 226 },
+	{ "option-227", "X",				&dhcp_universe, 227 },
+	{ "option-228", "X",				&dhcp_universe, 228 },
+	{ "option-229", "X",				&dhcp_universe, 229 },
+	{ "option-230", "X",				&dhcp_universe, 230 },
+	{ "option-231", "X",				&dhcp_universe, 231 },
+	{ "option-232", "X",				&dhcp_universe, 232 },
+	{ "option-233", "X",				&dhcp_universe, 233 },
+	{ "option-234", "X",				&dhcp_universe, 234 },
+	{ "option-235", "X",				&dhcp_universe, 235 },
+	{ "option-236", "X",				&dhcp_universe, 236 },
+	{ "option-237", "X",				&dhcp_universe, 237 },
+	{ "option-238", "X",				&dhcp_universe, 238 },
+	{ "option-239", "X",				&dhcp_universe, 239 },
+	{ "option-240", "X",				&dhcp_universe, 240 },
+	{ "option-241", "X",				&dhcp_universe, 241 },
+	{ "option-242", "X",				&dhcp_universe, 242 },
+	{ "option-243", "X",				&dhcp_universe, 243 },
+	{ "option-244", "X",				&dhcp_universe, 244 },
+	{ "option-245", "X",				&dhcp_universe, 245 },
+	{ "option-246", "X",				&dhcp_universe, 246 },
+	{ "option-247", "X",				&dhcp_universe, 247 },
+	{ "option-248", "X",				&dhcp_universe, 248 },
+	{ "option-249", "X",				&dhcp_universe, 249 },
+	{ "option-250", "X",				&dhcp_universe, 250 },
+	{ "option-251", "X",				&dhcp_universe, 251 },
+	{ "option-252", "X",				&dhcp_universe, 252 },
+	{ "option-253", "X",				&dhcp_universe, 253 },
+	{ "option-254", "X",				&dhcp_universe, 254 },
+	{ "option-end", "e",				&dhcp_universe, 255 },
+};
+
+/*
+ * Default dhcp option priority list (this is ad hoc and should not be
+ * mistaken for a carefully crafted and optimized list).
+ */
+unsigned char dhcp_option_default_priority_list[] = {
+	DHO_DHCP_REQUESTED_ADDRESS,
+	DHO_DHCP_OPTION_OVERLOAD,
+	DHO_DHCP_MAX_MESSAGE_SIZE,
+	DHO_DHCP_RENEWAL_TIME,
+	DHO_DHCP_REBINDING_TIME,
+	DHO_DHCP_CLASS_IDENTIFIER,
+	DHO_DHCP_CLIENT_IDENTIFIER,
+	DHO_SUBNET_MASK,
+	DHO_TIME_OFFSET,
+	DHO_CLASSLESS_ROUTES,
+	DHO_ROUTERS,
+	DHO_TIME_SERVERS,
+	DHO_NAME_SERVERS,
+	DHO_DOMAIN_NAME_SERVERS,
+	DHO_HOST_NAME,
+	DHO_LOG_SERVERS,
+	DHO_COOKIE_SERVERS,
+	DHO_LPR_SERVERS,
+	DHO_IMPRESS_SERVERS,
+	DHO_RESOURCE_LOCATION_SERVERS,
+	DHO_HOST_NAME,
+	DHO_BOOT_SIZE,
+	DHO_MERIT_DUMP,
+	DHO_DOMAIN_NAME,
+	DHO_SWAP_SERVER,
+	DHO_ROOT_PATH,
+	DHO_EXTENSIONS_PATH,
+	DHO_IP_FORWARDING,
+	DHO_NON_LOCAL_SOURCE_ROUTING,
+	DHO_POLICY_FILTER,
+	DHO_MAX_DGRAM_REASSEMBLY,
+	DHO_DEFAULT_IP_TTL,
+	DHO_PATH_MTU_AGING_TIMEOUT,
+	DHO_PATH_MTU_PLATEAU_TABLE,
+	DHO_INTERFACE_MTU,
+	DHO_ALL_SUBNETS_LOCAL,
+	DHO_BROADCAST_ADDRESS,
+	DHO_PERFORM_MASK_DISCOVERY,
+	DHO_MASK_SUPPLIER,
+	DHO_ROUTER_DISCOVERY,
+	DHO_ROUTER_SOLICITATION_ADDRESS,
+	DHO_STATIC_ROUTES,
+	DHO_TRAILER_ENCAPSULATION,
+	DHO_ARP_CACHE_TIMEOUT,
+	DHO_IEEE802_3_ENCAPSULATION,
+	DHO_DEFAULT_TCP_TTL,
+	DHO_TCP_KEEPALIVE_INTERVAL,
+	DHO_TCP_KEEPALIVE_GARBAGE,
+	DHO_NIS_DOMAIN,
+	DHO_NIS_SERVERS,
+	DHO_NTP_SERVERS,
+	DHO_VENDOR_ENCAPSULATED_OPTIONS,
+	DHO_NETBIOS_NAME_SERVERS,
+	DHO_NETBIOS_DD_SERVER,
+	DHO_NETBIOS_NODE_TYPE,
+	DHO_NETBIOS_SCOPE,
+	DHO_FONT_SERVERS,
+	DHO_X_DISPLAY_MANAGER,
+	DHO_DHCP_PARAMETER_REQUEST_LIST,
+	DHO_NISPLUS_DOMAIN,
+	DHO_NISPLUS_SERVERS,
+	DHO_TFTP_SERVER_NAME,
+	DHO_BOOTFILE_NAME,
+	DHO_MOBILE_IP_HOME_AGENT,
+	DHO_SMTP_SERVER,
+	DHO_POP_SERVER,
+	DHO_NNTP_SERVER,
+	DHO_WWW_SERVER,
+	DHO_FINGER_SERVER,
+	DHO_IRC_SERVER,
+	DHO_STREETTALK_SERVER,
+	DHO_STREETTALK_DA_SERVER,
+
+	/* Presently-undefined options... */
+	62, 63, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91,
+	92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105,
+	106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117,
+	118, 119, 120, 122, 123, 124, 125, 126, 127, 128, 129, 130,
+	131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142,
+	143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154,
+	155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166,
+	167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178,
+	179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190,
+	191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202,
+	203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214,
+	215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226,
+	227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238,
+	239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250,
+	251, 252, 253, 254,
+};
+
+int sizeof_dhcp_option_default_priority_list =
+	sizeof(dhcp_option_default_priority_list);
+
+struct hash_table universe_hash;
+
+void
+initialize_universes(void)
+{
+	int i;
+
+	dhcp_universe.name = "dhcp";
+	dhcp_universe.hash = new_hash();
+	if (!dhcp_universe.hash)
+		error("Can't allocate dhcp option hash table.");
+	for (i = 0; i < 256; i++) {
+		dhcp_universe.options[i] = &dhcp_options[i];
+		add_hash(dhcp_universe.hash,
+		    (unsigned char *)dhcp_options[i].name, 0,
+		    (unsigned char *)&dhcp_options[i]);
+	}
+	universe_hash.hash_count = DEFAULT_HASH_SIZE;
+	add_hash(&universe_hash,
+	    (unsigned char *)dhcp_universe.name, 0,
+	    (unsigned char *)&dhcp_universe);
+}
diff --git a/freebsd-userspace/commands/sbin/dhclient/tree.c b/freebsd-userspace/commands/sbin/dhclient/tree.c
new file mode 100644
index 0000000..0ed2919
--- /dev/null
+++ b/freebsd-userspace/commands/sbin/dhclient/tree.c
@@ -0,0 +1,59 @@
+/*	$OpenBSD: tree.c,v 1.13 2004/05/06 22:29:15 deraadt Exp $	*/
+
+/* Routines for manipulating parse trees... */
+
+/*
+ * Copyright (c) 1995, 1996, 1997 The Internet Software Consortium.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of The Internet Software Consortium nor the names
+ *    of its contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM 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 INTERNET SOFTWARE CONSORTIUM 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 software has been written for the Internet Software Consortium
+ * by Ted Lemon <mellon at fugue.com> in cooperation with Vixie
+ * Enterprises.  To learn more about the Internet Software Consortium,
+ * see ``http://www.vix.com/isc''.  To learn more about Vixie
+ * Enterprises, see ``http://www.vix.com''.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "dhcpd.h"
+
+extern int h_errno;
+
+pair
+cons(caddr_t car, pair cdr)
+{
+	pair foo = calloc(1, sizeof(*foo));
+	if (!foo)
+		error("no memory for cons.");
+	foo->car = car;
+	foo->cdr = cdr;
+	return (foo);
+}
diff --git a/freebsd-userspace/commands/sbin/dhclient/tree.h b/freebsd-userspace/commands/sbin/dhclient/tree.h
new file mode 100644
index 0000000..04e08e7
--- /dev/null
+++ b/freebsd-userspace/commands/sbin/dhclient/tree.h
@@ -0,0 +1,66 @@
+/*	$OpenBSD: tree.h,v 1.5 2004/05/06 22:29:15 deraadt Exp $	*/
+
+/* Definitions for address trees... */
+
+/*
+ * Copyright (c) 1995 The Internet Software Consortium.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of The Internet Software Consortium nor the names
+ *    of its contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM 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 INTERNET SOFTWARE CONSORTIUM 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 software has been written for the Internet Software Consortium
+ * by Ted Lemon <mellon at fugue.com> in cooperation with Vixie
+ * Enterprises.  To learn more about the Internet Software Consortium,
+ * see ``http://www.vix.com/isc''.  To learn more about Vixie
+ * Enterprises, see ``http://www.vix.com''.
+ */
+
+/* A pair of pointers, suitable for making a linked list. */
+typedef struct _pair {
+	caddr_t car;
+	struct _pair *cdr;
+} *pair;
+
+struct tree_cache {
+	unsigned char *value;
+	int len;
+	int buf_size;
+	time_t timeout;
+};
+
+struct universe {
+	char *name;
+	struct hash_table *hash;
+	struct option *options[256];
+};
+
+struct option {
+	char *name;
+	char *format;
+	struct universe *universe;
+	unsigned char code;
+};




More information about the vc mailing list