diff options
Diffstat (limited to 'nest/neighbor.c')
-rw-r--r-- | nest/neighbor.c | 34 |
1 files changed, 27 insertions, 7 deletions
diff --git a/nest/neighbor.c b/nest/neighbor.c index 67bd32b..458d9fb 100644 --- a/nest/neighbor.c +++ b/nest/neighbor.c @@ -49,6 +49,9 @@ static slab *neigh_slab; static list sticky_neigh_list, neigh_hash_table[NEIGH_HASH_SIZE]; +static neighbor * +neigh_find_internal(struct proto *p, ip_addr *a, struct iface *ifa, char *bound_iface, unsigned flags); + static inline unsigned int neigh_hash(struct proto *p, ip_addr *a) { @@ -103,18 +106,32 @@ if_connected(ip_addr *a, struct iface *i) /* -1=error, 1=match, 0=no match */ * If the node is not connected directly or *@a is not a valid unicast * IP address, neigh_find() returns %NULL. */ + + neighbor * neigh_find(struct proto *p, ip_addr *a, unsigned flags) { - return neigh_find2(p, a, NULL, flags); + return neigh_find_internal(p, a, NULL, NULL, flags); } neighbor * neigh_find2(struct proto *p, ip_addr *a, struct iface *ifa, unsigned flags) { + return neigh_find_internal(p, a, ifa, ifa ? ifa->name : NULL, flags); +} + +neighbor * +neigh_find_ifname(struct proto *p, ip_addr *a, char *ifname, unsigned flags) +{ + return neigh_find_internal(p, a, ifname ? if_find_by_name(ifname) : NULL, ifname, flags); +} + +static neighbor * +neigh_find_internal(struct proto *p, ip_addr *a, struct iface *ifa, char *ifname, unsigned flags) +{ neighbor *n; - int class, scope = -1; ; + int class, scope = -1; unsigned int h = neigh_hash(p, a); struct iface *i; @@ -126,7 +143,7 @@ neigh_find2(struct proto *p, ip_addr *a, struct iface *ifa, unsigned flags) if (class < 0) /* Invalid address */ return NULL; if (((class & IADDR_SCOPE_MASK) == SCOPE_HOST) || - (((class & IADDR_SCOPE_MASK) == SCOPE_LINK) && (ifa == NULL)) || + (((class & IADDR_SCOPE_MASK) == SCOPE_LINK) && (ifa == NULL) && (ifname == NULL)) || !(class & IADDR_HOST)) return NULL; /* Bad scope or a somecast */ @@ -137,7 +154,7 @@ neigh_find2(struct proto *p, ip_addr *a, struct iface *ifa, unsigned flags) if ((scope < 0) && (flags & NEF_ONLINK)) scope = class & IADDR_SCOPE_MASK; } - else + else if (ifname == NULL) WALK_LIST(i, iface_list) if ((scope = if_connected(a, i)) >= 0) { @@ -160,8 +177,6 @@ neigh_find2(struct proto *p, ip_addr *a, struct iface *ifa, unsigned flags) } else { - /* sticky flag does not work for link-local neighbors; - fortunately, we don't use this combination */ add_tail(&sticky_neigh_list, &n->n); ifa = NULL; scope = -1; @@ -172,6 +187,8 @@ neigh_find2(struct proto *p, ip_addr *a, struct iface *ifa, unsigned flags) n->aux = 0; n->flags = flags; n->scope = scope; + strncpy(n->bound_iface, ifname ?: "", sizeof(n->bound_iface)-1); + return n; } @@ -193,6 +210,8 @@ neigh_dump(neighbor *n) debug("%s %p %08x scope %s", n->proto->name, n->data, n->aux, ip_scope_text(n->scope)); if (n->flags & NEF_STICKY) debug(" STICKY"); + if (*n->bound_iface) + debug(" bound to %s", n->bound_iface); debug("\n"); } @@ -262,7 +281,8 @@ neigh_if_up(struct iface *i) int scope; WALK_LIST_DELSAFE(n, next, sticky_neigh_list) - if ((scope = if_connected(&n->addr, i)) >= 0) + if ((!(*n->bound_iface) || strcmp(n->bound_iface, i->name) == 0) + && (scope = if_connected(&n->addr, i)) >= 0) neigh_up(n, i, scope); } |