summaryrefslogtreecommitdiffstats
path: root/ffd/send.c
diff options
context:
space:
mode:
Diffstat (limited to 'ffd/send.c')
-rw-r--r--ffd/send.c84
1 files changed, 78 insertions, 6 deletions
diff --git a/ffd/send.c b/ffd/send.c
index ebda0de..936e1fb 100644
--- a/ffd/send.c
+++ b/ffd/send.c
@@ -27,6 +27,7 @@
#include "ffd.h"
#include "neigh.h"
#include "packet.h"
+#include "queue.h"
#include "tlv.h"
#include "tlv_types.h"
@@ -72,6 +73,7 @@ static bool send_eth(const eth_addr_t *addr, unsigned ifindex, const void *buf,
return true;
}
+
static inline bool send_neigh(const ffd_neigh_t *neigh, const ffd_packet_t *packet) {
if (!neigh->iface)
return false;
@@ -84,8 +86,12 @@ static inline bool send_neigh(const ffd_neigh_t *neigh, const ffd_packet_t *pack
return true;
}
+static inline bool send_ifindex(unsigned ifindex, const ffd_packet_t *packet) {
+ return send_eth(&ffd_addr, ifindex, packet, sizeof(ffd_packet_t)+ntohs(packet->len));
+}
+
static inline bool send_iface(const ffd_iface_t *iface, const ffd_packet_t *packet) {
- if (!send_eth(&ffd_addr, iface->ifindex, packet, sizeof(ffd_packet_t)+ntohs(packet->len))) {
+ if (!send_ifindex(iface->ifindex, packet)) {
fprintf(stderr, "send_eth: %m\n");
return false;
}
@@ -108,6 +114,54 @@ static inline void send_any(const ffd_iface_t *iface, const ffd_neigh_t *neigh,
send_broadcast(packet);
}
+
+typedef struct _retransmit_arg {
+ unsigned iface;
+ ffd_neigh_t *neigh;
+ ffd_packet_t *packet;
+
+ unsigned ref;
+} retransmit_arg;
+
+static void retransmit_cb(const struct timespec *timeout, void *argp) {
+ retransmit_arg *arg = argp;
+
+ fprintf(stderr, "debug: doing retransmit\n");
+
+ if (arg->neigh)
+ send_neigh(arg->neigh, arg->packet);
+ else if(arg->iface)
+ send_ifindex(arg->iface, arg->packet);
+ else
+ send_broadcast(arg->packet);
+
+ if (!--arg->ref) {
+ if (arg->neigh)
+ ffd_neigh_unref(arg->neigh);
+
+ free(arg->packet);
+ free(arg);
+ }
+}
+
+static void send_retransmit(ffd_iface_t *iface, ffd_neigh_t *neigh, ffd_packet_t *packet) {
+ if (neigh)
+ ffd_neigh_ref(neigh);
+
+ retransmit_arg *arg = malloc(sizeof(retransmit_arg));
+ arg->iface = iface ? iface->ifindex : 0;
+ arg->neigh = neigh;
+ arg->packet = packet;
+ arg->ref = 5;
+
+ ffd_queue_put_delayed(&retransmits, retransmit_cb, &now, 100, arg);
+ ffd_queue_put_delayed(&retransmits, retransmit_cb, &now, 75, arg);
+ ffd_queue_put_delayed(&retransmits, retransmit_cb, &now, 50, arg);
+ ffd_queue_put_delayed(&retransmits, retransmit_cb, &now, 25, arg);
+ ffd_queue_put_delayed(&retransmits, retransmit_cb, &now, 0, arg);
+}
+
+
void ffd_send_ack(ffd_neigh_t *neigh, uint16_t nonce) {
ffd_packet_t *packet = alloca(sizeof(ffd_packet_t)+FFD_PACKET_MAX);
@@ -223,8 +277,12 @@ static bool add_update(ffd_packet_t *packet, size_t max_len, ffd_node_id_t *node
return true;
}
-void ffd_send_update(ffd_iface_t *iface, ffd_neigh_t *neigh, ffd_announce_t *announce, bool with_data) {
- ffd_packet_t *packet = alloca(sizeof(ffd_packet_t)+FFD_PACKET_MAX);
+void ffd_send_update(ffd_iface_t *iface, ffd_neigh_t *neigh, ffd_announce_t *announce, bool urgent, bool with_data) {
+ ffd_packet_t *packet;
+ if (urgent)
+ packet = malloc(sizeof(ffd_packet_t)+FFD_PACKET_MAX);
+ else
+ packet = alloca(sizeof(ffd_packet_t)+FFD_PACKET_MAX);
packet->version_magic = htons(FFD_VERSION_MAGIC);
packet->len = 0;
@@ -238,7 +296,13 @@ void ffd_send_update(ffd_iface_t *iface, ffd_neigh_t *neigh, ffd_announce_t *ann
ffd_announce_t *a;
for (a = announce_list; a; a = a->next) {
if (!add_update(packet, FFD_PACKET_MAX, &node_id, a, with_data, iface || neigh)) {
- send_any(iface, neigh, packet);
+ if (urgent) {
+ send_retransmit(iface, neigh, packet);
+ packet = malloc(sizeof(ffd_packet_t)+FFD_PACKET_MAX);
+ }
+ else {
+ send_any(iface, neigh, packet);
+ }
node_id = FFD_NODE_ID_UNSPEC;
packet->len = 0;
@@ -251,8 +315,16 @@ void ffd_send_update(ffd_iface_t *iface, ffd_neigh_t *neigh, ffd_announce_t *ann
}
}
- if (packet->len)
- send_any(iface, neigh, packet);
+ if (urgent) {
+ if (packet->len)
+ send_retransmit(iface, neigh, packet);
+ else
+ free(packet);
+ }
+ else {
+ if (packet->len)
+ send_any(iface, neigh, packet);
+ }
}
void ffd_send_retract(ffd_neigh_t *neigh, ffd_node_id_t node, uint16_t type, uint16_t key) {