summaryrefslogtreecommitdiff
path: root/contrib/isc-dhcp/common
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/isc-dhcp/common')
-rw-r--r--contrib/isc-dhcp/common/alloc.c330
-rw-r--r--contrib/isc-dhcp/common/bpf.c425
-rw-r--r--contrib/isc-dhcp/common/conflex.c560
-rw-r--r--contrib/isc-dhcp/common/dhcp-options.5581
-rw-r--r--contrib/isc-dhcp/common/dispatch.c847
-rw-r--r--contrib/isc-dhcp/common/lpf.c287
-rw-r--r--contrib/isc-dhcp/common/memory.c941
-rw-r--r--contrib/isc-dhcp/common/nit.c367
-rw-r--r--contrib/isc-dhcp/common/parse.c649
-rw-r--r--contrib/isc-dhcp/common/print.c184
-rw-r--r--contrib/isc-dhcp/common/socket.c280
-rw-r--r--contrib/isc-dhcp/common/tables.c692
-rw-r--r--contrib/isc-dhcp/common/upf.c318
13 files changed, 6461 insertions, 0 deletions
diff --git a/contrib/isc-dhcp/common/alloc.c b/contrib/isc-dhcp/common/alloc.c
new file mode 100644
index 000000000000..a9584622a6ba
--- /dev/null
+++ b/contrib/isc-dhcp/common/alloc.c
@@ -0,0 +1,330 @@
+/* alloc.c
+
+ Memory allocation... */
+
+/*
+ * Copyright (c) 1995, 1996, 1998 The Internet Software Consortium.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of The Internet Software Consortium nor the names
+ * of its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
+ * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This software has been written for the Internet Software Consortium
+ * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
+ * Enterprises. To learn more about the Internet Software Consortium,
+ * see ``http://www.vix.com/isc''. To learn more about Vixie
+ * Enterprises, see ``http://www.vix.com''.
+ */
+
+#ifndef lint
+static char copyright[] =
+"$Id: alloc.c,v 1.13.2.1 1998/11/24 22:17:15 mellon Exp $ Copyright (c) 1995, 1996 The Internet Software Consortium. All rights reserved.\n";
+#endif /* not lint */
+
+#include "dhcpd.h"
+
+struct dhcp_packet *dhcp_free_list;
+struct packet *packet_free_list;
+
+VOIDPTR dmalloc (size, name)
+ int size;
+ char *name;
+{
+ VOIDPTR foo = (VOIDPTR)malloc (size);
+ if (!foo)
+ warn ("No memory for %s.", name);
+ else
+ memset (foo, 0, size);
+ return foo;
+}
+
+void dfree (ptr, name)
+ VOIDPTR ptr;
+ char *name;
+{
+ if (!ptr) {
+ warn ("dfree %s: free on null pointer.", name);
+ return;
+ }
+ free (ptr);
+}
+
+struct packet *new_packet (name)
+ char *name;
+{
+ struct packet *rval;
+ rval = (struct packet *)dmalloc (sizeof (struct packet), name);
+ return rval;
+}
+
+struct dhcp_packet *new_dhcp_packet (name)
+ char *name;
+{
+ struct dhcp_packet *rval;
+ rval = (struct dhcp_packet *)dmalloc (sizeof (struct dhcp_packet),
+ name);
+ return rval;
+}
+
+struct tree *new_tree (name)
+ char *name;
+{
+ struct tree *rval = dmalloc (sizeof (struct tree), name);
+ return rval;
+}
+
+struct tree_cache *free_tree_caches;
+
+struct tree_cache *new_tree_cache (name)
+ char *name;
+{
+ struct tree_cache *rval;
+
+ if (free_tree_caches) {
+ rval = free_tree_caches;
+ free_tree_caches =
+ (struct tree_cache *)(rval -> value);
+ } else {
+ rval = dmalloc (sizeof (struct tree_cache), name);
+ if (!rval)
+ error ("unable to allocate tree cache for %s.", name);
+ }
+ return rval;
+}
+
+struct hash_table *new_hash_table (count, name)
+ int count;
+ char *name;
+{
+ struct hash_table *rval = dmalloc (sizeof (struct hash_table)
+ - (DEFAULT_HASH_SIZE
+ * sizeof (struct hash_bucket *))
+ + (count
+ * sizeof (struct hash_bucket *)),
+ name);
+ rval -> hash_count = count;
+ return rval;
+}
+
+struct hash_bucket *new_hash_bucket (name)
+ char *name;
+{
+ struct hash_bucket *rval = dmalloc (sizeof (struct hash_bucket), name);
+ return rval;
+}
+
+struct lease *new_leases (n, name)
+ int n;
+ char *name;
+{
+ struct lease *rval = dmalloc (n * sizeof (struct lease), name);
+ return rval;
+}
+
+struct lease *new_lease (name)
+ char *name;
+{
+ struct lease *rval = dmalloc (sizeof (struct lease), name);
+ return rval;
+}
+
+struct subnet *new_subnet (name)
+ char *name;
+{
+ struct subnet *rval = dmalloc (sizeof (struct subnet), name);
+ return rval;
+}
+
+struct class *new_class (name)
+ char *name;
+{
+ struct class *rval = dmalloc (sizeof (struct class), name);
+ return rval;
+}
+
+struct shared_network *new_shared_network (name)
+ char *name;
+{
+ struct shared_network *rval =
+ dmalloc (sizeof (struct shared_network), name);
+ return rval;
+}
+
+struct group *new_group (name)
+ char *name;
+{
+ struct group *rval =
+ dmalloc (sizeof (struct group), name);
+ return rval;
+}
+
+struct protocol *new_protocol (name)
+ char *name;
+{
+ struct protocol *rval = dmalloc (sizeof (struct protocol), name);
+ return rval;
+}
+
+struct lease_state *free_lease_states;
+
+struct lease_state *new_lease_state (name)
+ char *name;
+{
+ struct lease_state *rval;
+
+ if (free_lease_states) {
+ rval = free_lease_states;
+ free_lease_states =
+ (struct lease_state *)(free_lease_states -> next);
+ } else {
+ rval = dmalloc (sizeof (struct lease_state), name);
+ }
+ return rval;
+}
+
+struct domain_search_list *new_domain_search_list (name)
+ char *name;
+{
+ struct domain_search_list *rval =
+ dmalloc (sizeof (struct domain_search_list), name);
+ return rval;
+}
+
+struct name_server *new_name_server (name)
+ char *name;
+{
+ struct name_server *rval =
+ dmalloc (sizeof (struct name_server), name);
+ return rval;
+}
+
+void free_name_server (ptr, name)
+ struct name_server *ptr;
+ char *name;
+{
+ dfree ((VOIDPTR)ptr, name);
+}
+
+void free_domain_search_list (ptr, name)
+ struct domain_search_list *ptr;
+ char *name;
+{
+ dfree ((VOIDPTR)ptr, name);
+}
+
+void free_lease_state (ptr, name)
+ struct lease_state *ptr;
+ char *name;
+{
+ ptr -> next = free_lease_states;
+ free_lease_states = ptr;
+}
+
+void free_protocol (ptr, name)
+ struct protocol *ptr;
+ char *name;
+{
+ dfree ((VOIDPTR)ptr, name);
+}
+
+void free_group (ptr, name)
+ struct group *ptr;
+ char *name;
+{
+ dfree ((VOIDPTR)ptr, name);
+}
+
+void free_shared_network (ptr, name)
+ struct shared_network *ptr;
+ char *name;
+{
+ dfree ((VOIDPTR)ptr, name);
+}
+
+void free_class (ptr, name)
+ struct class *ptr;
+ char *name;
+{
+ dfree ((VOIDPTR)ptr, name);
+}
+
+void free_subnet (ptr, name)
+ struct subnet *ptr;
+ char *name;
+{
+ dfree ((VOIDPTR)ptr, name);
+}
+
+void free_lease (ptr, name)
+ struct lease *ptr;
+ char *name;
+{
+ dfree ((VOIDPTR)ptr, name);
+}
+
+void free_hash_bucket (ptr, name)
+ struct hash_bucket *ptr;
+ char *name;
+{
+ dfree ((VOIDPTR)ptr, name);
+}
+
+void free_hash_table (ptr, name)
+ struct hash_table *ptr;
+ char *name;
+{
+ dfree ((VOIDPTR)ptr, name);
+}
+
+void free_tree_cache (ptr, name)
+ struct tree_cache *ptr;
+ char *name;
+{
+ ptr -> value = (unsigned char *)free_tree_caches;
+ free_tree_caches = ptr;
+}
+
+void free_packet (ptr, name)
+ struct packet *ptr;
+ char *name;
+{
+ dfree ((VOIDPTR)ptr, name);
+}
+
+void free_dhcp_packet (ptr, name)
+ struct dhcp_packet *ptr;
+ char *name;
+{
+ dfree ((VOIDPTR)ptr, name);
+}
+
+void free_tree (ptr, name)
+ struct tree *ptr;
+ char *name;
+{
+ dfree ((VOIDPTR)ptr, name);
+}
diff --git a/contrib/isc-dhcp/common/bpf.c b/contrib/isc-dhcp/common/bpf.c
new file mode 100644
index 000000000000..ba42a43903cd
--- /dev/null
+++ b/contrib/isc-dhcp/common/bpf.c
@@ -0,0 +1,425 @@
+/* bpf.c
+
+ BPF socket interface code, originally contributed by Archie Cobbs. */
+
+/*
+ * Copyright (c) 1995, 1996, 1998, 1999
+ * The Internet Software Consortium. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of The Internet Software Consortium nor the names
+ * of its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
+ * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This software has been written for the Internet Software Consortium
+ * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
+ * Enterprises. To learn more about the Internet Software Consortium,
+ * see ``http://www.vix.com/isc''. To learn more about Vixie
+ * Enterprises, see ``http://www.vix.com''.
+ */
+
+#ifndef lint
+static char copyright[] =
+"$Id: bpf.c,v 1.19.2.6 1999/02/09 04:46:59 mellon Exp $ Copyright (c) 1995, 1996, 1998, 1999 The Internet Software Consortium. All rights reserved.\n";
+#endif /* not lint */
+
+#include "dhcpd.h"
+#if defined (USE_BPF_SEND) || defined (USE_BPF_RECEIVE) \
+ || defined (USE_LPF_RECEIVE)
+# if defined (USE_LPF_RECEIVE)
+# include <asm/types.h>
+# include <linux/filter.h>
+# define bpf_insn sock_filter /* Linux: dare to be gratuitously different. */
+# else
+# include <sys/ioctl.h>
+# include <sys/uio.h>
+
+# include <net/bpf.h>
+# if defined (NEED_OSF_PFILT_HACKS)
+# include <net/pfilt.h>
+# endif
+# endif
+
+#include <netinet/in_systm.h>
+#include "includes/netinet/ip.h"
+#include "includes/netinet/udp.h"
+#include "includes/netinet/if_ether.h"
+#endif
+
+/* Reinitializes the specified interface after an address change. This
+ is not required for packet-filter APIs. */
+
+#ifdef USE_BPF_SEND
+void if_reinitialize_send (info)
+ struct interface_info *info;
+{
+}
+#endif
+
+#ifdef USE_BPF_RECEIVE
+void if_reinitialize_receive (info)
+ struct interface_info *info;
+{
+}
+#endif
+
+/* Called by get_interface_list for each interface that's discovered.
+ Opens a packet filter for each interface and adds it to the select
+ mask. */
+
+#if defined (USE_BPF_SEND) || defined (USE_BPF_RECEIVE)
+int if_register_bpf (info)
+ struct interface_info *info;
+{
+ int sock;
+ char filename[50];
+ int b;
+
+ /* Open a BPF device */
+ for (b = 0; 1; b++) {
+#ifndef NO_SNPRINTF
+ snprintf(filename, sizeof(filename), BPF_FORMAT, b);
+#else
+ sprintf(filename, BPF_FORMAT, b);
+#endif
+ sock = open (filename, O_RDWR, 0);
+ if (sock < 0) {
+ if (errno == EBUSY) {
+ continue;
+ } else {
+ if (!b)
+ error ("No bpf devices.%s%s%s",
+ " Please read the README",
+ " section for your operating",
+ " system.");
+ error ("Can't find free bpf: %m");
+ }
+ } else {
+ break;
+ }
+ }
+
+ /* Set the BPF device to point at this interface. */
+ if (ioctl (sock, BIOCSETIF, info -> ifp) < 0)
+ error ("Can't attach interface %s to bpf device %s: %m",
+ info -> name, filename);
+
+ return sock;
+}
+#endif /* USE_BPF_SEND || USE_BPF_RECEIVE */
+
+#ifdef USE_BPF_SEND
+void if_register_send (info)
+ struct interface_info *info;
+{
+ /* If we're using the bpf API for sending and receiving,
+ we don't need to register this interface twice. */
+#ifndef USE_BPF_RECEIVE
+ info -> wfdesc = if_register_bpf (info, interface);
+#else
+ info -> wfdesc = info -> rfdesc;
+#endif
+ if (!quiet_interface_discovery)
+ note ("Sending on BPF/%s/%s/%s",
+ info -> name,
+ print_hw_addr (info -> hw_address.htype,
+ info -> hw_address.hlen,
+ info -> hw_address.haddr),
+ (info -> shared_network ?
+ info -> shared_network -> name : "unattached"));
+}
+#endif /* USE_BPF_SEND */
+
+#if defined (USE_BPF_RECEIVE) || defined (USE_LPF_RECEIVE)
+/* Packet filter program...
+ XXX Changes to the filter program may require changes to the constant
+ offsets used in if_register_send to patch the BPF program! XXX */
+
+struct bpf_insn dhcp_bpf_filter [] = {
+ /* Make sure this is an IP packet... */
+ BPF_STMT (BPF_LD + BPF_H + BPF_ABS, 12),
+ BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 0, 8),
+
+ /* Make sure it's a UDP packet... */
+ BPF_STMT (BPF_LD + BPF_B + BPF_ABS, 23),
+ BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 6),
+
+ /* Make sure this isn't a fragment... */
+ BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 20),
+ BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 4, 0),
+
+ /* Get the IP header length... */
+ BPF_STMT (BPF_LDX + BPF_B + BPF_MSH, 14),
+
+ /* Make sure it's to the right port... */
+ BPF_STMT (BPF_LD + BPF_H + BPF_IND, 16),
+ BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, 67, 0, 1), /* patch */
+
+ /* If we passed all the tests, ask for the whole packet. */
+ BPF_STMT(BPF_RET+BPF_K, (u_int)-1),
+
+ /* Otherwise, drop it. */
+ BPF_STMT(BPF_RET+BPF_K, 0),
+};
+
+int dhcp_bpf_filter_len = sizeof dhcp_bpf_filter / sizeof (struct bpf_insn);
+#endif
+
+#if defined (USE_BPF_RECEIVE)
+void if_register_receive (info)
+ struct interface_info *info;
+{
+ int flag = 1;
+ struct bpf_version v;
+ u_int32_t addr;
+ struct bpf_program p;
+ u_int32_t bits;
+
+ /* Open a BPF device and hang it on this interface... */
+ info -> rfdesc = if_register_bpf (info);
+
+ /* Make sure the BPF version is in range... */
+ if (ioctl (info -> rfdesc, BIOCVERSION, &v) < 0)
+ error ("Can't get BPF version: %m");
+
+ if (v.bv_major != BPF_MAJOR_VERSION ||
+ v.bv_minor < BPF_MINOR_VERSION)
+ error ("Kernel BPF version out of range - recompile dhcpd!");
+
+ /* Set immediate mode so that reads return as soon as a packet
+ comes in, rather than waiting for the input buffer to fill with
+ packets. */
+ if (ioctl (info -> rfdesc, BIOCIMMEDIATE, &flag) < 0)
+ error ("Can't set immediate mode on bpf device: %m");
+
+#ifdef NEED_OSF_PFILT_HACKS
+ /* Allow the copyall flag to be set... */
+ if (ioctl(info -> rfdesc, EIOCALLOWCOPYALL, &flag) < 0)
+ error ("Can't set ALLOWCOPYALL: %m");
+
+ /* Clear all the packet filter mode bits first... */
+ bits = 0;
+ if (ioctl (info -> rfdesc, EIOCMBIS, &bits) < 0)
+ error ("Can't clear pfilt bits: %m");
+
+ /* Set the ENBATCH, ENCOPYALL, ENBPFHDR bits... */
+ bits = ENBATCH | ENCOPYALL | ENBPFHDR;
+ if (ioctl (info -> rfdesc, EIOCMBIS, &bits) < 0)
+ error ("Can't set ENBATCH|ENCOPYALL|ENBPFHDR: %m");
+#endif
+ /* Get the required BPF buffer length from the kernel. */
+ if (ioctl (info -> rfdesc, BIOCGBLEN, &info -> rbuf_max) < 0)
+ error ("Can't get bpf buffer length: %m");
+ info -> rbuf = malloc (info -> rbuf_max);
+ if (!info -> rbuf)
+ error ("Can't allocate %d bytes for bpf input buffer.");
+ info -> rbuf_offset = 0;
+ info -> rbuf_len = 0;
+
+ /* Set up the bpf filter program structure. */
+ p.bf_len = dhcp_bpf_filter_len;
+ p.bf_insns = dhcp_bpf_filter;
+
+ /* Patch the server port into the BPF program...
+ XXX changes to filter program may require changes
+ to the insn number(s) used below! XXX */
+ dhcp_bpf_filter [8].k = ntohs (local_port);
+
+ if (ioctl (info -> rfdesc, BIOCSETF, &p) < 0)
+ error ("Can't install packet filter program: %m");
+ if (!quiet_interface_discovery)
+ note ("Listening on BPF/%s/%s/%s",
+ info -> name,
+ print_hw_addr (info -> hw_address.htype,
+ info -> hw_address.hlen,
+ info -> hw_address.haddr),
+ (info -> shared_network ?
+ info -> shared_network -> name : "unattached"));
+}
+#endif /* USE_BPF_RECEIVE */
+
+#ifdef USE_BPF_SEND
+ssize_t send_packet (interface, packet, raw, len, from, to, hto)
+ struct interface_info *interface;
+ struct packet *packet;
+ struct dhcp_packet *raw;
+ size_t len;
+ struct in_addr from;
+ struct sockaddr_in *to;
+ struct hardware *hto;
+{
+ int bufp = 0;
+ unsigned char buf [256];
+ struct iovec iov [2];
+
+ if (!strcmp (interface -> name, "fallback"))
+ return send_fallback (interface, packet, raw,
+ len, from, to, hto);
+
+ /* Assemble the headers... */
+ assemble_hw_header (interface, buf, &bufp, hto);
+ assemble_udp_ip_header (interface, buf, &bufp, from.s_addr,
+ to -> sin_addr.s_addr, to -> sin_port,
+ (unsigned char *)raw, len);
+
+ /* Fire it off */
+ iov [0].iov_base = (char *)buf;
+ iov [0].iov_len = bufp;
+ iov [1].iov_base = (char *)raw;
+ iov [1].iov_len = len;
+
+ return writev(interface -> wfdesc, iov, 2);
+}
+#endif /* USE_BPF_SEND */
+
+#ifdef USE_BPF_RECEIVE
+ssize_t receive_packet (interface, buf, len, from, hfrom)
+ struct interface_info *interface;
+ unsigned char *buf;
+ size_t len;
+ struct sockaddr_in *from;
+ struct hardware *hfrom;
+{
+ int length = 0;
+ int offset = 0;
+ struct bpf_hdr hdr;
+
+ /* All this complexity is because BPF doesn't guarantee
+ that only one packet will be returned at a time. We're
+ getting what we deserve, though - this is a terrible abuse
+ of the BPF interface. Sigh. */
+
+ /* Process packets until we get one we can return or until we've
+ done a read and gotten nothing we can return... */
+
+ do {
+ /* If the buffer is empty, fill it. */
+ if (interface -> rbuf_offset == interface -> rbuf_len) {
+ length = read (interface -> rfdesc,
+ interface -> rbuf,
+ interface -> rbuf_max);
+ if (length <= 0)
+ return length;
+ interface -> rbuf_offset = 0;
+ interface -> rbuf_len = length;
+ }
+
+ /* If there isn't room for a whole bpf header, something went
+ wrong, but we'll ignore it and hope it goes away... XXX */
+ if (interface -> rbuf_len -
+ interface -> rbuf_offset < sizeof hdr) {
+ interface -> rbuf_offset = interface -> rbuf_len;
+ continue;
+ }
+
+ /* Copy out a bpf header... */
+ memcpy (&hdr, &interface -> rbuf [interface -> rbuf_offset],
+ sizeof hdr);
+
+ /* If the bpf header plus data doesn't fit in what's left
+ of the buffer, stick head in sand yet again... */
+ if (interface -> rbuf_offset +
+ hdr.bh_hdrlen + hdr.bh_caplen > interface -> rbuf_len) {
+ interface -> rbuf_offset = interface -> rbuf_len;
+ continue;
+ }
+
+ /* If the captured data wasn't the whole packet, or if
+ the packet won't fit in the input buffer, all we
+ can do is drop it. */
+ if (hdr.bh_caplen != hdr.bh_datalen) {
+ interface -> rbuf_offset +=
+ hdr.bh_hdrlen = hdr.bh_caplen;
+ continue;
+ }
+
+ /* Skip over the BPF header... */
+ interface -> rbuf_offset += hdr.bh_hdrlen;
+
+ /* Decode the physical header... */
+ offset = decode_hw_header (interface,
+ interface -> rbuf,
+ interface -> rbuf_offset,
+ hfrom);
+
+ /* If a physical layer checksum failed (dunno of any
+ physical layer that supports this, but WTH), skip this
+ packet. */
+ if (offset < 0) {
+ interface -> rbuf_offset += hdr.bh_caplen;
+ continue;
+ }
+ interface -> rbuf_offset += offset;
+ hdr.bh_caplen -= offset;
+
+ /* Decode the IP and UDP headers... */
+ offset = decode_udp_ip_header (interface,
+ interface -> rbuf,
+ interface -> rbuf_offset,
+ from,
+ (unsigned char *)0,
+ hdr.bh_caplen);
+
+ /* If the IP or UDP checksum was bad, skip the packet... */
+ if (offset < 0) {
+ interface -> rbuf_offset += hdr.bh_caplen;
+ continue;
+ }
+ interface -> rbuf_offset += offset;
+ hdr.bh_caplen -= offset;
+
+ /* If there's not enough room to stash the packet data,
+ we have to skip it (this shouldn't happen in real
+ life, though). */
+ if (hdr.bh_caplen > len) {
+ interface -> rbuf_offset += hdr.bh_caplen;
+ continue;
+ }
+
+ /* Copy out the data in the packet... */
+ memcpy (buf, interface -> rbuf + interface -> rbuf_offset,
+ hdr.bh_caplen);
+ interface -> rbuf_offset += hdr.bh_caplen;
+ return hdr.bh_caplen;
+ } while (!length);
+ return 0;
+}
+
+int can_unicast_without_arp ()
+{
+ return 1;
+}
+
+void maybe_setup_fallback ()
+{
+ struct interface_info *fbi;
+ fbi = setup_fallback ();
+ if (fbi) {
+ if_register_fallback (fbi);
+ add_protocol ("fallback", fallback_interface -> wfdesc,
+ fallback_discard, fallback_interface);
+ }
+}
+#endif
diff --git a/contrib/isc-dhcp/common/conflex.c b/contrib/isc-dhcp/common/conflex.c
new file mode 100644
index 000000000000..c84daad6bcb8
--- /dev/null
+++ b/contrib/isc-dhcp/common/conflex.c
@@ -0,0 +1,560 @@
+/* conflex.c
+
+ Lexical scanner for dhcpd config file... */
+
+/*
+ * Copyright (c) 1995, 1996, 1997 The Internet Software Consortium.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of The Internet Software Consortium nor the names
+ * of its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
+ * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This software has been written for the Internet Software Consortium
+ * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
+ * Enterprises. To learn more about the Internet Software Consortium,
+ * see ``http://www.vix.com/isc''. To learn more about Vixie
+ * Enterprises, see ``http://www.vix.com''.
+ */
+
+#ifndef lint
+static char copyright[] =
+"$Id: conflex.c,v 1.29.2.3 1999/02/09 04:49:04 mellon Exp $ Copyright (c) 1995, 1996, 1997 The Internet Software Consortium. All rights reserved.\n";
+#endif /* not lint */
+
+#include "dhcpd.h"
+#include "dhctoken.h"
+#include <ctype.h>
+
+int lexline;
+int lexchar;
+char *token_line;
+char *prev_line;
+char *cur_line;
+char *tlname;
+int eol_token;
+
+static char line1 [81];
+static char line2 [81];
+static int lpos;
+static int line;
+static int tlpos;
+static int tline;
+static int token;
+static int ugflag;
+static char *tval;
+static char tokbuf [1500];
+
+#ifdef OLD_LEXER
+char comments [4096];
+int comment_index;
+#endif
+
+
+static int get_char PROTO ((FILE *));
+static int get_token PROTO ((FILE *));
+static void skip_to_eol PROTO ((FILE *));
+static int read_string PROTO ((FILE *));
+static int read_number PROTO ((int, FILE *));
+static int read_num_or_name PROTO ((int, FILE *));
+static int intern PROTO ((char *, int));
+
+void new_parse (name)
+ char *name;
+{
+ tlname = name;
+ lpos = line = 1;
+ cur_line = line1;
+ prev_line = line2;
+ token_line = cur_line;
+ cur_line [0] = prev_line [0] = 0;
+ warnings_occurred = 0;
+}
+
+static int get_char (cfile)
+ FILE *cfile;
+{
+ int c = getc (cfile);
+ if (!ugflag) {
+ if (c == EOL) {
+ if (cur_line == line1) {
+ cur_line = line2;
+ prev_line = line1;
+ } else {
+ cur_line = line2;
+ prev_line = line1;
+ }
+ line++;
+ lpos = 1;
+ cur_line [0] = 0;
+ } else if (c != EOF) {
+ if (lpos <= 81) {
+ cur_line [lpos - 1] = c;
+ cur_line [lpos] = 0;
+ }
+ lpos++;
+ }
+ } else
+ ugflag = 0;
+ return c;
+}
+
+static int get_token (cfile)
+ FILE *cfile;
+{
+ int c;
+ int ttok;
+ static char tb [2];
+ int l, p, u;
+
+ do {
+ l = line;
+ p = lpos;
+ u = ugflag;
+
+ c = get_char (cfile);
+#ifdef OLD_LEXER
+ if (c == '\n' && p == 1 && !u
+ && comment_index < sizeof comments)
+ comments [comment_index++] = '\n';
+#endif
+
+ if (!(c == '\n' && eol_token) && isascii (c) && isspace (c))
+ continue;
+ if (c == '#') {
+#ifdef OLD_LEXER
+ if (comment_index < sizeof comments)
+ comments [comment_index++] = '#';
+#endif
+ skip_to_eol (cfile);
+ continue;
+ }
+ if (c == '"') {
+ lexline = l;
+ lexchar = p;
+ ttok = read_string (cfile);
+ break;
+ }
+ if ((isascii (c) && isdigit (c)) || c == '-') {
+ lexline = l;
+ lexchar = p;
+ ttok = read_number (c, cfile);
+ break;
+ } else if (isascii (c) && isalpha (c)) {
+ lexline = l;
+ lexchar = p;
+ ttok = read_num_or_name (c, cfile);
+ break;
+ } else {
+ lexline = l;
+ lexchar = p;
+ tb [0] = c;
+ tb [1] = 0;
+ tval = tb;
+ ttok = c;
+ break;
+ }
+ } while (1);
+ return ttok;
+}
+
+int next_token (rval, cfile)
+ char **rval;
+ FILE *cfile;
+{
+ int rv;
+
+ if (token) {
+ if (lexline != tline)
+ token_line = cur_line;
+ lexchar = tlpos;
+ lexline = tline;
+ rv = token;
+ token = 0;
+ } else {
+ rv = get_token (cfile);
+ token_line = cur_line;
+ }
+ if (rval)
+ *rval = tval;
+#ifdef DEBUG_TOKENS
+ fprintf (stderr, "%s:%d ", tval, rv);
+#endif
+ return rv;
+}
+
+int peek_token (rval, cfile)
+ char **rval;
+ FILE *cfile;
+{
+ int x;
+
+ if (!token) {
+ tlpos = lexchar;
+ tline = lexline;
+ token = get_token (cfile);
+ if (lexline != tline)
+ token_line = prev_line;
+ x = lexchar; lexchar = tlpos; tlpos = x;
+ x = lexline; lexline = tline; tline = x;
+ }
+ if (rval)
+ *rval = tval;
+#ifdef DEBUG_TOKENS
+ fprintf (stderr, "(%s:%d) ", tval, token);
+#endif
+ return token;
+}
+
+static void skip_to_eol (cfile)
+ FILE *cfile;
+{
+ int c;
+ do {
+ c = get_char (cfile);
+ if (c == EOF)
+ return;
+#ifdef OLD_LEXER
+ if (comment_index < sizeof (comments))
+ comments [comment_index++] = c;
+#endif
+ if (c == EOL) {
+ return;
+ }
+ } while (1);
+}
+
+static int read_string (cfile)
+ FILE *cfile;
+{
+ int i;
+ int bs = 0;
+ int c;
+
+ for (i = 0; i < sizeof tokbuf; i++) {
+ c = get_char (cfile);
+ if (c == EOF) {
+ parse_warn ("eof in string constant");
+ break;
+ }
+ if (bs) {
+ bs = 0;
+ tokbuf [i] = c;
+ } else if (c == '\\')
+ bs = 1;
+ else if (c == '"')
+ break;
+ else
+ tokbuf [i] = c;
+ }
+ /* Normally, I'd feel guilty about this, but we're talking about
+ strings that'll fit in a DHCP packet here... */
+ if (i == sizeof tokbuf) {
+ parse_warn ("string constant larger than internal buffer");
+ --i;
+ }
+ tokbuf [i] = 0;
+ tval = tokbuf;
+ return STRING;
+}
+
+static int read_number (c, cfile)
+ int c;
+ FILE *cfile;
+{
+ int seenx = 0;
+ int i = 0;
+ int token = NUMBER;
+
+ tokbuf [i++] = c;
+ for (; i < sizeof tokbuf; i++) {
+ c = get_char (cfile);
+ if (!seenx && c == 'x') {
+ seenx = 1;
+#ifndef OLD_LEXER
+ } else if (isascii (c) && !isxdigit (c) &&
+ (c == '-' || c == '_' || isalpha (c))) {
+ token = NAME;
+ } else if (isascii (c) && !isdigit (c) && isxdigit (c)) {
+ token = NUMBER_OR_NAME;
+#endif
+ } else if (!isascii (c) || !isxdigit (c)) {
+ ungetc (c, cfile);
+ ugflag = 1;
+ break;
+ }
+ tokbuf [i] = c;
+ }
+ if (i == sizeof tokbuf) {
+ parse_warn ("numeric token larger than internal buffer");
+ --i;
+ }
+ tokbuf [i] = 0;
+ tval = tokbuf;
+ return token;
+}
+
+static int read_num_or_name (c, cfile)
+ int c;
+ FILE *cfile;
+{
+ int i = 0;
+ int rv = NUMBER_OR_NAME;
+ tokbuf [i++] = c;
+ for (; i < sizeof tokbuf; i++) {
+ c = get_char (cfile);
+ if (!isascii (c) ||
+ (c != '-' && c != '_' && !isalnum (c))) {
+ ungetc (c, cfile);
+ ugflag = 1;
+ break;
+ }
+ if (!isxdigit (c))
+ rv = NAME;
+ tokbuf [i] = c;
+ }
+ if (i == sizeof tokbuf) {
+ parse_warn ("token larger than internal buffer");
+ --i;
+ }
+ tokbuf [i] = 0;
+ tval = tokbuf;
+ return intern (tval, rv);
+}
+
+static int intern (atom, dfv)
+ char *atom;
+ int dfv;
+{
+ if (!isascii (atom [0]))
+ return dfv;
+
+ switch (tolower (atom [0])) {
+ case 'a':
+ if (!strcasecmp (atom + 1, "ppend"))
+ return APPEND;
+ if (!strcasecmp (atom + 1, "llow"))
+ return ALLOW;
+ if (!strcasecmp (atom + 1, "lias"))
+ return ALIAS;
+ if (!strcasecmp (atom + 1, "bandoned"))
+ return ABANDONED;
+ if (!strcasecmp (atom + 1, "uthoritative"))
+ return AUTHORITATIVE;
+ break;
+ case 'b':
+ if (!strcasecmp (atom + 1, "ackoff-cutoff"))
+ return BACKOFF_CUTOFF;
+ if (!strcasecmp (atom + 1, "ootp"))
+ return BOOTP;
+ if (!strcasecmp (atom + 1, "ooting"))
+ return BOOTING;
+ if (!strcasecmp (atom + 1, "oot-unknown-clients"))
+ return BOOT_UNKNOWN_CLIENTS;
+ case 'c':
+ if (!strcasecmp (atom + 1, "lass"))
+ return CLASS;
+ if (!strcasecmp (atom + 1, "iaddr"))
+ return CIADDR;
+ if (!strcasecmp (atom + 1, "lient-identifier"))
+ return CLIENT_IDENTIFIER;
+ if (!strcasecmp (atom + 1, "lient-hostname"))
+ return CLIENT_HOSTNAME;
+ break;
+ case 'd':
+ if (!strcasecmp (atom + 1, "omain"))
+ return DOMAIN;
+ if (!strcasecmp (atom + 1, "eny"))
+ return DENY;
+ if (!strncasecmp (atom + 1, "efault", 6)) {
+ if (!atom [7])
+ return DEFAULT;
+ if (!strcasecmp (atom + 7, "-lease-time"))
+ return DEFAULT_LEASE_TIME;
+ break;
+ }
+ if (!strncasecmp (atom + 1, "ynamic-bootp", 12)) {
+ if (!atom [13])
+ return DYNAMIC_BOOTP;
+ if (!strcasecmp (atom + 13, "-lease-cutoff"))
+ return DYNAMIC_BOOTP_LEASE_CUTOFF;
+ if (!strcasecmp (atom + 13, "-lease-length"))
+ return DYNAMIC_BOOTP_LEASE_LENGTH;
+ break;
+ }
+ break;
+ case 'e':
+ if (!strcasecmp (atom + 1, "thernet"))
+ return ETHERNET;
+ if (!strcasecmp (atom + 1, "nds"))
+ return ENDS;
+ if (!strcasecmp (atom + 1, "xpire"))
+ return EXPIRE;
+ break;
+ case 'f':
+ if (!strcasecmp (atom + 1, "ilename"))
+ return FILENAME;
+ if (!strcasecmp (atom + 1, "ixed-address"))
+ return FIXED_ADDR;
+ if (!strcasecmp (atom + 1, "ddi"))
+ return FDDI;
+ break;
+ case 'g':
+ if (!strcasecmp (atom + 1, "iaddr"))
+ return GIADDR;
+ if (!strcasecmp (atom + 1, "roup"))
+ return GROUP;
+ if (!strcasecmp (atom + 1, "et-lease-hostnames"))
+ return GET_LEASE_HOSTNAMES;
+ break;
+ case 'h':
+ if (!strcasecmp (atom + 1, "ost"))
+ return HOST;
+ if (!strcasecmp (atom + 1, "ardware"))
+ return HARDWARE;
+ if (!strcasecmp (atom + 1, "ostname"))
+ return HOSTNAME;
+ break;
+ case 'i':
+ if (!strcasecmp (atom + 1, "nitial-interval"))
+ return INITIAL_INTERVAL;
+ if (!strcasecmp (atom + 1, "nterface"))
+ return INTERFACE;
+ break;
+ case 'l':
+ if (!strcasecmp (atom + 1, "ease"))
+ return LEASE;
+ break;
+ case 'm':
+ if (!strcasecmp (atom + 1, "ax-lease-time"))
+ return MAX_LEASE_TIME;
+ if (!strncasecmp (atom + 1, "edi", 3)) {
+ if (!strcasecmp (atom + 4, "a"))
+ return MEDIA;
+ if (!strcasecmp (atom + 4, "um"))
+ return MEDIUM;
+ break;
+ }
+ break;
+ case 'n':
+ if (!strcasecmp (atom + 1, "ameserver"))
+ return NAMESERVER;
+ if (!strcasecmp (atom + 1, "etmask"))
+ return NETMASK;
+ if (!strcasecmp (atom + 1, "ext-server"))
+ return NEXT_SERVER;
+ if (!strcasecmp (atom + 1, "ot"))
+ return TOKEN_NOT;
+ break;
+ case 'o':
+ if (!strcasecmp (atom + 1, "ption"))
+ return OPTION;
+ if (!strcasecmp (atom + 1, "ne-lease-per-client"))
+ return ONE_LEASE_PER_CLIENT;
+ break;
+ case 'p':
+ if (!strcasecmp (atom + 1, "repend"))
+ return PREPEND;
+ if (!strcasecmp (atom + 1, "acket"))
+ return PACKET;
+ break;
+ case 'r':
+ if (!strcasecmp (atom + 1, "ange"))
+ return RANGE;
+ if (!strcasecmp (atom + 1, "equest"))
+ return REQUEST;
+ if (!strcasecmp (atom + 1, "equire"))
+ return REQUIRE;
+ if (!strcasecmp (atom + 1, "etry"))
+ return RETRY;
+ if (!strcasecmp (atom + 1, "enew"))
+ return RENEW;
+ if (!strcasecmp (atom + 1, "ebind"))
+ return REBIND;
+ if (!strcasecmp (atom + 1, "eboot"))
+ return REBOOT;
+ if (!strcasecmp (atom + 1, "eject"))
+ return REJECT;
+ break;
+ case 's':
+ if (!strcasecmp (atom + 1, "earch"))
+ return SEARCH;
+ if (!strcasecmp (atom + 1, "tarts"))
+ return STARTS;
+ if (!strcasecmp (atom + 1, "iaddr"))
+ return SIADDR;
+ if (!strcasecmp (atom + 1, "ubnet"))
+ return SUBNET;
+ if (!strcasecmp (atom + 1, "hared-network"))
+ return SHARED_NETWORK;
+ if (!strcasecmp (atom + 1, "erver-name"))
+ return SERVER_NAME;
+ if (!strcasecmp (atom + 1, "erver-identifier"))
+ return SERVER_IDENTIFIER;
+ if (!strcasecmp (atom + 1, "elect-timeout"))
+ return SELECT_TIMEOUT;
+ if (!strcasecmp (atom + 1, "end"))
+ return SEND;
+ if (!strcasecmp (atom + 1, "cript"))
+ return SCRIPT;
+ if (!strcasecmp (atom + 1, "upersede"))
+ return SUPERSEDE;
+ break;
+ case 't':
+ if (!strcasecmp (atom + 1, "imestamp"))
+ return TIMESTAMP;
+ if (!strcasecmp (atom + 1, "imeout"))
+ return TIMEOUT;
+ if (!strcasecmp (atom + 1, "oken-ring"))
+ return TOKEN_RING;
+ break;
+ case 'u':
+ if (!strncasecmp (atom + 1, "se", 2)) {
+ if (!strcasecmp (atom + 3, "r-class"))
+ return USER_CLASS;
+ if (!strcasecmp (atom + 3, "-host-decl-names"))
+ return USE_HOST_DECL_NAMES;
+ if (!strcasecmp (atom + 3,
+ "-lease-addr-for-default-route"))
+ return USE_LEASE_ADDR_FOR_DEFAULT_ROUTE;
+ break;
+ }
+ if (!strcasecmp (atom + 1, "id"))
+ return UID;
+ if (!strcasecmp (atom + 1, "nknown-clients"))
+ return UNKNOWN_CLIENTS;
+ break;
+ case 'v':
+ if (!strcasecmp (atom + 1, "endor-class"))
+ return VENDOR_CLASS;
+ break;
+ case 'y':
+ if (!strcasecmp (atom + 1, "iaddr"))
+ return YIADDR;
+ break;
+ }
+ return dfv;
+}
diff --git a/contrib/isc-dhcp/common/dhcp-options.5 b/contrib/isc-dhcp/common/dhcp-options.5
new file mode 100644
index 000000000000..3375c507f14d
--- /dev/null
+++ b/contrib/isc-dhcp/common/dhcp-options.5
@@ -0,0 +1,581 @@
+.\" dhcp-options.5
+.\"
+.\" Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of The Internet Software Consortium nor the names
+.\" of its contributors may be used to endorse or promote products derived
+.\" from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
+.\" CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+.\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+.\" DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
+.\" CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+.\" USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+.\" ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+.\" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+.\" OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" This software has been written for the Internet Software Consortium
+.\" by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
+.\" Enterprises. To learn more about the Internet Software Consortium,
+.\" see ``http://www.isc.org/isc''. To learn more about Vixie
+.\" Enterprises, see ``http://www.vix.com''.
+.TH dhcpd-options 5
+.SH NAME
+dhcp-options - Dynamic Host Configuration Protocol options
+.SH DESCRIPTION
+The Dynamic Host Configuration protocol allows the client to receive
+.B options
+from the DHCP server describing the network configuration and various
+services that are available on the network. When configuring
+.B dhcpd(8)
+or
+.B dhclient(8) ,
+options must often be declared. The syntax for declaring options,
+and the names and formats of the options that can be declared, are
+documented here.
+.SH REFERENCE: OPTION STATEMENTS
+.PP
+DHCP \fIoption\fR statements always start with the \fIoption\fR
+keyword, followed by an option name, followed by option data. The
+option names and data formats are described below. It is not
+necessary to exhaustively specify all DHCP options - only those
+options which are needed by clients must be specified.
+.PP
+Option data comes in a variety of formats, as defined below:
+.PP
+The
+.B ip-address
+data type can be entered either as an explicit IP
+address (e.g., 239.254.197.10) or as a domain name (e.g.,
+haagen.isc.org). When entering a domain name, be sure that that
+domain name resolves to a single IP address.
+.PP
+The
+.B int32
+data type specifies a signed 32-bit integer. The
+.B uint32
+data type specifies an unsigned 32-bit integer. The
+.B int16
+and
+.B uint16
+data types specify signed and unsigned 16-bit integers. The
+.B int8
+and
+.B uint8
+data types specify signed and unsigned 8-bit integers.
+Unsigned 8-bit integers are also sometimes referred to as octets.
+.PP
+The
+.B string
+data type specifies an NVT ASCII string, which must be
+enclosed in double quotes - for example, to specify a domain-name
+option, the syntax would be
+.nf
+.sp 1
+ option domain-name "isc.org";
+.fi
+.PP
+The
+.B flag
+data type specifies a boolean value. Booleans can be either true or
+false (or on or off, if that makes more sense to you).
+.PP
+The
+.B data-string
+data type specifies either an NVT ASCII string
+enclosed in double quotes, or a series of octets specified in
+hexadecimal, seperated by colons. For example:
+.nf
+.sp 1
+ option client-identifier "CLIENT-FOO";
+or
+ option client-identifier 43:4c:49:45:54:2d:46:4f:4f;
+.fi
+.PP
+The documentation for the various options mentioned below is taken
+from the latest IETF draft document on DHCP options. Options which
+are not listed by name may be defined by the name option-\fInnn\fR,
+where \fInnn\fI is the decimal number of the option code. These
+options may be followed either by a string, enclosed in quotes, or by
+a series of octets, expressed as two-digit hexadecimal numbers seperated
+by colons. For example:
+.PP
+.nf
+ option option-133 "my-option-133-text";
+ option option-129 1:54:c9:2b:47;
+.fi
+.PP
+Because dhcpd does not know the format of these undefined option codes,
+no checking is done to ensure the correctness of the entered data.
+.PP
+The standard options are:
+.PP
+.B option subnet-mask \fIip-address\fR\fB;\fR
+.RS 0.25i
+.PP
+The subnet mask option specifies the client's subnet mask as per RFC
+950. If no subnet mask option is provided anywhere in scope, as a
+last resort dhcpd will use the subnet mask from the subnet declaration
+for the network on which an address is being assigned. However,
+.I any
+subnet-mask option declaration that is in scope for the address being
+assigned will override the subnet mask specified in the subnet
+declaration.
+.RE
+.PP
+.B option time-offset \fIint32\fR\fB;\fR
+.RS 0.25i
+.PP
+The time-offset option specifies the offset of the client's subnet in
+seconds from Coordinated Universal Time (UTC).
+.RE
+.PP
+.B option routers \fIip-address\fR [\fB,\fR \fIip-address\fR...
+]\fB;\fR
+.RS 0.25i
+.PP
+The routers option specifies a list of IP addresses for routers on the
+client's subnet. Routers should be listed in order of preference.
+.RE
+.PP
+.B option time-servers \fIip-address\fR [, \fIip-address\fR...
+]\fB;\fR
+.RS 0.25i
+.PP
+The time-server option specifies a list of RFC 868 time servers
+available to the client. Servers should be listed in order of
+preference.
+.RE
+.PP
+.B option \fBien116-name-servers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR...
+];
+.RS 0.25i
+.PP
+The ien116-name-servers option specifies a list of IEN 116 name servers
+available to the client. Servers should be listed in order of
+preference.
+.RE
+.PP
+.B option \fBdomain-name-servers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR...
+]\fB;\fR
+.RS 0.25i
+.PP
+The domain-name-servers option specifies a list of Domain Name System
+(STD 13, RFC 1035) name servers available to the client. Servers
+should be listed in order of preference.
+.RE
+.PP
+.B option \fBlog-servers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR...
+]\fB;\fR
+.RS 0.25i
+.PP
+The log-server option specifies a list of MIT-LCS UDP log servers
+available to the client. Servers should be listed in order of
+preference.
+.RE
+.PP
+.B option \fBcookie-servers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR...
+]\fB;\fR
+.RS 0.25i
+.PP
+The cookie server option specifies a list of RFC 865 cookie
+servers available to the client. Servers should be listed in order
+of preference.
+.RE
+.PP
+.B option \fBlpr-servers\fR \fIip-address \fR [\fB,\fR \fIip-address\fR...
+]\fB;\fR
+.RS 0.25i
+.PP
+The LPR server option specifies a list of RFC 1179 line printer
+servers available to the client. Servers should be listed in order
+of preference.
+.RE
+.PP
+.B option \fBimpress-servers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR...
+]\fB;\fR
+.RS 0.25i
+.PP
+The impress-server option specifies a list of Imagen Impress servers
+available to the client. Servers should be listed in order of
+preference.
+.RE
+.PP
+.B option \fBresource-location-servers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR...
+]\fB;\fR
+.RS 0.25i
+.PP
+This option specifies a list of RFC 887 Resource Location
+servers available to the client. Servers should be listed in order
+of preference.
+.RE
+.PP
+.B option \fBhost-name\fR \fIstring\fR\fB;\fR
+.RS 0.25i
+.PP
+This option specifies the name of the client. The name may or may
+not be qualified with the local domain name (it is preferable to use
+the domain-name option to specify the domain name). See RFC 1035 for
+character set restrictions.
+.RE
+.PP
+.B option \fBboot-size\fR \fIuint16\fR\fB;\fR
+.RS 0.25i
+.PP
+This option specifies the length in 512-octet blocks of the default
+boot image for the client.
+.RE
+.PP
+.B option \fBmerit-dump\fR \fIstring\fR\fB;\fR
+.RS 0.25i
+.PP
+This option specifies the path-name of a file to which the client's
+core image should be dumped in the event the client crashes. The
+path is formatted as a character string consisting of characters from
+the NVT ASCII character set.
+.RE
+.PP
+.B option \fBdomain-name\fR \fIstring\fR\fB;\fR
+.RS 0.25i
+.PP
+This option specifies the domain name that client should use when
+resolving hostnames via the Domain Name System.
+.RE
+.PP
+.B option \fBswap-server\fR \fIip-address\fR\fB;\fR
+.RS 0.25i
+.PP
+This specifies the IP address of the client's swap server.
+.RE
+.PP
+.B option \fBroot-path\fR \fIstring\fB;\fR\fR
+.RS 0.25i
+.PP
+This option specifies the path-name that contains the client's root
+disk. The path is formatted as a character string consisting of
+characters from the NVT ASCII character set.
+.RE
+.PP
+.B option \fBip-forwarding\fR \fIflag\fR\fB;\fR
+.RS 0.25i
+.PP
+This option specifies whether the client should configure its IP
+layer for packet forwarding. A value of 0 means disable IP
+forwarding, and a value of 1 means enable IP forwarding.
+.RE
+.PP
+.B option \fBnon-local-source-routing\fR \fIflag\fR\fB;\fR
+.RS 0.25i
+.PP
+This option specifies whether the client should configure its IP
+layer to allow forwarding of datagrams with non-local source routes
+(see Section 3.3.5 of [4] for a discussion of this topic). A value
+of 0 means disallow forwarding of such datagrams, and a value of 1
+means allow forwarding.
+.RE
+.PP
+.B option \fBpolicy-filter\fR \fIip-address ip-address\fR [\fB,\fR \fIip-address ip-address\fR...
+]\fB;\fR
+.RS 0.25i
+.PP
+This option specifies policy filters for non-local source routing.
+The filters consist of a list of IP addresses and masks which specify
+destination/mask pairs with which to filter incoming source routes.
+.PP
+Any source routed datagram whose next-hop address does not match one
+of the filters should be discarded by the client.
+.PP
+See STD 3 (RFC1122) for further information.
+.RE
+.PP
+.B option \fBmax-dgram-reassembly\fR \fIuint16\fR\fB;\fR
+.RS 0.25i
+.PP
+This option specifies the maximum size datagram that the client
+should be prepared to reassemble. The minimum value legal value is
+576.
+.RE
+.PP
+.B option \fBdefault-ip-ttl\fR \fIuint8;\fR
+.RS 0.25i
+.PP
+This option specifies the default time-to-live that the client should
+use on outgoing datagrams.
+.RE
+.PP
+.B option \fBpath-mtu-aging-timeout\fR \fIuint32\fR\fB;\fR
+.RS 0.25i
+.PP
+This option specifies the timeout (in seconds) to use when aging Path
+MTU values discovered by the mechanism defined in RFC 1191.
+.RE
+.PP
+.B option \fBpath-mtu-plateau-table\fR \fIuint16\fR [\fB,\fR \fIuint16\fR...
+]\fB;\fR
+.RS 0.25i
+.PP
+This option specifies a table of MTU sizes to use when performing
+Path MTU Discovery as defined in RFC 1191. The table is formatted as
+a list of 16-bit unsigned integers, ordered from smallest to largest.
+The minimum MTU value cannot be smaller than 68.
+.RE
+.PP
+.B option \fBinterface-mtu\fR \fIuint16\fR\fB;\fR
+.RS 0.25i
+.PP
+This option specifies the MTU to use on this interface. The minimum
+legal value for the MTU is 68.
+.RE
+.PP
+.B option \fBall-subnets-local\fR \fIflag\fR\fB;\fR
+.RS 0.25i
+.PP
+This option specifies whether or not the client may assume that all
+subnets of the IP network to which the client is connected use the
+same MTU as the subnet of that network to which the client is
+directly connected. A value of 1 indicates that all subnets share
+the same MTU. A value of 0 means that the client should assume that
+some subnets of the directly connected network may have smaller MTUs.
+.RE
+.PP
+.B option \fBbroadcast-address\fR \fIip-address\fR\fB;\fR
+.RS 0.25i
+.PP
+This option specifies the broadcast address in use on the client's
+subnet. Legal values for broadcast addresses are specified in
+section 3.2.1.3 of STD 3 (RFC1122).
+.RE
+.PP
+.B option \fBperform-mask-discovery\fR \fIflag\fR\fB;\fR
+.RS 0.25i
+.PP
+This option specifies whether or not the client should perform subnet
+mask discovery using ICMP. A value of 0 indicates that the client
+should not perform mask discovery. A value of 1 means that the
+client should perform mask discovery.
+.RE
+.PP
+.B option \fBmask-supplier\fR \fIflag\fR\fB;\fR
+.RS 0.25i
+.PP
+This option specifies whether or not the client should respond to
+subnet mask requests using ICMP. A value of 0 indicates that the
+client should not respond. A value of 1 means that the client should
+respond.
+.RE
+.PP
+.B option \fBrouter-discovery\fR \fIflag\fR\fB;\fR
+.RS 0.25i
+.PP
+This option specifies whether or not the client should solicit
+routers using the Router Discovery mechanism defined in RFC 1256.
+A value of 0 indicates that the client should not perform
+router discovery. A value of 1 means that the client should perform
+router discovery.
+.RE
+.PP
+.B option \fBrouter-solicitation-address\fR \fIip-address\fR\fB;\fR
+.RS 0.25i
+.PP
+This option specifies the address to which the client should transmit
+router solicitation requests.
+.RE
+.PP
+.B option \fBstatic-routes\fR \fIip-address ip-address\fR [\fB,\fR \fIip-address ip-address\fR...
+]\fB;\fR
+.RS 0.25i
+.PP
+This option specifies a list of static routes that the client should
+install in its routing cache. If multiple routes to the same
+destination are specified, they are listed in descending order of
+priority.
+.PP
+The routes consist of a list of IP address pairs. The first address
+is the destination address, and the second address is the router for
+the destination.
+.PP
+The default route (0.0.0.0) is an illegal destination for a static
+route. To specify the default route, use the
+.B routers
+option.
+.RE
+.PP
+.B option \fBtrailer-encapsulation\fR \fIflag\fR\fB;\fR
+.RS 0.25i
+.PP
+This option specifies whether or not the client should negotiate the
+use of trailers (RFC 893 [14]) when using the ARP protocol. A value
+of 0 indicates that the client should not attempt to use trailers. A
+value of 1 means that the client should attempt to use trailers.
+.RE
+.PP
+.B option \fBarp-cache-timeout\fR \fIuint32\fR\fB;\fR
+.RS 0.25i
+.PP
+This option specifies the timeout in seconds for ARP cache entries.
+.RE
+.PP
+.B option \fBieee802-3-encapsulation\fR \fIflag\fR\fB;\fR
+.RS 0.25i
+.PP
+This option specifies whether or not the client should use Ethernet
+Version 2 (RFC 894) or IEEE 802.3 (RFC 1042) encapsulation if the
+interface is an Ethernet. A value of 0 indicates that the client
+should use RFC 894 encapsulation. A value of 1 means that the client
+should use RFC 1042 encapsulation.
+.RE
+.PP
+.B option \fBdefault-tcp-ttl\fR \fIuint8\fR\fB;\fR
+.RS 0.25i
+.PP
+This option specifies the default TTL that the client should use when
+sending TCP segments. The minimum value is 1.
+.RE
+.PP
+.B option \fBtcp-keepalive-interval\fR \fIuint32\fR\fB;\fR
+.RS 0.25i
+.PP
+This option specifies the interval (in seconds) that the client TCP
+should wait before sending a keepalive message on a TCP connection.
+The time is specified as a 32-bit unsigned integer. A value of zero
+indicates that the client should not generate keepalive messages on
+connections unless specifically requested by an application.
+.RE
+.PP
+.B option \fBtcp-keepalive-garbage\fR \fIflag\fR\fB;\fR
+.RS 0.25i
+.PP
+This option specifies the whether or not the client should send TCP
+keepalive messages with a octet of garbage for compatibility with
+older implementations. A value of 0 indicates that a garbage octet
+should not be sent. A value of 1 indicates that a garbage octet
+should be sent.
+.RE
+.PP
+.B option \fBnis-domain\fR \fIstring\fR\fB;\fR
+.RS 0.25i
+.PP
+This option specifies the name of the client's NIS (Sun Network
+Information Services) domain. The domain is formatted as a character
+string consisting of characters from the NVT ASCII character set.
+.RE
+.PP
+.B option \fBnis-servers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR...
+]\fB;\fR
+.RS 0.25i
+.PP
+This option specifies a list of IP addresses indicating NIS servers
+available to the client. Servers should be listed in order of
+preference.
+.RE
+.PP
+.B option \fBntp-servers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR...
+]\fB;\fR
+.RS 0.25i
+.PP
+This option specifies a list of IP addresses indicating NTP (RFC 1035)
+servers available to the client. Servers should be listed in order
+of preference.
+.RE
+.PP
+.B option \fBnetbios-name-servers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR...
+]\fB;\fR
+.RS 0.25i
+.PP
+The NetBIOS name server (NBNS) option specifies a list of RFC
+1001/1002 NBNS name servers listed in order of preference. NetBIOS
+Name Service is currently more commonly referred to as WINS. WINS
+servers can be specified using the netbios-name-servers option.
+.RE
+.PP
+.B option \fBnetbios-dd-server\fR \fIip-address\fR [\fB,\fR \fIip-address\fR...
+]\fB;\fR
+.RS 0.25i
+.PP
+The NetBIOS datagram distribution server (NBDD) option specifies a
+list of RFC 1001/1002 NBDD servers listed in order of preference.
+.RE
+.PP
+.B option \fBnetbios-node-type\fR \fIuint8\fR\fB;\fR
+.RS 0.25i
+.PP
+The NetBIOS node type option allows NetBIOS over TCP/IP clients which
+are configurable to be configured as described in RFC 1001/1002. The
+value is specified as a single octet which identifies the client type.
+.PP
+Possible node types are:
+.PP
+.TP 5
+.I 1
+B-node: Broadcast - no WINS
+.TP
+.I 2
+P-node: Peer - WINS only.
+.TP
+.I 4
+M-node: Mixed - broadcast, then WINS
+.TP
+.I 8
+H-node: Hybrid - WINS, then broadcast
+.RE
+.PP
+.B option
+.B netbios-scope
+.I string\fB;\fR
+.RS 0.25i
+.PP
+The NetBIOS scope option specifies the NetBIOS over TCP/IP scope
+parameter for the client as specified in RFC 1001/1002. See RFC1001,
+RFC1002, and RFC1035 for character-set restrictions.
+.RE
+.PP
+.B option \fBfont-servers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR...
+]\fB;\fR
+.RS 0.25i
+.PP
+This option specifies a list of X Window System Font servers available
+to the client. Servers should be listed in order of preference.
+.RE
+.PP
+.B option \fBx-display-manager\fR \fIip-address\fR [\fB,\fR \fIip-address\fR...
+]\fB;\fR
+.RS 0.25i
+.PP
+This option specifies a list of systems that are running the X Window
+System Display Manager and are available to the client. Addresses
+should be listed in order of preference.
+.RE
+.PP
+.B option \fBdhcp-client-identifier\fR \fIdata-string\fR\fB;\fR
+.RS 0.25i
+.PP
+This option can be used to specify the a DHCP client identifier in a
+host declaration, so that dhcpd can find the host record by matching
+against the client identifier.
+.RE
+.SH SEE ALSO
+dhcpd.conf(5), dhcpd.leases(5), dhclient.conf(5), dhcpd(8),
+dhclient(8), RFC2132, RFC2131.
+.SH AUTHOR
+.B dhcpd(8)
+was written by Ted Lemon <mellon@vix.com>
+under a contract with Vixie Labs. Funding
+for this project was provided by the Internet Software Corporation.
+Information about the Internet Software Consortium can be found at
+.B http://www.isc.org/isc.
diff --git a/contrib/isc-dhcp/common/dispatch.c b/contrib/isc-dhcp/common/dispatch.c
new file mode 100644
index 000000000000..0a383a04d48c
--- /dev/null
+++ b/contrib/isc-dhcp/common/dispatch.c
@@ -0,0 +1,847 @@
+/* dispatch.c
+
+ Network input dispatcher... */
+
+/*
+ * Copyright (c) 1995, 1996, 1997, 1998, 1999 The Internet Software Consortium.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of The Internet Software Consortium nor the names
+ * of its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
+ * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This software has been written for the Internet Software Consortium
+ * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
+ * Enterprises. To learn more about the Internet Software Consortium,
+ * see ``http://www.vix.com/isc''. To learn more about Vixie
+ * Enterprises, see ``http://www.vix.com''.
+ */
+
+#ifndef lint
+static char copyright[] =
+"$Id: dispatch.c,v 1.47.2.9 1999/02/05 20:23:50 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998, 1999 The Internet Software Consortium. All rights reserved.\n";
+#endif /* not lint */
+
+#include "dhcpd.h"
+#include <sys/ioctl.h>
+
+struct interface_info *interfaces, *dummy_interfaces, *fallback_interface;
+struct protocol *protocols;
+struct timeout *timeouts;
+static struct timeout *free_timeouts;
+static int interfaces_invalidated;
+void (*bootp_packet_handler) PROTO ((struct interface_info *,
+ struct dhcp_packet *, int, unsigned int,
+ struct iaddr, struct hardware *));
+
+int quiet_interface_discovery;
+
+/* Use the SIOCGIFCONF ioctl to get a list of all the attached interfaces.
+ For each interface that's of type INET and not the loopback interface,
+ register that interface with the network I/O software, figure out what
+ subnet it's on, and add it to the list of interfaces. */
+
+void discover_interfaces (state)
+ int state;
+{
+ struct interface_info *tmp;
+ struct interface_info *last, *next;
+ char buf [8192];
+ struct ifconf ic;
+ struct ifreq ifr;
+ int i;
+ int sock;
+ int address_count = 0;
+ struct subnet *subnet;
+ struct shared_network *share;
+ struct sockaddr_in foo;
+ int ir;
+#ifdef ALIAS_NAMES_PERMUTED
+ char *s;
+#endif
+
+ /* Create an unbound datagram socket to do the SIOCGIFADDR ioctl on. */
+ if ((sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
+ error ("Can't create addrlist socket");
+
+ /* Get the interface configuration information... */
+ ic.ifc_len = sizeof buf;
+ ic.ifc_ifcu.ifcu_buf = (caddr_t)buf;
+ i = ioctl(sock, SIOCGIFCONF, &ic);
+
+ if (i < 0)
+ error ("ioctl: SIOCGIFCONF: %m");
+
+ /* If we already have a list of interfaces, and we're running as
+ a DHCP server, the interfaces were requested. */
+ if (interfaces && (state == DISCOVER_SERVER ||
+ state == DISCOVER_RELAY ||
+ state == DISCOVER_REQUESTED))
+ ir = 0;
+ else if (state == DISCOVER_UNCONFIGURED)
+ ir = INTERFACE_REQUESTED | INTERFACE_AUTOMATIC;
+ else
+ ir = INTERFACE_REQUESTED;
+
+ /* Cycle through the list of interfaces looking for IP addresses. */
+ for (i = 0; i < ic.ifc_len;) {
+ struct ifreq *ifp = (struct ifreq *)((caddr_t)ic.ifc_req + i);
+#ifdef HAVE_SA_LEN
+ if (ifp -> ifr_addr.sa_len)
+ i += (sizeof ifp -> ifr_name) + ifp -> ifr_addr.sa_len;
+ else
+#endif
+ i += sizeof *ifp;
+
+#ifdef ALIAS_NAMES_PERMUTED
+ if ((s = strrchr (ifp -> ifr_name, ':'))) {
+ *s = 0;
+ }
+#endif
+
+#ifdef SKIP_DUMMY_INTERFACES
+ if (!strncmp (ifp -> ifr_name, "dummy", 5))
+ continue;
+#endif
+
+
+ /* See if this is the sort of interface we want to
+ deal with. */
+ strcpy (ifr.ifr_name, ifp -> ifr_name);
+ if (ioctl (sock, SIOCGIFFLAGS, &ifr) < 0)
+ error ("Can't get interface flags for %s: %m",
+ ifr.ifr_name);
+
+ /* Skip loopback, point-to-point and down interfaces,
+ except don't skip down interfaces if we're trying to
+ get a list of configurable interfaces. */
+ if ((ifr.ifr_flags & IFF_LOOPBACK) ||
+#ifdef IFF_POINTOPOINT
+ (ifr.ifr_flags & IFF_POINTOPOINT) ||
+#endif
+ (!(ifr.ifr_flags & IFF_UP) &&
+ state != DISCOVER_UNCONFIGURED))
+ continue;
+
+ /* See if we've seen an interface that matches this one. */
+ for (tmp = interfaces; tmp; tmp = tmp -> next)
+ if (!strcmp (tmp -> name, ifp -> ifr_name))
+ break;
+
+ /* If there isn't already an interface by this name,
+ allocate one. */
+ if (!tmp) {
+ tmp = ((struct interface_info *)
+ dmalloc (sizeof *tmp, "discover_interfaces"));
+ if (!tmp)
+ error ("Insufficient memory to %s %s",
+ "record interface", ifp -> ifr_name);
+ strcpy (tmp -> name, ifp -> ifr_name);
+ tmp -> next = interfaces;
+ tmp -> flags = ir;
+ interfaces = tmp;
+ }
+
+ /* If we have the capability, extract link information
+ and record it in a linked list. */
+#ifdef AF_LINK
+ if (ifp -> ifr_addr.sa_family == AF_LINK) {
+ struct sockaddr_dl *foo = ((struct sockaddr_dl *)
+ (&ifp -> ifr_addr));
+ tmp -> hw_address.hlen = foo -> sdl_alen;
+ tmp -> hw_address.htype = HTYPE_ETHER; /* XXX */
+ memcpy (tmp -> hw_address.haddr,
+ LLADDR (foo), foo -> sdl_alen);
+ } else
+#endif /* AF_LINK */
+
+ if (ifp -> ifr_addr.sa_family == AF_INET) {
+ struct iaddr addr;
+
+ /* Get a pointer to the address... */
+ memcpy (&foo, &ifp -> ifr_addr,
+ sizeof ifp -> ifr_addr);
+
+ /* We don't want the loopback interface. */
+ if (foo.sin_addr.s_addr == htonl (INADDR_LOOPBACK))
+ continue;
+
+
+ /* If this is the first real IP address we've
+ found, keep a pointer to ifreq structure in
+ which we found it. */
+ if (!tmp -> ifp) {
+ struct ifreq *tif;
+#ifdef HAVE_SA_LEN
+ int len = ((sizeof ifp -> ifr_name) +
+ ifp -> ifr_addr.sa_len);
+#else
+ int len = sizeof *ifp;
+#endif
+ tif = (struct ifreq *)malloc (len);
+ if (!tif)
+ error ("no space to remember ifp.");
+ memcpy (tif, ifp, len);
+ tmp -> ifp = tif;
+ tmp -> primary_address = foo.sin_addr;
+ }
+
+ /* Grab the address... */
+ addr.len = 4;
+ memcpy (addr.iabuf, &foo.sin_addr.s_addr,
+ addr.len);
+
+ /* If there's a registered subnet for this address,
+ connect it together... */
+ if ((subnet = find_subnet (addr))) {
+ /* If this interface has multiple aliases
+ on the same subnet, ignore all but the
+ first we encounter. */
+ if (!subnet -> interface) {
+ subnet -> interface = tmp;
+ subnet -> interface_address = addr;
+ } else if (subnet -> interface != tmp) {
+ warn ("Multiple %s %s: %s %s",
+ "interfaces match the",
+ "same subnet",
+ subnet -> interface -> name,
+ tmp -> name);
+ }
+ share = subnet -> shared_network;
+ if (tmp -> shared_network &&
+ tmp -> shared_network != share) {
+ warn ("Interface %s matches %s",
+ tmp -> name,
+ "multiple shared networks");
+ } else {
+ tmp -> shared_network = share;
+ }
+
+ if (!share -> interface) {
+ share -> interface = tmp;
+ } else if (share -> interface != tmp) {
+ warn ("Multiple %s %s: %s %s",
+ "interfaces match the",
+ "same shared network",
+ share -> interface -> name,
+ tmp -> name);
+ }
+ }
+ }
+ }
+
+#if defined (LINUX_SLASHPROC_DISCOVERY)
+ /* On Linux, interfaces that don't have IP addresses don't show up
+ in the SIOCGIFCONF syscall. We got away with this prior to
+ Linux 2.1 because we would give each interface an IP address of
+ 0.0.0.0 before trying to boot, but that doesn't work after 2.1
+ because we're using LPF, because we can't configure interfaces
+ with IP addresses of 0.0.0.0 anymore (grumble). This only
+ matters for the DHCP client, of course - the relay agent and
+ server should only care about interfaces that are configured
+ with IP addresses anyway.
+
+ The PROCDEV_DEVICE (/proc/net/dev) is a kernel-supplied file
+ that, when read, prints a human readable network status. We
+ extract the names of the network devices by skipping the first
+ two lines (which are header) and then parsing off everything
+ up to the colon in each subsequent line - these lines start
+ with the interface name, then a colon, then a bunch of
+ statistics. Yes, Virgina, this is a kludge, but you work
+ with what you have. */
+
+ if (state == DISCOVER_UNCONFIGURED) {
+ FILE *proc_dev;
+ char buffer [256];
+ struct ifreq *tif;
+ int skip = 2;
+
+ proc_dev = fopen (PROCDEV_DEVICE, "r");
+ if (!proc_dev)
+ error ("%s: %m", PROCDEV_DEVICE);
+
+ while (fgets (buffer, sizeof buffer, proc_dev)) {
+ char *name = buffer;
+ char *sep;
+
+ /* Skip the first two blocks, which are header
+ lines. */
+ if (skip) {
+ --skip;
+ continue;
+ }
+
+ sep = strrchr (buffer, ':');
+ if (sep)
+ *sep = '\0';
+ while (*name == ' ')
+ name++;
+
+ /* See if we've seen an interface that matches
+ this one. */
+ for (tmp = interfaces; tmp; tmp = tmp -> next)
+ if (!strcmp (tmp -> name, name))
+ break;
+
+ /* If we found one, and it already has an ifreq
+ structure, nothing more to do.. */
+ if (tmp && tmp -> ifp)
+ continue;
+
+ /* Make up an ifreq structure. */
+ tif = (struct ifreq *)malloc (sizeof (struct ifreq));
+ if (!tif)
+ error ("no space to remember ifp.");
+ memset (tif, 0, sizeof (struct ifreq));
+ strcpy (tif -> ifr_name, name);
+
+ /* Now, if we just needed the ifreq structure, hook
+ it in and move on. */
+ if (tmp) {
+ tmp -> ifp = tif;
+ continue;
+ }
+
+ /* Otherwise, allocate one. */
+ tmp = ((struct interface_info *)
+ dmalloc (sizeof *tmp, "discover_interfaces"));
+ if (!tmp)
+ error ("Insufficient memory to %s %s",
+ "record interface", name);
+ memset (tmp, 0, sizeof *tmp);
+ strcpy (tmp -> name, name);
+
+ tmp -> ifp = tif;
+ tmp -> flags = ir;
+ tmp -> next = interfaces;
+ interfaces = tmp;
+ }
+ fclose (proc_dev);
+ }
+#endif
+
+ /* Now cycle through all the interfaces we found, looking for
+ hardware addresses. */
+#if defined (SIOCGIFHWADDR) && !defined (AF_LINK)
+ for (tmp = interfaces; tmp; tmp = tmp -> next) {
+ struct ifreq ifr;
+ struct sockaddr sa;
+ int b, sk;
+
+ /* Read the hardware address from this interface. */
+ ifr = *tmp -> ifp;
+ if (ioctl (sock, SIOCGIFHWADDR, &ifr) < 0)
+ continue;
+
+ sa = *(struct sockaddr *)&ifr.ifr_hwaddr;
+
+ switch (sa.sa_family) {
+#ifdef ARPHRD_LOOPBACK
+ case ARPHRD_LOOPBACK:
+ /* ignore loopback interface */
+ break;
+#endif
+
+ case ARPHRD_ETHER:
+ tmp -> hw_address.hlen = 6;
+ tmp -> hw_address.htype = ARPHRD_ETHER;
+ memcpy (tmp -> hw_address.haddr, sa.sa_data, 6);
+ break;
+
+#ifndef ARPHRD_IEEE802
+# define ARPHRD_IEEE802 HTYPE_IEEE802
+#endif
+ case ARPHRD_IEEE802:
+ tmp -> hw_address.hlen = 6;
+ tmp -> hw_address.htype = ARPHRD_IEEE802;
+ memcpy (tmp -> hw_address.haddr, sa.sa_data, 6);
+ break;
+
+#ifndef ARPHRD_FDDI
+# define ARPHRD_FDDI HTYPE_FDDI
+#endif
+ case ARPHRD_FDDI:
+ tmp -> hw_address.hlen = 16;
+ tmp -> hw_address.htype = HTYPE_FDDI; /* XXX */
+ memcpy (tmp -> hw_address.haddr, sa.sa_data, 16);
+ break;
+
+#ifdef ARPHRD_METRICOM
+ case ARPHRD_METRICOM:
+ tmp -> hw_address.hlen = 6;
+ tmp -> hw_address.htype = ARPHRD_METRICOM;
+ memcpy (tmp -> hw_address.haddr, sa.sa_data, 6);
+ break;
+#endif
+
+ default:
+ error ("%s: unknown hardware address type %d",
+ ifr.ifr_name, sa.sa_family);
+ }
+ }
+#endif /* defined (SIOCGIFHWADDR) && !defined (AF_LINK) */
+
+ /* If we're just trying to get a list of interfaces that we might
+ be able to configure, we can quit now. */
+ if (state == DISCOVER_UNCONFIGURED)
+ return;
+
+ /* Weed out the interfaces that did not have IP addresses. */
+ last = (struct interface_info *)0;
+ for (tmp = interfaces; tmp; tmp = next) {
+ next = tmp -> next;
+ if ((tmp -> flags & INTERFACE_AUTOMATIC) &&
+ state == DISCOVER_REQUESTED)
+ tmp -> flags &= ~(INTERFACE_AUTOMATIC |
+ INTERFACE_REQUESTED);
+ if (!tmp -> ifp || !(tmp -> flags & INTERFACE_REQUESTED)) {
+ if ((tmp -> flags & INTERFACE_REQUESTED) != ir)
+ error ("%s: not found", tmp -> name);
+ if (!last)
+ interfaces = interfaces -> next;
+ else
+ last -> next = tmp -> next;
+
+ /* Remember the interface in case we need to know
+ about it later. */
+ tmp -> next = dummy_interfaces;
+ dummy_interfaces = tmp;
+ continue;
+ }
+ last = tmp;
+
+ memcpy (&foo, &tmp -> ifp -> ifr_addr,
+ sizeof tmp -> ifp -> ifr_addr);
+
+ /* We must have a subnet declaration for each interface. */
+ if (!tmp -> shared_network && (state == DISCOVER_SERVER))
+ error ("No subnet declaration for %s (%s).",
+ tmp -> name, inet_ntoa (foo.sin_addr));
+
+ /* Find subnets that don't have valid interface
+ addresses... */
+ for (subnet = (tmp -> shared_network
+ ? tmp -> shared_network -> subnets
+ : (struct subnet *)0);
+ subnet; subnet = subnet -> next_sibling) {
+ if (!subnet -> interface_address.len) {
+ /* Set the interface address for this subnet
+ to the first address we found. */
+ subnet -> interface_address.len = 4;
+ memcpy (subnet -> interface_address.iabuf,
+ &foo.sin_addr.s_addr, 4);
+ }
+ }
+
+ /* Register the interface... */
+ if_register_receive (tmp);
+ if_register_send (tmp);
+ }
+
+ /* Now register all the remaining interfaces as protocols. */
+ for (tmp = interfaces; tmp; tmp = tmp -> next)
+ add_protocol (tmp -> name, tmp -> rfdesc, got_one, tmp);
+
+ close (sock);
+
+ maybe_setup_fallback ();
+}
+
+struct interface_info *setup_fallback ()
+{
+ fallback_interface =
+ ((struct interface_info *)
+ dmalloc (sizeof *fallback_interface, "discover_interfaces"));
+ if (!fallback_interface)
+ error ("Insufficient memory to record fallback interface.");
+ memset (fallback_interface, 0, sizeof *fallback_interface);
+ strcpy (fallback_interface -> name, "fallback");
+ fallback_interface -> shared_network =
+ new_shared_network ("parse_statement");
+ if (!fallback_interface -> shared_network)
+ error ("No memory for shared subnet");
+ memset (fallback_interface -> shared_network, 0,
+ sizeof (struct shared_network));
+ fallback_interface -> shared_network -> name = "fallback-net";
+ return fallback_interface;
+}
+
+void reinitialize_interfaces ()
+{
+ struct interface_info *ip;
+
+ for (ip = interfaces; ip; ip = ip -> next) {
+ if_reinitialize_receive (ip);
+ if_reinitialize_send (ip);
+ }
+
+ if (fallback_interface)
+ if_reinitialize_send (fallback_interface);
+
+ interfaces_invalidated = 1;
+}
+
+#ifdef USE_POLL
+/* Wait for packets to come in using poll(). When a packet comes in,
+ call receive_packet to receive the packet and possibly strip hardware
+ addressing information from it, and then call through the
+ bootp_packet_handler hook to try to do something with it. */
+
+void dispatch ()
+{
+ struct protocol *l;
+ int nfds = 0;
+ struct pollfd *fds;
+ int count;
+ int i;
+ int to_msec;
+
+ nfds = 0;
+ for (l = protocols; l; l = l -> next) {
+ ++nfds;
+ }
+ fds = (struct pollfd *)malloc ((nfds) * sizeof (struct pollfd));
+ if (!fds)
+ error ("Can't allocate poll structures.");
+
+ do {
+ /* Call any expired timeouts, and then if there's
+ still a timeout registered, time out the select
+ call then. */
+ another:
+ if (timeouts) {
+ struct timeout *t;
+ if (timeouts -> when <= cur_time) {
+ t = timeouts;
+ timeouts = timeouts -> next;
+ (*(t -> func)) (t -> what);
+ t -> next = free_timeouts;
+ free_timeouts = t;
+ goto another;
+ }
+ /* Figure timeout in milliseconds, and check for
+ potential overflow. We assume that integers
+ are 32 bits, which is harmless if they're 64
+ bits - we'll just get extra timeouts in that
+ case. Lease times would have to be quite
+ long in order for a 32-bit integer to overflow,
+ anyway. */
+ to_msec = timeouts -> when - cur_time;
+ if (to_msec > 2147483)
+ to_msec = 2147483;
+ to_msec *= 1000;
+ } else
+ to_msec = -1;
+
+ /* Set up the descriptors to be polled. */
+ i = 0;
+ for (l = protocols; l; l = l -> next) {
+ fds [i].fd = l -> fd;
+ fds [i].events = POLLIN;
+ fds [i].revents = 0;
+ ++i;
+ }
+
+ /* Wait for a packet or a timeout... XXX */
+ count = poll (fds, nfds, to_msec);
+
+ /* Get the current time... */
+ GET_TIME (&cur_time);
+
+ /* Not likely to be transitory... */
+ if (count < 0) {
+ if (errno == EAGAIN || errno == EINTR)
+ continue;
+ else
+ error ("poll: %m");
+ }
+
+ i = 0;
+ for (l = protocols; l; l = l -> next) {
+ if ((fds [i].revents & POLLIN)) {
+ fds [i].revents = 0;
+ if (l -> handler)
+ (*(l -> handler)) (l);
+ if (interfaces_invalidated)
+ break;
+ }
+ ++i;
+ }
+ interfaces_invalidated = 0;
+ } while (1);
+}
+#else
+/* Wait for packets to come in using select(). When one does, call
+ receive_packet to receive the packet and possibly strip hardware
+ addressing information from it, and then call through the
+ bootp_packet_handler hook to try to do something with it. */
+
+void dispatch ()
+{
+ fd_set r, w, x;
+ struct protocol *l;
+ int max = 0;
+ int count;
+ struct timeval tv, *tvp;
+
+ FD_ZERO (&w);
+ FD_ZERO (&x);
+
+ do {
+ /* Call any expired timeouts, and then if there's
+ still a timeout registered, time out the select
+ call then. */
+ another:
+ if (timeouts) {
+ struct timeout *t;
+ if (timeouts -> when <= cur_time) {
+ t = timeouts;
+ timeouts = timeouts -> next;
+ (*(t -> func)) (t -> what);
+ t -> next = free_timeouts;
+ free_timeouts = t;
+ goto another;
+ }
+ tv.tv_sec = timeouts -> when - cur_time;
+ tv.tv_usec = 0;
+ tvp = &tv;
+ } else
+ tvp = (struct timeval *)0;
+
+ /* Set up the read mask. */
+ FD_ZERO (&r);
+
+ for (l = protocols; l; l = l -> next) {
+ FD_SET (l -> fd, &r);
+ if (l -> fd > max)
+ max = l -> fd;
+ }
+
+ /* Wait for a packet or a timeout... XXX */
+ count = select (max + 1, &r, &w, &x, tvp);
+
+ /* Get the current time... */
+ GET_TIME (&cur_time);
+
+ /* Not likely to be transitory... */
+ if (count < 0)
+ error ("select: %m");
+
+ for (l = protocols; l; l = l -> next) {
+ if (!FD_ISSET (l -> fd, &r))
+ continue;
+ if (l -> handler)
+ (*(l -> handler)) (l);
+ if (interfaces_invalidated)
+ break;
+ }
+ interfaces_invalidated = 0;
+ } while (1);
+}
+#endif /* USE_POLL */
+
+void got_one (l)
+ struct protocol *l;
+{
+ struct sockaddr_in from;
+ struct hardware hfrom;
+ struct iaddr ifrom;
+ int result;
+ union {
+ unsigned char packbuf [4095]; /* Packet input buffer.
+ Must be as large as largest
+ possible MTU. */
+ struct dhcp_packet packet;
+ } u;
+ struct interface_info *ip = l -> local;
+
+ if ((result =
+ receive_packet (ip, u.packbuf, sizeof u, &from, &hfrom)) < 0) {
+ warn ("receive_packet failed on %s: %m", ip -> name);
+ return;
+ }
+ if (result == 0)
+ return;
+
+ if (bootp_packet_handler) {
+ ifrom.len = 4;
+ memcpy (ifrom.iabuf, &from.sin_addr, ifrom.len);
+
+ (*bootp_packet_handler) (ip, &u.packet, result,
+ from.sin_port, ifrom, &hfrom);
+ }
+}
+
+int locate_network (packet)
+ struct packet *packet;
+{
+ struct iaddr ia;
+
+ /* If this came through a gateway, find the corresponding subnet... */
+ if (packet -> raw -> giaddr.s_addr) {
+ struct subnet *subnet;
+ ia.len = 4;
+ memcpy (ia.iabuf, &packet -> raw -> giaddr, 4);
+ subnet = find_subnet (ia);
+ if (subnet)
+ packet -> shared_network = subnet -> shared_network;
+ else
+ packet -> shared_network = (struct shared_network *)0;
+ } else {
+ packet -> shared_network =
+ packet -> interface -> shared_network;
+ }
+ if (packet -> shared_network)
+ return 1;
+ return 0;
+}
+
+void add_timeout (when, where, what)
+ TIME when;
+ void (*where) PROTO ((void *));
+ void *what;
+{
+ struct timeout *t, *q;
+
+ /* See if this timeout supersedes an existing timeout. */
+ t = (struct timeout *)0;
+ for (q = timeouts; q; q = q -> next) {
+ if (q -> func == where && q -> what == what) {
+ if (t)
+ t -> next = q -> next;
+ else
+ timeouts = q -> next;
+ break;
+ }
+ t = q;
+ }
+
+ /* If we didn't supersede a timeout, allocate a timeout
+ structure now. */
+ if (!q) {
+ if (free_timeouts) {
+ q = free_timeouts;
+ free_timeouts = q -> next;
+ q -> func = where;
+ q -> what = what;
+ } else {
+ q = (struct timeout *)malloc (sizeof (struct timeout));
+ if (!q)
+ error ("Can't allocate timeout structure!");
+ q -> func = where;
+ q -> what = what;
+ }
+ }
+
+ q -> when = when;
+
+ /* Now sort this timeout into the timeout list. */
+
+ /* Beginning of list? */
+ if (!timeouts || timeouts -> when > q -> when) {
+ q -> next = timeouts;
+ timeouts = q;
+ return;
+ }
+
+ /* Middle of list? */
+ for (t = timeouts; t -> next; t = t -> next) {
+ if (t -> next -> when > q -> when) {
+ q -> next = t -> next;
+ t -> next = q;
+ return;
+ }
+ }
+
+ /* End of list. */
+ t -> next = q;
+ q -> next = (struct timeout *)0;
+}
+
+void cancel_timeout (where, what)
+ void (*where) PROTO ((void *));
+ void *what;
+{
+ struct timeout *t, *q;
+
+ /* Look for this timeout on the list, and unlink it if we find it. */
+ t = (struct timeout *)0;
+ for (q = timeouts; q; q = q -> next) {
+ if (q -> func == where && q -> what == what) {
+ if (t)
+ t -> next = q -> next;
+ else
+ timeouts = q -> next;
+ break;
+ }
+ t = q;
+ }
+
+ /* If we found the timeout, put it on the free list. */
+ if (q) {
+ q -> next = free_timeouts;
+ free_timeouts = q;
+ }
+}
+
+/* Add a protocol to the list of protocols... */
+void add_protocol (name, fd, handler, local)
+ char *name;
+ int fd;
+ void (*handler) PROTO ((struct protocol *));
+ void *local;
+{
+ struct protocol *p;
+
+ p = (struct protocol *)malloc (sizeof *p);
+ if (!p)
+ error ("can't allocate protocol struct for %s", name);
+
+ p -> fd = fd;
+ p -> handler = handler;
+ p -> local = local;
+
+ p -> next = protocols;
+ protocols = p;
+}
+
+void remove_protocol (proto)
+ struct protocol *proto;
+{
+ struct protocol *p, *next, *prev;
+
+ prev = (struct protocol *)0;
+ for (p = protocols; p; p = next) {
+ next = p -> next;
+ if (p == proto) {
+ if (prev)
+ prev -> next = p -> next;
+ else
+ protocols = p -> next;
+ free (p);
+ }
+ }
+}
diff --git a/contrib/isc-dhcp/common/lpf.c b/contrib/isc-dhcp/common/lpf.c
new file mode 100644
index 000000000000..7c6ff74d628e
--- /dev/null
+++ b/contrib/isc-dhcp/common/lpf.c
@@ -0,0 +1,287 @@
+/* lpf.c
+
+ Linux packet filter code, contributed by Brian Murrel at Interlinx
+ Support Services in Vancouver, B.C. */
+
+/*
+ * Copyright (c) 1995, 1996, 1998, 1999
+ * The Internet Software Consortium. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of The Internet Software Consortium nor the names
+ * of its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
+ * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This software has been written for the Internet Software Consortium
+ * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
+ * Enterprises. To learn more about the Internet Software Consortium,
+ * see ``http://www.vix.com/isc''. To learn more about Vixie
+ * Enterprises, see ``http://www.vix.com''.
+ */
+
+#ifndef lint
+static char copyright[] =
+"$Id: lpf.c,v 1.1.2.4 1999/02/09 04:51:05 mellon Exp $ Copyright (c) 1995, 1996, 1998, 1999 The Internet Software Consortium. All rights reserved.\n";
+#endif /* not lint */
+
+#include "dhcpd.h"
+#if defined (USE_LPF_SEND) || defined (USE_LPF_RECEIVE)
+#include <sys/ioctl.h>
+#include <sys/uio.h>
+
+#include <asm/types.h>
+#include <linux/filter.h>
+#include <linux/if_ether.h>
+#include <netinet/in_systm.h>
+#include "includes/netinet/ip.h"
+#include "includes/netinet/udp.h"
+#include "includes/netinet/if_ether.h"
+
+/* Reinitializes the specified interface after an address change. This
+ is not required for packet-filter APIs. */
+
+#ifdef USE_LPF_SEND
+void if_reinitialize_send (info)
+ struct interface_info *info;
+{
+}
+#endif
+
+#ifdef USE_LPF_RECEIVE
+void if_reinitialize_receive (info)
+ struct interface_info *info;
+{
+}
+#endif
+
+/* Called by get_interface_list for each interface that's discovered.
+ Opens a packet filter for each interface and adds it to the select
+ mask. */
+
+int if_register_lpf (info)
+ struct interface_info *info;
+{
+ int sock;
+ char filename[50];
+ int b;
+ struct sockaddr sa;
+
+ /* Make an LPF socket. */
+ if ((sock = socket(PF_PACKET, SOCK_PACKET, htons(ETH_P_ALL))) < 0) {
+ if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT ||
+ errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT ||
+ errno == EAFNOSUPPORT)
+ error ("socket: %m - make sure %s %s!",
+ "CONFIG_PACKET and CONFIG_FILTER are defined",
+ "in your kernel configuration");
+ error("Open a socket for LPF: %m");
+ }
+
+ /* Bind to the interface name */
+ memset (&sa, 0, sizeof sa);
+ sa.sa_family = AF_PACKET;
+ strncpy (sa.sa_data, (const char *)info -> ifp, sizeof sa.sa_data);
+ if (bind (sock, &sa, sizeof sa)) {
+ if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT ||
+ errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT ||
+ errno == EAFNOSUPPORT)
+ error ("socket: %m - make sure %s %s!",
+ "CONFIG_PACKET and CONFIG_FILTER are defined",
+ "in your kernel configuration");
+ error("Bind socket to interface: %m");
+ }
+
+ return sock;
+}
+#endif /* USE_LPF_SEND || USE_LPF_RECEIVE */
+
+#ifdef USE_LPF_SEND
+void if_register_send (info)
+ struct interface_info *info;
+{
+ /* If we're using the lpf API for sending and receiving,
+ we don't need to register this interface twice. */
+#ifndef USE_LPF_RECEIVE
+ info -> wfdesc = if_register_lpf (info, interface);
+#else
+ info -> wfdesc = info -> rfdesc;
+#endif
+ if (!quiet_interface_discovery)
+ note ("Sending on LPF/%s/%s/%s",
+ info -> name,
+ print_hw_addr (info -> hw_address.htype,
+ info -> hw_address.hlen,
+ info -> hw_address.haddr),
+ (info -> shared_network ?
+ info -> shared_network -> name : "unattached"));
+}
+#endif /* USE_LPF_SEND */
+
+#ifdef USE_LPF_RECEIVE
+/* Defined in bpf.c. We can't extern these in dhcpd.h without pulling
+ in bpf includes... */
+extern struct sock_filter dhcp_bpf_filter [];
+extern int dhcp_bpf_filter_len;
+
+void if_register_receive (info)
+ struct interface_info *info;
+{
+ struct sock_fprog p;
+
+ /* Open a LPF device and hang it on this interface... */
+ info -> rfdesc = if_register_lpf (info);
+
+ /* Set up the bpf filter program structure. This is defined in
+ bpf.c */
+ p.len = dhcp_bpf_filter_len;
+ p.filter = dhcp_bpf_filter;
+
+ /* Patch the server port into the LPF program...
+ XXX changes to filter program may require changes
+ to the insn number(s) used below! XXX */
+ dhcp_bpf_filter [8].k = ntohs (local_port);
+
+ if (setsockopt (info -> rfdesc, SOL_SOCKET, SO_ATTACH_FILTER, &p,
+ sizeof p) < 0) {
+ if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT ||
+ errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT ||
+ errno == EAFNOSUPPORT)
+ error ("socket: %m - make sure %s %s!",
+ "CONFIG_PACKET and CONFIG_FILTER are defined",
+ "in your kernel configuration");
+ error ("Can't install packet filter program: %m");
+ }
+ if (!quiet_interface_discovery)
+ note ("Listening on LPF/%s/%s/%s",
+ info -> name,
+ print_hw_addr (info -> hw_address.htype,
+ info -> hw_address.hlen,
+ info -> hw_address.haddr),
+ (info -> shared_network ?
+ info -> shared_network -> name : "unattached"));
+}
+#endif /* USE_LPF_RECEIVE */
+
+#ifdef USE_LPF_SEND
+ssize_t send_packet (interface, packet, raw, len, from, to, hto)
+ struct interface_info *interface;
+ struct packet *packet;
+ struct dhcp_packet *raw;
+ size_t len;
+ struct in_addr from;
+ struct sockaddr_in *to;
+ struct hardware *hto;
+{
+ int bufp = 0;
+ unsigned char buf [1500];
+ struct sockaddr sa;
+
+ if (!strcmp (interface -> name, "fallback"))
+ return send_fallback (interface, packet, raw,
+ len, from, to, hto);
+
+ /* Assemble the headers... */
+ assemble_hw_header (interface, buf, &bufp, hto);
+ assemble_udp_ip_header (interface, buf, &bufp, from.s_addr,
+ to -> sin_addr.s_addr, to -> sin_port,
+ (unsigned char *)raw, len);
+ memcpy (buf + bufp, raw, len);
+
+ /* For some reason, SOCK_PACKET sockets can't be connected,
+ so we have to do a sentdo every time. */
+ memset (&sa, 0, sizeof sa);
+ sa.sa_family = AF_PACKET;
+ strncpy (sa.sa_data,
+ (const char *)interface -> ifp, sizeof sa.sa_data);
+
+ return sendto (interface -> wfdesc, buf, bufp + len, 0,
+ &sa, sizeof sa);
+}
+#endif /* USE_LPF_SEND */
+
+#ifdef USE_LPF_RECEIVE
+ssize_t receive_packet (interface, buf, len, from, hfrom)
+ struct interface_info *interface;
+ unsigned char *buf;
+ size_t len;
+ struct sockaddr_in *from;
+ struct hardware *hfrom;
+{
+ int nread;
+ int length = 0;
+ int offset = 0;
+ unsigned char ibuf [1500];
+ int bufix = 0;
+
+ length = read (interface -> rfdesc, ibuf, sizeof ibuf);
+ if (length <= 0)
+ return length;
+
+ bufix = 0;
+ /* Decode the physical header... */
+ offset = decode_hw_header (interface, ibuf, bufix, hfrom);
+
+ /* If a physical layer checksum failed (dunno of any
+ physical layer that supports this, but WTH), skip this
+ packet. */
+ if (offset < 0) {
+ return 0;
+ }
+
+ bufix += offset;
+ length -= offset;
+
+ /* Decode the IP and UDP headers... */
+ offset = decode_udp_ip_header (interface, ibuf, bufix,
+ from, (unsigned char *)0, length);
+
+ /* If the IP or UDP checksum was bad, skip the packet... */
+ if (offset < 0)
+ return 0;
+
+ bufix += offset;
+ length -= offset;
+
+ /* Copy out the data in the packet... */
+ memcpy (buf, &ibuf [bufix], length);
+ return length;
+}
+
+int can_unicast_without_arp ()
+{
+ return 1;
+}
+
+void maybe_setup_fallback ()
+{
+ struct interface_info *fbi;
+ fbi = setup_fallback ();
+ if (fbi) {
+ if_register_fallback (fbi);
+ add_protocol ("fallback", fallback_interface -> wfdesc,
+ fallback_discard, fallback_interface);
+ }
+}
+#endif
diff --git a/contrib/isc-dhcp/common/memory.c b/contrib/isc-dhcp/common/memory.c
new file mode 100644
index 000000000000..871fe0772d4a
--- /dev/null
+++ b/contrib/isc-dhcp/common/memory.c
@@ -0,0 +1,941 @@
+/* memory.c
+
+ Memory-resident database... */
+
+/*
+ * Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of The Internet Software Consortium nor the names
+ * of its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
+ * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This software has been written for the Internet Software Consortium
+ * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
+ * Enterprises. To learn more about the Internet Software Consortium,
+ * see ``http://www.vix.com/isc''. To learn more about Vixie
+ * Enterprises, see ``http://www.vix.com''.
+ */
+
+#ifndef lint
+static char copyright[] =
+"$Id: memory.c,v 1.35.2.3 1998/11/24 22:32:43 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium. All rights reserved.\n";
+#endif /* not lint */
+
+#include "dhcpd.h"
+
+static struct subnet *subnets;
+static struct shared_network *shared_networks;
+static struct hash_table *host_hw_addr_hash;
+static struct hash_table *host_uid_hash;
+static struct hash_table *lease_uid_hash;
+static struct hash_table *lease_ip_addr_hash;
+static struct hash_table *lease_hw_addr_hash;
+static struct lease *dangling_leases;
+
+static struct hash_table *vendor_class_hash;
+static struct hash_table *user_class_hash;
+
+void enter_host (hd)
+ struct host_decl *hd;
+{
+ struct host_decl *hp = (struct host_decl *)0;
+ struct host_decl *np = (struct host_decl *)0;
+
+ hd -> n_ipaddr = (struct host_decl *)0;
+
+ if (hd -> interface.hlen) {
+ if (!host_hw_addr_hash)
+ host_hw_addr_hash = new_hash ();
+ else
+ hp = (struct host_decl *)
+ hash_lookup (host_hw_addr_hash,
+ hd -> interface.haddr,
+ hd -> interface.hlen);
+
+ /* If there isn't already a host decl matching this
+ address, add it to the hash table. */
+ if (!hp)
+ add_hash (host_hw_addr_hash,
+ hd -> interface.haddr, hd -> interface.hlen,
+ (unsigned char *)hd);
+ }
+
+ /* If there was already a host declaration for this hardware
+ address, add this one to the end of the list. */
+
+ if (hp) {
+ for (np = hp; np -> n_ipaddr; np = np -> n_ipaddr)
+ ;
+ np -> n_ipaddr = hd;
+ }
+
+ if (hd -> group -> options [DHO_DHCP_CLIENT_IDENTIFIER]) {
+ if (!tree_evaluate (hd -> group -> options
+ [DHO_DHCP_CLIENT_IDENTIFIER]))
+ return;
+
+ /* If there's no uid hash, make one; otherwise, see if
+ there's already an entry in the hash for this host. */
+ if (!host_uid_hash) {
+ host_uid_hash = new_hash ();
+ hp = (struct host_decl *)0;
+ } else
+ hp = (struct host_decl *) hash_lookup
+ (host_uid_hash,
+ hd -> group -> options
+ [DHO_DHCP_CLIENT_IDENTIFIER] -> value,
+ hd -> group -> options
+ [DHO_DHCP_CLIENT_IDENTIFIER] -> len);
+
+ /* If there's already a host declaration for this
+ client identifier, add this one to the end of the
+ list. Otherwise, add it to the hash table. */
+ if (hp) {
+ /* Don't link it in twice... */
+ if (!np) {
+ for (np = hp; np -> n_ipaddr;
+ np = np -> n_ipaddr)
+ ;
+ np -> n_ipaddr = hd;
+ }
+ } else {
+ add_hash (host_uid_hash,
+ hd -> group -> options
+ [DHO_DHCP_CLIENT_IDENTIFIER] -> value,
+ hd -> group -> options
+ [DHO_DHCP_CLIENT_IDENTIFIER] -> len,
+ (unsigned char *)hd);
+ }
+ }
+}
+
+struct host_decl *find_hosts_by_haddr (htype, haddr, hlen)
+ int htype;
+ unsigned char *haddr;
+ int hlen;
+{
+ struct host_decl *foo;
+
+ foo = (struct host_decl *)hash_lookup (host_hw_addr_hash,
+ haddr, hlen);
+ return foo;
+}
+
+struct host_decl *find_hosts_by_uid (data, len)
+ unsigned char *data;
+ int len;
+{
+ struct host_decl *foo;
+
+ foo = (struct host_decl *)hash_lookup (host_uid_hash, data, len);
+ return foo;
+}
+
+/* More than one host_decl can be returned by find_hosts_by_haddr or
+ find_hosts_by_uid, and each host_decl can have multiple addresses.
+ Loop through the list of hosts, and then for each host, through the
+ list of addresses, looking for an address that's in the same shared
+ network as the one specified. Store the matching address through
+ the addr pointer, update the host pointer to point at the host_decl
+ that matched, and return the subnet that matched. */
+
+struct subnet *find_host_for_network (host, addr, share)
+ struct host_decl **host;
+ struct iaddr *addr;
+ struct shared_network *share;
+{
+ int i;
+ struct subnet *subnet;
+ struct iaddr ip_address;
+ struct host_decl *hp;
+
+ for (hp = *host; hp; hp = hp -> n_ipaddr) {
+ if (!hp -> fixed_addr || !tree_evaluate (hp -> fixed_addr))
+ continue;
+ for (i = 0; i < hp -> fixed_addr -> len; i += 4) {
+ ip_address.len = 4;
+ memcpy (ip_address.iabuf,
+ hp -> fixed_addr -> value + i, 4);
+ subnet = find_grouped_subnet (share, ip_address);
+ if (subnet) {
+ *addr = ip_address;
+ *host = hp;
+ return subnet;
+ }
+ }
+ }
+ return (struct subnet *)0;
+}
+
+void new_address_range (low, high, subnet, dynamic)
+ struct iaddr low, high;
+ struct subnet *subnet;
+ int dynamic;
+{
+ struct lease *address_range, *lp, *plp;
+ struct iaddr net;
+ int min, max, i;
+ char lowbuf [16], highbuf [16], netbuf [16];
+ struct shared_network *share = subnet -> shared_network;
+ struct hostent *h;
+ struct in_addr ia;
+
+ /* All subnets should have attached shared network structures. */
+ if (!share) {
+ strcpy (netbuf, piaddr (subnet -> net));
+ error ("No shared network for network %s (%s)",
+ netbuf, piaddr (subnet -> netmask));
+ }
+
+ /* Initialize the hash table if it hasn't been done yet. */
+ if (!lease_uid_hash)
+ lease_uid_hash = new_hash ();
+ if (!lease_ip_addr_hash)
+ lease_ip_addr_hash = new_hash ();
+ if (!lease_hw_addr_hash)
+ lease_hw_addr_hash = new_hash ();
+
+ /* Make sure that high and low addresses are in same subnet. */
+ net = subnet_number (low, subnet -> netmask);
+ if (!addr_eq (net, subnet_number (high, subnet -> netmask))) {
+ strcpy (lowbuf, piaddr (low));
+ strcpy (highbuf, piaddr (high));
+ strcpy (netbuf, piaddr (subnet -> netmask));
+ error ("Address range %s to %s, netmask %s spans %s!",
+ lowbuf, highbuf, netbuf, "multiple subnets");
+ }
+
+ /* Make sure that the addresses are on the correct subnet. */
+ if (!addr_eq (net, subnet -> net)) {
+ strcpy (lowbuf, piaddr (low));
+ strcpy (highbuf, piaddr (high));
+ strcpy (netbuf, piaddr (subnet -> netmask));
+ error ("Address range %s to %s not on net %s/%s!",
+ lowbuf, highbuf, piaddr (subnet -> net), netbuf);
+ }
+
+ /* Get the high and low host addresses... */
+ max = host_addr (high, subnet -> netmask);
+ min = host_addr (low, subnet -> netmask);
+
+ /* Allow range to be specified high-to-low as well as low-to-high. */
+ if (min > max) {
+ max = min;
+ min = host_addr (high, subnet -> netmask);
+ }
+
+ /* Get a lease structure for each address in the range. */
+ address_range = new_leases (max - min + 1, "new_address_range");
+ if (!address_range) {
+ strcpy (lowbuf, piaddr (low));
+ strcpy (highbuf, piaddr (high));
+ error ("No memory for address range %s-%s.", lowbuf, highbuf);
+ }
+ memset (address_range, 0, (sizeof *address_range) * (max - min + 1));
+
+ /* Fill in the last lease if it hasn't been already... */
+ if (!share -> last_lease) {
+ share -> last_lease = &address_range [0];
+ }
+
+ /* Fill out the lease structures with some minimal information. */
+ for (i = 0; i < max - min + 1; i++) {
+ address_range [i].ip_addr =
+ ip_addr (subnet -> net, subnet -> netmask, i + min);
+ address_range [i].starts =
+ address_range [i].timestamp = MIN_TIME;
+ address_range [i].ends = MIN_TIME;
+ address_range [i].subnet = subnet;
+ address_range [i].shared_network = share;
+ address_range [i].flags = dynamic ? DYNAMIC_BOOTP_OK : 0;
+
+ memcpy (&ia, address_range [i].ip_addr.iabuf, 4);
+
+ if (subnet -> group -> get_lease_hostnames) {
+ h = gethostbyaddr ((char *)&ia, sizeof ia, AF_INET);
+ if (!h)
+ warn ("No hostname for %s", inet_ntoa (ia));
+ else {
+ address_range [i].hostname =
+ malloc (strlen (h -> h_name) + 1);
+ if (!address_range [i].hostname)
+ error ("no memory for hostname %s.",
+ h -> h_name);
+ strcpy (address_range [i].hostname,
+ h -> h_name);
+ }
+ }
+
+ /* Link this entry into the list. */
+ address_range [i].next = share -> leases;
+ address_range [i].prev = (struct lease *)0;
+ share -> leases = &address_range [i];
+ if (address_range [i].next)
+ address_range [i].next -> prev = share -> leases;
+ add_hash (lease_ip_addr_hash,
+ address_range [i].ip_addr.iabuf,
+ address_range [i].ip_addr.len,
+ (unsigned char *)&address_range [i]);
+ }
+
+ /* Find out if any dangling leases are in range... */
+ plp = (struct lease *)0;
+ for (lp = dangling_leases; lp; lp = lp -> next) {
+ struct iaddr lnet;
+ int lhost;
+
+ lnet = subnet_number (lp -> ip_addr, subnet -> netmask);
+ lhost = host_addr (lp -> ip_addr, subnet -> netmask);
+
+ /* If it's in range, fill in the real lease structure with
+ the dangling lease's values, and remove the lease from
+ the list of dangling leases. */
+ if (addr_eq (lnet, subnet -> net) &&
+ lhost >= i && lhost <= max) {
+ if (plp) {
+ plp -> next = lp -> next;
+ } else {
+ dangling_leases = lp -> next;
+ }
+ lp -> next = (struct lease *)0;
+ address_range [lhost - i].hostname = lp -> hostname;
+ address_range [lhost - i].client_hostname =
+ lp -> client_hostname;
+ supersede_lease (&address_range [lhost - i], lp, 0);
+ free_lease (lp, "new_address_range");
+ } else
+ plp = lp;
+ }
+}
+
+struct subnet *find_subnet (addr)
+ struct iaddr addr;
+{
+ struct subnet *rv;
+
+ for (rv = subnets; rv; rv = rv -> next_subnet) {
+ if (addr_eq (subnet_number (addr, rv -> netmask), rv -> net))
+ return rv;
+ }
+ return (struct subnet *)0;
+}
+
+struct subnet *find_grouped_subnet (share, addr)
+ struct shared_network *share;
+ struct iaddr addr;
+{
+ struct subnet *rv;
+
+ for (rv = share -> subnets; rv; rv = rv -> next_sibling) {
+ if (addr_eq (subnet_number (addr, rv -> netmask), rv -> net))
+ return rv;
+ }
+ return (struct subnet *)0;
+}
+
+int subnet_inner_than (subnet, scan, warnp)
+ struct subnet *subnet, *scan;
+ int warnp;
+{
+ if (addr_eq (subnet_number (subnet -> net, scan -> netmask),
+ scan -> net) ||
+ addr_eq (subnet_number (scan -> net, subnet -> netmask),
+ subnet -> net)) {
+ char n1buf [16];
+ int i, j;
+ for (i = 0; i < 32; i++)
+ if (subnet -> netmask.iabuf [3 - (i >> 3)]
+ & (1 << (i & 7)))
+ break;
+ for (j = 0; j < 32; j++)
+ if (scan -> netmask.iabuf [3 - (j >> 3)] &
+ (1 << (j & 7)))
+ break;
+ strcpy (n1buf, piaddr (subnet -> net));
+ if (warnp)
+ warn ("%ssubnet %s/%d conflicts with subnet %s/%d",
+ "Warning: ", n1buf, 32 - i,
+ piaddr (scan -> net), 32 - j);
+ if (i < j)
+ return 1;
+ }
+ return 0;
+}
+
+/* Enter a new subnet into the subnet list. */
+
+void enter_subnet (subnet)
+ struct subnet *subnet;
+{
+ struct subnet *scan, *prev = (struct subnet *)0;
+
+ /* Check for duplicates... */
+ for (scan = subnets; scan; scan = scan -> next_subnet) {
+ /* When we find a conflict, make sure that the
+ subnet with the narrowest subnet mask comes
+ first. */
+ if (subnet_inner_than (subnet, scan, 1)) {
+ if (prev) {
+ prev -> next_subnet = subnet;
+ } else
+ subnets = subnet;
+ subnet -> next_subnet = scan;
+ return;
+ }
+ prev = scan;
+ }
+
+ /* XXX use the BSD radix tree code instead of a linked list. */
+ subnet -> next_subnet = subnets;
+ subnets = subnet;
+}
+
+/* Enter a new shared network into the shared network list. */
+
+void enter_shared_network (share)
+ struct shared_network *share;
+{
+ /* XXX Sort the nets into a balanced tree to make searching quicker. */
+ share -> next = shared_networks;
+ shared_networks = share;
+}
+
+/* Enter a lease into the system. This is called by the parser each
+ time it reads in a new lease. If the subnet for that lease has
+ already been read in (usually the case), just update that lease;
+ otherwise, allocate temporary storage for the lease and keep it around
+ until we're done reading in the config file. */
+
+void enter_lease (lease)
+ struct lease *lease;
+{
+ struct lease *comp = find_lease_by_ip_addr (lease -> ip_addr);
+
+ /* If we don't have a place for this lease yet, save it for
+ later. */
+ if (!comp) {
+ comp = new_lease ("enter_lease");
+ if (!comp) {
+ error ("No memory for lease %s\n",
+ piaddr (lease -> ip_addr));
+ }
+ *comp = *lease;
+ comp -> next = dangling_leases;
+ comp -> prev = (struct lease *)0;
+ dangling_leases = comp;
+ } else {
+ /* Record the hostname information in the lease. */
+ comp -> hostname = lease -> hostname;
+ comp -> client_hostname = lease -> client_hostname;
+ supersede_lease (comp, lease, 0);
+ }
+}
+
+/* Replace the data in an existing lease with the data in a new lease;
+ adjust hash tables to suit, and insertion sort the lease into the
+ list of leases by expiry time so that we can always find the oldest
+ lease. */
+
+int supersede_lease (comp, lease, commit)
+ struct lease *comp, *lease;
+ int commit;
+{
+ int enter_uid = 0;
+ int enter_hwaddr = 0;
+ struct lease *lp;
+
+ /* Static leases are not currently kept in the database... */
+ if (lease -> flags & STATIC_LEASE)
+ return 1;
+
+ /* If the existing lease hasn't expired and has a different
+ unique identifier or, if it doesn't have a unique
+ identifier, a different hardware address, then the two
+ leases are in conflict. If the existing lease has a uid
+ and the new one doesn't, but they both have the same
+ hardware address, and dynamic bootp is allowed on this
+ lease, then we allow that, in case a dynamic BOOTP lease is
+ requested *after* a DHCP lease has been assigned. */
+
+ if (!(lease -> flags & ABANDONED_LEASE) &&
+ comp -> ends > cur_time &&
+ (((comp -> uid && lease -> uid) &&
+ (comp -> uid_len != lease -> uid_len ||
+ memcmp (comp -> uid, lease -> uid, comp -> uid_len))) ||
+ (!comp -> uid &&
+ ((comp -> hardware_addr.htype !=
+ lease -> hardware_addr.htype) ||
+ (comp -> hardware_addr.hlen !=
+ lease -> hardware_addr.hlen) ||
+ memcmp (comp -> hardware_addr.haddr,
+ lease -> hardware_addr.haddr,
+ comp -> hardware_addr.hlen))))) {
+ warn ("Lease conflict at %s",
+ piaddr (comp -> ip_addr));
+ return 0;
+ } else {
+ /* If there's a Unique ID, dissociate it from the hash
+ table and free it if necessary. */
+ if (comp -> uid) {
+ uid_hash_delete (comp);
+ enter_uid = 1;
+ if (comp -> uid != &comp -> uid_buf [0]) {
+ free (comp -> uid);
+ comp -> uid_max = 0;
+ comp -> uid_len = 0;
+ }
+ comp -> uid = (unsigned char *)0;
+ } else
+ enter_uid = 1;
+
+ if (comp -> hardware_addr.htype &&
+ ((comp -> hardware_addr.hlen !=
+ lease -> hardware_addr.hlen) ||
+ (comp -> hardware_addr.htype !=
+ lease -> hardware_addr.htype) ||
+ memcmp (comp -> hardware_addr.haddr,
+ lease -> hardware_addr.haddr,
+ comp -> hardware_addr.hlen))) {
+ hw_hash_delete (comp);
+ enter_hwaddr = 1;
+ } else if (!comp -> hardware_addr.htype)
+ enter_hwaddr = 1;
+
+ /* Copy the data files, but not the linkages. */
+ comp -> starts = lease -> starts;
+ comp -> timestamp = lease -> timestamp;
+ if (lease -> uid) {
+ if (lease -> uid_len < sizeof (lease -> uid_buf)) {
+ memcpy (comp -> uid_buf,
+ lease -> uid, lease -> uid_len);
+ comp -> uid = &comp -> uid_buf [0];
+ comp -> uid_max = sizeof comp -> uid_buf;
+ } else if (lease -> uid != &lease -> uid_buf [0]) {
+ comp -> uid = lease -> uid;
+ comp -> uid_max = lease -> uid_max;
+ lease -> uid = (unsigned char *)0;
+ lease -> uid_max = 0;
+ } else {
+ error ("corrupt lease uid."); /* XXX */
+ }
+ } else {
+ comp -> uid = (unsigned char *)0;
+ comp -> uid_max = 0;
+ }
+ comp -> uid_len = lease -> uid_len;
+ comp -> host = lease -> host;
+ comp -> hardware_addr = lease -> hardware_addr;
+ comp -> flags = ((lease -> flags & ~PERSISTENT_FLAGS) |
+ (comp -> flags & ~EPHEMERAL_FLAGS));
+
+ /* Record the lease in the uid hash if necessary. */
+ if (enter_uid && lease -> uid) {
+ uid_hash_add (comp);
+ }
+
+ /* Record it in the hardware address hash if necessary. */
+ if (enter_hwaddr && lease -> hardware_addr.htype) {
+ hw_hash_add (comp);
+ }
+
+ /* Remove the lease from its current place in the
+ timeout sequence. */
+ if (comp -> prev) {
+ comp -> prev -> next = comp -> next;
+ } else {
+ comp -> shared_network -> leases = comp -> next;
+ }
+ if (comp -> next) {
+ comp -> next -> prev = comp -> prev;
+ }
+ if (comp -> shared_network -> last_lease == comp) {
+ comp -> shared_network -> last_lease = comp -> prev;
+ }
+
+ /* Find the last insertion point... */
+ if (comp == comp -> shared_network -> insertion_point ||
+ !comp -> shared_network -> insertion_point) {
+ lp = comp -> shared_network -> leases;
+ } else {
+ lp = comp -> shared_network -> insertion_point;
+ }
+
+ if (!lp) {
+ /* Nothing on the list yet? Just make comp the
+ head of the list. */
+ comp -> shared_network -> leases = comp;
+ comp -> shared_network -> last_lease = comp;
+ } else if (lp -> ends > lease -> ends) {
+ /* Skip down the list until we run out of list
+ or find a place for comp. */
+ while (lp -> next && lp -> ends > lease -> ends) {
+ lp = lp -> next;
+ }
+ if (lp -> ends > lease -> ends) {
+ /* If we ran out of list, put comp
+ at the end. */
+ lp -> next = comp;
+ comp -> prev = lp;
+ comp -> next = (struct lease *)0;
+ comp -> shared_network -> last_lease = comp;
+ } else {
+ /* If we didn't, put it between lp and
+ the previous item on the list. */
+ if ((comp -> prev = lp -> prev))
+ comp -> prev -> next = comp;
+ comp -> next = lp;
+ lp -> prev = comp;
+ }
+ } else {
+ /* Skip up the list until we run out of list
+ or find a place for comp. */
+ while (lp -> prev && lp -> ends < lease -> ends) {
+ lp = lp -> prev;
+ }
+ if (lp -> ends < lease -> ends) {
+ /* If we ran out of list, put comp
+ at the beginning. */
+ lp -> prev = comp;
+ comp -> next = lp;
+ comp -> prev = (struct lease *)0;
+ comp -> shared_network -> leases = comp;
+ } else {
+ /* If we didn't, put it between lp and
+ the next item on the list. */
+ if ((comp -> next = lp -> next))
+ comp -> next -> prev = comp;
+ comp -> prev = lp;
+ lp -> next = comp;
+ }
+ }
+ comp -> shared_network -> insertion_point = comp;
+ comp -> ends = lease -> ends;
+ }
+
+ /* Return zero if we didn't commit the lease to permanent storage;
+ nonzero if we did. */
+ return commit && write_lease (comp) && commit_leases ();
+}
+
+/* Release the specified lease and re-hash it as appropriate. */
+
+void release_lease (lease)
+ struct lease *lease;
+{
+ struct lease lt;
+
+ lt = *lease;
+ if (lt.ends > cur_time) {
+ lt.ends = cur_time;
+ supersede_lease (lease, &lt, 1);
+ }
+}
+
+/* Abandon the specified lease (set its timeout to infinity and its
+ particulars to zero, and re-hash it as appropriate. */
+
+void abandon_lease (lease, message)
+ struct lease *lease;
+ char *message;
+{
+ struct lease lt;
+
+ lease -> flags |= ABANDONED_LEASE;
+ lt = *lease;
+ lt.ends = cur_time;
+ warn ("Abandoning IP address %s: %s",
+ piaddr (lease -> ip_addr), message);
+ lt.hardware_addr.htype = 0;
+ lt.hardware_addr.hlen = 0;
+ lt.uid = (unsigned char *)0;
+ lt.uid_len = 0;
+ supersede_lease (lease, &lt, 1);
+}
+
+/* Locate the lease associated with a given IP address... */
+
+struct lease *find_lease_by_ip_addr (addr)
+ struct iaddr addr;
+{
+ struct lease *lease = (struct lease *)hash_lookup (lease_ip_addr_hash,
+ addr.iabuf,
+ addr.len);
+ return lease;
+}
+
+struct lease *find_lease_by_uid (uid, len)
+ unsigned char *uid;
+ int len;
+{
+ struct lease *lease = (struct lease *)hash_lookup (lease_uid_hash,
+ uid, len);
+ return lease;
+}
+
+struct lease *find_lease_by_hw_addr (hwaddr, hwlen)
+ unsigned char *hwaddr;
+ int hwlen;
+{
+ struct lease *lease = (struct lease *)hash_lookup (lease_hw_addr_hash,
+ hwaddr, hwlen);
+ return lease;
+}
+
+/* Add the specified lease to the uid hash. */
+
+void uid_hash_add (lease)
+ struct lease *lease;
+{
+ struct lease *head =
+ find_lease_by_uid (lease -> uid, lease -> uid_len);
+ struct lease *scan;
+
+#ifdef DEBUG
+ if (lease -> n_uid)
+ abort ();
+#endif
+
+ /* If it's not in the hash, just add it. */
+ if (!head)
+ add_hash (lease_uid_hash, lease -> uid,
+ lease -> uid_len, (unsigned char *)lease);
+ else {
+ /* Otherwise, attach it to the end of the list. */
+ for (scan = head; scan -> n_uid; scan = scan -> n_uid)
+#ifdef DEBUG
+ if (scan == lease)
+ abort ()
+#endif
+ ;
+ scan -> n_uid = lease;
+ }
+}
+
+/* Delete the specified lease from the uid hash. */
+
+void uid_hash_delete (lease)
+ struct lease *lease;
+{
+ struct lease *head =
+ find_lease_by_uid (lease -> uid, lease -> uid_len);
+ struct lease *scan;
+
+ /* If it's not in the hash, we have no work to do. */
+ if (!head) {
+ lease -> n_uid = (struct lease *)0;
+ return;
+ }
+
+ /* If the lease we're freeing is at the head of the list,
+ remove the hash table entry and add a new one with the
+ next lease on the list (if there is one). */
+ if (head == lease) {
+ delete_hash_entry (lease_uid_hash,
+ lease -> uid, lease -> uid_len);
+ if (lease -> n_uid)
+ add_hash (lease_uid_hash,
+ lease -> n_uid -> uid,
+ lease -> n_uid -> uid_len,
+ (unsigned char *)(lease -> n_uid));
+ } else {
+ /* Otherwise, look for the lease in the list of leases
+ attached to the hash table entry, and remove it if
+ we find it. */
+ for (scan = head; scan -> n_uid; scan = scan -> n_uid) {
+ if (scan -> n_uid == lease) {
+ scan -> n_uid = scan -> n_uid -> n_uid;
+ break;
+ }
+ }
+ }
+ lease -> n_uid = (struct lease *)0;
+}
+
+/* Add the specified lease to the hardware address hash. */
+
+void hw_hash_add (lease)
+ struct lease *lease;
+{
+ struct lease *head =
+ find_lease_by_hw_addr (lease -> hardware_addr.haddr,
+ lease -> hardware_addr.hlen);
+ struct lease *scan;
+
+ /* If it's not in the hash, just add it. */
+ if (!head)
+ add_hash (lease_hw_addr_hash,
+ lease -> hardware_addr.haddr,
+ lease -> hardware_addr.hlen,
+ (unsigned char *)lease);
+ else {
+ /* Otherwise, attach it to the end of the list. */
+ for (scan = head; scan -> n_hw; scan = scan -> n_hw)
+ ;
+ scan -> n_hw = lease;
+ }
+}
+
+/* Delete the specified lease from the hardware address hash. */
+
+void hw_hash_delete (lease)
+ struct lease *lease;
+{
+ struct lease *head =
+ find_lease_by_hw_addr (lease -> hardware_addr.haddr,
+ lease -> hardware_addr.hlen);
+ struct lease *scan;
+
+ /* If it's not in the hash, we have no work to do. */
+ if (!head) {
+ lease -> n_hw = (struct lease *)0;
+ return;
+ }
+
+ /* If the lease we're freeing is at the head of the list,
+ remove the hash table entry and add a new one with the
+ next lease on the list (if there is one). */
+ if (head == lease) {
+ delete_hash_entry (lease_hw_addr_hash,
+ lease -> hardware_addr.haddr,
+ lease -> hardware_addr.hlen);
+ if (lease -> n_hw)
+ add_hash (lease_hw_addr_hash,
+ lease -> n_hw -> hardware_addr.haddr,
+ lease -> n_hw -> hardware_addr.hlen,
+ (unsigned char *)(lease -> n_hw));
+ } else {
+ /* Otherwise, look for the lease in the list of leases
+ attached to the hash table entry, and remove it if
+ we find it. */
+ for (scan = head; scan -> n_hw; scan = scan -> n_hw) {
+ if (scan -> n_hw == lease) {
+ scan -> n_hw = scan -> n_hw -> n_hw;
+ break;
+ }
+ }
+ }
+ lease -> n_hw = (struct lease *)0;
+}
+
+
+struct class *add_class (type, name)
+ int type;
+ char *name;
+{
+ struct class *class = new_class ("add_class");
+ char *tname = (char *)malloc (strlen (name) + 1);
+
+ if (!vendor_class_hash)
+ vendor_class_hash = new_hash ();
+ if (!user_class_hash)
+ user_class_hash = new_hash ();
+
+ if (!tname || !class || !vendor_class_hash || !user_class_hash)
+ return (struct class *)0;
+
+ memset (class, 0, sizeof *class);
+ strcpy (tname, name);
+ class -> name = tname;
+
+ if (type)
+ add_hash (user_class_hash,
+ (unsigned char *)tname, strlen (tname),
+ (unsigned char *)class);
+ else
+ add_hash (vendor_class_hash,
+ (unsigned char *)tname, strlen (tname),
+ (unsigned char *)class);
+ return class;
+}
+
+struct class *find_class (type, name, len)
+ int type;
+ unsigned char *name;
+ int len;
+{
+ struct class *class =
+ (struct class *)hash_lookup (type
+ ? user_class_hash
+ : vendor_class_hash, name, len);
+ return class;
+}
+
+struct group *clone_group (group, caller)
+ struct group *group;
+ char *caller;
+{
+ struct group *g = new_group (caller);
+ if (!g)
+ error ("%s: can't allocate new group", caller);
+ *g = *group;
+ return g;
+}
+
+/* Write all interesting leases to permanent storage. */
+
+void write_leases ()
+{
+ struct lease *l;
+ struct shared_network *s;
+
+ for (s = shared_networks; s; s = s -> next) {
+ for (l = s -> leases; l; l = l -> next) {
+ if (l -> hardware_addr.hlen ||
+ l -> uid_len ||
+ (l -> flags & ABANDONED_LEASE))
+ if (!write_lease (l))
+ error ("Can't rewrite lease database");
+ }
+ }
+ if (!commit_leases ())
+ error ("Can't commit leases to new database: %m");
+}
+
+void dump_subnets ()
+{
+ struct lease *l;
+ struct shared_network *s;
+ struct subnet *n;
+
+ note ("Subnets:");
+ for (n = subnets; n; n = n -> next_subnet) {
+ debug (" Subnet %s", piaddr (n -> net));
+ debug (" netmask %s",
+ piaddr (n -> netmask));
+ }
+ note ("Shared networks:");
+ for (s = shared_networks; s; s = s -> next) {
+ note (" %s", s -> name);
+ for (l = s -> leases; l; l = l -> next) {
+ print_lease (l);
+ }
+ if (s -> last_lease) {
+ debug (" Last Lease:");
+ print_lease (s -> last_lease);
+ }
+ }
+}
diff --git a/contrib/isc-dhcp/common/nit.c b/contrib/isc-dhcp/common/nit.c
new file mode 100644
index 000000000000..1801bb9f3579
--- /dev/null
+++ b/contrib/isc-dhcp/common/nit.c
@@ -0,0 +1,367 @@
+/* nit.c
+
+ Network Interface Tap (NIT) network interface code, by Ted Lemon
+ with one crucial tidbit of help from Stu Grossmen. */
+
+/*
+ * Copyright (c) 1996 The Internet Software Consortium.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of The Internet Software Consortium nor the names
+ * of its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
+ * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This software has been written for the Internet Software Consortium
+ * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
+ * Enterprises. To learn more about the Internet Software Consortium,
+ * see ``http://www.vix.com/isc''. To learn more about Vixie
+ * Enterprises, see ``http://www.vix.com''. */
+
+#ifndef lint
+static char copyright[] =
+"$Id: nit.c,v 1.15.2.1 1998/12/20 18:27:44 mellon Exp $ Copyright (c) 1996 The Internet Software Consortium. All rights reserved.\n";
+#endif /* not lint */
+
+#include "dhcpd.h"
+#if defined (USE_NIT_SEND) || defined (USE_NIT_RECEIVE)
+#include <sys/ioctl.h>
+#include <sys/uio.h>
+
+#include <sys/time.h>
+#include <net/nit.h>
+#include <net/nit_if.h>
+#include <net/nit_pf.h>
+#include <net/nit_buf.h>
+#include <sys/stropts.h>
+#include <net/packetfilt.h>
+
+#include <netinet/in_systm.h>
+#include "includes/netinet/ip.h"
+#include "includes/netinet/udp.h"
+#include "includes/netinet/if_ether.h"
+
+/* Reinitializes the specified interface after an address change. This
+ is not required for packet-filter APIs. */
+
+#ifdef USE_NIT_SEND
+void if_reinitialize_send (info)
+ struct interface_info *info;
+{
+}
+#endif
+
+#ifdef USE_NIT_RECEIVE
+void if_reinitialize_receive (info)
+ struct interface_info *info;
+{
+}
+#endif
+
+/* Called by get_interface_list for each interface that's discovered.
+ Opens a packet filter for each interface and adds it to the select
+ mask. */
+
+int if_register_nit (info)
+ struct interface_info *info;
+{
+ int sock;
+ char filename[50];
+ struct ifreq ifr;
+ struct strioctl sio;
+
+ /* Open a NIT device */
+ sock = open ("/dev/nit", O_RDWR);
+ if (sock < 0)
+ error ("Can't open NIT device for %s: %m", info -> name);
+
+ /* Set the NIT device to point at this interface. */
+ sio.ic_cmd = NIOCBIND;
+ sio.ic_len = sizeof *(info -> ifp);
+ sio.ic_dp = (char *)(info -> ifp);
+ sio.ic_timout = INFTIM;
+ if (ioctl (sock, I_STR, &sio) < 0)
+ error ("Can't attach interface %s to nit device: %m",
+ info -> name);
+
+ /* Get the low-level address... */
+ sio.ic_cmd = SIOCGIFADDR;
+ sio.ic_len = sizeof ifr;
+ sio.ic_dp = (char *)&ifr;
+ sio.ic_timout = INFTIM;
+ if (ioctl (sock, I_STR, &sio) < 0)
+ error ("Can't get physical layer address for %s: %m",
+ info -> name);
+
+ /* XXX code below assumes ethernet interface! */
+ info -> hw_address.hlen = 6;
+ info -> hw_address.htype = ARPHRD_ETHER;
+ memcpy (info -> hw_address.haddr, ifr.ifr_ifru.ifru_addr.sa_data, 6);
+
+ if (ioctl (sock, I_PUSH, "pf") < 0)
+ error ("Can't push packet filter onto NIT for %s: %m",
+ info -> name);
+
+ return sock;
+}
+#endif /* USE_NIT_SEND || USE_NIT_RECEIVE */
+
+#ifdef USE_NIT_SEND
+void if_register_send (info)
+ struct interface_info *info;
+{
+ /* If we're using the nit API for sending and receiving,
+ we don't need to register this interface twice. */
+#ifndef USE_NIT_RECEIVE
+ struct packetfilt pf;
+ struct strioctl sio;
+
+ info -> wfdesc = if_register_nit (info);
+
+ pf.Pf_Priority = 0;
+ pf.Pf_FilterLen = 1;
+ pf.Pf_Filter [0] = ENF_PUSHZERO;
+
+ /* Set up an NIT filter that rejects everything... */
+ sio.ic_cmd = NIOCSETF;
+ sio.ic_len = sizeof pf;
+ sio.ic_dp = (char *)&pf;
+ sio.ic_timout = INFTIM;
+ if (ioctl (info -> wfdesc, I_STR, &sio) < 0)
+ error ("Can't set NIT filter: %m");
+#else
+ info -> wfdesc = info -> rfdesc;
+#endif
+ if (!quiet_interface_discovery)
+ note ("Sending on NIT/%s/%s",
+ print_hw_addr (info -> hw_address.htype,
+ info -> hw_address.hlen,
+ info -> hw_address.haddr),
+ (info -> shared_network ?
+ info -> shared_network -> name : "unattached"));
+}
+#endif /* USE_NIT_SEND */
+
+#ifdef USE_NIT_RECEIVE
+/* Packet filter program...
+ XXX Changes to the filter program may require changes to the constant
+ offsets used in if_register_send to patch the NIT program! XXX */
+
+void if_register_receive (info)
+ struct interface_info *info;
+{
+ int flag = 1;
+ u_int32_t x;
+ struct packetfilt pf;
+ struct strioctl sio;
+ u_int16_t addr [2];
+ struct timeval t;
+
+ /* Open a NIT device and hang it on this interface... */
+ info -> rfdesc = if_register_nit (info);
+
+ /* Set the snap length to 0, which means always take the whole
+ packet. */
+ x = 0;
+ if (ioctl (info -> rfdesc, NIOCSSNAP, &x) < 0)
+ error ("Can't set NIT snap length on %s: %m", info -> name);
+
+ /* Set the stream to byte stream mode */
+ if (ioctl (info -> rfdesc, I_SRDOPT, RMSGN) != 0)
+ note ("I_SRDOPT failed on %s: %m", info -> name);
+
+#if 0
+ /* Push on the chunker... */
+ if (ioctl (info -> rfdesc, I_PUSH, "nbuf") < 0)
+ error ("Can't push chunker onto NIT STREAM: %m");
+
+ /* Set the timeout to zero. */
+ t.tv_sec = 0;
+ t.tv_usec = 0;
+ if (ioctl (info -> rfdesc, NIOCSTIME, &t) < 0)
+ error ("Can't set chunk timeout: %m");
+#endif
+
+ /* Ask for no header... */
+ x = 0;
+ if (ioctl (info -> rfdesc, NIOCSFLAGS, &x) < 0)
+ error ("Can't set NIT flags on %s: %m", info -> name);
+
+ /* Set up the NIT filter program. */
+ /* XXX Unlike the BPF filter program, this one won't work if the
+ XXX IP packet is fragmented or if there are options on the IP
+ XXX header. */
+ pf.Pf_Priority = 0;
+ pf.Pf_FilterLen = 0;
+
+ pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + 6;
+ pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT + ENF_CAND;
+ pf.Pf_Filter [pf.Pf_FilterLen++] = htons (ETHERTYPE_IP);
+ pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT;
+ pf.Pf_Filter [pf.Pf_FilterLen++] = htons (IPPROTO_UDP);
+ pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + 11;
+ pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT + ENF_AND;
+ pf.Pf_Filter [pf.Pf_FilterLen++] = htons (0xFF);
+ pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_CAND;
+ pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + 18;
+ pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT + ENF_CAND;
+ pf.Pf_Filter [pf.Pf_FilterLen++] = local_port;
+
+ /* Install the filter... */
+ sio.ic_cmd = NIOCSETF;
+ sio.ic_len = sizeof pf;
+ sio.ic_dp = (char *)&pf;
+ sio.ic_timout = INFTIM;
+ if (ioctl (info -> rfdesc, I_STR, &sio) < 0)
+ error ("Can't set NIT filter on %s: %m", info -> name);
+
+ if (!quiet_interface_discovery)
+ note ("Listening on NIT/%s/%s",
+ print_hw_addr (info -> hw_address.htype,
+ info -> hw_address.hlen,
+ info -> hw_address.haddr),
+ (info -> shared_network ?
+ info -> shared_network -> name : "unattached"));
+}
+#endif /* USE_NIT_RECEIVE */
+
+#ifdef USE_NIT_SEND
+ssize_t send_packet (interface, packet, raw, len, from, to, hto)
+ struct interface_info *interface;
+ struct packet *packet;
+ struct dhcp_packet *raw;
+ size_t len;
+ struct in_addr from;
+ struct sockaddr_in *to;
+ struct hardware *hto;
+{
+ int bufp;
+ unsigned char buf [1536 + sizeof (struct sockaddr)];
+ struct sockaddr *junk;
+ struct strbuf ctl, data;
+ int hw_end;
+ struct sockaddr_in foo;
+
+ if (!strcmp (interface -> name, "fallback"))
+ return send_fallback (interface, packet, raw,
+ len, from, to, hto);
+
+ /* Start with the sockaddr struct... */
+ junk = (struct sockaddr *)&buf [0];
+ bufp = ((unsigned char *)&junk -> sa_data [0]) - &buf [0];
+
+ /* Assemble the headers... */
+ assemble_hw_header (interface, buf, &bufp, hto);
+ hw_end = bufp;
+ assemble_udp_ip_header (interface, buf, &bufp, from.s_addr,
+ to -> sin_addr.s_addr, to -> sin_port,
+ raw, len);
+
+ /* Copy the data into the buffer (yuk). */
+ memcpy (buf + bufp, raw, len);
+
+ /* Set up the sockaddr structure... */
+#if USE_SIN_LEN
+ junk -> sa_len = hw_end - 2; /* XXX */
+#endif
+ junk -> sa_family = AF_UNSPEC;
+
+#if 0 /* Already done. */
+ memcpy (junk.sa_data, buf, hw_len);
+#endif
+
+ /* Set up the msg_buf structure... */
+ ctl.buf = (char *)&buf [0];
+ ctl.maxlen = ctl.len = hw_end;
+ data.buf = (char *)&buf [hw_end];
+ data.maxlen = data.len = bufp + len - hw_end;
+
+ return putmsg (interface -> wfdesc, &ctl, &data, 0);
+}
+#endif /* USE_NIT_SEND */
+
+#ifdef USE_NIT_RECEIVE
+ssize_t receive_packet (interface, buf, len, from, hfrom)
+ struct interface_info *interface;
+ unsigned char *buf;
+ size_t len;
+ struct sockaddr_in *from;
+ struct hardware *hfrom;
+{
+ int nread;
+ int length = 0;
+ int offset = 0;
+ unsigned char ibuf [1536];
+ int bufix = 0;
+
+ length = read (interface -> rfdesc, ibuf, sizeof ibuf);
+ if (length <= 0)
+ return length;
+
+ /* Decode the physical header... */
+ offset = decode_hw_header (interface, ibuf, bufix, hfrom);
+
+ /* If a physical layer checksum failed (dunno of any
+ physical layer that supports this, but WTH), skip this
+ packet. */
+ if (offset < 0) {
+ return 0;
+ }
+
+ bufix += offset;
+ length -= offset;
+
+ /* Decode the IP and UDP headers... */
+ offset = decode_udp_ip_header (interface, ibuf, bufix,
+ from, (unsigned char *)0, length);
+
+ /* If the IP or UDP checksum was bad, skip the packet... */
+ if (offset < 0)
+ return 0;
+
+ bufix += offset;
+ length -= offset;
+
+ /* Copy out the data in the packet... */
+ memcpy (buf, &ibuf [bufix], length);
+ return length;
+}
+
+int can_unicast_without_arp ()
+{
+ return 1;
+}
+
+void maybe_setup_fallback ()
+{
+ struct interface_info *fbi;
+ fbi = setup_fallback ();
+ if (fbi) {
+ if_register_fallback (fbi);
+ add_protocol ("fallback", fallback_interface -> wfdesc,
+ fallback_discard, fallback_interface);
+ }
+}
+#endif
diff --git a/contrib/isc-dhcp/common/parse.c b/contrib/isc-dhcp/common/parse.c
new file mode 100644
index 000000000000..d750ec53434d
--- /dev/null
+++ b/contrib/isc-dhcp/common/parse.c
@@ -0,0 +1,649 @@
+/* parse.c
+
+ Common parser code for dhcpd and dhclient. */
+
+/*
+ * Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of The Internet Software Consortium nor the names
+ * of its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
+ * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This software has been written for the Internet Software Consortium
+ * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
+ * Enterprises. To learn more about the Internet Software Consortium,
+ * see ``http://www.vix.com/isc''. To learn more about Vixie
+ * Enterprises, see ``http://www.vix.com''.
+ */
+
+#ifndef lint
+static char copyright[] =
+"$Id: parse.c,v 1.2.2.3 1998/12/22 22:43:22 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium. All rights reserved.\n";
+#endif /* not lint */
+
+#include "dhcpd.h"
+#include "dhctoken.h"
+
+/* Skip to the semicolon ending the current statement. If we encounter
+ braces, the matching closing brace terminates the statement. If we
+ encounter a right brace but haven't encountered a left brace, return
+ leaving the brace in the token buffer for the caller. If we see a
+ semicolon and haven't seen a left brace, return. This lets us skip
+ over:
+
+ statement;
+ statement foo bar { }
+ statement foo bar { statement { } }
+ statement}
+
+ ...et cetera. */
+
+void skip_to_semi (cfile)
+ FILE *cfile;
+{
+ int token;
+ char *val;
+ int brace_count = 0;
+
+ do {
+ token = peek_token (&val, cfile);
+ if (token == RBRACE) {
+ if (brace_count) {
+ token = next_token (&val, cfile);
+ if (!--brace_count)
+ return;
+ } else
+ return;
+ } else if (token == LBRACE) {
+ brace_count++;
+ } else if (token == SEMI && !brace_count) {
+ token = next_token (&val, cfile);
+ return;
+ } else if (token == EOL) {
+ /* EOL only happens when parsing /etc/resolv.conf,
+ and we treat it like a semicolon because the
+ resolv.conf file is line-oriented. */
+ token = next_token (&val, cfile);
+ return;
+ }
+ token = next_token (&val, cfile);
+ } while (token != EOF);
+}
+
+int parse_semi (cfile)
+ FILE *cfile;
+{
+ int token;
+ char *val;
+
+ token = next_token (&val, cfile);
+ if (token != SEMI) {
+ parse_warn ("semicolon expected.");
+ skip_to_semi (cfile);
+ return 0;
+ }
+ return 1;
+}
+
+/* string-parameter :== STRING SEMI */
+
+char *parse_string (cfile)
+ FILE *cfile;
+{
+ char *val;
+ int token;
+ char *s;
+
+ token = next_token (&val, cfile);
+ if (token != STRING) {
+ parse_warn ("filename must be a string");
+ skip_to_semi (cfile);
+ return (char *)0;
+ }
+ s = (char *)malloc (strlen (val) + 1);
+ if (!s)
+ error ("no memory for string %s.", val);
+ strcpy (s, val);
+
+ if (!parse_semi (cfile))
+ return (char *)0;
+ return s;
+}
+
+/* hostname :== identifier | hostname DOT identifier */
+
+char *parse_host_name (cfile)
+ FILE *cfile;
+{
+ char *val;
+ int token;
+ int len = 0;
+ char *s;
+ char *t;
+ pair c = (pair)0;
+
+ /* Read a dotted hostname... */
+ do {
+ /* Read a token, which should be an identifier. */
+ token = next_token (&val, cfile);
+ if (!is_identifier (token) && token != NUMBER) {
+ parse_warn ("expecting an identifier in hostname");
+ skip_to_semi (cfile);
+ return (char *)0;
+ }
+ /* Store this identifier... */
+ if (!(s = (char *)malloc (strlen (val) + 1)))
+ error ("can't allocate temp space for hostname.");
+ strcpy (s, val);
+ c = cons ((caddr_t)s, c);
+ len += strlen (s) + 1;
+ /* Look for a dot; if it's there, keep going, otherwise
+ we're done. */
+ token = peek_token (&val, cfile);
+ if (token == DOT)
+ token = next_token (&val, cfile);
+ } while (token == DOT);
+
+ /* Assemble the hostname together into a string. */
+ if (!(s = (char *)malloc (len)))
+ error ("can't allocate space for hostname.");
+ t = s + len;
+ *--t = 0;
+ while (c) {
+ pair cdr = c -> cdr;
+ int l = strlen ((char *)(c -> car));
+ t -= l;
+ memcpy (t, (char *)(c -> car), l);
+ /* Free up temp space. */
+ free (c -> car);
+ free (c);
+ c = cdr;
+ if (t != s)
+ *--t = '.';
+ }
+ return s;
+}
+
+int parse_ip_addr (cfile, addr)
+ FILE *cfile;
+ struct iaddr *addr;
+{
+ char *val;
+ int token;
+
+ addr -> len = 4;
+ if (parse_numeric_aggregate (cfile, addr -> iabuf,
+ &addr -> len, DOT, 10, 8))
+ return 1;
+ return 0;
+}
+
+/* hardware-parameter :== HARDWARE ETHERNET csns SEMI
+ csns :== NUMBER | csns COLON NUMBER */
+
+void parse_hardware_param (cfile, hardware)
+ FILE *cfile;
+ struct hardware *hardware;
+{
+ char *val;
+ int token;
+ int hlen;
+ unsigned char *t;
+
+ token = next_token (&val, cfile);
+ switch (token) {
+ case ETHERNET:
+ hardware -> htype = HTYPE_ETHER;
+ break;
+ case TOKEN_RING:
+ hardware -> htype = HTYPE_IEEE802;
+ break;
+ case FDDI:
+ hardware -> htype = HTYPE_FDDI;
+ break;
+ default:
+ parse_warn ("expecting a network hardware type");
+ skip_to_semi (cfile);
+ return;
+ }
+
+ /* Parse the hardware address information. Technically,
+ it would make a lot of sense to restrict the length of the
+ data we'll accept here to the length of a particular hardware
+ address type. Unfortunately, there are some broken clients
+ out there that put bogus data in the chaddr buffer, and we accept
+ that data in the lease file rather than simply failing on such
+ clients. Yuck. */
+ hlen = 0;
+ t = parse_numeric_aggregate (cfile, (unsigned char *)0, &hlen,
+ COLON, 16, 8);
+ if (!t)
+ return;
+ if (hlen > sizeof hardware -> haddr) {
+ free (t);
+ parse_warn ("hardware address too long");
+ } else {
+ hardware -> hlen = hlen;
+ memcpy ((unsigned char *)&hardware -> haddr [0],
+ t, hardware -> hlen);
+ if (hlen < sizeof hardware -> haddr)
+ memset (&hardware -> haddr [hlen], 0,
+ (sizeof hardware -> haddr) - hlen);
+ free (t);
+ }
+
+ token = next_token (&val, cfile);
+ if (token != SEMI) {
+ parse_warn ("expecting semicolon.");
+ skip_to_semi (cfile);
+ }
+}
+
+/* lease-time :== NUMBER SEMI */
+
+void parse_lease_time (cfile, timep)
+ FILE *cfile;
+ TIME *timep;
+{
+ char *val;
+ int token;
+
+ token = next_token (&val, cfile);
+ if (token != NUMBER) {
+ parse_warn ("Expecting numeric lease time");
+ skip_to_semi (cfile);
+ return;
+ }
+ convert_num ((unsigned char *)timep, val, 10, 32);
+ /* Unswap the number - convert_num returns stuff in NBO. */
+ *timep = ntohl (*timep); /* XXX */
+
+ parse_semi (cfile);
+}
+
+/* No BNF for numeric aggregates - that's defined by the caller. What
+ this function does is to parse a sequence of numbers seperated by
+ the token specified in seperator. If max is zero, any number of
+ numbers will be parsed; otherwise, exactly max numbers are
+ expected. Base and size tell us how to internalize the numbers
+ once they've been tokenized. */
+
+unsigned char *parse_numeric_aggregate (cfile, buf,
+ max, seperator, base, size)
+ FILE *cfile;
+ unsigned char *buf;
+ int *max;
+ int seperator;
+ int base;
+ int size;
+{
+ char *val;
+ int token;
+ unsigned char *bufp = buf, *s;
+ char *t;
+ int count = 0;
+ pair c = (pair)0;
+
+ if (!bufp && *max) {
+ bufp = (unsigned char *)malloc (*max * size / 8);
+ if (!bufp)
+ error ("can't allocate space for numeric aggregate");
+ } else
+ s = bufp;
+
+ do {
+ if (count) {
+ token = peek_token (&val, cfile);
+ if (token != seperator) {
+ if (!*max)
+ break;
+ if (token != RBRACE && token != LBRACE)
+ token = next_token (&val, cfile);
+ parse_warn ("too few numbers.");
+ if (token != SEMI)
+ skip_to_semi (cfile);
+ return (unsigned char *)0;
+ }
+ token = next_token (&val, cfile);
+ }
+ token = next_token (&val, cfile);
+
+ if (token == EOF) {
+ parse_warn ("unexpected end of file");
+ break;
+ }
+
+ /* Allow NUMBER_OR_NAME if base is 16. */
+ if (token != NUMBER &&
+ (base != 16 || token != NUMBER_OR_NAME)) {
+ parse_warn ("expecting numeric value.");
+ skip_to_semi (cfile);
+ return (unsigned char *)0;
+ }
+ /* If we can, convert the number now; otherwise, build
+ a linked list of all the numbers. */
+ if (s) {
+ convert_num (s, val, base, size);
+ s += size / 8;
+ } else {
+ t = (char *)malloc (strlen (val) + 1);
+ if (!t)
+ error ("no temp space for number.");
+ strcpy (t, val);
+ c = cons (t, c);
+ }
+ } while (++count != *max);
+
+ /* If we had to cons up a list, convert it now. */
+ if (c) {
+ bufp = (unsigned char *)malloc (count * size / 8);
+ if (!bufp)
+ error ("can't allocate space for numeric aggregate.");
+ s = bufp + count - size / 8;
+ *max = count;
+ }
+ while (c) {
+ pair cdr = c -> cdr;
+ convert_num (s, (char *)(c -> car), base, size);
+ s -= size / 8;
+ /* Free up temp space. */
+ free (c -> car);
+ free (c);
+ c = cdr;
+ }
+ return bufp;
+}
+
+void convert_num (buf, str, base, size)
+ unsigned char *buf;
+ char *str;
+ int base;
+ int size;
+{
+ char *ptr = str;
+ int negative = 0;
+ u_int32_t val = 0;
+ int tval;
+ int max;
+
+ if (*ptr == '-') {
+ negative = 1;
+ ++ptr;
+ }
+
+ /* If base wasn't specified, figure it out from the data. */
+ if (!base) {
+ if (ptr [0] == '0') {
+ if (ptr [1] == 'x') {
+ base = 16;
+ ptr += 2;
+ } else if (isascii (ptr [1]) && isdigit (ptr [1])) {
+ base = 8;
+ ptr += 1;
+ } else {
+ base = 10;
+ }
+ } else {
+ base = 10;
+ }
+ }
+
+ do {
+ tval = *ptr++;
+ /* XXX assumes ASCII... */
+ if (tval >= 'a')
+ tval = tval - 'a' + 10;
+ else if (tval >= 'A')
+ tval = tval - 'A' + 10;
+ else if (tval >= '0')
+ tval -= '0';
+ else {
+ warn ("Bogus number: %s.", str);
+ break;
+ }
+ if (tval >= base) {
+ warn ("Bogus number: %s: digit %d not in base %d\n",
+ str, tval, base);
+ break;
+ }
+ val = val * base + tval;
+ } while (*ptr);
+
+ if (negative)
+ max = (1 << (size - 1));
+ else
+ max = (1 << (size - 1)) + ((1 << (size - 1)) - 1);
+ if (val > max) {
+ switch (base) {
+ case 8:
+ warn ("value %s%o exceeds max (%d) for precision.",
+ negative ? "-" : "", val, max);
+ break;
+ case 16:
+ warn ("value %s%x exceeds max (%d) for precision.",
+ negative ? "-" : "", val, max);
+ break;
+ default:
+ warn ("value %s%u exceeds max (%d) for precision.",
+ negative ? "-" : "", val, max);
+ break;
+ }
+ }
+
+ if (negative) {
+ switch (size) {
+ case 8:
+ *buf = -(unsigned long)val;
+ break;
+ case 16:
+ putShort (buf, -(unsigned long)val);
+ break;
+ case 32:
+ putLong (buf, -(unsigned long)val);
+ break;
+ default:
+ warn ("Unexpected integer size: %d\n", size);
+ break;
+ }
+ } else {
+ switch (size) {
+ case 8:
+ *buf = (u_int8_t)val;
+ break;
+ case 16:
+ putUShort (buf, (u_int16_t)val);
+ break;
+ case 32:
+ putULong (buf, val);
+ break;
+ default:
+ warn ("Unexpected integer size: %d\n", size);
+ break;
+ }
+ }
+}
+
+/* date :== NUMBER NUMBER SLASH NUMBER SLASH NUMBER
+ NUMBER COLON NUMBER COLON NUMBER SEMI
+
+ Dates are always in GMT; first number is day of week; next is
+ year/month/day; next is hours:minutes:seconds on a 24-hour
+ clock. */
+
+TIME parse_date (cfile)
+ FILE *cfile;
+{
+ struct tm tm;
+ int guess;
+ char *val;
+ int token;
+ static int months [11] = { 31, 59, 90, 120, 151, 181,
+ 212, 243, 273, 304, 334 };
+
+ /* Day of week... */
+ token = next_token (&val, cfile);
+ if (token != NUMBER) {
+ parse_warn ("numeric day of week expected.");
+ if (token != SEMI)
+ skip_to_semi (cfile);
+ return (TIME)0;
+ }
+ tm.tm_wday = atoi (val);
+
+ /* Year... */
+ token = next_token (&val, cfile);
+ if (token != NUMBER) {
+ parse_warn ("numeric year expected.");
+ if (token != SEMI)
+ skip_to_semi (cfile);
+ return (TIME)0;
+ }
+ tm.tm_year = atoi (val);
+ if (tm.tm_year > 1900)
+ tm.tm_year -= 1900;
+
+ /* Slash seperating year from month... */
+ token = next_token (&val, cfile);
+ if (token != SLASH) {
+ parse_warn ("expected slash seperating year from month.");
+ if (token != SEMI)
+ skip_to_semi (cfile);
+ return (TIME)0;
+ }
+
+ /* Month... */
+ token = next_token (&val, cfile);
+ if (token != NUMBER) {
+ parse_warn ("numeric month expected.");
+ if (token != SEMI)
+ skip_to_semi (cfile);
+ return (TIME)0;
+ }
+ tm.tm_mon = atoi (val) - 1;
+
+ /* Slash seperating month from day... */
+ token = next_token (&val, cfile);
+ if (token != SLASH) {
+ parse_warn ("expected slash seperating month from day.");
+ if (token != SEMI)
+ skip_to_semi (cfile);
+ return (TIME)0;
+ }
+
+ /* Month... */
+ token = next_token (&val, cfile);
+ if (token != NUMBER) {
+ parse_warn ("numeric day of month expected.");
+ if (token != SEMI)
+ skip_to_semi (cfile);
+ return (TIME)0;
+ }
+ tm.tm_mday = atoi (val);
+
+ /* Hour... */
+ token = next_token (&val, cfile);
+ if (token != NUMBER) {
+ parse_warn ("numeric hour expected.");
+ if (token != SEMI)
+ skip_to_semi (cfile);
+ return (TIME)0;
+ }
+ tm.tm_hour = atoi (val);
+
+ /* Colon seperating hour from minute... */
+ token = next_token (&val, cfile);
+ if (token != COLON) {
+ parse_warn ("expected colon seperating hour from minute.");
+ if (token != SEMI)
+ skip_to_semi (cfile);
+ return (TIME)0;
+ }
+
+ /* Minute... */
+ token = next_token (&val, cfile);
+ if (token != NUMBER) {
+ parse_warn ("numeric minute expected.");
+ if (token != SEMI)
+ skip_to_semi (cfile);
+ return (TIME)0;
+ }
+ tm.tm_min = atoi (val);
+
+ /* Colon seperating minute from second... */
+ token = next_token (&val, cfile);
+ if (token != COLON) {
+ parse_warn ("expected colon seperating hour from minute.");
+ if (token != SEMI)
+ skip_to_semi (cfile);
+ return (TIME)0;
+ }
+
+ /* Minute... */
+ token = next_token (&val, cfile);
+ if (token != NUMBER) {
+ parse_warn ("numeric minute expected.");
+ if (token != SEMI)
+ skip_to_semi (cfile);
+ return (TIME)0;
+ }
+ tm.tm_sec = atoi (val);
+ tm.tm_isdst = 0;
+
+ /* XXX */ /* We assume that mktime does not use tm_yday. */
+ tm.tm_yday = 0;
+
+ /* Make sure the date ends in a semicolon... */
+ token = next_token (&val, cfile);
+ if (token != SEMI) {
+ parse_warn ("semicolon expected.");
+ skip_to_semi (cfile);
+ return 0;
+ }
+
+ /* Guess the time value... */
+ guess = ((((((365 * (tm.tm_year - 70) + /* Days in years since '70 */
+ (tm.tm_year - 69) / 4 + /* Leap days since '70 */
+ (tm.tm_mon /* Days in months this year */
+ ? months [tm.tm_mon - 1]
+ : 0) +
+ (tm.tm_mon > 1 && /* Leap day this year */
+ !((tm.tm_year - 72) & 3)) +
+ tm.tm_mday - 1) * 24) + /* Day of month */
+ tm.tm_hour) * 60) +
+ tm.tm_min) * 60) + tm.tm_sec;
+
+ /* This guess could be wrong because of leap seconds or other
+ weirdness we don't know about that the system does. For
+ now, we're just going to accept the guess, but at some point
+ it might be nice to do a successive approximation here to
+ get an exact value. Even if the error is small, if the
+ server is restarted frequently (and thus the lease database
+ is reread), the error could accumulate into something
+ significant. */
+
+ return guess;
+}
diff --git a/contrib/isc-dhcp/common/print.c b/contrib/isc-dhcp/common/print.c
new file mode 100644
index 000000000000..4a2b464862d6
--- /dev/null
+++ b/contrib/isc-dhcp/common/print.c
@@ -0,0 +1,184 @@
+/* print.c
+
+ Turn data structures into printable text. */
+
+/*
+ * Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of The Internet Software Consortium nor the names
+ * of its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
+ * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This software has been written for the Internet Software Consortium
+ * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
+ * Enterprises. To learn more about the Internet Software Consortium,
+ * see ``http://www.vix.com/isc''. To learn more about Vixie
+ * Enterprises, see ``http://www.vix.com''.
+ */
+
+#ifndef lint
+static char copyright[] =
+"$Id: print.c,v 1.16.2.2 1998/11/24 22:39:35 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium. All rights reserved.\n";
+#endif /* not lint */
+
+#include "dhcpd.h"
+
+char *print_hw_addr (htype, hlen, data)
+ int htype;
+ int hlen;
+ unsigned char *data;
+{
+ static char habuf [49];
+ char *s;
+ int i;
+
+ if (htype == 0 || hlen == 0) {
+ strcpy (habuf, "<null>");
+ } else {
+ s = habuf;
+ for (i = 0; i < hlen; i++) {
+ sprintf (s, "%02x", data [i]);
+ s += strlen (s);
+ *s++ = ':';
+ }
+ *--s = 0;
+ }
+ return habuf;
+}
+
+void print_lease (lease)
+ struct lease *lease;
+{
+ struct tm *t;
+ char tbuf [32];
+
+ debug (" Lease %s",
+ piaddr (lease -> ip_addr));
+
+ t = gmtime (&lease -> starts);
+ strftime (tbuf, sizeof tbuf, "%D %H:%M:%S", t);
+ debug (" start %s", tbuf);
+
+ t = gmtime (&lease -> ends);
+ strftime (tbuf, sizeof tbuf, "%D %H:%M:%S", t);
+ debug (" end %s", tbuf);
+
+ t = gmtime (&lease -> timestamp);
+ strftime (tbuf, sizeof tbuf, "%D %H:%M:%S", t);
+ debug (" stamp %s", tbuf);
+
+ debug (" hardware addr = %s",
+ print_hw_addr (lease -> hardware_addr.htype,
+ lease -> hardware_addr.hlen,
+ lease -> hardware_addr.haddr));
+ debug (" host %s ",
+ lease -> host ? lease -> host -> name : "<none>");
+}
+
+void dump_packet (tp)
+ struct packet *tp;
+{
+ struct dhcp_packet *tdp = tp -> raw;
+
+ debug ("packet length %d", tp -> packet_length);
+ debug ("op = %d htype = %d hlen = %d hops = %d",
+ tdp -> op, tdp -> htype, tdp -> hlen, tdp -> hops);
+ debug ("xid = %x secs = %d flags = %x",
+ tdp -> xid, tdp -> secs, tdp -> flags);
+ debug ("ciaddr = %s", inet_ntoa (tdp -> ciaddr));
+ debug ("yiaddr = %s", inet_ntoa (tdp -> yiaddr));
+ debug ("siaddr = %s", inet_ntoa (tdp -> siaddr));
+ debug ("giaddr = %s", inet_ntoa (tdp -> giaddr));
+ debug ("chaddr = %02.2x:%02.2x:%02.2x:%02.2x:%02.2x:%02.2x",
+ ((unsigned char *)(tdp -> chaddr)) [0],
+ ((unsigned char *)(tdp -> chaddr)) [1],
+ ((unsigned char *)(tdp -> chaddr)) [2],
+ ((unsigned char *)(tdp -> chaddr)) [3],
+ ((unsigned char *)(tdp -> chaddr)) [4],
+ ((unsigned char *)(tdp -> chaddr)) [5]);
+ debug ("filename = %s", tdp -> file);
+ debug ("server_name = %s", tdp -> sname);
+ if (tp -> options_valid) {
+ int i;
+
+ for (i = 0; i < 256; i++) {
+ if (tp -> options [i].data)
+ debug (" %s = %s",
+ dhcp_options [i].name,
+ pretty_print_option
+ (i, tp -> options [i].data,
+ tp -> options [i].len, 1, 1));
+ }
+ }
+ debug ("");
+}
+
+void dump_raw (buf, len)
+ unsigned char *buf;
+ int len;
+{
+ int i;
+ char lbuf [80];
+ int lbix = 0;
+
+ lbuf [0] = 0;
+
+ for (i = 0; i < len; i++) {
+ if ((i & 15) == 0) {
+ if (lbix)
+ note (lbuf);
+ sprintf (lbuf, "%03x:", i);
+ lbix = 4;
+ } else if ((i & 7) == 0)
+ lbuf [lbix++] = ' ';
+ sprintf (&lbuf [lbix], " %02x", buf [i]);
+ lbix += 3;
+ }
+ note (lbuf);
+}
+
+void hash_dump (table)
+ struct hash_table *table;
+{
+ int i;
+ struct hash_bucket *bp;
+
+ if (!table)
+ return;
+
+ for (i = 0; i < table -> hash_count; i++) {
+ if (!table -> buckets [i])
+ continue;
+ note ("hash bucket %d:", i);
+ for (bp = table -> buckets [i]; bp; bp = bp -> next) {
+ if (bp -> len)
+ dump_raw (bp -> name, bp -> len);
+ else
+ note ((char *)bp -> name);
+ }
+ }
+}
diff --git a/contrib/isc-dhcp/common/socket.c b/contrib/isc-dhcp/common/socket.c
new file mode 100644
index 000000000000..b2ae5b4cae97
--- /dev/null
+++ b/contrib/isc-dhcp/common/socket.c
@@ -0,0 +1,280 @@
+/* socket.c
+
+ BSD socket interface code... */
+
+/*
+ * Copyright (c) 1995, 1996, 1997, 1998, 1999
+ * The Internet Software Consortium. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of The Internet Software Consortium nor the names
+ * of its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
+ * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This software has been written for the Internet Software Consortium
+ * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
+ * Enterprises. To learn more about the Internet Software Consortium,
+ * see ``http://www.vix.com/isc''. To learn more about Vixie
+ * Enterprises, see ``http://www.vix.com''.
+ */
+
+/* SO_BINDTODEVICE support added by Elliot Poger (poger@leland.stanford.edu).
+ * This sockopt allows a socket to be bound to a particular interface,
+ * thus enabling the use of DHCPD on a multihomed host.
+ * If SO_BINDTODEVICE is defined in your system header files, the use of
+ * this sockopt will be automatically enabled.
+ * I have implemented it under Linux; other systems should be doable also.
+ */
+
+#ifndef lint
+static char copyright[] =
+"$Id: socket.c,v 1.26.2.6 1999/02/03 19:46:04 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998, 1999 The Internet Software Consortium. All rights reserved.\n";
+#endif /* not lint */
+
+#include "dhcpd.h"
+
+#ifdef USE_SOCKET_FALLBACK
+# define USE_SOCKET_SEND
+# define if_register_send if_register_fallback
+# define send_packet send_fallback
+# define if_reinitialize_send if_reinitialize_fallback
+#endif
+
+static int once = 0;
+
+/* Reinitializes the specified interface after an address change. This
+ is not required for packet-filter APIs. */
+
+#ifdef USE_SOCKET_SEND
+void if_reinitialize_send (info)
+ struct interface_info *info;
+{
+#if 0
+#ifndef USE_SOCKET_RECEIVE
+ once = 0;
+ close (info -> wfdesc);
+#endif
+ if_register_send (info);
+#endif
+}
+#endif
+
+#ifdef USE_SOCKET_RECEIVE
+void if_reinitialize_receive (info)
+ struct interface_info *info;
+{
+#if 0
+ once = 0;
+ close (info -> rfdesc);
+ if_register_receive (info);
+#endif
+}
+#endif
+
+#if defined (USE_SOCKET_SEND) || defined (USE_SOCKET_RECEIVE)
+/* Generic interface registration routine... */
+int if_register_socket (info)
+ struct interface_info *info;
+{
+ struct sockaddr_in name;
+ int sock;
+ int flag;
+
+#if !defined (SO_BINDTODEVICE) && !defined (USE_FALLBACK)
+ /* Make sure only one interface is registered. */
+ if (once)
+ error ("The standard socket API can only support %s",
+ "hosts with a single network interface.");
+ once = 1;
+#endif
+
+ /* Set up the address we're going to bind to. */
+ name.sin_family = AF_INET;
+ name.sin_port = local_port;
+ name.sin_addr.s_addr = INADDR_ANY;
+ memset (name.sin_zero, 0, sizeof (name.sin_zero));
+
+ /* Make a socket... */
+ if ((sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
+ error ("Can't create dhcp socket: %m");
+
+ /* Set the REUSEADDR option so that we don't fail to start if
+ we're being restarted. */
+ flag = 1;
+ if (setsockopt (sock, SOL_SOCKET, SO_REUSEADDR,
+ (char *)&flag, sizeof flag) < 0)
+ error ("Can't set SO_REUSEADDR option on dhcp socket: %m");
+
+ /* Set the BROADCAST option so that we can broadcast DHCP responses. */
+ if (setsockopt (sock, SOL_SOCKET, SO_BROADCAST,
+ (char *)&flag, sizeof flag) < 0)
+ error ("Can't set SO_BROADCAST option on dhcp socket: %m");
+
+ /* Bind the socket to this interface's IP address. */
+ if (bind (sock, (struct sockaddr *)&name, sizeof name) < 0)
+ error ("Can't bind to dhcp address: %m");
+
+#if defined (SO_BINDTODEVICE)
+ /* Bind this socket to this interface. */
+ if (info -> ifp &&
+ setsockopt (sock, SOL_SOCKET, SO_BINDTODEVICE,
+ (char *)(info -> ifp), sizeof *(info -> ifp)) < 0) {
+ error("setting SO_BINDTODEVICE");
+ }
+#endif
+
+ return sock;
+}
+#endif /* USE_SOCKET_SEND || USE_SOCKET_RECEIVE */
+
+#ifdef USE_SOCKET_SEND
+void if_register_send (info)
+ struct interface_info *info;
+{
+#ifndef USE_SOCKET_RECEIVE
+ info -> wfdesc = if_register_socket (info);
+#else
+ info -> wfdesc = info -> rfdesc;
+#endif
+ if (!quiet_interface_discovery)
+ note ("Sending on Socket/%s/%s",
+ info -> name,
+ (info -> shared_network ?
+ info -> shared_network -> name : "unattached"));
+
+}
+#endif /* USE_SOCKET_SEND */
+
+#ifdef USE_SOCKET_RECEIVE
+void if_register_receive (info)
+ struct interface_info *info;
+{
+ /* If we're using the socket API for sending and receiving,
+ we don't need to register this interface twice. */
+ info -> rfdesc = if_register_socket (info);
+ if (!quiet_interface_discovery)
+ note ("Listening on Socket/%s/%s",
+ info -> name,
+ (info -> shared_network ?
+ info -> shared_network -> name : "unattached"));
+}
+#endif /* USE_SOCKET_RECEIVE */
+
+#ifdef USE_SOCKET_SEND
+ssize_t send_packet (interface, packet, raw, len, from, to, hto)
+ struct interface_info *interface;
+ struct packet *packet;
+ struct dhcp_packet *raw;
+ size_t len;
+ struct in_addr from;
+ struct sockaddr_in *to;
+ struct hardware *hto;
+{
+ int result;
+#ifdef IGNORE_HOSTUNREACH
+ int retry = 0;
+ do {
+#endif
+ result = sendto (interface -> wfdesc, (char *)raw, len, 0,
+ (struct sockaddr *)to, sizeof *to);
+#ifdef IGNORE_HOSTUNREACH
+ } while (to -> sin_addr.s_addr == htonl (INADDR_BROADCAST) &&
+ result < 0 &&
+ (errno == EHOSTUNREACH ||
+ errno == ECONNREFUSED) &&
+ retry++ < 10);
+#endif
+ return result;
+}
+#endif /* USE_SOCKET_SEND */
+
+#ifdef USE_SOCKET_RECEIVE
+ssize_t receive_packet (interface, buf, len, from, hfrom)
+ struct interface_info *interface;
+ unsigned char *buf;
+ size_t len;
+ struct sockaddr_in *from;
+ struct hardware *hfrom;
+{
+ int flen = sizeof *from;
+ int result;
+
+#ifdef IGNORE_HOSTUNREACH
+ int retry = 0;
+ do {
+#endif
+ result = recvfrom (interface -> rfdesc, (char *)buf, len, 0,
+ (struct sockaddr *)from, &flen);
+#ifdef IGNORE_HOSTUNREACH
+ } while (result < 0 &&
+ (errno == EHOSTUNREACH ||
+ errno == ECONNREFUSED) &&
+ retry++ < 10);
+#endif
+ return result;
+}
+#endif /* USE_SOCKET_RECEIVE */
+
+#ifdef USE_SOCKET_SEND
+/* This just reads in a packet and silently discards it. */
+
+void fallback_discard (protocol)
+ struct protocol *protocol;
+{
+ char buf [1540];
+ struct sockaddr_in from;
+ int flen = sizeof from;
+ int status;
+ struct interface_info *interface = protocol -> local;
+
+ status = recvfrom (interface -> wfdesc, buf, sizeof buf, 0,
+ (struct sockaddr *)&from, &flen);
+ if (status < 0)
+ warn ("fallback_discard: %m");
+}
+#endif /* USE_SOCKET_SEND */
+
+#if defined (USE_SOCKET_SEND) && !defined (USE_SOCKET_FALLBACK)
+int can_unicast_without_arp ()
+{
+ return 0;
+}
+
+/* If we have SO_BINDTODEVICE, set up a fallback interface; otherwise,
+ do not. */
+
+void maybe_setup_fallback ()
+{
+#if defined (SO_BINDTODEVICE)
+ struct interface_info *fbi;
+ fbi = setup_fallback ();
+ if (fbi) {
+ fbi -> wfdesc = if_register_socket (fbi);
+ add_protocol ("fallback",
+ fbi -> wfdesc, fallback_discard, fbi);
+ }
+#endif
+}
+#endif /* USE_SOCKET_SEND && !USE_SOCKET_FALLBACK */
diff --git a/contrib/isc-dhcp/common/tables.c b/contrib/isc-dhcp/common/tables.c
new file mode 100644
index 000000000000..abbff6f4cbe7
--- /dev/null
+++ b/contrib/isc-dhcp/common/tables.c
@@ -0,0 +1,692 @@
+/* tables.c
+
+ Tables of information... */
+
+/*
+ * Copyright (c) 1995, 1996 The Internet Software Consortium.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of The Internet Software Consortium nor the names
+ * of its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
+ * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This software has been written for the Internet Software Consortium
+ * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
+ * Enterprises. To learn more about the Internet Software Consortium,
+ * see ``http://www.vix.com/isc''. To learn more about Vixie
+ * Enterprises, see ``http://www.vix.com''.
+ */
+
+#ifndef lint
+static char copyright[] =
+"$Id: tables.c,v 1.13.2.3 1998/12/22 22:45:44 mellon Exp $ Copyright (c) 1995, 1996 The Internet Software Consortium. All rights reserved.\n";
+#endif /* not lint */
+
+#include "dhcpd.h"
+
+/* DHCP Option names, formats and codes, from RFC1533.
+
+ Format codes:
+
+ e - end of data
+ I - IP address
+ l - 32-bit signed integer
+ L - 32-bit unsigned integer
+ s - 16-bit signed integer
+ S - 16-bit unsigned integer
+ b - 8-bit signed integer
+ B - 8-bit unsigned integer
+ t - ASCII text
+ f - flag (true or false)
+ A - array of whatever precedes (e.g., IA means array of IP addresses)
+*/
+
+struct universe dhcp_universe;
+struct option dhcp_options [256] = {
+ { "pad", "", &dhcp_universe, 0 },
+ { "subnet-mask", "I", &dhcp_universe, 1 },
+ { "time-offset", "l", &dhcp_universe, 2 },
+ { "routers", "IA", &dhcp_universe, 3 },
+ { "time-servers", "IA", &dhcp_universe, 4 },
+ { "ien116-name-servers", "IA", &dhcp_universe, 5 },
+ { "domain-name-servers", "IA", &dhcp_universe, 6 },
+ { "log-servers", "IA", &dhcp_universe, 7 },
+ { "cookie-servers", "IA", &dhcp_universe, 8 },
+ { "lpr-servers", "IA", &dhcp_universe, 9 },
+ { "impress-servers", "IA", &dhcp_universe, 10 },
+ { "resource-location-servers", "IA", &dhcp_universe, 11 },
+ { "host-name", "X", &dhcp_universe, 12 },
+ { "boot-size", "S", &dhcp_universe, 13 },
+ { "merit-dump", "t", &dhcp_universe, 14 },
+ { "domain-name", "t", &dhcp_universe, 15 },
+ { "swap-server", "I", &dhcp_universe, 16 },
+ { "root-path", "t", &dhcp_universe, 17 },
+ { "extensions-path", "t", &dhcp_universe, 18 },
+ { "ip-forwarding", "f", &dhcp_universe, 19 },
+ { "non-local-source-routing", "f", &dhcp_universe, 20 },
+ { "policy-filter", "IIA", &dhcp_universe, 21 },
+ { "max-dgram-reassembly", "S", &dhcp_universe, 22 },
+ { "default-ip-ttl", "B", &dhcp_universe, 23 },
+ { "path-mtu-aging-timeout", "L", &dhcp_universe, 24 },
+ { "path-mtu-plateau-table", "SA", &dhcp_universe, 25 },
+ { "interface-mtu", "S", &dhcp_universe, 26 },
+ { "all-subnets-local", "f", &dhcp_universe, 27 },
+ { "broadcast-address", "I", &dhcp_universe, 28 },
+ { "perform-mask-discovery", "f", &dhcp_universe, 29 },
+ { "mask-supplier", "f", &dhcp_universe, 30 },
+ { "router-discovery", "f", &dhcp_universe, 31 },
+ { "router-solicitation-address", "I", &dhcp_universe, 32 },
+ { "static-routes", "IIA", &dhcp_universe, 33 },
+ { "trailer-encapsulation", "f", &dhcp_universe, 34 },
+ { "arp-cache-timeout", "L", &dhcp_universe, 35 },
+ { "ieee802-3-encapsulation", "f", &dhcp_universe, 36 },
+ { "default-tcp-ttl", "B", &dhcp_universe, 37 },
+ { "tcp-keepalive-interval", "L", &dhcp_universe, 38 },
+ { "tcp-keepalive-garbage", "f", &dhcp_universe, 39 },
+ { "nis-domain", "t", &dhcp_universe, 40 },
+ { "nis-servers", "IA", &dhcp_universe, 41 },
+ { "ntp-servers", "IA", &dhcp_universe, 42 },
+ { "vendor-encapsulated-options", "X", &dhcp_universe, 43 },
+ { "netbios-name-servers", "IA", &dhcp_universe, 44 },
+ { "netbios-dd-server", "IA", &dhcp_universe, 45 },
+ { "netbios-node-type", "B", &dhcp_universe, 46 },
+ { "netbios-scope", "t", &dhcp_universe, 47 },
+ { "font-servers", "IA", &dhcp_universe, 48 },
+ { "x-display-manager", "IA", &dhcp_universe, 49 },
+ { "dhcp-requested-address", "I", &dhcp_universe, 50 },
+ { "dhcp-lease-time", "L", &dhcp_universe, 51 },
+ { "dhcp-option-overload", "B", &dhcp_universe, 52 },
+ { "dhcp-message-type", "B", &dhcp_universe, 53 },
+ { "dhcp-server-identifier", "I", &dhcp_universe, 54 },
+ { "dhcp-parameter-request-list", "BA", &dhcp_universe, 55 },
+ { "dhcp-message", "t", &dhcp_universe, 56 },
+ { "dhcp-max-message-size", "S", &dhcp_universe, 57 },
+ { "dhcp-renewal-time", "L", &dhcp_universe, 58 },
+ { "dhcp-rebinding-time", "L", &dhcp_universe, 59 },
+ { "dhcp-class-identifier", "t", &dhcp_universe, 60 },
+ { "dhcp-client-identifier", "X", &dhcp_universe, 61 },
+ { "option-62", "X", &dhcp_universe, 62 },
+ { "option-63", "X", &dhcp_universe, 63 },
+ { "option-64", "X", &dhcp_universe, 64 },
+ { "option-65", "X", &dhcp_universe, 65 },
+ { "option-66", "X", &dhcp_universe, 66 },
+ { "option-67", "X", &dhcp_universe, 67 },
+ { "option-68", "X", &dhcp_universe, 68 },
+ { "option-69", "X", &dhcp_universe, 69 },
+ { "option-70", "X", &dhcp_universe, 70 },
+ { "option-71", "X", &dhcp_universe, 71 },
+ { "option-72", "X", &dhcp_universe, 72 },
+ { "option-73", "X", &dhcp_universe, 73 },
+ { "option-74", "X", &dhcp_universe, 74 },
+ { "option-75", "X", &dhcp_universe, 75 },
+ { "option-76", "X", &dhcp_universe, 76 },
+ { "dhcp-user-class-identifier", "t", &dhcp_universe, 77 },
+ { "option-78", "X", &dhcp_universe, 78 },
+ { "option-79", "X", &dhcp_universe, 79 },
+ { "option-80", "X", &dhcp_universe, 80 },
+ { "option-81", "X", &dhcp_universe, 81 },
+ { "option-82", "X", &dhcp_universe, 82 },
+ { "option-83", "X", &dhcp_universe, 83 },
+ { "option-84", "X", &dhcp_universe, 84 },
+ { "nds-servers", "IA", &dhcp_universe, 85 },
+ { "nds-tree-name", "X", &dhcp_universe, 86 },
+ { "nds-context", "X", &dhcp_universe, 87 },
+ { "option-88", "X", &dhcp_universe, 88 },
+ { "option-89", "X", &dhcp_universe, 89 },
+ { "option-90", "X", &dhcp_universe, 90 },
+ { "option-91", "X", &dhcp_universe, 91 },
+ { "option-92", "X", &dhcp_universe, 92 },
+ { "option-93", "X", &dhcp_universe, 93 },
+ { "option-94", "X", &dhcp_universe, 94 },
+ { "option-95", "X", &dhcp_universe, 95 },
+ { "option-96", "X", &dhcp_universe, 96 },
+ { "option-97", "X", &dhcp_universe, 97 },
+ { "option-98", "X", &dhcp_universe, 98 },
+ { "option-99", "X", &dhcp_universe, 99 },
+ { "option-100", "X", &dhcp_universe, 100 },
+ { "option-101", "X", &dhcp_universe, 101 },
+ { "option-102", "X", &dhcp_universe, 102 },
+ { "option-103", "X", &dhcp_universe, 103 },
+ { "option-104", "X", &dhcp_universe, 104 },
+ { "option-105", "X", &dhcp_universe, 105 },
+ { "option-106", "X", &dhcp_universe, 106 },
+ { "option-107", "X", &dhcp_universe, 107 },
+ { "option-108", "X", &dhcp_universe, 108 },
+ { "option-109", "X", &dhcp_universe, 109 },
+ { "option-110", "X", &dhcp_universe, 110 },
+ { "option-111", "X", &dhcp_universe, 111 },
+ { "option-112", "X", &dhcp_universe, 112 },
+ { "option-113", "X", &dhcp_universe, 113 },
+ { "option-114", "X", &dhcp_universe, 114 },
+ { "option-115", "X", &dhcp_universe, 115 },
+ { "option-116", "X", &dhcp_universe, 116 },
+ { "option-117", "X", &dhcp_universe, 117 },
+ { "option-118", "X", &dhcp_universe, 118 },
+ { "option-119", "X", &dhcp_universe, 119 },
+ { "option-120", "X", &dhcp_universe, 120 },
+ { "option-121", "X", &dhcp_universe, 121 },
+ { "option-122", "X", &dhcp_universe, 122 },
+ { "option-123", "X", &dhcp_universe, 123 },
+ { "option-124", "X", &dhcp_universe, 124 },
+ { "option-125", "X", &dhcp_universe, 125 },
+ { "option-126", "X", &dhcp_universe, 126 },
+ { "option-127", "X", &dhcp_universe, 127 },
+ { "option-128", "X", &dhcp_universe, 128 },
+ { "option-129", "X", &dhcp_universe, 129 },
+ { "option-130", "X", &dhcp_universe, 130 },
+ { "option-131", "X", &dhcp_universe, 131 },
+ { "option-132", "X", &dhcp_universe, 132 },
+ { "option-133", "X", &dhcp_universe, 133 },
+ { "option-134", "X", &dhcp_universe, 134 },
+ { "option-135", "X", &dhcp_universe, 135 },
+ { "option-136", "X", &dhcp_universe, 136 },
+ { "option-137", "X", &dhcp_universe, 137 },
+ { "option-138", "X", &dhcp_universe, 138 },
+ { "option-139", "X", &dhcp_universe, 139 },
+ { "option-140", "X", &dhcp_universe, 140 },
+ { "option-141", "X", &dhcp_universe, 141 },
+ { "option-142", "X", &dhcp_universe, 142 },
+ { "option-143", "X", &dhcp_universe, 143 },
+ { "option-144", "X", &dhcp_universe, 144 },
+ { "option-145", "X", &dhcp_universe, 145 },
+ { "option-146", "X", &dhcp_universe, 146 },
+ { "option-147", "X", &dhcp_universe, 147 },
+ { "option-148", "X", &dhcp_universe, 148 },
+ { "option-149", "X", &dhcp_universe, 149 },
+ { "option-150", "X", &dhcp_universe, 150 },
+ { "option-151", "X", &dhcp_universe, 151 },
+ { "option-152", "X", &dhcp_universe, 152 },
+ { "option-153", "X", &dhcp_universe, 153 },
+ { "option-154", "X", &dhcp_universe, 154 },
+ { "option-155", "X", &dhcp_universe, 155 },
+ { "option-156", "X", &dhcp_universe, 156 },
+ { "option-157", "X", &dhcp_universe, 157 },
+ { "option-158", "X", &dhcp_universe, 158 },
+ { "option-159", "X", &dhcp_universe, 159 },
+ { "option-160", "X", &dhcp_universe, 160 },
+ { "option-161", "X", &dhcp_universe, 161 },
+ { "option-162", "X", &dhcp_universe, 162 },
+ { "option-163", "X", &dhcp_universe, 163 },
+ { "option-164", "X", &dhcp_universe, 164 },
+ { "option-165", "X", &dhcp_universe, 165 },
+ { "option-166", "X", &dhcp_universe, 166 },
+ { "option-167", "X", &dhcp_universe, 167 },
+ { "option-168", "X", &dhcp_universe, 168 },
+ { "option-169", "X", &dhcp_universe, 169 },
+ { "option-170", "X", &dhcp_universe, 170 },
+ { "option-171", "X", &dhcp_universe, 171 },
+ { "option-172", "X", &dhcp_universe, 172 },
+ { "option-173", "X", &dhcp_universe, 173 },
+ { "option-174", "X", &dhcp_universe, 174 },
+ { "option-175", "X", &dhcp_universe, 175 },
+ { "option-176", "X", &dhcp_universe, 176 },
+ { "option-177", "X", &dhcp_universe, 177 },
+ { "option-178", "X", &dhcp_universe, 178 },
+ { "option-179", "X", &dhcp_universe, 179 },
+ { "option-180", "X", &dhcp_universe, 180 },
+ { "option-181", "X", &dhcp_universe, 181 },
+ { "option-182", "X", &dhcp_universe, 182 },
+ { "option-183", "X", &dhcp_universe, 183 },
+ { "option-184", "X", &dhcp_universe, 184 },
+ { "option-185", "X", &dhcp_universe, 185 },
+ { "option-186", "X", &dhcp_universe, 186 },
+ { "option-187", "X", &dhcp_universe, 187 },
+ { "option-188", "X", &dhcp_universe, 188 },
+ { "option-189", "X", &dhcp_universe, 189 },
+ { "option-190", "X", &dhcp_universe, 190 },
+ { "option-191", "X", &dhcp_universe, 191 },
+ { "option-192", "X", &dhcp_universe, 192 },
+ { "option-193", "X", &dhcp_universe, 193 },
+ { "option-194", "X", &dhcp_universe, 194 },
+ { "option-195", "X", &dhcp_universe, 195 },
+ { "option-196", "X", &dhcp_universe, 196 },
+ { "option-197", "X", &dhcp_universe, 197 },
+ { "option-198", "X", &dhcp_universe, 198 },
+ { "option-199", "X", &dhcp_universe, 199 },
+ { "option-200", "X", &dhcp_universe, 200 },
+ { "option-201", "X", &dhcp_universe, 201 },
+ { "option-202", "X", &dhcp_universe, 202 },
+ { "option-203", "X", &dhcp_universe, 203 },
+ { "option-204", "X", &dhcp_universe, 204 },
+ { "option-205", "X", &dhcp_universe, 205 },
+ { "option-206", "X", &dhcp_universe, 206 },
+ { "option-207", "X", &dhcp_universe, 207 },
+ { "option-208", "X", &dhcp_universe, 208 },
+ { "option-209", "X", &dhcp_universe, 209 },
+ { "option-210", "X", &dhcp_universe, 210 },
+ { "option-211", "X", &dhcp_universe, 211 },
+ { "option-212", "X", &dhcp_universe, 212 },
+ { "option-213", "X", &dhcp_universe, 213 },
+ { "option-214", "X", &dhcp_universe, 214 },
+ { "option-215", "X", &dhcp_universe, 215 },
+ { "option-216", "X", &dhcp_universe, 216 },
+ { "option-217", "X", &dhcp_universe, 217 },
+ { "option-218", "X", &dhcp_universe, 218 },
+ { "option-219", "X", &dhcp_universe, 219 },
+ { "option-220", "X", &dhcp_universe, 220 },
+ { "option-221", "X", &dhcp_universe, 221 },
+ { "option-222", "X", &dhcp_universe, 222 },
+ { "option-223", "X", &dhcp_universe, 223 },
+ { "option-224", "X", &dhcp_universe, 224 },
+ { "option-225", "X", &dhcp_universe, 225 },
+ { "option-226", "X", &dhcp_universe, 226 },
+ { "option-227", "X", &dhcp_universe, 227 },
+ { "option-228", "X", &dhcp_universe, 228 },
+ { "option-229", "X", &dhcp_universe, 229 },
+ { "option-230", "X", &dhcp_universe, 230 },
+ { "option-231", "X", &dhcp_universe, 231 },
+ { "option-232", "X", &dhcp_universe, 232 },
+ { "option-233", "X", &dhcp_universe, 233 },
+ { "option-234", "X", &dhcp_universe, 234 },
+ { "option-235", "X", &dhcp_universe, 235 },
+ { "option-236", "X", &dhcp_universe, 236 },
+ { "option-237", "X", &dhcp_universe, 237 },
+ { "option-238", "X", &dhcp_universe, 238 },
+ { "option-239", "X", &dhcp_universe, 239 },
+ { "option-240", "X", &dhcp_universe, 240 },
+ { "option-241", "X", &dhcp_universe, 241 },
+ { "option-242", "X", &dhcp_universe, 242 },
+ { "option-243", "X", &dhcp_universe, 243 },
+ { "option-244", "X", &dhcp_universe, 244 },
+ { "option-245", "X", &dhcp_universe, 245 },
+ { "option-246", "X", &dhcp_universe, 246 },
+ { "option-247", "X", &dhcp_universe, 247 },
+ { "option-248", "X", &dhcp_universe, 248 },
+ { "option-249", "X", &dhcp_universe, 249 },
+ { "option-250", "X", &dhcp_universe, 250 },
+ { "option-251", "X", &dhcp_universe, 251 },
+ { "option-252", "X", &dhcp_universe, 252 },
+ { "option-253", "X", &dhcp_universe, 253 },
+ { "option-254", "X", &dhcp_universe, 254 },
+ { "option-end", "e", &dhcp_universe, 255 },
+};
+
+/* Default dhcp option priority list (this is ad hoc and should not be
+ mistaken for a carefully crafted and optimized list). */
+unsigned char dhcp_option_default_priority_list [] = {
+ DHO_DHCP_REQUESTED_ADDRESS,
+ DHO_DHCP_OPTION_OVERLOAD,
+ DHO_DHCP_MAX_MESSAGE_SIZE,
+ DHO_DHCP_RENEWAL_TIME,
+ DHO_DHCP_REBINDING_TIME,
+ DHO_DHCP_CLASS_IDENTIFIER,
+ DHO_DHCP_CLIENT_IDENTIFIER,
+ DHO_SUBNET_MASK,
+ DHO_TIME_OFFSET,
+ DHO_ROUTERS,
+ DHO_TIME_SERVERS,
+ DHO_NAME_SERVERS,
+ DHO_DOMAIN_NAME_SERVERS,
+ DHO_HOST_NAME,
+ DHO_LOG_SERVERS,
+ DHO_COOKIE_SERVERS,
+ DHO_LPR_SERVERS,
+ DHO_IMPRESS_SERVERS,
+ DHO_RESOURCE_LOCATION_SERVERS,
+ DHO_HOST_NAME,
+ DHO_BOOT_SIZE,
+ DHO_MERIT_DUMP,
+ DHO_DOMAIN_NAME,
+ DHO_SWAP_SERVER,
+ DHO_ROOT_PATH,
+ DHO_EXTENSIONS_PATH,
+ DHO_IP_FORWARDING,
+ DHO_NON_LOCAL_SOURCE_ROUTING,
+ DHO_POLICY_FILTER,
+ DHO_MAX_DGRAM_REASSEMBLY,
+ DHO_DEFAULT_IP_TTL,
+ DHO_PATH_MTU_AGING_TIMEOUT,
+ DHO_PATH_MTU_PLATEAU_TABLE,
+ DHO_INTERFACE_MTU,
+ DHO_ALL_SUBNETS_LOCAL,
+ DHO_BROADCAST_ADDRESS,
+ DHO_PERFORM_MASK_DISCOVERY,
+ DHO_MASK_SUPPLIER,
+ DHO_ROUTER_DISCOVERY,
+ DHO_ROUTER_SOLICITATION_ADDRESS,
+ DHO_STATIC_ROUTES,
+ DHO_TRAILER_ENCAPSULATION,
+ DHO_ARP_CACHE_TIMEOUT,
+ DHO_IEEE802_3_ENCAPSULATION,
+ DHO_DEFAULT_TCP_TTL,
+ DHO_TCP_KEEPALIVE_INTERVAL,
+ DHO_TCP_KEEPALIVE_GARBAGE,
+ DHO_NIS_DOMAIN,
+ DHO_NIS_SERVERS,
+ DHO_NTP_SERVERS,
+ DHO_VENDOR_ENCAPSULATED_OPTIONS,
+ DHO_NETBIOS_NAME_SERVERS,
+ DHO_NETBIOS_DD_SERVER,
+ DHO_NETBIOS_NODE_TYPE,
+ DHO_NETBIOS_SCOPE,
+ DHO_FONT_SERVERS,
+ DHO_X_DISPLAY_MANAGER,
+ DHO_DHCP_PARAMETER_REQUEST_LIST,
+
+ /* Presently-undefined options... */
+ 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76,
+ 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92,
+ 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106,
+ 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118,
+ 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130,
+ 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142,
+ 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154,
+ 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166,
+ 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178,
+ 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190,
+ 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202,
+ 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214,
+ 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226,
+ 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238,
+ 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250,
+ 251, 252, 253, 254,
+};
+
+int sizeof_dhcp_option_default_priority_list =
+ sizeof dhcp_option_default_priority_list;
+
+
+char *hardware_types [] = {
+ "unknown-0",
+ "ethernet",
+ "unknown-2",
+ "unknown-3",
+ "unknown-4",
+ "unknown-5",
+ "token-ring",
+ "unknown-7",
+ "fddi",
+ "unknown-9",
+ "unknown-10",
+ "unknown-11",
+ "unknown-12",
+ "unknown-13",
+ "unknown-14",
+ "unknown-15",
+ "unknown-16",
+ "unknown-17",
+ "unknown-18",
+ "unknown-19",
+ "unknown-20",
+ "unknown-21",
+ "unknown-22",
+ "unknown-23",
+ "unknown-24",
+ "unknown-25",
+ "unknown-26",
+ "unknown-27",
+ "unknown-28",
+ "unknown-29",
+ "unknown-30",
+ "unknown-31",
+ "unknown-32",
+ "unknown-33",
+ "unknown-34",
+ "unknown-35",
+ "unknown-36",
+ "unknown-37",
+ "unknown-38",
+ "unknown-39",
+ "unknown-40",
+ "unknown-41",
+ "unknown-42",
+ "unknown-43",
+ "unknown-44",
+ "unknown-45",
+ "unknown-46",
+ "unknown-47",
+ "unknown-48",
+ "unknown-49",
+ "unknown-50",
+ "unknown-51",
+ "unknown-52",
+ "unknown-53",
+ "unknown-54",
+ "unknown-55",
+ "unknown-56",
+ "unknown-57",
+ "unknown-58",
+ "unknown-59",
+ "unknown-60",
+ "unknown-61",
+ "unknown-62",
+ "unknown-63",
+ "unknown-64",
+ "unknown-65",
+ "unknown-66",
+ "unknown-67",
+ "unknown-68",
+ "unknown-69",
+ "unknown-70",
+ "unknown-71",
+ "unknown-72",
+ "unknown-73",
+ "unknown-74",
+ "unknown-75",
+ "unknown-76",
+ "unknown-77",
+ "unknown-78",
+ "unknown-79",
+ "unknown-80",
+ "unknown-81",
+ "unknown-82",
+ "unknown-83",
+ "unknown-84",
+ "unknown-85",
+ "unknown-86",
+ "unknown-87",
+ "unknown-88",
+ "unknown-89",
+ "unknown-90",
+ "unknown-91",
+ "unknown-92",
+ "unknown-93",
+ "unknown-94",
+ "unknown-95",
+ "unknown-96",
+ "unknown-97",
+ "unknown-98",
+ "unknown-99",
+ "unknown-100",
+ "unknown-101",
+ "unknown-102",
+ "unknown-103",
+ "unknown-104",
+ "unknown-105",
+ "unknown-106",
+ "unknown-107",
+ "unknown-108",
+ "unknown-109",
+ "unknown-110",
+ "unknown-111",
+ "unknown-112",
+ "unknown-113",
+ "unknown-114",
+ "unknown-115",
+ "unknown-116",
+ "unknown-117",
+ "unknown-118",
+ "unknown-119",
+ "unknown-120",
+ "unknown-121",
+ "unknown-122",
+ "unknown-123",
+ "unknown-124",
+ "unknown-125",
+ "unknown-126",
+ "unknown-127",
+ "unknown-128",
+ "unknown-129",
+ "unknown-130",
+ "unknown-131",
+ "unknown-132",
+ "unknown-133",
+ "unknown-134",
+ "unknown-135",
+ "unknown-136",
+ "unknown-137",
+ "unknown-138",
+ "unknown-139",
+ "unknown-140",
+ "unknown-141",
+ "unknown-142",
+ "unknown-143",
+ "unknown-144",
+ "unknown-145",
+ "unknown-146",
+ "unknown-147",
+ "unknown-148",
+ "unknown-149",
+ "unknown-150",
+ "unknown-151",
+ "unknown-152",
+ "unknown-153",
+ "unknown-154",
+ "unknown-155",
+ "unknown-156",
+ "unknown-157",
+ "unknown-158",
+ "unknown-159",
+ "unknown-160",
+ "unknown-161",
+ "unknown-162",
+ "unknown-163",
+ "unknown-164",
+ "unknown-165",
+ "unknown-166",
+ "unknown-167",
+ "unknown-168",
+ "unknown-169",
+ "unknown-170",
+ "unknown-171",
+ "unknown-172",
+ "unknown-173",
+ "unknown-174",
+ "unknown-175",
+ "unknown-176",
+ "unknown-177",
+ "unknown-178",
+ "unknown-179",
+ "unknown-180",
+ "unknown-181",
+ "unknown-182",
+ "unknown-183",
+ "unknown-184",
+ "unknown-185",
+ "unknown-186",
+ "unknown-187",
+ "unknown-188",
+ "unknown-189",
+ "unknown-190",
+ "unknown-191",
+ "unknown-192",
+ "unknown-193",
+ "unknown-194",
+ "unknown-195",
+ "unknown-196",
+ "unknown-197",
+ "unknown-198",
+ "unknown-199",
+ "unknown-200",
+ "unknown-201",
+ "unknown-202",
+ "unknown-203",
+ "unknown-204",
+ "unknown-205",
+ "unknown-206",
+ "unknown-207",
+ "unknown-208",
+ "unknown-209",
+ "unknown-210",
+ "unknown-211",
+ "unknown-212",
+ "unknown-213",
+ "unknown-214",
+ "unknown-215",
+ "unknown-216",
+ "unknown-217",
+ "unknown-218",
+ "unknown-219",
+ "unknown-220",
+ "unknown-221",
+ "unknown-222",
+ "unknown-223",
+ "unknown-224",
+ "unknown-225",
+ "unknown-226",
+ "unknown-227",
+ "unknown-228",
+ "unknown-229",
+ "unknown-230",
+ "unknown-231",
+ "unknown-232",
+ "unknown-233",
+ "unknown-234",
+ "unknown-235",
+ "unknown-236",
+ "unknown-237",
+ "unknown-238",
+ "unknown-239",
+ "unknown-240",
+ "unknown-241",
+ "unknown-242",
+ "unknown-243",
+ "unknown-244",
+ "unknown-245",
+ "unknown-246",
+ "unknown-247",
+ "unknown-248",
+ "unknown-249",
+ "unknown-250",
+ "unknown-251",
+ "unknown-252",
+ "unknown-253",
+ "unknown-254",
+ "unknown-255" };
+
+
+
+struct hash_table universe_hash;
+
+void initialize_universes()
+{
+ int i;
+
+ dhcp_universe.name = "dhcp";
+ dhcp_universe.hash = new_hash ();
+ if (!dhcp_universe.hash)
+ error ("Can't allocate dhcp option hash table.");
+ for (i = 0; i < 256; i++) {
+ dhcp_universe.options [i] = &dhcp_options [i];
+ add_hash (dhcp_universe.hash,
+ (unsigned char *)dhcp_options [i].name, 0,
+ (unsigned char *)&dhcp_options [i]);
+ }
+ universe_hash.hash_count = DEFAULT_HASH_SIZE;
+ add_hash (&universe_hash,
+ (unsigned char *)dhcp_universe.name, 0,
+ (unsigned char *)&dhcp_universe);
+}
diff --git a/contrib/isc-dhcp/common/upf.c b/contrib/isc-dhcp/common/upf.c
new file mode 100644
index 000000000000..7da9aff62ee8
--- /dev/null
+++ b/contrib/isc-dhcp/common/upf.c
@@ -0,0 +1,318 @@
+/* upf.c
+
+ Ultrix PacketFilter interface code.
+
+/*
+ * Copyright (c) 1995, 1996, 1997 The Internet Software Consortium.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of The Internet Software Consortium nor the names
+ * of its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
+ * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This software has been written for the Internet Software Consortium
+ * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
+ * Enterprises. To learn more about the Internet Software Consortium,
+ * see ``http://www.vix.com/isc''. To learn more about Vixie
+ * Enterprises, see ``http://www.vix.com''.
+ */
+
+#ifndef lint
+static char copyright[] =
+"$Id: upf.c,v 1.3.2.1 1998/12/20 18:29:48 mellon Exp $ Copyright (c) 1995, 1996 The Internet Software Consortium. All rights reserved.\n";
+#endif /* not lint */
+
+#include "dhcpd.h"
+#if defined (USE_UPF_SEND) || defined (USE_UPF_RECEIVE)
+#include <sys/ioctl.h>
+#include <sys/uio.h>
+
+#include <net/pfilt.h>
+#include <netinet/in_systm.h>
+#include "includes/netinet/ip.h"
+#include "includes/netinet/udp.h"
+#include "includes/netinet/if_ether.h"
+
+/* Reinitializes the specified interface after an address change. This
+ is not required for packet-filter APIs. */
+
+#ifdef USE_UPF_SEND
+void if_reinitialize_send (info)
+ struct interface_info *info;
+{
+}
+#endif
+
+#ifdef USE_UPF_RECEIVE
+void if_reinitialize_receive (info)
+ struct interface_info *info;
+{
+}
+#endif
+
+/* Called by get_interface_list for each interface that's discovered.
+ Opens a packet filter for each interface and adds it to the select
+ mask. */
+
+int if_register_upf (info)
+ struct interface_info *info;
+{
+ int sock;
+ char filename[50];
+ int b;
+ struct endevp param;
+
+ /* Open a UPF device */
+ for (b = 0; 1; b++) {
+#ifndef NO_SNPRINTF
+ snprintf(filename, sizeof(filename), "/dev/pf/pfilt%d", b);
+#else
+ sprintf(filename, "/dev/pf/pfilt%d", b);
+#endif
+ sock = open (filename, O_RDWR, 0);
+ if (sock < 0) {
+ if (errno == EBUSY) {
+ continue;
+ } else {
+ error ("Can't find free upf: %m");
+ }
+ } else {
+ break;
+ }
+ }
+
+ /* Set the UPF device to point at this interface. */
+ if (ioctl (sock, EIOCSETIF, info -> ifp) < 0)
+ error ("Can't attach interface %s to upf device %s: %m",
+ info -> name, filename);
+
+ /* Get the hardware address. */
+ if (ioctl (sock, EIOCDEVP, &param) < 0)
+ error ("Can't get interface %s hardware address: %m",
+ info -> name);
+
+ /* We only know how to do ethernet. */
+ if (param.end_dev_type != ENDT_10MB)
+ error ("Invalid device type on network interface %s: %d",
+ info -> name, param.end_dev_type);
+
+ if (param.end_addr_len != 6)
+ error ("Invalid hardware address length on %s: %d",
+ info -> name, param.end_addr_len);
+
+ info -> hw_address.hlen = 6;
+ info -> hw_address.htype = ARPHRD_ETHER;
+ memcpy (&info -> hw_address.haddr [0], param.end_addr, 6);
+
+ return sock;
+}
+#endif /* USE_UPF_SEND || USE_UPF_RECEIVE */
+
+#ifdef USE_UPF_SEND
+void if_register_send (info)
+ struct interface_info *info;
+{
+ /* If we're using the upf API for sending and receiving,
+ we don't need to register this interface twice. */
+#ifndef USE_UPF_RECEIVE
+ info -> wfdesc = if_register_upf (info, interface);
+#else
+ info -> wfdesc = info -> rfdesc;
+#endif
+ if (!quiet_interface_discovery)
+ note ("Sending on UPF/%s/%s/%s",
+ info -> name,
+ print_hw_addr (info -> hw_address.htype,
+ info -> hw_address.hlen,
+ info -> hw_address.haddr),
+ (info -> shared_network ?
+ info -> shared_network -> name : "unattached"));
+}
+#endif /* USE_UPF_SEND */
+
+#ifdef USE_UPF_RECEIVE
+/* Packet filter program...
+ XXX Changes to the filter program may require changes to the constant
+ offsets used in if_register_send to patch the UPF program! XXX */
+
+
+void if_register_receive (info)
+ struct interface_info *info;
+{
+ int flag = 1;
+ u_int32_t addr;
+ struct enfilter pf;
+ u_int32_t bits;
+
+ /* Open a UPF device and hang it on this interface... */
+ info -> rfdesc = if_register_upf (info);
+
+ /* Allow the copyall flag to be set... */
+ if (ioctl(info -> rfdesc, EIOCALLOWCOPYALL, &flag) < 0)
+ error ("Can't set ALLOWCOPYALL: %m");
+
+ /* Clear all the packet filter mode bits first... */
+ flag = (ENHOLDSIG | ENBATCH | ENTSTAMP | ENPROMISC |
+ ENNONEXCL | ENCOPYALL);
+ if (ioctl (info -> rfdesc, EIOCMBIC, &flag) < 0)
+ error ("Can't clear pfilt bits: %m");
+
+ /* Set the ENBATCH and ENCOPYALL bits... */
+ bits = ENBATCH | ENCOPYALL;
+ if (ioctl (info -> rfdesc, EIOCMBIS, &bits) < 0)
+ error ("Can't set ENBATCH|ENCOPYALL: %m");
+
+ /* Set up the UPF filter program. */
+ /* XXX Unlike the BPF filter program, this one won't work if the
+ XXX IP packet is fragmented or if there are options on the IP
+ XXX header. */
+ pf.enf_Priority = 0;
+ pf.enf_FilterLen = 0;
+
+ pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHWORD + 6;
+ pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT + ENF_CAND;
+ pf.enf_Filter [pf.enf_FilterLen++] = htons (ETHERTYPE_IP);
+ pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT;
+ pf.enf_Filter [pf.enf_FilterLen++] = htons (IPPROTO_UDP);
+ pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHWORD + 11;
+ pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT + ENF_AND;
+ pf.enf_Filter [pf.enf_FilterLen++] = htons (0xFF);
+ pf.enf_Filter [pf.enf_FilterLen++] = ENF_CAND;
+ pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHWORD + 18;
+ pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT + ENF_CAND;
+ pf.enf_Filter [pf.enf_FilterLen++] = local_port;
+
+ if (ioctl (info -> rfdesc, EIOCSETF, &pf) < 0)
+ error ("Can't install packet filter program: %m");
+ if (!quiet_interface_discovery)
+ note ("Listening on UPF/%s/%s/%s",
+ info -> name,
+ print_hw_addr (info -> hw_address.htype,
+ info -> hw_address.hlen,
+ info -> hw_address.haddr),
+ (info -> shared_network ?
+ info -> shared_network -> name : "unattached"));
+}
+#endif /* USE_UPF_RECEIVE */
+
+#ifdef USE_UPF_SEND
+ssize_t send_packet (interface, packet, raw, len, from, to, hto)
+ struct interface_info *interface;
+ struct packet *packet;
+ struct dhcp_packet *raw;
+ size_t len;
+ struct in_addr from;
+ struct sockaddr_in *to;
+ struct hardware *hto;
+{
+ int bufp = 0;
+ unsigned char buf [256];
+ struct iovec iov [2];
+
+ if (!strcmp (interface -> name, "fallback"))
+ return send_fallback (interface, packet, raw,
+ len, from, to, hto);
+
+ /* Assemble the headers... */
+ assemble_hw_header (interface, buf, &bufp, hto);
+ assemble_udp_ip_header (interface, buf, &bufp, from.s_addr,
+ to -> sin_addr.s_addr, to -> sin_port,
+ (unsigned char *)raw, len);
+
+ /* Fire it off */
+ iov [0].iov_base = (char *)buf;
+ iov [0].iov_len = bufp;
+ iov [1].iov_base = (char *)raw;
+ iov [1].iov_len = len;
+
+ return writev(interface -> wfdesc, iov, 2);
+}
+#endif /* USE_UPF_SEND */
+
+#ifdef USE_UPF_RECEIVE
+ssize_t receive_packet (interface, buf, len, from, hfrom)
+ struct interface_info *interface;
+ unsigned char *buf;
+ size_t len;
+ struct sockaddr_in *from;
+ struct hardware *hfrom;
+{
+ int nread;
+ int length = 0;
+ int offset = 0;
+ unsigned char ibuf [1500 + sizeof (struct enstamp)];
+ int bufix = 0;
+
+ length = read (interface -> rfdesc, ibuf, sizeof ibuf);
+ if (length <= 0)
+ return length;
+
+ bufix = sizeof (struct enstamp);
+ /* Decode the physical header... */
+ offset = decode_hw_header (interface, ibuf, bufix, hfrom);
+
+ /* If a physical layer checksum failed (dunno of any
+ physical layer that supports this, but WTH), skip this
+ packet. */
+ if (offset < 0) {
+ return 0;
+ }
+
+ bufix += offset;
+ length -= offset;
+
+ /* Decode the IP and UDP headers... */
+ offset = decode_udp_ip_header (interface, ibuf, bufix,
+ from, (unsigned char *)0, length);
+
+ /* If the IP or UDP checksum was bad, skip the packet... */
+ if (offset < 0)
+ return 0;
+
+ bufix += offset;
+ length -= offset;
+
+ /* Copy out the data in the packet... */
+ memcpy (buf, &ibuf [bufix], length);
+ return length;
+}
+
+int can_unicast_without_arp ()
+{
+ return 1;
+}
+
+void maybe_setup_fallback ()
+{
+ struct interface_info *fbi;
+ fbi = setup_fallback ();
+ if (fbi) {
+ if_register_fallback (fbi);
+ add_protocol ("fallback", fallback_interface -> wfdesc,
+ fallback_discard, fallback_interface);
+ }
+}
+#endif