diff options
-rw-r--r-- | ffd/CMakeLists.txt | 2 | ||||
-rw-r--r-- | ffd/ffd.c | 169 | ||||
-rw-r--r-- | ffd/ffd.h | 20 | ||||
-rw-r--r-- | ffd/neigh.c | 78 | ||||
-rw-r--r-- | ffd/neigh.h | 50 | ||||
-rw-r--r-- | ffd/send.c | 121 |
6 files changed, 288 insertions, 152 deletions
diff --git a/ffd/CMakeLists.txt b/ffd/CMakeLists.txt index d04e69f..2a661a3 100644 --- a/ffd/CMakeLists.txt +++ b/ffd/CMakeLists.txt @@ -2,7 +2,9 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${FFD_BINARY_DIR} ${CMAKE_CURREN add_executable(ffd ffd.c + neigh.c netif.c + send.c tlv.c util.c ) @@ -25,6 +25,7 @@ #include "ffd.h" +#include "neigh.h" #include "netif.h" #include "packet.h" #include "tlv.h" @@ -40,24 +41,17 @@ #include <netpacket/packet.h> #include <sys/socket.h> -#include <sys/uio.h> -#define FFD_PROTO 0xffd - -static const eth_addr_t ffd_addr = {{0x03, 0x00, 0x00, 0x00, 0x0f, 0xfd}}; - -#define HELLO_INTERVAL 400 -#define IHU_INTERVAL (3*HELLO_INTERVAL) -#define PACKET_MAX 1000 +const eth_addr_t ffd_addr = {{0x03, 0x00, 0x00, 0x00, 0x0f, 0xfd}}; static char *mesh = "bat0"; -static int sockfd; -static struct timespec now; +int sockfd; +struct timespec now; -static ffd_iface_t *iface_list = NULL; +ffd_iface_t *iface_list = NULL; static ffd_neigh_t self; //static ffd_orig_t own_data; @@ -156,62 +150,6 @@ static void update_netif(const char *ifname, unsigned ifindex, void *arg) { iface->addr = netif_get_eth_addr(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 = calloc(1, sizeof(ffd_neigh_t)); - neigh->next = iface->neigh_list; - iface->neigh_list = neigh; - neigh->addr = *addr; - - neigh->txcost = 0xffff; - } - - return neigh; -} - -static void free_neighs(ffd_neigh_t *neigh) { - ffd_neigh_t *next; - for (; neigh; neigh = next) { - next = neigh->next; - free(neigh); - } -} - -static uint16_t get_neigh_rxcost(const ffd_neigh_t *neigh) { - int timediff = timespec_diff(&now, &neigh->last_hello)/10; - int shift = (timediff - neigh->hello_interval/2)/neigh->hello_interval; - int received = __builtin_popcount(neigh->hello_log << shift); - - if (received == 0) - return 0xffff; - else - return (0x1000/received); -} - -static uint16_t get_neigh_cost(const ffd_neigh_t *neigh) { - uint16_t txcost = neigh->txcost; - if (txcost < 256) - txcost = 256; - - uint32_t cost = (txcost * get_neigh_rxcost(neigh)) >> 8; - - if (cost > 0xffff) - return 0xffff; - else - return cost; -} - static void update_netifs() { ffd_iface_t *iface, **cur; @@ -227,7 +165,7 @@ static void update_netifs() { if (iface->type == IF_UNSPEC) { *cur = iface->next; - free_neighs(iface->neigh_list); + ffd_neigh_free_list(iface->neigh_list); free(iface); } else { @@ -236,82 +174,6 @@ static void update_netifs() { } } -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 add_ihus(ffd_packet_t *packet, size_t max_len, const ffd_iface_t *iface) { - const ffd_neigh_t *neigh; - - for (neigh = iface->neigh_list; neigh; neigh = neigh->next) { - ffd_tlv_ihu_t *ihu = ffd_tlv_add(packet, PACKET_MAX, TLV_IHU, sizeof(ffd_tlv_ihu_t)+sizeof(eth_addr_t)); - if (!ihu) - return; - - ihu->ae = ADDR_ENC_ETH; - ihu->reserved = 0; - ihu->rxcost = htons(get_neigh_rxcost(neigh)); - ihu->interval = htons(IHU_INTERVAL); - memcpy(ihu->address, &neigh->addr, sizeof(eth_addr_t)); - } -} - -static void send_hellos() { - ffd_packet_t *packet = alloca(sizeof(ffd_packet_t)+PACKET_MAX); - - packet->version_magic = htons(FFD_VERSION_MAGIC); - packet->len = 0; - - ffd_tlv_hello_t *hello = ffd_tlv_add(packet, PACKET_MAX, TLV_HELLO, sizeof(ffd_tlv_hello_t)); - if (!hello) - return; - - hello->reserved = 0; - hello->interval = htons(HELLO_INTERVAL); - - uint16_t len = packet->len; - - ffd_iface_t *iface; - for (iface = iface_list; iface; iface = iface->next) { - hello->seqno = htons(iface->seqno++); - - packet->len = len; - - add_ihus(packet, PACKET_MAX, iface); - - if (!send_eth(&ffd_addr, iface->ifindex, packet, sizeof(ffd_packet_t)+ntohs(packet->len))) - fprintf(stderr, "send_eth: %m\n"); - } -} - 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"); @@ -320,7 +182,7 @@ static void handle_tlv_hello(const ffd_tlv_hello_t *tlv_hello, size_t len, const fprintf(stderr, "debug: received hello with seqno %u.\n", ntohs(tlv_hello->seqno)); - ffd_neigh_t *neigh = get_neigh_create(iface, addr); + ffd_neigh_t *neigh = ffd_neigh_get(iface, addr); uint16_t seqno = ntohs(tlv_hello->seqno); @@ -352,7 +214,10 @@ static void handle_tlv_hello(const ffd_tlv_hello_t *tlv_hello, size_t len, const neigh->last_seqno = seqno; neigh->last_hello = now; - fprintf(stderr, "debug: accepted hello, log %04x, rxcost is %u, cost is %u now.\n", neigh->hello_log, get_neigh_rxcost(neigh), get_neigh_cost(neigh)); + if (neigh->hello_log == 1) /* new or reset neighbour */ + ffd_neigh_reset(iface, neigh); + + fprintf(stderr, "debug: accepted hello, log %04x, rxcost is %u, cost is %u now.\n", neigh->hello_log, ffd_neigh_get_rxcost(neigh), ffd_neigh_get_cost(neigh)); } static void handle_tlv_ihu(const ffd_tlv_ihu_t *tlv_ihu, size_t len, const eth_addr_t *addr, ffd_iface_t *iface) { @@ -374,11 +239,11 @@ static void handle_tlv_ihu(const ffd_tlv_ihu_t *tlv_ihu, size_t len, const eth_a return; } - ffd_neigh_t *neigh = get_neigh_create(iface, addr); + ffd_neigh_t *neigh = ffd_neigh_get(iface, addr); neigh->last_ihu = now; neigh->txcost = ntohs(tlv_ihu->rxcost); - fprintf(stderr, "debug: accepted IHU, txcost is %u, cost is %u now.\n", neigh->txcost, get_neigh_cost(neigh)); + fprintf(stderr, "debug: accepted IHU, txcost is %u, cost is %u now.\n", neigh->txcost, ffd_neigh_get_cost(neigh)); } static void handle_tlv(ffd_tlv_type_t type, const void *data, size_t len, void *arg) { @@ -405,11 +270,11 @@ static void handle_tlv(ffd_tlv_type_t type, const void *data, size_t len, void * } static void receive_packet() { - ffd_packet_t *packet = alloca(sizeof(ffd_packet_t)+PACKET_MAX); + ffd_packet_t *packet = alloca(sizeof(ffd_packet_t)+FFD_PACKET_MAX); struct sockaddr_ll from; socklen_t fromlen = sizeof(from); - ssize_t readlen = recvfrom(sockfd, packet, sizeof(ffd_packet_t)+PACKET_MAX, 0, (struct sockaddr*)&from, &fromlen); + ssize_t readlen = recvfrom(sockfd, packet, sizeof(ffd_packet_t)+FFD_PACKET_MAX, 0, (struct sockaddr*)&from, &fromlen); if (readlen < 0) { fprintf(stderr, "error: recvfrom: %m\n"); @@ -458,9 +323,9 @@ int main() { int timeout = timespec_diff(&next_hello, &now); if (timeout <= 0) { - send_hellos(); + ffd_send_hellos(); - add_interval(&next_hello, HELLO_INTERVAL); + add_interval(&next_hello, FFD_HELLO_INTERVAL); continue; } @@ -33,6 +33,14 @@ #include <net/if.h> +#define FFD_PACKET_MAX 1000 + +#define FFD_PROTO 0xffd + +#define FFD_HELLO_INTERVAL 400 +#define FFD_IHU_INTERVAL (3*FFD_HELLO_INTERVAL) + + typedef struct _ffd_announce_t { struct _ffd_announce_t *next; @@ -68,4 +76,16 @@ typedef struct _ffd_iface_t { ffd_neigh_t *neigh_list; } ffd_iface_t; + +extern const eth_addr_t ffd_addr; + +extern ffd_iface_t *iface_list; + +extern int sockfd; +extern struct timespec now; + + +void ffd_send_hellos(); +void ffd_send_announce_request(ffd_iface_t *iface, ffd_neigh_t *neigh, void *announce); + #endif /* _FFD_FFD_H_ */ diff --git a/ffd/neigh.c b/ffd/neigh.c new file mode 100644 index 0000000..6cfd5e8 --- /dev/null +++ b/ffd/neigh.c @@ -0,0 +1,78 @@ +/* + 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. +*/ + + +#include "neigh.h" + + +ffd_neigh_t* ffd_neigh_get(ffd_iface_t *iface, const eth_addr_t *addr) { + ffd_neigh_t *neigh = ffd_neigh_find(iface, addr); + if (!neigh) { + neigh = calloc(1, sizeof(ffd_neigh_t)); + neigh->next = iface->neigh_list; + iface->neigh_list = neigh; + neigh->addr = *addr; + + neigh->txcost = 0xffff; + } + + return neigh; +} + +void ffd_neigh_free_list(ffd_neigh_t *neigh) { + ffd_neigh_t *next; + for (; neigh; neigh = next) { + next = neigh->next; + free(neigh); + } +} + +uint16_t ffd_neigh_get_rxcost(const ffd_neigh_t *neigh) { + int timediff = timespec_diff(&now, &neigh->last_hello)/10; + int shift = (timediff - neigh->hello_interval/2)/neigh->hello_interval; + int received = __builtin_popcount(neigh->hello_log << shift); + + if (received == 0) + return 0xffff; + else + return (0x1000/received); +} + +uint16_t ffd_neigh_get_cost(const ffd_neigh_t *neigh) { + uint16_t txcost = neigh->txcost; + if (txcost < 256) + txcost = 256; + + uint32_t cost = (txcost * ffd_neigh_get_rxcost(neigh)) >> 8; + + if (cost > 0xffff) + return 0xffff; + else + return cost; +} + +void ffd_neigh_reset(ffd_iface_t *iface, ffd_neigh_t *neigh) { + ffd_send_announce_request(iface, neigh, NULL); +} diff --git a/ffd/neigh.h b/ffd/neigh.h new file mode 100644 index 0000000..6874dbe --- /dev/null +++ b/ffd/neigh.h @@ -0,0 +1,50 @@ +/* + 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_NEIGH_H_ +#define _FFD_NEIGH_H_ + +#include "ffd.h" + + +static inline ffd_neigh_t* ffd_neigh_find(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 NULL; +} + +ffd_neigh_t* ffd_neigh_get(ffd_iface_t *iface, const eth_addr_t *addr); +void ffd_neigh_free_list(ffd_neigh_t *neigh); + +uint16_t ffd_neigh_get_rxcost(const ffd_neigh_t *neigh); +uint16_t ffd_neigh_get_cost(const ffd_neigh_t *neigh); +void ffd_neigh_reset(ffd_iface_t *iface, ffd_neigh_t *neigh); + +#endif /* _FFD_NEIGH_H_ */ diff --git a/ffd/send.c b/ffd/send.c new file mode 100644 index 0000000..d020aca --- /dev/null +++ b/ffd/send.c @@ -0,0 +1,121 @@ +/* + 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. +*/ + + +#include "ffd.h" +#include "neigh.h" +#include "packet.h" +#include "tlv.h" +#include "tlv_types.h" + +#include <errno.h> +#include <stdio.h> +#include <string.h> + +#include <netpacket/packet.h> + +#include <sys/socket.h> +#include <sys/uio.h> + + +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 add_ihus(ffd_packet_t *packet, size_t max_len, const ffd_iface_t *iface) { + const ffd_neigh_t *neigh; + + for (neigh = iface->neigh_list; neigh; neigh = neigh->next) { + ffd_tlv_ihu_t *ihu = ffd_tlv_add(packet, FFD_PACKET_MAX, TLV_IHU, sizeof(ffd_tlv_ihu_t)+sizeof(eth_addr_t)); + if (!ihu) + return; + + ihu->ae = ADDR_ENC_ETH; + ihu->reserved = 0; + ihu->rxcost = htons(ffd_neigh_get_rxcost(neigh)); + ihu->interval = htons(FFD_IHU_INTERVAL); + memcpy(ihu->address, &neigh->addr, sizeof(eth_addr_t)); + } +} + +void ffd_send_hellos() { + ffd_packet_t *packet = alloca(sizeof(ffd_packet_t)+FFD_PACKET_MAX); + + packet->version_magic = htons(FFD_VERSION_MAGIC); + packet->len = 0; + + ffd_tlv_hello_t *hello = ffd_tlv_add(packet, FFD_PACKET_MAX, TLV_HELLO, sizeof(ffd_tlv_hello_t)); + if (!hello) + return; + + hello->reserved = 0; + hello->interval = htons(FFD_HELLO_INTERVAL); + + uint16_t len = packet->len; + + ffd_iface_t *iface; + for (iface = iface_list; iface; iface = iface->next) { + hello->seqno = htons(iface->seqno++); + + packet->len = len; + + add_ihus(packet, FFD_PACKET_MAX, iface); + + if (!send_eth(&ffd_addr, iface->ifindex, packet, sizeof(ffd_packet_t)+ntohs(packet->len))) + fprintf(stderr, "send_eth: %m\n"); + } +} + +void ffd_send_announce_request(ffd_iface_t *iface, ffd_neigh_t *neigh, void *announce) { + +} |