really_send_update(struct interface *ifp,
                   const unsigned char *id,
                   const unsigned char *prefix, unsigned char plen,
                   unsigned short seqno, unsigned short metric,
                   unsigned char *channels, int channels_len)
{
    babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
    int add_metric, v4, real_plen, omit = 0;
    const unsigned char *real_prefix;
    unsigned short flags = 0;
    int channels_size;

    if(diversity_kind != DIVERSITY_CHANNEL)
        channels_len = -1;

    channels_size = channels_len >= 0 ? channels_len + 2 : 0;

    if(!if_up(ifp))
        return;

    add_metric = output_filter(id, prefix, plen, ifp->ifindex);
    if(add_metric >= INFINITY)
        return;

    metric = MIN(metric + add_metric, INFINITY);
    /* Worst case */
    ensure_space(ifp, 20 + 12 + 28);

    v4 = plen >= 96 && v4mapped(prefix);

    if(v4) {
        if(!babel_ifp->ipv4)
            return;
        if(!babel_ifp->have_buffered_nh ||
           memcmp(babel_ifp->buffered_nh, babel_ifp->ipv4, 4) != 0) {
            start_message(ifp, MESSAGE_NH, 6);
            accumulate_byte(ifp, 1);
            accumulate_byte(ifp, 0);
            accumulate_bytes(ifp, babel_ifp->ipv4, 4);
            end_message(ifp, MESSAGE_NH, 6);
            memcpy(babel_ifp->buffered_nh, babel_ifp->ipv4, 4);
            babel_ifp->have_buffered_nh = 1;
        }

        real_prefix = prefix + 12;
        real_plen = plen - 96;
    } else {
        if(babel_ifp->have_buffered_prefix) {
            while(omit < plen / 8 &&
                  babel_ifp->buffered_prefix[omit] == prefix[omit])
                omit++;
        }
        if(!babel_ifp->have_buffered_prefix || plen >= 48)
            flags |= 0x80;
        real_prefix = prefix;
        real_plen = plen;
    }

    if(!babel_ifp->have_buffered_id
       || memcmp(id, babel_ifp->buffered_id, 8) != 0) {
        if(real_plen == 128 && memcmp(real_prefix + 8, id, 8) == 0) {
            flags |= 0x40;
        } else {
            start_message(ifp, MESSAGE_ROUTER_ID, 10);
            accumulate_short(ifp, 0);
            accumulate_bytes(ifp, id, 8);
            end_message(ifp, MESSAGE_ROUTER_ID, 10);
        }
        memcpy(babel_ifp->buffered_id, id, sizeof(babel_ifp->buffered_id));
        babel_ifp->have_buffered_id = 1;
    }

    start_message(ifp, MESSAGE_UPDATE, 10 + (real_plen + 7) / 8 - omit +
                  channels_size);
    accumulate_byte(ifp, v4 ? 1 : 2);
    accumulate_byte(ifp, flags);
    accumulate_byte(ifp, real_plen);
    accumulate_byte(ifp, omit);
    accumulate_short(ifp, (babel_ifp->update_interval + 5) / 10);
    accumulate_short(ifp, seqno);
    accumulate_short(ifp, metric);
    accumulate_bytes(ifp, real_prefix + omit, (real_plen + 7) / 8 - omit);
    /* Note that an empty channels TLV is different from no such TLV. */
    if(channels_len >= 0) {
        accumulate_byte(ifp, 2);
        accumulate_byte(ifp, channels_len);

	if (channels && channels_len > 0)
		accumulate_bytes(ifp, channels, channels_len);
    }
    end_message(ifp, MESSAGE_UPDATE, 10 + (real_plen + 7) / 8 - omit +
                channels_size);

    if(flags & 0x80) {
        memcpy(babel_ifp->buffered_prefix, prefix, 16);
        babel_ifp->have_buffered_prefix = 1;
    }
}
really_send_update(struct interface *ifp,
                   const unsigned char *id,
                   const unsigned char *prefix, unsigned char plen,
                   unsigned short seqno, unsigned short metric,
                   unsigned char *channels, int channels_len)
{
    babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
    int add_metric, v4, real_plen, omit = 0;
    const unsigned char *real_prefix;
    unsigned short flags = 0;
    int channels_size;

    if(diversity_kind != DIVERSITY_CHANNEL)
        channels_len = -1;

    channels_size = channels_len >= 0 ? channels_len + 2 : 0;

    if(!if_up(ifp))
        return;

    add_metric = output_filter(id, prefix, plen, ifp->ifindex);
    if(add_metric >= INFINITY)
        return;

    metric = MIN(metric + add_metric, INFINITY);
     
    ensure_space(ifp, 20 + 12 + 28);

    v4 = plen >= 96 && v4mapped(prefix);

    if(v4) {
        if(!babel_ifp->ipv4)
            return;
        if(!babel_ifp->have_buffered_nh ||
           memcmp(babel_ifp->buffered_nh, babel_ifp->ipv4, 4) != 0) {
            start_message(ifp, MESSAGE_NH, 6);
            accumulate_byte(ifp, 1);
            accumulate_byte(ifp, 0);
            accumulate_bytes(ifp, babel_ifp->ipv4, 4);
            end_message(ifp, MESSAGE_NH, 6);
            memcpy(babel_ifp->buffered_nh, babel_ifp->ipv4, 4);
            babel_ifp->have_buffered_nh = 1;
        }

        real_prefix = prefix + 12;
        real_plen = plen - 96;
    } else {
        if(babel_ifp->have_buffered_prefix) {
            while(omit < plen / 8 &&
                  babel_ifp->buffered_prefix[omit] == prefix[omit])
                omit++;
        }
        if(!babel_ifp->have_buffered_prefix || plen >= 48)
            flags |= 0x80;
        real_prefix = prefix;
        real_plen = plen;
    }

    if(!babel_ifp->have_buffered_id
       || memcmp(id, babel_ifp->buffered_id, 8) != 0) {
        if(real_plen == 128 && memcmp(real_prefix + 8, id, 8) == 0) {
            flags |= 0x40;
        } else {
            start_message(ifp, MESSAGE_ROUTER_ID, 10);
            accumulate_short(ifp, 0);
            accumulate_bytes(ifp, id, 8);
            end_message(ifp, MESSAGE_ROUTER_ID, 10);
        }
        memcpy(babel_ifp->buffered_id, id, sizeof(babel_ifp->buffered_id));
        babel_ifp->have_buffered_id = 1;
    }

    start_message(ifp, MESSAGE_UPDATE, 10 + (real_plen + 7) / 8 - omit +
                  channels_size);
    accumulate_byte(ifp, v4 ? 1 : 2);
    accumulate_byte(ifp, flags);
    accumulate_byte(ifp, real_plen);
    accumulate_byte(ifp, omit);
    accumulate_short(ifp, (babel_ifp->update_interval + 5) / 10);
    accumulate_short(ifp, seqno);
    accumulate_short(ifp, metric);
    accumulate_bytes(ifp, real_prefix + omit, (real_plen + 7) / 8 - omit);
     
    if(channels_len >= 0) {
        accumulate_byte(ifp, 2);
        accumulate_byte(ifp, channels_len);

	if (channels && channels_len > 0)
		accumulate_bytes(ifp, channels, channels_len);
    }
    end_message(ifp, MESSAGE_UPDATE, 10 + (real_plen + 7) / 8 - omit +
                channels_size);

    if(flags & 0x80) {
        memcpy(babel_ifp->buffered_prefix, prefix, 16);
        babel_ifp->have_buffered_prefix = 1;
    }
}