]> git.ipfire.org Git - thirdparty/dhcp.git/commitdiff
Sync with 3.0rc7
authorTed Lemon <source@isc.org>
Thu, 17 May 2001 19:04:09 +0000 (19:04 +0000)
committerTed Lemon <source@isc.org>
Thu, 17 May 2001 19:04:09 +0000 (19:04 +0000)
21 files changed:
common/conflex.c
common/discover.c
dhcpctl/dhcpctl.c
dhcpctl/dhcpctl.h
dhcpctl/omshell.c
includes/cf/linux.h
includes/dhcpd.h
includes/dhctoken.h
includes/version.h
omapip/alloc.c
omapip/connection.c
omapip/hash.c
omapip/message.c
omapip/protocol.c
omapip/support.c
server/bootp.c
server/db.c
server/dhcp.c
server/failover.c
server/mdb.c
server/omapi.c

index 495088ea9ec7c24e842c9ad32c0835ab233cf547..5f2d895c6d916607872374bb90db06c9a5ca33b8 100644 (file)
@@ -43,7 +43,7 @@
 
 #ifndef lint
 static char copyright[] =
-"$Id: conflex.c,v 1.92 2001/05/02 06:32:54 mellon Exp $ Copyright (c) 1995-2001 The Internet Software Consortium.  All rights reserved.\n";
+"$Id: conflex.c,v 1.93 2001/05/17 19:03:43 mellon Exp $ Copyright (c) 1995-2001 The Internet Software Consortium.  All rights reserved.\n";
 #endif /* not lint */
 
 #include "dhcpd.h"
@@ -926,6 +926,8 @@ static enum dhcp_token intern (atom, dfv)
                        return TOKEN_RESET;
                if (!strcasecmp (atom + 1, "eserved"))
                        return TOKEN_RESERVED;
+               if (!strcasecmp (atom + 1, "emove"))
+                       return REMOVE;
                break;
              case 's':
                if (!strcasecmp (atom + 1, "tate"))
index 6619fb27396768417a0f45bfdcb98f6c2f9fe4a7..4dc8b25f1744a4d25bfb68ad43be1a67b161845d 100644 (file)
@@ -43,7 +43,7 @@
 
 #ifndef lint
 static char copyright[] =
-"$Id: discover.c,v 1.42 2001/05/02 06:36:54 mellon Exp $ Copyright (c) 1995-2001 The Internet Software Consortium.  All rights reserved.\n";
+"$Id: discover.c,v 1.43 2001/05/17 19:03:44 mellon Exp $ Copyright (c) 1995-2001 The Internet Software Consortium.  All rights reserved.\n";
 #endif /* not lint */
 
 #include "dhcpd.h"
@@ -184,6 +184,15 @@ void discover_interfaces (state)
        if (i < 0)
                log_fatal ("ioctl: SIOCGIFCONF: %m");
 
+#ifdef SIOCGIFCONF_ZERO_PROBE
+       /* Workaround for SIOCGIFCONF bug on some Linux versions. */
+       if (ic.ifc_ifcu.ifcu_buf == 0 && ic.ifc_len == 0) {
+               ic.ifc_len = sizeof buf;
+               ic.ifc_ifcu.ifcu_buf = (caddr_t)buf;
+               goto gifconf_again;
+       }
+#endif
+
        /* If the SIOCGIFCONF resulted in more data than would fit in
           a buffer, allocate a bigger buffer. */
        if ((ic.ifc_ifcu.ifcu_buf == buf 
@@ -198,7 +207,7 @@ void discover_interfaces (state)
 #ifdef SIOCGIFCONF_ZERO_PROBE
        } else if (ic.ifc_ifcu.ifcu_buf == 0) {
                ic.ifc_ifcu.ifcu_buf = (caddr_t)buf;
-               if.ifc_len = sizeof buf;
+               ic.ifc_len = sizeof buf;
                goto gifconf_again;
 #endif
        }
index 70e368ab8309301615a4445634fbf75963051b53..9e3fafa3c8332b87357fa0c05776ae988adea13e 100644 (file)
@@ -321,6 +321,43 @@ dhcpctl_status dhcpctl_set_string_value (dhcpctl_handle h, const char *value,
        return status;
 }
 
+/* dhcpctl_set_buffer_value
+
+   Sets a NUL-terminated ASCII value on an object referred to by
+   a dhcpctl_handle.   like dhcpctl_set_value, but saves the
+   trouble of creating a data_string for a NUL-terminated string.
+   Does not update the server - just sets the value on the handle. */
+
+dhcpctl_status dhcpctl_set_data_value (dhcpctl_handle h,
+                                      const char *value, unsigned len,
+                                      const char *value_name)
+{
+       isc_result_t status;
+       omapi_typed_data_t *tv = (omapi_typed_data_t *)0;
+       omapi_data_string_t *name = (omapi_data_string_t *)0;
+       int ip;
+       unsigned ll;
+
+       ll = strlen (value_name);
+       status = omapi_data_string_new (&name, ll, MDL);
+       if (status != ISC_R_SUCCESS)
+               return status;
+       memcpy (name -> value, value_name, ll);
+
+       status = omapi_typed_data_new (MDL, &tv,
+                                      omapi_datatype_data, len, value);
+       if (status != ISC_R_SUCCESS) {
+               omapi_data_string_dereference (&name, MDL);
+               return status;
+       }
+       memcpy (tv -> u.buffer.value, value, len);
+
+       status = omapi_set_value (h, (omapi_object_t *)0, name, tv);
+       omapi_data_string_dereference (&name, MDL);
+       omapi_typed_data_dereference (&tv, MDL);
+       return status;
+}
+
 /* dhcpctl_set_boolean_value
 
    Sets a boolean value on an object - like dhcpctl_set_value,
index e78a64eeb591e3154f505efa9b4d099561ac98a5..8cfe133ace7badb5a73d7d9a08aa8701156056bc 100644 (file)
@@ -85,6 +85,8 @@ dhcpctl_status dhcpctl_set_value (dhcpctl_handle,
                                  dhcpctl_data_string, const char *);
 dhcpctl_status dhcpctl_set_string_value (dhcpctl_handle, const char *,
                                         const char *);
+dhcpctl_status dhcpctl_set_data_value (dhcpctl_handle,
+                                      const char *, unsigned, const char *);
 dhcpctl_status dhcpctl_set_boolean_value (dhcpctl_handle, int, const char *);
 dhcpctl_status dhcpctl_set_int_value (dhcpctl_handle, int, const char *);
 dhcpctl_status dhcpctl_object_update (dhcpctl_handle, dhcpctl_handle);
index 24d2b6bfd14146f2ccfdf8f82e9dae301b620618..bbcd2073305a6663f40fa1eb5d25aef86595d423 100644 (file)
@@ -107,6 +107,13 @@ int main (int argc, char **argv, char **envp)
                usage(argv[0]);
        }
 
+       /* Initially, log errors to stderr as well as to syslogd. */
+#ifdef SYSLOG_4_2
+       openlog ("dhcpd", LOG_NDELAY);
+       log_priority = DHCPD_LOG_FACILITY;
+#else
+       openlog ("dhcpd", LOG_NDELAY, DHCPD_LOG_FACILITY);
+#endif
        status = dhcpctl_initialize ();
        if (status != ISC_R_SUCCESS) {
                fprintf (stderr, "dhcpctl_initialize: %s\n",
@@ -208,7 +215,7 @@ int main (int argc, char **argv, char **envp)
                            if (se)
                                    port = ntohs (se -> s_port);
                            else {
-                                   printf ("unknown service name: %s", val);
+                                   printf ("unknown service name: %s\n", val);
                                    break;
                            }
                    } else if (token == NUMBER) {
@@ -287,7 +294,7 @@ int main (int argc, char **argv, char **envp)
 
                    s = dmalloc (strlen (val) + 1, MDL);
                    if (!server) {
-                           printf ("no memory to store server name.");
+                           printf ("no memory to store server name.\n");
                            skip_to_semi (cfile);
                            break;
                    }
@@ -305,13 +312,13 @@ int main (int argc, char **argv, char **envp)
                  case KEY:
                    token = next_token (&val, (unsigned *)0, cfile);
                    if (!is_identifier (token)) {
-                           printf ("usage: key <name> <value>");
+                           printf ("usage: key <name> <value>\n");
                            skip_to_semi (cfile);
                            break;
                    }
                    s = dmalloc (strlen (val) + 1, MDL);
                    if (!s) {
-                           printf ("no memory for key name.");
+                           printf ("no memory for key name.\n");
                            skip_to_semi (cfile);
                            break;
                    }
@@ -379,7 +386,7 @@ int main (int argc, char **argv, char **envp)
                    }
                    
                    if (!connected) {
-                           printf ("not connected.");
+                           printf ("not connected.\n");
                            skip_to_semi (cfile);
                            break;
                    }
@@ -408,7 +415,7 @@ int main (int argc, char **argv, char **envp)
                    }
 
                    if (!connected) {
-                           printf ("not connected.");
+                           printf ("not connected.\n");
                            skip_to_semi (cfile);
                            break;
                    }
@@ -434,7 +441,7 @@ int main (int argc, char **argv, char **envp)
                    }
                    
                    if (!connected) {
-                           printf ("not connected.");
+                           printf ("not connected.\n");
                            skip_to_semi (cfile);
                            break;
                    }
