summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Schiffer <mschiffer@universe-factory.net>2012-09-07 03:50:44 +0200
committerMatthias Schiffer <mschiffer@universe-factory.net>2012-09-07 03:50:44 +0200
commitf22dc0880f1b9348dc8c056cba0bbce223a39e62 (patch)
treed88090edf80436cef422214cda7b61f172358825
parent5998b096b969cb931e5e3d7850415be1c70f122c (diff)
downloadffd-f22dc0880f1b9348dc8c056cba0bbce223a39e62.tar
ffd-f22dc0880f1b9348dc8c056cba0bbce223a39e62.zip
Basic code for the data distribution daemon
-rw-r--r--CMakeLists.txt3
-rw-r--r--ffd/CMakeLists.txt10
-rw-r--r--ffd/ffd.c162
-rw-r--r--ffd/ffd.h70
-rw-r--r--ffd/netif.c182
-rw-r--r--ffd/netif.h56
-rw-r--r--ffd/types.h44
-rw-r--r--ffd/util.c42
-rw-r--r--ffd/util.h51
9 files changed, 619 insertions, 1 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 38e5e96..772feba 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -3,4 +3,5 @@ project(FFD C)
set(CMAKE_MODULE_PATH ${FFD_SOURCE_DIR})
-add_subdirectory(ffvisd)
+add_subdirectory(ffd)
+#add_subdirectory(ffvisd)
diff --git a/ffd/CMakeLists.txt b/ffd/CMakeLists.txt
new file mode 100644
index 0000000..d2d2a52
--- /dev/null
+++ b/ffd/CMakeLists.txt
@@ -0,0 +1,10 @@
+include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${FFD_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR})
+
+add_executable(ffd
+ ffd.c
+ netif.c
+ util.c
+)
+target_link_libraries(ffd rt)
+
+install(TARGETS ffd RUNTIME DESTINATION sbin)
diff --git a/ffd/ffd.c b/ffd/ffd.c
new file mode 100644
index 0000000..d182ee0
--- /dev/null
+++ b/ffd/ffd.c
@@ -0,0 +1,162 @@
+/*
+ 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 "netif.h"
+
+#include <errno.h>
+#include <poll.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <netpacket/packet.h>
+
+
+#define FFD_PROTO 0xffd
+#define FFD_VERSION 0
+
+static const eth_addr_t ffd_addr = {{0x03, 0x00, 0x00, 0x00, 0x0f, 0xfd}};
+
+#define ANNOUNCE_INTERVAL 10
+
+
+static char *mesh = "bat0";
+static unsigned mtu = 1500;
+
+static int sockfd;
+static struct timespec now;
+
+//static ffd_neigh_t self = {NULL, ETH_ADDR_UNSPEC, 0};
+//static ffd_orig_t own_data = {NULL, ETH_ADDR_UNSPEC, 0, NULL};
+
+//static ffd_neigh_t *neigh_data = NULL;
+static ffd_orig_t *orig_data = NULL;
+
+
+static void update_time() {
+ clock_gettime(CLOCK_MONOTONIC, &now);
+}
+
+static bool check_config() {
+ if (!netif_is_mesh(mesh)) {
+ fprintf(stderr, "error: configured interface is no mesh\n");
+ return false;
+ }
+
+ return true;
+}
+
+static bool init_socket() {
+ sockfd = socket(AF_PACKET, SOCK_DGRAM, htons(FFD_PROTO));
+ if (sockfd < 0) {
+ fprintf(stderr, "error: socket: %m\n");
+ return false;
+ }
+
+ return true;
+}
+
+static inline bool use_netif(const char *ifname) {
+ char *if_mesh = netif_get_mesh(ifname);
+ bool ret = (if_mesh && !strcmp(if_mesh, mesh));
+ free(if_mesh);
+
+ return ret;
+}
+
+static void join_mcast(const char *ifname, unsigned ifindex, void *arg) {
+ if (!use_netif(ifname))
+ return;
+
+ struct packet_mreq mr;
+ memset(&mr, 0, sizeof(mr));
+ mr.mr_ifindex = ifindex;
+ mr.mr_type = PACKET_MR_MULTICAST;
+ mr.mr_alen = ETH_ALEN;
+ memcpy(mr.mr_address, ffd_addr.d, ETH_ALEN);
+ if (setsockopt(sockfd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mr, sizeof(mr)) && errno != EADDRINUSE)
+ fprintf(stderr, "warning: setsockopt: %m\n");
+}
+
+static void send_announce() {
+ if (!orig_data)
+ return;
+}
+
+static void receive_packet() {
+ uint8_t buf[mtu];
+
+ int readlen = read(sockfd, buf, sizeof(buf));
+
+ if (readlen < 0) {
+ fprintf(stderr, "error: read: %m\n");
+ return;
+ }
+
+ fprintf(stderr, "debug: read %i bytes.\n", readlen);
+}
+
+int main() {
+ if (!check_config())
+ return 1;
+
+ if (!init_socket())
+ return 1;
+
+ update_time();
+
+ struct timespec next_announce = now;
+
+ while (true) {
+ netif_foreach(join_mcast, NULL);
+
+ int timeout = timespec_diff(&next_announce, &now);
+
+ if (timeout <= 0) {
+ send_announce();
+
+ next_announce.tv_sec += ANNOUNCE_INTERVAL;
+ continue;
+ }
+
+ struct pollfd fds[1];
+
+ fds[0].fd = sockfd;
+ fds[0].events = POLLIN;
+
+ poll(fds, 1, timeout);
+
+ update_time();
+
+ if (fds[0].revents & POLLIN)
+ receive_packet();
+ }
+
+ return 0;
+}
+
diff --git a/ffd/ffd.h b/ffd/ffd.h
new file mode 100644
index 0000000..3f9f81c
--- /dev/null
+++ b/ffd/ffd.h
@@ -0,0 +1,70 @@
+/*
+ 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_FFD_H_
+#define _FFD_FFD_H_
+
+#include "util.h"
+
+
+typedef enum _ffd_msg_type_t {
+ MSG_UNSPEC = 0,
+ MSG_SERVICE,
+ MSG_ROUTE4,
+ MSG_ROUTE6,
+} ffd_msg_type_t;
+
+typedef struct _ffd_msg_head_t {
+ struct _ffd_msg_head_t *next;
+
+ uint16_t changed_rev;
+ bool deleted;
+
+ ffd_msg_type_t type;
+ uint16_t len;
+ uint8_t data[];
+} ffd_msg_head_t;
+
+typedef struct _ffd_orig_t {
+ struct _ffd_orig_t *next;
+
+ uint64_t id;
+ eth_addr_t addr;
+ uint16_t orig_interval;
+ uint16_t rev;
+
+ ffd_msg_head_t *messages;
+} ffd_orig_t;
+
+typedef struct _ffd_neigh_t {
+ struct _ffd_neigh_t *next;
+
+ uint64_t id;
+ eth_addr_t addr;
+ uint16_t rev;
+} ffd_neigh_t;
+
+#endif /* _FFD_FFD_H_ */
diff --git a/ffd/netif.c b/ffd/netif.c
new file mode 100644
index 0000000..c63b19b
--- /dev/null
+++ b/ffd/netif.c
@@ -0,0 +1,182 @@
+/*
+ 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.
+*/
+
+#define _GNU_SOURCE
+
+#include "netif.h"
+#include "util.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <linux/rtnetlink.h>
+
+#include <net/if.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+
+
+#define SYSFS_PATH_MAX 256
+#define SYSFS_CLASS_NET "/sys/class/net"
+
+
+static bool netif_file_read(const char *ifname, const char *file, const char *format, ...) {
+ char filename[SYSFS_PATH_MAX];
+
+ snprintf(filename, SYSFS_PATH_MAX, SYSFS_CLASS_NET"/%s/%s", ifname, file);
+
+ va_list ap;
+ va_start(ap, format);
+ bool ret = file_readv(filename, format, ap);
+ va_end(ap);
+
+ return ret;
+}
+
+static bool netif_file_exists(const char *ifname, const char *file) {
+ char filename[SYSFS_PATH_MAX];
+
+ snprintf(filename, SYSFS_PATH_MAX, SYSFS_CLASS_NET"/%s/%s", ifname, file);
+
+ struct stat st;
+ return (stat(filename, &st) == 0);
+}
+
+bool netif_is_mesh(const char *ifname) {
+ return netif_file_exists(ifname, "mesh");
+}
+
+char* netif_get_mesh(const char *ifname) {
+ char *mesh = NULL;
+
+ if (!netif_file_read(ifname, "batman_adv/mesh_iface", "%as", &mesh) || !strcmp(mesh, "none")) {
+ free(mesh);
+ return NULL;
+ }
+
+ return mesh;
+}
+
+char* netif_get_bridge(const char *ifname) {
+ char filename[SYSFS_PATH_MAX], filename2[SYSFS_PATH_MAX] = {0};
+
+ snprintf(filename, SYSFS_PATH_MAX, SYSFS_CLASS_NET"/%s/brport/bridge", ifname);
+ if (readlink(filename, filename2, sizeof(filename2)) < 0)
+ return NULL;
+
+ return strdup(basename(filename2));
+}
+
+eth_addr_t netif_get_eth_addr(const char *ifname) {
+ eth_addr_t ret;
+ uint8_t *a = ret.d;
+
+ if (!netif_file_read(ifname, "address", "%x:%x:%x:%x:%x:%x", &a[0], &a[1], &a[2], &a[3], &a[4], &a[5]))
+ return ETH_ADDR_UNSPEC;
+
+ return ret;
+}
+
+struct in6_addr netif_get_addr(unsigned ifindex, int scope) {
+ struct msg {
+ struct nlmsghdr nh;
+ struct ifaddrmsg addr;
+ uint8_t attrbuf[16384];
+ } msg;
+
+ memset(&msg, 0, sizeof(msg));
+
+ int rtnetlink_sk = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+
+ msg.nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
+ msg.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT;
+ msg.nh.nlmsg_type = RTM_GETADDR;
+
+ msg.addr.ifa_family = AF_INET6;
+
+ if(write(rtnetlink_sk, &msg, msg.nh.nlmsg_len) <= 0) {
+ fprintf(stderr, "error: write: %m\n");
+ close(rtnetlink_sk);
+ return in6addr_any;
+ }
+
+ int readlen = read(rtnetlink_sk, &msg, sizeof(msg));
+
+ if (readlen <= 0) {
+ fprintf(stderr, "error: read: %m\n");
+ close(rtnetlink_sk);
+ return in6addr_any;
+ }
+
+ close(rtnetlink_sk);
+
+ struct msg *chunk;
+
+ for (chunk = &msg; readlen > sizeof(struct nlmsghdr);) {
+ int len = chunk->nh.nlmsg_len - sizeof(struct nlmsghdr);
+
+ if (len < sizeof(struct ifaddrmsg) || readlen < len)
+ return in6addr_any;
+
+ if (!NLMSG_OK(&chunk->nh, readlen))
+ return in6addr_any;
+
+ if (chunk->nh.nlmsg_type == RTM_NEWADDR && chunk->addr.ifa_scope == scope && chunk->addr.ifa_index == ifindex) {
+ struct rtattr *rta = (struct rtattr *)IFA_RTA(&chunk->addr);
+ int rtattrlen = IFA_PAYLOAD(&chunk->nh);
+
+ for (; RTA_OK(rta, rtattrlen); rta = RTA_NEXT(rta, rtattrlen)) {
+ if(rta->rta_type == IFA_ADDRESS && rta->rta_len == RTA_LENGTH(16)) {
+ struct in6_addr ret;
+ memcpy(ret.s6_addr, RTA_DATA(rta), 16);
+ return ret;
+ }
+ }
+ }
+
+ readlen -= NLMSG_ALIGN(chunk->nh.nlmsg_len);
+ chunk = (struct msg*)((uint8_t*)chunk + NLMSG_ALIGN(chunk->nh.nlmsg_len));
+ }
+
+ return in6addr_any;
+}
+
+void netif_foreach(netif_cb cb, void *arg) {
+ struct if_nameindex *ifaces = if_nameindex();
+
+ if (!ifaces) {
+ fprintf(stderr, "error: if_nameindex: %m\n");
+ return;
+ }
+
+ int i;
+ for (i = 0; ifaces[i].if_name; i++)
+ cb(ifaces[i].if_name, ifaces[i].if_index, arg);
+
+ if_freenameindex(ifaces);
+}
diff --git a/ffd/netif.h b/ffd/netif.h
new file mode 100644
index 0000000..f1ae2b7
--- /dev/null
+++ b/ffd/netif.h
@@ -0,0 +1,56 @@
+/*
+ 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_NETIF_H_
+#define _FFD_NETIF_H_
+
+#include "types.h"
+
+#include <netinet/in.h>
+
+
+typedef enum _netif_type_t {
+ IF_UNKNOWN = 0,
+ IF_WIRED,
+ IF_WIRELESS,
+ IF_VIRTUAL,
+ IF_BRIDGE,
+ IF_MESH,
+ IF_MAX
+} netif_type_t;
+
+typedef void (*netif_cb)(const char *ifname, unsigned ifindex, void *arg);
+
+
+bool netif_is_mesh(const char *ifname);
+char* netif_get_mesh(const char *ifname);
+char* netif_get_bridge(const char *ifname);
+eth_addr_t netif_get_eth_addr(const char *ifname);
+struct in6_addr netif_get_addr(unsigned ifindex, int scope);
+void netif_foreach(netif_cb cb, void *arg);
+
+
+#endif /* _FFD_NETIF_H_ */
diff --git a/ffd/types.h b/ffd/types.h
new file mode 100644
index 0000000..5eaaf46
--- /dev/null
+++ b/ffd/types.h
@@ -0,0 +1,44 @@
+/*
+ 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_TYPES_H_
+#define _FFD_TYPES_H_
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <net/ethernet.h>
+
+
+typedef struct __attribute__((__packed__)) _eth_addr_t {
+ uint8_t d[ETH_ALEN];
+} eth_addr_t;
+
+
+#define ETH_ADDR_UNSPEC ((eth_addr_t){{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}})
+
+
+#endif /* _FFD_TYPES_H_ */
diff --git a/ffd/util.c b/ffd/util.c
new file mode 100644
index 0000000..c8bb90b
--- /dev/null
+++ b/ffd/util.c
@@ -0,0 +1,42 @@
+/*
+ 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 "util.h"
+
+#include <stdio.h>
+
+
+bool file_readv(const char *file, const char *format, va_list ap) {
+ FILE *f = fopen(file, "r");
+ if (!f)
+ return false;
+
+ int ret = vfscanf(f, format, ap);
+
+ fclose(f);
+
+ return (ret > 0);
+}
diff --git a/ffd/util.h b/ffd/util.h
new file mode 100644
index 0000000..8020381
--- /dev/null
+++ b/ffd/util.h
@@ -0,0 +1,51 @@
+/*
+ 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_UTIL_H_
+#define _FFD_UTIL_H_
+
+#include "types.h"
+
+#include <stdarg.h>
+#include <time.h>
+
+
+bool file_readv(const char *file, const char *format, va_list ap);
+
+
+static inline bool are_eth_addrs_equal(const eth_addr_t *address1, const eth_addr_t *address2) {
+ const uint8_t *a = address1->d;
+ const uint8_t *b = address2->d;
+
+ return (a[0]==b[0] && a[1]==b[1] && a[2]==b[2] && a[3]==b[3] && a[4]==b[4] && a[5]==b[5]);
+}
+
+/* returns (tp1 - tp2) in milliseconds */
+static inline int timespec_diff(const struct timespec *tp1, const struct timespec *tp2) {
+ return ((tp1->tv_sec - tp2->tv_sec))*1000 + (tp1->tv_nsec - tp2->tv_nsec)/1e6;
+}
+
+#endif /* _FFD_UTIL_H_ */