Handle hello packets

This commit is contained in:
Matthias Schiffer 2012-09-28 18:56:06 +02:00
parent c5a1d00fc4
commit afffa65f90
3 changed files with 133 additions and 12 deletions

136
ffd/ffd.c
View file

@ -52,7 +52,6 @@ static const eth_addr_t ffd_addr = {{0x03, 0x00, 0x00, 0x00, 0x0f, 0xfd}};
static char *mesh = "bat0"; static char *mesh = "bat0";
static unsigned mtu = 1528;
static int sockfd; static int sockfd;
static struct timespec now; static struct timespec now;
@ -114,6 +113,16 @@ static bool init_socket() {
return true; return true;
} }
static inline ffd_iface_t* get_iface(unsigned ifindex) {
ffd_iface_t *iface;
for (iface = iface_list; iface; iface = iface->next) {
if (iface->ifindex == ifindex)
return iface;
}
return NULL;
}
static void update_netif(const char *ifname, unsigned ifindex, void *arg) { static void update_netif(const char *ifname, unsigned ifindex, void *arg) {
if (!use_netif(ifname)) if (!use_netif(ifname))
return; return;
@ -128,11 +137,7 @@ static void update_netif(const char *ifname, unsigned ifindex, void *arg) {
if (setsockopt(sockfd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mr, sizeof(mr)) && errno != EADDRINUSE) if (setsockopt(sockfd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mr, sizeof(mr)) && errno != EADDRINUSE)
fprintf(stderr, "warning: setsockopt: %m\n"); fprintf(stderr, "warning: setsockopt: %m\n");
ffd_iface_t *iface; ffd_iface_t *iface = get_iface(ifindex);
for (iface = iface_list; iface; iface = iface->next) {
if (iface->ifindex == ifindex)
break;
}
if (!iface) { if (!iface) {
/* new iface */ /* new iface */
@ -141,7 +146,7 @@ static void update_netif(const char *ifname, unsigned ifindex, void *arg) {
iface_list = iface; iface_list = iface;
iface->seqno = 0; iface->seqno = 0;
iface->neighs = NULL; iface->neigh_list = NULL;
} }
iface->ifindex = ifindex; iface->ifindex = ifindex;
@ -149,6 +154,41 @@ static void update_netif(const char *ifname, unsigned ifindex, void *arg) {
iface->type = netif_get_type(ifname); iface->type = netif_get_type(ifname);
} }
static inline ffd_neigh_t* get_neigh(const ffd_iface_t *iface, const eth_addr_t *addr) {
ffd_neigh_t *neigh;
for (neigh = iface->neigh_list; neigh; neigh = neigh->next) {
if (are_eth_addrs_equal(addr, &neigh->addr))
return neigh;
}
return neigh;
}
static ffd_neigh_t* get_neigh_create(ffd_iface_t *iface, const eth_addr_t *addr) {
ffd_neigh_t *neigh = get_neigh(iface, addr);
if (!neigh) {
neigh = malloc(sizeof(ffd_neigh_t));
neigh->next = iface->neigh_list;
iface->neigh_list = neigh;
neigh->addr = *addr;
neigh->hello_log = 0;
neigh->hello_interval = 0;
neigh->last_seqno = 0;
neigh->last_hello = (struct timespec){};
}
return neigh;
}
static void free_neighs(ffd_neigh_t *neigh) {
ffd_neigh_t *next;
for (; neigh; neigh = next) {
next = neigh->next;
free(neigh);
}
}
static void update_netifs() { static void update_netifs() {
ffd_iface_t *iface, **cur; ffd_iface_t *iface, **cur;
@ -163,6 +203,8 @@ static void update_netifs() {
if (iface->type == IF_UNSPEC) { if (iface->type == IF_UNSPEC) {
*cur = iface->next; *cur = iface->next;
free_neighs(iface->neigh_list);
free(iface); free(iface);
} }
else { else {
@ -226,19 +268,93 @@ static void send_hellos() {
} }
} }
static void handle_tlv_hello(const ffd_tlv_hello_t *tlv_hello, size_t len, const eth_addr_t *addr, ffd_iface_t *iface) {
if (len < sizeof(ffd_tlv_hello_t)) {
fprintf(stderr, "warn: received short hello TLV.\n");
return;
}
fprintf(stderr, "debug: received hello with seqno %u.\n", ntohs(tlv_hello->seqno));
ffd_neigh_t *neigh = get_neigh_create(iface, addr);
uint16_t seqno = ntohs(tlv_hello->seqno);
if (neigh->last_hello.tv_sec) {
int16_t seqdiff = seqno - neigh->last_seqno;
if (seqdiff <= 0) {
fprintf(stderr, "debug: seqno already seen, ignorin.\n");
return;
}
int timediff = timespec_diff(&now, &neigh->last_hello)/10;
uint16_t seqexp = neigh->last_seqno + (timediff - neigh->hello_interval/2)/neigh->hello_interval;
/* cast to int16_t to ensure correct handling of seqno wrapping */
if (abs((int16_t)(seqno - seqexp)) > 16) {
fprintf(stderr, "info: neighbor was reset.\n");
neigh->hello_log = 0;
}
else {
neigh->hello_log <<= seqdiff;
}
}
else {
fprintf(stderr, "info: received hello from new neighbor.\n");
}
neigh->hello_log |= 1;
neigh->hello_interval = ntohs(tlv_hello->interval);
neigh->last_seqno = seqno;
neigh->last_hello = now;
fprintf(stderr, "debug: accepted hello, log %04x.\n", neigh->hello_log);
}
static void handle_tlv(ffd_tlv_type_t type, const void *data, size_t len, void *arg) {
const struct sockaddr_ll *from = arg;
const eth_addr_t *addr = (const eth_addr_t*)from->sll_addr;
ffd_iface_t *iface = get_iface(from->sll_ifindex);
if (!iface)
return;
switch (type) {
case TLV_HELLO:
handle_tlv_hello(data, len, addr, iface);
return;
default:
fprintf(stderr, "debug: received unknown TLV %u on %s.\n", type, iface->name);
return;
}
}
static void receive_packet() { static void receive_packet() {
uint8_t buf[mtu]; ffd_packet_t *packet = alloca(sizeof(ffd_packet_t)+PACKET_MAX);
struct sockaddr_ll from; struct sockaddr_ll from;
socklen_t fromlen = sizeof(from); socklen_t fromlen = sizeof(from);
ssize_t readlen = recvfrom(sockfd, buf, sizeof(buf), 0, (struct sockaddr*)&from, &fromlen); ssize_t readlen = recvfrom(sockfd, packet, sizeof(ffd_packet_t)+PACKET_MAX, 0, (struct sockaddr*)&from, &fromlen);
if (readlen < 0) { if (readlen < 0) {
fprintf(stderr, "error: recvfrom: %m\n"); fprintf(stderr, "error: recvfrom: %m\n");
return; return;
} }
fprintf(stderr, "debug: read %zi bytes.\n", readlen); if (from.sll_halen != ETH_ALEN) {
fprintf(stderr, "error: receive_packet: strange address length\n");
return;
}
if (readlen < sizeof(ffd_packet_t) || readlen < sizeof(ffd_packet_t)+ntohs(packet->len)) {
fprintf(stderr, "debug: received short packet.\n");
return;
}
if (!ffd_tlv_parse(packet, handle_tlv, &from)) {
fprintf(stderr, "debug: received invalid packet.\n");
}
} }
int main() { int main() {

View file

@ -45,6 +45,11 @@ typedef struct _ffd_neigh_t {
struct _ffd_neigh_t *next; struct _ffd_neigh_t *next;
eth_addr_t addr; eth_addr_t addr;
uint16_t hello_log;
uint16_t hello_interval;
uint16_t last_seqno;
struct timespec last_hello;
} ffd_neigh_t; } ffd_neigh_t;
typedef struct _ffd_iface_t { typedef struct _ffd_iface_t {
@ -56,7 +61,7 @@ typedef struct _ffd_iface_t {
netif_type_t type; netif_type_t type;
uint16_t seqno; uint16_t seqno;
ffd_neigh_t *neighs; ffd_neigh_t *neigh_list;
} ffd_iface_t; } ffd_iface_t;
#endif /* _FFD_FFD_H_ */ #endif /* _FFD_FFD_H_ */

View file

@ -36,7 +36,7 @@ bool ffd_tlv_parse(const ffd_packet_t *packet, ffd_tlv_cb cb, void *arg) {
if (packet->version_magic != htons(FFD_VERSION_MAGIC)) if (packet->version_magic != htons(FFD_VERSION_MAGIC))
return false; return false;
const uint8_t *data = packet->tlv + 2, *end = packet->tlv + packet->len; const uint8_t *data = packet->tlv + 2, *end = packet->tlv + ntohs(packet->len);
while (data <= end) { while (data <= end) {
if (data[-2] == TLV_PAD1) { if (data[-2] == TLV_PAD1) {