@@ -450,23 +457,77 @@ int main (int argc, char **argv, char **envp)
                    switch (token) {
                          case STRING:
                            dhcpctl_set_string_value (oh, val, s1);
+                           token = next_token (&val, (unsigned *)0, cfile);
                            break;
                            
                          case NUMBER:
-                           dhcpctl_set_int_value (oh, atoi (val), s1);
+                           strcpy (buf, val);
+                           token = peek_token (&val, (unsigned *)0, cfile);
+                           /* Colon-seperated hex list? */
+                           if (token == COLON)
+                               goto cshl;
+                           else if (token == DOT) {
+                               s = buf;
+                               val = buf;
+                               do {
+                                   int intval = atoi (val);
+                                   if (intval > 255) {
+                                       parse_warn (cfile,
+                                                   "dotted octet > 255: %s",
+                                                   val);
+                                       skip_to_semi (cfile);
+                                       goto badnum;
+                                   }
+                                   *s++ = intval;
+                                   token = next_token (&val,
+                                                       (unsigned *)0, cfile);
+                                   if (token != DOT)
+                                           break;
+                                   token = next_token (&val,
+                                                       (unsigned *)0, cfile);
+                               } while (token == NUMBER);
+                               dhcpctl_set_data_value (oh, buf,
+                                                       (unsigned)(s - buf),
+                                                       s1);
+                               break;
+                           }
+                           dhcpctl_set_int_value (oh, atoi (buf), s1);
+                           token = next_token (&val, (unsigned *)0, cfile);
+                         badnum:
                            break;
                            
+                         case NUMBER_OR_NAME:
+                           strcpy (buf, val);
+                         cshl:
+                           s = buf;
+                           val = buf;
+                           do {
+                               convert_num (cfile, s, val, 16, 8);
+                               ++s;
+                               token = next_token (&val,
+                                                   (unsigned *)0, cfile);
+                               if (token != COLON)
+                                   break;
+                               token = next_token (&val,
+                                                   (unsigned *)0, cfile);
+                           } while (token == NUMBER ||
+                                    token == NUMBER_OR_NAME);
+                           dhcpctl_set_data_value (oh, buf,
+                                                   (unsigned)(s - buf), s1);
+                           break;
+
                          default:
                            printf ("invalid value.\n");
+                           skip_to_semi (cfile);
                    }
                    
-                   token = next_token (&val, (unsigned *)0, cfile);
                    if (token != END_OF_FILE && token != EOL)
                            goto set_usage;
                    break;
                    
                  case TOKEN_CREATE:
                  case TOKEN_OPEN:
+                   i = token;
                    token = next_token (&val, (unsigned *)0, cfile);
                    if (token != END_OF_FILE && token != EOL) {
                            printf ("usage: %s\n", val);
@@ -475,14 +536,21 @@ int main (int argc, char **argv, char **envp)
                    }
                    
                    if (!connected) {
-                           printf ("not connected.");
+                           printf ("not connected.\n");
                            skip_to_semi (cfile);
                            break;
                    }
 
-                   i = 0;
-                   if (token == TOKEN_CREATE)
+                   if (!oh) {
+                           printf ("you must make a new object first!\n");
+                           skip_to_semi (cfile);
+                           break;
+                   }
+
+                   if (i == TOKEN_CREATE)
                            i = DHCPCTL_CREATE | DHCPCTL_EXCL;
+                   else
+                           i = 0;
                    
                    status = dhcpctl_open_object (oh, connection, i);
                    if (status == ISC_R_SUCCESS)
