void config_del_obstacle(struct config *);
void order_shutdown(void);
+static inline void
+cf_range(const char *opt, int val, int min, int max)
+{
+ if ((val < min) || (val > max))
+ cf_error("%s must be in range %d-%d", opt, min, max);
+}
+
+
#define CONF_DONE 0
#define CONF_PROGRESS 1
#define CONF_QUEUED 2
CF_DEFINES
+static void
+check_u8(unsigned val)
+{
+ if (val > 0xFF)
+ cf_error("Value %d out of range (0-255)", val);
+}
+
static void
check_u16(unsigned val)
{
else
ip=ipv4
SUFFIX=""
- all_protocols=bgp,ospf,pipe,rip,static
+ all_protocols=bgp,ospf,isis,pipe,rip,static
fi
if test "$given_suffix" = yes ; then
#ifdef CONFIG_OSPF
proto_build(&proto_ospf);
#endif
+#ifdef CONFIG_ISIS
+ proto_build(&proto_isis);
+#endif
#ifdef CONFIG_PIPE
proto_build(&proto_pipe);
#endif
extern struct protocol
proto_device, proto_radv, proto_rip, proto_static,
- proto_ospf, proto_pipe, proto_bgp;
+ proto_ospf, proto_isis, proto_pipe, proto_bgp;
/*
* Routing Protocol Instance
--- /dev/null
+source=isis.c ifaces.c lsdb.c packets.c
+root-rel=../../
+dir-name=proto/isis
+
+include ../../Rules
--- /dev/null
+/*
+ * BIRD -- IS-IS Configuration
+ *
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+CF_HDR
+
+#include "proto/isis/isis.h"
+
+CF_DEFINES
+
+#define ISIS_CFG ((struct isis_config *) this_proto)
+#define ISIS_IFACE ((struct isis_iface_config *) this_ipatt)
+
+static byte area_id_buffer[13];
+static byte *area_id_bpos;
+
+CF_DECLS
+
+CF_KEYWORDS(AREA, BCAST, BROADCAST, BUFFER, CSNP, HELLO, HOLD, ID, INTERFACE, ISIS, LEVEL, LIFETIME,
+ LSP, METRIC, MULT, PASSIVE, POINTOPOINT, PRIORITY, PSNP, PTP, RETRANSMIT, RX, SIZE, SYSTEM,
+ TX, TYPE)
+
+
+%type<i> isis_level
+
+CF_GRAMMAR
+
+CF_ADDTO(proto, isis_proto)
+
+isis_proto_start: proto_start ISIS
+{
+ this_proto = proto_config_new(&proto_isis, sizeof(struct isis_config), $1);
+ init_list(&ISIS_CFG->patt_list);
+ ISIS_CFG->lsp_lifetime = ISIS_DEFAULT_LSP_LIFETIME;
+ ISIS_CFG->rx_buffer_size = ISIS_DEFAULT_RX_BUFFER_SIZE;
+ ISIS_CFG->tx_buffer_size = ISIS_DEFAULT_TX_BUFFER_SIZE;
+};
+
+isis_proto_item:
+ proto_item
+ | INTERFACE isis_iface
+ | AREA ID isis_area_id
+ | SYSTEM ID isis_system_id
+ | LSP LIFETIME expr { ISIS_CFG->lsp_lifetime = $3; cf_range("LSP lifetime", $3, 300, 65535); }
+ | RX BUFFER SIZE expr { ISIS_CFG->rx_buffer_size = $4; cf_range("RX buffer size", $4, 256, 65535); }
+ | TX BUFFER SIZE expr { ISIS_CFG->tx_buffer_size = $4; cf_range("TX buffer size", $4, 256, 65535); }
+ ;
+
+isis_proto_finish:
+{
+ struct isis_config *cf = ISIS_CFG;
+
+ if (! cf->areas[0])
+ cf_error("Missing area ID");
+
+ if (cf->rx_buffer_size < cf->tx_buffer_size)
+ cf_error("RX buffer size must be greater than TX buffer size");
+}
+
+isis_proto_opts:
+ /* empty */
+ | isis_proto_opts isis_proto_item ';'
+ ;
+
+isis_proto:
+ isis_proto_start proto_name '{' isis_proto_opts '}';
+
+
+isis_iface_start:
+{
+ this_ipatt = cfg_allocz(sizeof(struct isis_iface_config));
+ add_tail(&ISIS_CFG->patt_list, NODE this_ipatt);
+
+ ISIS_IFACE->levels[ISIS_L1] = ISIS_DEFAULT_LEVEL_1;
+ ISIS_IFACE->levels[ISIS_L2] = ISIS_DEFAULT_LEVEL_2;
+ ISIS_IFACE->metric = ISIS_DEFAULT_METRIC;
+ ISIS_IFACE->priority = ISIS_DEFAULT_PRIORITY;
+
+ ISIS_IFACE->hello_int = ISIS_DEFAULT_HELLO_INT;
+ ISIS_IFACE->hold_int = ISIS_DEFAULT_HOLD_INT;
+ ISIS_IFACE->hold_mult = ISIS_DEFAULT_HOLD_MULT;
+ ISIS_IFACE->rxmt_int = ISIS_DEFAULT_RXMT_INT;
+ ISIS_IFACE->csnp_int = ISIS_DEFAULT_CSNP_INT;
+ ISIS_IFACE->psnp_int = ISIS_DEFAULT_PSNP_INT;
+};
+
+isis_level: expr { $$ = $1 - 1; if (($1 < 1) || ($1 > 2)) cf_error("Level must be 1 or 2"); }
+
+isis_iface_item:
+ LEVEL isis_level bool { ISIS_IFACE->levels[$2] = $3; }
+ | LEVEL isis_level PASSIVE { ISIS_IFACE->levels[$2] = ISIS_LEVEL_PASSIVE; }
+ | PASSIVE bool { ISIS_IFACE->passive = $2; }
+
+ | TYPE BROADCAST { ISIS_IFACE->type = ISIS_IT_BCAST; }
+ | TYPE BCAST { ISIS_IFACE->type = ISIS_IT_BCAST; }
+ | TYPE POINTOPOINT { ISIS_IFACE->type = ISIS_IT_PTP; }
+ | TYPE PTP { ISIS_IFACE->type = ISIS_IT_PTP; }
+
+ | METRIC expr { ISIS_IFACE->metric = $2; cf_range("Metric", $2, 1, 63); }
+ | PRIORITY expr { ISIS_IFACE->priority = $2; cf_range("Priority", $2, 1, 127); }
+
+ | HELLO expr { ISIS_IFACE->hello_int = $2; cf_range("Hello interval", $2, 1, 65535); }
+ | HOLD expr { ISIS_IFACE->hold_int = $2; cf_range("Hold interval", $2, 3, 65535); }
+ | HOLD MULT expr { ISIS_IFACE->hold_mult = $3; cf_range("Hold multiplier", $3, 3, 255); }
+ | RETRANSMIT expr { ISIS_IFACE->rxmt_int = $2; cf_range("Retransmit interval", $2, 3, 65535); }
+ | CSNP expr { ISIS_IFACE->csnp_int = $2; cf_range("CSNP interval", $2, 1, 65535); }
+ | PSNP expr { ISIS_IFACE->psnp_int = $2; cf_range("PSNP interval", $2, 1, 65535); }
+ ;
+
+isis_iface_finish:
+{
+ struct isis_iface_config *ic = ISIS_IFACE;
+
+ if (! ic->hold_int)
+ {
+ u32 hold_int = ic->hold_mult * (u32) ic->hello_int;
+ if (hold_int > 65535)
+ cf_error("Hello interval times Hold multiplier greater than 65535");
+ ic->hold_int = hold_int;
+ }
+};
+
+isis_iface_opts:
+ /* empty */
+ | isis_iface_opts isis_iface_item ';'
+ ;
+
+isis_iface_opt_list:
+ /* empty */
+ | '{' isis_iface_opts '}'
+ ;
+
+isis_iface:
+ isis_iface_start iface_patt_list isis_iface_opt_list isis_iface_finish;
+
+
+
+isis_area_id_read:
+ NUM
+ {
+ check_u8($1);
+ if ($1 == 0)
+ cf_error("Area ID must not start with 0");
+ area_id_bpos = area_id_buffer;
+ *area_id_bpos++ = $1;
+ }
+ | isis_area_id_read '-' NUM
+ {
+ check_u16($3);
+ if ((area_id_bpos + 2 - area_id_buffer) > sizeof(area_id_buffer))
+ cf_error("Area ID too long");
+ put_u16(area_id_bpos, $3);
+ area_id_bpos += 2;
+ }
+ ;
+
+isis_area_id: isis_area_id_read
+{
+ struct isis_area_id *area_id;
+ int i, blen;
+
+ for (i = 0; i < ISIS_AREAS; i++)
+ if (! ISIS_CFG->areas[i])
+ goto found;
+
+ cf_error("Too many areas");
+
+found:
+ blen = area_id_bpos - area_id_buffer;
+ area_id = cfg_allocz(1 + blen);
+ area_id->length = blen;
+ memcpy(area_id->body, area_id_buffer, blen);
+ ISIS_CFG->areas[i] = area_id;
+}
+
+isis_system_id: NUM '-' NUM '-' NUM
+{
+ check_u16($1); check_u16($3); check_u16($5);
+ ISIS_CFG->system_id = (((u64) $1) << 48) | (((u64) $3) << 32) | (((u64) $5) << 16);
+}
+
+CF_CODE
+
+CF_END
--- /dev/null
+/*
+ * BIRD -- IS-IS Interfaces and Neighbors
+ *
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+
+#include <stdlib.h>
+#include "isis.h"
+
+static char* ev_name[] = { NULL, "Init", "Change", "RS" };
+
+#ifdef XXX
+static void
+isis_timer(timer *tm)
+{
+ struct isis_iface *ifa = tm->data;
+ struct isis_proto *p = ifa->ra;
+
+ ISIS_TRACE(D_EVENTS, "Timer fired on %s", ifa->iface->name);
+
+ isis_send_ra(ifa, 0);
+
+ /* Update timer */
+ ifa->last = now;
+ unsigned after = ifa->cf->min_ra_int;
+ after += random() % (ifa->cf->max_ra_int - ifa->cf->min_ra_int + 1);
+
+ if (ifa->initial)
+ ifa->initial--;
+
+ if (ifa->initial)
+ after = MIN(after, MAX_INITIAL_RTR_ADVERT_INTERVAL);
+
+ tm_start(ifa->timer, after);
+}
+
+void
+isis_iface_notify(struct isis_iface *ifa, int event)
+{
+ struct isis_proto *p = ifa->p;
+
+ if (!ifa->sk)
+ return;
+
+ ISIS_TRACE(D_EVENTS, "Event %s on %s", ev_name[event], ifa->iface->name);
+
+ switch (event)
+ {
+ case RA_EV_CHANGE:
+ ifa->plen = 0;
+ case RA_EV_INIT:
+ ifa->initial = MAX_INITIAL_RTR_ADVERTISEMENTS;
+ break;
+
+ case RA_EV_RS:
+ break;
+ }
+
+ /* Update timer */
+ unsigned delta = now - ifa->last;
+ unsigned after = 0;
+
+ if (delta < ifa->cf->min_delay)
+ after = ifa->cf->min_delay - delta;
+
+ tm_start(ifa->timer, after);
+}
+#endif
+
+/*
+isis_dr_election()
+{
+
+ at least one up, all relevant neighbors and myself
+
+ local system becomes or resign -> event lANLevel1/2DesignatedIntermediateSystemChange
+ becomes ->
+ set lan-id
+ originate new and purge old pseudonode LSP
+
+ zmena dr -> zmenit lan-id
+ zmena lan-id -> zmena me LSP
+}
+ */
+
+static struct isis_iface *
+isis_iface_find(struct isis_proto *p, struct iface *what)
+{
+ struct isis_iface *ifa;
+
+ WALK_LIST(ifa, p->iface_list)
+ if (ifa->iface == what)
+ return ifa;
+
+ return NULL;
+}
+
+static void
+iface_olock_hook(struct object_lock *lock)
+{
+ struct isis_iface *ifa = lock->data;
+ struct isis_proto *p = ifa->p;
+
+ if (! isis_sk_open(ifa))
+ {
+ log(L_ERR "%s: Socket open failed on interface %s", p->p.name, ifa->iface->name);
+ return;
+ }
+
+ // XXX isis_iface_notify(ifa, RA_EV_INIT);
+}
+
+
+static void
+l1_hello_timer_hook(timer *timer)
+{
+ struct isis_iface *ifa = (struct isis_iface *) timer->data;
+
+ isis_send_lan_hello(ifa, ISIS_L1);
+}
+
+static void
+l2_hello_timer_hook(timer *timer)
+{
+ struct isis_iface *ifa = (struct isis_iface *) timer->data;
+
+ isis_send_lan_hello(ifa, ISIS_L2);
+}
+
+static void
+ptp_hello_timer_hook(timer *timer)
+{
+ struct isis_iface *ifa = (struct isis_iface *) timer->data;
+
+ isis_send_ptp_hello(ifa);
+}
+
+static void
+csnp_timer_hook(timer *timer)
+{
+ struct isis_iface *ifa = (struct isis_iface *) timer->data;
+ struct isis_proto *p = ifa->p;
+ struct isis_lsp *lsp;
+ int n;
+
+ /* FIXME: CSNP rate limiting */
+
+ if (XXX)
+ {
+ n = 0;
+ lsp = isis_lsdb_first(p->lsdb[ISIS_L1], lsp, ifa);
+ while (lsp)
+ isis_send_csnp(ifa, ISIS_L1, &lsp, n++ == 0);
+ }
+
+ if (XXX)
+ {
+ n = 0;
+ lsp = isis_lsdb_first(p->lsdb[ISIS_L2], lsp, ifa);
+ while (lsp)
+ isis_send_csnp(ifa, ISIS_L2, &lsp, n++ == 0);
+ }
+}
+
+static void
+psnp_timer_hook(timer *timer)
+{
+ struct isis_iface *ifa = (struct isis_iface *) timer->data;
+ struct isis_proto *p = ifa->p;
+ struct isis_lsp *lsp;
+
+ if (XXX)
+ {
+ lsp = isis_lsdb_first_ssn(p->lsdb[ISIS_L1], lsp, ifa);
+ while (lsp)
+ isis_send_psnp(ifa, ISIS_L1, &lsp);
+ }
+
+ if (XXX)
+ {
+ lsp = isis_lsdb_first_ssn(p->lsdb[ISIS_L2], lsp, ifa);
+ while (lsp)
+ isis_send_psnp(ifa, ISIS_L2, &lsp);
+ }
+}
+
+
+static void
+isis_iface_new(struct isis_proto *p, struct iface *iface, struct isis_iface_config *cf)
+{
+ ISIS_TRACE(D_EVENTS, "Adding interface %s", iface->name);
+
+ pool *pool = rp_new(p->p.pool, "ISIS Interface");
+ struct isis_iface *ifa = mb_allocz(pool, sizeof(struct isis_iface));
+
+ add_tail(&p->iface_list, NODE ifa);
+ ifa->p = p;
+ ifa->cf = cf;
+ ifa->iface = iface;
+
+ ifa->pool = pool;
+ init_list(&ifa->neigh_list);
+
+ ifa->type = ifa->cf->type;
+ ifa->levels = ifa->cf->levels;
+ ifa->priority = ifa->cf->priority;
+ ifa->hello_int = ifa->cf->hello_int;
+ ifa->hold_int = ifa->cf->hold_int;
+
+ if (ifa->type == ISIS_IT_PASSIVE)
+ return;
+
+ ifa->hello_timer = tm_new_set(pool, hello_timer_hook, ifa, xxx, xxx);
+
+ struct object_lock *lock = olock_new(pool);
+ lock->addr = IPA_NONE;
+ lock->type = OBJLOCK_IP;
+ lock->port = ISIS_PROTO;
+ lock->iface = iface;
+ lock->data = ifa;
+ lock->hook = iface_olock_hook;
+ ifa->lock = lock;
+
+ olock_acquire(lock);
+}
+
+/*
+static inline void
+isis_iface_shutdown(struct isis_iface *ifa)
+{
+ if (ifa->sk)
+ isis_send_ra(ifa, 1);
+}
+*/
+
+static void
+isis_iface_remove(struct isis_iface *ifa)
+{
+ struct isis_proto *p = ifa->p;
+
+ ISIS_TRACE(D_EVENTS, "Removing interface %s", ifa->iface->name);
+
+ // XXX isis_iface_sm(ifa, ISM_DOWN);
+ rem_node(NODE ifa);
+ rfree(ifa->pool);
+}
+
+void
+isis_if_notify(struct proto *pp, unsigned flags, struct iface *iface)
+{
+ struct isis_proto *p = (struct isis_proto *) pp;
+ struct isis_config *cf = (struct isis_config *) (pp->cf);
+
+ if (iface->flags & IF_IGNORE)
+ return;
+
+ if (flags & IF_CHANGE_UP)
+ {
+ struct isis_iface_config *ic = (struct isis_iface_config *)
+ iface_patt_find(&cf->patt_list, iface, NULL);
+
+ if (ic)
+ isis_iface_new(p, iface, ic);
+
+ return;
+ }
+
+ struct isis_iface *ifa = isis_iface_find(p, iface);
+ if (!ifa)
+ return;
+
+ if (flags & IF_CHANGE_DOWN)
+ {
+ isis_iface_remove(ifa);
+ return;
+ }
+
+ if ((flags & IF_CHANGE_LINK) && (iface->flags & IF_LINK_UP))
+ isis_iface_notify(ifa, RA_EV_INIT);
+}
+
+/*
+void
+isis_ifa_notify(struct proto *pp, unsigned flags, struct ifa *a)
+{
+ struct isis_proto *p = (struct isis_proto *) pp;
+
+ if (a->flags & IA_SECONDARY)
+ return;
+
+ if (a->scope <= SCOPE_LINK)
+ return;
+
+ struct isis_iface *ifa = isis_iface_find(ra, a->iface);
+
+ if (ifa)
+ isis_iface_notify(ifa, RA_EV_CHANGE);
+}
+
+*/
+
+
+
+
+static void
+hold_timer_hook(timer *timer)
+{
+ struct isis_neighbor *n = (struct isis_neighbor *) timer->data;
+ struct isis_iface *ifa = n->ifa;
+ struct isis_proto *p = ifa->p;
+
+ // xxx ISIS_TRACE(D_EVENTS, "Hold timer expired for neighbor %I", n->ip);
+ isis_neighbor_remove(n);
+}
+
+
+struct isis_neighbor *
+isis_neighbor_add(struct isis_iface *ifa)
+{
+ struct isis_proto *p = ifa->p;
+ struct isis_neighbor *n = mb_allocz(ifa->pool, sizeof(struct isis_neighbor));
+
+ add_tail(&ifa->neigh_list, NODE n);
+ n->ifa = ifa;
+
+ n->hold_timer = tm_new_set(ifa->pool, hold_timer_hook, n, xxx, xxx);
+
+ return (n);
+}
+
+void
+isis_neighbor_remove(struct isis_neighbor *n)
+{
+ struct isis_iface *ifa = n->ifa;
+ struct isis_proto *p = ifa->p;
+
+ // xxx ISIS_TRACE(D_EVENTS, "Removing neigbor");
+
+ rem_node(NODE n);
+ rfree(n->hold_timer);
+}
+
+/*
+ new:
+ t neighbourSystemType - podle typu paketu
+ holdingTimer, priorityOfNeighbour, neighbour-SystemID and areaAddressesOfNeighbour - podle obsahu
+ mac_addr
+ state -> init
+ checknout my sysID in list -> up
+
+
+ */
--- /dev/null
+/*
+ * BIRD -- IS-IS
+ *
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+
+#include <stdlib.h>
+#include "isis.h"
+
+/**
+ * DOC: Intermediate System to Intermediate System (IS-IS)
+ *
+ * Intermediate System to Intermediate System
+ * intra-domain routeing information exchange protocol
+ *
+ * XXXX
+ *
+ * Supported standards:
+ * - ISO 10589 - main IS-IS standard
+ * - RFC xxxx -
+ */
+
+
+static struct proto *
+isis_init(struct proto_config *c)
+{
+ struct proto *pp = proto_new(c, sizeof(struct isis_proto));
+
+ pp->if_notify = isis_if_notify;
+ pp->ifa_notify = isis_ifa_notify;
+ return pp;
+}
+
+static int
+isis_start(struct proto *pp)
+{
+ struct isis_proto *p = (struct isis_proto *) pp;
+ // struct isis_config *cf = (struct isis_config *) (pp->cf);
+
+ init_list(&(p->iface_list));
+
+ return PS_UP;
+}
+
+static int
+isis_shutdown(struct proto *pp)
+{
+ struct isis_proto *p = (struct isis_proto *) pp;
+
+ struct isis_iface *ifa;
+ WALK_LIST(ifa, p->iface_list)
+ isis_iface_shutdown(ifa);
+
+ return PS_DOWN;
+}
+
+#ifdef XXX
+static int
+isis_reconfigure(struct proto *pp, struct proto_config *c)
+{
+ struct isis_proto *p = (struct isis_proto *) pp;
+ // struct isis_config *old = (struct isis_config *) (p->cf);
+ struct isis_config *new = (struct isis_config *) c;
+
+ /*
+ * The question is why there is a reconfigure function for RAdv if
+ * it has almost none internal state so restarting the protocol
+ * would probably suffice. One small reason is that restarting the
+ * protocol would lead to sending a RA with Router Lifetime 0
+ * causing nodes to temporary remove their default routes.
+ */
+
+ struct iface *iface;
+ WALK_LIST(iface, iface_list)
+ {
+ struct isis_iface *ifa = isis_iface_find(ra, iface);
+ struct isis_iface_config *ic = (struct isis_iface_config *)
+ iface_patt_find(&new->patt_list, iface, NULL);
+
+ if (ifa && ic)
+ {
+ ifa->cf = ic;
+
+ /* We cheat here - always notify the change even if there isn't
+ any. That would leads just to a few unnecessary RAs. */
+ isis_iface_notify(ifa, RA_EV_CHANGE);
+ }
+
+ if (ifa && !ic)
+ {
+ isis_iface_shutdown(ifa);
+ isis_iface_remove(ifa);
+ }
+
+ if (!ifa && ic)
+ isis_iface_new(ra, iface, ic);
+ }
+
+ return 1;
+}
+
+static void
+isis_copy_config(struct proto_config *dest, struct proto_config *src)
+{
+ struct isis_config *d = (struct isis_config *) dest;
+ struct isis_config *s = (struct isis_config *) src;
+
+ /* We clean up patt_list, ifaces are non-sharable */
+ init_list(&d->patt_list);
+}
+#endif
+
+
+struct protocol isis_proto = {
+ .name = "IS-IS",
+ .template = "isis%d",
+ .init = isis_init,
+ .start = isis_start,
+ .shutdown = isis_shutdown,
+ // .reconfigure = isis_reconfigure,
+ // .copy_config = isis_copy_config
+};
--- /dev/null
+/*
+ * BIRD -- Router Advertisement
+ *
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#ifndef _BIRD_ISIS_H_
+#define _BIRD_ISIS_H_
+
+#include "nest/bird.h"
+
+#include "lib/ip.h"
+#include "lib/lists.h"
+#include "lib/socket.h"
+#include "lib/timer.h"
+#include "lib/resource.h"
+#include "nest/protocol.h"
+#include "nest/iface.h"
+#include "nest/route.h"
+#include "nest/cli.h"
+#include "nest/locks.h"
+#include "conf/conf.h"
+#include "lib/string.h"
+
+
+#define ISIS_PROTO 90 // XXX
+
+#define ISIS_LEVELS 2
+#define ISIS_L1 0
+#define ISIS_L2 1
+
+#define ISIS_AREAS 3
+
+
+#define mac_addr ip_addr // XXX
+
+#define ETH_ALL_ISS ipa_from_u32(0xe0000005) /* 224.0.0.5 */
+#define ETH_ALL_L1_ISS ipa_from_u32(0xe0000005) /* 224.0.0.5 */
+#define ETH_ALL_L2_ISS ipa_from_u32(0xe0000005) /* 224.0.0.5 */
+
+
+struct isis_area_id
+{
+ byte length;
+ byte body[];
+};
+
+struct isis_config
+{
+ struct proto_config c;
+ list patt_list; /* List of iface configs (struct isis_iface_config) */
+ struct isis_area_id *areas[ISIS_AREAS];
+
+ u64 system_id;
+
+ u16 lsp_lifetime;
+ u16 rx_buffer_size;
+ u16 tx_buffer_size;
+};
+
+#define ISIS_DEFAULT_LSP_LIFETIME 1200
+#define ISIS_DEFAULT_RX_BUFFER_SIZE 1492
+#define ISIS_DEFAULT_TX_BUFFER_SIZE 1492
+
+struct isis_iface_config
+{
+ struct iface_patt i;
+
+ u8 levels[ISIS_LEVELS];
+ u8 passive;
+ u8 type;
+ u8 metric;
+ u8 priority;
+
+ u16 hello_int;
+ u16 hold_int;
+ u16 hold_mult;
+ u16 rxmt_int;
+ u16 csnp_int;
+ u16 psnp_int;
+};
+
+#define ISIS_LEVEL_PASSIVE 2
+
+#define ISIS_DEFAULT_LEVEL_1 1
+#define ISIS_DEFAULT_LEVEL_2 0
+#define ISIS_DEFAULT_METRIC 1
+#define ISIS_DEFAULT_PRIORITY 64
+
+#define ISIS_DEFAULT_HELLO_INT 10
+#define ISIS_DEFAULT_HOLD_INT 0
+#define ISIS_DEFAULT_HOLD_MULT 3
+#define ISIS_DEFAULT_RXMT_INT 5
+#define ISIS_DEFAULT_CSNP_INT 10
+#define ISIS_DEFAULT_PSNP_INT 2
+
+
+struct isis_proto
+{
+ struct proto p;
+ list iface_list; /* List of active ifaces */
+
+ u64 system_id;
+ u16 lsp_max_age;
+ u16 lsp_refresh;
+ u16 buffer_size;
+};
+
+struct isis_iface
+{
+ node n;
+ struct isis_proto *p;
+ struct isis_iface_config *cf; /* Related config, must be updated in reconfigure */
+ struct iface *iface;
+
+ pool *pool;
+ struct object_lock *lock;
+ sock *sk;
+ list neigh_list; /* List of neigbours */
+
+ u8 type;
+ u8 levels;
+ u8 priority;
+
+ u16 hello_int;
+ u16 hold_int;
+};
+
+#define ISIS_IT_UNDEF 0
+#define ISIS_IT_BCAST 1
+#define ISIS_IT_PTP 2
+
+
+struct isis_neighbor
+{
+ node n;
+ struct isis_iface *ifa;
+ mac_addr addr;
+ u64 id;
+
+ timer *hold_timer;
+
+ u8 levels;
+ u8 priority;
+};
+
+struct isis_lsdb
+{
+ pool *pool;
+ slab *slab;
+ list list;
+};
+
+struct isis_lsp_hdr
+{
+ u64 id;
+ u32 seqnum;
+ u16 lifetime;
+ u16 checksum;
+}
+
+struct isis_lsp
+{
+ node n;
+ struct isis_lsp_hdr hdr;
+ void *body;
+ u16 blen;
+};
+
+
+
+#define RA_EV_INIT 1 /* Switch to initial mode */
+#define RA_EV_CHANGE 2 /* Change of options or prefixes */
+#define RA_EV_RS 3 /* Received RS */
+
+
+
+#ifdef LOCAL_DEBUG
+#define ISIS_FORCE_DEBUG 1
+#else
+#define ISIS_FORCE_DEBUG 0
+#endif
+#define ISIS_TRACE(flags, msg, args...) do { if ((p->p.debug & flags) || ISIS_FORCE_DEBUG) \
+ log(L_TRACE "%s: " msg, p->p.name , ## args ); } while(0)
+
+
+/* isis.c */
+void isis_iface_notify(struct isis_iface *ifa, int event);
+
+/* ifaces.c */
+void isis_if_notify(struct proto *pp, unsigned flags, struct iface *iface);
+void isis_ifa_notify(struct proto *pp, unsigned flags, struct ifa *a);
+
+/* packets.c */
+void isis_send_lan_hello(struct isis_iface *ifa, int level);
+void isis_send_ptp_hello(struct isis_iface *ifa);
+void isis_send_lsp(struct isis_iface *ifa, struct lsp_entry *en);
+void isis_send_csnp(struct isis_iface *ifa, int level);
+void isis_send_psnp(struct isis_iface *ifa, int level);
+
+int isis_sk_open(struct isis_iface *ifa);
+
+
+
+#endif /* _BIRD_ISIS_H_ */
--- /dev/null
+/*
+ * BIRD -- IS-IS LSP database
+ *
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+
+static inline int
+isis_lsp_comp(struct isis_lsp_hdr *l1, struct isis_lsp_hdr *l2)
+{
+ if (l1->seqnum != l2->seqnum)
+ return (l1->seqnum > l2->seqnum) ? LSP_NEWER : LSP_OLDER;
+
+ // XXX review
+ if (l1->checksum != l2->checksum)
+ return (l1->checksum > l2->checksum) ? LSP_NEWER : LSP_OLDER;
+
+ return LSP_SAME;
+}
+
+struct isis_lsp *
+isis_get_lsp(struct isis_lsdb *db, xxx)
+{
+}
+
+
+void
+isis_lsp_received(struct isis_lsdb *db, struct isis_iface *ifa,
+ struct isis_lsp_hdr *hdr, byte *body, int blen)
+{
+ struct isis_lsp *lsp = isis_get_lsp(db, hdr);
+
+ int cmp = isis_lsp_comp(hdr, &lsp->hdr);
+ switch (cmp)
+ {
+ LSP_NEWER:
+ xxx();
+ LSP_SAME:
+ isis_lsp_clear_srm(lsp, ifa);
+ isis_lsp_set_ack(lsp, ifa);
+ break;
+
+ LSP_OLDER:
+ isis_lsp_set_srm(lsp, ifa);
+ isis_lsp_clear_ssn(lsp, ifa);
+ break;
+ }
+}
+
+void
+isis_snp_received(struct isis_lsdb *db, struct isis_iface *ifa, struct isis_lsp_hdr *hdr)
+{
+ struct isis_lsp *lsp = isis_get_lsp(db, hdr);
+
+ int cmp = isis_lsp_comp(hdr, &lsp->hdr);
+ switch (cmp)
+ {
+ LSP_NEWER:
+ isis_lsp_set_ssn(lsp, ifa);
+ LSP_SAME:
+ isis_lsp_clear_ack(lsp, ifa);
+ break;
+
+ LSP_OLDER:
+ isis_lsp_set_srm(lsp, ifa);
+ isis_lsp_clear_ssn(lsp, ifa);
+ break;
+ }
+
+ isis_lsp_clear_csnp(lsp);
+}
+
+struct isis_lsdb *
+isis_lsdb_new(struct isis_proto *p)
+{
+ pool *pool = rp_new(p->p.pool, "ISIS LSP database");
+ struct isis_lsdb *db = mb_allocz(pool, sizeof(struct isis_lsdb));
+
+ db->pool = pool;
+ db->slab = sl_new(pool, sizeof(struct lsp_entry));
+ init_list(&db->list);
+}
+
+void
+isis_lsdb_free(struct isis_lsdb *db)
+{
+ rfree(db->pool);
+}
--- /dev/null
+/*
+ * BIRD -- IS-IS Packet Processing
+ *
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+
+#include <stdlib.h>
+#include "isis.h"
+
+
+/*
+ * IS-IS common packet header
+ *
+ * 1B Protocol ID, constant
+ * 1B Fixed header length depends on packet type
+ * 1B Version 1 fixed 1
+ * 1B System ID length fixed 0 or 6
+ * 1B Packet type 0xe0 bits reserved
+ * 1B Version 2 fixed 1
+ * 1B Reserved ignored
+ * 1B Max area addrs fixed 0 or 3
+ *
+ *
+ * IS-IS Hello header
+ *
+ * 8B Common header
+ * 1B Circuit type levels (1, 2 or 1+2), 0xfc bits reserved
+ * 6B System ID
+ * 2B Hold time
+ * 2B Packet length hdr + data
+ * LAN:
+ * 1B Priority 0x80 bit reserved
+ * 7B LAN ID for DR selection
+ * PTP:
+ * 1B Circuit ID we could ignore this (?)
+ *
+ *
+ *
+ * IS-IS LSP header
+ *
+ * 8B Common header
+ * 2B Packet length hdr + data
+ * 2B LSP lifetime
+ * 8B LSP ID
+ * 4B LSP sequence number
+ * 2B LSP checksum
+ * 1B LSP flags
+ *
+ *
+ * IS-IS CSNP header
+ *
+ * 8B Common header
+ * 2B Packet length hdr + data
+ * 7B System ID
+ * 8B Start LSP ID
+ * 8B End LSP ID
+ *
+ *
+ * IS-IS PSNP header
+ *
+ * 8B Common header
+ * 2B Packet length hdr + data
+ * 7B System ID
+ */
+
+
+
+#define ISIS_PROTO_ID 0x83
+
+#define ISIS_L1_HELLO 15
+#define ISIS_L2_HELLO 16
+#define ISIS_PTP_HELLO 17
+#define ISIS_L1_LSP 18
+#define ISIS_L2_LSP 20
+#define ISIS_L1_CSNP 24
+#define ISIS_L2_CSNP 25
+#define ISIS_L1_PSNP 26
+#define ISIS_L2_PSNP 27
+
+#define ISIS_COMMON_HLEN 8
+#define ISIS_LHELLO_HLEN 27
+#define ISIS_PHELLO_HLEN 20
+#define ISIS_LSP_HLEN 27
+#define ISIS_CSNP_HLEN 33
+#define ISIS_PSNP_HLEN 17
+
+#define ISIS_TYPE_MASK 0x1f
+
+
+IntradomainRouteingPD
+
+static inline byte * isis_tx_buffer(struct isis_iface *ifa) { return ifa->sk->tbuf; }
+
+static void
+isis_fill_hdr(byte *pkt, u8 pdu_type, u8 hdr_len)
+{
+ pkt[0] = ISIS_PROTO_ID;
+ pkt[1] = hdr_len;
+ pkt[2] = 1; // Version 1
+ pkt[3] = 6; // System ID length
+ pkt[4] = pdu_type;
+ pkt[5] = 1; // Version 2
+ pkt[6] = 0; // Reserved
+ pkt[7] = 3; // Max area addresses
+}
+
+static inline byte *
+put_lsp_hdr(byte *buf, struct isis_lsp_hdr *hdr)
+{
+ put_u16(buf+ 0, hdr->lifetime);
+ put_u64(buf+ 2, hdr->id);
+ put_u32(buf+10, hdr->seqnum);
+ put_u16(buf+14, hdr->checksum);
+ return buf+16;
+}
+
+static byte *
+isis_put_tlv_areas(struct isis_proto *p, byte *buf)
+{
+ byte *bp = buf + 2;
+ int i;
+
+ for (i = 0; i < ISIS_AREAS; i++)
+ if (cf->areas[i])
+ {
+ int alen = 1 + cf->areas[i]->length;
+ memcpy(bp, cf->areas[i], alen);
+ bp += alen;
+ }
+
+ buf[0] = ISIS_TLV_AREAS;
+ buf[1] = bp - (buf + 2);
+
+ return bp;
+}
+
+static byte *
+isis_put_tlv_protocols(struct isis_proto *p, byte *buf)
+{
+ buf[0] = ISIS_TLV_PROTOCOLS;
+ buf[1] = 1;
+ buf[2] = ISIS_NLPID_IPv4;
+
+ return buf + 3;
+}
+
+static byte *
+isis_put_tlv_ip4_iface_addrs(struct isis_iface *ifa, byte *buf)
+{
+ struct ifa *a;
+ byte *bp = buf + 2;
+ int i;
+
+ WALK_LIST(a, ifa->iface->addrs)
+ {
+ bp = ipa_put_addr(bp, a);
+ }
+
+ buf[0] = ISIS_TLV_IP4_IFACE_ADDRS;
+ buf[1] = bp - (buf + 2);
+
+ return bp;
+}
+
+
+void
+isis_send_lan_hello(struct isis_iface *ifa, int level)
+{
+ struct isis_proto *p = ifa->p;
+
+ byte *pkt = isis_tx_buffer(ifa);
+ isis_fill_hdr(pkt, !level ? ISIS_L1_HELLO : ISIS_L2_HELLO, ISIS_LHELLO_HLEN);
+ put_u8 (pkt+ 8, ifa->levels);
+ put_id6(pkt+ 9, p->system_id);
+ put_u16(pkt+15, ifa->hold_int);
+ // put_u16(pkt+17, ISIS_ + en->blen);
+ put_u8 (pkt+19, ifa->priority);
+ put_id7(pkt+20, 0); // xxx DR
+}
+
+void
+isis_send_ptp_hello(struct isis_iface *ifa)
+{
+ struct isis_proto *p = ifa->p;
+
+ byte *pkt = isis_tx_buffer(ifa);
+ byte *bp = pkt + ISIS_PHELLO_HLEN;
+ byte *be = isis_tx_buffer_end(ifa);
+
+ isis_fill_hdr(pkt, ISIS_PTP_HELLO, ISIS_PHELLO_HLEN);
+ put_u8 (pkt+ 8, ifa->levels);
+ put_id6(pkt+ 9, p->system_id);
+ put_u16(pkt+15, ifa->hold_int);
+ // put_u16(pkt+17, 0); /* Length postponed */
+ put_u8 (pkt+19, 0); /* Fake circuit-id */
+
+ bp = isis_put_tlv_areas(p, bp, be);
+ bp = isis_put_tlv_protocols(p, bp, be);
+ bp = isis_put_tlv_ip4_iface_addrs(ifa, bp, be);
+
+ put_u16(pkt+17, bp - pkt); /* Packet length */
+}
+
+void
+isis_send_lsp(struct isis_iface *ifa, struct isis_lsp *lsp)
+{
+ struct isis_proto *p = ifa->p;
+
+ byte *pkt = isis_tx_buffer(ifa);
+ isis_fill_hdr(pkt, xxx ? ISIS_L1_LSP : ISIS_L2_LSP, ISIS_LSP_HLEN);
+ put_u16(pkt+ 8, ISIS_LSP_HLEN - 1 + lsp->blen);
+ put_lsp_hdr(pkt+10, &lsp->hdr);
+
+ if (lsp->body)
+ memcpy(pkt+26, lsp->body, lsp->blen);
+
+ ISIS_TRACE(D_PACKETS, "Sending LSP via %s", ifa->iface->name);
+ // xxx sk_send_to(ifa->sk, ifa->plen, AllNodes, 0);
+}
+
+void
+isis_process_lsp(struct isis_iface *ifa, int level, byte *pkt, int len)
+{
+ struct isis_proto *p = ifa->p;
+
+ if ((pkt[ISIS_HLEN_POS] != ISIS_LSP_HLEN) || (pkt[8] != len))
+ XXX;
+
+ put_u16(pkt+ 8, ISIS_LSP_HLEN - 1 + lsp->blen);
+ get_lsp_hdr(pkt+10, &hdr);
+ isis_lsp_received(db, ifa, &hdr, pkt+26, len-26)
+
+ if (lsp->body)
+ memcpy(pkt+26, lsp->body, lsp->blen);
+
+}
+
+
+static byte *
+isis_put_tlv_lsp_entries(struct isis_iface *ifa, byte *buf, byte *be,
+ struct isis_lsdb *db, struct isis_lsp **lspp, int psnp)
+{
+ struct isis_lsp *lsp = *lspp;
+ byte *bp = buf + 2;
+ int i = 0;
+
+ be -= 2 + 16; /* TLV header + sizeof(struct isis_lsp_hdr) */
+
+ while (lsp && bp <= be)
+ {
+ if (i == 15)
+ {
+ buf[0] = ISIS_TLV_LSP_ENTRIES;
+ buf[1] = i * 16;
+ i = 0;
+ buf = bp;
+ bp += 2;
+ }
+
+ bp = put_lsp_hdr(bp, &lsp->hdr);
+
+ if (psnp)
+ {
+ // XXX check
+ isis_lsdb_clear_ssn(db, lsp, ifa);
+ lsp = isis_lsdb_next_ssn(db, lsp, ifa);
+ }
+ else
+ lsp = isis_lsdb_next(db, lsp);
+
+ }
+ buf[0] = ISIS_TLV_LSP_ENTRIES;
+ buf[1] = i * 16;
+ *lspp = lsp;
+}
+
+void
+isis_send_csnp(struct isis_iface *ifa, int level, struct isis_lsp **lspp, int first)
+{
+ struct isis_proto *p = ifa->p;
+
+ byte *pkt = isis_tx_buffer(ifa);
+ byte *bp = pkt + ISIS_CSNP_HLEN;
+ byte *be = isis_tx_buffer_end(ifa);
+
+ /* First put TLVs */
+ u64 start_id = first ? ISIS_MIN_LSP_ID : (*lspp)->hdr.id;
+ bp = isis_put_tlv_lsp_entries(p, bp, be, p->lsdb[level], lspp, 0);
+ u64 end_id = *lspp ? (*lspp)->hdr.id - 1 : ISIS_MAX_LSP_ID;
+
+ /* Then put header */
+ isis_fill_hdr(pkt, !level ? ISIS_L1_CSNP : ISIS_L2_CSNP, ISIS_CSNP_HLEN);
+ put_u16(pkt+08, bp - pkt);
+ put_id7(pkt+10, p->system_id);
+ put_u64(pkt+17, start_id);
+ put_u64(pkt+25, end_id);
+
+ ISIS_TRACE(D_PACKETS, "Sending CSNP via %s", ifa->iface->name);
+ // xxx sk_send_to(ifa->sk, ifa->plen, AllNodes, 0);
+}
+
+void
+isis_send_psnp(struct isis_iface *ifa, int level, struct isis_lsp **lspp)
+{
+ struct isis_proto *p = ifa->p;
+
+ byte *pkt = isis_tx_buffer(ifa);
+ byte *bp = pkt + ISIS_PSNP_HLEN;
+ byte *be = isis_tx_buffer_end(ifa);
+
+ /* First put TLVs */
+ bp = isis_put_tlv_lsp_entries(p, bp, be, p->lsdb[level], lspp, 1);
+
+ /* Then put header */
+ isis_fill_hdr(pkt, !level ? ISIS_L1_PSNP : ISIS_L2_PSNP, ISIS_PSNP_HLEN);
+ put_u16(pkt+08, bp - pkt);
+ put_id7(pkt+10, p->system_id);
+
+ ISIS_TRACE(D_PACKETS, "Sending PSNP via %s", ifa->iface->name);
+ // xxx sk_send_to(ifa->sk, ifa->plen, AllNodes, 0);
+}
+
+static inline void
+isis_process_tlv_lsp_entries(struct isis_iface *ifa, byte *tlv, byte *te, struct isis_lsdb *db)
+{
+ struct isis_proto *p = ifa->p;
+ struct isis_lsp_hdr hdr;
+ byte *bp = tlv + 2;
+
+ while (bp + 16 <= te)
+ {
+ bp = get_lsp_hdr(bp, &hdr);
+ isis_snp_received(db, ifa, &hdr);
+ }
+
+ if (bp < te)
+ XXX;
+}
+
+
+static void
+isis_process_csnp(struct isis_iface *ifa, int level, byte *pkt, int len)
+{
+ struct isis_proto *p = ifa->p;
+
+ if ((pkt[ISIS_HLEN_POS] != ISIS_CSNP_HLEN) || (pkt[8] != len))
+ XXX;
+
+ u64 start_id = get_u64(pkt+17);
+ u64 end_id = get_u64(pkt+25);
+ XXX;
+
+ byte *pe = pkt + len;
+ byte *tlv = pkt + ISIS_CSNP_HLEN;
+
+ while (tlv < pe)
+ {
+ byte *te = tlv + 2 + tlv[1];
+ if (te > pe)
+ XXX;
+
+ if (tlv[0] == ISIS_TLV_LSP_ENTRIES)
+ isis_process_tlv_lsp_entries(ifa, tlv, te, p->lsdb[level]);
+
+ tlv = te;
+ }
+
+}
+
+static void
+isis_process_psnp(struct isis_iface *ifa, int level, byte *pkt, int len)
+{
+ struct isis_proto *p = ifa->p;
+
+ if ((pkt[ISIS_HLEN_POS] != ISIS_PSNP_HLEN) || (pkt[8] != len))
+ XXX;
+
+ byte *pe = pkt + len;
+ byte *tlv = pkt + ISIS_PSNP_HLEN;
+
+ while (tlv < pe)
+ {
+ byte *te = tlv + 2 + tlv[1];
+ if (te > pe)
+ XXX;
+
+ if (tlv[0] == ISIS_TLV_LSP_ENTRIES)
+ isis_process_tlv_lsp_entries(ifa, tlv, te, p->lsdb[level]);
+
+ tlv = te;
+ }
+
+}
+
+
+
+#define DROP(DSC,VAL) do { err_dsc = DSC; err_val = VAL; goto drop; } while(0)
+
+static int
+isis_rx_hook(sock *sk, int len)
+{
+ struct isis_iface *ifa = sk->data;
+ struct isis_proto *p = ifa->p;
+ const char *err_dsc = NULL;
+ unsigned err_val = 0;
+
+ if (sk->lifindex != sk->iface->index)
+ return 1;
+
+ DBG("ISIS: RX hook called (iface %s, src %I, dst %I)\n",
+ sk->iface->name, sk->faddr, sk->laddr); // XXX
+
+ // XXX check src addr
+
+ // XXX skip eth header
+ byte *pkt = ip_skip_header(sk->rbuf, &len);
+ if (pkt == NULL)
+ DROP("too short", len);
+
+ if ((len < ISIS_COMMON_HLEN) || (len < pkt[ISIS_HLEN_POS]))
+ DROP("too short", len);
+
+ if (len > sk->rbsize) // XXX
+ DROP("too large", len);
+
+ if (pkt[0] != ISIS_PROTO_ID)
+ DROP("protocol ID mismatch", pkt[0]);
+
+ if (pkt[2] != 1)
+ DROP("version1 mismatch", pkt[2]);
+
+ if (pkt[3] != 0 && pkt[3] != 6)
+ DROP("id_length mismatch", pkt[3]);
+
+ if (pkt[5] != 1)
+ DROP("version2 mismatch", pkt[5]);
+
+ if (pkt[7] != 0 && pkt[7] != 3)
+ DROP("max_area_addrs mismatch", pkt[7]);
+
+
+ // XXX find neighbor?
+
+ int type = pkt[4] & ISIS_TYPE_MASK;
+ int level = ISIS_L1;
+ switch (type)
+ {
+ // XXX ptp
+ // case ISIS_PTP_HELLO:
+
+ case ISIS_L2_HELLO:
+ level = ISIS_L2;
+ case ISIS_L1_HELLO:
+ ISIS_TRACE(D_PACKETS, "Received Hello from xxx via %s", ifa->iface->name);
+ isis_lan_hello_rx(pkt, ifa, n, level);
+ break;
+
+ case ISIS_L2_LSP:
+ level = ISIS_L2;
+ case ISIS_L1_LSP:
+ ISIS_TRACE(D_PACKETS, "Received LSP from xxx via %s", ifa->iface->name);
+ isis_lsp_rx(pkt, ifa, n, level);
+ break;
+
+ case ISIS_L2_CSNP:
+ level = ISIS_L2;
+ case ISIS_L1_CSNP:
+ ISIS_TRACE(D_PACKETS, "Received CSNP from xxx via %s", ifa->iface->name);
+ isis_process_csnp(pkt, ifa, n, level);
+ break;
+
+ case ISIS_L2_PSNP:
+ level = ISIS_L2;
+ case ISIS_L1_PSNP:
+ ISIS_TRACE(D_PACKETS, "Received PSNP from xxx via %s", ifa->iface->name);
+ isis_psnp_received(pkt, ifa, n, level);
+ break;
+
+ default:
+ DROP("unknown type", type);
+ };
+ return 1;
+
+ drop:
+ log(L_WARN "%s: Bad packet from %I - %s (%u)", p->p.name, sk->faddr, err_dsc, err_val);
+ return 1;
+}
+
+static void
+isis_tx_hook(sock *sk)
+{
+ struct isis_iface *ifa = sk->data;
+ log(L_WARN "%s: TX hook called", ifa->p->p.name);
+}
+
+static void
+isis_err_hook(sock *sk, int err)
+{
+ struct isis_iface *ifa = sk->data;
+ log(L_ERR "%s: Socket error: %m", ifa->p->p.name, err);
+}
+
+int
+isis_sk_open(struct isis_iface *ifa)
+{
+ sock *sk = sk_new(ifa->pool);
+ sk->type = SK_IP;
+ sk->dport = ISIS_PROTO;
+ sk->saddr = IPA_NONE;
+
+ sk->ttl = 0;
+ sk->rx_hook = isis_rx_hook;
+ sk->tx_hook = isis_tx_hook;
+ sk->err_hook = isis_err_hook;
+ sk->iface = ifa->iface;
+ sk->rbsize = p->rx_buffer_size + 64; // XXX
+ sk->tbsize = p->tx_buffer_size + 64; // XXX
+ sk->data = ifa;
+ sk->flags = SKF_LADDR_RX;
+
+ if (sk_open(sk) != 0)
+ goto err;
+
+ sk->saddr = ifa->addr->ip;
+
+ if (sk_setup_multicast(sk) < 0)
+ goto err;
+
+ if (sk_join_group(sk, AllRouters) < 0)
+ goto err;
+
+ ifa->sk = sk;
+ return 1;
+
+ err:
+ rfree(sk);
+ return 0;
+}
+
#undef CONFIG_RADV
#undef CONFIG_BGP
#undef CONFIG_OSPF
+#undef CONFIG_ISIS
#undef CONFIG_PIPE
/* We have <syslog.h> and syslog() */