--- /dev/null
+diff -up dhcp-3.1.0/omapip/dispatch.c.libdhcp4client dhcp-3.1.0/omapip/dispatch.c
+--- dhcp-3.1.0/omapip/dispatch.c.libdhcp4client 2005-03-17 15:15:21.000000000 -0500
++++ dhcp-3.1.0/omapip/dispatch.c 2007-10-24 14:55:56.000000000 -0400
+@@ -34,7 +34,7 @@
+
+ #include <omapip/omapip_p.h>
+
+-static omapi_io_object_t omapi_io_states;
++omapi_io_object_t omapi_io_states;
+ TIME cur_time;
+
+ OMAPI_OBJECT_ALLOC (omapi_io,
+diff -up dhcp-3.1.0/omapip/errwarn.c.libdhcp4client dhcp-3.1.0/omapip/errwarn.c
+--- dhcp-3.1.0/omapip/errwarn.c.libdhcp4client 2007-10-24 14:55:56.000000000 -0400
++++ dhcp-3.1.0/omapip/errwarn.c 2007-10-24 14:57:16.000000000 -0400
+@@ -39,6 +39,11 @@ static char copyright[] =
+ #include <omapip/omapip_p.h>
+ #include <errno.h>
+
++#ifdef LIBDHCP
++#include <isc-dhcp/libdhcp_control.h>
++extern LIBDHCP_Control *libdhcp_control;
++#endif
++
+ #ifdef DEBUG
+ int log_perror = -1;
+ #else
+@@ -48,7 +53,9 @@ int log_priority;
+ void (*log_cleanup) (void);
+
+ #define CVT_BUF_MAX 1023
++#ifndef LIBDHCP
+ static char mbuf [CVT_BUF_MAX + 1];
++#endif
+ static char fbuf [CVT_BUF_MAX + 1];
+
+ /* Log an error message, then exit... */
+@@ -58,6 +65,16 @@ void log_fatal (const char * fmt, ... )
+ va_list list;
+
+ do_percentm (fbuf, fmt);
++
++#ifdef LIBDHCP
++ if (libdhcp_control && (libdhcp_control->eh)) {
++ va_start (list, fmt);
++ libdhcp_control->eh(libdhcp_control, LOG_FATAL, fbuf, list);
++ va_end(list);
++ libdhcp_control->finished = 1;
++ return;
++ }
++#else
+
+ /* %Audit% This is log output. %2004.06.17,Safe%
+ * If we truncate we hope the user can get a hint from the log.
+@@ -91,6 +108,7 @@ void log_fatal (const char * fmt, ... )
+ if (log_cleanup)
+ (*log_cleanup) ();
+ exit (1);
++#endif
+ }
+
+ /* Log an error message... */
+@@ -101,6 +119,13 @@ int log_error (const char * fmt, ...)
+
+ do_percentm (fbuf, fmt);
+
++#ifdef LIBDHCP
++ if (libdhcp_control && libdhcp_control->eh) {
++ va_start (list, fmt);
++ libdhcp_control->eh(libdhcp_control, LOG_ERR, fbuf, list);
++ va_end(list);
++ }
++#else
+ /* %Audit% This is log output. %2004.06.17,Safe%
+ * If we truncate we hope the user can get a hint from the log.
+ */
+@@ -116,7 +141,7 @@ int log_error (const char * fmt, ...)
+ write (STDERR_FILENO, mbuf, strlen (mbuf));
+ write (STDERR_FILENO, "\n", 1);
+ }
+-
++#endif
+ return 0;
+ }
+
+@@ -128,6 +153,13 @@ int log_info (const char *fmt, ...)
+
+ do_percentm (fbuf, fmt);
+
++#ifdef LIBDHCP
++ if (libdhcp_control && libdhcp_control->eh) {
++ va_start (list, fmt);
++ libdhcp_control->eh(libdhcp_control, LOG_INFO, fbuf, list);
++ va_end(list);
++ }
++#else
+ /* %Audit% This is log output. %2004.06.17,Safe%
+ * If we truncate we hope the user can get a hint from the log.
+ */
+@@ -143,7 +175,7 @@ int log_info (const char *fmt, ...)
+ write (STDERR_FILENO, mbuf, strlen (mbuf));
+ write (STDERR_FILENO, "\n", 1);
+ }
+-
++#endif
+ return 0;
+ }
+
+@@ -154,7 +186,13 @@ int log_debug (const char *fmt, ...)
+ va_list list;
+
+ do_percentm (fbuf, fmt);
+-
++#ifdef LIBDHCP
++ if (libdhcp_control && libdhcp_control->eh) {
++ va_start (list, fmt);
++ libdhcp_control->eh(libdhcp_control, LOG_DEBUG, fbuf, list);
++ va_end(list);
++ }
++#else
+ /* %Audit% This is log output. %2004.06.17,Safe%
+ * If we truncate we hope the user can get a hint from the log.
+ */
+@@ -170,7 +208,7 @@ int log_debug (const char *fmt, ...)
+ write (STDERR_FILENO, mbuf, strlen (mbuf));
+ write (STDERR_FILENO, "\n", 1);
+ }
+-
++#endif
+ return 0;
+ }
+
+diff -up dhcp-3.1.0/omapip/alloc.c.libdhcp4client dhcp-3.1.0/omapip/alloc.c
+--- dhcp-3.1.0/omapip/alloc.c.libdhcp4client 2006-02-24 18:16:30.000000000 -0500
++++ dhcp-3.1.0/omapip/alloc.c 2007-10-24 14:55:56.000000000 -0400
+@@ -40,6 +40,33 @@ static char copyright[] =
+
+ #include <omapip/omapip_p.h>
+
++#ifdef LIBDHCP
++/* OK, we need a quick and dirty way of freeing all memory used by libdhcp.
++ All pointers will be stored in a glibc tree on alloc, and removed on free.
++ This is not too expensive for light single-call library use.
++*/
++#include <search.h>
++extern void tdestroy (void *root, void (*free_node)(void *nodep));
++static void *all_pointers=0L;
++static int ptr_comparator(const void *p1, const void *p2) {
++ return ((p1 == p2) ? 0 : ((p1 > p2) ? 1 : -1));
++}
++
++static void record_pointer(void *ptr) {
++ tsearch(ptr, &(all_pointers), ptr_comparator);
++}
++
++static void forget_pointer(void *ptr) {
++ tdelete(ptr, &(all_pointers), ptr_comparator);
++}
++
++void omapi_free_all_pointers(void) {
++ if (all_pointers != NULL)
++ tdestroy(all_pointers, free);
++ all_pointers = NULL;
++}
++#endif
++
+ #if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \
+ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
+ struct dmalloc_preamble *dmalloc_list;
+@@ -78,7 +105,9 @@ VOIDPTR dmalloc (size, file, line)
+ return (VOIDPTR)0;
+
+ foo = malloc(len);
+-
++#ifdef LIBDHCP
++ record_pointer(foo);
++#endif
+ if (!foo)
+ return (VOIDPTR)0;
+ bar = (VOIDPTR)(foo + DMDOFFSET);
+@@ -200,6 +229,9 @@ void dfree (ptr, file, line)
+ 0, (unsigned char *)ptr + DMDOFFSET, 0, 1, RC_MALLOC);
+ #endif
+ free (ptr);
++#ifdef LIBDHCP
++ forget_pointer(ptr);
++#endif
+ }
+
+ #if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \
+diff -up dhcp-3.1.0/configure.libdhcp4client dhcp-3.1.0/configure
+--- dhcp-3.1.0/configure.libdhcp4client 2005-03-17 15:14:55.000000000 -0500
++++ dhcp-3.1.0/configure 2007-10-24 14:55:56.000000000 -0400
+@@ -246,7 +246,7 @@ if [ ! -d $workname ]; then
+ fi
+
+ if [ x"$dirs" = x ]; then
+- dirs=". client server relay common omapip dhcpctl minires dst"
++ dirs=". client server relay common omapip dhcpctl minires dst libdhcp4client"
+ fi
+
+ for foo in $dirs; do
+diff -up dhcp-3.1.0/dst/hmac_link.c.libdhcp4client dhcp-3.1.0/dst/hmac_link.c
+--- dhcp-3.1.0/dst/hmac_link.c.libdhcp4client 2001-02-22 02:22:08.000000000 -0500
++++ dhcp-3.1.0/dst/hmac_link.c 2007-10-24 14:55:56.000000000 -0400
+@@ -38,6 +38,10 @@ static const char rcsid[] = "$Header: /p
+
+ #include "dst_internal.h"
+
++#ifdef LIBDHCP
++extern void* dmalloc(size_t,char *,int);
++#endif
++
+ #ifdef USE_MD5
+ # include "md5.h"
+ # ifndef _MD5_H_
+@@ -86,7 +90,11 @@ dst_hmac_md5_sign(const int mode, DST_KE
+ MD5_CTX *ctx = NULL;
+
+ if (mode & SIG_MODE_INIT)
++#ifdef LIBDHCP
++ ctx = (MD5_CTX *) dmalloc(sizeof(*ctx),__FILE__,__LINE__);
++#else
+ ctx = (MD5_CTX *) malloc(sizeof(*ctx));
++#endif
+ else if (context)
+ ctx = (MD5_CTX *) *context;
+ if (ctx == NULL)
+@@ -153,7 +161,11 @@ dst_hmac_md5_verify(const int mode, DST_
+ MD5_CTX *ctx = NULL;
+
+ if (mode & SIG_MODE_INIT)
++#ifdef LIBDHCP
++ ctx = (MD5_CTX *) dmalloc(sizeof(*ctx),__FILE__,__LINE__);
++#else
+ ctx = (MD5_CTX *) malloc(sizeof(*ctx));
++#endif
+ else if (context)
+ ctx = (MD5_CTX *) *context;
+ if (ctx == NULL)
+@@ -217,8 +229,11 @@ dst_buffer_to_hmac_md5(DST_KEY *dkey, co
+
+ if (dkey == NULL || key == NULL || keylen < 0)
+ return (-1);
+-
++#ifdef LIBDHCP
++ if ((hkey = (HMAC_Key *) dmalloc(sizeof(HMAC_Key),__FILE__,__LINE__)) == NULL)
++#else
+ if ((hkey = (HMAC_Key *) malloc(sizeof(HMAC_Key))) == NULL)
++#endif
+ return (-2);
+
+ memset(hkey->hk_ipad, 0, sizeof(hkey->hk_ipad));
+@@ -347,7 +362,11 @@ dst_hmac_md5_key_from_file_format(DST_KE
+ if (eol == NULL)
+ return (-4);
+ len = eol - p;
++#ifdef LIBDHCP
++ tmp = dmalloc(len + 2,__FILE__,__LINE__);
++#else
+ tmp = malloc(len + 2);
++#endif
+ memcpy(tmp, p, len);
+ *(tmp + len) = 0x0;
+ key_len = b64_pton((char *)tmp, key, HMAC_LEN+1); /* see above */
+@@ -439,8 +458,11 @@ dst_hmac_md5_generate_key(DST_KEY *key,
+ return(0);
+
+ len = size > 64 ? 64 : size;
++#ifdef LIBDHCP
++ buff = dmalloc(len+8,__FILE__,__LINE__);
++#else
+ buff = malloc(len+8);
+-
++#endif
+ n = dst_random(DST_RAND_SEMI, len, buff);
+ n += dst_random(DST_RAND_KEY, len, buff);
+ if (n <= len) { /* failed getting anything */
+@@ -463,7 +485,11 @@ dst_hmac_md5_init()
+ {
+ if (dst_t_func[KEY_HMAC_MD5] != NULL)
+ return (1);
++#ifdef LIBDHCP
++ dst_t_func[KEY_HMAC_MD5] = dmalloc(sizeof(struct dst_func),__FILE__,__LINE__);
++#else
+ dst_t_func[KEY_HMAC_MD5] = malloc(sizeof(struct dst_func));
++#endif
+ if (dst_t_func[KEY_HMAC_MD5] == NULL)
+ return (0);
+ memset(dst_t_func[KEY_HMAC_MD5], 0, sizeof(struct dst_func));
+diff -up dhcp-3.1.0/common/discover.c.libdhcp4client dhcp-3.1.0/common/discover.c
+--- dhcp-3.1.0/common/discover.c.libdhcp4client 2006-11-07 18:41:39.000000000 -0500
++++ dhcp-3.1.0/common/discover.c 2007-10-24 14:55:56.000000000 -0400
+@@ -121,6 +121,10 @@ isc_result_t interface_initialize (omapi
+ register that interface with the network I/O software, figure out what
+ subnet it's on, and add it to the list of interfaces. */
+
++#ifdef LIBDHCP
++int have_setup_fallback = 0;
++#endif
++
+ void discover_interfaces (state)
+ int state;
+ {
+@@ -141,7 +145,9 @@ void discover_interfaces (state)
+ char *s;
+ #endif
+ isc_result_t status;
++#ifndef LIBDHCP
+ static int setup_fallback = 0;
++#endif
+ int wifcount = 0;
+
+ /* Create an unbound datagram socket to do the SIOCGIFADDR ioctl on. */
+@@ -695,10 +701,17 @@ void discover_interfaces (state)
+ log_fatal ("Not configured to listen on any interfaces!");
+ }
+
++#ifdef LIBDHCP
++ if (!have_setup_fallback) {
++ have_setup_fallback = 1;
++ maybe_setup_fallback ();
++ }
++#else
+ if (!setup_fallback) {
+ setup_fallback = 1;
+ maybe_setup_fallback ();
+ }
++#endif
+
+ #if defined (HAVE_SETFD)
+ if (fallback_interface) {
+diff -up dhcp-3.1.0/common/tree.c.libdhcp4client dhcp-3.1.0/common/tree.c
+--- dhcp-3.1.0/common/tree.c.libdhcp4client 2007-02-14 17:41:22.000000000 -0500
++++ dhcp-3.1.0/common/tree.c 2007-10-24 14:55:56.000000000 -0400
+@@ -41,7 +41,7 @@ static char copyright[] =
+ #include <omapip/omapip_p.h>
+ #include <ctype.h>
+
+-struct binding_scope *global_scope;
++struct binding_scope __attribute__ ((visibility ("default"))) *global_scope;
+
+ static int do_host_lookup PROTO ((struct data_string *,
+ struct dns_host_entry *));
+@@ -2761,6 +2761,7 @@ int evaluate_numeric_expression (result,
+ result of that evaluation. There should never be both an expression
+ and a valid data_string. */
+
++__attribute__ ((visibility ("default")))
+ int evaluate_option_cache (result, packet, lease, client_state,
+ in_options, cfg_options, scope, oc, file, line)
+ struct data_string *result;
+diff -up dhcp-3.1.0/common/options.c.libdhcp4client dhcp-3.1.0/common/options.c
+--- dhcp-3.1.0/common/options.c.libdhcp4client 2007-05-23 15:26:22.000000000 -0400
++++ dhcp-3.1.0/common/options.c 2007-10-24 14:55:56.000000000 -0400
+@@ -2501,6 +2501,7 @@ int fqdn_option_space_encapsulate (resul
+ return 1;
+ }
+
++__attribute__ ((visibility ("default")))
+ void option_space_foreach (struct packet *packet, struct lease *lease,
+ struct client_state *client_state,
+ struct option_state *in_options,
+diff -up dhcp-3.1.0/common/dispatch.c.libdhcp4client dhcp-3.1.0/common/dispatch.c
+--- dhcp-3.1.0/common/dispatch.c.libdhcp4client 2007-10-24 14:55:56.000000000 -0400
++++ dhcp-3.1.0/common/dispatch.c 2007-10-24 14:55:56.000000000 -0400
+@@ -39,8 +39,24 @@ static char copyright[] =
+
+ #include "dhcpd.h"
+
+-struct timeout *timeouts;
+-static struct timeout *free_timeouts;
++struct timeout {
++#ifndef LIBDHCP
++ struct timeout *next;
++#endif
++ TIME when;
++ void (*func) PROTO ((void *));
++ void *what;
++ tvref_t ref;
++ tvunref_t unref;
++};
++
++#ifdef LIBDHCP
++static struct timeout *timeouts = NULL;
++static int ntimeouts = 0;
++#else
++static struct timeout *timeouts = NULL;
++static struct timeout *free_timeouts = NULL;
++#endif
+
+ void set_time(TIME t)
+ {
+@@ -53,9 +69,41 @@ void set_time(TIME t)
+
+ struct timeval *process_outstanding_timeouts (struct timeval *tvp)
+ {
++#ifdef LIBDHCP
++ int i;
++ struct timeout t = { 0 };
++#endif
+ /* Call any expired timeouts, and then if there's
+ still a timeout registered, time out the select
+ call then. */
++#ifdef LIBDHCP
++ if (!ntimeouts)
++ return NULL;
++
++ for (i = 0; i < ntimeouts && timeouts[i].when <= cur_time;) {
++ struct timeout *new_timeouts;
++ size_t n;
++
++ memmove(&t, &timeouts[i], sizeof (t));
++
++ n = (ntimeouts - i - 1) * sizeof (t);
++ memmove(&timeouts[i+1], &timeouts[i], n);
++
++ n = --ntimeouts * sizeof (t);
++ new_timeouts = realloc(timeouts, n);
++ /* XXX broken API, no way to return error here */
++ if (new_timeouts || !n)
++ timeouts = new_timeouts;
++
++ if (t.func)
++ t.func(t.what);
++ if (t.unref)
++ t.unref(t.what, MDL);
++ }
++ if (tvp && ntimeouts) {
++ tvp->tv_sec = timeouts[0].when;
++ tvp->tv_usec = 0;
++#else
+ another:
+ if (timeouts) {
+ struct timeout *t;
+@@ -73,9 +121,15 @@ struct timeval *process_outstanding_time
+ tvp -> tv_sec = timeouts -> when;
+ tvp -> tv_usec = 0;
+ }
++#endif
+ return tvp;
++#ifdef LIBDHCP
++ }
++ return NULL;
++#else
+ } else
+ return (struct timeval *)0;
++#endif
+ }
+
+ /* Wait for packets to come in using select(). When one does, call
+@@ -104,13 +158,28 @@ void add_timeout (when, where, what, ref
+ tvref_t ref;
+ tvunref_t unref;
+ {
++#ifdef LIBDHCP
++ struct timeout t = {
++ .when = when,
++ .func = where,
++ .what = what,
++ .ref = ref,
++ .unref = unref
++ };
++ struct timeout *new_timeouts;
++ int i, pos = 0;
++#else
+ struct timeout *t, *q;
++#endif
+
+ /* See if this timeout supersedes an existing timeout. */
++#ifdef LIBDHCP
++ for (i = 0; i < ntimeouts; i++) {
++ struct timeout *q = &timeouts[i];
++#else
+ t = (struct timeout *)0;
+ for (q = timeouts; q; q = q -> next) {
+- if ((where == NULL || q -> func == where) &&
+- q -> what == what) {
++ if ((where == NULL || q -> func == where) && q -> what == what) {
+ if (t)
+ t -> next = q -> next;
+ else
+@@ -119,7 +188,29 @@ void add_timeout (when, where, what, ref
+ }
+ t = q;
+ }
++#endif
+
++#ifdef LIBDHCP
++ /* If this one is already in the list with a different time,
++ * remove it and re-add */
++ if ((where == NULL || q->func == where) &&
++ q->what == what) {
++ size_t n = (--ntimeouts - i) * sizeof (*q);
++ memmove(&t, q, sizeof (t));
++
++ if (n)
++ memmove(&timeouts[i], &timeouts[i+1], n);
++
++ if (ntimeouts) {
++ new_timeouts = realloc(timeouts, ntimeouts * sizeof (*q));
++ /* XXX broken API, no way to return error here */
++ if (new_timeouts)
++ timeouts = new_timeouts;
++ } else {
++ timeouts = NULL;
++ }
++ add_timeout(when, where, what, ref, unref);
++#else
+ /* If we didn't supersede a timeout, allocate a timeout
+ structure now. */
+ if (!q) {
+@@ -128,7 +219,7 @@ void add_timeout (when, where, what, ref
+ free_timeouts = q -> next;
+ } else {
+ q = ((struct timeout *)
+- dmalloc (sizeof (struct timeout), MDL));
++ dmalloc (sizeof (struct timeout), MDL));
+ if (!q)
+ log_fatal ("add_timeout: no memory!");
+ }
+@@ -158,22 +249,76 @@ void add_timeout (when, where, what, ref
+ if (t -> next -> when > q -> when) {
+ q -> next = t -> next;
+ t -> next = q;
++#endif
+ return;
++#ifdef LIBDHCP
++ } else if (timeouts[i].when > when) {
++ pos = i;
++#endif
+ }
+ }
+
++#ifdef LIBDHCP
++ /* If we didn't supersede an existing timeout, then pos is set
++ * to the timeout which will post after this one. Insert this
++ * one before it. */
++
++ new_timeouts = realloc(timeouts, sizeof (t) * (ntimeouts+1));
++ /* XXX broken API, no way to return error here */
++ if (new_timeouts) {
++ /* ntimeouts = 10
++ * pos = 3;
++ * n = 10-3 * sizeof (t) = 7 * sizeof (t)
++ */
++ size_t n = (ntimeouts - pos) * sizeof (t);
++
++ timeouts = new_timeouts;
++ memmove(&timeouts[pos+1], &timeouts[pos], n);
++ memmove(&timeouts[pos], &t, sizeof (t));
++ ntimeouts++;
++ }
++#else
+ /* End of list. */
+ t -> next = q;
+ q -> next = (struct timeout *)0;
++#endif
+ }
+
+ void cancel_timeout (where, what)
+ void (*where) PROTO ((void *));
+ void *what;
+ {
++#ifdef LIBDHCP
++ struct timeout t;
++ int i = 0;
++#else
+ struct timeout *t, *q;
++#endif
+
+ /* Look for this timeout on the list, and unlink it if we find it. */
++#ifdef LIBDHCP
++ for (i = 0; i < ntimeouts; i++) {
++ struct timeout *new_timeouts, *q = &timeouts[i];
++
++ if (q->func == where && q->what == what) {
++ size_t n;
++
++ memmove(&t, q, sizeof (t));
++
++ n = (ntimeouts - i - 1) * sizeof (t);
++ memmove(&timeouts[i+1], &timeouts[i], n);
++
++ n = --ntimeouts * sizeof (t);
++ new_timeouts = realloc(timeouts, n);
++ /* XXX broken API, no way to return error here */
++ if (new_timeouts || !n)
++ timeouts = new_timeouts;
++
++ if (t.unref)
++ t.unref(t.what, MDL);
++ }
++ }
++#else
+ t = (struct timeout *)0;
+ for (q = timeouts; q; q = q -> next) {
+ if (q -> func == where && q -> what == what) {
+@@ -193,11 +338,16 @@ void cancel_timeout (where, what)
+ q -> next = free_timeouts;
+ free_timeouts = q;
+ }
++#endif
+ }
+
+ #if defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
+ void cancel_all_timeouts ()
+ {
++#ifdef LIBDHCP
++ cur_time = TIME_MAX;
++ process_outstanding_timeouts(NULL);
++#else
+ struct timeout *t, *n;
+ for (t = timeouts; t; t = n) {
+ n = t -> next;
+@@ -205,13 +355,20 @@ void cancel_all_timeouts ()
+ t -> next = free_timeouts;
+ free_timeouts = t;
+ }
++#endif
+ }
+
++__attribute__ ((visibility ("default")))
+ void relinquish_timeouts ()
+ {
++#ifdef LIBDHCP
++ while (ntimeouts)
++ cancel_timeout(timeouts[0].func, timeouts[0].what);
++#else
+ struct timeout *t, *n;
+ for (t = free_timeouts; t; t = n) {
+ n = t -> next;
+ dfree (t, MDL);
+ }
++#endif
+ }
+diff -up dhcp-3.1.0/common/alloc.c.libdhcp4client dhcp-3.1.0/common/alloc.c
+--- dhcp-3.1.0/common/alloc.c.libdhcp4client 2006-06-01 16:23:17.000000000 -0400
++++ dhcp-3.1.0/common/alloc.c 2007-10-24 14:55:56.000000000 -0400
+@@ -1013,7 +1013,11 @@ int executable_statement_reference (ptr,
+ return 1;
+ }
+
++#ifdef LIBDHCP
++struct packet *free_packets;
++#else
+ static struct packet *free_packets;
++#endif
+
+ #if defined (DEBUG_MEMORY_LEAKAGE) || \
+ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
+diff -up dhcp-3.1.0/includes/dhcpd.h.libdhcp4client dhcp-3.1.0/includes/dhcpd.h
+--- dhcp-3.1.0/includes/dhcpd.h.libdhcp4client 2007-10-24 14:55:56.000000000 -0400
++++ dhcp-3.1.0/includes/dhcpd.h 2007-10-24 14:55:56.000000000 -0400
+@@ -1000,14 +1000,6 @@ struct hardware_link {
+
+ typedef void (*tvref_t)(void *, void *, const char *, int);
+ typedef void (*tvunref_t)(void *, const char *, int);
+-struct timeout {
+- struct timeout *next;
+- TIME when;
+- void (*func) PROTO ((void *));
+- void *what;
+- tvref_t ref;
+- tvunref_t unref;
+-};
+
+ struct protocol {
+ struct protocol *next;
+@@ -1960,7 +1952,6 @@ extern void (*bootp_packet_handler) PROT
+ struct dhcp_packet *, unsigned,
+ unsigned int,
+ struct iaddr, struct hardware *));
+-extern struct timeout *timeouts;
+ extern omapi_object_type_t *dhcp_type_interface;
+ #if defined (TRACING)
+ trace_type_t *interface_trace;
+diff -up dhcp-3.1.0/client/dhclient.c.libdhcp4client dhcp-3.1.0/client/dhclient.c
+--- dhcp-3.1.0/client/dhclient.c.libdhcp4client 2007-10-24 14:55:56.000000000 -0400
++++ dhcp-3.1.0/client/dhclient.c 2007-10-24 14:56:20.000000000 -0400
+@@ -82,16 +82,52 @@ int quiet=0;
+ int nowait=0;
+ int bootp_broadcast_always = 0;
+
++#ifdef LIBDHCP
++FILE *leaseFile = NULL;
++#endif
++
+ extern u_int32_t default_requested_options[];
+ #ifdef EXTENDED_NEW_OPTION_INFO
+ int extended_option_environment = 0;
+ #endif
+ static void usage PROTO ((void));
+
++#ifdef LIBDHCP
++#include "isc-dhcp/libdhcp_control.h"
++LIBDHCP_Control *libdhcp_control;
++static void libdhcp_dispatch(void)
++{
++ struct timeval tv = { 0, 0 }, *tvp;
++ isc_result_t status;
++
++ /* Wait for a packet, or a timeout, or libdhcp being finished */
++ do {
++ tvp = process_outstanding_timeouts(&tv);
++ status = omapi_one_dispatch(0, tvp);
++
++ if (libdhcp_control && ((status == ISC_R_TIMEDOUT) || (libdhcp_control->timeout && (time(NULL) >= (libdhcp_control->timeout + libdhcp_control->now))))) {
++ if (libdhcp_control->callback)
++ libdhcp_control->callback(libdhcp_control, DHC_TIMEDOUT, NULL);
++
++ break;
++ }
++ } while ((status != ISC_R_TIMEDOUT) && ((!libdhcp_control) || (!(libdhcp_control->finished))));
++}
++
++extern void omapi_free_all_pointers(void);
++
++__attribute__ ((visibility ("default")))
++int dhcpv4_client (libdhcp_ctl, argc, argv, envp)
++ LIBDHCP_Control *libdhcp_ctl;
++#else
+ int main (argc, argv, envp)
++#endif
+ int argc;
+ char **argv, **envp;
+ {
++#ifdef LIBDHCP
++ libdhcp_control = libdhcp_ctl;
++#endif
+ int fd;
+ int i;
+ struct servent *ent;
+@@ -120,6 +156,7 @@ int main (argc, argv, envp)
+ char *arg_conf = NULL;
+ int arg_conf_len = 0;
+
++#ifndef LIBDHCP
+ /* Make sure that file descriptors 0 (stdin), 1, (stdout), and
+ 2 (stderr) are open. To do this, we assume that when we
+ open a file the lowest available file decriptor is used. */
+@@ -143,6 +180,7 @@ int main (argc, argv, envp)
+ #if !(defined (DEBUG) || defined (SYSLOG_4_2) || defined (__CYGWIN32__))
+ setlogmask (LOG_UPTO (LOG_INFO));
+ #endif
++#endif
+
+ /* Set up the OMAPI. */
+ status = omapi_init ();
+@@ -439,6 +477,10 @@ int main (argc, argv, envp)
+ }
+ }
+
++#ifdef LIBDHCP
++ if (libdhcp_control && (libdhcp_control->capability & DHCP_USE_PID_FILE))
++#endif
++#ifndef LIBDHCP
+ if (!quiet) {
+ log_info ("%s %s", message, DHCP_VERSION);
+ log_info (copyright);
+@@ -449,6 +491,7 @@ int main (argc, argv, envp)
+ log_info ("%s", "");
+ } else
+ log_perror = 0;
++#endif
+
+ /* If we're given a relay agent address to insert, for testing
+ purposes, figure out what it is. */
+@@ -680,11 +723,17 @@ int main (argc, argv, envp)
+ arg_conf_len = 0;
+ }
+
++#ifdef LIBDHCP
++ if (libdhcp_control && (libdhcp_control->capability & DHCP_USE_LEASE_DATABASE)) {
++#endif
+ /* Parse the lease database. */
+ read_client_leases ();
+
+ /* Rewrite the lease database... */
+ rewrite_client_leases ();
++#ifdef LIBDHCP
++ }
++#endif
+
+ /* XXX */
+ /* config_counter(&snd_counter, &rcv_counter); */
+@@ -703,7 +752,7 @@ int main (argc, argv, envp)
+ if (!persist) {
+ /* Nothing more to do. */
+ log_info ("No broadcast interfaces found - exiting.");
+- exit (0);
++ return (0);
+ }
+ } else if (!release_mode && !exit_mode) {
+ /* Call the script with the list of interfaces. */
+@@ -799,6 +848,7 @@ int main (argc, argv, envp)
+ dmalloc_outstanding = 0;
+ #endif
+
++#ifndef LIBDHCP
+ /* If we're not supposed to wait before getting the address,
+ don't. */
+ if (nowait)
+@@ -811,6 +861,126 @@ int main (argc, argv, envp)
+
+ /* Start dispatching packets and timeouts... */
+ dispatch ();
++#else
++ if (libdhcp_control) {
++ if (libdhcp_control->timeout)
++ libdhcp_control->now = time(NULL);
++ else
++ libdhcp_control->now = 0;
++ }
++
++ libdhcp_dispatch();
++
++ /* libdhcp is finished with us. */
++
++ /* close all file descriptors: */
++ for (ip = interfaces; ip; ip = ip->next) {
++ shutdown(ip->wfdesc, SHUT_RDWR);
++ close(ip->wfdesc);
++
++ if (ip->rfdesc != ip->wfdesc)
++ close(ip->rfdesc);
++ }
++
++ if (fallback_interface != 0) {
++ ip = fallback_interface;
++ shutdown(ip->wfdesc, SHUT_RDWR);
++ close(ip->wfdesc);
++
++ if (ip->rfdesc != ip->wfdesc)
++ close(ip->rfdesc);
++ }
++
++ if (leaseFile)
++ fclose (leaseFile);
++
++ closelog();
++
++ char *current_pid_file = _PATH_DHCLIENT_PID;
++
++ /* Free ALL allocated memory: */
++ omapi_free_all_pointers();
++
++ /* Re-Initialize globals: */
++ client_env = 0;
++ client_env_count = 0;
++ default_lease_time = 43200;
++
++ dhcp_max_agent_option_packet_length = 0;
++ iaddr_any.len = 4;
++ memset(&(iaddr_any.iabuf[0]), '\0', 4);
++ iaddr_broadcast.len = 4;
++ memset(&(iaddr_broadcast.iabuf[0]), 0xff, 4);
++ interfaces_requested = 0;
++ leaseFile = 0;
++
++ libdhcp_control = 0;
++
++ local_port = 0;
++ no_daemon = 0;
++ nowait = 0;
++ onetry = 0;
++ quiet = 0;
++ max_lease_time = 86400;
++ path_dhclient_conf = _PATH_DHCLIENT_CONF;
++ path_dhclient_db = _PATH_DHCLIENT_DB;
++ path_dhclient_pid = _PATH_DHCLIENT_PID;
++ strcpy(&(path_dhclient_script_array[0]), _PATH_DHCLIENT_SCRIPT);
++ path_dhclient_script = path_dhclient_script_array;
++ remote_port = 0;
++ resolver_inited = 0;
++ log_perror = 1;
++ global_scope = NULL;
++ root_group = NULL;
++ group_name_hash = NULL;
++ interfaces = NULL;
++ dummy_interfaces = NULL;
++ fallback_interface = NULL;
++ extern int have_setup_fallback;
++ have_setup_fallback = 0;
++ quiet_interface_discovery = 1;
++#ifndef LIBDHCP
++ timeouts = NULL;
++#endif
++ dhcp_type_interface = NULL;
++ interface_vector = NULL;
++ interface_count = 0;
++ interface_max = 0;
++ name_servers = 0;
++ domains = 0;
++ dhcp_type_interface = NULL;
++ dhcp_type_group = NULL;
++ dhcp_type_shared_network = NULL;
++ dhcp_type_control = NULL;
++ memset(&dhcp_universe, '\0', sizeof(struct universe));
++ memset(&nwip_universe, '\0', sizeof(struct universe));
++ memset(&fqdn_universe, '\0', sizeof(struct universe));
++ universe_hash = 0;
++ universes = 0;
++ universe_count = 0;
++ universe_max = 0;
++ config_universe = 0;
++ extern struct hash_bucket *free_hash_buckets;
++ free_hash_buckets = NULL;
++ extern struct dhcp_packet *dhcp_free_list;
++ dhcp_free_list = NULL;
++ extern struct packet *packet_free_list;
++ packet_free_list = NULL;
++ extern struct binding_value *free_binding_values;
++ free_binding_values = NULL;
++ extern struct expression *free_expressions;
++ free_expressions = NULL;
++ extern struct option_cache *free_option_caches;
++ free_option_caches = NULL;
++ extern struct packet *free_packets;
++ free_packets = NULL;
++ extern pair free_pairs;
++ free_pairs = NULL;
++ extern omapi_io_object_t omapi_io_states;
++ memset(&omapi_io_states, '\0', sizeof(omapi_io_states));
++ dhcp_control_object = NULL;
++ unlink(current_pid_file);
++#endif
+
+ /*NOTREACHED*/
+ return 0;
+@@ -1203,7 +1373,20 @@ void dhcpack (packet)
+ if (client -> new -> rebind < cur_time)
+ client -> new -> rebind = TIME_MAX;
+
++#ifdef LIBDHCP
++ /* We need the server's siaddr for the 'bootServer'
++ * pump option
++ */
++ u_int32_t set_siaddr = 0;
++ set_siaddr = client->packet.siaddr.s_addr;
++ client->packet.siaddr.s_addr = packet->raw->siaddr.s_addr;
++#endif
++
+ bind_lease (client);
++
++#ifdef LIBDHCP
++ client->packet.siaddr.s_addr = set_siaddr;
++#endif
+ }
+
+ void bind_lease (client)
+@@ -1241,6 +1424,9 @@ void bind_lease (client)
+ return;
+ }
+
++#ifdef LIBDHCP
++ if (libdhcp_control && (libdhcp_control->capability & DHCP_USE_LEASE_DATABASE))
++#endif
+ /* Write out the new lease. */
+ write_client_lease (client, client -> new, 0, 0);
+
+@@ -1343,11 +1529,13 @@ int commit_leases ()
+ return 0;
+ }
+
++#ifndef LIBDHCP
+ int write_lease (lease)
+ struct lease *lease;
+ {
+ return 0;
+ }
++#endif
+
+ int write_host (host)
+ struct host_decl *host;
+@@ -1957,6 +2145,10 @@ void state_panic (cpp)
+ tell the shell script that we failed to allocate an address,
+ and try again later. */
+ if (onetry) {
++#ifdef LIBDHCP
++ script_init (client, "FAIL", (struct string_list *)0);
++ return;
++#endif
+ if (!quiet)
+ log_info ("Unable to obtain a lease on first try.%s",
+ " Exiting.");
+@@ -2579,7 +2771,9 @@ void destroy_client_lease (lease)
+ free_client_lease (lease, MDL);
+ }
+
++#ifndef LIBDHCP
+ FILE *leaseFile;
++#endif
+
+ void rewrite_client_leases ()
+ {
+@@ -2960,6 +3154,54 @@ void script_write_params (client, prefix
+ int script_go (client)
+ struct client_state *client;
+ {
++#ifdef LIBDHCP
++ struct string_list *sp;
++
++ if (libdhcp_control && libdhcp_control->callback) {
++ int dhcmsg;
++ char *reason="";
++
++ for (sp = client->env; sp; sp = sp->next)
++ if (strncmp(sp->string, "reason=", 7) == 0) {
++ reason = sp->string + 7;
++ break;
++ }
++
++ if (strcmp(reason,"NBI") == 0)
++ dhcmsg = DHC4_NBI;
++ else if (strcmp(reason,"PREINIT") == 0)
++ dhcmsg = DHC4_PREINIT;
++ else if (strcmp(reason,"BOUND") == 0)
++ dhcmsg = DHC4_BOUND;
++ else if (strcmp(reason,"RENEW") == 0)
++ dhcmsg = DHC4_RENEW;
++ else if (strcmp(reason,"REBOOT") == 0)
++ dhcmsg = DHC4_REBOOT;
++ else if (strcmp(reason,"REBIND") == 0)
++ dhcmsg = DHC4_REBIND;
++ else if (strcmp(reason,"STOP") == 0)
++ dhcmsg = DHC4_STOP;
++ else if (strcmp(reason,"MEDIUM") == 0)
++ dhcmsg = DHC4_MEDIUM;
++ else if (strcmp(reason,"TIMEOUT") == 0)
++ dhcmsg = DHC4_TIMEOUT;
++ else if (strcmp(reason,"FAIL") == 0)
++ dhcmsg = DHC4_FAIL;
++ else if (strcmp(reason,"EXPIRE") == 0)
++ dhcmsg = DHC4_EXPIRE;
++ else if (strcmp(reason,"RELEASE") == 0)
++ dhcmsg = DHC4_RELEASE;
++ else
++ dhcmsg = DHC4_NBI;
++
++ (*libdhcp_control->callback) (libdhcp_control, dhcmsg, client);
++
++ if (libdhcp_control->decline)
++ return 1;
++ }
++
++ return 0;
++#else
+ int rval;
+ char *scriptName;
+ char *argv [2];
+@@ -3038,6 +3280,7 @@ int script_go (client)
+ GET_TIME (&cur_time);
+ return (WIFEXITED (wstatus) ?
+ WEXITSTATUS (wstatus) : -WTERMSIG (wstatus));
++#endif
+ }
+
+ void client_envadd (struct client_state *client,
+@@ -3120,6 +3363,9 @@ void go_daemon ()
+
+ /* Don't become a daemon if the user requested otherwise. */
+ if (no_daemon) {
++#ifdef LIBDHCP
++ if (libdhcp_control && (libdhcp_control->capability & DHCP_USE_PID_FILE ))
++#endif
+ write_client_pid_file ();
+ return;
+ }
+@@ -3129,6 +3375,10 @@ void go_daemon ()
+ return;
+ state = 1;
+
++#ifdef LIBDHCP
++ return;
++#endif
++
+ /* Stop logging to stderr... */
+ log_perror = 0;
+
+diff -up dhcp-3.1.0/Makefile.dist.libdhcp4client dhcp-3.1.0/Makefile.dist
+--- dhcp-3.1.0/Makefile.dist.libdhcp4client 2005-03-17 15:14:54.000000000 -0500
++++ dhcp-3.1.0/Makefile.dist 2007-10-24 14:55:56.000000000 -0400
+@@ -22,7 +22,7 @@
+ # http://www.isc.org/
+
+
+-SUBDIRS= common $(MINIRES) dst omapip server client relay dhcpctl
++SUBDIRS= common $(MINIRES) dst omapip server client relay dhcpctl libdhcp4client
+
+ all:
+ @for dir in ${SUBDIRS}; do \
--- /dev/null
+diff -up dhcp-3.1.0/common/conflex.c.options dhcp-3.1.0/common/conflex.c
+--- dhcp-3.1.0/common/conflex.c.options 2007-10-22 15:46:24.000000000 -0400
++++ dhcp-3.1.0/common/conflex.c 2007-10-22 15:48:07.000000000 -0400
+@@ -599,6 +599,8 @@ static enum dhcp_token intern (atom, dfv
+ return BALANCE;
+ if (!strcasecmp (atom + 1, "ound"))
+ return BOUND;
++ if (!strcasecmp (atom + 1, "ootp-broadcast-always"))
++ return BOOTP_BROADCAST_ALWAYS;
+ break;
+ case 'c':
+ if (!strcasecmp (atom + 1, "ase"))
+diff -up dhcp-3.1.0/includes/dhcpd.h.options dhcp-3.1.0/includes/dhcpd.h
+--- dhcp-3.1.0/includes/dhcpd.h.options 2007-10-22 15:46:24.000000000 -0400
++++ dhcp-3.1.0/includes/dhcpd.h 2007-10-22 15:48:21.000000000 -0400
+@@ -912,6 +912,9 @@ struct client_config {
+ int do_forward_update; /* If nonzero, and if we have the
+ information we need, update the
+ A record for the address we get. */
++
++ int bootp_broadcast_always; /* If nonzero, always set the BOOTP_BROADCAST
++ flag in requests */
+ };
+
+ /* Per-interface state used in the dhcp client... */
+diff -up dhcp-3.1.0/includes/dhctoken.h.options dhcp-3.1.0/includes/dhctoken.h
+--- dhcp-3.1.0/includes/dhctoken.h.options 2006-07-31 18:19:51.000000000 -0400
++++ dhcp-3.1.0/includes/dhctoken.h 2007-10-22 15:49:24.000000000 -0400
+@@ -325,7 +325,8 @@ enum dhcp_token {
+ MIN_BALANCE = 629,
+ DOMAIN_LIST = 630,
+ LEASEQUERY = 631,
+- EXECUTE = 632
++ EXECUTE = 632,
++ BOOTP_BROADCAST_ALWAYS = 633
+ };
+
+ #define is_identifier(x) ((x) >= FIRST_TOKEN && \
+diff -up dhcp-3.1.0/client/dhclient.c.options dhcp-3.1.0/client/dhclient.c
+--- dhcp-3.1.0/client/dhclient.c.options 2007-05-22 16:37:04.000000000 -0400
++++ dhcp-3.1.0/client/dhclient.c 2007-10-22 15:47:51.000000000 -0400
+@@ -38,6 +38,12 @@ static char ocopyright[] =
+ #include "dhcpd.h"
+ #include "version.h"
+
++/*
++ * Defined in stdio.h when _GNU_SOURCE is set, but we don't want to define
++ * that when building ISC code.
++ */
++extern int asprintf(char **strp, const char *fmt, ...);
++
+ TIME default_lease_time = 43200; /* 12 hours... */
+ TIME max_lease_time = 86400; /* 24 hours... */
+
+@@ -74,6 +80,9 @@ int client_env_count=0;
+ int onetry=0;
+ int quiet=0;
+ int nowait=0;
++int bootp_broadcast_always = 0;
++
++extern u_int32_t default_requested_options[];
+ #ifdef EXTENDED_NEW_OPTION_INFO
+ int extended_option_environment = 0;
+ #endif
+@@ -101,6 +110,15 @@ int main (argc, argv, envp)
+ int no_dhclient_pid = 0;
+ int no_dhclient_script = 0;
+ char *s;
++ char *dhcp_client_identifier_arg = NULL;
++ char *dhcp_host_name_arg = NULL;
++ char *dhcp_fqdn_arg = NULL;
++ char *dhcp_vendor_class_identifier_arg = NULL;
++ char *dhclient_request_options = NULL;
++
++ int timeout_arg = 0;
++ char *arg_conf = NULL;
++ int arg_conf_len = 0;
+
+ /* Make sure that file descriptors 0 (stdin), 1, (stdout), and
+ 2 (stderr) are open. To do this, we assume that when we
+@@ -211,6 +229,88 @@ int main (argc, argv, envp)
+ } else if (!strcmp (argv [i], "--version")) {
+ log_info ("isc-dhclient-%s", DHCP_VERSION);
+ exit (0);
++ } else if (!strcmp (argv [i], "-I")) {
++ if ((++i == argc) || (argv[i] == NULL) || (*(argv[i])=='\0')) {
++ usage ();
++ return EXIT_FAILURE;
++ }
++
++ if (strlen(argv[i]) >= DHCP_OPTION_LEN) {
++ log_error("-I option dhcp-client-identifier string \"%s\" is too long - maximum length is: %d", argv[i], DHCP_OPTION_LEN-1);
++ exit(1);
++ }
++
++ dhcp_client_identifier_arg = argv[i];
++ } else if (!strcmp (argv [i], "-B")) {
++ bootp_broadcast_always = 1;
++ } else if (!strcmp (argv [i], "-H")) {
++ if ((++i == argc) || (argv[i] == NULL) || (*(argv[i])=='\0')) {
++ usage ();
++ return EXIT_FAILURE;
++ }
++
++ if (strlen(argv[i]) >= DHCP_OPTION_LEN) {
++ log_error("-H option host-name string \"%s\" is too long - maximum length is: %d", argv[i], DHCP_OPTION_LEN-1);
++ exit(1);
++ }
++
++ if (dhcp_host_name_arg != NULL) {
++ log_error("The -H <host-name> and -F <fqdn> arguments are mutually exclusive");
++ exit(1);
++ }
++
++ dhcp_host_name_arg = argv[i];
++ } else if (!strcmp (argv [i], "-F")) {
++ if ((++i == argc) || (argv[i] == NULL) || (*(argv[i])=='\0')) {
++ usage ();
++ return EXIT_FAILURE;
++ }
++
++ if (strlen(argv[i]) >= DHCP_OPTION_LEN) {
++ log_error("-F option fqdn.fqdn string \"%s\" is too long - maximum length is: %d", argv[i], DHCP_OPTION_LEN-1);
++ exit(1);
++ }
++
++ if (dhcp_fqdn_arg != NULL) {
++ log_error("Only one -F <fqdn> argument can be specified");
++ exit(1);
++ }
++
++ if (dhcp_host_name_arg != NULL) {
++ log_error("The -F <fqdn> and -H <host-name> arguments are mutually exclusive");
++ exit(1);
++ }
++
++ dhcp_fqdn_arg = argv[i];
++ } else if (!strcmp (argv [i], "-T")) {
++ if ((++i == argc) || (argv[i] == NULL) || (*(argv[i])=='\0')) {
++ usage ();
++ return EXIT_FAILURE;
++ }
++
++ if ((timeout_arg = atoi(argv[i])) <= 0) {
++ log_error("-T timeout option must be > 0 - bad value: %s",argv[i]);
++ exit(1);
++ }
++ } else if (!strcmp (argv [i], "-V")) {
++ if ((++i == argc) || (argv[i] == NULL) || (*(argv[i])=='\0')) {
++ usage ();
++ return EXIT_FAILURE;
++ }
++
++ if (strlen(argv[i]) >= DHCP_OPTION_LEN) {
++ log_error("-V option vendor-class-identifier string \"%s\" is too long - maximum length is: %d", argv[i], DHCP_OPTION_LEN-1);
++ exit(1);
++ }
++
++ dhcp_vendor_class_identifier_arg = argv[i];
++ } else if (!strcmp (argv [i], "-R")) {
++ if ((++i == argc) || (argv[i] == NULL) || (*(argv[i])=='\0')) {
++ usage ();
++ return EXIT_FAILURE;
++ }
++
++ dhclient_request_options=argv[i];
+ #ifdef EXTENDED_NEW_OPTION_INFO
+ } else if (!strcmp (argv [i], "-y")) {
+ extended_option_environment = 1;
+@@ -347,6 +447,167 @@ int main (argc, argv, envp)
+ /* Parse the dhclient.conf file. */
+ read_client_conf ();
+
++ /* Parse any extra command line configuration arguments: */
++ if ((dhcp_client_identifier_arg != NULL) && (*dhcp_client_identifier_arg != '\0')) {
++ arg_conf_len = asprintf(&arg_conf, "send dhcp-client-identifier \"%s\";", dhcp_client_identifier_arg);
++
++ if ((arg_conf == 0) || (arg_conf_len <= 0))
++ log_fatal("Unable to send -I option dhcp-client-identifier");
++ }
++
++ if ((dhcp_host_name_arg != NULL) && (*dhcp_host_name_arg != '\0')) {
++ if (arg_conf == 0) {
++ arg_conf_len = asprintf(&arg_conf, "send host-name \"%s\";", dhcp_host_name_arg);
++
++ if ((arg_conf == 0) || (arg_conf_len <= 0))
++ log_fatal("Unable to send -H option host-name");
++ } else {
++ char *last_arg_conf = arg_conf;
++ arg_conf = NULL;
++ arg_conf_len = asprintf( &arg_conf, "%s\nsend host-name \"%s\";", last_arg_conf, dhcp_host_name_arg);
++
++ if ((arg_conf == 0) || (arg_conf_len <= 0))
++ log_fatal("Unable to send -H option host-name");
++
++ free(last_arg_conf);
++ }
++ }
++
++ if ((dhcp_fqdn_arg != NULL) && (*dhcp_fqdn_arg != '\0')) {
++ if (arg_conf == 0) {
++ arg_conf_len = asprintf(&arg_conf, "send fqdn.fqdn \"%s\";", dhcp_fqdn_arg);
++
++ if ((arg_conf == 0) || (arg_conf_len <= 0))
++ log_fatal("Unable to send -F option fqdn.fqdn");
++ } else {
++ char *last_arg_conf = arg_conf;
++ arg_conf = NULL;
++ arg_conf_len = asprintf( &arg_conf, "%s\nsend fqdn.fqdn \"%s\";", last_arg_conf, dhcp_fqdn_arg);
++
++ if ((arg_conf == 0) || (arg_conf_len <= 0))
++ log_fatal("Unable to send -F option fqdn.fqdn");
++
++ free(last_arg_conf);
++ }
++ }
++
++ if (timeout_arg) {
++ if (arg_conf == 0) {
++ arg_conf_len = asprintf(&arg_conf, "timeout %d;", timeout_arg);
++
++ if ((arg_conf == 0) || (arg_conf_len <= 0))
++ log_fatal("Unable to process -T timeout argument");
++ } else {
++ char *last_arg_conf = arg_conf;
++ arg_conf = NULL;
++ arg_conf_len = asprintf( &arg_conf, "%s\ntimeout %d;", last_arg_conf, timeout_arg);
++
++ if ((arg_conf == 0) || (arg_conf_len == 0))
++ log_fatal("Unable to process -T timeout argument");
++
++ free(last_arg_conf);
++ }
++ }
++
++ if ((dhcp_vendor_class_identifier_arg != NULL) && (*dhcp_vendor_class_identifier_arg != '\0')) {
++ if (arg_conf == 0) {
++ arg_conf_len = asprintf(&arg_conf, "send vendor-class-identifier \"%s\";", dhcp_vendor_class_identifier_arg);
++
++ if ((arg_conf == 0) || (arg_conf_len <= 0))
++ log_fatal("Unable to send -V option vendor-class-identifier");
++ } else {
++ char *last_arg_conf = arg_conf;
++ arg_conf = NULL;
++ arg_conf_len = asprintf(&arg_conf, "%s\nsend vendor-class-identifier \"%s\";", last_arg_conf, dhcp_vendor_class_identifier_arg);
++
++ if ((arg_conf == 0) || (arg_conf_len <= 0))
++ log_fatal("Unable to send -V option vendor-class-identifier");
++
++ free(last_arg_conf);
++ }
++ }
++
++ if (dhclient_request_options != NULL) {
++ if (arg_conf == 0) {
++ arg_conf_len = asprintf(&arg_conf, "request %s;", dhclient_request_options);
++
++ if ((arg_conf == 0) || (arg_conf_len <= 0))
++ log_fatal("Unable to parse -R <request options list> argument");
++ } else {
++ char *last_arg_conf = arg_conf;
++ arg_conf = NULL;
++ arg_conf_len = asprintf(&arg_conf, "%s\nrequest %s;", last_arg_conf, dhclient_request_options);
++
++ if ((arg_conf == 0) || (arg_conf_len <= 0))
++ log_fatal("Unable to parse -R <request options list> argument");
++
++ free(last_arg_conf);
++ }
++ }
++
++ if (arg_conf) {
++ if (arg_conf_len == 0)
++ if ((arg_conf_len = strlen(arg_conf)) == 0)
++ /* huh ? cannot happen ! */
++ log_fatal("Unable to process -I/-H/-F/-T/-V/-R configuration arguments");
++
++ /* parse the extra dhclient.conf configuration arguments
++ * into top level config: */
++ struct parse *cfile = (struct parse *)0;
++ const char *val = NULL;
++ int token;
++
++ status = new_parse (&cfile, -1, arg_conf, arg_conf_len, "extra dhclient -I/-H/-F/-T/-V/-R configuration arguments", 0);
++
++ if ((status != ISC_R_SUCCESS) || (cfile -> warnings_occurred))
++ log_fatal("Cannot parse -I/-H/-F/-T/-V/-R configuration arguments !");
++ /* more detailed parse failures will be logged */
++
++ do {
++ token = peek_token (&val, (unsigned *)0, cfile);
++ if (token == END_OF_FILE)
++ break;
++
++ parse_client_statement (cfile, (struct interface_info *)0, &top_level_config);
++ } while (1);
++
++ if (cfile -> warnings_occurred)
++ log_fatal ("Cannot parse -I/-H/-F/-T/-V/-R configuration arguments !");
++ end_parse (&cfile);
++
++ if (timeout_arg) {
++ /* we just set the toplevel timeout, but per-client
++ * timeouts may still be at defaults. Also, it makes no
++ * sense having the reboot_timeout or backoff_cutoff
++ * greater than the timeout:
++ */
++ if ((top_level_config.backoff_cutoff == 15) && (top_level_config.backoff_cutoff > (timeout_arg / 2)))
++ top_level_config.backoff_cutoff = (((unsigned long)(timeout_arg / 2)) == 0) ? timeout_arg : (unsigned long)(timeout_arg / 2);
++
++ for (ip = interfaces; ip; ip = ip -> next) {
++ if (ip->client->config->timeout == 60)
++ ip->client->config->timeout = timeout_arg;
++
++ if ((ip->client->config->reboot_timeout == 10) && (ip->client->config->reboot_timeout > ip->client->config->timeout))
++ ip->client->config->reboot_timeout = ip->client->config->timeout;
++
++ if ((ip->client->config->backoff_cutoff == 15) && (ip->client->config->backoff_cutoff > top_level_config.backoff_cutoff))
++ ip->client->config->backoff_cutoff = top_level_config.backoff_cutoff;
++ }
++ }
++
++ if ((dhclient_request_options != 0) && (top_level_config.requested_options != default_requested_options)) {
++ for (ip = interfaces; ip; ip = ip -> next) {
++ if (ip->client->config->requested_options == default_requested_options)
++ ip->client->config->requested_options = top_level_config.requested_options;
++ }
++ }
++
++ free(arg_conf);
++ arg_conf = NULL;
++ arg_conf_len = 0;
++ }
++
+ /* Parse the lease database. */
+ read_client_leases ();
+
+@@ -1978,7 +2239,8 @@ void make_discover (client, lease)
+ client -> packet.xid = random ();
+ client -> packet.secs = 0; /* filled in by send_discover. */
+
+- if (can_receive_unicast_unconfigured (client -> interface))
++ if ((!(bootp_broadcast_always || client->config->bootp_broadcast_always))
++ && can_receive_unicast_unconfigured(client->interface))
+ client -> packet.flags = 0;
+ else
+ client -> packet.flags = htons (BOOTP_BROADCAST);
+@@ -2065,7 +2327,9 @@ void make_request (client, lease)
+ } else {
+ memset (&client -> packet.ciaddr, 0,
+ sizeof client -> packet.ciaddr);
+- if (can_receive_unicast_unconfigured (client -> interface))
++ if ((!(bootp_broadcast_always ||
++ client ->config->bootp_broadcast_always)) &&
++ can_receive_unicast_unconfigured (client -> interface))
+ client -> packet.flags = 0;
+ else
+ client -> packet.flags = htons (BOOTP_BROADCAST);
+@@ -2125,7 +2389,8 @@ void make_decline (client, lease)
+ client -> packet.hops = 0;
+ client -> packet.xid = client -> xid;
+ client -> packet.secs = 0; /* Filled in by send_request. */
+- if (can_receive_unicast_unconfigured (client -> interface))
++ if ((!(bootp_broadcast_always || client->config-> bootp_broadcast_always))
++ && can_receive_unicast_unconfigured (client->interface))
+ client -> packet.flags = 0;
+ else
+ client -> packet.flags = htons (BOOTP_BROADCAST);
+diff -up dhcp-3.1.0/client/clparse.c.options dhcp-3.1.0/client/clparse.c
+--- dhcp-3.1.0/client/clparse.c.options 2007-02-14 17:41:22.000000000 -0500
++++ dhcp-3.1.0/client/clparse.c 2007-10-22 15:47:12.000000000 -0400
+@@ -84,6 +84,7 @@ isc_result_t read_client_conf ()
+ top_level_config.requested_options = default_requested_options;
+ top_level_config.omapi_port = -1;
+ top_level_config.do_forward_update = 1;
++ top_level_config.bootp_broadcast_always = 0;
+
+ group_allocate (&top_level_config.on_receipt, MDL);
+ if (!top_level_config.on_receipt)
+@@ -230,7 +231,8 @@ void read_client_leases ()
+ interface-declaration |
+ LEASE client-lease-statement |
+ ALIAS client-lease-statement |
+- KEY key-definition */
++ KEY key-definition |
++ BOOTP_BROADCAST_ALWAYS */
+
+ void parse_client_statement (cfile, ip, config)
+ struct parse *cfile;
+@@ -554,6 +556,12 @@ void parse_client_statement (cfile, ip,
+ parse_reject_statement (cfile, config);
+ return;
+
++ case BOOTP_BROADCAST_ALWAYS:
++ token = next_token(&val, (unsigned*)0, cfile);
++ config -> bootp_broadcast_always = 1;
++ parse_semi (cfile);
++ return;
++
+ default:
+ lose = 0;
+ stmt = (struct executable_statement *)0;