]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
Reboot off the last lease and use the last lease if not expired and user has asked...
authorRoy Marples <roy@marples.name>
Mon, 15 Sep 2008 15:23:46 +0000 (15:23 +0000)
committerRoy Marples <roy@marples.name>
Mon, 15 Sep 2008 15:23:46 +0000 (15:23 +0000)
dhcp.c
dhcpcd.8.in
dhcpcd.c
dhcpcd.conf.5.in
dhcpcd.h
if-options.c
if-options.h
ipv4ll.c

diff --git a/dhcp.c b/dhcp.c
index 7b2993e042a95e7313a665be89d5643b9164de14..0aa13fa6366371841f75b33fd7e517b010b36b3b 100644 (file)
--- a/dhcp.c
+++ b/dhcp.c
@@ -1254,7 +1254,6 @@ get_lease(struct dhcp_lease *lease, const struct dhcp_message *dhcp)
 {
        time_t t;
 
-       lease->frominfo = 0;
        lease->addr.s_addr = dhcp->yiaddr;
        if (get_option_addr(&lease->net.s_addr, dhcp, DHO_SUBNETMASK) == -1)
                lease->net.s_addr = get_netmask(dhcp->yiaddr);
index f0ae80a5a83df276cc27de4465facf0d09297d8b..4905a88c45e6f60e9ac13a9e00923188911134c0 100644 (file)
@@ -22,7 +22,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd September 11, 2008
+.Dd September 15, 2008
 .Dt DHCPCD 8 SMM
 .Sh NAME
 .Nm dhcpcd
@@ -42,6 +42,7 @@
 .Op Fl t , -timeout Ar seconds
 .Op Fl u , -userclass Ar class
 .Op Fl v , -vendor Ar code , Ar value
+.Op Fl y , -reboot Ar seconds
 .Op Fl z , -allowinterfaces Ar pattern
 .Op Fl C , -nohook Ar hook
 .Op Fl F , -fqdn Ar FQDN
@@ -304,6 +305,14 @@ to deconfigure the
 and exit.
 .Nm
 then waits until this process has exited.
+.It Fl y , -reboot Ar seconds
+Allow
+.Ar reboot
+seconds before moving to the discover phase if we have an old lease to use.
+The default is 10 seconds.
+A setting if 0 seconds causes
+.Nm
+to skip the reboot phase and go straight into discover.
 .It Fl D , -duid 
 Generate an
 .Li RFC 4361
index 53b95f99ecbb15ba07f3b2b24f222d5bbd180cdb..47ef462a372a7ba8aa7851b0f708ebd3edb25279 100644 (file)
--- a/dhcpcd.c
+++ b/dhcpcd.c
@@ -127,7 +127,7 @@ read_pid(void)
 static void
 usage(void)
 {
-       printf("usage: "PACKAGE" [-dknpqxADEGHKLOTV] [-c script] [-f file ] [-h hostname]\n"
+       printf("usage: "PACKAGE" [-dknpqxyADEGHKLOTV] [-c script] [-f file ] [-h hostname]\n"
               "              [-i classID ] [-l leasetime] [-m metric] [-o option] [-r ipaddr]\n"
               "              [-s ipaddr] [-t timeout] [-u userclass] [-F none|ptr|both]\n"
               "              [-I clientID] [-C hookscript] [-Q option] [-X ipaddr] <interface>\n");
@@ -326,7 +326,7 @@ start_rebind(void *arg)
 
        syslog(LOG_ERR, "%s: failed to renew, attmepting to rebind",
               iface->name);
-       iface->state->state = DHS_REBINDING;
+       iface->state->state = DHS_REBIND;
        delete_timeout(send_renew, iface);
        iface->state->lease.server.s_addr = 0;
        send_rebind(iface);
@@ -336,14 +336,20 @@ void
 start_expire(void *arg)
 {
        struct interface *iface = arg;
-       int ll = IN_LINKLOCAL(htonl(iface->state->lease.addr.s_addr));
+
+       if (iface->addr.s_addr == 0) {
+               /* We failed to reboot, so enter discovery. */
+               iface->state->interval = 0;
+               start_discover(iface);
+               return;
+       }
 
        syslog(LOG_ERR, "%s: lease expired", iface->name);
        delete_timeout(NULL, iface);
        drop_config(iface, "EXPIRE");
        iface->state->interval = 0;
        if (iface->carrier != LINK_DOWN) {
-               if (ll)
+               if (IN_LINKLOCAL(htonl(iface->state->lease.addr.s_addr)))
                        start_interface(iface);
                else
                        start_ipv4ll(iface);
@@ -454,7 +460,8 @@ handle_dhcp(struct interface *iface, struct dhcp_message **dhcpp)
                }
        }
 
-       if (type == DHCP_OFFER && state->state == DHS_DISCOVERING) {
+       if (type == DHCP_OFFER && state->state == DHS_DISCOVER) {
+               lease->frominfo = 0;
                lease->addr.s_addr = dhcp->yiaddr;
                get_option_addr(&lease->server.s_addr, dhcp, DHO_SERVERID);
                log_dhcp(LOG_INFO, "offered", iface, dhcp);
@@ -477,7 +484,6 @@ handle_dhcp(struct interface *iface, struct dhcp_message **dhcpp)
                         * then we can't ARP for duplicate detection. */
                        addr.s_addr = state->offer->yiaddr;
                        if (!has_address(iface->name, &addr, NULL)) {
-                               state->state = DHS_PROBING;
                                state->claims = 0;
                                state->probes = 0;
                                state->conflicts = 0;
@@ -485,7 +491,7 @@ handle_dhcp(struct interface *iface, struct dhcp_message **dhcpp)
                                return;
                        }
                }
-               state->state = DHS_REQUESTING;
+               state->state = DHS_REQUEST;
                send_request(iface);
                return;
        }
@@ -509,6 +515,7 @@ handle_dhcp(struct interface *iface, struct dhcp_message **dhcpp)
        *dhcpp = NULL;
        /* Delete all timeouts for this interface. */
        delete_timeout(NULL, iface);
+       lease->frominfo = 0;
        bind_interface(iface);
 }
 
@@ -636,7 +643,7 @@ start_discover(void *arg)
        struct interface *iface = arg;
        struct if_options *ifo = iface->state->options;
 
-       iface->state->state = DHS_DISCOVERING;
+       iface->state->state = DHS_DISCOVER;
        iface->state->xid = arc4random();
        open_sockets(iface);
        delete_timeout(NULL, iface);
@@ -660,12 +667,22 @@ start_renew(void *arg)
 
        syslog(LOG_INFO, "%s: renewing lease of %s",
               iface->name, inet_ntoa(iface->state->lease.addr));
-       iface->state->state = DHS_RENEWING;
+       iface->state->state = DHS_RENEW;
        iface->state->xid = arc4random();
        open_sockets(iface);
        send_renew(iface);
 }
 
+static void
+start_timeout(void *arg)
+{
+       struct interface *iface = arg;
+
+       bind_interface(iface);
+       iface->state->interval = 0;
+       start_discover(iface);
+}
+
 void
 start_reboot(struct interface *iface)
 {
@@ -675,15 +692,33 @@ start_reboot(struct interface *iface)
                syslog(LOG_INFO, "%s: waiting for carrier", iface->name);
                return;
        }
+       if (ifo->reboot == 0) {
+               start_discover(iface);
+               return;
+       }
+       if (IN_LINKLOCAL(htonl(iface->state->lease.addr.s_addr))) {
+               if (ifo->options & DHCPCD_IPV4LL) {
+                       iface->state->claims = 0;
+                       send_arp_announce(iface);
+               } else
+                       start_discover(iface);
+               return;
+       }
        syslog(LOG_INFO, "%s: rebinding lease of %s",
               iface->name, inet_ntoa(iface->state->lease.addr));
-       iface->state->state = DHS_REBINDING;
+       iface->state->state = DHS_REBOOT;
        iface->state->xid = arc4random();
        iface->state->lease.server.s_addr = 0;
        delete_timeout(NULL, iface);
-       add_timeout_sec(ifo->timeout, start_expire, iface);
+       if (ifo->options & DHCPCD_LASTLEASE && iface->state->lease.frominfo)
+               add_timeout_sec(ifo->reboot, start_timeout, iface);
+       else
+               add_timeout_sec(ifo->reboot, start_expire, iface);
        open_sockets(iface);
-       send_rebind(iface);
+       if (ifo->options & DHCPCD_ARP)
+               send_arp_probe(iface);
+       else
+               send_request(iface);
 }
 
 static void
