From b3b606e7f3e2f8bab7c92e70e8d0e15bf06e3e3b Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Sun, 9 Sep 2012 04:15:05 +0200 Subject: Implement sending of neigh announcements --- ffd/ffd.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++--------- ffd/ffd.h | 13 ++++--- ffd/netif.c | 24 +++++++++++++ ffd/netif.h | 1 + ffd/packet.h | 57 ++++++++++++++++++++++++++++++ ffd/util.c | 36 +++++++++++++++++++ ffd/util.h | 10 ++++++ 7 files changed, 234 insertions(+), 21 deletions(-) create mode 100644 ffd/packet.h 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 #include @@ -36,6 +37,9 @@ #include +#include +#include + #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 + 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 +#include #include +#include + +#include 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 +#include #include 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; -- cgit v1.2.3