diff options
Diffstat (limited to 'nest/iface.c')
-rw-r--r-- | nest/iface.c | 177 |
1 files changed, 177 insertions, 0 deletions
diff --git a/nest/iface.c b/nest/iface.c new file mode 100644 index 00000000..79a7b7d9 --- /dev/null +++ b/nest/iface.c @@ -0,0 +1,177 @@ +/* + * BIRD -- Management of Interfaces + * + * (c) 1998 Martin Mares <mj@ucw.cz> + * + * Can be freely distributed and used under the terms of the GNU GPL. + */ + +#include "nest/bird.h" +#include "nest/iface.h" +#include "lib/resource.h" + +list iface_list; + +static pool *if_pool; + +void +if_dump(struct iface *i) +{ + struct ifa *a; + + debug("IF%d: %s", i->index, i->name); + if (i->flags & IF_ADMIN_DOWN) + debug(" ADMIN-DOWN"); + if (i->flags & IF_UP) + debug(" UP"); + if (i->flags & IF_MULTIACCESS) + debug(" MA"); + if (i->flags & IF_UNNUMBERED) + debug(" UNNUM"); + if (i->flags & IF_BROADCAST) + debug(" BC"); + if (i->flags & IF_MULTICAST) + debug(" MC"); + if (i->flags & IF_TUNNEL) + debug(" TUNL"); + if (i->flags & IF_LOOPBACK) + debug(" LOOP"); + if (i->flags & IF_IGNORE) + debug(" IGN"); + debug(" MTU=%d\n", i->mtu); + for(a=i->ifa; a; a=a->next) + debug("\t%08x, net %08x/%-2d bc %08x -> %08x\n", _I(a->ip), _I(a->prefix), a->pxlen, _I(a->brd), _I(a->opposite)); +} + +void +if_dump_all(void) +{ + struct iface *i; + + debug("Known network interfaces:\n\n"); + WALK_LIST(i, iface_list) + if_dump(i); + debug("\n"); +} + +struct if_with_a { + struct iface i; + struct ifa a[0]; +}; + +static struct iface * +if_copy(struct iface *j) +{ + int len; + struct if_with_a *w; + struct iface *i; + struct ifa *a, **b, *c; + + len = 0; + for(a=j->ifa; a; a=a->next) + len++; + w = mb_alloc(if_pool, sizeof(struct if_with_a) + len*sizeof(struct ifa)); + i = &w->i; + c = w->a; + memcpy(i, j, sizeof(struct iface)); + b = &i->ifa; + a = j->ifa; + while (a) + { + *b = c; + memcpy(c, a, sizeof(struct ifa)); + b = &c->next; + a = a->next; + c++; + } + *b = NULL; + return i; +} + +static inline void +if_free(struct iface *i) +{ + mb_free(i); +} + +static unsigned +if_changed(struct iface *i, struct iface *j) +{ + unsigned f = 0; + struct ifa *x, *y; + + x = i->ifa; + y = j->ifa; + while (x && y) + { + x = x->next; + y = y->next; + } + if (x || y) + f |= IF_CHANGE_ADDR; + if (i->mtu != j->mtu) + f |= IF_CHANGE_MTU; + if (i->flags != j->flags) + { + f |= IF_CHANGE_FLAGS; + if ((i->flags ^ j->flags) & IF_UP) + if (i->flags & IF_UP) + f |= IF_CHANGE_DOWN; + else + f |= IF_CHANGE_UP; + } + return f; +} + +static void +if_notify_change(unsigned c, struct iface *old, struct iface *new) +{ + debug("Interface change notification (%x) for %s\n", c, new->name); +} + +void +if_update(struct iface *new) +{ + struct iface *i; + + WALK_LIST(i, iface_list) + if (!strcmp(new->name, i->name)) + { + unsigned c = if_changed(i, new); + if (c) + { + struct iface *j = if_copy(new); + if_notify_change(c, i, j); + insert_node(&j->n, &i->n); + rem_node(&i->n); + if_free(i); + } + return; + } + i = if_copy(new); + add_tail(&iface_list, &i->n); + if_notify_change(IF_CHANGE_UP | IF_CHANGE_FLAGS | IF_CHANGE_MTU | IF_CHANGE_ADDR, NULL, i); +} + +void +if_end_update(void) +{ + struct iface *i, j; + + WALK_LIST(i, iface_list) + if (i->flags & IF_UPDATED) + i->flags &= ~IF_UPDATED; + else + { + memcpy(&j, i, sizeof(struct iface)); + i->flags = (i->flags & ~IF_UP) | IF_ADMIN_DOWN; + if_notify_change(IF_CHANGE_DOWN | IF_CHANGE_FLAGS, &j, i); + } +} + +void +if_init(void) +{ + if_pool = rp_new(&root_pool, "Interfaces"); + init_list(&iface_list); +} |