@@ -703,6 +738,9 @@ void
 start_interface(void *arg)
 {
        struct interface *iface = arg;
+       struct stat st;
+       struct timeval now;
+       uint32_t l;
 
        if (iface->carrier == LINK_DOWN) {
                syslog(LOG_INFO, "%s: waiting for carrier", iface->name);
@@ -710,9 +748,36 @@ start_interface(void *arg)
        }
 
        iface->start_uptime = uptime();
-       if (!iface->state->lease.addr.s_addr)
+       iface->state->offer = read_lease(iface);
+/*     if (iface->state->offer) {
+               if (IN_LINKLOCAL(htonl(iface->state->offer->yiaddr))) {
+                       free(iface->state->offer);
+                       iface->state->offer = NULL;
+               }
+       } */
+       if (iface->state->offer) {
+               get_lease(&iface->state->lease, iface->state->offer);
+               iface->state->lease.frominfo = 1;
+               /* Offset lease times and check expiry */
+               if (stat(iface->leasefile, &st) == 0 &&
+                   get_option_uint32(&l, iface->state->offer, DHO_LEASETIME) == 0)
+               {
+                       gettimeofday(&now, NULL);
+                       if ((time_t)l < now.tv_sec - st.st_mtime) {
+                               free(iface->state->offer);
+                               iface->state->offer = NULL;
+                       } else {
+                               l = now.tv_sec - st.st_mtime;
+                               iface->state->lease.leasetime -= l;
+                               iface->state->lease.renewaltime -= l;
+                               iface->state->lease.rebindtime -= l;
+                       }
+               }
+       }
+       if (!iface->state->offer)
                start_discover(iface);
-       else if (IN_LINKLOCAL(htonl(iface->state->lease.addr.s_addr)))
+       else if (IN_LINKLOCAL(htonl(iface->state->lease.addr.s_addr)) &&
+                iface->state->options->options & DHCPCD_IPV4LL)
                start_ipv4ll(iface);
        else
                start_reboot(iface);
@@ -861,7 +926,7 @@ handle_signal(_unused void *arg)
 {
        struct interface *iface, *ifl;
        int sig = signal_read();
-       int do_reboot = 0, do_release = 0;
+       int do_release = 0;
 
        switch (sig) {
        case SIGINT:
@@ -872,15 +937,17 @@ handle_signal(_unused void *arg)
                break;
        case SIGALRM:
                syslog(LOG_INFO, "received SIGALRM, rebinding lease");
-               do_reboot = 1;
+               for (iface = ifaces; iface; iface = iface->next)
+                       start_reboot(iface);
+               return;
        case SIGHUP:
                syslog(LOG_INFO, "received SIGHUP, releasing lease");
                do_release = 1;
                break;
        default:
-               syslog (LOG_ERR,
-                       "received signal %d, but don't know what to do with it",
-                       sig);
+               syslog(LOG_ERR,
+                      "received signal %d, but don't know what to do with it",
+                      sig);
                return;
        }
 
@@ -893,14 +960,10 @@ handle_signal(_unused void *arg)
                                ifl = iface;
                if (!ifl)
                        break;
-               if (do_reboot)
-                       start_reboot(ifl);
-               else {
-                       if (do_release)
-                               send_release(ifl);
-                       if (!(ifl->state->options->options & DHCPCD_PERSISTENT))
-                               drop_config(ifl, do_release ? "RELEASE" : "STOP");
-               }
+               if (do_release)
+                       send_release(ifl);
+               if (!(ifl->state->options->options & DHCPCD_PERSISTENT))
+                       drop_config(ifl, do_release ? "RELEASE" : "STOP");
        }
        exit(EXIT_FAILURE);
 }
