diff --git a/src/dhcp.c b/src/dhcp.c index 078f6927..0e05db93 100644 --- a/src/dhcp.c +++ b/src/dhcp.c @@ -57,6 +57,7 @@ #include #include #include +#include #include #define ELOOP_QUEUE ELOOP_DHCP @@ -4390,6 +4391,57 @@ dhcp_handleifa(int cmd, struct ipv4_addr *ia, pid_t pid) } #ifndef SMALL +static int +dhcp_dump_lease_time(FILE *fp, const char *name, struct eloop *eloop, + void (*callback)(void *), void *arg, unsigned long long esecs, + unsigned int ensecs, uint32_t lifetime) +{ + unsigned int seconds; + + if (lifetime == DHCP_INFINITE_LIFETIME) + return efprintf(fp, "%s=never", name); + + if (eloop_timeout_remaining(eloop, callback, arg, esecs, ensecs, + &seconds) == 0) + seconds = 0; + return efprintf(fp, "%s=%u", name, seconds); +} + +int +dhcp_dump_lease_times(FILE *fp, const struct interface *ifp) +{ + const struct dhcp_state *state; + const struct dhcp_lease *lease; + void *arg; + unsigned long long esecs; + unsigned int ensecs; + + state = D_CSTATE(ifp); + if (state == NULL) + return 0; + if (state->state != DHS_BOUND && state->state != DHS_RENEW && + state->state != DHS_REBIND) + return 0; + + if (eloop_monotonic_elapsed(ifp->ctx->eloop, &esecs, &ensecs) == -1) { + logerr("eloop_monotonic_elapsed"); + return -1; + } + + lease = &state->lease; + arg = UNCONST(ifp); + if (dhcp_dump_lease_time(fp, "time_to_renew", ifp->ctx->eloop, + dhcp_startrenew, arg, esecs, ensecs, lease->renewaltime) == -1) + return -1; + if (dhcp_dump_lease_time(fp, "time_to_rebind", ifp->ctx->eloop, + dhcp_rebind, arg, esecs, ensecs, lease->rebindtime) == -1) + return -1; + if (dhcp_dump_lease_time(fp, "time_to_expire", ifp->ctx->eloop, + dhcp_expire, arg, esecs, ensecs, lease->leasetime) == -1) + return -1; + return 0; +} + int dhcp_dump(struct interface *ifp) { diff --git a/src/dhcp.h b/src/dhcp.h index 73ac5e9c..e17a9077 100644 --- a/src/dhcp.h +++ b/src/dhcp.h @@ -263,6 +263,9 @@ uint16_t dhcp_get_mtu(const struct interface *); int dhcp_get_routes(rb_tree_t *, struct interface *); ssize_t dhcp_env(FILE *, const char *, const struct interface *, const struct bootp *, size_t); +#ifndef SMALL +int dhcp_dump_lease_times(FILE *, const struct interface *); +#endif struct ipv4_addr *dhcp_handleifa(int, struct ipv4_addr *, pid_t pid); void dhcp_drop(struct interface *, const char *); diff --git a/src/dhcp6.c b/src/dhcp6.c index 07ffeb50..06ba63ff 100644 --- a/src/dhcp6.c +++ b/src/dhcp6.c @@ -44,6 +44,7 @@ #include #include #include +#include #include #define ELOOP_QUEUE ELOOP_DHCP6 @@ -4511,6 +4512,57 @@ dhcp6_env(FILE *fp, const char *prefix, const struct interface *ifp, return 1; } + +#ifndef SMALL +static int +dhcp6_dump_lease_time(FILE *fp, const char *name, struct eloop *eloop, + void (*callback)(void *), void *arg, unsigned long long esecs, + unsigned int ensecs, uint32_t lifetime) +{ + unsigned int seconds; + + if (lifetime == ND6_INFINITE_LIFETIME) + return efprintf(fp, "%s=never", name); + + if (eloop_timeout_remaining(eloop, callback, arg, esecs, ensecs, + &seconds) == 0) + seconds = 0; + return efprintf(fp, "%s=%u", name, seconds); +} + +int +dhcp6_dump_lease_times(FILE *fp, const struct interface *ifp) +{ + const struct dhcp6_state *state; + void *arg; + unsigned long long esecs; + unsigned int ensecs; + + state = D6_CSTATE(ifp); + if (state == NULL) + return 0; + if (state->state != DH6S_BOUND && state->state != DH6S_RENEW && + state->state != DH6S_REBIND) + return 0; + + if (eloop_monotonic_elapsed(ifp->ctx->eloop, &esecs, &ensecs) == -1) { + logerr("eloop_monotonic_elapsed"); + return -1; + } + + arg = UNCONST(ifp); + if (dhcp6_dump_lease_time(fp, "time_to_renew", ifp->ctx->eloop, + dhcp6_startrenew, arg, esecs, ensecs, state->renew) == -1) + return -1; + if (dhcp6_dump_lease_time(fp, "time_to_rebind", ifp->ctx->eloop, + dhcp6_startrebind, arg, esecs, ensecs, state->rebind) == -1) + return -1; + if (dhcp6_dump_lease_time(fp, "time_to_expire", ifp->ctx->eloop, + dhcp6_startexpire, arg, esecs, ensecs, state->expire) == -1) + return -1; + return 0; +} +#endif #endif #ifndef SMALL diff --git a/src/dhcp6.h b/src/dhcp6.h index 01af741c..fb3c73bf 100644 --- a/src/dhcp6.h +++ b/src/dhcp6.h @@ -245,6 +245,9 @@ void dhcp6_reboot(struct interface *); void dhcp6_renew(struct interface *); ssize_t dhcp6_env(FILE *, const char *, const struct interface *, const struct dhcp6_message *, size_t); +#ifndef SMALL +int dhcp6_dump_lease_times(FILE *, const struct interface *); +#endif void dhcp6_free(struct interface *); void dhcp6_handleifa(int, struct ipv6_addr *, pid_t); bool dhcp6_dadcompleted(const struct interface *); diff --git a/src/eloop.c b/src/eloop.c index 70090551..ffaa7b28 100644 --- a/src/eloop.c +++ b/src/eloop.c @@ -606,6 +606,47 @@ eloop_q_timeout_delete(struct eloop *eloop, int queue, void (*callback)(void *), return n; } +#ifndef SMALL +int +eloop_monotonic_elapsed(struct eloop *eloop, unsigned long long *secs, + unsigned int *nsecs) +{ + struct timespec now; + + if (clock_gettime(CLOCK_MONOTONIC, &now) == -1) + return -1; + *secs = eloop_timespec_diff(&now, &eloop->now, nsecs); + return 0; +} + +int +eloop_q_timeout_remaining(struct eloop *eloop, int queue, + void (*callback)(void *), void *arg, unsigned long long secs, + unsigned int nsecs, unsigned int *seconds) +{ + struct eloop_timeout *t; + unsigned int left; + + TAILQ_FOREACH(t, &eloop->timeouts, next) { + if ((queue == 0 || t->queue == queue) && + t->callback == callback && t->arg == arg) { + if (seconds == NULL) + return 1; + if (secs > t->seconds) + left = 0; + else { + left = t->seconds - (unsigned int)secs; + if (nsecs > t->nseconds && left > 0) + left--; + } + *seconds = left; + return 1; + } + } + return 0; +} +#endif + void eloop_exit(struct eloop *eloop, int code) { diff --git a/src/eloop.h b/src/eloop.h index acd183b0..d0e56c94 100644 --- a/src/eloop.h +++ b/src/eloop.h @@ -81,6 +81,13 @@ unsigned long long eloop_timespec_diff(const struct timespec *tsp, eloop_q_timeout_add_msec((eloop), ELOOP_QUEUE, (ms), (cb), (ctx)) #define eloop_timeout_delete(eloop, cb, ctx) \ eloop_q_timeout_delete((eloop), ELOOP_QUEUE, (cb), (ctx)) +#ifndef SMALL +int eloop_monotonic_elapsed(struct eloop *, unsigned long long *, + unsigned int *); +#define eloop_timeout_remaining(eloop, cb, ctx, esecs, ensecs, sec) \ + eloop_q_timeout_remaining((eloop), ELOOP_QUEUE, (cb), (ctx), (esecs), \ + (ensecs), (sec)) +#endif int eloop_q_timeout_add_tv(struct eloop *, int, const struct timespec *, void (*)(void *), void *); int eloop_q_timeout_add_sec(struct eloop *, int, unsigned int, void (*)(void *), @@ -88,6 +95,10 @@ int eloop_q_timeout_add_sec(struct eloop *, int, unsigned int, void (*)(void *), int eloop_q_timeout_add_msec(struct eloop *, int, unsigned long, void (*)(void *), void *); int eloop_q_timeout_delete(struct eloop *, int, void (*)(void *), void *); +#ifndef SMALL +int eloop_q_timeout_remaining(struct eloop *, int, void (*)(void *), void *, + unsigned long long, unsigned int, unsigned int *); +#endif int eloop_signal_set_cb(struct eloop *, const int *, size_t, void (*)(int, void *), void *); diff --git a/src/script.c b/src/script.c index 2464643f..156d0c62 100644 --- a/src/script.c +++ b/src/script.c @@ -524,6 +524,11 @@ make_env(struct dhcpcd_ctx *ctx, const struct interface *ifp, if (append_config(fp, "new", (const char *const *)ifo->config) == -1) goto eexit; +#ifndef SMALL + if (ifp->ctx->options & DHCPCD_DUMPLEASE && + dhcp_dump_lease_times(fp, ifp) == -1) + goto eexit; +#endif } #endif #ifdef INET6 @@ -536,6 +541,11 @@ make_env(struct dhcpcd_ctx *ctx, const struct interface *ifp, if (dhcp6_env(fp, "new", ifp, d6_state->new, d6_state->new_len) == -1) goto eexit; +#ifndef SMALL + if (ifp->ctx->options & DHCPCD_DUMPLEASE && + dhcp6_dump_lease_times(fp, ifp) == -1) + goto eexit; +#endif } #endif if (protocol == PROTO_RA) {