]> git.ipfire.org Git - thirdparty/dhcp.git/commitdiff
- Add support for dhcpv6 "Release" messages [rt16905]
authorEvan Hunt <each@isc.org>
Wed, 6 Jun 2007 22:57:32 +0000 (22:57 +0000)
committerEvan Hunt <each@isc.org>
Wed, 6 Jun 2007 22:57:32 +0000 (22:57 +0000)
- Add -x option, which causes running dhclient processes to exist
  gracefully *without* releasing leases [rt16741]
(Merging both at once because the first one depended on the second one)

RELNOTES
client/dhc6.c
client/dhclient.8
client/dhclient.c
client/scripts/bsdos
client/scripts/freebsd
client/scripts/linux
client/scripts/netbsd
client/scripts/openbsd
includes/dhcpd.h

index c088ec2073a2011773a280e9d8c15e1f67e27668..7064897873fee2211a6be2999e1d95583b6de2fe 100644 (file)
--- a/RELNOTES
+++ b/RELNOTES
@@ -61,6 +61,11 @@ suggested fixes to <dhcp-users@isc.org>.
 
 - Fixed a bug in which write_lease() might report a failure incorrectly
 
+- Added support for DHCPv6 Release messages
+
+- Added -x option to dhclient, which triggers dhclient processes
+  to exit gracefully without releasing leases first
+
                        Changes since 4.0.0-20070413
 
 - Old (expired) leases are now cleaned.
index 02f87487ad9f9811d14c82fae4bfdbdcfcfcd748..2e63b7357654e472c0bd188ea816248b872fcf68 100644 (file)
@@ -24,7 +24,7 @@
 
 #ifndef lint
 static char ocopyright[] =
-"$Id: dhc6.c,v 1.5 2007/05/19 18:47:13 dhankins Exp $ Copyright (c) 2006-2007 Internet Systems Consortium.  All rights reserved.\n";
+"$Id: dhc6.c,v 1.6 2007/06/06 22:57:31 each Exp $ Copyright (c) 2006-2007 Internet Systems Consortium.  All rights reserved.\n";
 #endif /* not lint */
 
 #include "dhcpd.h"
@@ -58,10 +58,12 @@ void do_confirm6(void *input);
 void reply_handler(struct packet *packet, struct client_state *client);
 static isc_result_t dhc6_add_ia(struct client_state *client,
                                struct data_string *packet,
-                               struct dhc6_lease *lease);
+                               struct dhc6_lease *lease,
+                                u_int8_t message);
 static void dhc6_merge_lease(struct dhc6_lease *src, struct dhc6_lease *dst);
 void do_select6(void *input);
 void do_refresh6(void *input);
+static void do_release6(void *input);
 static void start_bound(struct client_state *client);
 void bound_handler(struct packet *packet, struct client_state *client);
 void start_renew6(void *input);
@@ -1141,64 +1143,144 @@ do_confirm6(void *input)
                                    &dhcpv6_universe);
 
        /* Append IA's. */