@@ -1102,6 +1165,8 @@ main(int argc, char **argv)
                        unlink(pidfile);
                        exit(EXIT_FAILURE);
                }
+               if (sig == SIGALRM)
+                       exit(EXIT_SUCCESS);
                /* Spin until it exits */
                syslog(LOG_INFO, "waiting for pid %d to exit", pid);
                ts.tv_sec = 0;
index a492855d15c27c699b6cfd654e93a6859d644e50..d70313107ec10c506ff927796d6fb05c8f1e5256 100644 (file)
@@ -22,7 +22,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd September 11, 2008
+.Dd September 15, 2008
 .Dt DHCPCD.CONF 5 SMM
 .Sh NAME
 .Nm dhcpcd.conf
@@ -124,6 +124,14 @@ It can be a variable to be used in
 .Xr dhcpcd-run-hooks 8
 or the numerical value.
 You can specify more options seperated by commas, spaces or more option lines.
+.Ic reboot Ar seconds
+Allow
+.Ar reboot
+seconds before moving to the discover phase if we have an old lease to use.
+The default is 10 seconds.
+A setting if 0 seconds causes
+.Nm dhcpcd
+to skip the reboot phase and go straight into discover.
 .It Ic require Ar option
 Requires the
 .Ar option
index 4bfed04ffc155cf51b1c5538675329f018711eab..ea4a37dfab519f42784fb734063d46c5c6f225c1 100644 (file)
--- a/dhcpcd.h
+++ b/dhcpcd.h
 
 enum DHS {
        DHS_INIT,
-       DHS_DISCOVERING,
-       DHS_REQUESTING,
+       DHS_DISCOVER,
+       DHS_REQUEST,
        DHS_BOUND,
-       DHS_RENEWING,
-       DHS_REBINDING,
+       DHS_RENEW,
+       DHS_REBIND,
        DHS_REBOOT,
        DHS_RENEW_REQUESTED,
-       DHS_INIT_IPV4LL,
-       DHS_PROBING,
-       DHS_ANNOUNCING
+       DHS_INIT_IPV4LL
 };
 
 #define LINK_UP        1