@@ -507,7 +575,7 @@ int main (int argc, char **argv, char **envp)
                    }
                    
                    if (!connected) {
-                           printf ("not connected.");
+                           printf ("not connected.\n");
                            skip_to_semi (cfile);
                            break;
                    }
@@ -524,9 +592,37 @@ int main (int argc, char **argv, char **envp)
                            break;
                    }
                    
+                   break;
+
+                 case REMOVE:
+                   token = next_token (&val, (unsigned *)0, cfile);
+                   if (token != END_OF_FILE && token != EOL) {
+                           printf ("usage: %s\n", val);
+                           skip_to_semi (cfile);
+                           break;
+                   }
+                   
+                   if (!connected) {
+                           printf ("not connected.\n");
+                           skip_to_semi (cfile);
+                           break;
+                   }
+
+                   status = dhcpctl_object_remove(connection, oh);
+                   if (status == ISC_R_SUCCESS)
+                           status = dhcpctl_wait_for_completion
+                                   (oh, &waitstatus);
+                   if (status == ISC_R_SUCCESS)
+                           status = waitstatus;
+                   if (status != ISC_R_SUCCESS) {
+                           printf ("can't destroy object: %s\n",
+                                   isc_result_totext (status));
+                           break;
+                   }
+                   
                    break;
            }
-       } while (token != END_OF_FILE);
+       } while (1);
 
        exit (0);
 }
index 7ce3e4c7cac1092c40e59c4924f294a297fee65c..808fe8468658252d66cd283c0039afd662f60a4d 100644 (file)
@@ -125,7 +125,7 @@ extern int h_errno;
 #   define USE_LPF
 #  endif
 #  if !defined (__sparc__)     /* XXX hopefully this will be fixed someday */
-#   define SIOCGIFCONF_NULL_BUF_GIVES_CORRECT_LEN
+#   define SIOCGIFCONF_ZERO_PROBE
 #  endif
 #  define LINUX_SLASHPROC_DISCOVERY
 #  define PROCDEV_DEVICE "/proc/net/dev"
