Update isc-dhcp to 3.0.2rc3 using patch infrastructure. vendor/DHCP
authorJoerg Sonnenberger <joerg@dragonflybsd.org>
Tue, 4 Jan 2005 19:58:53 +0000 (19:58 +0000)
committerJoerg Sonnenberger <joerg@dragonflybsd.org>
Tue, 4 Jan 2005 19:58:53 +0000 (19:58 +0000)
Also include the server and relay, but currently without rcNG script.

Submitted-by: Simon 'corecode' Schubert <corecode@fs.ei.tum.de>
150 files changed:
contrib/dhcp-3.0/LICENSE [new file with mode: 0644]
contrib/dhcp-3.0/README [new file with mode: 0644]
contrib/dhcp-3.0/README.DELETED [new file with mode: 0644]
contrib/dhcp-3.0/README.DRAGONFLY [new file with mode: 0644]
contrib/dhcp-3.0/RELNOTES [new file with mode: 0644]
contrib/dhcp-3.0/client/clparse.c [new file with mode: 0644]
contrib/dhcp-3.0/client/dhclient-script.8 [new file with mode: 0644]
contrib/dhcp-3.0/client/dhclient.8 [new file with mode: 0644]
contrib/dhcp-3.0/client/dhclient.c [new file with mode: 0644]
contrib/dhcp-3.0/client/dhclient.conf [new file with mode: 0644]
contrib/dhcp-3.0/client/dhclient.conf.5 [new file with mode: 0644]
contrib/dhcp-3.0/client/dhclient.leases.5 [new file with mode: 0644]
contrib/dhcp-3.0/client/scripts/freebsd [new file with mode: 0644]
contrib/dhcp-3.0/common/alloc.c [new file with mode: 0644]
contrib/dhcp-3.0/common/bpf.c [new file with mode: 0644]
contrib/dhcp-3.0/common/comapi.c [new file with mode: 0644]
contrib/dhcp-3.0/common/conflex.c [new file with mode: 0644]
contrib/dhcp-3.0/common/ctrace.c [new file with mode: 0644]
contrib/dhcp-3.0/common/dhcp-eval.5 [new file with mode: 0644]
contrib/dhcp-3.0/common/dhcp-options.5 [new file with mode: 0644]
contrib/dhcp-3.0/common/discover.c [new file with mode: 0644]
contrib/dhcp-3.0/common/dispatch.c [new file with mode: 0644]
contrib/dhcp-3.0/common/dlpi.c [new file with mode: 0644]
contrib/dhcp-3.0/common/dns.c [new file with mode: 0644]
contrib/dhcp-3.0/common/ethernet.c [new file with mode: 0644]
contrib/dhcp-3.0/common/execute.c [new file with mode: 0644]
contrib/dhcp-3.0/common/fddi.c [new file with mode: 0644]
contrib/dhcp-3.0/common/icmp.c [new file with mode: 0644]
contrib/dhcp-3.0/common/inet.c [new file with mode: 0644]
contrib/dhcp-3.0/common/lpf.c [new file with mode: 0644]
contrib/dhcp-3.0/common/memory.c [new file with mode: 0644]
contrib/dhcp-3.0/common/nit.c [new file with mode: 0644]
contrib/dhcp-3.0/common/options.c [new file with mode: 0644]
contrib/dhcp-3.0/common/packet.c [new file with mode: 0644]
contrib/dhcp-3.0/common/parse.c [new file with mode: 0644]
contrib/dhcp-3.0/common/print.c [new file with mode: 0644]
contrib/dhcp-3.0/common/raw.c [new file with mode: 0644]
contrib/dhcp-3.0/common/resolv.c [new file with mode: 0644]
contrib/dhcp-3.0/common/socket.c [new file with mode: 0644]
contrib/dhcp-3.0/common/tables.c [new file with mode: 0644]
contrib/dhcp-3.0/common/tr.c [new file with mode: 0644]
contrib/dhcp-3.0/common/tree.c [new file with mode: 0644]
contrib/dhcp-3.0/common/upf.c [new file with mode: 0644]
contrib/dhcp-3.0/dhcpctl/callback.c [new file with mode: 0644]
contrib/dhcp-3.0/dhcpctl/dhcpctl.3 [new file with mode: 0644]
contrib/dhcp-3.0/dhcpctl/dhcpctl.c [new file with mode: 0644]
contrib/dhcp-3.0/dhcpctl/dhcpctl.h [new file with mode: 0644]
contrib/dhcp-3.0/dhcpctl/omshell.1 [new file with mode: 0644]
contrib/dhcp-3.0/dhcpctl/omshell.c [new file with mode: 0644]
contrib/dhcp-3.0/dhcpctl/remote.c [new file with mode: 0644]
contrib/dhcp-3.0/dst/base64.c [new file with mode: 0644]
contrib/dhcp-3.0/dst/dst_api.c [new file with mode: 0644]
contrib/dhcp-3.0/dst/dst_internal.h [new file with mode: 0644]
contrib/dhcp-3.0/dst/dst_support.c [new file with mode: 0644]
contrib/dhcp-3.0/dst/hmac_link.c [new file with mode: 0644]
contrib/dhcp-3.0/dst/md5.h [new file with mode: 0644]
contrib/dhcp-3.0/dst/md5_dgst.c [new file with mode: 0644]
contrib/dhcp-3.0/dst/md5_locl.h [new file with mode: 0644]
contrib/dhcp-3.0/dst/prandom.c [new file with mode: 0644]
contrib/dhcp-3.0/includes/arpa/nameser.h [new file with mode: 0644]
contrib/dhcp-3.0/includes/arpa/nameser_compat.h [new file with mode: 0644]
contrib/dhcp-3.0/includes/cdefs.h [new file with mode: 0644]
contrib/dhcp-3.0/includes/cf/freebsd.h [new file with mode: 0644]
contrib/dhcp-3.0/includes/ctrace.h [new file with mode: 0644]
contrib/dhcp-3.0/includes/dhcp.h [new file with mode: 0644]
contrib/dhcp-3.0/includes/dhcpd.h [new file with mode: 0644]
contrib/dhcp-3.0/includes/dhctoken.h [new file with mode: 0644]
contrib/dhcp-3.0/includes/failover.h [new file with mode: 0644]
contrib/dhcp-3.0/includes/inet.h [new file with mode: 0644]
contrib/dhcp-3.0/includes/isc-dhcp/boolean.h [new file with mode: 0644]
contrib/dhcp-3.0/includes/isc-dhcp/dst.h [new file with mode: 0644]
contrib/dhcp-3.0/includes/isc-dhcp/int.h [new file with mode: 0644]
contrib/dhcp-3.0/includes/isc-dhcp/lang.h [new file with mode: 0644]
contrib/dhcp-3.0/includes/isc-dhcp/list.h [new file with mode: 0644]
contrib/dhcp-3.0/includes/isc-dhcp/result.h [new file with mode: 0644]
contrib/dhcp-3.0/includes/isc-dhcp/types.h [new file with mode: 0644]
contrib/dhcp-3.0/includes/minires/minires.h [new file with mode: 0644]
contrib/dhcp-3.0/includes/minires/res_update.h [new file with mode: 0644]
contrib/dhcp-3.0/includes/minires/resolv.h [new file with mode: 0644]
contrib/dhcp-3.0/includes/netinet/if_ether.h [new file with mode: 0644]
contrib/dhcp-3.0/includes/netinet/ip.h [new file with mode: 0644]
contrib/dhcp-3.0/includes/netinet/ip_icmp.h [new file with mode: 0644]
contrib/dhcp-3.0/includes/netinet/udp.h [new file with mode: 0644]
contrib/dhcp-3.0/includes/omapip/alloc.h [new file with mode: 0644]
contrib/dhcp-3.0/includes/omapip/buffer.h [new file with mode: 0644]
contrib/dhcp-3.0/includes/omapip/convert.h [new file with mode: 0644]
contrib/dhcp-3.0/includes/omapip/hash.h [new file with mode: 0644]
contrib/dhcp-3.0/includes/omapip/omapip.h [new file with mode: 0644]
contrib/dhcp-3.0/includes/omapip/omapip_p.h [new file with mode: 0644]
contrib/dhcp-3.0/includes/omapip/trace.h [new file with mode: 0644]
contrib/dhcp-3.0/includes/osdep.h [new file with mode: 0644]
contrib/dhcp-3.0/includes/site.h [new file with mode: 0644]
contrib/dhcp-3.0/includes/statement.h [new file with mode: 0644]
contrib/dhcp-3.0/includes/tree.h [new file with mode: 0644]
contrib/dhcp-3.0/includes/version.h [new file with mode: 0644]
contrib/dhcp-3.0/minires/ns_date.c [new file with mode: 0644]
contrib/dhcp-3.0/minires/ns_name.c [new file with mode: 0644]
contrib/dhcp-3.0/minires/ns_parse.c [new file with mode: 0644]
contrib/dhcp-3.0/minires/ns_samedomain.c [new file with mode: 0644]
contrib/dhcp-3.0/minires/ns_sign.c [new file with mode: 0644]
contrib/dhcp-3.0/minires/ns_verify.c [new file with mode: 0644]
contrib/dhcp-3.0/minires/res_comp.c [new file with mode: 0644]
contrib/dhcp-3.0/minires/res_findzonecut.c [new file with mode: 0644]
contrib/dhcp-3.0/minires/res_init.c [new file with mode: 0644]
contrib/dhcp-3.0/minires/res_mkquery.c [new file with mode: 0644]
contrib/dhcp-3.0/minires/res_mkupdate.c [new file with mode: 0644]
contrib/dhcp-3.0/minires/res_query.c [new file with mode: 0644]
contrib/dhcp-3.0/minires/res_send.c [new file with mode: 0644]
contrib/dhcp-3.0/minires/res_sendsigned.c [new file with mode: 0644]
contrib/dhcp-3.0/minires/res_update.c [new file with mode: 0644]
contrib/dhcp-3.0/omapip/alloc.c [new file with mode: 0644]
contrib/dhcp-3.0/omapip/array.c [new file with mode: 0644]
contrib/dhcp-3.0/omapip/auth.c [new file with mode: 0644]
contrib/dhcp-3.0/omapip/buffer.c [new file with mode: 0644]
contrib/dhcp-3.0/omapip/connection.c [new file with mode: 0644]
contrib/dhcp-3.0/omapip/convert.c [new file with mode: 0644]
contrib/dhcp-3.0/omapip/dispatch.c [new file with mode: 0644]
contrib/dhcp-3.0/omapip/errwarn.c [new file with mode: 0644]
contrib/dhcp-3.0/omapip/generic.c [new file with mode: 0644]
contrib/dhcp-3.0/omapip/handle.c [new file with mode: 0644]
contrib/dhcp-3.0/omapip/hash.c [new file with mode: 0644]
contrib/dhcp-3.0/omapip/inet_addr.c [new file with mode: 0644]
contrib/dhcp-3.0/omapip/iscprint.c [new file with mode: 0644]
contrib/dhcp-3.0/omapip/listener.c [new file with mode: 0644]
contrib/dhcp-3.0/omapip/message.c [new file with mode: 0644]
contrib/dhcp-3.0/omapip/mrtrace.c [new file with mode: 0644]
contrib/dhcp-3.0/omapip/omapi.3 [new file with mode: 0644]
contrib/dhcp-3.0/omapip/protocol.c [new file with mode: 0644]
contrib/dhcp-3.0/omapip/result.c [new file with mode: 0644]
contrib/dhcp-3.0/omapip/support.c [new file with mode: 0644]
contrib/dhcp-3.0/omapip/toisc.c [new file with mode: 0644]
contrib/dhcp-3.0/omapip/trace.c [new file with mode: 0644]
contrib/dhcp-3.0/relay/dhcrelay.8 [new file with mode: 0644]
contrib/dhcp-3.0/relay/dhcrelay.c [new file with mode: 0644]
contrib/dhcp-3.0/server/bootp.c [new file with mode: 0644]
contrib/dhcp-3.0/server/class.c [new file with mode: 0644]
contrib/dhcp-3.0/server/confpars.c [new file with mode: 0644]
contrib/dhcp-3.0/server/db.c [new file with mode: 0644]
contrib/dhcp-3.0/server/ddns.c [new file with mode: 0644]
contrib/dhcp-3.0/server/dhcp.c [new file with mode: 0644]
contrib/dhcp-3.0/server/dhcpd.8 [new file with mode: 0644]
contrib/dhcp-3.0/server/dhcpd.c [new file with mode: 0644]
contrib/dhcp-3.0/server/dhcpd.conf [new file with mode: 0644]
contrib/dhcp-3.0/server/dhcpd.conf.5 [new file with mode: 0644]
contrib/dhcp-3.0/server/dhcpd.leases.5 [new file with mode: 0644]
contrib/dhcp-3.0/server/failover.c [new file with mode: 0644]
contrib/dhcp-3.0/server/mdb.c [new file with mode: 0644]
contrib/dhcp-3.0/server/omapi.c [new file with mode: 0644]
contrib/dhcp-3.0/server/salloc.c [new file with mode: 0644]
contrib/dhcp-3.0/server/stables.c [new file with mode: 0644]