index 7e2d4faac6c688085dce5e8566e240f869d9e0ee..da16e4c27b992c53e8f42111e915ebb302409ee0 100644 (file)
@@ -48,7 +48,7 @@
 
 /* Don't set any optional arguments here so we retain POSIX
  * compatibility with getopt */
-#define OPTS "bc:df:h:i:kl:m:no:pqr:s:t:u:v:xABC:DEF:GI:KLO:Q:TVX:"
+#define OPTS "bc:df:h:i:kl:m:no:pqr:s:t:u:v:xy:z:ABC:DEF:GI:KLO:Q:TVX:Z:"
 
 const struct option cf_options[] = {
        {"background",      no_argument,       NULL, 'b'},
@@ -70,6 +70,7 @@ const struct option cf_options[] = {
        {"userclass",       required_argument, NULL, 'u'},
        {"vendor",          required_argument, NULL, 'v'},
        {"exit",            no_argument,       NULL, 'x'},
+       {"reboot",          required_argument, NULL, 'y'},
        {"allowinterfaces", required_argument, NULL, 'z'},
        {"noarp",           no_argument,       NULL, 'A'},
        {"nobackground",    no_argument,       NULL, 'B'},
@@ -382,7 +383,7 @@ parse_option(struct if_options *ifo, int opt, const char *arg)
        case 't':
                ifo->timeout = atoint(arg);
                if (ifo->timeout < 0) {
-                       syslog (LOG_ERR, "timeout must be a positive value");
+                       syslog(LOG_ERR, "timeout must be a positive value");
                        return -1;
                }
                break;
@@ -435,6 +436,13 @@ parse_option(struct if_options *ifo, int opt, const char *arg)
                        ifo->vendor[0] += s + 2;
                }
                break;
+       case 'y':
+               ifo->reboot = atoint(arg);
+               if (ifo->reboot < 0) {
+                       syslog(LOG_ERR, "reboot must be a positive value");
+                       return -1;
+               }
+               break;
        case 'z':
                /* We only set this if we haven't got any interfaces */
                if (!ifaces)
@@ -587,6 +595,7 @@ read_config(const char *file, const char *ifname)
        ifo->options |= DHCPCD_CLIENTID | DHCPCD_GATEWAY | DHCPCD_DAEMONISE;
        ifo->options |= DHCPCD_ARP | DHCPCD_IPV4LL | DHCPCD_LINK;
        ifo->timeout = DEFAULT_TIMEOUT;
+       ifo->reboot = DEFAULT_REBOOT;
        ifo->metric = -1;
        gethostname(ifo->hostname + 1, sizeof(ifo->hostname));
        if (strcmp(ifo->hostname + 1, "(none)") == 0 ||
index 0559eec0158390786ca354c7c954c2ee528c4593..80f788da90fdd07022a5e3c2aa45eeb1ee38899a 100644 (file)
@@ -40,6 +40,7 @@
 #define IF_OPTS "bc:df:h:i:kl:m:no:pqr:s:t:u:v:xz:ABC:DEF:GI:KLO:Q:TVX:Z:"
 
 #define DEFAULT_TIMEOUT                30
+#define DEFAULT_REBOOT         10
 #define DEFAULT_LEASETIME      3600    /* 1 hour */
 
 #define HOSTNAME_MAX_LEN       250     /* 255 - 3 (FQDN) - 2 (DNS enc) */
@@ -76,6 +77,7 @@ struct if_options {
        uint8_t nomask[256 / 8];
        uint32_t leasetime;
        time_t timeout;
+       time_t reboot;
        int options;
 
        struct in_addr request_address;
index 0ae91005e51a7eed48808a4bc1fbb9a2cebd3986..fcd690e2f8c0fd3c2630963f3fa777348c7f54e7 100644 (file)
--- a/ipv4ll.c
+++ b/ipv4ll.c
@@ -87,11 +87,16 @@ start_ipv4ll(void *arg)
                }
        }
 
-       syslog(LOG_INFO, "%s: probing for an IPv4LL address", iface->name);
-       delete_timeout(NULL, iface);
-       iface->state->state = DHS_PROBING;
-       free(iface->state->offer);
-       iface->state->offer = make_ipv4ll_lease(0);
+       /* We maybe rebooting of an IPv4LL address. */
+       if (!iface->state->offer ||
+           !IN_LINKLOCAL(htonl(iface->state->offer->yiaddr)))
+       {
+               syslog(LOG_INFO, "%s: probing for an IPv4LL address", iface->name);
+               delete_timeout(NULL, iface);
+               free(iface->state->offer);
+               iface->state->offer = make_ipv4ll_lease(0);
+               iface->state->lease.frominfo = 0;
+       }
        send_arp_probe(iface);
 }
 
