diff options
Diffstat (limited to 'src/netlink.c')
-rw-r--r-- | src/netlink.c | 56 |
1 files changed, 56 insertions, 0 deletions
diff --git a/src/netlink.c b/src/netlink.c index 39f6245..63a0f8b 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -205,10 +205,66 @@ static void refresh_iface_addr6(int ifindex) change = len != (ssize_t)iface->addr6_len; for (ssize_t i = 0; !change && i < len; ++i) { if (!IN6_ARE_ADDR_EQUAL(&addr[i].addr.in6, &iface->addr6[i].addr.in6) || + addr[i].prefix != iface->addr6[i].prefix || (addr[i].preferred > (uint32_t)now) != (iface->addr6[i].preferred > (uint32_t)now) || addr[i].valid < iface->addr6[i].valid || addr[i].preferred < iface->addr6[i].preferred) change = true; } + + if (change) { + /* + * Keep track on removed prefixes, so we could advertise them as invalid + * for at least a couple of times. + * + * RFC7084 ยง 4.3 : + * L-13: If the delegated prefix changes, i.e., the current prefix is + * replaced with a new prefix without any overlapping time + * period, then the IPv6 CE router MUST immediately advertise the + * old prefix with a Preferred Lifetime of zero and a Valid + * Lifetime of either a) zero or b) the lower of the current + * Valid Lifetime and two hours (which must be decremented in + * real time) in a Router Advertisement message as described in + * Section 5.5.3, (e) of [RFC4862]. + */ + + for (size_t i = 0; i < iface->addr6_len; ++i) { + bool removed = true; + + if (iface->addr6[i].valid <= (uint32_t)now) + continue; + + for (ssize_t j = 0; removed && j < len; ++j) { + size_t plen = min(addr[j].prefix, iface->addr6[i].prefix); + + if (odhcpd_bmemcmp(&addr[j].addr.in6, &iface->addr6[i].addr.in6, plen) == 0) + removed = false; + } + + for (size_t j = 0; removed && j < iface->invalid_addr6_len; ++j) { + size_t plen = min(iface->invalid_addr6[j].prefix, iface->addr6[i].prefix); + + if (odhcpd_bmemcmp(&iface->invalid_addr6[j].addr.in6, &iface->addr6[i].addr.in6, plen) == 0) + removed = false; + } + + if (removed) { + size_t pos = iface->invalid_addr6_len; + struct odhcpd_ipaddr *new_invalid_addr6 = realloc(iface->invalid_addr6, + sizeof(*iface->invalid_addr6) * (pos + 1)); + + if (!new_invalid_addr6) + break; + + iface->invalid_addr6 = new_invalid_addr6; + iface->invalid_addr6_len++; + memcpy(&iface->invalid_addr6[pos], &iface->addr6[i], sizeof(*iface->invalid_addr6)); + iface->invalid_addr6[pos].valid = iface->invalid_addr6[pos].preferred = (uint32_t)now; + + if (iface->invalid_addr6[pos].prefix < 64) + iface->invalid_addr6[pos].prefix = 64; + } + } + } } iface->addr6 = addr; |