summaryrefslogtreecommitdiff
path: root/babeld/message.c
diff options
context:
space:
mode:
Diffstat (limited to 'babeld/message.c')
-rw-r--r--babeld/message.c1561
1 files changed, 0 insertions, 1561 deletions
diff --git a/babeld/message.c b/babeld/message.c
deleted file mode 100644
index 9dcfc6771c..0000000000
--- a/babeld/message.c
+++ /dev/null
@@ -1,1561 +0,0 @@
-/*
- * 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 (c) 2007, 2008 by 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 "if.h"
-
-#include "babeld.h"
-#include "util.h"
-#include "net.h"
-#include "babel_interface.h"
-#include "source.h"
-#include "neighbour.h"
-#include "route.h"
-#include "xroute.h"
-#include "resend.h"
-#include "message.h"
-#include "kernel.h"
-
-unsigned char packet_header[4] = {42, 2};
-
-int split_horizon = 1;
-
-unsigned short myseqno = 0;
-struct timeval seqno_time = {0, 0};
-
-#define UNICAST_BUFSIZE 1024
-int unicast_buffered = 0;
-unsigned char *unicast_buffer = NULL;
-struct neighbour *unicast_neighbour = NULL;
-struct timeval unicast_flush_timeout = {0, 0};
-
-static const unsigned char v4prefix[16] =
- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 };
-
-/* Parse a network prefix, encoded in the somewhat baroque compressed
- representation used by Babel. Return the number of bytes parsed. */
-static int
-network_prefix(int ae, int plen, unsigned int omitted,
- const unsigned char *p, const unsigned char *dp,
- unsigned int len, unsigned char *p_r)
-{
- unsigned pb;
- unsigned char prefix[16];
- int ret = -1;
-
- if(plen >= 0)
- pb = (plen + 7) / 8;
- else if(ae == 1)
- pb = 4;
- else
- pb = 16;
-
- if(pb > 16)
- return -1;
-
- memset(prefix, 0, 16);
-
- switch(ae) {
- case 0:
- ret = 0;
- break;
- case 1:
- if(omitted > 4 || pb > 4 || (pb > omitted && len < pb - omitted))
- return -1;
- memcpy(prefix, v4prefix, 12);
- if(omitted) {
- if (dp == NULL || !v4mapped(dp)) return -1;
- memcpy(prefix, dp, 12 + omitted);
- }
- if(pb > omitted) memcpy(prefix + 12 + omitted, p, pb - omitted);
- ret = pb - omitted;
- break;
- case 2:
- if(omitted > 16 || (pb > omitted && len < pb - omitted)) return -1;
- if(omitted) {
- if (dp == NULL || v4mapped(dp)) return -1;
- memcpy(prefix, dp, omitted);
- }
- if(pb > omitted) memcpy(prefix + omitted, p, pb - omitted);
- ret = pb - omitted;
- break;
- case 3:
- if(pb > 8 && len < pb - 8) return -1;
- prefix[0] = 0xfe;
- prefix[1] = 0x80;
- if(pb > 8) memcpy(prefix + 8, p, pb - 8);
- ret = pb - 8;
- break;
- default:
- return -1;
- }
-
- mask_prefix(p_r, prefix, plen < 0 ? 128 : ae == 1 ? plen + 96 : plen);
- return ret;
-}
-
-static void
-parse_route_attributes(const unsigned char *a, int alen,
- unsigned char *channels)
-{
- int type, len, i = 0;
-
- while(i < alen) {
- type = a[i];
- if(type == 0) {
- i++;
- continue;
- }
-
- if(i + 1 > alen) {
- fprintf(stderr, "Received truncated attributes.\n");
- return;
- }
- len = a[i + 1];
- if(i + len > alen) {
- fprintf(stderr, "Received truncated attributes.\n");
- return;
- }
-
- if(type == 1) {
- /* Nothing. */
- } else if(type == 2) {
- if(len > DIVERSITY_HOPS) {
- fprintf(stderr,
- "Received overlong channel information (%d > %d).\n",
- len, DIVERSITY_HOPS);
- len = DIVERSITY_HOPS;
- }
- if(memchr(a + i + 2, 0, len) != NULL) {
- /* 0 is reserved. */
- fprintf(stderr, "Channel information contains 0!");
- return;
- }
- memset(channels, 0, DIVERSITY_HOPS);
- memcpy(channels, a + i + 2, len);
- } else {
- fprintf(stderr, "Received unknown route attribute %d.\n", type);
- }
-
- i += len + 2;
- }
-}
-
-static int
-network_address(int ae, const unsigned char *a, unsigned int len,
- unsigned char *a_r)
-{
- return network_prefix(ae, -1, 0, a, NULL, len, a_r);
-}
-
-static int
-channels_len(unsigned char *channels)
-{
- unsigned char *p = memchr(channels, 0, DIVERSITY_HOPS);
- return p ? (p - channels) : DIVERSITY_HOPS;
-}
-
-void
-parse_packet(const unsigned char *from, struct interface *ifp,
- const unsigned char *packet, int packetlen)
-{
- int i;
- const unsigned char *message;
- unsigned char type, len;
- int bodylen;
- struct neighbour *neigh;
- int have_router_id = 0, have_v4_prefix = 0, have_v6_prefix = 0,
- have_v4_nh = 0, have_v6_nh = 0;
- unsigned char router_id[8], v4_prefix[16], v6_prefix[16],
- v4_nh[16], v6_nh[16];
-
- if(!linklocal(from)) {
- zlog_err("Received packet from non-local address %s.",
- format_address(from));
- return;
- }
-
- if(packet[0] != 42) {
- zlog_err("Received malformed packet on %s from %s.",
- ifp->name, format_address(from));
- return;
- }
-
- if(packet[1] != 2) {
- zlog_err("Received packet with unknown version %d on %s from %s.",
- packet[1], ifp->name, format_address(from));
- return;
- }
-
- neigh = find_neighbour(from, ifp);
- if(neigh == NULL) {
- zlog_err("Couldn't allocate neighbour.");
- return;
- }
-
- DO_NTOHS(bodylen, packet + 2);
-
- if(bodylen + 4 > packetlen) {
- zlog_err("Received truncated packet (%d + 4 > %d).",
- bodylen, packetlen);
- bodylen = packetlen - 4;
- }
-
- i = 0;
- while(i < bodylen) {
- message = packet + 4 + i;
- type = message[0];
- if(type == MESSAGE_PAD1) {
- debugf(BABEL_DEBUG_COMMON,"Received pad1 from %s on %s.",
- format_address(from), ifp->name);
- i++;
- continue;
- }
- if(i + 1 > bodylen) {
- zlog_err("Received truncated message.");
- break;
- }
- len = message[1];
- if(i + len > bodylen) {
- zlog_err("Received truncated message.");
- break;
- }
-
- if(type == MESSAGE_PADN) {
- debugf(BABEL_DEBUG_COMMON,"Received pad%d from %s on %s.",
- len, format_address(from), ifp->name);
- } else if(type == MESSAGE_ACK_REQ) {
- unsigned short nonce, interval;
- if(len < 6) goto fail;
- DO_NTOHS(nonce, message + 4);
- DO_NTOHS(interval, message + 6);
- debugf(BABEL_DEBUG_COMMON,"Received ack-req (%04X %d) from %s on %s.",
- nonce, interval, format_address(from), ifp->name);
- send_ack(neigh, nonce, interval);
- } else if(type == MESSAGE_ACK) {
- debugf(BABEL_DEBUG_COMMON,"Received ack from %s on %s.",
- format_address(from), ifp->name);
- /* Nothing right now */
- } else if(type == MESSAGE_HELLO) {
- unsigned short seqno, interval;
- int changed;
- if(len < 6) goto fail;
- DO_NTOHS(seqno, message + 4);
- DO_NTOHS(interval, message + 6);
- debugf(BABEL_DEBUG_COMMON,"Received hello %d (%d) from %s on %s.",
- seqno, interval,
- format_address(from), ifp->name);
- changed = update_neighbour(neigh, seqno, interval);
- update_neighbour_metric(neigh, changed);
- if(interval > 0)
- schedule_neighbours_check(interval * 10, 0);
- } else if(type == MESSAGE_IHU) {
- unsigned short txcost, interval;
- unsigned char address[16];
- int rc;
- if(len < 6) goto fail;
- DO_NTOHS(txcost, message + 4);
- DO_NTOHS(interval, message + 6);
- rc = network_address(message[2], message + 8, len - 6, address);
- if(rc < 0) goto fail;
- debugf(BABEL_DEBUG_COMMON,"Received ihu %d (%d) from %s on %s for %s.",
- txcost, interval,
- format_address(from), ifp->name,
- format_address(address));
- if(message[2] == 0 || is_interface_ll_address(ifp, address)) {
- int changed = txcost != neigh->txcost;
- neigh->txcost = txcost;
- neigh->ihu_time = babel_now;
- neigh->ihu_interval = interval;
- update_neighbour_metric(neigh, changed);
- if(interval > 0)
- schedule_neighbours_check(interval * 10 * 3, 0);
- }
- } else if(type == MESSAGE_ROUTER_ID) {
- if(len < 10) {
- have_router_id = 0;
- goto fail;
- }
- memcpy(router_id, message + 4, 8);
- have_router_id = 1;
- debugf(BABEL_DEBUG_COMMON,"Received router-id %s from %s on %s.",
- format_eui64(router_id), format_address(from), ifp->name);
- } else if(type == MESSAGE_NH) {
- unsigned char nh[16];
- int rc;
- if(len < 2) {
- have_v4_nh = 0;
- have_v6_nh = 0;
- goto fail;
- }
- rc = network_address(message[2], message + 4, len - 2,
- nh);
- if(rc < 0) {
- have_v4_nh = 0;
- have_v6_nh = 0;
- goto fail;
- }
- debugf(BABEL_DEBUG_COMMON,"Received nh %s (%d) from %s on %s.",
- format_address(nh), message[2],
- format_address(from), ifp->name);
- if(message[2] == 1) {
- memcpy(v4_nh, nh, 16);
- have_v4_nh = 1;
- } else {
- memcpy(v6_nh, nh, 16);
- have_v6_nh = 1;
- }
- } else if(type == MESSAGE_UPDATE) {
- unsigned char prefix[16], *nh;
- unsigned char plen;
- unsigned char channels[DIVERSITY_HOPS];
- unsigned short interval, seqno, metric;
- int rc, parsed_len;
- if(len < 10) {
- if(len < 2 || message[3] & 0x80)
- have_v4_prefix = have_v6_prefix = 0;
- goto fail;
- }
- DO_NTOHS(interval, message + 6);
- DO_NTOHS(seqno, message + 8);
- DO_NTOHS(metric, message + 10);
- if(message[5] == 0 ||
- (message[3] == 1 ? have_v4_prefix : have_v6_prefix))
- rc = network_prefix(message[2], message[4], message[5],
- message + 12,
- message[2] == 1 ? v4_prefix : v6_prefix,
- len - 10, prefix);
- else
- rc = -1;
- if(rc < 0) {
- if(message[3] & 0x80)
- have_v4_prefix = have_v6_prefix = 0;
- goto fail;
- }
- parsed_len = 10 + rc;
-
- plen = message[4] + (message[2] == 1 ? 96 : 0);
-
- if(message[3] & 0x80) {
- if(message[2] == 1) {
- memcpy(v4_prefix, prefix, 16);
- have_v4_prefix = 1;
- } else {
- memcpy(v6_prefix, prefix, 16);
- have_v6_prefix = 1;
- }
- }
- if(message[3] & 0x40) {
- if(message[2] == 1) {
- memset(router_id, 0, 4);
- memcpy(router_id + 4, prefix + 12, 4);
- } else {
- memcpy(router_id, prefix + 8, 8);
- }
- have_router_id = 1;
- }
- if(!have_router_id && message[2] != 0) {
- zlog_err("Received prefix with no router id.");
- goto fail;
- }
- debugf(BABEL_DEBUG_COMMON,"Received update%s%s for %s from %s on %s.",
- (message[3] & 0x80) ? "/prefix" : "",
- (message[3] & 0x40) ? "/id" : "",
- format_prefix(prefix, plen),
- format_address(from), ifp->name);
-
- if(message[2] == 0) {
- if(metric < 0xFFFF) {
- zlog_err("Received wildcard update with finite metric.");
- goto done;
- }
- retract_neighbour_routes(neigh);
- goto done;
- } else if(message[2] == 1) {
- if(!have_v4_nh)
- goto fail;
- nh = v4_nh;
- } else if(have_v6_nh) {
- nh = v6_nh;
- } else {
- nh = neigh->address;
- }
-
- if(message[2] == 1) {
- if(!babel_get_if_nfo(ifp)->ipv4)
- goto done;
- }
-
- if((ifp->flags & BABEL_IF_FARAWAY)) {
- channels[0] = 0;
- } else {
- /* This will be overwritten by parse_route_attributes below. */
- if(metric < 256) {
- /* Assume non-interfering (wired) link. */
- channels[0] = 0;
- } else {
- /* Assume interfering. */
- channels[0] = BABEL_IF_CHANNEL_INTERFERING;
- channels[1] = 0;
- }
-
- if(parsed_len < len)
- parse_route_attributes(message + 2 + parsed_len,
- len - parsed_len, channels);
- }
-
- update_route(router_id, prefix, plen, seqno, metric, interval,
- neigh, nh,
- channels, channels_len(channels));
- } else if(type == MESSAGE_REQUEST) {
- unsigned char prefix[16], plen;
- int rc;
- if(len < 2) goto fail;
- rc = network_prefix(message[2], message[3], 0,
- message + 4, NULL, len - 2, prefix);
- if(rc < 0) goto fail;
- plen = message[3] + (message[2] == 1 ? 96 : 0);
- debugf(BABEL_DEBUG_COMMON,"Received request for %s from %s on %s.",
- message[2] == 0 ? "any" : format_prefix(prefix, plen),
- format_address(from), ifp->name);
- if(message[2] == 0) {
- struct babel_interface *babel_ifp =babel_get_if_nfo(neigh->ifp);
- /* If a neighbour is requesting a full route dump from us,
- we might as well send it an IHU. */
- send_ihu(neigh, NULL);
- /* Since nodes send wildcard requests on boot, booting
- a large number of nodes at the same time may cause an
- update storm. Ignore a wildcard request that happens
- shortly after we sent a full update. */
- if(babel_ifp->last_update_time <
- (time_t)(babel_now.tv_sec -
- MAX(babel_ifp->hello_interval / 100, 1)))
- send_update(neigh->ifp, 0, NULL, 0);
- } else {
- send_update(neigh->ifp, 0, prefix, plen);
- }
- } else if(type == MESSAGE_MH_REQUEST) {
- unsigned char prefix[16], plen;
- unsigned short seqno;
- int rc;
- if(len < 14) goto fail;
- DO_NTOHS(seqno, message + 4);
- rc = network_prefix(message[2], message[3], 0,
- message + 16, NULL, len - 14, prefix);
- if(rc < 0) goto fail;
- plen = message[3] + (message[2] == 1 ? 96 : 0);
- debugf(BABEL_DEBUG_COMMON,"Received request (%d) for %s from %s on %s (%s, %d).",
- message[6],
- format_prefix(prefix, plen),
- format_address(from), ifp->name,
- format_eui64(message + 8), seqno);
- handle_request(neigh, prefix, plen, message[6],
- seqno, message + 8);
- } else {
- debugf(BABEL_DEBUG_COMMON,"Received unknown packet type %d from %s on %s.",
- type, format_address(from), ifp->name);
- }
- done:
- i += len + 2;
- continue;
-
- fail:
- zlog_err("Couldn't parse packet (%d, %d) from %s on %s.",
- message[0], message[1], format_address(from), ifp->name);
- goto done;
- }
- return;
-}
-
-/* Under normal circumstances, there are enough moderation mechanisms
- elsewhere in the protocol to make sure that this last-ditch check
- should never trigger. But I'm superstitious. */
-
-static int
-check_bucket(struct interface *ifp)
-{
- babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
- if(babel_ifp->bucket <= 0) {
- int seconds = babel_now.tv_sec - babel_ifp->bucket_time;
- if(seconds > 0) {
- babel_ifp->bucket = MIN(BUCKET_TOKENS_MAX,
- seconds * BUCKET_TOKENS_PER_SEC);
- }
- /* Reset bucket time unconditionally, in case clock is stepped. */
- babel_ifp->bucket_time = babel_now.tv_sec;
- }
-
- if(babel_ifp->bucket > 0) {
- babel_ifp->bucket--;
- return 1;
- } else {
- return 0;
- }
-}
-
-void
-flushbuf(struct interface *ifp)
-{
- int rc;
- struct sockaddr_in6 sin6;
- babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
-
- assert(babel_ifp->buffered <= babel_ifp->bufsize);
-
- flushupdates(ifp);
-
- if(babel_ifp->buffered > 0) {
- debugf(BABEL_DEBUG_COMMON," (flushing %d buffered bytes on %s)",
- babel_ifp->buffered, ifp->name);
- if(check_bucket(ifp)) {
- memset(&sin6, 0, sizeof(sin6));
- sin6.sin6_family = AF_INET6;
- memcpy(&sin6.sin6_addr, protocol_group, 16);
- sin6.sin6_port = htons(protocol_port);
- sin6.sin6_scope_id = ifp->ifindex;
- DO_HTONS(packet_header + 2, babel_ifp->buffered);
- rc = babel_send(protocol_socket,
- packet_header, sizeof(packet_header),
- babel_ifp->sendbuf, babel_ifp->buffered,
- (struct sockaddr*)&sin6, sizeof(sin6));
- if(rc < 0)
- zlog_err("send: %s", safe_strerror(errno));
- } else {
- zlog_err("Warning: bucket full, dropping packet to %s.",
- ifp->name);
- }
- }
- VALGRIND_MAKE_MEM_UNDEFINED(babel_ifp->sendbuf, babel_ifp->bufsize);
- babel_ifp->buffered = 0;
- babel_ifp->have_buffered_hello = 0;
- babel_ifp->have_buffered_id = 0;
- babel_ifp->have_buffered_nh = 0;
- babel_ifp->have_buffered_prefix = 0;
- babel_ifp->flush_timeout.tv_sec = 0;
- babel_ifp->flush_timeout.tv_usec = 0;
-}
-
-static void
-schedule_flush(struct interface *ifp)
-{
- babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
- unsigned msecs = jitter(babel_ifp, 0);
- if(babel_ifp->flush_timeout.tv_sec != 0 &&
- timeval_minus_msec(&babel_ifp->flush_timeout, &babel_now) < msecs)
- return;
- set_timeout(&babel_ifp->flush_timeout, msecs);
-}
-
-static void
-schedule_flush_now(struct interface *ifp)
-{
- babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
- /* Almost now */
- unsigned msecs = roughly(10);
- if(babel_ifp->flush_timeout.tv_sec != 0 &&
- timeval_minus_msec(&babel_ifp->flush_timeout, &babel_now) < msecs)
- return;
- set_timeout(&babel_ifp->flush_timeout, msecs);
-}
-
-static void
-schedule_unicast_flush(unsigned msecs)
-{
- if(!unicast_neighbour)
- return;
- if(unicast_flush_timeout.tv_sec != 0 &&
- timeval_minus_msec(&unicast_flush_timeout, &babel_now) < msecs)
- return;
- unicast_flush_timeout.tv_usec = (babel_now.tv_usec + msecs * 1000) %1000000;
- unicast_flush_timeout.tv_sec =
- babel_now.tv_sec + (babel_now.tv_usec / 1000 + msecs) / 1000;
-}
-
-static void
-ensure_space(struct interface *ifp, int space)
-{
- babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
- if(babel_ifp->bufsize - babel_ifp->buffered < space)
- flushbuf(ifp);
-}
-
-static void
-start_message(struct interface *ifp, int type, int len)
-{
- babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
- if(babel_ifp->bufsize - babel_ifp->buffered < len + 2)
- flushbuf(ifp);
- babel_ifp->sendbuf[babel_ifp->buffered++] = type;
- babel_ifp->sendbuf[babel_ifp->buffered++] = len;
-}
-
-static void
-end_message(struct interface *ifp, int type, int bytes)
-{
- babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
- assert(babel_ifp->buffered >= bytes + 2 &&
- babel_ifp->sendbuf[babel_ifp->buffered - bytes - 2] == type &&
- babel_ifp->sendbuf[babel_ifp->buffered - bytes - 1] == bytes);
- schedule_flush(ifp);
-}
-
-static void
-accumulate_byte(struct interface *ifp, unsigned char value)
-{
- babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
- babel_ifp->sendbuf[babel_ifp->buffered++] = value;
-}
-
-static void
-accumulate_short(struct interface *ifp, unsigned short value)
-{
- babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
- DO_HTONS(babel_ifp->sendbuf + babel_ifp->buffered, value);
- babel_ifp->buffered += 2;
-}
-
-static void
-accumulate_bytes(struct interface *ifp,
- const unsigned char *value, unsigned len)
-{
- babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
- memcpy(babel_ifp->sendbuf + babel_ifp->buffered, value, len);
- babel_ifp->buffered += len;
-}
-
-static int
-start_unicast_message(struct neighbour *neigh, int type, int len)
-{
- if(unicast_neighbour) {
- if(neigh != unicast_neighbour ||
- unicast_buffered + len + 2 >=
- MIN(UNICAST_BUFSIZE, babel_get_if_nfo(neigh->ifp)->bufsize))
- flush_unicast(0);
- }
- if(!unicast_buffer)
- unicast_buffer = malloc(UNICAST_BUFSIZE);
- if(!unicast_buffer) {
- zlog_err("malloc(unicast_buffer): %s", safe_strerror(errno));
- return -1;
- }
-
- unicast_neighbour = neigh;
-
- unicast_buffer[unicast_buffered++] = type;
- unicast_buffer[unicast_buffered++] = len;
- return 1;
-}
-
-static void
-end_unicast_message(struct neighbour *neigh, int type, int bytes)
-{
- assert(unicast_neighbour == neigh && unicast_buffered >= bytes + 2 &&
- unicast_buffer[unicast_buffered - bytes - 2] == type &&
- unicast_buffer[unicast_buffered - bytes - 1] == bytes);
- schedule_unicast_flush(jitter(babel_get_if_nfo(neigh->ifp), 0));
-}
-
-static void
-accumulate_unicast_byte(struct neighbour *neigh, unsigned char value)
-{
- unicast_buffer[unicast_buffered++] = value;
-}
-
-static void
-accumulate_unicast_short(struct neighbour *neigh, unsigned short value)
-{
- DO_HTONS(unicast_buffer + unicast_buffered, value);
- unicast_buffered += 2;
-}
-
-static void
-accumulate_unicast_bytes(struct neighbour *neigh,
- const unsigned char *value, unsigned len)
-{
- memcpy(unicast_buffer + unicast_buffered, value, len);
- unicast_buffered += len;
-}
-
-void
-send_ack(struct neighbour *neigh, unsigned short nonce, unsigned short interval)
-{
- int rc;
- debugf(BABEL_DEBUG_COMMON,"Sending ack (%04x) to %s on %s.",
- nonce, format_address(neigh->address), neigh->ifp->name);
- rc = start_unicast_message(neigh, MESSAGE_ACK, 2); if(rc < 0) return;
- accumulate_unicast_short(neigh, nonce);
- end_unicast_message(neigh, MESSAGE_ACK, 2);
- /* Roughly yields a value no larger than 3/2, so this meets the deadline */
- schedule_unicast_flush(roughly(interval * 6));
-}
-
-void
-send_hello_noupdate(struct interface *ifp, unsigned interval)
-{
- babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
- /* This avoids sending multiple hellos in a single packet, which breaks
- link quality estimation. */
- if(babel_ifp->have_buffered_hello)
- flushbuf(ifp);
-
- babel_ifp->hello_seqno = seqno_plus(babel_ifp->hello_seqno, 1);
- set_timeout(&babel_ifp->hello_timeout, babel_ifp->hello_interval);
-
- if(!if_up(ifp))
- return;
-
- debugf(BABEL_DEBUG_COMMON,"Sending hello %d (%d) to %s.",
- babel_ifp->hello_seqno, interval, ifp->name);
-
- start_message(ifp, MESSAGE_HELLO, 6);
- accumulate_short(ifp, 0);
- accumulate_short(ifp, babel_ifp->hello_seqno);
- accumulate_short(ifp, interval > 0xFFFF ? 0xFFFF : interval);
- end_message(ifp, MESSAGE_HELLO, 6);
- babel_ifp->have_buffered_hello = 1;
-}
-
-void
-send_hello(struct interface *ifp)
-{
- babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
- send_hello_noupdate(ifp, (babel_ifp->hello_interval + 9) / 10);
- /* Send full IHU every 3 hellos, and marginal IHU each time */
- if(babel_ifp->hello_seqno % 3 == 0)
- send_ihu(NULL, ifp);
- else
- send_marginal_ihu(ifp);
-}
-
-void
-flush_unicast(int dofree)
-{
- struct sockaddr_in6 sin6;
- int rc;
-
- if(unicast_buffered == 0)
- goto done;
-
- if(!if_up(unicast_neighbour->ifp))
- goto done;
-
- /* Preserve ordering of messages */
- flushbuf(unicast_neighbour->ifp);
-
- if(check_bucket(unicast_neighbour->ifp)) {
- memset(&sin6, 0, sizeof(sin6));
- sin6.sin6_family = AF_INET6;
- memcpy(&sin6.sin6_addr, unicast_neighbour->address, 16);
- sin6.sin6_port = htons(protocol_port);
- sin6.sin6_scope_id = unicast_neighbour->ifp->ifindex;
- DO_HTONS(packet_header + 2, unicast_buffered);
- rc = babel_send(protocol_socket,
- packet_header, sizeof(packet_header),
- unicast_buffer, unicast_buffered,
- (struct sockaddr*)&sin6, sizeof(sin6));
- if(rc < 0)
- zlog_err("send(unicast): %s", safe_strerror(errno));
- } else {
- zlog_err("Warning: bucket full, dropping unicast packet to %s if %s.",
- format_address(unicast_neighbour->address),
- unicast_neighbour->ifp->name);
- }
-
- done:
- VALGRIND_MAKE_MEM_UNDEFINED(unicast_buffer, UNICAST_BUFSIZE);
- unicast_buffered = 0;
- if(dofree && unicast_buffer) {
- free(unicast_buffer);
- unicast_buffer = NULL;
- }
- unicast_neighbour = NULL;
- unicast_flush_timeout.tv_sec = 0;
- unicast_flush_timeout.tv_usec = 0;
-}
-
-static void
-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, 16);
- 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);
- 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;
- }
-}
-
-static int
-compare_buffered_updates(const void *av, const void *bv)
-{
- const struct buffered_update *a = av, *b = bv;
- int rc, v4a, v4b, ma, mb;
-
- rc = memcmp(a->id, b->id, 8);
- if(rc != 0)
- return rc;
-
- v4a = (a->plen >= 96 && v4mapped(a->prefix));
- v4b = (b->plen >= 96 && v4mapped(b->prefix));
-
- if(v4a > v4b)
- return 1;
- else if(v4a < v4b)
- return -1;
-
- ma = (!v4a && a->plen == 128 && memcmp(a->prefix + 8, a->id, 8) == 0);
- mb = (!v4b && b->plen == 128 && memcmp(b->prefix + 8, b->id, 8) == 0);
-
- if(ma > mb)
- return -1;
- else if(mb > ma)
- return 1;
-
- if(a->plen < b->plen)
- return 1;
- else if(a->plen > b->plen)
- return -1;
-
- return memcmp(a->prefix, b->prefix, 16);
-}
-
-void
-flushupdates(struct interface *ifp)
-{
- babel_interface_nfo *babel_ifp = NULL;
- struct xroute *xroute;
- struct babel_route *route;
- const unsigned char *last_prefix = NULL;
- unsigned char last_plen = 0xFF;
- int i;
-
- if(ifp == NULL) {
- struct interface *ifp_aux;
- struct listnode *linklist_node = NULL;
- FOR_ALL_INTERFACES(ifp_aux, linklist_node)
- flushupdates(ifp_aux);
- return;
- }
-
- babel_ifp = babel_get_if_nfo(ifp);
- if(babel_ifp->num_buffered_updates > 0) {
- struct buffered_update *b = babel_ifp->buffered_updates;
- int n = babel_ifp->num_buffered_updates;
-
- babel_ifp->buffered_updates = NULL;
- babel_ifp->update_bufsize = 0;
- babel_ifp->num_buffered_updates = 0;
-
- if(!if_up(ifp))
- goto done;
-
- debugf(BABEL_DEBUG_COMMON," (flushing %d buffered updates on %s (%d))",
- n, ifp->name, ifp->ifindex);
-
- /* In order to send fewer update messages, we want to send updates
- with the same router-id together, with IPv6 going out before IPv4. */
-
- for(i = 0; i < n; i++) {
- route = find_installed_route(b[i].prefix, b[i].plen);
- if(route)
- memcpy(b[i].id, route->src->id, 8);
- else
- memcpy(b[i].id, myid, 8);
- }
-
- qsort(b, n, sizeof(struct buffered_update), compare_buffered_updates);
-
- for(i = 0; i < n; i++) {
- /* The same update may be scheduled multiple times before it is
- sent out. Since our buffer is now sorted, it is enough to
- compare with the previous update. */
-
- if(last_prefix) {
- if(b[i].plen == last_plen &&
- memcmp(b[i].prefix, last_prefix, 16) == 0)
- continue;
- }
-
- xroute = find_xroute(b[i].prefix, b[i].plen);
- route = find_installed_route(b[i].prefix, b[i].plen);
-
- if(xroute && (!route || xroute->metric <= kernel_metric)) {
- really_send_update(ifp, myid,
- xroute->prefix, xroute->plen,
- myseqno, xroute->metric,
- NULL, 0);
- last_prefix = xroute->prefix;
- last_plen = xroute->plen;
- } else if(route) {
- unsigned char channels[DIVERSITY_HOPS];
- int chlen;
- struct interface *route_ifp = route->neigh->ifp;
- struct babel_interface *babel_route_ifp = NULL;
- unsigned short metric;
- unsigned short seqno;
-
- seqno = route->seqno;
- metric =
- route_interferes(route, ifp) ?
- route_metric(route) :
- route_metric_noninterfering(route);
-
- if(metric < INFINITY)
- satisfy_request(route->src->prefix, route->src->plen,
- seqno, route->src->id, ifp);
- if((babel_ifp->flags & BABEL_IF_SPLIT_HORIZON) &&
- route->neigh->ifp == ifp)
- continue;
-
- babel_route_ifp = babel_get_if_nfo(route_ifp);
- if(babel_route_ifp->channel ==BABEL_IF_CHANNEL_NONINTERFERING) {
- memcpy(channels, route->channels, DIVERSITY_HOPS);
- } else {
- if(babel_route_ifp->channel == BABEL_IF_CHANNEL_UNKNOWN)
- channels[0] = BABEL_IF_CHANNEL_INTERFERING;
- else {
- assert(babel_route_ifp->channel > 0 &&
- babel_route_ifp->channel <= 255);
- channels[0] = babel_route_ifp->channel;
- }
- memcpy(channels + 1, route->channels, DIVERSITY_HOPS - 1);
- }
-
- chlen = channels_len(channels);
- really_send_update(ifp, route->src->id,
- route->src->prefix,
- route->src->plen,
- seqno, metric,
- channels, chlen);
- update_source(route->src, seqno, metric);
- last_prefix = route->src->prefix;
- last_plen = route->src->plen;
- } else {
- /* There's no route for this prefix. This can happen shortly
- after an xroute has been retracted, so send a retraction. */
- really_send_update(ifp, myid, b[i].prefix, b[i].plen,
- myseqno, INFINITY, NULL, -1);
- }
- }
- schedule_flush_now(ifp);
- done:
- free(b);
- }
- babel_ifp->update_flush_timeout.tv_sec = 0;
- babel_ifp->update_flush_timeout.tv_usec = 0;
-}
-
-static void
-schedule_update_flush(struct interface *ifp, int urgent)
-{
- babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
- unsigned msecs;
- msecs = update_jitter(babel_ifp, urgent);
- if(babel_ifp->update_flush_timeout.tv_sec != 0 &&
- timeval_minus_msec(&babel_ifp->update_flush_timeout, &babel_now) < msecs)
- return;
- set_timeout(&babel_ifp->update_flush_timeout, msecs);
-}
-
-static void
-buffer_update(struct interface *ifp,
- const unsigned char *prefix, unsigned char plen)
-{
- babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
- if(babel_ifp->num_buffered_updates > 0 &&
- babel_ifp->num_buffered_updates >= babel_ifp->update_bufsize)
- flushupdates(ifp);
-
- if(babel_ifp->update_bufsize == 0) {
- int n;
- assert(babel_ifp->buffered_updates == NULL);
- /* Allocate enough space to hold a full update. Since the
- number of installed routes will grow over time, make sure we
- have enough space to send a full-ish frame. */
- n = installed_routes_estimate() + xroutes_estimate() + 4;
- n = MAX(n, babel_ifp->bufsize / 16);
- again:
- babel_ifp->buffered_updates = malloc(n *sizeof(struct buffered_update));
- if(babel_ifp->buffered_updates == NULL) {
- zlog_err("malloc(buffered_updates): %s", safe_strerror(errno));
- if(n > 4) {
- /* Try again with a tiny buffer. */
- n = 4;
- goto again;
- }
- return;
- }
- babel_ifp->update_bufsize = n;
- babel_ifp->num_buffered_updates = 0;
- }
-
- memcpy(babel_ifp->buffered_updates[babel_ifp->num_buffered_updates].prefix,
- prefix, 16);
- babel_ifp->buffered_updates[babel_ifp->num_buffered_updates].plen = plen;
- babel_ifp->num_buffered_updates++;
-}
-
-static void
-buffer_update_callback(struct babel_route *route, void *closure)
-{
- buffer_update((struct interface*)closure,
- route->src->prefix, route->src->plen);
-}
-
-void
-send_update(struct interface *ifp, int urgent,
- const unsigned char *prefix, unsigned char plen)
-{
- babel_interface_nfo *babel_ifp = NULL;
-
- if(ifp == NULL) {
- struct interface *ifp_aux;
- struct listnode *linklist_node = NULL;
- struct babel_route *route;
- FOR_ALL_INTERFACES(ifp_aux, linklist_node)
- send_update(ifp_aux, urgent, prefix, plen);
- if(prefix) {
- /* Since flushupdates only deals with non-wildcard interfaces, we
- need to do this now. */
- route = find_installed_route(prefix, plen);
- if(route && route_metric(route) < INFINITY)
- satisfy_request(prefix, plen, route->src->seqno, route->src->id,
- NULL);
- }
- return;
- }
-
- if(!if_up(ifp))
- return;
-
- babel_ifp = babel_get_if_nfo(ifp);
- if(prefix) {
- debugf(BABEL_DEBUG_COMMON,"Sending update to %s for %s.",
- ifp->name, format_prefix(prefix, plen));
- buffer_update(ifp, prefix, plen);
- } else {
- send_self_update(ifp);
- debugf(BABEL_DEBUG_COMMON,"Sending update to %s for any.", ifp->name);
- for_all_installed_routes(buffer_update_callback, ifp);
- set_timeout(&babel_ifp->update_timeout, babel_ifp->update_interval);
- babel_ifp->last_update_time = babel_now.tv_sec;
- }
- schedule_update_flush(ifp, urgent);
-}
-
-void
-send_update_resend(struct interface *ifp,
- const unsigned char *prefix, unsigned char plen)
-{
- assert(prefix != NULL);
-
- send_update(ifp, 1, prefix, plen);
- record_resend(RESEND_UPDATE, prefix, plen, 0, 0, NULL, resend_delay);
-}
-
-void
-send_wildcard_retraction(struct interface *ifp)
-{
- babel_interface_nfo *babel_ifp = NULL;
- if(ifp == NULL) {
- struct interface *ifp_aux;
- struct listnode *linklist_node = NULL;
- FOR_ALL_INTERFACES(ifp_aux, linklist_node)
- send_wildcard_retraction(ifp_aux);
- return;
- }
-
- if(!if_up(ifp))
- return;
-
- babel_ifp = babel_get_if_nfo(ifp);
- start_message(ifp, MESSAGE_UPDATE, 10);
- accumulate_byte(ifp, 0);
- accumulate_byte(ifp, 0x40);
- accumulate_byte(ifp, 0);
- accumulate_byte(ifp, 0);
- accumulate_short(ifp, 0xFFFF);
- accumulate_short(ifp, myseqno);
- accumulate_short(ifp, 0xFFFF);
- end_message(ifp, MESSAGE_UPDATE, 10);
-
- babel_ifp->have_buffered_id = 0;
-}
-
-void
-update_myseqno()
-{
- myseqno = seqno_plus(myseqno, 1);
- seqno_time = babel_now;
-}
-
-static void
-send_xroute_update_callback(struct xroute *xroute, void *closure)
-{
- struct interface *ifp = (struct interface*)closure;
- send_update(ifp, 0, xroute->prefix, xroute->plen);
-}
-
-void
-send_self_update(struct interface *ifp)
-{
- if(ifp == NULL) {
- struct interface *ifp_aux;
- struct listnode *linklist_node = NULL;
- FOR_ALL_INTERFACES(ifp_aux, linklist_node) {
- if(!if_up(ifp_aux))
- continue;
- send_self_update(ifp_aux);
- }
- return;
- }
-
- debugf(BABEL_DEBUG_COMMON,"Sending self update to %s.", ifp->name);
- for_all_xroutes(send_xroute_update_callback, ifp);
-}
-
-void
-send_ihu(struct neighbour *neigh, struct interface *ifp)
-{
- babel_interface_nfo *babel_ifp = NULL;
- int rxcost, interval;
- int ll;
-
- if(neigh == NULL && ifp == NULL) {
- struct interface *ifp_aux;
- struct listnode *linklist_node = NULL;
- FOR_ALL_INTERFACES(ifp_aux, linklist_node) {
- if(if_up(ifp_aux))
- continue;
- send_ihu(NULL, ifp_aux);
- }
- return;
- }
-
- if(neigh == NULL) {
- struct neighbour *ngh;
- FOR_ALL_NEIGHBOURS(ngh) {
- if(ngh->ifp == ifp)
- send_ihu(ngh, ifp);
- }
- return;
- }
-
-
- if(ifp && neigh->ifp != ifp)
- return;
-
- ifp = neigh->ifp;
- babel_ifp = babel_get_if_nfo(ifp);
- if(!if_up(ifp))
- return;
-
- rxcost = neighbour_rxcost(neigh);
- interval = (babel_ifp->hello_interval * 3 + 9) / 10;
-
- /* Conceptually, an IHU is a unicast message. We usually send them as
- multicast, since this allows aggregation into a single packet and
- avoids an ARP exchange. If we already have a unicast message queued
- for this neighbour, however, we might as well piggyback the IHU. */
- debugf(BABEL_DEBUG_COMMON,"Sending %sihu %d on %s to %s.",
- unicast_neighbour == neigh ? "unicast " : "",
- rxcost,
- neigh->ifp->name,
- format_address(neigh->address));
-
- ll = linklocal(neigh->address);
-
- if(unicast_neighbour != neigh) {
- start_message(ifp, MESSAGE_IHU, ll ? 14 : 22);
- accumulate_byte(ifp, ll ? 3 : 2);
- accumulate_byte(ifp, 0);
- accumulate_short(ifp, rxcost);
- accumulate_short(ifp, interval);
- if(ll)
- accumulate_bytes(ifp, neigh->address + 8, 8);
- else
- accumulate_bytes(ifp, neigh->address, 16);
- end_message(ifp, MESSAGE_IHU, ll ? 14 : 22);
- } else {
- int rc;
- rc = start_unicast_message(neigh, MESSAGE_IHU, ll ? 14 : 22);
- if(rc < 0) return;
- accumulate_unicast_byte(neigh, ll ? 3 : 2);
- accumulate_unicast_byte(neigh, 0);
- accumulate_unicast_short(neigh, rxcost);
- accumulate_unicast_short(neigh, interval);
- if(ll)
- accumulate_unicast_bytes(neigh, neigh->address + 8, 8);
- else
- accumulate_unicast_bytes(neigh, neigh->address, 16);
- end_unicast_message(neigh, MESSAGE_IHU, ll ? 14 : 22);
- }
-}
-
-/* Send IHUs to all marginal neighbours */
-void
-send_marginal_ihu(struct interface *ifp)
-{
- struct neighbour *neigh;
- FOR_ALL_NEIGHBOURS(neigh) {
- if(ifp && neigh->ifp != ifp)
- continue;
- if(neigh->txcost >= 384 || (neigh->reach & 0xF000) != 0xF000)
- send_ihu(neigh, ifp);
- }
-}
-
-void
-send_request(struct interface *ifp,
- const unsigned char *prefix, unsigned char plen)
-{
- int v4, len;
-
- if(ifp == NULL) {
- struct interface *ifp_aux;
- struct listnode *linklist_node = NULL;
- FOR_ALL_INTERFACES(ifp_aux, linklist_node) {
- if(if_up(ifp_aux))
- continue;
- send_request(ifp_aux, prefix, plen);
- }
- return;
- }
-
- /* make sure any buffered updates go out before this request. */
- flushupdates(ifp);
-
- if(!if_up(ifp))
- return;
-
- debugf(BABEL_DEBUG_COMMON,"sending request to %s for %s.",
- ifp->name, prefix ? format_prefix(prefix, plen) : "any");
- v4 = plen >= 96 && v4mapped(prefix);
- len = !prefix ? 2 : v4 ? 6 : 18;
-
- start_message(ifp, MESSAGE_REQUEST, len);
- accumulate_byte(ifp, !prefix ? 0 : v4 ? 1 : 2);
- accumulate_byte(ifp, !prefix ? 0 : v4 ? plen - 96 : plen);
- if(prefix) {
- if(v4)
- accumulate_bytes(ifp, prefix + 12, 4);
- else
- accumulate_bytes(ifp, prefix, 16);
- }
- end_message(ifp, MESSAGE_REQUEST, len);
-}
-
-void
-send_unicast_request(struct neighbour *neigh,
- const unsigned char *prefix, unsigned char plen)
-{
- int rc, v4, len;
-
- /* make sure any buffered updates go out before this request. */
- flushupdates(neigh->ifp);
-
- debugf(BABEL_DEBUG_COMMON,"sending unicast request to %s for %s.",
- format_address(neigh->address),
- prefix ? format_prefix(prefix, plen) : "any");
- v4 = plen >= 96 && v4mapped(prefix);
- len = !prefix ? 2 : v4 ? 6 : 18;
-
- rc = start_unicast_message(neigh, MESSAGE_REQUEST, len);
- if(rc < 0) return;
- accumulate_unicast_byte(neigh, !prefix ? 0 : v4 ? 1 : 2);
- accumulate_unicast_byte(neigh, !prefix ? 0 : v4 ? plen - 96 : plen);
- if(prefix) {
- if(v4)
- accumulate_unicast_bytes(neigh, prefix + 12, 4);
- else
- accumulate_unicast_bytes(neigh, prefix, 16);
- }
- end_unicast_message(neigh, MESSAGE_REQUEST, len);
-}
-
-void
-send_multihop_request(struct interface *ifp,
- const unsigned char *prefix, unsigned char plen,
- unsigned short seqno, const unsigned char *id,
- unsigned short hop_count)
-{
- int v4, pb, len;
-
- /* Make sure any buffered updates go out before this request. */
- flushupdates(ifp);
-
- if(ifp == NULL) {
- struct interface *ifp_aux;
- struct listnode *linklist_node = NULL;
- FOR_ALL_INTERFACES(ifp_aux, linklist_node) {
- if(!if_up(ifp_aux))
- continue;
- send_multihop_request(ifp_aux, prefix, plen, seqno, id, hop_count);
- }
- return;
- }
-
- if(!if_up(ifp))
- return;
-
- debugf(BABEL_DEBUG_COMMON,"Sending request (%d) on %s for %s.",
- hop_count, ifp->name, format_prefix(prefix, plen));
- v4 = plen >= 96 && v4mapped(prefix);
- pb = v4 ? ((plen - 96) + 7) / 8 : (plen + 7) / 8;
- len = 6 + 8 + pb;
-
- start_message(ifp, MESSAGE_MH_REQUEST, len);
- accumulate_byte(ifp, v4 ? 1 : 2);
- accumulate_byte(ifp, v4 ? plen - 96 : plen);
- accumulate_short(ifp, seqno);
- accumulate_byte(ifp, hop_count);
- accumulate_byte(ifp, 0);
- accumulate_bytes(ifp, id, 8);
- if(prefix) {
- if(v4)
- accumulate_bytes(ifp, prefix + 12, pb);
- else
- accumulate_bytes(ifp, prefix, pb);
- }
- end_message(ifp, MESSAGE_MH_REQUEST, len);
-}
-
-void
-send_unicast_multihop_request(struct neighbour *neigh,
- const unsigned char *prefix, unsigned char plen,
- unsigned short seqno, const unsigned char *id,
- unsigned short hop_count)
-{
- int rc, v4, pb, len;
-
- /* Make sure any buffered updates go out before this request. */
- flushupdates(neigh->ifp);
-
- debugf(BABEL_DEBUG_COMMON,"Sending multi-hop request to %s for %s (%d hops).",
- format_address(neigh->address),
- format_prefix(prefix, plen), hop_count);
- v4 = plen >= 96 && v4mapped(prefix);
- pb = v4 ? ((plen - 96) + 7) / 8 : (plen + 7) / 8;
- len = 6 + 8 + pb;
-
- rc = start_unicast_message(neigh, MESSAGE_MH_REQUEST, len);
- if(rc < 0) return;
- accumulate_unicast_byte(neigh, v4 ? 1 : 2);
- accumulate_unicast_byte(neigh, v4 ? plen - 96 : plen);
- accumulate_unicast_short(neigh, seqno);
- accumulate_unicast_byte(neigh, hop_count);
- accumulate_unicast_byte(neigh, 0);
- accumulate_unicast_bytes(neigh, id, 8);
- if(prefix) {
- if(v4)
- accumulate_unicast_bytes(neigh, prefix + 12, pb);
- else
- accumulate_unicast_bytes(neigh, prefix, pb);
- }
- end_unicast_message(neigh, MESSAGE_MH_REQUEST, len);
-}
-
-void
-send_request_resend(struct neighbour *neigh,
- const unsigned char *prefix, unsigned char plen,
- unsigned short seqno, unsigned char *id)
-{
- if(neigh)
- send_unicast_multihop_request(neigh, prefix, plen, seqno, id, 127);
- else
- send_multihop_request(NULL, prefix, plen, seqno, id, 127);
-
- record_resend(RESEND_REQUEST, prefix, plen, seqno, id,
- neigh ? neigh->ifp : NULL, resend_delay);
-}
-
-void
-handle_request(struct neighbour *neigh, const unsigned char *prefix,
- unsigned char plen, unsigned char hop_count,
- unsigned short seqno, const unsigned char *id)
-{
- struct xroute *xroute;
- struct babel_route *route;
- struct neighbour *successor = NULL;
-
- xroute = find_xroute(prefix, plen);
- route = find_installed_route(prefix, plen);
-
- if(xroute && (!route || xroute->metric <= kernel_metric)) {
- if(hop_count > 0 && memcmp(id, myid, 8) == 0) {
- if(seqno_compare(seqno, myseqno) > 0) {
- if(seqno_minus(seqno, myseqno) > 100) {
- /* Hopelessly out-of-date request */
- return;
- }
- update_myseqno();
- }
- }
- send_update(neigh->ifp, 1, prefix, plen);
- return;
- }
-
- if(route &&
- (memcmp(id, route->src->id, 8) != 0 ||
- seqno_compare(seqno, route->seqno) <= 0)) {
- send_update(neigh->ifp, 1, prefix, plen);
- return;
- }
-
- if(hop_count <= 1)
- return;
-
- if(route && memcmp(id, route->src->id, 8) == 0 &&
- seqno_minus(seqno, route->seqno) > 100) {
- /* Hopelessly out-of-date */
- return;
- }
-
- if(request_redundant(neigh->ifp, prefix, plen, seqno, id))
- return;
-
- /* Let's try to forward this request. */
- if(route && route_metric(route) < INFINITY)
- successor = route->neigh;
-
- if(!successor || successor == neigh) {
- /* We were about to forward a request to its requestor. Try to
- find a different neighbour to forward the request to. */
- struct babel_route *other_route;
-
- other_route = find_best_route(prefix, plen, 0, neigh);
- if(other_route && route_metric(other_route) < INFINITY)
- successor = other_route->neigh;
- }
-
- if(!successor || successor == neigh)
- /* Give up */
- return;
-
- send_unicast_multihop_request(successor, prefix, plen, seqno, id,
- hop_count - 1);
- record_resend(RESEND_REQUEST, prefix, plen, seqno, id,
- neigh->ifp, 0);
-}