241 lines
7.5 KiB
C
241 lines
7.5 KiB
C
/*
|
|
Copyright (c) 2013, Matthias Schiffer <mschiffer@universe-factory.net>
|
|
All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions are met:
|
|
|
|
1. Redistributions of source code must retain the above copyright notice,
|
|
this list of conditions and the following disclaimer.
|
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
this list of conditions and the following disclaimer in the documentation
|
|
and/or other materials provided with the distribution.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
|
|
#include "babel.h"
|
|
#include "neigh.h"
|
|
#include "packet.h"
|
|
#include "tlv.h"
|
|
#include "tlv_types.h"
|
|
|
|
#include <assert.h>
|
|
|
|
|
|
static inline bool send_neigh(gmrf_context_t *ctx, const gp_babel_neigh_t *neigh, const gp_babel_packet_t *packet) {
|
|
if (!neigh->iface)
|
|
return false;
|
|
|
|
if (!gmrf_iface_send(ctx->gmrf, neigh->iface->gmrf_iface, packet, gp_babel_packet_size(packet), &neigh->addr)) {
|
|
gmrf_logf(ctx->gmrf, LOG_WARNING, "gmrf_iface_send: %m");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static inline bool send_iface(gmrf_context_t *ctx, const gmrf_iface_state_t *iface, const gp_babel_packet_t *packet) {
|
|
if (!gmrf_iface_send_bc(ctx->gmrf, iface->gmrf_iface, packet, gp_babel_packet_size(packet))) {
|
|
gmrf_logf(ctx->gmrf, LOG_WARNING, "gmrf_iface_send_bc: %m");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static inline void send_bc(gmrf_context_t *ctx, const gp_babel_packet_t *packet) {
|
|
gmrf_iface_state_t *iface;
|
|
for (iface = ctx->interfaces; iface; iface = iface->next)
|
|
send_iface(ctx, iface, packet);
|
|
}
|
|
|
|
void gp_babel_send_ack(gmrf_context_t *ctx, gp_babel_neigh_t *neigh, uint16_t nonce) {
|
|
gp_babel_packet_buf_t *buf = gp_babel_packet_alloca(GP_BABEL_PACKET_MAX);
|
|
|
|
gp_babel_tlv_ack_t *ack = gp_babel_tlv_add(buf, TLV_ACK, sizeof(gp_babel_tlv_ack_t));
|
|
if (!ack)
|
|
return;
|
|
|
|
ack->nonce = htons(nonce);
|
|
|
|
send_neigh(ctx, neigh, &buf->packet);
|
|
}
|
|
|
|
static void add_ihus(gmrf_context_t *ctx, gp_babel_packet_buf_t *buf, const gmrf_iface_state_t *iface) {
|
|
const gp_babel_neigh_t *neigh;
|
|
|
|
for (neigh = iface->neighbours; neigh; neigh = neigh->next) {
|
|
gp_babel_tlv_ihu_t *ihu = gp_babel_tlv_add(buf, TLV_IHU, sizeof(gp_babel_tlv_ihu_t)+sizeof(gmrf_addr_t));
|
|
if (!ihu)
|
|
return;
|
|
|
|
ihu->ae = ADDR_ENC_GMRF;
|
|
ihu->reserved = 0;
|
|
ihu->rxcost = htons(gp_babel_neigh_get_rxcost(ctx, neigh));
|
|
ihu->interval = htons(GP_BABEL_IHU_INTERVAL);
|
|
memcpy(ihu->address, &neigh->addr, sizeof(gmrf_addr_t));
|
|
}
|
|
}
|
|
|
|
void gp_babel_send_hellos(gmrf_context_t *ctx) {
|
|
gmrf_logf(ctx->gmrf, LOG_DEBUG, "sending hellos...");
|
|
|
|
gp_babel_packet_buf_t *buf = gp_babel_packet_alloca(GP_BABEL_PACKET_MAX);
|
|
|
|
gp_babel_tlv_hello_t *hello = gp_babel_tlv_add(buf, TLV_HELLO, sizeof(gp_babel_tlv_hello_t));
|
|
if (!hello)
|
|
return;
|
|
|
|
hello->reserved = 0;
|
|
hello->interval = htons(GP_BABEL_HELLO_INTERVAL);
|
|
|
|
uint16_t len = buf->packet.len;
|
|
|
|
gmrf_iface_state_t *iface;
|
|
for (iface = ctx->interfaces; iface; iface = iface->next) {
|
|
hello->seqno = htons(iface->seqno++);
|
|
|
|
buf->packet.len = len;
|
|
add_ihus(ctx, buf, iface);
|
|
|
|
send_iface(ctx, iface, &buf->packet);
|
|
}
|
|
}
|
|
|
|
/*static inline bool add_node_id_tlv(gp_babel_packet_buf_t *buf, const gp_babel_node_id_t *node_id) {
|
|
gp_babel_tlv_node_id_t *tlv = gp_babel_tlv_add(buf, TLV_NODE_ID, sizeof(gp_babel_tlv_node_id_t));
|
|
if (!tlv)
|
|
return false;
|
|
|
|
tlv->id = *node_id;
|
|
|
|
return true;
|
|
}*/
|
|
|
|
static gp_babel_tlv_update_t* add_update_tlv(gp_babel_packet_buf_t *buf, const gp_babel_node_id_t *node, gp_babel_metric_seqno_t ms) {
|
|
gp_babel_tlv_update_t *update = gp_babel_tlv_add(buf, TLV_UPDATE, sizeof(gp_babel_tlv_update_t));
|
|
|
|
if (!update)
|
|
return NULL;
|
|
|
|
update->flags = 0;
|
|
update->reserved = 0;
|
|
update->interval = htons(GP_BABEL_UPDATE_INTERVAL);
|
|
update->seqno = htons(ms.seqno);
|
|
update->metric = htons(ms.metric);
|
|
update->node = *node;
|
|
|
|
return update;
|
|
}
|
|
|
|
static gp_babel_tlv_update_t* add_retract_tlv(gp_babel_packet_buf_t *buf, const gp_babel_node_id_t *node) {
|
|
return add_update_tlv(buf, node, (gp_babel_metric_seqno_t){GP_BABEL_INFINITY, 0});
|
|
}
|
|
|
|
static bool add_update(gp_babel_packet_buf_t *buf, gp_babel_route_t *route, bool targetted) {
|
|
gp_babel_tlv_update_t *update = add_update_tlv(buf, &route->node, route->metric);
|
|
if (!update)
|
|
return false;
|
|
|
|
if (gp_babel_is_metric_better(route->metric, route->feasibility_distance))
|
|
route->feasibility_distance = route->metric;
|
|
|
|
if (!targetted)
|
|
route->last_metric = route->metric.metric;
|
|
|
|
return true;
|
|
}
|
|
|
|
void gp_babel_send_update(gmrf_context_t *ctx, gmrf_iface_state_t *iface, gp_babel_neigh_t *neigh) {
|
|
gp_babel_packet_buf_t *buf = gp_babel_packet_alloca(GP_BABEL_PACKET_MAX);
|
|
|
|
gp_babel_route_t *a;
|
|
for (a = ctx->routes; a; a = a->next) {
|
|
if (!add_update(buf, a, neigh)) {
|
|
if (neigh)
|
|
send_neigh(ctx, neigh, &buf->packet);
|
|
else
|
|
send_iface(ctx, iface, &buf->packet);
|
|
|
|
buf->packet.len = 0;
|
|
|
|
assert(add_update(buf, a, neigh));
|
|
}
|
|
}
|
|
|
|
if (buf->packet.len) {
|
|
if (neigh)
|
|
send_neigh(ctx, neigh, &buf->packet);
|
|
else
|
|
send_iface(ctx, iface, &buf->packet);
|
|
}
|
|
}
|
|
|
|
void gp_babel_send_update_for_route(gmrf_context_t *ctx, gmrf_iface_state_t *iface, gp_babel_neigh_t *neigh, gp_babel_route_t *route) {
|
|
gp_babel_packet_buf_t *buf = gp_babel_packet_alloca(GP_BABEL_PACKET_MAX);
|
|
|
|
assert(add_update(buf, route, neigh));
|
|
|
|
if (neigh)
|
|
send_neigh(ctx, neigh, &buf->packet);
|
|
else
|
|
send_iface(ctx, iface, &buf->packet);
|
|
}
|
|
|
|
void gp_babel_send_retract(gmrf_context_t *ctx, gmrf_iface_state_t *iface, gp_babel_neigh_t *neigh, const gp_babel_node_id_t *node) {
|
|
gp_babel_packet_buf_t *buf = gp_babel_packet_alloca(GP_BABEL_PACKET_MAX);
|
|
|
|
assert(add_retract_tlv(buf, node));
|
|
|
|
if (neigh)
|
|
send_neigh(ctx, neigh, &buf->packet);
|
|
else
|
|
send_iface(ctx, iface, &buf->packet);
|
|
}
|
|
|
|
void gp_babel_send_route_request(gmrf_context_t *ctx, gmrf_iface_state_t *iface, gp_babel_neigh_t *neigh, const gp_babel_node_id_t *node) {
|
|
gp_babel_packet_buf_t *buf = gp_babel_packet_alloca(GP_BABEL_PACKET_MAX);
|
|
|
|
gp_babel_tlv_route_req_t *req = gp_babel_tlv_add(buf, TLV_ROUTE_REQ, sizeof(gp_babel_tlv_route_req_t));
|
|
if (!req)
|
|
return;
|
|
|
|
req->node = node ? (*node) : (gp_babel_node_id_t){};
|
|
|
|
req->flags = 0;
|
|
req->reserved = 0;
|
|
|
|
if (neigh)
|
|
send_neigh(ctx, neigh, &buf->packet);
|
|
else
|
|
send_iface(ctx, iface, &buf->packet);
|
|
}
|
|
|
|
void gp_babel_send_seqno_request(gmrf_context_t *ctx, gp_babel_neigh_t *neigh, gp_babel_route_t *route, uint16_t seqno, uint8_t hop_count) {
|
|
gp_babel_packet_buf_t *buf = gp_babel_packet_alloca(GP_BABEL_PACKET_MAX);
|
|
|
|
gp_babel_tlv_seqno_req_t *req = gp_babel_tlv_add(buf, TLV_SEQNO_REQ, sizeof(gp_babel_tlv_seqno_req_t));
|
|
if (!req)
|
|
return;
|
|
|
|
req->seqno = htons(seqno);
|
|
req->hop_count = hop_count;
|
|
req->reserved = 0;
|
|
req->node = route->node;
|
|
|
|
if (neigh)
|
|
send_neigh(ctx, neigh, &buf->packet);
|
|
else
|
|
send_bc(ctx, &buf->packet);
|
|
}
|