Implement sending of neigh announcements

This commit is contained in:
Matthias Schiffer 2012-09-09 04:15:05 +02:00
parent f22dc0880f
commit b3b606e7f3
7 changed files with 234 additions and 21 deletions

114
ffd/ffd.c
View file

@ -26,6 +26,7 @@
#include "ffd.h" #include "ffd.h"
#include "netif.h" #include "netif.h"
#include "packet.h"
#include <errno.h> #include <errno.h>
#include <poll.h> #include <poll.h>
@ -36,6 +37,9 @@
#include <netpacket/packet.h> #include <netpacket/packet.h>
#include <sys/socket.h>
#include <sys/uio.h>
#define FFD_PROTO 0xffd #define FFD_PROTO 0xffd
#define FFD_VERSION 0 #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 char *mesh = "bat0";
static unsigned mtu = 1500; static unsigned mtu = 1528;
static int sockfd; static int sockfd;
static struct timespec now; static struct timespec now;
//static ffd_neigh_t self = {NULL, ETH_ADDR_UNSPEC, 0}; static ffd_neigh_t self;
//static ffd_orig_t own_data = {NULL, ETH_ADDR_UNSPEC, 0, NULL}; 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_neigh_t *neigh_data = NULL;
static ffd_orig_t *orig_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() { static void update_time() {
clock_gettime(CLOCK_MONOTONIC, &now); clock_gettime(CLOCK_MONOTONIC, &now);
} }
@ -71,6 +84,22 @@ static bool check_config() {
return true; 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() { static bool init_socket() {
sockfd = socket(AF_PACKET, SOCK_DGRAM, htons(FFD_PROTO)); sockfd = socket(AF_PACKET, SOCK_DGRAM, htons(FFD_PROTO));
if (sockfd < 0) { if (sockfd < 0) {
@ -81,14 +110,6 @@ static bool init_socket() {
return true; 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) { static void join_mcast(const char *ifname, unsigned ifindex, void *arg) {
if (!use_netif(ifname)) if (!use_netif(ifname))
return; return;
@ -103,28 +124,89 @@ static void join_mcast(const char *ifname, unsigned ifindex, void *arg) {
fprintf(stderr, "warning: setsockopt: %m\n"); 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) if (!orig_data)
return; 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() { static void receive_packet() {
uint8_t buf[mtu]; 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) { if (readlen < 0) {
fprintf(stderr, "error: read: %m\n"); fprintf(stderr, "error: recvfrom: %m\n");
return; return;
} }
fprintf(stderr, "debug: read %i bytes.\n", readlen); fprintf(stderr, "debug: read %zi bytes.\n", readlen);
} }
int main() { int main() {
if (!check_config()) if (!check_config())
return 1; return 1;
if (!init_self())
return 1;
if (!init_socket()) if (!init_socket())
return 1; return 1;
@ -138,7 +220,7 @@ int main() {
int timeout = timespec_diff(&next_announce, &now); int timeout = timespec_diff(&next_announce, &now);
if (timeout <= 0) { if (timeout <= 0) {
send_announce(); send_announces();
next_announce.tv_sec += ANNOUNCE_INTERVAL; next_announce.tv_sec += ANNOUNCE_INTERVAL;
continue; continue;

View file

@ -40,7 +40,8 @@ typedef enum _ffd_msg_type_t {
typedef struct _ffd_msg_head_t { typedef struct _ffd_msg_head_t {
struct _ffd_msg_head_t *next; 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; bool deleted;
ffd_msg_type_t type; ffd_msg_type_t type;
@ -51,10 +52,13 @@ typedef struct _ffd_msg_head_t {
typedef struct _ffd_orig_t { typedef struct _ffd_orig_t {
struct _ffd_orig_t *next; 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; eth_addr_t addr;
uint16_t orig_interval; uint16_t orig_interval;
uint16_t rev;
ffd_msg_head_t *messages; ffd_msg_head_t *messages;
} ffd_orig_t; } ffd_orig_t;
@ -62,9 +66,8 @@ typedef struct _ffd_orig_t {
typedef struct _ffd_neigh_t { typedef struct _ffd_neigh_t {
struct _ffd_neigh_t *next; struct _ffd_neigh_t *next;
uint64_t id; uint64_t rev;
eth_addr_t addr; eth_addr_t addr;
uint16_t rev;
} ffd_neigh_t; } ffd_neigh_t;
#endif /* _FFD_FFD_H_ */ #endif /* _FFD_FFD_H_ */

View file

@ -43,6 +43,7 @@
#define SYSFS_PATH_MAX 256 #define SYSFS_PATH_MAX 256
#define SYSFS_CLASS_NET "/sys/class/net" #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, ...) { 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); 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) { bool netif_is_mesh(const char *ifname) {
return netif_file_exists(ifname, "mesh"); return netif_file_exists(ifname, "mesh");
} }
@ -180,3 +194,13 @@ void netif_foreach(netif_cb cb, void *arg) {
if_freenameindex(ifaces); 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;
}

View file

@ -52,5 +52,6 @@ eth_addr_t netif_get_eth_addr(const char *ifname);
struct in6_addr netif_get_addr(unsigned ifindex, int scope); struct in6_addr netif_get_addr(unsigned ifindex, int scope);
void netif_foreach(netif_cb cb, void *arg); void netif_foreach(netif_cb cb, void *arg);
eth_addr_t netif_mesh_get_primary_addr(const char *ifname);
#endif /* _FFD_NETIF_H_ */ #endif /* _FFD_NETIF_H_ */

57
ffd/packet.h Normal file
View file

@ -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_ */

View file

@ -24,9 +24,16 @@
*/ */
#define _GNU_SOURCE
#include "util.h" #include "util.h"
#include <errno.h>
#include <fcntl.h>
#include <stdio.h> #include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
bool file_readv(const char *file, const char *format, va_list ap) { 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); 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);
}

View file

@ -30,11 +30,21 @@
#include "types.h" #include "types.h"
#include <stdarg.h> #include <stdarg.h>
#include <stdlib.h>
#include <time.h> #include <time.h>
bool file_readv(const char *file, const char *format, va_list ap); 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) { 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 *a = address1->d;