diff --git a/contrib/dhcp-3.0/LICENSE b/contrib/dhcp-3.0/LICENSE
new file mode 100644 (file)
index 0000000..ef2536b
--- /dev/null
@@ -0,0 +1,20 @@
+# Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+# Copyright (c) 1995-2003 by Internet Software Consortium
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+#   Internet Systems Consortium, Inc.
+#   950 Charter Street
+#   Redwood City, CA 94063
+#   <info@isc.org>
+#   http://www.isc.org/
diff --git a/contrib/dhcp-3.0/README b/contrib/dhcp-3.0/README
new file mode 100644 (file)
index 0000000..a487a2c
--- /dev/null
@@ -0,0 +1,656 @@
+              Internet Systems Consortium DHCP Distribution
+                            Version 3.0.2rc3
+                           December  3, 2004
+
+                             README FILE
+
+You should read this file carefully before trying to install or use
+the ISC DHCP Distribution.
+
+                         TABLE OF CONTENTS
+
+       1       WHERE TO FIND DOCUMENTATION
+       2       RELEASE STATUS
+       3       BUILDING THE DHCP DISTRIBUTION
+        3.1     UNPACKING IT
+        3.2     CONFIGURING IT
+         3.2.1   DYNAMIC DNS UPDATES
+         3.2.2   LOCALLY DEFINED OPTIONS
+        3.3     BUILDING IT
+       4       INSTALLING THE DHCP DISTRIBUTION
+       5       USING THE DHCP DISTRIBUTION
+        5.1      FIREWALL RULES
+        5.2     LINUX
+         5.2.1   IF_TR.H NOT FOUND
+         5.2.2   SO_ATTACH_FILTER UNDECLARED
+         5.2.3   PROTOCOL NOT CONFIGURED
+         5.2.4   BROADCAST
+         5.2.6   IP BOOTP AGENT
+         5.2.7   MULTIPLE INTERFACES
+        5.3     SCO
+        5.4     HP-UX
+        5.5     ULTRIX
+        5.6     FreeBSD
+        5.7     NeXTSTEP
+        5.8     SOLARIS
+       6       SUPPORT
+        6.1     HOW TO REPORT BUGS
+
+                     WHERE TO FIND DOCUMENTATION
+
+Documentation for this software includes this README file, the
+RELNOTES file, and the manual pages, which are in the server, common,
+client and relay subdirectories.  The README file (this file) includes
+late-breaking operational and system-specific information that you
+should read even if you don't want to read the manual pages, and that
+you should *certainly* read if you run into trouble.  Internet
+standards relating to the DHCP protocol are stored in the doc
+subdirectory.  You will have the best luck reading the manual pages if
+you build this software and then install it, although you can read
+them directly out of the distribution if you need to.
+
+DHCP server documentation is in the dhcpd man page.  Information about
+the DHCP server lease database is in the dhcpd.leases man page.
+Server configuration documentation is in the dhcpd.conf man page as
+well as the dhcp-options man page.   A sample DHCP server
+configuration is in the file server/dhcpd.conf.   The source for the
+dhcpd, dhcpd.leases and dhcpd.conf man pages is in the server/ sub-
+directory in the distribution.   The source for the dhcp-options.5
+man page is in the common/ subdirectory.
+
+DHCP Client documentation is in the dhclient man page.  DHCP client
+configuration documentation is in the dhclient.conf man page and the
+dhcp-options man page.  The DHCP client configuration script is
+documented in the dhclient-script man page.   The format of the DHCP
+client lease database is documented in the dhclient.leases man page.
+The source for all these man pages is in the client/ subdirectory in
+the distribution.   In addition, the dhcp-options man page should be
+referred to for information about DHCP options.
+
+DHCP relay agent documentation is in the dhcrelay man page, the source
+for which is distributed in the relay/ subdirectory.
+
+To read installed manual pages, use the man command.  Type "man page"
+where page is the name of the manual page.   This will only work if
+you have installed the ISC DHCP distribution using the ``make install''
+command (described later).
+
+If you want to read manual pages that aren't installed, you can type
+``nroff -man page |more'' where page is the filename of the
+unformatted manual page.  The filename of an unformatted manual page
+is the name of the manual page, followed by '.', followed by some
+number - 5 for documentation about files, and 8 for documentation
+about programs.   For example, to read the dhcp-options man page,
+you would type ``nroff -man common/dhcp-options.5 |more'', assuming
+your current working directory is the top level directory of the ISC
+DHCP Distribution.
+
+If you do not have the nroff command, you can type ``more catpage''
+where catpage is the filename of the catted man page.  Catted man
+pages names are the name of the manual page followed by ".cat"
+followed by 5 or 8, as with unformatted manual pages.
+
+Please note that until you install the manual pages, the pathnames of
+files to which they refer will not be correct for your operating
+system.
+
+                           RELEASE STATUS
+
+This is the second release candidate of ISC DHCP 3.0.2.  This is a
+maintenance release which seeks only to fix bugs present in versions
+3.0.1 and earlier.  No new features have or will be added in subsequent
+release candidates of this release.
+
+In this release, the server and relay agent are currently fully
+functional on NetBSD, Linux systems with kernel version 2.2 or later,
+FreeBSD, OpenBSD, BSD/OS, Digital Tru64 Unix and Solaris.  The software
+will also run on AIX and HP-UX, but only supports a single network
+interface.  Ports also exist for QNX, SCO, NeXTStep, and MacOS X, but
+are not in wide use, with all that implies.   We are not aware of an
+easy way to get this software running on HP-UX.
+
+The DHCP client currently only knows how to configure the network on
+NetBSD, FreeBSD, OpenBSD, BSD/os, Linux, Solaris and NextStep.  The
+client depends on a system-dependent shell script to do network
+configuration - support for other operating systems is simply a matter
+of porting this shell script to the new platform.
+
+If you are running the DHCP distribution on a machine which is a
+firewall, or if there is a firewall between your DHCP server(s) and
+DHCP clients, please read the section on firewalls which appears later
+in this document.
+
+If you wish to run the DHCP Distribution on Linux, please see the
+Linux-specific notes later in this document.  If you wish to run on an
+SCO release, please see the SCO-specific notes later in this document.
+You particularly need to read these notes if you intend to support
+Windows 95 clients.  If you are running a version of FreeBSD prior to
+2.2, please read the note on FreeBSD.  If you are running HP-UX or
+Ultrix, please read the notes for those operating systems below.  If
+you are running NeXTSTEP, please see the notes on NeXTSTEP below.
+
+If you start dhcpd and get a message, "no free bpf", that means you
+need to configure the Berkeley Packet Filter into your operating
+system kernel.   On NetBSD, FreeBSD and BSD/os, type ``man bpf'' for
+information.   On Digital Unix, type ``man pfilt''.
+
+
+                   BUILDING THE DHCP DISTRIBUTION
+
+                            UNPACKING IT
+
+To build the DHCP Distribution, unpack the compressed tar file using
+the tar utility and the gzip command - type something like:
+
+       zcat dhcp-3.0.2rc3.tar.gz |tar xvf -
+
+On BSD/OS, you have to type gzcat, not zcat, and you may run into
+similar problems on other operating systems.
+
+                           CONFIGURING IT
+
+Now, cd to the dhcp-3.0.2rc3 subdirectory that you've just created and
+configure the source tree by typing:
+
+       ./configure
+
+If the configure utility can figure out what sort of system you're
+running on, it will create a custom Makefile for you for that
+system; otherwise, it will complain.  If it can't figure out what
+system you are using, that system is not supported - you are on
+your own.
+
+                        DYNAMIC DNS UPDATES
+
+A fully-featured implementation of dynamic DNS updates is included in
+this release.   There are no build dependencies with any BIND version
+- this version can and should just use the resolver in your C library.
+
+There is documentation for the DDNS support in the dhcpd.conf manual
+page - see the beginning of this document for information on finding
+manual pages.
+
+                      LOCALLY DEFINED OPTIONS
+
+In previous versions of the DHCP server there was a mechanism whereby
+options that were not known by the server could be configured using
+a name made up of the option code number and an identifier:
+"option-nnn"   This is no longer supported, because it is not future-
+proof.   Instead, if you want to use an option that the server doesn't
+know about, you must explicitly define it using the method described
+in the dhcp-options man page under the DEFINING NEW OPTIONS heading.
+
+                            BUILDING IT
+
+Once you've run configure, just type ``make'', and after a while
+you should have a dhcp server.  If you get compile errors on one
+of the supported systems mentioned earlier, please let us know.
+If you get warnings, it's not likely to be a problem - the DHCP
+server compiles completely warning-free on as many architectures
+as we can manage, but there are a few for which this is difficult.
+If you get errors on a system not mentioned above, you will need
+to do some programming or debugging on your own to get the DHCP
+Distribution working.
+
+                  INSTALLING THE DHCP DISTRIBUTION
+
+Once you have successfully gotten the DHCP Distribution to build, you
+can install it by typing ``make install''.   If you already have an old
+version of the DHCP Distribution installed, you may want to save it
+before typing ``make install''.
+
+                    USING THE DHCP DISTRIBUTION
+
+                           FIREWALL RULES
+
+If you are running the DHCP server or client on a computer that's also
+acting as a firewall, you must be sure to allow DHCP packets through
+the firewall.  In particular, your firewall rules _must_ allow packets
+from IP address 0.0.0.0 to IP address 255.255.255.255 from UDP port 68
+to UDP port 67 through.  They must also allow packets from your local
+firewall's IP address and UDP port 67 through to any address your DHCP
+server might serve on UDP port 68.  Finally, packets from relay agents
+on port 67 to the DHCP server on port 67, and vice versa, must be
+permitted.
+
+We have noticed that on some systems where we are using a packet
+filter, if you set up a firewall that blocks UDP port 67 and 68
+entirely, packets sent through the packet filter will not be blocked.
+However, unicast packets will be blocked.   This can result in strange
+behaviour, particularly on DHCP clients, where the initial packet
+exchange is broadcast, but renewals are unicast - the client will
+appear to be unable to renew until it starts broadcasting its
+renewals, and then suddenly it'll work.   The fix is to fix the
+firewall rules as described above.
+
+                          PARTIAL SERVERS
+
+If you have a server that is connected to two networks, and you only
+want to provide DHCP service on one of those networks (e.g., you are
+using a cable modem and have set up a NAT router), if you don't write
+any subnet declaration for the network you aren't supporting, the DHCP
+server will ignore input on that network interface if it can.  If it
+can't, it will refuse to run - some operating systems do not have the
+capability of supporting DHCP on machines with more than one
+interface, and ironically this is the case even if you don't want to
+provide DHCP service on one of those interfaces.
+
+                               LINUX
+
+There are three big LINUX issues: the all-ones broadcast address,
+Linux 2.1 ip_bootp_agent enabling, and operations with more than one
+network interface.   There are also two potential compilation/runtime
+problems for Linux 2.1/2.2: the "SO_ATTACH_FILTER undeclared" problem
+and the "protocol not configured" problem.
+
+                 LINUX: SO_ATTACH_FILTER UNDECLARED
+
+In addition, there is a minor issue that we will mention here because
+this release is so close on the heels of the Linux 2.2 release: there
+is a symlink in /usr/include that points at the linux asm headers.  It
+appears to be not uncommon that this link won't be updated correctly,
+in which case you'll get the following error when you try to build:
+
+   lpf.c: In function `if_register_receive':
+   lpf.c:152: `SO_ATTACH_FILTER' undeclared (first use this function)
+   lpf.c:152: (Each undeclared identifier is reported only once
+   lpf.c:152: for each function it appears in.)
+
+The line numbers may be different, of course.   If you see this
+header, your linux asm header link is probably bad, and you should
+make sure it's pointing to correct linux source directory.
+
+                   LINUX: PROTOCOL NOT CONFIGURED
+
+One additional Linux 2.1/2.2 issue: if you get the following message,
+it's because your kernel doesn't have the linux packetfilter or raw
+packet socket configured:
+
+ Make sure CONFIG_PACKET (Packet socket) and CONFIG_FILTER (Socket
+ Filtering) are enabled in your kernel configuration
+
+If this happens, you need to configure your Linux kernel to support
+Socket Filtering and the Packet socket.  You can do this by typing
+``make config'', ``make menuconfig'' or ``make xconfig'', and then
+enabling the Packet socket and Socket Filtering options that you'll
+see displayed on the menu or in the questionnaire.  You can also edit
+your linux kernel .config file directly: set CONFIG_FILTER=y and
+CONFIG_PACKET=y.  If you do this, make sure you run ``make oldconfig''
+afterwards, so that the changes you've made are propogated to the
+kernel header files.   After you've reconfigured, you need to type
+``make'' to build a new Linux kernel, and then install it in the
+appropriate place (probably /linux).  Make sure to save a copy of your
+old /linux.
+
+If the preceding paragraph made no sense to you, ask your Linux
+vendor/guru for help - please don't ask us.
+
+If you set CONFIG_PACKET=m or CONFIG_FILTER=m, then you must tell the
+kernel module loader to load the appropriate modules.  If this doesn't
+make sense to you, don't use CONFIG_whatever=m - use CONFIG_whatever=y.  
+Don't ask for help with this on the DHCP mailing list - it's a Linux
+kernel issue.   This is probably not a problem with the most recent
+Linux 2.2.x kernels.
+
+                          LINUX: BROADCAST
+
+If you are running a recent version of Linux, this won't be a problem,
+but on older versions of Linux (kernel versions prior to 2.2), there
+is a potential problem with the broadcast address being sent
+incorrectly.
+
+In order for dhcpd to work correctly with picky DHCP clients (e.g.,
+Windows 95), it must be able to send packets with an IP destination
+address of 255.255.255.255.  Unfortunately, Linux changes an IP
+destination of 255.255.255.255 into the local subnet broadcast address
+(here, that's 192.5.5.223).
+
+This isn't generally a problem on Linux 2.2 and later kernels, since
+we completely bypass the Linux IP stack, but on old versions of Linux
+2.1 and all versions of Linux prior to 2.1, it is a problem - pickier
+DHCP clients connected to the same network as the ISC DHCP server or
+ISC relay agent will not see messages from the DHCP server.   It *is*
+possible to run into trouble with this on Linux 2.2 and later if you
+are running a verson of the DHCP server that was compiled on a Linux
+2.0 system, though.
+
+It is possible to work around this problem on some versions of Linux
+by creating a host route from your network interface address to
+255.255.255.255.   The command you need to use to do this on Linux
+varies from version to version.   The easiest version is:
+
+       route add -host 255.255.255.255 dev eth0
+
+On some older Linux systems, you will get an error if you try to do
+this.   On those systems, try adding the following entry to your
+/etc/hosts file:
+
+255.255.255.255        all-ones
+
+Then, try:
+
+       route add -host all-ones dev eth0
+
+Another route that has worked for some users is:
+
+       route add -net 255.255.255.0 dev eth0
+
+If you are not using eth0 as your network interface, you should
+specify the network interface you *are* using in your route command.
+
+                       LINUX: IP BOOTP AGENT
+
+Some versions of the Linux 2.1 kernel apparently prevent dhcpd from
+working unless you enable it by doing the following:
+
+             echo 1 >/proc/sys/net/ipv4/ip_bootp_agent
+
+
+                     LINUX: MULTIPLE INTERFACES
+
+Very old versions of the Linux kernel do not provide a networking API
+that allows dhcpd to operate correctly if the system has more than one
+broadcast network interface.  However, Linux 2.0 kernels with version
+numbers greater than or equal to 2.0.31 add an API feature: the
+SO_BINDTODEVICE socket option.  If SO_BINDTODEVICE is present, it is
+possible for dhcpd to operate on Linux with more than one network
+interface.  In order to take advantage of this, you must be running a
+2.0.31 or greater kernel, and you must have 2.0.31 or later system
+headers installed *before* you build the DHCP Distribution.
+
+We have heard reports that you must still add routes to 255.255.255.255
+in order for the all-ones broadcast to work, even on 2.0.31 kernels.
+In fact, you now need to add a route for each interface.   Hopefully
+the Linux kernel gurus will get this straight eventually.
+
+Linux 2.1 and later kernels do not use SO_BINDTODEVICE or require the
+broadcast address hack, but do support multiple interfaces, using the
+Linux Packet Filter.
+
+                                SCO
+
+SCO has the same problem as Linux (described earlier).  The thing is,
+SCO *really* doesn't want to let you add a host route to the all-ones
+broadcast address.
+
+On more recent versions of SCO, you can do this:
+
+  ifconfig net0 xxx.xxx.xxx.xxx netmask 0xNNNNNNNN broadcast 255.255.255.255
+
+If this doesn't work, you can also try the following strange hack:
+
+  ifconfig net0 alias 10.1.1.1 netmask 8.0.0.0
+
+Apparently this works because of an interaction between SCO's support
+for network classes and the weird netmask.  The 10.* network is just a
+dummy that can generally be assumed to be safe.   Don't ask why this
+works.   Just try it.   If it works for you, great.   SCO has added
+support for doing DHCP in a more sensible way, but I have not had the
+time or cause to implement them.   If you are interested in this, and
+are able to hack your way out of a wet paper back without assistance,
+we'd appreciate it if you'd give it a try, but don't expect too much
+support from us (sorry!).
+
+                               HP-UX
+
+HP-UX has the same problem with the all-ones broadcast address that
+SCO and Linux have.   One user reported that adding the following to
+/etc/rc.config.d/netconf helped (you may have to modify this to suit
+your local configuration):
+
+INTERFACE_NAME[0]=lan0
+IP_ADDRESS[0]=1.1.1.1
+SUBNET_MASK[0]=255.255.255.0
+BROADCAST_ADDRESS[0]="255.255.255.255"
+LANCONFIG_ARGS[0]="ether"
+DHCP_ENABLE[0]=0
+
+                               ULTRIX
+
+Now that we have Ultrix packet filter support, the DHCP Distribution
+on Ultrix should be pretty trouble-free.  However, one thing you do
+need to be aware of is that it now requires that the pfilt device be
+configured into your kernel and present in /dev.  If you type ``man
+packetfilter'', you will get some information on how to configure your
+kernel for the packet filter (if it isn't already) and how to make an
+entry for it in /dev.
+
+                              FreeBSD
+
+Versions of FreeBSD prior to 2.2 have a bug in BPF support in that the
+ethernet driver swaps the ethertype field in the ethernet header
+downstream from BPF, which corrupts the output packet.   If you are
+running a version of FreeBSD prior to 2.2, and you find that dhcpd
+can't communicate with its clients, you should #define BROKEN_FREEBSD_BPF 
+in site.h and recompile.
+
+Modern versions of FreeBSD include the ISC DHCP 3.0 client as part of
+the base system, and the full distribution (for the DHCP server and
+relay agent) is available from the Ports Collection in
+/usr/ports/net/isc-dhcp3, or as a package on FreeBSD installation
+CDROMs.
+
+                              NeXTSTEP
+
+The NeXTSTEP support uses the NeXTSTEP Berkeley Packet Filter
+extension, which is not included in the base NextStep system.  You
+must install this extension in order to get dhcpd or dhclient to work.
+
+                              SOLARIS
+
+One problem which has been observed and is not fixed in this
+patchlevel has to do with using DLPI on Solaris machines.  The symptom
+of this problem is that the DHCP server never receives any requests.
+This has been observed with Solaris 2.6 and Solaris 7 on Intel x86
+systems, although it may occur with other systems as well.  If you
+encounter this symptom, and you are running the DHCP server on a
+machine with a single broadcast network interface, you may wish to
+edit the includes/site.h file and uncomment the #define USE_SOCKETS
+line.  Then type ``make clean; make''.
+
+The DHCP client on Solaris will only work with DLPI.  If you run it
+and it just keeps saying it's sending DHCPREQUEST packets, but never
+gets a response, you may be having DLPI trouble as described above.
+If so, we have no solution to offer at this time.  Also, because
+Solaris requires you to "plumb" an interface before it can be detected
+by the DHCP client, you must either specify the name(s) of the
+interface(s) you want to configure on the command line, or must plumb
+the interfaces prior to invoking the DHCP client.  This can be done
+with ``ifconfig iface plumb'', where iface is the name of the
+interface (e.g., ``ifconfig hme0 plumb'').
+
+It should be noted that Solaris versions from 2.6 onward include a
+DHCP client that you can run with ``/sbin/ifconfig iface dhcp start''
+rather than using the ISC DHCP client.  The feature set of the Solaris
+client is different (not necessarily better or worse) than that of the
+ISC client, but in most cases it will be a lot easier for you to just
+use that.  Please do not ask for help in using the Solaris DHCP client
+on Internet Systems Consortium mailing lists - that's why you're
+paying Sun the big bucks.   If you're having a problem with the
+Solaris client interoperating with the ISC dhcp server, that's another
+matter, but please check with Sun first.
+
+                               AIX
+
+The AIX support uses the BSD socket API, which cannot differentiate on
+which network interface a broadcast packet was received; thus the DHCP
+server and relay will work only on a single interface.  (They do work
+on multi-interface machines if configured to listen on only one of the
+interfaces.)
+
+The ISC DHCP distribution does not include a dhclient-script for AIX--
+AIX comes with a DHCP client.  Contribution of a working dhclient-script
+for AIX would be welcome.
+
+                              SUPPORT
+
+The Internet Systems Consortium DHCP server is not a commercial
+product, and is not supported by the ISC.  However, it has attracted a
+fairly sizable following on the Internet, which means that there are a
+lot of knowledgable users who may be able to help you if you get
+stuck.  These people generally read the dhcp-server@isc.org mailing
+list.
+
+If you are going to use dhcpd, you should probably subscribe to the
+dhcp-server and dhcp-announce mailing lists.  If you will be using
+dhclient, you should subscribe to the dhcp-client mailing list.
+
+If you need help, you should ask on the dhcp-server or dhcp-client
+mailing list - whichever is appropriate to your application.  Support
+requests for the ISC DHCP client should go to dhcp-client@isc.org.
+Support requests for the DHCP server should go to dhcp-server@isc.org.
+If you are having trouble with a combination of the client and server,
+send the request to dhcp-server@isc.org.  Please do not cross-post to
+both lists under any circumstances.
+
+WHERE TO REPORT BUGS: If you want the act of sending in a bug report
+to result in you getting help in the form of a fixed piece of
+software, you are asking for help.  Your bug report is helpful to us,
+but fundamentally you are making a support request, so please use the
+addresses described in the previous paragraphs.  If you are _sure_ that
+your problem is a bug, and not user error, or if your bug report
+includes a patch, you can send it to dhcp-bugs@isc.org without
+subscribing.   This mailing list goes into a bug tracking system, so
+you don't need to check periodically to see if we still remember the
+bug - if you haven't been notified that the bug has been closed, we
+still consider it a bug, and still have it in the system.
+
+PLEASE DO NOT REPORT BUGS IN OLD SOFTWARE RELEASES!  Fetch the latest
+release and see if the bug is still in that version of the software,
+and if it's not, _then_ report it.  It's okay to report bugs in the
+latest patchlevel of a major version that's not the most recent major
+version, though - for example, if you're running 3.0.1, you don't have
+to upgrade to a 3.0.2rc (release candidate) before you can report bugs.
+
+PLEASE DO NOT REPORT BUGS IF YOU ARE RUNNING A VERSION OF THE ISC
+DHCP DISTRIBUTION THAT YOU DIDN'T GET FROM THE ISC!   Free operating
+system distributions are notorious for including outdated versions of
+software, and also versions of software that were not compiled on your
+particular version of the operating system.   These versions
+frequently do not work.   Getting a source distribution from the ISC
+and installing it frequently *does* work.   Please try this *before*
+asking for help.
+
+PLEASE READ THIS README FILE CAREFULLY BEFORE REPORTING BUGS,
+PARTICULARLY THE SECTION BELOW ON WHAT TO INCLUDE IN A BUG REPORT OR
+HELP REQUEST.
+
+PLEASE DO NOT SEND REQUESTS FOR SUPPORT DIRECTLY TO THE ENGINEERS WHO
+WORK ON THE ISC DHCP DISTRIBUTION!  *PARTICULARLY*, DO NOT SEND MAIL
+TO THE ENGINEERS BECAUSE YOU AREN'T SURE TO WHOM YOU SHOULD SEND MAIL
+- if you aren't sure, *ask* on the dhcp-server@isc.org or
+dhcp-client@isc.org mailing list.
+
+The number of people using the DHCP Distribution is sufficiently large
+that if we take interrupts every time any one of those people runs
+into trouble, we will never get any more coding done.  If you send a
+support request directly to any ISC or Nominum engineer, we will
+forward it to the mailing list, or possibly ignore it, depending on
+how much stress we are under at the time.
+
+Please do not Cc: us on mail you send to these lists - we read both
+mailing lists, so this just means we get two copies!
+
+If your question can only be answered by one of the engineers, send it
+to the appropriate public mailing list anyway - we will answer it
+there.  When we have time.
+
+Please do not think "Oh, I don't want to bother the whole mailing list
+with this question."  If you are too embarrassed to ask publically,
+get a support contract.
+
+If you are concerned about bothering everybody on the list, that's
+great, but that's what the list is there for.  When you send mail to
+one of the engineers, you are taking resources away from everybody on
+the mailing list *anyway* - they just don't know it.
+
+We're not writing this because we don't respect you - we really do
+want to help you, and we appreciate your bug reports and comments.
+But please use the mechanisms we have in place to provide you with
+help, because otherwise you are almost certainly depriving someone
+else of our help.
+
+PLEASE DO NOT CALL US ON THE PHONE FOR HELP!  Answering the phone
+takes a lot more of our time and attention than answering email.  If
+you do call us on the phone, we will tell you to send email to the
+mailing list or buy a support contract, so please don't waste your
+time or ours.  If you have a support contract, please use the support
+channel mentioned in the support contract - otherwise you probably
+won't get timely support unless you happen to ask an interesting
+question and we happen to have some time to kill, because we can't
+tell you're a support customer if you send mail to the public mailing
+lists.
+
+               HOW TO REPORT BUGS OR REQUEST HELP
+
+When you report bugs or ask for help, please provide us complete
+information.  A list of information we need follows.  Please read it
+carefully, and put all the information you can into your initial bug
+report, so that we don't have to ask you any questions in order to
+figure out your problem.   If you need handholding support, please
+consider contacting a commercial provider of the ISC DHCP
+Distribution.
+
+      1.  The specific operating system name and version of the
+          machine on which the DHCP server or client is running.
+      2.  The specific operating system name and version of the
+          machine on which the client is running, if you are having
+          trouble getting a client working with the server.
+      3.  If you're running Linux, the version number we care about is
+          the kernel version and maybe the library version, not the
+          distribution version - e.g., while we don't mind knowing
+          that you're running Redhat version mumble.foo, we must know
+          what kernel version you're running, and it helps if you can
+          tell us what version of the C library you're running,
+          although if you don't know that off the top of your head it
+          may be hard for you to figure it out, so don't go crazy
+          trying.
+      4.  The specific version of the DHCP distribution you're
+          running, for example "2.0b1pl19", not "2.0".
+      5.  Please explain the problem carefully, thinking through what
+          you're saying to ensure that you don't assume we know
+          something about your situation that we don't know.
+      6.  Include your dhcpd.conf and dhcpd.leases file if they're not
+          huge (if they are huge, we may need them anyway, but don't
+          send them until you're asked).   Huge means more than 100
+          kilobytes each.
+      7.  Include a log of your server or client running until it
+          encounters the problem - for example, if you are having
+          trouble getting some client to get an address, restart the
+          server with the -d flag and then restart the client, and
+          send us what the server prints.   Likewise, with the client,
+          include the output of the client as it fails to get an
+          address or otherwise does the wrong thing.   Do not leave
+          out parts of the output that you think aren't interesting.
+      8.  If the client or server is dumping core, please run the
+          debugger and get a stack trace, and include that in your
+          bug report.   For example, if your debugger is gdb, do the
+          following:
+
+               gdb dhcpd dhcpd.core
+               (gdb) where
+                     [...]
+               (gdb) quit
+
+         This assumes that it's the dhcp server you're debugging, and
+         that the core file is in dhcpd.core.
+      9.  If you know that the problem is an actual bug, and you can
+         reproduce the bug, you can skip steps 6 through 8 and instead
+         capture a trace file using the -tf flag (see the man page for
+         details).   If you do this, and there is anything in your
+         dhcp configuration that you are not willing to make public,
+         please send the trace file to dhcp-bugs@isc.org and NOT to
+         dhcp-server@isc.org, because the tracefile contains your entire
+         dhcp configuration.
+
+PLEASE DO NOT send queries about non-isc clients to the dhcp-client
+mailing list.   If you're asking about them on an ISC mailing list,
+it's probably because you're using the ISC DHCP server, so ask there.
+If you are having problems with a client whose executable is called
+dhcpcd, this is _not_ the ISC DHCP client, and we probably can't help
+you with it.
+
+Please see http://www.isc.org/sw/dhcp/ for details on how to subscribe
+to the ISC DHCP mailing lists.
+
+
diff --git a/contrib/dhcp-3.0/README.DELETED b/contrib/dhcp-3.0/README.DELETED
new file mode 100644 (file)
index 0000000..786887d
--- /dev/null
@@ -0,0 +1,41 @@
+Makefile
+Makefile.conf
+Makefile.dist
+client/Makefile.dist
+client/scripts/bsdos
+client/scripts/linux
+client/scripts/netbsd
+client/scripts/nextstep
+client/scripts/openbsd
+client/scripts/solaris
+common/Makefile.dist
+configure
+contrib
+dhcpctl/Makefile.dist
+dhcpctl/cltest.c
+doc
+dst/Makefile.dist
+includes/cf/aix.h
+includes/cf/alphaosf.h
+includes/cf/bsdos.h
+includes/cf/cygwin32.h
+includes/cf/hpux.h
+includes/cf/irix.h
+includes/cf/linux.h
+includes/cf/netbsd.h
+includes/cf/nextstep.h
+includes/cf/openbsd.h
+includes/cf/qnx.h
+includes/cf/rhapsody.h
+includes/cf/sample.h
+includes/cf/sco.h
+includes/cf/sunos4.h
+includes/cf/sunos5-5.h
+includes/cf/ultrix.h
+minires/Makefile.dist
+omapip/Makefile.dist
+omapip/test.c
+relay/Makefile.dist
+server/Makefile.dist
+site.conf
+tests
diff --git a/contrib/dhcp-3.0/README.DRAGONFLY b/contrib/dhcp-3.0/README.DRAGONFLY
new file mode 100644 (file)
index 0000000..f02023b
--- /dev/null
@@ -0,0 +1,5 @@
+Original Source can be downloaded from:
+ftp://ftp.isc.org/isc/dhcp/dhcp-3.0.2rc3.tar.gz
+MD5 (dhcp-3.0.2rc3.tar.gz) = 7c5dd4587d0236275ddf026750513131
+
+A list of files and directories removed is in README.DELETED.
diff --git a/contrib/dhcp-3.0/RELNOTES b/contrib/dhcp-3.0/RELNOTES
new file mode 100644 (file)
index 0000000..2200102
--- /dev/null
@@ -0,0 +1,1441 @@
+             Internet Systems Consortium DHCP Distribution
+                            Version 3.0.2rc3
+                           December  3, 2004
+
+                            Release Notes
+
+                            NEW FEATURES
+
+Version 3 of the ISC DHCP Distribution includes the following features
+that are new since version 2.0:
+
+     - DHCP Failover Protocol support
+     - OMAPI, an API for accessing and modifying the DHCP server and
+       client state.
+     - Conditional behaviour
+     - Storing arbitrary information on leases
+     - Address pools with access control
+     - Client classing
+     - Address allocation restriction by class
+     - Relay agent information option support 
+     - Dynamic DNS updates
+     - Many bug fixes, performance enhancements, and minor new DHCP
+       protocol features. 
+
+The main bug fixed here is a bug in the subclass allocation code that
+could result in a memory smash.   Any users of the ISC DHCP server who
+are using subclasses should seriously consider upgrading to 3.0.1.
+
+If you are running 3.0 beta 1 and are doing dynamic DNS updates, the
+lease file is no longer forward-compatible to 3.0 final.   A script
+has been provided to convert 3.0b1 lease files.   This is in
+contrib/3.0b1-lease-convert.
+
+For information on how to install, configure and run this software,
+as well as how to find documentation and report bugs, please consult
+the README file.
+
+The Dynamic DNS Update support is a descendent of an implementation
+done by Lans Carstensen and Brian Dols at Rose-Hulman Institute of
+Technology, Jim Watt at Applied Biosystems, Irina Goble at Integrated
+Measurement Systems, Igor Sharfmesser at Kazakh Telecom, and Brian
+Murrell at BC Tel Advanced Communications.  I'd like to express my
+thanks to all of these good people here, both for working on the code
+and for prodding me into improving it.
+
+                       Changes since 3.0.2rc2
+
+- Two varaibles introduced in 3.0.2b1 were used without being initialized
+  in the case where neither the FILE nor SNAME fields were available for
+  overloading.  This was repaired.
+
+- A heretofore believed to be impossible corner case of the option
+  overloading implementation turned out to be possible ("Unable to sort
+  overloaded options after 10 tries.").  The implementation was reworked
+  to consider the case of an option so large it would require more than
+  three chunks to fit.
+
+- Many other instances of variables being used without being initialized
+  were repaired.
+
+- An uninitialized variable in omapi_io_destroy() led to the discovery
+  that this function may result in orphaned pointers (and hence, a memory
+  leak).
+
+                       Changes since 3.0.2rc1
+
+- allocate_lease() was rewritten to repair a bug in which the server would
+  try to allocate an ABANDONED lease when FREE leases were available.
+
+                       Changes since 3.0.2b1
+
+- Some dhcp-eval.5 manpage formatting was repaired.
+
+                       Changes since 3.0.1
+
+- A bug was fixed in the server's 'option overloading' implementation,
+  where options loaded into the 'file' and 'sname' packet fields were
+  not aligned precisely as rfc2131 dictates.
+
+- The FreeBSD client script was changed to support the case where a domain
+  name was not provided by the server.
+
+- A memory leak in 'omshell' per each command line parsed was
+  repaired, thanks to a patch from Jarkko Torppa.
+
+- Log functions writing to stderr were adjusted to use the STDERR_FILENO
+  system definition rather than '2'.  This is a no-op for 90% of platforms.
+
+- One call to trace_write_packet_iov() counted the number of io vectors
+  incorrectly, causing inconsistent tracefiles.  This was fixed.
+
+- Some expression parse failure memory leaks were closed.
+
+- A host byte order problem in tracefiles was repaired.
+
+- Pools configured in DHCPD for failover possessing permission lists that
+  previously were assumed to not include dyanmic bootp clients are now
+  a little more pessimistic.  The result is, dhcpd will nag you about just
+  about most pools that possess a 'allow' statement with no 'deny' that
+  would definitely match a dynamic bootp client.
+
+- The 'ddns-update-style' configuration warning bit now insists that
+  the configuration be globally scoped.
+
+- Two memory leaks in dhclient were closed thanks to a patch from Felix
+  Farkas.
+
+- Some minor but excellently pedantic documentation errors were fixed
+  thanks to a patch from Thomas Klausner.
+
+- Bugs in operator precedence in executable statements have been repaired
+  once again.  More legal syntaxes should be parsed legally.
+
+- Failing to initialize a tracefile for any reason if a tracefile was
+  specified is now a fatal error.  Thanks to a patch from Albert Herranz.
+
+- Corrected a bug in which the number of leases transferred as calculated
+  by the failover primary and sent to peers in POOLRESP responses may be
+  incorrect.  This value is not believed to be used by other failover
+  implementations, excepting perhaps as logged information.
+
+- Corrected a bug in which 'dhcp_failover_send_poolresp()' was in fact
+  sending POOLREQ messages instead of POOLRESP mesasges.  This message
+  was essentially ignored since failover secondaries effectively do not
+  respond to POOLREQ messages.
+
+- Type definitions for various bitwidths of integers in the sunos5-5
+  build of ISC DHCP have been fixed.  It should compile and run more
+  easily when built in 64-bit for this platform.
+
+- "allow known-clients;" is now a legal syntax, to avoid confusion.
+
+- If one dhcp server chooses to 'load balance' a request to its failover
+  peer, it first checks to see if it believes said peer has a free
+  lease to allocate before ignoring the DISCOVER.
+
+- log() was logging a work buffer, rather than the value returned by
+  executing the statements configured by the user.  In some cases,
+  the work buffer and the intended results were the same.  In some other
+  cases, they were not.  This was fixed thanks to a patch from Gunnar
+  Fjone and directconnect.no.
+
+- Compiler warnings for some string type conversions was fixed, thanks
+  to Andreas Gustafsson.
+
+- The netbsd build environments were simplified to one, in which
+  -Wconversion is not used, thanks to Andreas Gustafsson.
+
+- How randomness in the backoff-cutoff dhclient configuration variable
+  is implemented was better documented in the manpage, and the behaviour
+  of dhclient in REQUEST timeout handling was changed to match that of
+  DISCOVER timeout handling.
+
+- Omapi was hardened against clients that pass in null values, thanks
+  to a patch from Mark Jason Dominus.
+
+- A bug was fixed in dhclient that kept it from doing client-side
+  ddns updates.  Thanks to a patch from Andreas Gustafsson, which
+  underwent some modification after review by Jason Vas Dias.
+
+- Failover implementations disconnected due to the network between
+  them (rather than one of the two shutting down) will now try to
+  re-establish the failover connection every 5 seconds, rather than
+  to simply try once and give up until one of them is restarted.
+  Thanks to a patch from Ulf Ekberg from Infoblox, and field testing
+  by Greger V. Teigre which led to an enhancement to it.
+
+- A problem that kept DHCP Failover secondaries from tearing down
+  ddns records was repaired.  Thanks to a patch from Ulf Ekberg from
+  Infoblox.
+
+- 64bit pointer sizes are detected properly on FreeBSD now.
+
+- A bug was repaired where the DHCP server would leave stale references
+  to host records on leases it once thought about offering to certain
+  clients.  The result would be to apply host and 'known' scopes to the
+  wrong clients (possibly denying booting).  NOTE:  The 'mis-host' patch
+  that was being circulated as a workaround is not the way this bug was
+  fixed.  If you were a victim of this bug in 3.0.1, you are cautioned
+  to proceed carefully and see if it fixes your problem.
+
+- A bug was repaired in the server's DHCPINFORM handling, where it
+  tried to divine the client's address from the source packet and
+  would get it wrong.  Thanks to Anshuman Singh Rawat.
+
+- A log message was introduced to help illuminate the case where the
+  server was unable to find a lease to assign to any BOOTP client.
+  Thanks to Daniel Baker.
+
+- A minor dhcpd.conf.5 manpage error was fixed.
+
+                       Changes since 3.0.1rc14
+
+- The global variable 'cur_time' was centralized and is now uniformly of a
+  type #defined in system-dependent headers.  It had previously been defined
+  in one of many places as a 32-bit value, and this causes mayhem on 64-bit
+  big endian systems.  It probably wasn't too healthy on little endian
+  systems either.
+
+- A printf format string error introduced in rc14 was repaired.
+
+- AIX system-dependent header file was altered to only define NO_SNPRINTF
+  if the condition used to #ifdef in vsnprintf in AIX' header files
+  is false.
+
+- The Alpha/OSF system-dependent header file was altered to define
+  NO_SNPRINTF on OS revisions older than 4.0G.
+
+- omapip/test.c had string.h added to its includes.
+
+                       Changes since 3.0.1rc13
+
+! CAN-2004-0460 - CERT VU#317350: Five stack overflow exploits were closed
+  in logging messages with excessively long hostnames provided by the
+  clients.  It is highly probable that these could have been used by
+  attackers to gain arbitrary root access on systems using ISC DHCP 3.0.1
+  release candidates 12 or 13.  Special thanks to Gregory Duchemin for
+  both finding and solving the problem.
+
+! CAN-2004-0461 - CERT VU#654390: Once the above was closed, an opening
+  in log_*() functions was evidented, on some specific platforms where
+  vsnprintf() was not believed to be available and calls were wrapped to
+  sprintf() instead.  Again, credit goes to Gregory Duchemin for finding
+  the problem.  Calls to snprintf() are now linked to a distribution-local
+  snprintf implementation, only in those cases where the architecture is
+  not known to provide one (see includes/cf/[arch].h).  If you experience
+  linking problems with snprintf/vsnprintf or 'isc_print_' functions, this
+  is where to look.  This vulnerability did not exist in any previously
+  published version of ISC DHCP.
+
+- Compilation on hpux 11.11 was repaired.
+
+- 'The cross-compile bug fix' was backed out.
+
+                       Changes since 3.0.1rc12
+
+- Fixed a bug in omapi lease lookup function, to form the hardware
+  address for the hash lookup correctly, thanks to a patch from
+  Richard Hirst.
+
+- Fixed a bug where dhcrelay was sending relayed responses back to the
+  broadcast address, but with the source's unicast mac address.  Should
+  now conform to rfc2131 section 4.1.
+
+- Cross-compile bug fix; use $(AR) instead of ar.  Thanks to Morten Brorup.
+
+- Fixed a crash bug in dhclient where dhcpd servers that do not provide
+  renewal times results in an FPE.  As a side effect, dhclient can now
+  properly handle 0xFFFFFFFF (-1) expiry times supplied by servers.  Thanks
+  to a patch from Burt Silverman.
+
+- The 'ping timeout' debugs from rc12 were removed to -DDEBUG only,
+  and reformatted to correct a compilation error on solaris platforms.
+
+- A patch was applied which fixes a case where leases read from the
+  leases database do not properly over-ride previously read leases.
+
+- dhcpctl.3 manpage was tweaked.
+
+                       Changes since 3.0.1rc11
+
+- A patch from Steve Campbell was applied with minor modifications to
+  permit reverse dns PTR record updates with values containing spaces.
+
+- A patch from Florian Lohoff was applied with some modifications to
+  dhcrelay.  It now discards packets whose hop count exceeds 10 by default,
+  and a command-line option (-c) can be used to set this threshold.
+
+- A failover bug relating to identifying peers by name length instead of
+  by name was fixed.
+
+- Delcaring failover configs within shared-network statements should no
+  longer result in error.
+
+- The -nw command line option to dhclient now works.
+
+- Thanks to a patch from Michael Richardson:
+       - Some problems with long option processing have been fixed.
+       - Some fixes to minires so that updates of KEY records will work.
+
+- contrib/ms2isc was updated by Shu-Min Chang of the Intel Corporation.
+  see contrib/ms2isc/readme.txt for revision notes.
+
+- Dhclient no longer uses shell commands to kill another instance of
+  itself, it sends the signal directly.  Thanks to a patch from Martin
+  Blapp.
+
+- The FreeBSD dhclient-script was changed so that a failure to write to
+  /etc/resolv.conf does not prematurely end the script.  This keeps dhclient
+  from looping infinitely when this is the case.  Thanks to a patch from
+  Martin Blapp.
+
+- A patch from Bill Stephens was applied which resolves a problem with lease
+  expiry times in failover configurations.
+
+- A memory leak in configuration parsing was closed thanks to a patch from
+  Steve G.
+
+- The function which discovers interfaces will now skip non-broadcast or
+  point-to-point interfaces, thanks to a patch from David Brownlee.
+
+- Options not yet known by the dhcpd or dhclient have had their names
+  changed such that they do not contain # symbols, in case they should ever
+  appear in a lease file.  An option that might have been named "#144" is
+  now "unknown-144".
+
+- Another patch from Bill Stephens which allows the ping-check timeout to
+  be configured as 'ping-timeout'.  Defaults to 1.
+
+                       Changes since 3.0.1rc10
+
+- Potential buffer overflows in minires repaired.
+
+- A change to the linux client script to use /bin/bash, since /bin/sh may
+  not be bash.
+
+- Some missing va_end cleanups thanks to a patch from Thomas Klausner.
+
+- A correction of boolean parsing syntax validation - some illegal syntaxes
+  that worked before are now detected and produce errs, some legal syntaxes
+  that errored before will now work properly.
+
+- Some search-and-replace errors that caused some options to change their
+  names was repaired.
+
+- Shu-min Chang of the Intel corporation has contributed a perl script and
+  module that converts the MS NT4 DHCP configuration to a ISC DHCP3
+  configuration file.
+
+- Applied the remainder of the dhcpctl memory leak patch provided by Bill
+  Squier at ReefEdge, Inc.  (groo@reefedge.com).
+
+- Missing non-optional failover peer configurations will now result in a soft
+  error rather than a null dereference.
+
+                       Changes since 3.0.1rc9
+
+- A format string was corrected to fix compiler warnings.
+
+- A number of spelling corrections were made in the man pages.
+
+- The dhclient.conf.5 man page was changed to refer to do-forward-updates
+  rather than a configuration option that doesn't exist.
+
+- A FreeBSD-specific bug in the interface removal handling was fixed.
+
+- A Linux-specific Token Ring detection problem was fixed.
+
+- Hashes removed from as-yet-unknown agent options, having those options
+  appear in reality before we know about them will no longer produce
+  self-corrupting lease databases.
+
+- dhclient will use the proper port numbers now when using the -g option.
+
+- A order-of-operations bug with 2 match clauses in 1 class statement is
+  fixed thanks to a patch from Andrew Matheson.
+
+- Compilation problems on Solaris were fixed.
+
+- Compilation problems when built with DEBUG or DEBUG_PACKET were repaired.
+
+- A fix to the dhcp ack process which makes certain group options will be
+  included in the first DHCPOFFER message was made thanks to a patch from
+  Ling Gou.
+
+- A few memory leaks were repaired thanks to patches from Bill Squier at
+  ReefEdge, Inc.  (groo@reefedge.com).
+
+- A fix for shared-networks that sometimes give clients options for the
+  wrong subnets (in particular, 'option routers') was applied, thanks to
+  Ted Lemon for the patch.
+
+- Omshell's handling of dotted octets as values was changed such that dots
+  one after the other produce zero values in the integer string.
+
+                       Changes since 3.0.1rc8
+
+- Fix a format string vulnerability in the server that could lead to a
+  remote root compromise (discovered by NGSEC Research Team, www.ngsec.com).
+
+- Add additional support for NetBSD/sparc64.
+
+- Fix a bug in the command-line parsing of the client.  Also, resolve
+  a memory leak.
+
+- Add better support for shells other than bash in the Linux client
+  script.
+
+- Various build fixes for modern versions of FreeBSD and Linux.
+
+- Fix a bad bounds check when printing binding state names.
+
+- Clarify documentation about fixed-address and multiple addresses.
+
+- Fix a typo in the authoritative error message.
+
+- Make a log entry when we can't write a billing class.
+
+- Use conversion targets that are the right size on all architectures.
+
+- Increment the hop count when relaying.
+
+- Log a message when lease state is changed through OMAPI.
+
+- Don't rerun the shared_network when evaluating the pool.
+
+- Fix a reversed test in the parser.
+
+- Change the type of rbuf_max.
+
+- Make FTS_LAST a manifest constant to quiet warnings.
+
+                       Changes since 3.0.1rc7
+
+- Fix two compiler warnings that are generated when compiling on Solaris
+  with gcc.   These stop the build, even though they weren't actually
+  errors, because we prefer that our builds generate no warnings.
+
+                       Changes since 3.0.1rc6
+
+- Don't allow a lease that's in the EXPIRED, RELEASED or RESET state
+  to be renewed.
+
+- Implement lease stealing for cases where the primary has fewer leases
+  than the secondary, as called for by the standard.
+
+- Add a fudge factor to the lease expiry acceptance code, (suggested
+  by Kevin Miller of CMU).
+
+- Fix a bug in permit_list_match that made it much too willing to say
+  that two permit lists matched.
+
+- Unless DEBUG_DNS_UPDATES is defined, print more user-friendly (and
+  also more compact) messages about DNS updates.
+
+- Fix a bug in generating wire-format domain names for the FQDN option.
+
+- Fix a bug where the FQDN option would not be returned if the client
+  requested it, contrary to the standard.
+
+- On Darwin, use the FreeBSD DHCP client script.
+
+- On NetBSD/sparc, don't check for casting warnings.
+
+- Add a flag in the DHCP client to disable updating the client's A
+  record when sending an FQDN option indicating that the client is
+  going to update its A record.
+
+- In the client, don't attempt a DNS update until one second after
+  configuring the new IP address, and if the update times out, keep
+  trying until a response, positive or negative, is received from the
+  DNS server.
+
+- Fix an uninitialized memory bug in the DHCP client.
+
+- Apply some FreeBSD-specific bug fixes suggested by Murray Stokely.
+
+- Fix a bug in ns_parserr(), where it was returning the wrong sort
+  of result code in some cases (suggested by Ben Harris of the
+  NetBSD project).
+
+- Fix a bug in is_identifier(), where it was checking against EOF
+  instead of the END_OF_FILE token (also suggested by Ben Harris).
+
+- Fix a bug where if an option universe contained no options, the
+  DHCP server could dump core (Walter Steiner).
+
+- Fix a bug in the handling of encapsulated options.
+
+- Fix a bug that prevented NWIP suboptions from being processed.
+
+- Delete the FTS_BOOTP and FTS_RESERVED states and implement them
+  as modifier flags to the FTS_ACTIVE state, as called for in the
+  failover protocol standard.
+
+- Fix bugs in the pool merging code that resulted in references and
+  dereferences of null pointers.   This bug had no impact unless the
+  POINTER_DEBUG flag was defined.
+
+- In the server, added a do-forward-updates flag that can be used to
+  disable forward updates in all cases, so that sites that want the
+  clients to take sole responsibility for updating their A record can
+  do so.
+
+- Make it possible to disable optimization of PTR record updates.
+
+                       Changes since 3.0.1rc5
+
+- Include some new documentation and changes provided by Karl Auer.
+
+- Add a workaround for some Lexmark printers that send a double-NUL-
+  terminated host-name option, which would break DNS updates.
+
+- Fix an off-by-one error in the MAC-address checking code for
+  DHCPRELEASE that was added in 3.0.1rc5.
+
+- Fix a bug where client-specific information was not being discarded
+  from the lease when it expired or was released, resulting in
+  problems if the lease was reallocated to a different client.
+
+- If more than one allocation pool is specified that has the same set
+  of constraints as another allocation pool on the same shared
+  network, merge the two pools.
+
+- Don't print an error in fallback_discard, since this just causes
+  confusion and does not appear to be helping to encourage anyone to
+  fix this bug.
+
+                       Changes since 3.0.1rc4
+
+- Fix a bug that would cause the DHCP server to spin if asked to parse
+  a certain kind of incorrect statement.
+
+- Fix a related bug that would prevent an error from being reported in
+  the same case.
+
+- Additional documentation.
+
+- Make sure that the hardware address matches the lease when
+  processing a DHCPRELEASE message.
+
+                       Changes since 3.0.1rc3
+
+- A minor bug fix in the arguments to a logging function call.
+- Documentation update for dhcpd.conf.
+
+                       Changes since 3.0.1rc2
+
+- Allow the primary to send a POOLREQ message.   This isn't what the current
+  failover draft says to do, so we may have to back it out if I can't get the
+  authors to relent, but the scheme for balancing that's specified in the
+  current draft seems needlessly hairy, so I'm floating a trial balloon.
+  The rc1 code did not implement the method described in the draft either.
+
+                       Changes since 3.0.1rc1
+
+- Treat NXDOMAIN and NXRRSET as success when we are trying to delete a
+  domain or RRSET.   This allows the DHCP server to forget about a name
+  it added to the DNS once it's been removed, even if the DHCP server
+  wasn't the one that removed it.
+
+- Install defaults for failover maximum outstanding updates and maximum
+  silent time.   This prevents problems that might occur if these values
+  were not configured.
+
+- Don't do DDNS deletes if ddns-update-style is none.
+
+- Return relay agent information options in DHCPNAK.   This prevents DHCPNAK
+  messages from being dropped when the relay agent information option contains
+  routing information.
+
+- Fix a problem where coming up in recover wouldn't result in an update
+  request being sent.
+
+- Add some more chatty messages when we start a recovery update and when it's
+  done.
+
+- Fix a possible problem where some state might have been left around
+  after the peer lost contact and regained contact about how many updates
+  were pending.
+
+- Don't nix a lease update because of a lease conflict.   This test has
+  never (as far as I know) prevented a mistake, and it appears to cause
+  problems with failover.
+
+- Add support in rc history code for keeping a selective history, rather
+  than a history of all references and dereferences.   This code is only used
+  when extensive additional debugging is enabled.
+
+                          Changes since 3.0
+
+- Make allocators for hash tables.   As a side effect, this fixes a memory
+  smash in the subclass allocation code.
+
+- Fix a small bug in omshell where if you try to close an object when
+  no object is open, it dumps core.
+
+- Fix an obscure coredump that could occur on shutdown.
+
+- Fix a bug in the recording of host declaration rubouts in the lease file.
+
+- Fix two potential spins in the host deletion code.
+
+- Fix a core dump that would happen if an application tried to update
+  a host object attribute with a null value.
+
+               Changes since 3.0 Release Candidate 12
+
+- Fix a memory leak in the evaluation code.
+
+- Fix an obscure core dump.
+
+- Print a couple of new warnings when parsing the configuration file
+  when crucial information is left out.
+
+- Log "no free leases" as an error.
+
+- Documentation updates.
+
+               Changes since 3.0 Release Candidate 11
+
+- Always return a subnet selection option if one is sent.
+
+- Fix a warning that was being printed because an automatic data
+  structure wasn't zeroed.
+
+- Fix some failover state transitions that were being handled
+  incorrectly.
+
+- When supersede_lease is called on a lease whose end time has already
+  expired, but for which a state transition has not yet been done, do
+  a state transition.   This fixes the case where if the secondary
+  allocated a lease to a client and the lease "expired" while the
+  secondary was in partner-down, no expiry event would actually
+  happen, so the lease would remain active until the primary was
+  restarted.
+
+               Changes since 3.0 Release Candidate 10
+
+- Fix a bug that was preventing released leases from changing state
+  in failover-enabled pools.
+
+- Fix a core dump in the client identifier finder code (for host
+  declarations).
+
+- Finish fixing a bug where bogus data would sometimes get logged to
+  the dhclient.leases file because it was opened as descriptor 2.
+
+- Fix the Linux dhclient-script according to suggestions made by
+  several people on the dhcp-client mailing list.
+
+- Log successful DNS updates at LOG_INFO, not LOG_ERROR.
+
+- Print an error message and refuse to run if a failover peer is
+  defined but not referenced by any pools.
+
+- Correct a confusing error message in failover.
+
+               Changes since 3.0 Release Candidate 9
+
+- Fix a bug in lease allocation for Dynamic BOOTP clients.
+
+         Changes since 3.0 Release Candidate 8 Patchlevel 2
+
+- Fix a bug that prevented update-static-leases from working.
+
+- Document failover-state OMAPI object.
+
+- Fix a compilation error on SunOS 4.
+
+         Changes since 3.0 Release Candidate 8 Patchlevel 1
+
+- Fix a parsing bug that broke dns updates (both interim and ad-hoc).
+  This was introduced in rc8pl1 as an unintended result of the memory
+  leakage fixes that were in pl1.
+
+- Fix a long-standing bug where the server would record that an update
+  had been done for a client with no name, even though no update had
+  been done, and then when the client's lease expired the deletion of
+  that nonexistant record would time out because the name was the null
+  string. 
+
+- Clean up the omshell, dhcpctl and omapi man pages a bit.
+
+               Changes since 3.0 Release Candidate 8
+
+- Fix a bug that could cause the DHCP server to spin if
+  one-lease-per-client was enabled.
+
+- Fix a bug that was causing core dumps on BSD/os in the presence of
+  malformed packets.
+
+- In partner-down state, don't restrict lease lengths to MCLT.
+
+- On the failover secondary, record the MCLT received from the primary
+  so that if we come up without a connection to the primary we don't
+  wind up giving out zero-length leases.
+
+- Fix some compilation problems on BSD/os.
+
+- Fix a bunch of memory leaks.
+
+- Fix a couple of bugs in the option printer.
+
+- Fix an obscure error reporting bug in the dns update code, and also
+  make the message clearer when a key algorithm isn't supported.
+
+- Fix a bug in the tracing code that prevented trace runs that used
+  tcp connections from being played back.
+
+- Add some additional debugging capability for catching memory leaks
+  on exit.
+
+- Make the client release the lease correctly on shutdown.
+
+- Add some configurability to the build system.
+
+- Install omshell manual page in man1, not man8.
+
+- Craig Gwydir sent in a patch that fixes a long-standing bug in the
+  DHCP client that could cause core dumps, but that for some reason
+  hadn't been noticed until now.
+
+               Changes since 3.0 Release Candidate 7
+
+- Fix a bug in failover where we weren't sending updates after a
+  transition from communications-interrupted to normal.
+
+- Handle expired/released/reset -> free transition according to the
+  protocol specification (this works - the other way not only wasn't
+  conformant, but also didn't work).
+
+- Add a control object in both client and server that allows either
+  daemon to be shut down cleanly.
+
+- When writing a lease, if we run out of disk space, shut down the
+  output file and insist on writing a new one before proceeding.
+
+- In the server, if the OMAPI listener port is occupied, keep trying
+  to get it, rather than simply giving up and exiting.
+
+- Support fetching variables from leases and also updating and adding
+  variables to leases via OMAPI.
+
+- If two failover peers have wildly different clocks, refuse to start
+  doing failover.
+
+- Fix a bug in the DNS update code that could cause core dumps when
+  running on alpha processors.
+
+- Fixed a bug in ddns updates for static lease entries, thanks to a
+  patch from Andrey M Linkevitch.
+
+- Add support for Darwin/MacOS X
+
+- Install omshell (including new documentation).
+
+- Support DNS updates in the client (this is a very obscure feature
+  that most DHCP client users probably will not be able to use).
+
+- Somewhat cleaner status logging in the client.
+
+- Make OMAPI key naming syntax compatible with the way keys are
+  actually named (key names are domain names).
+
+- Fix a bug in the lease file writer.
+
+- Install DHCP ISC headers in a different place than BIND 9 ISC
+  headers, to avoid causing trouble in BIND 9 builds.
+
+- Don't send updates for attributes on an object when the attributes
+  haven't changed.   Support deleting attributes on remote objects.
+
+- Fix a number of bugs in omshell, and add the unset and refresh
+  statements.
+
+- Handle disconnects in OMAPI a little bit more intelligently (so that
+  the caller gets ECONNRESET instead of EINVAL).
+
+- Fix a bunch of bugs in the handling of clients that have existing
+  leases when the try to renew their leases while failover is
+  operating.
+
+               Changes since 3.0 Release Candidate 6
+
+- Fix a core dump that could happen when processing a DHCPREQUEST from
+  a client that had a host declaration that contained both a
+  fixed-address declaration and a dhcp-client-identifier option
+  declaration, if the client identifier was longer than nine bytes.
+
+- Fix a memory leak that could happen in certain obscure cases when
+  using omapi to manipulate leases.
+
+- Fix some bugs and omissions in omshell.
+
+
+               Changes since 3.0 Release Candidate 5
+
+- Fix a bug in omapi_object_dereference that prevented objects in
+  chains from having their reference counts decreased on dereference.
+
+- Fix a bug in omapi_object_dereference that would prevent object
+  chains from being freed upon removal of the last reference external
+  to the chain.
+
+- Fix a number of other memory leaks in the OMAPI protocol subsystem.
+
+- Add code in the OMAPI protocol handler to trace memory leakage.
+
+- Clean up the memory allocation/reference history printer.
+
+- Support input of dotted quads and colon-separated hex lists as
+  attribute values in omshell.
+
+- Fix a typo in the Linux interface discovery code.
+
+- Conditionalize a piece of trace code that wasn't conditional.
+
+               Changes since 3.0 Release Candidate 4
+
+- Fix a bug that would prevent leases from being abandoned properly on
+  DHCPDECLINE.
+
+- Fix failover peer OMAPI support.
+
+- In failover, correctly handle expiration of leases.   Previously,
+  leases would never be reclaimed because they couldn't make the
+  transition from EXPIRED to FREE.
+
+- Fix some broken failover state transitions.
+
+- Documentation fixes.
+
+- Take out an unnecessary check in DHCP relay agent information option
+  stashing code that was preventing REBINDING clients from rebinding.
+
+- Prevent failover peers from allocating leases in DHCPREQUEST
+  processing if the lease belongs to the other server.
+
+- Record server version in lease file introductory comment.
+
+- Correctly report connection errors in OMAPI and failover.
+
+- Make authentication signature algorithm name comparisons in OMAPI
+  case-insensitive.
+
+- Fix compile problem on SunOS 4.x
+
+- If a signature algorithm is not terminated with '.', terminate it so
+  that comparisons between fully-qualified names will work
+  consistently.
+
+- Different SIOCGIFCONF probe code, may "fix" problem on some Linux
+  systems with the probe not working correctly.
+
+- Don't allow user to type omapi key on command line of omshell.
+
+               Changes since 3.0 Release Candidate 3
+
+- Do lease billing on startup in a way that I *think* will finally do
+  the billing correctly - the previous method could overbill as a
+  result of duplicate leases.
+
+- Document OMAPI server objects.
+
+         Changes since 3.0 Release Candidate 2 Patchlevel 1
+
+- Fix some problems in the DDNS update code.   Thanks to Albert
+  Herranz for figuring out the main problem.
+
+- Fix some reference counting errors on host entries that were causing
+  core dumps.
+
+- Fix a byte-swap bug in the token ring code, thanks to Jochen
+  Friedrich.
+
+- Fix a bug in lease billing, thanks to Jonas Bulow.
+
+               Changes since 3.0 Release Candidate 2
+
+- Change the conditions under which a DHCPRELEASE is actually
+  committed to be consistent with lease binding states rather than
+  using the lease end time.   This may fix some problems with the
+  billing class code.
+
+- Fix a bug where lease updates would fail on Digital Unix (and maybe
+  others) because malloc was called with a size of zero.
+
+- Fix a core dump that happens when the DHCP server can't create its
+  trace file.
+
+         Changes since 3.0 Release Candidate 1 Patchlevel 1
+
+- Fix the dhcp_failover_put_message to not attempt to allocate a
+  zero-length buffer.   Some versions of malloc() fail if you try to
+  allocate a zero-length buffer, and this was causing problems on,
+  e.g., Digital Unix.
+
+- Fix a case where the failover code was printing an error message
+  when no error had occurred.
+
+- Fix a problem where when a server went down and back up again, the
+  peer would not see a state transition and so would stay in the
+  non-communicating state.
+
+- Be smart about going into recover_wait.
+
+- Fix a problem in the failover implementation where peers would fail
+  to come into sync if interrupted in the RECOVER state.   This could
+  have been the cause of some problems people have reported recently.
+
+- Fix a problem with billing classes where they would not be unbilled
+  when the client lease expired.
+
+- If select fails, figure out which descriptor is bad, and cut it out
+  of the I/O loop.   This prevents a potentially nasty spin.  I
+  haven't heard any report it in a while, but it came up consistently
+  in testing.
+
+- Fix a bug in the relay agent where if you specified interfaces on
+  the command line, it would fail.
+
+- Fix a couple of small bugs in the omapi connection object (no known
+  user impact).
+
+- Add the missing 3.0 Beta 1 lease conversion script.
+
+- Read dhcp client script hooks if they exist, rather than only if
+  they're executable.
+
+               Changes since 3.0 Release Candidate 1
+
+- Fix a memory smash that happens when fixed-address leases are used.
+  ANY SITE AT WHICH FIXED-ADDRESS STATEMENTS ARE BEING USED SHOULD
+  UPGRADE IMMEDIATELY.   This has been a long-standing bug - thanks to
+  Alvise Nobile for discovering it and helping me to find it!
+
+- Fix a small bug in binary-to-ascii, thanks to H. Peter Anvin of
+  Transmeta.
+
+- There is a known problem with the DHCP server doing failover on
+  Compaq Alpha systems.   This patchlevel is not a release candidate
+  because of this bug.   The bug should be straightforward to fix, so
+  a new release candidate is expected shortly.
+
+- There is a known problem in the DDNS update code that is probably a
+  bug, and is not, as far as we know, fixed in this patchlevel.
+
+               Changes since 3.0 Beta 2 Patchlevel 24
+
+- Went over problematic failover state transitions and made them all
+  work, so that failover should now much less fragile.
+
+- Add some dhcpctl and omapi documentation
+
+- Fix compile errors when compiling with unusual predefines.
+
+- Make Token Ring work on Linux 2.4
+
+- Fix the Digital Unix BPF_WORDALIGN bug.
+
+- Fix some dhcp client documentation errors.
+
+- Update some parts of the README file.
+
+- Support GCC on SCO.
+
+               Changes since 3.0 Beta 2 Patchlevel 23
+
+- Fix a bug in the DNS update code where a status code was not being
+  checked.   This may have been causing core dumps.
+
+- When parsing the lease file, if a lease declaration includes a
+  billing class statement, and the lease already has a billing class,
+  unbill the old class.
+
+- When processing failover transactions, where acks will be deferred,
+  process the state transition immediately.
+
+-  Don't try to use the new SIOCGIFCONF buffer size detection code on
+   Linux 2.0, which doesn't provide this functionality.
+
+- Apply a patch suggested by Tuan Uong for a problem in dlpi.c.
+
+- Fix a problem in using the which command in the configure script.
+
+- Fix a parse error in the client when setting up an omapi listener.
+
+- Document the -n and -g flags to the client.
+
+- Make sure there is always a stdin and stdout on startup.   This
+  prevents shell scripts from accidentally writing error messages into
+  configuration files that happen to be opened as stderr.
+
+- If an interface is removed, the client will now notice that it is
+  gone rather than spinning.   This has only been tested on NetBSD.
+
+- The client will attempt to get an address even if it can't create a
+  lease file.
+
+- Don't overwrite tracefiles.
+
+- Fix some memory allocation bugs in failover.
+
+               Changes since 3.0 Beta 2 Patchlevel 22
+
+- Apply some patches suggested by Cyrille Lefevre, who is maintaining
+  the FreeBSD ISC DHCP Distribution port.
+
+- Fix a core dump in DHCPRELEASE.
+
+               Changes since 3.0 Beta 2 Patchlevel 21
+
+- This time for sure: fix the spin described in the changes for pl20.
+
+               Changes since 3.0 Beta 2 Patchlevel 20
+
+- Fix a problem with Linux detecting large numbers of interfaces (Ben)
+
+- Fix a memory smash in the quotify code, which was introduced in
+  pl19.
+
+- Actually fix the spin described in the changes for pl20.   The
+  previous fix only partially fixed the problem - enough to get it
+  past the regression test.
+
+               Changes since 3.0 Beta 2 Patchlevel 19
+
+- Fix a bug that could cause the server to abort if compiled with
+  POINTER_DEBUG enabled.
+
+- Fix a bug that could cause the server to spin when responding to a
+  DHCPREQUEST.
+
+- Apply Joost Mulders' suggested patches for DLPI on x86.
+
+- Support NUL characters in quoted strings.
+
+- Install unformatted man pages on SunOS.
+
+               Changes since 3.0 Beta 2 Patchlevel 18
+
+- Allow the server to be placed in partner-down state using OMAPI.
+  (Damien Neil)
+
+- Implement omshell, which can be used to do arbitrary things to the
+  server (in theory). (Damien Neil)
+
+- Fix a case where if a client had two different leases the server could
+  actually dereference the second one when it hadn't been referenced,
+  leading to memory corruption and a core dump. (James Brister)
+
+- Fix a case where a client could request the address of another client's
+  lease, but find_lease wouldn't detect that the other client had it, and
+  would attempt to allocate it to the client, resulting in a lease conflict
+  message.
+
+- Fix a case where a client with more than one client identifier could be
+  given a lease where the hardware address was correct but the client
+  identifier was not, resulting in a lease conflict message.
+
+- Fix a problem where the server could write out a colon-separated
+  hex list as a value for a variable, which would then not parse.
+  The fix is to always write strings as quoted strings, with any
+  non-printable characters quoted as octal escape sequences.   So
+  a file written the old way still won't work, but new files written
+  this way will work.
+
+- Fix documentation for sending non-standard options.
+
+- Use unparsable names for unknown options.    WARNING: this will
+  break any configuration files that use the option-nnn convention.
+  If you want to continue to use this convention for some options,
+  please be sure to write a definition, like this:
+
+  option option-nnn code nnn = string;
+
+  You can use a descriptive name instead of option-nnn if you like.
+
+- Fix a problem where we would see a DHCPDISCOVER/DHCPOFFER/
+  DHCPREQUEST/DHCPACK/DHCPREQUEST/DHCPNAK sequence.   This was the
+  result of a deceptively silly bug in supersede_lease.
+
+- Fix client script exit status check, according to a fix supplied by
+  Hermann Lauer.
+
+- Fix an endianness bug in the tracefile support, regarding ICMP
+  messages.
+
+- Fix a bug in the client where the medium would not work correctly if
+  it contained quoted strings.
+
+                      ** there was no pl17 **
+
+               Changes since 3.0 Beta 2 Patchlevel 16
+
+- Add support for transaction tracing.   This allows the state of the
+  DHCP server on startup, and all the subsequent transactions, to be
+  recorded in a file which can then be played back to reproduce the
+  behaviour of the DHCP server.   This can be used to quickly
+  reproduce bugs that cause core dumps or corruption, and also for
+  tracking down memory leaks.
+
+- Incorporate some bug fixes provided by Joost Mulders for the DLPI
+  package which should clear up problems people have been seeing on
+  Solaris.
+
+- Fix bugs in the handling of options stored as linked lists (agent
+  options, fqdn options and nwip options) that could cause memory
+  corruption and core dumps.
+
+- Fix a bug in DHCPREQUEST handling that resulted in DHCPNAK messages
+  not being send in some cases when they were needed.
+
+- Make the lease structure somewhat more compact.
+
+- Make initial failover startup *much* faster.   This was researched
+  and implemented by Damien Neil.
+
+- Add a --version flag to all executables, which prints the program
+  name and version to standard output.
+
+- Don't rewrite the lease file every thousand leases.
+
+- A bug in nit.c for older SunOS machines was fixed by a patch sent in
+  by Takeshi Hagiwara.
+
+- Fix a memory corruption bug in the DHCP client.
+
+- Lots of documentation updates.
+
+- Add a feature allowing environment variables to be passed to the
+  DHCP client script on the DHCP client command line.
+
+- Fix client medium support, which had been broken for some time.
+
+- Fix a bug in the DHCP client initial startup backoff interval, which
+  would cause two DHCPDISCOVERS to be sent back-to-back on startup.
+
+
+               Changes since 3.0 Beta 2 Patchlevel 15
+
+- Some documentation tweaks.
+
+- Maybe fix a problem in the DLPI code.
+
+- Fix some error code space inconsistencies in ddns update code.
+
+- Support relay agents that intercept unicast DHCP messages to stuff
+  agent options into them.
+
+- Fix a small memory leak in the relay agent option support code.
+
+- Fix a core dump that would occur if a packet was sent with no
+  options.
+
+               Changes since 3.0 Beta 2 Patchlevel 14
+
+- Finish fixing a long-standing bug in the agent options code.   This
+  was causing core dumps and failing to operate correctly - in
+  particular, agent option stashing wasn't working.   Agent option
+  stashing should now be working, meaning that agent options can be
+  used in class statements to control address allocation.
+
+- Fix up documentation.
+
+- Fix a couple of small memory leaks that would have added up
+  significantly in a high-demand situation.
+
+- Add a log-facility configuration parameter.
+
+- Fix a compile error on some older operating systems.
+
+- Add the ability in the client to execute certain statements before
+  transmitting packets to the server.   Handy for debugging; not much
+  practical use otherwise.
+
+- Don't send faked-out giaddr when renewing or bound - again, useful
+  for debugging.
+
+               Changes since 3.0 Beta 2 Patchlevel 13
+
+- Fixed a problem where the fqdn decoder would sometimes try to store
+  an option with an (unsigned) negative length, resulting in a core
+  dump on some systems.
+
+- Work around the Win98 DHCP client, which NUL-terminates the FQDN
+  option.
+
+- Work around Win98 and Win2k clients that will claim they want to do
+  the update even when they don't have any way to do it.
+
+- Fix some log messages that can be printed when failover is operating
+  that were not printing enough information.
+
+- It was possible for a DHCPDISCOVER to get an allocation even when
+  the state machine said the server shouldn't be responding.
+
+- Don't load balance DHCPREQUESTs from clients in RENEWING and
+  REBINDING, since in RENEWING, if we heard it, it's for us, and in
+  REBINDING, the client wouldn't have got to REBINDING if its primary
+  were answering.
+
+- When we get a bogus state lease binding state transition, don't do
+  the transition.
+  
+
+               Changes since 3.0 Beta 2 Patchlevel 12
+
+- Fixed a couple of silly compile errors.
+
+               Changes since 3.0 Beta 2 Patchlevel 11
+
+- Albert Herranz tracked down and fixed a subtle bug in the base64
+  decoder that would prevent any key with an 'x' in its base64
+  representation from working correctly.
+
+- Thanks to Chris Cheney and Michael Sanders, we have a fix for the
+  hang that they both spotted in the DHCP server - when
+  one-lease-per-client was set, the code to release the "other" lease
+  could spin.
+
+- Fix a problem with alignment of the input buffer in bpf in cases
+  where two packets arrive in the same bpf read.
+
+- Fix a problem where the relay agent would crash if you specified an
+  interface name on the command line.
+
+- Add the ability to conditionalize client behaviour based on the
+  client state.
+
+- Add support for the FQDN option, and added support for a new way of
+  doing ddns updates (ddns update style interim) that allows more than
+  one DHCP server to update the DNS for the same network(s).   This
+  was implemented by Damien Neil with some additional functionality
+  added by Ted Lemon.
+
+- Damien added a "log" statement, so that the configuration file can
+  be made to log debugging information and other information.
+
+- Fixed a bug that caused option buffers not to be terminated with an
+  end option.
+
+- Fixed a long-standing bug in the support for option spaces where the
+  options are stored as an ordered list rather than in a hash table,
+  which could theoretically result in memory pool corruption.
+
+- Prevent hardware declarations with no actual hardware address from
+  being written as something unparsable, and behave correctly in the
+  face of a null hardware address on input.
+
+- Allow key names to be FQDNs, and qualify the algorithm name if it is
+  specified unqualified.
+
+- Modify the DDNS update code so that it never prints the "resolver
+  failed" message, but instead says *why* the resolver failed.
+
+- Officially support the subnet selection option, which now has an
+  RFC.
+
+- Fix a build bug on MacOS X.
+
+- Allow administrator to disable ping checking.
+
+- Clean up dhcpd.conf documentation and add more information about how
+  it works.
+
+               Changes since 3.0 Beta 2 Patchlevel 10
+
+- Fix a bug introduced during debugging (!) and accidentally committed
+  to CVS.
+
+               Changes since 3.0 Beta 2 Patchlevel 9
+
+- Fix DHCP client handling of vendor encapsulated options.
+
+- Fix a bug in the handling of relay agent information options introduced
+  in patchlevel 9.
+
+- Stash agent options on client leases by default, and use the stashed
+  options at renewal time.
+
+- Add the ability to test the client's binding state in the client
+  configuration language.
+
+- Fix a core dump in the DNS update code.
+
+- Fix some expression evaluation bugs that were causing updates to be
+  done when no client hostname was received.
+
+- Fix expression evaluation debugging printfs.
+
+- Teach pretty_print_option to print options in option spaces other than
+  the DHCP option space.
+
+- Add a warning message if the RHS of a not is not boolean.
+
+- Never select for more than a day, because some implementations of
+  select will just fail if the timeout is too long (!).
+
+- Fix a case where a DHCPDISCOVER from an unknown network would be
+  silently dropped.
+
+- Fix a bug where if a client requested an IP address for which a different
+  client had the lease, the DHCP server would reallocate it anyway.
+
+- Fix the DNS update code so that if the client changes its name, the DNS
+  will be correctly updated.
+
+               Changes since 3.0 Beta 2 Patchlevel 8
+
+- Oops, there was another subtle math error in the header-length
+  bounds-checking.
+
+               Changes since 3.0 Beta 2 Patchlevel 7
+
+- Oops, forgot to byte-swap udp header length before bounds-checking it.
+
+               Changes since 3.0 Beta 2 Patchlevel 6
+
+- Fix a possible DoS attack where a client could cause the checksummer
+  to dump core.   This was a read, not a write, so it shouldn't be
+  possible to exploit it any further than that.
+
+- Implement client- and server-side support for using the Client FQDN
+  option.
+
+- Support for other option spaces in the client has been added.   This
+  means that it is now possible to define a vendor option space on the
+  client, request options in that space from the server (which must
+  define the same option space), and then use those options in the
+  client.   This also allows NWIP and Client FQDN options to be used
+  meaningfully.
+
+- Add object initializer support.   This means that objects can now be
+  initialized to something other than all-zeros when allocated, which
+  makes, e.g., the interface object support code a little more robust.
+
+- Fix an off-by-one bug in the host stuffer.   This was causing host
+  deletes not the work, and may also have been causing OMAPI
+  connections to get dropped.   Thanks to James Brister for tracking
+  this one down!
+
+- Fixed a core dump in the interface discovery code that is triggered
+  when there is no subnet declaration for an interface, but the server
+  decides to continue running.   Thanks to Shane Kerr for tracking
+  down and fixing this problem.
+
+               Changes since 3.0 Beta 2 Patchlevel 5
+
+- Fix a bug in the recent enhancement to the interface discovery code
+  to support arbitrary-length interface lists.
+
+- Support NUL-terminated DHCP options when initializing client-script
+  environment.
+
+- Fix suffix operator.
+
+- Fix NetWare/IP option parsing.
+
+- Better error/status checking in dhcpctl initialization and omapi
+  connection code.
+
+- Fix a potential memory smash in dhcpctl code.
+
+- Fix SunOS4 and (maybe) Ultrix builds.
+
+- Fix a bug where a certain sort of incoming packet could cause a core
+  dump on Solaris (and probably elsewhere).
+
+- Add some more safety checks in error logging code.
+
+- Add support for ISC_R_INCOMPLETE in OMAPI protocol connection code.
+
+- Fix relay agent so that if an interface is specified on the command
+  line, the relay agent does not dump core.
+
+- Fix class matching so that match if can be combined with match or
+  spawn with.
+
+- Do not allow spurious leases in the lease database to introduce
+  potentially bogus leases into the in-memory database.
+
+- Fix a byte-order problem in the client hardware address type code
+  for OMAPI.
+
+- Be slightly less picky about what sort of hardware addresses OMAPI
+  can install in host declarations.
+
+               Changes since 3.0 Beta 2 Patchlevel 4
+
+- Incorporated Peter Marschall's proposed change to array/record
+  parsing, which allows things like the slp-agent option to be encoded
+  correctly.   Thanks very much to Peter for taking the initiative to
+  do this, and for doing such a careful job of it (e.g., updating the
+  comments)!
+
+- Added an encoding for the slp-agent option.   :')
+
+- Fixed SunOS 4 build.  Thanks to Robert Elz for responding to my
+  request for help on this with patches!
+
+- Incorporated a change that should fix a problem reported by Philippe
+  Jumelle where when the network connection between two servers is
+  lost, they never reconnect.
+
+- Fix client script files other than that for NetBSD to actually use
+  make_resolv_conf as documented in the manual page.
+
+- Fix a bug in the packet handling code that could result in a core
+  dump.
+
+- Fix a bug in the bootp code where responses on the local net would
+  be sent to the wrong MAC address.   Thanks to Jerry Schave for
+  catching this one.
+
+               Changes since 3.0 Beta 2 Patchlevel 3
+
+- In the DHCP client, execute client statements prior to using the values
+  of options, so that the client configuration can overried, e.g., the
+  lease renewal time.
+
+- Fix a reference counting error that would result in very reproducible
+  failures in updates, as well as occasional core dumps, if a zone was
+  declared without a key.
+
+- Fix some Linux 2.0 compilation problems.
+
+- Fix a bug in scope evaluation during execution of "on" statements that
+  caused values not to be recorded on leases.
+
+- If the dhcp-max-message-size option is specified in scope, and the
+  client didn't send this option, use the one specified in scope to
+  determine the maximum size of the response.
+
+               Changes since 3.0 Beta 2 Patchlevel 2
+
+- Fix a case where spawning subclasses were being allocated
+  incorrectly, resulting in a core dump.
+
+- Fix a case where the DHCP server might inappropriately NAK a
+  RENEWING client.
+
+- Fix a place dhcprequest() where static leases could leak.
+
+- Include memory.h in omapip_p.h so that we don't get warnings about
+  using memcmp().
+
+               Changes since 3.0 Beta 2 Patchlevel 1
+
+- Notice when SIOCFIGCONF returns more data than fit in the buffer -
+  allocate a larger buffer, and retry.   Thanks to Greg Fausak for
+  pointing this out.
+
+- In the server, if no interfaces were configured, report an error and
+  exit.
+
+- Don't ever record a state of 'startup'.
+
+- Don't try to evaluate the local failover binding address if none was
+  specified.   Thanks to Joseph Breu for finding this.
diff --git a/contrib/dhcp-3.0/client/clparse.c b/contrib/dhcp-3.0/client/clparse.c
new file mode 100644 (file)
index 0000000..e5079a1
--- /dev/null
@@ -0,0 +1,1170 @@
+/* clparse.c
+
+   Parser for dhclient config and lease files... */
+
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996-2003 by Internet Software Consortium
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *   Internet Systems Consortium, Inc.
+ *   950 Charter Street
+ *   Redwood City, CA 94063
+ *   <info@isc.org>
+ *   http://www.isc.org/
+ *
+ * This software has been written for Internet Systems Consortium
+ * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
+ * To learn more about Internet Systems Consortium, see
+ * ``http://www.isc.org/''.  To learn more about Vixie Enterprises,
+ * see ``http://www.vix.com''.   To learn more about Nominum, Inc., see
+ * ``http://www.nominum.com''.
+ */
+
+#ifndef lint
+static char copyright[] =
+"$Id: clparse.c,v 1.62.2.7 2004/11/24 17:39:14 dhankins Exp $ Copyright (c) 2004 Internet Systems Consortium.  All rights reserved.\n";
+#endif /* not lint */
+
+#include "dhcpd.h"
+
+static TIME parsed_time;
+
+struct client_config top_level_config;
+
+u_int32_t default_requested_options [] = {
+       DHO_SUBNET_MASK,
+       DHO_BROADCAST_ADDRESS,
+       DHO_TIME_OFFSET,
+       DHO_ROUTERS,
+       DHO_DOMAIN_NAME,
+       DHO_DOMAIN_NAME_SERVERS,
+       DHO_HOST_NAME,
+       0
+};
+
+/* client-conf-file :== client-declarations END_OF_FILE
+   client-declarations :== <nil>
+                        | client-declaration
+                        | client-declarations client-declaration */
+
+isc_result_t read_client_conf ()
+{
+       struct client_config *config;
+       struct client_state *state;
+       struct interface_info *ip;
+       isc_result_t status;
+
+       /* Set up the initial dhcp option universe. */
+       initialize_common_option_spaces ();
+
+       /* 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 = P_ACCEPT;
+       top_level_config.script_name = path_dhclient_script;
+       top_level_config.requested_options = default_requested_options;
+       top_level_config.omapi_port = -1;
+       top_level_config.do_forward_update = 1;
+
+       group_allocate (&top_level_config.on_receipt, MDL);
+       if (!top_level_config.on_receipt)
+               log_fatal ("no memory for top-level on_receipt group");
+
+       group_allocate (&top_level_config.on_transmission, MDL);
+       if (!top_level_config.on_transmission)
+               log_fatal ("no memory for top-level on_transmission group");
+
+       status = read_client_conf_file (path_dhclient_conf,
+                                       (struct interface_info *)0,
+                                       &top_level_config);
+       if (status != ISC_R_SUCCESS) {
+               ;
+#ifdef LATER
+               /* Set up the standard name service updater routine. */
+               parse = (struct parse *)0;
+               status = new_parse (&parse, -1, default_client_config,
+                                   (sizeof default_client_config) - 1,
+                                   "default client configuration", 0);
+               if (status != ISC_R_SUCCESS)
+                       log_fatal ("can't begin default client config!");
+
+               do {
+                       token = peek_token (&val, (unsigned *)0, cfile);
+                       if (token == END_OF_FILE)
+                               break;
+                       parse_client_statement (cfile,
+                                               (struct interface_info *)0,
+                                               &top_level_config);
+               } while (1);
+               end_parse (&parse);
+#endif
+       }
+
+       /* Set up state and config structures for clients that don't
+          have per-interface configuration statements. */
+       config = (struct client_config *)0;
+       for (ip = interfaces; ip; ip = ip -> next) {
+               if (!ip -> client) {
+                       ip -> client = (struct client_state *)
+                               dmalloc (sizeof (struct client_state), MDL);
+                       if (!ip -> client)
+                               log_fatal ("no memory for client state.");
+                       memset (ip -> client, 0, sizeof *(ip -> client));
+                       ip -> client -> interface = ip;
+               }
+
+               if (!ip -> client -> config) {
+                       if (!config) {
+                               config = (struct client_config *)
+                                       dmalloc (sizeof (struct client_config),
+                                                MDL);
+                               if (!config)
+                                   log_fatal ("no memory for client config.");
+                               memcpy (config, &top_level_config,
+                                       sizeof top_level_config);
+                       }
+                       ip -> client -> config = config;
+               }
+       }
+       return status;
+}
+
+int read_client_conf_file (const char *name, struct interface_info *ip,
+                          struct client_config *client)
+{
+       int file;
+       struct parse *cfile;
+       const char *val;
+       int token;
+       isc_result_t status;
+       
+       if ((file = open (name, O_RDONLY)) < 0)
+               return uerr2isc (errno);
+
+       cfile = (struct parse *)0;
+       new_parse (&cfile, file, (char *)0, 0, path_dhclient_conf, 0);
+
+       do {
+               token = peek_token (&val, (unsigned *)0, cfile);
+               if (token == END_OF_FILE)
+                       break;
+               parse_client_statement (cfile, ip, client);
+       } while (1);
+       token = next_token (&val, (unsigned *)0, cfile);
+       status = (cfile -> warnings_occurred
+                 ? ISC_R_BADPARSE
+                 : ISC_R_SUCCESS);
+       close (file);
+       end_parse (&cfile);
+       return status;
+}
+
+
+/* lease-file :== client-lease-statements END_OF_FILE
+   client-lease-statements :== <nil>
+                    | client-lease-statements LEASE client-lease-statement */
+
+void read_client_leases ()
+{
+       int file;
+       struct parse *cfile;
+       const char *val;
+       int token;
+
+       /* Open the lease file.   If we can't open it, just return -
+          we can safely trust the server to remember our state. */
+       if ((file = open (path_dhclient_db, O_RDONLY)) < 0)
+               return;
+       cfile = (struct parse *)0;
+       new_parse (&cfile, file, (char *)0, 0, path_dhclient_db, 0);
+
+       do {
+               token = next_token (&val, (unsigned *)0, cfile);
+               if (token == END_OF_FILE)
+                       break;
+               if (token != LEASE) {
+                       log_error ("Corrupt lease file - possible data loss!");
+                       skip_to_semi (cfile);
+                       break;
+               } else
+                       parse_client_lease_statement (cfile, 0);
+
+       } while (1);
+
+       close (file);
+       end_parse (&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 |
+       VENDOR_SPACE string |
+       interface-declaration |
+       LEASE client-lease-statement |
+       ALIAS client-lease-statement |
+       KEY key-definition */
+
+void parse_client_statement (cfile, ip, config)
+       struct parse *cfile;
+       struct interface_info *ip;
+       struct client_config *config;
+{
+       int token;
+       const char *val;
+       struct option *option;
+       struct executable_statement *stmt, **p;
+       enum statement_op op;
+       int lose;
+       char *name;
+       struct data_string key_id;
+       enum policy policy;
+       int known;
+       int tmp, i;
+       isc_result_t status;
+
+       switch (peek_token (&val, (unsigned *)0, cfile)) {
+             case INCLUDE:
+               next_token (&val, (unsigned *)0, cfile);
+               token = next_token (&val, (unsigned *)0, cfile);
+               if (token != STRING) {
+                       parse_warn (cfile, "filename string expected.");
+                       skip_to_semi (cfile);
+               } else {
+                       status = read_client_conf_file (val, ip, config);
+                       if (status != ISC_R_SUCCESS)
+                               parse_warn (cfile, "%s: bad parse.", val);
+                       parse_semi (cfile);
+               }
+               return;
+               
+             case KEY:
+               next_token (&val, (unsigned *)0, cfile);
+               if (ip) {
+                       /* This may seem arbitrary, but there's a reason for
+                          doing it: the authentication key database is not
+                          scoped.  If we allow the user to declare a key other
+                          than in the outer scope, the user is very likely to
+                          believe that the key will only be used in that
+                          scope.  If the user only wants the key to be used on
+                          one interface, because it's known that the other
+                          interface may be connected to an insecure net and
+                          the secret key is considered sensitive, we don't
+                          want to lull them into believing they've gotten
+                          their way.   This is a bit contrived, but people
+                          tend not to be entirely rational about security. */
+                       parse_warn (cfile, "key definition not allowed here.");
+                       skip_to_semi (cfile);
+                       break;
+               }
+               parse_key (cfile);
+               return;
+
+               /* REQUIRE can either start a policy statement or a
+                  comma-seperated list of names of required options. */
+             case REQUIRE:
+               next_token (&val, (unsigned *)0, cfile);
+               token = peek_token (&val, (unsigned *)0, cfile);
+               if (token == AUTHENTICATION) {
+                       policy = P_REQUIRE;
+                       goto do_policy;
+               }
+               parse_option_list (cfile, &config -> required_options);
+               return;
+
+             case IGNORE:
+               next_token (&val, (unsigned *)0, cfile);
+               policy = P_IGNORE;
+               goto do_policy;
+
+             case ACCEPT:
+               next_token (&val, (unsigned *)0, cfile);
+               policy = P_ACCEPT;
+               goto do_policy;
+
+             case PREFER:
+               next_token (&val, (unsigned *)0, cfile);
+               policy = P_PREFER;
+               goto do_policy;
+
+             case DONT:
+               next_token (&val, (unsigned *)0, cfile);
+               policy = P_DONT;
+               goto do_policy;
+
+             do_policy:
+               token = next_token (&val, (unsigned *)0, cfile);
+               if (token == AUTHENTICATION) {
+                       if (policy != P_PREFER &&
+                           policy != P_REQUIRE &&
+                           policy != P_DONT) {
+                               parse_warn (cfile,
+                                           "invalid authentication policy.");
+                               skip_to_semi (cfile);
+                               return;
+                       }
+                       config -> auth_policy = policy;
+               } else if (token != TOKEN_BOOTP) {
+                       if (policy != P_PREFER &&
+                           policy != P_IGNORE &&
+                           policy != P_ACCEPT) {
+                               parse_warn (cfile, "invalid bootp policy.");
+                               skip_to_semi (cfile);
+                               return;
+                       }
+                       config -> bootp_policy = policy;
+               } else {
+                       parse_warn (cfile, "expecting a policy type.");
+                       skip_to_semi (cfile);
+                       return;
+               } 
+               break;
+
+             case OPTION:
+               token = next_token (&val, (unsigned *)0, cfile);
+
+               token = peek_token (&val, (unsigned *)0, cfile);
+               if (token == SPACE) {
+                       if (ip) {
+                               parse_warn (cfile,
+                                           "option space definitions %s",
+                                           " may not be scoped.");
+                               skip_to_semi (cfile);
+                               break;
+                       }
+                       parse_option_space_decl (cfile);
+                       return;
+               }
+
+               option = parse_option_name (cfile, 1, &known);
+               if (!option)
+                       return;
+
+               token = next_token (&val, (unsigned *)0, cfile);
+               if (token != CODE) {
+                       parse_warn (cfile, "expecting \"code\" keyword.");
+                       skip_to_semi (cfile);
+                       free_option (option, MDL);
+                       return;
+               }
+               if (ip) {
+                       parse_warn (cfile,
+                                   "option definitions may only appear in %s",
+                                   "the outermost scope.");
+                       skip_to_semi (cfile);
+                       free_option (option, MDL);
+                       return;
+               }
+               if (!parse_option_code_definition (cfile, option))
+                       free_option (option, MDL);
+               return;
+
+             case MEDIA:
+               token = next_token (&val, (unsigned *)0, cfile);
+               parse_string_list (cfile, &config -> media, 1);
+               return;
+
+             case HARDWARE:
+               token = next_token (&val, (unsigned *)0, cfile);
+               if (ip) {
+                       parse_hardware_param (cfile, &ip -> hw_address);
+               } else {
+                       parse_warn (cfile, "hardware address parameter %s",
+                                   "not allowed here.");
+                       skip_to_semi (cfile);
+               }
+               return;
+
+             case REQUEST:
+               token = next_token (&val, (unsigned *)0, cfile);
+               if (config -> requested_options == default_requested_options)
+                       config -> requested_options = (u_int32_t *)0;
+               parse_option_list (cfile, &config -> requested_options);
+               return;
+
+             case TIMEOUT:
+               token = next_token (&val, (unsigned *)0, cfile);
+               parse_lease_time (cfile, &config -> timeout);
+               return;
+
+             case RETRY:
+               token = next_token (&val, (unsigned *)0, cfile);
+               parse_lease_time (cfile, &config -> retry_interval);
+               return;
+
+             case SELECT_TIMEOUT:
+               token = next_token (&val, (unsigned *)0, cfile);
+               parse_lease_time (cfile, &config -> select_interval);
+               return;
+
+             case OMAPI:
+               token = next_token (&val, (unsigned *)0, cfile);
+               token = next_token (&val, (unsigned *)0, cfile);
+               if (token != PORT) {
+                       parse_warn (cfile,
+                                   "unexpected omapi subtype: %s", val);
+                       skip_to_semi (cfile);
+                       return;
+               }
+               token = next_token (&val, (unsigned *)0, cfile);
+               if (token != NUMBER) {
+                       parse_warn (cfile, "invalid port number: `%s'", val);
+                       skip_to_semi (cfile);
+                       return;
+               }
+               tmp = atoi (val);
+               if (tmp < 0 || tmp > 65535)
+                       parse_warn (cfile, "invalid omapi port %d.", tmp);
+               else if (config != &top_level_config)
+                       parse_warn (cfile,
+                                   "omapi port only works at top level.");
+               else
+                       config -> omapi_port = tmp;
+               parse_semi (cfile);
+               return;
+               
+             case DO_FORWARD_UPDATE:
+               token = next_token (&val, (unsigned *)0, cfile);
+               token = next_token (&val, (unsigned *)0, cfile);
+               if (!strcasecmp (val, "on") ||
+                   !strcasecmp (val, "true"))
+                       config -> do_forward_update = 1;
+               else if (!strcasecmp (val, "off") ||
+                        !strcasecmp (val, "false"))
+                       config -> do_forward_update = 0;
+               else {
+                       parse_warn (cfile, "expecting boolean value.");
+                       skip_to_semi (cfile);
+                       return;
+               }
+               parse_semi (cfile);
+               return;
+
+             case REBOOT:
+               token = next_token (&val, (unsigned *)0, cfile);
+               parse_lease_time (cfile, &config -> reboot_timeout);
+               return;
+
+             case BACKOFF_CUTOFF:
+               token = next_token (&val, (unsigned *)0, cfile);
+               parse_lease_time (cfile, &config -> backoff_cutoff);
+               return;
+
+             case INITIAL_INTERVAL:
+               token = next_token (&val, (unsigned *)0, cfile);
+               parse_lease_time (cfile, &config -> initial_interval);
+               return;
+
+             case SCRIPT:
+               token = next_token (&val, (unsigned *)0, cfile);
+               parse_string (cfile, &config -> script_name, (unsigned *)0);
+               return;
+
+             case VENDOR:
+               token = next_token (&val, (unsigned *)0, cfile);
+               token = next_token (&val, (unsigned *)0, cfile);
+               if (token != OPTION) {
+                       parse_warn (cfile, "expecting 'vendor option space'");
+                       skip_to_semi (cfile);
+                       return;
+               }
+               token = next_token (&val, (unsigned *)0, cfile);
+               if (token != SPACE) {
+                       parse_warn (cfile, "expecting 'vendor option space'");
+                       skip_to_semi (cfile);
+                       return;
+               }
+               token = next_token (&val, (unsigned *)0, cfile);
+               if (!is_identifier (token)) {
+                       parse_warn (cfile, "expecting an identifier.");
+                       skip_to_semi (cfile);
+                       return;
+               }
+               config -> vendor_space_name = dmalloc (strlen (val) + 1, MDL);
+               if (!config -> vendor_space_name)
+                       log_fatal ("no memory for vendor option space name.");
+               strcpy (config -> vendor_space_name, val);
+               for (i = 0; i < universe_count; i++)
+                       if (!strcmp (universes [i] -> name,
+                                    config -> vendor_space_name))
+                               break;
+               if (i == universe_count) {
+                       log_error ("vendor option space %s not found.",
+                                  config -> vendor_space_name);
+               }
+               parse_semi (cfile);
+               return;
+
+             case INTERFACE:
+               token = next_token (&val, (unsigned *)0, cfile);
+               if (ip)
+                       parse_warn (cfile, "nested interface declaration.");
+               parse_interface_declaration (cfile, config, (char *)0);
+               return;
+
+             case PSEUDO:
+               token = next_token (&val, (unsigned *)0, cfile);
+               token = next_token (&val, (unsigned *)0, cfile);
+               name = dmalloc (strlen (val) + 1, MDL);
+               if (!name)
+                       log_fatal ("no memory for pseudo interface name");
+               strcpy (name, val);
+               parse_interface_declaration (cfile, config, name);
+               return;
+               
+             case LEASE:
+               token = next_token (&val, (unsigned *)0, cfile);
+               parse_client_lease_statement (cfile, 1);
+               return;
+
+             case ALIAS:
+               token = next_token (&val, (unsigned *)0, cfile);
+               parse_client_lease_statement (cfile, 2);
+               return;
+
+             case REJECT:
+               token = next_token (&val, (unsigned *)0, cfile);
+               parse_reject_statement (cfile, config);
+               return;
+
+             default:
+               lose = 0;
+               stmt = (struct executable_statement *)0;
+               if (!parse_executable_statement (&stmt,
+                                                cfile, &lose, context_any)) {
+                       if (!lose) {
+                               parse_warn (cfile, "expecting a statement.");
+                               skip_to_semi (cfile);
+                       }
+               } else {
+                       struct executable_statement **eptr, *sptr;
+                       if (stmt &&
+                           (stmt -> op == send_option_statement ||
+                            (stmt -> op == on_statement &&
+                             (stmt -> data.on.evtypes & ON_TRANSMISSION)))) {
+                           eptr = &config -> on_transmission -> statements;
+                           if (stmt -> op == on_statement) {
+                                   sptr = (struct executable_statement *)0;
+                                   executable_statement_reference
+                                           (&sptr,
+                                            stmt -> data.on.statements, MDL);
+                                   executable_statement_dereference (&stmt,
+                                                                     MDL);
+                                   executable_statement_reference (&stmt,
+                                                                   sptr,
+                                                                   MDL);
+                                   executable_statement_dereference (&sptr,
+                                                                     MDL);
+                           }
+                       } else
+                           eptr = &config -> on_receipt -> statements;
+
+                       if (stmt) {
+                               for (; *eptr; eptr = &(*eptr) -> next)
+                                       ;
+                               executable_statement_reference (eptr,
+                                                               stmt, MDL);
+                       }
+                       return;
+               }
+               break;
+       }
+       parse_semi (cfile);
+}
+
+/* option-list :== option_name |
+                  option_list COMMA option_name */
+
+void parse_option_list (cfile, list)
+       struct parse *cfile;
+       u_int32_t **list;
+{
+       int ix;
+       int token;
+       const char *val;
+       pair p = (pair)0, q = (pair)0, r;
+       struct option *option;
+
+       ix = 0;
+       do {
+               token = peek_token (&val, (unsigned *)0, cfile);
+               if (token == SEMI) {
+                       token = next_token (&val, (unsigned *)0, cfile);
+                       break;
+               }
+               if (!is_identifier (token)) {
+                       parse_warn (cfile, "%s: expected option name.", val);
+                       token = next_token (&val, (unsigned *)0, cfile);
+                       skip_to_semi (cfile);
+                       return;
+               }
+               option = parse_option_name (cfile, 0, NULL);
+               if (!option) {
+                       parse_warn (cfile, "%s: expected option name.", val);
+                       return;
+               }
+               if (option -> universe != &dhcp_universe) {
+                       parse_warn (cfile,
+                               "%s.%s: Only global options allowed.",
+                               option -> universe -> name, option->name );
+                       skip_to_semi (cfile);
+                       return;
+               }
+               r = new_pair (MDL);
+               if (!r)
+                       log_fatal ("can't allocate pair for option code.");
+               r -> car = (caddr_t)(long)option -> code;
+               r -> cdr = (pair)0;
+               if (p)
+                       q -> cdr = r;
+               else
+                       p = r;
+               q = r;
+               ++ix;
+               token = next_token (&val, (unsigned *)0, cfile);
+       } while (token == COMMA);
+       if (token != SEMI) {
+               parse_warn (cfile, "expecting semicolon.");
+               skip_to_semi (cfile);
+               return;
+       }
+       /* XXX we can't free the list here, because we may have copied
+          XXX it from an outer config state. */
+       *list = (u_int32_t *)0;
+       if (ix) {
+               *list = dmalloc ((ix + 1) * sizeof **list, MDL);
+               if (!*list)
+                       log_error ("no memory for option list.");
+               else {
+                       ix = 0;
+                       for (q = p; q; q = q -> cdr)
+                               (*list) [ix++] = (u_int32_t)(long)q -> car;
+                       (*list) [ix] = 0;
+               }
+               while (p) {
+                       q = p -> cdr;
+                       free_pair (p, MDL);
+                       p = q;
+               }
+       }
+}
+
+/* interface-declaration :==
+       INTERFACE string LBRACE client-declarations RBRACE */
+
+void parse_interface_declaration (cfile, outer_config, name)
+       struct parse *cfile;
+       struct client_config *outer_config;
+       char *name;
+{
+       int token;
+       const char *val;
+       struct client_state *client, **cp;
+       struct interface_info *ip = (struct interface_info *)0;
+
+       token = next_token (&val, (unsigned *)0, cfile);
+       if (token != STRING) {
+               parse_warn (cfile, "expecting interface name (in quotes).");
+               skip_to_semi (cfile);
+               return;
+       }
+
+       if (!interface_or_dummy (&ip, val))
+               log_fatal ("Can't allocate interface %s.", val);
+
+       /* If we were given a name, this is a pseudo-interface. */
+       if (name) {
+               make_client_state (&client);
+               client -> name = name;
+               client -> interface = ip;
+               for (cp = &ip -> client; *cp; cp = &((*cp) -> next))
+                       ;
+               *cp = client;
+       } else {
+               if (!ip -> client) {
+                       make_client_state (&ip -> client);
+                       ip -> client -> interface = ip;
+               }
+               client = ip -> client;
+       }
+
+       if (!client -> config)
+               make_client_config (client, outer_config);
+
+       ip -> flags &= ~INTERFACE_AUTOMATIC;
+       interfaces_requested = 1;
+
+       token = next_token (&val, (unsigned *)0, cfile);
+       if (token != LBRACE) {
+               parse_warn (cfile, "expecting left brace.");
+               skip_to_semi (cfile);
+               return;
+       }
+
+       do {
+               token = peek_token (&val, (unsigned *)0, cfile);
+               if (token == END_OF_FILE) {
+                       parse_warn (cfile,
+                                   "unterminated interface declaration.");
+                       return;
+               }
+               if (token == RBRACE)
+                       break;
+               parse_client_statement (cfile, ip, client -> config);
+       } while (1);
+       token = next_token (&val, (unsigned *)0, cfile);
+}
+
+int interface_or_dummy (struct interface_info **pi, const char *name)
+{
+       struct interface_info *i;
+       struct interface_info *ip = (struct interface_info *)0;
+       isc_result_t status;
+
+       /* Find the interface (if any) that matches the name. */
+       for (i = interfaces; i; i = i -> next) {
+               if (!strcmp (i -> name, name)) {
+                       interface_reference (&ip, i, MDL);
+                       break;
+               }
+       }
+
+       /* If it's not a real interface, see if it's on the dummy list. */
+       if (!ip) {
+               for (ip = dummy_interfaces; ip; ip = ip -> next) {
+                       if (!strcmp (ip -> name, name)) {
+                               interface_reference (&ip, i, MDL);
+                               break;
+                       }
+               }
+       }
+
+       /* If we didn't find an interface, make a dummy interface as
+          a placeholder. */
+       if (!ip) {
+               if ((status = interface_allocate (&ip, MDL)) != ISC_R_SUCCESS)
+                       log_fatal ("Can't record interface %s: %s",
+                                  name, isc_result_totext (status));
+               strcpy (ip -> name, name);
+               if (dummy_interfaces) {
+                       interface_reference (&ip -> next,
+                                            dummy_interfaces, MDL);
+                       interface_dereference (&dummy_interfaces, MDL);
+               }
+               interface_reference (&dummy_interfaces, ip, MDL);
+       }
+       if (pi)
+               status = interface_reference (pi, ip, MDL);
+       else
+               status = ISC_R_FAILURE;
+       interface_dereference (&ip, MDL);
+       if (status != ISC_R_SUCCESS)
+               return 0;
+       return 1;
+}
+
+void make_client_state (state)
+       struct client_state **state;
+{
+       *state = ((struct client_state *)dmalloc (sizeof **state, MDL));
+       if (!*state)
+               log_fatal ("no memory for client state\n");
+       memset (*state, 0, sizeof **state);
+}
+
+void make_client_config (client, config)
+       struct client_state *client;
+       struct client_config *config;
+{
+       client -> config = (((struct client_config *)
+                            dmalloc (sizeof (struct client_config), MDL)));
+       if (!client -> config)
+               log_fatal ("no memory for client config\n");
+       memcpy (client -> config, config, sizeof *config);
+       if (!clone_group (&client -> config -> on_receipt,
+                         config -> on_receipt, MDL) ||
+           !clone_group (&client -> config -> on_transmission,
+                         config -> on_transmission, MDL))
+               log_fatal ("no memory for client state groups.");
+}
+
+/* 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 (cfile, is_static)
+       struct parse *cfile;
+       int is_static;
+{
+       struct client_lease *lease, *lp, *pl, *next;
+       struct interface_info *ip = (struct interface_info *)0;
+       int token;
+       const char *val;
+       struct client_state *client = (struct client_state *)0;
+
+       token = next_token (&val, (unsigned *)0, cfile);
+       if (token != LBRACE) {
+               parse_warn (cfile, "expecting left brace.");
+               skip_to_semi (cfile);
+               return;
+       }
+
+       lease = ((struct client_lease *)
+                dmalloc (sizeof (struct client_lease), MDL));
+       if (!lease)
+               log_fatal ("no memory for lease.\n");
+       memset (lease, 0, sizeof *lease);
+       lease -> is_static = is_static;
+       if (!option_state_allocate (&lease -> options, MDL))
+               log_fatal ("no memory for lease options.\n");
+
+       do {
+               token = peek_token (&val, (unsigned *)0, cfile);
+               if (token == END_OF_FILE) {
+                       parse_warn (cfile, "unterminated lease declaration.");
+                       return;
+               }
+               if (token == RBRACE)
+                       break;
+               parse_client_lease_declaration (cfile, lease, &ip, &client);
+       } while (1);
+       token = next_token (&val, (unsigned *)0, cfile);
+
+       /* If the lease declaration didn't include an interface
+          declaration that we recognized, it's of no use to us. */
+       if (!ip) {
+               destroy_client_lease (lease);
+               return;
+       }
+
+       /* Make sure there's a client state structure... */
+       if (!ip -> client) {
+               make_client_state (&ip -> client);
+               ip -> client -> interface = ip;
+       }
+       if (!client)
+               client = ip -> client;
+
+       /* 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 = (struct client_lease *)0;
+       for (lp = client -> leases; lp; lp = next) {
+               next = lp -> next;
+               if (lp -> address.len == lease -> address.len &&
+                   !memcmp (lp -> address.iabuf, lease -> address.iabuf,
+                            lease -> address.len)) {
+                       if (pl)
+                               pl -> next = next;
+                       else
+                               client -> leases = next;
+                       destroy_client_lease (lp);
+                       break;
+               } else
+                       pl = lp;
+       }
+
+       /* 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 = client -> leases;
+               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 (client -> active) {
+               if (client -> active -> expiry < cur_time)
+                       destroy_client_lease (client -> active);
+               else if (client -> active -> address.len ==
+                        lease -> address.len &&
+                        !memcmp (client -> active -> address.iabuf,
+                                 lease -> address.iabuf,
+                                 lease -> address.len))
+                       destroy_client_lease (client -> active);
+               else {
+                       client -> active -> next = client -> leases;
+                       client -> leases = client -> active;
+               }
+       }
+       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 |
+       KEY id */
+
+void parse_client_lease_declaration (cfile, lease, ipp, clientp)
+       struct parse *cfile;
+       struct client_lease *lease;
+       struct interface_info **ipp;
+       struct client_state **clientp;
+{
+       int token;
+       const char *val;
+       char *t, *n;
+       struct interface_info *ip;
+       struct option_cache *oc;
+       struct client_state *client = (struct client_state *)0;
+       struct data_string key_id;
+
+       switch (next_token (&val, (unsigned *)0, cfile)) {
+             case KEY:
+               token = next_token (&val, (unsigned *)0, cfile);
+               if (token != STRING && !is_identifier (token)) {
+                       parse_warn (cfile, "expecting key name.");
+                       skip_to_semi (cfile);
+                       break;
+               }
+               if (omapi_auth_key_lookup_name (&lease -> key, val) !=
+                   ISC_R_SUCCESS)
+                       parse_warn (cfile, "unknown key %s", val);
+               parse_semi (cfile);
+               break;
+             case TOKEN_BOOTP:
+               lease -> is_bootp = 1;
+               break;
+
+             case INTERFACE:
+               token = next_token (&val, (unsigned *)0, cfile);
+               if (token != STRING) {
+                       parse_warn (cfile,
+                                   "expecting interface name (in quotes).");
+                       skip_to_semi (cfile);
+                       break;
+               }
+               interface_or_dummy (ipp, val);
+               break;
+
+             case NAME:
+               token = next_token (&val, (unsigned *)0, cfile);
+               ip = *ipp;
+               if (!ip) {
+                       parse_warn (cfile, "state name precedes interface.");
+                       break;
+               }
+               for (client = ip -> client; client; client = client -> next)
+                       if (client -> name && !strcmp (client -> name, val))
+                               break;
+               if (!client)
+                       parse_warn (cfile,
+                                   "lease specified for unknown pseudo.");
+               *clientp = client;
+               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:
+               parse_string (cfile, &lease -> filename, (unsigned *)0);
+               return;
+
+             case SERVER_NAME:
+               parse_string (cfile, &lease -> server_name, (unsigned *)0);
+               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:
+               oc = (struct option_cache *)0;
+               if (parse_option_decl (&oc, cfile)) {
+                       save_option (oc -> option -> universe,
+                                    lease -> options, oc);
+                       option_cache_dereference (&oc, MDL);
+               }
+               return;
+
+             default:
+               parse_warn (cfile, "expecting lease declaration.");
+               skip_to_semi (cfile);
+               break;
+       }
+       token = next_token (&val, (unsigned *)0, cfile);
+       if (token != SEMI) {
+               parse_warn (cfile, "expecting semicolon.");
+               skip_to_semi (cfile);
+       }
+}
+
+void parse_string_list (cfile, lp, multiple)
+       struct parse *cfile;
+       struct string_list **lp;
+       int multiple;
+{
+       int token;
+       const 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)
+                       ;
+       } else {
+               cur = (struct string_list *)0;
+       }
+
+       do {
+               token = next_token (&val, (unsigned *)0, cfile);
+               if (token != STRING) {
+                       parse_warn (cfile, "Expecting media options.");
+                       skip_to_semi (cfile);
+                       return;
+               }
+
+               tmp = ((struct string_list *)
+                      dmalloc (strlen (val) + sizeof (struct string_list),
+                               MDL));
+               if (!tmp)
+                       log_fatal ("no memory for string list entry.");
+
+               strcpy (tmp -> string, val);
+               tmp -> next = (struct string_list *)0;
+
+               /* Store this medium at the end of the media list. */
+               if (cur)
+                       cur -> next = tmp;
+               else
+                       *lp = tmp;
+               cur = tmp;
+
+               token = next_token (&val, (unsigned *)0, cfile);
+       } while (multiple && token == COMMA);
+
+       if (token != SEMI) {
+               parse_warn (cfile, "expecting semicolon.");
+               skip_to_semi (cfile);
+       }
+}
+
+void parse_reject_statement (cfile, config)
+       struct parse *cfile;
+       struct client_config *config;
+{
+       int token;
+       const char *val;
+       struct iaddr addr;
+       struct iaddrlist *list;
+
+       do {
+               if (!parse_ip_addr (cfile, &addr)) {
+                       parse_warn (cfile, "expecting IP address.");
+                       skip_to_semi (cfile);
+                       return;
+               }
+
+               list = (struct iaddrlist *)dmalloc (sizeof (struct iaddrlist),
+                                                   MDL);
+               if (!list)
+                       log_fatal ("no memory for reject list!");
+
+               list -> addr = addr;
+               list -> next = config -> reject_list;
+               config -> reject_list = list;
+
+               token = next_token (&val, (unsigned *)0, cfile);
+       } while (token == COMMA);
+
+       if (token != SEMI) {
+               parse_warn (cfile, "expecting semicolon.");
+               skip_to_semi (cfile);
+       }
+}      
+
+/* allow-deny-keyword :== BOOTP
+                       | BOOTING
+                       | DYNAMIC_BOOTP
+                       | UNKNOWN_CLIENTS */
+
+int parse_allow_deny (oc, cfile, flag)
+       struct option_cache **oc;
+       struct parse *cfile;
+       int flag;
+{
+       enum dhcp_token token;
+       const char *val;
+       unsigned char rf = flag;
+       struct expression *data = (struct expression *)0;
+       int status;
+
+       parse_warn (cfile, "allow/deny/ignore not permitted here.");
+       skip_to_semi (cfile);
+       return 0;
+}
+
diff --git a/contrib/dhcp-3.0/client/dhclient-script.8 b/contrib/dhcp-3.0/client/dhclient-script.8
new file mode 100644 (file)
index 0000000..d81cf41
--- /dev/null
@@ -0,0 +1,221 @@
+.\"    dhclient-script.8
+.\"
+.\" Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+.\" Copyright (c) 1996-2003 by Internet Software Consortium
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+.\" OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.\"   Internet Systems Consortium, Inc.
+.\"   950 Charter Street
+.\"   Redwood City, CA 94063
+.\"   <info@isc.org>
+.\"   http://www.isc.org/
+.\"
+.\" This software has been written for Internet Systems Consortium
+.\" by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
+.\" To learn more about Internet Systems Consortium, see
+.\" ``http://www.isc.org/''.  To learn more about Vixie Enterprises,
+.\" see ``http://www.vix.com''.   To learn more about Nominum, Inc., see
+.\" ``http://www.nominum.com''.
+.\"
+.\" $Id: dhclient-script.8,v 1.8.2.5 2004/06/10 17:59:12 dhankins Exp $
+.\"
+.TH dhclient-script 8
+.SH NAME
+dhclient-script - DHCP client network configuration script
+.SH DESCRIPTION
+The DHCP client network configuration script is invoked from time to
+time by \fBdhclient(8)\fR.  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
+This script is not meant to be customized by the end user.  If local
+customizations are needed, they should be possible using the enter and
+exit hooks provided (see HOOKS for details).   These hooks will allow the
+user to override the default behaviour of the client in creating a
+.B /etc/resolv.conf
+file.
+.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
+.B ETCDIR/dhclient.conf
+file.   If you find that you can't make such a customization without
+customizing
+.B ETCDIR/dhclient.conf
+or using the enter and exit hooks, please submit a bug report.
+.SH HOOKS
+When it starts, the client script first defines a shell function,
+.B make_resolv_conf ,
+which is later used to create the
+.B /etc/resolv.conf
+file.   To override the default behaviour, redefine this function in
+the enter hook script.
+.PP
+On after defining the make_resolv_conf function, the client script checks
+for the presence of an executable
+.B ETCDIR/dhclient-enter-hooks
+script, and if present, it invokes the script inline, using the Bourne
+shell '.' command.   The entire environment documented under OPERATION
+is available to this script, which may modify the environment if needed
+to change the behaviour of the script.   If an error occurs during the
+execution of the script, it can set the exit_status variable to a nonzero
+value, and
+.B CLIENTBINDIR/dhclient-script
+will exit with that error code immediately after the client script exits.
+.PP
+After all processing has completed,
+.B CLIENTBINDIR/dhclient-script
+checks for the presence of an executable
+.B ETCDIR/dhclient-exit-hooks
+script, which if present is invoked using the '.' command.  The exit
+status of dhclient-script will be passed to dhclient-exit-hooks in the
+exit_status shell variable, and will always be zero if the script
+succeeded at the task for which it was invoked.   The rest of the
+environment as described previously for dhclient-enter-hooks is also
+present.   The
+.B ETCDIR/dhclient-exit-hooks
+script can modify the valid of exit_status to change the exit status
+of dhclient-script.
+.SH OPERATION
+When dhclient needs to invoke the client configuration script, it
+defines a set of variables in the environment, and then invokes
+.B CLIENTBINDIR/dhclient-script.
+In all cases, $reason is set to the name of the reason why the script
+has been invoked.   The following reasons are currently defined:
+MEDIUM, PREINIT, BOUND, RENEW, REBIND, REBOOT, EXPIRE, FAIL and TIMEOUT.
+.PP
+.SH MEDIUM
+The DHCP client is requesting that an interface's media type
+be set.  The interface name is passed in $interface, and the media
+type is passed in $medium.
+.SH 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 $interface,
+and the media type in $medium.
+.PP
+If an IP alias has been declared in dhclient.conf, its address will be
+passed in $alias_ip_address, and that ip alias should be deleted from
+the interface, along with any routes to it.
+.SH BOUND
+The DHCP client has done an initial binding to a new address.   The
+new ip address is passed in $new_ip_address, and the interface name is
+passed in $interface.   The media type is passed in $medium.   Any
+options acquired from the server are passed using the option name
+described in \fBdhcp-options\fR, except that dashes ('-') are replaced
+by underscores ('_') in order to make valid shell variables, and the
+variable names start with new_.   So for example, the new subnet mask
+would be passed in $new_subnet_mask.
+.PP
+Before actually configuring the address, dhclient-script should
+somehow ARP for it and exit with a nonzero status if it receives a
+reply.   In this case, the client will send a DHCPDECLINE message to
+the server and acquire a different address.   This may also be done in
+the RENEW, REBIND, or REBOOT states, but is not required, and indeed
+may not be desirable.
+.PP
+When a binding has been completed, a lot of network parameters are
+likely to need to be set up.   A new /etc/resolv.conf needs to be
+created, using the values of $new_domain_name and
+$new_domain_name_servers (which may list more than one server,
+separated by spaces).   A default route should be set using
+$new_routers, and static routes may need to be set up using
+$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 $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
+$alias_ instead of $new_.   Care should be taken that the alias IP
+address not be used if it is identical to the bound IP address
+($new_ip_address), since the other alias parameters may be incorrect
+in this case.
+.SH RENEW
+When a binding has been renewed, the script is called as in BOUND,
+except that in addition to all the variables starting with $new_,
+there is another set of variables starting with $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
+BOUND.
+.SH REBIND
+The DHCP client has rebound to a new DHCP server.  This can be handled
+as with RENEW, except that if the IP address has changed, the ARP
+table should be cleared.
+.SH REBOOT
+The DHCP client has successfully reacquired its old address after a
+reboot.   This can be processed as with BOUND.
+.SH 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 RENEW and REBIND.
+.SH 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 EXPIRE.
+.SH 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 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.
+.PP
+The usual way to test a lease is to set up the network as with REBIND
+(since this may be called to test more than one lease) and then ping
+the first router defined in $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 $new_routers, as well as those listed in
+$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 Internet
+Systems 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 BUGS
+If more than one interface is being used, there's no obvious way to
+avoid clashes between server-supplied configuration parameters - for
+example, the stock dhclient-script rewrites /etc/resolv.conf.   If
+more than one interface is being configured, /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 shouldn't cause any real problems, but it could be
+confusing.
+.SH SEE ALSO
+dhclient(8), dhcpd(8), dhcrelay(8), dhclient.conf(5) and
+dhclient.leases(5).
+.SH AUTHOR
+.B dhclient-script(8)
+has been written for Internet Systems Consortium
+by Ted Lemon in cooperation with Vixie
+Enterprises.  To learn more about Internet Systems Consortium,
+see
+.B http://www.isc.org.
+To learn more about Vixie
+Enterprises, see
+.B http://www.vix.com.
diff --git a/contrib/dhcp-3.0/client/dhclient.8 b/contrib/dhcp-3.0/client/dhclient.8
new file mode 100644 (file)
index 0000000..01d1368
--- /dev/null
@@ -0,0 +1,319 @@
+.\"    dhclient.8
+.\"
+.\" Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+.\" Copyright (c) 1996-2003 by Internet Software Consortium
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+.\" OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.\"   Internet Systems Consortium, Inc.
+.\"   950 Charter Street
+.\"   Redwood City, CA 94063
+.\"   <info@isc.org>
+.\"   http://www.isc.org/
+.\"
+.\" $Id: dhclient.8,v 1.12.2.9 2004/09/29 23:01:46 dhankins Exp $
+.\"
+.TH dhclient 8
+.SH NAME
+dhclient - Dynamic Host Configuration Protocol Client
+.SH SYNOPSIS
+.B dhclient
+[
+.B -p
+.I port
+]
+[
+.B -d
+]
+[
+.B -q
+]
+[
+.B -1
+]
+[
+.B -r
+]
+[
+.B -lf
+.I lease-file
+]
+[
+.B -pf
+.I pid-file
+]
+[
+.B -cf
+.I config-file
+]
+[
+.B -sf
+.I script-file
+]
+[
+.B -s
+server
+]
+[
+.B -g
+relay
+]
+[
+.B -n
+]
+[
+.B -nw
+]
+[
+.B -w
+]
+[
+.I if0
+[
+.I ...ifN
+]
+]
+.SH DESCRIPTION
+The Internet Systems Consortium DHCP Client, dhclient, provides a
+means for configuring one or more network interfaces using the Dynamic
+Host Configuration Protocol, BOOTP protocol, or if these protocols
+fail, by statically assigning an address.
+.SH OPERATION
+.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 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, dhclient reads the
+.IR dhclient.conf
+for configuration instructions.   It then gets a list of all the
+network interfaces that are configured in the current system.   For
+each interface, it attempts to configure the interface using the DHCP
+protocol.
+.PP
+In order to keep track of leases across system reboots and server
+restarts, dhclient keeps a list of leases it has been assigned in the
+dhclient.leases(5) file.   On startup, after reading the dhclient.conf
+file, dhclient reads the dhclient.leases file to refresh its memory
+about what leases it has been assigned.
+.PP
+When a new lease is acquired, it is appended to the end of the
+dhclient.leases file.   In order to prevent the file from becoming
+arbitrarily large, from time to time dhclient creates a new
+dhclient.leases file from its in-core lease database.  The old version
+of the dhclient.leases file is retained under the name
+.IR dhclient.leases~
+until the next time dhclient rewrites the database.
+.PP
+Old leases are kept around in case the DHCP server is unavailable when
+dhclient is first invoked (generally during the initial system boot
+process).   In that event, old leases from the dhclient.leases 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, dhclient will try to validate the static lease, and if it
+succeeds, 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 COMMAND LINE
+.PP
+The names of the network interfaces that dhclient should attempt to
+configure may be specified on the command line.  If no interface names
+are specified on the command line dhclient will normally identify all
+network interfaces, eliminating non-broadcast interfaces if
+possible, and attempt to configure each interface.
+.PP
+It is also possible to specify interfaces by name in the
+.B dhclient.conf(5)
+file.   If interfaces are specified in this way, then the client will
+only configure interfaces that are either specified in the
+configuration file or on the command line, and will ignore all other
+interfaces.
+.PP
+If the DHCP client should listen and transmit on a port other than the
+standard (port 68), the
+.B -p
+flag may used.  It should be followed by the udp port number that
+dhclient should use.  This is mostly useful for debugging purposes.
+If a different port is specified for the client to listen on and
+transmit on, the client will also use a different destination port -
+one greater than the specified destination port.
+.PP
+The DHCP client normally transmits any protocol messages it sends
+before acquiring an IP address to, 255.255.255.255, the IP limited
+broadcast address.   For debugging purposes, it may be useful to have
+the server transmit these messages to some other address.   This can
+be specified with the 
+.B -s
+flag, followed by the IP address or domain name of the destination.
+.PP
+For testing purposes, the giaddr field of all packets that the client
+sends can be set using the
+.B -g
+flag, followed by the IP address to send.   This is only useful for testing,
+and should not be expected to work in any consistent or useful way.
+.PP
+The DHCP client will normally run in the foreground until it has
+configured an interface, and then will revert to running in the
+background.   To run force dhclient to always run as a foreground
+process, the
+.B -d
+flag should be specified.  This is useful when running the client
+under a debugger, or when running it out of inittab on System V
+systems.
+.PP
+The client normally prints a startup message and displays the
+protocol sequence to the standard error descriptor until it has
+acquired an address, and then only logs messages using the
+.B syslog (3)
+facility.   The
+.B -q
+flag prevents any messages other than errors from being printed to the
+standard error descriptor.
+.PP
+The client normally doesn't release the current lease as it is not
+required by the DHCP protocol.  Some cable ISPs require their clients
+to notify the server if they wish to release an assigned IP address.
+The
+.B -r
+flag explicitly releases the current lease, and once the lease has been
+released, the client exits.
+.PP
+The
+.B -1
+flag cause dhclient to try once to get a lease.  If it fails, dhclient exits
+with exit code two.
+.PP
+The DHCP client normally gets its configuration information from
+.B ETCDIR/dhclient.conf,
+its lease database from
+.B DBDIR/dhclient.leases,
+stores its process ID in a file called
+.B RUNDIR/dhclient.pid,
+and configures the network interface using
+.B CLIENTBINDIR/dhclient-script
+To specify different names and/or locations for these files, use the
+.B -cf,
+.B -lf,
+.B -pf
+and
+.B -sf
+flags, respectively, followed by the name of the file.   This can be
+particularly useful if, for example,
+.B DBDIR
+or
+.B RUNDIR
+has not yet been mounted when the DHCP client is started.
+.PP
+The DHCP client normally exits if it isn't able to identify any
+network interfaces to configure.   On laptop computers and other
+computers with hot-swappable I/O buses, it is possible that a
+broadcast interface may be added after system startup.   The
+.B -w
+flag can be used to cause the client not to exit when it doesn't find
+any such interfaces.   The
+.B omshell (8)
+program can then be used to notify the client when a network interface
+has been added or removed, so that the client can attempt to configure an IP
+address on that interface.
+.PP
+The DHCP client can be directed not to attempt to configure any interfaces
+using the
+.B -n
+flag.   This is most likely to be useful in combination with the
+.B -w
+flag.
+.PP
+The client can also be instructed to become a daemon immediately, rather
+than waiting until it has acquired an IP address.   This can be done by
+supplying the
+.B -nw
+flag.
+.SH CONFIGURATION
+The syntax of the dhclient.conf(5) file is discussed separately.
+.SH OMAPI
+The DHCP client provides some ability to control it while it is
+running, without stopping it.  This capability is provided using OMAPI,
+an API for manipulating remote objects.  OMAPI clients connect to the
+client using TCP/IP, authenticate, and can then examine the client's
+current status and make changes to it. 
+.PP
+Rather than implementing the underlying OMAPI protocol directly, user
+programs should use the dhcpctl API or OMAPI itself.   Dhcpctl is a
+wrapper that handles some of the housekeeping chores that OMAPI does
+not do automatically.   Dhcpctl and OMAPI are documented in \fBdhcpctl(3)\fR
+and \fBomapi(3)\fR.   Most things you'd want to do with the client can
+be done directly using the \fBomshell(1)\fR command, rather than
+having to write a special program.
+.SH THE CONTROL OBJECT
+The control object allows you to shut the client down, releasing all
+leases that it holds and deleting any DNS records it may have added.
+It also allows you to pause the client - this unconfigures any
+interfaces the client is using.   You can then restart it, which
+causes it to reconfigure those interfaces.   You would normally pause
+the client prior to going into hibernation or sleep on a laptop
+computer.   You would then resume it after the power comes back.
+This allows PC cards to be shut down while the computer is hibernating
+or sleeping, and then reinitialized to their previous state once the
+computer comes out of hibernation or sleep.
+.PP
+The control object has one attribute - the state attribute.   To shut
+the client down, set its state attribute to 2.   It will automatically
+do a DHCPRELEASE.   To pause it, set its state attribute to 3.   To
+resume it, set its state attribute to 4.
+.PP
+.SH FILES
+.B CLIENTBINDIR/dhclient-script,
+.B ETCDIR/dhclient.conf, DBDIR/dhclient.leases, RUNDIR/dhclient.pid,
+.B DBDIR/dhclient.leases~.
+.SH SEE ALSO
+dhcpd(8), dhcrelay(8), dhclient-script(8), dhclient.conf(5),
+dhclient.leases(5).
+.SH AUTHOR
+.B dhclient(8)
+has been written for Internet Systems Consortium
+by Ted Lemon in cooperation with Vixie
+Enterprises.  To learn more about Internet Systems Consortium,
+see
+.B http://www.isc.org
+To learn more about Vixie
+Enterprises, see
+.B http://www.vix.com.
+.PP
+This client was substantially modified and enhanced by Elliot Poger
+for use on Linux while he was working on the MosquitoNet project at
+Stanford.
+.PP
+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 Systems
+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.
+.PP
diff --git a/contrib/dhcp-3.0/client/dhclient.c b/contrib/dhcp-3.0/client/dhclient.c
new file mode 100644 (file)
index 0000000..709c507
--- /dev/null
@@ -0,0 +1,3162 @@
+/* dhclient.c
+
+   DHCP Client. */
+
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1995-2003 by Internet Software Consortium
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *   Internet Systems Consortium, Inc.
+ *   950 Charter Street
+ *   Redwood City, CA 94063
+ *   <info@isc.org>
+ *   http://www.isc.org/
+ *
+ * This code is based on the original client state machine that was
+ * written by Elliot Poger.  The code has been extensively hacked on
+ * by Ted Lemon since then, so any mistakes you find are probably his
+ * fault and not Elliot's.
+ */
+
+#ifndef lint
+static char ocopyright[] =
+"$Id: dhclient.c,v 1.129.2.23 2004/11/24 17:39:14 dhankins Exp $ Copyright (c) 2004 Internet Systems Consortium.  All rights reserved.\n";
+#endif /* not lint */
+
+#include "dhcpd.h"
+#include "version.h"
+
+TIME default_lease_time = 43200; /* 12 hours... */
+TIME max_lease_time = 86400; /* 24 hours... */
+
+const char *path_dhclient_conf = _PATH_DHCLIENT_CONF;
+const char *path_dhclient_db = _PATH_DHCLIENT_DB;
+const char *path_dhclient_pid = _PATH_DHCLIENT_PID;
+static char path_dhclient_script_array [] = _PATH_DHCLIENT_SCRIPT;
+char *path_dhclient_script = path_dhclient_script_array;
+
+int dhcp_max_agent_option_packet_length = 0;
+
+int interfaces_requested = 0;
+
+struct iaddr iaddr_broadcast = { 4, { 255, 255, 255, 255 } };
+struct iaddr iaddr_any = { 4, { 0, 0, 0, 0 } };
+struct in_addr inaddr_any;
+struct sockaddr_in sockaddr_broadcast;
+struct in_addr giaddr;
+
+/* ASSERT_STATE() does nothing now; it used to be
+   assert (state_is == state_shouldbe). */
+#define ASSERT_STATE(state_is, state_shouldbe) {}
+
+static char copyright[] = "Copyright 2004 Internet Systems Consortium.";
+static char arr [] = "All rights reserved.";
+static char message [] = "Internet Systems Consortium DHCP Client";
+static char url [] = "For info, please visit http://www.isc.org/products/DHCP";
+
+u_int16_t local_port=0;
+u_int16_t remote_port=0;
+int no_daemon=0;
+struct string_list *client_env=NULL;
+int client_env_count=0;
+int onetry=0;
+int quiet=0;
+int nowait=0;
+
+static void usage PROTO ((void));
+
+void do_release(struct client_state *);
+
+int main (argc, argv, envp)
+       int argc;
+       char **argv, **envp;
+{
+       int i;
+       struct servent *ent;
+       struct interface_info *ip;
+       struct client_state *client;
+       unsigned seed;
+       char *server = (char *)0;
+       char *relay = (char *)0;
+       isc_result_t status;
+       int release_mode = 0;
+       omapi_object_t *listener;
+       isc_result_t result;
+       int persist = 0;
+       int omapi_port;
+       int no_dhclient_conf = 0;
+       int no_dhclient_db = 0;
+       int no_dhclient_pid = 0;
+       int no_dhclient_script = 0;
+       char *s;
+
+       /* Make sure we have stdin, stdout and stderr. */
+       i = open ("/dev/null", O_RDWR);
+       if (i == 0)
+               i = open ("/dev/null", O_RDWR);
+       if (i == 1) {
+               i = open ("/dev/null", O_RDWR);
+               log_perror = 0; /* No sense logging to /dev/null. */
+       } else if (i != -1)
+               close (i);
+
+#ifdef SYSLOG_4_2
+       openlog ("dhclient", LOG_NDELAY);
+       log_priority = LOG_DAEMON;
+#else
+       openlog ("dhclient", LOG_NDELAY, LOG_DAEMON);
+#endif
+
+#if !(defined (DEBUG) || defined (SYSLOG_4_2) || defined (__CYGWIN32__))
+       setlogmask (LOG_UPTO (LOG_INFO));
+#endif 
+
+       /* Set up the OMAPI. */
+       status = omapi_init ();
+       if (status != ISC_R_SUCCESS)
+               log_fatal ("Can't initialize OMAPI: %s",
+                          isc_result_totext (status));
+
+       /* Set up the OMAPI wrappers for various server database internal
+          objects. */
+       dhcp_common_objects_setup ();
+
+       dhcp_interface_discovery_hook = dhclient_interface_discovery_hook;
+       dhcp_interface_shutdown_hook = dhclient_interface_shutdown_hook;
+       dhcp_interface_startup_hook = dhclient_interface_startup_hook;
+
+       for (i = 1; i < argc; i++) {
+               if (!strcmp (argv [i], "-r")) {
+                       release_mode = 1;
+                       no_daemon = 1;
+               } else if (!strcmp (argv [i], "-p")) {
+                       if (++i == argc)
+                               usage ();
+                       local_port = htons (atoi (argv [i]));
+                       log_debug ("binding to user-specified port %d",
+                              ntohs (local_port));
+               } else if (!strcmp (argv [i], "-d")) {
+                       no_daemon = 1;
+                } else if (!strcmp (argv [i], "-pf")) {
+                        if (++i == argc)
+                                usage ();
+                        path_dhclient_pid = argv [i];
+                       no_dhclient_pid = 1;
+                } else if (!strcmp (argv [i], "-cf")) {
+                        if (++i == argc)
+                                usage ();
+                        path_dhclient_conf = argv [i];
+                       no_dhclient_conf = 1;
+                } else if (!strcmp (argv [i], "-lf")) {
+                        if (++i == argc)
+                                usage ();
+                        path_dhclient_db = argv [i];
+                       no_dhclient_db = 1;
+               } else if (!strcmp (argv [i], "-sf")) {
+                       if (++i == argc)
+                               usage ();
+                        path_dhclient_script = argv [i];
+                       no_dhclient_script = 1;
+               } else if (!strcmp (argv [i], "-1")) {
+                       onetry = 1;
+               } else if (!strcmp (argv [i], "-q")) {
+                       quiet = 1;
+                       quiet_interface_discovery = 1;
+               } else if (!strcmp (argv [i], "-s")) {
+                       if (++i == argc)
+                               usage ();
+                       server = argv [i];
+               } else if (!strcmp (argv [i], "-g")) {
+                       if (++i == argc)
+                               usage ();
+                       relay = argv [i];
+               } else if (!strcmp (argv [i], "-nw")) {
+                       nowait = 1;
+               } else if (!strcmp (argv [i], "-n")) {
+                       /* do not start up any interfaces */
+                       interfaces_requested = 1;
+               } else if (!strcmp (argv [i], "-w")) {
+                       /* do not exit if there are no broadcast interfaces. */
+                       persist = 1;
+               } else if (!strcmp (argv [i], "-e")) {
+                       struct string_list *tmp;
+                       if (++i == argc)
+                               usage ();
+                       tmp = dmalloc (strlen (argv [i]) + sizeof *tmp, MDL);
+                       if (!tmp)
+                               log_fatal ("No memory for %s", argv [i]);
+                       strcpy (tmp -> string, argv [i]);
+                       tmp -> next = client_env;
+                       client_env = tmp;
+                       client_env_count++;
+               } else if (!strcmp (argv [i], "--version")) {
+                       log_info ("isc-dhclient-%s", DHCP_VERSION);
+                       exit (0);
+               } else if (argv [i][0] == '-') {
+                   usage ();
+               } else {
+                   struct interface_info *tmp = (struct interface_info *)0;
+                   status = interface_allocate (&tmp, MDL);
+                   if (status != ISC_R_SUCCESS)
+                       log_fatal ("Can't record interface %s:%s",
+                                  argv [i], isc_result_totext (status));
+                   if (strlen (argv [i]) > sizeof tmp -> name)
+                           log_fatal ("%s: interface name too long (max %ld)",
+                                      argv [i], (long)strlen (argv [i]));
+                   strcpy (tmp -> name, argv [i]);
+                   if (interfaces) {
+                           interface_reference (&tmp -> next,
+                                                interfaces, MDL);
+                           interface_dereference (&interfaces, MDL);
+                   }
+                   interface_reference (&interfaces, tmp, MDL);
+                   tmp -> flags = INTERFACE_REQUESTED;
+                   interfaces_requested = 1;
+               }
+       }
+
+       if (!no_dhclient_conf && (s = getenv ("PATH_DHCLIENT_CONF"))) {
+               path_dhclient_conf = s;
+       }
+       if (!no_dhclient_db && (s = getenv ("PATH_DHCLIENT_DB"))) {
+               path_dhclient_db = s;
+       }
+       if (!no_dhclient_pid && (s = getenv ("PATH_DHCLIENT_PID"))) {
+               path_dhclient_pid = s;
+       }
+       if (!no_dhclient_script && (s = getenv ("PATH_DHCLIENT_SCRIPT"))) {
+               path_dhclient_script = s;
+       }
+
+       /* first kill of any currently running client */
+       if (release_mode) {
+               FILE *pidfd;
+               pid_t oldpid;
+               long temp;
+               int e;
+
+               oldpid = 0;
+               if ((pidfd = fopen(path_dhclient_pid, "r")) != NULL) {
+                       e = fscanf(pidfd, "%ld\n", &temp);
+                       oldpid = (pid_t)temp;
+
+                       if (e != 0 && e != EOF) {
+                               if (oldpid) {
+                                       if (kill(oldpid, SIGTERM) == 0)
+                                               unlink(path_dhclient_pid);
+                               }
+                       }
+                       fclose(pidfd);
+               }
+       }
+
+       if (!quiet) {
+               log_info ("%s %s", message, DHCP_VERSION);
+               log_info (copyright);
+               log_info (arr);
+               log_info (url);
+               log_info ("%s", "");
+       } else
+               log_perror = 0;
+
+       /* If we're given a relay agent address to insert, for testing
+          purposes, figure out what it is. */
+       if (relay) {
+               if (!inet_aton (relay, &giaddr)) {
+                       struct hostent *he;
+                       he = gethostbyname (relay);
+                       if (he) {
+                               memcpy (&giaddr, he -> h_addr_list [0],
+                                       sizeof giaddr);
+                       } else {
+                               log_fatal ("%s: no such host", relay);
+                       }
+               }
+       }
+
+       /* Default to the DHCP/BOOTP port. */
+       if (!local_port) {
+               /* If we're faking a relay agent, and we're not using loopback,
+                  use the server port, not the client port. */
+               if (relay && giaddr.s_addr != htonl (INADDR_LOOPBACK)) {
+                       local_port = htons(67);
+               } else {
+                       ent = getservbyname ("dhcpc", "udp");
+                       if (!ent)
+                               local_port = htons (68);
+                       else
+                               local_port = ent -> s_port;
+#ifndef __CYGWIN32__
+                       endservent ();
+#endif
+               }
+       }
+
+       /* If we're faking a relay agent, and we're not using loopback,
+          we're using the server port, not the client port. */
+       if (relay && giaddr.s_addr != htonl (INADDR_LOOPBACK)) {
+               remote_port = local_port;
+       } else
+               remote_port = htons (ntohs (local_port) - 1);   /* XXX */
+
+       /* Get the current time... */
+       GET_TIME (&cur_time);
+
+       sockaddr_broadcast.sin_family = AF_INET;
+       sockaddr_broadcast.sin_port = remote_port;
+       if (server) {
+               if (!inet_aton (server, &sockaddr_broadcast.sin_addr)) {
+                       struct hostent *he;
+                       he = gethostbyname (server);
+                       if (he) {
+                               memcpy (&sockaddr_broadcast.sin_addr,
+                                       he -> h_addr_list [0],
+                                       sizeof sockaddr_broadcast.sin_addr);
+                       } else
+                               sockaddr_broadcast.sin_addr.s_addr =
+                                       INADDR_BROADCAST;
+               }
+       } else {
+               sockaddr_broadcast.sin_addr.s_addr = INADDR_BROADCAST;
+       }
+
+       inaddr_any.s_addr = INADDR_ANY;
+
+       /* Discover all the network interfaces. */
+       discover_interfaces (DISCOVER_UNCONFIGURED);
+
+       /* Parse the dhclient.conf file. */
+       read_client_conf ();
+
+       /* Parse the lease database. */
+       read_client_leases ();
+
+       /* Rewrite the lease database... */
+       rewrite_client_leases ();
+
+       /* XXX */
+/*     config_counter(&snd_counter, &rcv_counter); */
+
+       /* If no broadcast interfaces were discovered, call the script
+          and tell it so. */
+       if (!interfaces) {
+               /* Call dhclient-script with the NBI flag, in case somebody
+                  cares. */
+               script_init ((struct client_state *)0, "NBI",
+                            (struct string_list *)0);
+               script_go ((struct client_state *)0);
+
+               /* If we haven't been asked to persist, waiting for new
+                  interfaces, then just exit. */
+               if (!persist) {
+                       /* Nothing more to do. */
+                       log_info ("No broadcast interfaces found - exiting.");
+                       exit (0);
+               }
+       } else if (!release_mode) {
+               /* Call the script with the list of interfaces. */
+               for (ip = interfaces; ip; ip = ip -> next) {
+                       /* If interfaces were specified, don't configure
+                          interfaces that weren't specified! */
+                       if (interfaces_requested &&
+                           ((ip -> flags & (INTERFACE_REQUESTED |
+                                            INTERFACE_AUTOMATIC)) !=
+                            INTERFACE_REQUESTED))
+                               continue;
+                       script_init (ip -> client,
+                                    "PREINIT", (struct string_list *)0);
+                       if (ip -> client -> alias)
+                               script_write_params (ip -> client, "alias_",
+                                                    ip -> client -> alias);
+                       script_go (ip -> client);
+               }
+       }
+
+       /* At this point, all the interfaces that the script thinks
+          are relevant should be running, so now we once again call
+          discover_interfaces(), and this time ask it to actually set
+          up the interfaces. */
+       discover_interfaces (interfaces_requested
+                            ? DISCOVER_REQUESTED
+                            : DISCOVER_RUNNING);
+
+       /* Make up a seed for the random number generator from current
+          time plus the sum of the last four bytes of each
+          interface's hardware address interpreted as an integer.
+          Not much entropy, but we're booting, so we're not likely to
+          find anything better. */
+       seed = 0;
+       for (ip = interfaces; ip; ip = ip -> next) {
+               int junk;
+               memcpy (&junk,
+                       &ip -> hw_address.hbuf [ip -> hw_address.hlen -
+                                              sizeof seed], sizeof seed);
+               seed += junk;
+       }
+       srandom (seed + cur_time);
+
+       /* Start a configuration state machine for each interface. */
+       for (ip = interfaces; ip; ip = ip -> next) {
+               ip -> flags |= INTERFACE_RUNNING;
+               for (client = ip -> client; client; client = client -> next) {
+                       if (release_mode)
+                               do_release (client);
+                       else {
+                               client -> state = S_INIT;
+                               /* Set up a timeout to start the initialization
+                                  process. */
+                               add_timeout (cur_time + random () % 5,
+                                            state_reboot, client, 0, 0);
+                       }
+               }
+       }
+
+       if (release_mode)
+               return 0;
+
+       /* Start up a listener for the object management API protocol. */
+       if (top_level_config.omapi_port != -1) {
+               listener = (omapi_object_t *)0;
+               result = omapi_generic_new (&listener, MDL);
+               if (result != ISC_R_SUCCESS)
+                       log_fatal ("Can't allocate new generic object: %s\n",
+                                  isc_result_totext (result));
+               result = omapi_protocol_listen (listener,
+                                               (unsigned)
+                                               top_level_config.omapi_port,
+                                               1);
+               if (result != ISC_R_SUCCESS)
+                       log_fatal ("Can't start OMAPI protocol: %s",
+                                  isc_result_totext (result));
+       }
+
+       /* Set up the bootp packet handler... */
+       bootp_packet_handler = do_packet;
+
+#if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \
+               defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
+       dmalloc_cutoff_generation = dmalloc_generation;
+       dmalloc_longterm = dmalloc_outstanding;
+       dmalloc_outstanding = 0;
+#endif
+
+       /* If we're not supposed to wait before getting the address,
+          don't. */
+       if (nowait)
+               go_daemon ();
+
+       /* If we're not going to daemonize, write the pid file
+          now. */
+       if (no_daemon || nowait)
+               write_client_pid_file ();
+
+       /* Start dispatching packets and timeouts... */
+       dispatch ();
+
+       /*NOTREACHED*/
+       return 0;
+}
+
+static void usage ()
+{
+       log_info ("%s %s", message, DHCP_VERSION);
+       log_info (copyright);
+       log_info (arr);
+       log_info (url);
+
+       log_error ("Usage: dhclient [-1dqr] [-nw] [-p <port>] %s",
+                  "[-s server]");
+       log_error ("                [-cf config-file] [-lf lease-file]%s",
+                  "[-pf pid-file] [-e VAR=val]");
+       log_fatal ("                [-sf script-file] [interface]");
+}
+
+isc_result_t find_class (struct class **c,
+               const char *s, const char *file, int line)
+{
+       return 0;
+}
+
+int check_collection (packet, lease, collection)
+       struct packet *packet;
+       struct lease *lease;
+       struct collection *collection;
+{
+       return 0;
+}
+
+void classify (packet, class)
+       struct packet *packet;
+       struct class *class;
+{
+}
+
+int unbill_class (lease, class)
+       struct lease *lease;
+       struct class *class;
+{
+       return 0;
+}
+
+int find_subnet (struct subnet **sp,
+                struct iaddr addr, const char *file, int line)
+{
+       return 0;
+}
+
+/* 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 (cpp)
+       void *cpp;
+{
+       struct client_state *client = cpp;
+
+       /* If we don't remember an active lease, go straight to INIT. */
+       if (!client -> active ||
+           client -> active -> is_bootp ||
+           client -> active -> expiry <= cur_time) {
+               state_init (client);
+               return;
+       }
+
+       /* We are in the rebooting state. */
+       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. */
+       client -> xid = random ();
+
+       /* Make a DHCPREQUEST packet, and set appropriate per-interface
+          flags. */
+       make_request (client, client -> active);
+       client -> destination = iaddr_broadcast;
+       client -> first_sending = cur_time;
+       client -> interval = client -> config -> initial_interval;
+
+       /* Zap the medium list... */
+       client -> medium = (struct string_list *)0;
+
+       /* Send out the first DHCPREQUEST packet. */
+       send_request (client);
+}
+
+/* Called when a lease has completely expired and we've been unable to
+   renew it. */
+
+void state_init (cpp)
+       void *cpp;
+{
+       struct client_state *client = cpp;
+
+       ASSERT_STATE(state, S_INIT);
+
+       /* Make a DHCPDISCOVER packet, and set appropriate per-interface
+          flags. */
+       make_discover (client, client -> active);
+       client -> xid = client -> packet.xid;
+       client -> destination = iaddr_broadcast;
+       client -> state = S_SELECTING;
+       client -> first_sending = cur_time;
+       client -> interval = client -> config -> initial_interval;
+
+       /* Add an immediate timeout to cause the first DHCPDISCOVER packet
+          to go out. */
+       send_discover (client);
+}
+
+/* state_selecting is called when one or more DHCPOFFER packets have been
+   received and a configurable period of time has passed. */
+
+void state_selecting (cpp)
+       void *cpp;
+{
+       struct client_state *client = cpp;
+       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, client);
+       cancel_timeout (send_discover, client);
+
+       /* 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 = (struct client_lease *)0;
+       for (lp = 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) {
+                       picked = lp;
+                       picked -> next = (struct client_lease *)0;
+               } else {
+                     freeit:
+                       destroy_client_lease (lp);
+               }
+       }
+       client -> offered_leases = (struct client_lease *)0;
+
+       /* If we just tossed all the leases we were offered, go back
+          to square one. */
+       if (!picked) {
+               client -> state = S_INIT;
+               state_init (client);
+               return;
+       }
+
+       /* If it was a BOOTREPLY, we can just take the address right now. */
+       if (picked -> is_bootp) {
+               client -> new = picked;
+
+               /* Make up some lease expiry times
+                  XXX these should be configurable. */
+               client -> new -> expiry = cur_time + 12000;
+               client -> new -> renewal += cur_time + 8000;
+               client -> new -> rebind += cur_time + 10000;
+
+               client -> state = S_REQUESTING;
+
+               /* Bind to the address we received. */
+               bind_lease (client);
+               return;
+       }
+
+       /* Go to the REQUESTING state. */
+       client -> destination = iaddr_broadcast;
+       client -> state = S_REQUESTING;
+       client -> first_sending = cur_time;
+       client -> interval = client -> config -> initial_interval;
+
+       /* Make a DHCPREQUEST packet from the lease we picked. */
+       make_request (client, picked);
+       client -> xid = client -> packet.xid;
+
+       /* Toss the lease we picked - we'll get it back in a DHCPACK. */
+       destroy_client_lease (picked);
+
+       /* Add an immediate timeout to send the first DHCPREQUEST packet. */
+       send_request (client);
+}  
+
+/* state_requesting is called when we receive a DHCPACK message after
+   having sent out one or more DHCPREQUEST packets. */
+
+void dhcpack (packet)
+       struct packet *packet;
+{
+       struct interface_info *ip = packet -> interface;
+       struct client_state *client;
+       struct client_lease *lease;
+       struct option_cache *oc;
+       struct data_string ds;
+       int i;
+       
+       /* If we're not receptive to an offer right now, or if the offer
+          has an unrecognizable transaction id, then just drop it. */
+       for (client = ip -> client; client; client = client -> next) {
+               if (client -> xid == packet -> raw -> xid)
+                       break;
+       }
+       if (!client ||
+           (packet -> interface -> hw_address.hlen - 1 !=
+            packet -> raw -> hlen) ||
+           (memcmp (&packet -> interface -> hw_address.hbuf [1],
+                    packet -> raw -> chaddr, packet -> raw -> hlen))) {
+#if defined (DEBUG)
+               log_debug ("DHCPACK in wrong transaction.");
+#endif
+               return;
+       }
+
+       if (client -> state != S_REBOOTING &&
+           client -> state != S_REQUESTING &&
+           client -> state != S_RENEWING &&
+           client -> state != S_REBINDING) {
+#if defined (DEBUG)
+               log_debug ("DHCPACK in wrong state.");
+#endif
+               return;
+       }
+
+       log_info ("DHCPACK from %s", piaddr (packet -> client_addr));
+
+       lease = packet_to_lease (packet, client);
+       if (!lease) {
+               log_info ("packet_to_lease failed.");
+               return;
+       }
+
+       client -> new = lease;
+
+       /* Stop resending DHCPREQUEST. */
+       cancel_timeout (send_request, client);
+
+       /* Figure out the lease time. */
+       oc = lookup_option (&dhcp_universe, client -> new -> options,
+                           DHO_DHCP_LEASE_TIME);
+       memset (&ds, 0, sizeof ds);
+       if (oc &&
+           evaluate_option_cache (&ds, packet, (struct lease *)0, client,
+                                  packet -> options, client -> new -> options,
+                                  &global_scope, oc, MDL)) {
+               if (ds.len > 3)
+                       client -> new -> expiry = getULong (ds.data);
+               else
+                       client -> new -> expiry = 0;
+               data_string_forget (&ds, MDL);
+       } else
+                       client -> new -> expiry = 0;
+
+       if (!client -> new -> expiry) {
+               log_error ("no expiry time on offered lease.");
+               /* XXX this is going to be bad - if this _does_
+                  XXX happen, we should probably dynamically 
+                  XXX disqualify the DHCP server that gave us the
+                  XXX bad packet from future selections and
+                  XXX then go back into the init state. */
+               state_init (client);
+               return;
+       }
+
+       /* A number that looks negative here is really just very large,
+          because the lease expiry offset is unsigned. */
+       if (client -> new -> expiry < 0)
+               client -> new -> expiry = TIME_MAX;
+       /* Take the server-provided renewal time if there is one. */
+       oc = lookup_option (&dhcp_universe, client -> new -> options,
+                           DHO_DHCP_RENEWAL_TIME);
+       if (oc &&
+           evaluate_option_cache (&ds, packet, (struct lease *)0, client,
+                                  packet -> options, client -> new -> options,
+                                  &global_scope, oc, MDL)) {
+               if (ds.len > 3)
+                       client -> new -> renewal = getULong (ds.data);
+               else
+                       client -> new -> renewal = 0;
+               data_string_forget (&ds, MDL);
+       } else
+                       client -> new -> renewal = 0;
+
+       /* If it wasn't specified by the server, calculate it. */
+       if (!client -> new -> renewal)
+               client -> new -> renewal = client -> new -> expiry / 2 + 1;
+
+       if (client -> new -> renewal <= 0)
+               client -> new -> renewal = TIME_MAX;
+
+       /* Now introduce some randomness to the renewal time: */
+       if (client -> new -> renewal <= TIME_MAX / 3 - 3)
+               client -> new -> renewal =
+                               (((client -> new -> renewal + 3) * 3 / 4) +
+                                   (random () % /* XXX NUMS */
+                                    ((client -> new -> renewal + 3) / 4)));
+
+       /* Same deal with the rebind time. */
+       oc = lookup_option (&dhcp_universe, client -> new -> options,
+                           DHO_DHCP_REBINDING_TIME);
+       if (oc &&
+           evaluate_option_cache (&ds, packet, (struct lease *)0, client,
+                                  packet -> options, client -> new -> options,
+                                  &global_scope, oc, MDL)) {
+               if (ds.len > 3)
+                       client -> new -> rebind = getULong (ds.data);
+               else
+                       client -> new -> rebind = 0;
+               data_string_forget (&ds, MDL);
+       } else
+                       client -> new -> rebind = 0;
+
+       if (client -> new -> rebind <= 0) {
+               if (client -> new -> expiry <= TIME_MAX / 7)
+                       client -> new -> rebind =
+                                       client -> new -> expiry * 7 / 8;
+               else
+                       client -> new -> rebind =
+                                       client -> new -> expiry / 8 * 7;
+       }
+
+       /* Make sure our randomness didn't run the renewal time past the
+          rebind time. */
+       if (client -> new -> renewal > client -> new -> rebind) {
+               if (client -> new -> rebind <= TIME_MAX / 3)
+                       client -> new -> renewal =
+                                       client -> new -> rebind * 3 / 4;
+               else
+                       client -> new -> renewal =
+                                       client -> new -> rebind / 4 * 3;
+       }
+
+       client -> new -> expiry += cur_time;
+       /* Lease lengths can never be negative. */
+       if (client -> new -> expiry < cur_time)
+               client -> new -> expiry = TIME_MAX;
+       client -> new -> renewal += cur_time;
+       if (client -> new -> renewal < cur_time)
+               client -> new -> renewal = TIME_MAX;
+       client -> new -> rebind += cur_time;
+       if (client -> new -> rebind < cur_time)
+               client -> new -> rebind = TIME_MAX;
+
+       bind_lease (client);
+}
+
+void bind_lease (client)
+       struct client_state *client;
+{
+       struct interface_info *ip = client -> interface;
+
+       /* Remember the medium. */
+       client -> new -> medium = client -> medium;
+
+       /* Run the client script with the new parameters. */
+       script_init (client, (client -> state == S_REQUESTING
+                         ? "BOUND"
+                         : (client -> state == S_RENEWING
+                            ? "RENEW"
+                            : (client -> state == S_REBOOTING
+                               ? "REBOOT" : "REBIND"))),
+                    client -> new -> medium);
+       if (client -> active && client -> state != S_REBOOTING)
+               script_write_params (client, "old_", client -> active);
+       script_write_params (client, "new_", client -> new);
+       if (client -> alias)
+               script_write_params (client, "alias_", client -> alias);
+
+       /* If the BOUND/RENEW code detects another machine using the
+          offered address, it exits nonzero.  We need to send a
+          DHCPDECLINE and toss the lease. */
+       if (script_go (client)) {
+               make_decline (client, client -> new);
+               send_decline (client);
+               destroy_client_lease (client -> new);
+               client -> new = (struct client_lease *)0;
+               state_init (client);
+               return;
+       }
+
+       /* Write out the new lease. */
+       write_client_lease (client, client -> new, 0, 0);
+
+       /* Replace the old active lease with the new one. */
+       if (client -> active)
+               destroy_client_lease (client -> active);
+       client -> active = client -> new;
+       client -> new = (struct client_lease *)0;
+
+       /* Set up a timeout to start the renewal process. */
+       add_timeout (client -> active -> renewal,
+                    state_bound, client, 0, 0);
+
+       log_info ("bound to %s -- renewal in %ld seconds.",
+             piaddr (client -> active -> address),
+             (long)(client -> active -> renewal - cur_time));
+       client -> state = S_BOUND;
+       reinitialize_interfaces ();
+       go_daemon ();
+       if (client -> config -> do_forward_update) {
+               client -> dns_update_timeout = 1;
+               add_timeout (cur_time + 1, client_dns_update_timeout,
+                            client, 0, 0);
+       }
+}  
+
+/* 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 (cpp)
+       void *cpp;
+{
+       struct client_state *client = cpp;
+       int i;
+       struct option_cache *oc;
+       struct data_string ds;
+
+       ASSERT_STATE(state, S_BOUND);
+
+       /* T1 has expired. */
+       make_request (client, client -> active);
+       client -> xid = client -> packet.xid;
+
+       memset (&ds, 0, sizeof ds);
+       oc = lookup_option (&dhcp_universe, client -> active -> options,
+                           DHO_DHCP_SERVER_IDENTIFIER);
+       if (oc &&
+           evaluate_option_cache (&ds, (struct packet *)0, (struct lease *)0,
+                                  client, (struct option_state *)0,
+                                  client -> active -> options,
+                                  &global_scope, oc, MDL)) {
+               if (ds.len > 3) {
+                       memcpy (client -> destination.iabuf, ds.data, 4);
+                       client -> destination.len = 4;
+               } else
+                       client -> destination = iaddr_broadcast;
+
+               data_string_forget (&ds, MDL);
+       } else
+               client -> destination = iaddr_broadcast;
+
+       client -> first_sending = cur_time;
+       client -> interval = client -> config -> initial_interval;
+       client -> state = S_RENEWING;
+
+       /* Send the first packet immediately. */
+       send_request (client);
+}  
+
+/* state_stop is called when we've been told to shut down.   We unconfigure
+   the interfaces, and then stop operating until told otherwise. */
+
+void state_stop (cpp)
+       void *cpp;
+{
+       struct client_state *client = cpp;
+       int i;
+
+       /* Cancel all timeouts. */
+       cancel_timeout (state_selecting, client);
+       cancel_timeout (send_discover, client);
+       cancel_timeout (send_request, client);
+       cancel_timeout (state_bound, client);
+
+       /* If we have an address, unconfigure it. */
+       if (client -> active) {
+               script_init (client, "STOP", client -> active -> medium);
+               script_write_params (client, "old_", client -> active);
+               if (client -> alias)
+                       script_write_params (client, "alias_",
+                                            client -> alias);
+               script_go (client);
+       }
+}  
+
+int commit_leases ()
+{
+       return 0;
+}
+
+int write_lease (lease)
+       struct lease *lease;
+{
+       return 0;
+}
+
+int write_host (host)
+       struct host_decl *host;
+{
+       return 0;
+}
+
+void db_startup (testp)
+       int testp;
+{
+}
+
+void bootp (packet)
+       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)) {
+                       log_info ("BOOTREPLY from %s rejected.",
+                             piaddr (ap -> addr));
+                       return;
+               }
+       }
+       
+       dhcpoffer (packet);
+
+}
+
+void dhcp (packet)
+       struct packet *packet;
+{
+       struct iaddrlist *ap;
+       void (*handler) PROTO ((struct packet *));
+       const 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)) {
+                       log_info ("%s from %s rejected.",
+                             type, piaddr (ap -> addr));
+                       return;
+               }
+       }
+       (*handler) (packet);
+}
+
+void dhcpoffer (packet)
+       struct packet *packet;
+{
+       struct interface_info *ip = packet -> interface;
+       struct client_state *client;
+       struct client_lease *lease, *lp;
+       int i;
+       int stop_selecting;
+       const char *name = packet -> packet_type ? "DHCPOFFER" : "BOOTREPLY";
+       struct iaddrlist *ap;
+       struct option_cache *oc;
+       char obuf [1024];
+       
+#ifdef DEBUG_PACKET
+       dump_packet (packet);
+#endif 
+
+       /* Find a client state that matches the xid... */
+       for (client = ip -> client; client; client = client -> next)
+               if (client -> xid == packet -> raw -> xid)
+                       break;
+
+       /* If we're not receptive to an offer right now, or if the offer
+          has an unrecognizable transaction id, then just drop it. */
+       if (!client ||
+           client -> state != S_SELECTING ||
+           (packet -> interface -> hw_address.hlen - 1 !=
+            packet -> raw -> hlen) ||
+           (memcmp (&packet -> interface -> hw_address.hbuf [1],
+                    packet -> raw -> chaddr, packet -> raw -> hlen))) {
+#if defined (DEBUG)
+               log_debug ("%s in wrong transaction.", name);
+#endif
+               return;
+       }
+
+       sprintf (obuf, "%s from %s", name, piaddr (packet -> client_addr));
+
+
+       /* If this lease doesn't supply the minimum required parameters,
+          blow it off. */
+       if (client -> config -> required_options) {
+           for (i = 0; client -> config -> required_options [i]; i++) {
+               if (!lookup_option
+                   (&dhcp_universe, packet -> options,
+                    client -> config -> required_options [i])) {
+                   log_info ("%s: no %s option.",
+                             obuf, (dhcp_universe.options
+                                    [client -> config -> required_options [i]]
+                                    -> name));
+                               return;
+                       }
+               }
+       }
+
+       /* If we've already seen this lease, don't record it again. */
+       for (lease = 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)) {
+                       log_debug ("%s: already seen.", obuf);
+                       return;
+               }
+       }
+
+       lease = packet_to_lease (packet, client);
+       if (!lease) {
+               log_info ("%s: packet_to_lease failed.", obuf);
+               return;
+       }
+
+       /* If this lease was acquired through a BOOTREPLY, record that
+          fact. */
+       if (!packet -> options_valid || !packet -> packet_type)
+               lease -> is_bootp = 1;
+
+       /* Record the medium under which this lease was offered. */
+       lease -> medium = client -> medium;
+
+       /* Figure out when we're supposed to stop selecting. */
+       stop_selecting = (client -> first_sending +
+                         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 == client -> requested_address.len &&
+           !memcmp (lease -> address.iabuf,
+                    client -> requested_address.iabuf,
+                    client -> requested_address.len)) {
+               lease -> next = client -> offered_leases;
+               client -> offered_leases = lease;
+       } else {
+               /* Put the lease at the end of the list. */
+               lease -> next = (struct client_lease *)0;
+               if (!client -> offered_leases)
+                       client -> offered_leases = lease;
+               else {
+                       for (lp = client -> offered_leases; lp -> next;
+                            lp = lp -> next)
+                               ;
+                       lp -> next = lease;
+               }
+       }
+
+       /* 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 (client);
+       else {
+               add_timeout (stop_selecting, state_selecting, client, 0, 0);
+               cancel_timeout (send_discover, client);
+       }
+       log_info ("%s", obuf);
+}
+
+/* Allocate a client_lease structure and initialize it from the parameters
+   in the specified packet. */
+
+struct client_lease *packet_to_lease (packet, client)
+       struct packet *packet;
+       struct client_state *client;
+{
+       struct client_lease *lease;
+       unsigned i;
+       struct option_cache *oc;
+       struct data_string data;
+
+       lease = (struct client_lease *)new_client_lease (MDL);
+
+       if (!lease) {
+               log_error ("packet_to_lease: no memory to record lease.\n");
+               return (struct client_lease *)0;
+       }
+
+       memset (lease, 0, sizeof *lease);
+
+       /* Copy the lease options. */
+       option_state_reference (&lease -> options, packet -> options, MDL);
+
+       lease -> address.len = sizeof (packet -> raw -> yiaddr);
+       memcpy (lease -> address.iabuf, &packet -> raw -> yiaddr,
+               lease -> address.len);
+
+       memset (&data, 0, sizeof data);
+
+       if (client -> config -> vendor_space_name) {
+               i = DHO_VENDOR_ENCAPSULATED_OPTIONS;
+
+               /* See if there was a vendor encapsulation option. */
+               oc = lookup_option (&dhcp_universe, lease -> options, i);
+               if (oc &&
+                   client -> config -> vendor_space_name &&
+                   evaluate_option_cache (&data, packet,
+                                          (struct lease *)0, client,
+                                          packet -> options, lease -> options,
+                                          &global_scope, oc, MDL)) {
+                       if (data.len) {
+                               parse_encapsulated_suboptions
+                                       (packet -> options, &dhcp_options [i],
+                                        data.data, data.len, &dhcp_universe,
+                                        client -> config -> vendor_space_name
+                                               );
+                       }
+                       data_string_forget (&data, MDL);
+               }
+       } else
+               i = 0;
+
+       /* Figure out the overload flag. */
+       oc = lookup_option (&dhcp_universe, lease -> options,
+                           DHO_DHCP_OPTION_OVERLOAD);
+       if (oc &&
+           evaluate_option_cache (&data, packet, (struct lease *)0, client,
+                                  packet -> options, lease -> options,
+                                  &global_scope, oc, MDL)) {
+               if (data.len > 0)
+                       i = data.data [0];
+               else
+                       i = 0;
+               data_string_forget (&data, MDL);
+       } else
+               i = 0;
+
+       /* If the server name was filled out, copy it. */
+       if (!(i & 2) && packet -> raw -> sname [0]) {
+               unsigned len;
+               /* Don't count on the NUL terminator. */
+               for (len = 0; len < 64; len++)
+                       if (!packet -> raw -> sname [len])
+                               break;
+               lease -> server_name = dmalloc (len + 1, MDL);
+               if (!lease -> server_name) {
+                       log_error ("dhcpoffer: no memory for filename.\n");
+                       destroy_client_lease (lease);
+                       return (struct client_lease *)0;
+               } else {
+                       memcpy (lease -> server_name,
+                               packet -> raw -> sname, len);
+                       lease -> server_name [len] = 0;
+               }
+       }
+
+       /* Ditto for the filename. */
+       if (!(i & 1) && packet -> raw -> file [0]) {
+               unsigned len;
+               /* Don't count on the NUL terminator. */
+               for (len = 0; len < 64; len++)
+                       if (!packet -> raw -> file [len])
+                               break;
+               lease -> filename = dmalloc (len + 1, MDL);
+               if (!lease -> filename) {
+                       log_error ("dhcpoffer: no memory for filename.\n");
+                       destroy_client_lease (lease);
+                       return (struct client_lease *)0;
+               } else {
+                       memcpy (lease -> filename,
+                               packet -> raw -> file, len);
+                       lease -> filename [len] = 0;
+               }
+       }
+
+       execute_statements_in_scope ((struct binding_value **)0,
+                                    (struct packet *)packet,
+                                    (struct lease *)0, client,
+                                    lease -> options, lease -> options,
+                                    &global_scope,
+                                    client -> config -> on_receipt,
+                                    (struct group *)0);
+
+       return lease;
+}      
+
+void dhcpnak (packet)
+       struct packet *packet;
+{
+       struct interface_info *ip = packet -> interface;
+       struct client_state *client;
+
+       /* Find a client state that matches the xid... */
+       for (client = ip -> client; client; client = client -> next)
+               if (client -> xid == packet -> raw -> xid)
+                       break;
+
+       /* If we're not receptive to an offer right now, or if the offer
+          has an unrecognizable transaction id, then just drop it. */
+       if (!client ||
+           (packet -> interface -> hw_address.hlen - 1 !=
+            packet -> raw -> hlen) ||
+           (memcmp (&packet -> interface -> hw_address.hbuf [1],
+                    packet -> raw -> chaddr, packet -> raw -> hlen))) {
+#if defined (DEBUG)
+               log_debug ("DHCPNAK in wrong transaction.");
+#endif
+               return;
+       }
+
+       if (client -> state != S_REBOOTING &&
+           client -> state != S_REQUESTING &&
+           client -> state != S_RENEWING &&
+           client -> state != S_REBINDING) {
+#if defined (DEBUG)
+               log_debug ("DHCPNAK in wrong state.");
+#endif
+               return;
+       }
+
+       log_info ("DHCPNAK from %s", piaddr (packet -> client_addr));
+
+       if (!client -> active) {
+#if defined (DEBUG)
+               log_info ("DHCPNAK with no active lease.\n");
+#endif
+               return;
+       }
+
+       destroy_client_lease (client -> active);
+       client -> active = (struct client_lease *)0;
+
+       /* Stop sending DHCPREQUEST packets... */
+       cancel_timeout (send_request, client);
+
+       client -> state = S_INIT;
+       state_init (client);
+}
+
+/* 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 (cpp)
+       void *cpp;
+{
+       struct client_state *client = cpp;
+
+       int result;
+       int interval;
+       int increase = 1;
+
+       /* Figure out how long it's been since we started transmitting. */
+       interval = cur_time - 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 > client -> config -> timeout) {
+               state_panic (client);
+               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 (!client -> offered_leases &&
+           client -> config -> media) {
+               int fail = 0;
+             again:
+               if (client -> medium) {
+                       client -> medium = client -> medium -> next;
+                       increase = 0;
+               } 
+               if (!client -> medium) {
+                       if (fail)
+                               log_fatal ("No valid media types for %s!",
+                                      client -> interface -> name);
+                       client -> medium =
+                               client -> config -> media;
+                       increase = 1;
+               }
+                       
+               log_info ("Trying medium \"%s\" %d",
+                         client -> medium -> string, increase);
+               script_init (client, "MEDIUM", client -> medium);
+               if (script_go (client)) {
+                       fail = 1;
+                       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 initial_interval; 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 (!client -> interval)
+                       client -> interval =
+                               client -> config -> initial_interval;
+               else
+                       client -> interval += ((random () >> 2) %
+                                              (2 * client -> interval));
+
+               /* Don't backoff past cutoff. */
+               if (client -> interval >
+                   client -> config -> backoff_cutoff)
+                       client -> interval =
+                               ((client -> config -> backoff_cutoff / 2)
+                                + ((random () >> 2) %
+                                   client -> config -> backoff_cutoff));
+       } else if (!client -> interval)
+               client -> interval = client -> config -> initial_interval;
+               
+       /* If the backoff would take us to the panic timeout, just use that
+          as the interval. */
+       if (cur_time + client -> interval >
+           client -> first_sending + client -> config -> timeout)
+               client -> interval =
+                       (client -> first_sending +
+                        client -> config -> timeout) - cur_time + 1;
+
+       /* Record the number of seconds since we started sending. */
+       if (interval < 65536)
+               client -> packet.secs = htons (interval);
+       else
+               client -> packet.secs = htons (65535);
+       client -> secs = client -> packet.secs;
+
+       log_info ("DHCPDISCOVER on %s to %s port %d interval %ld",
+             client -> name ? client -> name : client -> interface -> name,
+             inet_ntoa (sockaddr_broadcast.sin_addr),
+             ntohs (sockaddr_broadcast.sin_port), (long)(client -> interval));
+
+       /* Send out a packet. */
+       result = send_packet (client -> interface, (struct packet *)0,
+                             &client -> packet,
+                             client -> packet_length,
+                             inaddr_any, &sockaddr_broadcast,
+                             (struct hardware *)0);
+
+       add_timeout (cur_time + client -> interval,
+                    send_discover, client, 0, 0);
+}
+
+/* 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 (cpp)
+       void *cpp;
+{
+       struct client_state *client = cpp;
+       struct client_lease *loop;
+       struct client_lease *lp;
+
+       loop = lp = client -> active;
+
+       log_info ("No DHCPOFFERS received.");
+
+       /* We may not have an active lease, but we may have some
+          predefined leases that we can try. */
+       if (!client -> active && client -> leases)
+               goto activate_next;
+
+       /* Run through the list of leases and see if one can be used. */
+       while (client -> active) {
+               if (client -> active -> expiry > cur_time) {
+                       log_info ("Trying recorded lease %s",
+                             piaddr (client -> active -> address));
+                       /* Run the client script with the existing
+                          parameters. */
+                       script_init (client, "TIMEOUT",
+                                    client -> active -> medium);
+                       script_write_params (client, "new_", client -> active);
+                       if (client -> alias)
+                               script_write_params (client, "alias_",
+                                                    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 (client)) {
+                           if (cur_time < client -> active -> renewal) {
+                               client -> state = S_BOUND;
+                               log_info ("bound: renewal in %ld %s.",
+                                         (long)(client -> active -> renewal -
+                                                cur_time), "seconds");
+                               add_timeout (client -> active -> renewal,
+                                            state_bound, client, 0, 0);
+                           } else {
+                               client -> state = S_BOUND;
+                               log_info ("bound: immediate renewal.");
+                               state_bound (client);
+                           }
+                           reinitialize_interfaces ();
+                           go_daemon ();
+                           return;
+                       }
+               }
+
+               /* If there are no other leases, give up. */
+               if (!client -> leases) {
+                       client -> leases = client -> active;
+                       client -> active = (struct client_lease *)0;
+                       break;
+               }
+
+       activate_next:
+               /* Otherwise, put the active lease at the end of the
+                  lease list, and try another lease.. */
+               for (lp = client -> leases; lp -> next; lp = lp -> next)
+                       ;
+               lp -> next = client -> active;
+               if (lp -> next) {
+                       lp -> next -> next = (struct client_lease *)0;
+               }
+               client -> active = client -> leases;
+               client -> leases = 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 (client -> active == loop)
+                       break;
+               else if (!loop)
+                       loop = 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. */
+       if (onetry) {
+               if (!quiet)
+                       log_info ("Unable to obtain a lease on first try.%s",
+                                 "  Exiting.");
+               exit (2);
+       }
+
+       log_info ("No working leases in persistent database - sleeping.");
+       script_init (client, "FAIL", (struct string_list *)0);
+       if (client -> alias)
+               script_write_params (client, "alias_", client -> alias);
+       script_go (client);
+       client -> state = S_INIT;
+       add_timeout (cur_time +
+                    ((client -> config -> retry_interval + 1) / 2 +
+                     (random () % client -> config -> retry_interval)),
+                    state_init, client, 0, 0);
+       go_daemon ();
+}
+
+void send_request (cpp)
+       void *cpp;
+{
+       struct client_state *client = cpp;
+
+       int result;
+       int interval;
+       struct sockaddr_in destination;
+       struct in_addr from;
+
+       /* Figure out how long it's been since we started transmitting. */
+       interval = cur_time - 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 ((client -> state == S_REBOOTING ||
+            client -> state == S_REQUESTING) &&
+           interval > client -> config -> reboot_timeout) {
+       cancel:
+               client -> state = S_INIT;
+               cancel_timeout (send_request, client);
+               state_init (client);
+               return;
+       }
+
+       /* If we're in the reboot state, make sure the media is set up
+          correctly. */
+       if (client -> state == S_REBOOTING &&
+           !client -> medium &&
+           client -> active -> medium ) {
+               script_init (client, "MEDIUM", client -> active -> medium);
+
+               /* If the medium we chose won't fly, go to INIT state. */
+               if (script_go (client))
+                       goto cancel;
+
+               /* Record the medium. */
+               client -> medium = client -> active -> medium;
+       }
+
+       /* If the lease has expired, relinquish the address and go back
+          to the INIT state. */
+       if (client -> state != S_REQUESTING &&
+           cur_time > client -> active -> expiry) {
+               /* Run the client script with the new parameters. */
+               script_init (client, "EXPIRE", (struct string_list *)0);
+               script_write_params (client, "old_", client -> active);
+               if (client -> alias)
+                       script_write_params (client, "alias_",
+                                            client -> alias);
+               script_go (client);
+
+               /* Now do a preinit on the interface so that we can
+                  discover a new address. */
+               script_init (client, "PREINIT", (struct string_list *)0);
+               if (client -> alias)
+                       script_write_params (client, "alias_",
+                                            client -> alias);
+               script_go (client);
+
+               client -> state = S_INIT;
+               state_init (client);
+               return;
+       }
+
+       /* Do the exponential backoff... */
+       if (!client -> interval)
+               client -> interval = client -> config -> initial_interval;
+       else {
+               client -> interval += ((random () >> 2) %
+                                      (2 * client -> interval));
+       }
+       
+       /* Don't backoff past cutoff. */
+       if (client -> interval >
+           client -> config -> backoff_cutoff)
+               client -> interval =
+                       ((client -> config -> backoff_cutoff / 2)
+                        + ((random () >> 2) %
+                                       client -> config -> backoff_cutoff));
+
+       /* If the backoff would take us to the expiry time, just set the
+          timeout to the expiry time. */
+       if (client -> state != S_REQUESTING &&
+           cur_time + client -> interval > client -> active -> expiry)
+               client -> interval =
+                       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. */
+       if (client -> state == S_REQUESTING ||
+           client -> state == S_REBOOTING ||
+           cur_time > client -> active -> rebind)
+               destination.sin_addr = sockaddr_broadcast.sin_addr;
+       else
+               memcpy (&destination.sin_addr.s_addr,
+                       client -> destination.iabuf,
+                       sizeof destination.sin_addr.s_addr);
+       destination.sin_port = remote_port;
+       destination.sin_family = AF_INET;
+#ifdef HAVE_SA_LEN
+       destination.sin_len = sizeof destination;
+#endif
+
+       if (client -> state == S_RENEWING ||
+           client -> state == S_REBINDING)
+               memcpy (&from, client -> active -> address.iabuf,
+                       sizeof from);
+       else
+               from.s_addr = INADDR_ANY;
+
+       /* Record the number of seconds since we started sending. */
+       if (client -> state == S_REQUESTING)
+               client -> packet.secs = client -> secs;
+       else {
+               if (interval < 65536)
+                       client -> packet.secs = htons (interval);
+               else
+                       client -> packet.secs = htons (65535);
+       }
+
+       log_info ("DHCPREQUEST on %s to %s port %d",
+             client -> name ? client -> name : client -> interface -> name,
+             inet_ntoa (destination.sin_addr),
+             ntohs (destination.sin_port));
+
+       if (destination.sin_addr.s_addr != INADDR_BROADCAST &&
+           fallback_interface)
+               result = send_packet (fallback_interface,
+                                     (struct packet *)0,
+                                     &client -> packet,
+                                     client -> packet_length,
+                                     from, &destination,
+                                     (struct hardware *)0);
+       else
+               /* Send out a packet. */
+               result = send_packet (client -> interface, (struct packet *)0,
+                                     &client -> packet,
+                                     client -> packet_length,
+                                     from, &destination,
+                                     (struct hardware *)0);
+
+       add_timeout (cur_time + client -> interval,
+                    send_request, client, 0, 0);
+}
+
+void send_decline (cpp)
+       void *cpp;
+{
+       struct client_state *client = cpp;
+
+       int result;
+
+       log_info ("DHCPDECLINE on %s to %s port %d",
+             client -> name ? client -> name : client -> interface -> name,
+             inet_ntoa (sockaddr_broadcast.sin_addr),
+             ntohs (sockaddr_broadcast.sin_port));
+
+       /* Send out a packet. */
+       result = send_packet (client -> interface, (struct packet *)0,
+                             &client -> packet,
+                             client -> packet_length,
+                             inaddr_any, &sockaddr_broadcast,
+                             (struct hardware *)0);
+}
+
+void send_release (cpp)
+       void *cpp;
+{
+       struct client_state *client = cpp;
+
+       int result;
+       struct sockaddr_in destination;
+       struct in_addr from;
+
+       memcpy (&from, client -> active -> address.iabuf,
+               sizeof from);
+       memcpy (&destination.sin_addr.s_addr,
+               client -> destination.iabuf,
+               sizeof destination.sin_addr.s_addr);
+       destination.sin_port = remote_port;
+       destination.sin_family = AF_INET;
+#ifdef HAVE_SA_LEN
+       destination.sin_len = sizeof destination;
+#endif
+
+       /* Set the lease to end now, so that we don't accidentally
+          reuse it if we restart before the old expiry time. */
+       client -> active -> expiry =
+               client -> active -> renewal =
+               client -> active -> rebind = cur_time;
+       if (!write_client_lease (client, client -> active, 1, 1)) {
+               log_error ("Can't release lease: lease write failed.");
+               return;
+       }
+
+       log_info ("DHCPRELEASE on %s to %s port %d",
+             client -> name ? client -> name : client -> interface -> name,
+             inet_ntoa (destination.sin_addr),
+             ntohs (destination.sin_port));
+
+       if (fallback_interface)
+               result = send_packet (fallback_interface,
+                                     (struct packet *)0,
+                                     &client -> packet,
+                                     client -> packet_length,
+                                     from, &destination,
+                                     (struct hardware *)0);
+       else
+               /* Send out a packet. */
+               result = send_packet (client -> interface, (struct packet *)0,
+                                     &client -> packet,
+                                     client -> packet_length,
+                                     from, &destination,
+                                     (struct hardware *)0);
+}
+
+void make_client_options (client, lease, type, sid, rip, prl, op)
+       struct client_state *client;
+       struct client_lease *lease;
+       u_int8_t *type;
+       struct option_cache *sid;
+       struct iaddr *rip;
+       u_int32_t *prl;
+       struct option_state **op;
+{
+       unsigned i;
+       struct option_cache *oc;
+       struct buffer *bp = (struct buffer *)0;
+
+       /* If there are any leftover options, get rid of them. */
+       if (*op)
+               option_state_dereference (op, MDL);
+
+       /* Allocate space for options. */
+       option_state_allocate (op, MDL);
+
+       /* Send the server identifier if provided. */
+       if (sid)
+               save_option (&dhcp_universe, *op, sid);
+
+       oc = (struct option_cache *)0;
+
+       /* Send the requested address if provided. */
+       if (rip) {
+               client -> requested_address = *rip;
+               if (!(make_const_option_cache
+                     (&oc, (struct buffer **)0, rip -> iabuf, rip -> len,
+                      &dhcp_options [DHO_DHCP_REQUESTED_ADDRESS], MDL)))
+                       log_error ("can't make requested address cache.");
+               else {
+                       save_option (&dhcp_universe, *op, oc);
+                       option_cache_dereference (&oc, MDL);
+               }
+       } else {
+               client -> requested_address.len = 0;
+       }
+
+       if (!(make_const_option_cache
+             (&oc, (struct buffer **)0,
+              type, 1, &dhcp_options [DHO_DHCP_MESSAGE_TYPE], MDL)))
+               log_error ("can't make message type.");
+       else {
+               save_option (&dhcp_universe, *op, oc);
+               option_cache_dereference (&oc, MDL);
+       }
+
+       if (prl) {
+               /* Figure out how many parameters were requested. */
+               for (i = 0; prl [i]; i++)
+                       ;
+               if (!buffer_allocate (&bp, i, MDL))
+                       log_error ("can't make parameter list buffer.");
+               else {
+                       for (i = 0; prl [i]; i++)
+                               bp -> data [i] = prl [i];
+                       if (!(make_const_option_cache
+                             (&oc, &bp, (u_int8_t *)0, i,
+                              &dhcp_options [DHO_DHCP_PARAMETER_REQUEST_LIST],
+                              MDL)))
+                               log_error ("can't make option cache");
+                       else {
+                               save_option (&dhcp_universe, *op, oc);
+                               option_cache_dereference (&oc, MDL);
+                       }
+               }
+       }
+
+       /* Run statements that need to be run on transmission. */
+       if (client -> config -> on_transmission)
+               execute_statements_in_scope
+                       ((struct binding_value **)0,
+                        (struct packet *)0, (struct lease *)0, client,
+                        (lease ? lease -> options : (struct option_state *)0),
+                        *op, &global_scope,
+                        client -> config -> on_transmission,
+                        (struct group *)0);
+}
+
+void make_discover (client, lease)
+       struct client_state *client;
+       struct client_lease *lease;
+{
+       unsigned char discover = DHCPDISCOVER;
+       int i;
+       struct option_state *options = (struct option_state *)0;
+
+       memset (&client -> packet, 0, sizeof (client -> packet));
+
+       make_client_options (client,
+                            lease, &discover, (struct option_cache *)0,
+                            lease ? &lease -> address : (struct iaddr *)0,
+                            client -> config -> requested_options,
+                            &options);
+
+       /* Set up the option buffer... */
+       client -> packet_length =
+               cons_options ((struct packet *)0, &client -> packet,
+                             (struct lease *)0, client,
+                             /* maximum packet size */1500,
+                             (struct option_state *)0,
+                             options,
+                             /* scope */ &global_scope,
+                             /* overload */ 0,
+                             /* terminate */0,
+                             /* bootpp    */0,
+                             (struct data_string *)0,
+                             client -> config -> vendor_space_name);
+
+       option_state_dereference (&options, MDL);
+       if (client -> packet_length < BOOTP_MIN_LEN)
+               client -> packet_length = BOOTP_MIN_LEN;
+
+       client -> packet.op = BOOTREQUEST;
+       client -> packet.htype = client -> interface -> hw_address.hbuf [0];
+       client -> packet.hlen = client -> interface -> hw_address.hlen - 1;
+       client -> packet.hops = 0;
+       client -> packet.xid = random ();
+       client -> packet.secs = 0; /* filled in by send_discover. */
+
+       if (can_receive_unicast_unconfigured (client -> interface))
+               client -> packet.flags = 0;
+       else
+               client -> packet.flags = htons (BOOTP_BROADCAST);
+
+       memset (&(client -> packet.ciaddr),
+               0, sizeof client -> packet.ciaddr);
+       memset (&(client -> packet.yiaddr),
+               0, sizeof client -> packet.yiaddr);
+       memset (&(client -> packet.siaddr),
+               0, sizeof client -> packet.siaddr);
+       client -> packet.giaddr = giaddr;
+       if (client -> interface -> hw_address.hlen > 0)
+           memcpy (client -> packet.chaddr,
+                   &client -> interface -> hw_address.hbuf [1],
+                   (unsigned)(client -> interface -> hw_address.hlen - 1));
+
+#ifdef DEBUG_PACKET
+       dump_raw ((unsigned char *)&client -> packet, client -> packet_length);
+#endif
+}
+
+
+void make_request (client, lease)
+       struct client_state *client;
+       struct client_lease *lease;
+{
+       unsigned char request = DHCPREQUEST;
+       int i, j;
+       unsigned char *tmp, *digest;
+       unsigned char *old_digest_loc;
+       struct option_cache *oc;
+
+       memset (&client -> packet, 0, sizeof (client -> packet));
+
+       if (client -> state == S_REQUESTING)
+               oc = lookup_option (&dhcp_universe, lease -> options,
+                                   DHO_DHCP_SERVER_IDENTIFIER);
+       else
+               oc = (struct option_cache *)0;
+
+       if (client -> sent_options)
+               option_state_dereference (&client -> sent_options, MDL);
+
+       make_client_options (client, lease, &request, oc,
+                            ((client -> state == S_REQUESTING ||
+                              client -> state == S_REBOOTING)
+                             ? &lease -> address
+                             : (struct iaddr *)0),
+                            client -> config -> requested_options,
+                            &client -> sent_options);
+
+       /* Set up the option buffer... */
+       client -> packet_length =
+               cons_options ((struct packet *)0, &client -> packet,
+                             (struct lease *)0, client,
+                             /* maximum packet size */1500,
+                             (struct option_state *)0,
+                             client -> sent_options, 
+                             /* scope */ &global_scope,
+                             /* overload */ 0,
+                             /* terminate */0,
+                             /* bootpp    */0,
+                             (struct data_string *)0,
+                             client -> config -> vendor_space_name);
+
+       if (client -> packet_length < BOOTP_MIN_LEN)
+               client -> packet_length = BOOTP_MIN_LEN;
+
+       client -> packet.op = BOOTREQUEST;
+       client -> packet.htype = client -> interface -> hw_address.hbuf [0];
+       client -> packet.hlen = client -> interface -> hw_address.hlen - 1;
+       client -> packet.hops = 0;
+       client -> packet.xid = client -> xid;
+       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 (client -> state == S_BOUND ||
+           client -> state == S_RENEWING ||
+           client -> state == S_REBINDING) {
+               memcpy (&client -> packet.ciaddr,
+                       lease -> address.iabuf, lease -> address.len);
+               client -> packet.flags = 0;
+       } else {
+               memset (&client -> packet.ciaddr, 0,
+                       sizeof client -> packet.ciaddr);
+               if (can_receive_unicast_unconfigured (client -> interface))
+                       client -> packet.flags = 0;
+               else
+                       client -> packet.flags = htons (BOOTP_BROADCAST);
+       }
+
+       memset (&client -> packet.yiaddr, 0,
+               sizeof client -> packet.yiaddr);
+       memset (&client -> packet.siaddr, 0,
+               sizeof client -> packet.siaddr);
+       if (client -> state != S_BOUND &&
+           client -> state != S_RENEWING)
+               client -> packet.giaddr = giaddr;
+       else
+               memset (&client -> packet.giaddr, 0,
+                       sizeof client -> packet.giaddr);
+       if (client -> interface -> hw_address.hlen > 0)
+           memcpy (client -> packet.chaddr,
+                   &client -> interface -> hw_address.hbuf [1],
+                   (unsigned)(client -> interface -> hw_address.hlen - 1));
+
+#ifdef DEBUG_PACKET
+       dump_raw ((unsigned char *)&client -> packet, client -> packet_length);
+#endif
+}
+
+void make_decline (client, lease)
+       struct client_state *client;
+       struct client_lease *lease;
+{
+       unsigned char decline = DHCPDECLINE;
+       int i;
+       struct option_cache *oc;
+
+       struct option_state *options = (struct option_state *)0;
+
+       oc = lookup_option (&dhcp_universe, lease -> options,
+                           DHO_DHCP_SERVER_IDENTIFIER);
+       make_client_options (client, lease, &decline, oc,
+                            &lease -> address, (u_int32_t *)0, &options);
+
+       /* Set up the option buffer... */
+       memset (&client -> packet, 0, sizeof (client -> packet));
+       client -> packet_length =
+               cons_options ((struct packet *)0, &client -> packet,
+                             (struct lease *)0, client, 0,
+                             (struct option_state *)0, options,
+                             &global_scope, 0, 0, 0, (struct data_string *)0,
+                             client -> config -> vendor_space_name);
+       option_state_dereference (&options, MDL);
+       if (client -> packet_length < BOOTP_MIN_LEN)
+               client -> packet_length = BOOTP_MIN_LEN;
+       option_state_dereference (&options, MDL);
+
+       client -> packet.op = BOOTREQUEST;
+       client -> packet.htype = client -> interface -> hw_address.hbuf [0];
+       client -> packet.hlen = client -> interface -> hw_address.hlen - 1;
+       client -> packet.hops = 0;
+       client -> packet.xid = client -> xid;
+       client -> packet.secs = 0; /* Filled in by send_request. */
+       if (can_receive_unicast_unconfigured (client -> interface))
+               client -> packet.flags = 0;
+       else
+               client -> packet.flags = htons (BOOTP_BROADCAST);
+
+       /* ciaddr must always be zero. */
+       memset (&client -> packet.ciaddr, 0,
+               sizeof client -> packet.ciaddr);
+       memset (&client -> packet.yiaddr, 0,
+               sizeof client -> packet.yiaddr);
+       memset (&client -> packet.siaddr, 0,
+               sizeof client -> packet.siaddr);
+       client -> packet.giaddr = giaddr;
+       memcpy (client -> packet.chaddr,
+               &client -> interface -> hw_address.hbuf [1],
+               client -> interface -> hw_address.hlen);
+
+#ifdef DEBUG_PACKET
+       dump_raw ((unsigned char *)&client -> packet, client -> packet_length);
+#endif
+}
+
+void make_release (client, lease)
+       struct client_state *client;
+       struct client_lease *lease;
+{
+       unsigned char request = DHCPRELEASE;
+       int i;
+       struct option_cache *oc;
+
+       struct option_state *options = (struct option_state *)0;
+
+       memset (&client -> packet, 0, sizeof (client -> packet));
+
+       oc = lookup_option (&dhcp_universe, lease -> options,
+                           DHO_DHCP_SERVER_IDENTIFIER);
+       make_client_options (client, lease, &request, oc,
+                            (struct iaddr *)0, (u_int32_t *)0,
+                            &options);
+
+       /* Set up the option buffer... */
+       client -> packet_length =
+               cons_options ((struct packet *)0, &client -> packet,
+                             (struct lease *)0, client,
+                             /* maximum packet size */1500,
+                             (struct option_state *)0,
+                             options,
+                             /* scope */ &global_scope,
+                             /* overload */ 0,
+                             /* terminate */0,
+                             /* bootpp    */0,
+                             (struct data_string *)0,
+                             client -> config -> vendor_space_name);
+
+       if (client -> packet_length < BOOTP_MIN_LEN)
+               client -> packet_length = BOOTP_MIN_LEN;
+       option_state_dereference (&options, MDL);
+
+       client -> packet.op = BOOTREQUEST;
+       client -> packet.htype = client -> interface -> hw_address.hbuf [0];
+       client -> packet.hlen = client -> interface -> hw_address.hlen - 1;
+       client -> packet.hops = 0;
+       client -> packet.xid = random ();
+       client -> packet.secs = 0;
+       client -> packet.flags = 0;
+       memcpy (&client -> packet.ciaddr,
+               lease -> address.iabuf, lease -> address.len);
+       memset (&client -> packet.yiaddr, 0,
+               sizeof client -> packet.yiaddr);
+       memset (&client -> packet.siaddr, 0,
+               sizeof client -> packet.siaddr);
+       client -> packet.giaddr = giaddr;
+       memcpy (client -> packet.chaddr,
+               &client -> interface -> hw_address.hbuf [1],
+               client -> interface -> hw_address.hlen);
+
+#ifdef DEBUG_PACKET
+       dump_raw ((unsigned char *)&client -> packet, client -> packet_length);
+#endif
+}
+
+void destroy_client_lease (lease)
+       struct client_lease *lease;
+{
+       int i;
+
+       if (lease -> server_name)
+               dfree (lease -> server_name, MDL);
+       if (lease -> filename)
+               dfree (lease -> filename, MDL);
+       option_state_dereference (&lease -> options, MDL);
+       free_client_lease (lease, MDL);
+}
+
+FILE *leaseFile;
+
+void rewrite_client_leases ()
+{
+       struct interface_info *ip;
+       struct client_state *client;
+       struct client_lease *lp;
+
+       if (leaseFile)
+               fclose (leaseFile);
+       leaseFile = fopen (path_dhclient_db, "w");
+       if (!leaseFile) {
+               log_error ("can't create %s: %m", path_dhclient_db);
+               return;
+       }
+
+       /* Write out all the leases attached to configured interfaces that
+          we know about. */
+       for (ip = interfaces; ip; ip = ip -> next) {
+               for (client = ip -> client; client; client = client -> next) {
+                       for (lp = client -> leases; lp; lp = lp -> next) {
+                               write_client_lease (client, lp, 1, 0);
+                       }
+                       if (client -> active)
+                               write_client_lease (client,
+                                                   client -> active, 1, 0);
+               }
+       }
+
+       /* Write out any leases that are attached to interfaces that aren't
+          currently configured. */
+       for (ip = dummy_interfaces; ip; ip = ip -> next) {
+               for (client = ip -> client; client; client = client -> next) {
+                       for (lp = client -> leases; lp; lp = lp -> next) {
+                               write_client_lease (client, lp, 1, 0);
+                       }
+                       if (client -> active)
+                               write_client_lease (client,
+                                                   client -> active, 1, 0);
+               }
+       }
+       fflush (leaseFile);
+}
+
+void write_lease_option (struct option_cache *oc,
+                        struct packet *packet, struct lease *lease,
+                        struct client_state *client_state,
+                        struct option_state *in_options,
+                        struct option_state *cfg_options,
+                        struct binding_scope **scope,
+                        struct universe *u, void *stuff)
+{
+       const char *name, *dot;
+       struct data_string ds;
+       int status;
+       struct client_state *client;
+
+       memset (&ds, 0, sizeof ds);
+
+       if (u != &dhcp_universe) {
+               name = u -> name;
+               dot = ".";
+       } else {
+               name = "";
+               dot = "";
+       }
+       if (evaluate_option_cache (&ds, packet, lease, client_state,
+                                  in_options, cfg_options, scope, oc, MDL)) {
+               fprintf (leaseFile,
+                        "  option %s%s%s %s;\n",
+                        name, dot, oc -> option -> name,
+                        pretty_print_option (oc -> option,
+                                             ds.data, ds.len, 1, 1));
+               data_string_forget (&ds, MDL);
+       }
+}
+
+int write_client_lease (client, lease, rewrite, makesure)
+       struct client_state *client;
+       struct client_lease *lease;
+       int rewrite;
+       int makesure;
+{
+       int i;
+       struct tm *t;
+       static int leases_written;
+       struct option_cache *oc;
+       struct data_string ds;
+       pair *hash;
+       int errors = 0;
+       char *s;
+
+       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 1;
+
+       if (!leaseFile) {       /* XXX */
+               leaseFile = fopen (path_dhclient_db, "w");
+               if (!leaseFile) {
+                       log_error ("can't create %s: %m", path_dhclient_db);
+                       return 0;
+               }
+       }
+
+       errno = 0;
+       fprintf (leaseFile, "lease {\n");
+       if (lease -> is_bootp) {
+               fprintf (leaseFile, "  bootp;\n");
+               if (errno) {
+                       ++errors;
+                       errno = 0;
+               }
+       }
+       fprintf (leaseFile, "  interface \"%s\";\n",
+                client -> interface -> name);
+       if (errno) {
+               ++errors;
+               errno = 0;
+       }
+       if (client -> name) {
+               fprintf (leaseFile, "  name \"%s\";\n", client -> name);
+               if (errno) {
+                       ++errors;
+                       errno = 0;
+               }
+       }
+       fprintf (leaseFile, "  fixed-address %s;\n",
+                piaddr (lease -> address));
+       if (errno) {
+               ++errors;
+               errno = 0;
+       }
+       if (lease -> filename) {
+               s = quotify_string (lease -> filename, MDL);
+               if (s) {
+                       fprintf (leaseFile, "  filename \"%s\";\n", s);
+                       if (errno) {
+                               ++errors;
+                               errno = 0;
+                       }
+                       dfree (s, MDL);
+               } else
+                       errors++;
+
+       }
+       if (lease -> server_name) {
+               s = quotify_string (lease -> filename, MDL);
+               if (s) {
+                       fprintf (leaseFile, "  server-name \"%s\";\n", s);
+                       if (errno) {
+                               ++errors;
+                               errno = 0;
+                       }
+                       dfree (s, MDL);
+               } else
+                       ++errors;
+       }
+       if (lease -> medium) {
+               s = quotify_string (lease -> medium -> string, MDL);
+               if (s) {
+                       fprintf (leaseFile, "  medium \"%s\";\n", s);
+                       if (errno) {
+                               ++errors;
+                               errno = 0;
+                       }
+                       dfree (s, MDL);
+               } else
+                       errors++;
+       }
+       if (errno != 0) {
+               errors++;
+               errno = 0;
+       }
+
+       memset (&ds, 0, sizeof ds);
+
+       for (i = 0; i < lease -> options -> universe_count; i++) {
+               option_space_foreach ((struct packet *)0, (struct lease *)0,
+                                     client, (struct option_state *)0,
+                                     lease -> options, &global_scope,
+                                     universes [i],
+                                     client, write_lease_option);
+       }
+
+       /* Note: the following is not a Y2K bug - it's a Y1.9K bug.   Until
+          somebody invents a time machine, I think we can safely disregard
+          it. */
+       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);
+       if (errno != 0) {
+               errors++;
+               errno = 0;
+       }
+       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);
+       if (errno != 0) {
+               errors++;
+               errno = 0;
+       }
+       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);
+       if (errno != 0) {
+               errors++;
+               errno = 0;
+       }
+       fprintf (leaseFile, "}\n");
+       if (errno != 0) {
+               errors++;
+               errno = 0;
+       }
+       fflush (leaseFile);
+       if (errno != 0) {
+               errors++;
+               errno = 0;
+       }
+       if (!errors && makesure) {
+               if (fsync (fileno (leaseFile)) < 0) {
+                       log_info ("write_client_lease: %m");
+                       return 0;
+               }
+       }
+       return errors ? 0 : 1;
+}
+
+/* Variables holding name of script and file pointer for writing to
+   script.   Needless to say, this is not reentrant - only one script
+   can be invoked at a time. */
+char scriptName [256];
+FILE *scriptFile;
+
+void script_init (client, reason, medium)
+       struct client_state *client;
+       const char *reason;
+       struct string_list *medium;
+{
+       struct string_list *sl, *next;
+
+       if (client) {
+               for (sl = client -> env; sl; sl = next) {
+                       next = sl -> next;
+                       dfree (sl, MDL);
+               }
+               client -> env = (struct string_list *)0;
+               client -> envc = 0;
+               
+               if (client -> interface) {
+                       client_envadd (client, "", "interface", "%s",
+                                      client -> interface -> name);
+               }
+               if (client -> name)
+                       client_envadd (client,
+                                      "", "client", "%s", client -> name);
+               if (medium)
+                       client_envadd (client,
+                                      "", "medium", "%s", medium -> string);
+
+               client_envadd (client, "", "reason", "%s", reason);
+               client_envadd (client, "", "pid", "%ld", (long int)getpid ());
+       }
+}
+
+struct envadd_state {
+       struct client_state *client;
+       const char *prefix;
+};
+
+void client_option_envadd (struct option_cache *oc,
+                          struct packet *packet, struct lease *lease,
+                          struct client_state *client_state,
+                          struct option_state *in_options,
+                          struct option_state *cfg_options,
+                          struct binding_scope **scope,
+                          struct universe *u, void *stuff)
+{
+       struct envadd_state *es = stuff;
+       struct data_string data;
+       memset (&data, 0, sizeof data);
+
+       if (evaluate_option_cache (&data, packet, lease, client_state,
+                                  in_options, cfg_options, scope, oc, MDL)) {
+               if (data.len) {
+                       char name [256];
+                       if (dhcp_option_ev_name (name, sizeof name,
+                                                oc -> option)) {
+                               client_envadd (es -> client, es -> prefix,
+                                              name, "%s",
+                                              (pretty_print_option
+                                               (oc -> option,
+                                                data.data, data.len,
+                                                0, 0)));
+                               data_string_forget (&data, MDL);
+                       }
+               }
+       }
+}
+
+void script_write_params (client, prefix, lease)
+       struct client_state *client;
+       const char *prefix;
+       struct client_lease *lease;
+{
+       int i;
+       struct data_string data;
+       struct option_cache *oc;
+       pair *hash;
+       char *s, *t;
+       struct envadd_state es;
+
+       es.client = client;
+       es.prefix = prefix;
+
+       client_envadd (client,
+                      prefix, "ip_address", "%s", piaddr (lease -> address));
+
+       /* For the benefit of Linux (and operating systems which may
+          have similar needs), compute the network address based on
+          the supplied ip address and netmask, if provided.  Also
+          compute the broadcast address (the host address all ones
+          broadcast address, not the host address all zeroes
+          broadcast address). */
+
+       memset (&data, 0, sizeof data);
+       oc = lookup_option (&dhcp_universe, lease -> options, DHO_SUBNET_MASK);
+       if (oc && evaluate_option_cache (&data, (struct packet *)0,
+                                        (struct lease *)0, client,
+                                        (struct option_state *)0,
+                                        lease -> options,
+                                        &global_scope, oc, MDL)) {
+               if (data.len > 3) {
+                       struct iaddr netmask, subnet, broadcast;
+
+                       memcpy (netmask.iabuf, data.data, data.len);
+                       netmask.len = data.len;
+                       data_string_forget (&data, MDL);
+
+                       subnet = subnet_number (lease -> address, netmask);
+                       if (subnet.len) {
+                           client_envadd (client, prefix, "network_number",
+                                          "%s", piaddr (subnet));
+
+                           oc = lookup_option (&dhcp_universe,
+                                               lease -> options,
+                                               DHO_BROADCAST_ADDRESS);
+                           if (!oc ||
+                               !(evaluate_option_cache
+                                 (&data, (struct packet *)0,
+                                  (struct lease *)0, client,
+                                  (struct option_state *)0,
+                                  lease -> options,
+                                  &global_scope, oc, MDL))) {
+                               broadcast = broadcast_addr (subnet, netmask);
+                               if (broadcast.len) {
+                                   client_envadd (client,
+                                                  prefix, "broadcast_address",
+                                                  "%s", piaddr (broadcast));
+                               }
+                           }
+                       }
+               }
+               data_string_forget (&data, MDL);
+       }
+
+       if (lease -> filename)
+               client_envadd (client,
+                              prefix, "filename", "%s", lease -> filename);
+       if (lease -> server_name)
+               client_envadd (client, prefix, "server_name",
+                              "%s", lease -> server_name);
+
+       for (i = 0; i < lease -> options -> universe_count; i++) {
+               option_space_foreach ((struct packet *)0, (struct lease *)0,
+                                     client, (struct option_state *)0,
+                                     lease -> options, &global_scope,
+                                     universes [i],
+                                     &es, client_option_envadd);
+       }
+       client_envadd (client, prefix, "expiry", "%d", (int)(lease -> expiry));
+}
+
+int script_go (client)
+       struct client_state *client;
+{
+       int rval;
+       char *scriptName;
+       char *argv [2];
+       char **envp;
+       char *epp [3];
+       char reason [] = "REASON=NBI";
+       static char client_path [] = CLIENT_PATH;
+       int i;
+       struct string_list *sp, *next;
+       int pid, wpid, wstatus;
+
+       if (client)
+               scriptName = client -> config -> script_name;
+       else
+               scriptName = top_level_config.script_name;
+
+       envp = dmalloc (((client ? client -> envc : 2) +
+                        client_env_count + 2) * sizeof (char *), MDL);
+       if (!envp) {
+               log_error ("No memory for client script environment.");
+               return 0;
+       }
+       i = 0;
+       /* Copy out the environment specified on the command line,
+          if any. */
+       for (sp = client_env; sp; sp = sp -> next) {
+               envp [i++] = sp -> string;
+       }
+       /* Copy out the environment specified by dhclient. */
+       if (client) {
+               for (sp = client -> env; sp; sp = sp -> next) {
+                       envp [i++] = sp -> string;
+               }
+       } else {
+               envp [i++] = reason;
+       }
+       /* Set $PATH. */
+       envp [i++] = client_path;
+       envp [i] = (char *)0;
+
+       argv [0] = scriptName;
+       argv [1] = (char *)0;
+
+       pid = fork ();
+       if (pid < 0) {
+               log_error ("fork: %m");
+               wstatus = 0;
+       } else if (pid) {
+               do {
+                       wpid = wait (&wstatus);
+               } while (wpid != pid && wpid > 0);
+               if (wpid < 0) {
+                       log_error ("wait: %m");
+                       wstatus = 0;
+               }
+       } else {
+               execve (scriptName, argv, envp);
+               log_error ("execve (%s, ...): %m", scriptName);
+               exit (0);
+       }
+
+       if (client) {
+               for (sp = client -> env; sp; sp = next) {
+                       next = sp -> next;
+                       dfree (sp, MDL);
+               }
+               client -> env = (struct string_list *)0;
+               client -> envc = 0;
+       }
+       dfree (envp, MDL);
+       GET_TIME (&cur_time);
+       return (WIFEXITED (wstatus) ?
+               WEXITSTATUS (wstatus) : -WTERMSIG (wstatus));
+}
+
+void client_envadd (struct client_state *client,
+                   const char *prefix, const char *name, const char *fmt, ...)
+{
+       char spbuf [1024];
+       char *s;
+       unsigned len, i;
+       struct string_list *val;
+       va_list list;
+
+       va_start (list, fmt);
+       len = vsnprintf (spbuf, sizeof spbuf, fmt, list);
+       va_end (list);
+
+       val = dmalloc (strlen (prefix) + strlen (name) + 1 /* = */ +
+                      len + sizeof *val, MDL);
+       if (!val)
+               return;
+       s = val -> string;
+       strcpy (s, prefix);
+       strcat (s, name);
+       s += strlen (s);
+       *s++ = '=';
+       if (len >= sizeof spbuf) {
+               va_start (list, fmt);
+               vsnprintf (s, len + 1, fmt, list);
+               va_end (list);
+       } else
+               strcpy (s, spbuf);
+       val -> next = client -> env;
+       client -> env = val;
+       client -> envc++;
+}
+
+int dhcp_option_ev_name (buf, buflen, option)
+       char *buf;
+       size_t buflen;
+       struct option *option;
+{
+       int i, j;
+       const char *s;
+
+       j = 0;
+       if (option -> universe != &dhcp_universe) {
+               s = option -> universe -> name;
+               i = 0;
+       } else { 
+               s = option -> name;
+               i = 1;
+       }
+
+       do {
+               while (*s) {
+                       if (j + 1 == buflen)
+                               return 0;
+                       if (*s == '-')
+                               buf [j++] = '_';
+                       else
+                               buf [j++] = *s;
+                       ++s;
+               }
+               if (!i) {
+                       s = option -> name;
+                       if (j + 1 == buflen)
+                               return 0;
+                       buf [j++] = '_';
+               }
+               ++i;
+       } while (i != 2);
+
+       buf [j] = 0;
+       return 1;
+}
+
+void go_daemon ()
+{
+       static int state = 0;
+       int pid;
+       int i;
+
+       /* Don't become a daemon if the user requested otherwise. */
+       if (no_daemon) {
+               write_client_pid_file ();
+               return;
+       }
+
+       /* Only do it once. */
+       if (state)
+               return;
+       state = 1;
+
+       /* Stop logging to stderr... */
+       log_perror = 0;
+
+       /* Become a daemon... */
+       if ((pid = fork ()) < 0)
+               log_fatal ("Can't fork daemon: %m");
+       else if (pid)
+               exit (0);
+       /* Become session leader and get pid... */
+       pid = setsid ();
+
+       /* Close standard I/O descriptors. */
+        close(0);
+        close(1);
+        close(2);
+
+       /* Reopen them on /dev/null. */
+       i = open ("/dev/null", O_RDWR);
+       if (i == 0)
+               i = open ("/dev/null", O_RDWR);
+       if (i == 1) {
+               i = open ("/dev/null", O_RDWR);
+               log_perror = 0; /* No sense logging to /dev/null. */
+       } else if (i != -1)
+               close (i);
+
+       write_client_pid_file ();
+}
+
+void write_client_pid_file ()
+{
+       FILE *pf;
+       int pfdesc;
+
+       pfdesc = open (path_dhclient_pid, O_CREAT | O_TRUNC | O_WRONLY, 0644);
+
+       if (pfdesc < 0) {
+               log_error ("Can't create %s: %m", path_dhclient_pid);
+               return;
+       }
+
+       pf = fdopen (pfdesc, "w");
+       if (!pf)
+               log_error ("Can't fdopen %s: %m", path_dhclient_pid);
+       else {
+               fprintf (pf, "%ld\n", (long)getpid ());
+               fclose (pf);
+       }
+}
+
+void client_location_changed ()
+{
+       struct interface_info *ip;
+       struct client_state *client;
+
+       for (ip = interfaces; ip; ip = ip -> next) {
+               for (client = ip -> client; client; client = client -> next) {
+                       switch (client -> state) {
+                             case S_SELECTING:
+                               cancel_timeout (send_discover, client);
+                               break;
+
+                             case S_BOUND:
+                               cancel_timeout (state_bound, client);
+                               break;
+
+                             case S_REBOOTING:
+                             case S_REQUESTING:
+                             case S_RENEWING:
+                               cancel_timeout (send_request, client);
+                               break;
+
+                             case S_INIT:
+                             case S_REBINDING:
+                             case S_STOPPED:
+                               break;
+                       }
+                       client -> state = S_INIT;
+                       state_reboot (client);
+               }
+       }
+}
+
+void do_release(client) 
+       struct client_state *client;
+{
+       struct data_string ds;
+       struct option_cache *oc;
+
+       /* Pick a random xid. */
+       client -> xid = random ();
+
+       /* is there even a lease to release? */
+       if (client -> active) {
+               /* Make a DHCPRELEASE packet, and set appropriate per-interface
+                  flags. */
+               make_release (client, client -> active);
+
+               memset (&ds, 0, sizeof ds);
+               oc = lookup_option (&dhcp_universe,
+                                   client -> active -> options,
+                                   DHO_DHCP_SERVER_IDENTIFIER);
+               if (oc &&
+                   evaluate_option_cache (&ds, (struct packet *)0,
+                                          (struct lease *)0, client,
+                                          (struct option_state *)0,
+                                          client -> active -> options,
+                                          &global_scope, oc, MDL)) {
+                       if (ds.len > 3) {
+                               memcpy (client -> destination.iabuf,
+                                       ds.data, 4);
+                               client -> destination.len = 4;
+                       } else
+                               client -> destination = iaddr_broadcast;
+
+                       data_string_forget (&ds, MDL);
+               } else
+                       client -> destination = iaddr_broadcast;
+               client -> first_sending = cur_time;
+               client -> interval = client -> config -> initial_interval;
+       
+               /* Zap the medium list... */
+               client -> medium = (struct string_list *)0;
+       
+               /* Send out the first and only DHCPRELEASE packet. */
+               send_release (client);
+
+               /* Do the client script RELEASE operation. */
+               script_init (client,
+                            "RELEASE", (struct string_list *)0);
+               if (client -> alias)
+                       script_write_params (client, "alias_",
+                                            client -> alias);
+               script_write_params (client, "old_", client -> active);
+               script_go (client);
+       }
+
+       /* Cancel any timeouts. */
+       cancel_timeout (state_bound, client);
+       cancel_timeout (send_discover, client);
+       cancel_timeout (state_init, client);
+       cancel_timeout (send_request, client);
+       cancel_timeout (state_reboot, client);
+       client -> state = S_STOPPED;
+}
+
+int dhclient_interface_shutdown_hook (struct interface_info *interface)
+{
+       do_release (interface -> client);
+
+       return 1;
+}
+
+int dhclient_interface_discovery_hook (struct interface_info *tmp)
+{
+       struct interface_info *last, *ip;
+       /* See if we can find the client from dummy_interfaces */
+       last = 0;
+       for (ip = dummy_interfaces; ip; ip = ip -> next) {
+               if (!strcmp (ip -> name, tmp -> name)) {
+                       /* Remove from dummy_interfaces */
+                       if (last) {
+                               ip = (struct interface_info *)0;
+                               interface_reference (&ip, last -> next, MDL);
+                               interface_dereference (&last -> next, MDL);
+                               if (ip -> next) {
+                                       interface_reference (&last -> next,
+                                                            ip -> next, MDL);
+                                       interface_dereference (&ip -> next,
+                                                              MDL);
+                               }
+                       } else {
+                               ip = (struct interface_info *)0;
+                               interface_reference (&ip,
+                                                    dummy_interfaces, MDL);
+                               interface_dereference (&dummy_interfaces, MDL);
+                               if (ip -> next) {
+                                       interface_reference (&dummy_interfaces,
+                                                            ip -> next, MDL);
+                                       interface_dereference (&ip -> next,
+                                                              MDL);
+                               }
+                       }
+                       /* Copy "client" to tmp */
+                       if (ip -> client) {
+                               tmp -> client = ip -> client;
+                               tmp -> client -> interface = tmp;
+                       }
+                       interface_dereference (&ip, MDL);
+                       break;
+               }
+               last = ip;
+       }
+       return 1;
+}
+
+isc_result_t dhclient_interface_startup_hook (struct interface_info *interface)
+{
+       struct interface_info *ip;
+       struct client_state *client;
+
+       /* This code needs some rethinking.   It doesn't test against
+          a signal name, and it just kind of bulls into doing something
+          that may or may not be appropriate. */
+
+       if (interfaces) {
+               interface_reference (&interface -> next, interfaces, MDL);
+               interface_dereference (&interfaces, MDL);
+       }
+       interface_reference (&interfaces, interface, MDL);
+
+       discover_interfaces (DISCOVER_UNCONFIGURED);
+
+       for (ip = interfaces; ip; ip = ip -> next) {
+               /* If interfaces were specified, don't configure
+                  interfaces that weren't specified! */
+               if (ip -> flags & INTERFACE_RUNNING ||
+                  (ip -> flags & (INTERFACE_REQUESTED |
+                                    INTERFACE_AUTOMATIC)) !=
+                    INTERFACE_REQUESTED)
+                       continue;
+               script_init (ip -> client,
+                            "PREINIT", (struct string_list *)0);
+               if (ip -> client -> alias)
+                       script_write_params (ip -> client, "alias_",
+                                            ip -> client -> alias);
+               script_go (ip -> client);
+       }
+       
+       discover_interfaces (interfaces_requested
+                            ? DISCOVER_REQUESTED
+                            : DISCOVER_RUNNING);
+
+       for (ip = interfaces; ip; ip = ip -> next) {
+               if (ip -> flags & INTERFACE_RUNNING)
+                       continue;
+               ip -> flags |= INTERFACE_RUNNING;
+               for (client = ip -> client; client; client = client -> next) {
+                       client -> state = S_INIT;
+                       /* Set up a timeout to start the initialization
+                          process. */
+                       add_timeout (cur_time + random () % 5,
+                                    state_reboot, client, 0, 0);
+               }
+       }
+       return ISC_R_SUCCESS;
+}
+
+/* The client should never receive a relay agent information option,
+   so if it does, log it and discard it. */
+
+int parse_agent_information_option (packet, len, data)
+       struct packet *packet;
+       int len;
+       u_int8_t *data;
+{
+       return 1;
+}
+
+/* The client never sends relay agent information options. */
+
+unsigned cons_agent_information_options (cfg_options, outpacket,
+                                        agentix, length)
+       struct option_state *cfg_options;
+       struct dhcp_packet *outpacket;
+       unsigned agentix;
+       unsigned length;
+{
+       return length;
+}
+
+static void shutdown_exit (void *foo)
+{
+       exit (0);
+}
+
+isc_result_t dhcp_set_control_state (control_object_state_t oldstate,
+                                    control_object_state_t newstate)
+{
+       struct interface_info *ip;
+       struct client_state *client;
+
+       /* Do the right thing for each interface. */
+       for (ip = interfaces; ip; ip = ip -> next) {
+           for (client = ip -> client; client; client = client -> next) {
+               switch (newstate) {
+                 case server_startup:
+                   return ISC_R_SUCCESS;
+
+                 case server_running:
+                   return ISC_R_SUCCESS;
+
+                 case server_shutdown:
+                   if (client -> active &&
+                       client -> active -> expiry > cur_time) {
+                           if (client -> config -> do_forward_update)
+                                   client_dns_update (client, 0, 0);
+                           do_release (client);
+                   }
+                   break;
+
+                 case server_hibernate:
+                   state_stop (client);
+                   break;
+
+                 case server_awaken:
+                   state_reboot (client);
+                   break;
+               }
+           }
+       }
+       if (newstate == server_shutdown)
+               add_timeout (cur_time + 1, shutdown_exit, 0, 0, 0);
+       return ISC_R_SUCCESS;
+}
+
+/* Called after a timeout if the DNS update failed on the previous try.
+   Retries the update, and if it times out, schedules a retry after
+   ten times as long of a wait. */
+
+void client_dns_update_timeout (void *cp)
+{
+       struct client_state *client = cp;
+       isc_result_t status;
+
+       if (client -> active) {
+               status = client_dns_update (client, 1,
+                                           (client -> active -> renewal -
+                                            cur_time));
+               if (status == ISC_R_TIMEDOUT) {
+                       client -> dns_update_timeout *= 10;
+                       add_timeout (cur_time + client -> dns_update_timeout,
+                                    client_dns_update_timeout, client, 0, 0);
+               }
+       }
+}
+                       
+/* See if we should do a DNS update, and if so, do it. */
+
+isc_result_t client_dns_update (struct client_state *client, int addp, int ttl)
+{
+       struct data_string ddns_fqdn, ddns_fwd_name,
+              ddns_dhcid, client_identifier;
+       struct option_cache *oc;
+       int ignorep;
+       int result;
+       isc_result_t rcode;
+
+       /* If we didn't send an FQDN option, we certainly aren't going to
+          be doing an update. */
+       if (!client -> sent_options)
+               return ISC_R_SUCCESS;
+
+       /* If we don't have a lease, we can't do an update. */
+       if (!client -> active)
+               return ISC_R_SUCCESS;
+
+       /* If we set the no client update flag, don't do the update. */
+       if ((oc = lookup_option (&fqdn_universe, client -> sent_options,
+                                 FQDN_NO_CLIENT_UPDATE)) &&
+           evaluate_boolean_option_cache (&ignorep, (struct packet *)0,
+                                          (struct lease *)0, client,
+                                          client -> sent_options,
+                                          (struct option_state *)0,
+                                          &global_scope, oc, MDL))
+               return ISC_R_SUCCESS;
+       
+       /* If we set the "server, please update" flag, or didn't set it
+          to false, don't do the update. */
+       if (!(oc = lookup_option (&fqdn_universe, client -> sent_options,
+                                 FQDN_SERVER_UPDATE)) ||
+           evaluate_boolean_option_cache (&ignorep, (struct packet *)0,
+                                          (struct lease *)0, client,
+                                          client -> sent_options,
+                                          (struct option_state *)0,
+                                          &global_scope, oc, MDL))
+               return ISC_R_SUCCESS;
+       
+       /* If no FQDN option was supplied, don't do the update. */
+       memset (&ddns_fwd_name, 0, sizeof ddns_fwd_name);
+       if (!(oc = lookup_option (&fqdn_universe, client -> sent_options,
+                                 FQDN_FQDN)) ||
+           !evaluate_option_cache (&ddns_fwd_name, (struct packet *)0, 
+                                   (struct lease *)0, client,
+                                   client -> sent_options,
+                                   (struct option_state *)0,
+                                   &global_scope, oc, MDL))
+               return ISC_R_SUCCESS;
+
+       /* Make a dhcid string out of either the client identifier,
+          if we are sending one, or the interface's MAC address,
+          otherwise. */
+       memset (&ddns_dhcid, 0, sizeof ddns_dhcid);
+
+       memset (&client_identifier, 0, sizeof client_identifier);
+       if ((oc = lookup_option (&dhcp_universe, client -> sent_options,
+                                DHO_DHCP_CLIENT_IDENTIFIER)) &&
+           evaluate_option_cache (&client_identifier, (struct packet *)0, 
+                                  (struct lease *)0, client,
+                                  client -> sent_options,
+                                  (struct option_state *)0,
+                                  &global_scope, oc, MDL)) {
+               result = get_dhcid (&ddns_dhcid,
+                                   DHO_DHCP_CLIENT_IDENTIFIER,
+                                   client_identifier.data,
+                                   client_identifier.len);
+               data_string_forget (&client_identifier, MDL);
+       } else
+               result = get_dhcid (&ddns_dhcid, 0,
+                                   client -> interface -> hw_address.hbuf,
+                                   client -> interface -> hw_address.hlen);
+       if (!result) {
+               data_string_forget (&ddns_fwd_name, MDL);
+               return ISC_R_SUCCESS;
+       }
+
+       /* Start the resolver, if necessary. */
+       if (!resolver_inited) {
+               minires_ninit (&resolver_state);
+               resolver_inited = 1;
+               resolver_state.retrans = 1;
+               resolver_state.retry = 1;
+       }
+
+       /*
+        * Perform updates.
+        */
+       if (ddns_fwd_name.len && ddns_dhcid.len) {
+               if (addp)
+                       rcode = ddns_update_a (&ddns_fwd_name,
+                                              client -> active -> address,
+                                              &ddns_dhcid, ttl,
+                                              1);
+               else
+                       rcode = ddns_remove_a (&ddns_fwd_name,
+                                              client -> active -> address,
+                                              &ddns_dhcid);
+       } else
+               rcode = ISC_R_FAILURE;
+       
+       data_string_forget (&ddns_fwd_name, MDL);
+       data_string_forget (&ddns_dhcid, MDL);
+       return rcode;
+}
diff --git a/contrib/dhcp-3.0/client/dhclient.conf b/contrib/dhcp-3.0/client/dhclient.conf
new file mode 100644 (file)
index 0000000..147e004
--- /dev/null
@@ -0,0 +1,36 @@
+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, 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/contrib/dhcp-3.0/client/dhclient.conf.5 b/contrib/dhcp-3.0/client/dhclient.conf.5
new file mode 100644 (file)
index 0000000..cc63f85
--- /dev/null
@@ -0,0 +1,623 @@
+.\"    $Id: dhclient.conf.5,v 1.12.2.11 2004/09/10 21:02:30 dhankins Exp $
+.\"
+.\" Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+.\" Copyright (c) 1996-2003 by Internet Software Consortium
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+.\" OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.\"   Internet Systems Consortium, Inc.
+.\"   950 Charter Street
+.\"   Redwood City, CA 94063
+.\"   <info@isc.org>
+.\"   http://www.isc.org/
+.\"
+.\" This software has been written for Internet Software Consortium
+.\" by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
+.\" To learn more about Internet Software Consortium, see
+.\" ``http://www.isc.org/''.  To learn more about Vixie Enterprises,
+.\" see ``http://www.vix.com''.   To learn more about Nominum, Inc., see
+.\" ``http://www.nominum.com''.
+.TH dhclient.conf 5
+.SH NAME
+dhclient.conf - DHCP client configuration file
+.SH DESCRIPTION
+The dhclient.conf file contains configuration information for
+.IR dhclient,
+the Internet Systems Consortium DHCP Client.
+.PP
+The dhclient.conf file is a free-form ASCII text file.   It is parsed by
+the recursive-descent parser built into dhclient.   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 # character and
+end at the end of the line.
+.PP
+The dhclient.conf 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 don't 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:
+.PP
+.I The
+.B timeout
+.I statement
+.PP
+.B timeout
+.I time
+.B ;
+.PP
+The
+.I 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's 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.
+.PP
+.I The
+.B retry
+.I statement
+.PP
+ \fBretry \fItime\fR\fB;\fR
+.PP
+The
+.I 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.
+.PP
+.I The
+.B select-timeout
+.I statement
+.PP
+ \fBselect-timeout \fItime\fR\fB;\fR
+.PP
+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
+.I 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
+.I select-timeout
+has expired, the client will accept the first offer that arrives.
+.PP
+By default, the select-timeout is zero seconds - that is, the client
+will take the first offer it sees.
+.PP
+.I The
+.B reboot
+.I statement
+.PP
+ \fBreboot \fItime\fR\fB;\fR
+.PP
+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
+.I 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.
+.PP
+.I The
+.B backoff-cutoff
+.I statement
+.PP
+ \fBbackoff-cutoff \fItime\fR\fB;\fR
+.PP
+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
+.I backoff-cutoff
+statement determines the maximum amount of time that the client is
+allowed to back off, the actual value will be evaluated randomly between
+1/2 to 1 1/2 times the \fItime\fR specified.   It defaults to two minutes.
+.PP
+.I The
+.B initial-interval
+.I statement
+.PP
+ \fBinitial-interval \fItime\fR\fB;\fR
+.PP
+The
+.I 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 backoff-cutoff amount, it is set to that
+amount.  It defaults to ten seconds.
+.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 don't 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 \fIDHCP Options\fR.  DHCP Options are defined in
+ \fBdhcp-options(5)\fR.
+.PP
+.I The
+.B request
+.I statement
+.PP
+ \fBrequest [ \fIoption\fR ] [\fB,\fI ... \fIoption\fR ]\fB;\fR
+.PP
+The 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.   By default, the DHCP server
+requests the subnet-mask, broadcast-address, time-offset, routers,
+domain-name, domain-name-servers and host-name options. 
+.PP
+In some cases, it may be desirable to send no parameter request list
+at all.   To do this, simply write the request statement but specify
+no parameters:
+.PP
+.nf
+       request;
+.fi
+.PP
+.I The
+.B require
+.I statement
+.PP
+ \fBrequire [ \fIoption\fR ] [\fB,\fI ... \fIoption ]\fB;\fR
+.PP
+The 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.
+.PP
+.I The
+.B send
+.I statement
+.PP
+ \fBsend { [ \fIoption declaration\fR ]
+[\fB,\fI ... \fIoption declaration\fR ]\fB}\fR
+.PP
+The 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 \fBdhcp-options(5)\fR.  Options that are
+always sent in the DHCP protocol should not be specified here, except
+that the client can specify a \fBrequested-lease-time\fR 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.
+.SH DYNAMIC DNS
+The client now has some very limited support for doing DNS updates
+when a lease is acquired.   This is prototypical, and probably doesn't
+do what you want.   It also only works if you happen to have control
+over your DNS server, which isn't very likely.
+.PP
+To make it work, you have to declare a key and zone as in the DHCP
+server (see \fBdhcpd.conf\fR(5) for details).   You also need to
+configure the fqdn option on the client, as follows:
+.PP
+.nf
+  send fqdn.fqdn "grosse.fugue.com.";
+  send fqdn.encoded on;
+  send fqdn.server-update off;
+.fi
+.PP
+The \fIfqdn.fqdn\fR option \fBMUST\fR be a fully-qualified domain
+name.   You \fBMUST\fR define a zone statement for the zone to be
+updated.   The \fIfqdn.encoded\fR option may need to be set to
+\fIon\fR or \fIoff\fR, depending on the DHCP server you are using.
+.PP
+.I The
+.B do-forward-updates
+.I statement
+.PP
+ \fBdo-forward-updates [ \fIflag\fR ] \fB;\fR
+.PP
+If you want to do DNS updates in the DHCP client
+script (see \fBdhclient-script(8)\fR) rather than having the
+DHCP client do the update directly (for example, if you want to
+use SIG(0) authentication, which is not supported directly by the
+DHCP client, you can instruct the client not to do the update using
+the \fBdo-forward-updates\fR statement.   \fIFlag\fR should be \fBtrue\fR
+if you want the DHCP client to do the update, and \fBfalse\fR if
+you don't want the DHCP client to do the update.   By default, the DHCP
+client will do the DNS update.
+.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.
+.PP
+.I The
+.B default
+.I statement
+.PP
+ \fBdefault [ \fIoption declaration\fR ] \fB;\fR
+.PP
+If for some option 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
+.B default
+statement.
+.PP
+.I The
+.B supersede
+.I statement
+.PP
+ \fBsupersede [ \fIoption declaration\fR ] \fB;\fR
+.PP
+If for some option the client should always use a locally-configured
+value or values rather than whatever is supplied by the server, these
+values can be defined in the 
+.B supersede
+statement.
+.PP
+.I The
+.B prepend
+.I statement
+.PP
+ \fBprepend [ \fIoption declaration\fR ] \fB;\fR
+.PP
+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
+.B prepend
+statement.   The
+.B prepend
+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.
+.PP
+.I The
+.B append
+.I statement
+.PP
+ \fBappend [ \fIoption declaration\fR ] \fB;\fR
+.PP
+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
+.B append
+statement.   The
+.B 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.
+.SH LEASE DECLARATIONS
+.PP
+.I The
+.B lease
+.I declaration
+.PP
+ \fBlease {\fR \fIlease-declaration\fR [ ... \fIlease-declaration ] \fB}\fR
+.PP
+The DHCP client may decide after some period of time (see \fBPROTOCOL
+TIMING\fR) 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 \fIfixed\fR 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
+.B lease
+statement.
+.PP
+NOTE: the lease statement is also used in the 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
+dhclient.leases file.   Such syntax is documented here for
+completeness.
+.PP
+A lease statement consists of the 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:
+.PP
+ \fBbootp;\fR
+.PP
+The
+.B 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.
+.PP
+ \fBinterface\fR \fB"\fR\fIstring\fR\fB";\fR
+.PP
+The
+.B 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 dhclient.conf file, the
+interface should also be specified, although this is not required.
+.PP
+ \fBfixed-address\fR \fIip-address\fR\fB;\fR
+.PP
+The
+.B 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., 12.34.56.78).
+.PP
+ \fBfilename "\fR\fIstring\fR\fB";\fR
+.PP
+The
+.B filename
+statement specifies the name of the boot filename to use.   This is
+not used&n