index 231c3644cf5a011bacd949f1b08297a2755d8fd4..2c34629e7fd4f49cee4d93d6b454a6036f5c0894 100644 (file)
@@ -2475,11 +2475,12 @@ void update_partner PROTO ((struct lease *));
 int load_balance_mine (struct packet *, dhcp_failover_state_t *);
 binding_state_t normal_binding_state_transition_check (struct lease *,
                                                       dhcp_failover_state_t *,
-                                                      binding_state_t);
+                                                      binding_state_t,
+                                                      u_int32_t);
 binding_state_t
 conflict_binding_state_transition_check (struct lease *,
                                         dhcp_failover_state_t *,
-                                        binding_state_t);
+                                        binding_state_t, u_int32_t);
 int lease_mine_to_reallocate (struct lease *);
 
 OMAPI_OBJECT_ALLOC_DECL (dhcp_failover_state, dhcp_failover_state_t,
index dd3aef4652f7d976d51e98e111b5fcc089bf2247..38cb5eea80b6f5641a3431843bee27f60c8e9bf2 100644 (file)
@@ -312,7 +312,8 @@ enum dhcp_token {
        END_OF_FILE = 607,
        RECOVER_WAIT = 608,
        SERVER = 609,
-       CONNECT = 610
+       CONNECT = 610,
+       REMOVE = 611
 };
 
 #define is_identifier(x)       ((x) >= FIRST_TOKEN &&  \
index b9b804b958d91b3963be2d5869703a21b4f6c25a..ec4e75ed42e1bc2125172086888061fd644e3671 100644 (file)
@@ -1,3 +1,3 @@
 /* Current version of ISC DHCP Distribution. */
 
-#define DHCP_VERSION   "V3.0rc4"
+#define DHCP_VERSION   "V3.1-unreleased"
index 873ec7dc763afbc366522c61fe40beab8ad59384..c7f0759754b602ba6214aed386fa9731534c2e63 100644 (file)
@@ -293,35 +293,34 @@ void dmalloc_dump_outstanding ()
                    somewhere. */
                if (dp -> file) {
 #if defined (DEBUG_RC_HISTORY)
+                       int i, count, inhistory = 0, noted = 0;
+
                        /* If we have the info, see if this is actually
                           new garbage. */
                        if (rc_history_count < RC_HISTORY_MAX) {
-                               int i, printit = 0, inhistory = 0, prefcnt = 0;
-                               i = rc_history_index - rc_history_count;
-                               if (i < 0)
-                                       i += RC_HISTORY_MAX;
-                               do {
-                                   if (rc_history [i].addr == dp + 1) {
-                                       if (rc_history [i].refcnt == 1 &&
-                                           prefcnt == 0 && !printit) {
-                                               printit = 1;
-                                               inhistory = 1;
-                                               log_info ("  %s(%d): %d",
-                                                         dp -> file,
-                                                         dp -> line,
-                                                         dp -> size);
-                                       }
-                                       prefcnt = rc_history [i].refcnt;
-                                       if (printit)
-                                               print_rc_hist_entry (i);
-                                   }
-                                   if (++i == RC_HISTORY_MAX)
-                                           i = 0;
-                               } while (i != rc_history_index);
-                               if (!inhistory)
-                                       log_info ("  %s(%d): %d", dp -> file,
-                                                 dp -> line, dp -> size);
+                           count = rc_history_count;
                        } else
+                           count = RC_HISTORY_MAX;
+                       i = rc_history_index - 1;
+                       if (i < 0)
+                               i += RC_HISTORY_MAX;
+
+                       do {
+                           if (rc_history [i].addr == dp + 1) {
+                               inhistory = 1;
+                               if (!noted) {
+                                   log_info ("  %s(%d): %d", dp -> file,
+                                             dp -> line, dp -> size);
+                                   noted = 1;
+                               }
+                               print_rc_hist_entry (i);
+                               if (!rc_history [i].refcnt)
+                                   break;
+                           }
+                           if (--i < 0)
+                               i = RC_HISTORY_MAX - 1;
+                       } while (count--);
+                       if (!inhistory)
 #endif
                                log_info ("  %s(%d): %d",
                                          dp -> file, dp -> line, dp -> size);
@@ -516,16 +515,20 @@ isc_result_t omapi_object_dereference (omapi_object_t **h,
                        extra_references = 0;
                        for (p = (*h) -> inner;
                             p && !extra_references; p = p -> inner) {
-                               extra_references += p -> refcnt - 1;
-                               if (p -> inner)
+                               extra_references += p -> refcnt;
+                               if (p -> inner && p -> inner -> outer == p)
+                                       --extra_references;
+                               if (p -> outer)
                                        --extra_references;
                                if (p -> handle)
                                        --extra_references;
                        }
                        for (p = (*h) -> outer;
                             p && !extra_references; p = p -> outer) {
-                               extra_references += p -> refcnt - 1;
-                               if (p -> outer)
+                               extra_references += p -> refcnt;
+                               if (p -> outer && p -> outer -> inner == p)
+                                       --extra_references;
+                               if (p -> inner)
                                        --extra_references;
                                if (p -> handle)
                                        --extra_references;
@@ -549,6 +552,11 @@ isc_result_t omapi_object_dereference (omapi_object_t **h,
                                ((*h) -> type -> freer (*h, file, line));
                        else
                                dfree (*h, file, line);
+               } else {
+                       (*h) -> refcnt--;
+                       if (!(*h) -> type -> freer)
+                               rc_register (file, line,
+                                            h, *h, (*h) -> refcnt);
                }
        } else {
                (*h) -> refcnt--;
index df811b39159a3ed8352450ae6055d84e83e7b864..43ad0a96b37bb9e9d09937d03a0c112bce17a2a3 100644 (file)
@@ -273,6 +273,7 @@ void omapi_connection_register (omapi_connection_object_t *obj,
                return;
        }
 
+#if defined (TRACING)
        if (trace_record ()) {
                /* Connection registration packet:
                   
@@ -305,6 +306,7 @@ void omapi_connection_register (omapi_connection_object_t *obj,
                status = trace_write_packet_iov (trace_connect,
                                                 iov_count, iov, file, line);
        }
+#endif
 }
 
 static void trace_connect_input (trace_type_t *ttype,
index 3cd85f7fc62312df69f3d7d88fe76443b095ef33..77fa36e91470b3e150dc6a414afd9c6557282022 100644 (file)
@@ -3,7 +3,7 @@
    Routines for manipulating hash tables... */
 
 /*
- * Copyright (c) 1995-2000 Internet Software Consortium.
+ * Copyright (c) 1995-2001 Internet Software Consortium.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -43,7 +43,7 @@
 
 #ifndef lint
 static char copyright[] =
-"$Id: hash.c,v 1.1 2000/08/01 22:55:07 neild Exp $ Copyright (c) 1995-2000 The Internet Software Consortium.  All rights reserved.\n";
+"$Id: hash.c,v 1.2 2001/05/17 19:03:57 mellon Exp $ Copyright (c) 1995-2000 The Internet Software Consortium.  All rights reserved.\n";
 #endif /* not lint */
 
 #include <omapip/omapip_p.h>
index 8c0d7f4e4a11144dd622b186e6778771384398b7..41c1f21f09d7ba45659d88a1d4084d121ff79dfc 100644 (file)
@@ -54,13 +54,10 @@ isc_result_t omapi_message_new (omapi_object_t **o, const char *file, int line)
        omapi_object_t *g;
        isc_result_t status;
 
-       m = dmalloc (sizeof *m, file, line);
-       if (!m)
-               return ISC_R_NOMEMORY;
-       memset (m, 0, sizeof *m);
-       m -> type = omapi_type_message;
-       rc_register (file, line, &m, m, m -> refcnt);
-       m -> refcnt = 1;
+       m = (omapi_message_object_t *)0;
+       status = omapi_message_allocate (&m, file, line);
+       if (status != ISC_R_SUCCESS)
+               return status;
 
        g = (omapi_object_t *)0;
        status = omapi_generic_new (&g, file, line);
@@ -84,7 +81,7 @@ isc_result_t omapi_message_new (omapi_object_t **o, const char *file, int line)
        }
 
        status = omapi_object_reference (o, (omapi_object_t *)m, file, line);
-       omapi_object_dereference ((omapi_object_t **)&m, file, line);
+       omapi_message_dereference (&m, file, line);
        omapi_object_dereference (&g, file, line);
        if (status != ISC_R_SUCCESS)
                return status;
@@ -369,7 +366,36 @@ static const char *omapi_message_op_name(int op) {
 }
 #endif
 
+static isc_result_t
+omapi_message_process_internal (omapi_object_t *, omapi_object_t *);
+
 isc_result_t omapi_message_process (omapi_object_t *mo, omapi_object_t *po)
+{
+       isc_result_t status;
+#if defined (DEBUG_MEMORY_LEAKAGE)
+       unsigned long previous_outstanding = dmalloc_outstanding;
+#endif
+
+       status = omapi_message_process_internal (mo, po);
+
+#if defined (DEBUG_MEMORY_LEAKAGE) && 0
+       log_info ("generation %ld: %ld new, %ld outstanding, %ld long-term",
+                 dmalloc_generation,
+                 dmalloc_outstanding - previous_outstanding,
+                 dmalloc_outstanding, dmalloc_longterm);
+#endif
+#if (defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL)) && 0
+       dmalloc_dump_outstanding ();
+#endif
+#if defined (DEBUG_RC_HISTORY_EXHAUSTIVELY) && 0
+       dump_rc_history ();
+#endif
+
+       return status;
+}
+
+static isc_result_t
+omapi_message_process_internal (omapi_object_t *mo, omapi_object_t *po)
 {
        omapi_message_object_t *message, *m;
        omapi_object_t *object = (omapi_object_t *)0;
index 17b37cf0ee43268382b7e3dfc28e10083dfa9a40..c8ae79fb34800de3ab19293f0129711c36fa7efa 100644 (file)
@@ -357,6 +357,10 @@ isc_result_t omapi_protocol_signal_handler (omapi_object_t *h,
        u_int16_t nlen;
        u_int32_t vlen;
        u_int32_t th;
+#if defined (DEBUG_MEMORY_LEAKAGE)
+       unsigned long previous_outstanding = 0xBEADCAFE;
+       unsigned long connect_outstanding = 0xBEADCAFE;
+#endif
 
        if (h -> type != omapi_type_protocol) {
                /* XXX shouldn't happen.   Put an assert here? */
@@ -365,6 +369,9 @@ isc_result_t omapi_protocol_signal_handler (omapi_object_t *h,
        p = (omapi_protocol_object_t *)h;
 
        if (!strcmp (name, "connect")) {
+#if defined (DEBUG_MEMORY_LEAKAGE)
+               connect_outstanding = dmalloc_outstanding;
+#endif
                /* Send the introductory message. */
                status = omapi_protocol_send_intro
                        (h, OMAPI_PROTOCOL_VERSION,
@@ -389,6 +396,26 @@ isc_result_t omapi_protocol_signal_handler (omapi_object_t *h,
                }
        }
 
+       /* If we get a disconnect, dump memory usage. */
+       if (!strcmp (name, "disconnect")
+#if defined (DEBUG_MEMORY_LEAKAGE)
+            && connect_outstanding != 0xBEADCAFE
+#endif
+               ) {
+#if defined (DEBUG_MEMORY_LEAKAGE)
+               log_info ("generation %ld: %ld new, %ld outstanding, %ld%s",
+                         dmalloc_generation,
+                         dmalloc_outstanding - previous_outstanding,
+                         dmalloc_outstanding, dmalloc_longterm, " long-term");
+#endif
+#if (defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL))
+               dmalloc_dump_outstanding ();
+#endif
+#if defined (DEBUG_RC_HISTORY_EXHAUSTIVELY)
+               dump_rc_history ();
+#endif
+       }
+
        /* Not a signal we recognize? */
        if (strcmp (name, "ready")) {
                if (p -> inner && p -> inner -> type -> signal_handler)
@@ -449,6 +476,24 @@ isc_result_t omapi_protocol_signal_handler (omapi_object_t *h,
                /* If we already have the data, fall through. */
 
              case omapi_protocol_header_wait:
+#if defined (DEBUG_MEMORY_LEAKAGE)
+               if (previous_outstanding != 0xBEADCAFE) {
+                       log_info ("%s %ld: %ld new, %ld outstanding, %ld%s",
+                                 "generation", dmalloc_generation,
+                                 dmalloc_outstanding - previous_outstanding,
+                                 dmalloc_outstanding, dmalloc_longterm,
+                                 " long-term");
+#endif
+#if (defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL))
+                       dmalloc_dump_outstanding ();
+#endif
+#if defined (DEBUG_RC_HISTORY_EXHAUSTIVELY)
+                       dump_rc_history ();
+#endif
+#if defined (DEBUG_MEMORY_LEAKAGE)
+               }
+               previous_outstanding = dmalloc_outstanding;
+#endif
                status = omapi_message_new ((omapi_object_t **)&p -> message,
                                            MDL);
                if (status != ISC_R_SUCCESS) {
@@ -690,7 +735,21 @@ isc_result_t omapi_protocol_signal_handler (omapi_object_t *h,
                }
 
                omapi_message_dereference (&p -> message, MDL);
-
+#if defined (DEBUG_MEMORY_LEAKAGE)
+               log_info ("generation %ld: %ld new, %ld outstanding, %ld%s",
+                         dmalloc_generation,
+                         dmalloc_outstanding - previous_outstanding,
+                         dmalloc_outstanding, dmalloc_longterm, " long-term");
+#endif
+#if (defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL))
+               dmalloc_dump_outstanding ();
+#endif
+#if defined (DEBUG_RC_HISTORY_EXHAUSTIVELY)
+               dump_rc_history ();
+#endif
+#if defined (DEBUG_MEMORY_LEAKAGE)
+               previous_outstanding = 0xBEADCAFE;
+#endif
                /* Now wait for the next message. */
                goto to_header_wait;            
 
index 40a4fb99e5b4437dd1ac9bcb092ce3fe417a3256..6d2e8cc3597d14d2e9c576a01059a7b2a6486c5a 100644 (file)
@@ -364,7 +364,9 @@ isc_result_t omapi_set_value_str (omapi_object_t *h,
                return status;
        memcpy (nds -> value, name, strlen (name));
 
-       return omapi_set_value (h, id, nds, value);
+       status = omapi_set_value (h, id, nds, value);
+       omapi_data_string_dereference (&nds, MDL);
+       return status;
 }
 
 isc_result_t omapi_set_boolean_value (omapi_object_t *h, omapi_object_t *id,
@@ -504,9 +506,12 @@ isc_result_t omapi_get_value_str (omapi_object_t *h,
        for (outer = h; outer -> outer; outer = outer -> outer)
                ;
        if (outer -> type -> get_value)
-               return (*(outer -> type -> get_value)) (outer,
-                                                       id, nds, value);
-       return ISC_R_NOTFOUND;
+               status = (*(outer -> type -> get_value)) (outer,
+                                                         id, nds, value);
+       else
+               status = ISC_R_NOTFOUND;
+       omapi_data_string_dereference (&nds, MDL);
+       return status;
 }
 
 isc_result_t omapi_stuff_values (omapi_object_t *c,
index 42972373a8797e51757759b6efc4133b97822e1f..019876f382669f7b7c7d80e22010358fd85e0bfd 100644 (file)
@@ -43,7 +43,7 @@
 
 #ifndef lint
 static char copyright[] =
-"$Id: bootp.c,v 1.69 2001/02/12 20:51:26 mellon Exp $ Copyright (c) 1995-2000 The Internet Software Consortium.  All rights reserved.\n";
+"$Id: bootp.c,v 1.70 2001/05/17 19:04:03 mellon Exp $ Copyright (c) 1995-2000 The Internet Software Consortium.  All rights reserved.\n";
 #endif /* not lint */
 
 #include "dhcpd.h"
@@ -341,7 +341,6 @@ void bootp (packet)
 
        /* We're done with the option state. */
        option_state_dereference (&options, MDL);
-       static_lease_dereference (lease, MDL);
 
        /* Set up the hardware destination address... */
        hto.hbuf [0] = packet -> raw -> htype;
@@ -403,10 +402,8 @@ void bootp (packet)
       out:
        if (options)
                option_state_dereference (&options, MDL);
-       if (lease) {
-               static_lease_dereference (lease, MDL);
+       if (lease)
                lease_dereference (&lease, MDL);
-       }
        if (hp)
                host_dereference (&hp, MDL);
        if (host)
index 863b93996e3fdd36068393f009215dc7117337ce..72503428292db4609d631c9bb14dd967c9d2e267 100644 (file)
 
 #ifndef lint
 static char copyright[] =
-"$Id: db.c,v 1.63 2001/03/15 23:21:25 mellon Exp $ Copyright (c) 1995-2000 The Internet Software Consortium.  All rights reserved.\n";
+"$Id: db.c,v 1.64 2001/05/17 19:04:04 mellon Exp $ Copyright (c) 1995-2000 The Internet Software Consortium.  All rights reserved.\n";
 #endif /* not lint */
 
 #include "dhcpd.h"
 #include <ctype.h>
+#include "version.h"
 
 FILE *db_file;
 
@@ -741,7 +742,9 @@ void new_lease_file ()
                 "confusing to you, we sincerely\n");
        fprintf (db_file, "# apologize.   Seriously, though - don't ask.\n");
        fprintf (db_file, "# The format of this file is documented in the %s",
-                "dhcpd.leases(5) manual page.\n\n");
+                "dhcpd.leases(5) manual page.\n");
+       fprintf (db_file, "# This lease file was written by isc-dhcp-%s\n\n",
+                DHCP_VERSION);
 
        /* Write out all the leases that we know of... */
        counting = 0;
index a7308ac97114f32651b8860cbdfad40287807c24..1b4f73176622fbfe2f7417c3b2c2941fc4bd783d 100644 (file)
@@ -43,7 +43,7 @@
 
 #ifndef lint
 static char copyright[] =
-"$Id: dhcp.c,v 1.192 2001/05/03 18:22:58 mellon Exp $ Copyright (c) 1995-2001 The Internet Software Consortium.  All rights reserved.\n";
+"$Id: dhcp.c,v 1.193 2001/05/17 19:04:05 mellon Exp $ Copyright (c) 1995-2001 The Internet Software Consortium.  All rights reserved.\n";
 #endif /* not lint */
 
 #include "dhcpd.h"
@@ -476,6 +476,16 @@ void dhcprequest (packet, ms_nulltp, ip_lease)
                                goto out;
                        }
                }
+
+               /* Don't let a client allocate a lease using DHCPREQUEST
+                  if the lease isn't ours to allocate. */
+               if ((lease -> binding_state == FTS_FREE &&
+                    peer -> i_am == secondary) ||
+                   (lease -> binding_state == FTS_BACKUP &&
+                    peer -> i_am == primary)) {
+                       log_debug ("%s: expired", msgbuf);
+                       goto out;
+               }
        } else
                peer = (dhcp_failover_state_t *)0;
 #endif
@@ -1579,7 +1589,6 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp)
                                          d1.data [0]);
                                data_string_forget (&d1, MDL);
                                free_lease_state (state, MDL);
-                               static_lease_dereference (lease, MDL);
                                return;
                        }
                        data_string_forget (&d1, MDL);
@@ -1639,7 +1648,6 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp)
                if (!ignorep)
                        log_info ("%s: unknown client", msg);
                free_lease_state (state, MDL);
-               static_lease_dereference (lease, MDL);
                return;
        } 
 
@@ -1656,7 +1664,6 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp)
                if (!ignorep)
                        log_info ("%s: bootp disallowed", msg);
                free_lease_state (state, MDL);
-               static_lease_dereference (lease, MDL);
                return;
        } 
 
@@ -1673,7 +1680,6 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp)
                if (!ignorep)
                        log_info ("%s: booting disallowed", msg);
                free_lease_state (state, MDL);
-               static_lease_dereference (lease, MDL);
                return;
        }
 
