babeld: Initial import, for Babel routing protocol.

* Initial import of the Babel routing protocol, ported to Quagga.
* LICENCE: Update the original LICENCE file to include all known potentially
  applicable copyright claims.  Ask that any future contributors to babeld/
  grant MIT/X11 licence to their work.
* *.{c,h}: Add GPL headers, in according with the SFLC guidance on
  dealing with potentially mixed GPL/other licensed work, at:

  https://www.softwarefreedom.org/resources/2007/gpl-non-gpl-collaboration.html
diff --git a/babeld/babeld.c b/babeld/babeld.c
new file mode 100644
index 0000000..18b4e34
--- /dev/null
+++ b/babeld/babeld.c
@@ -0,0 +1,766 @@
+/*  
+ *  This file is free software: you may copy, redistribute and/or modify it  
+ *  under the terms of the GNU General Public License as published by the  
+ *  Free Software Foundation, either version 2 of the License, or (at your  
+ *  option) any later version.  
+ *  
+ *  This file is distributed in the hope that it will be useful, but  
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of  
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU  
+ *  General Public License for more details.  
+ *  
+ *  You should have received a copy of the GNU General Public License  
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.  
+ *  
+ * This file incorporates work covered by the following copyright and  
+ * permission notice:  
+ *  
+
+Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <zebra.h>
+#include "command.h"
+#include "prefix.h"
+#include "memory.h"
+#include "memtypes.h"
+#include "table.h"
+#include "distribute.h"
+#include "prefix.h"
+#include "filter.h"
+#include "plist.h"
+
+#include "babel_main.h"
+#include "babeld.h"
+#include "util.h"
+#include "net.h"
+#include "kernel.h"
+#include "babel_interface.h"
+#include "neighbour.h"
+#include "route.h"
+#include "message.h"
+#include "resend.h"
+#include "babel_filter.h"
+
+
+static int babel_init_routing_process(struct thread *thread);
+static void babel_get_myid(void);
+static void babel_initial_noise(void);
+static int babel_read_protocol (struct thread *thread);
+static int babel_main_loop(struct thread *thread);
+static void babel_set_timer(struct timeval *timeout);
+static void babel_fill_with_next_timeout(struct timeval *tv);
+
+
+/* Informations relative to the babel running daemon. */
+static struct babel *babel_routing_process = NULL;
+static unsigned char *receive_buffer = NULL;
+static int receive_buffer_size = 0;
+
+/* timeouts */
+struct timeval check_neighbours_timeout;
+static time_t expiry_time;
+static time_t source_expiry_time;
+
+/* Babel node structure. */
+static struct cmd_node cmd_babel_node =
+{
+    .node   = BABEL_NODE,
+    .prompt = "%s(config-router)# ",
+    .vtysh  = 1,
+};
+
+/* print current babel configuration on vty */
+static int
+babel_config_write (struct vty *vty)
+{
+    return 0;
+}
+
+
+static int
+babel_create_routing_process (void)
+{
+    assert (babel_routing_process == NULL);
+
+    /* Allocaste Babel instance. */
+    babel_routing_process = XCALLOC (MTYPE_BABEL, sizeof (struct babel));
+
+    /* Initialize timeouts */
+    gettime(&babel_now);
+    expiry_time = babel_now.tv_sec + roughly(30);
+    source_expiry_time = babel_now.tv_sec + roughly(300);
+
+    /* Make socket for Babel protocol. */
+    protocol_socket = babel_socket(protocol_port);
+    if (protocol_socket < 0) {
+        zlog_err("Couldn't create link local socket: %s", safe_strerror(errno));
+        goto fail;
+    }
+
+    /* Threads. */
+    babel_routing_process->t_read =
+    thread_add_read(master, &babel_read_protocol, NULL, protocol_socket);
+    /* wait a little: zebra will announce interfaces, addresses, routes... */
+    babel_routing_process->t_update =
+    thread_add_timer_msec(master, &babel_init_routing_process, NULL, 200L);
+    return 0;
+
+fail:
+    XFREE(MTYPE_BABEL, babel_routing_process);
+    babel_routing_process = NULL;
+    return -1;
+}
+
+/* thread reading entries form others babel daemons */
+static int
+babel_read_protocol (struct thread *thread)
+{
+    int rc;
+    struct interface *ifp = NULL;
+    struct sockaddr_in6 sin6;
+    struct listnode *linklist_node = NULL;
+
+    assert(babel_routing_process != NULL);
+    assert(protocol_socket >= 0);
+
+    rc = babel_recv(protocol_socket,
+                    receive_buffer, receive_buffer_size,
+                    (struct sockaddr*)&sin6, sizeof(sin6));
+    if(rc < 0) {
+        if(errno != EAGAIN && errno != EINTR) {
+            zlog_err("recv: %s", safe_strerror(errno));
+        }
+    } else {
+        FOR_ALL_INTERFACES(ifp, linklist_node) {
+            if(!if_up(ifp))
+                continue;
+            if(ifp->ifindex == sin6.sin6_scope_id) {
+                parse_packet((unsigned char*)&sin6.sin6_addr, ifp,
+                             receive_buffer, rc);
+                break;
+            }
+        }
+    }
+
+    /* re-add thread */
+    babel_routing_process->t_read =
+    thread_add_read(master, &babel_read_protocol, NULL, protocol_socket);
+    return 0;
+}
+
+/* Zebra will give some information, especially about interfaces. This function
+ must be call with a litte timeout wich may give zebra the time to do his job,
+ making these inits have sense. */
+static int
+babel_init_routing_process(struct thread *thread)
+{
+    babel_get_myid();
+    debugf(BABEL_DEBUG_COMMON, "My ID is : %s.", format_eui64(myid));
+    babel_initial_noise();
+    babel_main_loop(thread);/* this function self-add to the t_update thread */
+    return 0;
+}
+
+/* fill "myid" with an unique id (only if myid != {0}). */
+static void
+babel_get_myid(void)
+{
+    struct interface *ifp = NULL;
+    struct listnode *linklist_node = NULL;
+    int rc;
+    int i;
+
+    /* if we already have an id (from state file), we return. */
+    if (memcmp(myid, zeroes, 8) != 0) {
+        return;
+    }
+
+    FOR_ALL_INTERFACES(ifp, linklist_node) {
+        /* ifp->ifindex is not necessarily valid at this point */
+        int ifindex = if_nametoindex(ifp->name);
+        if(ifindex > 0) {
+            unsigned char eui[8];
+            rc = if_eui64(ifp->name, ifindex, eui);
+            if(rc < 0)
+                continue;
+            memcpy(myid, eui, 8);
+            return;
+        }
+    }
+
+    /* We failed to get a global EUI64 from the interfaces we were given.
+     Let's try to find an interface with a MAC address. */
+    for(i = 1; i < 256; i++) {
+        char buf[IF_NAMESIZE], *ifname;
+        unsigned char eui[8];
+        ifname = if_indextoname(i, buf);
+        if(ifname == NULL)
+            continue;
+        rc = if_eui64(ifname, i, eui);
+        if(rc < 0)
+            continue;
+        memcpy(myid, eui, 8);
+        return;
+    }
+
+    zlog_err("Warning: couldn't find router id -- using random value.");
+
+    rc = read_random_bytes(myid, 8);
+    if(rc < 0) {
+        zlog_err("read(random): %s (cannot assign an ID)",safe_strerror(errno));
+        exit(1);
+    }
+    /* Clear group and global bits */
+    myid[0] &= ~3;
+}
+
+/* Make some noise so that others notice us, and send retractions in
+ case we were restarted recently */
+static void
+babel_initial_noise(void)
+{
+    struct interface *ifp = NULL;
+    struct listnode *linklist_node = NULL;
+
+    FOR_ALL_INTERFACES(ifp, linklist_node) {
+        if(!if_up(ifp))
+            continue;
+        /* Apply jitter before we send the first message. */
+        usleep(roughly(10000));
+        gettime(&babel_now);
+        send_hello(ifp);
+        send_wildcard_retraction(ifp);
+    }
+
+    FOR_ALL_INTERFACES(ifp, linklist_node) {
+        if(!if_up(ifp))
+            continue;
+        usleep(roughly(10000));
+        gettime(&babel_now);
+        send_hello(ifp);
+        send_wildcard_retraction(ifp);
+        send_self_update(ifp);
+        send_request(ifp, NULL, 0);
+        flushupdates(ifp);
+        flushbuf(ifp);
+    }
+}
+
+/* Delete all the added babel routes, make babeld only speak to zebra. */
+static void
+babel_clean_routing_process()
+{
+    babel_uninstall_all_routes();
+    babel_interface_close_all();
+
+    /* cancel threads */
+    if (babel_routing_process->t_read != NULL) {
+        thread_cancel(babel_routing_process->t_read);
+    }
+    if (babel_routing_process->t_update != NULL) {
+        thread_cancel(babel_routing_process->t_update);
+    }
+
+    XFREE(MTYPE_BABEL, babel_routing_process);
+    babel_routing_process = NULL;
+}
+
+/* Function used with timeout. */
+static int
+babel_main_loop(struct thread *thread)
+{
+    struct timeval tv;
+    struct interface *ifp = NULL;
+    struct listnode *linklist_node = NULL;
+
+    while(1) {
+        gettime(&babel_now);
+
+        /* timeouts --------------------------------------------------------- */
+        /* get the next timeout */
+        babel_fill_with_next_timeout(&tv);
+        /* if there is no timeout, we must wait. */
+        if(timeval_compare(&tv, &babel_now) > 0) {
+            timeval_minus(&tv, &tv, &babel_now);
+            debugf(BABEL_DEBUG_TIMEOUT, "babel main loop : timeout: %ld msecs",
+                   tv.tv_sec * 1000 + tv.tv_usec / 1000);
+            /* it happens often to have less than 1 ms, it's bad. */
+            timeval_add_msec(&tv, &tv, 300);
+            babel_set_timer(&tv);
+            return 0;
+        }
+
+        gettime(&babel_now);
+
+        /* update database -------------------------------------------------- */
+        if(timeval_compare(&check_neighbours_timeout, &babel_now) < 0) {
+            int msecs;
+            msecs = check_neighbours();
+            msecs = MAX(msecs, 10);
+            schedule_neighbours_check(msecs, 1);
+        }
+
+        if(babel_now.tv_sec >= expiry_time) {
+            expire_routes();
+            expire_resend();
+            expiry_time = babel_now.tv_sec + roughly(30);
+        }
+
+        if(babel_now.tv_sec >= source_expiry_time) {
+            expire_sources();
+            source_expiry_time = babel_now.tv_sec + roughly(300);
+        }
+
+        FOR_ALL_INTERFACES(ifp, linklist_node) {
+            babel_interface_nfo *babel_ifp = NULL;
+            if(!if_up(ifp))
+                continue;
+            babel_ifp = babel_get_if_nfo(ifp);
+            if(timeval_compare(&babel_now, &babel_ifp->hello_timeout) >= 0)
+                send_hello(ifp);
+            if(timeval_compare(&babel_now, &babel_ifp->update_timeout) >= 0)
+                send_update(ifp, 0, NULL, 0);
+            if(timeval_compare(&babel_now,
+                               &babel_ifp->update_flush_timeout) >= 0)
+                flushupdates(ifp);
+        }
+
+        if(resend_time.tv_sec != 0) {
+            if(timeval_compare(&babel_now, &resend_time) >= 0)
+                do_resend();
+        }
+
+        if(unicast_flush_timeout.tv_sec != 0) {
+            if(timeval_compare(&babel_now, &unicast_flush_timeout) >= 0)
+                flush_unicast(1);
+        }
+
+        FOR_ALL_INTERFACES(ifp, linklist_node) {
+            babel_interface_nfo *babel_ifp = NULL;
+            if(!if_up(ifp))
+                continue;
+            babel_ifp = babel_get_if_nfo(ifp);
+            if(babel_ifp->flush_timeout.tv_sec != 0) {
+                if(timeval_compare(&babel_now, &babel_ifp->flush_timeout) >= 0)
+                    flushbuf(ifp);
+            }
+        }
+    }
+
+    assert(0); /* this line should never be reach */
+}
+
+static void
+printIfMin(struct timeval *tv, int cmd, const char *tag, const char *ifname)
+{
+    static struct timeval curr_tv;
+    static char buffer[200];
+    static const char *curr_tag = NULL;
+
+    switch (cmd) {
+        case 0: /* reset timeval */
+            curr_tv = *tv;
+            if(ifname != NULL) {
+                snprintf(buffer, 200L, "interface: %s; %s", ifname, tag);
+                curr_tag = buffer;
+            } else {
+                curr_tag = tag;
+            }
+            break;
+        case 1: /* take the min */
+            if (tv->tv_sec == 0 && tv->tv_usec == 0) { /* if (tv == ∞) */
+                break;
+            }
+            if (tv->tv_sec < curr_tv.tv_sec ||(tv->tv_sec == curr_tv.tv_sec &&
+                                               tv->tv_usec < curr_tv.tv_usec)) {
+                curr_tv = *tv;
+                if(ifname != NULL) {
+                    snprintf(buffer, 200L, "interface: %s; %s", ifname, tag);
+                    curr_tag = buffer;
+                } else {
+                    curr_tag = tag;
+                }
+            }
+            break;
+        case 2: /* print message */
+            debugf(BABEL_DEBUG_TIMEOUT, "next timeout due to: %s", curr_tag);
+            break;
+        default:
+            break;
+    }
+}
+
+static void
+babel_fill_with_next_timeout(struct timeval *tv)
+{
+#if (defined NO_DEBUG)
+#define printIfMin(a,b,c,d)
+#else
+#define printIfMin(a,b,c,d) \
+  if (UNLIKELY(debug & BABEL_DEBUG_TIMEOUT)) {printIfMin(a,b,c,d);}
+
+    struct interface *ifp = NULL;
+    struct listnode *linklist_node = NULL;
+
+    *tv = check_neighbours_timeout;
+    printIfMin(tv, 0, "check_neighbours_timeout", NULL);
+    timeval_min_sec(tv, expiry_time);
+    printIfMin(tv, 1, "expiry_time", NULL);
+    timeval_min_sec(tv, source_expiry_time);
+    printIfMin(tv, 1, "source_expiry_time", NULL);
+    timeval_min(tv, &resend_time);
+    printIfMin(tv, 1, "resend_time", NULL);
+    FOR_ALL_INTERFACES(ifp, linklist_node) {
+        babel_interface_nfo *babel_ifp = NULL;
+        if(!if_up(ifp))
+            continue;
+        babel_ifp = babel_get_if_nfo(ifp);
+        timeval_min(tv, &babel_ifp->flush_timeout);
+        printIfMin(tv, 1, "flush_timeout", ifp->name);
+        timeval_min(tv, &babel_ifp->hello_timeout);
+        printIfMin(tv, 1, "hello_timeout", ifp->name);
+        timeval_min(tv, &babel_ifp->update_timeout);
+        printIfMin(tv, 1, "update_timeout", ifp->name);
+        timeval_min(tv, &babel_ifp->update_flush_timeout);
+        printIfMin(tv, 1, "update_flush_timeout",ifp->name);
+    }
+    timeval_min(tv, &unicast_flush_timeout);
+    printIfMin(tv, 1, "unicast_flush_timeout", NULL);
+    printIfMin(tv, 2, NULL, NULL);
+#undef printIfMin
+#endif
+}
+
+/* set the t_update thread of the babel routing process to be launch in
+ 'timeout' (approximate at the milisecond) */
+static void
+babel_set_timer(struct timeval *timeout)
+{
+    long msecs = timeout->tv_sec * 1000 + timeout->tv_usec / 1000;
+    if (babel_routing_process->t_update != NULL) {
+        thread_cancel(babel_routing_process->t_update);
+    }
+    babel_routing_process->t_update =
+    thread_add_timer_msec(master, &babel_main_loop, NULL, msecs);
+}
+
+/* Schedule a neighbours check after roughly 3/2 times msecs have elapsed. */
+void
+schedule_neighbours_check(int msecs, int override)
+{
+    struct timeval timeout;
+
+    timeval_add_msec(&timeout, &babel_now, roughly(msecs * 3 / 2));
+    if(override)
+        check_neighbours_timeout = timeout;
+    else
+        timeval_min(&check_neighbours_timeout, &timeout);
+}
+
+int
+resize_receive_buffer(int size)
+{
+    if(size <= receive_buffer_size)
+        return 0;
+
+    if(receive_buffer == NULL) {
+        receive_buffer = malloc(size);
+        if(receive_buffer == NULL) {
+            zlog_err("malloc(receive_buffer): %s", safe_strerror(errno));
+            return -1;
+        }
+        receive_buffer_size = size;
+    } else {
+        unsigned char *new;
+        new = realloc(receive_buffer, size);
+        if(new == NULL) {
+            zlog_err("realloc(receive_buffer): %s", safe_strerror(errno));
+            return -1;
+        }
+        receive_buffer = new;
+        receive_buffer_size = size;
+    }
+    return 1;
+}
+
+static void
+babel_distribute_update (struct distribute *dist)
+{
+    struct interface *ifp;
+    babel_interface_nfo *babel_ifp;
+    struct access_list *alist;
+    struct prefix_list *plist;
+
+    if (! dist->ifname)
+        return;
+
+    ifp = if_lookup_by_name (dist->ifname);
+    if (ifp == NULL)
+        return;
+
+    babel_ifp = babel_get_if_nfo(ifp);
+
+    if (dist->list[DISTRIBUTE_IN]) {
+        alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_IN]);
+        if (alist)
+            babel_ifp->list[BABEL_FILTER_IN] = alist;
+        else
+            babel_ifp->list[BABEL_FILTER_IN] = NULL;
+    } else {
+        babel_ifp->list[BABEL_FILTER_IN] = NULL;
+    }
+
+    if (dist->list[DISTRIBUTE_OUT]) {
+        alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_OUT]);
+        if (alist)
+            babel_ifp->list[BABEL_FILTER_OUT] = alist;
+        else
+            babel_ifp->list[BABEL_FILTER_OUT] = NULL;
+    } else {
+        babel_ifp->list[BABEL_FILTER_OUT] = NULL;
+    }
+
+    if (dist->prefix[DISTRIBUTE_IN]) {
+        plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_IN]);
+        if (plist)
+            babel_ifp->prefix[BABEL_FILTER_IN] = plist;
+        else
+            babel_ifp->prefix[BABEL_FILTER_IN] = NULL;
+    } else {
+        babel_ifp->prefix[BABEL_FILTER_IN] = NULL;
+    }
+
+    if (dist->prefix[DISTRIBUTE_OUT]) {
+        plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_OUT]);
+        if (plist)
+            babel_ifp->prefix[BABEL_FILTER_OUT] = plist;
+        else
+            babel_ifp->prefix[BABEL_FILTER_OUT] = NULL;
+    } else {
+        babel_ifp->prefix[BABEL_FILTER_OUT] = NULL;
+    }
+}
+
+void
+babel_distribute_update_interface (struct interface *ifp)
+{
+    struct distribute *dist;
+
+    dist = distribute_lookup (ifp->name);
+    if (dist)
+        babel_distribute_update (dist);
+}
+
+/* Update all interface's distribute list. */
+static void
+babel_distribute_update_all (struct prefix_list *notused)
+{
+    struct interface *ifp;
+    struct listnode *node;
+
+    for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
+        babel_distribute_update_interface (ifp);
+}
+
+static void
+babel_distribute_update_all_wrapper (struct access_list *notused)
+{
+    babel_distribute_update_all(NULL);
+}
+
+
+/* [Command] */
+DEFUN (router_babel,
+       router_babel_cmd,
+       "router babel",
+       "Enable a routing process\n"
+       "Make Babel instance command\n")
+{
+    int ret;
+
+    vty->node = BABEL_NODE;
+
+    if (!babel_routing_process) {
+        ret = babel_create_routing_process ();
+
+        /* Notice to user we couldn't create Babel. */
+        if (ret < 0) {
+            zlog_warn ("can't create Babel");
+        }
+    }
+
+    return CMD_SUCCESS;
+}
+
+/* [Command] */
+DEFUN (no_router_babel,
+       no_router_babel_cmd,
+       "no router babel",
+       NO_STR
+       "Disable a routing process\n"
+       "Remove Babel instance command\n")
+{
+    if(babel_routing_process)
+        babel_clean_routing_process();
+    return CMD_SUCCESS;
+}
+
+/* [Babel Command] */
+DEFUN (babel_set_protocol_group,
+       babel_set_protocol_group_cmd,
+       "protocol group ADDR",
+       "Set the protocol group, default is ff02::1:6.\n"
+       "IPv6 address")
+{
+    int ret;
+    struct prefix p;
+
+    ret = str2prefix (argv[0], &p);
+
+    /* Given string is:                 */
+    if (ret) { /* an IPv4 or v6 network */
+        if (p.family != AF_INET6) {
+            return CMD_WARNING;
+        }
+        in6addr_to_uchar(protocol_group, &p.u.prefix6);
+    } else {   /* an interface name     */
+        return CMD_WARNING;
+    }
+
+    if (ret < 0) {
+        vty_out (vty, "%s must be an ipv6 address%s", argv[0],
+                 VTY_NEWLINE);
+        return CMD_WARNING;
+    }
+
+    return CMD_SUCCESS;
+}
+
+/* [Babel Command] */
+DEFUN (babel_set_protocol_port,
+       babel_set_protocol_port_cmd,
+       "protocol port <1-65535>",
+       "Set the protocol port (default is defined in RFC).\n"
+       "IPv6 address")
+{
+    int port = atoi(argv[0]);
+    protocol_port = port;
+
+    return CMD_SUCCESS;
+}
+
+
+void
+babeld_quagga_init(void)
+{
+
+    install_node(&cmd_babel_node, &babel_config_write);
+
+    install_element(CONFIG_NODE, &router_babel_cmd);
+    install_element(CONFIG_NODE, &no_router_babel_cmd);
+
+    install_default(BABEL_NODE);
+
+    babel_if_init();
+
+    /* Access list install. */
+    access_list_init ();
+    access_list_add_hook (babel_distribute_update_all_wrapper);
+    access_list_delete_hook (babel_distribute_update_all_wrapper);
+
+    /* Prefix list initialize.*/
+    prefix_list_init ();
+    prefix_list_add_hook (babel_distribute_update_all);
+    prefix_list_delete_hook (babel_distribute_update_all);
+
+    /* Distribute list install. */
+    distribute_list_init (BABEL_NODE);
+    distribute_list_add_hook (babel_distribute_update);
+    distribute_list_delete_hook (babel_distribute_update);
+}
+
+int /* DEPRECATED: for compatibility with old babeld (configuration.{c,h})*/
+input_filter(const unsigned char *id,
+             const unsigned char *prefix, unsigned short plen,
+             const unsigned char *neigh, unsigned int ifindex)
+{
+    struct interface *ifp = NULL;
+    struct prefix p;
+    p.family = v4mapped(prefix) ? AF_INET : AF_INET6;
+    p.prefixlen = plen;
+    if (p.family == AF_INET) {
+        uchar_to_inaddr(&p.u.prefix4, prefix);
+    } else {
+        uchar_to_in6addr(&p.u.prefix6, prefix);
+    }
+
+    ifp = if_lookup_by_index(ifindex);
+    if (ifp != NULL) {
+        return babel_filter_in(&p, babel_get_if_nfo(ifp));
+    }
+
+    return babel_filter_in(&p, NULL);
+}
+
+int /* DEPRECATED: for compatibility with old babeld */
+output_filter(const unsigned char *id, const unsigned char *prefix,
+              unsigned short plen, unsigned int ifindex)
+{
+    struct interface *ifp = NULL;
+    struct prefix p;
+    p.family = v4mapped(prefix) ? AF_INET : AF_INET6;
+    p.prefixlen = plen;
+    if (p.family == AF_INET) {
+        uchar_to_inaddr(&p.u.prefix4, prefix);
+    } else {
+        uchar_to_in6addr(&p.u.prefix6, prefix);
+    }
+
+    ifp = if_lookup_by_index(ifindex);
+    if (ifp != NULL) {
+        return babel_filter_out(&p, babel_get_if_nfo(ifp));
+    }
+
+    return babel_filter_out(&p, NULL);
+}
+
+int /* DEPRECATED: for compatibility with old babeld */
+redistribute_filter(const unsigned char *prefix, unsigned short plen,
+                    unsigned int ifindex, int proto)
+{
+    struct interface *ifp = NULL;
+    struct prefix p;
+    p.family = v4mapped(prefix) ? AF_INET : AF_INET6;
+    p.prefixlen = plen;
+    if (p.family == AF_INET) {
+        uchar_to_inaddr(&p.u.prefix4, prefix);
+    } else {
+        uchar_to_in6addr(&p.u.prefix6, prefix);
+    }
+
+    ifp = if_lookup_by_index(ifindex);
+    if (ifp != NULL) {
+        return babel_filter_redistribute(&p,babel_get_if_nfo(ifp));
+    }
+
+    return babel_filter_redistribute(&p, NULL);
+}