static int
dhcp6_findna(struct interface *ifp, uint16_t ot, const uint8_t *iaid,
- const uint8_t *d, size_t l)
+ const uint8_t *d, size_t l, const struct timeval *acquired)
{
struct dhcp6_state *state;
const struct dhcp6_option *o;
a->flags |= IPV6_AF_ONLINK | IPV6_AF_NEW;
a->flags &= ~IPV6_AF_STALE;
}
+ a->acquired = *acquired;
a->prefix_pltime = ntohl(iap->pltime);
u32 = ntohl(iap->vltime);
if (a->prefix_vltime != u32) {
static int
dhcp6_findpd(struct interface *ifp, const uint8_t *iaid,
- const uint8_t *d, size_t l)
+ const uint8_t *d, size_t l, const struct timeval *acquired)
{
struct dhcp6_state *state;
const struct dhcp6_option *o, *ex;
a->flags |= IPV6_AF_NEW;
}
+ a->acquired = *acquired;
a->prefix_pltime = ntohl(pdp->pltime);
a->prefix_vltime = ntohl(pdp->vltime);
static int
dhcp6_findia(struct interface *ifp, const struct dhcp6_message *m, size_t l,
- const char *sfrom)
+ const char *sfrom, const struct timeval *acquired)
{
struct dhcp6_state *state;
const struct if_options *ifo;
}
if (code == D6_OPTION_IA_PD) {
if (!(ifo->options & DHCPCD_NOPFXDLG) &&
- dhcp6_findpd(ifp, iaid, p, ol) == 0)
+ dhcp6_findpd(ifp, iaid, p, ol, acquired) == 0)
{
syslog(LOG_WARNING,
"%s: %s: DHCPv6 REPLY missing Prefix",
continue;
}
} else if (!(ifo->options & DHCPCD_PFXDLGONLY)) {
- if (dhcp6_findna(ifp, code, iaid, p, ol) == 0) {
+ if (dhcp6_findna(ifp, code, iaid, p, ol, acquired) == 0)
+ {
syslog(LOG_WARNING,
"%s: %s: DHCPv6 REPLY missing IA Address",
ifp->name, sfrom);
static int
dhcp6_validatelease(struct interface *ifp,
const struct dhcp6_message *m, size_t len,
- const char *sfrom)
+ const char *sfrom, const struct timeval *acquired)
{
struct dhcp6_state *state;
int nia;
+ struct timeval aq;
if (len <= sizeof(*m)) {
syslog(LOG_ERR, "%s: DHCPv6 lease truncated", ifp->name);
state->renew = state->rebind = state->expire = 0;
state->lowpl = ND6_INFINITE_LIFETIME;
- nia = dhcp6_findia(ifp, m, len, sfrom);
+ if (!acquired) {
+ get_monotonic(&aq);
+ acquired = &aq;
+ }
+ nia = dhcp6_findia(ifp, m, len, sfrom, acquired);
if (nia == 0) {
syslog(LOG_ERR, "%s: no useable IA found in lease",
ifp->name);
ssize_t bytes;
struct timeval now;
const struct dhcp6_option *o;
+ struct timeval acquired;
state = D6_STATE(ifp);
if (stat(state->leasefile, &st) == -1) {
goto ex;
}
+ gettimeofday(&now, NULL);
+ get_monotonic(&acquired);
+ acquired.tv_sec -= now.tv_sec - st.st_mtime;
+
/* Check to see if the lease is still valid */
- fd = dhcp6_validatelease(ifp, state->new, state->new_len, NULL);
+ fd = dhcp6_validatelease(ifp, state->new, state->new_len, NULL,
+ &acquired);
if (fd == -1)
goto ex;
if (!(ifp->ctx->options & DHCPCD_DUMPLEASE) &&
state->expire != ND6_INFINITE_LIFETIME)
{
- gettimeofday(&now, NULL);
if ((time_t)state->expire < now.tv_sec - st.st_mtime) {
syslog(LOG_DEBUG,"%s: discarding expired lease",
ifp->name);
a->dadcallback = dhcp6_dadcallback;
a->delegating_iface = ifs;
memcpy(&a->iaid, &prefix->iaid, sizeof(a->iaid));
+ a->acquired = prefix->acquired;
a->prefix_pltime = prefix->prefix_pltime;
a->prefix_vltime = prefix->prefix_vltime;
a->prefix = addr;
if (error == 1)
goto recv;
if (error == -1 ||
- dhcp6_validatelease(ifp, r, len, ctx->sfrom) == -1)
+ dhcp6_validatelease(ifp, r, len,
+ ctx->sfrom, NULL) == -1)
{
dhcp6_startdiscover(ifp);
return;
case DH6S_REQUEST: /* FALLTHROUGH */
case DH6S_RENEW: /* FALLTHROUGH */
case DH6S_REBIND:
- if (dhcp6_validatelease(ifp, r, len, ctx->sfrom) == -1){
+ if (dhcp6_validatelease(ifp, r, len,
+ ctx->sfrom, NULL) == -1)
+ {
/* PD doesn't use CONFIRM, so REBIND could
* throw up an invalid prefix if we
* changed link */
syslog(LOG_ERR, "%s: invalid INF_MAX_RT %d",
ifp->name, u32);
}
- if (dhcp6_validatelease(ifp, r, len, ctx->sfrom) == -1)
+ if (dhcp6_validatelease(ifp, r, len, ctx->sfrom, NULL) == -1)
return;
break;
case DHCP6_RECONFIGURE:
}
int
-ipv6_addaddr(struct ipv6_addr *ap)
+ipv6_addaddr(struct ipv6_addr *ap, const struct timeval *now)
{
struct interface *ifp;
struct ipv6_state *state;
struct ipv6_addr *nap;
+ struct timeval n;
+ uint32_t pltime, vltime;
/* Ensure no other interface has this address */
TAILQ_FOREACH(ifp, ap->iface->ctx->ifaces, next) {
}
}
+ /* Adjust plftime and vltime based on acquired time */
+ pltime = ap->prefix_pltime;
+ vltime = ap->prefix_vltime;
+ if (timerisset(&ap->acquired) &&
+ (ap->prefix_pltime != ND6_INFINITE_LIFETIME ||
+ ap->prefix_vltime != ND6_INFINITE_LIFETIME))
+ {
+ if (now == NULL) {
+ get_monotonic(&n);
+ now = &n;
+ }
+ timersub(now, &ap->acquired, &n);
+ if (ap->prefix_pltime != ND6_INFINITE_LIFETIME)
+ ap->prefix_pltime -= n.tv_sec;
+ if (ap->prefix_vltime != ND6_INFINITE_LIFETIME)
+ ap->prefix_vltime -= n.tv_sec;
+ }
+
syslog(ap->flags & IPV6_AF_NEW ? LOG_INFO : LOG_DEBUG,
"%s: adding address %s", ap->iface->name, ap->saddr);
if (!(ap->flags & IPV6_AF_DADCOMPLETED) &&
ap->flags |= IPV6_AF_DADCOMPLETED;
if (if_addaddress6(ap) == -1) {
syslog(LOG_ERR, "if_addaddress6: %m");
+ /* Restore real pltime and vltime */
+ ap->prefix_pltime = pltime;
+ ap->prefix_vltime = vltime;
return -1;
}
+
+ /* Restore real pltime and vltime */
+ ap->prefix_pltime = pltime;
+ ap->prefix_vltime = vltime;
ap->flags &= ~IPV6_AF_NEW;
ap->flags |= IPV6_AF_ADDED;
if (ap->delegating_iface)
{
struct ipv6_addr *ap, *apn, *apf;
ssize_t i;
+ struct timeval now;
i = 0;
+ timerclear(&now);
TAILQ_FOREACH_SAFE(ap, addrs, next, apn) {
if (ap->prefix_vltime == 0) {
if (ap->flags & IPV6_AF_ADDED) {
apf->flags &= ~IPV6_AF_ADDED;
if (ap->flags & IPV6_AF_NEW)
i++;
- ipv6_addaddr(ap);
+ if (!timerisset(&now))
+ get_monotonic(&now);
+ ipv6_addaddr(ap, &now);
}
}
const struct interface *ifd)
{
struct ipv6_addr *ap, *apn, *apf;
+ struct timeval now;
+ timerclear(&now);
TAILQ_FOREACH_SAFE(ap, addrs, next, apn) {
if (ifd && ap->delegating_iface != ifd)
continue;
ipv6_deleteaddr(ap);
if (!(ap->iface->options->options &
DHCPCD_EXITING) && apf)
- ipv6_addaddr(apf);
+ {
+ if (!timerisset(&now))
+ get_monotonic(&now);
+ ipv6_addaddr(apf, &now);
+ }
}
free(ap);
}
inet_ntop(AF_INET6, &ap->addr, ap->saddr, sizeof(ap->saddr));
TAILQ_INSERT_TAIL(&state->addrs, ap, next);
- ipv6_addaddr(ap);
+ ipv6_addaddr(ap, NULL);
return 1;
}