@@ -1710,7 +1716,6 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp)
                                                  msg);
                                        free_lease_state (state, MDL);
                                        /* XXX probably not necessary: */
-                                       static_lease_dereference (lease, MDL);
                                        return;
                                }
                        }
@@ -1743,7 +1748,6 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp)
                log_info ("%s: can't allocate temporary lease structure: %s",
                          msg, isc_result_totext (result));
                free_lease_state (state, MDL);
-               static_lease_dereference (lease, MDL);
                return;
        }
                
@@ -2096,7 +2100,6 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp)
                                      offer == DHCPACK, offer == DHCPACK)) {
                        log_info ("%s: database update failed", msg);
                        free_lease_state (state, MDL);
-                       static_lease_dereference (lease, MDL);
                        lease_dereference (&lt, MDL);
                        return;
                }
@@ -2475,7 +2478,6 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp)
                ++outstanding_pings;
        } else {
                lease -> timestamp = cur_time;
-               static_lease_dereference (lease, MDL);
                dhcp_reply (lease);
        }
 }
@@ -3366,38 +3368,6 @@ int mockup_lease (struct lease **lp, struct packet *packet,
        return 1;
 }
 
-/* Dereference all dynamically-allocated information that may be dangling
-   off of a static lease.   Otherwise, once ack_lease returns, the information
-   dangling from the lease will be lost, so reference counts will be screwed
-   up and memory leaks will occur. */
-
-void static_lease_dereference (lease, file, line)
-       struct lease *lease;
-       const char *file;
-       int line;
-{
-       if (!(lease -> flags & STATIC_LEASE))
-               return;
-       if (lease -> on_release)
-               executable_statement_dereference (&lease -> on_release,
-                                                 file, line);
-       if (lease -> on_expiry)
-               executable_statement_dereference (&lease -> on_expiry,
-                                                 file, line);
-       if (lease -> on_commit)
-               executable_statement_dereference (&lease -> on_commit,
-                                                 file, line);
-       if (lease -> scope)
-               binding_scope_dereference (&lease -> scope, file, line);
-       if (lease -> agent_options)
-               option_chain_head_dereference (&lease -> agent_options,
-                                              file, line);
-       if (lease -> uid != lease -> uid_buf) {
-               dfree (lease -> uid, file, line);
-               lease -> uid = (unsigned char *)0;
-       }
-}
-
 /* Look through all the pools in a list starting with the specified pool
    for a free lease.   We try to find a virgin lease if we can.   If we
    don't find a virgin lease, we try to find a non-virgin lease that's
index ec6f99e7c160f09af5b7aa60c1ae2d89db494571..52683af5bd93760fa345dd0695a399b8f1b69fbf 100644 (file)
@@ -43,7 +43,7 @@
 
 #ifndef lint
 static char copyright[] =
-"$Id: failover.c,v 1.53 2001/05/03 18:31:28 mellon Exp $ Copyright (c) 1999-2001 The Internet Software Consortium.  All rights reserved.\n";
+"$Id: failover.c,v 1.54 2001/05/17 19:04:07 mellon Exp $ Copyright (c) 1999-2001 The Internet Software Consortium.  All rights reserved.\n";
 #endif /* not lint */
 
 #include "dhcpd.h"
