- if (!iface || !iface->learn_routes)
- return;
-
- odhcpd_setup_route(addr, 128, iface, NULL, add);
-}
-
-static void free_neighbor(struct ndp_neighbor *n)
-{
- setup_route(&n->addr, n->iface, false);
- list_del(&n->head);
- free(n);
- --neighbor_count;
-}
-
-
-static bool match_neighbor(struct ndp_neighbor *n, struct in6_addr *addr)
-{
- if (n->len <= 32)
- return ntohl(n->addr.s6_addr32[0]) >> (32 - n->len) ==
- ntohl(addr->s6_addr32[0]) >> (32 - n->len);
-
- if (n->addr.s6_addr32[0] != addr->s6_addr32[0])
- return false;
-
- if (n->len <= 64)
- return ntohl(n->addr.s6_addr32[1]) >> (64 - n->len) ==
- ntohl(addr->s6_addr32[1]) >> (64 - n->len);
-
- if (n->addr.s6_addr32[1] != addr->s6_addr32[1])
- return false;
-
- if (n->len <= 96)
- return ntohl(n->addr.s6_addr32[2]) >> (96 - n->len) ==
- ntohl(addr->s6_addr32[2]) >> (96 - n->len);
-
- if (n->addr.s6_addr32[2] != addr->s6_addr32[2])
- return false;
-
- return ntohl(n->addr.s6_addr32[3]) >> (128 - n->len) ==
- ntohl(addr->s6_addr32[3]) >> (128 - n->len);
-}
-
-
-static struct ndp_neighbor* find_neighbor(struct in6_addr *addr, bool strict)
-{
- time_t now = time(NULL);
- struct ndp_neighbor *n, *e;
- list_for_each_entry_safe(n, e, &neighbors, head) {
- if ((!strict && match_neighbor(n, addr)) ||
- (n->len == 128 && IN6_ARE_ADDR_EQUAL(&n->addr, addr)))
- return n;
-
- if (!n->iface && abs(n->timeout - now) >= 5)
- free_neighbor(n);
- }
- return NULL;
-}
-
-
-// Modified our own neighbor-entries
-static void modify_neighbor(struct in6_addr *addr,
- struct interface *iface, bool add)
-{
- if (!addr || (void*)addr == (void*)iface)
- return;
-
- struct ndp_neighbor *n = find_neighbor(addr, true);
- if (!add) { // Delete action
- if (n && (!n->iface || n->iface == iface))
- free_neighbor(n);
- } else if (!n) { // No entry yet, add one if possible
- if (neighbor_count >= NDP_MAX_NEIGHBORS ||
- !(n = malloc(sizeof(*n))))
- return;
-
- n->len = 128;
- n->addr = *addr;
- n->iface = iface;
- if (!n->iface)
- time(&n->timeout);
- list_add(&n->head, &neighbors);
- ++neighbor_count;
- setup_route(addr, n->iface, add);
- } else if (n->iface == iface) {
- if (!n->iface)
- time(&n->timeout);
- } else if (iface && (!n->iface ||
- (!iface->external && n->iface->external))) {
- setup_route(addr, n->iface, false);
- n->iface = iface;
- setup_route(addr, n->iface, add);
- }
- // TODO: In case a host switches interfaces we might want
- // to set its old neighbor entry to NUD_STALE and ping it
- // on the old interface to confirm if the MACs match.