summaryrefslogtreecommitdiffstats
path: root/ffd/ffd.c
diff options
context:
space:
mode:
Diffstat (limited to 'ffd/ffd.c')
-rw-r--r--ffd/ffd.c101
1 files changed, 97 insertions, 4 deletions
diff --git a/ffd/ffd.c b/ffd/ffd.c
index 3512906..5f17446 100644
--- a/ffd/ffd.c
+++ b/ffd/ffd.c
@@ -98,9 +98,8 @@ static bool init_self(void) {
announce->node = self;
announce->type = 1;
announce->key = 1337;
- announce->interval = 6000;
- announce->nexthop_list = calloc(1, sizeof(ffd_nexthop_t));
+ announce->nexthop_list = announce->selected = calloc(1, sizeof(ffd_nexthop_t));
return true;
}
@@ -273,13 +272,107 @@ static void handle_tlv_node_id(const ffd_tlv_node_id_t *tlv_node_id, size_t len,
arg->node_id = tlv_node_id->id;
}
-static void handle_tlv_update(const ffd_tlv_node_id_t *tlv_node_id, size_t len, handle_tlv_arg_t *arg) {
+static ffd_announce_t* get_announce(const ffd_node_id_t *node, uint16_t type, uint16_t key) {
+ ffd_announce_t *announce;
+ for (announce = announce_list; announce; announce = announce->next) {
+ if (ffd_are_node_ids_equal(&announce->node, node)
+ && announce->type == type
+ && announce->key == key)
+ return announce;
+ }
+
+ /* not found */
+ announce = ffd_announce_new();
+ announce->node = *node;
+ announce->type = type;
+ announce->key = key;
+
+ return announce;
+}
+
+static ffd_nexthop_t* find_nexthop(const ffd_announce_t *announce, ffd_neigh_t *neigh) {
+ ffd_nexthop_t *nexthop;
+ for (nexthop = announce->nexthop_list; nexthop; nexthop = nexthop->next) {
+ if (nexthop->neigh == neigh)
+ return nexthop;
+ }
+
+ return NULL;
+}
+
+static ffd_nexthop_t* new_nexthop(ffd_announce_t *announce, ffd_neigh_t *neigh) {
+ ffd_nexthop_t *nexthop = calloc(1, sizeof(ffd_nexthop_t));
+ nexthop->neigh = neigh;
+
+ nexthop->next = announce->nexthop_list;
+ announce->nexthop_list = nexthop;
+
+ return nexthop;
+}
+
+static void handle_tlv_update(const ffd_tlv_update_t *tlv_update, size_t len, handle_tlv_arg_t *arg) {
if (len < sizeof(ffd_tlv_update_t)) {
fprintf(stderr, "warn: received short update TLV.\n");
return;
}
+ if (ffd_is_node_id_unspec(&arg->node_id)) {
+ fprintf(stderr, "warn: received update TLV without node id TLV.\n");
+ return;
+ }
+
+ if (ffd_are_node_ids_equal(&arg->node_id, &self)) {
+ fprintf(stderr, "debug: update source is myself.\n");
+ return;
+ }
+
fprintf(stderr, "debug: update received from %04x%04x.\n", ntohl(*(uint32_t*)arg->node_id.id), ntohl(*(uint32_t*)(arg->node_id.id+4)));
+
+ ffd_announce_t *announce = get_announce(&arg->node_id, ntohs(tlv_update->type), ntohs(tlv_update->key));
+ ffd_metric_seqno_t ms = { ntohs(tlv_update->metric), ntohs(tlv_update->seqno) };
+ bool feasable = ffd_is_feasable(announce, ms);
+
+ ffd_neigh_t *neigh = get_tlv_neigh(arg);
+ ffd_nexthop_t *nexthop = find_nexthop(announce, neigh);
+
+ if (!nexthop) {
+ if (!feasable || tlv_update->metric == 0xffff /* no need to ntohs */)
+ return;
+
+ nexthop = new_nexthop(announce, neigh);
+ }
+ else {
+ if (!feasable && nexthop == announce->selected)
+ return;
+ }
+
+ nexthop->metric_seqno.metric = ntohs(tlv_update->metric);
+ nexthop->metric_seqno.seqno = ntohs(tlv_update->seqno);
+ nexthop->interval = ntohs(tlv_update->interval);
+
+ fprintf(stderr, "debug: the update was accepted.\n");
+
+ if (nexthop->metric_seqno.metric == 0xffff)
+ return;
+
+ /* only update the timestamp for finite metrics */
+ nexthop->last_update = now;
+
+ if ((tlv_update->flags & FFD_UPDATE_WITH_DATA) && !announce->data) {
+ if (len > sizeof(ffd_tlv_update_t)) {
+ announce->len = len - sizeof(ffd_tlv_update_t);
+ announce->data = malloc(announce->len);
+ memcpy(announce->data, tlv_update->data, announce->len);
+ }
+ else {
+ announce->len = 0xff;
+
+ /* request data */
+ ffd_send_announce_request(arg->iface, neigh, announce->node, announce->type, announce->key, true);
+ }
+ }
+
+ ffd_announce_update_nexthop(announce);
}
static void handle_tlv_announce_req(const ffd_tlv_announce_req_t *tlv_req, size_t len, handle_tlv_arg_t *arg) {
@@ -294,7 +387,7 @@ static void handle_tlv_announce_req(const ffd_tlv_announce_req_t *tlv_req, size_
announce = NULL;
}
- ffd_send_update(arg->iface, get_tlv_neigh(arg), announce);
+ ffd_send_update(arg->iface, get_tlv_neigh(arg), announce, tlv_req->flags & FFD_UPDATE_WITH_DATA);
}
static void handle_tlv(ffd_tlv_type_t type, const void *data, size_t len, void *arg) {