unsigned int updated_IAs = 0;
bool handled_status_codes[_DHCPV6_Status_Max] = { false, };
- odhcp6c_expire();
+ odhcp6c_expire(true);
if (orig == DHCPV6_MSG_UNKNOWN) {
static time_t last_update = 0;
{
struct odhcp6c_entry *e;
size_t ia_na_entries, ia_pd_entries, i;
+ size_t invalid_entries = 0;
int64_t l_t1 = UINT32_MAX, l_t2 = UINT32_MAX, l_t3 = 0;
e = odhcp6c_get_state(STATE_IA_NA, &ia_na_entries);
ia_na_entries /= sizeof(*e);
for (i = 0; i < ia_na_entries; i++) {
+ /* Exclude invalid IA_NA entries */
+ if (!e[i].valid) {
+ invalid_entries++;
+ continue;
+ }
+
if (e[i].t1 < l_t1)
l_t1 = e[i].t1;
ia_pd_entries /= sizeof(*e);
for (i = 0; i < ia_pd_entries; i++) {
+ /* Exclude invalid IA_PD entries */
+ if (!e[i].valid) {
+ invalid_entries++;
+ continue;
+ }
+
if (e[i].t1 < l_t1)
l_t1 = e[i].t1;
l_t3 = e[i].valid;
}
- if (ia_pd_entries || ia_na_entries) {
+ if (ia_pd_entries + ia_na_entries - invalid_entries) {
t1 = l_t1;
t2 = l_t2;
t3 = l_t3;
break;
}
- odhcp6c_expire();
+ odhcp6c_expire(false);
size_t ia_pd_len, ia_na_len, server_id_len;
odhcp6c_get_state(STATE_IA_PD, &ia_pd_len);
bool odhcp6c_update_entry(enum odhcp6c_state state, struct odhcp6c_entry *new,
uint32_t safe, unsigned int holdoff_interval)
{
- size_t len;
struct odhcp6c_entry *x = odhcp6c_find_entry(state, new);
- uint8_t *start = odhcp6c_get_state(state, &len);
if (x && x->valid > new->valid && new->valid < safe)
new->valid = safe;
- if (new->valid > 0) {
- if (x) {
- if (holdoff_interval && new->valid >= x->valid &&
- new->valid != UINT32_MAX &&
- new->valid - x->valid < holdoff_interval &&
- new->preferred >= x->preferred &&
- new->preferred != UINT32_MAX &&
- new->preferred - x->preferred < holdoff_interval)
- return false;
-
- x->valid = new->valid;
- x->preferred = new->preferred;
- x->t1 = new->t1;
- x->t2 = new->t2;
- x->iaid = new->iaid;
- } else if (odhcp6c_add_state(state, new, odhcp6c_entry_size(new)))
+ if (x) {
+ if (holdoff_interval && new->valid >= x->valid &&
+ new->valid != UINT32_MAX &&
+ new->valid - x->valid < holdoff_interval &&
+ new->preferred >= x->preferred &&
+ new->preferred != UINT32_MAX &&
+ new->preferred - x->preferred < holdoff_interval)
return false;
- } else if (x)
- odhcp6c_remove_state(state, ((uint8_t*)x) - start, odhcp6c_entry_size(x));
+
+ x->valid = new->valid;
+ x->preferred = new->preferred;
+ x->t1 = new->t1;
+ x->t2 = new->t2;
+ x->iaid = new->iaid;
+ } else if (odhcp6c_add_state(state, new, odhcp6c_entry_size(new)))
+ return false;
return true;
}
-static void odhcp6c_expire_list(enum odhcp6c_state state, uint32_t elapsed)
+static void odhcp6c_expire_list(enum odhcp6c_state state, uint32_t elapsed, bool remove_expired)
{
size_t len;
uint8_t *start = odhcp6c_get_state(state, &len);
else if (c->valid != UINT32_MAX)
c->valid -= elapsed;
- if (!c->valid) {
+ if (!c->valid && remove_expired) {
odhcp6c_remove_state(state, ((uint8_t*)c) - start, odhcp6c_entry_size(c));
start = odhcp6c_get_state(state, &len);
} else
return NULL;
}
-void odhcp6c_expire(void)
+void odhcp6c_expire(bool expire_ia_pd)
{
time_t now = odhcp6c_get_milli_time() / 1000;
uint32_t elapsed = (last_update > 0) ? now - last_update : 0;
last_update = now;
- odhcp6c_expire_list(STATE_RA_PREFIX, elapsed);
- odhcp6c_expire_list(STATE_RA_ROUTE, elapsed);
- odhcp6c_expire_list(STATE_RA_DNS, elapsed);
- odhcp6c_expire_list(STATE_RA_SEARCH, elapsed);
- odhcp6c_expire_list(STATE_IA_NA, elapsed);
- odhcp6c_expire_list(STATE_IA_PD, elapsed);
+ odhcp6c_expire_list(STATE_RA_PREFIX, elapsed, true);
+ odhcp6c_expire_list(STATE_RA_ROUTE, elapsed, true);
+ odhcp6c_expire_list(STATE_RA_DNS, elapsed, true);
+ odhcp6c_expire_list(STATE_RA_SEARCH, elapsed, true);
+ odhcp6c_expire_list(STATE_IA_NA, elapsed, true);
+ odhcp6c_expire_list(STATE_IA_PD, elapsed, expire_ia_pd);
}
uint32_t odhcp6c_elapsed(void)
buf[buf_len++] = '=';
for (size_t i = 0; i < len / sizeof(*e); ++i) {
+ /*
+ * The only invalid entries allowed to be passed to the script are prefix entries.
+ * This will allow immediate removal of the old ipv6-prefix-assignment that might
+ * otherwise be kept for up to 2 hours (see L-13 requirement of RFC 7084).
+ */
+ if (!e[i].valid && type != ENTRY_PREFIX)
+ continue;
+
inet_ntop(AF_INET6, &e[i].target, &buf[buf_len], INET6_ADDRSTRLEN);
buf_len += strlen(&buf[buf_len]);
(uint8_t*)e < &start[len] &&
(uint8_t*)odhcp6c_next_entry(e) <= &start[len];
e = odhcp6c_next_entry(e)) {
+ if (!e->valid)
+ continue;
c = mempcpy(c, e->auxtarget, e->auxlen);
*c++ = ' ';
}
signal(SIGTERM, SIG_DFL);
if (delay > 0) {
sleep(delay);
- odhcp6c_expire();
+ odhcp6c_expire(false);
}
struct in6_addr *addr = odhcp6c_get_state(STATE_SERVER_ADDR, &addr_len);