@@ -102,26 +107,25 @@ handle_ipv4ll_failure(void *arg)
        time_t up;
 
        if (iface->state->fail.s_addr == iface->state->lease.addr.s_addr) {
-               if (iface->state->state == DHS_PROBING)
+               up = uptime();
+               if (iface->state->defend + DEFEND_INTERVAL > up) {
                        drop_config(iface, "EXPIRE");
-               else {
-                       up = uptime();
-                       if (iface->state->defend + DEFEND_INTERVAL > up) {
-                               drop_config(iface, "EXPIRE");
-                               iface->state->conflicts = -1;
-                       } else {
-                               iface->state->defend = up;
-                               return;
-                       }
+                       iface->state->conflicts = -1;
+               } else {
+                       iface->state->defend = up;
+                       return;
                }
        }
 
        close_sockets(iface);
+       free(iface->state->offer);
+       iface->state->offer = NULL;
        if (++iface->state->conflicts > MAX_CONFLICTS) {
                syslog(LOG_ERR, "%s: failed to acquire an IPv4LL address",
                                iface->name);
                iface->state->interval = RATE_LIMIT_INTERVAL / 2;
                start_discover(iface);
-       } else
+       } else {
                add_timeout_sec(PROBE_WAIT, start_ipv4ll, iface);
+       }
 }