summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Schiffer <mschiffer@universe-factory.net>2012-09-09 04:15:05 +0200
committerMatthias Schiffer <mschiffer@universe-factory.net>2012-09-09 04:15:05 +0200
commitb3b606e7f3e2f8bab7c92e70e8d0e15bf06e3e3b (patch)
tree408de7c36f52f91b32963cd036d35d047848bf1c
parentf22dc0880f1b9348dc8c056cba0bbce223a39e62 (diff)
downloadffd-b3b606e7f3e2f8bab7c92e70e8d0e15bf06e3e3b.tar
ffd-b3b606e7f3e2f8bab7c92e70e8d0e15bf06e3e3b.zip
Implement sending of neigh announcements
-rw-r--r--ffd/ffd.c114
-rw-r--r--ffd/ffd.h13
-rw-r--r--ffd/netif.c24
-rw-r--r--ffd/netif.h1
-rw-r--r--ffd/packet.h57
-rw-r--r--ffd/util.c36
-rw-r--r--ffd/util.h10
7 files changed, 234 insertions, 21 deletions
diff --git a/ffd/ffd.c b/ffd/ffd.c
index d182ee0..ce71d4b 100644
--- a/ffd/ffd.c
+++ b/ffd/ffd.c
@@ -26,6 +26,7 @@
#include "ffd.h"
#include "netif.h"
+#include "packet.h"
#include <errno.h>
#include <poll.h>
@@ -36,6 +37,9 @@
#include <netpacket/packet.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+
#define FFD_PROTO 0xffd
#define FFD_VERSION 0
@@ -46,18 +50,27 @@ static const eth_addr_t ffd_addr = {{0x03, 0x00, 0x00, 0x00, 0x0f, 0xfd}};
static char *mesh = "bat0";
-static unsigned mtu = 1500;
+static unsigned mtu = 1528;
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 self;
+static ffd_orig_t own_data;
+/* neighs and origs that have been changed must be moved to front */
//static ffd_neigh_t *neigh_data = NULL;
static ffd_orig_t *orig_data = NULL;
+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 update_time() {
clock_gettime(CLOCK_MONOTONIC, &now);
}
@@ -71,6 +84,22 @@ static bool check_config() {
return true;
}
+static bool init_self() {
+ eth_addr_t primary_addr = netif_mesh_get_primary_addr(mesh);
+ if (is_eth_addr_unspec(&primary_addr))
+ return false;
+
+ memset(&self, 0, sizeof(self));
+ memset(&own_data, 0, sizeof(own_data));
+
+ self.addr = own_data.addr = primary_addr;
+
+ random_bytes(&self.rev, sizeof(self.rev));
+ random_bytes(&own_data.rev, sizeof(own_data.rev));
+
+ return true;
+}
+
static bool init_socket() {
sockfd = socket(AF_PACKET, SOCK_DGRAM, htons(FFD_PROTO));
if (sockfd < 0) {
@@ -81,14 +110,6 @@ static bool init_socket() {
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;
@@ -103,28 +124,89 @@ static void join_mcast(const char *ifname, unsigned ifindex, void *arg) {
fprintf(stderr, "warning: setsockopt: %m\n");
}
-static void send_announce() {
+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 send_announce(const char *ifname, unsigned ifindex, void *arg) {
+ if (!use_netif(ifname))
+ return;
+
+ ffd_packet_announce_t *announce = arg;
+
+ if (!send_eth(&ffd_addr, ifindex, announce, PACKET_ANNOUNCE_SIZE(announce->n_origs)))
+ fprintf(stderr, "send_eth: %m\n");
+}
+
+static void send_announces() {
if (!orig_data)
return;
+
+ ffd_packet_announce_t *announce = alloca(PACKET_ANNOUNCE_SIZE(PACKET_ANNOUNCE_MAX_ORIGS));
+
+ memset(announce, 0, PACKET_ANNOUNCE_SIZE(PACKET_ANNOUNCE_MAX_ORIGS));
+
+ announce->version = FFD_VERSION;
+ announce->type = PACKET_ANNOUNCE;
+ announce->self_rev = self.rev;
+
+ ffd_orig_t *orig;
+ for (orig = orig_data; orig && (announce->n_origs < PACKET_ANNOUNCE_MAX_ORIGS); orig = orig->next)
+ announce->origs[announce->n_origs++] = orig->rev;
+
+ netif_foreach(send_announce, announce);
}
static void receive_packet() {
uint8_t buf[mtu];
+ struct sockaddr_ll from;
+ socklen_t fromlen = sizeof(from);
- int readlen = read(sockfd, buf, sizeof(buf));
+ ssize_t readlen = recvfrom(sockfd, buf, sizeof(buf), 0, (struct sockaddr*)&from, &fromlen);
if (readlen < 0) {
- fprintf(stderr, "error: read: %m\n");
+ fprintf(stderr, "error: recvfrom: %m\n");
return;
}
- fprintf(stderr, "debug: read %i bytes.\n", readlen);
+ fprintf(stderr, "debug: read %zi bytes.\n", readlen);
}
int main() {
if (!check_config())
return 1;
+ if (!init_self())
+ return 1;
+
if (!init_socket())
return 1;
@@ -138,7 +220,7 @@ int main() {
int timeout = timespec_diff(&next_announce, &now);
if (timeout <= 0) {
- send_announce();
+ send_announces();
next_announce.tv_sec += ANNOUNCE_INTERVAL;
continue;
diff --git a/ffd/ffd.h b/ffd/ffd.h
index 3f9f81c..90fefb6 100644
--- a/ffd/ffd.h
+++ b/ffd/ffd.h
@@ -40,7 +40,8 @@ typedef enum _ffd_msg_type_t {
typedef struct _ffd_msg_head_t {
struct _ffd_msg_head_t *next;
- uint16_t changed_rev;
+ /* orig rev this message was added or removed last */
+ uint64_t changed_rev;
bool deleted;
ffd_msg_type_t type;
@@ -51,10 +52,13 @@ typedef struct _ffd_msg_head_t {
typedef struct _ffd_orig_t {
struct _ffd_orig_t *next;
- uint64_t id;
+ /* neigh rev this orig has changed last */
+ uint64_t changed_rev;
+ struct timespec changed_time;
+
+ uint64_t rev;
eth_addr_t addr;
uint16_t orig_interval;
- uint16_t rev;
ffd_msg_head_t *messages;
} ffd_orig_t;
@@ -62,9 +66,8 @@ typedef struct _ffd_orig_t {
typedef struct _ffd_neigh_t {
struct _ffd_neigh_t *next;
- uint64_t id;
+ uint64_t rev;
eth_addr_t addr;
- uint16_t rev;
} ffd_neigh_t;
#endif /* _FFD_FFD_H_ */
diff --git a/ffd/netif.c b/ffd/netif.c
index c63b19b..d521a12 100644
--- a/ffd/netif.c
+++ b/ffd/netif.c
@@ -43,6 +43,7 @@
#define SYSFS_PATH_MAX 256
#define SYSFS_CLASS_NET "/sys/class/net"
+#define SYSFS_BATADV "/sys/kernel/debug/batman_adv"
static bool netif_file_read(const char *ifname, const char *file, const char *format, ...) {
@@ -67,6 +68,19 @@ static bool netif_file_exists(const char *ifname, const char *file) {
return (stat(filename, &st) == 0);
}
+static bool batadv_file_read(const char *ifname, const char *file, const char *format, ...) {
+ char filename[SYSFS_PATH_MAX];
+
+ snprintf(filename, SYSFS_PATH_MAX, SYSFS_BATADV"/%s/%s", ifname, file);
+
+ va_list ap;
+ va_start(ap, format);
+ bool ret = file_readv(filename, format, ap);
+ va_end(ap);
+
+ return ret;
+}
+
bool netif_is_mesh(const char *ifname) {
return netif_file_exists(ifname, "mesh");
}
@@ -180,3 +194,13 @@ void netif_foreach(netif_cb cb, void *arg) {
if_freenameindex(ifaces);
}
+
+eth_addr_t netif_mesh_get_primary_addr(const char *ifname) {
+ eth_addr_t ret;
+ uint8_t *a = ret.d;
+
+ if (!batadv_file_read(ifname, "originators", "%*[^,], MainIF/MAC: %*[^/]/%x:%x:%x:%x:%x:%x", &a[0], &a[1], &a[2], &a[3], &a[4], &a[5]))
+ return ETH_ADDR_UNSPEC;
+
+ return ret;
+}
diff --git a/ffd/netif.h b/ffd/netif.h
index f1ae2b7..8dc5b94 100644
--- a/ffd/netif.h
+++ b/ffd/netif.h
@@ -52,5 +52,6 @@ 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);
+eth_addr_t netif_mesh_get_primary_addr(const char *ifname);
#endif /* _FFD_NETIF_H_ */
diff --git a/ffd/packet.h b/ffd/packet.h
new file mode 100644
index 0000000..9252c4e
--- /dev/null
+++ b/ffd/packet.h
@@ -0,0 +1,57 @@
+/*
+ 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_PACKET_H_
+#define _FFD_PACKET_H_
+
+#include "util.h"
+
+
+typedef enum _ffd_packet_type_t {
+ PACKET_UNSPEC = 0,
+ PACKET_ANNOUNCE,
+ PACKET_ORIG,
+} ffd_packet_type_t;
+
+typedef struct __attribute__((packed)) _ffd_packet_head_t {
+ uint8_t version;
+ uint8_t type;
+} ffd_packet_head_t;
+
+typedef struct __attribute__((packed)) _ffd_packet_announce_t {
+ uint8_t version;
+ uint8_t type;
+ uint64_t self_rev;
+ uint8_t flags;
+ uint8_t n_origs;
+ uint64_t origs[];
+} ffd_packet_announce_t;
+
+
+#define PACKET_ANNOUNCE_MAX_ORIGS 16
+#define PACKET_ANNOUNCE_SIZE(n_origs) (sizeof(ffd_packet_announce_t) + (n_origs)*sizeof(uint64_t))
+
+#endif /* _FFD_PACKET_H_ */
diff --git a/ffd/util.c b/ffd/util.c
index c8bb90b..5c3d6e6 100644
--- a/ffd/util.c
+++ b/ffd/util.c
@@ -24,9 +24,16 @@
*/
+#define _GNU_SOURCE
+
#include "util.h"
+#include <errno.h>
+#include <fcntl.h>
#include <stdio.h>
+#include <unistd.h>
+
+#include <sys/stat.h>
bool file_readv(const char *file, const char *format, va_list ap) {
@@ -40,3 +47,32 @@ bool file_readv(const char *file, const char *format, va_list ap) {
return (ret > 0);
}
+
+
+
+void random_bytes(void *buffer, size_t len) {
+ size_t read_bytes = 0;
+
+ int fd = open("/dev/urandom", O_RDONLY);
+
+ if (fd < 0) {
+ fprintf(stderr, "unable to open random device: %m\n");
+ exit(1);
+ }
+
+ while (read_bytes < len) {
+ ssize_t ret = read(fd, ((char*)buffer)+read_bytes, len-read_bytes);
+
+ if (ret < 0) {
+ if (errno == EINTR)
+ continue;
+
+ fprintf(stderr, "unable to read from random device: %m\n");
+ exit(1);
+ }
+
+ read_bytes += ret;
+ }
+
+ close(fd);
+}
diff --git a/ffd/util.h b/ffd/util.h
index 8020381..9fd6d66 100644
--- a/ffd/util.h
+++ b/ffd/util.h
@@ -30,11 +30,21 @@
#include "types.h"
#include <stdarg.h>
+#include <stdlib.h>
#include <time.h>
bool file_readv(const char *file, const char *format, va_list ap);
+void random_bytes(void *buffer, size_t len);
+static inline bool is_eth_addr_unspec(const eth_addr_t *address) {
+ const uint8_t *a = address->d;
+
+ if (a[0]||a[1]||a[2]||a[3]||a[4]||a[5])
+ return false;
+ else
+ return true;
+}
static inline bool are_eth_addrs_equal(const eth_addr_t *address1, const eth_addr_t *address2) {
const uint8_t *a = address1->d;