-       memset(&ia_data, 0, sizeof(ia_data));
-       memset(&addr_data, 0, sizeof(addr_data));
-       for (ia = client->active_lease->bindings ; ia != NULL ;
-            ia = ia->next) {
-               if (!buffer_allocate(&ia_data.buffer, 12, MDL)) {
-                       log_error("Unable to allocate memory for IA_NA.");
-                       data_string_forget(&ds, MDL);
-                       return;
-               }
+       if (dhc6_add_ia(client, &ds, client->active_lease,
+                        DHCPV6_CONFIRM) != ISC_R_SUCCESS) {
+               data_string_forget(&ds, MDL);
+               return;
+       }
 
-               /* Copy the IAID into the packet buffer. */
-               memcpy(ia_data.buffer->data, ia->iaid, 4);
-               /* Set t1 and t2 to zero (RFC3315 section 17.1.3) */
-               memset(ia_data.buffer->data + 4, 0, 8);
+       /* Transmit and wait. */
 
-               log_debug("XMT:  X-- IA_NA %s",
-                         print_hex_1(4, ia_data.buffer->data, 55));
+       log_info("XMT: Confirm on %s, interval %ld.",
+                client->name ? client->name : client->interface->name,
+                client->RT);
 
-               for (addr = ia->addrs ; addr != NULL ; addr = addr->next) {
-                       if (addr->address.len != 16) {
-                               log_error("Illegal IPv6 address length (%d), "
-                                         "ignoring.  (%s:%d)",
-                                         addr->address.len, MDL);
-                               continue;
-                       }
+       send_ret = send_packet6(client->interface, ds.data, ds.len,
+                               &DHCPv6DestAddr);
+       if (send_ret != ds.len) {
+               log_error("dhc6: sendpacket6() sent %d of %d bytes",
+                         send_ret, ds.len);
+       }
 
-                       if (!buffer_allocate(&addr_data.buffer, 24, MDL)) {
-                               log_error("Unable to allocate memory for "
-                                         "IAADDR.");
-                               data_string_forget(&ia_data, MDL);
-                               data_string_forget(&ds, MDL);
-                               return;
-                       }
+       data_string_forget(&ds, MDL);
 
-                       /* Copy the address into the packet buffer. */
-                       memcpy(addr_data.buffer->data, addr->address.iabuf,
-                              16);
+       add_timeout(cur_time + client->RT, do_confirm6, client, NULL, NULL);
 
-                       /* Set preferred and max life to zero, per 17.1.3. */
-                       memset(addr_data.buffer->data + 16, 0, 8);
+       dhc6_retrans_advance(client);
+}
 
-                       log_debug("XMT:  | X-- Confirm Address %s",
-                                 piaddr(addr->address));
+/*
+ * Release addresses.
+ */
+void
+start_release6(struct client_state *client)
+{
+       struct data_string packet;
 
-                       append_option(&ia_data, &dhcpv6_universe,
-                                     iaaddr_option, &addr_data);
+        /* Cancel any pending transmissions */
+       cancel_timeout(do_confirm6, client);
+       cancel_timeout(do_select6, client);
+       cancel_timeout(do_refresh6, client);
+       cancel_timeout(do_release6, client);
+        client->state = S_STOPPED;
+
+        /*
+         * It is written:  "The client MUST NOT use any of the addresses it
+         * is releasing as the source address in the Release message or in
+         * any subsequently transmitted message."  So unconfigure now.
+         */
+        unconfigure6(client, "RELEASE6");
+
+       /* Fetch a 24-bit transaction ID. */
+       dhc6_new_xid(client);
+
+       /* Set timers per RFC3315 section 18.1.1. */
+       client->IRT = REL_TIMEOUT;
+       client->MRT = 0;
+       client->MRC = REL_MAX_RC;
+       client->MRD = 0;
 
-                       data_string_forget(&addr_data, MDL);
+       dhc6_retrans_init(client);
+       client->v6_handler = reply_handler;
+
+       /* ("re")transmit the first packet. */
+       do_release6(client);
+}
+/*
+ * do_release6() creates a Release packet and transmits it.
+ */
+static void
+do_release6(void *input)
+{
+       struct sockaddr_in6 unicast, *dest_addr = &DHCPv6DestAddr;
+       struct client_state *client;
+       struct dhc6_ia *ia;
+       struct dhc6_addr *addr;
+       struct data_string ds;
+       struct data_string ia_data;
+       struct data_string addr_data;
+       struct option_cache *oc;
+        struct dhc6_lease *lease;
+       int send_ret;
+
+       client = input;
+
+       if (client->active_lease == NULL)
+               log_fatal("Impossible condition at %s:%d.", MDL);
+
+       if ((client->MRC != 0) && (client->txcount > client->MRC))  {
+               log_info("Max retransmission count exceeded.");
+               return;
+       }
+
+       /*
+        * Check whether the server has sent a unicast option; if so, we can
+        * use the address it specified.
+        */
+       oc = lookup_option(&dhcpv6_universe, lease->options, D6O_UNICAST);
+       if (oc && evaluate_option_cache(&ds, NULL, NULL, NULL,
+                                        lease->options, NULL, &global_scope,
+                                       oc, MDL)) {
+               if (ds.len < 16) {
+                       log_error("Invalid unicast option length %d.", ds.len);
+               } else {
+                       memset(&unicast, 0, sizeof(DHCPv6DestAddr));
+                       unicast.sin6_family = AF_INET6;
+                       unicast.sin6_port = remote_port;
+                       memcpy(&unicast.sin6_addr, ds.data, 16);
+                       dest_addr = &unicast;
                }
 
-               append_option(&ds, &dhcpv6_universe, ia_na_option, &ia_data);
+               data_string_forget(&ds, MDL);
+       }
 
-               data_string_forget(&ia_data, MDL);
+       memset(&ds, 0, sizeof(ds));
+       if (!buffer_allocate(&ds.buffer, 4, MDL)) {
+               log_error("Unable to allocate memory for Release.");
+               return;
        }
 
-       /* Transmit and wait. */
+       ds.data = ds.buffer->data;
+       ds.len = 4;
+       ds.buffer->data[0] = DHCPV6_RELEASE;
+       memcpy(ds.buffer->data + 1, client->dhcpv6_transaction_id, 3);
 
-       log_info("XMT: Confirm on %s, interval %ld.",
+       log_debug("XMT: Forming Release.");
+       make_client6_options(client, &client->sent_options,
+                            client->active_lease, DHCPV6_RELEASE);
+       dhcpv6_universe.encapsulate(&ds, NULL, NULL, client, NULL,
+                                   client->sent_options, &global_scope,
+                                   &dhcpv6_universe);
+
+       /* Append IA's. */
+       if (dhc6_add_ia(client, &ds, client->active_lease,
+                        DHCPV6_RELEASE) != ISC_R_SUCCESS) {
+               data_string_forget(&ds, MDL);
+               return;
+       }
+
+       /* Transmit and wait. */
+       log_info("XMT: Release on %s, interval %ld.",
                 client->name ? client->name : client->interface->name,
                 client->RT);
 
@@ -1211,8 +1293,7 @@ do_confirm6(void *input)
 
        data_string_forget(&ds, MDL);
 
-       add_timeout(cur_time + client->RT, do_confirm6, client, NULL, NULL);
-
+       add_timeout(cur_time + client->RT, do_release6, client, NULL, NULL);
        dhc6_retrans_advance(client);
 }
 
@@ -1998,7 +2079,7 @@ do_select6(void *input)
                                    &dhcpv6_universe);
 
        /* Now append any IA_NA's, and within them any IAADDRs. */
-       if (dhc6_add_ia(client, &ds, lease) != ISC_R_SUCCESS) {
+       if (dhc6_add_ia(client, &ds, lease, DHCPV6_REQUEST) != ISC_R_SUCCESS) {
                data_string_forget(&ds, MDL);
                return;
        }
@@ -2022,12 +2103,11 @@ do_select6(void *input)
 }
 
 /* For each IA in the lease, for each address in the IA, append that
- * information onto the packet-so-far in a "what I would like to have
- * please" fashion.
+ * information onto the packet-so-far.
  */
 static isc_result_t
 dhc6_add_ia(struct client_state *client, struct data_string *packet,
-           struct dhc6_lease *lease)
+           struct dhc6_lease *lease, u_int8_t message)
 {
        struct data_string iads;
        struct data_string addrds;
@@ -2035,79 +2115,144 @@ dhc6_add_ia(struct client_state *client, struct data_string *packet,
        struct dhc6_ia *ia;
        isc_result_t rval = ISC_R_SUCCESS;
        TIME t1, t2;
-       
-       /* Now appended any IA_NA's, and within them any IAADDRs. */
+
        memset(&iads, 0, sizeof(iads));
        memset(&addrds, 0, sizeof(addrds));
-       for (ia = lease->bindings ; ia ; ia = ia->next) {
+       for (ia = lease->bindings;
+             ia != NULL && rval == ISC_R_SUCCESS;
+             ia = ia->next) {
                if (!buffer_allocate(&iads.buffer, 12, MDL)) {
-                       log_error("Unable to allocate memory for IA.");
+                       log_error("Unable to allocate memory for IA_NA.");
+                       rval = ISC_R_NOMEMORY;
                        break;
                }
-               iads.data = iads.buffer->data;
-               iads.len = 12;
 
+               /* Copy the IAID into the packet buffer. */
                memcpy(iads.buffer->data, ia->iaid, 4);
+               iads.data = iads.buffer->data;
+               iads.len = 12;
 
-               t1 = client->config->requested_lease / 2;
-               t2 = t1 + (t1 / 2);
+                switch (message) {
+                      case DHCPV6_REQUEST:
+                      case DHCPV6_RENEW:
+                      case DHCPV6_REBIND:
+                        
+                        t1 = client->config->requested_lease / 2;
+                        t2 = t1 + (t1 / 2);
 #if MAX_TIME > 0xffffffff
-               if (t1 > 0xffffffff)
-                       t1 = 0xffffffff;
-               if (t2 > 0xffffffff)
-                       t2 = 0xffffffff;
+                        if (t1 > 0xffffffff)
+                                t1 = 0xffffffff;
+                        if (t2 > 0xffffffff)
+                                t2 = 0xffffffff;
 #endif
-               putULong(iads.buffer->data + 4, t1);
-               putULong(iads.buffer->data + 8, t2);
+                        putULong(iads.buffer->data + 4, t1);
+                        putULong(iads.buffer->data + 8, t2);
+
+                        log_debug("XMT:  X-- IA_NA %s",
+                                  print_hex_1(4, iads.data, 59));
+                        log_debug("XMT:  | X-- Requested renew  +%u",
+                                  (unsigned) t1);
+                        log_debug("XMT:  | X-- Requested rebind +%u",
+                                  (unsigned) t2);
+                        break;
+
+                      case DHCPV6_CONFIRM:
+                      case DHCPV6_RELEASE:
+                       /* Set t1 and t2 to zero; server will ignore them */
+                        memset(iads.buffer->data + 4, 0, 8);
+                        log_debug("XMT:  X-- IA_NA %s",
+                                  print_hex_1(4, iads.buffer->data, 55));
+
+                        break;
+
+                      default:
+                        log_fatal("Impossible condition at %s:%d.", MDL);
+                }
 
-               log_debug("XMT:  X-- IA_NA %s",
-                         print_hex_1(4, iads.data, 59));
-               log_debug("XMT:  | X-- Requested renew  +%u", (unsigned)t1);
-               log_debug("XMT:  | X-- Requested rebind +%u", (unsigned)t2);
+               for (addr = ia->addrs ; addr != NULL ; addr = addr->next) {
+                       if (addr->address.len != 16) {
+                               log_error("Illegal IPv6 address length (%d), "
+                                         "ignoring.  (%s:%d)",
+                                         addr->address.len, MDL);
+                               continue;
+                       }
 
-               for (addr = ia->addrs ; addr ; addr = addr->next) {
                        if (!buffer_allocate(&addrds.buffer, 24, MDL)) {
                                log_error("Unable to allocate memory for "
                                          "IAADDR.");
+                               rval = ISC_R_NOMEMORY;
                                break;
                        }
+
                        addrds.data = addrds.buffer->data;
                        addrds.len = 24;
 
+                       /* Copy the address into the packet buffer. */
                        memcpy(addrds.buffer->data, addr->address.iabuf, 16);
-                       t1 = client->config->requested_lease;
-                       t2 = t1 + 300;
-                       putULong(addrds.buffer->data + 16, t1);
-                       putULong(addrds.buffer->data + 20, t2);
 
-                       log_debug("XMT:  | | X-- IAADDR %s",
-                                 piaddr(addr->address));
-                       log_debug("XMT:  | | | X-- Preferred lifetime +%u",
-                                 (unsigned)t1);
-                       log_debug("XMT:  | | | X-- Max lifetime +%u",
-                                 (unsigned)t2);
+                        /* Copy in additional information as appropriate */
+                        switch (message) {
+                              case DHCPV6_REQUEST:
+                              case DHCPV6_RENEW:
+                              case DHCPV6_REBIND:
+                                t1 = client->config->requested_lease;
+                                t2 = t1 + 300;
+                                putULong(addrds.buffer->data + 16, t1);
+                                putULong(addrds.buffer->data + 20, t2);
+
+                                log_debug("XMT:  | | X-- IAADDR %s",
+                                          piaddr(addr->address));
+                                log_debug("XMT:  | | | X-- Preferred "
+                                          "lifetime +%u", (unsigned)t1);
+                                log_debug("XMT:  | | | X-- Max lifetime +%u",
+                                          (unsigned)t2);
+
+                                break;
+
+                              case DHCPV6_CONFIRM:
+                               /*
+                                 * Set preferred and max life to zero,
+                                 * per 17.1.3.
+                                 */
+                               memset(addrds.buffer->data + 16, 0, 8);
+                                log_debug("XMT:  | X-- Confirm Address %s",
+                                          piaddr(addr->address));
+                                break;
+
+                              case DHCPV6_RELEASE:
+                                /* Preferred and max life are irrelevant */
+                               memset(addrds.buffer->data + 16, 0, 8);
+                                log_debug("XMT:  | X-- Release Address %s",
+                                          piaddr(addr->address));
+                                break;
+
+                              default:
+                                log_fatal("Impossible condition at %s:%d.",
+                                          MDL);
+                        }
 
                        append_option(&iads, &dhcpv6_universe, iaaddr_option,
-                                     &addrds);
+                                      &addrds);
                        data_string_forget(&addrds, MDL);
                }
 
-               /* It doesn't make sense to make a request without an
+               /*
+                 * It doesn't make sense to make a request without an
                 * address.
                 */
-               if (ia->addrs != NULL) {
+               if (ia->addrs == NULL) {
+                       log_debug("!!!:  V IA_NA has no IAADDRs - removed.");
+                       rval = ISC_R_FAILURE;
+               } else if (rval == ISC_R_SUCCESS) {
                        log_debug("XMT:  V IA_NA appended.");
                        append_option(packet, &dhcpv6_universe, ia_na_option,
                                      &iads);
-               } else {
-                       log_debug("!!!:  V IA_NA has no IAADDRs - removed.");
-                       rval = ISC_R_FAILURE;
                }
 
                data_string_forget(&iads, MDL);
        }
 
-       return rval;
+        return rval;
 }
 
 /* reply_handler() accepts a Reply while we're attempting Select or Renew or
@@ -2153,6 +2298,7 @@ reply_handler(struct packet *packet, struct client_state *client)
        cancel_timeout(do_confirm6, client);
        cancel_timeout(do_select6, client);
        cancel_timeout(do_refresh6, client);
+       cancel_timeout(do_release6, client);
 
        /* Action was taken, so now that we've torn down our scheduled
         * retransmissions, return.
@@ -2165,6 +2311,16 @@ reply_handler(struct packet *packet, struct client_state *client)
                client->selected_lease = NULL;
        }
 
+        /* If this is in response to a Release, clean up and return. */
+       if (client->state == S_STOPPED) {
+               if (client->active_lease == NULL)
+                       log_fatal("Impossible condition at %s:%d.", MDL);
+
+                dhc6_lease_destroy(client->active_lease, MDL);
+                client->active_lease = NULL;
+                return;
+        }
+
        /* If this is in response to a confirm, we use the lease we've
         * already got, not the reply we were sent.
         */
@@ -2769,7 +2925,9 @@ do_refresh6(void *input)
                                    client->sent_options, &global_scope,
                                    &dhcpv6_universe);
 
-       if (dhc6_add_ia(client, &ds, lease) != ISC_R_SUCCESS) {
+        /* Append IA's */
+       if (dhc6_add_ia(client, &ds, lease,
+                        client->refresh_type) != ISC_R_SUCCESS) {
                data_string_forget(&ds, MDL);
                return;
        }
@@ -2944,6 +3102,33 @@ do_expire(void *input)
        dhc6_check_times(client);
 }
 
+/*
+ * Run client script to unconfigure interface.
+ * Called with reason STOP6 when dhclient -x is run, or with reason
+ * RELEASE6 when server has replied to a Release message.
+ */
+void
+unconfigure6(struct client_state *client, const char *reason)
+{
+       struct dhc6_lease *lease;
+       struct dhc6_ia *ia;
+       struct dhc6_addr *addr;
+
+       if (client->active_lease == NULL)
+               return;
+
+       for (ia = client->active_lease->bindings ; ia != NULL ; ia = ia->next) {
+               for (addr = ia->addrs ; addr != NULL ; addr = addr->next) {
+                       script_init(client, reason, NULL);
+                       dhc6_marshall_values("old_", client, lease, ia, addr);
+                       script_go(client);
+                
+                       if (client->config->do_forward_update)
+                               client_dns_update(client, 0, 0, &addr->address);
+               }
+       }
+}
+
 /* make_client6_options() fetches option caches relevant to the client's
  * scope and places them into the sent_options cache.  This cache is later
  * used to populate DHCPv6 output packets with options.
index e2eb4b807512198ffc3add42fdb016900163562a..9844a69aae4a55c98710cb343cca64e250bcf185 100644 (file)
@@ -1,4 +1,4 @@
-.\"    $Id: dhclient.8,v 1.23 2007/05/19 19:16:23 dhankins Exp $
+.\"    $Id: dhclient.8,v 1.24 2007/06/06 22:57:32 each Exp $
 .\"
 .\" Copyright (c) 2004,2007 by Internet Systems Consortium, Inc. ("ISC")
 .\" Copyright (c) 1996-2003 by Internet Software Consortium
@@ -55,6 +55,9 @@ dhclient - Dynamic Host Configuration Protocol Client
 .B -r
 ]
 [
+.B -x
+]
+[
 .B -lf
 .I lease-file
 ]
@@ -240,6 +243,17 @@ The
 flag explicitly releases the current lease, and once the lease has been
 released, the client exits.
 .PP
+If the client is killed by a signal (for example at shutdown or reboot)
+it won't execute the
+.B dhclient-script (8)
+at exit. However if you shut the client down gracefully with
+.B -r
+or
+.B -x
+it will execute
+.B dhclient-script (8)
+at shutdown with the specific reason for calling the script set.
+.PP
 The
 .B -1
 flag will cause dhclient to try once to get a lease.  If it fails, dhclient
index ee2a0e14f884f74efe798fb54c8738d9fc4f0070..5466af928bc7ee4280d6fe70785aaaffb41827dd 100644 (file)
@@ -32,7 +32,7 @@
 
 #ifndef lint
 static char ocopyright[] =
-"$Id: dhclient.c,v 1.151 2007/05/21 18:16:54 dhankins Exp $ Copyright (c) 2004-2007 Internet Systems Consortium.  All rights reserved.\n";
+"$Id: dhclient.c,v 1.152 2007/06/06 22:57:32 each Exp $ Copyright (c) 2004-2007 Internet Systems Consortium.  All rights reserved.\n";
 #endif /* not lint */
 
 #include "dhcpd.h"
@@ -82,8 +82,6 @@ char *mockup_relay = NULL;
 
 static void usage PROTO ((void));
 
-void do_release(struct client_state *);
-
 static isc_result_t write_duid(struct data_string *duid);
 
 int 
@@ -95,6 +93,7 @@ main(int argc, char **argv) {
        unsigned seed;
        char *server = (char *)0;
        isc_result_t status;
+       int exit_mode = 0;
        int release_mode = 0;
        omapi_object_t *listener;
        isc_result_t result;
@@ -159,6 +158,10 @@ main(int argc, char **argv) {
                } else if (!strcmp(argv[i], "-r")) {
                        release_mode = 1;
                        no_daemon = 1;
+                } else if (!strcmp (argv [i], "-x")) { /* eXit, no release */
+                        release_mode = 0;
+                        no_daemon = 0;
+                        exit_mode = 1;
                } else if (!strcmp (argv [i], "-p")) {
                        if (++i == argc)
                                usage ();
@@ -274,7 +277,7 @@ main(int argc, char **argv) {
                log_fatal("Impossible condition at %s:%d.", MDL);
 
        /* first kill of any currently running client */
-       if (release_mode) {
+       if (release_mode || exit_mode) {
                FILE *pidfd;
                pid_t oldpid;
                long temp;
@@ -375,7 +378,7 @@ main(int argc, char **argv) {
                        log_info ("No broadcast interfaces found - exiting.");
                        exit (0);
                }
-       } else if (!release_mode) {
+       } else if (!release_mode && !exit_mode) {
                /* Call the script with the list of interfaces. */
                for (ip = interfaces; ip; ip = ip -> next) {
                        /* If interfaces were specified, don't configure
@@ -441,6 +444,14 @@ main(int argc, char **argv) {
                for (ip = interfaces ; ip != NULL ; ip = ip->next) {
                        for (client = ip->client ; client != NULL ;
                             client = client->next) {
+                                if (release_mode) {
+                                        start_release6(client);
+                                        continue;
+                                } else if (exit_mode) {
+                                        unconfigure6(client, "STOP6");
+                                        continue;
+                                }
+
                                /* If we have a previous binding, Confirm
                                 * that we can (or can't) still use it.
                                 */
@@ -457,7 +468,9 @@ main(int argc, char **argv) {
                        ip->flags |= INTERFACE_RUNNING;
                        for (client = ip->client ; client ;
                             client = client->next) {
-                               if (release_mode)
+                                if (exit_mode)
+                                        state_stop(client);
+                                else if (release_mode)
                                        do_release(client);
                                else {
                                        client->state = S_INIT;
@@ -471,7 +484,7 @@ main(int argc, char **argv) {
                }
        }
 
-       if (release_mode)
+       if (release_mode || exit_mode)
                return 0;
 
        /* Start up a listener for the object management API protocol. */
@@ -527,7 +540,7 @@ static void usage ()
        log_info (arr);
        log_info (url);
 
-       log_error ("Usage: dhclient [-1dvr] [-nw] [-p <port>] %s",
+       log_error ("Usage: dhclient [-1dvrx] [-nw] [-p <port>] %s",
                   "[-s server]");
        log_error ("                [-cf config-file] [-lf lease-file]%s",
                   "[-pf pid-file] [-e VAR=val]");
@@ -1003,22 +1016,20 @@ void state_stop (cpp)
        void *cpp;
 {
        struct client_state *client = cpp;
-       int i;
 
        /* Cancel all timeouts. */
-       cancel_timeout (state_selecting, client);
-       cancel_timeout (send_discover, client);
-       cancel_timeout (send_request, client);
-       cancel_timeout (state_bound, client);
+       cancel_timeout(state_selecting, client);
+       cancel_timeout(send_discover, client);
+       cancel_timeout(send_request, client);
+       cancel_timeout(state_bound, client);
 
        /* If we have an address, unconfigure it. */
-       if (client -> active) {
-               script_init (client, "STOP", client -> active -> medium);
-               script_write_params (client, "old_", client -> active);
-               if (client -> alias)
-                       script_write_params (client, "alias_",
-                                            client -> alias);
-               script_go (client);
+       if (client->active) {
+               script_init(client, "STOP", client->active->medium);
+               script_write_params(client, "old_", client->active);
+               if (client->alias)
+                       script_write_params(client, "alias_", client->alias);
+               script_go(client);
        }
 }  
 
@@ -3323,6 +3334,7 @@ isc_result_t dhcp_set_control_state (control_object_state_t oldstate,
                }
            }
        }
+
        if (newstate == server_shutdown)
                add_timeout (cur_time + 1, shutdown_exit, 0, 0, 0);
        return ISC_R_SUCCESS;
index de3b18d78860d5918b18315e53b544622687b7f9..12077f0ceb49970c32ce2af92c995df9f00a3364 100755 (executable)
@@ -279,7 +279,7 @@ if [ ${reason} = DEPREF6 ] ; then
   exit_with_hooks 0
 fi
 
-if [ ${reason} = EXPIRE6 ] ; then
+if [ ${reason} = EXPIRE6 -o ${reason} = RELEASE6 -o ${reason} = STOP6 ] ; then
   if [ x${old_ip6_address} = x ] || [ x${old_ip6_prefixlen} = x ] ; then
     exit_with_hooks 2;
   fi
index b4567a50c317f0a41f35a544292663bb8ef53930..05c41a97675b5d40b79a7999081c07b92a2b63fd 100755 (executable)
@@ -1,6 +1,6 @@
 #!/bin/sh
 #
-# $Id: freebsd,v 1.18 2007/05/18 17:18:05 dhankins Exp $
+# $Id: freebsd,v 1.19 2007/06/06 22:57:32 each Exp $
 #
 # $FreeBSD$
 
@@ -334,7 +334,7 @@ if [ ${reason} = DEPREF6 ] ; then
   exit_with_hooks 0
 fi
 
-if [ ${reason} = EXPIRE6 ] ; then
+if [ ${reason} = EXPIRE6 -o ${reason} = RELEASE6 -o ${reason} = STOP6 ] ; then
   if [ x${old_ip6_address} = x ] || [ x${old_ip6_prefixlen} = x ] ; then
     exit_with_hooks 2;
   fi
index ee3ef42d6e8d202aab0c74272d208fd8d83bab8f..6ac25dd4958527933e9467b757e573763d981d05 100755 (executable)
@@ -276,7 +276,7 @@ if [ ${reason} = DEPREF6 ] ; then
   exit_with_hooks 0
 fi
 
-if [ ${reason} = EXPIRE6 ] ; then
+if [ ${reason} = EXPIRE6 -o ${reason} = RELEASE6 -o ${reason} = STOP6 ] ; then
   if [ x${old_ip6_address} = x ] || [ x${old_ip6_prefixlen} = x ] ; then
     exit_with_hooks 2;
   fi
index 5629ee785de1d122c8423e4fd0f381d1aa7b1946..a5394796278b626022dc34a9fd516f7943df793a 100755 (executable)
@@ -279,7 +279,7 @@ if [ ${reason} = DEPREF6 ] ; then
   exit_with_hooks 0
 fi
 
-if [ ${reason} = EXPIRE6 ] ; then
+if [ ${reason} = EXPIRE6 -o ${reason} = RELEASE6 -o ${reason} = STOP6 ] ; then
   if [ x${old_ip6_address} = x ] || [ x${old_ip6_prefixlen} = x ] ; then
     exit_with_hooks 2;
   fi
index a17a0a451fe27909fbb1e9f9fa3fb293638b8564..1b8d7b0218a099cb14db149fe384b6dfc2607082 100644 (file)
@@ -279,7 +279,7 @@ if [ ${reason} = DEPREF6 ] ; then
   exit_with_hooks 0
 fi
 
-if [ ${reason} = EXPIRE6 ] ; then
+if [ ${reason} = EXPIRE6 -o ${reason} = RELEASE6 -o ${reason} = STOP6 ] ; then
   if [ x${old_ip6_address} = x ] || [ x${old_ip6_prefixlen} = x ] ; then
     exit_with_hooks 2;
   fi
index dd10416ad7e8dac1a9670b63341df91b561346eb..51ff4f714914e85cce936640357fdc18f3d0995f 100644 (file)
@@ -2416,10 +2416,12 @@ void form_duid(struct data_string *duid, char *file, int line);
 void dhc6_lease_destroy(struct dhc6_lease *lease, char *file, int line);
 void start_init6(struct client_state *client);
 void start_confirm6(struct client_state *client);
+void start_release6(struct client_state *client);
 void start_selecting6(struct client_state *client);
 isc_result_t write_client6_lease(struct client_state *client,
                                 struct dhc6_lease *lease,
                                 int rewrite, int sync);
+void unconfigure6(struct client_state *client, const char *reason);
 
 /* db.c */
 int write_lease PROTO ((struct lease *));