Implement sending of neigh announcements
This commit is contained in:
parent
f22dc0880f
commit
b3b606e7f3
7 changed files with 234 additions and 21 deletions
114
ffd/ffd.c
114
ffd/ffd.c
|
@ -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;
|
||||||
|
|
13
ffd/ffd.h
13
ffd/ffd.h
|
@ -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_ */
|
||||||
|
|
24
ffd/netif.c
24
ffd/netif.c
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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
57
ffd/packet.h
Normal 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_ */
|
36
ffd/util.c
36
ffd/util.c
|
@ -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);
|
||||||
|
}
|
||||||
|
|
10
ffd/util.h
10
ffd/util.h
|
@ -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;
|
||||||
|
|
Reference in a new issue