batman-0.3.2/allocate.c0000666000000000000000000002553511211455340011606 0ustar /* * Copyright (C) 2006-2009 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 #include "os.h" #include "allocate.h" #define MAGIC_NUMBER 0x12345678 #if defined DEBUG_MALLOC 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() { 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 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 tag) { free(memory); } #endif batman-0.3.2/allocate.h0000666000000000000000000000210211133202550011570 0ustar /* * Copyright (C) 2006-2009 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 _ALLOCATE_H #define _ALLOCATE_H 1 #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 batman-0.3.2/batman.c0000666000000000000000000010171111207175617011266 0ustar /* * Copyright (C) 2006-2009 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" uint8_t debug_level = 0; #ifdef PROFILE_DATA uint8_t debug_level_max = 5; #elif DEBUG_MALLOC && 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" ); } 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"); old_router = orig_node->router; /* also handles orig_node->router == NULL and neigh_node == NULL */ if ((orig_node != NULL) && (orig_node->router != neigh_node)) { 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, old_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 & 0x7C) >> 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; } batman-0.3.2/batman.h0000666000000000000000000002240411214541762011270 0ustar /* * Copyright (C) 2006-2009 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 _BATMAN_BATMAN_H #define _BATMAN_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" #include "bitarray.h" #include "hash.h" #include "allocate.h" #include "profile.h" #include "vis-types.h" #include "ring_buffer.h" #define SOURCE_VERSION "0.3.2" /* put exactly one distinct word inside the string like "0.3-pre-alpha" or "0.3-rc1" or "0.3" */ #define COMPAT_VERSION 5 #define PORT 4305 #define GW_PORT 4306 #define DIRECTLINK 0x40 #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 * ***/ #ifndef REVISION_VERSION #define REVISION_VERSION "0" #endif /* * 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 10 #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 5 #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; struct bat_packet { uint8_t version; /* batman version field */ uint8_t flags; /* 0x80: UNIDIRECTIONAL link, 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 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; }; struct batgat_ioc_args { char dev_name[16]; unsigned char exists; uint32_t universal; uint32_t ifindex; }; 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 batman-0.3.2/bitarray.c0000666000000000000000000001232111133202550011620 0ustar /* * Copyright (C) 2006-2009 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 /* printf() */ #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] & 1<= 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]|= 1<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 * * 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 * */ /* This file contains functions that are used by batman but are not * present in BSD libc. */ #warning BSD support is known broken - if you compile this on BSD you are expected to fix it :-P #include #include #include #include /* Adapted from busybox */ int vdprintf(int d, const char *format, va_list ap) { char buf[1024]; int len; len = vsnprintf(buf, sizeof(buf), format, ap); return write(d, buf, len); } /* From glibc */ int dprintf(int d, const char *format, ...) { va_list arg; int done; va_start (arg, format); done = vdprintf (d, format, arg); va_end (arg); return done; } batman-0.3.2/bsd/kernel.c0000666000000000000000000000650711133434771012060 0ustar /* * Copyright (C) 2006, 2007 BATMAN contributors: * Stefan Sperling * * 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 * */ /* This file contains functions that deal with BSD kernel interfaces, * such as sysctls. */ #warning BSD support is known broken - if you compile this on BSD you are expected to fix it :-P #include #include #include #include #include #include #include #include #include "../os.h" #include "../batman.h" void set_forwarding(int32_t state) { int mib[4]; /* FreeBSD allows us to set a boolean sysctl to anything. * Check the value for sanity. */ if (state < 0 || state > 1) { errno = EINVAL; err(1, "set_forwarding: %i", state); } /* "net.inet.ip.forwarding" */ mib[0] = CTL_NET; mib[1] = PF_INET; mib[2] = IPPROTO_IP; mib[3] = IPCTL_FORWARDING; if (sysctl(mib, 4, NULL, 0, (void*)&state, sizeof(state)) == -1) err(1, "Cannot change net.inet.ip.forwarding"); } int32_t get_forwarding(void) { int state; size_t len; int mib[4]; /* "net.inet.ip.forwarding" */ mib[0] = CTL_NET; mib[1] = PF_INET; mib[2] = IPPROTO_IP; mib[3] = IPCTL_FORWARDING; len = sizeof(state); if (sysctl(mib, 4, &state, &len, NULL, 0) == -1) err(1, "Cannot tell if packet forwarding is enabled"); return state; } void set_send_redirects(int32_t state, char* BATMANUNUSED(dev)) { int mib[4]; /* FreeBSD allows us to set a boolean sysctl to anything. * Check the value for sanity. */ if (state < 0 || state > 1) { errno = EINVAL; err(1, "set_send_redirects: %i", state); } /* "net.inet.ip.redirect" */ mib[0] = CTL_NET; mib[1] = PF_INET; mib[2] = IPPROTO_IP; mib[3] = IPCTL_SENDREDIRECTS; if (sysctl(mib, 4, NULL, 0, (void*)&state, sizeof(state)) == -1) err(1, "Cannot change net.inet.ip.redirect"); } int32_t get_send_redirects(char *BATMANUNUSED(dev)) { int state; size_t len; int mib[4]; /* "net.inet.ip.redirect" */ mib[0] = CTL_NET; mib[1] = PF_INET; mib[2] = IPPROTO_IP; mib[3] = IPCTL_SENDREDIRECTS; len = sizeof(state); if (sysctl(mib, 4, &state, &len, NULL, 0) == -1) err(1, "Cannot tell if redirects are enabled"); return state; } void set_rp_filter( int32_t BATMANUNUSED(state), char* BATMANUNUSED(dev) ) { /* On BSD, reverse path filtering should be disabled in the firewall. */ return; } int32_t get_rp_filter( char *BATMANUNUSED(dev) ) { /* On BSD, reverse path filtering should be disabled in the firewall. */ return 0; } int8_t bind_to_iface( int32_t BATMANUNUSED(udp_recv_sock), char *BATMANUNUSED(dev) ) { /* XXX: Is binding a socket to a specific * interface possible in *BSD? * Possibly via bpf... */ return 1; } int32_t use_gateway_module(void) { return -1; } batman-0.3.2/bsd/route.c0000666000000000000000000001352711133434771011736 0ustar /* * Copyright (C) 2006, 2007 BATMAN contributors: * Stefan Sperling * * 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 * */ /* This file contains interface functions for the routing table on BSD. */ #warning BSD support is known broken - if you compile this on BSD you are expected to fix it :-P #include #include #include #include #include #include #include #include #include #include #include #include #include "../os.h" #include "../batman.h" /* Message structure used to interface the kernel routing table. * See route(4) for details on the message passing interface for * manipulating the kernel routing table. */ struct rt_msg { struct rt_msghdr hdr; struct sockaddr_in dest; struct sockaddr_in gateway; struct sockaddr_in netmask; }; static inline int32_t n_bits(uint8_t n) { int32_t i, result; result = 0; if (n > 32) n = 32; for (i = 0; i < n; i++) result |= (0x80000000 >> i); return result; } /* Send routing message msg to the kernel. * The kernel's reply is returned in msg. */ static int rt_message(struct rt_msg *msg) { int rt_sock; static unsigned int seq = 0; ssize_t len; pid_t pid; rt_sock = socket(PF_ROUTE, SOCK_RAW, AF_INET); if (rt_sock < 0) err(1, "Could not open socket to routing table"); pid = getpid(); len = 0; seq++; /* Send message */ do { msg->hdr.rtm_seq = seq; len = write(rt_sock, msg, msg->hdr.rtm_msglen); if (len < 0) { warn("Error sending routing message to kernel"); return -1; } } while (len < msg->hdr.rtm_msglen); /* Get reply */ do { len = read(rt_sock, msg, sizeof(struct rt_msg)); if (len < 0) err(1, "Error reading from routing socket"); } while (len > 0 && (msg->hdr.rtm_seq != seq || msg->hdr.rtm_pid != pid)); if (msg->hdr.rtm_version != RTM_VERSION) warn("RTM_VERSION mismatch: compiled with version %i, " "but running kernel uses version %i", RTM_VERSION, msg->hdr.rtm_version); /* Check reply for errors. */ if (msg->hdr.rtm_errno) { errno = msg->hdr.rtm_errno; return -1; } return 0; } /* Get IP address of a network device (e.g. "tun0"). */ static uint32_t get_dev_addr(char *dev) { int so; struct ifreq ifr; struct sockaddr_in *addr; memset(&ifr, 0, sizeof(ifr)); strlcpy(ifr.ifr_name, dev, IFNAMSIZ); so = socket(AF_INET, SOCK_DGRAM, 0); if (ioctl(so, SIOCGIFADDR, &ifr, sizeof(ifr)) < 0) { perror("SIOCGIFADDR"); return -1; } if (ifr.ifr_addr.sa_family != AF_INET) { warn("get_dev_addr: got a non-IPv4 interface"); return -1; } addr = (struct sockaddr_in*)&ifr.ifr_addr; return addr->sin_addr.s_addr; } void add_del_route(uint32_t dest, uint8_t netmask, uint32_t router, uint32_t BATMANUNUSED(src_ip), int32_t BATMANUNUSED(ifi), char *dev, uint8_t BATMANUNUSED(rt_table), int8_t BATMANUNUSED(route_type), int8_t del) { char dest_str[16], router_str[16]; struct rt_msg msg; memset(&msg, 0, sizeof(struct rt_msg)); inet_ntop(AF_INET, &dest, dest_str, sizeof (dest_str)); inet_ntop(AF_INET, &router, router_str, sizeof (router_str)); /* Message header */ msg.hdr.rtm_type = del ? RTM_DELETE : RTM_ADD; msg.hdr.rtm_version = RTM_VERSION; msg.hdr.rtm_flags = RTF_STATIC | RTF_UP; if (netmask == 32) msg.hdr.rtm_flags |= RTF_HOST; msg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; msg.hdr.rtm_msglen = sizeof(struct rt_msg); /* Destination and gateway sockaddrs */ msg.dest.sin_family = AF_INET; msg.dest.sin_len = sizeof(struct sockaddr_in); msg.gateway.sin_family = AF_INET; msg.gateway.sin_len = sizeof(struct sockaddr_in); msg.hdr.rtm_flags = RTF_GATEWAY; if (dest == router) { if (dest == 0) { /* Add default route via dev */ fprintf(stderr, "%s default route via %s\n", del ? "Deleting" : "Adding", dev); msg.gateway.sin_addr.s_addr = get_dev_addr(dev); } else { /* Route to dest via default route. * This is a nop. */ return; } } else { if (router != 0) { /* Add route to dest via router */ msg.dest.sin_addr.s_addr = dest; msg.gateway.sin_addr.s_addr = router; fprintf(stderr, "%s route to %s/%i via %s\n", del ? "Deleting" : "Adding", dest_str, netmask, router_str); } else { /* Route to dest via default route. * This is a nop. */ return; } } /* Netmask sockaddr */ msg.netmask.sin_family = AF_INET; msg.netmask.sin_len = sizeof(struct sockaddr_in); /* Netmask is passed as decimal value (e.g. 28 for a /28). * So we need to convert it into a bit pattern with n_bits(). */ msg.netmask.sin_addr.s_addr = htonl(n_bits(netmask)); if (rt_message(&msg) < 0) err(1, "Cannot %s route to %s/%i", del ? "delete" : "add", dest_str, netmask); } void add_del_rule(uint32_t BATMANUNUSED(network), uint8_t BATMANUNUSED(netmask), int8_t BATMANUNUSED(rt_table), uint32_t BATMANUNUSED(prio), char *BATMANUNUSED(iif), int8_t BATMANUNUSED(dst_rule), int8_t BATMANUNUSED(del) ) { fprintf(stderr, "add_del_rule: not implemented\n"); return; } int add_del_interface_rules( int8_t BATMANUNUSED(del) ) { fprintf(stderr, "add_del_interface_rules: not implemented\n"); return 0; } int flush_routes_rules( int8_t BATMANUNUSED(rt_table) ) { fprintf(stderr, "flush_routes_rules: not implemented\n"); return 0; } batman-0.3.2/bsd/tun.c0000666000000000000000000001354511167732564011416 0ustar /* * Copyright (C) 2006, 2007 BATMAN contributors: * Stefan Sperling * * 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 * */ /* This file contains functions interfacing tun devices on BSD. */ #warning BSD support is known broken - if you compile this on BSD you are expected to fix it :-P #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../os.h" #include "../batman.h" /* * open_tun_any() opens an available tun device. * It returns the file descriptor as return value, * or -1 on failure. * * The human readable name of the device (e.g. "/dev/tun0") is * copied into the dev_name parameter. The buffer to hold * this string is assumed to be dev_name_size bytes large. */ #if defined(__OpenBSD__) || defined(__Darwin__) static int open_tun_any(char *dev_name, size_t dev_name_size) { int i; int fd; char tun_dev_name[12]; /* 12 = length("/dev/tunxxx\0") */ for (i = 0; i < sizeof(tun_dev_name); i++) tun_dev_name[i] = '\0'; /* Try opening tun device /dev/tun[0..255] */ for (i = 0; i < 256; i++) { snprintf(tun_dev_name, sizeof(tun_dev_name), "/dev/tun%i", i); if ((fd = open(tun_dev_name, O_RDWR)) != -1) { if (dev_name != NULL) strlcpy(dev_name, tun_dev_name, dev_name_size); return fd; } } return -1; } #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) static int open_tun_any(char *dev_name, size_t dev_name_size) { int fd; struct stat buf; /* Open lowest unused tun device */ if ((fd = open("/dev/tun", O_RDWR)) != -1) { fstat(fd, &buf); printf("Using %s\n", devname(buf.st_rdev, S_IFCHR)); if (dev_name != NULL) strlcpy(dev_name, devname(buf.st_rdev, S_IFCHR), dev_name_size); return fd; } return -1; } #endif /* Probe for nat tool availability */ int probe_nat_tool(void) { fprintf(stderr, "probe_nat_tool: not implemented\n"); return -1; } void add_nat_rule(char *BATMANUNUSED(dev)) { fprintf(stderr, "add_nat_rule: not implemented\n"); } void del_nat_rule(char *BATMANUNUSED(dev)) { fprintf(stderr, "del_nat_rule: not implemented\n"); } void own_hna_rules(uint32_t hna_ip, uint8_t netmask, int8_t route_action) { fprintf(stderr, "own_hna_rules: not implemented\n"); } /* Probe for tun interface availability */ int8_t probe_tun(uint8_t BATMANUNUSED(print_to_stderr)) { int fd; fd = open_tun_any(NULL, 0); if (fd == -1) return 0; close(fd); return 1; } int8_t del_dev_tun(int32_t fd) { return close(fd); } int8_t set_tun_addr(int32_t BATMANUNUSED(fd), uint32_t tun_addr, char *tun_ifname) { int so; struct ifreq ifr_tun; struct sockaddr_in *addr; memset(&ifr_tun, 0, sizeof(ifr_tun)); strlcpy(ifr_tun.ifr_name, tun_ifname, IFNAMSIZ); so = socket(AF_INET, SOCK_DGRAM, 0); /* Get interface flags */ if (ioctl(so, SIOCGIFFLAGS, &ifr_tun) < 0) { perror("SIOCGIFFLAGS"); return -1; } /* Set address */ addr = (struct sockaddr_in*)&ifr_tun.ifr_addr; addr->sin_family = AF_INET; addr->sin_addr.s_addr = tun_addr; if (ioctl(so, SIOCAIFADDR, &ifr_tun) < 0) { perror("SIOCAIFADDR"); return -1; } close(so); return 0; } 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 *BATMANUNUSED(ifi)) { int so; struct ifreq ifr_tun, ifr_if; struct tuninfo ti; char *tun_ifname; memset(&ifr_tun, 0, sizeof(ifr_tun)); memset(&ifr_if, 0, sizeof(ifr_if)); memset(&ti, 0, sizeof(ti)); if ((*fd = open_tun_any(tun_dev, tun_dev_size)) < 0) { perror("Could not open tun device"); return -1; } printf("Using %s\n", tun_dev); /* Initialise tuninfo to defaults. */ if (ioctl(*fd, TUNGIFINFO, &ti) < 0) { perror("TUNGIFINFO"); del_dev_tun(*fd); return -1; } /* Set name of interface to configure ("tunX") */ tun_ifname = strstr(tun_dev, "tun"); if (tun_ifname == NULL) { warn("Cannot determine tun interface name!"); return -1; } strlcpy(ifr_tun.ifr_name, tun_ifname, IFNAMSIZ); /* Open temporary socket to configure tun interface. */ so = socket(AF_INET, SOCK_DGRAM, 0); /* Get interface flags for tun device */ if (ioctl(so, SIOCGIFFLAGS, &ifr_tun) < 0) { perror("SIOCGIFFLAGS"); del_dev_tun(*fd); return -1; } /* Set up and running interface flags on tun device. */ ifr_tun.ifr_flags |= IFF_UP; ifr_tun.ifr_flags |= IFF_RUNNING; if (ioctl(so, SIOCSIFFLAGS, &ifr_tun) < 0) { perror("SIOCSIFFLAGS"); del_dev_tun(*fd); return -1; } /* Set IP of this end point of tunnel */ if (set_tun_addr(*fd, tun_addr, tun_ifname) < 0) { perror("set_tun_addr"); del_dev_tun(*fd); return -1; } /* get MTU from real interface */ strlcpy(ifr_if.ifr_name, batman_if->dev, IFNAMSIZ); if (ioctl(so, SIOCGIFMTU, &ifr_if) < 0) { perror("SIOCGIFMTU"); del_dev_tun(*fd); return -1; } /* set MTU of tun interface: real MTU - 28 */ if (ifr_if.ifr_mtu < 100) { fprintf(stderr, "Warning: MTU smaller than 100 - cannot reduce MTU anymore\n" ); } else { ti.mtu = ifr_if.ifr_mtu - 28; if (ioctl(*fd, TUNSIFINFO, &ti) < 0) { perror("TUNSIFINFO"); del_dev_tun(*fd); return -1; } } strlcpy(tun_dev, ifr_tun.ifr_name, tun_dev_size); close(so); return 1; } batman-0.3.2/CHANGELOG0000666000000000000000000000012111133403541011047 0ustar For a reasonable up-to-date CHANGELOG visit: http://www.open-mesh.net/log/trunk batman-0.3.2/hash.c0000666000000000000000000002020411206005452010730 0ustar /* * Copyright (C) 2006-2009 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 /* NULL */ #include "hash.h" #include "allocate.h" /* clears the hash */ void hash_init(struct hashtable_t *hash) { int i; hash->elements=0; for (i=0 ; isize ; 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; isize; 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); } /* free only the hashtable and the hash itself. */ void hash_destroy(struct hashtable_t *hash) { debugFree( hash->table, 1302 ); debugFree( hash, 1303 ); } /* 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++; while ( iter->index < hash->size ) { /* go through the entries of the hash table */ if ((hash->table[ iter->index ]) != NULL){ 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 */ } else iter->index++; /* else, go to the next */ } /* nothing to iterate over anymore */ debugFree(iter, 1304); 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 == NULL ) /* could not allocate the hash control structure */ return (NULL); hash->size= size; hash->table= debugMalloc( sizeof(struct element_t *) * size, 303); if ( hash->table == NULL ) { /* could not allocate the 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 index; struct element_t *bucket, *prev_bucket = NULL; index = hash->choose( data, hash->size ); bucket = hash->table[index]; while (bucket!=NULL) { if (hash->compare(bucket->data, data)) return(-1); prev_bucket = bucket; bucket= bucket->next; } /* found the tail of the list, add new element */ if (NULL == (bucket= debugMalloc(sizeof(struct element_t),304))) return(-1); /* debugMalloc failed */ bucket->data= data; /* init the new bucket */ bucket->next= NULL; /* and link it */ if ( prev_bucket == NULL ) { hash->table[index] = bucket; } else { prev_bucket->next = bucket; } hash->elements++; return(0); } /* 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; data_save = hash_it_t->bucket->data; /* save the pointer to the 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)) { hash_it_t.first_bucket = (hash_it_t.bucket == hash->table[hash_it_t.index] ? &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 */ if (NULL == (new_hash= hash_new(size, hash->compare, hash->choose))) return(NULL); /* copy the elements */ for (i=0; isize; i++) { bucket= hash->table[i]; while (bucket != NULL) { hash_add( new_hash, bucket->data ); bucket= bucket->next; } } hash_delete(hash, NULL); /* remove hash and eventual overflow buckets but not the content itself. */ 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; isize;i++) { printf("[%d] ",i); bucket= hash->table[i]; while (bucket != NULL) { printf("-> [%10p] ", (void *)bucket); bucket= bucket->next; } printf("\n"); } printf("\n"); }*/ batman-0.3.2/hash.h0000666000000000000000000000737211133202550010745 0ustar /* * Copyright (C) 2006-2009 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 _BATMAN_HASH_H #define _BATMAN_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); #endif batman-0.3.2/hna.c0000666000000000000000000005556011207175617010604 0ustar /* * Copyright (C) 2006-2009 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 "hna.h" #include "os.h" #include "hash.h" #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; int compare_hna(void *data1, void *data2) { return (memcmp(data1, data2, 5) == 0 ? 1 : 0); } 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 list_head *list_pos; 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(list_pos, &hna_list) { hna_local_entry = list_entry(list_pos, struct hna_local_entry, 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 list_head *list_pos; struct hna_local_entry *hna_local_entry; struct vis_data *vis_data; if (num_hna_local < 1) return vis_packet; list_for_each(list_pos, &hna_list) { hna_local_entry = list_entry(list_pos, struct hna_local_entry, 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 list_head *list_pos; 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; 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(list_pos, &hna_global_entry->orig_list) { hna_orig_ptr = list_entry(list_pos, struct hna_orig_ptr, list); if (hna_orig_ptr->orig_node == orig_node) break; hna_orig_ptr = NULL; } /* append the given orig node to the list */ if (!hna_orig_ptr) { 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); } batman-0.3.2/hna.h0000666000000000000000000000447711211456337010606 0ustar /* * Copyright (C) 2006-2009 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 "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); batman-0.3.2/INSTALL0000666000000000000000000000334711214542060010703 0ustar ################################### 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 (currently BSD Make is not cooperating). The *BSD and Mac OS operating systems are currently unmaintained, make targets are still available but will most probably not work. 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. Compiling --------- You don't necessarily need to compile. May be your distribution or our download store offers precompiled packages. Check http://www.open-mesh.net/wiki/Download to get an overview. Download and compile the latest stable sources from the download section http://www.open-mesh.net/wiki/Download by executing eg.: $ wget http://downloads.open-mesh.net/batman/releases/batman-0.3.2/batman-0.3.2.tar.gz $ tar xzvf batman-0.3.2.tar.gz $ cd batmand-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. batman-0.3.2/linux/kernel.c0000666000000000000000000001012311207275153012433 0ustar /* * Copyright (C) 2006-2009 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 #include "../os.h" #include "../batman.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, 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(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, 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(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, 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; } int32_t use_gateway_module(void) { int32_t fd; if ((fd = open("/dev/batgat", O_WRONLY)) < 0) { debug_output(0, "Warning - batgat kernel modul interface (/dev/batgat) not usable: %s\nThis may decrease the performance of batman!\n", strerror(errno)); return -1; } return fd; } 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; } batman-0.3.2/linux/modules/compat26.h0000666000000000000000000000336711133202550014264 0ustar /* * Copyright (C) 2008-2009 B.A.T.M.A.N. contributors: * * Thomas Lopatic, Corinna 'Elektra' Aichele, Axel Neumann, Marek Lindner, Andreas Langer * 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 * * * This file contains macros for maintaining compatibility with older versions * of the Linux kernel. */ #include /* LINUX_VERSION_CODE */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22) #define skb_network_header(_skb) \ ((_skb)->nh.raw) static inline struct iphdr *ip_hdr(const struct sk_buff *skb) { return (struct iphdr *)skb_network_header(skb); } #endif /* KERNEL_VERSION(2, 6, 22) */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) static inline int kernel_bind(struct socket *sock, struct sockaddr *addr, int addrlen) { return sock->ops->bind(sock, addr, addrlen); } #endif /* KERNEL_VERSION(2, 6, 19) */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26) #define device_create \ class_device_create #define device_destroy \ class_device_destroy #else #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) #define device_create \ device_create_drvdata #endif /* KERNEL_VERSION(2,6,27) */ #endif /* KERNEL_VERSION(2,6,26) */ batman-0.3.2/linux/modules/gateway24.c0000666000000000000000000004273511133202550014435 0ustar /* * Copyright (C) 2006-2009 B.A.T.M.A.N. contributors: * * Thomas Lopatic, Corinna 'Elektra' Aichele, Axel Neumann, Marek Lindner, Andreas Langer * 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 "gateway24.h" #include "hash.h" static int batgat_open(struct inode *inode, struct file *filp); static int batgat_release(struct inode *inode, struct file *file); static int batgat_ioctl( struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg ); static int bat_netdev_setup( struct net_device *dev); static int create_bat_netdev(void); static int bat_netdev_open( struct net_device *dev ); static int bat_netdev_close( struct net_device *dev ); static int bat_netdev_xmit( struct sk_buff *skb, struct net_device *dev ); static struct gw_client *get_ip_addr(struct sockaddr_in *client_addr); static int packet_recv_thread(void *data); static void udp_data_ready(struct sock *sk, int len); static int compare_wip( void *data1, void *data2 ); static int choose_wip( void *data, int32_t size ); static int compare_vip( void *data1, void *data2 ); static int choose_vip( void *data, int32_t size ); static int kernel_sendmsg(struct socket *sock, struct msghdr *msg, struct iovec *vec, size_t num, size_t size); static int kernel_recvmsg(struct socket *sock, struct msghdr *msg, struct iovec *vec, size_t num, size_t size, int flags); static struct file_operations fops = { .open = batgat_open, .release = batgat_release, .ioctl = batgat_ioctl, }; static int Major; static int thread_pid; static struct completion thread_complete; DECLARE_WAIT_QUEUE_HEAD(thread_wait); spinlock_t hash_lock = SPIN_LOCK_UNLOCKED; static struct net_device gate_device = { init: bat_netdev_setup, name: "gate%d", }; atomic_t gate_device_run; atomic_t data_ready_cond; static struct hashtable_t *wip_hash; static struct hashtable_t *vip_hash; static struct list_head free_client_list; int init_module(void) { printk(KERN_DEBUG "B.A.T.M.A.N. gateway modul\n"); if ( ( Major = register_chrdev( 0, DRIVER_DEVICE, &fops ) ) < 0 ) { DBG( "registering the character device failed with %d", Major ); return Major; } DBG( "batgat loaded %s", strlen(REVISION_VERSION) > 3 ? REVISION_VERSION : "" ); DBG( "I was assigned major number %d. To talk to", Major ); DBG( "the driver, create a dev file with 'mknod /dev/batgat c %d 0'.", Major ); printk(KERN_DEBUG "Remove the device file and module when done." ); INIT_LIST_HEAD(&free_client_list); atomic_set(&gate_device_run, 0); /* TODO: error handling */ vip_hash = hash_new( 128, compare_vip, choose_vip ); wip_hash = hash_new( 128, compare_wip, choose_wip ); printk(KERN_DEBUG "modul successfully loaded\n"); return(0); } void cleanup_module(void) { struct gate_priv *priv; struct free_client_data *entry, *next; struct gw_client *gw_client; unregister_chrdev( Major, DRIVER_DEVICE ); if(thread_pid) { kill_proc(thread_pid, SIGTERM, 1 ); wait_for_completion(&thread_complete); } if(atomic_read(&gate_device_run)) { priv = (struct gate_priv*)gate_device.priv; if( priv->tun_socket ) sock_release(priv->tun_socket); kfree(gate_device.priv); gate_device.priv = NULL; unregister_netdev(&gate_device); atomic_dec(&gate_device_run); } list_for_each_entry_safe(entry, next, &free_client_list, list) { if(entry->gw_client != NULL) { gw_client = entry->gw_client; list_del(&entry->list); kfree(entry); kfree(gw_client); } } printk(KERN_DEBUG "modul successfully unloaded\n" ); return; } static int batgat_open(struct inode *inode, struct file *filp) { MOD_INC_USE_COUNT; return(0); } static int batgat_release(struct inode *inode, struct file *file) { MOD_DEC_USE_COUNT; return(0); } static int batgat_ioctl( struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg ) { uint8_t tmp_ip[4]; struct batgat_ioc_args ioc; struct free_client_data *entry, *next; struct gw_client *gw_client; struct gate_priv *priv; int ret_value = 0; if( cmd == IOCSETDEV || cmd == IOCREMDEV ) { if( !access_ok( VERIFY_READ, (void *)arg, sizeof( ioc ) ) ) { printk(KERN_DEBUG "access to memory area of arg not allowed" ); ret_value = -EFAULT; goto end; } if( __copy_from_user( &ioc, (void *)arg, sizeof( ioc ) ) ) { ret_value = -EFAULT; goto end; } } switch( cmd ) { case IOCSETDEV: if( ( ret_value = create_bat_netdev() ) == 0 && !thread_pid) { init_completion(&thread_complete); thread_pid = kernel_thread( packet_recv_thread, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND ); if(thread_pid<0) { printk(KERN_DEBUG "unable to start packet receive thread\n"); ret_value = -EFAULT; goto end; } } if( ret_value == -1 || ret_value == 0 ) { tmp_ip[0] = 169; tmp_ip[1] = 254; tmp_ip[2] = 0; tmp_ip[3] = 0; ioc.universal = *(uint32_t*)tmp_ip; ioc.ifindex = gate_device.ifindex; strncpy( ioc.dev_name, gate_device.name, IFNAMSIZ - 1 ); DBG("name %s index %d", ioc.dev_name, ioc.ifindex); if( ret_value == -1 ) { ioc.exists = 1; ret_value = 0; } if( copy_to_user( (void *)arg, &ioc, sizeof( ioc ) ) ) ret_value = -EFAULT; } break; case IOCREMDEV: printk(KERN_DEBUG "disconnect daemon\n"); if(thread_pid) { kill_proc(thread_pid, SIGTERM, 1 ); wait_for_completion( &thread_complete ); } thread_pid = 0; printk(KERN_DEBUG "thread shutdown\n"); // dev_put(gate_device); if(atomic_read(&gate_device_run)) { priv = (struct gate_priv*)gate_device.priv; if( priv->tun_socket ) sock_release(priv->tun_socket); kfree(gate_device.priv); gate_device.priv = NULL; unregister_netdev(&gate_device); atomic_dec(&gate_device_run); printk(KERN_DEBUG "gate shutdown\n"); } list_for_each_entry_safe(entry, next, &free_client_list, list) { gw_client = entry->gw_client; list_del(&entry->list); kfree(entry); kfree(gw_client); } printk(KERN_DEBUG "device unregistered successfully\n" ); break; default: DBG( "ioctl %d is not supported",cmd ); ret_value = -EFAULT; } end: return( ret_value ); } static int packet_recv_thread(void *data) { sigset_t tmpsig; struct msghdr msg, inet_msg; struct iovec iov, inet_iov; struct iphdr *iph; struct gw_client *client_data; struct sockaddr_in client, inet_addr, server_addr; struct free_client_data *tmp_entry; struct socket *server_sock = NULL; struct socket *inet_sock = NULL; unsigned long time = jiffies; struct hash_it_t *hashit; int length, ret_value; unsigned char buffer[1600]; server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = INADDR_ANY; server_addr.sin_port = __constant_htons( (unsigned short) BATMAN_PORT ); if ( ( sock_create( PF_INET, SOCK_RAW, IPPROTO_RAW, &inet_sock ) ) < 0 ) { printk(KERN_DEBUG "can't create raw socket\n"); return -1; } if( sock_create( PF_INET, SOCK_DGRAM, IPPROTO_UDP, &server_sock ) < 0 ) { printk(KERN_DEBUG "can't create udp socket\n"); sock_release(inet_sock); return -1; } if( server_sock->ops->bind(server_sock, (struct sockaddr *) &server_addr, sizeof( server_addr ) ) < 0 ) { printk(KERN_DEBUG "can't bind udp server socket\n"); sock_release(server_sock); sock_release(inet_sock); return -1; } server_sock->sk->user_data = server_sock->sk->data_ready; server_sock->sk->data_ready = udp_data_ready; msg.msg_name = &client; msg.msg_namelen = sizeof( struct sockaddr_in ); msg.msg_control = NULL; msg.msg_controllen = 0; msg.msg_flags = MSG_NOSIGNAL | MSG_DONTWAIT; iph = ( struct iphdr*)(buffer + 1 ); strcpy(current->comm,"udp_recv"); daemonize(); spin_lock_irq(¤t->sigmask_lock); tmpsig = current->blocked; siginitsetinv(¤t->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP) | sigmask(SIGTERM) ); recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); atomic_set(&data_ready_cond, 0); while(!signal_pending(current)) { wait_event_interruptible(thread_wait, atomic_read(&data_ready_cond)); if (signal_pending(current)) break; client_data = NULL; iov.iov_base = buffer; iov.iov_len = sizeof(buffer); while ( ( length = kernel_recvmsg( server_sock, &msg, &iov, 1, sizeof(buffer), MSG_NOSIGNAL | MSG_DONTWAIT ) ) > 0 ) { if( ( jiffies - time ) / HZ > LEASE_TIME ) { hashit = NULL; spin_lock(&hash_lock); while( NULL != ( hashit = hash_iterate( wip_hash, hashit ) ) ) { client_data = hashit->bucket->data; if( ( jiffies - client_data->last_keep_alive ) / HZ > LEASE_TIME ) { hash_remove_bucket(wip_hash, hashit); hash_remove(vip_hash, client_data); tmp_entry = kmalloc(sizeof(struct free_client_data), GFP_KERNEL); if(tmp_entry != NULL) { tmp_entry->gw_client = client_data; list_add(&tmp_entry->list,&free_client_list); } else printk(KERN_DEBUG "can't add free gw_client to free list\n"); } } spin_unlock(&hash_lock); time = jiffies; } if( length > 0 && buffer[0] == TUNNEL_IP_REQUEST ) { client_data = get_ip_addr(&client); if(client_data != NULL) { memcpy( &buffer[1], &client_data->vip_addr, sizeof( client_data->vip_addr ) ); iov.iov_base = buffer; iov.iov_len = length; if( ( ret_value = kernel_sendmsg(server_sock, &msg, &iov, 1, length ) ) < 0 ) DBG("tunnel ip request socket return %d", ret_value); } else printk(KERN_DEBUG "can't get an ip address\n"); } else if( length > 0 && buffer[0] == TUNNEL_DATA ) { spin_lock(&hash_lock); client_data = ((struct gw_client *)hash_find(wip_hash, &client.sin_addr.s_addr)); spin_unlock(&hash_lock); if(client_data == NULL) { buffer[0] = TUNNEL_IP_INVALID; iov.iov_base = buffer; iov.iov_len = length; if( ( ret_value = kernel_sendmsg(server_sock, &msg, &iov, 1, length ) ) < 0 ) DBG("tunnel ip invalid socket return %d", ret_value); continue; } client_data->last_keep_alive = jiffies; inet_iov.iov_base = &buffer[1]; inet_iov.iov_len = length - 1; inet_addr.sin_port = 0; inet_addr.sin_addr.s_addr = iph->daddr; if( (ret_value = kernel_sendmsg(inet_sock, &inet_msg, &inet_iov, 1, length - 1 ) ) < 0 ) DBG("tunnel data socket return %d", ret_value); } else if( length > 0 && buffer[0] == TUNNEL_KEEPALIVE_REQUEST ) { spin_lock(&hash_lock); client_data = ((struct gw_client *)hash_find(wip_hash, &client.sin_addr.s_addr)); spin_unlock(&hash_lock); if(client_data != NULL) { buffer[0] = TUNNEL_KEEPALIVE_REPLY; client_data->last_keep_alive = jiffies; } else buffer[0] = TUNNEL_IP_INVALID; iov.iov_base = buffer; iov.iov_len = length; if( ( ret_value = kernel_sendmsg(server_sock, &msg, &iov, 1, length ) ) < 0 ) DBG("tunnel keep alive socket return %d", ret_value); } else printk(KERN_DEBUG "recive unknown message\n" ); } iov.iov_base = buffer; iov.iov_len = sizeof(buffer); atomic_set(&data_ready_cond, 0); } if(server_sock) sock_release(server_sock); printk(KERN_DEBUG "thread terminated\n"); complete(&thread_complete); return 0; } /* bat_netdev part */ static int bat_netdev_setup( struct net_device *dev ) { ether_setup(dev); dev->open = bat_netdev_open; dev->stop = bat_netdev_close; dev->hard_start_xmit = bat_netdev_xmit; // dev->destructor = free_netdev; dev->features |= NETIF_F_NO_CSUM; dev->hard_header_cache = NULL; dev->mtu = 1471; dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST; dev->hard_header_cache = NULL; dev->priv = kmalloc(sizeof(struct gate_priv), GFP_KERNEL); if (dev->priv == NULL) return -ENOMEM; memset( dev->priv, 0, sizeof( struct gate_priv ) ); return(0); } static int bat_netdev_xmit( struct sk_buff *skb, struct net_device *dev ) { struct gate_priv *priv = priv = (struct gate_priv*)dev->priv; struct sockaddr_in sa; struct iphdr *iph = ip_hdr( skb ); struct iovec iov[2]; struct msghdr msg; struct gw_client *client_data; unsigned char msg_number[1]; msg_number[0] = TUNNEL_DATA; /* we use saddr , because hash choose and compare begin at + 4 bytes */ spin_lock(&hash_lock); client_data = ((struct gw_client *)hash_find(vip_hash, & iph->saddr )); /* daddr */ spin_unlock(&hash_lock); if( client_data != NULL ) { sa.sin_family = AF_INET; sa.sin_addr.s_addr = client_data->wip_addr; sa.sin_port = __constant_htons( (unsigned short)BATMAN_PORT ); msg.msg_flags = MSG_NOSIGNAL | MSG_DONTWAIT; msg.msg_name = &sa; msg.msg_namelen = sizeof(sa); msg.msg_control = NULL; msg.msg_controllen = 0; iov[0].iov_base = msg_number; iov[0].iov_len = 1; iov[1].iov_base = skb->data + sizeof( struct ethhdr ); iov[1].iov_len = skb->len - sizeof( struct ethhdr ); kernel_sendmsg(priv->tun_socket, &msg, iov, 2, skb->len - sizeof( struct ethhdr ) + 1); } else printk(KERN_DEBUG "client not found\n"); kfree_skb( skb ); return( 0 ); } static int bat_netdev_open( struct net_device *dev ) { printk(KERN_DEBUG "receive open\n" ); netif_start_queue( dev ); return( 0 ); } static int bat_netdev_close( struct net_device *dev ) { printk(KERN_DEBUG "receive close\n" ); netif_stop_queue( dev ); return( 0 ); } static int create_bat_netdev(void) { struct gate_priv *priv; if(!atomic_read(&gate_device_run)) { if( ( register_netdev( &gate_device ) ) < 0 ) return -ENODEV; priv = (struct gate_priv*)gate_device.priv; if( sock_create( PF_INET, SOCK_DGRAM, IPPROTO_UDP, &priv->tun_socket ) < 0 ) { printk(KERN_DEBUG "can't create gate socket\n"); netif_stop_queue(&gate_device); return -EFAULT; } atomic_inc(&gate_device_run); } else { printk(KERN_DEBUG "net device already exists\n"); return(-1); } return( 0 ); } static struct gw_client *get_ip_addr(struct sockaddr_in *client_addr) { static uint8_t next_free_ip[4] = {169,254,0,1}; struct free_client_data *entry, *next; struct gw_client *gw_client = NULL; struct hashtable_t *swaphash; spin_lock(&hash_lock); gw_client = ((struct gw_client *)hash_find(wip_hash, &client_addr->sin_addr.s_addr)); if (gw_client != NULL) { printk(KERN_DEBUG "found client in hash"); spin_unlock(&hash_lock); return gw_client; } list_for_each_entry_safe(entry, next, &free_client_list, list) { printk(KERN_DEBUG "use free client from list"); gw_client = entry->gw_client; list_del(&entry->list); kfree(entry); break; } if(gw_client == NULL) { printk(KERN_DEBUG "malloc client"); gw_client = kmalloc( sizeof(struct gw_client), GFP_KERNEL ); gw_client->vip_addr = 0; } gw_client->wip_addr = client_addr->sin_addr.s_addr; gw_client->client_port = client_addr->sin_port; gw_client->last_keep_alive = jiffies; /* TODO: check if enough space available */ 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) { printk(KERN_DEBUG "Couldn't resize hash table" ); } wip_hash = swaphash; swaphash = hash_resize(vip_hash, vip_hash->size * 2); if (swaphash == NULL) { printk(KERN_DEBUG "Couldn't resize hash table" ); } vip_hash = swaphash; } spin_unlock(&hash_lock); return gw_client; } static void udp_data_ready(struct sock *sk, int len) { void (*data_ready)(struct sock *, int) = sk->user_data; data_ready(sk,len); atomic_set(&data_ready_cond, 1); wake_up_interruptible(&thread_wait); } static int kernel_sendmsg(struct socket *sock, struct msghdr *msg, struct iovec *vec, size_t num, size_t size) { mm_segment_t oldfs = get_fs(); int result; set_fs(KERNEL_DS); msg->msg_iov = vec; msg->msg_iovlen = num; result = sock_sendmsg(sock, msg, size); set_fs(oldfs); return result; } static int kernel_recvmsg(struct socket *sock, struct msghdr *msg, struct iovec *vec, size_t num, size_t size, int flags) { mm_segment_t oldfs = get_fs(); int result; set_fs(KERNEL_DS); msg->msg_iov = (struct iovec *)vec, msg->msg_iovlen = num; result = sock_recvmsg(sock, msg, size, flags); set_fs(oldfs); return result; } int compare_wip(void *data1, void *data2) { return ( !memcmp( data1, data2, 4 ) ); } int compare_vip(void *data1, void *data2) { return ( !memcmp( data1 + 4, data2 + 4, 4 ) ); } 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); } 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); } MODULE_LICENSE("GPL"); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_SUPPORTED_DEVICE(DRIVER_DEVICE); batman-0.3.2/linux/modules/gateway24.h0000666000000000000000000000567211133202550014441 0ustar /* * Copyright (C) 2006-2009 B.A.T.M.A.N. contributors: * * Thomas Lopatic, Corinna 'Elektra' Aichele, Axel Neumann, Marek Lindner, Andreas Langer * 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 * */ #define LINUX #define DRIVER_AUTHOR "Andreas Langer , Marek Lindner " #define DRIVER_DESC "batman gateway module" #define DRIVER_DEVICE "batgat" #include /* KERNEL_VERSION ... */ #include /* fops ...*/ #include #include #include /* sockaddr_in */ #include /* socket */ #include /* strlen, strstr, strncmp ... */ #include /* iphdr */ #include /* ARPHRD_NONE */ #include /* sock */ #include /* class_create, class_destroy, class_device_create */ #include /* list handling */ #include /*IFNAMSIZ*/ #include #include #include // #include /* lock_kernel */ /* io controls */ #define IOCSETDEV 1 #define IOCREMDEV 2 #define TRANSPORT_PACKET_SIZE 29 #define VIP_BUFFER_SIZE 5 #define BATMAN_PORT 4306 #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 LEASE_TIME 1500 #define DBG(msg,args...) do { printk(KERN_DEBUG "batgat: [%s:%u] " msg "\n", __func__ ,__LINE__, ##args); } while(0) #define ip_hdr(skb) (struct iphdr*)skb->nh.iph #ifndef list_for_each_entry_safe #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 != (head); \ pos = n, n = list_entry(n->member.next, typeof(*n), member)) #endif #define PROC_ROOT_DIR "batgat" #define PROC_FILE_CLIENTS "clients" #ifndef REVISION_VERSION #define REVISION_VERSION "1" #endif struct gw_client { uint32_t wip_addr; uint32_t vip_addr; uint16_t client_port; uint32_t last_keep_alive; }; struct batgat_ioc_args { char dev_name[IFNAMSIZ]; unsigned char exists; uint32_t universal; uint32_t ifindex; }; struct gate_priv { struct socket *tun_socket; }; struct free_client_data { struct list_head list; struct gw_client *gw_client; }; batman-0.3.2/linux/modules/gateway.c0000666000000000000000000004510311133202550014257 0ustar /* * Copyright (C) 2006-2009 B.A.T.M.A.N. contributors: * * Thomas Lopatic, Corinna 'Elektra' Aichele, Axel Neumann, Marek Lindner, Andreas Langer * 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 "gateway.h" #include "hash.h" #include "compat26.h" static struct class *batman_class; static int batgat_open(struct inode *inode, struct file *filp); static int batgat_release(struct inode *inode, struct file *file); static int batgat_ioctl( struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg ); static void udp_data_ready(struct sock *sk, int len); static int packet_recv_thread(void *data); static int compare_wip( void *data1, void *data2 ); static int choose_wip( void *data, int32_t size ); static int compare_vip( void *data1, void *data2 ); static int choose_vip( void *data, int32_t size ); static struct gw_client *get_ip_addr(struct sockaddr_in *client_addr); static void bat_netdev_setup( struct net_device *dev); static int create_bat_netdev(void); static int bat_netdev_open( struct net_device *dev ); static int bat_netdev_close( struct net_device *dev ); static int bat_netdev_xmit( struct sk_buff *skb, struct net_device *dev ); static void cleanup_procfs(void); static int setup_procfs(void); static int proc_clients_read(char *buf, char **start, off_t offset, int size, int *eof, void *data); static struct file_operations fops = { .open = batgat_open, .release = batgat_release, .ioctl = batgat_ioctl, }; static int Major; /* Major number assigned to our device driver */ static struct net_device *gate_device = NULL; static struct hashtable_t *wip_hash; static struct hashtable_t *vip_hash; static struct list_head free_client_list; DEFINE_SPINLOCK(hash_lock); atomic_t data_ready_cond; atomic_t exit_cond; DECLARE_WAIT_QUEUE_HEAD(thread_wait); static struct task_struct *kthread_task = NULL; static struct proc_dir_entry *proc_dir, *clients_file; int init_module(void) { /* register our device - kernel assigns a free major number */ if ( ( Major = register_chrdev( 0, DRIVER_DEVICE, &fops ) ) < 0 ) { DBG( "registering the character device failed with %d", Major ); return Major; } batman_class = class_create( THIS_MODULE, "batgat" ); if ( IS_ERR( batman_class ) ) DBG( "could not register class 'batgat'" ); else device_create(batman_class, NULL, MKDEV(Major, 0), NULL, "batgat"); DBG( "batgat loaded %s", strlen(REVISION_VERSION) > 3 ? REVISION_VERSION : "" ); DBG( "I was assigned major number %d. To talk to", Major ); DBG( "the driver, create a dev file with 'mknod /dev/batgat c %d 0'.", Major ); DBG( "Remove the device file and module when done." ); setup_procfs(); /* TODO: error handling */ vip_hash = hash_new( 128, compare_vip, choose_vip ); wip_hash = hash_new( 128, compare_wip, choose_wip ); INIT_LIST_HEAD(&free_client_list); return(0); } void cleanup_module(void) { struct free_client_data *entry, *next; struct gw_client *gw_client; device_destroy( batman_class, MKDEV( Major, 0 ) ); class_destroy( batman_class ); /* Unregister the device */ unregister_chrdev( Major, DRIVER_DEVICE ); if(kthread_task) { atomic_set(&exit_cond, 1); wake_up_interruptible(&thread_wait); kthread_stop(kthread_task); } if(gate_device) { // dev_put(gate_device); unregister_netdev(gate_device); } list_for_each_entry_safe(entry, next, &free_client_list, list) { if(entry->gw_client != NULL) { gw_client = entry->gw_client; list_del(&entry->list); kfree(entry); kfree(gw_client); } } cleanup_procfs(); DBG( "unload module complete" ); return; } static int batgat_open(struct inode *inode, struct file *filp) { try_module_get(THIS_MODULE); return( 0 ); } static int batgat_release(struct inode *inode, struct file *file) { module_put(THIS_MODULE); return( 0 ); } static int batgat_ioctl( struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg ) { uint8_t tmp_ip[4]; struct batgat_ioc_args ioc; struct free_client_data *entry, *next; struct gw_client *gw_client; int ret_value = 0; if( cmd == IOCSETDEV || cmd == IOCREMDEV ) { if( !access_ok( VERIFY_READ, ( void __user* )arg, sizeof( ioc ) ) ) { DBG( "access to memory area of arg not allowed" ); ret_value = -EFAULT; goto end; } if( __copy_from_user( &ioc, ( void __user* )arg, sizeof( ioc ) ) ) { ret_value = -EFAULT; goto end; } } switch( cmd ) { case IOCSETDEV: if( ( ret_value = create_bat_netdev() ) == 0 && !kthread_task) { kthread_task = kthread_run(packet_recv_thread, NULL, "mod_batgat"); if (IS_ERR(kthread_task)) { DBG( "unable to start packet receive thread"); kthread_task = NULL; ret_value = -EFAULT; goto end; } } if( ret_value == -1 || ret_value == 0 ) { tmp_ip[0] = 169; tmp_ip[1] = 254; tmp_ip[2] = 0; tmp_ip[3] = 0; ioc.universal = *(uint32_t*)tmp_ip; ioc.ifindex = gate_device->ifindex; strlcpy( ioc.dev_name, gate_device->name, IFNAMSIZ - 1 ); DBG("name %s index %d", ioc.dev_name, ioc.ifindex); if( ret_value == -1 ) { DBG("device already exists"); ioc.exists = 1; ret_value = 0; } if( copy_to_user( ( void __user* )arg, &ioc, sizeof( ioc ) ) ) ret_value = -EFAULT; } break; case IOCREMDEV: DBG("disconnect daemon"); if (kthread_task) { atomic_set(&exit_cond, 1); wake_up_interruptible(&thread_wait); kthread_stop(kthread_task); } kthread_task = NULL; DBG("thread shutdown"); // dev_put(gate_device); if(gate_device) { unregister_netdev(gate_device); gate_device = NULL; DBG("gate shutdown"); } list_for_each_entry_safe(entry, next, &free_client_list, list) { if(entry->gw_client) { gw_client = entry->gw_client; list_del(&entry->list); kfree(entry); kfree(gw_client); } } DBG( "device unregistered successfully" ); break; default: DBG( "ioctl %d is not supported",cmd ); ret_value = -EFAULT; } end: return( ret_value ); } static void udp_data_ready(struct sock *sk, int len) { void (*data_ready)(struct sock *, int) = sk->sk_user_data; data_ready(sk,len); atomic_set(&data_ready_cond, 1); wake_up_interruptible(&thread_wait); } static int packet_recv_thread(void *data) { struct msghdr msg, inet_msg; struct kvec iov, inet_iov; struct iphdr *iph; struct gw_client *client_data; struct sockaddr_in client, inet_addr, server_addr; struct free_client_data *tmp_entry; struct socket *server_sock = NULL; struct socket *inet_sock = NULL; int length,ret_value; unsigned char buffer[1600]; unsigned long time = jiffies; struct hash_it_t *hashit; server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = INADDR_ANY; server_addr.sin_port = __constant_htons( (unsigned short) BATMAN_PORT ); if ( ( sock_create_kern( PF_INET, SOCK_RAW, IPPROTO_RAW, &inet_sock ) ) < 0 ) { DBG( "can't create raw socket"); return -1; } if( sock_create_kern( PF_INET, SOCK_DGRAM, IPPROTO_UDP, &server_sock ) < 0 ) { DBG( "can't create udp socket"); sock_release(inet_sock); return -1; } if( kernel_bind( server_sock, (struct sockaddr *) &server_addr, sizeof( server_addr ) ) ) { DBG( "can't bind udp server socket"); sock_release(server_sock); sock_release(inet_sock); return -1; } server_sock->sk->sk_user_data = server_sock->sk->sk_data_ready; server_sock->sk->sk_data_ready = udp_data_ready; msg.msg_name = &client; msg.msg_namelen = sizeof( struct sockaddr_in ); msg.msg_control = NULL; msg.msg_controllen = 0; msg.msg_flags = MSG_NOSIGNAL | MSG_DONTWAIT; inet_addr.sin_family = AF_INET; inet_msg.msg_flags = MSG_NOSIGNAL | MSG_DONTWAIT; inet_msg.msg_name = &inet_addr; inet_msg.msg_namelen = sizeof( inet_addr ); inet_msg.msg_control = NULL; inet_msg.msg_controllen = 0; atomic_set(&data_ready_cond, 0); atomic_set(&exit_cond, 0); iph = ( struct iphdr*)(buffer + 1 ); while (!kthread_should_stop() && !atomic_read(&exit_cond)) { wait_event_interruptible(thread_wait, atomic_read(&data_ready_cond) || atomic_read(&exit_cond)); if (kthread_should_stop() || atomic_read(&exit_cond)) break; client_data = NULL; iov.iov_base = buffer; iov.iov_len = sizeof(buffer); while ( ( length = kernel_recvmsg( server_sock, &msg, &iov, 1, sizeof(buffer), MSG_NOSIGNAL | MSG_DONTWAIT ) ) > 0 ) { if( ( jiffies - time ) / HZ > LEASE_TIME ) { hashit = NULL; spin_lock(&hash_lock); while( NULL != ( hashit = hash_iterate( wip_hash, hashit ) ) ) { client_data = hashit->bucket->data; if( ( jiffies - client_data->last_keep_alive ) / HZ > LEASE_TIME ) { hash_remove_bucket(wip_hash, hashit); hash_remove(vip_hash, client_data); tmp_entry = kmalloc(sizeof(struct free_client_data), GFP_KERNEL); if(tmp_entry != NULL) { tmp_entry->gw_client = client_data; list_add(&tmp_entry->list,&free_client_list); } else DBG("can't add free gw_client to free list"); } } spin_unlock(&hash_lock); time = jiffies; } if( length > 0 && buffer[0] == TUNNEL_IP_REQUEST ) { client_data = get_ip_addr(&client); if(client_data != NULL) { memcpy( &buffer[1], &client_data->vip_addr, sizeof( client_data->vip_addr ) ); iov.iov_base = buffer; iov.iov_len = length; if( ( ret_value = kernel_sendmsg(server_sock, &msg, &iov, 1, length ) ) < 0 ) DBG("tunnel ip request socket return %d", ret_value); } else DBG("can't get an ip address"); } else if( length > 0 && buffer[0] == TUNNEL_DATA ) { spin_lock(&hash_lock); client_data = ((struct gw_client *)hash_find(wip_hash, &client.sin_addr.s_addr)); spin_unlock(&hash_lock); if(client_data == NULL) { buffer[0] = TUNNEL_IP_INVALID; iov.iov_base = buffer; iov.iov_len = length; if( ( ret_value = kernel_sendmsg(server_sock, &msg, &iov, 1, length ) ) < 0 ) DBG("tunnel ip invalid socket return %d", ret_value); continue; } client_data->last_keep_alive = jiffies; inet_iov.iov_base = &buffer[1]; inet_iov.iov_len = length - 1; inet_addr.sin_port = 0; inet_addr.sin_addr.s_addr = iph->daddr; if( (ret_value = kernel_sendmsg(inet_sock, &inet_msg, &inet_iov, 1, length - 1 ) ) < 0 ) DBG("tunnel data socket return %d", ret_value); } else if( length > 0 && buffer[0] == TUNNEL_KEEPALIVE_REQUEST ) { DBG("keep alive"); spin_lock(&hash_lock); client_data = ((struct gw_client *)hash_find(wip_hash, &client.sin_addr.s_addr)); spin_unlock(&hash_lock); if(client_data != NULL) { DBG("refresh ip"); buffer[0] = TUNNEL_KEEPALIVE_REPLY; client_data->last_keep_alive = jiffies; } else buffer[0] = TUNNEL_IP_INVALID; iov.iov_base = buffer; iov.iov_len = length; if( ( ret_value = kernel_sendmsg(server_sock, &msg, &iov, 1, length ) ) < 0 ) DBG("tunnel keep alive socket return %d", ret_value); } else DBG( "recive unknown message" ); iov.iov_base = buffer; iov.iov_len = sizeof(buffer); } atomic_set(&data_ready_cond, 0); } if(server_sock) { sock_release(server_sock); server_sock = NULL; } if(inet_sock) { sock_release(inet_sock); inet_sock = NULL; } while(!kthread_should_stop()) { if(kthread_should_stop()) break; schedule(); } DBG( "thread stop" ); return 0; } /* bat_netdev part */ static void bat_netdev_setup( struct net_device *dev ) { struct gate_priv *priv; ether_setup(dev); dev->open = bat_netdev_open; dev->stop = bat_netdev_close; dev->hard_start_xmit = bat_netdev_xmit; dev->destructor = free_netdev; dev->features |= NETIF_F_NO_CSUM; #ifndef __NET_NET_NAMESPACE_H dev->hard_header_cache = NULL; #endif dev->mtu = 1471; dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST; #ifdef HAVE_VALIDATE_ADDR dev->validate_addr = NULL; #endif priv = netdev_priv( dev ); memset( priv, 0, sizeof( struct gate_priv ) ); return; } static int bat_netdev_xmit( struct sk_buff *skb, struct net_device *dev ) { struct gate_priv *priv = netdev_priv( dev ); struct sockaddr_in sa; struct iphdr *iph = ip_hdr( skb ); struct iovec iov[2]; struct msghdr msg; struct gw_client *client_data; unsigned char msg_number[1]; msg_number[0] = TUNNEL_DATA; /* we use saddr , because hash choose and compare begin at + 4 bytes */ spin_lock(&hash_lock); client_data = ((struct gw_client *)hash_find(vip_hash, & iph->saddr )); /* daddr */ spin_unlock(&hash_lock); if( client_data != NULL ) { sa.sin_family = AF_INET; sa.sin_addr.s_addr = client_data->wip_addr; sa.sin_port = __constant_htons( (unsigned short)BATMAN_PORT ); msg.msg_flags = MSG_NOSIGNAL | MSG_DONTWAIT; msg.msg_name = &sa; msg.msg_namelen = sizeof(sa); msg.msg_control = NULL; msg.msg_controllen = 0; iov[0].iov_base = msg_number; iov[0].iov_len = 1; iov[1].iov_base = skb->data + sizeof( struct ethhdr ); iov[1].iov_len = skb->len - sizeof( struct ethhdr ); kernel_sendmsg(priv->tun_socket, &msg, (struct kvec *)&iov, 2, skb->len - sizeof( struct ethhdr ) + 1); } else DBG("client not found"); kfree_skb( skb ); return( 0 ); } static int bat_netdev_open( struct net_device *dev ) { DBG( "receive open" ); netif_start_queue( dev ); return( 0 ); } static int bat_netdev_close( struct net_device *dev ) { struct gate_priv *priv = netdev_priv(dev); DBG( "receive close" ); if(priv->tun_socket) sock_release(priv->tun_socket); netif_stop_queue( dev ); return( 0 ); } static int create_bat_netdev(void) { struct gate_priv *priv; if( gate_device == NULL ) { if( ( gate_device = alloc_netdev( sizeof( struct gate_priv ) , "gate%d", bat_netdev_setup ) ) == NULL ) return -ENOMEM; if( ( register_netdev( gate_device ) ) < 0 ) return -ENODEV; priv = netdev_priv( gate_device ); if( sock_create_kern( PF_INET, SOCK_DGRAM, IPPROTO_UDP, &priv->tun_socket ) < 0 ) { DBG( "can't create gate socket"); netif_stop_queue(gate_device); return -EFAULT; } // dev_hold(gate_device); } else { DBG( "bat_device for is already created" ); return( -1 ); } return( 0 ); } /* ip handling */ static struct gw_client *get_ip_addr(struct sockaddr_in *client_addr) { static uint8_t next_free_ip[4] = {169,254,0,1}; struct free_client_data *entry, *next; struct gw_client *gw_client = NULL; struct hashtable_t *swaphash; spin_lock(&hash_lock); gw_client = ((struct gw_client *)hash_find(wip_hash, &client_addr->sin_addr.s_addr)); if (gw_client != NULL) { DBG("found client in hash"); spin_unlock(&hash_lock); return gw_client; } list_for_each_entry_safe(entry, next, &free_client_list, list) { DBG("use free client from list"); gw_client = entry->gw_client; list_del(&entry->list); kfree(entry); break; } if(gw_client == NULL) { DBG("malloc client"); gw_client = kmalloc( sizeof(struct gw_client), GFP_KERNEL ); gw_client->vip_addr = 0; } gw_client->wip_addr = client_addr->sin_addr.s_addr; gw_client->client_port = client_addr->sin_port; gw_client->last_keep_alive = jiffies; /* TODO: check if enough space available */ 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) { DBG( "Couldn't resize hash table" ); } wip_hash = swaphash; swaphash = hash_resize(vip_hash, vip_hash->size * 2); if (swaphash == NULL) { DBG( "Couldn't resize hash table" ); } vip_hash = swaphash; } spin_unlock(&hash_lock); 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 */ int compare_wip(void *data1, void *data2) { return ( !memcmp( data1, data2, 4 ) ); } int compare_vip(void *data1, void *data2) { return ( !memcmp( data1 + 4, data2 + 4, 4 ) ); } /* hashfunction to choose an entry in a hash table of given size */ /* hash algorithm from http://en.wikipedia.org/wiki/Hash_table */ 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); } 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); } static void cleanup_procfs(void) { if (clients_file) remove_proc_entry(PROC_FILE_CLIENTS, proc_dir); #ifdef __NET_NET_NAMESPACE_H if (proc_dir) remove_proc_entry(PROC_ROOT_DIR, init_net.proc_net); #else if (proc_dir) remove_proc_entry(PROC_ROOT_DIR, proc_net); #endif } static int setup_procfs(void) { #ifdef __NET_NET_NAMESPACE_H proc_dir = proc_mkdir(PROC_ROOT_DIR, init_net.proc_net); #else proc_dir = proc_mkdir(PROC_ROOT_DIR, proc_net); #endif clients_file = create_proc_read_entry(PROC_FILE_CLIENTS, S_IRUGO, proc_dir, proc_clients_read, NULL); return(0); } static int proc_clients_read(char *buf, char **start, off_t offset, int size, int *eof, void *data) { struct gw_client *client_data; unsigned char *wip, *vip; int bytes_written = 0, total_bytes = 0; struct hash_it_t *hashit = NULL; spin_lock(&hash_lock); while( NULL != ( hashit = hash_iterate( wip_hash, hashit ) ) ) { client_data = hashit->bucket->data; wip = (unsigned char *)&client_data->wip_addr; vip = (unsigned char *)&client_data->vip_addr; bytes_written = snprintf(buf + total_bytes, (size - total_bytes), "%u.%u.%u.%u - %u.%u.%u.%u\n", wip[0],wip[1],wip[2],wip[3],vip[0],vip[1],vip[2],vip[3]); total_bytes += (bytes_written > (size - total_bytes) ? size - total_bytes : bytes_written); } spin_unlock(&hash_lock); *eof = 1; return total_bytes; } MODULE_LICENSE("GPL"); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_SUPPORTED_DEVICE(DRIVER_DEVICE); batman-0.3.2/linux/modules/gateway.h0000666000000000000000000000516411133202550014267 0ustar /* * Copyright (C) 2006-2009 B.A.T.M.A.N. contributors: * * Thomas Lopatic, Corinna 'Elektra' Aichele, Axel Neumann, Marek Lindner, Andreas Langer * 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 * */ #define LINUX #define DRIVER_AUTHOR "Andreas Langer , Marek Lindner " #define DRIVER_DESC "batman gateway module" #define DRIVER_DEVICE "batgat" #include /* KERNEL_VERSION ... */ #include /* fops ...*/ #include /* sockaddr_in */ #include /* socket */ #include /* strlen, strstr, strncmp ... */ #include /* iphdr */ #include /* ARPHRD_NONE */ #include /* sock */ #include /* class_create, class_destroy, class_device_create */ #include /* list handling */ //#include /* init_net */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) #include #include /* __in_dev_get_rtnl */ #else #include /*IFNAMSIZ*/ #endif #include /* io controls */ #define IOCSETDEV 1 #define IOCREMDEV 2 #define TRANSPORT_PACKET_SIZE 29 #define VIP_BUFFER_SIZE 5 #define BATMAN_PORT 4306 #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 LEASE_TIME 1500 #define DBG(msg,args...) do { printk(KERN_DEBUG "batgat: [%s:%u] " msg "\n", __func__ ,__LINE__, ##args); } while(0) #define PROC_ROOT_DIR "batgat" #define PROC_FILE_CLIENTS "clients" #ifndef REVISION_VERSION #define REVISION_VERSION "1" #endif struct gw_client { uint32_t wip_addr; uint32_t vip_addr; uint16_t client_port; uint32_t last_keep_alive; }; struct batgat_ioc_args { char dev_name[IFNAMSIZ]; unsigned char exists; uint32_t universal; uint32_t ifindex; }; struct gate_priv { struct socket *tun_socket; }; struct free_client_data { struct list_head list; struct gw_client *gw_client; }; batman-0.3.2/linux/modules/hash.c0000666000000000000000000001677211214541762013566 0ustar /* * Copyright (C) 2006-2009 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 /* strlen, strstr, strncmp ... */ #include #include "hash.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; kfree(last_bucket); } } hash_destroy(hash); } /* free only the hashtable and the hash itself. */ void hash_destroy(struct hashtable_t *hash) { kfree(hash->table); kfree(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) { struct hash_it_t *iter; if (iter_in == NULL) { iter = kmalloc(sizeof(struct hash_it_t), GFP_KERNEL); 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->prev_bucket = NULL; iter->bucket = hash->table[iter->index]; iter->first_bucket = &hash->table[iter->index]; return iter; } else { iter->index++; } } /* nothing to iterate over anymore */ kfree(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 = kmalloc(sizeof(struct hashtable_t) , GFP_KERNEL); if (hash == NULL) return NULL; hash->size = size; hash->table = kmalloc(sizeof(struct element_t *) * size, GFP_KERNEL); if (hash->table == NULL) { kfree(hash); 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 index; struct element_t *bucket, *prev_bucket = NULL; index = hash->choose(data, hash->size); bucket = hash->table[index]; while (bucket != NULL) { if (hash->compare(bucket->data, data)) return -1; prev_bucket = bucket; bucket = bucket->next; } /* found the tail of the list, add new element */ bucket = kmalloc(sizeof(struct element_t),GFP_KERNEL); if (bucket == NULL) return -1; 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; } /* 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; 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; kfree(hash_it_t->bucket); 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)) { hash_it_t.first_bucket = (hash_it_t.bucket == hash->table[hash_it_t.index] ? &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 == NULL) return NULL; /* copy the elements */ for (i = 0; i < hash->size; i++) { bucket = hash->table[i]; while (bucket != NULL) { hash_add(new_hash, bucket->data); bucket = bucket->next; } } /* remove hash and eventual overflow buckets but not the content itself. */ hash_delete(hash, NULL); return new_hash; } batman-0.3.2/linux/modules/hash.h0000666000000000000000000000737611133202550013560 0ustar /* * Copyright (C) 2006-2009 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 _BATMAN_HASH_H #define _BATMAN_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); #endif batman-0.3.2/linux/modules/Makefile0000666000000000000000000000233711203033222014110 0ustar PWD:=$(shell pwd) ifeq ($(wildcard $(KERNELPATH)),) KERNELPATH = /lib/modules/$(shell uname -r)/build # sanity check: does KERNELPATH exist? ifeq ($(shell cd $(KERNELPATH) && pwd),) $(error $(KERNELPATH) is missing, please set KERNELPATH) endif export KERNELPATH endif UNAME:=$(shell uname -r) LINUX26=2.6 LINUX_VERSION:=$(findstring $(LINUX26),$(UNAME)) REVISION:= $(shell if [ -d .svn ]; then \ if which svn > /dev/null; then \ svn info | grep "Rev:" | sed -e '1p' -n | awk '{print $$4}'; \ else \ echo "[unknown]"; \ fi ; \ else \ if [ -d ~/.svk ]; then \ if which svk > /dev/null; then \ echo $$(svk info | grep "Mirrored From" | awk '{print $$5}'); \ else \ echo "[unknown]"; \ fi; \ fi; \ fi) include $(PWD)/Makefile.kbuild ifneq ($(LINUX_VERSION),$(LINUX26)) TARGET:=batgat INCLUDE:=-I/lib/modules/$(UNAME)/build/include -I/usr/src/kernel-headers-$(UNAME)/include EXTRA_CFLAGS+=-D__KERNEL__ -DMODULE -O2 -Wall $(INCLUDE) CC:=gcc endif ifeq ($(LINUX_VERSION),$(LINUX26)) all: $(MAKE) -C $(KERNELPATH) REVISION=$(REVISION) M=$(PWD) PWD=$(PWD) modules clean: $(MAKE) -C $(KERNELPATH) M=$(PWD) PWD=$(PWD) clean else clean: rm -f *.o *~ endif batman-0.3.2/linux/modules/Makefile.kbuild0000666000000000000000000000051511007074241015365 0ustar ifeq ($(MAKING_MODULES),1) -include $(TOPDIR)/Rules.make endif LINUX26:=2.6 EXTRA_CFLAGS +=-DREVISION_VERSION=\"\ rv$(REVISION)\" ifeq ($(strip $(findstring $(LINUX26),$(LINUX_VERSION))),$(LINUX26)) obj-m += batgat.o batgat-objs := gateway.o hash.o else modules: batgat.o batgat.o: gateway24.o hash.o $(LD) -r $^ -o $@ endif batman-0.3.2/linux/modules/mod_batman.c0000666000000000000000000002423311133202550014720 0ustar /* * Copyright (C) 2006-2009 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 * */ /* Kernel Programming */ #define LINUX #define SUCCESS 0 #define IOCGETNWDEV 1 #define DRIVER_AUTHOR "Marek Lindner " #define DRIVER_DESC "B.A.T.M.A.N. performance accelerator" #define DRIVER_DEVICE "batman" #include /* needed by all modules */ #include /* LINUX_VERSION_CODE */ #include /* KERN_ALERT */ #include /* struct inode */ #include /* sock_create(), sock_release() */ #include /* SOCK_RAW */ #include /* IPPROTO_RAW */ #include /* SOCK_RAW */ #include /* iphdr */ #include /* udphdr */ #include /* get_unused_fd() */ #include /* fsnotify_open() */ #include /* sys_close() */ #include /* schedule_timeout() */ #include /* get_user() */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) #include #else #include "compat26.h" static struct class *batman_class; #endif static int device_open( struct inode *, struct file * ); static int device_release( struct inode *, struct file * ); static int device_ioctl( struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg ); static ssize_t device_write( struct file *, const char *, size_t, loff_t * ); struct orig_packet { struct iphdr ip; struct udphdr udp; } __attribute__((packed)); struct minor { int minor_num; int in_use; struct class *minor_class; struct socket *raw_sock; struct kiocb kiocb; struct sock_iocb siocb; struct msghdr msg; struct iovec iov; struct sockaddr_in addr_out; }; static struct file_operations fops = { .open = device_open, .release = device_release, .write = device_write, .ioctl = device_ioctl, }; static int Major; /* Major number assigned to our device driver */ struct minor *minor_array[256]; /* minor numbers for device users */ int init_module( void ) { int i; /* register our device - kernel assigns a free major number */ if ( ( Major = register_chrdev( 0, DRIVER_DEVICE, &fops ) ) < 0 ) { printk( "B.A.T.M.A.N.: Registering the character device failed with %d\n", Major ); return Major; } #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) if ( devfs_mk_cdev( MKDEV( Major, 0 ), S_IFCHR | S_IRUGO | S_IWUGO, "batman", 0 ) ) printk( "B.A.T.M.A.N.: Could not create /dev/batman \n" ); #else batman_class = class_create( THIS_MODULE, "batman" ); if ( IS_ERR(batman_class) ) printk( "B.A.T.M.A.N.: Could not register class 'batman' \n" ); else device_create_drvdata( batman_class, NULL, MKDEV( Major, 0 ), NULL, "batman" ); #endif for ( i = 0; i < 255; i++ ) { minor_array[i] = NULL; } printk( "B.A.T.M.A.N.: I was assigned major number %d. To talk to\n", Major ); printk( "B.A.T.M.A.N.: the driver, create a dev file with 'mknod /dev/batman c %d 0'.\n", Major ); printk( "B.A.T.M.A.N.: Remove the device file and module when done.\n" ); return SUCCESS; } void cleanup_module( void ) { #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) devfs_remove( "batman", 0 ); #else device_destroy_drvdata( batman_class, MKDEV( Major, 0 ) ); class_destroy( batman_class ); #endif /* Unregister the device */ int ret = unregister_chrdev( Major, DRIVER_DEVICE ); if ( ret < 0 ) printk( "B.A.T.M.A.N.: Unregistering the character device failed with %d\n", ret ); printk( "B.A.T.M.A.N.: Unload complete\n" ); } static int device_open( struct inode *inode, struct file *file ) { int minor_num, retval; struct minor *minor = NULL; if ( iminor( inode ) == 0 ) { #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) MOD_INC_USE_COUNT; #else try_module_get(THIS_MODULE); #endif } else { minor_num = iminor( inode ); minor = minor_array[minor_num]; if ( minor == NULL ) { printk( "B.A.T.M.A.N.: open() only allowed on /dev/batman: minor number not registered \n" ); return -EINVAL; } if ( minor->in_use > 0 ) { printk( "B.A.T.M.A.N.: open() only allowed on /dev/batman: minor number already in use \n" ); return -EPERM; } if ( ( retval = sock_create_kern( PF_INET, SOCK_RAW, IPPROTO_RAW, &minor->raw_sock ) ) < 0 ) { printk( "B.A.T.M.A.N.: Can't create raw socket: %i", retval ); return retval; } /* Enable broadcast */ sock_valbool_flag( minor->raw_sock->sk, SOCK_BROADCAST, 1 ); init_sync_kiocb( &minor->kiocb, NULL ); minor->kiocb.private = &minor->siocb; minor->siocb.sock = minor->raw_sock; minor->siocb.scm = NULL; minor->siocb.msg = &minor->msg; minor->addr_out.sin_family = AF_INET; minor->msg.msg_iov = &minor->iov; minor->msg.msg_iovlen = 1; minor->msg.msg_flags = MSG_NOSIGNAL | MSG_DONTWAIT; minor->msg.msg_name = &minor->addr_out; minor->msg.msg_namelen = sizeof(minor->addr_out); minor->msg.msg_control = NULL; minor->msg.msg_controllen = 0; minor->in_use++; } return SUCCESS; } static int device_release( struct inode *inode, struct file *file ) { int minor_num; struct minor *minor = NULL; if ( ( minor_num = iminor( inode ) ) > 0 ) { minor = minor_array[minor_num]; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) devfs_remove( "batman", minor_num ); #else device_destroy(minor->minor_class, MKDEV(Major, minor_num)); class_destroy( minor->minor_class ); #endif sock_release( minor->raw_sock ); kfree( minor ); minor_array[minor_num] = NULL; } /* decrement usage count */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) MOD_DEC_USE_COUNT; #else module_put(THIS_MODULE); #endif return SUCCESS; } static ssize_t device_write( struct file *file, const char *buff, size_t len, loff_t *off ) { int minor_num; struct minor *minor = NULL; if ( len < sizeof(struct orig_packet) + 10 ) { printk( "B.A.T.M.A.N.: dropping data - packet too small (%i)\n", len ); return -EINVAL; } if ( ( minor_num = iminor( file->f_dentry->d_inode ) ) == 0 ) { printk( "B.A.T.M.A.N.: write() not allowed on /dev/batman \n" ); return -EPERM; } if ( !access_ok( VERIFY_READ, buff, sizeof(struct orig_packet) ) ) return -EFAULT; minor = minor_array[minor_num]; if ( minor == NULL ) { printk( "B.A.T.M.A.N.: write() - minor number not registered: %i \n", minor_num ); return -EINVAL; } minor->iov.iov_base = buff; minor->iov.iov_len = len; __copy_from_user( &minor->addr_out.sin_port, &((struct orig_packet *)buff)->udp.dest, sizeof(minor->addr_out.sin_port) ); __copy_from_user( &minor->addr_out.sin_addr.s_addr, &((struct orig_packet *)buff)->ip.daddr, sizeof(minor->addr_out.sin_addr.s_addr) ); minor->siocb.size = len; return minor->raw_sock->ops->sendmsg( &minor->kiocb, minor->raw_sock, &minor->msg, len ); } static int device_ioctl( struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg ) { int minor_num, fd; char filename[100]; struct minor *minor = NULL; switch ( cmd ) { case IOCGETNWDEV: for ( minor_num = 1; minor_num < 255; minor_num++ ) { if ( minor_array[minor_num] == NULL ) { minor = kmalloc( sizeof(struct minor), GFP_KERNEL ); if ( !minor ) return -ENOMEM; memset( minor, 0, sizeof(struct minor) ); minor_array[minor_num] = minor; break; } } if ( minor == NULL ) { printk( "B.A.T.M.A.N.: Maximum number of open batman instances reached \n" ); return -EMFILE; } #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) if ( devfs_mk_cdev( MKDEV( Major, minor_num ), S_IFCHR | S_IRUGO | S_IWUGO, "batman%d", minor_num ) ) { printk( "B.A.T.M.A.N.: Could not create /dev/batman%d \n", minor_num ); #else sprintf( filename, "batman%d", minor_num ); minor->minor_class = class_create( THIS_MODULE, filename ); if ( IS_ERR(minor->minor_class) ) printk( "B.A.T.M.A.N.: Could not register class '%s' \n", filename ); else device_create_drvdata( minor->minor_class, NULL, MKDEV( Major, minor_num ), NULL, "batman%d", minor_num ); #endif /* let udev create the device file */ set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(100); sprintf( filename, "/dev/batman%d", minor_num ); fd = get_unused_fd(); if ( fd >= 0 ) { struct file *f = filp_open( filename, O_WRONLY, 0660 ); if ( IS_ERR(f) ) { put_unused_fd(fd); fd = PTR_ERR(f); printk( "B.A.T.M.A.N.: Could not open %s: %i \n", filename, fd ); #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) devfs_remove( "batman", minor_num ); #else device_destroy( minor->minor_class, MKDEV(Major, minor_num )); class_destroy( minor->minor_class ); #endif kfree( minor ); minor_array[minor_num] = NULL; return fd; } else { fsnotify_open( f->f_dentry ); fd_install( fd, f ); } } /* increment usage count */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) MOD_INC_USE_COUNT; #else try_module_get(THIS_MODULE); #endif return fd; break; default: if ( ( minor_num = iminor( inode ) ) == 0 ) { printk( "B.A.T.M.A.N.: ioctl( SO_BINDTODEVICE ) not allowed on /dev/batman \n" ); return -EPERM; } minor = minor_array[minor_num]; if ( minor == NULL ) { printk( "B.A.T.M.A.N.: ioctl( SO_BINDTODEVICE ) - minor number not registered: %i \n", minor_num ); return -EINVAL; } return sock_setsockopt( minor->raw_sock, SOL_SOCKET, SO_BINDTODEVICE, (void __user *)arg, cmd ); } } MODULE_LICENSE("GPL"); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_SUPPORTED_DEVICE(DRIVER_DEVICE); batman-0.3.2/linux/route.c0000666000000000000000000005431411211455712012317 0ustar /* * Copyright (C) 2006-2009 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 * */ #define _GNU_SOURCE #include #include /* inet_ntop() */ #include #include /* close() */ #include /* ifr_if, ifr_tun */ #include #include #include #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 * ***/ #if NO_POLICY_ROUTING #include void add_del_route(uint32_t dest, uint8_t netmask, uint32_t router, uint32_t src_ip, int32_t ifi, 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), 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, 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, 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 batman-0.3.2/linux/tun.c0000666000000000000000000001726411203342534011770 0ustar /* * Copyright (C) 2006-2009 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 /* iph */ #include /* TUNSETPERSIST, ... */ #include /* ifr_if, ifr_tun */ #include #include #include /* system() */ #include /* WEXITSTATUS */ #include "../os.h" #include "../batman.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_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" int run_cmd(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"); } void exec_iptables_rule(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[100]; sprintf(cmd, IPTABLES_ADD_MASQ, dev); exec_iptables_rule(cmd, ROUTE_ADD); } void del_nat_rule(char *dev) { char cmd[100]; sprintf(cmd, IPTABLES_DEL_MASQ, 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; } batman-0.3.2/list-batman.c0000666000000000000000000000552711133202550012230 0ustar /* * Copyright (C) 2006-2009 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; } batman-0.3.2/list-batman.h0000666000000000000000000000562111133202550012230 0ustar /* * Copyright (C) 2006-2009 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 /* offsetof() */ #ifndef _LINUX_LIST_H #define _LINUX_LIST_H /* * XXX: Resolve conflict between this file and on BSD systems. */ #ifdef LIST_HEAD #undef LIST_HEAD #endif /* * 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) #endif batman-0.3.2/Makefile0000666000000000000000000000737511203342534011321 0ustar # # Copyright (C) 2006-2009 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 # ifneq ($(findstring $(MAKEFLAGS),s),s) ifndef V Q_CC = @echo ' ' CC $@; Q_LD = @echo ' ' LD $@; export Q_CC export Q_LD endif endif # activate this variable to deactivate policy routing for backward compatibility #NO_POLICY_ROUTING = -DNO_POLICY_ROUTING CC = gcc CFLAGS += -pedantic -Wall -W -O1 -g3 -std=gnu99 EXTRA_CFLAGS = -DDEBUG_MALLOC -DMEMORY_USAGE -DPROFILE_DATA $(NO_POLICY_ROUTING) -DREVISION_VERSION=$(REVISION_VERSION) LDFLAGS += -lpthread SBINDIR = $(INSTALL_PREFIX)/usr/sbin UNAME= $(shell uname) POSIX_C= posix/init.c posix/posix.c posix/tunnel.c posix/unix_socket.c BSD_C= bsd/route.c bsd/tun.c bsd/kernel.c bsd/compat.c ifeq ($(UNAME),Linux) OS_C= linux/route.c linux/tun.c linux/kernel.c $(POSIX_C) endif ifeq ($(UNAME),Darwin) OS_C= $(BSD_C) $(POSIX_C) endif ifeq ($(UNAME),GNU/kFreeBSD) OS_C= $(BSD_C) $(POSIX_C) LDFLAGS+= -lfreebsd -lbsd endif ifeq ($(UNAME),FreeBSD) OS_C= $(BSD_C) $(POSIX_C) endif ifeq ($(UNAME),OpenBSD) OS_C= $(BSD_C) $(POSIX_C) endif LOG_BRANCH= trunk/batman SRC_FILES= "\(\.c\)\|\(\.h\)\|\(Makefile\)\|\(INSTALL\)\|\(LIESMICH\)\|\(README\)\|\(THANKS\)\|\(TRASH\)\|\(Doxyfile\)\|\(./posix\)\|\(./linux\)\|\(./bsd\)\|\(./man\)\|\(./doc\)" SRC_C= batman.c originator.c schedule.c list-batman.c allocate.c bitarray.c hash.c profile.c ring_buffer.c hna.c $(OS_C) SRC_H= batman.h originator.h schedule.h list-batman.h os.h allocate.h bitarray.h hash.h profile.h vis-types.h ring_buffer.h hna.h SRC_O= $(SRC_C:.c=.o) PACKAGE_NAME= batmand BINARY_NAME= batmand SOURCE_VERSION_HEADER= batman.h REVISION:= $(shell if [ -d .svn ]; then svn info | grep "Rev:" | sed -e '1p' -n | awk '{print $$4}'; else if [ -d ~/.svk ]; then echo $$(svk info | grep "Mirrored From" | awk '{print $$5}'); fi; fi) REVISION_VERSION=\"\ rv$(REVISION)\" BAT_VERSION= $(shell grep "^\#define SOURCE_VERSION " $(SOURCE_VERSION_HEADER) | sed -e '1p' -n | awk -F '"' '{print $$2}' | awk '{print $$1}') FILE_NAME= $(PACKAGE_NAME)_$(BAT_VERSION)-rv$(REVISION)_$@ NUM_CPUS = $(shell NUM_CPUS=`cat /proc/cpuinfo | grep -v 'model name' | grep processor | tail -1 | awk -F' ' '{print $$3}'`;echo `expr $$NUM_CPUS + 1`) all: $(MAKE) -j $(NUM_CPUS) $(BINARY_NAME) $(BINARY_NAME): $(SRC_O) $(SRC_H) Makefile $(Q_LD)$(CC) -o $@ $(SRC_O) $(LDFLAGS) .c.o: $(Q_CC)$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -MD -c $< -o $@ -include $(SRC_C:.c=.d) sources: mkdir -p $(FILE_NAME) for i in $$( find . | grep $(SRC_FILES) | grep -v "\.svn" ); do [ -d $$i ] && mkdir -p $(FILE_NAME)/$$i ; [ -f $$i ] && cp -Lvp $$i $(FILE_NAME)/$$i ;done wget -O changelog.html http://www.open-mesh.net/log/$(LOG_BRANCH)/ html2text -o changelog.txt -nobs -ascii changelog.html awk '/View revision/,/10\/01\/06 20:23:03/' changelog.txt > $(FILE_NAME)/CHANGELOG for i in $$( find man | grep -v "\.svn" ); do [ -f $$i ] && groff -man -Thtml $$i > $(FILE_NAME)/$$i.html ;done tar czvf $(FILE_NAME).tgz $(FILE_NAME) clean: rm -f $(BINARY_NAME) *.o posix/*.o linux/*.o bsd/*.o rm -f `find . -name '*.d' -print` clean-long: rm -rf $(PACKAGE_NAME)_* install: mkdir -p $(SBINDIR) install -m 0755 $(BINARY_NAME) $(SBINDIR) batman-0.3.2/man/batmand.80000666000000000000000000002007211202521464012120 0ustar .\" 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) .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 http://www.open\-mesh.net/ 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 seperate 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 orginator 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 modus" 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 modus". The deamon 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 watching the uplinks throughput and the link quality. 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 \-\-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. batman-0.3.2/originator.c0000666000000000000000000004251011207175617012202 0ustar /* * Copyright (C) 2006-2009 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 "os.h" #include "batman.h" #include "originator.h" #include "hna.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 http://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, *best_neigh_node = NULL; uint8_t max_bcast_own = 0, max_tq = 0; 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; } else { if ( !is_duplicate ) { 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 we got have a better tq value via this neighbour or same tq value if it is currently our best neighbour (to avoid route flipping) */ if ( ( tmp_neigh_node->tq_avg > max_tq ) || ( ( tmp_neigh_node->tq_avg == max_tq ) && ( tmp_neigh_node->orig_node->bcast_own_sum[if_incoming->if_num] > max_bcast_own ) ) || ( ( orig_node->router == tmp_neigh_node ) && ( tmp_neigh_node->tq_avg == max_tq ) ) ) { max_tq = tmp_neigh_node->tq_avg; max_bcast_own = tmp_neigh_node->orig_node->bcast_own_sum[if_incoming->if_num]; best_neigh_node = tmp_neigh_node; } } } if ( neigh_node == NULL ) { 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); /* is_new_seqno = bit_get_packet( neigh_node->seq_bits, in->seqno - orig_node->last_seqno, 1 ); is_new_seqno = ! get_bit_status( neigh_node->real_bits, orig_node->last_real_seqno, in->seqno ); */ if ( !is_duplicate ) { orig_node->last_ttl = in->ttl; neigh_node->last_ttl = in->ttl; } if ( ( neigh_node->tq_avg > max_tq ) || ( ( neigh_node->tq_avg == max_tq ) && ( neigh_node->orig_node->bcast_own_sum[if_incoming->if_num] > max_bcast_own ) ) || ( ( orig_node->router == neigh_node ) && ( neigh_node->tq_avg == max_tq ) ) ) { best_neigh_node = neigh_node; } /* update routing table and check for changed hna announcements */ update_routes( orig_node, best_neigh_node, 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%s, MainIF/IP: %s/%s, UT: %id%2ih%2im] \n", "Gateway", "#", TQ_MAX_VALUE, "Nexthop", "outgoingIF", SOURCE_VERSION, (strlen(REVISION_VERSION) > 3 ? REVISION_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%s, MainIF/IP: %s/%s, UT: %id%2ih%2im] \n", "Originator", "#", TQ_MAX_VALUE, "Nexthop", "outgoingIF", "Potential nexthops", SOURCE_VERSION, (strlen(REVISION_VERSION) > 3 ? REVISION_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" ); } } batman-0.3.2/originator.h0000666000000000000000000000251211133202550012166 0ustar /* * Copyright (C) 2006-2009 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 "batman.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); batman-0.3.2/os.h0000666000000000000000000000673411207275153010457 0ustar /* * Copyright (C) 2006-2009 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 _BATMAN_OS_H #define _BATMAN_OS_H #include "batman.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, 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, 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, char* dev ); int32_t get_rp_filter( char *dev ); void set_send_redirects( int32_t state, char* dev ); int32_t get_send_redirects( char *dev ); void set_forwarding( int32_t state ); int32_t get_forwarding( void ); int8_t bind_to_iface( int32_t sock, char *dev ); int32_t use_gateway_module(void); 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, char *format, ... ); #endif batman-0.3.2/posix/init.c0000666000000000000000000007151511207741250012131 0ustar /* * Copyright (C) 2006-2009 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 "../os.h" #include "../batman.h" #include "../hna.h" #define IOCSETDEV 1 int8_t stop; static int my_daemon(void) { int fd; switch( fork() ) { case -1: return -1; case 0: break; default: exit(EXIT_SUCCESS); } if ( setsid() == -1 ) return(-1); /* Make certain we are not a session leader, or else we might reacquire a controlling terminal */ if ( fork() ) exit(EXIT_SUCCESS); chdir( "/" ); if ( ( fd = open(_PATH_DEVNULL, O_RDWR, 0) ) != -1 ) { dup2(fd, STDIN_FILENO); dup2(fd, STDOUT_FILENO); dup2(fd, STDERR_FILENO); if ( fd > 2 ) close(fd); } return 0; } 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'}, {0, 0, 0, 0} }; memset( &tmp_ip_holder, 0, sizeof (struct in_addr) ); stop = 0; prog_name = argv[0]; if ( strstr( SOURCE_VERSION, "-" ) != NULL ) printf( "WARNING: You are using the unstable batman branch. If you are interested in *using* batman get the latest stable release !\n" ); while ( ( optchar = getopt_long( argc, argv, "a:A:bcd:hHio:g:p:r:s:vV", 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%s (compatibility version %i)\n", SOURCE_VERSION, (strlen(REVISION_VERSION) > 3 ? REVISION_VERSION : ""), COMPAT_VERSION); exit(EXIT_SUCCESS); case 'V': print_animation(); printf("\x1B[0;0HB.A.T.M.A.N. %s%s (compatibility version %i)\n", SOURCE_VERSION, (strlen(REVISION_VERSION) > 3 ? REVISION_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 '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 (my_daemon() < 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%s (compatibility version %i)\n", SOURCE_VERSION, (strlen(REVISION_VERSION) > 3 ? REVISION_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 ) system( "clear" ); } 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, err, skfd; struct ifreq ifr; struct sockaddr_in sin; struct batgat_ioc_args ioc; struct batman_if *batman_if = (struct batman_if *)if_list.next; if ((batman_if->udp_tunnel_sock = use_gateway_module()) < 0) { 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 ); } else { ioc.universal = strlen(batman_if->dev); ioc.exists = 0; strncpy(ioc.dev_name, batman_if->dev, IFNAMSIZ - 1); if (ioctl(batman_if->udp_tunnel_sock, IOCSETDEV, &ioc) < 0) { debug_output(0, "Error - can't add device %s: %s\n", batman_if->dev,strerror(errno)); batman_if->dev = NULL; restore_defaults(); exit(EXIT_FAILURE); } /* set ip address of gate device */ if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { debug_output( 0, "Error - can't create socket to gate\n" ); restore_defaults(); exit( EXIT_FAILURE ); } memset(&ifr, 0, sizeof(ifr)); memset(&sin, 0, sizeof(struct sockaddr)); strncpy(ifr.ifr_name, ioc.dev_name, IFNAMSIZ - 1); sin.sin_family = AF_INET; sin.sin_addr.s_addr = ioc.universal; memcpy(&ifr.ifr_addr, &sin, sizeof(struct sockaddr)); if ((err = ioctl(skfd, SIOCSIFADDR, &ifr)) < 0) { debug_output(0, "Error - can't set IFADDR %s: %s\n", ioc.dev_name, strerror(err)); close(skfd); restore_defaults(); exit( EXIT_FAILURE ); } memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, ioc.dev_name, IFNAMSIZ - 1); if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0) { debug_output(0, "Error - can't get IFFLAGS for %s: %s\n", ioc.dev_name, strerror(errno)); close(skfd); restore_defaults(); exit( EXIT_FAILURE ); } strncpy(ifr.ifr_name, ioc.dev_name, IFNAMSIZ - 1); ifr.ifr_flags |= (IFF_UP | IFF_RUNNING); if (ioctl(skfd, SIOCSIFFLAGS, &ifr) < 0) { debug_output(0, "Error - can't set IFFLAGS for %s: %s\n", ioc.dev_name, strerror(errno)); close(skfd); restore_defaults(); exit( EXIT_FAILURE ); } close(skfd); if (!ioc.exists) add_del_route(ioc.universal, 16, 0, 0, ioc.ifindex, ioc.dev_name, 254, ROUTE_TYPE_UNICAST, ROUTE_ADD); } } batman-0.3.2/posix/posix.c0000666000000000000000000003176211206006276012331 0ustar /* * Copyright (C) 2006-2009 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 "../os.h" #include "../batman.h" #include "../hna.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 */ #define IOCREMDEV 2 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, 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 ) { system( "clear" ); 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; struct batgat_ioc_args args; /* TODO: unregister from kernel module per ioctl */ if (batman_if->udp_tunnel_sock > 0) { if (batman_if->listen_thread_id != 0) { pthread_join(batman_if->listen_thread_id, NULL); } else { if (batman_if->dev != NULL) { strncpy(args.dev_name, batman_if->dev, IFNAMSIZ - 1); args.universal = strlen(batman_if->dev); if (ioctl(batman_if->udp_tunnel_sock, IOCREMDEV, &args) < 0) debug_output(0, "Error - can't remove device %s from kernel module : %s\n", batman_if->dev,strerror(errno)); } } 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; } batman-0.3.2/posix/tunnel.c0000666000000000000000000005606011211455712012471 0ustar /* * Copyright (C) 2006-2009 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 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__Darwin__) #include #endif #include #include /* open(), O_RDWR */ #include "../os.h" #include "../batman.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) { #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__Darwin__) return ((struct ip *)(buff + 1))->ip_p; #else return ((struct iphdr *)(buff + 1))->protocol; #endif } static uint32_t get_tunneled_sender_ip(const unsigned char *buff) { #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__Darwin__) return ((struct ip *)(buff + 1))->ip_src; #else return ((struct iphdr *)(buff + 1))->saddr; #endif } static uint16_t get_tunneled_udpdest(const unsigned char *buff) { #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__Darwin__) return ((struct udphdr *)(buff + 1 + ((struct ip *)(buff + 1))->ip_hl*4))->uh_dport; #else return ((struct udphdr *)(buff + 1 + ((struct iphdr *)(buff + 1))->ihl*4))->dest; #endif } 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 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 http://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; } batman-0.3.2/posix/unix_socket.c0000666000000000000000000004250711206007016013512 0ustar /* * Copyright (C) 2006-2009 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 * */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include "../os.h" #include "../batman.h" #include "../hna.h" void debug_output(int8_t debug_prio, 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)) system("clear"); 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: %i\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; } batman-0.3.2/profile.c0000666000000000000000000000366011133202550011451 0ustar /* * Copyright (C) 2006-2009 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 "os.h" #include "batman.h" #if defined PROFILE_DATA static struct prof_container prof_container[PROF_COUNT]; void prof_init(int32_t index, 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 = %''10i, 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 void prof_init( int32_t index, char *name ) { } void prof_start( int32_t index ) { } void prof_stop( int32_t index ) { } void prof_print(void) { } #endif batman-0.3.2/profile.h0000666000000000000000000000232511133202550011453 0ustar /* * Copyright (C) 2006-2009 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 * */ 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; char *name; uint64_t calls; }; void prof_init(int32_t index, char *name); void prof_start(int32_t index); void prof_stop(int32_t index); void prof_print(void); batman-0.3.2/README0000666000000000000000000000560711135444036010541 0ustar 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 batman-0.3.2/ring_buffer.c0000666000000000000000000000231211133202550012272 0ustar /* * Copyright (C) 2007-2009 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 "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); } batman-0.3.2/ring_buffer.h0000666000000000000000000000161611133202550012305 0ustar /* * Copyright (C) 2007-2009 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 "batman.h" void ring_buffer_set(uint8_t tq_recv[], uint8_t *tq_index, uint8_t value); uint8_t ring_buffer_avg(uint8_t tq_recv[]); batman-0.3.2/schedule.c0000666000000000000000000003017211212005456011607 0ustar /* * Copyright (C) 2006-2009 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 "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 compability * -> 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; 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); /** * if the outgoing interface is a wifi interface and equal to the incoming interface * add extra penalty (own packets are to be ignored) */ if ((batman_if->wifi_if) && (!forw_node->own) && (forw_node->if_incoming == batman_if)) bat_packet->tq = (bat_packet->tq * (TQ_MAX_VALUE - (2 * hop_penalty))) / (TQ_MAX_VALUE); 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) schedule_own_packet(forw_node->if_incoming); debugFree(forw_node->pack_buff, 1501); debugFree(forw_node, 1502); } prof_stop(PROF_send_outstanding_packets); } batman-0.3.2/schedule.h0000666000000000000000000000205011133202550011602 0ustar /* * Copyright (C) 2006-2009 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 * */ 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); batman-0.3.2/THANKS0000666000000000000000000000106711135306674010575 0ustar We 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 (siwu-at-hrz.tu-chemnitz.de) Andreas Langer (a.langer-at-q-dsl.de) Sven Eckelmann (sven.eckelmann-at-gmx.de) Antoine van Gelder (antoine-at-7degrees.co.za) batman-0.3.2/vis-types.h0000666000000000000000000000210511133202550011752 0ustar /* * Copyright (C) 2006-2009 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 #define VIS_COMPAT_VERSION 23 #define DATA_TYPE_NEIGH 1 #define DATA_TYPE_SEC_IF 2 #define DATA_TYPE_HNA 3 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));