@@ -1363,6 +1363,7 @@ isc_result_t dhcp_failover_state_transition (dhcp_failover_state_t *state,
                      case resolution_interrupted:
                      case partner_down:
                      case communications_interrupted:
+                     case recover:
                        /* Already in the right state? */
                        if (state -> me.state == startup)
                                return (dhcp_failover_set_state
@@ -1373,14 +1374,6 @@ isc_result_t dhcp_failover_state_transition (dhcp_failover_state_t *state,
                        return dhcp_failover_set_state
                                (state, resolution_interrupted);
                                
-                     case recover:
-                       /* XXX I don't think it makes sense to make a
-                          XXX transition from recover to communications-
-                          XXX interrupted, because then when the connect
-                          XXX occurred, we'd make a transition into
-                          XXX normal, not recover. */
-                       break;  /* Kim says stay in recover. */
-
                      case normal:
                        return dhcp_failover_set_state
                                (state, communications_interrupted);
@@ -1533,6 +1526,9 @@ isc_result_t dhcp_failover_set_state (dhcp_failover_state_t *state,
 {
     enum failover_state saved_state;
     TIME saved_stos;
+    struct pool *p;
+    struct shared_network *s;
+    struct lease *l;
 
     /* First make the transition out of the current state. */
     switch (state -> me.state) {
@@ -1658,6 +1654,27 @@ isc_result_t dhcp_failover_set_state (dhcp_failover_state_t *state,
                    dhcp_failover_send_update_request_all (state);
            break;
 
+         case partner_down:
+           /* For every expired lease, set a timeout for it to become free. */
+            for (s = shared_networks; s; s = s -> next) {
+                for (p = s -> pools; p; p = p -> next) {
+                   if (p -> failover_peer == state) {
+                       for (l = p -> expired; l; l = l -> next)
+                           l -> tsfp = state -> me.stos + state -> mclt;
+                       if (p -> next_event_time >
+                           state -> me.stos + state -> mclt) {
+                           p -> next_event_time =
+                                       state -> me.stos + state -> mclt;
+                           add_timeout (p -> next_event_time, pool_timer, p,
+                                        (tvref_t)pool_reference,
+                                                (tvunref_t)pool_dereference);
+                       }
+                   }
+               }
+           }
+           break;
+                               
+
          default:
            break;
     }
@@ -2307,7 +2324,6 @@ int dhcp_failover_queue_ack (dhcp_failover_state_t *state,
                             (tvunref_t)dhcp_failover_state_dereference);
        }
 
-
        return 1;
 }
 
@@ -4234,13 +4250,13 @@ isc_result_t dhcp_failover_process_bind_update (dhcp_failover_state_t *state,
                if (state -> me.state == normal) {
                        new_binding_state =
                                (normal_binding_state_transition_check
-                                (lease, state,
-                                 msg -> binding_status));
+                                (lease, state, msg -> binding_status,
+                                 msg -> potential_expiry));
                } else {
                        new_binding_state =
                                (conflict_binding_state_transition_check
-                                (lease, state,
-                                 msg -> binding_status));
+                                (lease, state, msg -> binding_status,
+                                 msg -> potential_expiry));
                }
                if (new_binding_state != msg -> binding_status) {
                        char outbuf [100];
@@ -4318,8 +4334,20 @@ isc_result_t dhcp_failover_process_bind_ack (dhcp_failover_state_t *state,
        if (msg -> options_present & FTB_POTENTIAL_EXPIRY) {
                /* XXX it could be a problem to do this directly if the
                   XXX lease is sorted by tsfp. */
-               lease -> tsfp = msg -> potential_expiry;
-               write_lease (lease);
+               if (lease -> binding_state == FTS_EXPIRED) {
+                       lease -> next_binding_state = FTS_FREE;
+                   supersede_lease (lease, (struct lease *)0, 0, 1, 0);
+                   write_lease (lease);
+                   if (state -> me.state == normal)
+                       commit_leases ();
+               } else {
+                   lease -> tsfp = msg -> potential_expiry;
+                   write_lease (lease);
+#if 0 /* XXX This might be needed. */
+                   if (state -> me.state == normal)
+                       commit_leases ();
+#endif
+               }
        }
 
       unqueue:
@@ -4639,7 +4667,8 @@ int load_balance_mine (struct packet *packet, dhcp_failover_state_t *state)
 binding_state_t
 normal_binding_state_transition_check (struct lease *lease,
                                       dhcp_failover_state_t *state,
-                                      binding_state_t binding_state)
+                                      binding_state_t binding_state,
+                                      u_int32_t tsfp)
 {
        binding_state_t new_state;
 
@@ -4688,8 +4717,7 @@ normal_binding_state_transition_check (struct lease *lease,
                      case FTS_BACKUP:
                        /* Can't set a lease to free or backup until the
                           peer agrees that it's expired. */
-                       /* XXX but have we updated tsfp yet? */
-                       if (lease -> tsfp > cur_time) {
+                       if (tsfp > cur_time) {
                                new_state = lease -> binding_state;
                                goto out;
                        }
@@ -4716,8 +4744,7 @@ normal_binding_state_transition_check (struct lease *lease,
                      case FTS_BACKUP:
                        /* Can't set a lease to free or backup until the
                           peer agrees that it's expired. */
-                       /* XXX but have we updated tsfp yet? */
-                       if (lease -> tsfp > cur_time) {
+                       if (tsfp > cur_time) {
                                new_state = lease -> binding_state;
                                goto out;
                        }
@@ -4738,8 +4765,7 @@ normal_binding_state_transition_check (struct lease *lease,
                      case FTS_BACKUP:
                        /* Can't set a lease to free or backup until the
                           peer agrees that it's expired. */
-                       /* XXX but have we updated tsfp yet? */
-                       if (lease -> tsfp > cur_time) {
+                       if (tsfp > cur_time) {
                                new_state = lease -> binding_state;
                                goto out;
                        }
@@ -4758,10 +4784,9 @@ normal_binding_state_transition_check (struct lease *lease,
                switch (binding_state) {
                      case FTS_FREE:
                      case FTS_BACKUP:
-                       /* XXX but have we updated tsfp yet? */
                        /* Can't set a lease to free or backup until the
                           peer agrees that it's expired. */
-                       if (lease -> tsfp > cur_time) {
+                       if (tsfp > cur_time) {
                                new_state = lease -> binding_state;
                                goto out;
                        }
@@ -4811,7 +4836,8 @@ normal_binding_state_transition_check (struct lease *lease,
 binding_state_t
 conflict_binding_state_transition_check (struct lease *lease,
                                         dhcp_failover_state_t *state,
-                                        binding_state_t binding_state)
+                                        binding_state_t binding_state,
+                                        u_int32_t tsfp)
 {
        binding_state_t new_state;
 
index 7c3c1db04124cbbb9fd682dc2b72dc7456199c5b..0e704814cea9224162be587a714306fd3de03d66 100644 (file)
@@ -43,7 +43,7 @@
 
 #ifndef lint
 static char copyright[] =
-"$Id: mdb.c,v 1.67 2001/05/02 07:09:36 mellon Exp $ Copyright (c) 1996-2000 The Internet Software Consortium.  All rights reserved.\n";
+"$Id: mdb.c,v 1.68 2001/05/17 19:04:08 mellon Exp $ Copyright (c) 1996-2000 The Internet Software Consortium.  All rights reserved.\n";
 #endif /* not lint */
 
 #include "dhcpd.h"
@@ -821,6 +821,7 @@ int supersede_lease (comp, lease, commit, propogate, pimmediate)
           requested *after* a DHCP lease has been assigned. */
 
        if (lease -> binding_state != FTS_ABANDONED &&
+           lease -> next_binding_state != FTS_ABANDONED &&
            (comp -> binding_state == FTS_ACTIVE ||
             comp -> binding_state == FTS_RESERVED ||
             comp -> binding_state == FTS_BOOTP) &&
@@ -1066,7 +1067,7 @@ int supersede_lease (comp, lease, commit, propogate, pimmediate)
           and the expiry code sets the timer if there's anything left
           to expire after it's run any outstanding expiry events on
           the pool. */
-       if (commit &&
+       if ((commit || !pimmediate) &&
            comp -> sort_time != MIN_TIME &&
            comp -> sort_time > cur_time &&
            (comp -> sort_time < comp -> pool -> next_event_time ||
@@ -1215,6 +1216,15 @@ void make_binding_state_transition (struct lease *lease)
              case FTS_ABANDONED:
              case FTS_RESET:
                lease -> next_binding_state = FTS_FREE;
+               /* If we are not in partner_down, leases don't go from
+                  EXPIRED to FREE on a timeout - only on an update.
+                  If we're in partner_down, they expire at mclt past
+                  the time we entered partner_down. */
+               if (lease -> pool -> failover_peer &&
+                   lease -> pool -> failover_peer -> me.state == partner_down)
+                       lease -> tsfp =
+                           (lease -> pool -> failover_peer -> me.stos +
+                            lease -> pool -> failover_peer -> mclt);
                break;
 
              case FTS_FREE:
@@ -1445,7 +1455,22 @@ void pool_timer (vpool)
                /* If there's nothing on the queue, skip it. */
                if (!*(lptr [i]))
                        continue;
-               
+
+#if defined (FAILOVER_PROTOCOL)
+               if (pool -> failover_peer &&
+                   pool -> failover_peer -> me.state != partner_down) {
+                       /* The secondary can't remove a lease from the
+                          active state except in partner_down. */
+                       if (i == ACTIVE_LEASES &&
+                           pool -> failover_peer -> i_am == secondary)
+                               continue;
+                       /* Leases in an expired state don't move to
+                          free because of a timeout unless we're in
+                          partner_down. */
+                       if (i == EXPIRED_LEASES)
+                               continue;
+               }
+#endif         
                lease_reference (&lease, *(lptr [i]), MDL);
 
                while (lease) {
index 23b2840b4fa7824836c60d6c6383836b8f715c47..991377c1c211b53d172ed90fd1bbd7d5dd46e938 100644 (file)
@@ -3,7 +3,7 @@
    OMAPI object interfaces for the DHCP server. */
 
 /*
- * Copyright (c) 1999-2000 Internet Software Consortium.
+ * Copyright (c) 1999-2001 Internet Software Consortium.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -50,7 +50,7 @@
 
 #ifndef lint
 static char copyright[] =
-"$Id: omapi.c,v 1.46 2001/05/02 07:11:38 mellon Exp $ Copyright (c) 1999-2000 The Internet Software Consortium.  All rights reserved.\n";
+"$Id: omapi.c,v 1.47 2001/05/17 19:04:09 mellon Exp $ Copyright (c) 1999-2001 The Internet Software Consortium.  All rights reserved.\n";
 #endif /* not lint */
 
 #include "dhcpd.h"
@@ -354,35 +354,43 @@ isc_result_t dhcp_lease_destroy (omapi_object_t *h, const char *file, int line)
                return ISC_R_INVALIDARG;
        lease = (struct lease *)h;
 
-       uid_hash_delete (lease);
+       if (lease -> uid)
+               uid_hash_delete (lease);
        hw_hash_delete (lease);
-       if (lease -> billing_class)
-               class_dereference
-                       (&lease -> billing_class, file, line);
-       if (lease -> uid && lease -> uid != &lease -> uid_buf [0]) {
+
+       if (lease -> on_release)
+               executable_statement_dereference (&lease -> on_release,
+                                                 file, line);
+       if (lease -> on_expiry)
+               executable_statement_dereference (&lease -> on_expiry,
+                                                 file, line);
+       if (lease -> on_commit)
+               executable_statement_dereference (&lease -> on_commit,
+                                                 file, line);
+       if (lease -> scope)
+               binding_scope_dereference (&lease -> scope, file, line);
+
+       if (lease -> agent_options)
+               option_chain_head_dereference (&lease -> agent_options,
+                                              file, line);
+       if (lease -> uid && lease -> uid != lease -> uid_buf) {
                dfree (lease -> uid, MDL);
                lease -> uid = &lease -> uid_buf [0];
                lease -> uid_len = 0;
        }
+
        if (lease -> client_hostname) {
                dfree (lease -> client_hostname, MDL);
                lease -> client_hostname = (char *)0;
        }
+
        if (lease -> host)
                host_dereference (&lease -> host, file, line);
        if (lease -> subnet)
                subnet_dereference (&lease -> subnet, file, line);
        if (lease -> pool)
                pool_dereference (&lease -> pool, file, line);
-       if (lease -> on_expiry)
-               executable_statement_dereference (&lease -> on_expiry,
-                                                 file, line);
-       if (lease -> on_commit)
-               executable_statement_dereference (&lease -> on_commit,
-                                                 file, line);
-       if (lease -> on_release)
-               executable_statement_dereference (&lease -> on_release,
-                                                 file, line);
+
        if (lease -> state) {
                free_lease_state (lease -> state, file, line);
                lease -> state = (struct lease_state *)0;
@@ -390,6 +398,11 @@ isc_result_t dhcp_lease_destroy (omapi_object_t *h, const char *file, int line)
                cancel_timeout (lease_ping_timeout, lease);
                --outstanding_pings; /* XXX */
        }
+
+       if (lease -> billing_class)
+               class_dereference
+                       (&lease -> billing_class, file, line);
+
        return ISC_R_SUCCESS;
 }