pax_global_header00006660000000000000000000000064143541021060014506gustar00rootroot0000000000000052 comment=2f62b17d4132f82c4716b672101eb7faa916192a batmand-0.3.2+74+g2f62b17/000077500000000000000000000000001435410210600145005ustar00rootroot00000000000000batmand-0.3.2+74+g2f62b17/CHANGELOG000066400000000000000000000001241435410210600157070ustar00rootroot00000000000000For a reasonable up-to-date CHANGELOG visit: https://git.open-mesh.org/batmand.git batmand-0.3.2+74+g2f62b17/INSTALL000066400000000000000000000042161435410210600155340ustar00rootroot00000000000000 ################################### B.A.T.M.A.N. Installation and Usage ################################### Compiling from source ===================== Pre-requirements --------------- You need the usual compile environment and the libpthread-library and the kernel module "tun". Both should already be installed on your machine, if you use a PC with Linux. On embedded devices both may not be installed in order to save space. GNU Make is needed for compilation. The ports to *BSD and Mac OS operating systems are currently not available. If you're interested in porting and maintaining B.A.T.M.A.N. for these systems, please contact us. We would appreciate your help. Tweaking -------- You can tweak the program requirements by editing the Makefile. Getting rid of the policy-routing requirement in the Linux kernel: By default batmand requires policy-routing to be enabled in the Linux kernel. On many embedded devices this can be an obstacle if you want to get batmand running, because it requires to install a different kernel. Remove the comment hash (#) leading this line in the Makefile: #NO_POLICY_ROUTING = -DNO_POLICY_ROUTING Compiling --------- You don't necessarily need to compile. May be your distribution or our download store offers precompiled packages. Check https://www.open-mesh.org/projects/open-mesh/wiki/Download to get an overview. Download and compile the latest stable sources from the download section https://www.open-mesh.org/projects/open-mesh/wiki/Download by executing eg.: $ wget https://downloads.open-mesh.org/batman/stable/sources/batmand/batmand-0.3.2.tar.gz $ tar xzvf batmand-0.3.2.tar.gz $ cd batman-0.3.2 $ make After the compilation process is finished you'll find a executable file called 'batmand'. This executable is quite big because it is not stripped. Don't strip it if you want to help us finding a bug in the daemon. Strip it by executing: $ strip batmand Install by executing (as root): $ make install Or start it right from the directory where you compiled it by issuing: ./batmand See the README file for "getting started" instructions or consult the manpage to get an overview about the command line options. batmand-0.3.2+74+g2f62b17/Makefile000077500000000000000000000052221435410210600161440ustar00rootroot00000000000000#!/usr/bin/make -f # -*- makefile -*- # # Copyright (C) 2006-2012 B.A.T.M.A.N. contributors # # This program is free software; you can redistribute it and/or # modify it under the terms of version 2 of the GNU General Public # License as published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA # # batmand build BINARY_NAME = batmand UNAME = $(shell uname) POSIX_OBJ = posix/init.o posix/posix.o posix/tunnel.o posix/unix_socket.o LINUX_OBJ = linux/route.o linux/tun.o linux/kernel.o ifeq ($(UNAME),Linux) OS_OBJ = $(LINUX_OBJ) $(POSIX_OBJ) CPPFLAGS += -D_GNU_SOURCE endif OBJ = batman.o originator.o schedule.o list-batman.o allocate.o bitarray.o hash.o profile.o ring_buffer.o hna.o $(OS_OBJ) MANPAGE = man/batmand.8 # activate this variable to deactivate policy routing for backward compatibility #NO_POLICY_ROUTING = -DNO_POLICY_ROUTING # batmand flags and options CFLAGS += -pedantic -Wall -W -std=gnu99 -MD -MP -fno-strict-aliasing CPPFLAGS += -DDEBUG_MALLOC -DMEMORY_USAGE -DPROFILE_DATA $(NO_POLICY_ROUTING) LDLIBS += -lpthread # disable verbose output ifneq ($(findstring $(MAKEFLAGS),s),s) ifndef V Q_CC = @echo ' ' CC $@; Q_LD = @echo ' ' LD $@; export Q_CC export Q_LD endif endif # standard build tools CC ?= gcc RM ?= rm -f INSTALL ?= install MKDIR ?= mkdir -p COMPILE.c = $(Q_CC)$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c LINK.o = $(Q_LD)$(CC) $(CFLAGS) $(LDFLAGS) $(TARGET_ARCH) # standard install paths PREFIX = /usr/local SBINDIR = $(PREFIX)/sbin MANDIR = $(PREFIX)/share/man # try to generate revision REVISION= $(shell if [ -d .git ]; then \ echo $$(git describe --always --dirty --match "v*" |sed 's/^v//' 2> /dev/null || echo "[unknown]"); \ fi) ifneq ($(REVISION),) CPPFLAGS += -DSOURCE_VERSION=\"$(REVISION)\" endif # default target all: $(BINARY_NAME) # standard build rules .SUFFIXES: .o .c .c.o: $(COMPILE.c) -o $@ $< $(BINARY_NAME): $(OBJ) $(LINK.o) $^ $(LDLIBS) -o $@ clean: $(RM) $(BINARY_NAME) $(OBJ) $(DEP) install: $(BINARY_NAME) $(MKDIR) $(DESTDIR)$(SBINDIR) $(MKDIR) $(DESTDIR)$(MANDIR)/man8 $(INSTALL) -m 0755 $(BINARY_NAME) $(DESTDIR)$(SBINDIR) $(INSTALL) -m 0644 $(MANPAGE) $(DESTDIR)$(MANDIR)/man8 # load dependencies DEP = $(OBJ:.o=.d) -include $(DEP) .PHONY: all clean install batmand-0.3.2+74+g2f62b17/README000066400000000000000000000056071435410210600153700ustar00rootroot00000000000000 Getting started with the batman daemon ====================================== Make sure you have no firewall running that is blocking UDP port 4305 (originator messages), port 4306 (gateway traffic). Port 4307 has to be open for incoming UDP traffic if you run the B.A.T.M.A.N. visualization server. First the network interfaces supposed to participate in the batman mesh must be configured properly. You either run it on top of any "normal" network interface (WiFi, Ethernet, etc) or on an alias interface. In normal scenarios the alias interface is not needed unless you want to test / verify / benchmark B.A.T.M.A.N. Alias interface example: Assuming you have an already configured interface eth1 with the IP address of 104.1.12.123/8 and want to run batman in parallel on the same physical interface but with a 105.1.12.123/8 IP/netmask. $ ifconfig eth1:bat 105.1.12.123 netmask 255.0.0.0 broadcast 105.255.255.255 $ batmand -d 3 eth1:bat This will configure an alias interface on top of eth1 named eth1:bat and start the batman daemon with debug level 3 on that alias interface. As soon as another running batmand (with the same netmask and broadcast address) is connected to that link (or within the range of the wireless link) both batman daemons should see each other and indicate this in the debug output. The daemon started with debug level 3 can be terminated with ctrl-c. If no debuglevel is given at startup, using $ batmand eth1:bat the daemon will immediateley fork to the background (as is the usual behavior of a daemon). However you can always connect to the main daemon (running in background) by launching a client-batmand process with the -c and -d option, where the number represents the desired debug-level. The following command will connect to a running batmand process providing debug-level 1 informations. $ batmand -c -d 1 # shows a list of other nodes in the mesh $ batmand -c -d 2 # shows a list of nodes offering internet GW access $ route -n # shows your current routing table as modified by batmand For a full list of supported debug-levels and other startup options see $ batmand -h # providing a brief summary of options and $ batmand -H # for a more detailed list of options Use ctrl-c to terminate a process running in foreground and $ killall batmand to terminate the main batmand daemon running in background. If you want to use one of the batman-internet gateways showed with debug-level 2 launch the main batmand using: $ batmand -r 3 eth1:bat # to automatically select a reasonable GW $ batmand -r 3 -p eth1:bat # to set a preferred GW In case of success this will setup a tunnel to a (preferred) batman-gw-node and configure the routing table that all packets matching the default route are forwarded (tunneled) respectively. More information is available using the -h and -H options and in the manpage. Happy routing! The B.A.T.M.A.N. contributors batmand-0.3.2+74+g2f62b17/THANKS000066400000000000000000000010641435410210600154140ustar00rootroot00000000000000We would like to thank all people that donated their time and skills to the B.A.T.M.A.N. mesh routing protocol! Marek Lindner (lindner_marek-at-yahoo.de) Stefan Sperling (stsp-at-stsp.in-berlin.de Axel Neumann (axel-at-open-mesh.net) Corinna 'Elektra' Aichele (onelektra-at-gmx.net) Thomas Lopatic (thomas-at-lopatic.de) Felix Fietkau (nbd-at-nbd.name) Ludger Schmudde (lui-at-schmudde.com) Simon Wunderlich (sw-at-simonwunderlich.de) Andreas Langer (an.langer-at-gmx.de) Sven Eckelmann (sven.eckelmann-at-gmx.de) Antoine van Gelder (antoine-at-7degrees.co.za) batmand-0.3.2+74+g2f62b17/allocate.c000066400000000000000000000257111435410210600164360ustar00rootroot00000000000000/* * Copyright (C) 2006-2012 B.A.T.M.A.N. contributors: * * Thomas Lopatic, Corinna 'Elektra' Aichele, Axel Neumann, Marek Lindner * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public * License as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA * */ #include #include #include "os.h" #include "allocate.h" #define MAGIC_NUMBER 0x12345678 #if defined DEBUG_MALLOC #ifndef MEMORY_USAGE #error DEBUG_MALLOC can only be used together with MEMORY_USAGE #endif static pthread_mutex_t chunk_mutex = PTHREAD_MUTEX_INITIALIZER; struct chunkHeader *chunkList = NULL; struct chunkHeader { struct chunkHeader *next; uint32_t length; int32_t tag; uint32_t magicNumber; }; struct chunkTrailer { uint32_t magicNumber; }; #if defined MEMORY_USAGE struct memoryUsage *memoryList = NULL; static pthread_mutex_t memory_mutex = PTHREAD_MUTEX_INITIALIZER; struct memoryUsage { struct memoryUsage *next; uint32_t length; uint32_t counter; int32_t tag; }; static size_t getHeaderPad(void) { size_t alignwith, pad; if (sizeof(TYPE_OF_WORD) > sizeof(void*)) alignwith = sizeof(TYPE_OF_WORD); else alignwith = sizeof(void*); pad = alignwith - (sizeof(struct chunkHeader) % alignwith); if (pad == alignwith) return 0; else return pad; } static size_t getTrailerPad(size_t length) { size_t alignwith, pad; if (sizeof(TYPE_OF_WORD) > sizeof(void*)) alignwith = sizeof(TYPE_OF_WORD); else alignwith = sizeof(void*); pad = alignwith - (length % alignwith); if (pad == alignwith) return 0; else return pad; } static void fillPadding(unsigned char* padding, size_t length) { unsigned char c = 0x00; size_t i; for (i = 0; i < length; i++) { c += 0xA7; padding[i] = c; } } static int checkPadding(unsigned char* padding, size_t length) { unsigned char c = 0x00; size_t i; for (i = 0; i < length; i++) { c += 0xA7; if (padding[i] != c) return 0; } return 1; } static void addMemory( uint32_t length, int32_t tag ) { struct memoryUsage *walker; pthread_mutex_lock(&memory_mutex); for ( walker = memoryList; walker != NULL; walker = walker->next ) { if ( walker->tag == tag ) { walker->counter++; break; } } if ( walker == NULL ) { walker = malloc( sizeof(struct memoryUsage) ); walker->length = length; walker->tag = tag; walker->counter = 1; walker->next = memoryList; memoryList = walker; } pthread_mutex_unlock(&memory_mutex); } static void removeMemory( int32_t tag, int32_t freetag ) { struct memoryUsage *walker; pthread_mutex_lock(&memory_mutex); for ( walker = memoryList; walker != NULL; walker = walker->next ) { if ( walker->tag == tag ) { if ( walker->counter == 0 ) { debug_output( 0, "Freeing more memory than was allocated: malloc tag = %d, free tag = %d\n", tag, freetag ); pthread_mutex_unlock(&memory_mutex); restore_and_exit(0); } walker->counter--; break; } } if ( walker == NULL ) { debug_output( 0, "Freeing memory that was never allocated: malloc tag = %d, free tag = %d\n", tag, freetag ); pthread_mutex_unlock(&memory_mutex); restore_and_exit(0); } pthread_mutex_unlock(&memory_mutex); } #endif void checkIntegrity(void) { struct chunkHeader *walker; struct chunkTrailer *chunkTrailer; unsigned char *memory; #if defined MEMORY_USAGE struct memoryUsage *memoryWalker; debug_output( 5, " \nMemory usage information:\n" ); pthread_mutex_lock(&memory_mutex); for ( memoryWalker = memoryList; memoryWalker != NULL; memoryWalker = memoryWalker->next ) { if ( memoryWalker->counter != 0 ) debug_output( 5, " tag: %4i, num malloc: %4i, bytes per malloc: %4i, total: %6i\n", memoryWalker->tag, memoryWalker->counter, memoryWalker->length, memoryWalker->counter * memoryWalker->length ); } pthread_mutex_unlock(&memory_mutex); #endif pthread_mutex_lock(&chunk_mutex); for (walker = chunkList; walker != NULL; walker = walker->next) { if (walker->magicNumber != MAGIC_NUMBER) { debug_output( 0, "checkIntegrity - invalid magic number in header: %08x, malloc tag = %d\n", walker->magicNumber, walker->tag ); pthread_mutex_unlock(&chunk_mutex); restore_and_exit(0); } memory = (unsigned char *)walker; chunkTrailer = (struct chunkTrailer *)(memory + sizeof(struct chunkHeader) + getHeaderPad() + walker->length + getTrailerPad(walker->length)); if (chunkTrailer->magicNumber != MAGIC_NUMBER) { debug_output( 0, "checkIntegrity - invalid magic number in trailer: %08x, malloc tag = %d\n", chunkTrailer->magicNumber, walker->tag ); pthread_mutex_unlock(&chunk_mutex); restore_and_exit(0); } } pthread_mutex_unlock(&chunk_mutex); } void checkLeak(void) { struct chunkHeader *walker; pthread_mutex_lock(&chunk_mutex); for (walker = chunkList; walker != NULL; walker = walker->next) debug_output( 0, "Memory leak detected, malloc tag = %d\n", walker->tag ); pthread_mutex_unlock(&chunk_mutex); } void *debugMalloc(uint32_t length, int32_t tag) { unsigned char *memory; struct chunkHeader *chunkHeader; struct chunkTrailer *chunkTrailer; unsigned char *chunk; /* printf("sizeof(struct chunkHeader) = %u, sizeof (struct chunkTrailer) = %u\n", sizeof (struct chunkHeader), sizeof (struct chunkTrailer)); */ memory = malloc(length + sizeof(struct chunkHeader) + sizeof(struct chunkTrailer) + getHeaderPad() + getTrailerPad(length)); if (memory == NULL) { debug_output( 0, "Cannot allocate %u bytes, malloc tag = %d\n", (unsigned int)(length + sizeof(struct chunkHeader) + sizeof(struct chunkTrailer)), tag ); restore_and_exit(0); } chunkHeader = (struct chunkHeader *)memory; chunk = memory + sizeof(struct chunkHeader) + getHeaderPad(); chunkTrailer = (struct chunkTrailer *)(memory + sizeof(struct chunkHeader) + length + getHeaderPad() + getTrailerPad(length)); fillPadding((unsigned char*)chunkHeader + sizeof(struct chunkHeader), getHeaderPad()); fillPadding(chunk + length, getTrailerPad(length)); chunkHeader->length = length; chunkHeader->tag = tag; chunkHeader->magicNumber = MAGIC_NUMBER; chunkTrailer->magicNumber = MAGIC_NUMBER; pthread_mutex_lock(&chunk_mutex); chunkHeader->next = chunkList; chunkList = chunkHeader; pthread_mutex_unlock(&chunk_mutex); #if defined MEMORY_USAGE addMemory( length, tag ); #endif return chunk; } void *debugRealloc(void *memoryParameter, uint32_t length, int32_t tag) { unsigned char *memory; struct chunkHeader *chunkHeader=NULL; struct chunkTrailer *chunkTrailer; unsigned char *result; uint32_t copyLength; if (memoryParameter) { /* if memoryParameter==NULL, realloc() should work like malloc() !! */ memory = memoryParameter; chunkHeader = (struct chunkHeader *)(memory - sizeof(struct chunkHeader) - getHeaderPad()); if (chunkHeader->magicNumber != MAGIC_NUMBER) { debug_output( 0, "debugRealloc - invalid magic number in header: %08x, malloc tag = %d\n", chunkHeader->magicNumber, chunkHeader->tag ); restore_and_exit(0); } if (checkPadding(memory - getHeaderPad(), getHeaderPad()) == 0) { debug_output( 0, "debugRealloc - invalid magic padding in header, malloc tag = %d\n", chunkHeader->tag ); restore_and_exit(0); } chunkTrailer = (struct chunkTrailer *)(memory + chunkHeader->length + getTrailerPad(chunkHeader->length)); if (chunkTrailer->magicNumber != MAGIC_NUMBER) { debug_output( 0, "debugRealloc - invalid magic number in trailer: %08x, malloc tag = %d\n", chunkTrailer->magicNumber, chunkHeader->tag ); restore_and_exit(0); } if (checkPadding(memory + chunkHeader->length, getTrailerPad(chunkHeader->length)) == 0) { debug_output( 0, "debugRealloc - invalid magic padding in trailer, malloc tag = %d\n", chunkHeader->tag ); restore_and_exit(0); } } result = debugMalloc(length, tag); if (memoryParameter) { copyLength = length; if (copyLength > chunkHeader->length) copyLength = chunkHeader->length; memcpy(result, memoryParameter, copyLength); debugFree(memoryParameter, 9999); } return result; } void debugFree(void *memoryParameter, int tag) { unsigned char *memory; struct chunkHeader *chunkHeader; struct chunkTrailer *chunkTrailer; struct chunkHeader *walker; struct chunkHeader *previous; memory = memoryParameter; chunkHeader = (struct chunkHeader *)(memory - sizeof(struct chunkHeader) - getHeaderPad()); if (chunkHeader->magicNumber != MAGIC_NUMBER) { debug_output( 0, "debugFree - invalid magic number in header: %08x, malloc tag = %d, free tag = %d\n", chunkHeader->magicNumber, chunkHeader->tag, tag ); restore_and_exit(0); } if (checkPadding(memory - getHeaderPad(), getHeaderPad()) == 0) { debug_output( 0, "debugFree - invalid magic padding in header, malloc tag = %d\n", chunkHeader->tag ); restore_and_exit(0); } previous = NULL; pthread_mutex_lock(&chunk_mutex); for (walker = chunkList; walker != NULL; walker = walker->next) { if (walker == chunkHeader) break; previous = walker; } if (walker == NULL) { debug_output( 0, "Double free detected, malloc tag = %d, free tag = %d\n", chunkHeader->tag, tag ); pthread_mutex_unlock(&chunk_mutex); restore_and_exit(0); } if (previous == NULL) chunkList = walker->next; else previous->next = walker->next; pthread_mutex_unlock(&chunk_mutex); chunkTrailer = (struct chunkTrailer *)(memory + chunkHeader->length + getTrailerPad(chunkHeader->length)); if (chunkTrailer->magicNumber != MAGIC_NUMBER) { debug_output( 0, "debugFree - invalid magic number in trailer: %08x, malloc tag = %d, free tag = %d\n", chunkTrailer->magicNumber, chunkHeader->tag, tag ); restore_and_exit(0); } if (checkPadding(memory + chunkHeader->length, getTrailerPad(chunkHeader->length)) == 0) { debug_output( 0, "debugFree - invalid magic padding in trailer, malloc tag = %d\n", chunkHeader->tag ); restore_and_exit(0); } #if defined MEMORY_USAGE removeMemory( chunkHeader->tag, tag ); #endif free(chunkHeader); } #else #include "batman.h" void checkIntegrity(void) { } void checkLeak(void) { } void *debugMalloc(uint32_t length, int32_t tag) { void *result; result = malloc(length); if (result == NULL) { debug_output( 0, "Cannot allocate %u bytes, malloc tag = %d\n", length, tag ); restore_and_exit(0); } return result; } void *debugRealloc(void *memory, uint32_t length, int32_t tag) { void *result; result = realloc(memory, length); if (result == NULL) { debug_output( 0, "Cannot re-allocate %u bytes, malloc tag = %d\n", length, tag ); restore_and_exit(0); } return result; } void debugFree(void *memory, int32_t BATMANUNUSED(tag)) { free(memory); } #endif batmand-0.3.2+74+g2f62b17/allocate.h000066400000000000000000000021201435410210600164300ustar00rootroot00000000000000/* * Copyright (C) 2006-2012 B.A.T.M.A.N. contributors: * * Thomas Lopatic, Corinna 'Elektra' Aichele, Axel Neumann, Marek Lindner * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public * License as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA * */ #ifndef _BATMAND_ALLOCATE_H #define _BATMAND_ALLOCATE_H #include void checkIntegrity(void); void checkLeak(void); void *debugMalloc(uint32_t length, int32_t tag); void *debugRealloc(void *memory, uint32_t length, int32_t tag); void debugFree(void *memoryParameter, int32_t tag); #endif batmand-0.3.2+74+g2f62b17/batman.c000066400000000000000000001022171435410210600161110ustar00rootroot00000000000000/* * Copyright (C) 2006-2012 B.A.T.M.A.N. contributors: * * Thomas Lopatic, Corinna 'Elektra' Aichele, Axel Neumann, * Felix Fietkau, Marek Lindner * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public * License as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA * */ #include #include #include #include #include "os.h" #include "batman.h" #include "originator.h" #include "schedule.h" #include "hna.h" #include "types.h" #include "profile.h" #include "allocate.h" #include "hash.h" #include "bitarray.h" #include "packet.h" uint8_t debug_level = 0; #ifdef PROFILE_DATA uint8_t debug_level_max = 5; #elif defined DEBUG_MALLOC && defined MEMORY_USAGE uint8_t debug_level_max = 5; #else uint8_t debug_level_max = 4; #endif char *prog_name; /* * "-g" is the command line switch for the gateway class, */ uint8_t gateway_class = 0; /* "-r" is the command line switch for the routing class, * 0 set no default route * 1 use fast internet connection * 2 use stable internet connection * 3 use use best statistic (olsr style) * this option is used to set the routing behaviour */ uint8_t routing_class = 0; int16_t originator_interval = 1000; /* originator message interval in miliseconds */ struct gw_node *curr_gateway = NULL; pthread_t curr_gateway_thread_id = 0; uint32_t pref_gateway = 0; char *policy_routing_script = NULL; int policy_routing_pipe = 0; pid_t policy_routing_script_pid; uint8_t found_ifs = 0; uint8_t active_ifs = 0; int32_t receive_max_sock = 0; fd_set receive_wait_set; uint8_t unix_client = 0; uint8_t log_facility_active = 0; struct hashtable_t *orig_hash; struct list_head_first forw_list; struct list_head_first gw_list; struct list_head_first if_list; struct vis_if vis_if; struct unix_if unix_if; struct debug_clients debug_clients; unsigned char *vis_packet = NULL; uint16_t vis_packet_size = 0; uint64_t batman_clock_ticks = 0; uint8_t hop_penalty = TQ_HOP_PENALTY; uint32_t purge_timeout = PURGE_TIMEOUT; uint8_t minimum_send = TQ_LOCAL_BIDRECT_SEND_MINIMUM; uint8_t minimum_recv = TQ_LOCAL_BIDRECT_RECV_MINIMUM; uint8_t global_win_size = TQ_GLOBAL_WINDOW_SIZE; uint8_t local_win_size = TQ_LOCAL_WINDOW_SIZE; uint8_t num_words = (TQ_LOCAL_WINDOW_SIZE / WORD_BIT_SIZE); uint8_t aggregation_enabled = 1; int nat_tool_avail = -1; int8_t disable_client_nat = 0; void usage(void) { fprintf( stderr, "Usage: batman [options] interface [interface interface]\n" ); fprintf( stderr, " -a add announced network(s)\n" ); fprintf( stderr, " -A delete announced network(s)\n" ); fprintf( stderr, " -b run connection in batch mode\n" ); fprintf( stderr, " -c connect via unix socket\n" ); fprintf( stderr, " -d debug level\n" ); fprintf( stderr, " -g gateway class\n" ); fprintf( stderr, " -h this help\n" ); fprintf( stderr, " -H verbose help\n" ); fprintf( stderr, " -i internal options output\n" ); fprintf( stderr, " -o originator interval in ms\n" ); fprintf( stderr, " -p preferred gateway\n" ); fprintf( stderr, " -r routing class\n" ); fprintf( stderr, " -s visualization server\n" ); fprintf( stderr, " -v print version\n" ); fprintf( stderr, " --policy-routing-script\n" ); fprintf( stderr, " --disable-client-nat\n" ); fprintf( stderr, " --no-detach\n" ); } void verbose_usage(void) { fprintf( stderr, "Usage: batman [options] interface [interface interface]\n\n" ); fprintf( stderr, " -a add announced network(s)\n" ); fprintf( stderr, " network/netmask is expected\n" ); fprintf( stderr, " -A delete announced network(s)\n" ); fprintf( stderr, " network/netmask is expected\n" ); fprintf( stderr, " -b run connection in batch mode\n" ); fprintf( stderr, " -c connect to running batmand via unix socket\n" ); fprintf( stderr, " -d debug level\n" ); fprintf( stderr, " default: 0 -> debug disabled\n" ); fprintf( stderr, " allowed values: 1 -> list neighbours\n" ); fprintf( stderr, " 2 -> list gateways\n" ); fprintf( stderr, " 3 -> observe batman\n" ); fprintf( stderr, " 4 -> observe batman (very verbose)\n\n" ); if ( debug_level_max == 5 ) fprintf( stderr, " 5 -> memory debug / cpu usage\n\n" ); fprintf( stderr, " -g gateway class\n" ); fprintf( stderr, " default: 0 -> gateway disabled\n" ); fprintf( stderr, " allowed values: download/upload in kbit/s (default) or mbit/s\n" ); fprintf( stderr, " note: batmand will choose the nearest gateway class representing your speeds\n" ); fprintf( stderr, " and therefore accepts all given values\n" ); fprintf( stderr, " e.g. 5000\n" ); fprintf( stderr, " 5000kbit\n" ); fprintf( stderr, " 5mbit\n" ); fprintf( stderr, " 5mbit/1024\n" ); fprintf( stderr, " 5mbit/1024kbit\n" ); fprintf( stderr, " 5mbit/1mbit\n" ); fprintf( stderr, " -h shorter help\n" ); fprintf( stderr, " -H this help\n" ); fprintf( stderr, " -i gives information about all internal options\n" ); fprintf( stderr, " -o originator interval in ms\n" ); fprintf( stderr, " default: 1000, allowed values: >0\n\n" ); fprintf( stderr, " -p preferred gateway\n" ); fprintf( stderr, " default: none, allowed values: IP\n\n" ); fprintf( stderr, " -r routing class (only needed if gateway class = 0)\n" ); fprintf( stderr, " default: 0 -> set no default route\n" ); fprintf( stderr, " allowed values: 1 -> use fast internet connection (gw_flags * TQ)\n" ); fprintf( stderr, " 2 -> use stable internet connection (TQ)\n" ); fprintf( stderr, " 3 -> use fast-switch internet connection (TQ but switch as soon as a better gateway appears)\n\n" ); fprintf( stderr, " XX -> use late-switch internet connection (TQ but switch as soon as a gateway appears which is XX TQ better)\n\n" ); fprintf( stderr, " -s visualization server\n" ); fprintf( stderr, " default: none, allowed values: IP\n\n" ); fprintf( stderr, " -v print version\n" ); fprintf( stderr, " --policy-routing-script send all routing table changes to the script\n" ); fprintf(stderr, " --disable-client-nat deactivates the 'set tunnel NAT rules' feature (useful for half tunneling)\n"); } int is_batman_if(char *dev, struct batman_if **batman_if) { struct list_head *if_pos; list_for_each( if_pos, &if_list ) { (*batman_if) = list_entry( if_pos, struct batman_if, list ); if ( strcmp( (*batman_if)->dev, dev ) == 0 ) return 1; } return 0; } void choose_gw(void) { struct list_head *pos; struct gw_node *gw_node, *tmp_curr_gw = NULL; uint8_t max_gw_class = 0, max_tq = 0; uint32_t current_time, max_gw_factor = 0, tmp_gw_factor = 0; int download_speed, upload_speed; char orig_str[ADDR_STR_LEN]; prof_start( PROF_choose_gw ); current_time = get_time_msec(); if ((routing_class == 0) || ((routing_class < 4) && ((int64_t)(get_time_msec64() - (originator_interval * local_win_size)) < 0))) { prof_stop( PROF_choose_gw ); return; } if ( list_empty( &gw_list ) ) { if ( curr_gateway != NULL ) { debug_output( 3, "Removing default route - no gateway in range\n" ); del_default_route(); } prof_stop( PROF_choose_gw ); return; } list_for_each( pos, &gw_list ) { gw_node = list_entry( pos, struct gw_node, list ); /* ignore this gateway if recent connection attempts were unsuccessful */ /* if it is our only gateway retry immediately */ if ((gw_node != (struct gw_node *)gw_list.next) || (gw_node->list.next != (struct list_head *)&gw_list)) { if ((int)(current_time - (gw_node->last_failure + 30000)) < 0) continue; } if ( gw_node->orig_node->router == NULL ) continue; if ( gw_node->deleted ) continue; switch ( routing_class ) { case 1: /* fast connection */ get_gw_speeds( gw_node->orig_node->gwflags, &download_speed, &upload_speed ); if (((tmp_gw_factor = (((gw_node->orig_node->router->tq_avg * 100 ) / local_win_size) * ((gw_node->orig_node->router->tq_avg * 100) / local_win_size) * (download_speed / 64))) > max_gw_factor) || ((tmp_gw_factor == max_gw_factor) && (gw_node->orig_node->router->tq_avg > max_tq))) tmp_curr_gw = gw_node; break; default: /* stable connection (use best statistic) */ /* fast-switch (use best statistic but change as soon as a better gateway appears) */ /* late-switch (use best statistic but change as soon as a better gateway appears which has $routing_class more tq points) */ if (gw_node->orig_node->router->tq_avg > max_tq) tmp_curr_gw = gw_node; break; } if ( gw_node->orig_node->gwflags > max_gw_class ) max_gw_class = gw_node->orig_node->gwflags; if (gw_node->orig_node->router->tq_avg > max_tq) max_tq = gw_node->orig_node->router->tq_avg; if ( tmp_gw_factor > max_gw_factor ) max_gw_factor = tmp_gw_factor; if ( ( pref_gateway != 0 ) && ( pref_gateway == gw_node->orig_node->orig ) ) { tmp_curr_gw = gw_node; addr_to_string( tmp_curr_gw->orig_node->orig, orig_str, ADDR_STR_LEN ); debug_output( 3, "Preferred gateway found: %s (gw_flags: %i, tq: %i, gw_product: %i)\n", orig_str, gw_node->orig_node->gwflags, gw_node->orig_node->router->tq_avg, tmp_gw_factor ); break; } } if ( curr_gateway != tmp_curr_gw ) { if ( curr_gateway != NULL ) { if ( tmp_curr_gw != NULL ) debug_output( 3, "Removing default route - better gateway found\n" ); else debug_output( 3, "Removing default route - no gateway in range\n" ); del_default_route(); } curr_gateway = tmp_curr_gw; /* may be the last gateway is now gone */ if ( ( curr_gateway != NULL ) && ( !is_aborted() ) ) { addr_to_string( curr_gateway->orig_node->orig, orig_str, ADDR_STR_LEN ); debug_output( 3, "Adding default route to %s (gw_flags: %i, tq: %i, gw_product: %i)\n", orig_str, max_gw_class, max_tq, max_gw_factor ); add_default_route(); } } prof_stop( PROF_choose_gw ); } void update_routes(struct orig_node *orig_node, struct neigh_node *neigh_node, unsigned char *hna_recv_buff, int16_t hna_buff_len) { char orig_str[ADDR_STR_LEN], next_str[ADDR_STR_LEN]; struct neigh_node *old_router; prof_start(PROF_update_routes); debug_output(4, "update_routes() \n"); /* also handles orig_node->router == NULL and neigh_node == NULL */ if ((orig_node != NULL) && (orig_node->router != neigh_node)) { old_router = orig_node->router; if ( ( orig_node != NULL ) && ( neigh_node != NULL ) ) { addr_to_string( orig_node->orig, orig_str, ADDR_STR_LEN ); addr_to_string( neigh_node->addr, next_str, ADDR_STR_LEN ); debug_output( 4, "Route to %s via %s\n", orig_str, next_str ); } /* adds duplicated code but makes it more readable */ /* new route added */ if ((orig_node->router == NULL) && (neigh_node != NULL)) { debug_output(4, "Adding new route\n"); add_del_route(orig_node->orig, 32, neigh_node->addr, neigh_node->if_incoming->addr.sin_addr.s_addr, neigh_node->if_incoming->if_index, neigh_node->if_incoming->dev, BATMAN_RT_TABLE_HOSTS, ROUTE_TYPE_UNICAST, ROUTE_ADD); orig_node->batman_if = neigh_node->if_incoming; orig_node->router = neigh_node; /* add new announced network(s) */ hna_global_add(orig_node, hna_recv_buff, hna_buff_len); /* route deleted */ } else if ((orig_node->router != NULL) && (neigh_node == NULL)) { debug_output(4, "Deleting previous route\n"); /* remove old announced network(s) */ hna_global_del(orig_node); add_del_route(orig_node->orig, 32, orig_node->router->addr, 0, orig_node->batman_if->if_index, orig_node->batman_if->dev, BATMAN_RT_TABLE_HOSTS, ROUTE_TYPE_UNICAST, ROUTE_DEL); /* route changed */ } else { debug_output(4, "Route changed\n"); /* add new route */ add_del_route(orig_node->orig, 32, neigh_node->addr, neigh_node->if_incoming->addr.sin_addr.s_addr, neigh_node->if_incoming->if_index, neigh_node->if_incoming->dev, BATMAN_RT_TABLE_HOSTS, ROUTE_TYPE_UNICAST, ROUTE_ADD); /* delete old route */ add_del_route(orig_node->orig, 32, orig_node->router->addr, 0, orig_node->batman_if->if_index, orig_node->batman_if->dev, BATMAN_RT_TABLE_HOSTS, ROUTE_TYPE_UNICAST, ROUTE_DEL); orig_node->batman_if = neigh_node->if_incoming; orig_node->router = neigh_node; /* update announced network(s) */ hna_global_update(orig_node, hna_recv_buff, hna_buff_len, old_router); } orig_node->router = neigh_node; } else if (orig_node != NULL) { hna_global_update(orig_node, hna_recv_buff, hna_buff_len, orig_node->router); } prof_stop(PROF_update_routes); } void update_gw_list(struct orig_node *orig_node, uint8_t new_gwflags, uint16_t gw_port) { struct list_head *gw_pos, *gw_pos_tmp; struct gw_node *gw_node; char orig_str[ADDR_STR_LEN]; int download_speed, upload_speed; prof_start( PROF_update_gw_list ); list_for_each_safe( gw_pos, gw_pos_tmp, &gw_list ) { gw_node = list_entry(gw_pos, struct gw_node, list); if ( gw_node->orig_node == orig_node ) { addr_to_string( gw_node->orig_node->orig, orig_str, ADDR_STR_LEN ); debug_output( 3, "Gateway class of originator %s changed from %i to %i\n", orig_str, gw_node->orig_node->gwflags, new_gwflags ); if ( new_gwflags == 0 ) { gw_node->deleted = get_time_msec(); gw_node->orig_node->gwflags = new_gwflags; debug_output( 3, "Gateway %s removed from gateway list\n", orig_str ); if (gw_node == curr_gateway) choose_gw(); } else { gw_node->deleted = 0; gw_node->orig_node->gwflags = new_gwflags; } prof_stop( PROF_update_gw_list ); return; } } addr_to_string( orig_node->orig, orig_str, ADDR_STR_LEN ); get_gw_speeds( new_gwflags, &download_speed, &upload_speed ); debug_output( 3, "Found new gateway %s -> class: %i - %i%s/%i%s\n", orig_str, new_gwflags, ( download_speed > 2048 ? download_speed / 1024 : download_speed ), ( download_speed > 2048 ? "MBit" : "KBit" ), ( upload_speed > 2048 ? upload_speed / 1024 : upload_speed ), ( upload_speed > 2048 ? "MBit" : "KBit" ) ); gw_node = debugMalloc(sizeof(struct gw_node), 103); memset(gw_node, 0, sizeof(struct gw_node)); INIT_LIST_HEAD( &gw_node->list ); gw_node->orig_node = orig_node; gw_node->gw_port = gw_port; gw_node->last_failure = get_time_msec(); list_add_tail( &gw_node->list, &gw_list ); prof_stop( PROF_update_gw_list ); } /* returns the up and downspeeds in kbit, calculated from the class */ void get_gw_speeds(unsigned char gw_class, int *down, int *up) { char sbit = (gw_class & 0x80) >> 7; char dpart = (gw_class & 0x78) >> 3; char upart = (gw_class & 0x07); *down = 32 * (sbit + 2) * (1 << dpart); *up = ((upart + 1) * (*down)) / 8; } /* calculates the gateway class from kbit */ unsigned char get_gw_class(int down, int up) { int mdown = 0, tdown, tup, difference = 0x0FFFFFFF; unsigned char gw_class = 0, sbit, part; /* test all downspeeds */ for (sbit = 0; sbit < 2; sbit++) { for (part = 0; part < 16; part++) { tdown = 32 * (sbit + 2) * (1 << part); if ( abs(tdown - down) < difference) { gw_class = (sbit << 7) + (part << 3); difference = abs(tdown - down); mdown = tdown; } } } /* test all upspeeds */ difference = 0x0FFFFFFF; for (part = 0; part < 8; part++) { tup = ((part + 1) * (mdown)) / 8; if (abs(tup - up) < difference) { gw_class = (gw_class & 0xF8) | part; difference = abs(tup - up); } } return gw_class; } static int isBidirectionalNeigh(struct orig_node *orig_node, struct orig_node *orig_neigh_node, struct bat_packet *in, uint32_t recv_time, struct batman_if *if_incoming) { struct list_head *list_pos; struct neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL; uint8_t total_count; char orig_str[ADDR_STR_LEN], neigh_str[ADDR_STR_LEN]; if ( orig_node == orig_neigh_node ) { list_for_each( list_pos, &orig_node->neigh_list ) { tmp_neigh_node = list_entry( list_pos, struct neigh_node, list ); if ( ( tmp_neigh_node->addr == orig_neigh_node->orig ) && ( tmp_neigh_node->if_incoming == if_incoming ) ) neigh_node = tmp_neigh_node; } if ( neigh_node == NULL ) neigh_node = create_neighbor(orig_node, orig_neigh_node, orig_neigh_node->orig, if_incoming); neigh_node->last_valid = recv_time; } else { /* find packet count of corresponding one hop neighbor */ list_for_each( list_pos, &orig_neigh_node->neigh_list ) { tmp_neigh_node = list_entry( list_pos, struct neigh_node, list ); if ( ( tmp_neigh_node->addr == orig_neigh_node->orig ) && ( tmp_neigh_node->if_incoming == if_incoming ) ) neigh_node = tmp_neigh_node; } if ( neigh_node == NULL ) neigh_node = create_neighbor(orig_neigh_node, orig_neigh_node, orig_neigh_node->orig, if_incoming); } orig_node->last_valid = recv_time; /* pay attention to not get a value bigger than 100 % */ total_count = ( orig_neigh_node->bcast_own_sum[if_incoming->if_num] > neigh_node->real_packet_count ? neigh_node->real_packet_count : orig_neigh_node->bcast_own_sum[if_incoming->if_num] ); /* if we have too few packets (too less data) we set tq_own to zero */ /* if we receive too few packets it is not considered bidirectional */ if ( ( total_count < minimum_send ) || ( neigh_node->real_packet_count < minimum_recv ) ) { orig_neigh_node->tq_own = 0; } else { /* neigh_node->real_packet_count is never zero as we only purge old information when getting new information */ orig_neigh_node->tq_own = (TQ_MAX_VALUE * total_count) / neigh_node->real_packet_count; } /* 1 - ((1-x)** 3), normalized to TQ_MAX_VALUE */ /* this does affect the nearly-symmetric links only a little, * but punishes asymetric links more. */ /* this will give a value between 0 and TQ_MAX_VALUE */ orig_neigh_node->tq_asym_penalty = TQ_MAX_VALUE - (TQ_MAX_VALUE * (local_win_size - neigh_node->real_packet_count) * (local_win_size - neigh_node->real_packet_count) * (local_win_size - neigh_node->real_packet_count)) / (local_win_size * local_win_size * local_win_size); in->tq = ((in->tq * orig_neigh_node->tq_own * orig_neigh_node->tq_asym_penalty) / (TQ_MAX_VALUE * TQ_MAX_VALUE)); addr_to_string( orig_node->orig, orig_str, ADDR_STR_LEN ); addr_to_string( orig_neigh_node->orig, neigh_str, ADDR_STR_LEN ); /*debug_output( 3, "bidirectional: orig = %-15s neigh = %-15s => own_bcast = %2i, real recv = %2i, local tq: %3i, asym_penalty: %3i, total tq: %3i \n", orig_str, neigh_str, total_count, neigh_node->real_packet_count, orig_neigh_node->tq_own, orig_neigh_node->tq_asym_penalty, in->tq );*/ debug_output(4, "bidirectional: orig = %-15s neigh = %-15s => own_bcast = %2i, real recv = %2i, local tq: %3i, asym_penalty: %3i, total tq: %3i \n", orig_str, neigh_str, total_count, neigh_node->real_packet_count, orig_neigh_node->tq_own, orig_neigh_node->tq_asym_penalty, in->tq); /* if link has the minimum required transmission quality consider it bidirectional */ if (in->tq >= TQ_TOTAL_BIDRECT_LIMIT) return 1; return 0; } static void generate_vis_packet(void) { struct hash_it_t *hashit = NULL; struct orig_node *orig_node; struct vis_data *vis_data; struct list_head *list_pos; struct batman_if *batman_if; if (vis_packet != NULL) { debugFree(vis_packet, 1102); vis_packet = NULL; vis_packet_size = 0; } vis_packet_size = sizeof(struct vis_packet); vis_packet = debugMalloc(vis_packet_size, 104); memcpy(&((struct vis_packet *)vis_packet)->sender_ip, (unsigned char *)&(((struct batman_if *)if_list.next)->addr.sin_addr.s_addr), 4); ((struct vis_packet *)vis_packet)->version = VIS_COMPAT_VERSION; ((struct vis_packet *)vis_packet)->gw_class = gateway_class; ((struct vis_packet *)vis_packet)->tq_max = TQ_MAX_VALUE; /* neighbor list */ while (NULL != (hashit = hash_iterate(orig_hash, hashit))) { orig_node = hashit->bucket->data; /* we interested in 1 hop neighbours only */ if ((orig_node->router != NULL) && (orig_node->orig == orig_node->router->addr) && (orig_node->router->tq_avg > 0)) { vis_packet_size += sizeof(struct vis_data); vis_packet = debugRealloc(vis_packet, vis_packet_size, 105); vis_data = (struct vis_data *)(vis_packet + vis_packet_size - sizeof(struct vis_data)); memcpy(&vis_data->ip, (unsigned char *)&orig_node->orig, 4); vis_data->data = orig_node->router->tq_avg; vis_data->type = DATA_TYPE_NEIGH; } } /* secondary interfaces */ if (found_ifs > 1) { list_for_each(list_pos, &if_list) { batman_if = list_entry(list_pos, struct batman_if, list); if (((struct vis_packet *)vis_packet)->sender_ip == batman_if->addr.sin_addr.s_addr) continue; vis_packet_size += sizeof(struct vis_data); vis_packet = debugRealloc(vis_packet, vis_packet_size, 106); vis_data = (struct vis_data *)(vis_packet + vis_packet_size - sizeof(struct vis_data)); memcpy(&vis_data->ip, (unsigned char *)&batman_if->addr.sin_addr.s_addr, 4); vis_data->data = 0; vis_data->type = DATA_TYPE_SEC_IF; } } /* hna announcements */ vis_packet = hna_local_update_vis_packet(vis_packet, &vis_packet_size); if (vis_packet_size == sizeof(struct vis_packet)) { debugFree(vis_packet, 1107); vis_packet = NULL; vis_packet_size = 0; } } static void send_vis_packet(void) { generate_vis_packet(); if ( vis_packet != NULL ) send_udp_packet(vis_packet, vis_packet_size, &vis_if.addr, vis_if.sock, NULL); } static uint8_t count_real_packets(struct bat_packet *in, uint32_t neigh, struct batman_if *if_incoming) { struct list_head *list_pos; struct orig_node *orig_node; struct neigh_node *tmp_neigh_node; uint8_t is_duplicate = 0; orig_node = get_orig_node( in->orig ); /*char orig_str[ADDR_STR_LEN], neigh_str[ADDR_STR_LEN]; addr_to_string( in->orig, orig_str, ADDR_STR_LEN ); addr_to_string( neigh, neigh_str, ADDR_STR_LEN ); debug_output( 3, "count_real_packets: orig = %s, neigh = %s, seq = %i, last seq = %i\n", orig_str, neigh_str, in->seqno, orig_node->last_real_seqno );*/ list_for_each( list_pos, &orig_node->neigh_list ) { tmp_neigh_node = list_entry( list_pos, struct neigh_node, list ); if ( !is_duplicate ) is_duplicate = get_bit_status( tmp_neigh_node->real_bits, orig_node->last_real_seqno, in->seqno ); if ( ( tmp_neigh_node->addr == neigh ) && ( tmp_neigh_node->if_incoming == if_incoming ) ) { bit_get_packet( tmp_neigh_node->real_bits, in->seqno - orig_node->last_real_seqno, 1 ); /*debug_output( 3, "count_real_packets (yes): neigh = %s, is_new = %s, seq = %i, last seq = %i\n", neigh_str, ( is_new_seqno ? "YES" : "NO" ), in->seqno, orig_node->last_real_seqno );*/ } else { bit_get_packet( tmp_neigh_node->real_bits, in->seqno - orig_node->last_real_seqno, 0 ); /*debug_output( 3, "count_real_packets (no): neigh = %s, is_new = %s, seq = %i, last seq = %i\n", neigh_str, ( is_new_seqno ? "YES" : "NO" ), in->seqno, orig_node->last_real_seqno );*/ } tmp_neigh_node->real_packet_count = bit_packet_count( tmp_neigh_node->real_bits ); } if ( !is_duplicate ) { debug_output( 4, "updating last_seqno: old %d, new %d \n", orig_node->last_real_seqno, in->seqno ); orig_node->last_real_seqno = in->seqno; } return is_duplicate; } int8_t batman(void) { struct list_head *list_pos, *forw_pos_tmp; struct orig_node *orig_neigh_node, *orig_node; struct batman_if *batman_if, *if_incoming; struct forw_node *forw_node; struct bat_packet *bat_packet; uint32_t neigh, debug_timeout, vis_timeout, select_timeout, curr_time; unsigned char in[2001], *hna_recv_buff; char orig_str[ADDR_STR_LEN], neigh_str[ADDR_STR_LEN], ifaddr_str[ADDR_STR_LEN], prev_sender_str[ADDR_STR_LEN]; int16_t hna_buff_len, packet_len, curr_packet_len; uint8_t forward_old, if_rp_filter_all_old, if_rp_filter_default_old, if_send_redirects_all_old, if_send_redirects_default_old; uint8_t is_my_addr, is_my_orig, is_my_oldorig, is_broadcast, is_duplicate, is_bidirectional, has_directlink_flag; int8_t res; debug_timeout = vis_timeout = get_time_msec(); if ( NULL == ( orig_hash = hash_new( 128, compare_orig, choose_orig ) ) ) return(-1); /* for profiling the functions */ prof_init(PROF_choose_gw, "choose_gw"); prof_init(PROF_update_routes, "update_routes"); prof_init(PROF_update_gw_list, "update_gw_list"); prof_init(PROF_is_duplicate, "isDuplicate"); prof_init(PROF_get_orig_node, "get_orig_node"); prof_init(PROF_update_originator, "update_orig"); prof_init(PROF_purge_originator, "purge_orig"); prof_init(PROF_schedule_forward_packet, "schedule_forward_packet"); prof_init(PROF_send_outstanding_packets, "send_outstanding_packets"); list_for_each(list_pos, &if_list) { batman_if = list_entry(list_pos, struct batman_if, list); batman_if->out.version = COMPAT_VERSION; batman_if->out.flags = 0x00; batman_if->out.ttl = (batman_if->if_num > 0 ? 2 : TTL); batman_if->out.gwflags = (batman_if->if_num > 0 ? 0 : gateway_class); batman_if->out.seqno = 1; batman_if->out.gwport = htons(GW_PORT); batman_if->out.tq = TQ_MAX_VALUE; schedule_own_packet(batman_if); } if_rp_filter_all_old = get_rp_filter("all"); if_rp_filter_default_old = get_rp_filter("default"); if_send_redirects_all_old = get_send_redirects("all"); if_send_redirects_default_old = get_send_redirects("default"); set_rp_filter(0, "all"); set_rp_filter(0, "default"); set_send_redirects(0, "all"); set_send_redirects(0, "default"); forward_old = get_forwarding(); set_forwarding(1); while (!is_aborted()) { debug_output( 4, " \n" ); /* harden select_timeout against sudden time change (e.g. ntpdate) */ curr_time = get_time_msec(); select_timeout = ((int)(((struct forw_node *)forw_list.next)->send_time - curr_time) > 0 ? ((struct forw_node *)forw_list.next)->send_time - curr_time : 10); res = receive_packet(in, sizeof(in), &packet_len, &neigh, select_timeout, &if_incoming); /* on receive error the interface is deactivated in receive_packet() */ if (res < 1) goto send_packets; curr_time = get_time_msec(); curr_packet_len = 0; bat_packet = (struct bat_packet *)in; addr_to_string(neigh, neigh_str, sizeof(neigh_str)); addr_to_string(if_incoming->addr.sin_addr.s_addr, ifaddr_str, sizeof(ifaddr_str)); while ((curr_packet_len + (int)sizeof(struct bat_packet) <= packet_len) && (curr_packet_len + (int)sizeof(struct bat_packet) + bat_packet->hna_len * 5 <= packet_len) && (curr_packet_len + (int)sizeof(struct bat_packet) + bat_packet->hna_len * 5 <= MAX_AGGREGATION_BYTES)) { bat_packet = (struct bat_packet *)(in + curr_packet_len); curr_packet_len += sizeof(struct bat_packet) + bat_packet->hna_len * 5; /* network to host order for our 16bit seqno */ bat_packet->seqno = ntohs(bat_packet->seqno); addr_to_string(bat_packet->orig, orig_str, sizeof(orig_str)); addr_to_string(bat_packet->prev_sender, prev_sender_str, sizeof(prev_sender_str)); is_my_addr = is_my_orig = is_my_oldorig = is_broadcast = 0; has_directlink_flag = (bat_packet->flags & DIRECTLINK ? 1 : 0); debug_output(4, "Received BATMAN packet via NB: %s, IF: %s %s (from OG: %s, via old OG: %s, seqno %d, tq %d, TTL %d, V %d, IDF %d) \n", neigh_str, if_incoming->dev, ifaddr_str, orig_str, prev_sender_str, bat_packet->seqno, bat_packet->tq, bat_packet->ttl, bat_packet->version, has_directlink_flag); hna_buff_len = bat_packet->hna_len * 5; hna_recv_buff = (hna_buff_len > 4 ? (unsigned char *)(bat_packet + 1) : NULL); list_for_each(list_pos, &if_list) { batman_if = list_entry(list_pos, struct batman_if, list); if (neigh == batman_if->addr.sin_addr.s_addr) is_my_addr = 1; if (bat_packet->orig == batman_if->addr.sin_addr.s_addr) is_my_orig = 1; if (neigh == batman_if->broad.sin_addr.s_addr) is_broadcast = 1; if (bat_packet->prev_sender == batman_if->addr.sin_addr.s_addr) is_my_oldorig = 1; } if (bat_packet->gwflags != 0) debug_output(4, "Is an internet gateway (class %i) \n", bat_packet->gwflags); if (bat_packet->version != COMPAT_VERSION) { debug_output(4, "Drop packet: incompatible batman version (%i) \n", bat_packet->version); goto send_packets; } if (is_my_addr) { debug_output(4, "Drop packet: received my own broadcast (sender: %s) \n", neigh_str); goto send_packets; } if (is_broadcast) { debug_output(4, "Drop packet: ignoring all packets with broadcast source IP (sender: %s) \n", neigh_str); goto send_packets; } if (is_my_orig) { orig_neigh_node = get_orig_node(neigh); if ((has_directlink_flag) && (if_incoming->addr.sin_addr.s_addr == bat_packet->orig) && (bat_packet->seqno - if_incoming->out.seqno + 2 == 0)) { debug_output(4, "count own bcast (is_my_orig): old = %i, ", orig_neigh_node->bcast_own_sum[if_incoming->if_num]); bit_mark((TYPE_OF_WORD *)&(orig_neigh_node->bcast_own[if_incoming->if_num * num_words]), 0); orig_neigh_node->bcast_own_sum[if_incoming->if_num] = bit_packet_count((TYPE_OF_WORD *)&(orig_neigh_node->bcast_own[if_incoming->if_num * num_words])); debug_output(4, "new = %i \n", orig_neigh_node->bcast_own_sum[if_incoming->if_num]); } debug_output(4, "Drop packet: originator packet from myself (via neighbour) \n"); goto send_packets; } if (bat_packet->tq == 0) { count_real_packets(bat_packet, neigh, if_incoming); debug_output(4, "Drop packet: originator packet with tq is 0 \n"); goto send_packets; } if (is_my_oldorig) { debug_output(4, "Drop packet: ignoring all rebroadcast echos (sender: %s) \n", neigh_str); goto send_packets; } is_duplicate = count_real_packets(bat_packet, neigh, if_incoming); orig_node = get_orig_node(bat_packet->orig); /* if sender is a direct neighbor the sender ip equals originator ip */ orig_neigh_node = (bat_packet->orig == neigh ? orig_node : get_orig_node(neigh)); /* drop packet if sender is not a direct neighbor and if we no route towards it */ if ((bat_packet->orig != neigh) && (orig_neigh_node->router == NULL)) { debug_output(4, "Drop packet: OGM via unknown neighbor! \n"); goto send_packets; } is_bidirectional = isBidirectionalNeigh(orig_node, orig_neigh_node, bat_packet, curr_time, if_incoming); /* update ranking if it is not a duplicate or has the same seqno and similar ttl as the non-duplicate */ if ((is_bidirectional) && ((!is_duplicate) || ((orig_node->last_real_seqno == bat_packet->seqno) && (orig_node->last_ttl - 3 <= bat_packet->ttl)))) update_orig(orig_node, bat_packet, neigh, if_incoming, hna_recv_buff, hna_buff_len, is_duplicate, curr_time); /* is single hop (direct) neighbour */ if (bat_packet->orig == neigh) { /* mark direct link on incoming interface */ schedule_forward_packet(orig_node, bat_packet, neigh, 1, hna_buff_len, if_incoming, curr_time); debug_output(4, "Forward packet: rebroadcast neighbour packet with direct link flag \n"); goto send_packets; } /* multihop originator */ if (!is_bidirectional) { debug_output(4, "Drop packet: not received via bidirectional link\n"); goto send_packets; } if (is_duplicate) { debug_output(4, "Drop packet: duplicate packet received\n"); goto send_packets; } debug_output(4, "Forward packet: rebroadcast originator packet \n"); schedule_forward_packet(orig_node, bat_packet, neigh, 0, hna_buff_len, if_incoming, curr_time); } send_packets: send_outstanding_packets(curr_time); if ((int)(curr_time - (debug_timeout + 1000)) > 0) { debug_timeout = curr_time; purge_orig( curr_time ); debug_orig(); check_inactive_interfaces(); if ( debug_clients.clients_num[4] > 0 ) { checkIntegrity(); prof_print(); } if ( ( routing_class != 0 ) && ( curr_gateway == NULL ) ) choose_gw(); if ((vis_if.sock) && ((int)(curr_time - (vis_timeout + 10000)) > 0)) { vis_timeout = curr_time; send_vis_packet(); } hna_local_task_exec(); } } if (debug_level > 0) printf("Deleting all BATMAN routes\n"); purge_orig(get_time_msec() + (5 * purge_timeout) + originator_interval); hash_destroy(orig_hash); list_for_each_safe(list_pos, forw_pos_tmp, &forw_list) { forw_node = list_entry(list_pos, struct forw_node, list); list_del((struct list_head *)&forw_list, list_pos, &forw_list); debugFree(forw_node->pack_buff, 1105); debugFree(forw_node, 1106); } if (vis_packet != NULL) debugFree(vis_packet, 1108); set_forwarding( forward_old ); set_rp_filter( if_rp_filter_all_old, "all" ); set_rp_filter( if_rp_filter_default_old, "default" ); set_send_redirects( if_send_redirects_all_old, "all" ); set_send_redirects( if_send_redirects_default_old, "default" ); return 0; } batmand-0.3.2+74+g2f62b17/batman.h000066400000000000000000000137741435410210600161270ustar00rootroot00000000000000/* * Copyright (C) 2006-2012 B.A.T.M.A.N. contributors: * * Thomas Lopatic, Corinna 'Elektra' Aichele, Axel Neumann, Marek Lindner * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public * License as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA * */ #ifndef _BATMAND_BATMAN_H #define _BATMAND_BATMAN_H #include #include #include #include #include #include #define TYPE_OF_WORD uintmax_t /* you should choose something big, if you don't want to waste cpu */ #include "list-batman.h" #ifndef SOURCE_VERSION #define SOURCE_VERSION "0.4" #endif #define ADDR_STR_LEN 16 #define TQ_MAX_VALUE 255 #define UNIX_PATH "/var/run/batmand.socket" /*** * * Things you should enable via your make file: * * DEBUG_MALLOC enables malloc() / free() wrapper functions to detect memory leaks / buffer overflows / etc * MEMORY_USAGE allows you to monitor the internal memory usage (needs DEBUG_MALLOC to work) * PROFILE_DATA allows you to monitor the cpu usage for each function * ***/ /* * No configuration files or fancy command line switches yet * To experiment with B.A.T.M.A.N. settings change them here * and recompile the code * Here is the stuff you may want to play with: */ #define JITTER 100 #define TTL 50 /* Time To Live of broadcast messages */ #define PURGE_TIMEOUT 200000u /* purge originators after time in ms if no valid packet comes in -> TODO: check influence on TQ_LOCAL_WINDOW_SIZE */ #define TQ_LOCAL_WINDOW_SIZE 64 /* sliding packet range of received originator messages in squence numbers (should be a multiple of our word size) */ #define TQ_GLOBAL_WINDOW_SIZE 5 #define TQ_LOCAL_BIDRECT_SEND_MINIMUM 1 #define TQ_LOCAL_BIDRECT_RECV_MINIMUM 1 #define TQ_TOTAL_BIDRECT_LIMIT 1 /** * hop penalty is applied "twice" * when the packet comes in and if rebroadcasted via the same interface */ #define TQ_HOP_PENALTY 10 #define DEFAULT_ROUTING_CLASS 30 #define MAX_AGGREGATION_BYTES 512 /* should not be bigger than 512 bytes or change the size of forw_node->direct_link_flags */ #define MAX_AGGREGATION_MS 100 #define ROUTE_TYPE_UNICAST 0 #define ROUTE_TYPE_THROW 1 #define ROUTE_TYPE_UNREACHABLE 2 #define ROUTE_TYPE_UNKNOWN 3 #define ROUTE_ADD 0 #define ROUTE_DEL 1 #define RULE_TYPE_SRC 0 #define RULE_TYPE_DST 1 #define RULE_TYPE_IIF 2 #define RULE_ADD 0 #define RULE_DEL 1 /*** * * Things you should leave as is unless your know what you are doing ! * * BATMAN_RT_TABLE_NETWORKS routing table for announced networks * BATMAN_RT_TABLE_HOSTS routing table for routes towards originators * BATMAN_RT_TABLE_UNREACH routing table for unreachable routing entry * BATMAN_RT_TABLE_TUNNEL routing table for the tunnel towards the internet gateway * BATMAN_RT_PRIO_DEFAULT standard priority for routing rules * BATMAN_RT_PRIO_UNREACH standard priority for unreachable rules * BATMAN_RT_PRIO_TUNNEL standard priority for tunnel routing rules * ***/ #define BATMAN_RT_TABLE_NETWORKS 65 #define BATMAN_RT_TABLE_HOSTS 66 #define BATMAN_RT_TABLE_UNREACH 67 #define BATMAN_RT_TABLE_TUNNEL 68 #define BATMAN_RT_PRIO_DEFAULT 6600 #define BATMAN_RT_PRIO_UNREACH BATMAN_RT_PRIO_DEFAULT + 100 #define BATMAN_RT_PRIO_TUNNEL BATMAN_RT_PRIO_UNREACH + 100 /*** * * ports which are to ignored by the blackhole check * ***/ #define BH_UDP_PORTS {4307, 162, 137, 138, 139, 5353} /* vis, SNMP-TRAP, netbios, mdns */ #define BATMANUNUSED(x) (x)__attribute__((unused)) #define ALIGN_WORD __attribute__ ((aligned(sizeof(TYPE_OF_WORD)))) #define ALIGN_POINTER __attribute__ ((aligned(sizeof(void*)))) extern char *prog_name; extern uint8_t debug_level; extern uint8_t debug_level_max; extern uint8_t gateway_class; extern uint8_t routing_class; extern int16_t originator_interval; extern uint32_t pref_gateway; extern char *policy_routing_script; extern int policy_routing_pipe; extern pid_t policy_routing_script_pid; extern int8_t stop; extern int nat_tool_avail; extern int8_t disable_client_nat; extern struct gw_node *curr_gateway; extern pthread_t curr_gateway_thread_id; extern uint8_t found_ifs; extern uint8_t active_ifs; extern int32_t receive_max_sock; extern fd_set receive_wait_set; extern uint8_t unix_client; extern uint8_t log_facility_active; extern struct hashtable_t *orig_hash; extern struct list_head_first if_list; extern struct list_head_first gw_list; extern struct list_head_first forw_list; extern struct vis_if vis_if; extern struct unix_if unix_if; extern struct debug_clients debug_clients; extern uint8_t tunnel_running; extern uint64_t batman_clock_ticks; extern uint8_t hop_penalty; extern uint32_t purge_timeout; extern uint8_t minimum_send; extern uint8_t minimum_recv; extern uint8_t global_win_size; extern uint8_t local_win_size; extern uint8_t num_words; extern uint8_t aggregation_enabled; /* fwd declarations */ struct batman_if; struct orig_node; struct neigh_node; int8_t batman(void); void usage(void); void verbose_usage(void); int is_batman_if(char *dev, struct batman_if **batman_if); void update_routes(struct orig_node *orig_node, struct neigh_node *neigh_node, unsigned char *hna_recv_buff, int16_t hna_buff_len); void update_gw_list(struct orig_node *orig_node, uint8_t new_gwflags, uint16_t gw_port); void get_gw_speeds(unsigned char gw_class, int *down, int *up); unsigned char get_gw_class(int down, int up); void choose_gw(void); #endif batmand-0.3.2+74+g2f62b17/bitarray.c000066400000000000000000000122561435410210600164670ustar00rootroot00000000000000/* * Copyright (C) 2006-2012 B.A.T.M.A.N. contributors: * * Simon Wunderlich, Axel Neumann, Marek Lindner * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public * License as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA * */ #include "bitarray.h" #include "os.h" /* clear the bits */ void bit_init( TYPE_OF_WORD *seq_bits ) { int i; for (i = 0 ; i < (int)num_words; i++) seq_bits[i]= 0; } /* returns true if corresponding bit in given seq_bits indicates so and curr_seqno is within range of last_seqno */ uint8_t get_bit_status( TYPE_OF_WORD *seq_bits, uint16_t last_seqno, uint16_t curr_seqno ) { int16_t diff, word_offset, word_num; diff= last_seqno- curr_seqno; if (diff < 0 || diff >= local_win_size) { return 0; } else { word_offset= ( last_seqno - curr_seqno ) % WORD_BIT_SIZE; /* which position in the selected word */ word_num = ( last_seqno - curr_seqno ) / WORD_BIT_SIZE; /* which word */ if ( seq_bits[word_num] & (1ULL << word_offset)) /* get position status */ return 1; else return 0; } } /* turn corresponding bit on, so we can remember that we got the packet */ void bit_mark( TYPE_OF_WORD *seq_bits, int32_t n ) { int32_t word_offset,word_num; if (n<0 || n >= local_win_size) { /* if too old, just drop it */ /* printf("got old packet, dropping\n");*/ return; } /* printf("mark bit %d\n", n); */ word_offset= n%WORD_BIT_SIZE; /* which position in the selected word */ word_num = n/WORD_BIT_SIZE; /* which word */ seq_bits[word_num] |= 1ULL << word_offset; /* turn the position on */ } /* shift the packet array p by n places. */ void bit_shift( TYPE_OF_WORD *seq_bits, int32_t n ) { int32_t word_offset, word_num; int32_t i; /* bit_print( seq_bits );*/ if( n<=0 ) return; word_offset= n%WORD_BIT_SIZE; /* shift how much inside each word */ word_num = n/WORD_BIT_SIZE; /* shift over how much (full) words */ for ( i=num_words-1; i>word_num; i-- ) { /* going from old to new, so we can't overwrite the data we copy from. * * left is high, right is low: FEDC BA98 7654 3210 * ^^ ^^ * vvvv * ^^^^ = from, vvvvv =to, we'd have word_num==1 and * word_offset==WORD_BIT_SIZE/2 ????? in this example. (=24 bits) * * our desired output would be: 9876 5432 1000 0000 * */ seq_bits[i]= (seq_bits[i - word_num] << word_offset) + /* take the lower port from the left half, shift it left to its final position */ (seq_bits[i - word_num - 1] >> (WORD_BIT_SIZE-word_offset)); /* and the upper part of the right half and shift it left to it's position */ /* for our example that would be: word[0] = 9800 + 0076 = 9876 */ } /* now for our last word, i==word_num, we only have the it's "left" half. that's the 1000 word in * our example.*/ seq_bits[i]= (seq_bits[i - word_num] << word_offset); /* pad the rest with 0, if there is anything */ i--; for (; i>=0; i--) { seq_bits[i]= 0; } /* bit_print( seq_bits ); */ } /* receive and process one packet, returns 1 if received seq_num is considered new, 0 if old */ char bit_get_packet( TYPE_OF_WORD *seq_bits, int16_t seq_num_diff, int8_t set_mark ) { int i; /* we already got a sequence number higher than this one, so we just mark it. this should wrap around the integer just fine */ if ((seq_num_diff < 0) && (seq_num_diff >= -local_win_size)) { if ( set_mark ) bit_mark( seq_bits, -seq_num_diff ); return 0; } if ((seq_num_diff > local_win_size) || (seq_num_diff < -local_win_size)) { /* it seems we missed a lot of packets or the other host restarted */ if (seq_num_diff > local_win_size) debug_output(4, "It seems we missed a lot of packets (%i) !\n", seq_num_diff-1); if (-seq_num_diff > local_win_size) debug_output(4, "Other host probably restarted !\n"); for (i=0; i #include "batman.h" #define WORD_BIT_SIZE ( sizeof(TYPE_OF_WORD) * 8 ) void bit_init( TYPE_OF_WORD *seq_bits ); uint8_t get_bit_status( TYPE_OF_WORD *seq_bits, uint16_t last_seqno, uint16_t curr_seqno ); char *bit_print( TYPE_OF_WORD *seq_bits ); void bit_mark( TYPE_OF_WORD *seq_bits, int32_t n ); void bit_shift( TYPE_OF_WORD *seq_bits, int32_t n ); char bit_get_packet( TYPE_OF_WORD *seq_bits, int16_t seq_num_diff, int8_t set_mark ); int bit_packet_count( TYPE_OF_WORD *seq_bits ); uint8_t bit_count( int32_t to_count ); #endif batmand-0.3.2+74+g2f62b17/hash.c000066400000000000000000000211711435410210600155710ustar00rootroot00000000000000/* * Copyright (C) 2006-2012 B.A.T.M.A.N. contributors: * * Simon Wunderlich, Marek Lindner * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public * License as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA * */ #include "hash.h" #include #include #include "allocate.h" /* clears the hash */ void hash_init(struct hashtable_t *hash) { int i; hash->elements = 0; for (i = 0; i < hash->size; i++) hash->table[i] = NULL; } /* remove the hash structure. if hashdata_free_cb != NULL, * this function will be called to remove the elements inside of the hash. * if you don't remove the elements, memory might be leaked. */ void hash_delete(struct hashtable_t *hash, hashdata_free_cb free_cb) { struct element_t *bucket, *last_bucket; int i; for (i = 0; i < hash->size; i++) { bucket = hash->table[i]; while (bucket != NULL) { if (free_cb != NULL) free_cb(bucket->data); last_bucket = bucket; bucket = bucket->next; debugFree(last_bucket, 1301); } } hash_destroy(hash); } /* adds data to the hashtable and reuse bucket. * returns 0 on success, -1 on error */ static int hash_add_bucket(struct hashtable_t *hash, void *data, struct element_t *bucket, int check_duplicate) { int index; struct element_t *bucket_it, *prev_bucket = NULL; index = hash->choose(data, hash->size); bucket_it = hash->table[index]; while (bucket_it != NULL) { if (check_duplicate && hash->compare(bucket_it->data, data)) return -1; prev_bucket = bucket_it; bucket_it = bucket_it->next; } /* init the new bucket */ bucket->data = data; bucket->next = NULL; /* and link it */ if (prev_bucket == NULL) hash->table[index] = bucket; else prev_bucket->next = bucket; hash->elements++; return 0; } /* free only the hashtable and the hash itself. */ void hash_destroy(struct hashtable_t *hash) { debugFree(hash->table, 1302); debugFree(hash, 1303); } /* free hash_it_t pointer when stopping hash_iterate early */ void hash_iterate_free(struct hash_it_t *iter_in) { debugFree(iter_in, 1304); } /* iterate though the hash. first element is selected with iter_in NULL. * use the returned iterator to access the elements until hash_it_t returns * NULL. */ struct hash_it_t *hash_iterate(struct hashtable_t *hash, struct hash_it_t *iter_in) { struct hash_it_t *iter; if (iter_in == NULL) { iter = debugMalloc(sizeof(struct hash_it_t), 301); iter->index = -1; iter->bucket = NULL; iter->prev_bucket = NULL; } else { iter = iter_in; } /* sanity checks first (if our bucket got deleted in the last * iteration): */ if (iter->bucket != NULL) { if (iter->first_bucket != NULL) { /* we're on the first element and it got removed after * the last iteration. */ if ((*iter->first_bucket) != iter->bucket) { /* there are still other elements in the list */ if ((*iter->first_bucket) != NULL) { iter->prev_bucket = NULL; iter->bucket = (*iter->first_bucket); iter->first_bucket = &hash->table[iter->index]; return iter; } else { iter->bucket = NULL; } } } else if (iter->prev_bucket != NULL) { /* we're not on the first element, and the bucket got * removed after the last iteration. The last bucket's * next pointer is not pointing to our actual bucket * anymore. Select the next. */ if (iter->prev_bucket->next != iter->bucket) iter->bucket = iter->prev_bucket; } } /* now as we are sane, select the next one if there is some */ if (iter->bucket != NULL) { if (iter->bucket->next != NULL) { iter->prev_bucket = iter->bucket; iter->bucket = iter->bucket->next; iter->first_bucket = NULL; return iter; } } /* if not returned yet, we've reached the last one on the index and * have to search forward */ iter->index++; /* go through the entries of the hash table */ while (iter->index < hash->size) { if ((hash->table[iter->index]) == NULL) { iter->index++; continue; } iter->prev_bucket = NULL; iter->bucket = hash->table[iter->index]; iter->first_bucket = &hash->table[iter->index]; return iter; /* if this table entry is not null, return it */ } /* nothing to iterate over anymore */ hash_iterate_free(iter); return NULL; } /* allocates and clears the hash */ struct hashtable_t *hash_new(int size, hashdata_compare_cb compare, hashdata_choose_cb choose) { struct hashtable_t *hash; hash = debugMalloc(sizeof(struct hashtable_t), 302); if (!hash) return NULL; hash->size = size; hash->table = debugMalloc(sizeof(struct element_t *)*size, 303); if (!hash->table) { debugFree(hash, 1305); return NULL; } hash_init(hash); hash->compare = compare; hash->choose = choose; return hash; } /* adds data to the hashtable. returns 0 on success, -1 on error */ int hash_add(struct hashtable_t *hash, void *data) { int ret; struct element_t *bucket; /* found the tail of the list, add new element */ bucket = debugMalloc(sizeof(struct element_t), 304); if (!bucket) return -1; ret = hash_add_bucket(hash, data, bucket, 1); if (ret < 0) debugFree(bucket, 1307); return ret; } /* finds data, based on the key in keydata. returns the found data on success, * or NULL on error */ void *hash_find(struct hashtable_t *hash, void *keydata) { int index; struct element_t *bucket; index = hash->choose(keydata , hash->size); bucket = hash->table[index]; while (bucket != NULL) { if (hash->compare(bucket->data, keydata)) return bucket->data; bucket = bucket->next; } return NULL; } /* remove bucket (this might be used in hash_iterate() if you already found * the bucket you want to delete and don't need the overhead to find it again * with hash_remove(). But usually, you don't want to use this function, as it * fiddles with hash-internals. */ void *hash_remove_bucket(struct hashtable_t *hash, struct hash_it_t *hash_it_t) { void *data_save; /* save the pointer to the data */ data_save = hash_it_t->bucket->data; if (hash_it_t->prev_bucket != NULL) hash_it_t->prev_bucket->next = hash_it_t->bucket->next; else if (hash_it_t->first_bucket != NULL) (*hash_it_t->first_bucket) = hash_it_t->bucket->next; debugFree(hash_it_t->bucket, 1306); hash->elements--; return data_save; } /* removes data from hash, if found. returns pointer do data on success, * so you can remove the used structure yourself, or NULL on error . * data could be the structure you use with just the key filled, * we just need the key for comparing. */ void *hash_remove(struct hashtable_t *hash, void *data) { struct hash_it_t hash_it_t; hash_it_t.index = hash->choose(data, hash->size); hash_it_t.bucket = hash->table[hash_it_t.index]; hash_it_t.prev_bucket = NULL; while (hash_it_t.bucket != NULL) { if (hash->compare(hash_it_t.bucket->data, data)) { int bucket_same; bucket_same = (hash_it_t.bucket == hash->table[hash_it_t.index]); hash_it_t.first_bucket = (bucket_same ? &hash->table[hash_it_t.index] : NULL); return hash_remove_bucket(hash, &hash_it_t); } hash_it_t.prev_bucket = hash_it_t.bucket; hash_it_t.bucket = hash_it_t.bucket->next; } return NULL; } /* resize the hash, returns the pointer to the new hash or NULL on error. * removes the old hash on success. */ struct hashtable_t *hash_resize(struct hashtable_t *hash, int size) { struct hashtable_t *new_hash; struct element_t *bucket; int i; /* initialize a new hash with the new size */ new_hash = hash_new(size, hash->compare, hash->choose); if (!new_hash) return NULL; /* copy the elements */ for (i = 0; i < hash->size; i++) { while (hash->table[i]) { bucket = hash->table[i]; hash->table[i] = bucket->next; hash_add_bucket(new_hash, bucket->data, bucket, 0); } } /* remove hash and eventual overflow buckets but not the * content itself. */ hash_delete(hash, NULL); return new_hash; } /* print the hash table for debugging */ /* void hash_debug(struct hashtable_t *hash) { int i; struct element_t *bucket; for (i = 0; i < hash->size; i++) { printf("[%d] ", i); bucket = hash->table[i]; while (bucket) { printf("-> [%10p] ", (void *)bucket); bucket = bucket->next; } printf("\n"); } printf("\n"); }*/ batmand-0.3.2+74+g2f62b17/hash.h000066400000000000000000000075041435410210600156020ustar00rootroot00000000000000/* * Copyright (C) 2006-2012 B.A.T.M.A.N. contributors: * * Simon Wunderlich, Marek Lindner * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public * License as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA * */ #ifndef _BATMAND_HASH_H #define _BATMAND_HASH_H typedef int (*hashdata_compare_cb)(void *, void *); typedef int (*hashdata_choose_cb)(void *, int); typedef void (*hashdata_free_cb)(void *); struct element_t { void *data; /* pointer to the data */ struct element_t *next; /* overflow bucket pointer */ }; struct hash_it_t { int index; struct element_t *bucket; struct element_t *prev_bucket; struct element_t **first_bucket; }; struct hashtable_t { struct element_t **table; /* the hashtable itself, with the * buckets */ int elements; /* number of elements registered */ int size; /* size of hashtable */ hashdata_compare_cb compare; /* callback to a compare function. * should compare 2 element datas for * their keys, return 0 if same and not * 0 if not same */ hashdata_choose_cb choose; /* the hashfunction, should return an * index based on the key in the data * of the first argument and the size * the second */ }; /* clears the hash */ void hash_init(struct hashtable_t *hash); /* allocates and clears the hash */ struct hashtable_t *hash_new(int size, hashdata_compare_cb compare, hashdata_choose_cb choose); /* remove bucket (this might be used in hash_iterate() if you already found * the bucket you want to delete and don't need the overhead to find it again * with hash_remove(). But usually, you don't want to use this function, as it * fiddles with hash-internals. */ void *hash_remove_bucket(struct hashtable_t *hash, struct hash_it_t *hash_it_t); /* remove the hash structure. if hashdata_free_cb != NULL, * this function will be called to remove the elements inside of the hash. * if you don't remove the elements, memory might be leaked. */ void hash_delete(struct hashtable_t *hash, hashdata_free_cb free_cb); /* free only the hashtable and the hash itself. */ void hash_destroy(struct hashtable_t *hash); /* adds data to the hashtable. returns 0 on success, -1 on error */ int hash_add(struct hashtable_t *hash, void *data); /* removes data from hash, if found. returns pointer do data on success, * so you can remove the used structure yourself, or NULL on error . * data could be the structure you use with just the key filled, * we just need the key for comparing. */ void *hash_remove(struct hashtable_t *hash, void *data); /* finds data, based on the key in keydata. returns the found data on success, * or NULL on error */ void *hash_find(struct hashtable_t *hash, void *keydata); /* resize the hash, returns the pointer to the new hash or NULL on error. * removes the old hash on success */ struct hashtable_t *hash_resize(struct hashtable_t *hash, int size); /* print the hash table for debugging */ void hash_debug(struct hashtable_t *hash); /* iterate though the hash. first element is selected with iter_in NULL. * use the returned iterator to access the elements until hash_it_t * returns NULL. */ struct hash_it_t *hash_iterate(struct hashtable_t *hash, struct hash_it_t *iter_in); /* free hash_it_t pointer when stopping hash_iterate early */ void hash_iterate_free(struct hash_it_t *iter_in); #endif batmand-0.3.2+74+g2f62b17/hna.c000066400000000000000000000555141435410210600154240ustar00rootroot00000000000000/* * Copyright (C) 2006-2012 B.A.T.M.A.N. contributors: * * Simon Wunderlich, Marek Lindner * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public * License as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA * */ #include "allocate.h" #include "hna.h" #include "os.h" #include "hash.h" #include "packet.h" #include "types.h" #include #include #include #include #include #include #include #include #include unsigned char *hna_buff_local = NULL; uint8_t num_hna_local = 0; struct list_head_first hna_list; struct list_head_first hna_chg_list; static pthread_mutex_t hna_chg_list_mutex; static struct hashtable_t *hna_global_hash = NULL; static int compare_hna(void *data1, void *data2) { return (memcmp(data1, data2, 5) == 0 ? 1 : 0); } static int choose_hna(void *data, int32_t size) { unsigned char *key= data; uint32_t hash = 0; size_t i; for (i = 0; i < 5; i++) { hash += key[i]; hash += (hash << 10); hash ^= (hash >> 6); } hash += (hash << 3); hash ^= (hash >> 11); hash += (hash << 15); return (hash % size); } void hna_init(void) { /* hna local */ INIT_LIST_HEAD_FIRST(hna_list); INIT_LIST_HEAD_FIRST(hna_chg_list); pthread_mutex_init(&hna_chg_list_mutex, NULL); /* hna global */ hna_global_hash = hash_new(128, compare_hna, choose_hna); if (hna_global_hash == NULL) { printf("Error - Could not create hna_global_hash (out of memory?)\n"); exit(EXIT_FAILURE); } } /* this function can be called when the daemon starts or at runtime */ void hna_local_task_add_ip(uint32_t ip_addr, uint16_t netmask, uint8_t route_action) { struct hna_task *hna_task; hna_task = debugMalloc(sizeof(struct hna_task), 701); memset(hna_task, 0, sizeof(struct hna_task)); INIT_LIST_HEAD(&hna_task->list); hna_task->addr = ip_addr; hna_task->netmask = netmask; hna_task->route_action = route_action; if (pthread_mutex_lock(&hna_chg_list_mutex) != 0) debug_output(0, "Error - could not lock hna_chg_list mutex in %s(): %s \n", __func__, strerror(errno)); list_add_tail(&hna_task->list, &hna_chg_list); if (pthread_mutex_unlock(&hna_chg_list_mutex) != 0) debug_output(0, "Error - could not unlock hna_chg_list mutex in %s(): %s \n", __func__, strerror(errno)); } /* this function can be called when the daemon starts or at runtime */ void hna_local_task_add_str(char *hna_string, uint8_t route_action, uint8_t runtime) { struct in_addr tmp_ip_holder; uint16_t netmask; char *slash_ptr; if ((slash_ptr = strchr(hna_string, '/')) == NULL) { if (runtime) { debug_output(3, "Invalid announced network (netmask is missing): %s\n", hna_string); return; } printf("Invalid announced network (netmask is missing): %s\n", hna_string); exit(EXIT_FAILURE); } *slash_ptr = '\0'; if (inet_pton(AF_INET, hna_string, &tmp_ip_holder) < 1) { *slash_ptr = '/'; if (runtime) { debug_output(3, "Invalid announced network (IP is invalid): %s\n", hna_string); return; } printf("Invalid announced network (IP is invalid): %s\n", hna_string); exit(EXIT_FAILURE); } errno = 0; netmask = strtol(slash_ptr + 1, NULL, 10); if ((errno == ERANGE) || (errno != 0 && netmask == 0)) { *slash_ptr = '/'; if (runtime) return; perror("strtol"); exit(EXIT_FAILURE); } if (netmask < 1 || netmask > 32) { *slash_ptr = '/'; if (runtime) { debug_output(3, "Invalid announced network (netmask is invalid): %s\n", hna_string); return; } printf("Invalid announced network (netmask is invalid): %s\n", hna_string); exit(EXIT_FAILURE); } *slash_ptr = '/'; tmp_ip_holder.s_addr = (tmp_ip_holder.s_addr & htonl(0xFFFFFFFF << (32 - netmask))); hna_local_task_add_ip(tmp_ip_holder.s_addr, netmask, route_action); } static void hna_local_buffer_fill(void) { struct hna_local_entry *hna_local_entry; if (hna_buff_local != NULL) debugFree(hna_buff_local, 1701); num_hna_local = 0; hna_buff_local = NULL; if (list_empty(&hna_list)) return; list_for_each_entry(hna_local_entry, &hna_list, list) { hna_buff_local = debugRealloc(hna_buff_local, (num_hna_local + 1) * 5 * sizeof(unsigned char), 15); memmove(&hna_buff_local[num_hna_local * 5], (unsigned char *)&hna_local_entry->addr, 4); hna_buff_local[(num_hna_local * 5) + 4] = (unsigned char)hna_local_entry->netmask; num_hna_local++; } } void hna_local_task_exec(void) { struct list_head *list_pos, *list_pos_tmp, *prev_list_head; struct list_head *hna_pos, *hna_pos_tmp; struct hna_task *hna_task; struct hna_local_entry *hna_local_entry; char hna_addr_str[ADDR_STR_LEN]; if (pthread_mutex_trylock(&hna_chg_list_mutex) != 0) return; if (list_empty(&hna_chg_list)) goto unlock_chg_list; list_for_each_safe(list_pos, list_pos_tmp, &hna_chg_list) { hna_task = list_entry(list_pos, struct hna_task, list); addr_to_string(hna_task->addr, hna_addr_str, sizeof(hna_addr_str)); hna_local_entry = NULL; prev_list_head = (struct list_head *)&hna_list; list_for_each_safe(hna_pos, hna_pos_tmp, &hna_list) { hna_local_entry = list_entry(hna_pos, struct hna_local_entry, list); if ((hna_task->addr == hna_local_entry->addr) && (hna_task->netmask == hna_local_entry->netmask)) { if (hna_task->route_action == ROUTE_DEL) { debug_output(3, "Deleting HNA from announce network list: %s/%i\n", hna_addr_str, hna_task->netmask); hna_local_update_routes(hna_local_entry, ROUTE_DEL); list_del(prev_list_head, hna_pos, &hna_list); debugFree(hna_local_entry, 1702); } else { debug_output(3, "Can't add HNA - already announcing network: %s/%i\n", hna_addr_str, hna_task->netmask); } break; } prev_list_head = &hna_local_entry->list; hna_local_entry = NULL; } if (hna_local_entry == NULL) { if (hna_task->route_action == ROUTE_ADD) { debug_output(3, "Adding HNA to announce network list: %s/%i\n", hna_addr_str, hna_task->netmask); /* add node */ hna_local_entry = debugMalloc(sizeof(struct hna_local_entry), 702); memset(hna_local_entry, 0, sizeof(struct hna_local_entry)); INIT_LIST_HEAD(&hna_local_entry->list); hna_local_entry->addr = hna_task->addr; hna_local_entry->netmask = hna_task->netmask; hna_local_update_routes(hna_local_entry, ROUTE_ADD); list_add_tail(&hna_local_entry->list, &hna_list); } else { debug_output(3, "Can't delete HNA - network is not announced: %s/%i\n", hna_addr_str, hna_task->netmask); } } list_del((struct list_head *)&hna_chg_list, list_pos, &hna_chg_list); debugFree(hna_task, 1703); } /* rewrite local buffer */ hna_local_buffer_fill(); unlock_chg_list: if (pthread_mutex_unlock(&hna_chg_list_mutex) != 0) debug_output(0, "Error - could not unlock hna_chg_list mutex in %s(): %s \n", __func__, strerror(errno)); } unsigned char *hna_local_update_vis_packet(unsigned char *vis_packet, uint16_t *vis_packet_size) { struct hna_local_entry *hna_local_entry; struct vis_data *vis_data; if (num_hna_local < 1) return vis_packet; list_for_each_entry(hna_local_entry, &hna_list, list) { *vis_packet_size += sizeof(struct vis_data); vis_packet = debugRealloc(vis_packet, *vis_packet_size, 107); vis_data = (struct vis_data *)(vis_packet + *vis_packet_size - sizeof(struct vis_data)); memcpy(&vis_data->ip, (unsigned char *)&hna_local_entry->addr, 4); vis_data->data = hna_local_entry->netmask; vis_data->type = DATA_TYPE_HNA; } return vis_packet; } void hna_local_update_routes(struct hna_local_entry *hna_local_entry, int8_t route_action) { /* add / delete throw routing entries for own hna */ add_del_route(hna_local_entry->addr, hna_local_entry->netmask, 0, 0, 0, "unknown", BATMAN_RT_TABLE_NETWORKS, ROUTE_TYPE_THROW, route_action); add_del_route(hna_local_entry->addr, hna_local_entry->netmask, 0, 0, 0, "unknown", BATMAN_RT_TABLE_HOSTS, ROUTE_TYPE_THROW, route_action); add_del_route(hna_local_entry->addr, hna_local_entry->netmask, 0, 0, 0, "unknown", BATMAN_RT_TABLE_UNREACH, ROUTE_TYPE_THROW, route_action); add_del_route(hna_local_entry->addr, hna_local_entry->netmask, 0, 0, 0, "unknown", BATMAN_RT_TABLE_TUNNEL, ROUTE_TYPE_THROW, route_action); /* do not NAT HNA networks automatically */ hna_local_update_nat(hna_local_entry->addr, hna_local_entry->netmask, route_action); } static void _hna_global_add(struct orig_node *orig_node, struct hna_element *hna_element) { struct hna_global_entry *hna_global_entry; struct hna_orig_ptr *hna_orig_ptr = NULL; struct orig_node *old_orig_node = NULL; struct hashtable_t *swaphash; int found = 0; hna_global_entry = ((struct hna_global_entry *)hash_find(hna_global_hash, hna_element)); /* add the hna node if it does not exist */ if (!hna_global_entry) { hna_global_entry = debugMalloc(sizeof(struct hna_global_entry), 703); if (!hna_global_entry) return; hna_global_entry->addr = hna_element->addr; hna_global_entry->netmask = hna_element->netmask; hna_global_entry->curr_orig_node = NULL; INIT_LIST_HEAD_FIRST(hna_global_entry->orig_list); hash_add(hna_global_hash, hna_global_entry); if (hna_global_hash->elements * 4 > hna_global_hash->size) { swaphash = hash_resize(hna_global_hash, hna_global_hash->size * 2); if (swaphash == NULL) debug_output(0, "Couldn't resize global hna hash table \n"); else hna_global_hash = swaphash; } } /* the given orig_node already is the current orig node for this HNA */ if (hna_global_entry->curr_orig_node == orig_node) return; list_for_each_entry(hna_orig_ptr, &hna_global_entry->orig_list, list) { if (hna_orig_ptr->orig_node == orig_node) { found = 1; break; } } /* append the given orig node to the list */ if (!found) { hna_orig_ptr = debugMalloc(sizeof(struct hna_orig_ptr), 704); if (!hna_orig_ptr) return; hna_orig_ptr->orig_node = orig_node; INIT_LIST_HEAD(&hna_orig_ptr->list); list_add_tail(&hna_orig_ptr->list, &hna_global_entry->orig_list); } /* our TQ value towards the HNA is better */ if ((!hna_global_entry->curr_orig_node) || (orig_node->router->tq_avg > hna_global_entry->curr_orig_node->router->tq_avg)) { old_orig_node = hna_global_entry->curr_orig_node; hna_global_entry->curr_orig_node = orig_node; /** * if we change the orig node towards the HNA we may still route via the same next hop * which does not require any routing table changes */ if ((old_orig_node) && (hna_global_entry->curr_orig_node->router->addr == old_orig_node->router->addr)) return; add_del_route(hna_element->addr, hna_element->netmask, orig_node->router->addr, orig_node->router->if_incoming->addr.sin_addr.s_addr, orig_node->router->if_incoming->if_index, orig_node->router->if_incoming->dev, BATMAN_RT_TABLE_NETWORKS, ROUTE_TYPE_UNICAST, ROUTE_ADD); } /* delete previous route */ if (old_orig_node) { add_del_route(hna_element->addr, hna_element->netmask, old_orig_node->router->addr, old_orig_node->router->if_incoming->addr.sin_addr.s_addr, old_orig_node->router->if_incoming->if_index, old_orig_node->router->if_incoming->dev, BATMAN_RT_TABLE_NETWORKS, ROUTE_TYPE_UNICAST, ROUTE_DEL); } } static void _hna_global_del(struct orig_node *orig_node, struct hna_element *hna_element) { struct list_head *list_pos, *list_pos_tmp, *prev_list_head; struct hna_global_entry *hna_global_entry; struct hna_orig_ptr *hna_orig_ptr = NULL; hna_global_entry = ((struct hna_global_entry *)hash_find(hna_global_hash, hna_element)); if (!hna_global_entry) return; hna_global_entry->curr_orig_node = NULL; prev_list_head = (struct list_head *)&hna_global_entry->orig_list; list_for_each_safe(list_pos, list_pos_tmp, &hna_global_entry->orig_list) { hna_orig_ptr = list_entry(list_pos, struct hna_orig_ptr, list); /* delete old entry in orig list */ if (hna_orig_ptr->orig_node == orig_node) { list_del(prev_list_head, list_pos, &hna_global_entry->orig_list); debugFree(hna_orig_ptr, 1707); continue; } /* find best alternative route */ if ((!hna_global_entry->curr_orig_node) || (hna_orig_ptr->orig_node->router->tq_avg > hna_global_entry->curr_orig_node->router->tq_avg)) hna_global_entry->curr_orig_node = hna_orig_ptr->orig_node; prev_list_head = &hna_orig_ptr->list; } /* set new route if available */ if (hna_global_entry->curr_orig_node) { /** * if we delete one orig node towards the HNA but we switch to an alternative * which is reachable via the same next hop no routing table changes are necessary */ if (hna_global_entry->curr_orig_node->router->addr == orig_node->router->addr) return; add_del_route(hna_element->addr, hna_element->netmask, hna_global_entry->curr_orig_node->router->addr, hna_global_entry->curr_orig_node->router->if_incoming->addr.sin_addr.s_addr, hna_global_entry->curr_orig_node->router->if_incoming->if_index, hna_global_entry->curr_orig_node->router->if_incoming->dev, BATMAN_RT_TABLE_NETWORKS, ROUTE_TYPE_UNICAST, ROUTE_ADD); } add_del_route(hna_element->addr, hna_element->netmask, orig_node->router->addr, orig_node->router->if_incoming->addr.sin_addr.s_addr, orig_node->router->if_incoming->if_index, orig_node->router->if_incoming->dev, BATMAN_RT_TABLE_NETWORKS, ROUTE_TYPE_UNICAST, ROUTE_DEL); /* if no alternative route is available remove the HNA entry completely */ if (!hna_global_entry->curr_orig_node) { hash_remove(hna_global_hash, hna_element); debugFree(hna_global_entry, 1708); } } /* hna_buff_delete searches in buf if element e is found. * * if found, delete it from the buf and return 1. * if not found, return 0. */ static int hna_buff_delete(struct hna_element *buf, int *buf_len, struct hna_element *e) { int i; int num_elements; if (buf == NULL) return 0; /* align to multiple of sizeof(struct hna_element) */ num_elements = *buf_len / sizeof(struct hna_element); for (i = 0; i < num_elements; i++) { if (memcmp(&buf[i], e, sizeof(struct hna_element)) == 0) { /* move last element forward */ memmove(&buf[i], &buf[num_elements - 1], sizeof(struct hna_element)); *buf_len -= sizeof(struct hna_element); return 1; } } return 0; } void hna_global_add(struct orig_node *orig_node, unsigned char *new_hna, int16_t new_hna_len) { struct hna_element *e, *buff; int i, num_elements; char hna_str[ADDR_STR_LEN]; if ((new_hna == NULL) || (new_hna_len == 0)) { orig_node->hna_buff = NULL; orig_node->hna_buff_len = 0; return; } orig_node->hna_buff = debugMalloc(new_hna_len, 705); orig_node->hna_buff_len = new_hna_len; memcpy(orig_node->hna_buff, new_hna, new_hna_len); /* add new routes */ num_elements = orig_node->hna_buff_len / sizeof(struct hna_element); buff = (struct hna_element *)orig_node->hna_buff; debug_output(4, "HNA information received (%i HNA network%s): \n", num_elements, (num_elements > 1 ? "s": "")); for (i = 0; i < num_elements; i++) { e = &buff[i]; addr_to_string(e->addr, hna_str, sizeof(hna_str)); if ((e->netmask > 0 ) && (e->netmask < 33)) debug_output(4, "hna: %s/%i\n", hna_str, e->netmask); else debug_output(4, "hna: %s/%i -> ignoring (invalid netmask) \n", hna_str, e->netmask); if ((e->netmask > 0) && (e->netmask <= 32)) _hna_global_add(orig_node, e); } } /** * hna_global_update() replaces the old add_del_hna function. This function * updates the new hna buffer for the supplied orig node and * adds/deletes/updates the announced routes. * * Instead of first deleting and then adding, we try to add new routes * before delting the old ones so that the kernel will not experience * a situation where no route is present. */ void hna_global_update(struct orig_node *orig_node, unsigned char *new_hna, int16_t new_hna_len, struct neigh_node *old_router) { struct hna_element *e, *buff; struct hna_global_entry *hna_global_entry; int i, num_elements, old_hna_len; unsigned char *old_hna; /* orig node stopped announcing any networks */ if ((orig_node->hna_buff) && ((new_hna == NULL) || (new_hna_len == 0))) { hna_global_del(orig_node); return; } /* orig node started to announce networks */ if ((!orig_node->hna_buff) && ((new_hna != NULL) || (new_hna_len != 0))) { hna_global_add(orig_node, new_hna, new_hna_len); return; } /** * next hop router changed - no need to change the global hna hash * we just have to make sure that the best orig node is still in place * NOTE: we may miss a changed HNA here which we will update with the next packet */ if (old_router != orig_node->router) { num_elements = orig_node->hna_buff_len / sizeof(struct hna_element); buff = (struct hna_element *)orig_node->hna_buff; for (i = 0; i < num_elements; i++) { e = &buff[i]; if ((e->netmask < 1) || (e->netmask > 32)) continue; hna_global_entry = ((struct hna_global_entry *)hash_find(hna_global_hash, e)); if (!hna_global_entry) continue; /* if the given orig node is not in use no routes need to change */ if (hna_global_entry->curr_orig_node != orig_node) continue; add_del_route(e->addr, e->netmask, orig_node->router->addr, orig_node->router->if_incoming->addr.sin_addr.s_addr, orig_node->router->if_incoming->if_index, orig_node->router->if_incoming->dev, BATMAN_RT_TABLE_NETWORKS, ROUTE_TYPE_UNICAST, ROUTE_ADD); add_del_route(e->addr, e->netmask, old_router->addr, old_router->if_incoming->addr.sin_addr.s_addr, old_router->if_incoming->if_index, old_router->if_incoming->dev, BATMAN_RT_TABLE_NETWORKS, ROUTE_TYPE_UNICAST, ROUTE_DEL); } return; } /** * check if the buffers even changed. if its still the same, there is no need to * update the routes. if the router changed, then we have to update all the routes * NOTE: no NULL pointer checking here because memcmp() just returns if n == 0 */ if ((orig_node->hna_buff_len == new_hna_len) && (memcmp(orig_node->hna_buff, new_hna, new_hna_len) == 0)) return; /* nothing to do */ /* changed HNA */ old_hna = orig_node->hna_buff; old_hna_len = orig_node->hna_buff_len; orig_node->hna_buff = debugMalloc(new_hna_len, 706); orig_node->hna_buff_len = new_hna_len; memcpy(orig_node->hna_buff, new_hna, new_hna_len); /* add new routes and keep old routes */ num_elements = orig_node->hna_buff_len / sizeof(struct hna_element); buff = (struct hna_element *)orig_node->hna_buff; for (i = 0; i < num_elements; i++) { e = &buff[i]; /** * if the router is the same, and the announcement was already in the old * buffer, we can keep the route. */ if (hna_buff_delete((struct hna_element *)old_hna, &old_hna_len, e) == 0) { /* not found / deleted, need to add this new route */ if ((e->netmask > 0) && (e->netmask <= 32)) _hna_global_add(orig_node, e); } } /* old routes which are not to be kept are deleted now. */ num_elements = old_hna_len / sizeof(struct hna_element); buff = (struct hna_element *)old_hna; for (i = 0; i < num_elements; i++) { e = &buff[i]; if ((e->netmask > 0) && (e->netmask <= 32)) _hna_global_del(orig_node, e); } /* dispose old hna buffer now. */ if (old_hna != NULL) debugFree(old_hna, 1704); } void hna_global_check_tq(struct orig_node *orig_node) { struct hna_element *e, *buff; struct hna_global_entry *hna_global_entry; int i, num_elements; if ((orig_node->hna_buff == NULL) || (orig_node->hna_buff_len == 0)) return; num_elements = orig_node->hna_buff_len / sizeof(struct hna_element); buff = (struct hna_element *)orig_node->hna_buff; for (i = 0; i < num_elements; i++) { e = &buff[i]; if ((e->netmask < 1) || (e->netmask > 32)) continue; hna_global_entry = ((struct hna_global_entry *)hash_find(hna_global_hash, e)); if (!hna_global_entry) continue; /* if the given orig node is not in use no routes need to change */ if (hna_global_entry->curr_orig_node == orig_node) continue; /* the TQ value has to better than the currently selected orig node */ if (hna_global_entry->curr_orig_node->router->tq_avg > orig_node->router->tq_avg) continue; /** * if we change the orig node towards the HNA we may still route via the same next hop * which does not require any routing table changes */ if (hna_global_entry->curr_orig_node->router->addr == orig_node->router->addr) goto set_orig_node; add_del_route(e->addr, e->netmask, orig_node->router->addr, orig_node->router->if_incoming->addr.sin_addr.s_addr, orig_node->router->if_incoming->if_index, orig_node->router->if_incoming->dev, BATMAN_RT_TABLE_NETWORKS, ROUTE_TYPE_UNICAST, ROUTE_ADD); add_del_route(e->addr, e->netmask, hna_global_entry->curr_orig_node->router->addr, hna_global_entry->curr_orig_node->router->if_incoming->addr.sin_addr.s_addr, hna_global_entry->curr_orig_node->router->if_incoming->if_index, hna_global_entry->curr_orig_node->router->if_incoming->dev, BATMAN_RT_TABLE_NETWORKS, ROUTE_TYPE_UNICAST, ROUTE_DEL); set_orig_node: hna_global_entry->curr_orig_node = orig_node; } } void hna_global_del(struct orig_node *orig_node) { struct hna_element *e, *buff; int i, num_elements; if ((orig_node->hna_buff == NULL) || (orig_node->hna_buff_len == 0)) return; /* delete routes */ num_elements = orig_node->hna_buff_len / sizeof(struct hna_element); buff = (struct hna_element *)orig_node->hna_buff; for (i = 0; i < num_elements; i++) { e = &buff[i]; /* not found / deleted, need to add this new route */ if ((e->netmask > 0) && (e->netmask <= 32)) _hna_global_del(orig_node, e); } debugFree(orig_node->hna_buff, 1709); orig_node->hna_buff = NULL; orig_node->hna_buff_len = 0; } static void _hna_global_hash_del(void *data) { struct hna_global_entry *hna_global_entry = data; struct hna_orig_ptr *hna_orig_ptr = NULL; struct list_head *list_pos, *list_pos_tmp; list_for_each_safe(list_pos, list_pos_tmp, &hna_global_entry->orig_list) { hna_orig_ptr = list_entry(list_pos, struct hna_orig_ptr, list); list_del((struct list_head *)&hna_global_entry->orig_list, list_pos, &hna_global_entry->orig_list); debugFree(hna_orig_ptr, 1710); } debugFree(hna_global_entry, 1711); } void hna_free(void) { struct list_head *list_pos, *list_pos_tmp; struct hna_local_entry *hna_local_entry; /* hna local */ list_for_each_safe(list_pos, list_pos_tmp, &hna_list) { hna_local_entry = list_entry(list_pos, struct hna_local_entry, list); hna_local_update_routes(hna_local_entry, ROUTE_DEL); debugFree(hna_local_entry, 1705); } if (hna_buff_local != NULL) debugFree(hna_buff_local, 1706); num_hna_local = 0; hna_buff_local = NULL; /* hna global */ if (hna_global_hash != NULL) hash_delete(hna_global_hash, _hna_global_hash_del); } batmand-0.3.2+74+g2f62b17/hna.h000066400000000000000000000046411435410210600154240ustar00rootroot00000000000000/* * Copyright (C) 2006-2012 B.A.T.M.A.N. contributors: * * Simon Wunderlich, Marek Lindner * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public * License as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA * */ #ifndef _BATMAND_HNA_H #define _BATMAND_HNA_H #include #include "list-batman.h" #include "batman.h" extern unsigned char *hna_buff_local; extern uint8_t num_hna_local; /* we print the announced hna over the unix socket */ extern struct list_head_first hna_list; /* batman client needs to feed that into the unix socket */ extern struct list_head_first hna_chg_list; struct hna_element { uint32_t addr; uint8_t netmask; } __attribute__((packed)); struct hna_task { struct list_head list; uint32_t addr; uint8_t netmask; uint8_t route_action; }; struct hna_local_entry { struct list_head list; uint32_t addr; uint8_t netmask; }; struct hna_global_entry { uint32_t addr; uint8_t netmask; struct orig_node *curr_orig_node ALIGN_POINTER; struct list_head_first orig_list ALIGN_POINTER; } __attribute__((packed)); struct hna_orig_ptr { struct list_head list; struct orig_node *orig_node; }; void hna_init(void); void hna_free(void); void hna_local_task_add_ip(uint32_t ip_addr, uint16_t netmask, uint8_t route_action); void hna_local_task_add_str(char *hna_string, uint8_t route_action, uint8_t runtime); void hna_local_task_exec(void); unsigned char *hna_local_update_vis_packet(unsigned char *vis_packet, uint16_t *vis_packet_size); void hna_local_update_routes(struct hna_local_entry *hna_local_entry, int8_t route_action); void hna_global_add(struct orig_node *orig_node, unsigned char *new_hna, int16_t new_hna_len); void hna_global_update(struct orig_node *orig_node, unsigned char *new_hna, int16_t new_hna_len, struct neigh_node *old_router); void hna_global_check_tq(struct orig_node *orig_node); void hna_global_del(struct orig_node *orig_node); #endif batmand-0.3.2+74+g2f62b17/linux/000077500000000000000000000000001435410210600156375ustar00rootroot00000000000000batmand-0.3.2+74+g2f62b17/linux/kernel.c000066400000000000000000000074501435410210600172710ustar00rootroot00000000000000/* * Copyright (C) 2006-2012 B.A.T.M.A.N. contributors: * * Thomas Lopatic * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public * License as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA * */ #include #include #include #include #include #include #include #include "../os.h" #define IOCGETNWDEV 1 #ifndef SIOCGIWNAME #define SIOCGIWNAME 0x8B01 #endif static int get_integer_file(const char* filename) { FILE *f; int32_t integer = 0; int n; if((f = fopen(filename, "r")) == NULL) return 0; n = fscanf(f, "%"SCNd32, &integer); fclose(f); if (n == 0 || n == EOF) integer = 0; return integer; } static void set_integer_file(const char* filename, int32_t integer) { FILE *f; if ((f = fopen(filename, "w")) == NULL) return; fprintf(f, "%"PRId32, integer); fclose(f); } void set_rp_filter(int32_t state, const char* dev) { char filename[100], *colon_ptr; /* if given interface is an alias use parent interface */ if ((colon_ptr = strchr(dev, ':')) != NULL) *colon_ptr = '\0'; sprintf(filename, "/proc/sys/net/ipv4/conf/%s/rp_filter", dev); set_integer_file(filename, state); if (colon_ptr != NULL) *colon_ptr = ':'; } int32_t get_rp_filter(const char *dev) { int32_t state = 0; char filename[100], *colon_ptr; /* if given interface is an alias use parent interface */ if ((colon_ptr = strchr(dev, ':')) != NULL) *colon_ptr = '\0'; sprintf(filename, "/proc/sys/net/ipv4/conf/%s/rp_filter", dev); state = get_integer_file(filename); if (colon_ptr != NULL) *colon_ptr = ':'; return state; } void set_send_redirects(int32_t state, const char* dev) { char filename[100], *colon_ptr; /* if given interface is an alias use parent interface */ if ((colon_ptr = strchr(dev, ':')) != NULL) *colon_ptr = '\0'; sprintf(filename, "/proc/sys/net/ipv4/conf/%s/send_redirects", dev); set_integer_file(filename, state); if (colon_ptr != NULL) *colon_ptr = ':'; } int32_t get_send_redirects(const char *dev) { int32_t state = 0; char filename[100], *colon_ptr; /* if given interface is an alias use parent interface */ if ((colon_ptr = strchr(dev, ':')) != NULL) *colon_ptr = '\0'; sprintf(filename, "/proc/sys/net/ipv4/conf/%s/send_redirects", dev); state = get_integer_file(filename); if (colon_ptr != NULL) *colon_ptr = ':'; return state; } void set_forwarding(int32_t state) { set_integer_file("/proc/sys/net/ipv4/ip_forward", state); } int32_t get_forwarding(void) { return get_integer_file("/proc/sys/net/ipv4/ip_forward"); } int8_t bind_to_iface(int32_t sock, const char *dev) { char *colon_ptr; /* if given interface is an alias bind to parent interface */ if ((colon_ptr = strchr(dev, ':')) != NULL) *colon_ptr = '\0'; if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, dev, strlen(dev) + 1) < 0) { if (colon_ptr != NULL) *colon_ptr = ':'; return -1; } if (colon_ptr != NULL) *colon_ptr = ':'; return 1; } int is_wifi_interface(char *dev, int fd) { struct ifreq int_req; char *colon_ptr; memset(&int_req, 0, sizeof (struct ifreq)); strncpy(int_req.ifr_name, dev, IFNAMSIZ - 1); if ((colon_ptr = strchr(int_req.ifr_name, ':')) != NULL) *colon_ptr = '\0'; if (ioctl(fd, SIOCGIWNAME, &int_req) >= 0) return 1; return 0; } batmand-0.3.2+74+g2f62b17/linux/route.c000066400000000000000000000546011435410210600171470ustar00rootroot00000000000000/* * Copyright (C) 2006-2012 B.A.T.M.A.N. contributors: * * Marek Lindner * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public * License as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA * */ #include #include /* inet_ntop() */ #include #include /* close() */ #include /* ifr_if, ifr_tun */ #include #include #include #include #include #include #include #include #include #include "../allocate.h" #include "../bitarray.h" #include "../os.h" #include "../batman.h" static const char *route_type_to_string[] = { [ROUTE_TYPE_UNICAST] = "route", [ROUTE_TYPE_UNREACHABLE] = "unreachable route", [ROUTE_TYPE_THROW] = "throw route", [ROUTE_TYPE_UNKNOWN] = "unknown route type", }; static const char *route_type_to_string_script[] = { [ROUTE_TYPE_UNICAST] = "UNICAST", [ROUTE_TYPE_UNREACHABLE] = "UNREACH", [ROUTE_TYPE_THROW] = "THROW", [ROUTE_TYPE_UNKNOWN] = "UNKNOWN", }; #ifndef NO_POLICY_ROUTING static const char *rule_type_to_string[] = { [RULE_TYPE_SRC] = "from", [RULE_TYPE_DST] = "to", [RULE_TYPE_IIF] = "iif", }; static const char *rule_type_to_string_script[] = { [RULE_TYPE_SRC] = "SRC", [RULE_TYPE_DST] = "DST", [RULE_TYPE_IIF] = "IIF", }; #endif /*** * * route types: 0 = UNICAST, 1 = THROW, 2 = UNREACHABLE * ***/ #ifdef NO_POLICY_ROUTING #include void add_del_route(uint32_t dest, uint8_t netmask, uint32_t router, uint32_t src_ip, int32_t ifi, const char *dev, uint8_t rt_table, int8_t route_type, int8_t route_action) { struct rtentry route; struct sockaddr_in *addr; char str1[16], str2[16], str3[16]; int sock; inet_ntop(AF_INET, &dest, str1, sizeof (str1)); inet_ntop(AF_INET, &router, str2, sizeof (str2)); inet_ntop(AF_INET, &src_ip, str3, sizeof(str3)); if (policy_routing_script != NULL) { dprintf(policy_routing_pipe, "ROUTE %s %s %s %i %s %s %i %s %i\n", (route_action == ROUTE_DEL ? "del" : "add"), route_type_to_string_script[route_type], str1, netmask, str2, str3, ifi, dev, rt_table); return; } /* ignore non-unicast routes as we can't handle them */ if (route_type != ROUTE_TYPE_UNICAST) return; memset(&route, 0, sizeof (struct rtentry)); addr = (struct sockaddr_in *)&route.rt_dst; addr->sin_family = AF_INET; addr->sin_addr.s_addr = dest; addr = (struct sockaddr_in *)&route.rt_genmask; addr->sin_family = AF_INET; addr->sin_addr.s_addr = (netmask == 32 ? 0xffffffff : htonl(~(0xffffffff >> netmask))); route.rt_flags = (netmask == 32 ? (RTF_HOST | RTF_UP) : RTF_UP); route.rt_metric = 1; /* adding default route */ if ((router == dest) && (dest == 0)) { addr = (struct sockaddr_in *)&route.rt_gateway; addr->sin_family = AF_INET; addr->sin_addr.s_addr = router; if (route_type != ROUTE_TYPE_UNREACHABLE) { debug_output(3, "%s default route via %s\n", (route_action == ROUTE_DEL ? "Deleting" : "Adding"), dev); debug_output(4, "%s default route via %s\n", (route_action == ROUTE_DEL ? "Deleting" : "Adding"), dev); } /* single hop neigbor */ } else if ((router == dest) && (dest != 0)) { debug_output(3, "%s route to %s via 0.0.0.0 (%s)\n", (route_action == ROUTE_DEL ? "Deleting" : "Adding"), str1, dev); debug_output(4, "%s route to %s via 0.0.0.0 (%s)\n", (route_action == ROUTE_DEL ? "Deleting" : "Adding"), str1, dev); /* multihop neighbor */ } else { addr = (struct sockaddr_in *)&route.rt_gateway; addr->sin_family = AF_INET; addr->sin_addr.s_addr = router; debug_output(3, "%s %s to %s/%i via %s (%s)\n", (route_action == ROUTE_DEL ? "Deleting" : "Adding"), route_type_to_string[route_type], str1, netmask, str2, dev); debug_output(4, "%s %s to %s/%i via %s (%s)\n", (route_action == ROUTE_DEL ? "Deleting" : "Adding"), route_type_to_string[route_type], str1, netmask, str2, dev); } route.rt_dev = dev; if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { debug_output(0, "Error - can't create socket for routing table manipulation: %s\n", strerror(errno)); return; } if (ioctl(sock, (route_action == ROUTE_DEL ? SIOCDELRT : SIOCADDRT), &route) < 0) debug_output(0, "Error - can't %s route to %s/%i via %s: %s\n", (route_action == ROUTE_DEL ? "delete" : "add"), str1, netmask, str2, strerror(errno)); close(sock); } void add_del_rule(uint32_t BATMANUNUSED(network), uint8_t BATMANUNUSED(netmask), int8_t BATMANUNUSED(rt_table), uint32_t BATMANUNUSED(prio), const char *BATMANUNUSED(iif), int8_t BATMANUNUSED(rule_type), int8_t BATMANUNUSED(rule_action)) { return; } int add_del_interface_rules(int8_t BATMANUNUSED(rule_action)) { return 1; } int flush_routes_rules(int8_t BATMANUNUSED(is_rule)) { return 1; } #else void add_del_route(uint32_t dest, uint8_t netmask, uint32_t router, uint32_t src_ip, int32_t ifi, const char *dev, uint8_t rt_table, int8_t route_type, int8_t route_action) { int netlink_sock; size_t len; uint32_t my_router; char buf[4096], str1[16], str2[16], str3[16]; struct rtattr *rta; struct sockaddr_nl nladdr; struct iovec iov; struct msghdr msg; struct nlmsghdr *nh; struct req_s { struct rtmsg rtm; char buff[4 * (sizeof(struct rtattr) + 4)]; } *req; char req_buf[NLMSG_LENGTH(sizeof(struct req_s))] ALIGN_WORD; iov.iov_base = buf; iov.iov_len = sizeof(buf); inet_ntop(AF_INET, &dest, str1, sizeof(str1)); inet_ntop(AF_INET, &router, str2, sizeof(str2)); inet_ntop(AF_INET, &src_ip, str3, sizeof(str3)); if (policy_routing_script != NULL) { dprintf(policy_routing_pipe, "ROUTE %s %s %s %i %s %s %i %s %i\n", (route_action == ROUTE_DEL ? "del" : "add"), route_type_to_string_script[route_type], str1, netmask, str2, str3, ifi, dev, rt_table); return; } /* adding default route */ if ((router == dest) && (dest == 0)) { if (route_type != ROUTE_TYPE_UNREACHABLE) { debug_output(3, "%s default route via %s (table %i)\n", (route_action == ROUTE_DEL ? "Deleting" : "Adding"), dev, rt_table); debug_output(4, "%s default route via %s (table %i)\n", (route_action == ROUTE_DEL ? "Deleting" : "Adding"), dev, rt_table); } my_router = router; /* single hop neigbor */ } else if ((router == dest) && (dest != 0)) { debug_output(3, "%s route to %s via 0.0.0.0 (table %i - %s)\n", (route_action == ROUTE_DEL ? "Deleting" : "Adding"), str1, rt_table, dev); debug_output(4, "%s route to %s via 0.0.0.0 (table %i - %s)\n", (route_action == ROUTE_DEL ? "Deleting" : "Adding"), str1, rt_table, dev); my_router = 0; /* multihop neighbor */ } else { debug_output(3, "%s %s to %s/%i via %s (table %i - %s)\n", (route_action == ROUTE_DEL ? "Deleting" : "Adding"), route_type_to_string[route_type], str1, netmask, str2, rt_table, dev); debug_output(4, "%s %s to %s/%i via %s (table %i - %s)\n", (route_action == ROUTE_DEL ? "Deleting" : "Adding"), route_type_to_string[route_type], str1, netmask, str2, rt_table, dev); my_router = router; } nh = (struct nlmsghdr *)req_buf; req = (struct req_s*)NLMSG_DATA(req_buf); memset(&nladdr, 0, sizeof(struct sockaddr_nl)); memset(req_buf, 0, NLMSG_LENGTH(sizeof(struct req_s))); memset(&msg, 0, sizeof(struct msghdr)); nladdr.nl_family = AF_NETLINK; len = sizeof(struct rtmsg) + sizeof(struct rtattr) + 4; /* additional information for the outgoing interface and the gateway */ if (route_type == ROUTE_TYPE_UNICAST) len += 2 * (sizeof(struct rtattr) + 4); if (src_ip != 0) len += sizeof(struct rtattr) + 4; nh->nlmsg_len = NLMSG_LENGTH(len); nh->nlmsg_pid = getpid(); req->rtm.rtm_family = AF_INET; req->rtm.rtm_table = rt_table; req->rtm.rtm_dst_len = netmask; if (route_action == ROUTE_DEL) { nh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; nh->nlmsg_type = RTM_DELROUTE; req->rtm.rtm_scope = RT_SCOPE_NOWHERE; } else { nh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE | NLM_F_APPEND; nh->nlmsg_type = RTM_NEWROUTE; if (route_type == ROUTE_TYPE_UNICAST && my_router == 0 && src_ip != 0) req->rtm.rtm_scope = RT_SCOPE_LINK; else req->rtm.rtm_scope = RT_SCOPE_UNIVERSE; req->rtm.rtm_protocol = RTPROT_STATIC; /* may be changed to some batman specific value - see */ switch(route_type) { case ROUTE_TYPE_UNICAST: req->rtm.rtm_type = RTN_UNICAST; break; case ROUTE_TYPE_THROW: req->rtm.rtm_type = RTN_THROW; break; case ROUTE_TYPE_UNREACHABLE: req->rtm.rtm_type = RTN_UNREACHABLE; break; default: debug_output(0, "Error - unknown route type (add_del_route): %i\n", route_type); return; } } rta = (struct rtattr *)req->buff; rta->rta_type = RTA_DST; rta->rta_len = sizeof(struct rtattr) + 4; memcpy(((char *)req->buff) + sizeof(struct rtattr), (char *)&dest, 4); if (route_type == ROUTE_TYPE_UNICAST) { rta = (struct rtattr *)(req->buff + sizeof(struct rtattr) + 4); rta->rta_type = RTA_GATEWAY; rta->rta_len = sizeof(struct rtattr) + 4; memcpy(((char *)req->buff) + 2 * sizeof(struct rtattr) + 4, (char *)&my_router, 4); rta = (struct rtattr *)(req->buff + 2 * sizeof(struct rtattr) + 8); rta->rta_type = RTA_OIF; rta->rta_len = sizeof(struct rtattr) + 4; memcpy(((char *)req->buff) + 3 * sizeof(struct rtattr) + 8, (char *)&ifi, 4); if (src_ip != 0) { rta = (struct rtattr *)(req->buff + 3 * sizeof(struct rtattr) + 12); rta->rta_type = RTA_PREFSRC; rta->rta_len = sizeof(struct rtattr) + 4; memcpy(((char *)req->buff) + 4 * sizeof(struct rtattr) + 12, (char *)&src_ip, 4); } } if ((netlink_sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)) < 0) { debug_output(0, "Error - can't create netlink socket for routing table manipulation: %s\n", strerror(errno)); return; } if (sendto(netlink_sock, req_buf, nh->nlmsg_len, 0, (struct sockaddr *)&nladdr, sizeof(struct sockaddr_nl)) < 0) { debug_output(0, "Error - can't send message to kernel via netlink socket for routing table manipulation: %s\n", strerror(errno)); close(netlink_sock); return; } msg.msg_name = (void *)&nladdr; msg.msg_namelen = sizeof(nladdr); msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = NULL; len = recvmsg(netlink_sock, &msg, 0); nh = (struct nlmsghdr *)buf; while (NLMSG_OK(nh, len)) { if (nh->nlmsg_type == NLMSG_DONE) break; if (( nh->nlmsg_type == NLMSG_ERROR) && (((struct nlmsgerr*)NLMSG_DATA(nh))->error != 0)) debug_output(0, "Error - can't %s %s to %s/%i via %s (table %i): %s\n", (route_action == ROUTE_DEL ? "delete" : "add"), route_type_to_string[route_type], str1, netmask, str2, rt_table, strerror(-((struct nlmsgerr*)NLMSG_DATA(nh))->error)); nh = NLMSG_NEXT(nh, len); } close(netlink_sock); } /*** * * rule types: 0 = RTA_SRC, 1 = RTA_DST, 2 = RTA_IIF * ***/ void add_del_rule(uint32_t network, uint8_t netmask, int8_t rt_table, uint32_t prio, const char *iif, int8_t rule_type, int8_t rule_action) { int netlink_sock; size_t len; char buf[4096], str1[16]; struct rtattr *rta; struct sockaddr_nl nladdr; struct iovec iov; struct msghdr msg; struct nlmsghdr *nh; struct req_s { struct rtmsg rtm; char buff[2 * (sizeof(struct rtattr) + 4)]; } *req; char req_buf[NLMSG_LENGTH(sizeof(struct req_s))] ALIGN_WORD; iov.iov_base = buf; iov.iov_len = sizeof(buf); inet_ntop(AF_INET, &network, str1, sizeof (str1)); if (policy_routing_script != NULL) { dprintf(policy_routing_pipe, "RULE %s %s %s %i %s %s %u %s %i\n", (rule_action == RULE_DEL ? "del" : "add"), rule_type_to_string[rule_type], str1, netmask, "unused", "unused", prio, iif, rt_table); return; } nh = (struct nlmsghdr *)req_buf; req = (struct req_s*)NLMSG_DATA(req_buf); memset(&nladdr, 0, sizeof(struct sockaddr_nl)); memset(req_buf, 0, NLMSG_LENGTH(sizeof(struct req_s))); memset(&msg, 0, sizeof(struct msghdr)); nladdr.nl_family = AF_NETLINK; len = sizeof(struct rtmsg) + sizeof(struct rtattr) + 4; if (prio != 0) len += sizeof(struct rtattr) + 4; nh->nlmsg_len = NLMSG_LENGTH(len); nh->nlmsg_pid = getpid(); req->rtm.rtm_family = AF_INET; req->rtm.rtm_table = rt_table; if (rule_action == RULE_DEL) { nh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; nh->nlmsg_type = RTM_DELRULE; req->rtm.rtm_scope = RT_SCOPE_NOWHERE; } else { nh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE | NLM_F_EXCL; nh->nlmsg_type = RTM_NEWRULE; req->rtm.rtm_scope = RT_SCOPE_UNIVERSE; req->rtm.rtm_protocol = RTPROT_STATIC; req->rtm.rtm_type = RTN_UNICAST; } switch(rule_type) { case RULE_TYPE_SRC: rta = (struct rtattr *)req->buff; rta->rta_type = RTA_SRC; req->rtm.rtm_src_len = netmask; rta->rta_len = sizeof(struct rtattr) + 4; memcpy(((char *)req->buff) + sizeof(struct rtattr), (char *)&network, 4); break; case RULE_TYPE_DST: rta = (struct rtattr *)req->buff; rta->rta_type = RTA_DST; req->rtm.rtm_dst_len = netmask; rta->rta_len = sizeof(struct rtattr) + 4; memcpy(((char *)req->buff) + sizeof(struct rtattr), (char *)&network, 4); break; case RULE_TYPE_IIF: rta = (struct rtattr *)req->buff; rta->rta_len = sizeof(struct rtattr) + 4; if (rule_action == RULE_DEL) { rta->rta_type = RTA_SRC; memcpy(((char *)req->buff) + sizeof(struct rtattr), (char *)&network, 4); } else { rta->rta_type = RTA_IIF; memcpy(((char *)req->buff) + sizeof(struct rtattr), iif, 4); } break; default: debug_output(0, "Error - unknown rule type (add_del_rule): %i\n", rule_type); return; } if (prio != 0) { rta = (struct rtattr *)(req->buff + sizeof(struct rtattr) + 4); rta->rta_type = RTA_PRIORITY; rta->rta_len = sizeof(struct rtattr) + 4; memcpy(((char *)req->buff) + 2 * sizeof(struct rtattr) + 4, (char *)&prio, 4); } if ((netlink_sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)) < 0) { debug_output(0, "Error - can't create netlink socket for routing rule manipulation: %s\n", strerror(errno)); return; } if (sendto(netlink_sock, req_buf, nh->nlmsg_len, 0, (struct sockaddr *)&nladdr, sizeof(struct sockaddr_nl)) < 0) { debug_output( 0, "Error - can't send message to kernel via netlink socket for routing rule manipulation: %s\n", strerror(errno)); close(netlink_sock); return; } msg.msg_name = (void *)&nladdr; msg.msg_namelen = sizeof(nladdr); msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = NULL; len = recvmsg(netlink_sock, &msg, 0); nh = (struct nlmsghdr *)buf; while (NLMSG_OK(nh, len)) { if (nh->nlmsg_type == NLMSG_DONE) break; if ((nh->nlmsg_type == NLMSG_ERROR) && (((struct nlmsgerr*)NLMSG_DATA(nh))->error != 0)) { inet_ntop(AF_INET, &network, str1, sizeof (str1)); debug_output(0, "Error - can't %s rule %s %s/%i: %s\n", (rule_action == RULE_DEL ? "delete" : "add"), rule_type_to_string_script[rule_type], str1, netmask, strerror(-((struct nlmsgerr*)NLMSG_DATA(nh))->error)); } nh = NLMSG_NEXT(nh, len); } close(netlink_sock); } int add_del_interface_rules(int8_t rule_action) { int32_t tmp_fd; uint32_t addr, netaddr; int len; uint8_t netmask, if_count = 1; char *buf, *buf_ptr; struct ifconf ifc; struct ifreq *ifr, ifr_tmp; struct batman_if *batman_if; tmp_fd = socket(AF_INET, SOCK_DGRAM, 0); if (tmp_fd < 0) { debug_output(0, "Error - can't %s interface rules (udp socket): %s\n", (rule_action == RULE_DEL ? "delete" : "add"), strerror(errno)); return -1; } len = 10 * sizeof(struct ifreq); /* initial buffer size guess (10 interfaces) */ while (1) { buf = debugMalloc(len, 601); ifc.ifc_len = len; ifc.ifc_buf = buf; if (ioctl(tmp_fd, SIOCGIFCONF, &ifc) < 0) { debug_output(0, "Error - can't %s interface rules (SIOCGIFCONF): %s\n", (rule_action == RULE_DEL ? "delete" : "add"), strerror(errno)); close(tmp_fd); debugFree(buf, 1606); return -1; } else { if (ifc.ifc_len < len) break; } len += 10 * sizeof(struct ifreq); debugFree(buf, 1601); } for (buf_ptr = buf; buf_ptr < buf + ifc.ifc_len;) { ifr = (struct ifreq *)buf_ptr; buf_ptr += (ifr->ifr_addr.sa_family == AF_INET6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr)) + sizeof(ifr->ifr_name); /* ignore if not IPv4 interface */ if (ifr->ifr_addr.sa_family != AF_INET) continue; /* the tunnel thread will remove the default route by itself */ if (strncmp(ifr->ifr_name, "gate", 4) == 0) continue; memset(&ifr_tmp, 0, sizeof (struct ifreq)); strncpy(ifr_tmp.ifr_name, ifr->ifr_name, IFNAMSIZ - 1); if (ioctl(tmp_fd, SIOCGIFFLAGS, &ifr_tmp ) < 0) { debug_output(0, "Error - can't get flags of interface %s (interface rules): %s\n", ifr->ifr_name, strerror(errno)); continue; } /* ignore if not up and running */ if (!( ifr_tmp.ifr_flags & IFF_UP) || !(ifr_tmp.ifr_flags & IFF_RUNNING)) continue; if (ioctl(tmp_fd, SIOCGIFADDR, &ifr_tmp) < 0) { debug_output(0, "Error - can't get IP address of interface %s (interface rules): %s\n", ifr->ifr_name, strerror(errno)); continue; } addr = ((struct sockaddr_in *)&ifr_tmp.ifr_addr)->sin_addr.s_addr; if (ioctl(tmp_fd, SIOCGIFNETMASK, &ifr_tmp) < 0) { debug_output(0, "Error - can't get netmask address of interface %s (interface rules): %s\n", ifr->ifr_name, strerror(errno)); continue; } netaddr = (((struct sockaddr_in *)&ifr_tmp.ifr_addr)->sin_addr.s_addr & addr); netmask = bit_count(((struct sockaddr_in *)&ifr_tmp.ifr_addr)->sin_addr.s_addr); add_del_route(netaddr, netmask, 0, 0, 0, ifr->ifr_name, BATMAN_RT_TABLE_TUNNEL, ROUTE_TYPE_THROW, rule_action); if (is_batman_if(ifr->ifr_name, &batman_if)) continue; add_del_rule(netaddr, netmask, BATMAN_RT_TABLE_TUNNEL, (rule_action == RULE_DEL ? 0 : BATMAN_RT_PRIO_TUNNEL + if_count), 0, RULE_TYPE_SRC, rule_action); if (strncmp( ifr->ifr_name, "lo", IFNAMSIZ - 1) == 0) add_del_rule(0, 0, BATMAN_RT_TABLE_TUNNEL, BATMAN_RT_PRIO_TUNNEL, "lo\0 ", RULE_TYPE_IIF, rule_action); if_count++; } close(tmp_fd); debugFree(buf, 1605); return 1; } int flush_routes_rules(int8_t is_rule) { int netlink_sock, rtl; size_t len; int32_t dest = 0, router = 0, ifi = 0; uint32_t prio = 0; int8_t rule_type = 0; char buf[8192], *dev = NULL; struct sockaddr_nl nladdr; struct iovec iov; struct msghdr msg; struct nlmsghdr *nh; struct rtmsg *rtm; struct req_s { struct rtmsg rtm; } *req; char req_buf[NLMSG_LENGTH(sizeof(struct req_s))] ALIGN_WORD; struct rtattr *rtap; iov.iov_base = buf; iov.iov_len = sizeof(buf); nh = (struct nlmsghdr *)req_buf; req = (struct req_s*)NLMSG_DATA(req_buf); memset(&nladdr, 0, sizeof(struct sockaddr_nl)); memset(req_buf, 0, NLMSG_LENGTH(sizeof(struct req_s))); memset(&msg, 0, sizeof(struct msghdr)); nladdr.nl_family = AF_NETLINK; nh->nlmsg_len = NLMSG_LENGTH(sizeof(struct req_s)); nh->nlmsg_pid = getpid(); req->rtm.rtm_family = AF_INET; nh->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; nh->nlmsg_type = (is_rule ? RTM_GETRULE : RTM_GETROUTE); req->rtm.rtm_scope = RTN_UNICAST; if ((netlink_sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)) < 0) { debug_output(0, "Error - can't create netlink socket for flushing the routing table: %s\n", strerror(errno)); return -1; } if (sendto(netlink_sock, req_buf, nh->nlmsg_len, 0, (struct sockaddr *)&nladdr, sizeof(struct sockaddr_nl)) < 0) { debug_output(0, "Error - can't send message to kernel via netlink socket for flushing the routing table: %s\n", strerror(errno)); close(netlink_sock); return -1; } msg.msg_name = (void *)&nladdr; msg.msg_namelen = sizeof(nladdr); msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = NULL; len = recvmsg(netlink_sock, &msg, 0); nh = (struct nlmsghdr *)buf; while (NLMSG_OK(nh, len)) { if (nh->nlmsg_type == NLMSG_DONE) break; if ((nh->nlmsg_type == NLMSG_ERROR) && (((struct nlmsgerr*)NLMSG_DATA(nh))->error != 0)) { debug_output(0, "Error - can't flush %s: %s \n", (is_rule ? "routing rules" : "routing table"), strerror(-((struct nlmsgerr*)NLMSG_DATA(nh))->error)); close(netlink_sock); return -1; } rtm = (struct rtmsg *)NLMSG_DATA(nh); rtap = (struct rtattr *)RTM_RTA(rtm); rtl = RTM_PAYLOAD(nh); nh = NLMSG_NEXT(nh, len); if ((rtm->rtm_table != BATMAN_RT_TABLE_UNREACH) && (rtm->rtm_table != BATMAN_RT_TABLE_NETWORKS) && (rtm->rtm_table != BATMAN_RT_TABLE_HOSTS) && (rtm->rtm_table != BATMAN_RT_TABLE_TUNNEL)) continue; while (RTA_OK(rtap, rtl)) { switch(rtap->rta_type) { case RTA_DST: dest = *((int32_t *)RTA_DATA(rtap)); rule_type = ROUTE_TYPE_UNREACHABLE; break; case RTA_SRC: dest = *((int32_t *)RTA_DATA(rtap)); rule_type = ROUTE_TYPE_UNICAST; break; case RTA_GATEWAY: router = *((int32_t *)RTA_DATA(rtap)); break; case RTA_OIF: ifi = *((int32_t *)RTA_DATA(rtap)); break; case RTA_PRIORITY: prio = *((uint32_t *)RTA_DATA(rtap)); break; case RTA_IIF: dev = ((char *)RTA_DATA(rtap)); rule_type = ROUTE_TYPE_THROW; break; case 15: /* FIXME: RTA_TABLE is not always available - not needed but avoid warning */ break; case RTA_PREFSRC: /* rta_type 7 - not needed but avoid warning */ break; default: debug_output(0, "Error - unknown rta type: %i \n", rtap->rta_type); break; } rtap = RTA_NEXT(rtap,rtl); } if (is_rule) { switch (rule_type) { case ROUTE_TYPE_UNICAST: add_del_rule(dest, rtm->rtm_src_len, rtm->rtm_table, prio, 0 , rule_type, RULE_DEL); break; case ROUTE_TYPE_THROW: add_del_rule(dest, rtm->rtm_dst_len, rtm->rtm_table, prio, 0 , rule_type, RULE_DEL); break; case ROUTE_TYPE_UNREACHABLE: add_del_rule(0 , 0, rtm->rtm_table, prio, dev , rule_type, RULE_DEL); break; } } else { switch (rtm->rtm_type) { case RTN_UNICAST: rule_type = ROUTE_TYPE_UNICAST; break; case RTN_THROW: rule_type = ROUTE_TYPE_THROW; break; case RTN_UNREACHABLE: rule_type = ROUTE_TYPE_UNREACHABLE; break; default: rule_type = ROUTE_TYPE_UNKNOWN; break; } /* sometimes dest and router are not reset */ if (rule_type == ROUTE_TYPE_UNREACHABLE) dest = router = 0; add_del_route(dest, rtm->rtm_dst_len, router, 0, ifi, "unknown", rtm->rtm_table, rule_type, ROUTE_DEL); } } close(netlink_sock); return 1; } #endif batmand-0.3.2+74+g2f62b17/linux/tun.c000066400000000000000000000202551435410210600166150ustar00rootroot00000000000000/* * Copyright (C) 2006-2012 B.A.T.M.A.N. contributors: * * Marek Lindner * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public * License as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA * */ #include /* close() */ #include /* open(), O_RDWR */ #include #include #include /* inet_ntop() */ #include #include /* TUNSETPERSIST, ... */ #include /* ifr_if, ifr_tun */ #include #include #include /* system() */ #include /* WEXITSTATUS */ #include #include #include #include "../os.h" #include "../batman.h" #include "../types.h" #define IPTABLES_ADD_MASQ "iptables -t nat -A POSTROUTING -o %s -j MASQUERADE" #define IPTABLES_DEL_MASQ "iptables -t nat -D POSTROUTING -o %s -j MASQUERADE" #define IPTABLES_ADD_MSS "iptables -t mangle -I POSTROUTING -p tcp --tcp-flags SYN,RST SYN -o %s -j TCPMSS --clamp-mss-to-pmtu" #define IPTABLES_DEL_MSS "iptables -t mangle -D POSTROUTING -p tcp --tcp-flags SYN,RST SYN -o %s -j TCPMSS --clamp-mss-to-pmtu" #define IPTABLES_ADD_ACC "iptables -t nat -I POSTROUTING -s %s/%i -j ACCEPT" #define IPTABLES_DEL_ACC "iptables -t nat -D POSTROUTING -s %s/%i -j ACCEPT" static int run_cmd(const char *cmd) { int error, pipes[2], stderr = -1, ret = 0; char error_log[256]; if (pipe(pipes) < 0) { debug_output(3, "Warning - could not create a pipe to '%s': %s\n", cmd, strerror(errno)); return -1; } memset(error_log, 0, 256); /* save stderr */ stderr = dup(STDERR_FILENO); /* connect the commands output with the pipe for later logging */ dup2(pipes[1], STDERR_FILENO); close(pipes[1]); error = system(cmd); /* copy stderr back */ dup2(stderr, STDERR_FILENO); close(stderr); if ((error < 0) || (WEXITSTATUS(error) != 0)) { ret = read(pipes[0], error_log, sizeof(error_log)); debug_output(3, "Warning - command '%s' returned an error\n", cmd); if (ret > 0) debug_output(3, " %s\n", error_log); ret = -1; } close(pipes[0]); return ret; } /* Probe for iptables binary availability */ int probe_nat_tool(void) { return run_cmd("which iptables > /dev/null"); } static void exec_iptables_rule(const char *cmd, int8_t route_action) { if (disable_client_nat) return; if (nat_tool_avail == -1) { debug_output(3, "Warning - could not %sactivate NAT: iptables binary not found!\n", (route_action == ROUTE_ADD ? "" : "de")); debug_output(3, " You may need to run this command: %s\n", cmd); return; } run_cmd(cmd); } void add_nat_rule(char *dev) { char cmd[150]; sprintf(cmd, IPTABLES_ADD_MASQ, dev); exec_iptables_rule(cmd, ROUTE_ADD); sprintf(cmd, IPTABLES_ADD_MSS, dev); exec_iptables_rule(cmd, ROUTE_ADD); } void del_nat_rule(char *dev) { char cmd[150]; sprintf(cmd, IPTABLES_DEL_MASQ, dev); exec_iptables_rule(cmd, ROUTE_DEL); sprintf(cmd, IPTABLES_ADD_MSS, dev); exec_iptables_rule(cmd, ROUTE_DEL); } void hna_local_update_nat(uint32_t hna_ip, uint8_t netmask, int8_t route_action) { char cmd[100], ip_addr[16]; inet_ntop(AF_INET, &hna_ip, ip_addr, sizeof(ip_addr)); if (route_action == ROUTE_DEL) sprintf(cmd, IPTABLES_DEL_ACC, ip_addr, netmask); else sprintf(cmd, IPTABLES_ADD_ACC, ip_addr, netmask); exec_iptables_rule(cmd, route_action); } /* Probe for tun interface availability */ int8_t probe_tun(uint8_t print_to_stderr) { int32_t fd; if ( ( fd = open( "/dev/net/tun", O_RDWR ) ) < 0 ) { if (print_to_stderr) fprintf( stderr, "Error - could not open '/dev/net/tun' ! Is the tun kernel module loaded ?\n" ); else debug_output( 0, "Error - could not open '/dev/net/tun' ! Is the tun kernel module loaded ?\n" ); return 0; } close( fd ); return 1; } int8_t del_dev_tun( int32_t fd ) { if ( ioctl( fd, TUNSETPERSIST, 0 ) < 0 ) { debug_output( 0, "Error - can't delete tun device: %s\n", strerror(errno) ); return -1; } close( fd ); return 1; } int8_t add_dev_tun( struct batman_if *batman_if, uint32_t tun_addr, char *tun_dev, size_t tun_dev_size, int32_t *fd, int32_t *ifi ) { int32_t tmp_fd, sock_opts; struct ifreq ifr_tun, ifr_if; struct sockaddr_in addr; /* set up tunnel device */ memset( &ifr_tun, 0, sizeof(ifr_tun) ); memset( &ifr_if, 0, sizeof(ifr_if) ); ifr_tun.ifr_flags = IFF_TUN | IFF_NO_PI; strncpy( ifr_tun.ifr_name, "gate%d", IFNAMSIZ ); if ( ( *fd = open( "/dev/net/tun", O_RDWR ) ) < 0 ) { debug_output( 0, "Error - can't create tun device (/dev/net/tun): %s\n", strerror(errno) ); return -1; } if ( ( ioctl( *fd, TUNSETIFF, (void *)&ifr_tun ) ) < 0 ) { debug_output( 0, "Error - can't create tun device (TUNSETIFF): %s\n", strerror(errno) ); close(*fd); return -1; } if ( ioctl( *fd, TUNSETPERSIST, 1 ) < 0 ) { debug_output( 0, "Error - can't create tun device (TUNSETPERSIST): %s\n", strerror(errno) ); close(*fd); return -1; } tmp_fd = socket( AF_INET, SOCK_DGRAM, 0 ); if ( tmp_fd < 0 ) { debug_output( 0, "Error - can't create tun device (udp socket): %s\n", strerror(errno) ); del_dev_tun( *fd ); return -1; } /* set ip of this end point of tunnel */ memset( &addr, 0, sizeof(addr) ); addr.sin_addr.s_addr = tun_addr; addr.sin_family = AF_INET; memcpy( &ifr_tun.ifr_addr, &addr, sizeof(struct sockaddr) ); if ( ioctl( tmp_fd, SIOCSIFADDR, &ifr_tun) < 0 ) { debug_output( 0, "Error - can't create tun device (SIOCSIFADDR): %s\n", strerror(errno) ); del_dev_tun( *fd ); close( tmp_fd ); return -1; } if ( ioctl( tmp_fd, SIOCGIFINDEX, &ifr_tun ) < 0 ) { debug_output( 0, "Error - can't create tun device (SIOCGIFINDEX): %s\n", strerror(errno) ); del_dev_tun( *fd ); close( tmp_fd ); return -1; } *ifi = ifr_tun.ifr_ifindex; if ( ioctl( tmp_fd, SIOCGIFFLAGS, &ifr_tun) < 0 ) { debug_output( 0, "Error - can't create tun device (SIOCGIFFLAGS): %s\n", strerror(errno) ); del_dev_tun( *fd ); close( tmp_fd ); return -1; } ifr_tun.ifr_flags |= IFF_UP; ifr_tun.ifr_flags |= IFF_RUNNING; if ( ioctl( tmp_fd, SIOCSIFFLAGS, &ifr_tun) < 0 ) { debug_output( 0, "Error - can't create tun device (SIOCSIFFLAGS): %s\n", strerror(errno) ); del_dev_tun( *fd ); close( tmp_fd ); return -1; } /* get MTU from real interface */ strncpy( ifr_if.ifr_name, batman_if->dev, IFNAMSIZ - 1 ); if ( ioctl( tmp_fd, SIOCGIFMTU, &ifr_if ) < 0 ) { debug_output( 0, "Error - can't create tun device (SIOCGIFMTU): %s\n", strerror(errno) ); del_dev_tun( *fd ); close( tmp_fd ); return -1; } /* set MTU of tun interface: real MTU - 29 */ if ( ifr_if.ifr_mtu < 100 ) { debug_output( 0, "Warning - MTU smaller than 100 -> can't reduce MTU anymore\n" ); } else { ifr_tun.ifr_mtu = ifr_if.ifr_mtu - 29; if ( ioctl( tmp_fd, SIOCSIFMTU, &ifr_tun ) < 0 ) { debug_output( 0, "Error - can't create tun device (SIOCSIFMTU): %s\n", strerror(errno) ); del_dev_tun( *fd ); close( tmp_fd ); return -1; } } /* make tun socket non blocking */ sock_opts = fcntl( *fd, F_GETFL, 0 ); fcntl( *fd, F_SETFL, sock_opts | O_NONBLOCK ); strncpy( tun_dev, ifr_tun.ifr_name, tun_dev_size - 1 ); close( tmp_fd ); return 1; } int8_t set_tun_addr( int32_t fd, uint32_t tun_addr, char *tun_dev ) { struct sockaddr_in addr; struct ifreq ifr_tun; memset( &ifr_tun, 0, sizeof(ifr_tun) ); memset( &addr, 0, sizeof(addr) ); addr.sin_addr.s_addr = tun_addr; addr.sin_family = AF_INET; memcpy( &ifr_tun.ifr_addr, &addr, sizeof(struct sockaddr) ); strncpy( ifr_tun.ifr_name, tun_dev, IFNAMSIZ - 1 ); if ( ioctl( fd, SIOCSIFADDR, &ifr_tun) < 0 ) { debug_output( 0, "Error - can't set tun address (SIOCSIFADDR): %s\n", strerror(errno) ); return -1; } return 1; } batmand-0.3.2+74+g2f62b17/list-batman.c000066400000000000000000000055271435410210600170700ustar00rootroot00000000000000/* * Copyright (C) 2006-2012 B.A.T.M.A.N. contributors: * * Marek Lindner * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public * License as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA * */ #include "list-batman.h" /* * Insert a new entry between two known consecutive entries. * * This is only for internal list manipulation where we know * the next entries already! */ static void __list_add( struct list_head *new, struct list_head *prev, struct list_head *next ) { new->next = next; prev->next = new; } /** * list_add - add a new entry * @new: new entry to be added * @head: list head to add it after * * Insert a new entry after the specified head. * This is good for implementing stacks. */ void list_add( struct list_head *new, struct list_head_first *head ) { __list_add( new, (struct list_head *)head, head->next ); if ( head->prev == (struct list_head *)head ) head->prev = new; } /** * list_add_tail - add a new entry * @new: new entry to be added * @head: list head to add it before * * Insert a new entry before the specified head. * This is useful for implementing queues. */ void list_add_tail( struct list_head *new, struct list_head_first *head ) { __list_add( new, head->prev, (struct list_head *)head ); head->prev = new; } void list_add_before( struct list_head *prev_node, struct list_head *next_node, struct list_head *new_node ) { prev_node->next = new_node; new_node->next = next_node; } /* * Delete a list entry by making the next entries * point to each other. * * This is only for internal list manipulation where we know * the next entries already! */ static void __list_del( struct list_head *prev, struct list_head *next ) { prev->next = next; } /** * list_del - deletes entry from list. * @entry: the element to delete from the list. * Note: list_empty on entry does not return true after this, the entry is in an undefined state. */ void list_del( struct list_head *prev_entry, struct list_head *entry, struct list_head_first *head ) { if ( head->prev == entry ) head->prev = prev_entry; __list_del( prev_entry, entry->next ); entry->next = (void *) 0; } /** * list_empty - tests whether a list is empty * @head: the list to test. */ int list_empty( struct list_head_first *head ) { return head->next == (struct list_head *)head; } batmand-0.3.2+74+g2f62b17/list-batman.h000066400000000000000000000076511435410210600170750ustar00rootroot00000000000000/* * Copyright (C) 2006-2012 B.A.T.M.A.N. contributors: * * Marek Lindner * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public * License as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA * */ #ifndef _LINUX_LIST_H #define _LINUX_LIST_H /* * Simple linked list implementation. * * Some of the internal functions ("__xxx") are useful when * manipulating whole lists rather than single entries, as * sometimes we already know the next entries and we can * generate better code by using them directly rather than * using the generic single-entry routines. */ struct list_head { struct list_head *next; }; struct list_head_first { struct list_head *next, *prev; }; void list_add( struct list_head *new, struct list_head_first *head ); void list_add_tail( struct list_head *new, struct list_head_first *head ); void list_add_before( struct list_head *prev_node, struct list_head *next_node, struct list_head *new_node ); void list_del( struct list_head *prev_entry, struct list_head *entry, struct list_head_first *head ); int list_empty( struct list_head_first *head ); #define INIT_LIST_HEAD(ptr) do { \ (ptr)->next = (ptr); \ } while (0) #define INIT_LIST_HEAD_FIRST(ptr) \ ptr.next = (struct list_head *)&ptr; ptr.prev = (struct list_head *)&ptr; \ /** * list_entry - get the struct for this entry * @ptr: the &struct list_head pointer. * @type: the type of the struct this is embedded in. * @member: the name of the list_struct within the struct. */ #define list_entry(ptr, type, member) \ ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))) /** * list_for_each - iterate over a list * @pos: the &struct list_head to use as a loop counter. * @head: the head for your list. */ #define list_for_each(pos, head) \ for (pos = (head)->next; pos != (struct list_head *)(head); \ pos = pos->next) /** * list_for_each_safe - iterate over a list safe against removal of list entry * @pos: the &struct list_head to use as a loop counter. * @n: another &struct list_head to use as temporary storage * @head: the head for your list. */ #define list_for_each_safe(pos, n, head) \ for (pos = (head)->next, n = pos->next; pos != (struct list_head *)(head); \ pos = n, n = pos->next) /** * list_for_each_entry - iterate over list of given type * @pos: the type * to use as a loop counter. * @head: the head for your list. * @member: the name of the list_struct within the struct. */ #define list_for_each_entry(pos, head, member) \ for (pos = list_entry((head)->next, typeof(*pos), member); \ &pos->member != (struct list_head *)(head); \ pos = list_entry(pos->member.next, typeof(*pos), member)) /** * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry * @pos: the type * to use as a loop counter. * @n: another type * to use as temporary storage * @head: the head for your list. * @member: the name of the list_struct within the struct. */ #define list_for_each_entry_safe(pos, n, head, member) \ for (pos = list_entry((head)->next, typeof(*pos), member), \ n = list_entry(pos->member.next, typeof(*pos), member); \ &pos->member != (struct list_head *)(head); \ pos = n, n = list_entry(n->member.next, typeof(*n), member)) #endif batmand-0.3.2+74+g2f62b17/man/000077500000000000000000000000001435410210600152535ustar00rootroot00000000000000batmand-0.3.2+74+g2f62b17/man/batmand.8000066400000000000000000000205561435410210600167620ustar00rootroot00000000000000.\" Hey, EMACS: -*- nroff -*- .\" First parameter, NAME, should be all caps .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection .\" other parameters are allowed: see man(7), man(1) .TH BATMAND 8 "Sep 7, 2007" .\" Please adjust this date whenever revising the manpage. .\" .\" Some roff macros, for reference: .\" .nh disable hyphenation .\" .hy enable hyphenation .\" .ad l left justify .\" .ad b justify to both left and right margins .\" .nf disable filling .\" .fi enable filling .\" .br insert line break .\" .sp insert n+1 empty lines .\" for manpage-specific macros, see man(7) .\" -------------------------------------------------------------------------- .\" Process this file with .\" groff -man batmand.8 -Tutf8 .\" -------------------------------------------------------------------------- .TH "batmand" 8 .SH NAME batmand \- better approach to mobile ad\(hyhoc networking .SH SYNOPSIS .B batmand .RI [ options ] interface [ interface ... ] .br .SH DESCRIPTION .B B.A.T.M.A.N means better approach to mobile ad\(hyhoc networking, this is a new routing protocol for multi\(hyhop ad\(hyhoc mesh networks. Go to https://www.open\-mesh.org/ to get more information. .PP The following document will explain how to use the \fBbatman daemon\fP. .PP The batmand binary can be run in 2 different ways. First you need to start the daemon with "batmand [options] interface" (daemon mode) and then you can connect to that daemon to issue further commands with "batmand \-c [options]" (client mode). Some of the options below are always available, some are not. See the example section to get an idea. .SH OPTIONS .TP .B \-a add announced network(s) Add networks to the daemons list of available connections to another network(s). This option can be used multiple times and can be used to add networks dynamically while the daemon is running. The parameter has to be in the form of ip\(hyaddress/netmask. .TP .B \-A delete announced network(s) Delete networks to the daemons list of available connections to another network(s). This option can be used multiple times and can only be used while the daemon is running. The parameter has to be in the form of ip\(hyaddress/netmask. .TP .B \-b run debug connection in batch mode The debug information are updated after a period of time by default, so if you use "\-b" it will execute once and then stop. This option is useful for script integration of the debug output and is only available in client mode together with "\-d 1" or "\-d 2". .TP .B \-c connect via unix socket Use this option to switch to client mode. Deploy it without any arguments to get the current configuration even if changed at runtime. .TP .B \-d debug level The debug level can be set to five values. .RS 17 default: 0 \-> debug disabled .RE .RS 10 allowed values: 1 \-> list neighbors .RE .RS 25 2 \-> list gateways 3 \-> observe batman 4 \-> observe batman (verbose) 5 \-> memory debug / cpu usage .RE .RS 7 Note that debug level 5 can be disabled at compile time. .RE .TP .B \-g gateway class The gateway class is used to tell other nodes in the network your available internet bandwidth. Just enter any number (optionally followed by "kbit" or "mbit") and the daemon will guess your appropriate gateway class. Use "/" to separate the down\(hy and upload rates. You can omit the upload rate and batmand will assume an upload of download / 5. .RS 17 default: 0 \-> gateway disabled .RE .RS 10 allowed values: 5000 .RE .RS 25 5000kbit 5mbit 5mbit/1024 5mbit/1024kbit 5mbit/1mbit .RE .TP .B \-h short help .TP .B \-H verbose help .TP .B \-o originator interval in ms A node transmits broadcast messages (we call them originator message or OGM) to inform the neighboring nodes about it's existence. Originator interval is the time to wait after sending one message and before sending the next message. The default value is 1000 ms (1 second). In a mobile network, you may want to detect network changes very quickly, so you need to send message very often, for example, use a value of 500 ms. In a static network, you can save bandwidth by using a higher value. This option is only available in daemon mode. .TP .B \-p preferred gateway Set the internet gateway by yourself. Note: This automatically switches your daemon to "internet search mode" with "\-r 1" unless "\-r" is given. If the preferred gateway is not found the gateway selection will use the current routing class to choose a gateway. .TP .B \-r routing class The routing class can be set to four values \(hy it enables "internet search mode". The daemon will choose an internet gateway based on certain criteria (unless "\-p" is specified): .RS 17 default: 0 \-> set no default route .RE .RS 10 allowed values: 1 \-> use fast connection .RE .RS 25 2 \-> use stable connection 3 \-> use fast\(hyswitch connection XX \-> use late\(hyswitch connection .RE .RS 7 In level 1, B.A.T.M.A.N tries to find the best available connection by considering the gateway's advertised throughput as well as the link quality towards the gateway. In level 2, B.A.T.M.A.N compares the link quality of the internet node and chooses the one with the best link quality. In level 3, B.A.T.M.A.N compares the link quality of the internet node and chooses the one with the best link quality but switches to another gateway as soon as a better connection is found. In level XX (number between 3 and 256) B.A.T.M.A.N compares the link quality of the internet node and chooses the one with the best link quality but switches to another gateway as soon as this gateway has a TQ value which is XX better than the currently selected gateway. .RE .TP .B \-s visualization server Since no topology database is computed by the protocol an additional solution to create topology graphs has been implemented, the vis server. Batman daemons may send their local view about their single\(hyhop neighbors to the vis server. It collects the information and provides data in a format similar to OLSR's topology information output. Therefore existing solutions to draw topology graphs developed for OLSR can be used to visualize mesh\(hyclouds using B.A.T.M.A.N. .TP .B \-v print version .TP .B \-\-disable\-client\-nat Since version 0.3.2 batmand uses iptables to set the NAT rules on the gateX interface of the batman client (\-r XX). That option disables this feature of batmand and switches the internet tunnel mode to "half tunnels" (the packets towards the gateway are tunneled but not the packets that are coming back) unless NAT was enabled manually. Be sure to know what you are doing! Without NAT the gateway needs to have a route to the client or the packets will be dropped silently. .TP .B \-\-no\-detach Run batmand in foreground .TP .B \-\-policy\-routing\-script This option disables the policy routing feature of batmand \(hy all routing changes are send to the script which can make use of this information or not. Firmware and package maintainers can use this option to tightly integrate batmand into their own routing policies. This option is only available in daemon mode. .SH EXAMPLES .TP .B batmand eth1 wlan0:test Start batman daemon on interface "eth1" and on alias interface "wlan0:test" .TP .B batmand \-o 2000 \-a 192.168.100.1/32 \-a 10.0.0.0/24 eth1 Start batman daemon on interface "eth1" with originator interval of 2000 ms while announcing 192.168.100.1 and 10.0.0.0/24. .TP .B batmand \-s 192.168.1.1 \-d 1 eth1 Start batman daemon on interface "eth1", sending topology information to 192.168.1.1 and with debug level 1 (does not fork into the background). .TP .B batmand eth1 && batmand \-c \-d 1 \-b Start batman daemon on interface "eth1". Connect in client mode to get the debug level 1 output once (batch mode). .TP .B batmand \-g 2000kbit/500kbit eth1 && batmand \-c \-r 1 Start batman daemon on interface "eth1" as internet gateway. Connect in client mode to disable the internet gateway and enable internet search mode. .br .SH AUTHOR batmand was written by Marek Lindner , Axel Neumann , Stefan Sperling , Corinna 'Elektra' Aichele , Thomas Lopatic , Felix Fietkau , Ludger Schmudde , Simon Wunderlich , Andreas Langer . .PP This manual page was written by Wesley Tsai , for the Debian GNU/Linux system. batmand-0.3.2+74+g2f62b17/originator.c000066400000000000000000000412611435410210600170250ustar00rootroot00000000000000/* * Copyright (C) 2006-2012 B.A.T.M.A.N. contributors: * * Simon Wunderlich, Marek Lindner * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public * License as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA * */ #include #include #include #include #include "list-batman.h" #include "packet.h" #include "os.h" #include "batman.h" #include "originator.h" #include "hna.h" #include "hash.h" #include "profile.h" #include "allocate.h" #include "ring_buffer.h" #include "types.h" struct neigh_node * create_neighbor(struct orig_node *orig_node, struct orig_node *orig_neigh_node, uint32_t neigh, struct batman_if *if_incoming) { struct neigh_node *neigh_node; debug_output( 4, "Creating new last-hop neighbour of originator\n" ); neigh_node = debugMalloc( sizeof(struct neigh_node), 403 ); memset( neigh_node, 0, sizeof(struct neigh_node) ); INIT_LIST_HEAD(&neigh_node->list); neigh_node->addr = neigh; neigh_node->orig_node = orig_neigh_node; neigh_node->if_incoming = if_incoming; neigh_node->tq_recv = debugMalloc(sizeof(uint16_t) * global_win_size, 406); memset(neigh_node->tq_recv, 0, sizeof(uint16_t) * global_win_size); neigh_node->real_bits = debugMalloc(sizeof(TYPE_OF_WORD) * num_words, 407); memset(neigh_node->real_bits, 0, sizeof(TYPE_OF_WORD) * num_words); list_add_tail(&neigh_node->list, &orig_node->neigh_list); return neigh_node; } /* needed for hash, compares 2 struct orig_node, but only their ip-addresses. assumes that * the ip address is the first field in the struct */ int compare_orig( void *data1, void *data2 ) { return (memcmp(data1, data2, 4) == 0 ? 1 : 0); } /* hashfunction to choose an entry in a hash table of given size */ /* hash algorithm from https://en.wikipedia.org/wiki/Hash_table */ int choose_orig( void *data, int32_t size ) { unsigned char *key= data; uint32_t hash = 0; size_t i; for (i = 0; i < 4; i++) { hash += key[i]; hash += (hash << 10); hash ^= (hash >> 6); } hash += (hash << 3); hash ^= (hash >> 11); hash += (hash << 15); return (hash%size); } /* this function finds or creates an originator entry for the given address if it does not exits */ struct orig_node *get_orig_node( uint32_t addr ) { struct orig_node *orig_node; struct hashtable_t *swaphash; char orig_str[ADDR_STR_LEN]; prof_start( PROF_get_orig_node ); orig_node = ((struct orig_node *)hash_find( orig_hash, &addr )); if ( orig_node != NULL ) { prof_stop( PROF_get_orig_node ); return orig_node; } addr_to_string( addr, orig_str, ADDR_STR_LEN ); debug_output( 4, "Creating new originator: %s \n", orig_str ); orig_node = debugMalloc( sizeof(struct orig_node), 401 ); memset(orig_node, 0, sizeof(struct orig_node)); INIT_LIST_HEAD_FIRST( orig_node->neigh_list ); orig_node->orig = addr; orig_node->router = NULL; orig_node->batman_if = NULL; orig_node->bcast_own = debugMalloc( found_ifs * sizeof(TYPE_OF_WORD) * num_words, 404 ); memset( orig_node->bcast_own, 0, found_ifs * sizeof(TYPE_OF_WORD) * num_words ); orig_node->bcast_own_sum = debugMalloc( found_ifs * sizeof(uint8_t), 405 ); memset( orig_node->bcast_own_sum, 0, found_ifs * sizeof(uint8_t) ); hash_add( orig_hash, orig_node ); if ( orig_hash->elements * 4 > orig_hash->size ) { swaphash = hash_resize( orig_hash, orig_hash->size * 2 ); if ( swaphash == NULL ) { debug_output( 0, "Couldn't resize hash table \n" ); restore_and_exit(0); } orig_hash = swaphash; } prof_stop( PROF_get_orig_node ); return orig_node; } void update_orig(struct orig_node *orig_node, struct bat_packet *in, uint32_t neigh, struct batman_if *if_incoming, unsigned char *hna_recv_buff, int16_t hna_buff_len, uint8_t is_duplicate, uint32_t curr_time) { struct list_head *list_pos; struct gw_node *gw_node; struct neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL; prof_start(PROF_update_originator); debug_output(4, "update_originator(): Searching and updating originator entry of received packet, \n"); list_for_each(list_pos, &orig_node->neigh_list) { tmp_neigh_node = list_entry(list_pos, struct neigh_node, list); if ((tmp_neigh_node->addr == neigh ) && (tmp_neigh_node->if_incoming == if_incoming)) { neigh_node = tmp_neigh_node; continue; } if (is_duplicate) continue; ring_buffer_set(tmp_neigh_node->tq_recv, &tmp_neigh_node->tq_index, 0); tmp_neigh_node->tq_avg = ring_buffer_avg(tmp_neigh_node->tq_recv); } if (!neigh_node) neigh_node = create_neighbor(orig_node, get_orig_node(neigh), neigh, if_incoming); else debug_output(4, "Updating existing last-hop neighbour of originator\n"); neigh_node->last_valid = curr_time; ring_buffer_set(neigh_node->tq_recv, &neigh_node->tq_index, in->tq); neigh_node->tq_avg = ring_buffer_avg(neigh_node->tq_recv); if (!is_duplicate) { orig_node->last_ttl = in->ttl; neigh_node->last_ttl = in->ttl; } /** * if we got have a better tq value via this neighbour or * same tq value but the link is more symetric change the next hop * router */ if ((orig_node->router != neigh_node) && ((!orig_node->router) || (neigh_node->tq_avg > orig_node->router->tq_avg) || ((neigh_node->tq_avg == orig_node->router->tq_avg) && (neigh_node->orig_node->bcast_own_sum[if_incoming->if_num] > orig_node->router->orig_node->bcast_own_sum[if_incoming->if_num])))) update_routes(orig_node, neigh_node, hna_recv_buff, hna_buff_len); else update_routes(orig_node, orig_node->router, hna_recv_buff, hna_buff_len); if (orig_node->gwflags != in->gwflags) update_gw_list(orig_node, in->gwflags, in->gwport); orig_node->gwflags = in->gwflags; hna_global_check_tq(orig_node); /* restart gateway selection if we have more packets and fast or late switching enabled */ if ((routing_class > 2) && (orig_node->gwflags != 0) && (curr_gateway != NULL)) { /* if the node is not our current gateway and we have preferred gateray disabled and a better tq value or we found our preferred gateway */ if ((curr_gateway->orig_node != orig_node) && (((pref_gateway == 0) && (orig_node->router->tq_avg > curr_gateway->orig_node->router->tq_avg)) || (pref_gateway == orig_node->orig))) { /* it is our preferred gateway or we have fast switching or the tq is $routing_class better than our old tq */ if ((pref_gateway == orig_node->orig) || (routing_class == 3) || (orig_node->router->tq_avg - curr_gateway->orig_node->router->tq_avg >= routing_class)) { gw_node = NULL; list_for_each(list_pos, &gw_list) { gw_node = list_entry(list_pos, struct gw_node, list); if (gw_node->orig_node == orig_node) break; gw_node = NULL; } /* if this gateway had not a gateway failure within the last 30 seconds */ if ((gw_node != NULL) && ((int)(curr_time - (gw_node->last_failure + 30000)) > 0)) { debug_output(3, "Gateway client - restart gateway selection: better gateway found (tq curr: %i, tq new: %i) \n", curr_gateway->orig_node->router->tq_avg, orig_node->router->tq_avg); del_default_route(); } } } } prof_stop(PROF_update_originator); } void purge_orig(uint32_t curr_time) { struct hash_it_t *hashit = NULL; struct list_head *neigh_pos, *neigh_temp, *prev_list_head; struct list_head *gw_pos, *gw_pos_tmp; struct orig_node *orig_node; struct neigh_node *neigh_node, *best_neigh_node; struct gw_node *gw_node; uint8_t gw_purged = 0, neigh_purged, max_tq; char orig_str[ADDR_STR_LEN], neigh_str[ADDR_STR_LEN]; prof_start( PROF_purge_originator ); /* for all origins... */ while ( NULL != ( hashit = hash_iterate( orig_hash, hashit ) ) ) { orig_node = hashit->bucket->data; if ((int)(curr_time - (orig_node->last_valid + (2 * purge_timeout))) > 0) { addr_to_string( orig_node->orig, orig_str, ADDR_STR_LEN ); debug_output( 4, "Originator timeout: originator %s, last_valid %u \n", orig_str, orig_node->last_valid ); hash_remove_bucket( orig_hash, hashit ); /* for all neighbours towards this originator ... */ list_for_each_safe( neigh_pos, neigh_temp, &orig_node->neigh_list ) { neigh_node = list_entry(neigh_pos, struct neigh_node, list); list_del((struct list_head *)&orig_node->neigh_list, neigh_pos, &orig_node->neigh_list); debugFree(neigh_node->tq_recv, 1407); debugFree(neigh_node->real_bits, 1409); debugFree(neigh_node, 1401); } list_for_each( gw_pos, &gw_list ) { gw_node = list_entry( gw_pos, struct gw_node, list ); if ( gw_node->deleted ) continue; if ( gw_node->orig_node == orig_node ) { addr_to_string( gw_node->orig_node->orig, orig_str, ADDR_STR_LEN ); debug_output( 3, "Removing gateway %s from gateway list \n", orig_str ); gw_node->deleted = get_time_msec(); gw_purged = 1; break; } } update_routes( orig_node, NULL, NULL, 0 ); debugFree( orig_node->bcast_own, 1403 ); debugFree( orig_node->bcast_own_sum, 1404 ); debugFree( orig_node, 1405 ); } else { best_neigh_node = NULL; max_tq = neigh_purged = 0; prev_list_head = (struct list_head *)&orig_node->neigh_list; /* for all neighbours towards this originator ... */ list_for_each_safe( neigh_pos, neigh_temp, &orig_node->neigh_list ) { neigh_node = list_entry( neigh_pos, struct neigh_node, list ); if ((int)(curr_time - (neigh_node->last_valid + purge_timeout)) > 0) { addr_to_string( orig_node->orig, orig_str, ADDR_STR_LEN ); addr_to_string( neigh_node->addr, neigh_str, ADDR_STR_LEN ); debug_output( 4, "Neighbour timeout: originator %s, neighbour: %s, last_valid %u \n", orig_str, neigh_str, neigh_node->last_valid ); if (orig_node->router == neigh_node) { /* we have to delete the route towards this node before it gets purged */ debug_output( 4, "Deleting previous route \n" ); /* remove old announced network(s) */ hna_global_del(orig_node); add_del_route(orig_node->orig, 32, orig_node->router->addr, 0, orig_node->batman_if->if_index, orig_node->batman_if->dev, BATMAN_RT_TABLE_HOSTS, ROUTE_TYPE_UNICAST, ROUTE_DEL); /* if the neighbour is the route towards our gateway */ if ((curr_gateway != NULL) && (curr_gateway->orig_node == orig_node)) del_default_route(); orig_node->router = NULL; } neigh_purged = 1; list_del(prev_list_head, neigh_pos, &orig_node->neigh_list); debugFree(neigh_node->tq_recv, 1408); debugFree(neigh_node->real_bits, 1410); debugFree(neigh_node, 1406); } else { if ((best_neigh_node == NULL) || (neigh_node->tq_avg > max_tq)) { best_neigh_node = neigh_node; max_tq = neigh_node->tq_avg; } prev_list_head = &neigh_node->list; } } if ((neigh_purged) && ((best_neigh_node == NULL) || (orig_node->router == NULL) || (max_tq > orig_node->router->tq_avg))) update_routes( orig_node, best_neigh_node, orig_node->hna_buff, orig_node->hna_buff_len ); } } prev_list_head = (struct list_head *)&gw_list; list_for_each_safe( gw_pos, gw_pos_tmp, &gw_list ) { gw_node = list_entry(gw_pos, struct gw_node, list); if ((gw_node->deleted) && ((int)(curr_time - (gw_node->deleted + (2 * purge_timeout))) > 0)) { list_del( prev_list_head, gw_pos, &gw_list ); debugFree( gw_pos, 1406 ); } else { prev_list_head = &gw_node->list; } } prof_stop( PROF_purge_originator ); if ( gw_purged ) choose_gw(); } void debug_orig(void) { struct hash_it_t *hashit = NULL; struct list_head *forw_pos, *orig_pos, *neigh_pos; struct forw_node *forw_node; struct orig_node *orig_node; struct neigh_node *neigh_node; struct gw_node *gw_node; uint16_t batman_count = 0; uint64_t uptime_sec; int download_speed, upload_speed, debug_out_size; char str[ADDR_STR_LEN], str2[ADDR_STR_LEN], orig_str[ADDR_STR_LEN], debug_out_str[1001]; if ( debug_clients.clients_num[1] > 0 ) { addr_to_string( ((struct batman_if *)if_list.next)->addr.sin_addr.s_addr, orig_str, sizeof(orig_str) ); uptime_sec = (uint64_t)(get_time_msec64() / 1000); debug_output(2, "BOD\n"); debug_output(2, "%12s (%s/%i) %15s [%10s], gw_class ... [B.A.T.M.A.N. %s, MainIF/IP: %s/%s, UT: %id%2ih%2im] \n", "Gateway", "#", TQ_MAX_VALUE, "Nexthop", "outgoingIF", SOURCE_VERSION, ((struct batman_if *)if_list.next)->dev, orig_str, (uint32_t)(uptime_sec/86400), (uint32_t)((uptime_sec%86400)/3600), (uint32_t)((uptime_sec%3600)/60)); if ( list_empty( &gw_list ) ) { debug_output( 2, "No gateways in range ... \n" ); } else { list_for_each( orig_pos, &gw_list ) { gw_node = list_entry( orig_pos, struct gw_node, list ); if ( gw_node->deleted ) continue; if (gw_node->orig_node->router == NULL) continue; addr_to_string( gw_node->orig_node->orig, str, sizeof (str) ); addr_to_string( gw_node->orig_node->router->addr, str2, sizeof (str2) ); get_gw_speeds( gw_node->orig_node->gwflags, &download_speed, &upload_speed ); debug_output(2, "%s %-15s (%3i) %15s [%10s], gw_class %3i - %i%s/%i%s, gateway failures: %i \n", ( curr_gateway == gw_node ? "=>" : " " ), str, gw_node->orig_node->router->tq_avg, str2, gw_node->orig_node->router->if_incoming->dev, gw_node->orig_node->gwflags, (download_speed > 2048 ? download_speed / 1024 : download_speed), (download_speed > 2048 ? "MBit" : "KBit"), (upload_speed > 2048 ? upload_speed / 1024 : upload_speed), (upload_speed > 2048 ? "MBit" : "KBit"), gw_node->gw_failure); batman_count++; } if ( batman_count == 0 ) debug_output( 2, "No gateways in range ... \n" ); } debug_output( 2, "EOD\n" ); } if ( ( debug_clients.clients_num[0] > 0 ) || ( debug_clients.clients_num[3] > 0 ) ) { addr_to_string( ((struct batman_if *)if_list.next)->addr.sin_addr.s_addr, orig_str, sizeof(orig_str) ); uptime_sec = (uint64_t)(get_time_msec64() / 1000); debug_output(1, "BOD \n"); debug_output(1, " %-11s (%s/%i) %15s [%10s]: %20s ... [B.A.T.M.A.N. %s, MainIF/IP: %s/%s, UT: %id%2ih%2im] \n", "Originator", "#", TQ_MAX_VALUE, "Nexthop", "outgoingIF", "Potential nexthops", SOURCE_VERSION, ((struct batman_if *)if_list.next)->dev, orig_str, (uint32_t)(uptime_sec/86400), (uint32_t)((uptime_sec%86400)/3600), (uint32_t)((uptime_sec%3600)/60)); if ( debug_clients.clients_num[3] > 0 ) { debug_output( 4, "------------------ DEBUG ------------------ \n" ); debug_output( 4, "Forward list \n" ); list_for_each( forw_pos, &forw_list ) { forw_node = list_entry( forw_pos, struct forw_node, list ); addr_to_string( ((struct bat_packet *)forw_node->pack_buff)->orig, str, sizeof(str) ); debug_output( 4, " %s at %u \n", str, forw_node->send_time ); } debug_output( 4, "Originator list \n" ); debug_output( 4, " %-11s (%s/%i) %15s [%10s]: %20s\n", "Originator", "#", TQ_MAX_VALUE, "Nexthop", "outgoingIF", "Potential nexthops" ); } while ( NULL != ( hashit = hash_iterate( orig_hash, hashit ) ) ) { orig_node = hashit->bucket->data; if ( orig_node->router == NULL ) continue; batman_count++; addr_to_string( orig_node->orig, str, sizeof (str) ); addr_to_string( orig_node->router->addr, str2, sizeof (str2) ); debug_output( 1, "%-15s (%3i) %15s [%10s]:", str, orig_node->router->tq_avg, str2, orig_node->router->if_incoming->dev ); debug_output( 4, "%15s (%3i) %15s [%10s], last_valid: %u: \n", str, orig_node->router->tq_avg, str2, orig_node->router->if_incoming->dev, orig_node->last_valid ); debug_out_size = 0; list_for_each( neigh_pos, &orig_node->neigh_list ) { neigh_node = list_entry( neigh_pos, struct neigh_node, list ); addr_to_string( neigh_node->addr, str, sizeof (str) ); debug_out_size = debug_out_size + snprintf( ( debug_out_str + debug_out_size ), ( sizeof(debug_out_str) - 1 - debug_out_size ), " %15s (%3i)", str, neigh_node->tq_avg); if ( (unsigned int)(debug_out_size + 30) > sizeof(debug_out_str) - 1 ) { debug_output( 1, "%s \n", debug_out_str ); debug_output( 4, "%s \n", debug_out_str ); debug_out_size = 0; } } if (debug_out_size > 0) { debug_output( 1, "%s \n", debug_out_str ); debug_output( 4, "%s \n", debug_out_str ); } } if ( batman_count == 0 ) { debug_output( 1, "No batman nodes in range ... \n" ); debug_output( 4, "No batman nodes in range ... \n" ); } debug_output( 1, "EOD\n" ); debug_output( 4, "---------------------------------------------- END DEBUG \n" ); } } batmand-0.3.2+74+g2f62b17/originator.h000066400000000000000000000026361435410210600170350ustar00rootroot00000000000000/* * Copyright (C) 2006-2012 B.A.T.M.A.N. contributors: * * Simon Wunderlich, Marek Lindner * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public * License as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA * */ #ifndef _BATMAND_ORIGINATOR_H #define _BATMAND_ORIGINATOR_H #include #include "types.h" struct neigh_node * create_neighbor(struct orig_node *orig_node, struct orig_node *orig_neigh_node, uint32_t neigh, struct batman_if *if_incoming); int compare_orig( void *data1, void *data2 ); int choose_orig( void *data, int32_t size ); struct orig_node *get_orig_node( uint32_t addr ); void update_orig( struct orig_node *orig_node, struct bat_packet *in, uint32_t neigh, struct batman_if *if_incoming, unsigned char *hna_recv_buff, int16_t hna_buff_len, uint8_t is_duplicate, uint32_t curr_time ); void purge_orig( uint32_t curr_time ); void debug_orig(void); #endif batmand-0.3.2+74+g2f62b17/os.h000066400000000000000000000071251435410210600152770ustar00rootroot00000000000000/* * Copyright (C) 2006-2012 B.A.T.M.A.N. contributors: * * Thomas Lopatic, Marek Lindner * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public * License as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA * */ #ifndef _BATMAND_OS_H #define _BATMAND_OS_H #include #include #include #include "types.h" #ifdef __GNUC_MINOR__ #define NO_RETURN __attribute__ ((__noreturn__)) #else #define NO_RETURN #endif uint32_t get_time_msec(void); uint64_t get_time_msec64(void); int32_t rand_num( int32_t limit ); void addr_to_string( uint32_t addr, char *str, int32_t len ); int8_t is_aborted(void); void handler(int32_t sig); void segmentation_fault(int32_t sig) NO_RETURN; void restore_and_exit(uint8_t is_sigsegv) NO_RETURN; /* route.c */ void add_del_route( uint32_t dest, uint8_t netmask, uint32_t router, uint32_t src_ip, int32_t ifi, const char *dev, uint8_t rt_table, int8_t route_type, int8_t del ); void add_del_rule( uint32_t network, uint8_t netmask, int8_t rt_table, uint32_t prio, const char *iif, int8_t dst_rule, int8_t del ); int add_del_interface_rules( int8_t del ); int flush_routes_rules( int8_t rt_table ); /* tun.c */ int probe_nat_tool(void); void add_nat_rule(char *dev); void del_nat_rule(char *dev); void hna_local_update_nat(uint32_t hna_ip, uint8_t netmask, int8_t route_action); int8_t probe_tun(uint8_t print_to_stderr); int8_t del_dev_tun( int32_t fd ); int8_t add_dev_tun( struct batman_if *batman_if, uint32_t dest_addr, char *tun_dev, size_t tun_dev_size, int32_t *fd, int32_t *ifi ); int8_t set_tun_addr( int32_t fd, uint32_t tun_addr, char *tun_dev ); /* init.c */ void apply_init_args(int argc, char *argv[]); void init_interface(struct batman_if *batman_if); void deactivate_interface(struct batman_if *batman_if); void check_inactive_interfaces(void); void check_active_interfaces(void); void init_interface_gw(void); void interface_listen_sockets(void); /* kernel.c */ void set_rp_filter( int32_t state, const char* dev ); int32_t get_rp_filter( const char *dev ); void set_send_redirects( int32_t state, const char* dev ); int32_t get_send_redirects( const char *dev ); void set_forwarding( int32_t state ); int32_t get_forwarding( void ); int8_t bind_to_iface( int32_t sock, const char *dev ); int is_wifi_interface(char *dev, int fd); /* posix.c */ void print_animation( void ); void del_default_route(void); void add_default_route(void); int8_t receive_packet(unsigned char *packet_buff, int32_t packet_buff_len, int16_t *packet_len, uint32_t *neigh, uint32_t timeout, struct batman_if **if_incoming); int8_t send_udp_packet(unsigned char *packet_buff, int packet_buff_len, struct sockaddr_in *broad, int send_sock, struct batman_if *batman_if); void del_gw_interface(void); void restore_defaults(void); void cleanup(void); /* tunnel.c */ void init_bh_ports(void); void *gw_listen(void *arg); void *client_to_gw_tun( void *arg ); /* unix_sokcet.c */ void *unix_listen( void *arg ); void internal_output(uint32_t sock); void debug_output( int8_t debug_prio, const char *format, ... ) __attribute__ ((format (printf, 2, 3))); #endif batmand-0.3.2+74+g2f62b17/packet.h000066400000000000000000000030561435410210600161240ustar00rootroot00000000000000/* * Copyright (C) 2009-2012 B.A.T.M.A.N. contributors: * * Marek Lindner * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public * License as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA * */ #ifndef _BATMAND_PACKET_H #define _BATMAND_PACKET_H #include #define COMPAT_VERSION 5 #define VIS_COMPAT_VERSION 23 #define DATA_TYPE_NEIGH 1 #define DATA_TYPE_SEC_IF 2 #define DATA_TYPE_HNA 3 #define PORT 4305 #define GW_PORT 4306 #define DIRECTLINK 0x40 struct bat_packet { uint8_t version; /* batman version field */ uint8_t flags; /* 0x40: DIRECTLINK flag, ... */ uint8_t ttl; uint8_t gwflags; /* flags related to gateway functions: gateway class */ uint16_t seqno; uint16_t gwport; uint32_t orig; uint32_t prev_sender; uint8_t tq; uint8_t hna_len; } __attribute__((packed)); struct vis_packet { uint32_t sender_ip; uint8_t version; uint8_t gw_class; uint8_t tq_max; } __attribute__((packed)); struct vis_data { uint8_t type; uint8_t data; uint32_t ip; } __attribute__((packed)); #endif batmand-0.3.2+74+g2f62b17/posix/000077500000000000000000000000001435410210600156425ustar00rootroot00000000000000batmand-0.3.2+74+g2f62b17/posix/init.c000066400000000000000000000647111435410210600167620ustar00rootroot00000000000000/* * Copyright (C) 2006-2012 BATMAN contributors: * * Thomas Lopatic, Marek Lindner * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public * License as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../os.h" #include "../batman.h" #include "../hna.h" #include "../allocate.h" #include "../bitarray.h" #include "../list-batman.h" #include "../packet.h" #include "../types.h" int8_t stop; int no_detach; static void create_routing_pipe(void) { int fd[2], pipe_opts; if (pipe(fd) < 0) { printf("Could not create a pipe to '%s': %s\n", policy_routing_script, strerror(errno)); exit(EXIT_FAILURE); } if ((policy_routing_script_pid = fork()) < 0) { printf("Could not fork to execute '%s': %s\n", policy_routing_script, strerror(errno)); exit(EXIT_FAILURE); /* parent */ } else if (policy_routing_script_pid > 0) { close(fd[0]); policy_routing_pipe = fd[1]; /* make pipe non blocking */ pipe_opts = fcntl(policy_routing_pipe, F_GETFL, 0); fcntl(policy_routing_pipe, F_SETFL, pipe_opts | O_NONBLOCK); /* child */ } else { close(fd[1]); if (fd[0] != STDIN_FILENO) { if (dup2(fd[0], STDIN_FILENO) != STDIN_FILENO) { printf("Could not dup2 to redirect stdin to '%s'\n", policy_routing_script); exit(EXIT_FAILURE); } close(fd[0]); } signal(SIGINT, SIG_IGN); signal(SIGTERM, SIG_IGN); signal(SIGPIPE, SIG_IGN); if (execl("/bin/sh", "/bin/sh", "-c", policy_routing_script, NULL) < 0) printf("Could not execute '%s': %s\n", policy_routing_script, strerror(errno)); } } void apply_init_args( int argc, char *argv[] ) { struct in_addr tmp_ip_holder; struct batman_if *batman_if; struct hna_task *hna_task; struct debug_level_info *debug_level_info; uint8_t found_args = 1, batch_mode = 0, info_output = 0, was_hna = 0; int8_t res; int32_t optchar, option_index, recv_buff_len, bytes_written, download_speed = 0, upload_speed = 0; char str1[16], str2[16], *slash_ptr, *unix_buff, *buff_ptr, *cr_ptr; char routing_class_opt = 0, gateway_class_opt = 0, pref_gw_opt = 0; char hop_penalty_opt = 0, purge_timeout_opt = 0; uint32_t vis_server = 0; struct option long_options[] = { {"policy-routing-script", required_argument, 0, 'n'}, {"hop-penalty", required_argument, 0, 'm'}, {"purge-timeout", required_argument, 0, 'q'}, {"disable-aggregation", no_argument, 0, 'x'}, {"disable-client-nat", no_argument, 0, 'z'}, {"no-detach", no_argument, 0, 'D'}, {0, 0, 0, 0} }; memset( &tmp_ip_holder, 0, sizeof (struct in_addr) ); stop = 0; prog_name = argv[0]; while ( ( optchar = getopt_long( argc, argv, "a:A:bcd:hHio:g:p:r:s:vVD", long_options, &option_index ) ) != -1 ) { switch ( optchar ) { case 'a': hna_local_task_add_str(optarg, ROUTE_ADD, 0); /* increment found_args only by one if optarg and optchar are directly following each other increment found_args by two if there is some space between the arguments */ found_args += ((*((char*)(optarg - 1)) == optchar ) ? 1 : 2); break; case 'A': hna_local_task_add_str(optarg, ROUTE_DEL, 0); found_args += ((*((char*)( optarg - 1)) == optchar) ? 1 : 2); break; case 'b': batch_mode++; found_args++; break; case 'c': unix_client++; found_args++; break; case 'd': errno = 0; debug_level = strtol( optarg, NULL, 10 ); if ( ( errno == ERANGE ) || ( errno != 0 && debug_level == 0 ) ) { perror("strtol"); exit(EXIT_FAILURE); } if ( debug_level > debug_level_max ) { printf( "Invalid debug level: %i\nDebug level has to be between 0 and %i.\n", debug_level, debug_level_max ); exit(EXIT_FAILURE); } found_args += ((*((char*)( optarg - 1)) == optchar) ? 1 : 2); break; case 'g': if ( ( slash_ptr = strchr( optarg, '/' ) ) != NULL ) *slash_ptr = '\0'; errno = 0; download_speed = strtol( optarg, NULL, 10 ); if ( ( errno == ERANGE ) || ( errno != 0 && download_speed == 0 ) ) { perror("strtol"); exit(EXIT_FAILURE); } if ( ( strlen( optarg ) > 4 ) && ( ( strncmp( optarg + strlen( optarg ) - 4, "MBit", 4 ) == 0 ) || ( strncmp( optarg + strlen( optarg ) - 4, "mbit", 4 ) == 0 ) || ( strncmp( optarg + strlen( optarg ) - 4, "Mbit", 4 ) == 0 ) ) ) download_speed *= 1024; if ( slash_ptr != NULL ) { errno = 0; upload_speed = strtol( slash_ptr + 1, NULL, 10 ); if ( ( errno == ERANGE ) || ( errno != 0 && upload_speed == 0 ) ) { perror("strtol"); exit(EXIT_FAILURE); } if ( ( strlen( slash_ptr + 1 ) > 4 ) && ( ( strncmp( slash_ptr + 1 + strlen( slash_ptr + 1 ) - 4, "MBit", 4 ) == 0 ) || ( strncmp( slash_ptr + 1 + strlen( slash_ptr + 1 ) - 4, "mbit", 4 ) == 0 ) || ( strncmp( slash_ptr + 1 + strlen( slash_ptr + 1 ) - 4, "Mbit", 4 ) == 0 ) ) ) upload_speed *= 1024; *slash_ptr = '/'; } gateway_class_opt = 1; found_args += ((*((char*)( optarg - 1)) == optchar) ? 1 : 2); break; case 'H': verbose_usage(); exit(EXIT_SUCCESS); case 'i': info_output++; found_args++; break; case 'n': policy_routing_script = optarg; found_args += ((*((char*)( optarg - 1)) == optchar) ? 1 : 2); break; case 'm': errno = 0; hop_penalty = strtol( optarg, NULL, 10 ); hop_penalty_opt = 1; found_args += ((*((char*)( optarg - 1)) == optchar) ? 1 : 2); break; case 'q': errno = 0; purge_timeout = strtol(optarg, NULL, 10); purge_timeout_opt = 1; found_args += ((*((char*)( optarg - 1)) == optchar ) ? 1 : 2); break; case 'o': errno = 0; originator_interval = strtol( optarg, NULL, 10 ); if ( originator_interval < 1 ) { printf( "Invalid originator interval specified: %i.\nThe Interval has to be greater than 0.\n", originator_interval ); exit(EXIT_FAILURE); } found_args += ((*((char*)( optarg - 1)) == optchar) ? 1 : 2); break; case 'p': errno = 0; if ( inet_pton( AF_INET, optarg, &tmp_ip_holder ) < 1 ) { printf( "Invalid preferred gateway IP specified: %s\n", optarg ); exit(EXIT_FAILURE); } pref_gateway = tmp_ip_holder.s_addr; pref_gw_opt = 1; found_args += ((*((char*)( optarg - 1)) == optchar) ? 1 : 2); break; case 'r': errno = 0; routing_class = strtol(optarg, NULL, 10); routing_class_opt = 1; found_args += ((*((char*)( optarg - 1)) == optchar) ? 1 : 2); break; case 's': errno = 0; if ( inet_pton( AF_INET, optarg, &tmp_ip_holder ) < 1 ) { printf( "Invalid preferred visualation server IP specified: %s\n", optarg ); exit(EXIT_FAILURE); } vis_server = tmp_ip_holder.s_addr; found_args += ((*((char*)( optarg - 1)) == optchar) ? 1 : 2); break; case 'v': printf("B.A.T.M.A.N. %s (compatibility version %i)\n", SOURCE_VERSION, COMPAT_VERSION); exit(EXIT_SUCCESS); case 'V': print_animation(); printf("\x1B[0;0HB.A.T.M.A.N. %s (compatibility version %i)\n", SOURCE_VERSION, COMPAT_VERSION); printf("\x1B[9;0H \t May the bat guide your path ...\n\n\n"); exit(EXIT_SUCCESS); case 'x': aggregation_enabled = 0; found_args++; break; case 'z': disable_client_nat = 1; found_args++; break; case 'D': no_detach = 1; found_args++; break; case 'h': default: usage(); exit(EXIT_SUCCESS); } } if (!unix_client && info_output) { internal_output(1); exit(EXIT_SUCCESS); } if ( ( download_speed > 0 ) && ( upload_speed == 0 ) ) upload_speed = download_speed / 5; if (download_speed > 0) { gateway_class = get_gw_class(download_speed, upload_speed); get_gw_speeds(gateway_class, &download_speed, &upload_speed); } if ( ( gateway_class != 0 ) && ( routing_class != 0 ) ) { fprintf( stderr, "Error - routing class can't be set while gateway class is in use !\n" ); usage(); exit(EXIT_FAILURE); } if ( ( gateway_class != 0 ) && ( pref_gateway != 0 ) ) { fprintf( stderr, "Error - preferred gateway can't be set while gateway class is in use !\n" ); usage(); exit(EXIT_FAILURE); } /* use routing class 1 if none specified */ if ( ( routing_class == 0 ) && ( pref_gateway != 0 ) ) routing_class = DEFAULT_ROUTING_CLASS; if ( ( ( routing_class != 0 ) || ( gateway_class != 0 ) ) && ( !probe_tun(1) ) ) exit(EXIT_FAILURE); if (!unix_client) { if (argc <= found_args) { fprintf(stderr, "Error - no interface specified\n"); usage(); exit(EXIT_FAILURE); } if ((disable_client_nat) && (routing_class == 0)) fprintf(stderr, "Warning - the activated option '--disable-client-nat' has no effect without setting a routing class.\n"); nat_tool_avail = probe_nat_tool(); if (policy_routing_script != NULL) create_routing_pipe(); signal( SIGINT, handler ); signal( SIGTERM, handler ); signal( SIGPIPE, SIG_IGN ); signal( SIGSEGV, segmentation_fault ); debug_clients.fd_list = debugMalloc( sizeof(struct list_head_first *) * debug_level_max, 203 ); debug_clients.mutex = debugMalloc( sizeof(pthread_mutex_t *) * debug_level_max, 209 ); debug_clients.clients_num = debugMalloc( sizeof(int16_t) * debug_level_max, 209 ); for (res = 0; res < debug_level_max; res++) { debug_clients.fd_list[res] = debugMalloc(sizeof(struct list_head_first), 204); ((struct list_head_first *)debug_clients.fd_list[res])->next = debug_clients.fd_list[res]; ((struct list_head_first *)debug_clients.fd_list[res])->prev = debug_clients.fd_list[res]; debug_clients.mutex[res] = debugMalloc(sizeof(pthread_mutex_t), 209); pthread_mutex_init((pthread_mutex_t *)debug_clients.mutex[res], NULL); debug_clients.clients_num[res] = 0; } if ( flush_routes_rules(0) < 0 ) exit(EXIT_FAILURE); if ( flush_routes_rules(1) < 0 ) exit(EXIT_FAILURE); while (argc > found_args) { if (argv[found_args][0] == '-') { fprintf(stderr, "%s: invalid option -- %s\n", argv[0], argv[found_args]); usage(); exit(EXIT_FAILURE); } batman_if = debugMalloc(sizeof(struct batman_if), 206); memset(batman_if, 0, sizeof(struct batman_if)); INIT_LIST_HEAD( &batman_if->list ); batman_if->dev = argv[found_args]; batman_if->if_num = found_ifs; batman_if->if_rp_filter_old = -1; batman_if->if_send_redirects_old = -1; list_add_tail(&batman_if->list, &if_list); init_interface(batman_if); if (batman_if->if_num > 0) hna_local_task_add_ip(batman_if->addr.sin_addr.s_addr, 32, ROUTE_ADD); if (batman_if->if_active) { addr_to_string(batman_if->addr.sin_addr.s_addr, str1, sizeof (str1)); addr_to_string(batman_if->broad.sin_addr.s_addr, str2, sizeof (str2)); printf("Using interface %s with address %s and broadcast address %s\n", batman_if->dev, str1, str2); } else { printf("Not using interface %s (retrying later): interface not active\n", batman_if->dev); } found_ifs++; found_args++; } unlink( UNIX_PATH ); unix_if.unix_sock = socket( AF_LOCAL, SOCK_STREAM, 0 ); memset( &unix_if.addr, 0, sizeof(struct sockaddr_un) ); unix_if.addr.sun_family = AF_LOCAL; strcpy( unix_if.addr.sun_path, UNIX_PATH ); if ( bind ( unix_if.unix_sock, (struct sockaddr *)&unix_if.addr, sizeof (struct sockaddr_un) ) < 0 ) { printf( "Error - can't bind unix socket '%s': %s\n", UNIX_PATH, strerror(errno) ); restore_defaults(); exit(EXIT_FAILURE); } if ( listen( unix_if.unix_sock, 10 ) < 0 ) { printf( "Error - can't listen unix socket '%s': %s\n", UNIX_PATH, strerror(errno) ); restore_defaults(); exit(EXIT_FAILURE); } /* daemonize */ if (debug_level == 0) { if (!no_detach && daemon(0, 0) < 0) { printf("Error - can't fork to background: %s\n", strerror(errno)); restore_defaults(); exit(EXIT_FAILURE); } openlog("batmand", LOG_PID, LOG_DAEMON); } else { printf("B.A.T.M.A.N. %s (compatibility version %i)\n", SOURCE_VERSION, COMPAT_VERSION); debug_clients.clients_num[ debug_level - 1 ]++; debug_level_info = debugMalloc( sizeof(struct debug_level_info), 205 ); INIT_LIST_HEAD( &debug_level_info->list ); debug_level_info->fd = 2; list_add( &debug_level_info->list, (struct list_head_first *)debug_clients.fd_list[debug_level - 1] ); } log_facility_active = 1; pthread_create( &unix_if.listen_thread_id, NULL, &unix_listen, NULL ); /* add rule for hna networks */ add_del_rule(0, 0, BATMAN_RT_TABLE_NETWORKS, BATMAN_RT_PRIO_UNREACH - 1, 0, RULE_TYPE_DST, RULE_ADD); /* add unreachable routing table entry */ add_del_route(0, 0, 0, 0, 0, "unknown", BATMAN_RT_TABLE_UNREACH, ROUTE_TYPE_UNREACHABLE, ROUTE_ADD); if (routing_class > 0) { if (add_del_interface_rules(RULE_ADD) < 0) { restore_defaults(); exit(EXIT_FAILURE); } } memset(&vis_if, 0, sizeof(vis_if)); if (vis_server) { vis_if.addr.sin_family = AF_INET; vis_if.addr.sin_port = htons(PORT + 2); vis_if.addr.sin_addr.s_addr = vis_server; vis_if.sock = socket( PF_INET, SOCK_DGRAM, 0 ); } if (gateway_class != 0) init_interface_gw(); if ( debug_level > 0 ) { printf( "debug level: %i\n", debug_level ); if ( originator_interval != 1000 ) printf( "originator interval: %i\n", originator_interval ); if ( gateway_class > 0 ) printf( "gateway class: %i -> propagating: %i%s/%i%s\n", gateway_class, ( download_speed > 2048 ? download_speed / 1024 : download_speed ), ( download_speed > 2048 ? "MBit" : "KBit" ), ( upload_speed > 2048 ? upload_speed / 1024 : upload_speed ), ( upload_speed > 2048 ? "MBit" : "KBit" ) ); if ( routing_class > 0 ) printf( "routing class: %i\n", routing_class ); if ( pref_gateway > 0 ) { addr_to_string( pref_gateway, str1, sizeof(str1) ); printf( "preferred gateway: %s\n", str1 ); } if ( vis_server > 0 ) { addr_to_string( vis_server, str1, sizeof(str1) ); printf( "visualisation server: %s\n", str1 ); } } /* connect to running batmand via unix socket */ } else { more_hna: unix_if.unix_sock = socket( AF_LOCAL, SOCK_STREAM, 0 ); memset( &unix_if.addr, 0, sizeof(struct sockaddr_un) ); unix_if.addr.sun_family = AF_LOCAL; strcpy( unix_if.addr.sun_path, UNIX_PATH ); if ( connect ( unix_if.unix_sock, (struct sockaddr *)&unix_if.addr, sizeof(struct sockaddr_un) ) < 0 ) { printf( "Error - can't connect to unix socket '%s': %s ! Is batmand running on this host ?\n", UNIX_PATH, strerror(errno) ); close( unix_if.unix_sock ); exit(EXIT_FAILURE); } unix_buff = debugMalloc( 1501, 5001 ); if ( debug_level > 0 ) { if ( debug_level <= debug_level_max ) { snprintf( unix_buff, 10, "d:%c", debug_level ); if ( ( debug_level > 2 ) && ( batch_mode ) ) printf( "WARNING: Your chosen debug level (%i) does not support batch mode !\n", debug_level ); } } else if ( routing_class_opt ) { batch_mode = 1; snprintf( unix_buff, 10, "r:%c", routing_class ); } else if ( pref_gw_opt ) { batch_mode = 1; addr_to_string( pref_gateway, str1, sizeof(str1) ); snprintf( unix_buff, 20, "p:%s", str1 ); } else if ( gateway_class_opt ) { batch_mode = 1; snprintf( unix_buff, 10, "g:%c", gateway_class ); } else if (hop_penalty_opt) { batch_mode = 1; snprintf(unix_buff, 10, "m:%c", hop_penalty); } else if (purge_timeout_opt) { batch_mode = 1; snprintf(unix_buff, 20, "q:%u", purge_timeout); } else if (info_output) { batch_mode = 1; snprintf( unix_buff, 10, "i" ); } else if (!list_empty(&hna_chg_list)) { batch_mode = was_hna = 1; hna_task = (struct hna_task *)hna_chg_list.next; addr_to_string(hna_task->addr, str1, sizeof(str1)); snprintf(unix_buff, 30, "%c:%s/%i", (hna_task->route_action == ROUTE_ADD ? 'a' : 'A'), str1, hna_task->netmask); list_del((struct list_head *)&hna_chg_list, &hna_task->list, &hna_chg_list); debugFree(hna_task, 1298); } else { batch_mode = 1; snprintf(unix_buff, 10, "y"); } if ( write( unix_if.unix_sock, unix_buff, 30 ) < 0 ) { printf( "Error - can't write to unix socket: %s\n", strerror(errno) ); close( unix_if.unix_sock ); debugFree( unix_buff, 5101 ); exit(EXIT_FAILURE); } while ( ( recv_buff_len = read( unix_if.unix_sock, unix_buff, 1500 ) ) > 0 ) { unix_buff[recv_buff_len] = '\0'; buff_ptr = unix_buff; bytes_written = 0; while ( ( cr_ptr = strchr( buff_ptr, '\n' ) ) != NULL ) { *cr_ptr = '\0'; if ( strncmp( buff_ptr, "EOD", 3 ) == 0 ) { if (batch_mode) goto close_con; } else if ( strncmp( buff_ptr, "BOD", 3 ) == 0 ) { if ( !batch_mode ) /* clear screen, set cursor back to 0,0 */ printf("\033[2J\033[0;0f"); } else { printf( "%s\n", buff_ptr ); } bytes_written += strlen( buff_ptr ) + 1; buff_ptr = cr_ptr + 1; } if ( bytes_written != recv_buff_len ) printf( "%s", buff_ptr ); } close_con: close( unix_if.unix_sock ); debugFree( unix_buff, 5102 ); if ( recv_buff_len < 0 ) { printf( "Error - can't read from unix socket: %s\n", strerror(errno) ); exit(EXIT_FAILURE); } else { if (!batch_mode) printf( "Connection terminated by remote host\n" ); } if ((was_hna) && (!list_empty(&hna_chg_list))) goto more_hna; exit(EXIT_SUCCESS); } } void interface_listen_sockets(void) { struct list_head *list_pos; struct batman_if *batman_if; FD_ZERO(&receive_wait_set); receive_max_sock = 0; list_for_each(list_pos, &if_list) { batman_if = list_entry(list_pos, struct batman_if, list); if (batman_if->if_active) { if (batman_if->udp_recv_sock > receive_max_sock) receive_max_sock = batman_if->udp_recv_sock; FD_SET(batman_if->udp_recv_sock, &receive_wait_set); } } } static int is_interface_up(char *dev) { struct ifreq int_req; int sock; if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) return 0; memset(&int_req, 0, sizeof (struct ifreq)); strncpy(int_req.ifr_name, dev, IFNAMSIZ - 1); if (ioctl(sock, SIOCGIFFLAGS, &int_req) < 0) goto failure; if (!(int_req.ifr_flags & IFF_UP)) goto failure; if (ioctl(sock, SIOCGIFADDR, &int_req) < 0) goto failure; close(sock); return 1; failure: close(sock); return 0; } void deactivate_interface(struct batman_if *batman_if) { if (batman_if->udp_recv_sock != 0) close(batman_if->udp_recv_sock); if (batman_if->udp_send_sock != 0) close(batman_if->udp_send_sock); batman_if->udp_recv_sock = 0; batman_if->udp_send_sock = 0; if ((batman_if->netaddr > 0) && (batman_if->netmask > 0)) { add_del_rule(batman_if->netaddr, batman_if->netmask, BATMAN_RT_TABLE_HOSTS, BATMAN_RT_PRIO_DEFAULT + batman_if->if_num, 0, RULE_TYPE_DST, RULE_DEL); add_del_rule(batman_if->netaddr, batman_if->netmask, BATMAN_RT_TABLE_UNREACH, BATMAN_RT_PRIO_UNREACH + batman_if->if_num, 0, RULE_TYPE_DST, RULE_DEL); } batman_if->if_active = 0; active_ifs--; if (batman_if->if_rp_filter_old > -1) set_rp_filter(batman_if->if_rp_filter_old, batman_if->dev); if (batman_if->if_send_redirects_old > -1) set_send_redirects(batman_if->if_send_redirects_old, batman_if->dev); batman_if->if_rp_filter_old = -1; batman_if->if_send_redirects_old = -1; interface_listen_sockets(); debug_output(3, "Interface deactivated: %s\n", batman_if->dev); } static void activate_interface(struct batman_if *batman_if) { struct ifreq int_req; int on = 1, sock_opts; if ( ( batman_if->udp_recv_sock = socket( PF_INET, SOCK_DGRAM, 0 ) ) < 0 ) { debug_output(3, "Error - can't create receive socket: %s\n", strerror(errno) ); goto error; } memset( &int_req, 0, sizeof (struct ifreq) ); strncpy( int_req.ifr_name, batman_if->dev, IFNAMSIZ - 1 ); if ( ioctl( batman_if->udp_recv_sock, SIOCGIFADDR, &int_req ) < 0 ) { debug_output(3, "Error - can't get IP address of interface %s: %s\n", batman_if->dev, strerror(errno) ); goto error; } batman_if->addr.sin_family = AF_INET; batman_if->addr.sin_port = htons(PORT); batman_if->addr.sin_addr.s_addr = ((struct sockaddr_in *)&int_req.ifr_addr)->sin_addr.s_addr; if (batman_if->addr.sin_addr.s_addr == 0) { debug_output(3, "Error - invalid ip address detected (0.0.0.0): %s\n", batman_if->dev); goto error; } if ( ioctl( batman_if->udp_recv_sock, SIOCGIFBRDADDR, &int_req ) < 0 ) { debug_output(3, "Error - can't get broadcast IP address of interface %s: %s\n", batman_if->dev, strerror(errno) ); goto error; } batman_if->broad.sin_family = AF_INET; batman_if->broad.sin_port = htons(PORT); batman_if->broad.sin_addr.s_addr = ((struct sockaddr_in *)&int_req.ifr_broadaddr)->sin_addr.s_addr; if ( batman_if->broad.sin_addr.s_addr == 0 ) { debug_output(3, "Error - invalid broadcast address detected (0.0.0.0): %s\n", batman_if->dev ); goto error; } #ifdef __linux__ /* The SIOCGIFINDEX ioctl is Linux specific, but I am not yet sure if the * equivalent exists on *BSD. There is a function called if_nametoindex() * on both Linux and BSD. * Maybe it does the same as this code and we can simply call it instead? * --stsp */ if ( ioctl( batman_if->udp_recv_sock, SIOCGIFINDEX, &int_req ) < 0 ) { debug_output(3, "Error - can't get index of interface %s: %s\n", batman_if->dev, strerror(errno) ); goto error; } batman_if->if_index = int_req.ifr_ifindex; #else batman_if->if_index = 0; #endif batman_if->wifi_if = is_wifi_interface(batman_if->dev, batman_if->udp_recv_sock); if (ioctl(batman_if->udp_recv_sock, SIOCGIFNETMASK, &int_req) < 0) { debug_output(3, "Error - can't get netmask address of interface %s: %s\n", batman_if->dev, strerror(errno)); goto error; } batman_if->netaddr = (((struct sockaddr_in *)&int_req.ifr_addr)->sin_addr.s_addr & batman_if->addr.sin_addr.s_addr); batman_if->netmask = bit_count(((struct sockaddr_in *)&int_req.ifr_addr)->sin_addr.s_addr); add_del_rule(batman_if->netaddr, batman_if->netmask, BATMAN_RT_TABLE_HOSTS, BATMAN_RT_PRIO_DEFAULT + batman_if->if_num, 0, RULE_TYPE_DST, RULE_ADD); add_del_rule(batman_if->netaddr, batman_if->netmask, BATMAN_RT_TABLE_UNREACH, BATMAN_RT_PRIO_UNREACH + batman_if->if_num, 0, RULE_TYPE_DST, RULE_ADD); if ( ( batman_if->udp_send_sock = socket( PF_INET, SOCK_DGRAM, 0 ) ) < 0 ) { debug_output(3, "Error - can't create send socket: %s\n", strerror(errno) ); goto error; } if ( setsockopt( batman_if->udp_send_sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on) ) < 0 ) { debug_output(3, "Error - can't enable broadcasts: %s\n", strerror(errno) ); goto error; } if ( bind_to_iface( batman_if->udp_send_sock, batman_if->dev ) < 0 ) { debug_output(3, "Cannot bind socket to device %s : %s \n", batman_if->dev, strerror(errno)); goto error; } if ( bind( batman_if->udp_send_sock, (struct sockaddr *)&batman_if->addr, sizeof(struct sockaddr_in) ) < 0 ) { debug_output(3, "Error - can't bind send socket: %s\n", strerror(errno) ); goto error; } /* make udp socket non blocking */ sock_opts = fcntl(batman_if->udp_send_sock, F_GETFL, 0); fcntl(batman_if->udp_send_sock, F_SETFL, sock_opts | O_NONBLOCK); if ( bind_to_iface( batman_if->udp_recv_sock, batman_if->dev ) < 0 ) { debug_output(3, "Cannot bind socket to device %s : %s \n", batman_if->dev, strerror(errno)); goto error; } if ( bind( batman_if->udp_recv_sock, (struct sockaddr *)&batman_if->broad, sizeof(struct sockaddr_in) ) < 0 ) { debug_output(3, "Error - can't bind receive socket: %s\n", strerror(errno)); goto error; } batman_if->out.orig = batman_if->addr.sin_addr.s_addr; batman_if->out.prev_sender = batman_if->addr.sin_addr.s_addr; batman_if->if_active = 1; active_ifs++; interface_listen_sockets(); debug_output(3, "Interface activated: %s\n", batman_if->dev); batman_if->if_rp_filter_old = get_rp_filter(batman_if->dev); set_rp_filter(0, batman_if->dev); batman_if->if_send_redirects_old = get_send_redirects(batman_if->dev); set_send_redirects(0, batman_if->dev); return; error: deactivate_interface(batman_if); } void init_interface(struct batman_if *batman_if) { if (strlen( batman_if->dev ) > IFNAMSIZ - 1) { printf("Error - interface name too long: %s\n", batman_if->dev); restore_defaults(); exit(EXIT_FAILURE); } if (is_interface_up(batman_if->dev)) activate_interface(batman_if); } void check_inactive_interfaces(void) { struct list_head *list_pos; struct batman_if *batman_if; /* all available interfaces are active */ if (found_ifs == active_ifs) return; list_for_each(list_pos, &if_list) { batman_if = list_entry(list_pos, struct batman_if, list); if ((!batman_if->if_active) && (is_interface_up(batman_if->dev))) activate_interface(batman_if); } } void check_active_interfaces(void) { struct list_head *list_pos; struct batman_if *batman_if; /* all available interfaces are deactive */ if (active_ifs == 0) return; list_for_each(list_pos, &if_list) { batman_if = list_entry(list_pos, struct batman_if, list); if ((batman_if->if_active) && (!is_interface_up(batman_if->dev))) deactivate_interface(batman_if); } } void init_interface_gw (void) { int32_t sock_opts; struct batman_if *batman_if = (struct batman_if *)if_list.next; batman_if->addr.sin_port = htons(GW_PORT); batman_if->udp_tunnel_sock = socket(PF_INET, SOCK_DGRAM, 0); if (batman_if->udp_tunnel_sock < 0) { debug_output( 0, "Error - can't create tunnel socket: %s\n", strerror(errno) ); restore_defaults(); exit(EXIT_FAILURE); } if ( bind( batman_if->udp_tunnel_sock, (struct sockaddr *)&batman_if->addr, sizeof(struct sockaddr_in) ) < 0 ) { debug_output( 0, "Error - can't bind tunnel socket: %s\n", strerror(errno) ); restore_defaults(); exit(EXIT_FAILURE); } /* make udp socket non blocking */ sock_opts = fcntl( batman_if->udp_tunnel_sock, F_GETFL, 0 ); fcntl( batman_if->udp_tunnel_sock, F_SETFL, sock_opts | O_NONBLOCK ); batman_if->addr.sin_port = htons(PORT); pthread_create( &batman_if->listen_thread_id, NULL, &gw_listen, batman_if ); } batmand-0.3.2+74+g2f62b17/posix/posix.c000066400000000000000000000315061435410210600171550ustar00rootroot00000000000000/* * Copyright (C) 2006-2012 BATMAN contributors: * * Thomas Lopatic, Marek Lindner * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public * License as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../os.h" #include "../batman.h" #include "../hna.h" #include "../allocate.h" #include "../hash.h" #include "../packet.h" #include "../types.h" #include "../list-batman.h" #define BAT_LOGO_PRINT(x,y,z) printf( "\x1B[%i;%iH%c", y + 1, x, z ) /* write char 'z' into column 'x', row 'y' */ #define BAT_LOGO_END(x,y) printf("\x1B[8;0H");fflush(NULL);bat_wait( x, y ); /* end of current picture */ static clock_t last_clock_tick; static float system_tick; uint8_t tunnel_running = 0; static pthread_mutex_t batman_clock_mutex = PTHREAD_MUTEX_INITIALIZER; static struct tms dummy_tms_struct; /* Make times(2) behave rationally on Linux */ static clock_t times_wrapper(void) { int save_errno = errno; clock_t ret; /** * times(2) really returns an unsigned value ... * * We don't check to see if we got back the error value (-1), because * the only possibility for an error would be if the address of * dummy_tms_struct was invalid. Since it's a * compiler-generated address, we assume that errors are impossible. * And, unfortunately, it is quite possible for the correct return * from times(2) to be exactly (clock_t)-1. Sigh... * */ errno = 0; ret = times(&dummy_tms_struct); /** * This is to work around a bug in the system call interface * for times(2) found in glibc on Linux (and maybe elsewhere) * It changes the return values from -1 to -4096 all into * -1 and then dumps the -(return value) into errno. * * This totally bizarre behavior seems to be widespread in * versions of Linux and glibc. * * Many thanks to Wolfgang Dumhs * for finding and documenting this bizarre behavior. */ if (errno != 0) { ret = (clock_t) (-errno); } errno = save_errno; return ret; } static void update_internal_clock(void) { clock_t current_clock_tick = times_wrapper(); batman_clock_ticks += (current_clock_tick - last_clock_tick); last_clock_tick = current_clock_tick; } uint32_t get_time_msec(void) { uint32_t time; pthread_mutex_lock(&batman_clock_mutex); update_internal_clock(); time = (uint32_t)(((float)(batman_clock_ticks) * 1000) / system_tick); pthread_mutex_unlock(&batman_clock_mutex); return time; } uint64_t get_time_msec64(void) { uint64_t time; pthread_mutex_lock(&batman_clock_mutex); update_internal_clock(); time = (uint64_t)(((float)(batman_clock_ticks) * 1000) / system_tick); pthread_mutex_unlock(&batman_clock_mutex); return time; } /* batman animation */ static void sym_print( char x, char y, const char *z ) { char i = 0, Z; do{ BAT_LOGO_PRINT( 25 + (int)x + (int)i, (int)y, z[(int)i] ); switch ( z[(int)i] ) { case 92: Z = 47; /* "\" --> "/" */ break; case 47: Z = 92; /* "/" --> "\" */ break; case 41: Z = 40; /* ")" --> "(" */ break; default: Z = z[(int)i]; break; } BAT_LOGO_PRINT( 24 - (int)x - (int)i, (int)y, Z ); i++; } while( z[(int)i - 1] ); return; } static void bat_wait( int32_t T, int32_t t ) { struct timeval time; time.tv_sec = T; time.tv_usec = ( t * 10000 ); select( 0, NULL, NULL, NULL, &time ); return; } void print_animation( void ) { /* clear screen, set cursor back to 0,0 */ printf("\033[2J\033[0;0f"); BAT_LOGO_END( 0, 50 ); sym_print( 0, 3, "." ); BAT_LOGO_END( 1, 0 ); sym_print( 0, 4, "v" ); BAT_LOGO_END( 0, 20 ); sym_print( 1, 3, "^" ); BAT_LOGO_END( 0, 20 ); sym_print( 1, 4, "/" ); sym_print( 0, 5, "/" ); BAT_LOGO_END( 0, 10 ); sym_print( 2, 3, "\\" ); sym_print( 2, 5, "/" ); sym_print( 0, 6, ")/" ); BAT_LOGO_END( 0, 10 ); sym_print( 2, 3, "_\\" ); sym_print( 4, 4, ")" ); sym_print( 2, 5, " /" ); sym_print( 0, 6, " )/" ); BAT_LOGO_END( 0, 10 ); sym_print( 4, 2, "'\\" ); sym_print( 2, 3, "__/ \\" ); sym_print( 4, 4, " )" ); sym_print( 1, 5, " " ); sym_print( 2, 6, " /" ); sym_print( 3, 7, "\\" ); BAT_LOGO_END( 0, 15 ); sym_print( 6, 3, " \\" ); sym_print( 3, 4, "_ \\ \\" ); sym_print( 10, 5, "\\" ); sym_print( 1, 6, " \\" ); sym_print( 3, 7, " " ); BAT_LOGO_END( 0, 20 ); sym_print( 7, 1, "____________" ); sym_print( 7, 3, " _ \\" ); sym_print( 3, 4, "_ " ); sym_print( 10, 5, " " ); sym_print( 11, 6, " " ); BAT_LOGO_END( 0, 25 ); sym_print( 3, 1, "____________ " ); sym_print( 1, 2, "'|\\ \\" ); sym_print( 2, 3, " / " ); sym_print( 3, 4, " " ); BAT_LOGO_END( 0, 25 ); sym_print( 3, 1, " ____________" ); sym_print( 1, 2, " '\\ " ); sym_print( 2, 3, "__/ _ \\" ); sym_print( 3, 4, "_" ); BAT_LOGO_END( 0, 35 ); sym_print( 7, 1, " " ); sym_print( 7, 3, " \\ " ); sym_print( 5, 4, "\\ \\" ); sym_print( 11, 5, "\\" ); sym_print( 12, 6, "\\" ); BAT_LOGO_END( 0 ,35 ); } void addr_to_string( uint32_t addr, char *str, int32_t len ) { inet_ntop( AF_INET, &addr, str, len ); } int32_t rand_num( int32_t limit ) { return ( limit == 0 ? 0 : rand() % limit ); } int8_t is_aborted(void) { return stop != 0; } void handler( int32_t BATMANUNUSED(sig) ) { stop = 1; } void del_default_route(void) { curr_gateway = NULL; } void add_default_route(void) { struct curr_gw_data *curr_gw_data; if (tunnel_running) { debug_output(3, "Error - couldn't create tunnel: old tunnel is still active\n"); return; } curr_gw_data = debugMalloc( sizeof(struct curr_gw_data), 207 ); curr_gw_data->orig = curr_gateway->orig_node->orig; curr_gw_data->gw_node = curr_gateway; curr_gw_data->batman_if = curr_gateway->orig_node->batman_if; tunnel_running = 1; if (pthread_create(&curr_gateway_thread_id, NULL, &client_to_gw_tun, curr_gw_data) != 0) { debug_output(0, "Error - couldn't spawn thread: %s\n", strerror(errno)); debugFree(curr_gw_data, 1213); curr_gateway = NULL; tunnel_running = 0; } else { pthread_detach(curr_gateway_thread_id); } } int8_t receive_packet(unsigned char *packet_buff, int32_t packet_buff_len, int16_t *packet_len, uint32_t *neigh, uint32_t timeout, struct batman_if **if_incoming) { struct sockaddr_in addr; struct timeval tv; struct list_head *if_pos; struct batman_if *batman_if; uint32_t addr_len; int8_t res; fd_set tmp_wait_set; addr_len = sizeof(struct sockaddr_in); memcpy( &tmp_wait_set, &receive_wait_set, sizeof(fd_set) ); while (1) { tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000; res = select(receive_max_sock + 1, &tmp_wait_set, NULL, NULL, &tv); if (res >= 0) break; if (errno != EINTR) { debug_output(0, "Error - can't select (receive_packet): %s\n", strerror(errno)); /* we might have a deactivated interface - check all active interfaces for problems */ check_active_interfaces(); /* on error the wait_sets are reset - we have to re-create them */ interface_listen_sockets(); return -1; } } if ( res == 0 ) return 0; list_for_each(if_pos, &if_list) { batman_if = list_entry(if_pos, struct batman_if, list); if (FD_ISSET(batman_if->udp_recv_sock, &tmp_wait_set)) { if ((*packet_len = recvfrom(batman_if->udp_recv_sock, packet_buff, packet_buff_len - 1, 0, (struct sockaddr *)&addr, &addr_len)) < 0) { debug_output(0, "Error - can't receive packet: %s\n", strerror(errno)); deactivate_interface(batman_if); return -1; } if (((unsigned int)*packet_len) < sizeof(struct bat_packet)) return 0; (*if_incoming) = batman_if; break; } } *neigh = addr.sin_addr.s_addr; return 1; } int8_t send_udp_packet(unsigned char *packet_buff, int32_t packet_buff_len, struct sockaddr_in *broad, int32_t send_sock, struct batman_if *batman_if) { if ((batman_if != NULL) && (!batman_if->if_active)) return 0; if ( sendto( send_sock, packet_buff, packet_buff_len, 0, (struct sockaddr *)broad, sizeof(struct sockaddr_in) ) < 0 ) { if ( errno == 1 ) { debug_output(0, "Error - can't send udp packet: %s.\nDoes your firewall allow outgoing packets on port %i ?\n", strerror(errno), ntohs(broad->sin_port)); } else { debug_output(0, "Error - can't send udp packet: %s\n", strerror(errno)); } return -1; } return 0; } void del_gw_interface(void) { struct batman_if *batman_if = (struct batman_if *)if_list.next; if (batman_if->udp_tunnel_sock > 0) { if (batman_if->listen_thread_id != 0) { pthread_join(batman_if->listen_thread_id, NULL); } close(batman_if->udp_tunnel_sock); batman_if->listen_thread_id = 0; batman_if->udp_tunnel_sock = 0; } } void restore_defaults(void) { struct list_head *if_pos, *if_pos_tmp; struct batman_if *batman_if; stop = 1; if ( routing_class > 0 ) add_del_interface_rules(RULE_DEL); del_gw_interface(); list_for_each_safe( if_pos, if_pos_tmp, &if_list ) { batman_if = list_entry( if_pos, struct batman_if, list ); deactivate_interface(batman_if); list_del( (struct list_head *)&if_list, if_pos, &if_list ); debugFree( if_pos, 1214 ); } /* delete rule for hna networks */ add_del_rule(0, 0, BATMAN_RT_TABLE_NETWORKS, BATMAN_RT_PRIO_UNREACH - 1, 0, RULE_TYPE_DST, RULE_DEL); /* delete unreachable routing table entry */ add_del_route(0, 0, 0, 0, 0, "unknown", BATMAN_RT_TABLE_UNREACH, ROUTE_TYPE_UNREACHABLE, ROUTE_DEL); if ( ( routing_class != 0 ) && ( curr_gateway != NULL ) ) del_default_route(); if ( vis_if.sock ) close( vis_if.sock ); if ( unix_if.unix_sock ) close( unix_if.unix_sock ); if ( unix_if.listen_thread_id != 0 ) { pthread_join( unix_if.listen_thread_id, NULL ); unix_if.listen_thread_id = 0; } if ( debug_level == 0 ) closelog(); if (policy_routing_script != NULL) { close(policy_routing_pipe); waitpid(policy_routing_script_pid, NULL, 0); } } void restore_and_exit( uint8_t is_sigsegv ) { struct orig_node *orig_node; struct hash_it_t *hashit = NULL; if ( !unix_client ) { /* remove tun interface first */ stop = 1; del_gw_interface(); if ( ( routing_class != 0 ) && ( curr_gateway != NULL ) ) del_default_route(); /* all rules and routes were purged in segmentation_fault() */ if ( !is_sigsegv ) { while ( NULL != ( hashit = hash_iterate( orig_hash, hashit ) ) ) { orig_node = hashit->bucket->data; update_routes( orig_node, NULL, NULL, 0 ); } } restore_defaults(); } if (is_sigsegv) raise(SIGSEGV); /* call exit always even if it will not be reached to make the compiler happy */ exit(EXIT_FAILURE); } void segmentation_fault(int32_t BATMANUNUSED(sig)) { signal(SIGSEGV, SIG_DFL); debug_output( 0, "Error - SIGSEGV received, trying to clean up ... \n" ); flush_routes_rules(0); flush_routes_rules(1); restore_and_exit(1); } void cleanup(void) { int8_t i; struct list_head *debug_pos, *debug_pos_tmp; for ( i = 0; i < debug_level_max; i++ ) { if ( debug_clients.clients_num[i] > 0 ) { list_for_each_safe( debug_pos, debug_pos_tmp, (struct list_head *)debug_clients.fd_list[i] ) { list_del( (struct list_head *)debug_clients.fd_list[i], debug_pos, (struct list_head_first *)debug_clients.fd_list[i] ); debugFree( debug_pos, 1218 ); } } debugFree( debug_clients.fd_list[i], 1219 ); debugFree( debug_clients.mutex[i], 1220 ); } debugFree( debug_clients.fd_list, 1221 ); debugFree( debug_clients.mutex, 1222 ); debugFree( debug_clients.clients_num, 1223 ); } int main(int argc, char *argv[]) { int8_t res; /* check if user is root */ if ((getuid()) || (getgid())) { fprintf(stderr, "Error - you must be root to run '%s' !\n", argv[0]); exit(EXIT_FAILURE); } INIT_LIST_HEAD_FIRST(forw_list); INIT_LIST_HEAD_FIRST(gw_list); INIT_LIST_HEAD_FIRST(if_list); hna_init(); /* save start value */ system_tick = (float)sysconf(_SC_CLK_TCK); last_clock_tick = times_wrapper(); update_internal_clock(); apply_init_args(argc, argv); init_bh_ports(); srand(getpid()); res = batman(); /* cleaning up */ hna_free(); restore_defaults(); cleanup(); checkLeak(); return res; } batmand-0.3.2+74+g2f62b17/posix/tunnel.c000066400000000000000000000552421435410210600173230ustar00rootroot00000000000000/* * Copyright (C) 2006-2012 BATMAN contributors: * * Marek Lindner * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public * License as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA * */ #include #include #include #include #include #include #include #include /* open(), O_RDWR */ #include #include #include #include #include #include #include "../os.h" #include "../batman.h" #include "../allocate.h" #include "../hash.h" #include "../list-batman.h" #include "../packet.h" #include "../types.h" #define TUNNEL_DATA 0x01 #define TUNNEL_IP_REQUEST 0x02 #define TUNNEL_IP_INVALID 0x03 #define TUNNEL_KEEPALIVE_REQUEST 0x04 #define TUNNEL_KEEPALIVE_REPLY 0x05 #define GW_STATE_UNKNOWN 0x01 #define GW_STATE_VERIFIED 0x02 #define GW_STATE_UNKNOWN_TIMEOUT 60000 #define GW_STATE_VERIFIED_TIMEOUT 5 * GW_STATE_UNKNOWN_TIMEOUT #define IP_LEASE_TIMEOUT 4 * GW_STATE_VERIFIED_TIMEOUT unsigned short bh_udp_ports[] = BH_UDP_PORTS; void init_bh_ports(void) { int i; for (i = 0; i < (int)(sizeof(bh_udp_ports)/sizeof(short)); i++) bh_udp_ports[i] = htons(bh_udp_ports[i]); } static uint8_t get_tunneled_protocol(const unsigned char *buff) { return ((struct iphdr *)(buff + 1))->protocol; } static uint32_t get_tunneled_sender_ip(const unsigned char *buff) { return ((struct iphdr *)(buff + 1))->saddr; } static uint16_t get_tunneled_udpdest(const unsigned char *buff) { return ((struct udphdr *)(buff + 1 + ((struct iphdr *)(buff + 1))->ihl*4))->dest; } static int8_t get_tun_ip(struct sockaddr_in *gw_addr, int32_t udp_sock, uint32_t *tun_addr) { struct sockaddr_in sender_addr; struct timeval tv; unsigned char buff[100]; int32_t res, buff_len; uint32_t addr_len; int8_t i = 12; fd_set wait_sockets; addr_len = sizeof(struct sockaddr_in); memset(&buff, 0, sizeof(buff)); while ((!is_aborted()) && (curr_gateway != NULL) && (i > 0)) { buff[0] = TUNNEL_IP_REQUEST; if (sendto(udp_sock, buff, sizeof(buff), 0, (struct sockaddr *)gw_addr, sizeof(struct sockaddr_in)) < 0) { debug_output(0, "Error - can't send ip request to gateway: %s \n", strerror(errno)); goto next_try; } tv.tv_sec = 0; tv.tv_usec = 250000; FD_ZERO(&wait_sockets); FD_SET(udp_sock, &wait_sockets); res = select(udp_sock + 1, &wait_sockets, NULL, NULL, &tv); if ((res < 0) && (errno != EINTR)) { debug_output(0, "Error - can't select (get_tun_ip): %s \n", strerror(errno)); break; } if (res <= 0) goto next_try; /* gateway message */ if (!FD_ISSET(udp_sock, &wait_sockets)) goto next_try; if ((buff_len = recvfrom(udp_sock, buff, sizeof(buff) - 1, 0, (struct sockaddr *)&sender_addr, &addr_len)) < 0) { debug_output(0, "Error - can't receive ip request: %s \n", strerror(errno)); goto next_try; } if (buff_len < 4) { debug_output(0, "Error - can't receive ip request: packet size is %i < 4 \n", buff_len); goto next_try; } /* a gateway with multiple interfaces breaks here */ /* if (sender_addr.sin_addr.s_addr != gw_addr->sin_addr.s_addr) { debug_output(0, "Error - can't receive ip request: sender IP is not gateway IP \n"); goto next_try; } */ memcpy(tun_addr, buff + 1, 4); return 1; next_try: i--; } if (i == 0) debug_output(0, "Error - can't receive ip from gateway: number of maximum retries reached \n"); return -1; } void *client_to_gw_tun(void *arg) { struct curr_gw_data *curr_gw_data = (struct curr_gw_data *)arg; struct sockaddr_in gw_addr, my_addr, sender_addr; struct timeval tv; struct list_head_first packet_list; int32_t res, max_sock, buff_len, udp_sock, tun_fd, tun_ifi, sock_opts, i, num_refresh_lease = 0, last_refresh_attempt = 0; uint32_t addr_len, current_time, ip_lease_time = 0, gw_state_time = 0, my_tun_addr = 0, ignore_packet; char tun_if[IFNAMSIZ], my_str[ADDR_STR_LEN], gw_str[ADDR_STR_LEN], gw_state = GW_STATE_UNKNOWN; unsigned char buff[1501]; fd_set wait_sockets, tmp_wait_sockets; addr_len = sizeof(struct sockaddr_in); INIT_LIST_HEAD_FIRST(packet_list); memset(&gw_addr, 0, sizeof(struct sockaddr_in)); memset(&my_addr, 0, sizeof(struct sockaddr_in)); gw_addr.sin_family = AF_INET; gw_addr.sin_port = curr_gw_data->gw_node->gw_port; gw_addr.sin_addr.s_addr = curr_gw_data->orig; my_addr.sin_family = AF_INET; my_addr.sin_port = curr_gw_data->gw_node->gw_port; my_addr.sin_addr.s_addr = curr_gw_data->batman_if->addr.sin_addr.s_addr; /* connect to server (establish udp tunnel) */ if ((udp_sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { debug_output(0, "Error - can't create udp socket: %s\n", strerror(errno)); goto out; } sock_opts = 1; if (setsockopt(udp_sock, SOL_SOCKET, SO_REUSEADDR, &sock_opts, sizeof(sock_opts)) < 0) { debug_output(0, "Error - can't set options on udp socket: %s\n", strerror(errno)); goto udp_out; } if (bind(udp_sock, (struct sockaddr *)&my_addr, sizeof(struct sockaddr_in)) < 0) { debug_output(0, "Error - can't bind tunnel socket: %s\n", strerror(errno)); goto udp_out; } /* make udp socket non blocking */ sock_opts = fcntl(udp_sock, F_GETFL, 0); fcntl(udp_sock, F_SETFL, sock_opts | O_NONBLOCK); if (get_tun_ip(&gw_addr, udp_sock, &my_tun_addr) < 0) { curr_gw_data->gw_node->last_failure = get_time_msec(); curr_gw_data->gw_node->gw_failure++; goto udp_out; } ip_lease_time = get_time_msec(); addr_to_string(my_tun_addr, my_str, sizeof(my_str)); addr_to_string(curr_gw_data->orig, gw_str, sizeof(gw_str)); debug_output(3, "Gateway client - got IP (%s) from gateway: %s \n", my_str, gw_str); if (add_dev_tun(curr_gw_data->batman_if, my_tun_addr, tun_if, sizeof(tun_if), &tun_fd, &tun_ifi) <= 0) goto udp_out; add_nat_rule(tun_if); add_del_route(0, 0, 0, my_tun_addr, tun_ifi, tun_if, BATMAN_RT_TABLE_TUNNEL, ROUTE_TYPE_UNICAST, ROUTE_ADD); FD_ZERO(&wait_sockets); FD_SET(udp_sock, &wait_sockets); FD_SET(tun_fd, &wait_sockets); max_sock = (udp_sock > tun_fd ? udp_sock : tun_fd); while ((!is_aborted()) && (curr_gateway != NULL) && (!curr_gw_data->gw_node->deleted)) { tv.tv_sec = 0; tv.tv_usec = 250; memcpy(&tmp_wait_sockets, &wait_sockets, sizeof(fd_set)); res = select(max_sock + 1, &tmp_wait_sockets, NULL, NULL, &tv); current_time = get_time_msec(); if ((res < 0) && (errno != EINTR)) { debug_output(0, "Error - can't select (client_to_gw_tun): %s \n", strerror(errno)); break; } if (res <= 0) goto after_incoming_packet; /* traffic that comes from the gateway via the tunnel */ if (FD_ISSET(udp_sock, &tmp_wait_sockets)) { while ((buff_len = recvfrom(udp_sock, buff, sizeof(buff) - 1, 0, (struct sockaddr *)&sender_addr, &addr_len)) > 0) { if (buff_len < 2) { debug_output(0, "Error - ignoring gateway packet from %s: packet too small (%i)\n", my_str, buff_len); continue; } /* a gateway with multiple interfaces breaks here */ /*if (sender_addr.sin_addr.s_addr != gw_addr.sin_addr.s_addr) { debug_output(0, "Error - can't receive ip request: sender IP is not gateway IP \n"); continue; }*/ switch(buff[0]) { /* got data from gateway */ case TUNNEL_DATA: if (write(tun_fd, buff + 1, buff_len - 1) < 0) debug_output(0, "Error - can't write packet: %s\n", strerror(errno)); if (get_tunneled_protocol(buff) != IPPROTO_ICMP) { gw_state = GW_STATE_VERIFIED; gw_state_time = current_time; } break; /* gateway told us that we have no valid ip */ case TUNNEL_IP_INVALID: addr_to_string(my_tun_addr, my_str, sizeof(my_str)); debug_output(3, "Gateway client - gateway (%s) says: IP (%s) is invalid (maybe expired) \n", gw_str, my_str); curr_gateway = NULL; goto cleanup; /* keep alive packet was confirmed */ case TUNNEL_KEEPALIVE_REPLY: debug_output(3, "Gateway client - successfully refreshed IP lease: %s \n", gw_str); ip_lease_time = current_time; num_refresh_lease = 0; break; } } if (errno != EWOULDBLOCK) { debug_output(0, "Error - gateway client can't receive packet: %s\n", strerror(errno)); break; } /* traffic that we should send to the gateway via the tunnel */ } else if (FD_ISSET(tun_fd, &tmp_wait_sockets)) { while ((buff_len = read(tun_fd, buff + 1, sizeof(buff) - 2)) > 0) { buff[0] = TUNNEL_DATA; if (sendto(udp_sock, buff, buff_len + 1, 0, (struct sockaddr *)&gw_addr, sizeof(struct sockaddr_in)) < 0) debug_output(0, "Error - can't send data to gateway: %s\n", strerror(errno)); if ((gw_state == GW_STATE_UNKNOWN) && (gw_state_time == 0)) { ignore_packet = 0; if (get_tunneled_protocol(buff) == IPPROTO_ICMP) ignore_packet = 1; if (get_tunneled_protocol(buff) == IPPROTO_UDP) { for (i = 0; i < (int)(sizeof(bh_udp_ports)/sizeof(short)); i++) { if (get_tunneled_udpdest(buff) == bh_udp_ports[i]) { ignore_packet = 1; break; } } } /* if the packet was not natted (half tunnel) don't active the blackhole detection */ if (get_tunneled_sender_ip(buff) != my_tun_addr) ignore_packet = 1; if (!ignore_packet) gw_state_time = current_time; } } if (errno != EWOULDBLOCK) { debug_output(0, "Error - gateway client can't read tun data: %s\n", strerror(errno)); break; } } after_incoming_packet: /* refresh leased IP */ if (((int)(current_time - (ip_lease_time + IP_LEASE_TIMEOUT)) > 0) && ((int)(current_time - (last_refresh_attempt + 1000)) > 0)) { if (num_refresh_lease < 12) { buff[0] = TUNNEL_KEEPALIVE_REQUEST; if (sendto(udp_sock, buff, 100, 0, (struct sockaddr *)&gw_addr, sizeof(struct sockaddr_in)) < 0) debug_output(0, "Error - can't send keep alive request to gateway: %s \n", strerror(errno)); num_refresh_lease++; last_refresh_attempt = current_time; } else { addr_to_string(my_tun_addr, my_str, sizeof(my_str)); debug_output(3, "Gateway client - disconnecting from unresponsive gateway (%s): could not refresh IP lease \n", gw_str); curr_gw_data->gw_node->last_failure = current_time; curr_gw_data->gw_node->gw_failure++; break; } } /* drop connection to gateway if the gateway does not respond */ if ((gw_state == GW_STATE_UNKNOWN) && (gw_state_time != 0) && ((int)(current_time - (gw_state_time + GW_STATE_UNKNOWN_TIMEOUT)) > 0)) { debug_output(3, "Gateway client - disconnecting from unresponsive gateway (%s): gateway seems to be a blackhole \n", gw_str); curr_gw_data->gw_node->last_failure = current_time; curr_gw_data->gw_node->gw_failure++; break; } /* change back to unknown state if gateway did not respond in time */ if ((gw_state == GW_STATE_VERIFIED) && ((int)(current_time - (gw_state_time + GW_STATE_VERIFIED_TIMEOUT)) > 0)) { gw_state = GW_STATE_UNKNOWN; gw_state_time = 0; } } cleanup: add_del_route(0, 0, 0, my_tun_addr, tun_ifi, tun_if, BATMAN_RT_TABLE_TUNNEL, ROUTE_TYPE_UNICAST, ROUTE_DEL); del_nat_rule(tun_if); del_dev_tun(tun_fd); udp_out: close(udp_sock); out: curr_gateway = NULL; tunnel_running = 0; debugFree(arg, 1212); return NULL; } static struct gw_client *get_ip_addr(struct sockaddr_in *client_addr, struct hashtable_t **wip_hash, struct hashtable_t **vip_hash, struct list_head_first *free_ip_list, uint8_t next_free_ip[]) { struct gw_client *gw_client; struct free_ip *free_ip; struct list_head *list_pos, *list_pos_tmp; struct hashtable_t *swaphash; gw_client = ((struct gw_client *)hash_find(*wip_hash, &client_addr->sin_addr.s_addr)); if (gw_client != NULL) return gw_client; gw_client = debugMalloc( sizeof(struct gw_client), 208 ); gw_client->wip_addr = client_addr->sin_addr.s_addr; gw_client->client_port = client_addr->sin_port; gw_client->last_keep_alive = get_time_msec(); gw_client->vip_addr = 0; gw_client->nat_warn = 0; list_for_each_safe(list_pos, list_pos_tmp, free_ip_list) { free_ip = list_entry(list_pos, struct free_ip, list); gw_client->vip_addr = free_ip->addr; list_del((struct list_head *)free_ip_list, list_pos, free_ip_list); debugFree(free_ip, 1216); break; } if (gw_client->vip_addr == 0) { gw_client->vip_addr = *(uint32_t *)next_free_ip; next_free_ip[3]++; if (next_free_ip[3] == 0) next_free_ip[2]++; } hash_add(*wip_hash, gw_client); hash_add(*vip_hash, gw_client); if ((*wip_hash)->elements * 4 > (*wip_hash)->size) { swaphash = hash_resize(*wip_hash, (*wip_hash)->size * 2); if (swaphash == NULL) { debug_output( 0, "Couldn't resize hash table \n" ); restore_and_exit(0); } *wip_hash = swaphash; swaphash = hash_resize(*vip_hash, (*vip_hash)->size * 2); if (swaphash == NULL) { debug_output( 0, "Couldn't resize hash table \n" ); restore_and_exit(0); } *vip_hash = swaphash; } return gw_client; } /* needed for hash, compares 2 struct gw_client, but only their ip-addresses. assumes that * the ip address is the first/second field in the struct */ static int compare_wip(void *data1, void *data2) { return (memcmp(data1, data2, 4) == 0 ? 1 : 0); } static int compare_vip(void *data1, void *data2) { return (memcmp(((char *)data1) + 4, ((char *)data2) + 4, 4) == 0 ? 1 : 0); } /* hashfunction to choose an entry in a hash table of given size */ /* hash algorithm from https://en.wikipedia.org/wiki/Hash_table */ static int choose_wip(void *data, int32_t size) { unsigned char *key= data; uint32_t hash = 0; size_t i; for (i = 0; i < 4; i++) { hash += key[i]; hash += (hash << 10); hash ^= (hash >> 6); } hash += (hash << 3); hash ^= (hash >> 11); hash += (hash << 15); return (hash%size); } static int choose_vip(void *data, int32_t size) { unsigned char *key= data; uint32_t hash = 0; size_t i; for (i = 4; i < 8; i++) { hash += key[i]; hash += (hash << 10); hash ^= (hash >> 6); } hash += (hash << 3); hash ^= (hash >> 11); hash += (hash << 15); return (hash%size); } void *gw_listen(void *BATMANUNUSED(arg)) { struct batman_if *batman_if = (struct batman_if *)if_list.next; struct timeval tv; struct sockaddr_in addr, client_addr; struct gw_client *gw_client; char gw_addr[16], str[16], tun_dev[IFNAMSIZ]; unsigned char buff[1501]; int32_t res, max_sock, buff_len, tun_fd, tun_ifi; uint32_t addr_len, client_timeout, current_time; uint8_t my_tun_ip[4] ALIGN_WORD, next_free_ip[4] ALIGN_WORD; struct hashtable_t *wip_hash, *vip_hash; struct list_head_first free_ip_list; fd_set wait_sockets, tmp_wait_sockets; struct hash_it_t *hashit; struct free_ip *free_ip; struct list_head *list_pos, *list_pos_tmp; my_tun_ip[0] = next_free_ip[0] = 169; my_tun_ip[1] = next_free_ip[1] = 254; my_tun_ip[2] = next_free_ip[2] = 0; my_tun_ip[3] = 0; next_free_ip[3] = 1; addr_len = sizeof (struct sockaddr_in); client_timeout = get_time_msec(); client_addr.sin_family = AF_INET; client_addr.sin_port = htons(PORT + 1); INIT_LIST_HEAD_FIRST(free_ip_list); if (add_dev_tun(batman_if, *(uint32_t *)my_tun_ip, tun_dev, sizeof(tun_dev), &tun_fd, &tun_ifi) < 0) return NULL; if (NULL == ( wip_hash = hash_new(128, compare_wip, choose_wip))) return NULL; if (NULL == (vip_hash = hash_new(128, compare_vip, choose_vip))) { hash_destroy(wip_hash); return NULL; } add_del_route(*(uint32_t *)my_tun_ip, 16, 0, 0, tun_ifi, tun_dev, 254, ROUTE_TYPE_UNICAST, ROUTE_ADD); FD_ZERO(&wait_sockets); FD_SET(batman_if->udp_tunnel_sock, &wait_sockets); FD_SET(tun_fd, &wait_sockets); max_sock = (batman_if->udp_tunnel_sock > tun_fd ? batman_if->udp_tunnel_sock : tun_fd); while ((!is_aborted()) && (gateway_class > 0)) { tv.tv_sec = 0; tv.tv_usec = 250; memcpy(&tmp_wait_sockets, &wait_sockets, sizeof(fd_set)); res = select(max_sock + 1, &tmp_wait_sockets, NULL, NULL, &tv); current_time = get_time_msec(); if ((res < 0) && (errno != EINTR)) { debug_output(0, "Error - can't select (gw_listen): %s \n", strerror(errno)); break; } if (res <= 0) goto after_incoming_packet; /* traffic coming from the tunnel client via UDP */ if (FD_ISSET(batman_if->udp_tunnel_sock, &tmp_wait_sockets)) { while ((buff_len = recvfrom(batman_if->udp_tunnel_sock, buff, sizeof(buff) - 1, 0, (struct sockaddr *)&addr, &addr_len)) > 0) { if (buff_len < 2) { addr_to_string(addr.sin_addr.s_addr, str, sizeof(str)); debug_output(0, "Error - ignoring client packet from %s: packet too small (%i)\n", str, buff_len); continue; } switch(buff[0]) { /* client sends us data that should to the internet */ case TUNNEL_DATA: /* compare_vip() adds 4 bytes, hence buff + 9 */ gw_client = ((struct gw_client *)hash_find(vip_hash, buff + 9)); /* check whether client IP is known */ if ((gw_client == NULL) || ((gw_client->wip_addr != addr.sin_addr.s_addr) && (gw_client->nat_warn == 0))) { buff[0] = TUNNEL_IP_INVALID; addr_to_string(addr.sin_addr.s_addr, str, sizeof(str)); debug_output(0, "Error - got packet from unknown client: %s (tunnelled sender ip %i.%i.%i.%i) \n", str, (uint8_t)buff[13], (uint8_t)buff[14], (uint8_t)buff[15], (uint8_t)buff[16]); if (gw_client == NULL) { /* TODO: only send refresh if the IP comes from 169.254.x.y ?? */ /*if (sendto(batman_if->udp_tunnel_sock, buff, buff_len, 0, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0) debug_output(0, "Error - can't send invalid ip information to client (%s): %s \n", str, strerror(errno));*/ /* auto assign a dummy address to output the NAT warning only once */ gw_client = get_ip_addr(&addr, &wip_hash, &vip_hash, &free_ip_list, next_free_ip); addr_to_string(gw_client->vip_addr, str, sizeof(str)); addr_to_string(addr.sin_addr.s_addr, gw_addr, sizeof(gw_addr)); debug_output(3, "Gateway - assigned %s to unregistered client: %s \n", str, gw_addr); } debug_output(0, "Either enable NAT on the client or make sure this host has a route back to the sender address.\n"); gw_client->nat_warn++; } if (write(tun_fd, buff + 1, buff_len - 1) < 0) debug_output(0, "Error - can't write packet into tun: %s\n", strerror(errno)); break; /* client asks us to refresh the IP lease */ case TUNNEL_KEEPALIVE_REQUEST: gw_client = ((struct gw_client *)hash_find(wip_hash, &addr.sin_addr.s_addr)); buff[0] = TUNNEL_IP_INVALID; if (gw_client != NULL) { gw_client->last_keep_alive = current_time; buff[0] = TUNNEL_KEEPALIVE_REPLY; } addr_to_string(addr.sin_addr.s_addr, str, sizeof(str)); if (sendto(batman_if->udp_tunnel_sock, buff, 100, 0, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0) { debug_output(0, "Error - can't send %s to client (%s): %s \n", (buff[0] == TUNNEL_KEEPALIVE_REPLY ? "keep alive reply" : "invalid ip information"), str, strerror(errno)); continue; } debug_output(3, "Gateway - send %s to client: %s \n", (buff[0] == TUNNEL_KEEPALIVE_REPLY ? "keep alive reply" : "invalid ip information"), str); break; /* client requests a fresh IP */ case TUNNEL_IP_REQUEST: gw_client = get_ip_addr(&addr, &wip_hash, &vip_hash, &free_ip_list, next_free_ip); memcpy(buff + 1, (char *)&gw_client->vip_addr, 4); if (sendto(batman_if->udp_tunnel_sock, buff, 100, 0, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0) { addr_to_string(addr.sin_addr.s_addr, str, sizeof (str)); debug_output(0, "Error - can't send requested ip to client (%s): %s \n", str, strerror(errno)); continue; } addr_to_string(gw_client->vip_addr, str, sizeof(str)); addr_to_string(addr.sin_addr.s_addr, gw_addr, sizeof(gw_addr)); debug_output(3, "Gateway - assigned %s to client: %s \n", str, gw_addr); break; } } if (errno != EWOULDBLOCK) { debug_output(0, "Error - gateway can't receive packet: %s\n", strerror(errno)); break; } /* traffic coming from the internet that needs to be sent back to the client */ } else if (FD_ISSET(tun_fd, &tmp_wait_sockets)) { while ((buff_len = read(tun_fd, buff + 1, sizeof(buff) - 2 )) > 0) { gw_client = ((struct gw_client *)hash_find(vip_hash, buff + 13)); if (gw_client != NULL) { client_addr.sin_addr.s_addr = gw_client->wip_addr; client_addr.sin_port = gw_client->client_port; buff[0] = TUNNEL_DATA; if (sendto(batman_if->udp_tunnel_sock, buff, buff_len + 1, 0, (struct sockaddr *)&client_addr, sizeof(struct sockaddr_in)) < 0) debug_output(0, "Error - can't send data to client (%s): %s \n", str, strerror(errno)); } else { addr_to_string( *(uint32_t *)(buff + 17), gw_addr, sizeof(gw_addr)); debug_output(3, "Gateway - could not resolve packet: %s \n", gw_addr); } } if (errno != EWOULDBLOCK) { debug_output(0, "Error - gateway can't read tun data: %s\n", strerror(errno)); break; } } after_incoming_packet: /* close unresponsive client connections (free unused IPs) */ if ((int)(current_time - (client_timeout + 60000)) > 0) { client_timeout = current_time; hashit = NULL; while (NULL != (hashit = hash_iterate(wip_hash, hashit))) { gw_client = hashit->bucket->data; if ((int)(current_time - (gw_client->last_keep_alive + IP_LEASE_TIMEOUT + GW_STATE_UNKNOWN_TIMEOUT)) > 0) { hash_remove_bucket(wip_hash, hashit); hash_remove(vip_hash, gw_client); free_ip = debugMalloc(sizeof(struct neigh_node), 210); INIT_LIST_HEAD(&free_ip->list); free_ip->addr = gw_client->vip_addr; list_add_tail( &free_ip->list, &free_ip_list ); debugFree(gw_client, 1216); } } } } /* delete tun device and routes on exit */ my_tun_ip[3] = 0; add_del_route( *(uint32_t *)my_tun_ip, 16, 0, 0, tun_ifi, tun_dev, 254, ROUTE_TYPE_UNICAST, ROUTE_DEL ); del_dev_tun( tun_fd ); hashit = NULL; while (NULL != (hashit = hash_iterate(wip_hash, hashit))) { gw_client = hashit->bucket->data; hash_remove_bucket(wip_hash, hashit); hash_remove(vip_hash, gw_client); debugFree(gw_client, 1217); } hash_destroy(wip_hash); hash_destroy(vip_hash); list_for_each_safe(list_pos, list_pos_tmp, &free_ip_list) { free_ip = list_entry(list_pos, struct free_ip, list); list_del((struct list_head *)&free_ip_list, list_pos, &free_ip_list); debugFree(free_ip, 1218); } return NULL; } batmand-0.3.2+74+g2f62b17/posix/unix_socket.c000066400000000000000000000431301435410210600203420ustar00rootroot00000000000000/* * Copyright (C) 2006-2012 BATMAN contributors: * * Marek Lindner * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public * License as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../os.h" #include "../batman.h" #include "../hna.h" #include "../allocate.h" #include "../list-batman.h" #include "../packet.h" #include "../types.h" void debug_output(int8_t debug_prio, const char *format, ...) { struct list_head *debug_pos; struct debug_level_info *debug_level_info; int8_t debug_prio_intern; va_list args; if (!log_facility_active) { va_start(args, format); vprintf(format, args); va_end(args); return; } if (debug_prio == 0) { if (debug_level == 0) { va_start(args, format); vsyslog(LOG_ERR, format, args); va_end(args); } else if ((debug_level == 3) || (debug_level == 4)) { if (debug_level == 4) printf("[%10u] ", get_time_msec()); va_start(args, format); vprintf(format, args); va_end(args); } debug_prio_intern = 3; } else { debug_prio_intern = debug_prio - 1; } if (debug_clients.clients_num[debug_prio_intern] < 1) return; if (pthread_mutex_trylock((pthread_mutex_t *)debug_clients.mutex[debug_prio_intern] ) != 0) { debug_output(0, "Warning - could not trylock mutex (debug_output): %s \n", strerror(EBUSY)); return; } va_start(args, format); list_for_each(debug_pos, (struct list_head *)debug_clients.fd_list[debug_prio_intern]) { debug_level_info = list_entry(debug_pos, struct debug_level_info, list); /* batman debug gets milliseconds prepended for better debugging */ if (debug_prio_intern == 3) dprintf(debug_level_info->fd, "[%10u] ", get_time_msec()); if (((debug_level == 1) || (debug_level == 2)) && (debug_level_info->fd == 1) && (strncmp(format, "BOD", 3) == 0)) /* clear screen, set cursor back to 0,0 */ printf("\033[2J\033[0;0f"); if (((debug_level != 1) && (debug_level != 2)) || (debug_level_info->fd != 1) || (strncmp(format, "EOD", 3) != 0)) vdprintf(debug_level_info->fd, format, args); } va_end(args); if (pthread_mutex_unlock((pthread_mutex_t *)debug_clients.mutex[debug_prio_intern]) < 0) debug_output(0, "Error - could not unlock mutex (debug_output): %s \n", strerror(errno)); } void internal_output(uint32_t sock) { dprintf(sock, "source_version=%s\n", SOURCE_VERSION); dprintf(sock, "compat_version=%i\n", COMPAT_VERSION); dprintf(sock, "vis_compat_version=%i\n", VIS_COMPAT_VERSION); dprintf(sock, "ogm_port=%i\n", PORT); dprintf(sock, "gw_port=%i\n", GW_PORT); dprintf(sock, "vis_port=%i\n", PORT + 2); dprintf(sock, "unix_socket_path=%s\n", UNIX_PATH); dprintf(sock, "own_ogm_jitter=%i\n", JITTER); dprintf(sock, "default_ttl=%i\n", TTL); dprintf(sock, "originator_timeout=%u (default: %u)\n", purge_timeout, PURGE_TIMEOUT); dprintf(sock, "tq_local_window_size=%i\n", TQ_LOCAL_WINDOW_SIZE); dprintf(sock, "tq_global_window_size=%i\n", TQ_GLOBAL_WINDOW_SIZE); dprintf(sock, "tq_local_bidirect_send_minimum=%i\n", TQ_LOCAL_BIDRECT_SEND_MINIMUM); dprintf(sock, "tq_local_bidirect_recv_minimum=%i\n", TQ_LOCAL_BIDRECT_RECV_MINIMUM); dprintf(sock, "tq_hop_penalty=%i (default: %i)\n", hop_penalty, TQ_HOP_PENALTY); dprintf(sock, "tq_total_limit=%i\n", TQ_TOTAL_BIDRECT_LIMIT); dprintf(sock, "tq_max_value=%i\n", TQ_MAX_VALUE); dprintf(sock, "rt_table_networks=%i\n", BATMAN_RT_TABLE_NETWORKS); dprintf(sock, "rt_table_hosts=%i\n", BATMAN_RT_TABLE_HOSTS); dprintf(sock, "rt_table_unreach=%i\n", BATMAN_RT_TABLE_UNREACH); dprintf(sock, "rt_table_tunnel=%i\n", BATMAN_RT_TABLE_TUNNEL); dprintf(sock, "rt_prio_default=%i\n", BATMAN_RT_PRIO_DEFAULT); dprintf(sock, "rt_prio_unreach=%i\n", BATMAN_RT_PRIO_UNREACH); dprintf(sock, "rt_prio_tunnel=%i\n", BATMAN_RT_PRIO_TUNNEL); } void *unix_listen(void * BATMANUNUSED(arg)) { struct unix_client *unix_client; struct debug_level_info *debug_level_info; struct list_head *list_pos, *unix_pos_tmp, *debug_pos, *debug_pos_tmp, *prev_list_head, *prev_list_head_unix; struct hna_local_entry *hna_local_entry; struct batman_if *batman_if; struct timeval tv; struct sockaddr_un sun_addr; struct in_addr tmp_ip_holder; int32_t status, max_sock, unix_opts, download_speed, upload_speed; int8_t res; char buff[100], str[16], was_gateway, tmp_unix_value; fd_set wait_sockets, tmp_wait_sockets; socklen_t sun_size = sizeof(struct sockaddr_un); INIT_LIST_HEAD_FIRST(unix_if.client_list); FD_ZERO(&wait_sockets); FD_SET(unix_if.unix_sock, &wait_sockets); max_sock = unix_if.unix_sock; while (!is_aborted()) { tv.tv_sec = 1; tv.tv_usec = 0; memcpy(&tmp_wait_sockets, &wait_sockets, sizeof(fd_set)); res = select(max_sock + 1, &tmp_wait_sockets, NULL, NULL, &tv); if ( res > 0 ) { /* new client */ if ( FD_ISSET( unix_if.unix_sock, &tmp_wait_sockets ) ) { unix_client = debugMalloc( sizeof(struct unix_client), 201 ); memset( unix_client, 0, sizeof(struct unix_client) ); if ( ( unix_client->sock = accept( unix_if.unix_sock, (struct sockaddr *)&sun_addr, &sun_size) ) == -1 ) { debug_output( 0, "Error - can't accept unix client: %s\n", strerror(errno) ); continue; } INIT_LIST_HEAD( &unix_client->list ); FD_SET( unix_client->sock, &wait_sockets ); if ( unix_client->sock > max_sock ) max_sock = unix_client->sock; /* make unix socket non blocking */ unix_opts = fcntl( unix_client->sock, F_GETFL, 0 ); fcntl( unix_client->sock, F_SETFL, unix_opts | O_NONBLOCK ); list_add_tail( &unix_client->list, &unix_if.client_list ); debug_output( 3, "Unix socket: got connection\n" ); /* client sent data */ } else { max_sock = unix_if.unix_sock; prev_list_head_unix = (struct list_head *)&unix_if.client_list; list_for_each_safe( list_pos, unix_pos_tmp, &unix_if.client_list ) { unix_client = list_entry( list_pos, struct unix_client, list ); if ( FD_ISSET( unix_client->sock, &tmp_wait_sockets ) ) { status = read( unix_client->sock, buff, sizeof( buff ) ); if ( status > 0 ) { if ( unix_client->sock > max_sock ) max_sock = unix_client->sock; /* debug_output( 3, "gateway: client sent data via unix socket: %s\n", buff ); */ if (buff[0] == 'a') { if (status > 2) { hna_local_task_add_str(buff + 2, ROUTE_ADD, 1); dprintf(unix_client->sock, "EOD\n"); } } else if (buff[0] == 'A') { if (status > 2) { hna_local_task_add_str(buff + 2, ROUTE_DEL, 1); dprintf(unix_client->sock, "EOD\n"); } } else if ( buff[0] == 'd' ) { if ( ( status > 2 ) && ( ( buff[2] > 0 ) && ( buff[2] <= debug_level_max ) ) ) { if ( unix_client->debug_level != 0 ) { prev_list_head = (struct list_head *)debug_clients.fd_list[unix_client->debug_level - 1]; if ( pthread_mutex_lock( (pthread_mutex_t *)debug_clients.mutex[unix_client->debug_level - 1] ) != 0 ) debug_output( 0, "Error - could not lock mutex (unix_listen => 1): %s \n", strerror( errno ) ); list_for_each_safe( debug_pos, debug_pos_tmp, (struct list_head *)debug_clients.fd_list[unix_client->debug_level - 1] ) { debug_level_info = list_entry( debug_pos, struct debug_level_info, list ); if ( debug_level_info->fd == unix_client->sock ) { list_del( prev_list_head, debug_pos, debug_clients.fd_list[unix_client->debug_level - 1] ); debug_clients.clients_num[unix_client->debug_level - 1]--; debugFree( debug_pos, 1201 ); break; } prev_list_head = &debug_level_info->list; } if ( pthread_mutex_unlock( (pthread_mutex_t *)debug_clients.mutex[unix_client->debug_level - 1] ) != 0 ) debug_output( 0, "Error - could not unlock mutex (unix_listen => 1): %s \n", strerror( errno ) ); } if ( unix_client->debug_level != buff[2] ) { if ( pthread_mutex_lock( (pthread_mutex_t *)debug_clients.mutex[buff[2] - 1] ) != 0 ) debug_output( 0, "Error - could not lock mutex (unix_listen => 2): %s \n", strerror( errno ) ); debug_level_info = debugMalloc( sizeof(struct debug_level_info), 202 ); INIT_LIST_HEAD( &debug_level_info->list ); debug_level_info->fd = unix_client->sock; list_add( &debug_level_info->list, (struct list_head_first *)debug_clients.fd_list[buff[2] - 1] ); debug_clients.clients_num[buff[2] - 1]++; unix_client->debug_level = buff[2]; if ( pthread_mutex_unlock( (pthread_mutex_t *)debug_clients.mutex[buff[2] - 1] ) != 0 ) debug_output( 0, "Error - could not unlock mutex (unix_listen => 2): %s \n", strerror( errno ) ); } else { unix_client->debug_level = 0; } } } else if ( buff[0] == 'i' ) { internal_output(unix_client->sock); dprintf( unix_client->sock, "EOD\n" ); } else if ( buff[0] == 'g' ) { if ( status > 2 ) { if ((buff[2] == 0) || (probe_tun(0))) { was_gateway = ( gateway_class > 0 ? 1 : 0 ); gateway_class = buff[2]; ((struct batman_if *)if_list.next)->out.gwflags = gateway_class; if ( ( gateway_class > 0 ) && ( routing_class > 0 ) ) { if ((routing_class != 0) && (curr_gateway != NULL)) del_default_route(); add_del_interface_rules(RULE_DEL); routing_class = 0; } if ( ( !was_gateway ) && ( gateway_class > 0 ) ) init_interface_gw(); else if ((was_gateway) && (gateway_class == 0)) del_gw_interface(); } } dprintf( unix_client->sock, "EOD\n" ); } else if ( buff[0] == 'm' ) { if ( status > 2 ) { debug_output(3, "Unix socket: changing hop penalty points from: %i to: %i\n", hop_penalty, buff[2]); hop_penalty = buff[2]; } dprintf( unix_client->sock, "EOD\n" ); } else if ( buff[0] == 'q' ) { if ( status > 2 ) { debug_output(3, "Unix socket: changing purge timeout from: %i to: %li\n", purge_timeout, strtol(buff + 2, NULL, 10)); purge_timeout = strtol(buff + 2, NULL, 10); } dprintf( unix_client->sock, "EOD\n" ); } else if ( buff[0] == 'r' ) { if ( status > 2 ) { if ((buff[2] == 0) || (probe_tun(0))) { tmp_unix_value = buff[2]; if ( ( tmp_unix_value >= 0 ) && ( tmp_unix_value <= 3 ) && (tmp_unix_value != routing_class) ) { if ((routing_class != 0) && (curr_gateway != NULL)) del_default_route(); if ( ( tmp_unix_value > 0 ) && ( gateway_class > 0 ) ) { gateway_class = 0; ((struct batman_if *)if_list.next)->out.gwflags = gateway_class; del_gw_interface(); } if ((tmp_unix_value > 0) && (routing_class == 0)) add_del_interface_rules(RULE_ADD); else if ((tmp_unix_value == 0) && (routing_class > 0)) add_del_interface_rules(RULE_DEL); routing_class = tmp_unix_value; } } } dprintf( unix_client->sock, "EOD\n" ); } else if ( buff[0] == 'p' ) { if ( status > 2 ) { if ( inet_pton( AF_INET, buff + 2, &tmp_ip_holder ) > 0 ) { pref_gateway = tmp_ip_holder.s_addr; if ( curr_gateway != NULL ) del_default_route(); } else { debug_output( 3, "Unix socket: rejected new preferred gw (%s) - invalid IP specified\n", buff + 2 ); } } dprintf( unix_client->sock, "EOD\n" ); } else if (buff[0] == 'y') { dprintf(unix_client->sock, "%s", prog_name); if (routing_class > 0) dprintf(unix_client->sock, " -r %i", routing_class); if (pref_gateway > 0) { addr_to_string( pref_gateway, str, sizeof (str) ); dprintf(unix_client->sock, " -p %s", str); } if (gateway_class > 0) { get_gw_speeds(gateway_class, &download_speed, &upload_speed); dprintf(unix_client->sock, " -g %i%s/%i%s", (download_speed > 2048 ? download_speed / 1024 : download_speed), (download_speed > 2048 ? "MBit" : "KBit"), (upload_speed > 2048 ? upload_speed / 1024 : upload_speed), (upload_speed > 2048 ? "MBit" : "KBit")); } list_for_each(debug_pos, &hna_list) { hna_local_entry = list_entry(debug_pos, struct hna_local_entry, list); addr_to_string(hna_local_entry->addr, str, sizeof (str)); dprintf(unix_client->sock, " -a %s/%i", str, hna_local_entry->netmask); } if (debug_level != 0) dprintf(unix_client->sock, " -d %i", debug_level); if (originator_interval != 1000) dprintf(unix_client->sock, " -o %i", originator_interval); if (vis_if.sock) { addr_to_string(vis_if.addr.sin_addr.s_addr, str, sizeof(str)); dprintf(unix_client->sock, " -s %s", str); } if (policy_routing_script != NULL) dprintf(unix_client->sock, " --policy-routing-script %s", policy_routing_script); if (hop_penalty != TQ_HOP_PENALTY) dprintf(unix_client->sock, " --hop-penalty %i", hop_penalty); if (!aggregation_enabled) dprintf(unix_client->sock, " --disable-aggregation"); if (purge_timeout != PURGE_TIMEOUT) dprintf(unix_client->sock, " --purge-timeout %u", purge_timeout); list_for_each(debug_pos, &if_list) { batman_if = list_entry(debug_pos, struct batman_if, list); dprintf(unix_client->sock, " %s", batman_if->dev); } dprintf(unix_client->sock, "\nEOD\n"); } prev_list_head_unix = &unix_client->list; } else { if ( status < 0 ) debug_output( 0, "Error - can't read unix message: %s\n", strerror(errno) ); if ( unix_client->debug_level != 0 ) { prev_list_head = (struct list_head *)debug_clients.fd_list[unix_client->debug_level - 1]; if ( pthread_mutex_lock( (pthread_mutex_t *)debug_clients.mutex[unix_client->debug_level - 1] ) != 0 ) debug_output( 0, "Error - could not lock mutex (unix_listen => 3): %s \n", strerror( errno ) ); list_for_each_safe( debug_pos, debug_pos_tmp, (struct list_head *)debug_clients.fd_list[unix_client->debug_level - 1] ) { debug_level_info = list_entry( debug_pos, struct debug_level_info, list ); if ( debug_level_info->fd == unix_client->sock ) { list_del( prev_list_head, debug_pos, debug_clients.fd_list[unix_client->debug_level - 1] ); debug_clients.clients_num[unix_client->debug_level - 1]--; debugFree( debug_pos, 1202 ); break; } prev_list_head = &debug_level_info->list; } if ( pthread_mutex_unlock( (pthread_mutex_t *)debug_clients.mutex[unix_client->debug_level - 1] ) != 0 ) debug_output( 0, "Error - could not unlock mutex (unix_listen => 3): %s \n", strerror( errno ) ); } debug_output( 3, "Unix client closed connection ...\n" ); FD_CLR(unix_client->sock, &wait_sockets); close( unix_client->sock ); list_del( prev_list_head_unix, list_pos, &unix_if.client_list ); debugFree( list_pos, 1203 ); } } else { if ( unix_client->sock > max_sock ) max_sock = unix_client->sock; } } } } else if ((res < 0) && (errno != EINTR)) { debug_output(0, "Error - can't select (unix_listen): %s\n", strerror(errno)); break; } } list_for_each_safe( list_pos, unix_pos_tmp, &unix_if.client_list ) { unix_client = list_entry( list_pos, struct unix_client, list ); if ( unix_client->debug_level != 0 ) { prev_list_head = (struct list_head *)debug_clients.fd_list[unix_client->debug_level - 1]; if ( pthread_mutex_lock( (pthread_mutex_t *)debug_clients.mutex[unix_client->debug_level - 1] ) != 0 ) debug_output( 0, "Error - could not lock mutex (unix_listen => 4): %s \n", strerror( errno ) ); list_for_each_safe( debug_pos, debug_pos_tmp, (struct list_head *)debug_clients.fd_list[unix_client->debug_level - 1] ) { debug_level_info = list_entry(debug_pos, struct debug_level_info, list); if ( debug_level_info->fd == unix_client->sock ) { list_del( prev_list_head, debug_pos, debug_clients.fd_list[unix_client->debug_level - 1] ); debug_clients.clients_num[unix_client->debug_level - 1]--; debugFree( debug_pos, 1204 ); break; } prev_list_head = &debug_level_info->list; } if ( pthread_mutex_unlock( (pthread_mutex_t *)debug_clients.mutex[unix_client->debug_level - 1] ) != 0 ) debug_output( 0, "Error - could not unlock mutex (unix_listen => 4): %s \n", strerror( errno ) ); } list_del( (struct list_head *)&unix_if.client_list, list_pos, &unix_if.client_list ); debugFree( list_pos, 1205 ); } return NULL; } batmand-0.3.2+74+g2f62b17/profile.c000066400000000000000000000041111435410210600163010ustar00rootroot00000000000000/* * Copyright (C) 2006-2012 B.A.T.M.A.N. contributors: * * Simon Wunderlich, Marek Lindner * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public * License as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA * */ #include #include #include #include "profile.h" #include "os.h" #if defined PROFILE_DATA static struct prof_container prof_container[PROF_COUNT]; void prof_init(int32_t index, const char *name) { prof_container[index].total_time = 0; prof_container[index].calls = 0; prof_container[index].name = name; } void prof_start(int32_t index) { prof_container[index].start_time = clock(); } void prof_stop(int32_t index) { prof_container[index].calls++; prof_container[index].total_time += clock() - prof_container[index].start_time; } void prof_print(void) { int32_t index; debug_output( 5, " \nProfile data:\n" ); for ( index = 0; index < PROF_COUNT; index++ ) { debug_output( 5, " %30s: cpu time = %10.3f, calls = %10"PRId64", avg time per call = %4.10f \n", prof_container[index].name, (float)prof_container[index].total_time/CLOCKS_PER_SEC, prof_container[index].calls, ( prof_container[index].calls == 0 ? 0.0 : ( ( (float)prof_container[index].total_time/CLOCKS_PER_SEC ) / (float)prof_container[index].calls ) ) ); } } #else #include "batman.h" void prof_init( int32_t BATMANUNUSED(index), const char *BATMANUNUSED(name) ) { } void prof_start( int32_t BATMANUNUSED(index) ) { } void prof_stop( int32_t BATMANUNUSED(index) ) { } void prof_print(void) { } #endif batmand-0.3.2+74+g2f62b17/profile.h000066400000000000000000000025051435410210600163130ustar00rootroot00000000000000/* * Copyright (C) 2006-2012 B.A.T.M.A.N. contributors: * * Simon Wunderlich, Marek Lindner * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public * License as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA * */ #ifndef _BATMAND_PROFILE_H #define _BATMAND_PROFILE_H #include #include enum { PROF_choose_gw, PROF_update_routes, PROF_update_gw_list, PROF_is_duplicate, PROF_get_orig_node, PROF_update_originator, PROF_purge_originator, PROF_schedule_forward_packet, PROF_send_outstanding_packets, PROF_COUNT }; struct prof_container { clock_t start_time; clock_t total_time; const char *name; uint64_t calls; }; void prof_init(int32_t index, const char *name); void prof_start(int32_t index); void prof_stop(int32_t index); void prof_print(void); #endif batmand-0.3.2+74+g2f62b17/ring_buffer.c000066400000000000000000000023351435410210600171370ustar00rootroot00000000000000/* * Copyright (C) 2007-2012 B.A.T.M.A.N. contributors: * * Marek Lindner * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public * License as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA * */ #include "batman.h" #include "ring_buffer.h" void ring_buffer_set(uint8_t tq_recv[], uint8_t *tq_index, uint8_t value) { tq_recv[*tq_index] = value; *tq_index = (*tq_index + 1) % global_win_size; } uint8_t ring_buffer_avg(uint8_t tq_recv[]) { uint8_t *ptr; uint16_t count = 0, i = 0; uint32_t sum = 0; ptr = tq_recv; while (i < global_win_size) { if (*ptr != 0) { count++; sum += *ptr; } i++; ptr++; } if (count == 0) return 0; return (uint8_t)(sum / count); } batmand-0.3.2+74+g2f62b17/ring_buffer.h000066400000000000000000000016751435410210600171520ustar00rootroot00000000000000/* * Copyright (C) 2007-2012 B.A.T.M.A.N. contributors: * * Marek Lindner * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public * License as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA * */ #ifndef _BATMAND_RING_BUFFER_H #define _BATMAND_RING_BUFFER_H #include void ring_buffer_set(uint8_t tq_recv[], uint8_t *tq_index, uint8_t value); uint8_t ring_buffer_avg(uint8_t tq_recv[]); #endif batmand-0.3.2+74+g2f62b17/schedule.c000066400000000000000000000300111435410210600164330ustar00rootroot00000000000000/* * Copyright (C) 2006-2012 B.A.T.M.A.N. contributors: * * Simon Wunderlich, Marek Lindner * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public * License as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA * */ #include #include #include #include "list-batman.h" #include "packet.h" #include "types.h" #include "allocate.h" #include "hash.h" #include "profile.h" #include "bitarray.h" #include "os.h" #include "batman.h" #include "schedule.h" #include "hna.h" void schedule_own_packet(struct batman_if *batman_if) { struct forw_node *forw_node_new, *forw_packet_tmp = NULL; struct list_head *list_pos, *prev_list_head; struct hash_it_t *hashit = NULL; struct orig_node *orig_node; debug_output(4, "schedule_own_packet(): %s \n", batman_if->dev); forw_node_new = debugMalloc(sizeof(struct forw_node), 501); INIT_LIST_HEAD(&forw_node_new->list); forw_node_new->send_time = get_time_msec() + originator_interval - JITTER + rand_num(2 * JITTER); forw_node_new->if_incoming = batman_if; forw_node_new->own = 1; forw_node_new->num_packets = 0; forw_node_new->direct_link_flags = 0; /* non-primary interfaces do not send hna information */ if ((num_hna_local > 0) && (batman_if->if_num == 0)) { forw_node_new->pack_buff = debugMalloc(MAX_AGGREGATION_BYTES, 502); memcpy(forw_node_new->pack_buff, (unsigned char *)&batman_if->out, sizeof(struct bat_packet)); memcpy(forw_node_new->pack_buff + sizeof(struct bat_packet), hna_buff_local, num_hna_local * 5); forw_node_new->pack_buff_len = sizeof(struct bat_packet) + num_hna_local * 5; ((struct bat_packet *)forw_node_new->pack_buff)->hna_len = num_hna_local; } else { forw_node_new->pack_buff = debugMalloc(MAX_AGGREGATION_BYTES, 503); memcpy(forw_node_new->pack_buff, &batman_if->out, sizeof(struct bat_packet)); forw_node_new->pack_buff_len = sizeof(struct bat_packet); ((struct bat_packet *)forw_node_new->pack_buff)->hna_len = 0; } /* change sequence number to network order */ ((struct bat_packet *)forw_node_new->pack_buff)->seqno = htons(((struct bat_packet *)forw_node_new->pack_buff)->seqno); prev_list_head = (struct list_head *)&forw_list; list_for_each(list_pos, &forw_list) { forw_packet_tmp = list_entry(list_pos, struct forw_node, list); if ((int)(forw_packet_tmp->send_time - forw_node_new->send_time) >= 0) { list_add_before(prev_list_head, list_pos, &forw_node_new->list); break; } prev_list_head = &forw_packet_tmp->list; forw_packet_tmp = NULL; } if (forw_packet_tmp == NULL) list_add_tail(&forw_node_new->list, &forw_list); batman_if->out.seqno++; while ( NULL != ( hashit = hash_iterate( orig_hash, hashit ) ) ) { orig_node = hashit->bucket->data; debug_output( 4, "count own bcast (schedule_own_packet): old = %i, ", orig_node->bcast_own_sum[batman_if->if_num] ); bit_get_packet( (TYPE_OF_WORD *)&(orig_node->bcast_own[batman_if->if_num * num_words]), 1, 0 ); orig_node->bcast_own_sum[batman_if->if_num] = bit_packet_count( (TYPE_OF_WORD *)&(orig_node->bcast_own[batman_if->if_num * num_words]) ); debug_output( 4, "new = %i \n", orig_node->bcast_own_sum[batman_if->if_num] ); } } void schedule_forward_packet(struct orig_node *orig_node, struct bat_packet *in, uint32_t neigh, uint8_t directlink, int16_t hna_buff_len, struct batman_if *if_incoming, uint32_t curr_time) { struct forw_node *forw_node_new = NULL, *forw_node_aggregate = NULL, *forw_node_pos = NULL; struct list_head *list_pos = forw_list.next, *prev_list_head = (struct list_head *)&forw_list; struct bat_packet *bat_packet; uint8_t tq_avg = 0; uint32_t send_time; prof_start(PROF_schedule_forward_packet); debug_output(4, "schedule_forward_packet(): \n"); if (in->ttl <= 1) { debug_output(4, "ttl exceeded \n"); prof_stop(PROF_schedule_forward_packet); return; } if (aggregation_enabled) send_time = curr_time + MAX_AGGREGATION_MS - (JITTER/2) + rand_num(JITTER); else send_time = curr_time + rand_num(JITTER/2); /* find position for the packet in the forward queue */ list_for_each(list_pos, &forw_list) { forw_node_pos = list_entry(list_pos, struct forw_node, list); if (aggregation_enabled) { /* don't save aggregation position if aggregation is disabled */ forw_node_aggregate = forw_node_pos; /** * we can aggregate the current packet to this packet if: * - the send time is within our MAX_AGGREGATION_MS time * - the resulting packet wont be bigger than MAX_AGGREGATION_BYTES */ if (((int)(forw_node_pos->send_time - send_time) < 0) && (forw_node_pos->pack_buff_len + sizeof(struct bat_packet) + hna_buff_len <= MAX_AGGREGATION_BYTES)) { bat_packet = (struct bat_packet *)forw_node_pos->pack_buff; /** * check aggregation compatibility * -> direct link packets are broadcasted on their interface only * -> aggregate packet if the current packet is a "global" packet * as well as the base packet */ /* packets without direct link flag and high TTL are flooded through the net */ if ((!directlink) && (!(bat_packet->flags & DIRECTLINK)) && (bat_packet->ttl != 1) && /* own packets originating non-primary interfaces leave only that interface */ ((!forw_node_pos->own) || (forw_node_pos->if_incoming->if_num == 0))) break; /* if the incoming packet is sent via this one interface only - we still can aggregate */ if ((directlink) && (in->ttl == 2) && (forw_node_pos->if_incoming == if_incoming)) break; } /* could not find packet to aggregate with */ forw_node_aggregate = NULL; } if ((int)(forw_node_pos->send_time - send_time) > 0) break; prev_list_head = &forw_node_pos->list; forw_node_pos = NULL; } /* nothing to aggregate with - either aggregation disabled or no suitable aggregation packet found */ if (forw_node_aggregate == NULL) { forw_node_new = debugMalloc(sizeof(struct forw_node), 504); forw_node_new->pack_buff = debugMalloc(MAX_AGGREGATION_BYTES, 505); INIT_LIST_HEAD(&forw_node_new->list); forw_node_new->pack_buff_len = sizeof(struct bat_packet) + hna_buff_len; memcpy(forw_node_new->pack_buff, in, forw_node_new->pack_buff_len); bat_packet = (struct bat_packet *)forw_node_new->pack_buff; forw_node_new->own = 0; forw_node_new->if_incoming = if_incoming; forw_node_new->num_packets = 0; forw_node_new->direct_link_flags = 0; forw_node_new->send_time = send_time; } else { memcpy(forw_node_aggregate->pack_buff + forw_node_aggregate->pack_buff_len, in, sizeof(struct bat_packet) + hna_buff_len); bat_packet = (struct bat_packet *)(forw_node_aggregate->pack_buff + forw_node_aggregate->pack_buff_len); forw_node_aggregate->pack_buff_len += sizeof(struct bat_packet) + hna_buff_len; forw_node_aggregate->num_packets++; forw_node_new = forw_node_aggregate; } /* save packet direct link flag status */ if (directlink) forw_node_new->direct_link_flags = forw_node_new->direct_link_flags | (1 << forw_node_new->num_packets); bat_packet->ttl--; bat_packet->prev_sender = neigh; /* rebroadcast tq of our best ranking neighbor to ensure the rebroadcast of our best tq value */ if ((orig_node->router != NULL) && (orig_node->router->tq_avg != 0)) { /* rebroadcast ogm of best ranking neighbor as is */ if (orig_node->router->addr != neigh) { bat_packet->tq = orig_node->router->tq_avg; if (orig_node->router->last_ttl) bat_packet->ttl = orig_node->router->last_ttl - 1; } tq_avg = orig_node->router->tq_avg; } /* apply hop penalty */ bat_packet->tq = (bat_packet->tq * (TQ_MAX_VALUE - hop_penalty)) / (TQ_MAX_VALUE); debug_output(4, "forwarding: tq_orig: %i, tq_avg: %i, tq_forw: %i, ttl_orig: %i, ttl_forw: %i \n", in->tq, tq_avg, bat_packet->tq, in->ttl - 1, bat_packet->ttl); /* change sequence number to network order */ bat_packet->seqno = htons(bat_packet->seqno); if (directlink) bat_packet->flags |= DIRECTLINK; else bat_packet->flags &= ~DIRECTLINK; /* if the packet was not aggregated */ if (forw_node_aggregate == NULL) { /* if the packet should go somewhere in the queue */ if (forw_node_pos != NULL) list_add_before(prev_list_head, list_pos, &forw_node_new->list); /* if the packet is the last packet in the queue */ else list_add_tail(&forw_node_new->list, &forw_list); } prof_stop(PROF_schedule_forward_packet); } void send_outstanding_packets(uint32_t curr_time) { struct forw_node *forw_node; struct list_head *forw_pos, *if_pos, *temp; struct batman_if *batman_if; struct bat_packet *bat_packet; char orig_str[ADDR_STR_LEN]; uint8_t directlink, curr_packet_num; int16_t curr_packet_len; prof_start(PROF_send_outstanding_packets); list_for_each_safe(forw_pos, temp, &forw_list) { forw_node = list_entry(forw_pos, struct forw_node, list); if ((int)(curr_time - forw_node->send_time) < 0) break; bat_packet = (struct bat_packet *)forw_node->pack_buff; addr_to_string(bat_packet->orig, orig_str, ADDR_STR_LEN); directlink = (bat_packet->flags & DIRECTLINK ? 1 : 0); if (forw_node->if_incoming == NULL) { debug_output(0, "Error - can't forward packet: incoming iface not specified \n"); goto packet_free; } /* multihomed peer assumed */ /* non-primary interfaces are only broadcasted on their interface */ if (((directlink) && (bat_packet->ttl == 1)) || ((forw_node->own) && (forw_node->if_incoming->if_num > 0))) { debug_output(4, "%s packet (originator %s, seqno %d, TTL %d) on interface %s\n", (forw_node->own ? "Sending own" : "Forwarding"), orig_str, ntohs(bat_packet->seqno), bat_packet->ttl, forw_node->if_incoming->dev); if (send_udp_packet(forw_node->pack_buff, forw_node->pack_buff_len, &forw_node->if_incoming->broad, forw_node->if_incoming->udp_send_sock, forw_node->if_incoming) < 0) deactivate_interface(forw_node->if_incoming); goto packet_free; } list_for_each(if_pos, &if_list) { batman_if = list_entry(if_pos, struct batman_if, list); curr_packet_num = curr_packet_len = 0; bat_packet = (struct bat_packet *)forw_node->pack_buff; while ((curr_packet_len + sizeof(struct bat_packet) <= forw_node->pack_buff_len) && (curr_packet_len + sizeof(struct bat_packet) + bat_packet->hna_len * 5 <= forw_node->pack_buff_len) && (curr_packet_len + sizeof(struct bat_packet) + bat_packet->hna_len * 5 <= MAX_AGGREGATION_BYTES)) { if ((forw_node->direct_link_flags & (1 << curr_packet_num)) && (forw_node->if_incoming == batman_if)) bat_packet->flags |= DIRECTLINK; else bat_packet->flags &= ~DIRECTLINK; if (curr_packet_num > 0) addr_to_string(bat_packet->orig, orig_str, ADDR_STR_LEN); debug_output(4, "%s %spacket (originator %s, seqno %d, TQ %d, TTL %d, IDF %s) on interface %s\n", (curr_packet_num > 0 ? "Forwarding" : (forw_node->own ? "Sending own" : "Forwarding")), (curr_packet_num > 0 ? "aggregated " : ""), orig_str, ntohs(bat_packet->seqno), bat_packet->tq, bat_packet->ttl, (bat_packet->flags & DIRECTLINK ? "on" : "off"), batman_if->dev); curr_packet_len += sizeof(struct bat_packet) + bat_packet->hna_len * 5; curr_packet_num++; bat_packet = (struct bat_packet *)(forw_node->pack_buff + curr_packet_len); } if (send_udp_packet(forw_node->pack_buff, forw_node->pack_buff_len, &batman_if->broad, batman_if->udp_send_sock, batman_if) < 0) deactivate_interface(batman_if); } packet_free: list_del((struct list_head *)&forw_list, forw_pos, &forw_list); if (forw_node->own && forw_node->if_incoming) schedule_own_packet(forw_node->if_incoming); debugFree(forw_node->pack_buff, 1501); debugFree(forw_node, 1502); } prof_stop(PROF_send_outstanding_packets); } batmand-0.3.2+74+g2f62b17/schedule.h000066400000000000000000000022201435410210600164410ustar00rootroot00000000000000/* * Copyright (C) 2006-2012 B.A.T.M.A.N. contributors: * * Simon Wunderlich, Marek Lindner * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public * License as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA * */ #ifndef _BATMAND_SCHEDULE_H #define _BATMAND_SCHEDULE_H #include #include "types.h" void schedule_own_packet( struct batman_if *batman_if ); void schedule_forward_packet(struct orig_node *orig_node, struct bat_packet *in, uint32_t neigh, uint8_t directlink, int16_t hna_buff_len, struct batman_if *if_outgoing, uint32_t curr_time); void send_outstanding_packets(uint32_t curr_time); #endif batmand-0.3.2+74+g2f62b17/types.h000066400000000000000000000067221435410210600160240ustar00rootroot00000000000000/* * Copyright (C) 2009-2012 B.A.T.M.A.N. contributors: * * Marek Lindner * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public * License as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA * */ #ifndef _BATMAND_TYPES_H #define _BATMAND_TYPES_H #include #include #include #include #include "list-batman.h" #include "packet.h" #include "batman.h" struct orig_node { /* structure for orig_list maintaining nodes of mesh */ uint32_t orig; struct neigh_node *router; struct batman_if *batman_if; TYPE_OF_WORD *bcast_own; uint8_t *bcast_own_sum; uint8_t tq_own; int tq_asym_penalty; uint32_t last_valid; /* when last packet from this node was received */ uint8_t gwflags; /* flags related to gateway functions: gateway class */ unsigned char *hna_buff; int16_t hna_buff_len; uint16_t last_real_seqno; /* last and best known squence number */ uint8_t last_ttl; /* ttl of last received packet */ struct list_head_first neigh_list; }; struct neigh_node { struct list_head list; uint32_t addr; uint8_t real_packet_count; uint8_t *tq_recv; uint8_t tq_index; uint8_t tq_avg; uint8_t last_ttl; uint32_t last_valid; /* when last packet via this neighbour was received */ TYPE_OF_WORD *real_bits; struct orig_node *orig_node; struct batman_if *if_incoming; }; struct forw_node { /* structure for forw_list maintaining packets to be send/forwarded */ struct list_head list; uint32_t send_time; uint8_t own; unsigned char *pack_buff; uint16_t pack_buff_len; uint32_t direct_link_flags; uint8_t num_packets; struct batman_if *if_incoming; }; struct gw_node { struct list_head list; struct orig_node *orig_node; uint16_t gw_port; uint16_t gw_failure; uint32_t last_failure; uint32_t deleted; }; struct batman_if { struct list_head list; char *dev; int32_t udp_send_sock; int32_t udp_recv_sock; int32_t udp_tunnel_sock; uint8_t if_num; uint8_t if_active; int32_t if_index; int8_t if_rp_filter_old; int8_t if_send_redirects_old; pthread_t listen_thread_id; struct sockaddr_in addr; struct sockaddr_in broad; uint32_t netaddr; uint8_t netmask; uint8_t wifi_if; struct bat_packet out; }; struct gw_client { uint32_t wip_addr; uint32_t vip_addr; uint16_t client_port; uint32_t last_keep_alive; uint8_t nat_warn; }; struct free_ip { struct list_head list; uint32_t addr; }; struct vis_if { int32_t sock; struct sockaddr_in addr; }; struct unix_if { int32_t unix_sock; pthread_t listen_thread_id; struct sockaddr_un addr; struct list_head_first client_list; }; struct unix_client { struct list_head list; int32_t sock; uint8_t debug_level; }; struct debug_clients { void **fd_list; int16_t *clients_num; pthread_mutex_t **mutex; }; struct debug_level_info { struct list_head list; int32_t fd; }; struct curr_gw_data { unsigned int orig; struct gw_node *gw_node; struct batman_if *batman_if; }; #endif