summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Schiffer <mschiffer@universe-factory.net>2012-09-30 15:59:21 +0200
committerMatthias Schiffer <mschiffer@universe-factory.net>2012-09-30 15:59:21 +0200
commite03169f8594f890162be16f72ea7000f802a252e (patch)
tree28613d25319ba8a8218eff1bb4dec59ad490be93
parentae4505db19ae5c13b2c9367fc0fe586df515025b (diff)
downloadffd-e03169f8594f890162be16f72ea7000f802a252e.tar
ffd-e03169f8594f890162be16f72ea7000f802a252e.zip
Restructure source files
-rw-r--r--ffd/CMakeLists.txt2
-rw-r--r--ffd/ffd.c169
-rw-r--r--ffd/ffd.h20
-rw-r--r--ffd/neigh.c78
-rw-r--r--ffd/neigh.h50
-rw-r--r--ffd/send.c121
6 files changed, 288 insertions, 152 deletions
diff --git a/ffd/CMakeLists.txt b/ffd/CMakeLists.txt
index d04e69f..2a661a3 100644
--- a/ffd/CMakeLists.txt
+++ b/ffd/CMakeLists.txt
@@ -2,7 +2,9 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${FFD_BINARY_DIR} ${CMAKE_CURREN
add_executable(ffd
ffd.c
+ neigh.c
netif.c
+ send.c
tlv.c
util.c
)
diff --git a/ffd/ffd.c b/ffd/ffd.c
index b1668b0..c4ddb5b 100644
--- a/ffd/ffd.c
+++ b/ffd/ffd.c
@@ -25,6 +25,7 @@
#include "ffd.h"
+#include "neigh.h"
#include "netif.h"
#include "packet.h"
#include "tlv.h"
@@ -40,24 +41,17 @@
#include <netpacket/packet.h>
#include <sys/socket.h>
-#include <sys/uio.h>
-#define FFD_PROTO 0xffd
-
-static const eth_addr_t ffd_addr = {{0x03, 0x00, 0x00, 0x00, 0x0f, 0xfd}};
-
-#define HELLO_INTERVAL 400
-#define IHU_INTERVAL (3*HELLO_INTERVAL)
-#define PACKET_MAX 1000
+const eth_addr_t ffd_addr = {{0x03, 0x00, 0x00, 0x00, 0x0f, 0xfd}};
static char *mesh = "bat0";
-static int sockfd;
-static struct timespec now;
+int sockfd;
+struct timespec now;
-static ffd_iface_t *iface_list = NULL;
+ffd_iface_t *iface_list = NULL;
static ffd_neigh_t self;
//static ffd_orig_t own_data;
@@ -156,62 +150,6 @@ static void update_netif(const char *ifname, unsigned ifindex, void *arg) {
iface->addr = netif_get_eth_addr(ifname);
}
-static inline ffd_neigh_t* get_neigh(const ffd_iface_t *iface, const eth_addr_t *addr) {
- ffd_neigh_t *neigh;
- for (neigh = iface->neigh_list; neigh; neigh = neigh->next) {
- if (are_eth_addrs_equal(addr, &neigh->addr))
- return neigh;
- }
-
- return neigh;
-}
-
-static ffd_neigh_t* get_neigh_create(ffd_iface_t *iface, const eth_addr_t *addr) {
- ffd_neigh_t *neigh = get_neigh(iface, addr);
- if (!neigh) {
- neigh = calloc(1, sizeof(ffd_neigh_t));
- neigh->next = iface->neigh_list;
- iface->neigh_list = neigh;
- neigh->addr = *addr;
-
- neigh->txcost = 0xffff;
- }
-
- return neigh;
-}
-
-static void free_neighs(ffd_neigh_t *neigh) {
- ffd_neigh_t *next;
- for (; neigh; neigh = next) {
- next = neigh->next;
- free(neigh);
- }
-}
-
-static uint16_t get_neigh_rxcost(const ffd_neigh_t *neigh) {
- int timediff = timespec_diff(&now, &neigh->last_hello)/10;
- int shift = (timediff - neigh->hello_interval/2)/neigh->hello_interval;
- int received = __builtin_popcount(neigh->hello_log << shift);
-
- if (received == 0)
- return 0xffff;
- else
- return (0x1000/received);
-}
-
-static uint16_t get_neigh_cost(const ffd_neigh_t *neigh) {
- uint16_t txcost = neigh->txcost;
- if (txcost < 256)
- txcost = 256;
-
- uint32_t cost = (txcost * get_neigh_rxcost(neigh)) >> 8;
-
- if (cost > 0xffff)
- return 0xffff;
- else
- return cost;
-}
-
static void update_netifs() {
ffd_iface_t *iface, **cur;
@@ -227,7 +165,7 @@ static void update_netifs() {
if (iface->type == IF_UNSPEC) {
*cur = iface->next;
- free_neighs(iface->neigh_list);
+ ffd_neigh_free_list(iface->neigh_list);
free(iface);
}
else {
@@ -236,82 +174,6 @@ static void update_netifs() {
}
}
-static bool send_eth(const eth_addr_t *addr, unsigned ifindex, void *buf, size_t len) {
- static const uint8_t zeros[46] = {0};
-
- struct sockaddr_ll sa;
- memset(&sa, 0, sizeof(sa));
- sa.sll_family = AF_PACKET;
- sa.sll_protocol = htons(FFD_PROTO);
- sa.sll_ifindex = ifindex;
- sa.sll_halen = ETH_ALEN;
- memcpy(sa.sll_addr, addr->d, ETH_ALEN);
-
- struct iovec vec[2] = {
- { .iov_base = buf, .iov_len = len },
- { .iov_base = (void*)zeros, .iov_len = sizeof(zeros) - len },
- };
-
- struct msghdr msg;
- memset(&msg, 0, sizeof(msg));
- msg.msg_name = &sa;
- msg.msg_namelen = sizeof(sa);
- msg.msg_iov = vec;
- msg.msg_iovlen = (len < 46) ? 2 : 1;
-
-
- while (sendmsg(sockfd, &msg, 0) < 0) {
- if (errno != EINTR)
- return false;
- }
-
- return true;
-}
-
-static void add_ihus(ffd_packet_t *packet, size_t max_len, const ffd_iface_t *iface) {
- const ffd_neigh_t *neigh;
-
- for (neigh = iface->neigh_list; neigh; neigh = neigh->next) {
- ffd_tlv_ihu_t *ihu = ffd_tlv_add(packet, PACKET_MAX, TLV_IHU, sizeof(ffd_tlv_ihu_t)+sizeof(eth_addr_t));
- if (!ihu)
- return;
-
- ihu->ae = ADDR_ENC_ETH;
- ihu->reserved = 0;
- ihu->rxcost = htons(get_neigh_rxcost(neigh));
- ihu->interval = htons(IHU_INTERVAL);
- memcpy(ihu->address, &neigh->addr, sizeof(eth_addr_t));
- }
-}
-
-static void send_hellos() {
- ffd_packet_t *packet = alloca(sizeof(ffd_packet_t)+PACKET_MAX);
-
- packet->version_magic = htons(FFD_VERSION_MAGIC);
- packet->len = 0;
-
- ffd_tlv_hello_t *hello = ffd_tlv_add(packet, PACKET_MAX, TLV_HELLO, sizeof(ffd_tlv_hello_t));
- if (!hello)
- return;
-
- hello->reserved = 0;
- hello->interval = htons(HELLO_INTERVAL);
-
- uint16_t len = packet->len;
-
- ffd_iface_t *iface;
- for (iface = iface_list; iface; iface = iface->next) {
- hello->seqno = htons(iface->seqno++);
-
- packet->len = len;
-
- add_ihus(packet, PACKET_MAX, iface);
-
- if (!send_eth(&ffd_addr, iface->ifindex, packet, sizeof(ffd_packet_t)+ntohs(packet->len)))
- fprintf(stderr, "send_eth: %m\n");
- }
-}
-
static void handle_tlv_hello(const ffd_tlv_hello_t *tlv_hello, size_t len, const eth_addr_t *addr, ffd_iface_t *iface) {
if (len < sizeof(ffd_tlv_hello_t)) {
fprintf(stderr, "warn: received short hello TLV.\n");
@@ -320,7 +182,7 @@ static void handle_tlv_hello(const ffd_tlv_hello_t *tlv_hello, size_t len, const
fprintf(stderr, "debug: received hello with seqno %u.\n", ntohs(tlv_hello->seqno));
- ffd_neigh_t *neigh = get_neigh_create(iface, addr);
+ ffd_neigh_t *neigh = ffd_neigh_get(iface, addr);
uint16_t seqno = ntohs(tlv_hello->seqno);
@@ -352,7 +214,10 @@ static void handle_tlv_hello(const ffd_tlv_hello_t *tlv_hello, size_t len, const
neigh->last_seqno = seqno;
neigh->last_hello = now;
- fprintf(stderr, "debug: accepted hello, log %04x, rxcost is %u, cost is %u now.\n", neigh->hello_log, get_neigh_rxcost(neigh), get_neigh_cost(neigh));
+ if (neigh->hello_log == 1) /* new or reset neighbour */
+ ffd_neigh_reset(iface, neigh);
+
+ fprintf(stderr, "debug: accepted hello, log %04x, rxcost is %u, cost is %u now.\n", neigh->hello_log, ffd_neigh_get_rxcost(neigh), ffd_neigh_get_cost(neigh));
}
static void handle_tlv_ihu(const ffd_tlv_ihu_t *tlv_ihu, size_t len, const eth_addr_t *addr, ffd_iface_t *iface) {
@@ -374,11 +239,11 @@ static void handle_tlv_ihu(const ffd_tlv_ihu_t *tlv_ihu, size_t len, const eth_a
return;
}
- ffd_neigh_t *neigh = get_neigh_create(iface, addr);
+ ffd_neigh_t *neigh = ffd_neigh_get(iface, addr);
neigh->last_ihu = now;
neigh->txcost = ntohs(tlv_ihu->rxcost);
- fprintf(stderr, "debug: accepted IHU, txcost is %u, cost is %u now.\n", neigh->txcost, get_neigh_cost(neigh));
+ fprintf(stderr, "debug: accepted IHU, txcost is %u, cost is %u now.\n", neigh->txcost, ffd_neigh_get_cost(neigh));
}
static void handle_tlv(ffd_tlv_type_t type, const void *data, size_t len, void *arg) {
@@ -405,11 +270,11 @@ static void handle_tlv(ffd_tlv_type_t type, const void *data, size_t len, void *
}
static void receive_packet() {
- ffd_packet_t *packet = alloca(sizeof(ffd_packet_t)+PACKET_MAX);
+ ffd_packet_t *packet = alloca(sizeof(ffd_packet_t)+FFD_PACKET_MAX);
struct sockaddr_ll from;
socklen_t fromlen = sizeof(from);
- ssize_t readlen = recvfrom(sockfd, packet, sizeof(ffd_packet_t)+PACKET_MAX, 0, (struct sockaddr*)&from, &fromlen);
+ ssize_t readlen = recvfrom(sockfd, packet, sizeof(ffd_packet_t)+FFD_PACKET_MAX, 0, (struct sockaddr*)&from, &fromlen);
if (readlen < 0) {
fprintf(stderr, "error: recvfrom: %m\n");
@@ -458,9 +323,9 @@ int main() {
int timeout = timespec_diff(&next_hello, &now);
if (timeout <= 0) {
- send_hellos();
+ ffd_send_hellos();
- add_interval(&next_hello, HELLO_INTERVAL);
+ add_interval(&next_hello, FFD_HELLO_INTERVAL);
continue;
}
diff --git a/ffd/ffd.h b/ffd/ffd.h
index 81bccfc..4d70f17 100644
--- a/ffd/ffd.h
+++ b/ffd/ffd.h
@@ -33,6 +33,14 @@
#include <net/if.h>
+#define FFD_PACKET_MAX 1000
+
+#define FFD_PROTO 0xffd
+
+#define FFD_HELLO_INTERVAL 400
+#define FFD_IHU_INTERVAL (3*FFD_HELLO_INTERVAL)
+
+
typedef struct _ffd_announce_t {
struct _ffd_announce_t *next;
@@ -68,4 +76,16 @@ typedef struct _ffd_iface_t {
ffd_neigh_t *neigh_list;
} ffd_iface_t;
+
+extern const eth_addr_t ffd_addr;
+
+extern ffd_iface_t *iface_list;
+
+extern int sockfd;
+extern struct timespec now;
+
+
+void ffd_send_hellos();
+void ffd_send_announce_request(ffd_iface_t *iface, ffd_neigh_t *neigh, void *announce);
+
#endif /* _FFD_FFD_H_ */
diff --git a/ffd/neigh.c b/ffd/neigh.c
new file mode 100644
index 0000000..6cfd5e8
--- /dev/null
+++ b/ffd/neigh.c
@@ -0,0 +1,78 @@
+/*
+ Copyright (c) 2012, 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 "neigh.h"
+
+
+ffd_neigh_t* ffd_neigh_get(ffd_iface_t *iface, const eth_addr_t *addr) {
+ ffd_neigh_t *neigh = ffd_neigh_find(iface, addr);
+ if (!neigh) {
+ neigh = calloc(1, sizeof(ffd_neigh_t));
+ neigh->next = iface->neigh_list;
+ iface->neigh_list = neigh;
+ neigh->addr = *addr;
+
+ neigh->txcost = 0xffff;
+ }
+
+ return neigh;
+}
+
+void ffd_neigh_free_list(ffd_neigh_t *neigh) {
+ ffd_neigh_t *next;
+ for (; neigh; neigh = next) {
+ next = neigh->next;
+ free(neigh);
+ }
+}
+
+uint16_t ffd_neigh_get_rxcost(const ffd_neigh_t *neigh) {
+ int timediff = timespec_diff(&now, &neigh->last_hello)/10;
+ int shift = (timediff - neigh->hello_interval/2)/neigh->hello_interval;
+ int received = __builtin_popcount(neigh->hello_log << shift);
+
+ if (received == 0)
+ return 0xffff;
+ else
+ return (0x1000/received);
+}
+
+uint16_t ffd_neigh_get_cost(const ffd_neigh_t *neigh) {
+ uint16_t txcost = neigh->txcost;
+ if (txcost < 256)
+ txcost = 256;
+
+ uint32_t cost = (txcost * ffd_neigh_get_rxcost(neigh)) >> 8;
+
+ if (cost > 0xffff)
+ return 0xffff;
+ else
+ return cost;
+}
+
+void ffd_neigh_reset(ffd_iface_t *iface, ffd_neigh_t *neigh) {
+ ffd_send_announce_request(iface, neigh, NULL);
+}
diff --git a/ffd/neigh.h b/ffd/neigh.h
new file mode 100644
index 0000000..6874dbe
--- /dev/null
+++ b/ffd/neigh.h
@@ -0,0 +1,50 @@
+/*
+ Copyright (c) 2012, 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.
+*/
+
+
+#ifndef _FFD_NEIGH_H_
+#define _FFD_NEIGH_H_
+
+#include "ffd.h"
+
+
+static inline ffd_neigh_t* ffd_neigh_find(const ffd_iface_t *iface, const eth_addr_t *addr) {
+ ffd_neigh_t *neigh;
+ for (neigh = iface->neigh_list; neigh; neigh = neigh->next) {
+ if (are_eth_addrs_equal(addr, &neigh->addr))
+ return neigh;
+ }
+
+ return NULL;
+}
+
+ffd_neigh_t* ffd_neigh_get(ffd_iface_t *iface, const eth_addr_t *addr);
+void ffd_neigh_free_list(ffd_neigh_t *neigh);
+
+uint16_t ffd_neigh_get_rxcost(const ffd_neigh_t *neigh);
+uint16_t ffd_neigh_get_cost(const ffd_neigh_t *neigh);
+void ffd_neigh_reset(ffd_iface_t *iface, ffd_neigh_t *neigh);
+
+#endif /* _FFD_NEIGH_H_ */
diff --git a/ffd/send.c b/ffd/send.c
new file mode 100644
index 0000000..d020aca
--- /dev/null
+++ b/ffd/send.c
@@ -0,0 +1,121 @@
+/*
+ Copyright (c) 2012, 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 "ffd.h"
+#include "neigh.h"
+#include "packet.h"
+#include "tlv.h"
+#include "tlv_types.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <netpacket/packet.h>
+
+#include <sys/socket.h>
+#include <sys/uio.h>
+
+
+static bool send_eth(const eth_addr_t *addr, unsigned ifindex, void *buf, size_t len) {
+ static const uint8_t zeros[46] = {0};
+
+ struct sockaddr_ll sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sll_family = AF_PACKET;
+ sa.sll_protocol = htons(FFD_PROTO);
+ sa.sll_ifindex = ifindex;
+ sa.sll_halen = ETH_ALEN;
+ memcpy(sa.sll_addr, addr->d, ETH_ALEN);
+
+ struct iovec vec[2] = {
+ { .iov_base = buf, .iov_len = len },
+ { .iov_base = (void*)zeros, .iov_len = sizeof(zeros) - len },
+ };
+
+ struct msghdr msg;
+ memset(&msg, 0, sizeof(msg));
+ msg.msg_name = &sa;
+ msg.msg_namelen = sizeof(sa);
+ msg.msg_iov = vec;
+ msg.msg_iovlen = (len < 46) ? 2 : 1;
+
+
+ while (sendmsg(sockfd, &msg, 0) < 0) {
+ if (errno != EINTR)
+ return false;
+ }
+
+ return true;
+}
+
+static void add_ihus(ffd_packet_t *packet, size_t max_len, const ffd_iface_t *iface) {
+ const ffd_neigh_t *neigh;
+
+ for (neigh = iface->neigh_list; neigh; neigh = neigh->next) {
+ ffd_tlv_ihu_t *ihu = ffd_tlv_add(packet, FFD_PACKET_MAX, TLV_IHU, sizeof(ffd_tlv_ihu_t)+sizeof(eth_addr_t));
+ if (!ihu)
+ return;
+
+ ihu->ae = ADDR_ENC_ETH;
+ ihu->reserved = 0;
+ ihu->rxcost = htons(ffd_neigh_get_rxcost(neigh));
+ ihu->interval = htons(FFD_IHU_INTERVAL);
+ memcpy(ihu->address, &neigh->addr, sizeof(eth_addr_t));
+ }
+}
+
+void ffd_send_hellos() {
+ ffd_packet_t *packet = alloca(sizeof(ffd_packet_t)+FFD_PACKET_MAX);
+
+ packet->version_magic = htons(FFD_VERSION_MAGIC);
+ packet->len = 0;
+
+ ffd_tlv_hello_t *hello = ffd_tlv_add(packet, FFD_PACKET_MAX, TLV_HELLO, sizeof(ffd_tlv_hello_t));
+ if (!hello)
+ return;
+
+ hello->reserved = 0;
+ hello->interval = htons(FFD_HELLO_INTERVAL);
+
+ uint16_t len = packet->len;
+
+ ffd_iface_t *iface;
+ for (iface = iface_list; iface; iface = iface->next) {
+ hello->seqno = htons(iface->seqno++);
+
+ packet->len = len;
+
+ add_ihus(packet, FFD_PACKET_MAX, iface);
+
+ if (!send_eth(&ffd_addr, iface->ifindex, packet, sizeof(ffd_packet_t)+ntohs(packet->len)))
+ fprintf(stderr, "send_eth: %m\n");
+ }
+}
+
+void ffd_send_announce_request(ffd_iface_t *iface, ffd_neigh_t *neigh, void *announce) {
+
+}