The following commit has been merged in the master branch: commit 4e94d2c0af33afd40f44084a9e50264c7331341f Author: Axel Neumann axel@open-mesh.net Date: Sat Dec 18 16:27:29 2010 +0100
initial version BMX6-0.1-alpha (compatibility=12 code=cv2)
* Support for IPv4 and IPv6 * Reduced overhead due to a statefull-compression technique using (globally) unambiguous SHA1 hashes and (locally) Individual IDentifiers (IIDs) * Simultaneous usage of different node-specific metrics (TQ, RTQ, ETX,...)
diff --git a/Makefile b/Makefile index 7ec0196..86ca784 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,5 @@ -# Copyright (C) 2010 BMX contributors: +# Copyright (c) 2010 BMX protocol 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. @@ -13,96 +14,73 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA
-REVISION_VERSION = $(shell if [ -d .svn ]; then which svn > /dev/null && which sed > /dev/null && which awk > /dev/null && { svn info | grep "Rev:" | sed -e '1p' -n | awk '{print $$4}';};else echo 0; fi )
-##CFLAGS ?= -I./lua-5.1.4/src -I./cyassl-1.4.0/include -O0 -ggdb3 -##LDFLAGS ?= -L./lua-5.1.4/src -L./cyassl-1.4.0/src/.libs
-#CFLAGS ?= -I$(shell pwd)/cyassl-1.4.0/ctaocrypt/include -DHAVE_CONFIG_H -#LDFLAGS ?= -L./cyassl-1.4.0/src/.libs + CFLAGS += -pedantic -Wall -W -Wno-unused-parameter -Os -g3 -std=gnu99 -I./ -DHAVE_CONFIG_H
+# optinal defines: +# CFLAGS += -static +# CFLAGS += -pg # "-pg" with openWrt toolchain results in "gcrt1.o: No such file" ?!
-CFLAGS += -pedantic -Wall -W -Wno-unused-parameter -Os -g3 -std=gnu99 -I./ \ - -DHAVE_CONFIG_H -DREVISION_VERSION=$(REVISION_VERSION) -DDEBUG_MALLOC -DMEMORY_USAGE +# paranoid defines (helps bug hunting during development): +# CFLAGS += -DPROFILING -DEXTREME_PARANOIA -DEXIT_ON_ERROR
-LDFLAGS += -Wl,-export-dynamic -ldl -g3 -lm +# Some test cases: +# CFLAGS += -DTEST_LINK_ID_COLLISION_DETECTION +# CFLAGS += -DTEST_DEBUG # (testing syntax of __VA_ARGS__ dbg...() macros) +# CFLAGS += -DAVL_DEBUG -DAVL_TEST
-#-lcyassl -#LDFLAGS += -shared -lssl -lcrypto -# -static -# -pg +# optional defines (you may disable these features if you dont need it): +# CFLAGS += -DNO_DEBUG_ALL +# CFLAGS += -DLESS_OPTIONS +# CFLAGS += -DNO_TRAFFIC_DUMP +# CFLAGS += -DNO_DYN_PLUGIN +# CFLAGS += -DNO_TRACE_FUNCTION_CALLS +# CFLAGS += -DNO_DEBU_GALL +# CFLAGS += -DNO_DEBUG_MALLOC +# CFLAGS += -DNO_MEMORY_USAGE
+# experimental or advanced defines (please dont touch): +# CFLAGS += -DNO_ASSERTIONS # (disable syntax error checking and error-code creation!) +# CFLAGS += -DEXTREME_PARANOIA # (check difficult syntax errors) +# CFLAGS += -DEXIT_ON_ERROR # (exit and return code due to unusual behavior) +# CFLAGS += -DTEST_DEBUG +# CFLAGS += -DWITH_UNUSED # (includes yet unused stuff and buggy stuff) +# CFLAGS += -DEXPORT_UNUSED # (export only locally used stuff) +# CFLAGS += -DPROFILING # (no static functions -> better profiling and cores) +# CFLAGS += -DNO_DEPRECATED # (for backward compatibility)
-#CFLAGS += -DTESTDEBUG -#CFLAGS += -DAVL_DEBUG -DAVL_TEST -#CFLAGS += -DPROFILING -DEXTREME_PARANOIA -D
-#EXTRA_CFLAGS += -#EXTRA_LDFLAGS +=
-# Recommended defines and approximate binary sizes with gcc-x86 -# -static -# -pedantic -Wall -W -Wno-unused-parameter -O1 -g3 -std=gnu99 -# -pg # "-pg" with openWrt toolchain results in "gcrt1.o: No such file" ?! -#
-# compared to -O1 stripped: -# -Os - ~29k +#EXTRA_CFLAGS += +#EXTRA_LDFLAGS +=
-# -DDEBUG_MALLOC + ~0k -# -DMEMORY_USAGE + ~1k +LDFLAGS += -g3
-# optional defines (you may disable these features if you dont need it): -# -DNOTRAILER - ~3K -# -DNODEBUGALL - ~13k -# -DLESS_OPTIONS - ~8K -# -# -DNOTUNNEL (only affects this node) - ~23k -# -DNOSRV (only affects this node) - ~3k -# -DNOVIS (only affects this node) - ~2k +LDFLAGS += $(shell echo "$(CFLAGS) $(EXTRA_CFLAGS)" | grep -q "DNO_DYNPLUGIN" || echo "-Wl,-export-dynamic -ldl" )
-# -DNODEPRECATED (for backward compatibility) - ~2k
-# experimental or advanced defines (please dont touch): -# -DNOHNA (affects all nodes in network) - ~6k -# -DNO_PARANOIA (makes bug-hunting impossible) - ~2k -# -DEXTREME_PARANOIA -# -DEXTDEBUG (this eats your cpu) + ~0k -# -DTESTDEBUG (testing syntax of __VA_ARGS__ dbg...() macros) -# -DWITHUNUSED (includes yet unused stuff) -# -DPROFILING (no static functions)
SBINDIR = $(INSTALL_PREFIX)/usr/sbin
-LOG_BRANCH= trunk/bmx2 - SRC_FILES= "(.c)|(.h)|(Makefile)|(INSTALL)|(LIESMICH)|(README)|(THANKS)|(./posix)|(./linux)|(./man)|(./doc)"
-SRC_C= bmx.c msg.c plugin.c list.c allocate.c avl.c iid.c hna.c control.c schedule.c route.c cyassl/sha.c -SRC_H= bmx.h msg.h plugin.h list.h allocate.h avl.h iid.h hna.h control.h schedule.h route.h cyassl/sha.h +SRC_C = bmx.c msg.c metrics.c tools.c plugin.c list.c allocate.c avl.c iid.c hna.c control.c schedule.c ip.c cyassl/sha.c cyassl/random.c cyassl/arc4.c +SRC_H = bmx.h msg.h metrics.h tools.h plugin.h list.h allocate.h avl.h iid.h hna.h control.h schedule.h ip.h cyassl/sha.h cyassl/random.h cyassl/arc4.h + +SRC_C += $(shell echo "$(CFLAGS)" | grep -q "DNO_TRAFFIC_DUMP" || echo dump.c ) +SRC_H += $(shell echo "$(CFLAGS)" | grep -q "DNO_TRAFFIC_DUMP" || echo dump.h ) + OBJS= $(SRC_C:.c=.o)
# #
-PACKAGE_NAME= bmxd -BINARY_NAME= bmxd - - - -SOURCE_VERSION_HEADER= bmx.h - - -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_VERSION)_$@ - -NOW= $(shell date +%Y%m%d%H%M)-$(REVISION_VERSION) - -IPKG_DEPENDS= "kmod-tun" - -SNAPSHOT_DIR= ../bmx-snapshots +PACKAGE_NAME= bmx6 +BINARY_NAME= bmx6
all: @@ -158,10 +136,10 @@ install_all: install install_libs help: # further make targets: # help show this help - # all compile bmxd core only - # libs compile bmx plugins - # build_all compile bmxd and plugins - # strip / strip_libs / strip_all strip bmxd / plugins / all - # install / install_libs / install_all install bmxd / plugins / all - # clean / clean_libs / clean_all clean bmxd / libs / all + # all compile bmx6 core only + # libs compile bmx6 plugins + # build_all compile bmx6 and plugins + # strip / strip_libs / strip_all strip bmx6 / plugins / all + # install / install_libs / install_all install bmx6 / plugins / all + # clean / clean_libs / clean_all clean bmx6 / libs / all
diff --git a/allocate.c b/allocate.c index 35bd499..7e3aae5 100644 --- a/allocate.c +++ b/allocate.c @@ -28,7 +28,8 @@
#define MAGIC_NUMBER 0x12345678
-#if defined DEBUG_MALLOC + +#ifndef NO_DEBUG_MALLOC
struct chunkHeader *chunkList = NULL; @@ -48,7 +49,7 @@ struct chunkTrailer
-#if defined MEMORY_USAGE +#ifdef MEMORY_USAGE
struct memoryUsage *memoryList = NULL;
@@ -61,8 +62,8 @@ struct memoryUsage int32_t tag; };
- -void addMemory( uint32_t length, int32_t tag ) { +void addMemory(uint32_t length, int32_t tag) +{
struct memoryUsage *walker;
@@ -89,8 +90,8 @@ void addMemory( uint32_t length, int32_t tag ) {
}
- -void removeMemory( int32_t tag, int32_t freetag ) { +void removeMemory(int32_t tag, int32_t freetag) +{
struct memoryUsage *walker;
@@ -123,11 +124,8 @@ void removeMemory( int32_t tag, int32_t freetag ) { } }
-#endif - -#if defined MEMORY_USAGE - -void debugMemory( struct ctrl_node *cn ) { +void debugMemory(struct ctrl_node *cn) +{ struct memoryUsage *memoryWalker;
@@ -184,13 +182,12 @@ void checkIntegrity(void) void checkLeak(void) { struct chunkHeader *walker; - - if ( chunkList != NULL ) { - - openlog( "bmx", LOG_PID, LOG_DAEMON ); - + + if (chunkList != NULL) { - for (walker = chunkList; walker != NULL; walker = walker->next) { + openlog( "bmx6", LOG_PID, LOG_DAEMON ); + + for (walker = chunkList; walker != NULL; walker = walker->next) { syslog( LOG_ERR, "Memory leak detected, malloc tag = %d\n", walker->tag ); fprintf( stderr, "Memory leak detected, malloc tag = %d \n", walker->tag ); @@ -231,7 +228,7 @@ void *_debugMalloc(uint32_t length, int32_t tag) { chunkHeader->next = chunkList; chunkList = chunkHeader;
-#if defined MEMORY_USAGE +#ifdef MEMORY_USAGE
addMemory( length, tag );
@@ -240,7 +237,8 @@ void *_debugMalloc(uint32_t length, int32_t tag) { return chunk; }
-void *_debugRealloc(void *memoryParameter, uint32_t length, int32_t tag) { +void *_debugRealloc(void *memoryParameter, uint32_t length, int32_t tag) +{ unsigned char *memory; struct chunkHeader *chunkHeader=NULL; @@ -280,13 +278,14 @@ void *_debugRealloc(void *memoryParameter, uint32_t length, int32_t tag) { copyLength = chunkHeader->length;
memcpy(result, memoryParameter, copyLength); - debugFree(memoryParameter, -300000); + debugFree(memoryParameter, -300280); }
return result; }
-void _debugFree(void *memoryParameter, int tag) { +void _debugFree(void *memoryParameter, int tag) +{ unsigned char *memory; struct chunkHeader *chunkHeader; @@ -339,7 +338,7 @@ void _debugFree(void *memoryParameter, int tag) { cleanup_all( -500082 ); }
-#if defined MEMORY_USAGE +#ifdef MEMORY_USAGE
removeMemory( chunkHeader->tag, tag );
diff --git a/allocate.h b/allocate.h index 9ae36a7..4c5a5df 100644 --- a/allocate.h +++ b/allocate.h @@ -20,13 +20,14 @@
#ifndef _ALLOCATE_H #define _ALLOCATE_H 1 + #include <stdint.h>
-// currently used memory tags: -300000 .. -300228 -#define debugMalloc( l,t ) _debugMalloc( (l), (t) ) -#define debugRealloc( m,l,t ) _debugRealloc( (m), (l), (t) ) -#define debugFree( m,t ) _debugFree( (m), (t) ) +// currently used memory tags: -300000, -300001 .. -300317 +#define debugMalloc( length,tag ) _debugMalloc( (length), (tag) ) +#define debugRealloc( mem,length,tag ) _debugRealloc( (mem), (length), (tag) ) +#define debugFree( mem,tag ) _debugFree( (mem), (tag) ) 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); diff --git a/avl.c b/avl.c index 492d7a4..808fa02 100644 --- a/avl.c +++ b/avl.c @@ -1,6 +1,5 @@ /* - * Copyright (C) 2010 BMX contributors: - * Axel Neumann + * Copyright (c) 2010 Axel Neumann * 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. @@ -17,12 +16,8 @@ */
/* - * avl code inspired by: + * avl code inspired by templates from Julienne Walker at * http://eternallyconfuzzled.com/tuts/datastructures/jsw_tut_avl.aspx - * where Julienne Walker said (web page from 28. 2. 2010 12:55): - * ...Once again, all of the code in this tutorial is in the public domain. - * You can do whatever you want with it, but I assume no responsibility - * for any damages from improper use. ;-) */
@@ -30,9 +25,7 @@ #include <string.h> #include <stdlib.h>
- #include "bmx.h" - #include "avl.h"
@@ -42,7 +35,6 @@ struct avl_node *avl_find( struct avl_tree *tree, void *key ) int cmp;
// Search for a dead path or a matching entry -// while ( an && ( cmp = memcmp( an->key, key, tree->key_size) ) ) while ( an && ( cmp = memcmp( AVL_NODE_KEY( tree, an ), key, tree->key_size) ) ) an = an->link[ cmp < 0 ];
@@ -85,6 +77,16 @@ void * avl_next_item( struct avl_tree *tree, void *key) return an ? an->item : NULL; }
+void *avl_first_item(struct avl_tree *tree) +{ + struct avl_node * an = tree->root; + + while (an && an->link[0]) + an = an->link[0]; + + return an ? an->item : NULL; +} +
struct avl_node *avl_iterate(struct avl_tree *tree, struct avl_node *an ) { @@ -112,6 +114,8 @@ struct avl_node *avl_iterate(struct avl_tree *tree, struct avl_node *an ) return NULL; }
+ + void *avl_iterate_item(struct avl_tree *tree, struct avl_node **an ) {
@@ -139,8 +143,8 @@ void *avl_iterate_item(struct avl_tree *tree, struct avl_node **an ) }
- -static struct avl_node *avl_create_node(void *node, int32_t tag) +STATIC_FUNC +struct avl_node *avl_create_node(void *node, int32_t tag) { struct avl_node *an = debugMalloc(sizeof (struct avl_node), tag);
@@ -150,7 +154,8 @@ static struct avl_node *avl_create_node(void *node, int32_t tag) return an; }
-static struct avl_node *avl_rotate_single(struct avl_node *root, int dir) +STATIC_FUNC +struct avl_node *avl_rotate_single(struct avl_node *root, int dir) { struct avl_node *save; int rlh, rrh, slh; @@ -179,7 +184,8 @@ static struct avl_node *avl_rotate_single(struct avl_node *root, int dir) return save; }
-static struct avl_node *avl_rotate_double(struct avl_node *root, int dir) +STATIC_FUNC +struct avl_node *avl_rotate_double(struct avl_node *root, int dir) { root->link[!dir] = avl_rotate_single(root->link[!dir], !dir);
@@ -189,8 +195,8 @@ static struct avl_node *avl_rotate_double(struct avl_node *root, int dir) return avl_rotate_single(root, dir); }
- -void avl_insert(struct avl_tree *tree, void *node, int32_t tag) { +void avl_insert(struct avl_tree *tree, void *node, int32_t tag) +{
if (tree->root) {
@@ -199,10 +205,9 @@ void avl_insert(struct avl_tree *tree, void *node, int32_t tag) { int upd[AVL_MAX_HEIGHT], top = 0; int done = 0;
- /* Search for an empty link, save the path */ + // Search for an empty link, save the path for (;;) { - /* Push direction and node onto stack */ -// upd[top] = memcmp(it->key, key, tree->key_size) <= 0; + // Push direction and node onto stack */ upd[top] = memcmp(AVL_NODE_KEY(tree, it), AVL_ITEM_KEY(tree, node), tree->key_size) <= 0;
up[top++] = it; @@ -213,13 +218,13 @@ void avl_insert(struct avl_tree *tree, void *node, int32_t tag) { it = it->link[upd[top - 1]]; }
- /* Insert a new node at the bottom of the tree */ + // Insert a new node at the bottom of the tree: it->link[upd[top - 1]] = avl_create_node(node, tag); it->link[upd[top - 1]]->up = it;
paranoia(-500178, (it->link[upd[top - 1]] == NULL));
- /* Walk back up the search path */ + // Walk back up the search path while (--top >= 0 && !done) {
int lh, rh, max; @@ -227,7 +232,7 @@ void avl_insert(struct avl_tree *tree, void *node, int32_t tag) { lh = avl_height(up[top]->link[upd[top]]); rh = avl_height(up[top]->link[!upd[top]]);
- /* Terminate or rebalance as necessary */ + // Terminate or rebalance as necessary: if (lh - rh == 0) done = 1; if (lh - rh >= 2) { @@ -239,7 +244,7 @@ void avl_insert(struct avl_tree *tree, void *node, int32_t tag) { else up[top] = avl_rotate_double(up[top], !upd[top]);
- /* Fix parent */ + // Fix parent: if (top != 0) { up[top - 1]->link[upd[top - 1]] = up[top]; up[top]->up = up[top - 1]; @@ -252,7 +257,7 @@ void avl_insert(struct avl_tree *tree, void *node, int32_t tag) { done = 1; }
- /* Update balance factors */ + // Update balance factors: lh = avl_height(up[top]->link[upd[top]]); rh = avl_height(up[top]->link[!upd[top]]); max = avl_max(lh, rh); @@ -281,7 +286,6 @@ void *avl_remove(struct avl_tree *tree, void *key, int32_t tag) if (!it) return NULL;
-// while ((cmp = memcmp(it->key, key, tree->key_size)) ) { while ((cmp = memcmp(AVL_NODE_KEY(tree, it), key, tree->key_size)) || (it->link[0] && !memcmp(AVL_NODE_KEY(tree, it->link[0]), key, tree->key_size))) {
@@ -535,8 +539,8 @@ void avl_test( int max ) { t->test_key = i; t->test_key2 = AVL_TEST_MAX-i; t->v = t->w = 0; - avl_insert(&test_tree, t); - avl_insert(&test_tree2, t); + avl_insert(&test_tree, t, -300300); + avl_insert(&test_tree2, t, -300301); printf(" inserted %d/%d %d/%d\n", t->test_key, t->v, t->test_key2, t->w ); }
@@ -545,9 +549,9 @@ void avl_test( int max ) {
for (i = AVL_TEST_MAX/2; i >= 0; i--) {
- t = avl_remove(&test_tree, &i); + t = avl_remove(&test_tree, &i, -300302);
- if ( t != avl_remove(&test_tree2, &t->test_key2) ) + if ( t != avl_remove(&test_tree2, &t->test_key2, -300303) ) printf("ERROR...\n");
printf(" removed %d/%d %d/%d\n", t->test_key, t->v, t->test_key2, t->w ); diff --git a/avl.h b/avl.h index 72e9c60..859c5d9 100644 --- a/avl.h +++ b/avl.h @@ -1,6 +1,5 @@ /* - * Copyright (C) 2010 BMX contributors: - * Axel Neumann + * Copyright (c) 2010 Axel Neumann * 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. @@ -76,6 +75,7 @@ struct avl_node *avl_find( struct avl_tree *tree, void *key ); void *avl_find_item( struct avl_tree *tree, void *key ); struct avl_node *avl_next( struct avl_tree *tree, void *key ); void *avl_next_item(struct avl_tree *tree, void *key); +void *avl_first_item(struct avl_tree *tree); struct avl_node *avl_iterate(struct avl_tree *tree, struct avl_node *it ); void *avl_iterate_item(struct avl_tree *tree, struct avl_node **it );
diff --git a/bmx.c b/bmx.c index bf351ff..2719c7f 100644 --- a/bmx.c +++ b/bmx.c @@ -1,6 +1,5 @@ /* - * Copyright (C) 2010 BMX contributors: - * Axel Neumann + * Copyright (c) 2010 Axel Neumann * 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. @@ -35,93 +34,54 @@
#include "bmx.h" #include "msg.h" -#include "hna.h" -#include "plugin.h" +#include "ip.h" #include "schedule.h" -#include "route.h" - -#define DEF_HELLO_IVAL 500 -#define MIN_HELLO_IVAL 10 -#define MAX_HELLO_IVAL 10000 -#define ARG_HELLO_IVAL "hello_interval" - - - -int32_t my_pws = DEF_PWS; +#include "tools.h" +#include "metrics.h" +#include "plugin.h"
-int32_t local_lws = DEF_LWS;
-int32_t local_rtq_lounge = DEF_RTQ_LOUNGE;
-int32_t my_path_lounge = DEF_PATH_LOUNGE;
int32_t dad_to = DEF_DAD_TO;
int32_t my_ttl = DEF_TTL;
-int32_t wl_clones = DEF_WL_CLONES; - -int32_t my_path_hystere = DEF_PATH_HYST; - -int32_t my_rcnt_hystere = DEF_RCNT_HYST; - -int32_t my_rcnt_pws = DEF_RCNT_PWS; - -int32_t my_rcnt_fk = DEF_RCNT_FK; - -int32_t my_late_penalty = DEF_LATE_PENAL; - -static int32_t drop_2hop_loop = DEF_DROP_2HLOOP; -
static int32_t Asocial_device = DEF_ASOCIAL;
+static int32_t ogm_purge_to = DEF_OGM_PURGE_TO;
-int32_t asym_weight = DEF_ASYM_WEIGHT; -int32_t sym_weight = DEF_SYM_WEIGHT; - -static int32_t asym_exp = DEF_ASYM_EXP; - -int32_t my_hop_penalty = DEF_HOP_PENALTY; - - -static int32_t ogi_pwrsave = MIN_OGM_INTERVAL; - +int32_t my_tx_interval = DEF_TX_INTERVAL;
-static int32_t purge_to = DEF_PURGE_TO; +int32_t my_ogm_interval = DEF_OGM_INTERVAL; /* orginator message interval in miliseconds */
+static int32_t link_purge_to = DEF_LINK_PURGE_TO;
-void* FAILURE_POINTER = &FAILURE_POINTER;
-static int8_t stop = 0; +IDM_T terminating = 0; +IDM_T initializing = YES;
static struct timeval start_time_tv; static struct timeval ret_tv, new_tv, diff_tv, acceptable_m_tv, acceptable_p_tv, max_tv = {0,(2000*MAX_SELECT_TIMEOUT_MS)};
uint32_t My_pid = 0; +static RNG rng;
-uint32_t bmx_time = 0; -uint32_t bmx_time_sec = 0; +TIME_T bmx_time = 0; +TIME_SEC_T bmx_time_sec = 0;
-uint8_t on_the_fly = NO;
uint32_t s_curr_avg_cpu_load = 0;
-struct dev_node *primary_if = NULL; +IDM_T my_description_changed = YES;
+struct orig_node self;
-struct metric_algo link_metric_algo[SQR_RANGE];
- -struct orig_node my_orig_node; - - -AVL_TREE(dev_ip4_tree, struct dev_node, ip4_addr); -AVL_TREE(dev_name_tree, struct dev_node, name); - -AVL_TREE(link_tree, struct link_node, llip4); +AVL_TREE(link_tree, struct link_node, link_id); AVL_TREE(blacklisted_tree, struct black_node, dhash);
AVL_TREE(link_dev_tree, struct link_dev_node, key); @@ -130,16 +90,12 @@ AVL_TREE(neigh_tree, struct neigh_node, nnkey);
AVL_TREE(dhash_tree, struct dhash_node, dhash); AVL_TREE(dhash_invalid_tree, struct dhash_node, dhash); -LIST_SIMPEL( dhash_invalid_plist, struct plist_node, list ); +LIST_SIMPEL( dhash_invalid_plist, struct plist_node, list, list );
AVL_TREE(orig_tree, struct orig_node, id); AVL_TREE(blocked_tree, struct orig_node, id);
-/* -STATIC_FUNC -void purge_neigh_node( struct link_node *ln, struct dhash_node *dhn ); -*/
/*********************************************************** Data Infrastructure @@ -149,176 +105,55 @@ void purge_neigh_node( struct link_node *ln, struct dhash_node *dhn );
void blacklist_neighbor(struct packet_buff *pb) { + TRACE_FUNCTION_CALL; + dbgf(DBGL_SYS, DBGT_ERR, "%s via %s", pb->i.llip_str, pb->i.iif->label_cfg.str);
- dbgf(DBGL_SYS, DBGT_ERR, "%s via %s", pb->neigh_str, pb->iif->name); + EXITERROR(-500697, (0)); }
IDM_T blacklisted_neighbor(struct packet_buff *pb, struct description_hash *dhash) { - - dbgf_all(DBGT_INFO, "%s via %s", pb->neigh_str, pb->iif->name); + TRACE_FUNCTION_CALL; + //dbgf_all(DBGT_INFO, "%s via %s", pb->i.neigh_str, pb->i.iif->label_cfg.str); return NO; }
- -IDM_T validate_metric_algo(struct metric_algo *ma, struct ctrl_node *cn) +IDM_T equal_link_key( struct link_dev_key *a, struct link_dev_key *b ) { + return (a->dev == b->dev && a->link == b->link); +}
- if (ma->sqn_window <= ma->sqn_steps) { - - dbg_cn(cn, DBGL_SYS, DBGT_ERR, "SQN: window=%d MUST be greater than steps=%d", - ma->sqn_window, ma->sqn_steps); - - } else if (ma->sqn_window <= ma->sqn_lounge) { - - dbg_cn(cn, DBGL_SYS, DBGT_ERR, "SQN: window=%d MUST BE greater than lounge=%d", - ma->sqn_window, ma->sqn_lounge); - - } else if (ma->sqn_window % ma->sqn_steps) { - - dbg_cn(cn, DBGL_SYS, DBGT_ERR, "SQN: window=%d MUST BE multiple of steps=%d", - ma->sqn_window, ma->sqn_steps); +IDM_T validate_param(int32_t probe, int32_t min, int32_t max, char *name) +{
- } else if (ma->sqn_lounge % ma->sqn_steps) { + if ( probe < min || probe > max ) {
- dbg_cn(cn, DBGL_SYS, DBGT_ERR, "SQN: lounge=%d MUST BE multiple of steps=%d", - ma->sqn_lounge, ma->sqn_steps); - } else { + dbgf( DBGL_SYS, DBGT_ERR, "Illegal %s parameter value %d ( min %d max %d )", + name, probe, min, max);
- return SUCCESS; + return FAILURE; }
- return FAILURE; + return SUCCESS; }
- -uint32_t update_metric(struct link_node *ln, struct orig_node *on, - struct metric_record *mr, struct metric_algo *ma, SQN_T sqn_in, SQN_T sqn_max, uint32_t probe) +struct dhash_node *is_described_neigh_dhn( struct packet_buff *pb ) { + assertion(-500730, (pb && pb->i.ln)); + + if (pb->i.ln->neigh && pb->i.ln->neigh->dhn && pb->i.ln->neigh->dhn->on && + pb->i.ln->neigh->dhn == iid_get_node_by_neighIID4x(pb->i.ln->neigh, pb->i.transmittersIID)) {
- dbgf_all( DBGT_INFO, - "sqn_in %d sqn_max %d probe %u " - "metric_algo: mask 0x%X steps %d window %d lounge %d metric_record: clr %d, set %d val %u", - sqn_in, sqn_max, probe, - ma->sqn_mask, ma->sqn_steps, ma->sqn_window, ma->sqn_lounge, mr->clr, mr->set, mr->val); - - - ASSERTION(-500491, (ma->sqn_mask == (SQN_T) (0XFFFF << (bits_count(((SQN_T) ~(ma->sqn_mask))))))); - ASSERTION(-500492, (ma->sqn_steps == (SQN_T) (0X0001 << (bits_count(((SQN_T) ~(ma->sqn_mask))))))); - assertion(-500493, (ma->sqn_window > ma->sqn_steps)); - assertion(-500494, (ma->sqn_window > ma->sqn_lounge)); - assertion(-500495, (!(ma->sqn_window & ((SQN_T)~(ma->sqn_mask))))); - assertion(-500496, (!(ma->sqn_lounge & ((SQN_T)~(ma->sqn_mask))))); - assertion(-500497, (!(mr->clr & ((SQN_T) ~(ma->sqn_mask))))); - -// assertion(-500498, (probe >= ma->sqn_window * ma->sqn_steps)); // may cause zero metric (which is ok) -// assertion(-500499, (!(probe % (ma->sqn_window * ma->sqn_steps)))); // may cause slightly unfair metric - assertion( -500500, (probe <= ma->metric_max)); - - sqn_max &= ma->sqn_mask; - SQN_T sqn_min = sqn_max - ma->sqn_lounge; - SQN_T sqn_low_boundary = sqn_min + ma->sqn_steps - ma->sqn_window; - SQN_T i; - - - // first purge out-of-lounge positioned records: - - if (((SQN_T) (mr->clr - sqn_low_boundary)) < (ma->sqn_window - ma->sqn_steps)) { - // mr->clr within A: - SQN_T sqn_purge = sqn_min - mr->clr; - SQN_T metric_purge = sqn_purge / ma->sqn_steps; - mr->clr = sqn_min; - - assertion(-500500, (((SQN_T) (metric_purge - 1)) < ((ma->sqn_window / ma->sqn_steps) - 1))); - - for (i = 0; i < metric_purge; i++) - mr->val -= (mr->val / ma->regression); - - - } else if (((SQN_T) (mr->clr - sqn_min)) <= ma->sqn_lounge) { - - // mr->clr within B: FINE! - - } else { - - // mr->clr out of any range: - if ( mr->clr ) { - - dbgf(DBGL_SYS, DBGT_ERR, "ln %s on %s sqn_min %d updated %u ", - ln ? ln->llip4_str : "---", - on ? on->id.name : "---", - on ? on->ogm_sqn_min : 0, - on ? on->updated_timestamp : 0); - - dbgf(DBGL_SYS, DBGT_ERR, - "sqn_in %d sqn_max %d probe %u " - "metric_algo: mask 0x%X steps %d window %d lounge %d metric_record: clr %d, set %d val %u", - sqn_in, sqn_max, probe, - ma->sqn_mask, ma->sqn_steps, ma->sqn_window, ma->sqn_lounge, mr->clr, mr->set, mr->val); - } - - mr->clr = sqn_min; - mr->val = 0; + return pb->i.ln->neigh->dhn; }
- - if (!probe) - return mr->val; - - // then update the metric: - - if (((SQN_T) (sqn_in - sqn_min)) < (ma->sqn_lounge + ma->sqn_steps)) { - - // sqn_in within B: - -// if (((SQN_T) ((mr->set) - sqn_min)) >= (ma->sqn_lounge + ma->sqn_steps)) { - if (((SQN_T) ((mr->set & ma->sqn_mask) - sqn_min)) >= (ma->sqn_lounge + ma->sqn_steps)) { - - // mr->set out of B (fix maybe illegal mr->set): then set to mr->clr - sqn_steps - mr->set = sqn_min - ma->sqn_steps; - } - - - if ((((sqn_in & ma->sqn_mask) == (mr->set & ma->sqn_mask)))) { - - // sqn_in already set ! - - } else if (((SQN_T) ((sqn_in & ma->sqn_mask)-(mr->set & ma->sqn_mask))) <= ma->sqn_lounge + ma->sqn_steps) { - - // sqn_in > mr->set: - - SQN_T sqn_purge = ((sqn_in & ma->sqn_mask)-(mr->clr & ma->sqn_mask)); - SQN_T metric_purge = sqn_purge / ma->sqn_steps; - - for (i = 0; i < metric_purge; i++) - mr->val -= (mr->val / ma->regression); - - mr->val += (((((SQN_T) (sqn_in & ~(ma->sqn_mask))) + 1) * (probe / ma->regression)) / ma->sqn_steps); - - mr->set = mr->clr = sqn_in & ma->sqn_mask; - - uint64_t add = ((((SQN_T) (sqn_in & ~(ma->sqn_mask))) * probe) + (rand_num(probe - 1))) / ma->metric_max; - - assertion(-500501, (add <= ((SQN_T) (sqn_in & ~(ma->sqn_mask))))); - - mr->set += add; + return NULL; +}
- } else {
- dbgf(DBGL_CHANGES, DBGT_WARN, - "sqn_in %d sqn_max %d probe %u " - "metric_algo: mask 0x%X steps %d window %d lounge %d metric_record: clr %d, set %d val %u", - sqn_in, sqn_max, probe, - ma->sqn_mask, ma->sqn_steps, ma->sqn_window, ma->sqn_lounge, mr->clr, mr->set, mr->val); - // impossible ?? assertion(-500502, (0)); - } - }
- assertion(-500503, (mr->val <= ma->metric_max)); - return mr->val; -}
@@ -327,6 +162,7 @@ uint32_t update_metric(struct link_node *ln, struct orig_node *on, STATIC_FUNC void assign_best_rtq_link(struct neigh_node *nn) { + TRACE_FUNCTION_CALL; struct list_node *lndev_pos; struct link_dev_node *lndev_best = NULL; struct link_node *ln; @@ -343,8 +179,8 @@ void assign_best_rtq_link(struct neigh_node *nn) struct link_dev_node *lndev = list_entry(lndev_pos, struct link_dev_node, list);
if (!lndev_best || - lndev->mr[SQR_RTQ].val > lndev_best->mr[SQR_RTQ].val || - GREAT_U32(lndev->rtq_time_max, lndev_best->rtq_time_max) + lndev->mr[SQR_RTQ].umetric_final > lndev_best->mr[SQR_RTQ].umetric_final || + U32_GT(lndev->rtq_time_max, lndev_best->rtq_time_max) ) lndev_best = lndev;
@@ -359,13 +195,13 @@ void assign_best_rtq_link(struct neigh_node *nn)
-//BMX3 (done) STATIC_FUNC void free_neigh_node(struct neigh_node *nn) { + TRACE_FUNCTION_CALL; paranoia(-500321, (nn->link_tree.items));
- dbgf(DBGL_SYS, DBGT_INFO," "); + dbgf_all(DBGT_INFO, "freeing %s", nn && nn->dhn && nn->dhn->on ? nn->dhn->on->id.name : "---");
avl_remove(&neigh_tree, &nn->nnkey, -300196); iid_purge_repos(&nn->neighIID4x_repos); @@ -373,68 +209,18 @@ void free_neigh_node(struct neigh_node *nn) }
-/* - * merging dhn->neigh into ln->neigh - * keeping ln->neigh and dhn - * purging ln->neigh->dhn and dhn->neigh - */ -//BMX3 (done) -/* - -STATIC_FUNC -struct neigh_node *merge_neigh_nodes(struct link_node *ln, struct dhash_node * dhn) -{ - struct neigh_node *neigh = ln->neigh; - - dbgf(DBGL_SYS, DBGT_ERR, "Neigh restarted ?!! purging %s %jX, keeping %s %jX", - neigh->dhn->on->desc0->id.name, neigh->dhn->on->desc0->id.rand.u64[0], - dhn->on->desc0->id.name, dhn->on->desc0->id.rand.u64[0]); - - if (dhn->neigh) { - struct neigh_node *del_neigh = dhn->neigh; - - dbgf(DBGL_SYS, DBGT_ERR, "Merging neigh_nodes, purging %d neighIID4x entries ", - del_neigh->neighIID4x_repos.tot_used); - - assertion(-500406, (del_neigh->link_tree.items));
- struct avl_node *an; - while ((an = del_neigh->link_tree.root)) { - - struct link_node * mv_ln = an->item; - - ASSERTION(-500408, (!avl_find(&neigh->link_tree, &mv_ln->llip4))); - assertion(-500409, (mv_ln != ln)); - - avl_insert(&neigh->link_tree, mv_ln, -300140); - mv_ln->neigh = neigh; - avl_remove(&del_neigh->link_tree, &mv_ln->llip4, -300199); - } - - free_neigh_node(del_neigh); - } - - neigh->dhn->neigh = NULL; - invalidate_dhash_node(neigh->dhn); - neigh->dhn = dhn; - dhn->neigh = neigh; - - return neigh; -} -*/ - - -//BMX3 (done) STATIC_FUNC -struct neigh_node * create_neigh_node(struct link_node *ln, struct dhash_node * dhn) +struct neigh_node *create_neigh_node(struct link_node *ln, struct dhash_node * dhn) { + TRACE_FUNCTION_CALL; assertion( -500400, ( ln && !ln->neigh && dhn && !dhn->neigh ) );
struct neigh_node *nn = debugMalloc(sizeof ( struct neigh_node), -300131);
memset(nn, 0, sizeof ( struct neigh_node));
- AVL_INIT_TREE(nn->link_tree, struct link_node, llip4); + AVL_INIT_TREE(nn->link_tree, struct link_node, link_id);
avl_insert(&nn->link_tree, ln, -300172);
@@ -449,13 +235,14 @@ struct neigh_node * create_neigh_node(struct link_node *ln, struct dhash_node * }
-//BMX3 (done) -IDM_T update_neigh_node(struct link_node *ln, struct dhash_node *dhn, IID_T neighIID4neigh) + +IDM_T update_neigh_node(struct link_node *ln, struct dhash_node *dhn, IID_T neighIID4neigh, struct description *dsc) { + TRACE_FUNCTION_CALL; struct neigh_node *neigh = NULL;
- dbgf_all( DBGT_INFO, "neigh %s neighIID4neigh %d dhn->orig %s", - ln->llip4_str, neighIID4neigh, dhn->on->desc0->id.name); + dbgf_all( DBGT_INFO, "link_id=0x%X NB=%s neighIID4neigh=%d dhn->orig=%s", + ln->link_id, ipXAsStr(af_cfg, &ln->link_ip), neighIID4neigh, dhn->on->desc->id.name);
assertion(-500389, (ln && neighIID4neigh > IID_RSVD_MAX)); assertion(-500390, (dhn && dhn->on)); @@ -464,35 +251,30 @@ IDM_T update_neigh_node(struct link_node *ln, struct dhash_node *dhn, IID_T neig
assertion(-500405, (ln->neigh->dhn && ln->neigh->dhn->on )); assertion(-500391, (ln->neigh->dhn->neigh == ln->neigh)); - ASSERTION(-500392, (avl_find(&ln->neigh->link_tree, &ln->llip4))); + ASSERTION(-500392, (avl_find(&ln->neigh->link_tree, &ln->link_id)));
if (ln->neigh == dhn->neigh) {
assertion(-500393, (ln->neigh->dhn == dhn));
-//always if new dhash: assertion(-500450, 0); //this never happen! or ? - neigh = ln->neigh; - assertion(-500518, (neigh->dhn != my_orig_node.dhn)); + assertion(-500518, (neigh->dhn != self.dhn));
} else {
//neigh = merge_neigh_nodes( ln, dhn); //they are the same! - dbgf(DBGL_SYS, DBGT_ERR, "Neigh restarted ?!! purging ln %s %jX and dhn %s %jX", - ln->neigh->dhn->on->desc0->id.name, - ln->neigh->dhn->on->desc0->id.rand.u64[0], - dhn->on->desc0->id.name, dhn->on->desc0->id.rand.u64[0]); + dbgf(DBGL_SYS, DBGT_ERR, + "Neigh restarted ?!! purging ln %s %jX and dhn %s %jX, neighIID4neigh %d dsc %s", + ln->neigh->dhn->on->desc->id.name, ln->neigh->dhn->on->desc->id.rand.u64[0], + dhn->on->desc->id.name, dhn->on->desc->id.rand.u64[0], + neighIID4neigh, dsc ? "YES" : "NO");
- invalidate_dhash_node( dhn ); - invalidate_dhash_node( ln->neigh->dhn ); + free_dhash_node( dhn ); + free_dhash_node( ln->neigh->dhn );
return FAILURE; - - - assertion(-500519, (neigh->dhn != my_orig_node.dhn)); - }
} else { @@ -501,35 +283,37 @@ IDM_T update_neigh_node(struct link_node *ln, struct dhash_node *dhn, IID_T neig
assertion(-500394, (dhn->neigh->dhn == dhn)); assertion(-500395, (dhn->neigh->link_tree.items)); - ASSERTION(-500396, (!avl_find(&dhn->neigh->link_tree, &ln->llip4))); + ASSERTION(-500396, (!avl_find(&dhn->neigh->link_tree, &ln->link_id)));
neigh = ln->neigh = dhn->neigh; avl_insert(&neigh->link_tree, ln, -300173);
- assertion(-500516, (neigh->dhn != my_orig_node.dhn)); + assertion(-500516, (neigh->dhn != self.dhn));
} else {
neigh = create_neigh_node( ln, dhn ); - assertion(-500517, (neigh->dhn != my_orig_node.dhn)); + assertion(-500517, (neigh->dhn != self.dhn)); } }
assign_best_rtq_link(neigh);
- assertion(-500510, (neigh->dhn != my_orig_node.dhn)); - - return update_neighIID4x_repository(neigh, neighIID4neigh, neigh->dhn); + assertion(-500510, (neigh->dhn != self.dhn)); + return SUCCESS; }
STATIC_FUNC struct link_dev_node *get_link_dev_node(struct link_node *ln, struct dev_node *dev) { + TRACE_FUNCTION_CALL; struct list_node *lndev_pos; struct link_dev_node *lndev;
+ assertion(-500607, (dev)); + list_for_each( lndev_pos, &ln->lndev_list ) {
lndev = list_entry( lndev_pos, struct link_dev_node, list ); @@ -538,15 +322,21 @@ struct link_dev_node *get_link_dev_node(struct link_node *ln, struct dev_node *d return lndev; }
+ lndev = debugMalloc( sizeof( struct link_dev_node ), -300023 );
memset( lndev, 0, sizeof( struct link_dev_node ) );
lndev->key.dev = dev; - lndev->key.llip4 = ln->llip4; + lndev->key.link = ln;
- dbgf_all( DBGT_INFO, "creating new lndev %16s %10s %s", - ipStr(ln->llip4), dev->name, dev->ip4_str ); + int i; + for (i = 0; i < FRAME_TYPE_ARRSZ; i++) { + LIST_INIT_HEAD(lndev->tx_task_lists[i], struct tx_task_node, list); + } + + + dbgf(DBGL_CHANGES, DBGT_INFO, "creating new lndev %16s %s", ipXAsStr(af_cfg, &ln->link_ip), dev->name_phy_cfg.str);
list_add_tail(&ln->lndev_list, &lndev->list);
@@ -554,173 +344,22 @@ struct link_dev_node *get_link_dev_node(struct link_node *ln, struct dev_node *d
avl_insert( &link_dev_tree, lndev, -300220 );
- lndev->link = ln; + cb_plugin_hooks( PLUGIN_CB_LINKDEV_CREATE, lndev);
return lndev; }
-STATIC_FUNC -struct link_node *get_link_node(uint32_t llip4) -{ - - dbgf_all( DBGT_INFO, "%s", ipStr(llip4) ); - - paranoia(-500210, !llip4); - - struct link_node *ln = avl_find_item(&link_tree, &llip4); - - if (!ln) { - - ln = debugMalloc(sizeof (struct link_node), -300024); - memset(ln, 0, sizeof (struct link_node)); - - LIST_INIT_HEAD(ln->lndev_list, struct link_dev_node, list); - - ln->llip4 = llip4; - - addr_to_str(llip4, ln->llip4_str); - - avl_insert(&link_tree, ln, -300147); - } - - return ln; -} - -void update_link_node(struct link_node *ln, struct dev_node *iif, SQN_T sqn, SQN_T sqn_max, uint8_t sqr, uint32_t probe) -{ -// uint8_t lounge_size = (sqr == SQR_RQ) ? RQ_LINK_LOUNGE : local_rtq_lounge; - - struct list_node *lndev_pos; - struct link_dev_node *lndev, *this_lndev = NULL; - - list_for_each(lndev_pos, &ln->lndev_list) - { - lndev = list_entry(lndev_pos, struct link_dev_node, list); - - if (lndev->key.dev == iif) { - - this_lndev = lndev; - - } else { - -// update_lounged_metric(0, lounge_size, sqn, sqn_max, &lndev->sqr[sqr], local_lws); - - update_metric(ln, NULL, &lndev->mr[sqr], &link_metric_algo[sqr], sqn, sqn_max, 0); - - } - - } - - if (this_lndev) { - -// update_lounged_metric(probe, lounge_size, sqn, sqn_max, &this_lndev->sqr[sqr], local_lws); - - update_metric(ln, NULL, &this_lndev->mr[sqr], &link_metric_algo[sqr], sqn, sqn_max, probe); - - if (probe && sqr == SQR_RTQ) { - - this_lndev->rtq_time_max = bmx_time; - - if ( - ln->neigh && - (!ln->neigh->best_rtq || - ln->neigh->best_rtq->mr[SQR_RTQ].val <= this_lndev->mr[SQR_RTQ].val)) { - - ln->neigh->best_rtq = this_lndev; - } - } - } - - if (probe && sqr == SQR_RQ) { - ln->rq_time_max = bmx_time; - ln->rq_sqn_max = sqn; - } - - dbgf_all(DBGT_INFO, "%s dev %s", - ipStr(ln->llip4), this_lndev ? this_lndev->key.dev->name : "???"); - -} - - - -STATIC_FUNC -void purge_link_node(uint32_t only_llip4, struct dev_node *only_dev, IDM_T only_expired) -{ - struct avl_node *an; - struct link_node *ln; - uint32_t itip4 = 0; - - dbgf_all( DBGT_INFO, "%s %s %s only_expired", - ipStr(only_llip4), only_dev ? only_dev->name : "---", only_expired ? " " : "not"); - - while ((an = (only_llip4 ? (avl_find(&link_tree, &only_llip4)) : (avl_next(&link_tree, &itip4)))) && (ln = an->item)) { - - struct list_node *pos, *tmp, *prev = (struct list_node *) & ln->lndev_list; - struct neigh_node *nn = ln->neigh; - IDM_T removed_lndev = NO; - - itip4 = ln->llip4; - - list_for_each_safe(pos, tmp, &ln->lndev_list) - { - struct link_dev_node *lndev = list_entry(pos, struct link_dev_node, list); - - if ((!only_dev || only_dev == lndev->key.dev) && - (!only_expired || (((uint32_t) (bmx_time - lndev->pkt_time_max)) > (uint32_t) purge_to))) { - - dbgf(DBGL_CHANGES, DBGT_INFO, "purging lndev %16s %10s %s", - ipStr(ln->llip4), lndev->key.dev->name, lndev->key.dev->ip4_str); - - list_del_next(&ln->lndev_list, prev); - avl_remove(&link_dev_tree, &lndev->key, -300221); - debugFree(pos, -300044); - removed_lndev = YES; - - } else { - prev = pos; - } - } - - assertion(-500323, (only_dev || only_expired || ln->lndev_list.items==0)); - - if (!ln->lndev_list.items) { - - dbgf(DBGL_CHANGES, DBGT_INFO, "purging: %s %s", ipStr(itip4), only_dev ? only_dev->name : "???");
- if (nn) { - - avl_remove(&nn->link_tree, &ln->llip4, -300198);
- if (!nn->link_tree.items) {
- if (nn->dhn) { - nn->dhn->neigh = NULL; - } - - free_neigh_node(nn); - nn = NULL; - } - } - - avl_remove(&link_tree, &ln->llip4, -300193 ); - - debugFree( ln, -300045 ); - } - - if (nn && removed_lndev) - assign_best_rtq_link(nn); - - if ( only_llip4 ) - break; - } -}
struct dhash_node* create_dhash_node(struct description_hash *dhash, struct orig_node *on) { + TRACE_FUNCTION_CALL;
struct dhash_node * dhn = debugMalloc(sizeof ( struct dhash_node), -300001); memset(dhn, 0, sizeof ( struct dhash_node)); - memcpy(&dhn->dhash, dhash, BMX_HASH0_LEN); + memcpy(&dhn->dhash, dhash, HASH0_SHA1_LEN); avl_insert(&dhash_tree, dhn, -300142);
dhn->myIID4orig = iid_new_myIID4x(dhn); @@ -729,47 +368,48 @@ struct dhash_node* create_dhash_node(struct description_hash *dhash, struct orig dhn->on = on; on->dhn = dhn;
- dbgf_all(DBGT_INFO, "dhash %8X.. myIID4orig %d", dhn->dhash.h.u32[0], dhn->myIID4orig); + dbgf(DBGL_CHANGES, DBGT_INFO, "dhash %8X.. myIID4orig %d", dhn->dhash.h.u32[0], dhn->myIID4orig);
return dhn; }
STATIC_FUNC -void free_dhash_iid(struct dhash_node *dhn) +void purge_dhash_iid(struct dhash_node *dhn) { + TRACE_FUNCTION_CALL; struct avl_node *an; struct neigh_node *nn;
- iid_free(&my_iid_repos, dhn->myIID4orig); - //reset all neigh_node->oid_repos[x]=dhn->mid4o entries for (an = NULL; (nn = avl_iterate_item(&neigh_tree, &an));) {
iid_free_neighIID4x_by_myIID4x(&nn->neighIID4x_repos, dhn->myIID4orig);
} - - debugFree(dhn, -300112); - }
STATIC_FUNC - void purge_dhash_to_list( IDM_T purge_all ) { + void purge_dhash_invalid_list( IDM_T force_purge_all ) {
+ TRACE_FUNCTION_CALL; struct dhash_node *dhn;
- dbgf_all( DBGT_INFO, "%s", purge_all ? "purge_all" : "only_expired"); + dbgf_all( DBGT_INFO, "%s", force_purge_all ? "force_purge_all" : "only_expired");
while ((dhn = plist_get_first(&dhash_invalid_plist)) ) {
- if (purge_all || ((uint32_t) (bmx_time - dhn->referred_timestamp) > MIN_DHASH_TO)) { + if (force_purge_all || ((uint32_t) (bmx_time - dhn->referred_by_me_timestamp) > MIN_DHASH_TO)) {
dbgf_all( DBGT_INFO, "dhash %8X myIID4orig %d", dhn->dhash.h.u32[0], dhn->myIID4orig);
plist_rem_head(&dhash_invalid_plist); avl_remove(&dhash_invalid_tree, &dhn->dhash, -300194);
- free_dhash_iid(dhn); + iid_free(&my_iid_repos, dhn->myIID4orig); + + purge_dhash_iid(dhn); + + debugFree(dhn, -300112);
} else { break; @@ -780,6 +420,7 @@ STATIC_FUNC STATIC_FUNC void unlink_dhash_node(struct dhash_node *dhn) { + TRACE_FUNCTION_CALL; dbgf_all(DBGT_INFO, "dhash %8X myIID4orig %d", dhn->dhash.h.u32[0], dhn->myIID4orig);
if (dhn->neigh) { @@ -789,13 +430,13 @@ void unlink_dhash_node(struct dhash_node *dhn)
while ((an = dhn->neigh->link_tree.root) && (ln = an->item)) {
- dbgf_all(DBGT_INFO, "dhn->neigh->link_tree item %s", ln->llip4_str); + dbgf_all(DBGT_INFO, "dhn->neigh->link_tree item link_id=0x%X", ln->link_id);
assertion(-500284, (ln->neigh == dhn->neigh));
ln->neigh = NULL;
- avl_remove(&dhn->neigh->link_tree, &ln->llip4, -300197); + avl_remove(&dhn->neigh->link_tree, &ln->link_id, -300197); }
free_neigh_node(dhn->neigh); @@ -809,246 +450,228 @@ void unlink_dhash_node(struct dhash_node *dhn) dhn->on = NULL; }
- - avl_remove(&dhash_tree, &dhn->dhash, -300195); - }
void free_dhash_node( struct dhash_node *dhn ) { - dbgf(DBGL_SYS, DBGT_INFO, "dhash %8X myIID4orig %d", dhn->dhash.h.u32[0], dhn->myIID4orig); + TRACE_FUNCTION_CALL; + static uint32_t blocked_counter = 1;
- invalidate_dhash_node(dhn); - return; + dbgf(terminating ? DBGL_CHANGES : DBGL_SYS, DBGT_INFO, + "dhash %8X myIID4orig %d", dhn->dhash.h.u32[0], dhn->myIID4orig); + + unlink_dhash_node(dhn); // will clear dhn->on and dhn->neigh
- unlink_dhash_node(dhn); + purge_dhash_iid(dhn);
- free_dhash_iid(dhn); + // It must be ensured that I am not reusing this IID for a while, so it must be invalidated + // but the description and its' resulting dhash might become valid again, so I give it a unique and illegal value. + memset(&dhn->dhash, 0, sizeof ( struct description_hash)); + dhn->dhash.h.u32[(sizeof ( struct description_hash) / sizeof (uint32_t)) - 1] = blocked_counter++;
+ avl_insert(&dhash_invalid_tree, dhn, -300168); + plist_add_tail(&dhash_invalid_plist, dhn); + dhn->referred_by_me_timestamp = bmx_time; }
+ +// called due to updated description void invalidate_dhash_node( struct dhash_node *dhn ) { + TRACE_FUNCTION_CALL;
- dbgf_all( DBGT_INFO, + dbgf(terminating ? DBGL_ALL : DBGL_SYS, DBGT_INFO, "dhash %8X myIID4orig %d, my_iid_repository: used %d, inactive %d min_free %d max_free %d ", dhn->dhash.h.u32[0], dhn->myIID4orig, my_iid_repos.tot_used, dhash_invalid_tree.items+1, my_iid_repos.min_free, my_iid_repos.max_free);
- unlink_dhash_node(dhn); // will clear dhn->on + assertion( -500698, (!dhn->on)); + assertion( -500699, (!dhn->neigh)); + unlink_dhash_node(dhn); // would clear dhn->on and dhn->neigh
avl_insert(&dhash_invalid_tree, dhn, -300168); plist_add_tail(&dhash_invalid_plist, dhn); - dhn->referred_timestamp = bmx_time; - - - //dhn->invalid=YES; + dhn->referred_by_me_timestamp = bmx_time; }
- -//BMX3 (done) -IDM_T update_neighIID4x_repository(struct neigh_node *neigh, IID_T neighIID4x, struct dhash_node *dhn) +STATIC_FUNC +void purge_router_tree(struct orig_node *on_key, struct link_dev_key *rt_key, IDM_T purge_all) { - assertion(-500386, (neigh->dhn != my_orig_node.dhn)); - - if (dhn == my_orig_node.dhn) - neigh->neighIID4me = neighIID4x; + TRACE_FUNCTION_CALL; + struct orig_node *on; + struct avl_node *an = NULL; + while ((on = on_key) || (on = avl_iterate_item( &orig_tree, &an))) {
- if (dhn == neigh->dhn) - neigh->neighIID4neigh = neighIID4x; + struct link_dev_key key; + memset(&key, 0, sizeof (key)); + struct router_node *rn;
- return iid_set_neighIID4x(&neigh->neighIID4x_repos, neighIID4x, dhn->myIID4orig); -} + while (rt_key ? (rn = avl_find_item(&on->rt_tree, rt_key)) : (rn = avl_next_item(&on->rt_tree, &key))) {
+ key = rn->key;
-STATIC_FUNC -void purge_router_tree( struct orig_node *on, IDM_T purge_all ) -{ - struct avl_node *an; - struct link_key key; - memset( &key, 0, sizeof(struct link_key)); + if (purge_all || rt_key || !avl_find(&link_dev_tree, &key)) {
- while ((an = avl_next(&on->router_tree, &key))) { + if (on->best_rn == rn) + on->best_rn = NULL;
- struct router_node *rn = an->item; + if (on->curr_rn == rn) {
- memcpy(&key, &rn->key, sizeof (struct link_key)); + set_ogmSqn_toBeSend_and_aggregated(on, on->ogmSqn_maxRcvd, on->ogmSqn_maxRcvd);
- if (purge_all || !avl_find(&link_dev_tree, &rn->key)) { - avl_remove(&on->router_tree, &rn->key, -300226); - debugFree(rn, -300225); - } - } -} + cb_route_change_hooks(DEL, on); + on->curr_rn = NULL; + }
-IDM_T update_orig_metrics(struct packet_buff *pb, struct orig_node *on, IID_T orig_sqn) -{ - dbgf_all( DBGT_INFO, "%s orig_sqn %d via neigh %s", on->id.name, orig_sqn,pb->neigh_str); + avl_remove(&on->rt_tree, &rn->key, -300226);
- struct router_node *rn_in = NULL; - uint32_t metric_in, metric_best = 0; - SQN_T mask = on->path_metric_algo.sqn_mask; - struct link_key *key_in = &pb->lndev->key; + debugFree(rn, -300225); + }
- if (on->blocked || (((SQN_T) (orig_sqn - on->ogm_sqn_min)) >= on->ogm_sqn_range)) - return FAILURE; + if (rt_key) + break; + }
- SQN_T ogm_sqn_max_rcvd = MAX_SQ(on->ogm_sqn_max_rcvd, orig_sqn); + if (on_key) + break; + } +}
- if (((SQN_T) ((ogm_sqn_max_rcvd & mask) - (orig_sqn & mask))) > on->path_metric_algo.sqn_lounge ) {
- dbgf(DBGL_CHANGES, DBGT_WARN, "%s orig_sqn %d to old max_sqn %d via neigh %s", - on->id.name, orig_sqn, on->ogm_sqn_max_rcvd, pb->neigh_str); +STATIC_FUNC +void purge_link_node(LINK_ID_T only_link_id, struct dev_node *only_dev, IDM_T only_expired) +{ + TRACE_FUNCTION_CALL; + struct avl_node *link_an; + struct link_node *ln; + LINK_ID_T it_link_id = LINK_ID_INVALID;
+ dbgf_all( DBGT_INFO, "link_id=0x%X %s %s only_expired", + only_link_id, only_dev ? only_dev->label_cfg.str : "---", only_expired ? " " : "not");
- return FAILURE; - } + while ((link_an = (only_link_id >= LINK_ID_MIN ? + (avl_find(&link_tree, &only_link_id)) : (avl_next(&link_tree, &it_link_id)))) && (ln = link_an->item)) {
- if (LESS_SQN((on->ogm_sqn_max_rcvd & mask), (orig_sqn & mask))) { + struct list_node *pos, *tmp, *prev = (struct list_node *) & ln->lndev_list; + struct neigh_node *nn = ln->neigh; + IDM_T removed_lndev = NO;
- for (;;) { - struct router_node *rn; - struct avl_node *an; - struct router_node *rn_best = NULL; - uint32_t metric_temp; - metric_best = 0; + it_link_id = ln->link_id;
- for (an = NULL; (rn = avl_iterate_item(&on->router_tree, &an));) { + list_for_each_safe(pos, tmp, &ln->lndev_list) + { + struct link_dev_node *lndev = list_entry(pos, struct link_dev_node, list);
- if (rn->key.dev == key_in->dev && rn->key.llip4 == key_in->llip4) { + if ((!only_dev || only_dev == lndev->key.dev) && + (!only_expired || (((TIME_T) (bmx_time - lndev->pkt_time_max)) > (TIME_T) link_purge_to))) {
- rn_in = rn; + dbgf(DBGL_CHANGES, DBGT_INFO, "purging lndev=%s dev=%10s", + ipXAsStr(af_cfg, &ln->link_ip), lndev->key.dev->label_cfg.str);
- } else { + cb_plugin_hooks( PLUGIN_CB_LINKDEV_DESTROY, lndev);
- metric_temp = update_metric(pb->ln, on, &rn->mr, &on->path_metric_algo, 0, ogm_sqn_max_rcvd, 0); + purge_router_tree(NULL, &lndev->key, NO);
- if (metric_best < metric_temp) { + purge_tx_task_list(lndev->tx_task_lists, NULL, NULL);
- metric_best = metric_temp; - rn_best = rn; - } - } - } + list_del_next(&ln->lndev_list, prev); + avl_remove(&link_dev_tree, &lndev->key, -300221); + debugFree(pos, -300044); + removed_lndev = YES;
- if (rn_best && !avl_find(&link_dev_tree, &rn_best->key)) { - purge_router_tree(on, NO); - continue; } else { - break; + prev = pos; } }
- } else { - // already cleaned up, simple use last best_metric: - - metric_best = on->router_best_metric; - - rn_in = avl_find_item( &on->router_tree, key_in ); - } - - if (!rn_in) { - rn_in = debugMalloc(sizeof (struct router_node), -300222); - memset( rn_in, 0, sizeof(struct router_node)); - memcpy( &rn_in->key, &pb->lndev->key, sizeof(struct link_key)); - - rn_in->mr.clr = on->ogm_sqn_max_rcvd & mask; - - avl_insert(&on->router_tree, rn_in, -300223); - } + assertion(-500323, (only_dev || only_expired || ln->lndev_list.items==0));
- metric_in = update_metric(pb->ln, on, &rn_in->mr, &on->path_metric_algo, orig_sqn, ogm_sqn_max_rcvd, pb->lndev->mr[SQR_RTQ].val); + if (!ln->lndev_list.items) {
+ dbgf(DBGL_CHANGES, DBGT_INFO, "purging: link_id=0x%X link_ip=%s %s", + ln->link_id, ipXAsStr(af_cfg, &ln->link_ip), only_dev ? only_dev->label_cfg.str : "???");
- if (metric_in > metric_best && GREAT_SQN(rn_in->mr.set & mask, on->ogm_sqn_to_be_send & mask)) { + cb_plugin_hooks(PLUGIN_CB_LINK_DESTROY, ln);
- on->router_path_metric = metric_in; - on->router_best_metric = metric_in; - on->ogm_sqn_to_be_send = rn_in->mr.set; - ogm_aggreg_pending++; + if (nn) {
- if (memcmp(&on->router_key, &rn_in->key, sizeof (struct link_key))) { + avl_remove(&nn->link_tree, &ln->link_id, -300198);
- struct link_dev_node *lndev_old = avl_find_item(&link_dev_tree, &on->router_key); + if (!nn->link_tree.items) {
- dbgf((!on->router_key.llip4 || lndev_old) ? DBGL_CHANGES : DBGL_SYS, - (!on->router_key.llip4 || lndev_old) ? DBGT_INFO : DBGT_ERR, - "changing router to %s %s via %s %s metric %d (prev %s %s)", - on->id.name, on->primary_ip4_str, - ipStr(rn_in ? rn_in->key.llip4 : 0), rn_in ? rn_in->key.dev->name : "---", metric_in, - ipStr(on->router_key.llip4), lndev_old ? on->router_key.dev->name : "---"); + if (nn->dhn) { + nn->dhn->neigh = NULL; + }
- //assertion(-500504, (!on->router_key.llip4 || lndev_old)); lndev_old not needed anymore beyond this point + free_neigh_node(nn); + nn = NULL; + } + }
- if (on->router_key.llip4) { - configure_route(on->primary_ip4, 32, 0, on->router_key.llip4, 0, - 0, NULL, RT_TABLE_HOSTS, RTN_UNICAST, DEL, TRACK_OTHER_HOST); + struct avl_node *dev_an; + struct dev_node *dev; + for(dev_an = NULL; (dev = avl_iterate_item(&dev_ip_tree, &dev_an));) { + purge_tx_task_list(dev->tx_task_lists, ln, NULL); }
- configure_route(on->primary_ip4, 32, 0, rn_in->key.llip4, my_orig_node.primary_ip4, - rn_in->key.dev->index, rn_in->key.dev->name, - RT_TABLE_HOSTS, RTN_UNICAST, ADD, TRACK_OTHER_HOST); + avl_remove(&link_tree, &ln->link_id, -300193);
- memcpy(&on->router_key, &rn_in->key, sizeof (struct link_key)); + debugFree( ln, -300045 ); }
- } else { - on->router_best_metric = metric_best; - } - - on->ogm_sqn_max_rcvd = ogm_sqn_max_rcvd; + if (nn && removed_lndev) + assign_best_rtq_link(nn);
- return SUCCESS; + if (only_link_id >= LINK_ID_MIN) + break; + } }
- void free_orig_node(struct orig_node *on) { - dbgf(DBGL_CHANGES, DBGT_INFO, "%s", on->primary_ip4_str); + TRACE_FUNCTION_CALL; + dbgf(DBGL_CHANGES, DBGT_INFO, "%s %s", on->id.name, on->primary_ip_str);
- if ( on == &my_orig_node) + if ( on == &self) return;
- if (on->router_key.llip4) { - configure_route(on->primary_ip4, 32, 0, on->router_key.llip4, 0, - 0, NULL, RT_TABLE_HOSTS, RTN_UNICAST, DEL, TRACK_OTHER_HOST); - } - + //cb_route_change_hooks(DEL, on, 0, &on->ort.rt_key.llip);
- process_description_tlvs(on, NULL, TLV_DEL_TEST_ADD, NULL); + purge_router_tree(on, NULL, YES);
+ if (on->desc && !on->blocked) + process_description_tlvs(NULL, on, on->desc, TLV_OP_DEL, FRAME_TYPE_PROCESS_ALL, NULL);
if ( on->dhn ) { on->dhn->on = NULL; free_dhash_node(on->dhn); }
- purge_router_tree(on, YES); - avl_remove(&orig_tree, &on->id, -300200); avl_remove(&blocked_tree, &on->id, -300201);
- debugFree( on->desc0, -300228 ); + if (on->desc) + debugFree(on->desc, -300228); + debugFree( on, -300086 ); }
- - -void purge_orig(struct dev_node *only_dev, IDM_T only_expired) +void purge_link_and_orig_nodes(struct dev_node *only_dev, IDM_T only_expired) { + TRACE_FUNCTION_CALL;
dbgf_all( DBGT_INFO, "%s %s only expired", - only_dev ? only_dev->name : "---", only_expired ? " " : "NOT"); + only_dev ? only_dev->label_cfg.str : "---", only_expired ? " " : "NOT");
- purge_link_node( 0, only_dev, only_expired ); + purge_link_node(LINK_ID_INVALID, only_dev, only_expired);
int i; for (i = IID_RSVD_MAX + 1; i < my_iid_repos.max_free; i++) { @@ -1057,13 +680,11 @@ void purge_orig(struct dev_node *only_dev, IDM_T only_expired)
if ((dhn = my_iid_repos.arr.node[i]) && dhn->on) {
- if ( only_dev ) { - - //TODO: keep on and only remove route - if ( dhn->on->router_key.dev == only_dev) - free_orig_node(dhn->on); + if (!only_dev && (!only_expired || + ((TIME_T) (bmx_time - dhn->referred_by_me_timestamp)) > (TIME_T) ogm_purge_to)) {
- } else if (!only_expired || ((uint32_t) (bmx_time - dhn->referred_timestamp)) > (uint32_t) purge_to) { + dbgf(terminating ? DBGL_ALL : DBGL_SYS, DBGT_INFO, "%s referred before: %d > purge_to=%d", + dhn->on->id.name, ((TIME_T) (bmx_time - dhn->referred_by_me_timestamp)), (TIME_T) ogm_purge_to);
free_orig_node(dhn->on); } @@ -1071,121 +692,268 @@ void purge_orig(struct dev_node *only_dev, IDM_T only_expired) } }
-struct dev_node * get_bif(char *dev) + +LINK_ID_T new_link_id(struct dev_node *dev) +{ + uint16_t tries = 0; + LINK_ID_T link_id = 0; + + dev->link_id_timestamp = bmx_time; + + do { + link_id |= (((LINK_ID_T) (dev->mac.u8[5])) << 0); + link_id |= (((LINK_ID_T) (dev->mac.u8[4])) << 8); + link_id |= (((LINK_ID_T) (dev->mac.u8[3])) << 16); + link_id |= (((LINK_ID_T) ((link_id < LINK_ID_MIN ? (rand_num(((uint8_t) - 1) - LINK_ID_MIN) + LINK_ID_MIN) : (rand_num(((uint8_t) - 1)))))) << 24); + +#ifdef TEST_LINK_ID_COLLISION_DETECTION + link_id = (tries || dev->link_id) ? link_id : LINK_ID_MIN; +#endif + + + struct avl_node *an; + struct dev_node *tmp; + + for (an = NULL; (tmp = avl_iterate_item(&dev_ip_tree, &an));) { + if (tmp->link_id == link_id) + break; + } + + if (!tmp && !avl_find_item(&link_tree, &link_id)) { + dev->link_id = link_id; + return link_id; + } + + tries++; + + if (tries % LINK_ID_ITERATIONS_WARN == 0) { + dbgf(DBGL_SYS, DBGT_ERR, "No free link_id after %d trials (link_tree.items=%d, dev_ip_tree.items=%d)!", + tries, link_tree.items, dev_ip_tree.items); + } + + } while (tries < LINK_ID_ITERATIONS_MAX); + + + dev->link_id = LINK_ID_INVALID; + return LINK_ID_INVALID; +} + +STATIC_FUNC +struct link_node *get_link_node(struct packet_buff *pb) { - char dev_name[IFNAMSIZ]; - memset(dev_name, 0, IFNAMSIZ); + TRACE_FUNCTION_CALL; + + dbgf_all(DBGT_INFO, "NB=%s, link_id=0x%X", pb->i.llip_str, pb->i.link_id); + + struct link_node *ln = avl_find_item(&link_tree, &pb->i.link_id); + + if (ln && !is_ip_equal(&pb->i.llip, &ln->link_ip)) { + + if (((TIME_T) (bmx_time - ln->pkt_time_max)) < (TIME_T) dad_to) {
- strncpy(dev_name, dev, IFNAMSIZ - 1); + dbgf(DBGL_SYS, DBGT_WARN, + " DAD-Alert (link_id collision, this can happen)! NB=%s via dev=%s" + "cached llIP=%s link_id=0x%X ! sending problem adv...", + pb->i.llip_str, pb->i.iif->label_cfg.str, ipXAsStr(af_cfg, &ln->link_ip), pb->i.link_id);
- return avl_find_item(&dev_name_tree, dev_name); + // better be carefull here. Errornous PROBLEM_ADVs cause neighboring nodes to cease!!! + struct link_dev_node dummy_lndev = {.key = {.dev = pb->i.iif, .link = ln}, .mr = {ZERO_METRIC_RECORD,ZERO_METRIC_RECORD}};
+ schedule_tx_task(&dummy_lndev, FRAME_TYPE_PROBLEM_ADV, sizeof (struct msg_problem_adv), + FRAME_TYPE_PROBLEM_CODE_DUP_LINK_ID, ln->link_id, 0, pb->i.transmittersIID); + + // we keep this entry until it timeouts + return NULL; + } + + dbgf(DBGL_SYS, DBGT_WARN, "Reinitialized! NB=%s via dev=%s " + "cached llIP=%s link_id=0x%X ! Reinitializing link_node...", + pb->i.llip_str, pb->i.iif->label_cfg.str, ipXAsStr(af_cfg, &ln->link_ip), pb->i.link_id); + + purge_link_node(ln->link_id, NULL, NO); + ASSERTION(-500213, !avl_find(&link_tree, &pb->i.link_id)); + ln = NULL; + + } + + if (!ln) { + + ln = debugMalloc(sizeof (struct link_node), -300024); + memset(ln, 0, sizeof (struct link_node)); + + LIST_INIT_HEAD(ln->lndev_list, struct link_dev_node, list); + + + ln->link_id = pb->i.link_id; + ln->link_ip = pb->i.llip; + + avl_insert(&link_tree, ln, -300147); + + cb_plugin_hooks(PLUGIN_CB_LINK_CREATE, ln); + + dbgf(DBGL_CHANGES, DBGT_INFO, "new %s (total %d)", pb->i.llip_str, link_tree.items); + + } + + ln->pkt_time_max = bmx_time; + + return ln; }
+ void rx_packet( struct packet_buff *pb ) { - struct dev_node *dev; - struct dev_node *iif = pb->iif; - struct packet_header *hdr = (struct packet_header *) pb->packet_in; - hdr->pkt_length = ntohs(hdr->pkt_length); - hdr->pkt_dev_sqn = ntohs(hdr->pkt_dev_sqn); - - if (pb->pkt_buff_llip4 == iif->ip4_broad) { - dbgf(DBGL_SYS, DBGT_WARN, - "drop OGM: %s via %s ignoring all packets with broadcast source IP", - ipStr(pb->pkt_buff_llip4), pb->iif->name); - return; - } + TRACE_FUNCTION_CALL; + struct dev_node *oif, *iif = pb->i.iif; + + assertion(-500841, ((iif->active && iif->if_llocal_addr))); + + if (af_cfg == AF_INET) { + ip42X(&pb->i.llip, (*((struct sockaddr_in*)&(pb->i.addr))).sin_addr.s_addr);
- if ((dev = avl_find_item(&dev_ip4_tree, &pb->pkt_buff_llip4))) { - // mark own packets; - pb->oif = iif; } else { - pb->oif = NULL; + pb->i.llip = (*((struct sockaddr_in6*) &(pb->i.addr))).sin6_addr; + + if (!is_ip_net_equal(&pb->i.llip, &IP6_LINKLOCAL_UC_PREF, IP6_LINKLOCAL_UC_PLEN, AF_INET6)) { + dbgf_all(DBGT_ERR, "non-link-local IPv6 source address %s", ip6Str(&pb->i.llip)); + return; + } } + //TODO: check broadcast source!!
+ struct packet_header *hdr = &pb->packet.header; + uint16_t pkt_length = ntohs(hdr->pkt_length); + pb->i.transmittersIID = ntohs(hdr->transmitterIID); + pb->i.link_id = ntohl(hdr->link_id); + ip2Str(af_cfg, &pb->i.llip, pb->i.llip_str);
- addr_to_str( pb->pkt_buff_llip4, pb->neigh_str ); + dbgf_all(DBGT_INFO, "via %s %s %s size %d", iif->label_cfg.str, iif->ip_llocal_str, pb->i.llip_str, pkt_length);
// immediately drop invalid packets... // we acceppt longer packets than specified by pos->size to allow padding for equal packet sizes - if ( pb->total_length < (int) (sizeof (struct packet_header) + sizeof (struct frame_header)) || - hdr->pkt_length < (int) (sizeof (struct packet_header) + sizeof (struct frame_header)) || - hdr->bmx_version != COMPAT_VERSION || - hdr->pkt_length > pb->total_length || hdr->pkt_length > MAX_UDPD_SIZE) { + if ( pb->i.total_length < (int) (sizeof (struct packet_header) + sizeof (struct frame_header_long)) || + pkt_length < (int) (sizeof (struct packet_header) + sizeof (struct frame_header_long)) || + hdr->bmx_version != COMPATIBILITY_VERSION || + pkt_length > pb->i.total_length || pkt_length > MAX_UDPD_SIZE || + pb->i.link_id < LINK_ID_MIN) {
- goto process_packet_error_hdr; + goto process_packet_error; }
- dbgf_all( DBGT_INFO, "version? %i, reserved? %X, size? %i, sqn %d rcvd udp_len %d via NB %s %s %s", - hdr->bmx_version, hdr->bmx_capabilities, hdr->pkt_length, hdr->pkt_dev_sqn, - pb->total_length, pb->neigh_str, iif->name, pb->unicast ? "UNICAST" : "BRC"); + if ((oif = avl_find_item(&dev_ip_tree, &pb->i.llip))) { + + ASSERTION(-500840, (oif == iif)); // so far, only unique own interface IPs are allowed!! + + if (((oif->link_id != pb->i.link_id) && (((TIME_T) (bmx_time - oif->link_id_timestamp)) > (4 * (TIME_T) my_tx_interval))) || + ((myIID4me != pb->i.transmittersIID) && (((TIME_T) (bmx_time - myIID4me_timestamp)) > (4 * (TIME_T) my_tx_interval)))) {
+ // own link_id or myIID4me might have just changed and then, due to delay, + // I might receive my own packet back containing my previous (now non-matching)link_id of myIID4me + dbgf(DBGL_SYS, DBGT_ERR, "DAD-Alert (duplicate Address) from NB=%s via dev=%s " + "my_link_id=0x%X rcvd_link_id=0x%X myIID4me=%d rcvdIID=%d", + oif->ip_llocal_str, iif->label_cfg.str, iif->link_id, pb->i.link_id, + myIID4me, pb->i.transmittersIID);
- if (!pb->oif) { + goto process_packet_error; + }
- iif->link_activity_timestamp = bmx_time; + return; + }
- } else if (((SQN_T) (pb->oif->packet_sqn - hdr->pkt_dev_sqn)) > 2) { + if (iif->link_id == pb->i.link_id) {
- dbgf(DBGL_SYS, DBGT_WARN, - "DAD-Alert via dev %s Somebody is using my Link-Local Address %s pkt_sqn %d != %d!!!", - iif->name, pb->oif->ip4_str, hdr->pkt_dev_sqn, pb->oif->packet_sqn); + if (new_link_id(iif) == LINK_ID_INVALID) { + DEV_MARK_PROBLEM(iif); + goto process_packet_error; + }
- goto process_packet_error_hdr; + dbgf(DBGL_SYS, DBGT_WARN, "DAD-Alert (duplicate link ID, this can happen) via dev=%s NB=%s " + "is using my link_id=0x%X! Choosing new link_id=0x%X for myself, dropping packet", + iif->label_cfg.str, pb->i.llip_str, pb->i.link_id, iif->link_id);
- } else { return; }
+ if (!(pb->i.ln = get_link_node(pb))) + return;
- struct link_node *ln = get_link_node(pb->pkt_buff_llip4); - - if (ln->pkt_time_max && ln->pkt_sqn_max && ((SQN_T) (hdr->pkt_dev_sqn - ln->pkt_sqn_max)) > SQN_DAD_RANGE) { + if (!(pb->i.lndev = get_link_dev_node(pb->i.ln, pb->i.iif))) + return;
- dbgf(DBGL_SYS, DBGT_WARN, - "NB %s (via %s) reinitialized (or DAD?!) pkt_sqn %d != %d! Reinitializing link_node", - pb->neigh_str, iif->name, hdr->pkt_dev_sqn, ln->pkt_sqn_max); + pb->i.lndev->pkt_time_max = bmx_time; + pb->i.described_dhn = is_described_neigh_dhn(pb);
- purge_link_node(ln->llip4, NULL, NO); - ASSERTION( -500213, !avl_find(&link_tree, &pb->pkt_buff_llip4 ) ); - ln = get_link_node(pb->pkt_buff_llip4); - }
- ln->pkt_sqn_max = hdr->pkt_dev_sqn; - ln->pkt_time_max = bmx_time; - pb->ln = ln; - pb->lndev = get_link_dev_node(ln, pb->iif); - pb->lndev->pkt_time_max = bmx_time; + dbgf_all(DBGT_INFO, "version=%i, reserved=%X, size=%i IID=%d rcvd udp_len=%d via NB %s %s %s", + hdr->bmx_version, hdr->reserved, pkt_length, pb->i.transmittersIID, + pb->i.total_length, pb->i.llip_str, iif->label_cfg.str, pb->i.unicast ? "UNICAST" : "BRC");
- dbgf_all( DBGT_INFO, "rcvd packet from %s size %d via dev %s", - pb->neigh_str, hdr->pkt_length, iif->name); + cb_packet_hooks(pb);
if (blacklisted_neighbor(pb, NULL)) return;
- if (rx_frames(pb, hdr->pkt_data, hdr->pkt_length - sizeof (struct packet_header)) == SUCCESS) + if (rx_frames(pb) == SUCCESS) return;
-process_packet_error_hdr: + +process_packet_error: + dbgf(DBGL_SYS, DBGT_WARN, - "Drop (remaining) packet: rcvd problematic packet via NB %s %s" - "(version? %i, reserved? %X, pkt_size? %i), rcvd udp_len % d My version is % d, max_udpd_size %d", - pb->neigh_str, iif->name, - hdr->bmx_version, hdr->bmx_capabilities, hdr->pkt_length, pb->total_length, - COMPAT_VERSION, MAX_UDPD_SIZE); + "Drop (remaining) packet: rcvd problematic packet via NB=%s dev=%s " + "(version=%i, link_id=0x%X, reserved=0x%X, pkt_size=%i), udp_len=%d my_version=%d, max_udpd_size=%d", + pb->i.llip_str, iif->label_cfg.str, + hdr->bmx_version, pb->i.link_id, hdr->reserved, pkt_length, pb->i.total_length, + COMPATIBILITY_VERSION, MAX_UDPD_SIZE); + + blacklist_neighbor(pb);
return; }
+ + /*********************************************************** Runtime Infrastructure ************************************************************/
-void upd_time( struct timeval *precise_tv ) { + +#ifndef NO_TRACE_FUNCTION_CALLS +char* function_call_buffer_name_array[FUNCTION_CALL_BUFFER_SIZE] = {0}; +TIME_T function_call_buffer_time_array[FUNCTION_CALL_BUFFER_SIZE] = {0}; +uint8_t function_call_buffer_pos = 0; + +static void debug_function_calls(void) +{ + uint8_t i; + for (i = function_call_buffer_pos + 1; i != function_call_buffer_pos; i = ((i+1) % FUNCTION_CALL_BUFFER_SIZE)) { + + if (!function_call_buffer_name_array[i]) + continue; + + dbgf(DBGL_SYS, DBGT_ERR, "%10d %s()", function_call_buffer_time_array[i], function_call_buffer_name_array[i]); + + } +} + + +void trace_function_call(const char *func) +{ + if (function_call_buffer_name_array[function_call_buffer_pos] != func) { + function_call_buffer_time_array[function_call_buffer_pos] = bmx_time; + function_call_buffer_name_array[function_call_buffer_pos] = (char*)func; + function_call_buffer_pos = ((function_call_buffer_pos+1) % FUNCTION_CALL_BUFFER_SIZE); + } +} + + +#endif + +void upd_time(struct timeval *precise_tv) +{
timeradd( &max_tv, &new_tv, &acceptable_p_tv ); timercpy( &acceptable_m_tv, &new_tv ); @@ -1201,7 +969,7 @@ void upd_time( struct timeval *precise_tv ) { diff_tv.tv_sec, diff_tv.tv_usec );
if ( diff_tv.tv_sec > CRITICAL_PURGE_TIME_DRIFT ) - purge_orig(NULL, NO); + purge_link_and_orig_nodes(NULL, NO);
} else if ( timercmp( &new_tv, &acceptable_m_tv, < ) ) {
@@ -1213,7 +981,7 @@ void upd_time( struct timeval *precise_tv ) { diff_tv.tv_sec, diff_tv.tv_usec );
if ( diff_tv.tv_sec > CRITICAL_PURGE_TIME_DRIFT ) - purge_orig(NULL, NO); + purge_link_and_orig_nodes(NULL, NO);
}
@@ -1229,13 +997,12 @@ void upd_time( struct timeval *precise_tv ) {
}
- - -char *get_human_uptime( uint32_t reference ) { +char *get_human_uptime(uint32_t reference) +{ // DD:HH:MM:SS static char ut[32]="00:00:00:00";
- sprintf( ut, "%2i:%i%i:%i%i:%i%i", + sprintf( ut, "%i:%i%i:%i%i:%i%i", (((bmx_time_sec-reference)/86400)), (((bmx_time_sec-reference)%86400)/36000)%10, (((bmx_time_sec-reference)%86400)/3600)%10, @@ -1249,209 +1016,76 @@ char *get_human_uptime( uint32_t reference ) { }
-void wait_sec_msec( uint32_t sec, uint32_t msec ) { +void wait_sec_msec(TIME_SEC_T sec, TIME_T msec) +{
+ TRACE_FUNCTION_CALL; struct timeval time;
//no debugging here because this is called from debug_output() -> dbg_fprintf() which may case a loop! - //dbgf_all( DBGT_INFO, "%d sec %d msec...", sec, msec );
time.tv_sec = sec + (msec/1000) ; time.tv_usec = ( msec * 1000 ) % 1000000;
select( 0, NULL, NULL, NULL, &time );
- //update_bmx_time( NULL ); //this will cause critical system time drift message from the client - //dbgf_all( DBGT_INFO, "bat_wait(): done"); - return; }
+static void handler(int32_t sig) +{
- -int32_t rand_num( uint32_t limit ) { - - return ( limit == 0 ? 0 : rand() % limit ); -} - - - -int8_t terminating() { - - return stop != 0; - -} - - -static void handler( int32_t sig ) { - + TRACE_FUNCTION_CALL; if ( !Client_mode ) { dbgf( DBGL_SYS, DBGT_ERR, "called with signal %d", sig); }
printf("\n");// to have a newline after ^C
- stop = 1; - cb_plugin_hooks( NULL, PLUGIN_CB_TERM ); - -} - - -/* counting bits based on http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetTable */ - -static unsigned char BitsSetTable256[256]; - -STATIC_FUNC -void init_set_bits_table256(void) -{ - BitsSetTable256[0] = 0; - int i; - for (i = 0; i < 256; i++) - { - BitsSetTable256[i] = (i & 1) + BitsSetTable256[i / 2]; - } -} - -// count the number of true bits in v - -uint8_t bits_count(uint32_t v) -{ - uint8_t c=0; - uint32_t w = v; - - for (; v; v = v>>8 ) - c += BitsSetTable256[v & 0xff]; - - dbgf_all( DBGT_INFO, "%8X, counted %d bits", w, c); - - return c; -} - -uint8_t bit_get(uint8_t *array, uint16_t array_bit_size, uint16_t bit) -{ - bit = bit % array_bit_size; - - uint16_t byte_pos = bit / 8; - uint8_t bit_pos = bit % 8; - - return (array[byte_pos] & (0x01 << bit_pos)) ? 1 : 0; -} - -void bit_set(uint8_t *array, uint16_t array_bit_size, uint16_t bit, IDM_T value) -{ - bit = bit % array_bit_size; - - uint16_t byte_pos = bit / 8; - uint8_t bit_pos = bit % 8; - - if (value) - array[byte_pos] |= (0x01 << bit_pos); - else - array[byte_pos] &= ~(0x01 << bit_pos); - - assertion(-500415, (!value == !bit_get(array, array_bit_size, bit))); -} - -/* - * clears bit range between and including begin and end - */ -void bit_clear(uint8_t *array, uint16_t array_bit_size, uint16_t begin_bit, uint16_t end_bit) -{ - assertion(-500435, (array_bit_size % 8 == 0)); - - if (((uint16_t) (end_bit - begin_bit)) >= (array_bit_size - 1)) { - - memset(array, 0, array_bit_size / 8); - return; - } - - begin_bit = begin_bit % array_bit_size; - end_bit = end_bit % array_bit_size; - - uint16_t begin_byte = begin_bit/8; - uint16_t end_byte = end_bit/8; - uint16_t array_byte_size = array_bit_size/8; - - - if (begin_byte != end_byte && ((begin_byte + 1) % array_byte_size) != end_byte) - byte_clear(array, array_byte_size, begin_byte + 1, end_byte - 1); - - - uint8_t begin_mask = ~(0xFF << (begin_bit%8)); - uint8_t end_mask = (0xFF >> ((end_bit%8)+1)); - - if (begin_byte == end_byte) { - - array[begin_byte] &= (begin_mask | end_mask); - - } else { - - array[begin_byte] &= begin_mask; - array[end_byte] &= end_mask; - } -} - -/* - * clears byte range between and including begin and end - */ -void byte_clear(uint8_t *array, uint16_t array_size, uint16_t begin, uint16_t end) -{ - - assertion(-500436, (array_size % 2 == 0)); - - begin = begin % array_size; - end = end % array_size; - - memset(array + begin, 0, end >= begin ? end + 1 - begin : array_size - begin); - - if ( begin > end) - memset(array, 0, end + 1); - + terminating = 1; + cb_plugin_hooks(PLUGIN_CB_TERM, NULL);
}
-uint8_t is_zero(char *data, int len) -{ - int i;
- for (i = 0; i < len && !data[i]; i++);
- if ( i < len ) - return NO;
- return YES; -} - - - -static int segfault = NO; static int cleaning_up = NO;
static void segmentation_fault(int32_t sig) { - - dbg(DBGL_SYS, DBGT_ERR, "SIGSEGV %d received, try cleaning up (%s-rv%d)...", - sig, SOURCE_VERSION, REVISION_VERSION); + TRACE_FUNCTION_CALL; + static int segfault = NO;
if (!segfault) {
segfault = YES;
- signal(SIGSEGV, SIG_DFL); + dbg(DBGL_SYS, DBGT_ERR, "First SIGSEGV %d received, try cleaning up...", sig); + +#ifndef NO_TRACE_FUNCTION_CALLS + debug_function_calls(); +#endif
+ dbg(DBGL_SYS, DBGT_ERR, "Terminating with error code %d (%s-%s-cv%d)! Please notify a developer", + sig, BMX_BRANCH, BRANCH_VERSION, CODE_VERSION);
- if (!on_the_fly) + if (initializing) { dbg(DBGL_SYS, DBGT_ERR, "check up-to-dateness of bmx libs in default lib path %s or customized lib path defined by %s !", BMX_DEF_LIB_PATH, BMX_ENV_LIB_PATH); - + }
if (!cleaning_up) cleanup_all(CLEANUP_RETURN);
dbg(DBGL_SYS, DBGT_ERR, "raising SIGSEGV again ..."); + + } else { + dbg(DBGL_SYS, DBGT_ERR, "Second SIGSEGV %d received, giving up! core contains second SIGSEV!", sig); }
+ signal(SIGSEGV, SIG_DFL); errno=0; if ( raise( SIGSEGV ) ) { dbg( DBGL_SYS, DBGT_ERR, "raising SIGSEGV failed: %s...", strerror(errno) ); @@ -1459,12 +1093,12 @@ static void segmentation_fault(int32_t sig) }
-void cleanup_all(int status) +void cleanup_all(int32_t status) { + TRACE_FUNCTION_CALL;
if (status < 0) { - dbg(DBGL_SYS, DBGT_ERR, "Terminating with error code %d ! Please notify a developer", status); - segmentation_fault(1); + segmentation_fault(status); }
if (!cleaning_up) { @@ -1475,48 +1109,33 @@ void cleanup_all(int status)
// first, restore defaults...
- stop = 1; + terminating = 1;
cleanup_schedule();
- - if (my_orig_node.dhn) { - my_orig_node.dhn->on = NULL; - free_dhash_node(my_orig_node.dhn); + if (self.dhn) { + self.dhn->on = NULL; + free_dhash_node(self.dhn); }
- avl_remove(&orig_tree, &(my_orig_node.id), -300203); + avl_remove(&orig_tree, &(self.id), -300203);
- purge_orig( NULL, NO ); + purge_link_and_orig_nodes(NULL, NO);
cleanup_plugin();
cleanup_config();
- cleanup_route(); - - cleanup_msg(); + cleanup_ip();
- purge_dhash_to_list(YES); + purge_dhash_invalid_list(YES);
- while (dev_name_tree.items) { - - struct dev_node *dev = dev_name_tree.root->item; - - if ( dev->active ) - dev_deactivate( dev ); - - avl_remove(&dev_name_tree, &dev->name, -300204); - - debugFree(dev, -300046); - - } - // last, close debugging system and check for forgotten resources... + cleanup_control();
- checkLeak(); + checkLeak();
dbgf_all( DBGT_ERR, "...cleaning up done");
@@ -1537,7 +1156,6 @@ void cleanup_all(int status) exit(EXIT_FAILURE); dbg(DBGL_SYS, DBGT_ERR, "exit ignored!?"); } - }
@@ -1556,390 +1174,159 @@ void cleanup_all(int status)
STATIC_FUNC -int32_t opt_show_origs(uint8_t cmd, uint8_t _save, struct opt_type *opt, struct opt_parent *patch, struct ctrl_node *cn) +int32_t opt_status(uint8_t cmd, uint8_t _save, struct opt_type *opt, struct opt_parent *patch, struct ctrl_node *cn) { - - int rq, tq, rtq; + TRACE_FUNCTION_CALL;
if ( cmd == OPT_APPLY ) {
- if (!strcmp(opt->long_name, ARG_ORIGINATORS)) { - - dbg_printf(cn, "Originator: rand primary_ip via " - "metric mid4o descSQN ogmSQN < max lupd lref pogi pws\n"); + if (!strcmp(opt->long_name, ARG_STATUS)) {
- struct avl_node *it = NULL; - - while ((it = avl_iterate(&orig_tree, it))) { - - struct orig_node *on = it->item; - - struct link_dev_node *lndev = avl_find_item(&link_dev_tree, &on->router_key); - - dbg_printf(cn, "%-22s %8X%8X %-15s %-15s %-10s" "%6i %5d %5d %5d %5d %5d %4d %5d %4d\n", - on->id.name, ntohl(on->id.rand.u32[0]), ntohl(on->id.rand.u32[1]), - on->blocked ? "BLOCKED" : on->primary_ip4_str, - ipStr(lndev ? lndev->key.llip4 : 0), - lndev ? lndev->key.dev->name : "---", - on->router_path_metric, - on->dhn->myIID4orig, on->desc0_sqn, - on->ogm_sqn_to_be_send, - (on->ogm_sqn_min + on->ogm_sqn_range), - (bmx_time - on->updated_timestamp) / 1000, - (bmx_time - on->dhn->referred_timestamp) / 1000, - ntohs(on->desc0->path_ogi), ntohs(on->desc0->path_window_size) - ); - - //process_description_tlvs( on, NULL, TLV_DEBUG, cn ); - } - - - } else if (!strcmp(opt->long_name, ARG_STATUS)) { - - dbg_printf(cn, "BMX %s-rv%d, %s, LWS %i, PWS %i, OGI %4ims, UT %s, CPU %d.%1d\n", - SOURCE_VERSION, REVISION_VERSION, my_orig_node.primary_ip4_str, local_lws, my_pws, my_ogm_interval, + dbg_printf(cn, "%s-%s (compatibility=%d code=cv%d) primary %s=%s ip=%s uptime=%s CPU=%d.%1d\n", + BMX_BRANCH, BRANCH_VERSION, COMPATIBILITY_VERSION, CODE_VERSION, + primary_dev_cfg->arg_cfg, primary_dev_cfg->label_cfg.str, self.primary_ip_str, get_human_uptime(0), s_curr_avg_cpu_load / 10, s_curr_avg_cpu_load % 10);
+ cb_plugin_hooks(PLUGIN_CB_STATUS, cn); + + dbg_printf(cn, "\n");
- } else if ( !strcmp( opt->long_name, ARG_LINKS ) ) { + } else if ( !strcmp( opt->long_name, ARG_LINKS ) ) { +#define DBG_STATUS4_LINK_HEAD "%-16s %-10s %3s %3s %3s %7s %1s %7s %8s %8s %5s %5s %4s %4s\n" +#define DBG_STATUS6_LINK_HEAD "%-30s %-10s %3s %3s %3s %7s %1s %7s %8s %8s %5s %5s %4s %4s\n" +#define DBG_STATUS4_LINK_INFO "%-16s %-10s %3ju %3ju %3ju %7ju %1s %7ju %8X %8X %5d %5d %4d %4s\n" +#define DBG_STATUS6_LINK_INFO "%-30s %-10s %3ju %3ju %3ju %7ju %1s %7ju %8X %8X %5d %5d %4d %4s\n"
- dbg_printf(cn, "LinkLocalIP viaIF bestIF primaryIP RTQ RQ TQ oid4m lseq lvld\n"); + dbg_printf(cn, (af_cfg == AF_INET ? DBG_STATUS4_LINK_HEAD : DBG_STATUS6_LINK_HEAD), + "LinkLocalIP", "viaIF", "RTQ", "RQ", "TQ", "linkM/k", " ", "bestM/k", + "myLinkID", "nbLinkID", "nbIID", "lSqn", "lVld", "pref");
- struct avl_node *it = NULL; + struct avl_node *it; + struct link_node *ln;
- while ((it = avl_iterate(&link_tree, it))) { + for (it = NULL; (ln = avl_iterate_item(&link_tree, &it));) {
- struct link_node *ln = it->item; struct neigh_node *nn = ln->neigh; - struct orig_node *on = nn ? nn->dhn->on : NULL;
struct list_node *lndev_pos;
- list_for_each( lndev_pos, &ln->lndev_list ) { - struct link_dev_node *lndev = list_entry( lndev_pos, struct link_dev_node, list ); - - rq = lndev->mr[SQR_RQ].val; - tq = TQ_RATE( lndev, PROBE_RANGE); // tq_rate( lndev, PROBE_RANGE ); - rtq = lndev->mr[SQR_RTQ].val; - - - dbg_printf( cn, "%-15s %-10s %-10s %-15s %4i %4i %4i %5d %5i %4i\n", - ipStr(ln->llip4), - lndev->key.dev->name, - ln->neigh && ln->neigh->best_rtq ? ln->neigh->best_rtq->key.dev->name : "---", - on ? on->primary_ip4_str : "???", - rtq , rq, tq, + list_for_each( lndev_pos, &ln->lndev_list ) + { + struct link_dev_node *lndev = list_entry(lndev_pos, struct link_dev_node, list); + UMETRIC_T bestM = ln->neigh && ln->neigh->dhn && ln->neigh->dhn->on->best_rn ? ln->neigh->dhn->on->best_rn->mr.umetric_final : 0; + + dbg_printf(cn, (af_cfg == AF_INET ? DBG_STATUS4_LINK_INFO : DBG_STATUS6_LINK_INFO), + ipXAsStr(af_cfg, &ln->link_ip), + lndev->key.dev->label_cfg.str, + (((lndev->mr[SQR_RTQ].umetric_final) *100)/lndev->key.dev->umetric_max), + (((lndev->mr[SQR_RQ].umetric_final) *100)/lndev->key.dev->umetric_max), + lndev->mr[SQR_RQ].umetric_final ? (((lndev->mr[SQR_RTQ].umetric_final) *100) / lndev->mr[SQR_RQ].umetric_final) : 0, + lndev->umetric_link >> 10, + lndev->umetric_link >= bestM ? ">" : "<", + bestM >> 10, + lndev->key.dev->link_id, + ln->link_id, nn ? nn->neighIID4me : 0, - ln->rq_sqn_max, - (bmx_time - lndev->rtq_time_max) / 1000 + ln->rq_hello_sqn_max, + (bmx_time - lndev->rtq_time_max) / 1000, + ln->neigh ? (lndev == ln->neigh->best_rtq ? "BEST" : "second") : "???" );
}
} + dbg_printf(cn, "\n");
- } else { - return FAILURE; - } - - dbg_printf( cn, "\n" ); - } - - return SUCCESS; -} - - -STATIC_FUNC -int32_t opt_dev_show(uint8_t cmd, uint8_t _save, struct opt_type *opt, struct opt_parent *patch, struct ctrl_node *cn) -{ - - if ( cmd == OPT_APPLY ) { - - struct avl_node *it=NULL; - struct dev_node *dev; - while ((dev = avl_iterate_item(&dev_name_tree, &it))) { - - dbg_cn( cn, DBGL_ALL, DBGT_NONE, "%-10s %5d %8s %15s/%-2d brc %-15s SQN %5d %14s %8s %11s", - dev->name, - dev->index, - !dev->active ? "-" : - ( dev->linklayer == VAL_DEV_LL_LO ? "loopback": - ( dev->linklayer == VAL_DEV_LL_LAN ? "ethernet": - ( dev->linklayer == VAL_DEV_LL_WLAN ? "wireless": "???" ) ) ), - dev->ip4_str, - dev->ip4_prefix_length, - ipStr(dev->ip4_broad), - dev->ogm_sqn, - dev->announce ? "announced" : "not announced", - dev->active ? "active" : "inactive", - dev == primary_if ? "primary" : "non-primary" - ); - - } - } - return SUCCESS; -} -STATIC_FUNC -int32_t opt_dev(uint8_t cmd, uint8_t _save, struct opt_type *opt, struct opt_parent *patch, struct ctrl_node *cn) -{ - - struct list_node *list_pos; - struct dev_node *dev = NULL; - - struct dev_node test_bif; - - char *colon_ptr; - - dbgf_all( DBGT_INFO, "cmd: %s opt: %s instance %s", - opt_cmd2str[cmd], opt->long_name, patch ? patch->p_val : ""); - - if ( cmd == OPT_CHECK || cmd == OPT_APPLY ) { - - if ( strlen(patch->p_val) >= IFNAMSIZ ) { - dbg_cn( cn, DBGL_SYS, DBGT_ERR, "dev name MUST be smaller than %d chars", IFNAMSIZ ); - return FAILURE; - } - - dev = get_bif( patch->p_val ); - - if ( patch->p_diff == DEL ) { - - if ( dev && primary_if == dev ) { + } else if (!strcmp(opt->long_name, ARG_ORIGINATORS)) {
- dbg_cn( cn, DBGL_SYS, DBGT_ERR, - "primary interface %s %s can not be removed!", - dev->name, dev->ip4_str ); - - return FAILURE; - - } else if ( dev && cmd == OPT_APPLY ) { - - if ( dev->active ) - dev_deactivate( dev ); - - avl_remove( &dev_name_tree, &dev->name, -300205 ); - - debugFree(dev, -300048); - - return SUCCESS; - - - } else if ( !dev ) { - - dbgf_cn( cn, DBGL_SYS, DBGT_ERR, "Interface does not exist!" ); - return FAILURE; - } - } - - if ( !dev ) { - - if ( cmd == OPT_APPLY ) { - int i; - dev = debugMalloc( sizeof(struct dev_node), -300002 ); - memset(dev, 0, sizeof (struct dev_node)); - - if (!dev_name_tree.items) - primary_if = dev; - - snprintf(dev->name, wordlen(patch->p_val) + 1, "%s", patch->p_val); - - avl_insert( &dev_name_tree, dev, -300144 ); + struct avl_node *it; + struct orig_node *on; + UMETRIC_T total_metric = 0; + uint32_t total_lref = 0; + char *empty = ""; + +#define DBG_STATUS4_ORIG_HEAD "%-22s %-16s %3s %-16s %-10s %9s %5s %5s %5s %1s %5s %4s\n" +#define DBG_STATUS6_ORIG_HEAD "%-22s %-40s %3s %-40s %-10s %9s %5s %5s %5s %1s %5s %4s\n" +#define DBG_STATUS4_ORIG_INFO "%-22s %-16s %3d %-16s %-10s %9ju %5d %5d %5d %1d %5d %4d\n" +#define DBG_STATUS6_ORIG_INFO "%-22s %-40s %3d %-40s %-10s %9ju %5d %5d %5d %1d %5d %4d\n" +#define DBG_STATUS4_ORIG_TAIL "%-22s %-16d %3s %-16s %-10s %9ju %5s %5s %5s %1s %5s %4d\n" +#define DBG_STATUS6_ORIG_TAIL "%-22s %-40d %3s %-40s %-10s %9ju %5s %5s %5s %1s %5s %4d\n" + + + + dbg_printf(cn, (af_cfg == AF_INET ? DBG_STATUS4_ORIG_HEAD : DBG_STATUS6_ORIG_HEAD), + "Orig ID.name", "primaryIP", "RTs", "currRT", "viaDev", + "Metric/k","myIID", "desc#", "ogm#", "d", "lUpd", "lRef"); + + for (it = NULL; (on = avl_iterate_item(&orig_tree, &it));) { + + dbg_printf(cn, (af_cfg == AF_INET ? DBG_STATUS4_ORIG_INFO : DBG_STATUS6_ORIG_INFO), + on->id.name, + on->blocked ? "BLOCKED" : on->primary_ip_str, + on->rt_tree.items, + ipXAsStr(af_cfg, (on->curr_rn ? &on->curr_rn->key.link->link_ip : &ZERO_IP)), + on->curr_rn && on->curr_rn->key.dev ? on->curr_rn->key.dev->name_phy_cfg.str : " ", + on->curr_rn ? ((on->curr_rn->mr.umetric_final) >> 10) : + (on == &self ? (umetric_max(DEF_FMETRIC_EXP_OFFSET)) >> 10 : 0), + on->dhn->myIID4orig, on->descSqn, + on->ogmSqn_toBeSend, + (on->ogmSqn_maxRcvd - on->ogmSqn_toBeSend), + (bmx_time - on->updated_timestamp) / 1000, + (bmx_time - on->dhn->referred_by_me_timestamp) / 1000 + );
- for (i = 0; i < FRAME_TYPE_ARRSZ; i++) { - LIST_INIT_HEAD(dev->tx_tasks_list[i], struct tx_task_node, list); + if (on != &self) { + total_metric += (on->curr_rn ? ((on->curr_rn->mr.umetric_final) >> 10) : 0); + total_lref += (bmx_time - on->dhn->referred_by_me_timestamp) / 1000; }
- AVL_INIT_TREE( dev->tx_timestamp_tree, struct tx_timestamp_node, key ); - - - - } else { - - dev = &test_bif; - memset(dev, 0, sizeof (struct dev_node)); - snprintf(dev->name, wordlen(patch->p_val) + 1, "%s", patch->p_val); - }
-// bif->aggregation_out = bif->aggregation_out_buff; - - snprintf( dev->name_phy, wordlen(patch->p_val)+1, "%s", patch->p_val ); - - /* if given interface is an alias record physical interface name*/ - if ( ( colon_ptr = strchr( dev->name_phy, ':' ) ) != NULL ) - *colon_ptr = '\0'; - - dbgf_all( DBGT_INFO, "assign dev %s physical name %s", dev->name, dev->name_phy ); - - dev->ogm_sqn = rand_num(MAX_SQN); - - dev->packet_sqn = rand_num(MAX_SQN); - - // bif->aggregation_len = sizeof( struct bmx_pkt_hdr ); - - - // some configurable interface values - initialized to unspecified: - dev->send_clones_conf = -1; - dev->antenna_diversity_conf = -1; - dev->linklayer_conf = -1; - dev->announce_conf = -1; - - } - - if ( cmd == OPT_CHECK ) - return SUCCESS; - - list_for_each( list_pos, &patch->childs_instance_list ) { - - struct opt_child *c = list_entry( list_pos, struct opt_child, list ); - - int32_t val = c->c_val ? strtol( c->c_val , NULL , 10 ) : -1 ; - - if ( !strcmp( c->c_opt->long_name, ARG_DEV_CLONE ) ) { - - dev->send_clones_conf = val; - - } else if ( !strcmp( c->c_opt->long_name, ARG_DEV_ANTDVSTY ) ) { - - dev->antenna_diversity_conf = val; - - } else if ( !strcmp( c->c_opt->long_name, ARG_DEV_LL ) ) { - - dev->linklayer_conf = val; - dev->hard_conf_changed = YES; - - } else if ( !strcmp( c->c_opt->long_name, ARG_DEV_ANNOUNCE ) ) { - - dev->announce_conf = val; - } + dbg_printf(cn, (af_cfg == AF_INET ? DBG_STATUS4_ORIG_TAIL : DBG_STATUS6_ORIG_TAIL), + "Averages:", orig_tree.items, empty, empty, empty, + (orig_tree.items > 1 ? total_metric / (orig_tree.items - 1) : 0), + empty, empty, empty, empty, empty, + orig_tree.items > 1 ? ((total_lref + ((orig_tree.items - 1) / 2)) / (orig_tree.items - 1)) : 0);
- dev->soft_conf_changed = YES;
+ } else { + return FAILURE; }
- - } else if ( cmd == OPT_POST && opt && !opt->parent_name ) { - - dev_check(); //will always be called whenever a parameter is changed (due to OPT_POST) - - } + }
return SUCCESS; }
+ STATIC_FUNC int32_t opt_purge(uint8_t cmd, uint8_t _save, struct opt_type *opt, struct opt_parent *patch, struct ctrl_node *cn) { + TRACE_FUNCTION_CALL;
if ( cmd == OPT_APPLY) - purge_orig(NULL, NO); - - return SUCCESS; -} - - -/* -STATIC_FUNC -int32_t opt_if_soft(uint8_t cmd, uint8_t _save, struct opt_type *opt, struct opt_parent *patch, struct ctrl_node *cn) -{ - - if ( cmd == OPT_APPLY ) - if_conf_soft_changed = YES; + purge_link_and_orig_nodes(NULL, NO);
return SUCCESS; } -*/
-#ifdef WITHUNUSED
STATIC_FUNC -int32_t opt_if_hard(uint8_t cmd, uint8_t _save, struct opt_type *opt, struct opt_parent *patch, struct ctrl_node *cn) -{ - - if ( cmd == OPT_APPLY ) - if_conf_hard_changed = YES; - - return SUCCESS; -} -#endif - - int32_t opt_update_description(uint8_t cmd, uint8_t _save, struct opt_type *opt, struct opt_parent *patch, struct ctrl_node *cn) { + TRACE_FUNCTION_CALL;
if ( cmd == OPT_APPLY ) - if_conf_soft_changed = YES; - - return SUCCESS; -} - -STATIC_FUNC -int32_t opt_path_metric(uint8_t cmd, uint8_t _save, struct opt_type *opt, struct opt_parent *patch, struct ctrl_node *cn) -{ - + my_description_changed = YES;
- if (cmd == OPT_CHECK || cmd == OPT_APPLY || cmd == OPT_REGISTER) {
- struct metric_algo test_algo; - memset(&test_algo, 0, sizeof (struct metric_algo)); + if (cmd == OPT_POST && my_description_changed) + update_my_description_adv();
- test_algo.sqn_mask = ((SQN_T)(0xFFFF << DEF_OGM0_PQ_BITS)); - test_algo.sqn_steps = (0x01 << DEF_OGM0_PQ_BITS); - test_algo.regression = my_pws / test_algo.sqn_steps / 2; - test_algo.sqn_lounge = my_path_lounge; - test_algo.sqn_window = my_pws; - test_algo.metric_max = PROBE_RANGE; - - if (validate_metric_algo(&test_algo, cn) == FAILURE) - return FAILURE; - - if (cmd == OPT_APPLY || cmd == OPT_REGISTER) - memcpy(&(my_orig_node.path_metric_algo), &test_algo, sizeof (struct metric_algo)); - - } - - if ( cmd == OPT_APPLY ) - if_conf_soft_changed = YES;
return SUCCESS; }
-STATIC_FUNC -int32_t opt_link_metric(uint8_t cmd, uint8_t _save, struct opt_type *opt, struct opt_parent *patch, struct ctrl_node *cn) -{ - if (cmd == OPT_CHECK || cmd == OPT_APPLY || cmd == OPT_REGISTER) { - - struct metric_algo test_algo[SQR_RANGE]; - memset(test_algo, 0, SQR_RANGE * sizeof (struct metric_algo)); - - test_algo[SQR_RTQ].sqn_mask = 0xFFFF; - test_algo[SQR_RTQ].sqn_steps = 1; - test_algo[SQR_RTQ].regression = local_lws / 2; - test_algo[SQR_RTQ].sqn_lounge = local_rtq_lounge; - test_algo[SQR_RTQ].sqn_window = local_lws; - test_algo[SQR_RTQ].metric_max = PROBE_RANGE; - - if (validate_metric_algo(&(test_algo[SQR_RTQ]), cn) == FAILURE) - return FAILURE; - - test_algo[SQR_RQ].sqn_mask = 0xFFFF; - test_algo[SQR_RQ].sqn_steps = 1; - test_algo[SQR_RQ].regression = local_lws / 2; - test_algo[SQR_RQ].sqn_lounge = RQ_LINK_LOUNGE; - test_algo[SQR_RQ].sqn_window = local_lws; - test_algo[SQR_RQ].metric_max = PROBE_RANGE; - - if (validate_metric_algo(&(test_algo[SQR_RQ]), cn) == FAILURE) - return FAILURE; - - if (cmd == OPT_APPLY || cmd == OPT_REGISTER) - memcpy(link_metric_algo, test_algo, SQR_RANGE * sizeof (struct metric_algo)); - - - } - - return SUCCESS; -}
static struct opt_type bmx_options[]= @@ -1949,115 +1336,49 @@ static struct opt_type bmx_options[]= {ODI,0,0, 0, 5,0,0,0,0,0, 0, 0, 0, 0, 0, 0, "\nProtocol options:"},
- {ODI,0,ARG_STATUS, 0, 5,A_PS0,A_USR,A_DYN,A_ARG,A_ANY, 0, 0, 0, 0, opt_show_origs, + {ODI,0,ARG_STATUS, 0, 5,A_PS0,A_USR,A_DYN,A_ARG,A_ANY, 0, 0, 0, 0, opt_status, 0, "show status\n"},
- {ODI,0,ARG_ROUTES, 0, 5,A_PS0,A_USR,A_DYN,A_ARG,A_ANY, 0, 0, 0, 0, opt_show_origs, +/* + {ODI,0,ARG_ROUTES, 0, 5,A_PS0,A_USR,A_DYN,A_ARG,A_ANY, 0, 0, 0, 0, opt_status, 0, "show routes\n"}, +*/
- {ODI,0,ARG_LINKS, 0, 5,A_PS0,A_USR,A_DYN,A_ARG,A_ANY, 0, 0, 0, 0, opt_show_origs, + {ODI,0,ARG_LINKS, 0, 5,A_PS0,A_USR,A_DYN,A_ARG,A_ANY, 0, 0, 0, 0, opt_status, 0, "show links\n"},
- {ODI,0,ARG_ORIGINATORS, 0, 5,A_PS0,A_USR,A_DYN,A_ARG,A_ANY, 0, 0, 0, 0, opt_show_origs, + {ODI,0,ARG_ORIGINATORS, 0, 5,A_PS0,A_USR,A_DYN,A_ARG,A_ANY, 0, 0, 0, 0, opt_status, 0, "show originators\n"},
- {ODI,0,ARG_DEV, 0, 5,A_PMN,A_ADM,A_DYI,A_CFA,A_ANY, 0, 0, 0, 0, opt_dev, - "<interface-name>", "add or change device or its configuration, options for specified device are:"}, - #ifndef LESS_OPTIONS - {ODI,ARG_DEV,ARG_DEV_TTL, 't',5,A_CS1,A_ADM,A_DYI,A_CFA,A_ANY, 0, MIN_TTL, MAX_TTL, DEF_TTL, opt_dev, - ARG_VALUE_FORM, "set TTL of generated OGMs"}, - - {ODI,ARG_DEV,ARG_DEV_CLONE, 'c',5,A_CS1,A_ADM,A_DYI,A_CFA,A_ANY, 0, MIN_WL_CLONES, MAX_WL_CLONES, DEF_WL_CLONES, opt_dev, - ARG_VALUE_FORM, "broadcast OGMs per ogm-interval with given probability (e.g. 200% will broadcast the same OGM twice)"}, - - /* Antenna-diversity support for bmxd seems working but unfortunately there are few wireless drivers which support - * my understanding of the typical antenna-diversity implementation. This is what I hoped (maybe I am wrong): - * - The RX-antenna is detected on-the-fly on a per-packet basis by comparing - * the rcvd signal-strength via each antenna during reception of the phy-preamble. - * - The TX-antenna is determined per MAC-address based on the last detected best RX-antenna for this MAC. - * - Broadcast packets should be send round-robin like via each enabled TX-antenna (e.g. alternating via ant1 and ant2). */ - {ODI,ARG_DEV,ARG_DEV_ANTDVSTY, 0, 5,A_CS1,A_ADM,A_DYI,A_CFA,A_ANY, 0, 1, 2, 1, opt_dev, - ARG_VALUE_FORM, 0/*"set number of broadcast antennas (e.g. for antenna-diversity use /d=2 /c=400 aggreg_interval=100)"*/}, - +
- {ODI,ARG_DEV,ARG_DEV_ANNOUNCE, 'a',5,A_CS1,A_ADM,A_DYI,A_CFA,A_ANY, 0, 0, 1, DEF_DEV_ANNOUNCE,opt_dev, - ARG_VALUE_FORM, "disable/enable announcement of interface IP"}, -#endif - - {ODI,ARG_DEV,ARG_DEV_LL, 'l',5,A_CS1,A_ADM,A_DYI,A_CFA,A_ANY, 0, VAL_DEV_LL_LAN, VAL_DEV_LL_WLAN,0, opt_dev, - ARG_VALUE_FORM, "manually set device type for linklayer specific optimization (1=lan, 2=wlan)"}, - - {ODI,0,ARG_INTERFACES, 0, 5,A_PS0,A_USR,A_DYI,A_ARG,A_ANY, 0, 0, 1, 0, opt_dev_show, - 0, "show configured interfaces"}, - - {ODI,0,ARG_LWS, 0, 5,A_PS1,A_ADM,A_DYI,A_CFA,A_ANY, &local_lws, MIN_LWS, MAX_LWS, DEF_LWS, opt_link_metric, - ARG_VALUE_FORM, "set link window size (LWS) for link-quality calculation (link metric)"}, - -#ifndef LESS_OPTIONS - - {ODI,0,ARG_RTQ_LOUNGE, 0, 5,A_PS1,A_ADM,A_DYI,A_CFA,A_ANY, &local_rtq_lounge,MIN_RTQ_LOUNGE,MAX_RTQ_LOUNGE,DEF_RTQ_LOUNGE, opt_link_metric, - ARG_VALUE_FORM, "set local LLS buffer size to artificially delay OGM processing for ordered link-quality calulation"}, - - {ODI,0,ARG_PWS, 0, 5,A_PS1,A_ADM,A_DYI,A_CFA,A_ANY, &my_pws, MIN_PWS, MAX_PWS, DEF_PWS, opt_path_metric, - ARG_VALUE_FORM, "set path window size (PWS) for end2end path-quality calculation (path metric)"}, - - {ODI,0,ARG_PATH_LOUNGE, 0, 5,A_PS1,A_ADM,A_DYI,A_CFA,A_ANY, &my_path_lounge,MIN_PATH_LOUNGE,MAX_PATH_LOUNGE,DEF_PATH_LOUNGE, opt_path_metric, - ARG_VALUE_FORM, "set default PLS buffer size to artificially delay my OGM processing for ordered path-quality calulation"}, - - {ODI,0,ARG_PATH_HYST, 0, 5,A_PS1,A_ADM,A_DYI,A_CFA,A_ANY, &my_path_hystere,MIN_PATH_HYST, MAX_PATH_HYST, DEF_PATH_HYST, opt_path_metric, - ARG_VALUE_FORM, "use hysteresis to delay route switching to alternative next-hop neighbors with better path metric"}, - - - {ODI,0,ARG_RCNT_PWS, 0, 5,A_PS1,A_ADM,A_DYI,A_CFA,A_ANY, &my_rcnt_pws, MIN_RCNT_PWS, MAX_RCNT_PWS, DEF_RCNT_PWS, opt_path_metric, - ARG_VALUE_FORM, ""}, - - {ODI,0,ARG_RCNT_HYST, 0, 5,A_PS1,A_ADM,A_DYI,A_CFA,A_ANY, &my_rcnt_hystere,MIN_RCNT_HYST, MAX_RCNT_HYST, DEF_RCNT_HYST, opt_path_metric, - ARG_VALUE_FORM, "use hysteresis to delay fast-route switching to alternative next-hop neighbors with a recently extremely better path metric"}, - - {ODI,0,ARG_RCNT_FK, 0, 5,A_PS1,A_ADM,A_DYI,A_CFA,A_ANY, &my_rcnt_fk, MIN_RCNT_FK, MAX_RCNT_FK, DEF_RCNT_FK, opt_path_metric, - ARG_VALUE_FORM, "configure threshold faktor for dead-path detection"}, - - - {ODI,0,ARG_DROP_2HLOOP, 0, 5,A_PS1,A_ADM,A_DYI,A_CFA,A_ANY, &drop_2hop_loop,MIN_DROP_2HLOOP,MAX_DROP_2HLOOP,DEF_DROP_2HLOOP,0, - ARG_VALUE_FORM, "drop OGMs received via two-hop loops"}, - - - {ODI,0,ARG_ASYM_EXP, 0, 5,A_PS1,A_ADM,A_DYI,A_CFA,A_ANY, &asym_exp, MIN_ASYM_EXP, MAX_ASYM_EXP, DEF_ASYM_EXP, 0, - ARG_VALUE_FORM, "ignore OGMs (rcvd via asymmetric links) with TQ^<val> to radically reflect asymmetric-links"},
{ODI,0,"asocial_device", 0, 5,A_PS1,A_ADM,A_DYI,A_CFA,A_ANY, &Asocial_device,MIN_ASOCIAL, MAX_ASOCIAL, DEF_ASOCIAL, 0, ARG_VALUE_FORM, "disable/enable asocial mode for devices unwilling to forward other nodes' traffic"},
- {ODI,0,ARG_WL_CLONES, 0, 5,A_PS1,A_ADM,A_DYI,A_CFA,A_ANY, &wl_clones, MIN_WL_CLONES, MAX_WL_CLONES, DEF_WL_CLONES, opt_path_metric, - ARG_VALUE_FORM, "broadcast OGMs per ogm-interval for wireless devices with\n" - " given probability [%] (eg 200% will broadcast the same OGM twice)"}, - - {ODI,0,ARG_ASYM_WEIGHT, 0, 5,A_PS1,A_ADM,A_DYI,A_CFA,A_ANY, &asym_weight, MIN_ASYM_WEIGHT,MAX_ASYM_WEIGHT,DEF_ASYM_WEIGHT,opt_path_metric, - ARG_VALUE_FORM, "ignore OGMs (rcvd via asymmetric links) with given probability [%] to better reflect asymmetric-links"}, - - // there SHOULD! be a minimal lateness_penalty >= 1 ! Otherwise a shorter path with equal path-cost than a longer path will never dominate - {ODI,0,ARG_LATE_PENAL, 0, 5,A_PS1,A_ADM,A_DYI,A_CFA,A_ANY, &my_late_penalty,MIN_LATE_PENAL,MAX_LATE_PENAL, DEF_LATE_PENAL, opt_path_metric, - ARG_VALUE_FORM, "penalize non-first rcvd OGMs "}, - #endif + {ODI,0,ARG_TTL, 't',5,A_PS1,A_ADM,A_DYI,A_CFA,A_ANY, &my_ttl, MIN_TTL, MAX_TTL, DEF_TTL, opt_update_description, + ARG_VALUE_FORM, "set time-to-live (TTL) for OGMs"} + , + {ODI,0,ARG_TX_INTERVAL, 0, 5, A_PS1, A_ADM, A_DYI, A_CFA, A_ANY, &my_tx_interval, MIN_TX_INTERVAL, MAX_TX_INTERVAL, DEF_TX_INTERVAL, opt_update_description, + ARG_VALUE_FORM, "set aggregation interval (SHOULD be smaller than the half of your and others OGM interval)"} + , + {ODI,0,ARG_OGM_INTERVAL, 'o',5, A_PS1, A_ADM, A_DYI, A_CFA, A_ANY, &my_ogm_interval, MIN_OGM_INTERVAL, MAX_OGM_INTERVAL, DEF_OGM_INTERVAL, 0, + ARG_VALUE_FORM, "set interval in ms with which new originator message (OGM) are send"} + , + {ODI,0,ARG_OGM_PURGE_TO, 0, 5,A_PS1,A_ADM,A_DYI,A_CFA,A_ANY, &ogm_purge_to, MIN_OGM_PURGE_TO, MAX_OGM_PURGE_TO, DEF_OGM_PURGE_TO, 0, + ARG_VALUE_FORM, "timeout in ms for purging stale originators"} + , + {ODI,0,ARG_LINK_PURGE_TO, 0, 5,A_PS1,A_ADM,A_DYI,A_CFA,A_ANY, &link_purge_to, MIN_LINK_PURGE_TO,MAX_LINK_PURGE_TO,DEF_LINK_PURGE_TO,0, + ARG_VALUE_FORM, "timeout in ms for purging stale originators"} + , {ODI,0,ARG_DAD_TO, 0, 5,A_PS1,A_ADM,A_DYI,A_CFA,A_ANY, &dad_to, MIN_DAD_TO, MAX_DAD_TO, DEF_DAD_TO, 0, - ARG_VALUE_FORM, "duplicate address (DAD) detection timout in seconds"}, - - {ODI,0,ARG_TTL, 't',5,A_PS1,A_ADM,A_DYI,A_CFA,A_ANY, &my_ttl, MIN_TTL, MAX_TTL, DEF_TTL, opt_path_metric, - ARG_VALUE_FORM, "set time-to-live (TTL) for OGMs of primary interface"}, - - {ODI,0,ARG_PURGE_TO, 0, 5,A_PS1,A_ADM,A_DYI,A_CFA,A_ANY, &purge_to, MIN_PURGE_TO, MAX_PURGE_TO, DEF_PURGE_TO, 0, - ARG_VALUE_FORM, "timeout in seconds for purging stale originators"} -, - + ARG_VALUE_FORM, "duplicate address (DAD) detection timout in ms"} + , {ODI,0,"flush_all", 0, 5,A_PS0,A_ADM,A_DYN,A_ARG,A_ANY, 0, 0, 0, 0, opt_purge, 0, "purge all neighbors and routes on the fly"},
- {ODI,0,ARG_OGI_PWRSAVE, 0, 5,A_PS1,A_ADM,A_DYI,A_CFA,A_ANY, &ogi_pwrsave, MIN_OGM_INTERVAL, MAX_OGM_INTERVAL, MIN_OGM_INTERVAL, 0, - ARG_VALUE_FORM, "enable power-saving feature by setting increased OGI when no other nodes are in range"} - - };
IDM_T validate_name( char* name ) { @@ -2078,41 +1399,49 @@ IDM_T validate_name( char* name ) { return SUCCESS; }
-STATIC_FUNC -void init_bmx(void) +void init_orig_node(struct orig_node *on, struct description_id *id) { + TRACE_FUNCTION_CALL; + memset(on, 0, sizeof ( struct orig_node)); + memcpy(&on->id, id, sizeof ( struct description_id));
- static uint8_t my_desc0[MAX_PKT_MSG_SIZE]; + AVL_INIT_TREE(on->rt_tree, struct router_node, key);
- memset( &my_orig_node, 0, sizeof(struct orig_node)); + avl_insert(&orig_tree, on, -300148);
- AVL_INIT_TREE((my_orig_node.router_tree), struct router_node, key); +} + + +STATIC_FUNC +void init_bmx(void) +{
- my_orig_node.desc0 = (struct description *) my_desc0; + static uint8_t my_desc0[MAX_PKT_MSG_SIZE]; + static struct description_id id; + memset(&id, 0, sizeof (id));
- if (gethostname(my_orig_node.id.name, DESCRIPTION0_ID_NAME_LEN)) + if (gethostname(id.name, DESCRIPTION0_ID_NAME_LEN)) cleanup_all(-500240);
- my_orig_node.id.name[DESCRIPTION0_ID_NAME_LEN - 1] = 0; + id.name[DESCRIPTION0_ID_NAME_LEN - 1] = 0;
- if (validate_name(my_orig_node.id.name) == FAILURE) { - dbg(DBGL_SYS, DBGT_ERR, "illegal hostname %s", my_orig_node.id.name); + if (validate_name(id.name) == FAILURE) { + dbg(DBGL_SYS, DBGT_ERR, "illegal hostname %s", id.name); cleanup_all(-500272); }
- my_orig_node.id.rand.u16[0] = (uint16_t) rand_num(U16_MAX); - my_orig_node.id.rand.u16[1] = (uint16_t) rand_num(U16_MAX); - my_orig_node.id.rand.u16[2] = (uint16_t) rand_num(U16_MAX); - my_orig_node.id.rand.u16[3] = (uint16_t) rand_num(U16_MAX); + RNG_GenerateBlock(&rng, id.rand.u8, DESCRIPTION0_ID_RANDOM_LEN); + + init_orig_node(&self, &id);
- my_orig_node.ogm_sqn_min = (((uint16_t) rand_num(MAX_SQN)) & (MAX_SQN << MAX_OGM0_PQ_BITS)); + self.desc = (struct description *) my_desc0;
- my_orig_node.desc0_sqn = rand_num(MAX_SQN);
- avl_insert( &orig_tree, &my_orig_node, -300175 ); + self.ogmSqn_rangeMin = ((OGM_SQN_MASK) & rand_num(OGM_SQN_MAX));
- register_options_array( bmx_options, sizeof( bmx_options ) ); + self.descSqn = ((DESC_SQN_MASK) & rand_num(DESC_SQN_MAX));
+ register_options_array(bmx_options, sizeof ( bmx_options)); }
@@ -2124,42 +1453,40 @@ void bmx(void)
struct list_node *list_pos; struct dev_node *dev; - uint32_t regular_timeout, statistic_timeout; + TIME_T regular_timeout, statistic_timeout;
- uint32_t s_last_cpu_time = 0, s_curr_cpu_time = 0; + TIME_T s_last_cpu_time = 0, s_curr_cpu_time = 0;
regular_timeout = statistic_timeout = bmx_time;
- on_the_fly = YES; + initializing = NO;
- while ( !terminating() ) { + while (!terminating) {
- uint32_t wait = whats_next( ); + TIME_T wait = whats_next( );
if ( wait ) wait4Event( MIN( wait, MAX_SELECT_TIMEOUT_MS ) );
// The regular tasks... - if ( LESS_U32( regular_timeout + 1000, bmx_time ) ) { - - - // check for changed kernel konfigurations... - check_kernel_config( NULL ); + if ( U32_LT( regular_timeout + 1000, bmx_time ) ) {
// check for changed interface konfigurations... struct avl_node *an = NULL; while ((dev = avl_iterate_item(&dev_name_tree, &an))) {
- if ( dev->active ) - check_kernel_config( dev ); + if ( dev->active ) { + + sysctl_config( dev );
- purge_tx_timestamp_tree(dev, NO); + //purge_tx_timestamp_tree(dev, NO); + }
}
- purge_orig(NULL, YES); + purge_link_and_orig_nodes(NULL, YES);
- purge_dhash_to_list(NO); + purge_dhash_invalid_list(NO);
close_ctrl_node( CTRL_CLEANUP, 0 );
@@ -2181,53 +1508,53 @@ void bmx(void) }
- if ( LESS_U32( statistic_timeout + 5000, bmx_time ) ) { + if ( U32_LT( statistic_timeout + 5000, bmx_time ) ) {
struct orig_node *on; struct description_id id; - memset(&id, 0, sizeof (struct description_id));
while ((on = avl_next_item(&blocked_tree, &id))) {
memcpy( &id, &on->id, sizeof(struct description_id));
- dbgf_all( DBGT_INFO, "trying to unblock %s...", on->desc0->id.name); + dbgf_all( DBGT_INFO, "trying to unblock %s...", on->desc->id.name);
- IDM_T tlvs_res = process_description_tlvs(on, on->desc0, TLV_DEL_TEST_ADD, NULL); - - assertion(-500364, (tlvs_res == TLVS_BLOCKED || tlvs_res == TLVS_SUCCESS)); + IDM_T tlvs_res; + if ((tlvs_res = process_description_tlvs(NULL, on, on->desc, TLV_OP_TEST, FRAME_TYPE_PROCESS_ALL, NULL)) == TLV_RX_DATA_DONE) { + tlvs_res = process_description_tlvs(NULL, on, on->desc, TLV_OP_ADD, FRAME_TYPE_PROCESS_ALL, NULL); + assertion(-500364, (tlvs_res == TLV_RX_DATA_DONE)); // checked, so MUST SUCCEED!! + }
dbgf(DBGL_CHANGES, DBGT_INFO, "unblocking %s %s !", - on->desc0->id.name, tlvs_res == TLVS_SUCCESS ? "success" : "failed"); + on->desc->id.name, tlvs_res == TLV_RX_DATA_DONE ? "success" : "failed");
}
- // check for corrupted memory.. checkIntegrity();
/* generating cpu load statistics... */ - s_curr_cpu_time = (uint32_t)clock(); + s_curr_cpu_time = (TIME_T)clock();
- s_curr_avg_cpu_load = ( (s_curr_cpu_time - s_last_cpu_time) / (uint32_t)(bmx_time - statistic_timeout) ); + s_curr_avg_cpu_load = ( (s_curr_cpu_time - s_last_cpu_time) / (TIME_T)(bmx_time - statistic_timeout) );
s_last_cpu_time = s_curr_cpu_time;
statistic_timeout = bmx_time; } } - }
-int main( int argc, char *argv[] ) -{
+int main(int argc, char *argv[]) +{ // make sure we are using compatible description0 sizes: assertion(-500201, (MSG_DESCRIPTION0_ADV_SIZE == sizeof ( struct msg_description_adv)));
+ gettimeofday( &start_time_tv, NULL ); gettimeofday( &new_tv, NULL );
@@ -2235,9 +1562,16 @@ int main( int argc, char *argv[] )
My_pid = getpid();
- srand( My_pid );
- init_set_bits_table256(); + if ( InitRng(&rng) != 0 ) { + cleanup_all( -500525 ); + } + + unsigned int random; + + RNG_GenerateBlock(&rng, (byte*)&random, sizeof (random)); + + srand( random );
signal( SIGINT, handler ); @@ -2245,23 +1579,56 @@ int main( int argc, char *argv[] ) signal( SIGPIPE, SIG_IGN ); signal( SIGSEGV, segmentation_fault );
+ init_tools(); + init_control();
- init_route(); + init_ip();
init_bmx();
- init_msg(); - init_schedule();
init_avl();
- init_plugin();
- apply_init_args( argc, argv ); + if (init_plugin() == SUCCESS) { + + activate_plugin((msg_get_plugin()), NULL, NULL); + + activate_plugin((metrics_get_plugin()), NULL, NULL); + + struct plugin * hna_get_plugin(void); + activate_plugin((hna_get_plugin()), NULL, NULL); + +#ifndef NO_TRAFFICDUMP + struct plugin * dump_get_plugin(void); + activate_plugin((dump_get_plugin()), NULL, NULL); +#endif + + +#ifdef BMX6_TODO
- check_kernel_config( NULL ); +#ifndef NO_VIS + activate_plugin((vis_get_plugin_v1()), NULL, NULL); +#endif + +#ifndef NO_TUNNEL + activate_plugin((tun_get_plugin_v1()), NULL, NULL); +#endif + +#ifndef NO_SRV + activate_plugin((srv_get_plugin_v1()), NULL, NULL); +#endif + +#endif + + } else { + assertion(-500809, (0)); + } + + + apply_init_args( argc, argv );
bmx();
@@ -2271,4 +1638,3 @@ int main( int argc, char *argv[] ) }
- diff --git a/bmx.h b/bmx.h index ba0078b..c40484f 100644 --- a/bmx.h +++ b/bmx.h @@ -1,6 +1,7 @@ /* - * Copyright (C) 2010 BMX contributors: - * Axel Neumann + * Copyright (c) 2010 BMX protocol contributor(s): + * Axel Neumann <neumann at cgws dot de> + * * 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. @@ -21,90 +22,306 @@ #include <sys/types.h> #include <netinet/in.h> #include <linux/if.h> +#include <linux/rtnetlink.h>
#include "cyassl/sha.h" +#include "cyassl/random.h"
-#include "avl.h" -#include "list.h" -#include "iid.h" -#include "control.h" -#include "allocate.h" +/* + * from other headers: + * TODO: partly move this to system.h + * dont touch this for compatibility reasons: + */ + +#define CODE_VERSION 2 // to be incremented after each critical code change +#define BMX_BRANCH "BMX6" +#define BRANCH_VERSION "0.1-alpha" //put exactly one distinct word inside the string like "0.3-pre-alpha" or "0.3-rc1" or "0.3" +#define COMPATIBILITY_VERSION 12 + +/* + * from iid.h: + */ +typedef uint16_t IID_T; + +typedef struct neigh_node IID_NEIGH_T; + +typedef struct dhash_node IID_NODE_T;
-#ifndef REVISION_VERSION -#define REVISION_VERSION 0 -#endif
/* - * from other headers: + * from ip.h: */
-#define IDM_T int8_t // int which size does NOT matter +#define GEN_ADDR_LEN 20 +#define IP6_ADDR_LEN 16 +#define IP4_ADDR_LEN 4 +#define MAC_ADDR_LEN 6
-// dont touch this for compatibility reasons: -#define IP4_T uint32_t +//#define INET_ADDRSTRLEN INET_ADDRSTRLEN // from in.h +//#define INET6_ADDRSTRLEN INET6_ADDRSTRLEN // from in.h
-#define DESCRIPTION0_ID_RANDOM_T uint64_t -#define DESCRIPTION0_ID_RANDOM_LEN sizeof( DESCRIPTION0_ID_RANDOM_T ) -#define DESCRIPTION0_ID_NAME_LEN 22 +#define IPX_STR_LEN INET6_ADDRSTRLEN
-#define BMX_HASH0_LEN SHA_DIGEST_SIZE // sha.h: 20 bytes -#define BMX_PKEY0_LEN 1024
-struct description_id { - char name[DESCRIPTION0_ID_NAME_LEN]; - union { - uint8_t u8[DESCRIPTION0_ID_RANDOM_LEN]; - uint16_t u16[DESCRIPTION0_ID_RANDOM_LEN / sizeof(uint16_t)]; - uint32_t u32[DESCRIPTION0_ID_RANDOM_LEN / sizeof(uint32_t)]; - uint64_t u64[DESCRIPTION0_ID_RANDOM_LEN / sizeof( uint64_t)]; - } rand; +typedef uint32_t IP4_T; + +typedef struct in6_addr IP6_T; + +typedef IP6_T IPX_T; + +typedef union { + uint8_t u8[GEN_ADDR_LEN]; + uint16_t u16[GEN_ADDR_LEN / sizeof(uint16_t)]; + uint32_t u32[GEN_ADDR_LEN / sizeof(uint32_t)]; + uint64_t u64[GEN_ADDR_LEN / sizeof(uint64_t)]; +} ADDR_T; + + +typedef union { + uint8_t u8[MAC_ADDR_LEN]; + uint16_t u16[MAC_ADDR_LEN / sizeof(uint16_t)]; +} MAC_T; + + +typedef uint32_t LINK_ID_T; +#define LINK_ID_ITERATIONS_MAX 256 +#define LINK_ID_ITERATIONS_WARN (LINK_ID_ITERATIONS_MAX<<3) +#define LINK_ID_INVALID 0 +#define LINK_ID_MIN 1 +#define LINK_ID_MAX ((LINK_ID_T)-1) + + + +/* + * from bmx.h: + */ +typedef uint32_t TIME_T; +typedef uint32_t TIME_SEC_T; + +typedef int8_t IDM_T; // smallest int which size does NOT matter + + +/* + * from msg.h: + */ + +// deprecated: +typedef uint16_t SQN_T; +#define SQN_MAX ((SQN_T)-1) +#define MAX_SQN_RANGE 8192 // the maxumim of all .._SQN_RANGE ranges, should never be more than SQN_MAX/4 + + + +// to be used: + +// OGMs: +typedef uint16_t OGM_SQN_T; +#define OGM_SQN_BIT_SIZE (16) +#define OGM_SQN_MASK ((1<<OGM_SQN_BIT_SIZE)-1) +#define OGM_SQN_MAX OGM_SQN_MASK +#define OGM_SQN_STEP 1 + +#define MIN_OGM_SQN_RANGE 32 +#define MAX_OGM_SQN_RANGE 8192 // changing this will cause compatibility trouble +#define DEF_OGM_SQN_RANGE MAX_OGM_SQN_RANGE +#define ARG_OGM_SQN_RANGE "ogm_validity_range" + + +typedef uint16_t OGM_MIX_T; +#define OGM_MIX_BIT_SIZE (sizeof (OGM_MIX_T) * 8) + +#define OGM_MANTISSA_BIT_SIZE 5 +#define OGM_EXPONENT_BIT_SIZE 5 +#define OGM_IIDOFFST_BIT_SIZE (OGM_MIX_BIT_SIZE-(OGM_MANTISSA_BIT_SIZE+OGM_EXPONENT_BIT_SIZE)) + +#define OGM_MANTISSA_BIT_POS (0) +#define OGM_EXPONENT_BIT_POS (0 + OGM_MANTISSA_BIT_SIZE) +#define OGM_IIDOFFST_BIT_POS (0 + OGM_MANTISSA_BIT_SIZE + OGM_EXPONENT_BIT_SIZE) + +#define OGM_MANTISSA_MASK ((1<<OGM_MANTISSA_BIT_SIZE)-1) +#define OGM_EXPONENT_MASK ((1<<OGM_EXPONENT_BIT_SIZE)-1) +#define OGM_IIDOFFST_MASK ((1<<OGM_IIDOFFST_BIT_SIZE)-1) + + + +// aggregations of OGMs: +typedef uint16_t AGGREG_SQN_T; +#define AGGREG_SQN_BIT_SIZE (16) +#define AGGREG_SQN_MASK ((1<<AGGREG_SQN_BIT_SIZE)-1) +#define AGGREG_SQN_MAX AGGREG_SQN_MASK + +#define AGGREG_SQN_CACHE_RANGE 64 +#define AGGREG_SQN_CACHE_WARN (AGGREG_SQN_CACHE_RANGE/2) +#define AGGREG_ARRAY_BYTE_SIZE (AGGREG_SQN_CACHE_RANGE/8) + + + +// hello and hello reply messages: +typedef uint16_t HELLO_FLAGS_SQN_T; +#define HELLO_MIX_BIT_SIZE (sizeof (HELLO_FLAGS_SQN_T) * 8) + +#define HELLO_SQN_BIT_SIZE (12) +#define HELLO_FLAGS_BIT_SIZE (HELLO_MIX_BIT_SIZE-HELLO_SQN_BIT_SIZE) + +#define HELLO_SQN_BIT_POS (0) +#define HELLO_FLAGS_BIT_POS (0 + HELLO_SQN_BIT_SIZE) + +#define HELLO_SQN_MASK ((1<<HELLO_SQN_BIT_SIZE)-1) +#define HELLO_FLAGS_MASK ((1<<HELLO_FLAGS_BIT_SIZE)-1) + +#define HELLO_SQN_MAX HELLO_SQN_MASK + + + +#define DEF_HELLO_SQN_RANGE 32 +#define DEF_HELLO_DAD_RANGE 32 + + + + +// descriptions +typedef uint16_t DESC_SQN_T; +#define DESC_SQN_BIT_SIZE (16) +#define DESC_SQN_MASK ((1<<DESC_SQN_BIT_SIZE)-1) +#define DESC_SQN_MAX DESC_SQN_MASK + +#define DEF_DESCRIPTION_DAD_RANGE 8192 + + +typedef uint8_t FRAME_TYPE_T; + +#define FRAME_ISSHORT_BIT_SIZE (1) +#define FRAME_RELEVANCE_BIT_SIZE (1) +#define FRAME_TYPE_BIT_SIZE ((8*sizeof(FRAME_TYPE_T)) - FRAME_ISSHORT_BIT_SIZE - FRAME_RELEVANCE_BIT_SIZE) +#define FRAME_TYPE_MASK MIN( (0x1F) /*some bits reserved*/, (((FRAME_TYPE_T)-1)>>(8*sizeof(FRAME_TYPE_T)-FRAME_TYPE_BIT_SIZE))) +#define FRAME_TYPE_ARRSZ (FRAME_TYPE_MASK+1) +#define FRAME_TYPE_PROCESS_ALL (0xFF) +#define FRAME_TYPE_PROCESS_NONE (0xFE) + + +#define HASH0_SHA1_LEN SHA_DIGEST_SIZE // sha.h: 20 bytes + +#define MAX_PACKET_SIZE 1600 + + + +struct packet_header // 10 bytes +{ + uint8_t bmx_version; + uint8_t reserved; // reserved + uint16_t pkt_length; // the relevant data size in bytes (including the bmx_header) + + IID_T transmitterIID; // IID of transmitter node + LINK_ID_T link_id; + } __attribute__((packed));
-struct description_hash { - union { - uint8_t u8[BMX_HASH0_LEN]; - uint32_t u32[BMX_HASH0_LEN/sizeof(uint32_t)]; - } h; -};
-// from msg.h -#define FRAME_TYPE_ARRSZ 14 + +
/* - * bmx.h: + * from metrics.h */
+typedef uint16_t ALGO_T; +typedef uint64_t UMETRIC_T;
-#define MIN_OGM0_SQN_RANGE 64 -#define MAX_OGM0_SQN_RANGE 8192// <=> 4096 / ogm_sqn_step_size=8 * ogm_interval=1000 = ~512sec -#define DEF_OGM0_SQN_RANGE 8192// <=> 1024 / ogm_sqn_step_size=8 * ogm_interval=1000 = ~128sec
-#define ARG_OGM0_SQN_RANGE "ogm0_validity_range" +struct float_val_t { +#if __BYTE_ORDER == __LITTLE_ENDIAN + unsigned int mantissa : 8; + unsigned int exp_total : 8; +#elif __BYTE_ORDER == __BIG_ENDIAN + unsigned int exp_total : 8; + unsigned int mantissa : 8; +#else +# error "Please fix <bits/endian.h>" +#endif +};
-#define SQN_DAD_RANGE 64 // if rcvd sqn is >= last_rcvd_sqn + SQN_TIMEOUT_RANGE then DAD -#define SQN_T uint16_t +struct float_metric_t { + union { + struct float_val_t f; + uint16_t u; + }val;
-#define MIN_SQN 0 -#define MAX_SQN ((SQN_T)-1) -#define DEF_SQN 0 /* causes seqno to be randomized */ + uint8_t exp_offset; + uint8_t reserved; +}; + +typedef struct float_metric_t FMETRIC_T; + + +struct metric_record { + SQN_T sqn_bit_mask; + + SQN_T clr; // SQN upto which waightedAverageVal has been purged + SQN_T set; // SQN which has been applied (if equals wa_pos) then wa_unscaled MUST NOT be set again! + + UMETRIC_T umetric_slow; + UMETRIC_T umetric_fast; + UMETRIC_T umetric_final; +}; + +#define ZERO_METRIC_RECORD {0, 0, 0, 0,0,0} + +struct host_metricalgo { + + uint8_t exp_offset; + uint8_t reserved_fmetric_mantissa_size; + uint8_t fmetric_mantissa_min; + uint8_t fmetric_exp_reduced_min; + UMETRIC_T umetric_min; + ALGO_T algo_type; + uint16_t flags; + + uint8_t window_size; // MUST be given as multiple of sqn_steps + uint8_t lounge_size; // MUST be given as multiple of sqn_steps e.g. 6 + uint8_t wavg_slow; // e.g. 16 + uint8_t wavg_fast; // e.g. 2 + uint8_t wavg_correction; // e.g. 8 + uint8_t hystere; + uint8_t hop_penalty; + uint8_t late_penalty; +};
-#define MIN_OGM0_PQ_BITS 0 -#define MAX_OGM0_PQ_BITS 5 -#define DEF_OGM0_PQ_BITS 5 -#define ARG_OGM0_PQ_BITS "path_quality_bits"
+#include "avl.h" +#include "list.h" +#include "iid.h" +#include "control.h" +#include "allocate.h"
+#define DESCRIPTION0_ID_RANDOM_T uint64_t +#define DESCRIPTION0_ID_RANDOM_LEN sizeof( DESCRIPTION0_ID_RANDOM_T ) +#define DESCRIPTION0_ID_NAME_LEN 32 + + +struct description_id { + char name[DESCRIPTION0_ID_NAME_LEN]; + union { + uint8_t u8[DESCRIPTION0_ID_RANDOM_LEN]; + uint16_t u16[DESCRIPTION0_ID_RANDOM_LEN / sizeof(uint16_t)]; + uint32_t u32[DESCRIPTION0_ID_RANDOM_LEN / sizeof(uint32_t)]; + uint64_t u64[DESCRIPTION0_ID_RANDOM_LEN / sizeof( uint64_t)]; + } rand; +} __attribute__((packed)); + +struct description_hash { + union { + uint8_t u8[HASH0_SHA1_LEN]; + uint32_t u32[HASH0_SHA1_LEN/sizeof(uint32_t)]; + } h; +}; +
-#define MIN_MASK 1 -#define MAX_MASK 32 -#define ARG_MASK "netmask" -#define ARG_NETW "network"
#define ARG_DEBUG "debug" @@ -113,14 +330,14 @@ struct description_hash {
#define ARG_CONNECT "connect" #define ARG_RUN_DIR "runtime_dir" -#define DEF_RUN_DIR "/var/run/bmx" +#define DEF_RUN_DIR "/var/run/bmx6"
extern uint32_t My_pid; -#define BMX_ENV_LIB_PATH "BMX_LIB_PATH" +#define BMX_ENV_LIB_PATH "BMX6_LIB_PATH" #define BMX_DEF_LIB_PATH "/usr/lib" -// e.g. sudo BMX_LIB_PATH="$(pwd)/lib" ./bmxd -d3 eth0:bmx -#define BMX_ENV_DEBUG "BMX_DEBUG" +// e.g. sudo BMX_LIB_PATH="$(pwd)/lib" ./bmx6 -d3 eth0:bmx +#define BMX_ENV_DEBUG "BMX6_DEBUG"
@@ -131,23 +348,10 @@ extern uint32_t My_pid; #define ARG_VERBOSE_EXP "verbose_exp_help"
#define ARG_VERSION "version" -#define ARG_TRAILER "trailer"
#define ARG_TEST "test" -#define ARG_SHOW_CHANGED "options" - - -#define ARG_DEV "dev" -#define ARG_DEV_TTL "ttl" -#define ARG_DEV_CLONE "clone" -#define ARG_DEV_ANTDVSTY "ant_diversity" -#define ARG_DEV_LL "linklayer" -#define ARG_DEV_ANNOUNCE "announce" -#define DEF_DEV_ANNOUNCE YES +#define ARG_SHOW_PARAMETER "parameters"
-#define VAL_DEV_LL_LO 0 -#define VAL_DEV_LL_LAN 1 -#define VAL_DEV_LL_WLAN 2
#define ARG_ORIGINATORS "originators" @@ -159,78 +363,29 @@ extern uint32_t My_pid; #define ARG_THROW "throw"
-#define PROBE_RANGE 1024 - - - -#define MAX_PWS 1024 /* 250 TBD: should not be larger until ogm->ws and neigh_node.packet_count (and related variables) is only 8 bit */ -#define MIN_PWS 32 -#define DEF_PWS 256 /* NBRF: NeighBor Ranking sequence Frame) sliding packet range of received orginator messages in squence numbers (should be a multiple of our word size) */ -#define ARG_PWS "path_window_size" -extern int32_t my_pws; // my path window size used to quantify the end to end path quality between me and other nodes - - -#define DEF_LWS 64 -#define MAX_LWS 250 -#define MIN_LWS 1 -#define ARG_LWS "link_window_size" -extern int32_t local_lws; // my link window size used to quantify the link qualities to direct neighbors
+#define MIN_TX_INTERVAL 35 +#define MAX_TX_INTERVAL 10000 // < U16_MAX due to metricalgo->ogm_interval field +#define DEF_TX_INTERVAL 500 +#define ARG_TX_INTERVAL "tx_interval" +extern int32_t my_tx_interval;
-// the default link_lounge_size of 2 is good to compensate for ogi ~ but <= aggreg_interval -#define MIN_RTQ_LOUNGE 0 -#define MAX_RTQ_LOUNGE 10 -#define DEF_RTQ_LOUNGE 2 -#define ARG_RTQ_LOUNGE "link_lounge_size" -extern int32_t local_rtq_lounge; +#define DEF_TX_DELAY ((2*my_tx_interval) + rand_num(my_tx_interval))
-#define RQ_LINK_LOUNGE 0 /* may also be rtq_link_lounge */ +#define ARG_OGM_INTERVAL "ogm_interval" +#define DEF_OGM_INTERVAL 3000 +#define MIN_OGM_INTERVAL 200 +#define MAX_OGM_INTERVAL 10000 // 60000 = 1 minutes +extern int32_t my_ogm_interval;
-#define MIN_PATH_LOUNGE 0 -#define MAX_PATH_LOUNGE (0x01 << MAX_OGM0_PQ_BITS) -#define DEF_PATH_LOUNGE (0x01 << DEF_OGM0_PQ_BITS) -#define ARG_PATH_LOUNGE "path_lounge_size" -extern int32_t my_path_lounge; - -#define MIN_PATH_HYST 0 -#define MAX_PATH_HYST (PROBE_RANGE)/2 -#define DEF_PATH_HYST 0 -#define ARG_PATH_HYST "path_hysteresis" -extern int32_t my_path_hystere; - -#define MIN_RCNT_HYST 0 -#define MAX_RCNT_HYST (PROBE_RANGE)/2 -#define DEF_RCNT_HYST 10 -#define ARG_RCNT_HYST "fast_path_hysteresis" -extern int32_t my_rcnt_hystere; - -#define DEF_RCNT_PWS 10 -#define MIN_RCNT_PWS 2 -#define MAX_RCNT_PWS 50 -#define ARG_RCNT_PWS "fast_path_window_size" -extern int32_t my_rcnt_pws; - - -#define DEF_RCNT_FK 4 -#define MIN_RCNT_FK 1 -#define MAX_RCNT_FK 11 -#define ARG_RCNT_FK "fast_path_faktor" -extern int32_t my_rcnt_fk; - -#define MIN_LATE_PENAL 0 -#define MAX_LATE_PENAL 100 -#define DEF_LATE_PENAL 1 -#define ARG_LATE_PENAL "lateness_penalty" -extern int32_t my_late_penalty; - -#define MIN_DROP_2HLOOP NO -#define MAX_DROP_2HLOOP YES -#define DEF_DROP_2HLOOP NO -#define ARG_DROP_2HLOOP "drop_two_hop_loops" - +#define MIN_OGM_PURGE_TO (MAX_OGM_INTERVAL + MAX_TX_INTERVAL) +#define MAX_OGM_PURGE_TO 864000000 /*10 days*/ +#define DEF_OGM_PURGE_TO MIN_OGM_PURGE_TO //MIN_OGM_PURGE_TO +#define ARG_OGM_PURGE_TO "purge_timeout" +// extern int32_t purge_to;
-#define DEF_DAD_TO 50000 +#define DEF_DAD_TO (MAX_OGM_INTERVAL + MAX_TX_INTERVAL) #define MIN_DAD_TO 100 #define MAX_DAD_TO 360000000 #define ARG_DAD_TO "dad_timeout" @@ -246,49 +401,12 @@ extern int32_t dad_to; #define ARG_TTL "ttl" extern int32_t my_ttl;
-#define DEF_WL_CLONES 200 -#define MIN_WL_CLONES 0 -#define MAX_WL_CLONES 400 -#define ARG_WL_CLONES "ogm_broadcasts" -extern int32_t wl_clones; - -#define DEF_LAN_CLONES 100
-#define DEF_ASYM_WEIGHT 100 -#define MIN_ASYM_WEIGHT 0 -#define MAX_ASYM_WEIGHT 100 -#define ARG_ASYM_WEIGHT "asymmetric_weight" -extern int32_t asym_weight; - - - -#define DEF_SYM_WEIGHT 80 -#define MIN_SYM_WEIGHT 0 -#define MAX_SYM_WEIGHT 100 -#define ARG_SYM_WEIGHT "symmetric_weight" -extern int32_t sym_weight; - -#define DEF_ASYM_EXP 1 -#define MIN_ASYM_EXP 0 -#define MAX_ASYM_EXP 3 -#define ARG_ASYM_EXP "asymmetric_exp" - -#define DEF_HOP_PENALTY 1 -#define MIN_HOP_PENALTY 0 -#define MAX_HOP_PENALTY 100 -#define ARG_HOP_PENALTY "hop_penalty" -extern int32_t my_hop_penalty; - -#define ARG_OGI_PWRSAVE "ogi_power_save" - - - -#define DEF_PURGE_TO 50000 -#define MIN_PURGE_TO 100 -#define MAX_PURGE_TO 864000000 /*10 days*/ -#define ARG_PURGE_TO "purge_timeout" -// extern int32_t purge_to; +#define DEF_LINK_PURGE_TO 100000 +#define MIN_LINK_PURGE_TO (MAX_TX_INTERVAL*2) +#define MAX_LINK_PURGE_TO 864000000 /*10 days*/ +#define ARG_LINK_PURGE_TO "link_purge_timeout"
#define MIN_DHASH_TO 300000 #define DHASH_TO_TOLERANCE_FK 10 @@ -297,20 +415,13 @@ extern int32_t my_hop_penalty;
-#define OGM_AGGREG_SQN_CACHE_RANGE 64 -#define OGM_AGGREG_SQN_CACHE_WARN (OGM_AGGREG_SQN_CACHE_RANGE/2) -#define OGM_AGGREG_ARRAY_BYTE_SIZE (OGM_AGGREG_SQN_CACHE_RANGE/8)
-#define SOURCE_VERSION "0.4-alpha" //put exactly one distinct word inside the string like "0.3-pre-alpha" or "0.3-rc1" or "0.3"
-#define COMPAT_VERSION 11 - -#define IP4_STR_LEN 16
#define MAX_DBG_STR_SIZE 1500 #define OUT_SEQNO_OFFSET 1 @@ -332,46 +443,38 @@ enum ADGSN { #define SUCCESS 0 #define FAILURE -1
-extern void* FAILURE_POINTER; - -#define ILLEGAL_STATE "Illegal program state. This should not happen!" - -#ifndef REVISION_VERSION -#define REVISION_VERSION 0 -#endif
#define MAX_SELECT_TIMEOUT_MS 400 /* MUST be smaller than (1000/2) to fit into max tv_usec */ #define CRITICAL_PURGE_TIME_DRIFT 5
-#define RAND_INIT_DELAY 50 -#define COMMON_OBSERVATION_WINDOW (DEF_OGM_INTERVAL*DEF_PWS) - -//#define TYPE_OF_WORD unsigned long /* you should choose something big, if you don't want to waste cpu */ -//#define WORD_BIT_SIZE ( sizeof(TYPE_OF_WORD) * 8 )
#define MAX( a, b ) ( (a>b) ? (a) : (b) ) #define MIN( a, b ) ( (a<b) ? (a) : (b) )
-#define U32_MAX 4294967296 -#define I32_MAX 2147483647 -#define U16_MAX 65536 -#define I16_MAX 32767 -#define U8_MAX 256 -#define I8_MAX 127 +#define U64_MAX ((uint64_t)(-1)) +#define U32_MAX ((uint32_t)(-1)) +#define I32_MAX ((U32_MAX>>1)) +#define U16_MAX ((uint16_t)(-1)) +#define I16_MAX ((U16_MAX>>1)) +#define U8_MAX ((uint8_t)(-1)) +#define I8_MAX ((U8_MAX>>1))
+#define U32_LT( a, b ) ( ((uint32_t)( (a) - (b) ) ) > I32_MAX ) +#define U32_LE( a, b ) ( ((uint32_t)( (b) - (a) ) ) <= I32_MAX ) +#define U32_GT( a, b ) ( ((uint32_t)( (b) - (a) ) ) > I32_MAX ) +#define U32_GE( a, b ) ( ((uint32_t)( (a) - (b) ) ) <= I32_MAX )
-#define LESS_SQN( a, b ) ( ((uint16_t)( (a) - (b) ) ) > I16_MAX ) -#define LSEQ_SQN( a, b ) ( ((uint16_t)( (b) - (a) ) ) <= I16_MAX ) -#define GREAT_SQN( a, b ) ( ((uint16_t)( (b) - (a) ) ) > I16_MAX ) -#define GRTEQ_SQN( a, b ) ( ((uint16_t)( (a) - (b) ) ) <= I16_MAX ) +#define UXX_LT( mask, a, b ) ( ((mask)&( (a) - (b) ) ) > (((mask)&U32_MAX)>>1) ) +#define UXX_LE( mask, a, b ) ( ((mask)&( (b) - (a) ) ) <= (((mask)&U32_MAX)>>1) ) +#define UXX_GT( mask, a, b ) ( ((mask)&( (b) - (a) ) ) > (((mask)&U32_MAX)>>1) ) +#define UXX_GE( mask, a, b ) ( ((mask)&( (a) - (b) ) ) <= (((mask)&U32_MAX)>>1) )
-#define LESS_U32( a, b ) ( ((uint32_t)( (a) - (b) ) ) > I32_MAX ) -#define LSEQ_U32( a, b ) ( ((uint32_t)( (b) - (a) ) ) <= I32_MAX ) -#define GREAT_U32( a, b ) ( ((uint32_t)( (b) - (a) ) ) > I32_MAX ) -#define GRTEQ_U32( a, b ) ( ((uint32_t)( (a) - (b) ) ) <= I32_MAX ) +#define MAX_UXX( mask, a, b ) ( (UXX_GT(mask,a,b)) ? (a) : (b) ) +#define MIN_UXX( mask, a, b ) ( (UXX_LT(mask,a,b)) ? (a) : (b) )
-#define MAX_SQ( a, b ) ( (GREAT_SQN( (a), (b) )) ? (a) : (b) ) + +#define UXX_GET_MAX(mask, a, b ) ( (UXX_GT( (mask), (a), (b) )) ? (a) : (b) )
@@ -382,28 +485,18 @@ extern void* FAILURE_POINTER; #define MAX_ARG_SIZE 200
-extern uint32_t bmx_time; -extern uint32_t bmx_time_sec; +extern TIME_T bmx_time; +extern TIME_SEC_T bmx_time_sec;
-extern uint8_t on_the_fly; +extern IDM_T initializing; +extern IDM_T terminating;
extern uint32_t s_curr_avg_cpu_load;
+extern IDM_T my_description_changed;
- - - -extern struct dev_node *primary_if; - - -extern struct orig_node my_orig_node; - - -//extern struct list_head if_list; - -extern struct avl_tree dev_ip4_tree; -extern struct avl_tree dev_name_tree; +extern struct orig_node self;
extern struct avl_tree link_tree; extern struct avl_tree link_dev_tree; @@ -417,10 +510,6 @@ extern struct avl_tree orig_tree; extern struct avl_tree blocked_tree; extern struct avl_tree blacklisted_tree;
- - - - /** * The most important data structures */ @@ -432,323 +521,177 @@ struct ogm_aggreg_node {
struct msg_ogm_adv *ogm_advs;
- uint16_t aggregated_ogms; + uint16_t aggregated_msgs;
- SQN_T sqn; - uint8_t tx_attempts; - uint32_t tx_timestamp; + AGGREG_SQN_T sqn; + uint8_t tx_attempt; };
- struct packet_buff {
- //filled by wait4Event() -#define pkt_buff_llip4 addr.sin_addr.s_addr - - unsigned char packet_in[2001]; - struct sockaddr_in addr; - struct timeval tv_stamp; - struct dev_node *iif; - int total_length; - uint8_t unicast; - - //filled in by rx_packet() - char neigh_str[IP4_STR_LEN]; - struct dev_node *oif; - struct link_node *ln; + struct packet_buff_info { + //filled by wait4Event() + struct sockaddr_storage addr; + struct timeval tv_stamp; + struct dev_node *iif; + int total_length; + uint8_t unicast; + + //filled in by rx_packet() + uint32_t rx_counter; + IID_T transmittersIID; + LINK_ID_T link_id; + IPX_T llip; + char llip_str[INET6_ADDRSTRLEN]; + struct dev_node *oif; + struct link_node *ln; + struct link_dev_node *lndev; + struct dhash_node *described_dhn; // might be updated again process_dhash_description_neighIID4x() + } i;
- //filled in by rx_frm_hey0_reps() or rx_frame() - struct link_dev_node *lndev; + union { + struct packet_header header; + unsigned char data[MAX_PACKET_SIZE + 1]; + } packet;
};
-struct task_node -{ +struct task_node { struct list_node list; - uint32_t expire; + TIME_T expire; void (* task) (void *fpara); // pointer to the function to be executed void *data; //NULL or pointer to data to be given to function. Data will be freed after functio is called. };
- - -struct tx_task_node { - struct list_node list; - - IP4_T dst_ip4; - IID_T myIID4x; - IID_T neighIID4x; - SQN_T sqn; - uint16_t frame_data_length_target; // because some variable msgs sizes may vary between scheduling and tx - uint8_t frame_type; - uint8_t tx_iterations; - uint32_t tx_timestamp; +struct tx_task_key { struct dev_node *dev; // the outgoing interface to be used for transmitting - -}; - -struct tx_timestamp_key { - IP4_T myIID4x_or_dest_ip4; + struct link_node *link; + struct link_dev_node *lndev; + uint32_t u32; + uint16_t u16; + IID_T myIID4x; IID_T neighIID4x; uint16_t type; };
-struct tx_timestamp_node { - struct tx_timestamp_key key; - uint32_t timestamp; -}; - -struct dev_node -{ +struct tx_task_node { struct list_node list; - char name[IFNAMSIZ]; - char name_phy[IFNAMSIZ]; - - char ip4_str[IP4_STR_LEN]; - - int32_t index; - - uint8_t active; - - uint16_t ip4_prefix_length; - - uint32_t ip4_addr; - uint32_t ip4_tree_addr; - uint32_t ip4_netaddr; - uint32_t ip4_broad; - uint32_t ip4_netmask; - - int ip4_mtu; - - int32_t rp_filter_orig; - int32_t send_redirects_orig; - - - struct sockaddr_in ip4_unicast_addr; - struct sockaddr_in ip4_netwbrc_addr; - - int32_t unicast_sock; - int32_t netwbrc_sock; - int32_t fullbrc_sock; - - SQN_T packet_sqn; - SQN_T ogm_sqn; - uint32_t link_activity_timestamp; - uint32_t next_powersave_hardbeat; - - uint16_t misc_flag; - - struct list_head tx_tasks_list[FRAME_TYPE_ARRSZ]; // scheduled frames and messages - struct tx_task_node *my_tx_tasks[FRAME_TYPE_ARRSZ]; - uint16_t tx_frames_data_len_target; // target (should) length of all currently scheduled tx messages (not including packet- or frame-headers - - struct avl_tree tx_timestamp_tree; // timestamps of recently send messages, ordered by type and iid - - // having a pointer right before the following array ensures 32/64 bit alignment. -// unsigned char *aggregation_out; -// unsigned char aggregation_out_buff[MAX_UDPD_SIZE + 1]; - -// int16_t aggregation_len; - - - int8_t soft_conf_changed; - int8_t hard_conf_changed; - - int8_t linklayer_conf; - int8_t linklayer; - - int16_t send_clones_conf; - int16_t send_clones; - - int16_t antenna_diversity_conf; - int16_t antenna_diversity; - - int8_t announce_conf; - int8_t announce;
+ struct tx_task_key content; + uint16_t frame_msgs_length; + int16_t tx_iterations; + TIME_T considered_ts; + TIME_T send_ts; };
-struct metric_algo { - SQN_T sqn_mask; - SQN_T sqn_steps; // e.g. 2 - SQN_T sqn_window; // MUST be given as multiple of sqn_steps - SQN_T sqn_lounge; // MUST be given as multiple of sqn_steps e.g. 6 - uint32_t regression; // e.g. window_size/2 - uint32_t metric_max; // e.g. 256 -};
#define SQR_RTQ 0x00 #define SQR_RQ 0x01 #define SQR_RANGE 0x02
-extern struct metric_algo link_metric_algo[SQR_RANGE]; - -#define TQ_RATE( lndev, range) ( ((lndev)->mr[SQR_RQ].val ) ? \ -(MIN( ( ((range) * ((lndev)->mr[SQR_RTQ].val) ) / ((lndev)->mr[SQR_RQ].val) ), (range) )): \ -(0) )
-struct metric_record { - SQN_T clr; // SQN upto which waightedAverageVal has been purged - SQN_T set; // SQN which has been applied (if equals wa_pos) then wa_unscaled MUST NOT be set again! - uint32_t val; -};
- -struct link_key { - IP4_T llip4; +struct link_dev_key { + struct link_node *link; struct dev_node *dev; };
struct link_dev_node { struct list_node list; + struct link_dev_key key; + struct metric_record mr[SQR_RANGE]; + UMETRIC_T umetric_link;
- struct link_key key; + struct list_head tx_task_lists[FRAME_TYPE_ARRSZ]; // scheduled frames and messages
- uint32_t pkt_time_max; + HELLO_FLAGS_SQN_T rx_hello_reply_flags; + HELLO_FLAGS_SQN_T tx_hello_reply_flags;
- uint32_t rtq_time_max; + TIME_T pkt_time_max; + TIME_T rtq_time_max; +};
- struct link_node *link; +struct link_node { + LINK_ID_T link_id; + IPX_T link_ip;
-// struct sq_record sqr[SQR_RANGE]; + TIME_T pkt_time_max;
- struct metric_record mr[SQR_RANGE]; + uint8_t rq_purge_iterations;
-}; + TIME_T rq_purge_interval; + TIME_T rq_time_max_prev; + TIME_T rq_time_max;
-/* MUST be allocated and initiated all or nothing ! - * MUST be initiated with any unidirectional received OGM - * from a direct link NB - */ -/* Only OG interfaces which are direct link neighbors have a link_node - * Because neighboring interfaces may be seen via several of our own interfaces - * each link_node points to one or several link_node_dev structures - */ -struct link_node -{ - uint32_t llip4; - char llip4_str[IP4_STR_LEN]; - - uint32_t pkt_time_max; - SQN_T pkt_sqn_max; - - SQN_T rq_sqn_max; - uint32_t rq_time_max; + HELLO_FLAGS_SQN_T rq_hello_sqn_max_prev; + HELLO_FLAGS_SQN_T rq_hello_sqn_max;
struct neigh_node *neigh; - + struct list_head lndev_list; // list with one link_node_dev element per link - };
/* Path statistics per neighbor via which OGMs of the parent orig_node have been received */ -/* Every OG has one ore several neigh_nodes. */ -struct router_node {
- struct link_key key; - -// SQN_T ogm_sqn_to_be_send;
+struct router_node { + struct link_dev_key key; struct metric_record mr; - -// uint32_t metric; - - - };
-struct orig_node {
+struct orig_node { // filled in by validate_new_link_desc0():
struct description_id id;
struct dhash_node *dhn; - struct description *desc0; -// struct orig_node *orig_key; - - uint32_t updated_timestamp; // last time this on's desc was succesfully updated -// uint32_t referred_timestamp;// use dhn->referred_timestamp instead - - SQN_T desc0_sqn; + struct description *desc;
- SQN_T ogm_sqn_min; - SQN_T ogm_sqn_to_be_send; - SQN_T ogm_sqn_aggregated; + TIME_T updated_timestamp; // last time this on's desc was succesfully updated
- SQN_T ogm_sqn_range; + DESC_SQN_T descSqn;
-// SQN_T ogm_sqn_mask; -// SQN_T ogm_sqn_steps; + OGM_SQN_T ogmSqn_rangeMin; + OGM_SQN_T ogmSqn_rangeSize;
- SQN_T ogm_sqn_max_rcvd;
- uint8_t ogm_sqn_pq_bits; - - struct metric_algo path_metric_algo; - - uint8_t blocked; - - // not yet filled in:
// filled in by process_desc0_tlvs()-> - - uint32_t primary_ip4; - char primary_ip4_str[IP4_STR_LEN]; - - - // filled in by ??? - - - struct link_key router_key; // the neighbor which is the currently best_next_hop - struct avl_tree router_tree; - uint32_t router_path_metric; - uint32_t router_best_metric; - - -/* - // old unused: + IPX_T primary_ip; + char primary_ip_str[IPX_STR_LEN]; + uint8_t blocked;
+ struct host_metricalgo *path_metricalgo;
+ // calculated by update_path_metric()
- uint32_t last_aware; // when last valid ogm via this node was received - uint32_t last_valid_time; // when last valid ogm from this node was received + OGM_SQN_T ogmSqn_maxRcvd; + OGM_SQN_T ogmSqn_toBeSend; + OGM_SQN_T ogmSqn_aggregated; + + UMETRIC_T *metricSqnMaxArr;
- uint32_t first_valid_sec; // only used for debugging purposes + struct avl_tree rt_tree;
- SQN_T last_decided_sqn; - SQN_T last_accepted_sqn; // last squence number acceppted for metric - SQN_T last_valid_sqn; // last and best known squence number - SQN_T last_wavg_sqn; // last sequence number used for estimating ogi + struct router_node *best_rn; + struct router_node *curr_rn;
- uint8_t last_path_ttl; - int8_t last_path_change_scenario;
- uint8_t pws; - uint8_t path_lounge; - uint8_t path_hystere; - uint8_t late_penalty;
- uint8_t rcnt_pws; - uint8_t rcnt_hystere; - uint8_t rcnt_fk; - - uint32_t ogi_wavg; - uint32_t rt_changes; -*/ - /*size of plugin data is defined during intialization and depends on registered plugin-data hooks */ + //size of plugin data is defined during intialization and depends on registered PLUGIN_DATA_ORIG hooks void *plugin_data[];
}; @@ -757,16 +700,13 @@ struct orig_node { struct neigh_node {
struct neigh_node *nnkey; + struct dhash_node *dhn; // confirmed dhash
struct avl_tree link_tree;
- struct dhash_node *dhn; - - // filled in by ???:
IID_T neighIID4me; - IID_T neighIID4neigh;
struct iid_repos neighIID4x_repos;
@@ -774,32 +714,26 @@ struct neigh_node { struct link_dev_node *best_rtq;
// filled in by ???: - SQN_T ogm_aggregation_rcvd_max; - uint8_t ogm_aggregations_acked[OGM_AGGREG_ARRAY_BYTE_SIZE]; - uint8_t ogm_aggregations_rcvd[OGM_AGGREG_ARRAY_BYTE_SIZE]; - + AGGREG_SQN_T ogm_aggregation_rcvd_set; + AGGREG_SQN_T ogm_aggregation_cleard_max; + uint8_t ogm_aggregations_acked[AGGREG_ARRAY_BYTE_SIZE]; + uint8_t ogm_aggregations_rcvd[AGGREG_ARRAY_BYTE_SIZE]; };
+ struct dhash_node {
struct description_hash dhash;
- // filled in by rx_frm_hiX0_advs() -> get_orig_node(): - - uint32_t referred_timestamp; // last time this dhn was referred + TIME_T referred_by_me_timestamp; // last time this dhn was referred
struct neigh_node *neigh;
IID_T myIID4orig;
- // filled in by rx_frm_hi40_reps(): - struct orig_node *on; - - // filled in by expire_dhash_node() - // uint8_t invalid; equal to on == NULL };
@@ -822,7 +756,7 @@ struct throw_node
-# define timercpy(d, a) (d)->tv_sec = (a)->tv_sec; (d)->tv_usec = (a)->tv_usec; +#define timercpy(d, a) (d)->tv_sec = (a)->tv_sec; (d)->tv_usec = (a)->tv_usec;
@@ -833,33 +767,88 @@ enum { CLEANUP_RETURN };
+ +/*********************************************************** + Data Infrastructure + ************************************************************/ +IDM_T equal_link_key( struct link_dev_key *a, struct link_dev_key *b ); + +void blacklist_neighbor(struct packet_buff *pb); + +IDM_T blacklisted_neighbor(struct packet_buff *pb, struct description_hash *dhash); + +struct dhash_node *is_described_neigh_dhn(struct packet_buff *pb); + + +void purge_link_and_orig_nodes(struct dev_node *only_dev, IDM_T only_expired); +void free_orig_node(struct orig_node *on); +void init_orig_node(struct orig_node *on, struct description_id *id); + + +struct dhash_node* create_dhash_node(struct description_hash *dhash, struct orig_node *on); +void free_dhash_node( struct dhash_node *dhn ); +void invalidate_dhash_node( struct dhash_node *dhn ); + + +IDM_T update_neigh_node(struct link_node *ln, struct dhash_node *dhn, IID_T neighIID4neigh, struct description *dsc); + +LINK_ID_T new_link_id(struct dev_node *dev); + +void rx_packet( struct packet_buff *pb ); + + +/*********************************************************** + Runtime Infrastructure +************************************************************/ + + /* - * PARANOIA ERROR CODES: + * ASSERTION / PARANOIA ERROR CODES: * Negative numbers are used as SIGSEV error codes ! - * Currently used numbers are: -500000 ... -500520 + * Currently used numbers are: -500000 -500001 ... -500922 */
-#ifdef NO_PARANOIA +#ifdef NO_ASSERTIONS #define paranoia( ... ) #define assertion( ... ) #define ASSERTION( ... ) -#else -#define paranoia( code , problem ); do { if ( (problem) ) { cleanup_all( code ); } }while(0) -#define assertion( code , condition ); do { if ( !(condition) ) { cleanup_all( code ); } }while(0) +#define EXITERROR( ... ) +#define CHECK_INTEGRITY( ... ) + +#else//NO_ASSERTIONS + +#define paranoia( code , problem ) do { if ( (problem) ) { cleanup_all( code ); } }while(0) +#define assertion( code , condition ) do { if ( !(condition) ) { cleanup_all( code ); } }while(0) + #ifdef EXTREME_PARANOIA -#define ASSERTION( code , condition ); do { if ( !(condition) ) { cleanup_all( code ); } }while(0) -#define CHECK_INTEGRITY( ... ) checkIntegrity() +#define ASSERTION( code , condition ) do { if ( !(condition) ) { cleanup_all( code ); } }while(0) +#define CHECK_INTEGRITY( ) checkIntegrity() #else -#define CHECK_INTEGRITY( ... ) -#define ASSERTION( ... ) +#define CHECK_INTEGRITY( ) +#define ASSERTION( code , condition ) #endif + +#ifdef EXIT_ON_ERROR +#define EXITERROR( code , condition ) \ + do { \ + if ( !(condition) ) { \ + dbgf(DBGL_SYS, DBGT_ERR, "This is paranoid! Disable EXIT_ON_ERROR to not exit due to minor or others' misbehavior"); \ + cleanup_all( code ); \ + } \ + }while(0) +#else +#define EXITERROR( code , condition ) #endif
+#endif//NO_ASSERTIONS +
#ifndef PROFILING #define STATIC_FUNC static +#define STATIC_INLINE_FUNC static inline #else #define STATIC_FUNC +#define STATIC_INLINE_FUNC #endif
#ifdef STATIC_VARIABLES @@ -868,64 +857,34 @@ enum { #define STATIC_VAR #endif
-/*********************************************************** - Data Infrastructure - ************************************************************/
-void blacklist_neighbor(struct packet_buff *pb); +#ifndef NO_TRACE_FUNCTION_CALLS
-IDM_T blacklisted_neighbor(struct packet_buff *pb, struct description_hash *dhash); +#define FUNCTION_CALL_BUFFER_SIZE 64
-IDM_T validate_metric_algo(struct metric_algo *ma, struct ctrl_node *cn); +extern char* function_call_buffer_name_array[FUNCTION_CALL_BUFFER_SIZE]; +extern TIME_T function_call_buffer_time_array[FUNCTION_CALL_BUFFER_SIZE]; +extern uint8_t function_call_buffer_pos;
-uint32_t update_metric(struct link_node *ln, struct orig_node *on, - struct metric_record *mr, struct metric_algo *ma, SQN_T sqn_in, SQN_T sqn_max, uint32_t probe); +void trace_function_call(const char *); +#define TRACE_FUNCTION_CALL trace_function_call ( __FUNCTION__ )
-void update_link_node(struct link_node *ln, struct dev_node *iif, SQN_T sqn, SQN_T sqn_max, uint8_t sqr, uint32_t probe); - -void purge_orig(struct dev_node *only_dev, IDM_T only_expired); -void free_orig_node(struct orig_node *on); - -IDM_T update_orig_metrics(struct packet_buff *pb, struct orig_node *on, IID_T orig_sqn); - -struct dhash_node* create_dhash_node(struct description_hash *dhash, struct orig_node *on); -void free_dhash_node( struct dhash_node *dhn ); -void invalidate_dhash_node( struct dhash_node *dhn );
+#else
-IDM_T update_neigh_node(struct link_node *ln, struct dhash_node *dhn, IID_T neighIID4neigh); +#define TRACE_FUNCTION_CALL
-IDM_T update_neighIID4x_repository(struct neigh_node *neigh, IID_T neighIID4x, struct dhash_node *dhn); +#endif
-struct dev_node * get_bif(char *dev);
-void rx_packet( struct packet_buff *pb ); -/*********************************************************** - Runtime Infrastructure -************************************************************/ -void wait_sec_msec( uint32_t sec, uint32_t msec ); +void wait_sec_msec( TIME_SEC_T sec, TIME_T msec );
-void cleanup_all( int status ); +void cleanup_all( int32_t status );
void upd_time( struct timeval *precise_tv );
char *get_human_uptime( uint32_t reference );
-int32_t rand_num( uint32_t limit ); - -int8_t terminating(); - -uint8_t bits_count( uint32_t v ); - -uint8_t bit_get(uint8_t *array, uint16_t array_bit_size, uint16_t bit); - -void bit_set(uint8_t *array, uint16_t array_bit_size, uint16_t bit, IDM_T value); - -void bit_clear(uint8_t *array, uint16_t array_bit_size, uint16_t begin, uint16_t end); - -void byte_clear(uint8_t *array, uint16_t array_size, uint16_t begin, uint16_t range); - -uint8_t is_zero(char *data, int len);
/*********************************************************** @@ -934,5 +893,4 @@ uint8_t is_zero(char *data, int len);
IDM_T validate_name( char* name ); - -int32_t opt_update_description ( uint8_t cmd, uint8_t _save, struct opt_type *opt, struct opt_parent *patch, struct ctrl_node *cn ); +IDM_T validate_param(int32_t probe, int32_t min, int32_t max, char *name); diff --git a/control.c b/control.c index ea21f8a..9e6ac91 100644 --- a/control.c +++ b/control.c @@ -1,6 +1,5 @@ /* - * Copyright (C) 2010 BMX contributors: - * Axel Neumann + * Copyright (c) 2010 Axel Neumann * 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. @@ -27,14 +26,16 @@ #include <sys/un.h> #include <arpa/inet.h> #include <sys/socket.h> +#include <sys/stat.h> #include <unistd.h> #include <fcntl.h> #include <paths.h>
#include "bmx.h" +#include "ip.h" #include "plugin.h" #include "schedule.h" - +#include "tools.h"
#define MAX_DBG_STR_SIZE 1500 @@ -51,15 +52,11 @@ static int32_t loop_interval = DEF_LOOP_INTERVAL;
static int32_t loop_mode;
-#define MIN_PEDANT_CHK NO -#define MAX_PEDANT_CHK YES -#define DEF_PEDANT_CHK NO -static int32_t pedantic_check = DEF_PEDANT_CHK;
int unix_sock = 0;
-LIST_SIMPEL( ctrl_list, struct ctrl_node, list ); +LIST_SIMPEL( ctrl_list, struct ctrl_node, list, list );
struct list_head dbgl_clients[DBGL_MAX+1]; static struct dbg_histogram dbgl_history[2][DBG_HIST_SIZE]; @@ -76,12 +73,14 @@ char *prog_name;
struct opt_type Patch_opt;
-LIST_SIMPEL( opt_list, struct opt_data, list ); // global opt_list +LIST_SIMPEL( opt_list, struct opt_data, list, list ); // global opt_list
int32_t Client_mode = NO; //this one must be initialized manually!
-static void remove_dbgl_node( struct ctrl_node *cn ) { +STATIC_FUNC +void remove_dbgl_node(struct ctrl_node *cn) +{ int8_t i; struct dbgl_node *dn; @@ -107,8 +106,9 @@ static void remove_dbgl_node( struct ctrl_node *cn ) { cn->dbgl = -1; }
- -static void add_dbgl_node( struct ctrl_node *cn, int dbgl ) { +STATIC_FUNC +void add_dbgl_node(struct ctrl_node *cn, int dbgl) +{ if ( !cn || dbgl < DBGL_MIN || dbgl > DBGL_MAX ) return; @@ -127,8 +127,8 @@ static void add_dbgl_node( struct ctrl_node *cn, int dbgl ) { }
- -static int daemonize() { +static int daemonize() +{
int fd;
@@ -173,7 +173,9 @@ static int daemonize() {
}
-static int update_pid_file( void ) { +STATIC_FUNC +int update_pid_file(void) +{ char tmp_path[MAX_PATH_SIZE+20] = ""; int tmp_fd = 0; @@ -194,7 +196,9 @@ static int update_pid_file( void ) { return SUCCESS; }
-static void activate_debug_system( void ) { +STATIC_FUNC +void activate_debug_system(void) +{ if ( !debug_system_active ) {
@@ -225,14 +229,15 @@ static void activate_debug_system( void ) { debug_system_active = YES; dbgf_all( DBGT_INFO, "activated level %d", debug_level); - - dbg( DBGL_CHANGES, DBGT_INFO, "BMX (BatMan-eXp) %s-rv%d (compatibility version %d): %s", - SOURCE_VERSION, REVISION_VERSION, COMPAT_VERSION, init_string); + + dbg(DBGL_CHANGES, DBGT_INFO, "%s-%s (compatibility=%d code=cv%d): %s", + BMX_BRANCH, BRANCH_VERSION, COMPATIBILITY_VERSION, CODE_VERSION, init_string); } }
-struct ctrl_node *create_ctrl_node( int fd, void (*cn_fd_handler) (struct ctrl_node *), uint8_t authorized ) { +struct ctrl_node *create_ctrl_node(int fd, void (*cn_fd_handler) (struct ctrl_node *), uint8_t authorized) +{ struct ctrl_node *cn = debugMalloc( sizeof(struct ctrl_node), -300010 ); memset( cn, 0, sizeof(struct ctrl_node) ); @@ -247,11 +252,11 @@ struct ctrl_node *create_ctrl_node( int fd, void (*cn_fd_handler) (struct ctrl_n return cn; }
- -void close_ctrl_node( uint8_t cmd, struct ctrl_node *ctrl_node ) { +void close_ctrl_node(uint8_t cmd, struct ctrl_node *ctrl_node) +{
struct list_node* list_pos, *list_prev, *list_tmp; - int trash; + ssize_t trash;
list_prev = (struct list_node *)&ctrl_list; @@ -286,7 +291,7 @@ void close_ctrl_node( uint8_t cmd, struct ctrl_node *ctrl_node ) { } else if ( ( cmd == CTRL_CLOSE_STRAIGHT && cn == ctrl_node ) || ( cmd == CTRL_PURGE_ALL ) || ( cmd == CTRL_CLEANUP && cn->closing_stamp &&/* cn->fd <= 0 && */ - GREAT_U32( bmx_time, cn->closing_stamp + CTRL_CLOSING_TIMEOUT ) ) ) + U32_GT( bmx_time, cn->closing_stamp + CTRL_CLOSING_TIMEOUT ) ) ) { if ( cn->fd > 0 && cn->fd != STDOUT_FILENO ) { @@ -310,8 +315,8 @@ void close_ctrl_node( uint8_t cmd, struct ctrl_node *ctrl_node ) { } }
- -void accept_ctrl_node( void ) { +void accept_ctrl_node(void) +{ struct sockaddr addr; socklen_t addr_size = sizeof(struct sockaddr); @@ -336,9 +341,8 @@ void accept_ctrl_node( void ) { }
- - -void handle_ctrl_node( struct ctrl_node *cn ) { +void handle_ctrl_node(struct ctrl_node *cn) +{ char buff[MAX_UNIX_MSG_SIZE+1]; if ( cn->cn_fd_handler ) { @@ -368,8 +372,8 @@ void handle_ctrl_node( struct ctrl_node *cn ) { } respect_opt_order( OPT_APPLY, 0, 99, NULL, NO/*load_cofig*/, OPT_POST, 0/*probably closed*/ ); - - cb_plugin_hooks( NULL, PLUGIN_CB_CONF ); + + cb_plugin_hooks(PLUGIN_CB_CONF, NULL); } else { @@ -385,10 +389,12 @@ void handle_ctrl_node( struct ctrl_node *cn ) { }
-#ifndef TESTDEBUG +#ifndef TEST_DEBUG
// returns DBG_HIST_NEW, DBG_HIST_MUTING, or DBG_HIST_MUTED -static uint8_t check_dbg_history ( int8_t dbgl, char *s, uint16_t check_len ) { +STATIC_FUNC +uint8_t check_dbg_history(int8_t dbgl, char *s, uint16_t check_len) +{ static int r=0; int i, unused_i, h; @@ -417,8 +423,8 @@ static uint8_t check_dbg_history ( int8_t dbgl, char *s, uint16_t check_len ) { dbgl_history[h][i].expire == dbg_mute_to && !memcmp( s, dbgl_history[h][i].text, MIN(check_len, strlen(s)) ) ) { - if ( LESS_U32( bmx_time, dbgl_history[h][i].print_stamp + dbg_mute_to ) && - GRTEQ_U32( bmx_time, dbgl_history[h][i].print_stamp ) ) + if ( U32_LT( bmx_time, dbgl_history[h][i].print_stamp + dbg_mute_to ) && + U32_GE( bmx_time, dbgl_history[h][i].print_stamp ) ) { dbgl_history[h][i].catched++; @@ -439,8 +445,8 @@ static uint8_t check_dbg_history ( int8_t dbgl, char *s, uint16_t check_len ) { if ( unused_i == -1 && ( dbgl_history[h][i].catched == 0 || - !( LESS_U32( bmx_time, dbgl_history[h][i].print_stamp + dbg_mute_to ) && - GRTEQ_U32( bmx_time, dbgl_history[h][i].print_stamp ) ) ) ) + !( U32_LT( bmx_time, dbgl_history[h][i].print_stamp + dbg_mute_to ) && + U32_GE( bmx_time, dbgl_history[h][i].print_stamp ) ) ) ) { unused_i = i; @@ -461,13 +467,14 @@ static uint8_t check_dbg_history ( int8_t dbgl, char *s, uint16_t check_len ) { memcpy( dbgl_history[h][unused_i].text, s, MIN( check_len, strlen(s) ) ); return DBG_HIST_NEW; - }
+ +void dbg_printf(struct ctrl_node *cn, char *last, ...) +{ #define MAX_DBG_WRITES 4 -void dbg_printf( struct ctrl_node *cn, char *last, ... ) { if ( !cn || cn->fd <= 0 ) return; @@ -508,8 +515,9 @@ void dbg_printf( struct ctrl_node *cn, char *last, ... ) { } }
- -static void debug_output ( uint32_t check_len, struct ctrl_node *cn, int8_t dbgl, int8_t dbgt, char const *f, char *s ) { +STATIC_FUNC +void debug_output(uint32_t check_len, struct ctrl_node *cn, int8_t dbgl, int8_t dbgt, const char *f, char *s) +{ static uint16_t dbgl_all_msg_num = 0; static char *dbgt2str[] = {"", "INFO ", "WARN ", "ERROR "}; @@ -523,16 +531,16 @@ static void debug_output ( uint32_t check_len, struct ctrl_node *cn, int8_t dbgl if ( cn && cn->fd != STDOUT_FILENO ) - dbg_printf( cn, "%s%s%s%s\n", dbgt2str[dbgt], f?f:"", f?"(): ":"", s ); + dbg_printf( cn, "%s%s: %s\n", dbgt2str[dbgt], f?f:"", s ); if ( !debug_system_active ) { - if ( dbgl == DBGL_SYS || debug_level == DBGL_ALL || debug_level == dbgl ) - printf( "[%d %8u] %s%s%s%s\n", My_pid, bmx_time, dbgt2str[dbgt], f?f:"", f?"(): ":"", s ); + if ( dbgl == DBGL_SYS || debug_level == DBGL_ALL || debug_level == dbgl) + printf("[%d %8u] %s%s: %s\n", My_pid, bmx_time, dbgt2str[dbgt], f ? f : "", s); if ( dbgl == DBGL_SYS ) - syslog( LOG_ERR, "%s%s%s%s\n", dbgt2str[dbgt], f?f:"", f?"(): ":"", s ); + syslog( LOG_ERR, "%s%s: %s\n", dbgt2str[dbgt], f?f:"", s ); return; } @@ -552,6 +560,11 @@ static void debug_output ( uint32_t check_len, struct ctrl_node *cn, int8_t dbgl if ( !LIST_EMPTY( &dbgl_clients[DBGL_TEST ] ) ) dbgl_out[i++] = DBGL_TEST; if ( !LIST_EMPTY( &dbgl_clients[DBGL_ALL ] ) ) dbgl_out[i++] = DBGL_ALL;
+ } else if ( dbgl == DBGL_DUMP ) { + + if ( !LIST_EMPTY( &dbgl_clients[DBGL_DUMP ] ) ) dbgl_out[i++] = DBGL_DUMP; + if ( !LIST_EMPTY( &dbgl_clients[DBGL_ALL ] ) ) dbgl_out[i++] = DBGL_ALL; + } else if ( dbgl == DBGL_PROFILE ) { if ( !LIST_EMPTY( &dbgl_clients[DBGL_PROFILE ] ) ) dbgl_out[i++] = DBGL_PROFILE; @@ -596,18 +609,19 @@ static void debug_output ( uint32_t check_len, struct ctrl_node *cn, int8_t dbgl if ( !dn->cn || dn->cn->fd <= 0 ) continue; - if ( level == DBGL_CHANGES || - level == DBGL_TEST || - level == DBGL_PROFILE || + if ( level == DBGL_CHANGES || + level == DBGL_TEST || + level == DBGL_DUMP || + level == DBGL_PROFILE || level == DBGL_SYS ) dbg_printf( dn->cn, "[%d %8u] ", My_pid, bmx_time ); if ( level == DBGL_ALL ) dbg_printf( dn->cn, "[%d %8u %5u] ", My_pid, bmx_time, dbgl_all_msg_num ); - - - dbg_printf( dn->cn, "%s%s%s%s\n", dbgt2str[dbgt], f?f:"", f?"(): ":"", s ); + + + dbg_printf(dn->cn, "%s%s: %s\n", dbgt2str[dbgt], f ? f : "", s); if ( ( level == DBGL_SYS && mute_dbgl_sys == DBG_HIST_MUTING ) || ( level == DBGL_CHANGES && mute_dbgl_changes == DBG_HIST_MUTING ) ) @@ -632,7 +646,7 @@ void dbg ( int8_t dbgl, int8_t dbgt, char *last, ... ) { debug_output ( 0, 0, dbgl, dbgt, 0, dbg_string_out ); }
-void _dbgf ( int8_t dbgl, int8_t dbgt, char const *f, char *last, ... ) { +void _dbgf ( int8_t dbgl, int8_t dbgt, const char *f, char *last, ... ) { va_list ap; va_start( ap, last ); vsnprintf( dbg_string_out, MAX_DBG_STR_SIZE, last, ap ); @@ -648,7 +662,7 @@ void dbg_cn ( struct ctrl_node *cn, int8_t dbgl, int8_t dbgt, char *last, ... ) debug_output ( 0, cn, dbgl, dbgt, 0, dbg_string_out ); }
-void _dbgf_cn ( struct ctrl_node *cn, int8_t dbgl, int8_t dbgt, char const *f, char *last, ... ) { +void _dbgf_cn ( struct ctrl_node *cn, int8_t dbgl, int8_t dbgt, const char *f, char *last, ... ) { va_list ap; va_start( ap, last ); vsnprintf( dbg_string_out, MAX_DBG_STR_SIZE, last, ap ); @@ -664,7 +678,16 @@ void dbg_mute ( uint32_t check_len, int8_t dbgl, int8_t dbgt, char *last, ... ) debug_output ( check_len, 0, dbgl, dbgt, 0, dbg_string_out ); }
-void _dbgf_all ( int8_t dbgt, char const *f, char *last, ... ) { +void _dbgf_mute(uint32_t check_len, int8_t dbgl, int8_t dbgt, const char *f, char *last, ...) +{ + va_list ap; + va_start( ap, last ); + vsnprintf( dbg_string_out, MAX_DBG_STR_SIZE, last, ap ); + va_end( ap ); + debug_output ( check_len, 0, dbgl, dbgt, f, dbg_string_out ); +} + +void _dbgf_all ( int8_t dbgt, const char *f, char *last, ... ) { va_list ap; va_start( ap, last ); vsnprintf( dbg_string_out, MAX_DBG_STR_SIZE, last, ap ); @@ -693,8 +716,8 @@ int (*save_config_cb) ( uint8_t del, struct opt_type *opt, char *parent, char *v
int (*derive_config) ( char *reference, char *derivation, struct ctrl_node *cn ) = NULL;
- -void get_init_string( int g_argc, char **g_argv ) { +void get_init_string(int g_argc, char **g_argv) +{ uint32_t size = 1, dbg_init_out = 0; int i; @@ -711,8 +734,9 @@ void get_init_string( int g_argc, char **g_argv ) { init_string = dbg_init_str; }
- -static void free_init_string ( void ) { +STATIC_FUNC +void free_init_string(void) +{ if ( init_string ) debugFree( init_string, -300052 ); @@ -720,8 +744,9 @@ static void free_init_string ( void ) { init_string = NULL; }
-#ifndef NODEPRECATED -static int32_t opt_deprecated ( uint8_t cmd, uint8_t _save, struct opt_type *opt, struct opt_parent *patch, struct ctrl_node *cn ) { +#ifndef NO_DEPRECATED +int32_t opt_deprecated(uint8_t cmd, uint8_t _save, struct opt_type *opt, struct opt_parent *patch, struct ctrl_node *cn) +{ char c = opt->short_name; @@ -736,16 +761,16 @@ static int32_t opt_deprecated ( uint8_t cmd, uint8_t _save, struct opt_type *opt
- +#ifdef ADJ_PATCHED_NETW int32_t get_tracked_network( struct opt_type *opt, struct opt_parent *patch, char *out, uint32_t *ip, int32_t *mask, struct ctrl_node *cn ) { struct opt_child *nc, *mc; struct opt_parent *p = get_opt_parent_val( opt, patch->p_val ); - if ( !p || !(nc = get_opt_child(get_option(opt,0,ARG_NETW), p) ) || !nc->c_val ) + if ( !p || !(nc = get_opt_child(get_option(opt,0,ARG_UHNA_NETWORK), p) ) || !nc->c_val ) return FAILURE; - if ( !p || !(mc = get_opt_child(get_option(opt,0,ARG_MASK), p) ) || !mc->c_val ) + if ( !p || !(mc = get_opt_child(get_option(opt,0,ARG_UHNA_PREFIXLEN), p) ) || !mc->c_val ) return FAILURE; sprintf( out, "%s/%s", nc->c_val, mc->c_val ); @@ -755,8 +780,9 @@ int32_t get_tracked_network( struct opt_type *opt, struct opt_parent *patch, cha return SUCCESS; } +#endif
- +#ifdef ADJ_PATCHED_NETW int32_t adj_patched_network( struct opt_type *opt, struct opt_parent *patch, char *out, uint32_t *ip, int32_t *mask, struct ctrl_node *cn ) { struct opt_child *nc, *mc; @@ -765,8 +791,8 @@ int32_t adj_patched_network( struct opt_type *opt, struct opt_parent *patch, cha if ( strpbrk( patch->p_val, "*'"#\/~?^°,;|<>()[]{}$%&=`´" ) ) { dbg_cn( cn, DBGL_SYS, DBGT_ERR, - "%s %s with /%s and /%s MUST NOT be named with special characters or a leading number", - opt->long_name, patch->p_val, ARG_MASK, ARG_NETW ); + "%s %s with %s%s and %s%s MUST NOT be named with special characters or a leading number", + opt->long_name, patch->p_val, LONG_OPT_ARG_DELIMITER_STR, ARG_UHNA_PREFIXLEN, LONG_OPT_ARG_DELIMITER_STR, ARG_UHNA_NETWORK); return FAILURE; }
@@ -774,7 +800,7 @@ int32_t adj_patched_network( struct opt_type *opt, struct opt_parent *patch, cha
p = get_opt_parent_val( opt, patch->p_val ); - if ( (mc = get_opt_child( get_option(opt,0,ARG_MASK), patch ) ) && mc->c_val ) { + if ( (mc = get_opt_child( get_option(opt,0,ARG_UHNA_PREFIXLEN), patch ) ) && mc->c_val ) {
// obtain the just-given netmask:
@@ -786,8 +812,8 @@ int32_t adj_patched_network( struct opt_type *opt, struct opt_parent *patch, cha sprintf( out, "%d", *mask ); set_opt_child_val( mc, out ); } else { - dbg_cn( cn, DBGL_SYS, DBGT_ERR, "invalid %s %s /%s %s", - opt->long_name, patch->p_val, ARG_MASK, mc->c_val ); + dbg_cn( cn, DBGL_SYS, DBGT_ERR, "invalid %s %s %s%s %s", + opt->long_name, patch->p_val, LONG_OPT_ARG_DELIMITER_STR, ARG_UHNA_PREFIXLEN, mc->c_val); return FAILURE; } @@ -796,60 +822,65 @@ int32_t adj_patched_network( struct opt_type *opt, struct opt_parent *patch, cha // the prefix_len /24 notation: if ( *mask < MIN_MASK || *mask > MAX_MASK ) { - dbg_cn( cn, DBGL_SYS, DBGT_ERR, "invalid prefix-length %s %s /%s %s", - opt->long_name, patch->p_val, ARG_MASK, mc->c_val ); + dbg_cn( cn, DBGL_SYS, DBGT_ERR, "invalid prefix-length %s %s %s%s %s", + opt->long_name, patch->p_val, LONG_OPT_ARG_DELIMITER_STR, ARG_UHNA_PREFIXLEN, mc->c_val ); return FAILURE; } } else { - dbg_cn( cn, DBGL_SYS, DBGT_ERR, "missing prefix-length %s %s /%s %s", - opt->long_name, patch->p_val, ARG_MASK, mc->c_val ); + dbg_cn( cn, DBGL_SYS, DBGT_ERR, "missing prefix-length %s %s %s%s %s", + opt->long_name, patch->p_val, LONG_OPT_ARG_DELIMITER_STR, ARG_UHNA_PREFIXLEN, mc->c_val ); return FAILURE; } - } else if ( p && (mc = get_opt_child(get_option(opt,0,ARG_MASK), p) ) && mc->c_val ) { + } else if ( p && (mc = get_opt_child(get_option(opt,0,ARG_UHNA_PREFIXLEN), p) ) && mc->c_val ) { // obtain the already-configured netmask: *mask = strtol( mc->c_val , NULL , 10 ); } else {
- dbg_cn( cn, DBGL_SYS, DBGT_ERR, "missing %s %s /%s", - opt->long_name, patch->p_val, ARG_MASK ); + dbg_cn( cn, DBGL_SYS, DBGT_ERR, "missing %s %s %s%s", + opt->long_name, patch->p_val, LONG_OPT_ARG_DELIMITER_STR, ARG_UHNA_PREFIXLEN ); return FAILURE; }
// obtain the network:
- if ((nc = get_opt_child(get_option(opt, 0, ARG_NETW), patch)) && nc->c_val) { + if ((nc = get_opt_child(get_option(opt, 0, ARG_UHNA_NETWORK), patch)) && nc->c_val) {
// obtain the just-given network:
sprintf( out, "%s/%d", nc->c_val, *mask ); if ( str2netw( out, ip, '/', cn, mask, 32 ) == FAILURE ) { - dbg_cn( cn, DBGL_SYS, DBGT_ERR, "invalid patch %s %s /%s %s", - opt->long_name, patch->p_val, ARG_NETW, mc->c_val ); + dbg_cn( cn, DBGL_SYS, DBGT_ERR, "invalid patch %s %s %s%s %s", + opt->long_name, patch->p_val, LONG_OPT_ARG_DELIMITER_STR, ARG_UHNA_NETWORK, mc->c_val ); return FAILURE; - } - - set_opt_child_val( nc, ipStr( validate_net_mask( *ip, *mask, 0 ) ) ); + } + + if (ip_netmask_validate(ipX, mask, family) == FAILURE) { + dbg_cn(cn, DBGL_SYS, DBGT_ERR, "invalid prefix"); + return FAILURE; + } + + set_opt_child_val(nc, ipXAsStr(family, ipX)); - } else if ( p && (nc=get_opt_child( get_option(opt,0,ARG_NETW), p )) && nc->c_val ) { + } else if ( p && (nc=get_opt_child( get_option(opt,0,ARG_UHNA_NETWORK), p )) && nc->c_val ) {
// obtain the already-configured network:
sprintf( out, "%s/%d", nc->c_val, *mask ); if ( str2netw( out, ip, '/', cn, mask, 32 ) == FAILURE ) { - dbg_cn( cn, DBGL_SYS, DBGT_ERR, "invalid trac %s %s /%s %s", - opt->long_name, patch->p_val, ARG_NETW, mc->c_val ); + dbg_cn( cn, DBGL_SYS, DBGT_ERR, "invalid trac %s %s %s%s %s", + opt->long_name, patch->p_val, LONG_OPT_ARG_DELIMITER_STR, ARG_UHNA_NETWORK, mc->c_val ); return FAILURE; } } else { - dbg_cn( cn, DBGL_SYS, DBGT_ERR, "missing %s %s /%s", - opt->long_name, patch->p_val, ARG_NETW ); + dbg_cn( cn, DBGL_SYS, DBGT_ERR, "missing %s %s %s%s", + opt->long_name, patch->p_val, LONG_OPT_ARG_DELIMITER_STR, ARG_UHNA_NETWORK ); return FAILURE; } @@ -857,8 +888,11 @@ int32_t adj_patched_network( struct opt_type *opt, struct opt_parent *patch, cha sprintf( out, "%s/%d", nc->c_val, *mask ); return SUCCESS; } +#endif
-static char* nextword( char *s ) { +STATIC_FUNC +char* nextword(char *s) +{ uint32_t i = 0; uint8_t found_gap = NO; @@ -883,7 +917,9 @@ static char* nextword( char *s ) { }
-static char *debugWordDup( char* word, int32_t tag ) { +STATIC_FUNC +char *debugWordDup(char* word, int32_t tag) +{ if ( !word ) return NULL; @@ -895,8 +931,9 @@ static char *debugWordDup( char* word, int32_t tag ) {
- -static void strchange( char *s, char i, char o ) { +STATIC_FUNC +void strchange(char *s, char i, char o) +{ char *p; while ( s && (p=strchr( s, i )) ) @@ -904,8 +941,9 @@ static void strchange( char *s, char i, char o ) { }
- -static int32_t end_of_cmd_stream( struct opt_type *opt, char *s ) { +STATIC_FUNC +int32_t is_end_of_cmd_stream(struct opt_type *opt, char *s) +{ char test[MAX_ARG_SIZE]=""; snprintf( test, wordlen(s)+1, "%s", s ); @@ -927,8 +965,9 @@ static int32_t end_of_cmd_stream( struct opt_type *opt, char *s ) { }
- -static int8_t is_valid_opt_ival( struct opt_type *opt, char *s, struct ctrl_node *cn ) { +STATIC_FUNC +int8_t is_valid_opt_ival(struct opt_type *opt, char *s, struct ctrl_node *cn) +{ if ( opt->imin == opt->imax ) return SUCCESS; @@ -958,8 +997,8 @@ static int8_t is_valid_opt_ival( struct opt_type *opt, char *s, struct ctrl_node * call given function for each applied option * thus: if several hna are active func() is called once for each */ -int8_t func_for_each_opt( struct ctrl_node *cn, void *data, char* func_name, - int8_t (*func) ( struct ctrl_node *cn, void *data, struct opt_type *opt, struct opt_parent *p, struct opt_child *c ) ) +int8_t func_for_each_opt(struct ctrl_node *cn, void *data, char* func_name, + int8_t(*func) (struct ctrl_node *cn, void *data, struct opt_type *opt, struct opt_parent *p, struct opt_child *c)) { struct list_node *list_pos; @@ -1008,20 +1047,20 @@ int8_t func_for_each_opt( struct ctrl_node *cn, void *data, char* func_name, }
-static void show_opts_help( uint8_t all_opts, uint8_t verbose, struct ctrl_node *cn ) { +STATIC_FUNC +void show_opts_help(uint8_t all_opts, uint8_t verbose, struct ctrl_node *cn) +{ if ( !cn ) return; dbg_printf(cn, "\n"); - dbg_printf(cn, "Usage: %s [LONGOPT [%c]VAL] | [-SHORTOPT[SHORTOPT...] [%c]VAL] ...\n", + dbg_printf(cn, "Usage: %s [LONGOPT=[%c]VAL] | -[SHORTOPT[SHORTOPT...] [%c]VAL] ...\n", prog_name, ARG_RESET_CHAR , ARG_RESET_CHAR); - dbg_printf(cn, " e.g. %s -cid8\n", prog_name); - dbg_printf(cn, " e.g. %s -c a 192.200.200.1/24\n", prog_name); - dbg_printf(cn, " e.g. %s -c %s my-vpn /n=192.168.115.0 /m=24\n", prog_name, ARG_THROW); - dbg_printf(cn, " e.g. %s -c %s -my-vpn \n", prog_name, ARG_THROW); + dbg_printf(cn, " e.g. %s %s=eth1 %s=wlan0 %s=wlan0 d=3\n", prog_name, ARG_DEV, ARG_DEV, ARG_DEV); + dbg_printf(cn, " e.g. %s -c %s %s %s %s \n", prog_name, ARG_STATUS, ARG_INTERFACES, ARG_LINKS, ARG_ORIGINATORS); + dbg_printf(cn, " e.g. %s -c %s %s=%cwlan1 %s \n", prog_name, ARG_STATUS, ARG_DEV, ARG_RESET_CHAR, ARG_INTERFACES ); dbg_printf(cn, "\n"); - //dbg_printf(cn, "\nValid options are:\n" ); struct list_node *list_pos; @@ -1034,10 +1073,6 @@ static void show_opts_help( uint8_t all_opts, uint8_t verbose, struct ctrl_node if ( !( all_opts || opt->short_name ) ) continue; -#ifndef NODEPRECATED - if ( opt->call_custom_option == opt_deprecated ) - continue; -#endif if ( opt->long_name && opt->help && !opt->parent_name ) { @@ -1076,17 +1111,14 @@ static void show_opts_help( uint8_t all_opts, uint8_t verbose, struct ctrl_node if ( !c_opt->parent_name || !c_opt->help ) continue; -#ifndef NODEPRECATED - if ( c_opt->call_custom_option == opt_deprecated ) - continue; -#endif
if ( c_opt->short_name ) - snprintf( sn,5, ", /%c", c_opt->short_name ); + snprintf( sn,5, ", %s%c", LONG_OPT_ARG_DELIMITER_STR, c_opt->short_name ); else *sn = '\0';
- sprintf( st, " /%s%s %s ", c_opt->long_name, sn, c_opt->syntax ? c_opt->syntax: "" ); + sprintf( st, " %s%s%s %s ", + LONG_OPT_ARG_DELIMITER_STR, c_opt->long_name, sn, c_opt->syntax ? c_opt->syntax : "");
if ( c_opt->opt_t != A_PS0 && c_opt->imin != c_opt->imax ) sprintf( defaults, "def: %-6d range: [ %d %s %d ]", @@ -1105,7 +1137,7 @@ static void show_opts_help( uint8_t all_opts, uint8_t verbose, struct ctrl_node dbg_printf( cn, "\n"); if ( all_opts ) { - dbg_printf( cn, "Environment variables (e.g. sudo %s=/usr/src/bmx/lib %s -d3 eth0:bmx ):\n", + dbg_printf( cn, "Environment variables (e.g. sudo %s=/usr/src/bmx6/lib %s -d3 eth0:bmx ):\n", BMX_ENV_LIB_PATH, prog_name ); dbg_printf(cn, "\t%s\n", BMX_ENV_LIB_PATH ); @@ -1116,7 +1148,8 @@ static void show_opts_help( uint8_t all_opts, uint8_t verbose, struct ctrl_node }
-void register_option( struct opt_type *opt ) { +void register_option(struct opt_type *opt) +{ dbgf_all( DBGT_INFO, "%s", (opt&&opt->long_name) ? opt->long_name : "" ); @@ -1218,8 +1251,9 @@ failure: paranoia( -500091, YES ); }
- -static void remove_option( struct opt_type *opt ) { +STATIC_FUNC +void remove_option(struct opt_type *opt) +{ struct list_node *tmp_pos, *list_pos, *prev_pos; @@ -1253,32 +1287,21 @@ static void remove_option( struct opt_type *opt ) { dbgf( DBGL_SYS, DBGT_ERR, "%s no matching opt found", opt->long_name ); }
- -void register_options_array ( struct opt_type *fixed_options, int size ) { +void register_options_array(struct opt_type *fixed_options, int size) +{ int i = 0; int i_max = size / sizeof( struct opt_type ); paranoia( -500149, ((size % sizeof( struct opt_type )) != 0 ) ); - while ( i<i_max && (fixed_options[i].long_name || fixed_options[i].help) ) - register_option( &(fixed_options[i++]) ); + while ( i<i_max && (fixed_options[i].long_name || fixed_options[i].help)) + register_option(&(fixed_options[i++])); }
-/* -void remove_options_array ( struct opt_type *fixed_options ) { - - int i = 0; - - while ( fixed_options[i].long_name != NULL || fixed_options[i].help != NULL ) - remove_option( &(fixed_options[i++]) ); - -} -*/ - - -struct opt_type *get_option( struct opt_type *parent_opt, uint8_t short_opt, char *sin ) { +struct opt_type *get_option(struct opt_type *parent_opt, uint8_t short_opt, char *sin) +{ struct list_node *list_pos; int32_t len = 0; @@ -1321,16 +1344,16 @@ struct opt_type *get_option( struct opt_type *parent_opt, uint8_t short_opt, cha else if ( !short_opt && len == (int)strlen( opt->long_name ) && !strncasecmp( s, opt->long_name, len ) ) break; - else if ( !short_opt && len == 1 && s[0] == opt->short_name && on_the_fly && opt->dyn_t != A_INI ) + else if ( !short_opt && len == 1 && s[0] == opt->short_name && !initializing && opt->dyn_t != A_INI ) break; - else if ( !short_opt && len == 1 && s[0] == opt->short_name && !on_the_fly && opt->dyn_t != A_DYN ) + else if ( !short_opt && len == 1 && s[0] == opt->short_name && initializing && opt->dyn_t != A_DYN ) break; - else if ( short_opt && s[0] == opt->short_name && on_the_fly && opt->dyn_t != A_INI ) + else if ( short_opt && s[0] == opt->short_name && !initializing && opt->dyn_t != A_INI ) break; - else if ( short_opt && s[0] == opt->short_name && !on_the_fly && opt->dyn_t != A_DYN ) + else if ( short_opt && s[0] == opt->short_name && initializing && opt->dyn_t != A_DYN ) break; @@ -1357,9 +1380,8 @@ get_option_failure: }
- - -struct opt_child *get_opt_child ( struct opt_type *opt, struct opt_parent *p ) { +struct opt_child *get_opt_child(struct opt_type *opt, struct opt_parent *p) +{ struct list_node *pos; @@ -1380,7 +1402,8 @@ struct opt_child *get_opt_child ( struct opt_type *opt, struct opt_parent *p ) { return NULL; }
-void set_opt_child_val( struct opt_child *c, char *val ) { +void set_opt_child_val(struct opt_child *c, char *val) +{ if ( val && c->c_val && wordsEqual( c->c_val, val ) ) return; @@ -1394,7 +1417,9 @@ void set_opt_child_val( struct opt_child *c, char *val ) { c->c_val = debugWordDup(val, -300013); }
-static void set_opt_child_ref( struct opt_child *c, char *ref ) { +STATIC_FUNC +void set_opt_child_ref(struct opt_child *c, char *ref) +{ if ( ref && c->c_ref && wordsEqual( c->c_ref, ref ) ) return; @@ -1408,8 +1433,9 @@ static void set_opt_child_ref( struct opt_child *c, char *ref ) { c->c_ref = debugWordDup( ref, -300014 ); }
- -static void del_opt_child_save( struct list_node *prev, struct list_node *pos, struct opt_parent *p ) { +STATIC_FUNC +void del_opt_child_save(struct list_node *prev, struct list_node *pos, struct opt_parent *p) +{ struct opt_child *c = list_entry( pos, struct opt_child, list );
@@ -1422,7 +1448,9 @@ static void del_opt_child_save( struct list_node *prev, struct list_node *pos, s return; }
-static void del_opt_child( struct opt_parent *p, struct opt_type *opt ) { +STATIC_FUNC +void del_opt_child(struct opt_parent *p, struct opt_type *opt) +{ struct list_node *pos, *tmp, *prev; @@ -1439,7 +1467,9 @@ static void del_opt_child( struct opt_parent *p, struct opt_type *opt ) { } }
-static struct opt_child *add_opt_child( struct opt_type *opt, struct opt_parent *p ) { +STATIC_FUNC +struct opt_child *add_opt_child(struct opt_type *opt, struct opt_parent *p) +{ struct opt_child *c = debugMalloc( sizeof( struct opt_child ), -300017 ); memset( c, 0, sizeof(struct opt_child) ); @@ -1451,10 +1481,8 @@ static struct opt_child *add_opt_child( struct opt_type *opt, struct opt_parent return c; }
- - - -void set_opt_parent_val( struct opt_parent *p, char *val ) { +void set_opt_parent_val(struct opt_parent *p, char *val) +{ if ( val && p->p_val && wordsEqual( p->p_val, val ) ) return; @@ -1468,7 +1496,8 @@ void set_opt_parent_val( struct opt_parent *p, char *val ) { p->p_val = debugWordDup( val, -300015 ); }
-void set_opt_parent_ref( struct opt_parent *p, char *ref ) { +void set_opt_parent_ref(struct opt_parent *p, char *ref) +{ if ( ref && p->p_ref && wordsEqual( p->p_ref, ref ) ) return; @@ -1483,8 +1512,9 @@ void set_opt_parent_ref( struct opt_parent *p, char *ref ) { }
-struct opt_parent *add_opt_parent( struct opt_type *opt ) { - +struct opt_parent *add_opt_parent( struct opt_type *opt ) +{ + struct opt_parent *p = debugMalloc( sizeof( struct opt_parent ), -300018 ); memset( p, 0, sizeof(struct opt_parent) );
@@ -1495,7 +1525,9 @@ struct opt_parent *add_opt_parent( struct opt_type *opt ) { return p; }
-static void del_opt_parent_save( struct opt_type *opt, struct list_node *prev, struct list_node *pos ) { +STATIC_FUNC +void del_opt_parent_save(struct opt_type *opt, struct list_node *prev, struct list_node *pos) +{ struct opt_parent *p = list_entry( pos, struct opt_parent, list );
@@ -1509,7 +1541,8 @@ static void del_opt_parent_save( struct opt_type *opt, struct list_node *prev, s debugFree( p, -300058 ); }
-void del_opt_parent( struct opt_type *opt, struct opt_parent *parent ) { +void del_opt_parent(struct opt_type *opt, struct opt_parent *parent) +{ struct list_node *pos, *tmp, *prev = (struct list_node*)&(opt->d.parents_instance_list); @@ -1524,8 +1557,8 @@ void del_opt_parent( struct opt_type *opt, struct opt_parent *parent ) { } }
- -struct opt_parent *get_opt_parent_val ( struct opt_type *opt, char *val ) { +struct opt_parent *get_opt_parent_val(struct opt_type *opt, char *val) +{ struct opt_parent *p = NULL; struct list_node *pos; @@ -1547,7 +1580,8 @@ struct opt_parent *get_opt_parent_val ( struct opt_type *opt, char *val ) { return NULL; }
-struct opt_parent *get_opt_parent_ref ( struct opt_type *opt, char *ref ) { +struct opt_parent *get_opt_parent_ref(struct opt_type *opt, char *ref) +{ struct opt_parent *p = NULL; struct list_node *pos; @@ -1569,7 +1603,9 @@ struct opt_parent *get_opt_parent_ref ( struct opt_type *opt, char *ref ) { return NULL; }
-static struct opt_parent *dup_opt_parent ( struct opt_type *opt, struct opt_parent *p ) { +STATIC_FUNC +struct opt_parent *dup_opt_parent(struct opt_type *opt, struct opt_parent *p) +{ struct opt_parent *dup_p = add_opt_parent( opt ); set_opt_parent_val ( dup_p, p->p_val ); @@ -1604,8 +1640,8 @@ char *opt_cmd2str[] = { "OPT_UNREGISTER" };
- -int32_t check_apply_parent_option( uint8_t del, uint8_t cmd, uint8_t _save, struct opt_type *opt, char *in, struct ctrl_node *cn ) { +int32_t check_apply_parent_option(uint8_t del, uint8_t cmd, uint8_t _save, struct opt_type *opt, char *in, struct ctrl_node *cn) +{ int32_t ret; @@ -1627,8 +1663,9 @@ int32_t check_apply_parent_option( uint8_t del, uint8_t cmd, uint8_t _save, stru }
- -static int32_t call_opt_patch( uint8_t ad, struct opt_type *opt, struct opt_parent *patch, char *strm, struct ctrl_node *cn ) { +STATIC_FUNC +int32_t call_opt_patch(uint8_t ad, struct opt_type *opt, struct opt_parent *patch, char *strm, struct ctrl_node *cn) +{ dbgf_all( DBGT_INFO, "ad:%d opt:%s val:%s strm:%s", ad, opt->long_name, patch->p_val, strm ); @@ -1704,8 +1741,9 @@ static int32_t call_opt_patch( uint8_t ad, struct opt_type *opt, struct opt_pare return SUCCESS; }
- -static int32_t cleanup_patch( struct opt_type *opt, struct opt_parent *patch, struct ctrl_node *cn ) { +STATIC_FUNC +int32_t cleanup_patch(struct opt_type *opt, struct opt_parent *patch, struct ctrl_node *cn) +{ uint8_t del = patch->p_diff; char *val = patch->p_val; @@ -1717,14 +1755,12 @@ static int32_t cleanup_patch( struct opt_type *opt, struct opt_parent *patch, st if ( opt->opt_t == A_PS0 ) { -// if ( (del && !opt->d.found_parents) || (!del && opt->d.found_parents) ) if ((del && !opt->d.parents_instance_list.items) || (!del && opt->d.parents_instance_list.items)) patch->p_diff = NOP; } else if ( opt->opt_t == A_PS1 ) { -// if ( (del && !opt->d.found_parents) || (!del && get_opt_parent_val( opt, val )) ) if ((del && !opt->d.parents_instance_list.items) || (!del && get_opt_parent_val(opt, val))) patch->p_diff = NOP; @@ -1771,8 +1807,9 @@ static int32_t cleanup_patch( struct opt_type *opt, struct opt_parent *patch, st }
- -static int32_t _opt_connect ( uint8_t cmd, struct opt_type *opt, struct ctrl_node *cn, char *curr_strm_pos ) { +STATIC_FUNC +int32_t _opt_connect(uint8_t cmd, struct opt_type *opt, struct ctrl_node *cn, char *curr_strm_pos) +{ char tmp_path[MAX_PATH_SIZE+20] = ""; char unix_buff[MAX_UNIX_MSG_SIZE+1] = ""; @@ -1787,8 +1824,8 @@ static int32_t _opt_connect ( uint8_t cmd, struct opt_type *opt, struct ctrl_nod cleanup_all( -500141 ); sprintf( tmp_path, "%s/sock", run_dir ); - - struct sockaddr_un unix_addr; + + struct sockaddr_un unix_addr; memset( &unix_addr, 0, sizeof(struct sockaddr_un) ); unix_addr.sun_family = AF_LOCAL; @@ -1843,7 +1880,7 @@ static int32_t _opt_connect ( uint8_t cmd, struct opt_type *opt, struct ctrl_nod if ( connect ( unix_sock, (struct sockaddr *)&unix_addr, sizeof(struct sockaddr_un) ) < 0 ) { dbg( DBGL_SYS, DBGT_ERR, - "can't connect to unix socket '%s': %s ! Is bmxd running on this host ?", + "can't connect to unix socket '%s': %s ! Is bmx6 running on this host ?", tmp_path, strerror(errno) ); cleanup_all( CLEANUP_FAILURE ); @@ -1857,14 +1894,12 @@ static int32_t _opt_connect ( uint8_t cmd, struct opt_type *opt, struct ctrl_nod } - //printf("::::::::::::::::: from %s begin :::::::::::::::::::\n", tmp_path ); - if ( loop_mode ) trash=system( "clear" ); int32_t recv_buff_len = 0; - - while ( !terminating() ) { + + while (!terminating) { recv_buff_len = 0; @@ -1885,18 +1920,20 @@ static int32_t _opt_connect ( uint8_t cmd, struct opt_type *opt, struct ctrl_nod recv_buff_len = read( unix_sock, unix_buff, MAX_UNIX_MSG_SIZE ); if ( recv_buff_len > 0 ) { - + ssize_t trash; char *p; unix_buff[recv_buff_len] = '\0'; if ( (p=strchr( unix_buff, CONNECTION_END_CHR )) ) { *p='\0'; - printf( "%s", unix_buff ); + + //printf( "%s", unix_buff ); + trash = write(STDOUT_FILENO, unix_buff, strlen(unix_buff)); break; - } - - printf( "%s", unix_buff ); + } + //printf( "%s", unix_buff ); + trash = write(STDOUT_FILENO, unix_buff, strlen(unix_buff)); } } while ( recv_buff_len > 0 ); @@ -1917,12 +1954,12 @@ static int32_t _opt_connect ( uint8_t cmd, struct opt_type *opt, struct ctrl_nod close( unix_sock ); unix_sock = 0; - - if ( loop_mode && !terminating() ) + + if (loop_mode && !terminating) wait_sec_msec( loop_interval/1000, loop_interval%1000 ); - - } while ( loop_mode && !terminating() ); + + } while (loop_mode && !terminating); cleanup_all( CLEANUP_SUCCESS ); @@ -1932,12 +1969,13 @@ static int32_t _opt_connect ( uint8_t cmd, struct opt_type *opt, struct ctrl_nod return SUCCESS; }
- -static int32_t opt_connect ( uint8_t cmd, uint8_t _save, struct opt_type *opt, struct opt_parent *patch, struct ctrl_node *cn ) { +STATIC_FUNC +int32_t opt_connect(uint8_t cmd, uint8_t _save, struct opt_type *opt, struct opt_parent *patch, struct ctrl_node *cn) +{ char tmp_path[MAX_PATH_SIZE+20] = ""; - if ( cmd == OPT_SET_POST && !on_the_fly ) { + if ( cmd == OPT_SET_POST && initializing ) { // create unix sock: @@ -1964,7 +2002,7 @@ static int32_t opt_connect ( uint8_t cmd, uint8_t _save, struct opt_type *opt, s } else { dbg( DBGL_SYS, DBGT_ERR, - "%s busy! Probably bmxd is already running! Use [--%s %s] -c ... to connect to a running bmxd", + "%s busy! Probably bmx6 is already running! Use [--%s %s] -c ... to connect to a running bmx6", tmp_path, ARG_RUN_DIR, run_dir ); cleanup_all( CLEANUP_FAILURE ); @@ -1993,9 +2031,11 @@ static int32_t opt_connect ( uint8_t cmd, uint8_t _save, struct opt_type *opt, s return SUCCESS; }
-static int32_t call_opt_apply( uint8_t cmd, uint8_t save, struct opt_type *opt, struct opt_parent *_patch, char *in, struct ctrl_node *cn ) { +STATIC_FUNC +int32_t call_opt_apply(uint8_t cmd, uint8_t save, struct opt_type *opt, struct opt_parent *_patch, char *in, struct ctrl_node *cn) +{ - paranoia( -500154, ( cmd != OPT_CHECK && cmd != OPT_APPLY ) ); + assertion( -500154, ( cmd == OPT_CHECK || cmd == OPT_APPLY ) ); //cleanup_patch will change the patch, so we'll work with a duplicate and destroy it afterwards struct opt_parent *patch = dup_opt_parent( &Patch_opt, _patch ); @@ -2014,18 +2054,18 @@ static int32_t call_opt_apply( uint8_t cmd, uint8_t save, struct opt_type *opt, // keep this check after cleanup_patch and p_diff==NOP and list_empty check to let config_reload // apply all unchanged options - if ( (!on_the_fly && opt->dyn_t == A_DYN) || ( on_the_fly && opt->dyn_t == A_INI) ) { + if ( (initializing && opt->dyn_t == A_DYN) || ( !initializing && opt->dyn_t == A_INI) ) { dbg_cn( cn, DBGL_SYS, DBGT_ERR, "--%s%s%c can %s be applied at startup", opt->long_name, opt->short_name ? ", -" : "", opt->short_name ? opt->short_name : ' ', - on_the_fly ? "ONLY" : "NOT" ); + !initializing ? "ONLY" : "NOT" ); goto call_opt_apply_error; } if ( opt->call_custom_option == opt_connect ) { - + // this is necessary because we dont have the "*in" argument for the opt_something(...) prototype if ( _opt_connect( cmd, opt, cn, in ) == FAILURE ) goto call_opt_apply_error; @@ -2044,7 +2084,7 @@ static int32_t call_opt_apply( uint8_t cmd, uint8_t save, struct opt_type *opt, if ( opt->auth_t == A_ADM ) {
- dbg(DBGL_CHANGES, DBGT_INFO, "--%-22s %-30s", opt->long_name, patch->p_val); +// dbg(DBGL_CHANGES, DBGT_INFO, "--%-22s %-30s", opt->long_name, patch->p_val);
dbgf_all( DBGT_INFO, "--%-22s %-30s (%s order %d)", opt->long_name, patch->p_val, opt_cmd2str[ cmd ], opt->order ); @@ -2119,7 +2159,10 @@ This has already been done during call_option( cmd==CHECK || cmd==APPLY ) (-) impossible to configue in one step for parent-options
*/ -static int32_t track_opt_parent( uint8_t cmd, uint8_t save, struct opt_type *p_opt, struct opt_parent *p_patch, struct ctrl_node *cn ) { + +STATIC_FUNC +int32_t track_opt_parent(uint8_t cmd, uint8_t save, struct opt_type *p_opt, struct opt_parent *p_patch, struct ctrl_node *cn) +{ struct list_node *pos; struct opt_parent *p_reftr = get_opt_parent_ref( p_opt, p_opt->opt_t == A_PMN ? p_patch->p_ref : NULL ); @@ -2212,8 +2255,8 @@ static int32_t track_opt_parent( uint8_t cmd, uint8_t save, struct opt_type *p_ } else if ( !c_patch->c_val && !c_track ) { if ( save ) { - dbg_cn( cn, DBGL_SYS, DBGT_ERR, "--%s %s /%s does not exist", - p_opt->long_name, p_patch->p_val, c_patch->c_opt->long_name ); + dbg_cn( cn, DBGL_SYS, DBGT_ERR, "--%s %s %s%s does not exist", + p_opt->long_name, p_patch->p_val, LONG_OPT_ARG_DELIMITER_STR, c_patch->c_opt->long_name ); return FAILURE; } @@ -2222,8 +2265,8 @@ static int32_t track_opt_parent( uint8_t cmd, uint8_t save, struct opt_type *p_ ( !c_patch->c_ref && !c_track->c_ref ) ) ) { - dbgf_all( DBGT_INFO, "--%s %s /%s %s already configured", - p_opt->long_name, p_patch->p_val, c_patch->c_opt->long_name, c_patch->c_val ); + dbgf_all( DBGT_INFO, "--%s %s %s%s %s already configured", + p_opt->long_name, p_patch->p_val, LONG_OPT_ARG_DELIMITER_STR, c_patch->c_opt->long_name, c_patch->c_val ); } else if ( c_patch->c_val ) { @@ -2246,15 +2289,15 @@ static int32_t track_opt_parent( uint8_t cmd, uint8_t save, struct opt_type *p_ } if ( cmd == OPT_APPLY && changed_child && c_patch->c_opt->auth_t == A_ADM ) - dbg_cn( cn, DBGL_CHANGES, DBGT_INFO, "--%-22s %-30s /%-22s %c%-30s", - p_opt->long_name, p_patch->p_val, + dbg_cn( cn, DBGL_CHANGES, DBGT_INFO, "--%-22s %-30s %s%-22s %c%-30s", + p_opt->long_name, p_patch->p_val, LONG_OPT_ARG_DELIMITER_STR, c_patch->c_opt->long_name, c_patch->c_val?' ':'-', c_patch->c_val ); } } - +/* // be pedantic only after startup (!on_the_fly) and not reload-config (!save) - if ( !changed && on_the_fly && save && pedantic_check ) { + if (!changed && !initializing && save) { dbg_cn( cn, DBGL_SYS, DBGT_ERR, "--%s %s already configured", p_opt->long_name, p_patch->p_val ); @@ -2263,12 +2306,15 @@ static int32_t track_opt_parent( uint8_t cmd, uint8_t save, struct opt_type *p_ // have already checked for double applied options return FAILURE; } +*/ } return SUCCESS; -} +} +
-int32_t call_option( uint8_t ad, uint8_t cmd, uint8_t save, struct opt_type *opt, struct opt_parent *patch, char *in, struct ctrl_node *cn ) { +int32_t call_option(uint8_t ad, uint8_t cmd, uint8_t save, struct opt_type *opt, struct opt_parent *patch, char *in, struct ctrl_node *cn) +{ dbgf_all( DBGT_INFO, "%s (cmd %s del %d save %d parent_name %s order %d) p_val: %s in: %s", opt->long_name, opt_cmd2str[ cmd ], ad, save, opt->parent_name, opt->order, patch?patch->p_val:"-", in ); @@ -2296,7 +2342,7 @@ int32_t call_option( uint8_t ad, uint8_t cmd, uint8_t save, struct opt_type *opt } - if ( (opt->pos_t==A_END || opt->pos_t==A_ETE) && in && !end_of_cmd_stream( opt, in ) ) { + if ( (opt->pos_t==A_END || opt->pos_t==A_ETE) && in && !is_end_of_cmd_stream( opt, in ) ) { if ( cn ) { dbg_cn( cn, DBGL_CHANGES, DBGT_ERR, "--%s%s%c MUST be last option before line feed", @@ -2375,7 +2421,7 @@ call_option_failure: opt->long_name ? opt->long_name : "-", in ? in: "-", patch ? patch->p_diff : -1, ad, opt->ival ? *(opt->ival) : 0, opt->imin, opt->imax, opt->idef, - opt_cmd2str[cmd], opt->opt_t, on_the_fly, wordlen(in) ); + opt_cmd2str[cmd], opt->opt_t, !initializing, wordlen(in) ); /* This results in too much side effects. And MUST be handled by calling function like apply_stream_opts() if ( !on_the_fly && !pedantic_cmd_check && ( cmd == OPT_PATCH || cmd == OPT_ADJUST || cmd == OPT_CHECK || cmd == OPT_APPLY ) ) { @@ -2391,9 +2437,8 @@ call_option_failure: return FAILURE; }
- - -int respect_opt_order( uint8_t test, int8_t last, int8_t next, struct opt_type *on, uint8_t load, uint8_t cmd, struct ctrl_node *cn ) { +int respect_opt_order(uint8_t test, int8_t last, int8_t next, struct opt_type *on, uint8_t load, uint8_t cmd, struct ctrl_node *cn) +{ struct list_node *list_pos; struct opt_type *opt; @@ -2456,21 +2501,24 @@ int respect_opt_order( uint8_t test, int8_t last, int8_t next, struct opt_type *
// if returns SUCCESS then fd might be closed ( called remove_ctrl_node( fd ) ) or not. // if returns FAILURE then fd IS open and must be closed -int8_t apply_stream_opts( char *s, uint8_t cmd, uint8_t load_cfg, struct ctrl_node *cn ) { + +int8_t apply_stream_opts(char *s, uint8_t cmd, uint8_t load_cfg, struct ctrl_node *cn) +{ enum { - NEXT_OPT, // 0 - NEW_OPT, // 1 - SHORT_OPT, // 2 - LONG_OPT, // 3 - LONG_OPT_VAL, // 4 - LONG_OPT_WHAT, // 5 - LONG_OPT_ARG, // 6 - LONG_OPT_ARG_VAL, // 7 + NEXT_OPT, // 0 + NEW_OPT, // 1 + SHORT_OPT, // 2 + LONG_OPT, // 3 + LONG_OPT_VAL, // 4 + LONG_OPT_WHAT, // 5 + LONG_OPT_ARG, // 6 + LONG_OPT_ARG_VAL, // 7 }; - + +#if !defined(NO_DEBUG_ALL) || defined(TEST_DEBUG) char *state2str[] = {"NEXT_OPT","NEW_OPT","SHORT_OPT","LONG_OPT","LONG_OPT_VAL","LONG_OPT_WHAT","LONG_OPT_ARG","LONG_OPT_ARG_VAL"}; - +#endif int8_t state = NEW_OPT; struct opt_type *opt = NULL; @@ -2502,23 +2550,23 @@ int8_t apply_stream_opts( char *s, uint8_t cmd, uint8_t load_cfg, struct ctrl_no return SUCCESS; } - - if ( state == NEXT_OPT ) { + + if (state == NEXT_OPT) { // assumes s points to last successfully processed word or its following gap s = nextword(s); state = NEW_OPT; - - } else if ( state == NEW_OPT && wordlen(s) >= 2 && s[0]=='-' && s[1]!='-' ) { + + } else if (state == NEW_OPT && wordlen(s) >= 2 && s[0] == '-' && s[1] != '-') { s++; state=SHORT_OPT; - - } else if ( state == NEW_OPT && wordlen(s) >=3 && s[0]=='-' && s[1]=='-' ) { + + } else if (state == NEW_OPT && wordlen(s) >= 3 && s[0] == '-' && s[1] == '-') { s+=2; state=LONG_OPT; - - } else if ( state == NEW_OPT && wordlen(s) >=1 && s[0]!='-' && s[0]!='/' ) { + + } else if (state == NEW_OPT && wordlen(s) >= 1 && s[0] != '-' && s[0] != LONG_OPT_ARG_DELIMITER_CHAR) { state=LONG_OPT; @@ -2617,8 +2665,8 @@ int8_t apply_stream_opts( char *s, uint8_t cmd, uint8_t load_cfg, struct ctrl_no if ( opt->opt_t == A_PS1 ) { s = s + (del = ((s[0]==ARG_RESET_CHAR) ? 1 : 0) ); - - if ( (pb=check_apply_parent_option( del, cmd, (on_the_fly?YES:NO)/*save*/, opt, s, cn )) == FAILURE ) + + if ((pb = check_apply_parent_option(del, cmd, (initializing ? NO : YES)/*save*/, opt, s, cn)) == FAILURE) goto apply_args_error; s+=pb; @@ -2646,24 +2694,24 @@ int8_t apply_stream_opts( char *s, uint8_t cmd, uint8_t load_cfg, struct ctrl_no if ( opt->opt_t != A_PMN ) goto apply_args_error; + + char* delmiter_ptr = index(s, LONG_OPT_ARG_DELIMITER_CHAR); - char* slashp = index( s, '/' ); - - if ( slashp && slashp == nextword(s) && patch->p_diff == DEL ) { + if ( delmiter_ptr && delmiter_ptr == nextword(s) && patch->p_diff == DEL ) { - wordCopy( argument, slashp+1 ); + wordCopy( argument, delmiter_ptr+1 ); dbg_cn( cn, DBGL_SYS, DBGT_ERR, - "--%s %s can not be resetted and refined at the same time. Just omit /%s!", - opt->long_name, patch->p_val, argument ); + "--%s %s can not be resetted and refined at the same time. Just omit %s%s!", + opt->long_name, patch->p_val, LONG_OPT_ARG_DELIMITER_STR, argument ); goto apply_args_error; - } else if ( slashp && slashp == nextword(s) ) { + } else if ( delmiter_ptr && delmiter_ptr == nextword(s) ) { //nextword starts with slashp - s = slashp+1; + s = delmiter_ptr+1; state = LONG_OPT_ARG; } else { @@ -2672,7 +2720,7 @@ int8_t apply_stream_opts( char *s, uint8_t cmd, uint8_t load_cfg, struct ctrl_no goto apply_args_error; //indicate end of LONG_OPT_ARGs - if ( (call_option( ADD, cmd, (on_the_fly?YES:NO)/*save*/, opt, patch, pmn_s, cn )) == FAILURE ) + if ( (call_option( ADD, cmd, (initializing?NO:YES)/*save*/, opt, patch, pmn_s, cn )) == FAILURE ) goto apply_args_error; del_opt_parent( &Patch_opt, patch ); @@ -2747,11 +2795,10 @@ apply_args_error: return FAILURE; -} - - +}
-void apply_init_args( int argc, char *argv[] ) { +void apply_init_args(int argc, char *argv[]) +{ prog_name = argv[0]; @@ -2768,249 +2815,38 @@ void apply_init_args( int argc, char *argv[] ) { respect_opt_order( OPT_APPLY, 0, 99, NULL, NO/*load_cofig*/, OPT_POST, 0/*probably closed*/ ); close_ctrl_node( CTRL_CLOSE_STRAIGHT, cn ); - - cb_plugin_hooks( NULL, PLUGIN_CB_CONF ); - - free_init_string(); -} - - - - - - - - -char *ipStr( uint32_t addr ) { -#define IP2S_ARRAY_LEN 10 - static uint8_t c=0; - static char str[IP2S_ARRAY_LEN][IP4_STR_LEN]; - - c = (c+1) % IP2S_ARRAY_LEN; - - inet_ntop( AF_INET, &addr, str[c], IP4_STR_LEN ); - - return str[c]; -} - - - -int8_t str2netw( char* args, uint32_t *ip, char delimiter, struct ctrl_node *cn, int32_t *val, int32_t max ) { - - struct in_addr tmp_ip_holder; - char *slashptr = NULL; - - char switch_arg[30]; - - if ( wordlen( args ) < 1 || wordlen( args ) > 29 ) - return FAILURE; - - wordCopy( switch_arg, args ); - switch_arg[wordlen( args )] = '\0'; - - if ( val ) { - - if ( ( slashptr = strchr( switch_arg, delimiter ) ) != NULL ) { - char *end = NULL; - - *slashptr = '\0'; - - errno = 0; - *val = strtol( slashptr+1, &end, 10 ); - - if ( ( errno == ERANGE ) || *val > max || *val < 0 ) { - - dbgf_cn( cn, DBGL_SYS, DBGT_ERR, "invalid argument %s %s", - args, strerror( errno ) ); - - return FAILURE; - - } else if ( end==slashptr+1 || wordlen(end) ) { - - dbgf_cn( cn, DBGL_SYS, DBGT_ERR, "invalid argument trailer %s", end ); - return FAILURE; - } - - } else { - - dbgf_cn( cn, DBGL_SYS, DBGT_ERR, "invalid argument %s! Fix you parameters!", switch_arg ); - return FAILURE; - } - } - - errno = 0; - - if ( (inet_pton( AF_INET, switch_arg, &tmp_ip_holder )) < 1 || !tmp_ip_holder.s_addr ) { - - dbgf_all( DBGT_WARN, "invalid argument: %s: %s", args, strerror(errno) ); - return FAILURE; - } - - *ip = tmp_ip_holder.s_addr; - - return SUCCESS; -} - - -void addr_to_str( uint32_t addr, char *str ) { - - inet_ntop( AF_INET, &addr, str, IP4_STR_LEN ); - return; -} - - - -uint32_t validate_net_mask( uint32_t ip, uint32_t mask, struct ctrl_node *cn ) { - - uint32_t nip = ip & htonl( 0xFFFFFFFF<<( 32 - mask ) ); - - if ( cn && nip != ip ) - dbg_cn( cn, DBGL_CHANGES, DBGT_WARN, - "inconsistent network prefix %s/%d - probably you mean: %s/%d", - ipStr(ip), mask, ipStr(nip), mask); - - return nip; -} - - - -int32_t check_file( char *path, uint8_t write, uint8_t exec ) { - - struct stat fstat; - - errno = 0; - int stat_ret = stat( path, &fstat ); - - if ( stat_ret < 0 ) { - - dbgf( DBGL_CHANGES, DBGT_WARN, "%s does not exist! (%s)", - path, strerror(errno)); - - } else { - - if ( S_ISREG( fstat.st_mode ) && - (S_IRUSR & fstat.st_mode) && - ((S_IWUSR & fstat.st_mode) || !write) && - ((S_IXUSR & fstat.st_mode) || !exec) ) - return SUCCESS; - - dbgf( DBGL_SYS, DBGT_ERR, - "%s exists but has inapropriate permissions (%s)", - path, strerror(errno)); - - } - - return FAILURE; -} - -int32_t check_dir( char *path, uint8_t create, uint8_t write ) { - - struct stat fstat; - - errno = 0; - int stat_ret = stat( path, &fstat ); - - if ( stat_ret < 0 ) { - - if ( create && mkdir( path, S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH ) >= 0 ) - return SUCCESS; - - dbgf( DBGL_SYS, DBGT_ERR, - "directory %s does not exist and can not be created (%s)", path, strerror(errno)); - - } else { - - if ( S_ISDIR( fstat.st_mode ) && - ( S_IRUSR & fstat.st_mode) && - ( S_IXUSR & fstat.st_mode) && - ((S_IWUSR & fstat.st_mode) || !write) ) - return SUCCESS; - - dbgf( DBGL_SYS, DBGT_ERR, - "directory %s exists but has inapropriate permissions (%s)", path, strerror(errno)); - - } - - return FAILURE; - -} - - - - -uint32_t wordlen ( char *s ) { - - uint32_t i = 0; - - if ( !s ) - return 0; - - for( i=0; i<strlen(s); i++ ) { - - if ( s[i] == '\0' || s[i] == '\n' || s[i]==' ' || s[i]=='\t' ) - return i; - } - - return i; -} -
-int8_t wordsEqual ( char *a, char *b ) { + cb_plugin_hooks(PLUGIN_CB_CONF, NULL); - if ( wordlen( a ) == wordlen ( b ) && !strncmp( a, b, wordlen(a) ) ) - return YES; - - return NO; -} - - -void wordCopy( char *out, char *in ) { - - if ( out && in && wordlen(in) < MAX_ARG_SIZE ) { - - snprintf( out, wordlen(in)+1, "%s", in ); - - } else if ( out && !in ) { - - out[0]=0; - - } else { - - dbgf( DBGL_SYS, DBGT_ERR, "called with out: %s and in: %s", out, in ); - cleanup_all( -500017 ); - - } + free_init_string(); }
+STATIC_FUNC +int8_t show_info(struct ctrl_node *cn, void *data, struct opt_type *opt, struct opt_parent *p, struct opt_child *c) +{
-static int8_t show_info ( struct ctrl_node *cn, void *data, struct opt_type *opt, struct opt_parent *p, struct opt_child *c ) { - - if ( c ) - dbg_printf( cn, " /%-18s %-20s %s%s\n", - c->c_opt->long_name, c->c_val, (c->c_ref ? "resolved from " : ""), (c->c_ref ? c->c_ref : "") ); - else - dbg_printf( cn, " %-22s %-20s %s%s\n", - opt->long_name, p->p_val, (p->p_ref ? "resolved from " : ""), (p->p_ref ? p->p_ref : "") ); + if (c) { + dbg_printf(cn, " %s%-18s %-20s %s%s\n", + LONG_OPT_ARG_DELIMITER_STR, c->c_opt->long_name, c->c_val, + (c->c_ref ? "resolved from " : ""), (c->c_ref ? c->c_ref : "")); + } else { + dbg_printf(cn, " %-22s %-20s %s%s\n", + opt->long_name, p->p_val, (p->p_ref ? "resolved from " : ""), (p->p_ref ? p->p_ref : "")); + } return SUCCESS; }
- -static int32_t opt_show_info ( uint8_t cmd, uint8_t _save, struct opt_type *opt, struct opt_parent *patch, struct ctrl_node *cn ) { +STATIC_FUNC +int32_t opt_show_parameter(uint8_t cmd, uint8_t _save, struct opt_type *opt, struct opt_parent *patch, struct ctrl_node *cn) +{ if ( cmd == OPT_APPLY ) { - /* - //TBD: include all routing tables - dbg_printf(cn, " source_version %s\n", SOURCE_VERSION); - dbg_printf(cn, " compat_version %i\n", COMPAT_VERSION); - dbg_printf(cn, "\n"); - */ - func_for_each_opt( cn, NULL, "opt_show_info()", show_info ); - - if ( !on_the_fly ) + + if (initializing) cleanup_all(CLEANUP_SUCCESS); @@ -3020,8 +2856,9 @@ static int32_t opt_show_info ( uint8_t cmd, uint8_t _save, struct opt_type *opt, }
- -static int32_t opt_no_fork ( uint8_t cmd, uint8_t _save, struct opt_type *opt, struct opt_parent *patch, struct ctrl_node *cn ) { +STATIC_FUNC +int32_t opt_no_fork(uint8_t cmd, uint8_t _save, struct opt_type *opt, struct opt_parent *patch, struct ctrl_node *cn) +{ if ( cmd == OPT_APPLY ) { @@ -3029,7 +2866,7 @@ static int32_t opt_no_fork ( uint8_t cmd, uint8_t _save, struct opt_type *opt, s activate_debug_system(); - } else if ( cmd == OPT_POST && !on_the_fly ) { + } else if ( cmd == OPT_POST && initializing ) { activate_debug_system(); @@ -3038,8 +2875,9 @@ static int32_t opt_no_fork ( uint8_t cmd, uint8_t _save, struct opt_type *opt, s return SUCCESS; }
- -static int32_t opt_debug ( uint8_t cmd, uint8_t _save, struct opt_type *opt, struct opt_parent *patch, struct ctrl_node *cn ) { +STATIC_FUNC +int32_t opt_debug(uint8_t cmd, uint8_t _save, struct opt_type *opt, struct opt_parent *patch, struct ctrl_node *cn) +{ if ( cmd == OPT_APPLY ) { @@ -3049,6 +2887,7 @@ static int32_t opt_debug ( uint8_t cmd, uint8_t _save, struct opt_type *opt, str if ( ival == DBGL_SYS || ival == DBGL_CHANGES || ival == DBGL_TEST || + ival == DBGL_DUMP || ival == DBGL_ALL ) { @@ -3056,6 +2895,7 @@ static int32_t opt_debug ( uint8_t cmd, uint8_t _save, struct opt_type *opt, str add_dbgl_node( cn, ival ); return SUCCESS; +/* } else if ( ival == DBGL_ROUTES ) { check_apply_parent_option( ADD, OPT_APPLY, _save, get_option( 0, 0, ARG_ROUTES ), 0, cn ); @@ -3063,10 +2903,11 @@ static int32_t opt_debug ( uint8_t cmd, uint8_t _save, struct opt_type *opt, str } else if ( ival == DBGL_LINKS ) { check_apply_parent_option( ADD, OPT_APPLY, _save, get_option( 0, 0, ARG_LINKS ), 0, cn ); - +*/ } else if ( ival == DBGL_DETAILS ) { check_apply_parent_option( ADD, OPT_APPLY, 0, get_option( 0, 0, ARG_STATUS ), 0, cn ); + check_apply_parent_option( ADD, OPT_APPLY, 0, get_option( 0, 0, ARG_INTERFACES ), 0, cn ); check_apply_parent_option( ADD, OPT_APPLY, _save, get_option( 0, 0, ARG_LINKS ), 0, cn ); check_apply_parent_option( ADD, OPT_APPLY, _save, get_option( 0, 0, ARG_ORIGINATORS ), 0, cn ); /* @@ -3094,8 +2935,9 @@ static int32_t opt_debug ( uint8_t cmd, uint8_t _save, struct opt_type *opt, str return SUCCESS; }
- -static int32_t opt_help ( uint8_t cmd, uint8_t _save, struct opt_type *opt, struct opt_parent *patch, struct ctrl_node *cn ) { +STATIC_FUNC +int32_t opt_help(uint8_t cmd, uint8_t _save, struct opt_type *opt, struct opt_parent *patch, struct ctrl_node *cn) +{ if ( cmd != OPT_APPLY ) return SUCCESS; @@ -3121,23 +2963,24 @@ static int32_t opt_help ( uint8_t cmd, uint8_t _save, struct opt_type *opt, stru show_opts_help( YES, NO, cn ); } else if ( !strcmp(opt->long_name, ARG_VERSION) ) { - - dbg_printf( cn, "BMX (BatMan-eXp) %s-rv%d (compatibility version %i)\n", - SOURCE_VERSION, REVISION_VERSION, COMPAT_VERSION); + + dbg_printf(cn, "%s-%s (compatibility=%d code=cv%d)\n", + BMX_BRANCH, BRANCH_VERSION, COMPATIBILITY_VERSION, CODE_VERSION); } else { show_opts_help( NO, NO, cn ); } - if ( !on_the_fly ) + if ( initializing ) cleanup_all(CLEANUP_SUCCESS); return SUCCESS; }
- -static int32_t opt_quit ( uint8_t cmd, uint8_t _save, struct opt_type *opt, struct opt_parent *patch, struct ctrl_node *cn ) { +STATIC_FUNC +int32_t opt_quit(uint8_t cmd, uint8_t _save, struct opt_type *opt, struct opt_parent *patch, struct ctrl_node *cn) +{ if ( cmd == OPT_APPLY ) close_ctrl_node( CTRL_CLOSE_SUCCESS, cn ); @@ -3146,8 +2989,9 @@ static int32_t opt_quit ( uint8_t cmd, uint8_t _save, struct opt_type *opt, stru }
- -static int32_t opt_run_dir ( uint8_t cmd, uint8_t _save, struct opt_type *opt, struct opt_parent *patch, struct ctrl_node *cn ) { +STATIC_FUNC +int32_t opt_run_dir(uint8_t cmd, uint8_t _save, struct opt_type *opt, struct opt_parent *patch, struct ctrl_node *cn) +{ char tmp_dir[MAX_PATH_SIZE] = ""; @@ -3165,7 +3009,7 @@ static int32_t opt_run_dir ( uint8_t cmd, uint8_t _save, struct opt_type *opt, s strcpy( run_dir, tmp_dir ); } - } else if ( cmd == OPT_SET_POST && !on_the_fly ) { + } else if ( cmd == OPT_SET_POST && initializing ) { if ( check_dir( run_dir, YES/*create*/, YES/*writable*/ ) == FAILURE ) return FAILURE; @@ -3203,10 +3047,6 @@ static struct opt_type control_options[]= {ODI,0,ARG_VERSION, 'v',0,A_PS0,A_USR,A_DYI,A_ARG,A_ANY, 0, 0, 0, 0, opt_help, 0, "show version"}, -#ifndef NOTRAILER - {ODI,0,ARG_TRAILER, 'V',0,A_PS0,A_USR,A_INI,A_ARG,A_END, 0, 0, 0, 0, opt_help, - 0, "show trailer"}, -#endif {ODI,0,ARG_TEST, 0, 0,A_PS0,A_ADM,A_DYI,A_ARG,A_ANY, &Testing, 0, 1, 0, 0, 0, "test remaining args and provide feedback about projected success (without applying them)"}, @@ -3216,15 +3056,15 @@ static struct opt_type control_options[]= {ODI,0,ARG_DEBUG, 'd',0,A_PS1,A_ADM,A_DYN,A_ARG,A_ETE, 0, DBGL_MIN, DBGL_MAX, -1, opt_debug, ARG_VALUE_FORM, "show debug information:\n" " 0 : system\n" - " 1 : originators\n" - " 2 : gateways\n" +// " 1 : routes\n" +// " 2 : gateways\n" " 3 : changes\n" - " 4 : verbose changes\n" - " 5 : profiling (depends on -DDEBUG_MALLOC -DMEMORY_USAGE -DPROFILE_DATA)\n" - " 7 : services\n" + " 4 : verbose changes (depends on -DNO_DEBUG_ALL)\n" + " 5 : profiling (depends on -DNO_DEBUG_MALLOC -DNO_MEMORY_USAGE -DPROFILE_DATA)\n" +// " 7 : services\n" " 8 : details\n" - " 9 : announced networks and interfaces\n" - " 10 : links\n" +// " 9 : announced networks and interfaces\n" +// " 10 : links\n" " 11 : testing" }, {ODI,0,ARG_RUN_DIR, 0, 2,A_PS1,A_ADM,A_INI,A_CFA,A_ANY, 0, 0, 0, 0, opt_run_dir, @@ -3240,31 +3080,24 @@ static struct opt_type control_options[]= ARG_VALUE_FORM, "periodicity in ms with which client daemon in loop-mode refreshes debug information"}, #endif -#ifndef NODEPRECATED - {ODI,0,"batch_mode", 'b',3,A_PS0,A_ADM,A_INI,A_ARG,A_ANY, 0, 0, 0, 0, opt_deprecated,0,0}, -#endif {ODI,0,ARG_CONNECT, 'c',3,A_PS0,A_ADM,A_INI,A_ARG,A_EAT, 0, 0, 0, 0, opt_connect, 0, "set client mode. Connect and forward remaining args to main routing daemon"},
//order=5: so when used during startup it also shows the config-file options - {ODI,0,ARG_SHOW_CHANGED, 'i',5,A_PS0,A_ADM,A_DYI,A_ARG,A_ANY, 0, 0, 0, 0, opt_show_info, - 0, "inform about configured options" }, -#ifndef LESS_OPTIONS - {ODI,0,ARG_PEDANTIC_CMDCHECK, 0, 5,A_PS1,A_ADM,A_DYI,A_CFA,A_ANY, &pedantic_check,MIN_PEDANT_CHK, MAX_PEDANT_CHK, DEF_PEDANT_CHK, 0, - ARG_VALUE_FORM, "disable/enable pedantic checking of command-line parameters and context -\n" - " ( e.g. fail setting a parameter without changing it)" }, -#endif - {ODI,0,"dbg_mute_timeout", 0, 5,A_PS1,A_ADM,A_DYI,A_CFA,A_ANY, &dbg_mute_to, 0, 10000000, 100000, 0, + {ODI,0,ARG_SHOW_PARAMETER, 'p',5,A_PS0,A_ADM,A_DYI,A_ARG,A_ANY, 0, 0, 0, 0, opt_show_parameter, + 0, "show configured parameters"} + , + + {ODI,0,"dbg_mute_timeout", 0, 5,A_PS1,A_ADM,A_DYI,A_CFA,A_ANY, &dbg_mute_to, 0, 10000000, 100000, 0, ARG_VALUE_FORM, "set timeout in ms for muting frequent messages"},
{ODI,0,ARG_QUIT,EOS_DELIMITER, 5,A_PS0,A_USR,A_DYN,A_ARG,A_END, 0, 0, 0, 0, opt_quit,0,0} };
- - -void init_control( void ) { +void init_control(void) +{ int i; @@ -3275,7 +3108,7 @@ void init_control( void ) { for ( i = DBGL_MIN; i <= DBGL_MAX; i++ ) LIST_INIT_HEAD( dbgl_clients[i], struct dbgl_node, list ); - openlog( "bmx", LOG_PID, LOG_DAEMON ); + openlog( "bmx6", LOG_PID, LOG_DAEMON ); memset( &Patch_opt, 0, sizeof( struct opt_type ) );
@@ -3286,7 +3119,8 @@ void init_control( void ) { }
-void cleanup_config( void ) { +void cleanup_config(void) +{ del_opt_parent( &Patch_opt, NULL ); @@ -3297,9 +3131,8 @@ void cleanup_config( void ) {
}
- - -void cleanup_control( void ) { +void cleanup_control(void) +{ int8_t i; @@ -3319,6 +3152,5 @@ void cleanup_control( void ) { remove_dbgl_node( (list_entry( (&dbgl_clients[i])->next, struct dbgl_node, list ))->cn ); } - }
diff --git a/control.h b/control.h index 27fe0f4..5b09231 100644 --- a/control.h +++ b/control.h @@ -1,6 +1,5 @@ /* - * Copyright (C) 2010 BMX contributors: - * Axel Neumann + * Copyright (c) 2010 Axel Neumann * 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. @@ -27,22 +26,22 @@ #define DBGT_ERR 3
-//extern int debug_level; #define DBGL_MIN 0 #define DBGL_SYS 0 -#define DBGL_ROUTES 1 -#define DBGL_GATEWAYS 2 +//#define DBGL_ROUTES 1 +//#define DBGL_GATEWAYS 2 #define DBGL_CHANGES 3 #define DBGL_ALL 4 #define DBGL_PROFILE 5 -#define DBGL_UNUSED 6 -#define DBGL_SERVICES 7 +//#define DBGL_UNUSED 6 +//#define DBGL_SERVICES 7 #define DBGL_DETAILS 8 -#define DBGL_HNAS 9 -#define DBGL_LINKS 10 +//#define DBGL_HNAS 9 +//#define DBGL_LINKS 10 #define DBGL_TEST 11 -#define DBGL_MAX 11 -#define DBGL_INVALID 12 +#define DBGL_DUMP 12 +#define DBGL_MAX 12 +#define DBGL_INVALID 13
extern int unix_sock; @@ -58,6 +57,19 @@ extern int32_t Client_mode; #define CONNECTION_END_STR "$" #define CONNECTION_END_CHR '$'
+ +#define LONG_OPT_ARG_DELIMITER_CHAR '/'//'\' +#define LONG_OPT_ARG_DELIMITER_STR "/"//"\" + +#define REFERENCE_KEY_WORD "ref:" + +#define EOS_DELIMITER '#' + + +#define ARG_RESET "-" /* s-string preamble for call_option() to reset opt to default */ +#define ARG_RESET_CHAR '-' +#define OPT_CHILD_UNDEFINED -1 + enum { CTRL_CLOSE_ERROR, CTRL_CLOSE_SUCCESS, @@ -75,7 +87,7 @@ struct ctrl_node struct list_node list; int fd; void (*cn_fd_handler) (struct ctrl_node *); - uint32_t closing_stamp; + TIME_T closing_stamp; uint8_t authorized; int8_t dbgl; }; @@ -96,7 +108,7 @@ struct dbgl_node //#define DBG_HIST_EXPIRE 100000
struct dbg_histogram { - uint32_t print_stamp; + TIME_T print_stamp; int32_t expire; uint16_t check_len; uint16_t catched; @@ -104,49 +116,46 @@ struct dbg_histogram { };
-#ifndef TESTDEBUG +#ifndef TEST_DEBUG
#define DBG_HIST_NEW 0x00 #define DBG_HIST_MUTING 0x01 #define DBG_HIST_MUTED 0x02
-#ifdef NODEBUGALL +#ifdef NO_DEBUG_ALL #define dbgf_all(...) {;} #else #define dbgf_all( dbgt, ... ); do { if ( __dbgf_all() ) { _dbgf_all( dbgt, __FUNCTION__, __VA_ARGS__ ); } } while (0) #endif
-#ifdef EXTDEBUG -#define dbgf_ext( dbgt, ... ); do { if ( __dbgf_all() ) { _dbgf_all( dbgt, __FUNCTION__, __VA_ARGS__ ); } } while (0) -#else -#define dbgf_ext(...) {;} -#endif - -#define dbgf( dbgl, dbgt, ...); _dbgf( dbgl, dbgt, __FUNCTION__, __VA_ARGS__ ); -#define dbgf_cn( cn, dbgl, dbgt, ...); _dbgf_cn( cn, dbgl, dbgt, __FUNCTION__, __VA_ARGS__ ); +#define dbgf( dbgl, dbgt, ...) _dbgf( dbgl, dbgt, __FUNCTION__, __VA_ARGS__ ) +#define dbgf_cn( cn, dbgl, dbgt, ...) _dbgf_cn( cn, dbgl, dbgt, __FUNCTION__, __VA_ARGS__ ) +#define dbgf_mute( len, dbgl, dbgt, ...) _dbgf_mute( len, dbgl, dbgt, __FUNCTION__, __VA_ARGS__ )
void dbg ( int8_t dbgl, int8_t dbgt, char *last, ... ); -void _dbgf ( int8_t dbgl, int8_t dbgt, char const *f, char *last, ... ); -void dbg_cn ( struct ctrl_node *cn, int8_t dbgl, int8_t dbgt, char *last, ... ); -void _dbgf_cn ( struct ctrl_node *cn, int8_t dbgl, int8_t dbgt, char const *f, char *last, ... ); -void dbg_mute ( uint32_t check_len, int8_t dbgl, int8_t dbgt, char *last, ... ); -void _dbgf_all ( int8_t dbgt, char const *f, char *last, ... ); +void _dbgf(int8_t dbgl, int8_t dbgt, const char *f, char *last, ...); +void dbg_cn(struct ctrl_node *cn, int8_t dbgl, int8_t dbgt, char *last, ...); +void _dbgf_cn(struct ctrl_node *cn, int8_t dbgl, int8_t dbgt, const char *f, char *last, ...); +void dbg_mute(uint32_t check_len, int8_t dbgl, int8_t dbgt, char *last, ...); +void _dbgf_mute(uint32_t check_len, int8_t dbgl, int8_t dbgt, const char *f, char *last, ...); +void _dbgf_all ( int8_t dbgt, const char *f, char *last, ... ); uint8_t __dbgf_all( void );
void dbg_printf( struct ctrl_node *cn, char *last, ... );
#else
-#define dbgf( dbgl, dbgt, ...); printf( __VA_ARGS__ ) -#define dbgf_cn( cn, dbgl, dbgt, ...); printf( __VA_ARGS__ ) +#define dbgf( dbgl, dbgt, ...) printf( __VA_ARGS__ ) +#define dbgf_cn( cn, dbgl, dbgt, ...) printf( __VA_ARGS__ ) +#define dbgf_cn( cn, dbgl, dbgt, ...) printf( __VA_ARGS__ ) #define dbg( dbgl, dbgt, ... ) printf( __VA_ARGS__ ) #define dbg_cn( cn, dbgl, dbgt, ... ) printf( __VA_ARGS__ ) #define dbg_mute( check_len, dbgl, dbgt, ... ) printf( __VA_ARGS__ ) +#define dbgf_mute( check_len, dbgl, dbgt, ... ) printf( __VA_ARGS__ ) #define dbgf_all( dbgt, ... ) printf( __VA_ARGS__ ) #define dbgf_ext( dbgt, ... ) printf( __VA_ARGS__ ) #define dbg_printf( cn, ... ) printf( __VA_ARGS__ )
- #endif
void accept_ctrl_node( void ); @@ -157,10 +166,6 @@ struct ctrl_node *create_ctrl_node( int fd, void (*cn_fd_handler) (struct ctrl_n
-#define REFERENCE_KEY_WORD "ref:" - -#define EOS_DELIMITER '#' - #define MAX_UNIX_MSG_SIZE 2000
extern struct list_head opt_list; @@ -236,7 +241,7 @@ struct opt_parent { };
-#define ODI {{0},0,{0,0,0,0},{0,0,0,0}} +#define ODI {{0},0,{0,0,0,0,0,0},{0,0,0,0,0,0}}
struct opt_data { @@ -294,9 +299,6 @@ struct opt_type { };
-#define ARG_RESET "-" /* s-string preamble for call_option() to reset opt to default */ -#define ARG_RESET_CHAR '-' -
enum opt_cmd { // option handlers are registered, configured, and unregistered using primitives. @@ -401,9 +403,10 @@ void register_options_array ( struct opt_type *fixed_options, int size ); extern int32_t Load_config;
+#ifdef ADJ_PATCHED_NETW int32_t get_tracked_network( struct opt_type *opt, struct opt_parent *patch, char *out, uint32_t *ip, int32_t *mask, struct ctrl_node *cn ); int32_t adj_patched_network( struct opt_type *opt, struct opt_parent *patch, char *out, uint32_t *ip, int32_t *mask, struct ctrl_node *cn ); - +#endif
void apply_init_args ( int argc, char *argv[] );
@@ -416,19 +419,9 @@ void cleanup_control( void ); void cleanup_config( void );
-//char *debugWordDup( char* word, int32_t tag ); -//static void strchange( char *s, char i, char o ); -//char* nextword( char *s ); - - -//usefult tools: -char *ipStr( uint32_t addr ); -int8_t str2netw( char* args, uint32_t *ip, char delimiter, struct ctrl_node *cn, int32_t *val, int32_t max ); -void addr_to_str( uint32_t addr, char *str ); +#ifdef EXPORT_UNUSED +char *debugWordDup( char* word, int32_t tag ); +static void strchange( char *s, char i, char o ); +char* nextword( char *s ); +#endif
-int8_t wordsEqual ( char *a, char *b ); -void wordCopy( char *out, char *in ); -uint32_t wordlen ( char *s ); -int32_t check_file( char *path, uint8_t write, uint8_t exec ); -int32_t check_dir( char *path, uint8_t create, uint8_t write ); -uint32_t validate_net_mask( uint32_t ip, uint32_t mask, struct ctrl_node *cn ); diff --git a/cyassl/arc4.c b/cyassl/arc4.c new file mode 100644 index 0000000..ecebe10 --- /dev/null +++ b/cyassl/arc4.c @@ -0,0 +1,76 @@ +/* arc4.c + * + * Copyright (C) 2006-2009 Sawtooth Consulting Ltd. + * + * This file is part of CyaSSL. + * + * CyaSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + + +#include "arc4.h" + + + +void Arc4SetKey(Arc4* arc4, const byte* key, word32 length) +{ + word32 i; + word32 keyIndex = 0, stateIndex = 0; + + arc4->x = 1; + arc4->y = 0; + + for (i = 0; i < ARC4_STATE_SIZE; i++) + arc4->state[i] = i; + + for (i = 0; i < ARC4_STATE_SIZE; i++) { + word32 a = arc4->state[i]; + stateIndex += key[keyIndex] + a; + stateIndex &= 0xFF; + arc4->state[i] = arc4->state[stateIndex]; + arc4->state[stateIndex] = a; + + if (++keyIndex >= length) + keyIndex = 0; + } +} + + +static INLINE word32 MakeByte(word32* x, word32* y, byte* s) +{ + word32 a = s[*x], b; + *y = (*y+a) & 0xff; + + b = s[*y]; + s[*x] = b; + s[*y] = a; + *x = (*x+1) & 0xff; + + return s[(a+b) & 0xff]; +} + + +void Arc4Process(Arc4* arc4, byte* out, const byte* in, word32 length) +{ + word32 x = arc4->x; + word32 y = arc4->y; + + while(length--) + *out++ = *in++ ^ MakeByte(&x, &y, arc4->state); + + arc4->x = x; + arc4->y = y; +} + diff --git a/cyassl/misc.h b/cyassl/arc4.h similarity index 62% copy from cyassl/misc.h copy to cyassl/arc4.h index 5ef75ec..bac267c 100644 --- a/cyassl/misc.h +++ b/cyassl/arc4.h @@ -1,4 +1,4 @@ -/* misc.h +/* arc4.h * * Copyright (C) 2006-2009 Sawtooth Consulting Ltd. * @@ -20,13 +20,11 @@ */
-#ifndef CTAO_CRYPT_MISC_H -#define CTAO_CRYPT_MISC_H +#ifndef CTAO_CRYPT_ARC4_H +#define CTAO_CRYPT_ARC4_H
#include "types.h" -#include <string.h> -
#ifdef __cplusplus @@ -34,23 +32,25 @@ #endif
-#ifdef NO_INLINE -word32 rotlFixed(word32, word32); -word32 rotrFixed(word32, word32); +enum { + ARC4_STATE_SIZE = 256 +};
-word32 ByteReverseWord32(word32); -void ByteReverseWords(word32*, const word32*, word32); -void ByteReverseBytes(byte*, const byte*, word32); +/* ARC4 encryption and decryption */ +typedef struct Arc4 { + byte x; + byte y; + byte state[ARC4_STATE_SIZE]; +} Arc4;
-void XorWords(word*, const word*, word32); -void xorbuf(byte*, const byte*, word32); -#endif /* NO_INLINE */ +void Arc4Process(Arc4*, byte*, const byte*, word32); +void Arc4SetKey(Arc4*, const byte*, word32);
#ifdef __cplusplus - } /* extern "C" */ + } /* extern "C" */ #endif
-#endif /* CTAO_CRYPT_MISC_H */ +#endif /* CTAO_CRYPT_ARC4_H */
diff --git a/cyassl/error.h b/cyassl/error.h new file mode 100644 index 0000000..4de29fc --- /dev/null +++ b/cyassl/error.h @@ -0,0 +1,93 @@ +/* error.h + * + * Copyright (C) 2006-2009 Sawtooth Consulting Ltd. + * + * This file is part of CyaSSL. + * + * CyaSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + + +#ifndef CTAO_CRYPT_ERROR_H +#define CTAO_CRYPT_ERROR_H + +#include "types.h" + + +#ifdef __cplusplus + extern "C" { +#endif + + +/* error codes */ +enum { + MAX_ERROR_SZ = 80, /* max size of error string */ + MAX_CODE_E = -100, /* errors -101 - -199 */ + OPEN_RAN_E = -101, /* opening random device error */ + READ_RAN_E = -102, /* reading random device error */ + WINCRYPT_E = -103, /* windows crypt init error */ + CRYPTGEN_E = -104, /* windows crypt generation error */ + RAN_BLOCK_E = -105, /* reading random device would block */ + + MP_INIT_E = -110, /* mp_init error state */ + MP_READ_E = -111, /* mp_read error state */ + MP_EXPTMOD_E = -112, /* mp_exptmod error state */ + MP_TO_E = -113, /* mp_to_xxx error state, can't convert */ + MP_SUB_E = -114, /* mp_sub error state, can't subtract */ + MP_ADD_E = -115, /* mp_add error state, can't add */ + MP_MUL_E = -116, /* mp_mul error state, can't multiply */ + MP_MULMOD_E = -117, /* mp_mulmod error state, can't multiply mod */ + MP_MOD_E = -118, /* mp_mod error state, can't mod */ + MP_INVMOD_E = -119, /* mp_invmod error state, can't inv mod */ + MP_CMP_E = -120, /* mp_cmp error state */ + + MEMORY_E = -125, /* out of memory error */ + + RSA_WRONG_TYPE_E = -130, /* RSA wrong block type for RSA function */ + RSA_BUFFER_E = -131, /* RSA buffer error, output too small or + input too large */ + + ASN_PARSE_E = -140, /* ASN parsing error, invalid input */ + ASN_VERSION_E = -141, /* ASN version error, invalid number */ + ASN_GETINT_E = -142, /* ASN get big int error, invalid data */ + ASN_RSA_KEY_E = -143, /* ASN key init error, invalid input */ + ASN_OBJECT_ID_E = -144, /* ASN object id error, invalid id */ + ASN_TAG_NULL_E = -145, /* ASN tag error, not null */ + ASN_EXPECT_0_E = -146, /* ASN expect error, not zero */ + ASN_BITSTR_E = -147, /* ASN bit string error, wrong id */ + ASN_UNKNOWN_OID_E = -148, /* ASN oid error, unknown sum id */ + ASN_DATE_SZ_E = -149, /* ASN date error, bad size */ + ASN_BEFORE_DATE_E = -150, /* ASN date error, current date before */ + ASN_AFTER_DATE_E = -151, /* ASN date error, current date after */ + ASN_SIG_OID_E = -152, /* ASN signature error, mismatched oid */ + ASN_TIME_E = -153, /* ASN time error, unkown time type */ + ASN_INPUT_E = -154, /* ASN input error, not enough data */ + ASN_SIG_CONFIRM_E = -155, /* ASN sig error, confirm failure */ + ASN_SIG_HASH_E = -156, /* ASN sig error, unsupported hash type */ + ASN_SIG_KEY_E = -157, /* ASN sig error, unsupported key type */ + ASN_DH_KEY_E = -158, /* ASN key init error, invalid input */ + MIN_CODE_E = -200 /* errors -101 - -199 */ +}; + + +void CTaoCryptErrorString(int error, char* buffer); + + +#ifdef __cplusplus + } /* extern "C" */ +#endif + +#endif /* CTAO_CRYPT_ERROR_H */ + diff --git a/cyassl/random.c b/cyassl/random.c new file mode 100644 index 0000000..0276919 --- /dev/null +++ b/cyassl/random.c @@ -0,0 +1,153 @@ +/* random.c + * + * Copyright (C) 2006-2009 Sawtooth Consulting Ltd. + * + * This file is part of CyaSSL. + * + * CyaSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CyaSSL 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + + +/* on HPUX 11 you may need to install /dev/random see + http://h20293.www2.hp.com/portal/swdepot/displayProductInfo.do?productNumber... + +*/ + +#include "random.h" +#include "error.h" +#include <string.h> + + +#if defined(_WIN32) + #define _WIN32_WINNT 0x0400 + #include <windows.h> + #include <wincrypt.h> +#else + #include <errno.h> + #include <fcntl.h> + #include <unistd.h> +#endif /* _WIN32 */ + + + +/* Get seed and key cipher */ +int InitRng(RNG* rng) +{ + byte key[32]; + byte junk[256]; + + int ret = GenerateSeed(&rng->seed, key, sizeof(key)); + + if (ret == 0) { + Arc4SetKey(&rng->cipher, key, sizeof(key)); + RNG_GenerateBlock(rng, junk, sizeof(junk)); /* rid initial state */ + } + + return ret; +} + + +/* place a generated block in output */ +void RNG_GenerateBlock(RNG* rng, byte* output, word32 sz) +{ + memset(output, 0, sz); + Arc4Process(&rng->cipher, output, output, sz); +} + + +byte RNG_GenerateByte(RNG* rng) +{ + byte b; + RNG_GenerateBlock(rng, &b, 1); + + return b; +} + + +#if defined(_WIN32) + + +int GenerateSeed(OS_Seed* os, byte* output, word32 sz) +{ + if(!CryptAcquireContext(&os->handle, 0, 0, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT)) + return WINCRYPT_E; + + if (!CryptGenRandom(os->handle, sz, output)) + return CRYPTGEN_E; + + CryptReleaseContext(os->handle, 0); + + return 0; +} + + +#elif THREADX + +#include "rtprand.h" /* rtp_rand () */ +#include "rtptime.h" /* rtp_get_system_msec() */ + + +int GenerateSeed(OS_Seed* os, byte* output, word32 sz) +{ + int i; + rtp_srand(rtp_get_system_msec()); + + for (i = 0; i < sz; i++ ) { + output[i] = rtp_rand() % 256; + if ( (i % 8) == 7) + rtp_srand(rtp_get_system_msec()); + } + + return 0; +} + + +#else /* !_WIN32 && !THREADX */ + + +/* may block */ +int GenerateSeed(OS_Seed* os, byte* output, word32 sz) +{ + os->fd = open("/dev/urandom",O_RDONLY); + if (os->fd == -1) { + /* may still have /dev/random */ + os->fd = open("/dev/random",O_RDONLY); + if (os->fd == -1) + return OPEN_RAN_E; + } + + while (sz) { + int len = read(os->fd, output, sz); + if (len == -1) + return READ_RAN_E; + + sz -= len; + output += len; + + if (sz) +#ifdef BLOCKING + sleep(0); /* context switch */ +#else + return RAN_BLOCK_E; +#endif + } + close(os->fd); + + return 0; +} + +#endif /* _WIN32 */ + diff --git a/cyassl/sha.h b/cyassl/random.h similarity index 52% copy from cyassl/sha.h copy to cyassl/random.h index 6ea882c..8ae26e4 100644 --- a/cyassl/sha.h +++ b/cyassl/random.h @@ -1,4 +1,4 @@ -/* sha.h +/* random.h * * Copyright (C) 2006-2009 Sawtooth Consulting Ltd. * @@ -20,43 +20,53 @@ */
-#ifndef CTAO_CRYPT_SHA_H -#define CTAO_CRYPT_SHA_H +#ifndef CTAO_CRYPT_RANDOM_H +#define CTAO_CRYPT_RANDOM_H
-#include "types.h" +#include "arc4.h"
#ifdef __cplusplus extern "C" { #endif
+#if defined(_WIN32) + #if defined(_WIN64) + typedef unsigned __int64 ProviderHandle; + /* type HCRYPTPROV, avoid #include <windows.h> */ + #else + typedef unsigned long ProviderHandle; + #endif +#endif + + +/* OS specific seeder */ +typedef struct OS_Seed { + #if defined(_WIN32) + ProviderHandle handle; + #else + int fd; + #endif +} OS_Seed;
-/* in bytes */ -enum { - SHA_BLOCK_SIZE = 64, - SHA_DIGEST_SIZE = 20, - SHA_PAD_SIZE = 56 -}; +int GenerateSeed(OS_Seed* os, byte* seed, word32 sz);
-/* Sha digest */ -typedef struct Sha { - word32 buffLen; /* in bytes */ - word32 loLen; /* length in bytes */ - word32 hiLen; /* length in bytes */ - word32 digest[SHA_DIGEST_SIZE / sizeof(word32)]; - word32 buffer[SHA_BLOCK_SIZE / sizeof(word32)]; -} Sha; +/* secure Random Nnumber Generator */ +typedef struct RNG { + OS_Seed seed; + Arc4 cipher; +} RNG;
-void InitSha(Sha*); -void ShaUpdate(Sha*, const byte*, word32); -void ShaFinal(Sha*, byte*); +int InitRng(RNG*); +void RNG_GenerateBlock(RNG*, byte*, word32 sz); +byte RNG_GenerateByte(RNG*);
#ifdef __cplusplus } /* extern "C" */ #endif
-#endif /* CTAO_CRYPT_SHA_H */ +#endif /* CTAO_CRYPT_RANDOM_H */
diff --git a/dump.c b/dump.c new file mode 100644 index 0000000..08cbae5 --- /dev/null +++ b/dump.c @@ -0,0 +1,419 @@ +/* + * Copyright (c) 2010 Axel Neumann + * 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 <stdio.h> +#include <stdarg.h> +#include <string.h> + + +#include "bmx.h" +#include "msg.h" +#include "ip.h" +#include "dump.h" +#include "schedule.h" +#include "plugin.h" +#include "tools.h" + +#define LESS_ROUNDING_ERRORS 0 +#define IMPROVE_ROUNDOFF 10 + +static int32_t dump_regression_exp = DEF_DUMP_REGRESSION_EXP; + + +static IDM_T dump_terminating = NO; +static int32_t data_dev_plugin_registry = FAILURE; + +static struct dump_data dump_all; + + +STATIC_FUNC +void update_traffic_statistics_data(struct dump_data *data) +{ + uint16_t i, t; + + for (i = 0; i < DUMP_DIRECTION_ARRSZ; i++) { + + for (t = 0; t < DUMP_TYPE_ARRSZ; t++) { + data->pre_all[i][t] = data->tmp_all[i][t]; + + data->avg_all[i][t] <<= LESS_ROUNDING_ERRORS; + data->avg_all[i][t] -= (data->avg_all[i][t] >> dump_regression_exp); + data->avg_all[i][t] += (((data->tmp_all[i][t]) << LESS_ROUNDING_ERRORS) >> dump_regression_exp); + data->avg_all[i][t] >>= LESS_ROUNDING_ERRORS; + data->tmp_all[i][t] = 0; + } + + + for (t = 0; t < FRAME_TYPE_ARRSZ; t++) { + data->pre_frame[i][t] = data->tmp_frame[i][t]; + + data->avg_frame[i][t] <<= LESS_ROUNDING_ERRORS; + data->avg_frame[i][t] -= (data->avg_frame[i][t] >> dump_regression_exp); + data->avg_frame[i][t] += (((data->tmp_frame[i][t]) << LESS_ROUNDING_ERRORS) >> dump_regression_exp); + data->avg_frame[i][t] >>= LESS_ROUNDING_ERRORS; + data->tmp_frame[i][t] = 0; + } + } +} + + +STATIC_FUNC +void update_traffic_statistics_task(void *data) +{ + struct dev_node *dev; + struct avl_node *an = NULL; + + register_task(DUMP_STATISTIC_PERIOD, update_traffic_statistics_task, NULL); + update_traffic_statistics_data( &dump_all ); + + while ((dev = avl_iterate_item(&dev_name_tree, &an))) { + + struct dump_data **dump_dev_plugin_data = + (struct dump_data **) (get_plugin_data(dev, PLUGIN_DATA_DEV, data_dev_plugin_registry)); + + if (*dump_dev_plugin_data) + update_traffic_statistics_data(*dump_dev_plugin_data); + + } +} + + +void dump(struct packet_buff *pb) +{ + + assertion(-500760, (XOR((pb->i.oif), (pb->i.iif)))); + + IDM_T direction = pb->i.iif ? DUMP_DIRECTION_IN : DUMP_DIRECTION_OUT; + struct dev_node *dev = pb->i.iif ? pb->i.iif : pb->i.oif; + struct packet_header *phdr = &pb->packet.header; + + struct dump_data **dev_plugin_data = + (struct dump_data **) (get_plugin_data(dev, PLUGIN_DATA_DEV, data_dev_plugin_registry)); + + assertion(-500761, (*dev_plugin_data)); + + uint16_t plength = ntohs(phdr->pkt_length); + + dbgf(DBGL_DUMP, DBGT_NONE, "%s srcIP=%-16s dev=%-12s udpPayload=%-d", + direction == DUMP_DIRECTION_IN ? "in " : "out", pb->i.llip_str, dev->label_cfg.str, plength); + + (*dev_plugin_data)->tmp_all[direction][DUMP_TYPE_UDP_PAYLOAD] += (plength << IMPROVE_ROUNDOFF); + + dump_all.tmp_all[direction][DUMP_TYPE_UDP_PAYLOAD] += (plength << IMPROVE_ROUNDOFF); + + + dbgf(DBGL_DUMP, DBGT_NONE, + "%s headerVersion=%-2d reserved=%-2X IID=%-5d headerSize=%-4zu", + direction == DUMP_DIRECTION_IN ? "in " : "out", + phdr->bmx_version, phdr->reserved, ntohs(phdr->transmitterIID), sizeof (struct packet_header)); + + (*dev_plugin_data)->tmp_all[direction][DUMP_TYPE_PACKET_HEADER] += (sizeof (struct packet_header) << IMPROVE_ROUNDOFF); + + dump_all.tmp_all[direction][DUMP_TYPE_PACKET_HEADER] += (sizeof (struct packet_header) << IMPROVE_ROUNDOFF); + + + struct rx_frame_iterator it = {.caller = __FUNCTION__, + .handls = packet_frame_handler, .handl_max = FRAME_TYPE_MAX, .process_filter = FRAME_TYPE_PROCESS_NONE, + .frames_in = (((uint8_t*) phdr) + sizeof (struct packet_header)), + .frames_length = (plength - sizeof (struct packet_header)), .frames_pos = 0 + }; + + IDM_T iterator_result; + uint16_t frame_length = 0; + + while ((iterator_result = rx_frame_iterate(&it)) > SUCCESS) { + + char tnum[4]; + char *tname; + int16_t frame_msgs = -1; + + if (!(tname = packet_frame_handler[it.frame_type].name)) { + sprintf(tnum, "%d", it.frame_type); + tname = tnum; + } + + frame_length = it.frame_data_length + + (it.is_short_header ? sizeof (struct frame_header_short) : sizeof (struct frame_header_long)); + + if (packet_frame_handler[it.frame_type].fixed_msg_size) { + frame_msgs = (it.frame_data_length - packet_frame_handler[it.frame_type].data_header_size) / packet_frame_handler[it.frame_type].min_msg_size; + } + + + dbgf(DBGL_DUMP, DBGT_NONE, "%s frameType=%-12s headerSize=%-3d msgs=%-3d frameSize=%-4d", + direction == DUMP_DIRECTION_IN ? "in " : "out", tname, + packet_frame_handler[it.frame_type].data_header_size, frame_msgs, frame_length); + + + (*dev_plugin_data)->tmp_frame[direction][it.frame_type] += (frame_length << IMPROVE_ROUNDOFF); + + dump_all.tmp_frame[direction][it.frame_type] += (frame_length << IMPROVE_ROUNDOFF); + + (*dev_plugin_data)->tmp_all[direction][DUMP_TYPE_FRAME_HEADER] += ((frame_length - it.frame_data_length) << IMPROVE_ROUNDOFF); + + dump_all.tmp_all[direction][DUMP_TYPE_FRAME_HEADER] += ((frame_length - it.frame_data_length) << IMPROVE_ROUNDOFF); + + } + + if (iterator_result != SUCCESS) { + dbgf(DBGL_DUMP, DBGT_NONE, "%s ERROR unknown frameType=%-12d size=%i4d - ignoring further frames!!", + direction == DUMP_DIRECTION_IN ? "in " : "out", it.frame_type, frame_length); + } + +} + + +STATIC_FUNC +void dbg_traffic_statistics(struct dump_data *data, struct ctrl_node *cn, char* dbg_name) +{ + uint16_t t; + + dbg_printf(cn, "%-20s \n", dbg_name); + + + for (t = 0; t < DUMP_TYPE_ARRSZ; t++) { + dbg_printf(cn, "%13s %5d (%3d) %5d (%3d) %5d (%3d) | %5d (%3d) %5d (%3d) %5d (%3d)\n", + t == DUMP_TYPE_UDP_PAYLOAD ? "UDP_PAYLOAD" : (t == DUMP_TYPE_PACKET_HEADER ? "PACKET_HEADER" : "FRAME_HEADER"), + + + ((data->pre_all[DUMP_DIRECTION_IN][t] + data->pre_all[DUMP_DIRECTION_OUT][t]) >> IMPROVE_ROUNDOFF), + + ((((data->pre_all[DUMP_DIRECTION_IN][DUMP_TYPE_UDP_PAYLOAD]) || (data->pre_all[DUMP_DIRECTION_OUT][DUMP_TYPE_UDP_PAYLOAD])) ? + (((data->pre_all[DUMP_DIRECTION_IN][t] + data->pre_all[DUMP_DIRECTION_OUT][t])*100) / + (data->pre_all[DUMP_DIRECTION_IN][DUMP_TYPE_UDP_PAYLOAD] + data->pre_all[DUMP_DIRECTION_OUT][DUMP_TYPE_UDP_PAYLOAD])) : 0)), + + + ((data->pre_all[DUMP_DIRECTION_IN][t]) >> IMPROVE_ROUNDOFF), + + ((data->pre_all[DUMP_DIRECTION_IN][DUMP_TYPE_UDP_PAYLOAD] ? + ((data->pre_all[DUMP_DIRECTION_IN][t]*100) / data->pre_all[DUMP_DIRECTION_IN][DUMP_TYPE_UDP_PAYLOAD]) : 0)), + + + ((data->pre_all[DUMP_DIRECTION_OUT][t]) >> IMPROVE_ROUNDOFF), + + ((data->pre_all[DUMP_DIRECTION_OUT][DUMP_TYPE_UDP_PAYLOAD] ? + ((data->pre_all[DUMP_DIRECTION_OUT][t]*100) / data->pre_all[DUMP_DIRECTION_OUT][DUMP_TYPE_UDP_PAYLOAD]) : 0)), + + + + ((data->avg_all[DUMP_DIRECTION_IN][t] + data->avg_all[DUMP_DIRECTION_OUT][t]) >> IMPROVE_ROUNDOFF), + + (((data->avg_all[DUMP_DIRECTION_IN][DUMP_TYPE_UDP_PAYLOAD] || data->avg_all[DUMP_DIRECTION_OUT][DUMP_TYPE_UDP_PAYLOAD]) ? + (((data->avg_all[DUMP_DIRECTION_IN][t] + data->avg_all[DUMP_DIRECTION_OUT][t])*100) / + (data->avg_all[DUMP_DIRECTION_IN][DUMP_TYPE_UDP_PAYLOAD] + data->avg_all[DUMP_DIRECTION_OUT][DUMP_TYPE_UDP_PAYLOAD])) : 0)), + + + ((data->avg_all[DUMP_DIRECTION_IN][t]) >> IMPROVE_ROUNDOFF), + + ((data->avg_all[DUMP_DIRECTION_IN][DUMP_TYPE_UDP_PAYLOAD] ? + ((data->avg_all[DUMP_DIRECTION_IN][t]*100) / data->avg_all[DUMP_DIRECTION_IN][DUMP_TYPE_UDP_PAYLOAD]) : 0)), + + + ((data->avg_all[DUMP_DIRECTION_OUT][t]) >> IMPROVE_ROUNDOFF), + + ((data->avg_all[DUMP_DIRECTION_OUT][DUMP_TYPE_UDP_PAYLOAD] ? + ((data->avg_all[DUMP_DIRECTION_OUT][t]*100) / data->avg_all[DUMP_DIRECTION_OUT][DUMP_TYPE_UDP_PAYLOAD]) : 0)) + + ); + } + + for (t = 0; t < FRAME_TYPE_NOP; t++) { + + if (packet_frame_handler[t].name || data->avg_frame[DUMP_DIRECTION_IN][t] || data->avg_frame[DUMP_DIRECTION_OUT][t]) { + + char tnum[4]; + char *tname = packet_frame_handler[t].name; + if (!tname) { + sprintf(tnum, "%d", t); + tname = tnum; + } + + + dbg_printf(cn, "%13s %5d (%3d) %5d (%3d) %5d (%3d) | %5d (%3d) %5d (%3d) %5d (%3d)\n", + tname, + + ((data->pre_frame[DUMP_DIRECTION_IN][t] + data->pre_frame[DUMP_DIRECTION_OUT][t]) >> IMPROVE_ROUNDOFF), + + ((data->pre_all[DUMP_DIRECTION_IN][DUMP_TYPE_UDP_PAYLOAD] || data->pre_all[DUMP_DIRECTION_OUT][DUMP_TYPE_UDP_PAYLOAD] ? + (((data->pre_frame[DUMP_DIRECTION_IN][t] + data->pre_frame[DUMP_DIRECTION_OUT][t])*100) / + (data->pre_all[DUMP_DIRECTION_IN][DUMP_TYPE_UDP_PAYLOAD] + data->pre_all[DUMP_DIRECTION_OUT][DUMP_TYPE_UDP_PAYLOAD])) : 0)), + + + ((data->pre_frame[DUMP_DIRECTION_IN][t]) >> IMPROVE_ROUNDOFF), + + ((data->pre_all[DUMP_DIRECTION_IN][DUMP_TYPE_UDP_PAYLOAD] ? + ((data->pre_frame[DUMP_DIRECTION_IN][t]*100) / data->pre_all[DUMP_DIRECTION_IN][DUMP_TYPE_UDP_PAYLOAD]) : 0)), + + + ((data->pre_frame[DUMP_DIRECTION_OUT][t]) >> IMPROVE_ROUNDOFF), + + ((data->pre_all[DUMP_DIRECTION_OUT][DUMP_TYPE_UDP_PAYLOAD] ? + ((data->pre_frame[DUMP_DIRECTION_OUT][t]*100) / data->pre_all[DUMP_DIRECTION_OUT][DUMP_TYPE_UDP_PAYLOAD]) : 0)), + + + + ((data->avg_frame[DUMP_DIRECTION_IN][t] + data->avg_frame[DUMP_DIRECTION_OUT][t]) >> IMPROVE_ROUNDOFF), + + ((data->avg_all[DUMP_DIRECTION_IN][DUMP_TYPE_UDP_PAYLOAD] || data->avg_all[DUMP_DIRECTION_OUT][DUMP_TYPE_UDP_PAYLOAD] ? + (((data->avg_frame[DUMP_DIRECTION_IN][t] + data->avg_frame[DUMP_DIRECTION_OUT][t])*100) / + (data->avg_all[DUMP_DIRECTION_IN][DUMP_TYPE_UDP_PAYLOAD] + data->avg_all[DUMP_DIRECTION_OUT][DUMP_TYPE_UDP_PAYLOAD])) : 0)), + + + ((data->avg_frame[DUMP_DIRECTION_IN][t]) >> IMPROVE_ROUNDOFF), + + ((data->avg_all[DUMP_DIRECTION_IN][DUMP_TYPE_UDP_PAYLOAD] ? + ((data->avg_frame[DUMP_DIRECTION_IN][t]*100) / data->avg_all[DUMP_DIRECTION_IN][DUMP_TYPE_UDP_PAYLOAD]) : 0)), + + + ((data->avg_frame[DUMP_DIRECTION_OUT][t]) >> IMPROVE_ROUNDOFF), + + ((data->avg_all[DUMP_DIRECTION_OUT][DUMP_TYPE_UDP_PAYLOAD] ? + ((data->avg_frame[DUMP_DIRECTION_OUT][t]*100) / data->avg_all[DUMP_DIRECTION_OUT][DUMP_TYPE_UDP_PAYLOAD]) : 0)) + + ); + } + } +} + + +STATIC_FUNC +int32_t opt_traffic_statistics(uint8_t cmd, uint8_t _save, struct opt_type *opt, struct opt_parent *patch, struct ctrl_node *cn) +{ + + if ( cmd == OPT_APPLY ) { + + struct dev_node *dev; + struct avl_node *an = NULL; + + dbg_printf(cn, "traffic statistics [B/%dsec]: last second | weighted averages \n", + DUMP_STATISTIC_PERIOD / 1000); + + dbg_printf(cn, "%20s ( %% ) in ( %% ) out ( %% ) | all ( %% ) in ( %% ) out ( %% )\n"," "); + + if (!strcmp(patch->p_val, ARG_DUMP_ALL) || !strcmp(patch->p_val, ARG_DUMP_SUMMARY)) + dbg_traffic_statistics(&dump_all, cn, ARG_DUMP_ALL); + + while ((dev = avl_iterate_item(&dev_name_tree, &an))) { + + if (strcmp(patch->p_val, ARG_DUMP_ALL) && strcmp(patch->p_val, dev->label_cfg.str)) + continue; + + struct dump_data **dump_dev_plugin_data = + (struct dump_data **) (get_plugin_data(dev, PLUGIN_DATA_DEV, data_dev_plugin_registry)); + + if (dev->active && *dump_dev_plugin_data) + dbg_traffic_statistics(*dump_dev_plugin_data, cn, dev->label_cfg.str); + + } + + } + + return SUCCESS; +} + + +STATIC_FUNC +struct opt_type dump_options[]= +{ +// ord parent long_name shrt Attributes *ival min max default *func,*syntax,*help + + {ODI, 0,0, 0, 5,0,0,0,0,0, 0, 0, 0, 0, 0, + 0, "\ntraffic-dump options:"} + , + {ODI, 0, ARG_DUMP_REGRESSION_EXP, 0, 5, A_PS1, A_ADM, A_DYN, A_ARG, A_ANY, &dump_regression_exp,MIN_DUMP_REGRESSION_EXP,MAX_DUMP_REGRESSION_EXP,DEF_DUMP_REGRESSION_EXP,0, + ARG_VALUE_FORM, "set regression exponent for traffic-dump statistics "} + , + {ODI, 0, ARG_DUMP, 0, 5, A_PS1, A_USR, A_DYN, A_ARG, A_ANY, 0, 0, 0, 0, opt_traffic_statistics, + "<DEV>", "show traffic statistics for given device name, summary, or all\n"} + +}; + + +void init_cleanup_dev_traffic_data(void* devp) { + + struct dev_node *dev; + struct avl_node *an; + + + for (an = NULL; (dev = avl_iterate_item(&dev_name_tree, &an));) { + + struct dump_data **dump_dev_plugin_data = (struct dump_data **) (get_plugin_data(dev, PLUGIN_DATA_DEV, data_dev_plugin_registry)); + + if (dump_terminating || (!dev->active && *dump_dev_plugin_data)) { + + if (*dump_dev_plugin_data) + debugFree(*dump_dev_plugin_data, -300305); + + *dump_dev_plugin_data = NULL; + + + } else if (dev->active && !(*dump_dev_plugin_data)) { + + *dump_dev_plugin_data = debugMalloc(sizeof (struct dump_data), -300306); + memset(*dump_dev_plugin_data, 0, sizeof (struct dump_data)); + + } + } +} + + + +STATIC_FUNC +void cleanup_dump( void ) +{ + dump_terminating = YES; + init_cleanup_dev_traffic_data(NULL); + set_packet_hook(dump, DEL); +} + + +STATIC_FUNC +int32_t init_dump( void ) +{ + memset(&dump_all, 0, sizeof (struct dump_data)); + + data_dev_plugin_registry = get_plugin_data_registry(PLUGIN_DATA_DEV); + + assertion(-500762, (data_dev_plugin_registry != FAILURE)); + + register_options_array(dump_options, sizeof ( dump_options)); + + register_task(DUMP_STATISTIC_PERIOD, update_traffic_statistics_task, NULL); + + set_packet_hook(dump, ADD); + + return SUCCESS; +} + + + +struct plugin *dump_get_plugin( void ) { + + static struct plugin dump_plugin; + memset( &dump_plugin, 0, sizeof ( struct plugin ) ); + + dump_plugin.plugin_name = "bmx6_trafficdump_plugin"; + dump_plugin.plugin_size = sizeof ( struct plugin ); + dump_plugin.plugin_code_version = CODE_VERSION; + dump_plugin.cb_init = init_dump; + dump_plugin.cb_cleanup = cleanup_dump; + dump_plugin.cb_plugin_handler[PLUGIN_CB_DEV_EVENT] = init_cleanup_dev_traffic_data; + + return &dump_plugin; +} + diff --git a/dump.h b/dump.h new file mode 100644 index 0000000..380eb49 --- /dev/null +++ b/dump.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2010 Axel Neumann + * 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 DUMP_ERROR_STR "DUMP_ERROR" +#define DUMP_MAX_STR_SIZE (MAX_DBG_STR_SIZE - strlen(DUMP_ERROR_STR)) +#define DUMP_MAX_MSG_SIZE 200 + + +#define DUMP_DIRECTION_OUT 0 +#define DUMP_DIRECTION_IN 1 +#define DUMP_DIRECTION_ARRSZ 2 + +#define DUMP_STATISTIC_PERIOD 1000 + +#define ARG_DUMP "traffic" +#define ARG_DUMP_ALL "all" +#define ARG_DUMP_DEV "dev" +#define ARG_DUMP_SUMMARY "summary" + + +#define DEF_DUMP_REGRESSION_EXP 4 +#define MIN_DUMP_REGRESSION_EXP 0 +#define MAX_DUMP_REGRESSION_EXP 20 +#define ARG_DUMP_REGRESSION_EXP "traffic_regression_exponent" + + +#define DUMP_TYPE_UDP_PAYLOAD 0 +#define DUMP_TYPE_PACKET_HEADER 1 +#define DUMP_TYPE_FRAME_HEADER 2 +#define DUMP_TYPE_ARRSZ 3 + + + +struct dump_data { + uint32_t tmp_frame[DUMP_DIRECTION_ARRSZ][FRAME_TYPE_ARRSZ]; + uint32_t pre_frame[DUMP_DIRECTION_ARRSZ][FRAME_TYPE_ARRSZ]; + uint32_t avg_frame[DUMP_DIRECTION_ARRSZ][FRAME_TYPE_ARRSZ]; + + uint32_t tmp_all[DUMP_DIRECTION_ARRSZ][DUMP_TYPE_ARRSZ]; + uint32_t pre_all[DUMP_DIRECTION_ARRSZ][DUMP_TYPE_ARRSZ]; + uint32_t avg_all[DUMP_DIRECTION_ARRSZ][DUMP_TYPE_ARRSZ]; +}; + diff --git a/hna.c b/hna.c index e148c43..c776c37 100644 --- a/hna.c +++ b/hna.c @@ -1,6 +1,5 @@ /* - * Copyright (C) 2010 BMX contributors: - * Axel Neumann + * Copyright (c) 2010 Axel Neumann * 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. @@ -31,266 +30,398 @@
#include "bmx.h" #include "msg.h" +#include "ip.h" #include "plugin.h" #include "hna.h" -#include "route.h" +#include "tools.h"
-AVL_TREE(global_uhna_tree, struct uhna4_node, key ); -AVL_TREE(local_uhna_tree, struct uhna4_node, key ); +AVL_TREE(global_uhna_tree, struct uhna_node, key ); +AVL_TREE(local_uhna_tree, struct uhna_node, key );
-/* -struct uhna4_node *get_global_uhna_node(struct uhna4_key* key) + +STATIC_FUNC +void set_uhna_key(struct uhna_key *key, uint8_t family, uint8_t prefixlen, IPX_T *glip, uint32_t metric) { - return avl_find_item(&global_uhna_tree, key); -} -*/ + memset( key, 0, sizeof(struct uhna_key)); + key->family = family; + key->prefixlen = prefixlen; + key->metric_nl = htonl(metric); + key->glip = *glip;
+}
-void set_uhna4_key(struct uhna4_key *key, uint8_t prefix_len, IP4_T glip4, uint32_t metric) +STATIC_FUNC +void set_uhna_to_key(struct uhna_key *key, struct description_msg_hna4 *uhna4, struct description_msg_hna6 *uhna6) { - memset( key, 0, sizeof(struct uhna4_key)); - key->prefix_len = prefix_len; - key->glip4 = glip4; - key->metric_be = htonl(metric); + if (uhna4) {
-} + IPX_T ipX; + ip42X(&ipX, uhna4->ip4);
+ set_uhna_key(key, AF_INET, uhna4->prefixlen, &ipX, ntohl(uhna4->metric));
+ } else {
+ set_uhna_key(key, AF_INET6, uhna6->prefixlen, &uhna6->ip6, ntohl(uhna6->metric)); + + } +}
-int create_description_tlv_ip4(uint8_t *data, uint16_t max_size) +STATIC_FUNC +int _create_tlv_hna(int family, uint8_t* data, uint16_t max_size, uint16_t pos, + IPX_T *ip, uint32_t metric, uint16_t prefixlen) { - struct avl_node *it = NULL; - struct dev_node *dev = primary_if; - int item = 0; - struct description0_msg_ip4 *glip4 = (struct description0_msg_ip4*) data; + int i; + uint16_t msg_size = family == AF_INET ? + sizeof (struct description_msg_hna4) : sizeof (struct description_msg_hna6);
- do { - if (item == 0 || (dev != primary_if && dev->announce)) {
- if ((item+1) * sizeof (struct description0_msg_ip4) > max_size) { + if ((pos + msg_size) > max_size) {
- dbgf(DBGL_SYS, DBGT_ERR, "unable to announce %s %s due to limiting --%s=%d", - dev->name, dev->ip4_str, ARG_UDPD_SIZE, max_size); - break; - } + dbgf(DBGL_SYS, DBGT_ERR, "unable to announce %s/%d metric %d due to limiting --%s=%d", + ipXAsStr(family, ip), prefixlen, ntohl(metric), ARG_UDPD_SIZE, max_size);
- glip4[item++].ip4 = dev->ip4_addr; - } + return pos; + }
- } while ((dev = avl_iterate_item(&dev_ip4_tree, &it))); + dbgf_all(DBGT_INFO, "announce %s/%d metric %d ", ipXAsStr(family, ip), prefixlen, ntohl(metric));
- return item * sizeof (struct description0_msg_ip4); -}
-int create_description_tlv_hna4(uint8_t *data, uint16_t max_size) -{ - struct avl_node *it = NULL; - struct dev_node *dev; - struct uhna4_node *un; - int item = 0; - struct description0_msg_hna4 *uhna4 = (struct description0_msg_hna4*) data; + assertion(-500610, (!(family == AF_INET6 && + is_ip_net_equal(ip, &IP6_LINKLOCAL_UC_PREF, IP6_LINKLOCAL_UC_PLEN, AF_INET6)))); + // this should be catched during configuration!!
- while ((un = avl_iterate_item(&local_uhna_tree, &it))) {
- if (!un->key.metric_be && un->key.prefix_len==32 && - (dev = avl_find_item(&dev_ip4_tree, &(un->key.glip4))) && dev->announce) - continue; + if (family == AF_INET) { + struct description_msg_hna4 * msg4 = ((struct description_msg_hna4 *) data);
- if (item * sizeof (struct description0_msg_hna4) > max_size) { + struct description_msg_hna4 hna4; + memset( &hna4, 0, sizeof(hna4)); + hna4.ip4 = ipXto4(*ip); + hna4.metric = metric; + hna4.prefixlen = prefixlen;
- dbgf( DBGL_SYS, DBGT_ERR, "unable to announce %s/%d metric %d due to limiting --%s=%d", - ipStr(un->key.glip4), un->key.prefix_len, ntohl(un->key.metric_be), - ARG_UDPD_SIZE, max_size ); - continue; + for (i = 0; i < pos / msg_size; i++) { + + if (!memcmp(&(msg4[i]), &hna4, sizeof (struct description_msg_hna4))) + return pos; }
- uhna4[item].ip4 = un->key.glip4; - uhna4[item].metric = un->key.metric_be; - uhna4[item].prefix_len = un->key.prefix_len; - item++; + msg4[i] = hna4; + + } else { + struct description_msg_hna6 * msg6 = ((struct description_msg_hna6 *) data); + + struct description_msg_hna6 hna6; + memset( &hna6, 0, sizeof(hna6)); + hna6.ip6 = *ip; + hna6.metric = metric; + hna6.prefixlen = prefixlen; + + for (i = 0; i < pos / msg_size; i++) { + + if (!memcmp(&(msg6[i]), &hna6, sizeof (struct description_msg_hna6))) + return pos; + } + + msg6[i] = hna6; + }
- return item * sizeof (struct description0_msg_hna4); -} + dbgf(DBGL_SYS, DBGT_INFO, "%s %s/%d metric %d", + family2Str(family), ipXAsStr(family, ip), prefixlen, metric);
+ return (pos + msg_size); +}
-int process_description_tlv_hna4(struct orig_node *on, struct frame_header *tlv, IDM_T op, struct ctrl_node *cn ) +STATIC_FUNC +int create_description_tlv_hna(struct tx_frame_iterator *it) { - struct description0_msg_ip4 *glip4 = NULL; - struct description0_msg_hna4 *uhna4 = NULL; + assertion(-500765, (it->frame_type == BMX_DSC_TLV_UHNA4 || it->frame_type == BMX_DSC_TLV_UHNA6));
- assertion(-500357, (tlv->type == BMX_DSC_TLV_GLIP4 || tlv->type == BMX_DSC_TLV_UHNA4)); + uint8_t *data = tx_iterator_cache_msg_ptr(it); + uint16_t max_size = tx_iterator_cache_data_space(it); + uint8_t family = it->frame_type == BMX_DSC_TLV_UHNA4 ? AF_INET : AF_INET6; + uint8_t max_prefixlen = ort_dat[ (AFINET2BMX(family)) ].max_prefixlen;
- uint16_t msgs_size = ntohs(tlv->length) - sizeof (struct frame_header); - uint16_t msg_size, m, msgs; + struct avl_node *an; + struct uhna_node *un; + struct dev_node *dev; + int pos = 0;
- if (tlv->type == BMX_DSC_TLV_GLIP4) { - glip4 = (struct description0_msg_ip4 *) tlv->data; - msg_size = sizeof (struct description0_msg_ip4); - } else { - uhna4 = (struct description0_msg_hna4 *) tlv->data; - msg_size = sizeof (struct description0_msg_hna4); + if (af_cfg != family || !is_ip_set(&self.primary_ip)) + return 0; + + pos = _create_tlv_hna(family, data, max_size, pos, &self.primary_ip, 0, max_prefixlen); + + for (an = NULL; (dev = avl_iterate_item(&dev_ip_tree, &an));) { + + if (!dev->active || !dev->announce) + continue; + + pos = _create_tlv_hna(family, data, max_size, pos, &dev->if_global_addr->ip_addr, 0, max_prefixlen); }
- msgs = msgs_size / msg_size; + for (an = NULL; (un = avl_iterate_item(&local_uhna_tree, &an));) {
- for (m = 0; m < msgs; m++) { - struct uhna4_key key; + if (un->key.family != family) + continue;
- if (glip4) { - set_uhna4_key(&key, 32, glip4[m].ip4, 0); - } else { - set_uhna4_key(&key, uhna4[m].prefix_len, uhna4[m].ip4, ntohl(uhna4[m].metric)); - } + pos = _create_tlv_hna(family, data, max_size, pos, &un->key.glip, un->key.metric_nl, un->key.prefixlen); + }
- dbgf_all( DBGT_INFO, "%s %s %s/%d metric %d", - tlv_op_str[op], glip4 ? "glip4:" : "uhna4:", - ipStr(key.glip4), key.prefix_len, ntohl(key.metric_be)); + return pos; +}
- if (op == TLV_DEL_TEST_ADD) {
- struct uhna4_node *un = avl_remove(&global_uhna_tree, &key, -300215); - assertion(-500358, (un && un->on == on)); - debugFree( un, -300161 ); - if (m == 0 && glip4) { - on->primary_ip4 = 0; - addr_to_str(0, on->primary_ip4_str); - } +STATIC_FUNC +IDM_T configure_route(IDM_T del, struct orig_node *on, struct uhna_key *key) +{
- } else if (op == TLV_TEST) { + IDM_T primary = is_ip_equal(&key->glip, &on->primary_ip); + uint8_t cmd = primary ? IP_ROUTE_HOST : IP_ROUTE_HNA; + int32_t table_macro = primary ? RT_TABLE_HOSTS : RT_TABLE_NETS;
- if (avl_find(&global_uhna_tree, &key)) - return TLVS_BLOCKED; + // update network routes: + if (del) {
- } else if (op == TLV_ADD) {
- struct uhna4_node *un = debugMalloc( sizeof(struct uhna4_node),-300162 ); - memset(un, 0, sizeof (struct uhna4_node)); - memcpy(&un->key, &key, sizeof ( struct uhna4_key)); - ASSERTION( -500359, (!avl_find(&global_uhna_tree, &key))); - un->on = on; - avl_insert(&global_uhna_tree, un, -300163); + return ip(key->family, cmd, DEL, NO, &key->glip, key->prefixlen, table_macro, ntohl(key->metric_nl), + NULL, 0, NULL, NULL);
- if (m == 0 && glip4) { - on->primary_ip4 = key.glip4; - addr_to_str(on->primary_ip4, on->primary_ip4_str); - }
- } else if ( op == TLV_DEBUG ) { + } else {
- dbg_printf(cn, " %s %s/%d metric %d\n", glip4 ? "glip4:" : "uhna4:", - ipStr(key.glip4), key.prefix_len, ntohl(key.metric_be) ); + struct router_node *curr_rn = on->curr_rn; + + assertion(-500820, (curr_rn)); + ASSERTION(-500239, (avl_find(&link_dev_tree, &(curr_rn->key)))); + assertion(-500579, (curr_rn->key.dev->if_llocal_addr)); + + return ip(key->family, cmd, ADD, NO, &key->glip, key->prefixlen, table_macro, ntohl(key->metric_nl), + NULL, curr_rn->key.dev->if_llocal_addr->ifa.ifa_index, &(curr_rn->key.link->link_ip), &(self.primary_ip));
- } else { - assertion( -500369, (NO)); - } }
- return TLVS_SUCCESS; }
+STATIC_FUNC +void configure_uhna ( IDM_T del, struct uhna_key* key, struct orig_node *on ) {
-void configure_hna ( IDM_T del, struct uhna4_key* key, struct orig_node *on ) { - - struct uhna4_node *un = avl_find_item( &global_uhna_tree, key ); + struct uhna_node *un = avl_find_item( &global_uhna_tree, key );
- paranoia( -500236, ((del && !un) || (!del && un)) ); + assertion(-500589, (on)); + assertion(-500236, ((del && un) != (!del && !un)));
// update uhna_tree: if ( del ) { - - paranoia(-500234, (on != un->on)); + + assertion(-500234, (on == un->on)); avl_remove(&global_uhna_tree, &un->key, -300212); ASSERTION( -500233, (!avl_find( &global_uhna_tree, key)) ); // there should be only one element with this key
- if ( !on) + if (on == &self) avl_remove(&local_uhna_tree, &un->key, -300213);
} else {
- un = debugMalloc( sizeof (struct uhna4_node), -300090 ); + un = debugMalloc( sizeof (struct uhna_node), -300090 ); un->key = *key; un->on = on; avl_insert(&global_uhna_tree, un, -300149);
- if (!on) + if (on == &self) avl_insert(&local_uhna_tree, un, -300150); + }
- if ( on ) {
- // update network routes: - if ( del) { - configure_route(key->glip4, key->prefix_len, ntohl(key->metric_be), - 0, my_orig_node.primary_ip4, - 0, 0, - RT_TABLE_NETWORKS, RTN_UNICAST, DEL, TRACK_OTHER_HNA); - } else { - ASSERTION(-500239, (avl_find( &link_dev_tree, &on->router_key))); + if (on == &self) {
- configure_route(key->glip4, key->prefix_len, ntohl(key->metric_be), - on->router_key.llip4, my_orig_node.primary_ip4, - on->router_key.dev->index, on->router_key.dev->name, - RT_TABLE_NETWORKS, RTN_UNICAST, ADD, TRACK_OTHER_HNA); - } + // update throw routes: + ip(key->family, IP_THROW_MY_HNA, del, NO, &key->glip, key->prefixlen, RT_TABLE_HOSTS, 0, NULL, 0, NULL, NULL); + ip(key->family, IP_THROW_MY_HNA, del, NO, &key->glip, key->prefixlen, RT_TABLE_NETS, 0, NULL, 0, NULL, NULL); + ip(key->family, IP_THROW_MY_HNA, del, NO, &key->glip, key->prefixlen, RT_TABLE_TUNS, 0, NULL, 0, NULL, NULL);
- } else { - // update my description: - update_my_description_adv(); + my_description_changed = YES;
- // update throw routes: - configure_route(key->glip4, key->prefix_len, 0, 0, 0, 0, "unknown", RT_TABLE_HOSTS, RTN_THROW, del, TRACK_MY_HNA); - configure_route(key->glip4, key->prefix_len, 0, 0, 0, 0, "unknown", RT_TABLE_NETWORKS, RTN_THROW, del, TRACK_MY_HNA); - configure_route(key->glip4, key->prefix_len, 0, 0, 0, 0, "unknown", RT_TABLE_TUNNEL, RTN_THROW, del, TRACK_MY_HNA); + } else if (on->curr_rn) { + + configure_route(del, on, key); }
- if ( del) + if (del) debugFree(un, -300089);
}
+ + STATIC_FUNC -int32_t opt_hna ( uint8_t cmd, uint8_t _save, struct opt_type *opt, struct opt_parent *patch, struct ctrl_node *cn ) { +int process_description_tlv_hna(struct rx_frame_iterator *it) +{ + ASSERTION(-500357, (it->frame_type == BMX_DSC_TLV_UHNA4 || it->frame_type == BMX_DSC_TLV_UHNA6)); + assertion(-500588, (it->on));
- uint32_t ip; - int32_t mask; - uint32_t metric = 0; - struct uhna4_key key; + struct orig_node *on = it->on; + IDM_T op = it->op; + uint8_t family = (it->frame_type == BMX_DSC_TLV_UHNA4 ? AF_INET : AF_INET6); + + if (af_cfg != family) { + dbgf(DBGL_SYS, DBGT_ERR, "invalid family %s", family2Str(family)); + return TLV_DATA_BLOCKED; + } + + uint16_t msg_size = it->handls[it->frame_type].min_msg_size; + uint16_t pos; + + for (pos = 0; pos < it->frame_data_length; pos += msg_size) { + + struct uhna_key key; + + if (it->frame_type == BMX_DSC_TLV_UHNA4) + set_uhna_to_key(&key, (struct description_msg_hna4 *) (it->frame_data + pos), NULL); + + else + set_uhna_to_key(&key, NULL, (struct description_msg_hna6 *) (it->frame_data + pos)); + + + + dbgf_all(DBGT_INFO, "%s %s %s=%s/%d %s=%d", + tlv_op_str[op], family2Str(key.family), ARG_UHNA, + ipXAsStr(key.family, &key.glip), key.prefixlen, ARG_UHNA_METRIC, ntohl(key.metric_nl)); + + if (op == TLV_OP_DEL) { + + configure_uhna(DEL, &key, on); + + if (pos == 0 && key.family == family) { + on->primary_ip = ZERO_IP; + ip2Str(family, &ZERO_IP, on->primary_ip_str); + } + + } else if (op == TLV_OP_TEST) { + + struct uhna_node *un = NULL; + + if (!is_ip_set(&key.glip) || is_ip_forbidden( &key.glip, family ) || + (un = avl_find_item(&global_uhna_tree, &key))) {
- char new[30]; + dbgf(DBGL_SYS, DBGT_ERR, + "id.name=%s id.rand=%X... %s=%s/%d %s=%d blocked by id.name=%s id.rand=%X...", + on->id.name, on->id.rand.u32[0], + ARG_UHNA, ipXAsStr(key.family, &key.glip), key.prefixlen, + ARG_UHNA_METRIC, ntohl(key.metric_nl), + un ? un->on->id.name : "---", un ? un->on->id.rand.u32[0] : 0); + + return TLV_DATA_BLOCKED; + } + + if (is_ip_net_equal(&key.glip, &IP6_LINKLOCAL_UC_PREF, IP6_LINKLOCAL_UC_PLEN, AF_INET6)) { + + dbgf(DBGL_SYS, DBGT_ERR, "NO link-local addresses %s", ipXAsStr(key.family, &key.glip)); + + return TLV_DATA_BLOCKED; + } + + + } else if (op == TLV_OP_ADD) { + + //TODO: return with TLVS_BLOCKED because this happens when node announces the same key twice !!! + ASSERTION( -500359, (!avl_find(&global_uhna_tree, &key))); + + if (pos == 0 && key.family == family) { + on->primary_ip = key.glip; + ip2Str(key.family, &key.glip, on->primary_ip_str); + } + + configure_uhna(ADD, &key, on); + + + } else if ( op == TLV_OP_DEBUG ) { + + dbg_printf(it->cn, "%s=%s/%d %s=%d", + ARG_UHNA, ipXAsStr(key.family, &key.glip), key.prefixlen, + ARG_UHNA_METRIC, ntohl(key.metric_nl)); + + if (pos == it->frame_data_length - msg_size) { + dbg_printf(it->cn, "\n"); + } else { + dbg_printf(it->cn, ", "); + } + + } else { + assertion( -500369, (NO)); + } + } + + + return pos; +} + + +STATIC_FUNC +void hna_status (struct ctrl_node *cn) +{ + process_description_tlvs(NULL, &self, self.desc, TLV_OP_DEBUG, af_cfg == AF_INET ? BMX_DSC_TLV_UHNA4 : BMX_DSC_TLV_UHNA6, cn); +} + + + + + +STATIC_FUNC +int32_t opt_uhna(uint8_t cmd, uint8_t _save, struct opt_type *opt, struct opt_parent *patch, struct ctrl_node *cn) +{ + IPX_T ipX; + uint8_t mask; + uint32_t metric = 0; + struct uhna_key key; + char new[IPXNET_STR_LEN];
if ( cmd == OPT_ADJUST || cmd == OPT_CHECK || cmd == OPT_APPLY ) {
- dbgf( DBGL_CHANGES, DBGT_INFO, "diff %d cmd %s save %d opt %s patch %s", + uint8_t family = 0; + + dbgf( DBGL_CHANGES, DBGT_INFO, "diff=%d cmd =%s save=%d opt=%s patch=%s", patch->p_diff, opt_cmd2str[cmd], _save, opt->long_name, patch->p_val);
- if ( patch->p_val[0] >= '0' && patch->p_val[0] <= '9' ) { + if (strchr(patch->p_val, '/')) { + + if (str2netw(patch->p_val, &ipX, '/', cn, &mask, &family) == FAILURE) + family = 0;
// the unnamed UHNA - dbgf(DBGL_CHANGES, DBGT_INFO, "unnamed UHNA diff %d cmd %s save %d opt %s patch %s", - patch->p_diff, opt_cmd2str[cmd], _save, opt->long_name, patch->p_val); + dbgf(DBGL_CHANGES, DBGT_INFO, "unnamed %s %s diff=%d cmd=%s save=%d opt=%s patch=%s", + ARG_UHNA, family2Str(family), patch->p_diff, opt_cmd2str[cmd], _save, opt->long_name, patch->p_val);
- if ( str2netw( patch->p_val, &ip, '/', cn, &mask, 32 ) == FAILURE ) - return FAILURE; + if ( family != AF_INET && family != AF_INET6) + return FAILURE; + + if (is_ip_forbidden(&ipX, family) || ip_netmask_validate(&ipX, mask, family, NO) == FAILURE) { + dbg_cn(cn, DBGL_SYS, DBGT_ERR, + "forbidden ip or invalid prefix %s/%d", ipXAsStr(family, &ipX), mask); + return FAILURE; + } + + sprintf(new, "%s/%d", ipXAsStr(family, &ipX), mask);
- sprintf( new, "%s/%d", ipStr( validate_net_mask( ip, mask, 0 ) ), mask ); set_opt_parent_val( patch, new );
if ( cmd == OPT_ADJUST ) return SUCCESS;
} else { - +#ifdef ADJ_PATCHED_NETW // the named UHNA
- if ( adj_patched_network( opt, patch, new, &ip, &mask, cn ) == FAILURE ) + if ( adj_patched_network( opt, patch, new, &ip4, &mask, cn ) == FAILURE ) return FAILURE;
if ( cmd == OPT_ADJUST ) @@ -306,46 +437,51 @@ int32_t opt_hna ( uint8_t cmd, uint8_t _save, struct opt_type *opt, struct opt_p if ( check_apply_parent_option( ADD, OPT_CHECK, NO, opt, new, cn ) == FAILURE ) return FAILURE;
- if ( get_tracked_network( opt, patch, old, &ip, &mask, cn ) == FAILURE ) + if ( get_tracked_network( opt, patch, old, &ip4, &mask, cn ) == FAILURE ) return FAILURE;
// 3. remove the old HNA and hope to not mess it up... - set_uhna4_key(&key, mask, ip, metric); - - if ( cmd == OPT_APPLY ) - configure_hna(DEL, &key, NULL); + set_uhna_key(&key, AF_INET, mask, ip4, metric);
+ if ( cmd == OPT_APPLY) + configure_uhna(DEL, &key, &self);
}
// then continue with the new HNA - if ( str2netw( new , &ip, '/', cn, &mask, 32 ) == FAILURE ) + if ( str2netw( new , &ip4, '/', cn, &mask, 32 ) == FAILURE ) return FAILURE; +#else + return FAILURE; +#endif }
- set_uhna4_key(&key, mask, ip, metric);
- struct uhna4_node *un; + set_uhna_key(&key, family, mask, &ipX, metric); + + struct uhna_node *un;
if (patch->p_diff != DEL && (un = (avl_find_item(&global_uhna_tree, &key)))) {
- dbg_cn( cn, DBGL_CHANGES, DBGT_ERR, "UHNA %s/%d metric %d already blocked by %s !", - ipStr(ip), mask, metric, (un->on ? un->on->primary_ip4_str : "myself")); + dbg_cn( cn, DBGL_CHANGES, DBGT_ERR, + "UHNA %s/%d metric %d already blocked by %s !", + ipXAsStr(key.family, &key.glip), mask, metric, + (un->on == &self ? "MYSELF" : un->on->id.name));
return FAILURE; }
if ( cmd == OPT_APPLY ) - configure_hna((patch->p_diff == DEL ? DEL : ADD), &key, NULL); + configure_uhna((patch->p_diff == DEL ? DEL : ADD), &key, &self);
} else if ( cmd == OPT_UNREGISTER ) {
- struct avl_node *an; + struct uhna_node * un;
- while ((an = global_uhna_tree.root)) - configure_hna(DEL, (struct uhna4_key*) AVL_NODE_KEY( &global_uhna_tree, an), NULL); + while ((un = avl_first_item(&global_uhna_tree))) + configure_uhna(DEL, &un->key, &self);
}
@@ -353,91 +489,135 @@ int32_t opt_hna ( uint8_t cmd, uint8_t _save, struct opt_type *opt, struct opt_p
}
+ + + STATIC_FUNC -int32_t opt_show_hnas ( uint8_t cmd, uint8_t _save, struct opt_type *opt, struct opt_parent *patch, struct ctrl_node *cn ) { +struct opt_type hna_options[]= { +// ord parent long_name shrt Attributes *ival min max default *function
+ {ODI,0,0, 0, 5,0,0,0,0,0, 0, 0, 0, 0, 0, + 0, "\nHost and Network Announcement (HNA) options:"} + , + {ODI,0,ARG_UHNA, 'u',5,A_PMN,A_ADM,A_DYI,A_CFA,A_ANY, 0, 0, 0, 0, opt_uhna, + ARG_PREFIX_FORM,"perform host-network announcement (HNA) for defined ip range"} +/* + , + {ODI,ARG_UHNA,ARG_UHNA_NETWORK, 'n',5,A_CS1,A_ADM,A_DYI,A_CFA,A_ANY, 0, 0, 0, 0, opt_uhna, + ARG_NETW_FORM, "specify network of announcement"} + , + {ODI,ARG_UHNA,ARG_UHNA_PREFIXLEN,'p',5,A_CS1,A_ADM,A_DYI,A_CFA,A_ANY, 0, 0, 0, 0, opt_uhna, + ARG_MASK_FORM, "specify network prefix of announcement"} + , + {ODI,ARG_UHNA,ARG_UHNA_METRIC, 'm',5,A_CS1,A_ADM,A_DYI,A_CFA,A_ANY, 0, MIN_UHNA_METRIC,MAX_UHNA_METRIC,DEF_UHNA_METRIC,opt_uhna, + ARG_VALUE_FORM, "specify hna-metric of announcement (0 means highest preference)"} +*/
- if ( cmd == OPT_APPLY ) { +};
- dbg_printf( cn, "unicast HNA metric Originator \n");
- struct avl_node *an = NULL; - struct uhna4_node *un; - uint16_t hna_count = 0; +STATIC_FUNC +void hna_route_change_hook(uint8_t del, struct orig_node *on) +{ + dbgf_all(DBGT_INFO, "%s", on->id.name);
- while ((un = (struct uhna4_node*) ((an = avl_iterate(&global_uhna_tree, an)) ? an->item : NULL))) { + uint16_t tlvs_length = ntohs(on->desc->dsc_tlvs_len); + uint8_t uhna_type = (af_cfg == AF_INET ? BMX_DSC_TLV_UHNA4 : BMX_DSC_TLV_UHNA6);
- paranoia(-500361, (un->on && !un->on->desc0)); + struct rx_frame_iterator it = {.caller = __FUNCTION__, .on = on, + .frames_in = (((uint8_t*) on->desc) + sizeof (struct description)), + .frames_pos = 0, .frames_length = tlvs_length, + .handls = description_tlv_handl, .handl_max = FRAME_TYPE_MAX, .process_filter = FRAME_TYPE_PROCESS_NONE + };
- dbg_printf(cn, "%15s/%-2d %10d %-15s %s \n", - ipStr(un->key.glip4), un->key.prefix_len, ntohl(un->key.metric_be), - un->on ? un->on->primary_ip4_str : "localhost", - un->on ? un->on->desc0->id.name : " "); + while (rx_frame_iterate(&it) > TLV_RX_DATA_DONE && it.frame_type != uhna_type);
- process_description_tlvs(un->on, NULL, TLV_DEBUG, cn); - hna_count++; - } + if (it.frame_type != uhna_type) + return;
- dbg_printf( cn, "\n" ); - } - return SUCCESS; -} + uint16_t pos; + uint16_t msg_size = it.handls[it.frame_type].min_msg_size;
+ for (pos = 0; pos < it.frame_data_length; pos += msg_size) {
+ struct uhna_key key;
-STATIC_FUNC -struct opt_type hna_options[]= { -// ord parent long_name shrt Attributes *ival min max default *function + if (uhna_type == BMX_DSC_TLV_UHNA4) + set_uhna_to_key(&key, (struct description_msg_hna4 *) (it.frame_data + pos), NULL);
- {ODI,0,0, 0, 5,0,0,0,0,0, 0, 0, 0, 0, 0, - 0, "\nHost and Network Announcement (HNA) options:"}, + else + set_uhna_to_key(&key, NULL, (struct description_msg_hna6 *) (it.frame_data + pos));
- {ODI,0,ARG_UHNA, 'u',5,A_PMN,A_ADM,A_DYI,A_CFA,A_ANY, 0, 0, 0, 0, opt_hna, - ARG_PREFIX_FORM,"perform host-network announcement (HNA) for defined ip range"},
- {ODI,ARG_UHNA,ARG_NETW, 'n',5,A_CS1,A_ADM,A_DYI,A_CFA,A_ANY, 0, 0, 0, 0, opt_hna, - ARG_NETW_FORM, "specify network of announcement"}, + if (configure_route(del, on, &key) != SUCCESS) {
- {ODI,ARG_UHNA,ARG_MASK, 'm',5,A_CS1,A_ADM,A_DYI,A_CFA,A_ANY, 0, 0, 0, 0, opt_hna, - ARG_MASK_FORM, "specify network prefix of announcement"}, + //assertion(-500670, (0)); + + } + + } +}
- {ODI,0,ARG_HNAS, 0, 5,A_PS0,A_USR,A_DYN,A_ARG,A_ANY, 0, 0, 0, 0, opt_show_hnas, - 0, "show HNAs of other nodes\n"}
-};
-STATIC_FUNC -void hna_cleanup( void ) {
+ +STATIC_FUNC +void hna_cleanup( void ) +{ + set_route_change_hooks(hna_route_change_hook, DEL); }
+ STATIC_FUNC -int32_t hna_init( void ) { +int32_t hna_init( void ) +{ + struct frame_handl tlv_handl;
- register_options_array( hna_options, sizeof( hna_options ) ); + memset( &tlv_handl, 0, sizeof(tlv_handl)); + tlv_handl.min_msg_size = sizeof (struct description_msg_hna4); + tlv_handl.fixed_msg_size = 1; + tlv_handl.is_relevant = 1; + tlv_handl.name = "desc_tlv_uhna4"; + tlv_handl.tx_frame_handler = create_description_tlv_hna; + tlv_handl.rx_frame_handler = process_description_tlv_hna; + register_frame_handler(description_tlv_handl, BMX_DSC_TLV_UHNA4, &tlv_handl);
- return SUCCESS; -}
+ memset( &tlv_handl, 0, sizeof(tlv_handl)); + tlv_handl.min_msg_size = sizeof (struct description_msg_hna6); + tlv_handl.fixed_msg_size = 1; + tlv_handl.is_relevant = 1; + tlv_handl.name = "desc_tlv_uhna6"; + tlv_handl.tx_frame_handler = create_description_tlv_hna; + tlv_handl.rx_frame_handler = process_description_tlv_hna; + register_frame_handler(description_tlv_handl, BMX_DSC_TLV_UHNA6, &tlv_handl); + + + set_route_change_hooks(hna_route_change_hook, ADD); + + register_options_array( hna_options, sizeof( hna_options ) ); + + return SUCCESS; +}
-struct plugin_v2 *hna_get_plugin_v2( void ) { +struct plugin *hna_get_plugin( void ) {
- static struct plugin_v2 hna_plugin; - memset( &hna_plugin, 0, sizeof ( struct plugin_v2 ) ); + static struct plugin hna_plugin; + memset( &hna_plugin, 0, sizeof ( struct plugin ) );
- hna_plugin.plugin_version = PLUGIN_VERSION_02; - hna_plugin.plugin_name = "bmx_hna_plugin"; - hna_plugin.plugin_size = sizeof ( struct plugin_v2 ); - hna_plugin.plugin_bmx_revision = REVISION_VERSION; - hna_plugin.plugin_bmx_version = SOURCE_VERSION; - hna_plugin.cb_init = hna_init; + hna_plugin.plugin_name = "bmx6_hna_plugin"; + hna_plugin.plugin_size = sizeof ( struct plugin ); + hna_plugin.plugin_code_version = CODE_VERSION; + hna_plugin.cb_init = hna_init; hna_plugin.cb_cleanup = hna_cleanup; + hna_plugin.cb_plugin_handler[PLUGIN_CB_STATUS] = (void (*) (void*)) hna_status;
return &hna_plugin; } diff --git a/hna.h b/hna.h index f3c7f07..512996f 100644 --- a/hna.h +++ b/hna.h @@ -1,6 +1,5 @@ /* - * Copyright (C) 2010 BMX contributors: - * Axel Neumann + * Copyright (c) 2010 Axel Neumann * 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. @@ -18,32 +17,44 @@
#define ARG_UHNA "unicast_hna" -#define ARG_HNAS "uhnas"
-struct uhna4_key { - uint8_t reserved; - uint8_t prefix_len; - IP4_T glip4; - uint32_t metric_be; -}; +#define ARG_UHNA_NETWORK "network"
-struct uhna4_node { - struct uhna4_key key; - struct orig_node *on; -}; +#define MIN_UHNA_PREFIXLEN 1 +#define MAX_UHNA_PREFIXLEN 32 +#define ARG_UHNA_PREFIXLEN "prefixlen" + +#define MIN_UHNA_METRIC 0 +#define MAX_UHNA_METRIC U32_MAX +#define DEF_UHNA_METRIC 0 +#define ARG_UHNA_METRIC "metric"
-extern struct avl_tree global_uhna_tree; -extern struct avl_tree local_uhna_tree;
-struct plugin_v2 *hna_get_plugin_v2( void ); +struct uhna_key { + uint8_t family; + uint8_t prefixlen; + IPX_T glip; + uint32_t metric_nl; +};
-void set_uhna4_key(struct uhna4_key *key, uint8_t prefix_len, IP4_T glip4, uint32_t metric); +struct uhna_node { + struct uhna_key key; + struct orig_node *on; +};
-int create_description_tlv_ip4(uint8_t *data, uint16_t max_size); -int create_description_tlv_hna4(uint8_t *data, uint16_t max_size);
-int process_description_tlv_hna4(struct orig_node *on, struct frame_header *tlv, IDM_T op, struct ctrl_node *cn ); +struct description_msg_hna4 { + uint8_t prefixlen; + uint8_t reserved; + IP4_T ip4; + uint32_t metric; +} __attribute__((packed));
-//struct uhna4_node *get_global_uhna_node( struct uhna4_key* key ); +struct description_msg_hna6 { + uint8_t prefixlen; + uint8_t reserved; + IP6_T ip6; + uint32_t metric; +} __attribute__((packed));
diff --git a/iid.c b/iid.c index 29a00ce..60131a5 100644 --- a/iid.c +++ b/iid.c @@ -1,6 +1,5 @@ /* - * Copyright (C) 2010 BMX contributors: - * Axel Neumann + * Copyright (c) 2010 Axel Neumann * 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. @@ -21,15 +20,18 @@
#include "bmx.h" #include "iid.h" +#include "tools.h"
struct iid_repos my_iid_repos = { 0,0,0,0,{NULL} };
int8_t iid_extend_repos(struct iid_repos *rep) { - dbgf_all(DBGT_INFO, "sizeof iid: %lu, tot_used %d arr_size %d ", + TRACE_FUNCTION_CALL; + + dbgf_all(DBGT_INFO, "sizeof iid: %zu, tot_used %d arr_size %d ", (rep == &my_iid_repos) ? sizeof (IID_NODE_T*) : sizeof (IID_T), rep->tot_used, rep->arr_size);
- paranoia(-500217, (rep == &my_iid_repos && rep->tot_used != rep->arr_size)); + assertion(-500217, (rep != &my_iid_repos || IID_SPREAD_FK != 1 || rep->tot_used == rep->arr_size));
if (rep->arr_size + IID_REPOS_SIZE_BLOCK >= IID_REPOS_SIZE_WARN) {
@@ -63,6 +65,7 @@ int8_t iid_extend_repos(struct iid_repos *rep)
void iid_purge_repos( struct iid_repos *rep ) { + TRACE_FUNCTION_CALL;
if (rep->arr.u8) debugFree(rep->arr.u8, -300135); @@ -73,6 +76,7 @@ void iid_purge_repos( struct iid_repos *rep )
void iid_free(struct iid_repos *rep, IID_T iid) { + TRACE_FUNCTION_CALL; int m = (rep == &my_iid_repos);
assertion(-500330, (iid > IID_RSVD_MAX)); @@ -83,7 +87,7 @@ void iid_free(struct iid_repos *rep, IID_T iid) rep->arr.node[iid] = NULL; } else { rep->arr.ref[iid].myIID4x = 0; - rep->arr.ref[iid].referred_timestamp_sec = 0; + rep->arr.ref[iid].referred_by_neigh_timestamp_sec = 0; }
rep->min_free = MIN(rep->min_free, iid); @@ -116,9 +120,9 @@ void iid_free(struct iid_repos *rep, IID_T iid)
}
- - -IID_NODE_T* iid_get_node_by_myIID4x( IID_T myIID4x ) { +IID_NODE_T* iid_get_node_by_myIID4x(IID_T myIID4x) +{ + TRACE_FUNCTION_CALL;
if ( my_iid_repos.max_free <= myIID4x ) return NULL; @@ -127,14 +131,12 @@ IID_NODE_T* iid_get_node_by_myIID4x( IID_T myIID4x ) {
assertion(-500328, (!dhn || dhn->myIID4orig == myIID4x));
- if (dhn) { + if (dhn && !dhn->on) {
- if (!dhn->on) { - dbgf_all( DBGT_INFO, "myIID4x %d INVALIDATED %d sec ago", - myIID4x, (bmx_time - dhn->referred_timestamp) / 1000); - } + dbgf(DBGL_CHANGES, DBGT_INFO, "myIID4x %d INVALIDATED %d sec ago", + myIID4x, (bmx_time - dhn->referred_by_me_timestamp) / 1000);
- dhn->referred_timestamp = bmx_time; + return NULL; }
@@ -142,30 +144,135 @@ IID_NODE_T* iid_get_node_by_myIID4x( IID_T myIID4x ) { }
-IID_NODE_T* iid_get_node_by_neighIID4x( IID_NEIGH_T *nn, IID_T neighIID4x ) +IID_NODE_T* _iid_get_node_by_neighIID4x( const char *f, IID_NEIGH_T *nn, IID_T neighIID4x ) { + TRACE_FUNCTION_CALL;
- if (!nn || nn->neighIID4x_repos.max_free <= neighIID4x) + if (!nn || nn->neighIID4x_repos.max_free <= neighIID4x) { + + dbgf(DBGL_CHANGES, DBGT_INFO, "%s NB=%s neighIID4x=%d to large for neighIID4x_repos", + f, nn ? nn->dhn->on->id.name: "???", neighIID4x); return NULL; + }
struct iid_ref *ref = &(nn->neighIID4x_repos.arr.ref[neighIID4x]);
- if (ref->myIID4x && ((((uint16_t) bmx_time_sec) - ref->referred_timestamp_sec) <= + if (!ref->myIID4x ) { + dbgf(DBGL_CHANGES, DBGT_WARN, "%s neighIID4x=%d not recorded by neighIID4x_repos", f, neighIID4x); + + } else if (((((uint16_t) bmx_time_sec) - ref->referred_by_neigh_timestamp_sec) > ((MIN_DHASH_TO - (MIN_DHASH_TO / DHASH_TO_TOLERANCE_FK)) / 1000))) {
- ref->referred_timestamp_sec = bmx_time_sec; + dbgf(DBGL_CHANGES, DBGT_WARN, "%s neighIID4x=%d outdated in neighIID4x_repos, now_sec=%d, ref_sec=%d", + f, neighIID4x, bmx_time_sec, ref->referred_by_neigh_timestamp_sec); + + } else {
- return iid_get_node_by_myIID4x(ref->myIID4x); + ref->referred_by_neigh_timestamp_sec = bmx_time_sec; + + if (ref->myIID4x < my_iid_repos.max_free) { + + IID_NODE_T *dhn = my_iid_repos.arr.node[ref->myIID4x]; + + if (dhn) + return dhn; + + dbgf(DBGL_CHANGES, DBGT_WARN, "%s neighIID4x=%d -> myIID4x=%d empty!", + f, neighIID4x, ref->myIID4x); + + } else { + + dbgf(DBGL_CHANGES, DBGT_WARN, "%s neighIID4x=%d -> myIID4x=%d to large!", + f, neighIID4x, ref->myIID4x); + } }
return NULL; }
+STATIC_FUNC +void _iid_set(struct iid_repos *rep, IID_T IIDpos, IID_T myIID4x, IID_NODE_T *dhn) +{ + TRACE_FUNCTION_CALL; + assertion(-500530, (rep && XOR(myIID4x, dhn))); // eihter the one ore the other !! + assertion(-500531, (!dhn || rep == &my_iid_repos)); + assertion(-500535, (IIDpos >= IID_MIN_USED)); + + rep->tot_used++; + rep->max_free = MAX( rep->max_free, IIDpos+1 ); + + IID_T min = rep->min_free; + + if (min == IIDpos) { + for (min++; min < rep->arr_size; min++) { + + if (myIID4x ? !(rep->arr.ref[min].myIID4x) : !(rep->arr.node[min])) + break; + } + } + + paranoia(-500244, (min > rep->max_free)); + + rep->min_free = min; + + if (myIID4x) { + rep->arr.ref[IIDpos].myIID4x = myIID4x; + rep->arr.ref[IIDpos].referred_by_neigh_timestamp_sec = bmx_time_sec; + } else { + rep->arr.node[IIDpos] = dhn; + dhn->referred_by_me_timestamp = bmx_time; + } +} + + +IID_T iid_new_myIID4x(IID_NODE_T *dhn) +{ + TRACE_FUNCTION_CALL; + IID_T mid; +#ifndef NO_ASSERTIONS + IDM_T warn = 0; +#endif + + assertion(-500216, (my_iid_repos.tot_used <= my_iid_repos.arr_size)); + + while (my_iid_repos.arr_size <= my_iid_repos.tot_used * IID_SPREAD_FK) + iid_extend_repos( &my_iid_repos ); + + if (IID_SPREAD_FK > 1) { + + uint32_t random = rand_num(my_iid_repos.arr_size);
-int8_t iid_set_neighIID4x(struct iid_repos *neigh_rep, IID_T neighIID4x, IID_T myIID4x) + // Never put random function intro MAX()! It would be called twice + mid = MAX(IID_MIN_USED, random); + + while (my_iid_repos.arr.node[mid]) { + + mid++; + if (mid >= my_iid_repos.arr_size) { + + mid = IID_MIN_USED; + + assertion(-500533, (!(warn++))); + } + } + + } else { + + mid = my_iid_repos.min_free; + } + + _iid_set(&my_iid_repos, mid, 0, dhn); + + return mid; + +} + + +IDM_T iid_set_neighIID4x(struct iid_repos *neigh_rep, IID_T neighIID4x, IID_T myIID4x) { + TRACE_FUNCTION_CALL; assertion(-500326, (neighIID4x > IID_RSVD_MAX)); assertion(-500327, (myIID4x > IID_RSVD_MAX)); assertion(-500384, (neigh_rep && neigh_rep != &my_iid_repos)); @@ -176,7 +283,7 @@ int8_t iid_set_neighIID4x(struct iid_repos *neigh_rep, IID_T neighIID4x, IID_T m
assertion(-500485, (dhn && dhn->on));
- dhn->referred_timestamp = bmx_time; + dhn->referred_by_me_timestamp = bmx_time;
if (neigh_rep->max_free > neighIID4x) {
@@ -185,16 +292,30 @@ int8_t iid_set_neighIID4x(struct iid_repos *neigh_rep, IID_T neighIID4x, IID_T m if (ref->myIID4x > IID_RSVD_MAX) {
if (ref->myIID4x == myIID4x || - (((uint16_t)(((uint16_t) bmx_time_sec) - ref->referred_timestamp_sec)) >= + (((uint16_t)(((uint16_t) bmx_time_sec) - ref->referred_by_neigh_timestamp_sec)) >= ((MIN_DHASH_TO - (MIN_DHASH_TO / DHASH_TO_TOLERANCE_FK)) / 1000))) {
- neigh_rep->arr.ref[neighIID4x].myIID4x = myIID4x; - neigh_rep->arr.ref[neighIID4x].referred_timestamp_sec = bmx_time_sec; + ref->myIID4x = myIID4x; + ref->referred_by_neigh_timestamp_sec = bmx_time_sec; return SUCCESS; }
- dbgf(DBGL_SYS, DBGT_ERR, "neighIID4x %d for %s changed (at sec %d ) faster than allowed!!", - neighIID4x, dhn->on->id.name, ref->referred_timestamp_sec); + IID_NODE_T *dhn_old = my_iid_repos.arr.node[ref->myIID4x]; + + dbgf(DBGL_SYS, DBGT_ERR, "demanding mapping: neighIID4x=%d to myIID4x=%d " + "(%s updated=%d last_referred_by_me=%d) " + "already used for ref->myIID4x=%d (last_referred_by_neigh_sec=%d %s=%jd last_referred_by_me=%jd)! Reused faster than allowed!!", + neighIID4x, myIID4x, dhn->on->id.name, dhn->on->updated_timestamp, + dhn->referred_by_me_timestamp, + ref->myIID4x, + ref->referred_by_neigh_timestamp_sec, + (!dhn_old ? "???" : (dhn_old->on ? dhn_old->on->id.name : + (!dhn_old->dhash.h.u32[0] && !dhn_old->dhash.h.u32[1] && !dhn_old->dhash.h.u32[2] ? "FREED" : "INVALIDATED"))), + dhn_old ? (int64_t) dhn_old->dhash.h.u32[(sizeof ( struct description_hash) / sizeof (uint32_t)) - 1] : -1, + dhn_old ? (int64_t)dhn_old->referred_by_me_timestamp : -1 + ); + +// EXITERROR(-500701, (0));
return FAILURE; } @@ -205,8 +326,12 @@ int8_t iid_set_neighIID4x(struct iid_repos *neigh_rep, IID_T neighIID4x, IID_T m
while (neigh_rep->arr_size <= neighIID4x) {
- if (neigh_rep->tot_used < neigh_rep->arr_size / IID_REPOS_USAGE_WARNING) { - dbgf(DBGL_SYS, DBGT_WARN, "IID_REPOS_USAGE_WARNING did %d sid %d arr_size %d used %d", + if ( + neigh_rep->arr_size > IID_REPOS_SIZE_BLOCK && + neigh_rep->arr_size > my_iid_repos.arr_size && + neigh_rep->tot_used < neigh_rep->arr_size / (2 * IID_SPREAD_FK)) { + + dbgf(DBGL_SYS, DBGT_WARN, "IID_REPOS USAGE WARNING neighIID4x %d myIID4x %d arr_size %d used %d", neighIID4x, myIID4x, neigh_rep->arr_size, neigh_rep->tot_used ); }
@@ -216,67 +341,33 @@ int8_t iid_set_neighIID4x(struct iid_repos *neigh_rep, IID_T neighIID4x, IID_T m assertion(-500243, ((neigh_rep->arr_size > neighIID4x && (neigh_rep->max_free <= neighIID4x || neigh_rep->arr.ref[neighIID4x].myIID4x == IID_RSVD_UNUSED))));
- neigh_rep->tot_used++; - neigh_rep->max_free = MAX( neigh_rep->max_free, neighIID4x+1 ); - - IID_T min = neigh_rep->min_free; - - if (min == neighIID4x) { - for (; min < neigh_rep->arr_size && neigh_rep->arr.ref[min].myIID4x; min++); - } - - paranoia(-500244, (min > neigh_rep->max_free)); - - neigh_rep->min_free = min; - - neigh_rep->arr.ref[neighIID4x].myIID4x = myIID4x; - neigh_rep->arr.ref[neighIID4x].referred_timestamp_sec = bmx_time_sec; + _iid_set( neigh_rep, neighIID4x, myIID4x, NULL);
return SUCCESS; }
+ void iid_free_neighIID4x_by_myIID4x( struct iid_repos *rep, IID_T myIID4x) { + TRACE_FUNCTION_CALL; assertion(-500282, (rep != &my_iid_repos)); assertion(-500328, (myIID4x > IID_RSVD_MAX));
IID_T p; + uint16_t removed = 0;
- for (p = IID_RSVD_MAX + 1; p < rep->max_free && rep->arr.ref[p].myIID4x != myIID4x; p++); + for (p = IID_RSVD_MAX + 1; p < rep->max_free; p++) {
- if (p < rep->max_free && rep->arr.ref[p].myIID4x == myIID4x) { + if (rep->arr.ref[p].myIID4x == myIID4x) {
- dbgf_all(DBGT_INFO, "removed stale rep->arr.sid[%d] = %d", p, myIID4x); + if (removed++) { + // there could indeed be several (if the neigh has timeouted this node and learned it again later) + dbgf(DBGL_TEST, DBGT_INFO, "removed %d. stale rep->arr.sid[%d] = %d", removed, p, myIID4x); + }
- iid_free(rep, p); + iid_free(rep, p); + } } }
-IID_T iid_new_myIID4x(IID_NODE_T *dhn) -{ - - paranoia( -500216, ( my_iid_repos.tot_used > my_iid_repos.arr_size ) ); - - while ( my_iid_repos.tot_used >= my_iid_repos.arr_size ) - iid_extend_repos( &my_iid_repos ); - - IID_T mid = my_iid_repos.min_free; - IID_T pos = mid + 1; - - - my_iid_repos.tot_used++; - my_iid_repos.arr.node[mid] = dhn; - - for (; pos < my_iid_repos.arr_size && (my_iid_repos.arr.node[pos]); pos++); - - my_iid_repos.min_free = pos; - my_iid_repos.max_free = MAX(pos, my_iid_repos.max_free); - - dbgf_all(DBGT_INFO, "mine %d, iid %d tot_used %d, min_free %d max_free %d", - 1, mid, my_iid_repos.tot_used, my_iid_repos.min_free, my_iid_repos.max_free); - - dhn->referred_timestamp = bmx_time; - - return mid; -}
diff --git a/iid.h b/iid.h index 04e5b97..87e441e 100644 --- a/iid.h +++ b/iid.h @@ -1,6 +1,5 @@ /* - * Copyright (C) 2010 BMX contributors: - * Axel Neumann + * Copyright (c) 2010 Axel Neumann * 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. @@ -19,29 +18,23 @@ #ifndef _IID_H #define _IID_H
-#define IID_T uint16_t
-#define IID_NEIGH_T struct neigh_node -extern IID_NEIGH_T *unused1; // ensure knowledge of this type
-#define IID_NODE_T struct dhash_node -extern IID_NODE_T *unused2; // ensure knowledge of this type - -#define IID_REPOS_SIZE_BLOCK 128 +#define IID_REPOS_SIZE_BLOCK 32
#define IID_REPOS_SIZE_MAX ((IID_T)(-1)) #define IID_REPOS_SIZE_WARN 1024 -#define IID_REPOS_USAGE_WARNING 10
#define IID_RSVD_UNUSED 0 -#define IID_RSVD_4YOU 1 -#define IID_RSVD_MAX 1 -#define IID_MIN_USED 2 +#define IID_RSVD_MAX 0 +#define IID_MIN_USED 1 + +#define IID_SPREAD_FK 1 /*default=2 , 1 means no spreading #define IID_REPOS_USAGE_WARNING 10 */
struct iid_ref { IID_T myIID4x; - uint16_t referred_timestamp_sec; + uint16_t referred_by_neigh_timestamp_sec; };
struct iid_repos { @@ -60,7 +53,7 @@ extern struct iid_repos my_iid_repos;
-int8_t iid_extend_repos( struct iid_repos *rep ); +//int8_t iid_extend_repos( struct iid_repos *rep );
void iid_purge_repos( struct iid_repos *rep );
@@ -68,14 +61,18 @@ void iid_free(struct iid_repos *rep, IID_T iid);
void iid_free_neighIID4x_by_myIID4x( struct iid_repos *rep, IID_T myIID4x);
-int8_t iid_set_neighIID4x(struct iid_repos *neigh_rep, IID_T neighIID4x, IID_T myIID4x); +IDM_T iid_set_neighIID4x(struct iid_repos *neigh_rep, IID_T neighIID4x, IID_T myIID4x);
IID_T iid_new_myIID4x( IID_NODE_T *dhn );
-IID_NODE_T* iid_get_node_by_neighIID4x( IID_NEIGH_T *nn, IID_T neighIID4x ); +IID_NODE_T* _iid_get_node_by_neighIID4x( const char *f, IID_NEIGH_T *nn, IID_T neighIID4x ); + +#define iid_get_node_by_neighIID4x( nn, neighIID4x ) _iid_get_node_by_neighIID4x( __FUNCTION__, nn, neighIID4x )
IID_NODE_T* iid_get_node_by_myIID4x( IID_T myIID4x );
+ + #endif diff --git a/ip.c b/ip.c new file mode 100644 index 0000000..d99c92a --- /dev/null +++ b/ip.c @@ -0,0 +1,2995 @@ +/* + * Copyright (c) 2010 Axel Neumann + * 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 <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/socket.h> +#include <string.h> +#include <errno.h> +#include <time.h> +#include <arpa/inet.h> +#include <sys/ioctl.h> +#include <fcntl.h> + + +#include <linux/rtnetlink.h> + +#include "bmx.h" +#include "ip.h" +#include "msg.h" +#include "schedule.h" +#include "plugin.h" +#include "tools.h" +#include "metrics.h" + +int32_t base_port = DEF_BASE_PORT; + + +int32_t Rt_prio = DEF_RT_PRIO; +int32_t Rt_table = DEF_RT_TABLE; + + + +int32_t prio_rules = DEF_PRIO_RULES; + +int32_t throw_rules = DEF_THROW_RULES; + + +static int32_t Lo_rule = DEF_LO_RULE; + +//TODO: make this configurable +static IPX_T cfg_llocal_bmx_prefix = {{{0}}}; +static uint8_t cfg_llocal_bmx_prefix_len = 0; +static IPX_T cfg_global_bmx_prefix = {{{0}}}; +static uint8_t cfg_global_bmx_prefix_len = 0; + +const IPX_T ZERO_IP = {{{0}}}; +const MAC_T ZERO_MAC = {{0}}; + +//const struct link_key ZERO_LINK_KEY = {.link = NULL, .dev = NULL}; + +const IFNAME_T ZERO_IFNAME = {{0}}; + +//#define IN6ADDR_ANY_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } } +//#define IN6ADDR_LOOPBACK_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } } + +const IP6_T IP6_LOOPBACK_ADDR = { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } }; + + +//const IP6_T IP6_ALLROUTERS_MC_ADDR = {.s6_addr[0] = 0xFF, .s6_addr[1] = 0x02, .s6_addr[15] = 0x02}; +const IP6_T IP6_ALLROUTERS_MC_ADDR = {{{0xFF,0x02,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0x02}}}; + +//const IP6_T IP6_LINKLOCAL_UC_PREF = {.s6_addr[0] = 0xFE, .s6_addr[1] = 0x80}; +const IP6_T IP6_LINKLOCAL_UC_PREF = {{{0xFE,0x80,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0}}}; +const uint8_t IP6_LINKLOCAL_UC_PLEN = 10; + +//const IP6_T IP6_MC_PREF = {.s6_addr[0] = 0xFF}; +const IP6_T IP6_MC_PREF = {{{0xFF,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0}}}; +const uint8_t IP6_MC_PLEN = 8; + + +static int nlsock_default = -1; +static int nlsock_flush_all = -1; + +const struct ort_data ort_dat[ORT_MAX + 1] = { + {AF_INET, IP4_MAX_PREFIXLEN}, + {AF_INET6, IP6_MAX_PREFIXLEN} +}; + + + +static int rt_sock = 0; + +struct rtnl_handle ip_rth = { .fd = -1 }; + +struct dev_node *primary_dev_cfg = NULL; +uint8_t af_cfg = 0; + + +AVL_TREE(if_link_tree, struct if_link_node, index); + +AVL_TREE(dev_ip_tree, struct dev_node, llocal_ip_key); +AVL_TREE(dev_name_tree, struct dev_node, name_phy_cfg); + +AVL_TREE(iptrack_tree, struct track_node, k); + + +static LIST_SIMPEL( throw4_list, struct throw_node, list, list ); + +IDM_T dev_soft_conf_changed = NO; // temporary enabled to trigger changed interface configuration + + + +static Sha ip_sha; + + +#define ARG_PEDANTIC_CLEANUP "pedantic_cleanup" +#define DEF_PEDANT_CLNUP NO +static int32_t Pedantic_cleanup = DEF_PEDANT_CLNUP; +static int32_t if6_forward_orig = -1; +static int32_t if4_forward_orig = -1; +static int32_t if4_rp_filter_all_orig = -1; +static int32_t if4_rp_filter_default_orig = -1; +static int32_t if4_send_redirects_all_orig = -1; +static int32_t if4_send_redirects_default_orig = -1; + + + + +STATIC_FUNC +int rtnl_open(struct rtnl_handle *rth) +{ + unsigned subscriptions = 0; + int protocol = NETLINK_ROUTE; + socklen_t addr_len; + int sndbuf = 32768; + int rcvbuf = 1024 * 1024; + + memset(rth, 0, sizeof(*rth)); + + rth->fd = socket(AF_NETLINK, SOCK_RAW, protocol); + if (rth->fd < 0) { + dbgf(DBGL_SYS, DBGT_ERR, "Cannot open netlink socket"); + return FAILURE; + } + + if (setsockopt(rth->fd,SOL_SOCKET,SO_SNDBUF,&sndbuf,sizeof(sndbuf)) < 0) { + dbgf(DBGL_SYS, DBGT_ERR, "SO_SNDBUF"); + return FAILURE; + } + + if (setsockopt(rth->fd,SOL_SOCKET,SO_RCVBUF,&rcvbuf,sizeof(rcvbuf)) < 0) { + dbgf(DBGL_SYS, DBGT_ERR, "SO_RCVBUF"); + return FAILURE; + } + + memset(&rth->local, 0, sizeof(rth->local)); + rth->local.nl_family = AF_NETLINK; + rth->local.nl_groups = subscriptions; + + if (bind(rth->fd, (struct sockaddr*)&rth->local, sizeof(rth->local)) < 0) { + dbgf(DBGL_SYS, DBGT_ERR, "Cannot bind netlink socket"); + return FAILURE; + } + addr_len = sizeof(rth->local); + if (getsockname(rth->fd, (struct sockaddr*)&rth->local, &addr_len) < 0) { + dbgf(DBGL_SYS, DBGT_ERR, "Cannot getsockname"); + return FAILURE; + } + if (addr_len != sizeof(rth->local)) { + dbgf(DBGL_SYS, DBGT_ERR, "Wrong address length %d\n", addr_len); + return FAILURE; + } + if (rth->local.nl_family != AF_NETLINK) { + dbgf(DBGL_SYS, DBGT_ERR, "Wrong address family %d\n", rth->local.nl_family); + return FAILURE; + } + rth->seq = time(NULL); + return SUCCESS; +} + + + +STATIC_FUNC +int open_netlink_socket( void ) { + + int sock = 0; + if ( ( sock = socket( AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE ) ) < 0 ) { + + dbg( DBGL_SYS, DBGT_ERR, "can't create netlink socket for routing table manipulation: %s", + strerror(errno) ); + + return -1; + } + + + if ( fcntl( sock, F_SETFL, O_NONBLOCK) < 0 ) { + + dbg( DBGL_SYS, DBGT_ERR, "can't set netlink socket nonblocking : (%s)", strerror(errno)); + close(sock); + return -1; + } + + return sock; +} + + + + +STATIC_FUNC +void parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len) +{ + memset(tb, 0, sizeof(struct rtattr *) * (max + 1)); + + while (RTA_OK(rta, len)) { + if (rta->rta_type <= max) + tb[rta->rta_type] = rta; + rta = RTA_NEXT(rta,len); + } + + if (len) { + dbgf(DBGL_SYS, DBGT_ERR, "!!!Deficit %d, rta_len=%d\n", len, rta->rta_len); + } + +} + +STATIC_FUNC +IDM_T get_if_req(IFNAME_T *dev_name, struct ifreq *if_req, int siocgi_req) +{ + + memset( if_req, 0, sizeof (struct ifreq) ); + + if (dev_name) + strncpy(if_req->ifr_name, dev_name->str, IFNAMSIZ - 1); + + errno = 0; + if ( ioctl( rt_sock, siocgi_req, if_req ) < 0 ) { + + if (siocgi_req != SIOCGIWNAME) { + dbg(DBGL_SYS, DBGT_ERR, + "can't get SIOCGI %d of interface %s: %s", + siocgi_req, dev_name->str, strerror(errno)); + } + return FAILURE; + } + + return SUCCESS; +} + + +STATIC_FUNC +int rt_macro_to_table( int rt_macro ) { + + dbgf_all( DBGT_INFO, "rt_macro %d", rt_macro ); + + if ( rt_macro == RT_TABLE_HOSTS ) + return Rt_table + RT_TABLE_HOSTS_OFFS; + + else if ( rt_macro == RT_TABLE_NETS ) + return Rt_table + RT_TABLE_NETS_OFFS; + + else if ( rt_macro == RT_TABLE_TUNS ) + return Rt_table + RT_TABLE_TUNS_OFFS; + + else if ( rt_macro > MAX_RT_TABLE ) + cleanup_all( -500170 ); + + else if ( rt_macro >= 0 ) + return rt_macro; + + cleanup_all( -500171 ); + + return 0; + +} +STATIC_FUNC +char *del2str(IDM_T del) +{ + return ( del ? "DEL" : "ADD"); +} + +#ifdef WITH_UNUSED +STATIC_FUNC +char *rtn2str(uint8_t rtn) +{ + if ( rtn == RTN_UNICAST ) + return "RTN_UNICAST"; + + else if ( rtn == RTN_THROW ) + return "RTN_THROW "; + + return "RTN_ILLEGAL"; +} + +STATIC_FUNC +char *rta2str(uint8_t rta) +{ + if ( rta == RTA_DST ) + return "RTA_DST"; + + return "RTA_ILLEGAL"; +} +#endif + +STATIC_FUNC +char *trackt2str(uint8_t cmd) +{ + if ( cmd == IP_NOP ) + return "TRACK_NOP"; + + else if ( cmd == IP_RULE_FLUSH ) + return "RULE_FLUSH"; + + else if ( cmd == IP_RULE_DEFAULT ) + return "RULE_DEFAULT"; + + else if (cmd == IP_ROUTE_FLUSH_ALL) + return "ROUTE_FLUSH_ALL"; + + else if (cmd == IP_ROUTE_FLUSH) + return "ROUTE_FLUSH"; + + else if ( cmd == IP_THROW_MY_HNA ) + return "THROW_MY_HNA"; + + else if ( cmd == IP_THROW_MY_NET ) + return "THROW_MY_NET"; + + else if ( cmd == IP_ROUTE_HOST ) + return "ROUTE_HOST"; + + else if ( cmd == IP_ROUTE_HNA ) + return "ROUTE_HNA"; + + return "TRACK_ILLEGAL"; +} + +char *family2Str(uint8_t family) +{ + static char b[B64_SIZE]; + + switch (family) { + case AF_INET: + return "inet"; + case AF_INET6: + return "inet6"; + default: + sprintf( b, "%d ???", family); + return b; + } +} + + + + +void ip2Str(int family, const IPX_T *addr, char *str) +{ + assertion(-500583, (str)); + uint32_t *a; + + if (!addr) + a = (uint32_t *)&(ZERO_IP.s6_addr32[0]); + + else if (family == AF_INET) { + + a = (uint32_t *)&(addr->s6_addr32[3]); + + } else if (family == AF_INET6) { + + a = (uint32_t *)&(addr->s6_addr32[0]); + + } else { + strcpy(str, "ERROR"); + return; + } + + inet_ntop(family, a, str, family == AF_INET ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN); + return; +} + +void ip42X(IPX_T *ipx, IP4_T ip4) +{ + *ipx = ZERO_IP; + ipx->s6_addr32[3] = ip4; +} + +char *ipXAsStr(int family, const IPX_T *addr) +{ + static uint8_t c=0; + static char str[IP2S_ARRAY_LEN][INET6_ADDRSTRLEN]; + + c = (c+1) % IP2S_ARRAY_LEN; + + ip2Str(family, addr, str[c]); + + return str[c]; +} + + + +char *ip4AsStr( IP4_T addr ) +{ + + static uint8_t c=0; + static char str[IP2S_ARRAY_LEN][INET_ADDRSTRLEN]; + + c = (c+1) % IP2S_ARRAY_LEN; + + inet_ntop( AF_INET, &addr, str[c], INET_ADDRSTRLEN ); + + return str[c]; +} + + +char* macAsStr(const MAC_T* mac) +{ + return memAsStr( mac, sizeof(MAC_T)); +} + +IDM_T is_mac_equal(const MAC_T *a, const MAC_T *b) +{ + return (a->u16[2] == b->u16[2] && + a->u16[1] == b->u16[1] && + a->u16[0] == b->u16[0]); + +} + + +IDM_T is_ip_equal(const IPX_T *a, const IPX_T *b) +{ + return (a->s6_addr32[3] == b->s6_addr32[3] && + a->s6_addr32[2] == b->s6_addr32[2] && + a->s6_addr32[1] == b->s6_addr32[1] && + a->s6_addr32[0] == b->s6_addr32[0]); + +} + +IDM_T is_ip_net_equal(const IPX_T *netA, const IPX_T *netB, const uint8_t plen, const uint8_t family) +{ + + IPX_T aprefix = *netA; + IPX_T bprefix = *netB; + + ip_netmask_validate(&aprefix, plen, family, YES /*force*/); + ip_netmask_validate(&bprefix, plen, family, YES /*force*/); + + return is_ip_equal(&aprefix, &bprefix); +} + + + + +IDM_T is_ip_set(const IPX_T *ip) +{ + return (ip && !is_ip_equal(ip, &ZERO_IP)); +} + +IDM_T is_ip_forbidden( const IPX_T *ip, const uint8_t family ) +{ + TRACE_FUNCTION_CALL; + + if (family == AF_INET6 ) { + + if (!is_ip_equal(ip, &IP6_LOOPBACK_ADDR)) { + + return NO; + } + + } else if (family == AF_INET ) { + + if (ipXto4(*ip) != INADDR_LOOPBACK && + ipXto4(*ip) != INADDR_NONE) { + + return NO; + } + } + + return YES; +} + + +IDM_T ip_netmask_validate(IPX_T *ipX, uint8_t mask, uint8_t family, uint8_t force) +{ + TRACE_FUNCTION_CALL; + uint8_t nmask = mask; + int i; + IP4_T ip32 = 0, m32 = 0; + + if (nmask > ort_dat[AFINET2BMX(family)].max_prefixlen) + goto validate_netmask_error; + + if (family == AF_INET) + nmask += (IP6_MAX_PREFIXLEN - IP4_MAX_PREFIXLEN); + + for (i = 3; i >= 0 && nmask > 0 && i >= ((nmask - 1) / 32); i--) { + + ip32 = ipX->s6_addr32[i]; + + if ( force ) { + + if (nmask <= (i * 32) && ip32) + ipX->s6_addr32[i] = 0; + else + ipX->s6_addr32[i] = (ip32 & (m32 = htonl(0xFFFFFFFF << (32 - (nmask - (i * 32)))))); + + } else { + + if (nmask <= (i * 32) && ip32) + goto validate_netmask_error; + + else if (ip32 != (ip32 & (m32 = htonl(0xFFFFFFFF << (32 - (nmask - (i * 32))))))) + goto validate_netmask_error; + } + } + + + return SUCCESS; +validate_netmask_error: + + dbgf(DBGL_SYS, DBGT_ERR, "inconsistent network prefix %s/%d (force=%d nmask=%d, ip32=%s m32=%s)", + ipXAsStr(family, ipX), mask, force, nmask, ip4AsStr(ip32), ip4AsStr(m32)); + + return FAILURE; + +} + + +STATIC_FUNC +struct dev_node * dev_get_by_name(char *name) +{ + IFNAME_T key = ZERO_IFNAME; + + strcpy(key.str, name); + + return avl_find_item(&dev_name_tree, &key); +} + + +STATIC_FUNC +IDM_T kernel_if_fix(IDM_T purge_all, uint16_t curr_sqn) +{ + TRACE_FUNCTION_CALL; + uint16_t changed = 0; + struct if_link_node *iln; + int index = 0; + + while ((iln = avl_next_item(&if_link_tree, &index))) { + + index = iln->index; + IPX_T addr = ZERO_IP; + struct if_addr_node *ian; + + while ((ian = avl_next_item(&iln->if_addr_tree, &addr))) { + + addr = ian->ip_addr; + + if ( purge_all || curr_sqn != ian->update_sqn) { + + dbgf(terminating || initializing ? DBGL_ALL : DBGL_SYS, DBGT_WARN, + "addr index %d %s addr %s REMOVED", + iln->index, ian->label.str, ipXAsStr(ian->ifa.ifa_family, &ian->ip_addr)); + + if (ian->dev) { + ian->dev->hard_conf_changed = YES; + ian->dev->if_llocal_addr = NULL; + ian->dev->if_global_addr = NULL; + } + + avl_remove(&iln->if_addr_tree, &addr, -300236); + debugFree(ian, -300237); + changed++; + + continue; + + } else { + + changed += ian->changed; + + } + } + + if (purge_all || curr_sqn != iln->update_sqn) { + + assertion(-500565, (!iln->if_addr_tree.items)); + + dbgf(terminating || initializing ? DBGL_ALL : DBGL_SYS, DBGT_WARN, + "link index %d %s addr %s REMOVED", + iln->index, iln->name.str, memAsStr(&iln->addr, iln->alen)); + + avl_remove(&if_link_tree, &iln->index, -300232); + avl_remove(&if_link_tree, &iln->name, -300234); + debugFree(iln, -300230); + changed++; + + + } else if (iln->changed) { + + struct dev_node *dev = dev_get_by_name(iln->name.str); + + if (dev) + dev->hard_conf_changed = YES; + + changed += iln->changed; + + } + } + + if (changed) { + + dbgf(DBGL_SYS, DBGT_WARN, "network configuration CHANGED"); + return YES; + + } else { + + dbgf_all(DBGT_INFO, "network configuration UNCHANGED"); + return NO; + } +} + +STATIC_INLINE_FUNC +void kernel_if_addr_config(struct nlmsghdr *nlhdr, uint16_t index_sqn) +{ + + int len = nlhdr->nlmsg_len; + struct ifaddrmsg *if_addr = NLMSG_DATA(nlhdr); + int index = if_addr->ifa_index; + int family = if_addr->ifa_family; + struct if_link_node *iln = avl_find_item(&if_link_tree, &index); + + if (!iln) + return; + + if (family != AF_INET && family != AF_INET6) + return; + + if (family != af_cfg) + return; + + if (nlhdr->nlmsg_type != RTM_NEWADDR) + return; + + if (len < (int) NLMSG_LENGTH(sizeof (if_addr))) + return; + + + len -= NLMSG_LENGTH(sizeof (*if_addr)); + if (len < 0) { + dbgf(DBGL_SYS, DBGT_ERR, "BUG: wrong nlmsg len %d", len); + return; + } + + struct rtattr * rta_tb[IFA_MAX + 1]; + + parse_rtattr(rta_tb, IFA_MAX, IFA_RTA(if_addr), nlhdr->nlmsg_len - NLMSG_LENGTH(sizeof (*if_addr))); + + + if (!rta_tb[IFA_LOCAL]) + rta_tb[IFA_LOCAL] = rta_tb[IFA_ADDRESS]; + + if (!rta_tb[IFA_LOCAL] || !if_addr) + return; + + IPX_T ip_addr = ZERO_IP; + + uint32_t alen = MIN(sizeof (ip_addr), RTA_PAYLOAD(rta_tb[IFA_LOCAL])); + + memcpy(&ip_addr, RTA_DATA(rta_tb[IFA_LOCAL]), alen); + + if (family == AF_INET) + ip42X(&ip_addr, *((IP4_T*) (&ip_addr))); + + if (is_ip_forbidden(&ip_addr, family)) // specially catch loopback ::1/128 + return; + + + + struct if_addr_node *new_ian = NULL; + struct if_addr_node *old_ian = avl_find_item(&iln->if_addr_tree, &ip_addr); + + if (old_ian) { + + old_ian->changed = 0; + + if (old_ian->update_sqn == index_sqn) { + dbgf(DBGL_SYS, DBGT_ERR, + "ifi %d addr %s found several times!", + iln->index, ipXAsStr(old_ian->ifa.ifa_family, &ip_addr)); + } + + if (nlhdr->nlmsg_len > old_ian->nlmsghdr->nlmsg_len) { + + if (old_ian->dev) { + old_ian->dev->hard_conf_changed = YES; + old_ian->dev->if_llocal_addr = NULL; + old_ian->dev->if_global_addr = NULL; + } + + avl_remove(&iln->if_addr_tree, &ip_addr, -300239); + dbgf(DBGL_SYS, DBGT_ERR, "new size"); + + } else if (memcmp(nlhdr, old_ian->nlmsghdr, nlhdr->nlmsg_len)) { + + if (nlhdr->nlmsg_len != old_ian->nlmsghdr->nlmsg_len) { + dbgf(DBGL_SYS, DBGT_ERR, + "different data and size %d != %d", + nlhdr->nlmsg_len, old_ian->nlmsghdr->nlmsg_len); + } + + memcpy(old_ian->nlmsghdr, nlhdr, nlhdr->nlmsg_len); + new_ian = old_ian; + + } else { + new_ian = old_ian; + } + + } + + if (!new_ian) { + new_ian = debugMalloc(sizeof (struct if_addr_node) +nlhdr->nlmsg_len, -300234); + memset(new_ian, 0, sizeof (struct if_addr_node) +nlhdr->nlmsg_len); + memcpy(new_ian->nlmsghdr, nlhdr, nlhdr->nlmsg_len); + new_ian->ip_addr = ip_addr; + new_ian->iln = iln; + avl_insert(&iln->if_addr_tree, new_ian, -300238); + } + + IFNAME_T label = { + {0}}; + IPX_T ip_mcast = ZERO_IP; + + if (rta_tb[IFA_LABEL]) + strcpy(label.str, (char*) RTA_DATA(rta_tb[IFA_LABEL])); + else + label = iln->name; + + + if (family == AF_INET && rta_tb[IFA_BROADCAST]) { + + memcpy(&ip_mcast, RTA_DATA(rta_tb[IFA_BROADCAST]), alen); + ip42X(&ip_mcast, *((IP4_T*) (&ip_mcast))); + + } else if (family == AF_INET6) { + + ip_mcast = IP6_ALLROUTERS_MC_ADDR; + } + + + if (!old_ian || + old_ian->ifa.ifa_family != if_addr->ifa_family || + old_ian->ifa.ifa_flags != if_addr->ifa_flags || + old_ian->ifa.ifa_prefixlen != if_addr->ifa_prefixlen || + old_ian->ifa.ifa_scope != if_addr->ifa_scope || + old_ian->ifa.ifa_index != if_addr->ifa_index || + memcmp(&old_ian->label, &label, sizeof (label)) || + // memcmp(&old_ian->ip_any, &ip_any, alen) || + memcmp(&old_ian->ip_mcast, &ip_mcast, alen) + ) { + + dbgf(DBGL_CHANGES, + (initializing || terminating) ? DBGT_INFO : DBGT_WARN, + "%s addr %s CHANGED", label.str, ipXAsStr(family, &ip_addr)); + + if (new_ian->dev) { + new_ian->dev->hard_conf_changed = YES; + new_ian->dev->if_llocal_addr = NULL; + new_ian->dev->if_global_addr = NULL; + } + + + new_ian->changed++; + } + + new_ian->ifa.ifa_family = if_addr->ifa_family; + new_ian->ifa.ifa_flags = if_addr->ifa_flags; + new_ian->ifa.ifa_prefixlen = if_addr->ifa_prefixlen; + new_ian->ifa.ifa_scope = if_addr->ifa_scope; + new_ian->ifa.ifa_index = if_addr->ifa_index; + + new_ian->label = label; + new_ian->ip_mcast = ip_mcast; + + new_ian->update_sqn = index_sqn; + + if (old_ian && old_ian != new_ian) + debugFree(old_ian, -300240); + +} + + +STATIC_FUNC +int kernel_if_link_config(struct nlmsghdr *nlhdr, uint16_t update_sqn) +{ + TRACE_FUNCTION_CALL; + + struct ifinfomsg *if_link_info = NLMSG_DATA(nlhdr); + //struct idxmap *im, **imp; + struct rtattr *tb[IFLA_MAX+1]; + + uint16_t changed = 0; + + if (nlhdr->nlmsg_type != RTM_NEWLINK) + return 0; + + if (nlhdr->nlmsg_len < NLMSG_LENGTH(sizeof(if_link_info))) + return -1; + + parse_rtattr(tb, IFLA_MAX, IFLA_RTA(if_link_info), IFLA_PAYLOAD(nlhdr)); + + if (!tb[IFLA_IFNAME]) + return 0; + + int index = if_link_info->ifi_index; + struct if_link_node *new_ilx = NULL, *old_ilx = avl_find_item(&if_link_tree, &index); + + if (old_ilx) { + + if (old_ilx->update_sqn == update_sqn) { + dbgf(DBGL_SYS, DBGT_ERR, "ifi %d found several times!", old_ilx->index); + } + + assertion(-500902, (nlhdr->nlmsg_len >= sizeof (struct nlmsghdr))); + + if (nlhdr->nlmsg_len > old_ilx->nlmsghdr->nlmsg_len) { + + avl_remove(&if_link_tree, &index, -300240); + dbgf(DBGL_SYS, DBGT_ERR, "newand larger nlmsg_len"); + + } else if (memcmp(nlhdr, old_ilx->nlmsghdr, nlhdr->nlmsg_len)) { + + if (nlhdr->nlmsg_len != old_ilx->nlmsghdr->nlmsg_len) { + dbgf(DBGL_SYS, DBGT_ERR, + "different data and size %d != %d", + nlhdr->nlmsg_len, old_ilx->nlmsghdr->nlmsg_len); + } + memcpy(old_ilx->nlmsghdr, nlhdr, nlhdr->nlmsg_len); + new_ilx = old_ilx; + + } else { + new_ilx = old_ilx; + } + } + + if (!new_ilx) { + new_ilx = debugMalloc(sizeof (struct if_link_node) + nlhdr->nlmsg_len, -300231); + memset(new_ilx, 0, sizeof (struct if_link_node)); + new_ilx->index = if_link_info->ifi_index; + AVL_INIT_TREE(new_ilx->if_addr_tree, struct if_addr_node, ip_addr); + avl_insert(&if_link_tree, new_ilx, -300233); + memcpy(new_ilx->nlmsghdr, nlhdr, nlhdr->nlmsg_len); + } + + IFNAME_T devname = {{0}}; + assertion(-500570, (is_zero(&devname, sizeof(devname)))); + strcpy(devname.str, RTA_DATA(tb[IFLA_IFNAME])); + + int32_t alen = (tb[IFLA_ADDRESS]) ? RTA_PAYLOAD(tb[IFLA_ADDRESS]) : 0; + ADDR_T addr = {{0}}; + memcpy(&addr, RTA_DATA(tb[IFLA_ADDRESS]), MIN(alen, (int)sizeof (addr))); + + if (!old_ilx || + old_ilx->type != if_link_info->ifi_type || + old_ilx->flags != if_link_info->ifi_flags || + old_ilx->alen != alen /*(int)RTA_PAYLOAD(tb[IFLA_ADDRESS])*/ || + memcmp(&old_ilx->addr, RTA_DATA(tb[IFLA_ADDRESS]), MIN(alen, (int)sizeof(old_ilx->addr))) || + memcmp(&old_ilx->name, &devname, sizeof (devname))) { + + dbgf(DBGL_SYS, (initializing || terminating) ? DBGT_INFO : DBGT_WARN, + "link %s addr %s CHANGED", devname.str, memAsStr(RTA_DATA(tb[IFLA_ADDRESS]), alen)); + + changed++; + } + + new_ilx->type = if_link_info->ifi_type; + new_ilx->flags = if_link_info->ifi_flags; + + new_ilx->addr = addr; + new_ilx->alen = alen; + + new_ilx->name = devname; + + new_ilx->update_sqn = update_sqn; + new_ilx->changed = changed; + + if (old_ilx && old_ilx != new_ilx) + debugFree(old_ilx, -300241); + + return 0; +} + + + + + + +IDM_T kernel_if_config(void) +{ + TRACE_FUNCTION_CALL; + + static uint16_t index_sqn = 0; + int rtm_type[2] = {RTM_GETLINK, RTM_GETADDR}; + int msg_count; + int info; + + index_sqn++; + dbgf_all( DBGT_INFO, "%d", index_sqn); + + for (info = LINK_INFO; info <= ADDR_INFO; info++) { + + struct ip_req req; + struct sockaddr_nl nla; + struct iovec iov; + struct msghdr msg = {.msg_name = &nla, .msg_namelen = sizeof (nla), .msg_iov = &iov, .msg_iovlen = 1}; + char buf[16384]; + + iov.iov_base = buf; + + memset(&req, 0, sizeof (req)); + req.nlmsghdr.nlmsg_len = sizeof (req); + req.nlmsghdr.nlmsg_type = rtm_type[info]; + req.nlmsghdr.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST; + req.nlmsghdr.nlmsg_pid = 0; + req.nlmsghdr.nlmsg_seq = ip_rth.dump = ++ip_rth.seq; + req.rtgenmsg.rtgen_family = AF_UNSPEC; + + if (send(ip_rth.fd, (void*) & req, sizeof (req), 0) < 0) { + dbgf(DBGL_SYS, DBGT_ERR, "failed"); + return FAILURE; + } + + dbgf_all(DBGT_INFO, "send %s_INFO request", info == LINK_INFO ? "LINK" : "ADDR"); + + while (1) { + int status; + + iov.iov_len = sizeof (buf); + + if ((status = recvmsg(ip_rth.fd, &msg, 0)) < 0) { + + if (errno == EINTR || errno == EAGAIN) + continue; + + dbgf(DBGL_SYS, DBGT_ERR, "netlink receive error %s (%d)", strerror(errno), errno); + return FAILURE; + + } else if (status == 0) { + + dbgf(DBGL_SYS, DBGT_ERR, "EOF on netlink"); + return FAILURE; + } + + dbgf_all(DBGT_INFO, "rcvd %s_INFO status %d", info == LINK_INFO ? "LINK" : "ADDR", status); + + struct nlmsghdr *nlhdr = (struct nlmsghdr*) buf; + + msg_count = 0; + + for (; NLMSG_OK(nlhdr, (unsigned) status); nlhdr = NLMSG_NEXT(nlhdr, status)) { + + msg_count++; + + if (nla.nl_pid || nlhdr->nlmsg_pid != ip_rth.local.nl_pid || nlhdr->nlmsg_seq != ip_rth.dump) + continue; + + if (nlhdr->nlmsg_type == NLMSG_DONE) + break; + + if (nlhdr->nlmsg_type == NLMSG_ERROR) { + dbgf(DBGL_SYS, DBGT_ERR, "NLMSG_ERROR"); + return FAILURE; + } + + + if (info == LINK_INFO ) + kernel_if_link_config(nlhdr, index_sqn); + else + kernel_if_addr_config(nlhdr, index_sqn); + + } + + dbgf_all(DBGT_INFO, "processed %d %s msgs", msg_count, info == LINK_INFO ? "LINK" : "ADDR"); + + if (nlhdr->nlmsg_type == NLMSG_DONE) + break; + + if (msg.msg_flags & MSG_TRUNC) { + dbgf(DBGL_SYS, DBGT_ERR, "Message truncated"); + continue; + } + + if (status) { + dbgf(DBGL_SYS, DBGT_ERR, "Remnant of size %d", status); + return FAILURE; + } + } + } + + return kernel_if_fix(NO, index_sqn); + +} + + +STATIC_FUNC +IDM_T iptrack(uint8_t family, uint8_t cmd, uint8_t quiet, int8_t del, IPX_T *net, uint8_t mask, uint16_t table, uint32_t prio, IFNAME_T *iif) +{ + TRACE_FUNCTION_CALL; + assertion(-500628, (cmd != IP_NOP)); + assertion(-500629, (del || (cmd != IP_ROUTE_FLUSH && cmd != IP_RULE_FLUSH))); + + IDM_T flush = (cmd == IP_RULE_FLUSH || cmd == IP_ROUTE_FLUSH_ALL || cmd == IP_ROUTE_FLUSH); + + uint8_t cmd_t = (cmd > IP_ROUTES && cmd < IP_ROUTE_MAX) ? IP_ROUTES : + ((cmd > IP_RULES && cmd < IP_RULE_MAX) ? IP_RULES : IP_NOP); + + struct track_key sk; + memset(&sk, 0, sizeof (sk)); + sk.net = net ? *net : ZERO_IP; + sk.iif = iif ? *iif : ZERO_IFNAME; + sk.prio = prio; + sk.table = table; + sk.family = family; + sk.mask = mask; + sk.cmd_type = cmd_t; + + int found = 0, exact = 0; + struct track_node *first_tn = NULL; + struct avl_node *an = avl_find(&iptrack_tree, &sk); + struct track_node *tn = an ? an->item : NULL; + + while (tn) { + + if (!first_tn && (tn->cmd == cmd || flush)) + first_tn = tn; + + if (tn->cmd == cmd) { + assertion(-500887, (exact == 0)); + exact += tn->items; + } + + found += tn->items; + + tn = (tn = avl_iterate_item(&iptrack_tree, &an)) && !memcmp(&sk, &tn->k, sizeof (sk)) ? tn : NULL; + } + + if (flush || (del && !first_tn) || (del && found != 1) || (!del && found > 0)) { + + dbgf( + quiet ? DBGL_ALL : (flush || (del && !first_tn)) ? DBGL_SYS : DBGL_CHANGES, + quiet ? DBGT_INFO : (flush || (del && !first_tn)) ? DBGT_ERR : DBGT_INFO, + " %s %s %s/%d table %d prio %d dev %s exists %d tims with %d exact match", + del2str(del), trackt2str(cmd), ipXAsStr(family, net), mask, table, prio, + iif ? iif->str : NULL, found, exact); + + EXITERROR(-500700, (!(!quiet && (flush || (del && !first_tn))))); + } + + if (flush) + return YES; + + if (del) { + + if (!first_tn) { + + dbgf( DBGL_SYS, DBGT_ERR, " "); + assertion(-500883, (0)); + + } else if (first_tn->items == 1) { + + struct track_node *rem_tn = avl_remove(&iptrack_tree, &first_tn->k, -300250); + assertion(-500882, (rem_tn == first_tn)); + debugFree(first_tn, -300072); + + } else if (first_tn->items > 1) { + + first_tn->items--; + } + + if ( found != 1 ) + return NO; + + } else { + + if (exact) { + + assertion(-500886, (first_tn)); + assertion(-500884, (!memcmp(&sk, &first_tn->k, sizeof (sk)))); + assertion(-500885, (first_tn->cmd == cmd)); + + first_tn->items++; + + } else { + + struct track_node *tn = debugMalloc(sizeof ( struct track_node), -300030); + memset(tn, 0, sizeof ( struct track_node)); + tn->k = sk; + tn->items = 1; + tn->cmd = cmd; + + avl_insert(&iptrack_tree, tn, -300251); + } + + if (found > 0) + return NO; + + } + + return YES; +} + + +STATIC_FUNC +void add_rtattr(struct rtmsg_req *req, int rta_type, char *data, uint16_t data_len, uint16_t family) +{ + TRACE_FUNCTION_CALL; + IP4_T ip4; + if (family == AF_INET) { + ip4 = ipXto4((*((IPX_T*)data))); + data_len = sizeof (ip4); + data = (char*) & ip4; + } + + struct rtattr *rta = (struct rtattr *)(((char *) req) + NLMSG_ALIGN(req->nlh.nlmsg_len)); + + req->nlh.nlmsg_len = NLMSG_ALIGN( req->nlh.nlmsg_len ) + RTA_LENGTH(data_len); + + assertion(-50173, (NLMSG_ALIGN(req->nlh.nlmsg_len) < sizeof ( struct rtmsg_req))); + // if this fails then double req buff size !! + + rta->rta_type = rta_type; + rta->rta_len = RTA_LENGTH(data_len); + memcpy( RTA_DATA(rta), data, data_len ); +} + + +IDM_T ip(uint8_t family, uint8_t cmd, int8_t del, uint8_t quiet, const IPX_T *NET, uint8_t nmask, + int32_t table_macro, uint32_t prio, IFNAME_T *iifname, int oif_idx, IPX_T *via, IPX_T *src) +{ + TRACE_FUNCTION_CALL; + + assertion(-500653, (family == af_cfg && (family == AF_INET || family == AF_INET6))); + assertion(-500650, ((NET && !is_ip_forbidden(NET, family)))); + assertion(-500651, (!(via && is_ip_forbidden(via, family)))); + assertion(-500652, (!(src && is_ip_forbidden(src, family)))); + + struct sockaddr_nl nladdr; + struct nlmsghdr *nh; + struct rtmsg_req req; + + uint16_t table = rt_macro_to_table(table_macro); + + IPX_T net_dummy = *NET; + IPX_T *net = &net_dummy; + + uint8_t more_data; + + int nlsock = 0; + + if ( cmd == IP_ROUTE_FLUSH_ALL ) + nlsock = nlsock_flush_all; + else + nlsock = nlsock_default; + + assertion(-500672, (ip_netmask_validate(net, nmask, family, NO) == SUCCESS)); + + + IDM_T llocal = (via && is_ip_equal(via, net)) ? YES : NO; + + if (!is_ip_set(src)) + src = NULL; + + if (!throw_rules && (cmd == IP_THROW_MY_HNA || cmd == IP_THROW_MY_NET)) + return SUCCESS;; + + if (iptrack(family, cmd, quiet, del,net, nmask, table, prio, iifname) == NO) + return SUCCESS; + + +#ifndef NO_DEBUG_ALL + struct if_link_node *oif_iln = oif_idx ? avl_find_item(&if_link_tree, &oif_idx) : NULL; + + dbgf(DBGL_ALL, DBGT_INFO, "%s %s %s %s/%-2d iif %s table %d prio %d oif %s via %s src %s (using nl_sock %d)", + family2Str(family), trackt2str(cmd), del2str(del), ipXAsStr(family, net), nmask, + iifname ? iifname->str : NULL, table, prio, oif_iln ? oif_iln->name.str : "---", + via ? ipXAsStr(family, via) : "---", src ? ipXAsStr(family, src) : "---", nlsock); +#endif + + memset(&nladdr, 0, sizeof (struct sockaddr_nl)); + memset(&req, 0, sizeof (req)); + + nladdr.nl_family = AF_NETLINK; + + req.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); + req.nlh.nlmsg_pid = My_pid; + + req.rtm.rtm_family = family; + req.rtm.rtm_table = table; + + req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; + + if (cmd > IP_ROUTES && cmd < IP_ROUTE_MAX) { + + if ( cmd == IP_ROUTE_FLUSH_ALL ) { + + req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; + req.nlh.nlmsg_type = RTM_GETROUTE; + req.rtm.rtm_scope = RTN_UNICAST; + + } else if (del) { + req.nlh.nlmsg_type = RTM_DELROUTE; + req.rtm.rtm_scope = RT_SCOPE_NOWHERE; + } else { + req.nlh.nlmsg_flags = req.nlh.nlmsg_flags | NLM_F_CREATE | NLM_F_EXCL; //| NLM_F_REPLACE; + req.nlh.nlmsg_type = RTM_NEWROUTE; + req.rtm.rtm_scope = ((cmd == IP_ROUTE_HNA || cmd == IP_ROUTE_HOST) && llocal) ? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE; + req.rtm.rtm_protocol = RTPROT_STATIC; + req.rtm.rtm_type = (cmd == IP_THROW_MY_HNA || cmd == IP_THROW_MY_NET) ? RTN_THROW : RTN_UNICAST; + } + + if (is_ip_set(net)) { + req.rtm.rtm_dst_len = nmask; + add_rtattr(&req, RTA_DST, (char*) net, sizeof (IPX_T), family); + } + + if (via && !llocal) + add_rtattr(&req, RTA_GATEWAY, (char*) via, sizeof (IPX_T), family); + + if (oif_idx) + add_rtattr(&req, RTA_OIF, (char*) & oif_idx, sizeof (oif_idx), 0); + + if (src) + add_rtattr(&req, RTA_PREFSRC, (char*) src, sizeof (IPX_T), family); + + + + } else if (cmd > IP_RULES && cmd < IP_RULE_MAX) { + + if (del) { + req.nlh.nlmsg_type = RTM_DELRULE; + req.rtm.rtm_scope = RT_SCOPE_NOWHERE; + } else { + req.nlh.nlmsg_flags = req.nlh.nlmsg_flags | NLM_F_CREATE | NLM_F_EXCL; + req.nlh.nlmsg_type = RTM_NEWRULE; + req.rtm.rtm_scope = RT_SCOPE_UNIVERSE; + req.rtm.rtm_protocol = RTPROT_STATIC; + req.rtm.rtm_type = RTN_UNICAST; + } + + if (is_ip_set(net)) { + req.rtm.rtm_src_len = nmask; + add_rtattr(&req, RTA_SRC, (char*) net, sizeof (IPX_T), family); + } + + if (iifname) + add_rtattr(&req, RTA_IIF, iifname->str, strlen(iifname->str) + 1, 0); + + } else { + + cleanup_all(-500628); + } + + + if (prio) + add_rtattr(&req, RTA_PRIORITY, (char*) & prio, sizeof (prio), 0); + + errno = 0; + + if (sendto(nlsock, &req, req.nlh.nlmsg_len, 0, (struct sockaddr *) & nladdr, sizeof (struct sockaddr_nl)) < 0) { + + dbg(DBGL_SYS, DBGT_ERR, "can't send netlink message to kernel: %s", strerror(errno)); + return FAILURE; + } + + int max_retries = 10; + + //TODO: see ip/libnetlink.c rtnl_talk() for HOWTO + while (1) { + struct msghdr msg; + char buf[4096]; // less causes lost messages !!?? + memset(&msg, 0, sizeof (struct msghdr)); + + memset(&nladdr, 0, sizeof (struct sockaddr_nl)); + nladdr.nl_family = AF_NETLINK; + + memset(buf, 0, sizeof(buf)); + struct iovec iov = {.iov_base = buf, .iov_len = sizeof (buf)}; + + msg.msg_name = (void *)&nladdr; + msg.msg_namelen = sizeof(nladdr); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = NULL; + + errno=0; + int status = recvmsg( nlsock, &msg, 0 ); + + more_data = NO; + + if ( status < 0 ) { + + if ( errno == EINTR ) { + + dbgf(DBGL_SYS, DBGT_WARN, "(EINTR) %s", strerror(errno)); + + } else if (errno == EWOULDBLOCK || errno == EAGAIN) { + + dbgf(DBGL_SYS, DBGT_ERR, "(EWOULDBLOCK || EAGAIN) %s", strerror(errno)); + + } else { + + dbgf(DBGL_SYS, DBGT_ERR, "%s", strerror(errno)); + } + + if ( max_retries-- > 0 ) { + usleep(500); + continue; + } else { + dbgf(DBGL_SYS, DBGT_ERR, "giving up!"); + return FAILURE; + } + + } else if (status == 0) { + dbgf(DBGL_SYS, DBGT_ERR, "netlink EOF"); + return FAILURE; + } + + if (msg.msg_flags & MSG_TRUNC) { + dbgf(DBGL_CHANGES, DBGT_INFO, "MSG_TRUNC"); + more_data = YES; + } + + nh = (struct nlmsghdr *)buf; + + while ( NLMSG_OK(nh, (size_t)status) ) { + + if (nh->nlmsg_flags & NLM_F_MULTI) { + dbgf(DBGL_ALL, DBGT_INFO, "NLM_F_MULTI"); + more_data = YES; + } + + if (nh->nlmsg_type == NLMSG_DONE) { + dbgf(DBGL_CHANGES, DBGT_INFO, "NLMSG_DONE"); + more_data = NO; + break; + + } else if ((nh->nlmsg_type == NLMSG_ERROR) && (((struct nlmsgerr*) NLMSG_DATA(nh))->error != 0)) { + + dbg(quiet ? DBGL_ALL : DBGL_SYS, quiet ? DBGT_INFO : DBGT_ERR, + "can't %s %s to %s/%i via %s table %i: %s", + del2str(del), trackt2str(cmd), ipXAsStr(family, net), nmask, ipXAsStr(family, via), + table, strerror(-((struct nlmsgerr*) NLMSG_DATA(nh))->error)); + + return FAILURE; + } + + if (cmd == IP_ROUTE_FLUSH_ALL) { + + struct rtmsg *rtm = (struct rtmsg *) NLMSG_DATA(nh); + struct rtattr *rtap = (struct rtattr *) RTM_RTA(rtm); + int rtl = RTM_PAYLOAD(nh); + + while (rtm->rtm_table == table && RTA_OK(rtap, rtl)) { + + if (rtap->rta_type == RTA_DST) { + + + IPX_T fip; + + if (family == AF_INET6) + fip = *((IPX_T *) RTA_DATA(rtap)); + else + ip42X(&fip, *((IP4_T *) RTA_DATA(rtap))); + + + ip(family, IP_ROUTE_FLUSH, DEL, YES, &fip, rtm->rtm_dst_len, table, 0, NULL, 0, NULL, NULL); + + } + + rtap = RTA_NEXT(rtap, rtl); + } + } + + nh = NLMSG_NEXT(nh, status); + } + + if ( more_data ) { + dbgf(DBGL_CHANGES, DBGT_INFO, "more data via netlink socket %d...", nlsock); + } else { + break; + } + } + + return SUCCESS; +} + + + + + + +STATIC_FUNC +void check_proc_sys_net(char *file, int32_t desired, int32_t *backup) +{ + TRACE_FUNCTION_CALL; + FILE *f; + int32_t state = 0; + char filename[MAX_PATH_SIZE]; + int trash; + + + sprintf( filename, "/proc/sys/net/%s", file ); + + if((f = fopen(filename, "r" )) == NULL) { + + dbgf( DBGL_SYS, DBGT_ERR, "can't open %s for reading! retry later..", filename ); + + return; + } + + trash=fscanf(f, "%d", &state); + fclose(f); + + if ( backup ) + *backup = state; + + // other routing protocols are probably not able to handle this therefore + // it is probably better to leave the routing configuration operational as it is! + if ( !backup && !Pedantic_cleanup && state != desired ) { + + dbg_mute( 50, DBGL_SYS, DBGT_INFO, + "NOT restoring %s to NOT mess up other routing protocols. " + "Use --%s=1 to enforce proper cleanup", + file, ARG_PEDANTIC_CLEANUP ); + + return; + } + + + if ( state != desired ) { + + dbg( DBGL_SYS, DBGT_INFO, "changing %s from %d to %d", filename, state, desired ); + + if((f = fopen(filename, "w" )) == NULL) { + + dbgf( DBGL_SYS, DBGT_ERR, + "can't open %s for writing! retry later...", filename ); + return; + } + + fprintf(f, "%d", desired?1:0 ); + fclose(f); + + } +} + +void sysctl_restore(struct dev_node *dev) +{ + TRACE_FUNCTION_CALL; + + if (dev && af_cfg == AF_INET) { + + char filename[100]; + + if (dev->ip4_rp_filter_orig > -1) { + sprintf( filename, "ipv4/conf/%s/rp_filter", dev->name_phy_cfg.str); + check_proc_sys_net( filename, dev->ip4_rp_filter_orig, NULL ); + } + + dev->ip4_rp_filter_orig = -1; + + + if (dev->ip4_send_redirects_orig > -1) { + sprintf( filename, "ipv4/conf/%s/send_redirects", dev->name_phy_cfg.str); + check_proc_sys_net( filename, dev->ip4_send_redirects_orig, NULL ); + } + + dev->ip4_send_redirects_orig = -1; + + } else if (dev && af_cfg == AF_INET6) { + + // nothing to restore + } + + if (!dev) { + + if( if4_rp_filter_all_orig != -1 ) + check_proc_sys_net( "ipv4/conf/all/rp_filter", if4_rp_filter_all_orig, NULL ); + + if4_rp_filter_all_orig = -1; + + if( if4_rp_filter_default_orig != -1 ) + check_proc_sys_net( "ipv4/conf/default/rp_filter", if4_rp_filter_default_orig, NULL ); + + if4_rp_filter_default_orig = -1; + + if( if4_send_redirects_all_orig != -1 ) + check_proc_sys_net( "ipv4/conf/all/send_redirects", if4_send_redirects_all_orig, NULL ); + + if4_send_redirects_all_orig = -1; + + if( if4_send_redirects_default_orig != -1 ) + check_proc_sys_net( "ipv4/conf/default/send_redirects", if4_send_redirects_default_orig, NULL ); + + if4_send_redirects_default_orig = -1; + + if( if4_forward_orig != -1 ) + check_proc_sys_net( "ipv4/ip_forward", if4_forward_orig, NULL ); + + if4_forward_orig = -1; + + + if (if6_forward_orig != -1) + check_proc_sys_net("ipv6/conf/all/forwarding", if6_forward_orig, NULL); + + if6_forward_orig = -1; + + } +} + +// TODO: check for further traps: http://lwn.net/Articles/45386/ +void sysctl_config( struct dev_node *dev ) +{ + TRACE_FUNCTION_CALL; + static TIME_T ipv4_timestamp = -1; + static TIME_T ipv6_timestamp = -1; + char filename[100]; + + if (!(dev->active && dev->if_llocal_addr && dev->if_llocal_addr->iln->flags && IFF_UP)) + return; + + + if (dev && af_cfg == AF_INET) { + + sprintf( filename, "ipv4/conf/%s/rp_filter", dev->name_phy_cfg.str); + check_proc_sys_net( filename, 0, &dev->ip4_rp_filter_orig ); + + sprintf( filename, "ipv4/conf/%s/send_redirects", dev->name_phy_cfg.str); + check_proc_sys_net( filename, 0, &dev->ip4_send_redirects_orig ); + + if (ipv4_timestamp != bmx_time) { + + check_proc_sys_net("ipv4/conf/all/rp_filter", 0, &if4_rp_filter_all_orig); + check_proc_sys_net("ipv4/conf/default/rp_filter", 0, &if4_rp_filter_default_orig); + check_proc_sys_net("ipv4/conf/all/send_redirects", 0, &if4_send_redirects_all_orig); + check_proc_sys_net("ipv4/conf/default/send_redirects", 0, &if4_send_redirects_default_orig); + check_proc_sys_net("ipv4/ip_forward", 1, &if4_forward_orig); + + ipv4_timestamp = bmx_time; + } + + } else if (dev && af_cfg == AF_INET6) { + + + if (ipv6_timestamp != bmx_time) { + + check_proc_sys_net("ipv6/conf/all/forwarding", 1, &if6_forward_orig); + + ipv6_timestamp = bmx_time; + } + } +} + + + + + +STATIC_FUNC +int8_t dev_bind_sock(int32_t sock, IFNAME_T *name) +{ + errno=0; + + if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, name->str, strlen(name->str) + 1) < 0) { + dbg(DBGL_SYS, DBGT_ERR, "Can not bind socket to device %s : %s", name->str, strerror(errno)); + return FAILURE; + } + + return SUCCESS; +} + + +STATIC_FUNC +void dev_reconfigure_soft(struct dev_node *dev) +{ + TRACE_FUNCTION_CALL; + + assertion(-500611, (dev->active)); + assertion(-500612, (dev->if_llocal_addr)); + assertion(-500613, (dev->if_global_addr || !dev->announce)); + assertion(-500614, (dev->if_global_addr || dev != primary_dev_cfg)); + assertion(-500615, (dev->if_global_addr || dev->linklayer != VAL_DEV_LL_LO)); + + if (!initializing) { + dbg(DBGL_SYS, DBGT_INFO, "%s soft interface configuration changed", dev->label_cfg.str); + } + + if (dev->umetric_max_conf != OPT_CHILD_UNDEFINED) + dev->umetric_max = dev->umetric_max_configured; + else if (dev->linklayer == VAL_DEV_LL_WLAN) + dev->umetric_max = DEF_DEV_BANDWIDTH_WIFI; + else if (dev->linklayer == VAL_DEV_LL_LAN) + dev->umetric_max = DEF_DEV_BANDWIDTH_LAN; + else if (dev->linklayer == VAL_DEV_LL_LO) + dev->umetric_max = umetric(0, 0, DEF_FMETRIC_EXP_OFFSET); + else + cleanup_all(-500821); + + dbg(bmx_time ? DBGL_CHANGES : DBGL_SYS, DBGT_INFO, + "enabled %sprimary %s %ju %s=%s MAC: %s link-local %s/%d global %s/%d brc %s", + dev == primary_dev_cfg ? "" : "non-", + dev->linklayer == VAL_DEV_LL_LO ? "loopback" : ( + dev->linklayer == VAL_DEV_LL_WLAN ? "wireless" : ( + dev->linklayer == VAL_DEV_LL_LAN ? "ethernet" : ("ILLEGAL"))), + dev->umetric_max, + dev->arg_cfg, + dev->label_cfg.str, macAsStr(&dev->mac), + dev->ip_llocal_str, dev->if_llocal_addr->ifa.ifa_prefixlen, + dev->ip_global_str, dev->if_global_addr ? dev->if_global_addr->ifa.ifa_prefixlen : 0, + dev->ip_brc_str); + + + my_description_changed = YES; + + dev->soft_conf_changed = NO; + +} + + +STATIC_FUNC +void dev_deactivate( struct dev_node *dev ) +{ + + TRACE_FUNCTION_CALL; + dbgf(DBGL_SYS, DBGT_WARN, "deactivating %s=%s %s", dev->arg_cfg, dev->label_cfg.str, dev->ip_llocal_str); + + if (dev->active) { + dev->active = NO; + cb_plugin_hooks(PLUGIN_CB_DEV_EVENT, dev); + } + + if (dev == primary_dev_cfg && !terminating) { + dbg_mute(30, DBGL_SYS, DBGT_WARN, + "Using an IP on the loopback device as primary interface ensures reachability under your primary IP!"); + } + + + if ( dev->linklayer != VAL_DEV_LL_LO ) { +/* + if (dev == primary_dev_cfg && !terminating) { + + purge_link_and_orig_nodes(NULL, NO); + + dbg_mute(30, DBGL_SYS, DBGT_WARN, + "Using an IP on the loopback interface as primary IP ensures reachability under your primary IP!"); + } else { + purge_link_and_orig_nodes(dev, NO); + } +*/ + purge_link_and_orig_nodes(dev, NO); + + purge_tx_task_list(dev->tx_task_lists, NULL, NULL); + + struct avl_node *an; + struct link_dev_node *lndev; + for (an = NULL; (lndev = avl_iterate_item(&link_dev_tree, &an));) { + purge_tx_task_list(lndev->tx_task_lists, NULL, dev); + } + + + if (dev->unicast_sock != 0) + close(dev->unicast_sock); + + dev->unicast_sock = 0; + + if (dev->rx_mcast_sock != 0) + close(dev->rx_mcast_sock); + + dev->rx_mcast_sock = 0; + + if (dev->rx_fullbrc_sock != 0) + close(dev->rx_fullbrc_sock); + + dev->rx_fullbrc_sock = 0; + } + + + if (!is_ip_set(&dev->llocal_ip_key)) { + dbgf(DBGL_SYS, DBGT_ERR, "no address given to remove in dev_ip_tree!"); + } else if (!avl_find(&dev_ip_tree, &dev->llocal_ip_key)) { + dbgf(DBGL_SYS, DBGT_ERR, "%s not in dev_ip_tree!", ipXAsStr(af_cfg, &dev->llocal_ip_key)); + } else { + assertion(-500842, (dev->link_id)); + //avl_remove(&dev_link_id_tree, &dev->link_id, -300311); + dev->link_id = LINK_ID_INVALID; + + avl_remove(&dev_ip_tree, &dev->llocal_ip_key, -300192); + dev->llocal_ip_key = ZERO_IP; + + if (dev_ip_tree.items == 0) + remove_task(tx_packets, NULL); + + } + + + + sysctl_restore ( dev ); + + change_selects(); + + dbgf_all( DBGT_WARN, "Interface %s deactivated", dev->label_cfg.str ); + + my_description_changed = YES; + +} + + +STATIC_FUNC +void set_sockaddr_storage(struct sockaddr_storage *ss, uint32_t family, IPX_T *ipx) +{ + TRACE_FUNCTION_CALL; + memset(ss, 0, sizeof ( struct sockaddr_storage)); + + ss->ss_family = family; + + if (family == AF_INET) { + struct sockaddr_in *in = (struct sockaddr_in*) ss; + in->sin_port = htons(base_port); + in->sin_addr.s_addr = ipXto4(*ipx); + } else { + struct sockaddr_in6 *in6 = (struct sockaddr_in6*) ss; + in6->sin6_port = htons(base_port); + in6->sin6_addr = *ipx; + } +} + + +STATIC_FUNC +IDM_T dev_init_sockets(struct dev_node *dev) +{ + + TRACE_FUNCTION_CALL; + assertion( -500618, (dev->linklayer != VAL_DEV_LL_LO)); + + int set_on = 1; + int sock_opts; + int pf_domain = af_cfg == AF_INET ? PF_INET : PF_INET6; + + if ((dev->unicast_sock = socket(pf_domain, SOCK_DGRAM, 0)) < 0) { + + dbg(DBGL_SYS, DBGT_ERR, "can't create send socket: %s", strerror(errno)); + return FAILURE; + } + + set_sockaddr_storage(&dev->llocal_unicast_addr, af_cfg, &dev->if_llocal_addr->ip_addr); + + if (af_cfg == AF_INET) { + if (setsockopt(dev->unicast_sock, SOL_SOCKET, SO_BROADCAST, &set_on, sizeof (set_on)) < 0) { + dbg(DBGL_SYS, DBGT_ERR, "can't enable broadcasts on unicast socket: %s", + strerror(errno)); + return FAILURE; + } + } else { + struct ipv6_mreq mreq6; + + mreq6.ipv6mr_multiaddr = dev->if_llocal_addr->ip_mcast; + + mreq6.ipv6mr_interface = dev->if_llocal_addr->iln->index;//0 corresponds to any interface + +/* + if (setsockopt(dev->unicast_sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &set_on, sizeof (set_on)) < 0) { + dbg(DBGL_SYS, DBGT_ERR, "can't set IPV6_MULTICAST_LOOP:: on unicast socket: %s", + strerror(errno)); + return FAILURE; + } +*/ + if (setsockopt(dev->unicast_sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &set_on, sizeof (set_on)) < 0) { + dbg(DBGL_SYS, DBGT_ERR, "can't set IPV6_MULTICAST_HOPS on unicast socket: %s", + strerror(errno)); + return FAILURE; + } + + if (setsockopt(dev->unicast_sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq6, sizeof (mreq6)) < 0) { + dbg(DBGL_SYS, DBGT_ERR, "can't set IPV6_ADD_MEMBERSHIP on unicast socket: %s", + strerror(errno)); + return FAILURE; + } + } + + // bind send socket to interface name + if (dev_bind_sock(dev->unicast_sock, &dev->name_phy_cfg) < 0) + return FAILURE; + + // bind send socket to address + if (bind(dev->unicast_sock, (struct sockaddr *) & dev->llocal_unicast_addr, sizeof (dev->llocal_unicast_addr)) < 0) { + dbg(DBGL_SYS, DBGT_ERR, "can't bind unicast socket: %s", strerror(errno)); + return FAILURE; + } + + // make udp send socket non blocking + sock_opts = fcntl(dev->unicast_sock, F_GETFL, 0); + fcntl(dev->unicast_sock, F_SETFL, sock_opts | O_NONBLOCK); + +#ifdef SO_TIMESTAMP + if (setsockopt(dev->unicast_sock, SOL_SOCKET, SO_TIMESTAMP, &set_on, sizeof(set_on))) + dbg( DBGL_SYS, DBGT_WARN, + "No SO_TIMESTAMP support, despite being defined, falling back to SIOCGSTAMP"); +#else + dbg( DBGL_SYS, DBGT_WARN, "No SO_TIMESTAMP support, falling back to SIOCGSTAMP"); +#endif + + + set_sockaddr_storage(&dev->tx_netwbrc_addr, af_cfg, &dev->if_llocal_addr->ip_mcast); + + + + + // get netwbrc recv socket + if ((dev->rx_mcast_sock = socket(pf_domain, SOCK_DGRAM, 0)) < 0) { + dbg(DBGL_CHANGES, DBGT_ERR, "can't create network-broadcast socket: %s", strerror(errno)); + return FAILURE; + } + + // bind recv socket to interface name + if (dev_bind_sock(dev->rx_mcast_sock, &dev->name_phy_cfg) < 0) + return FAILURE; + + + struct sockaddr_storage rx_netwbrc_addr; + + if (af_cfg == AF_INET && ipXto4(dev->if_llocal_addr->ip_mcast) == 0xFFFFFFFF) { + // if the mcast address is the full-broadcast address + // we'll listen on the network-broadcast address : + IPX_T brc; + ip42X(&brc, ipXto4(dev->if_llocal_addr->ip_addr) | htonl(~(0XFFFFFFFF << dev->if_llocal_addr->ifa.ifa_prefixlen))); + set_sockaddr_storage(&rx_netwbrc_addr, af_cfg, &brc); + } else { + set_sockaddr_storage(&rx_netwbrc_addr, af_cfg, &dev->if_llocal_addr->ip_mcast); + } + + + if (bind(dev->rx_mcast_sock, (struct sockaddr *) & rx_netwbrc_addr, sizeof (rx_netwbrc_addr)) < 0) { + char ip6[IP6_ADDR_LEN]; + + if (af_cfg == AF_INET) + inet_ntop(af_cfg, &((struct sockaddr_in*) (&rx_netwbrc_addr))->sin_addr, ip6, sizeof (ip6)); + else + inet_ntop(af_cfg, &((struct sockaddr_in6*) (&rx_netwbrc_addr))->sin6_addr, ip6, sizeof (ip6)); + + dbg(DBGL_CHANGES, DBGT_ERR, "can't bind network-broadcast socket to %s: %s", + ip6, strerror(errno)); + return FAILURE; + } + + if (af_cfg == AF_INET) { + // we'll always listen on the full-broadcast address + struct sockaddr_storage rx_fullbrc_addr; + IPX_T brc; + ip42X(&brc, 0XFFFFFFFF); + set_sockaddr_storage(&rx_fullbrc_addr, af_cfg, &brc); + + // get fullbrc recv socket + if ((dev->rx_fullbrc_sock = socket(pf_domain, SOCK_DGRAM, 0)) < 0) { + dbg(DBGL_CHANGES, DBGT_ERR, "can't create full-broadcast socket: %s", + strerror(errno)); + return FAILURE; + } + + // bind recv socket to interface name + if (dev_bind_sock(dev->rx_fullbrc_sock, &dev->name_phy_cfg) < 0) + return FAILURE; + + + // bind recv socket to address + if (bind(dev->rx_fullbrc_sock, (struct sockaddr *) & rx_fullbrc_addr, sizeof (rx_fullbrc_addr)) < 0) { + dbg(DBGL_CHANGES, DBGT_ERR, "can't bind full-broadcast socket: %s", strerror(errno)); + return FAILURE; + } + + } + + return SUCCESS; +} + + +STATIC_FUNC +void dev_activate( struct dev_node *dev ) +{ + TRACE_FUNCTION_CALL; + + assertion(-500575, (dev && !dev->active && dev->if_llocal_addr && dev->if_llocal_addr->iln->flags & IFF_UP)); + assertion(-500593, (af_cfg == dev->if_llocal_addr->ifa.ifa_family)); + assertion(-500599, (is_ip_set(&dev->if_llocal_addr->ip_addr) && dev->if_llocal_addr->ifa.ifa_prefixlen)); + + + if ( wordsEqual( "lo", dev->name_phy_cfg.str ) ) { + + dev->linklayer = VAL_DEV_LL_LO; + + if (!dev->if_global_addr) { + dbg_mute(30, DBGL_SYS, DBGT_WARN, "loopback dev %s should be given with global address", + dev->label_cfg.str); + + cleanup_all(-500621); + } + + uint8_t prefixlen = ((af_cfg == AF_INET) ? IP4_MAX_PREFIXLEN : IP6_MAX_PREFIXLEN); + + if (!dev->if_global_addr || dev->if_global_addr->ifa.ifa_prefixlen != prefixlen) { + dbg_mute(30, DBGL_SYS, DBGT_WARN, + "prefix length of loopback interface is %d but SHOULD BE %d and global", + dev->if_global_addr->ifa.ifa_prefixlen, prefixlen); + } + + + } else { + + if (dev->linklayer_conf != OPT_CHILD_UNDEFINED) { + + dev->linklayer = dev->linklayer_conf; + + } else /* check if interface is a wireless interface */ { + + struct ifreq int_req; + + if (get_if_req(&dev->name_phy_cfg, &int_req, SIOCGIWNAME) == SUCCESS) + dev->linklayer = VAL_DEV_LL_WLAN; + + else + dev->linklayer = VAL_DEV_LL_LAN; + + } + } + + + + if (dev->linklayer != VAL_DEV_LL_LO) { + + if (dev_init_sockets(dev) == FAILURE) + goto error; + + sysctl_config(dev); + + // from here on, nothing should fail anymore !!: + + dev->mac = *((MAC_T*)&(dev->if_llocal_addr->iln->addr)); + + } + + + if (new_link_id(dev) == LINK_ID_INVALID) + goto error; + + assertion(-500592, (!avl_find(&dev_ip_tree, &dev->if_llocal_addr->ip_addr))); + dev->llocal_ip_key = dev->if_llocal_addr->ip_addr; + avl_insert(&dev_ip_tree, dev, -300151); + + + ip2Str(af_cfg, &dev->if_llocal_addr->ip_addr, dev->ip_llocal_str); + + if ( dev->if_global_addr) + ip2Str(af_cfg, &dev->if_global_addr->ip_addr, dev->ip_global_str); + + ip2Str(af_cfg, &dev->if_llocal_addr->ip_mcast, dev->ip_brc_str); + + if (dev == primary_dev_cfg) { + self.primary_ip = dev->if_global_addr->ip_addr; + ip2Str(af_cfg, &dev->if_global_addr->ip_addr, self.primary_ip_str); + } + + dev->active = YES; + + assertion(-500595, (primary_dev_cfg)); + + if (!(dev->link_hello_sqn )) { + dev->link_hello_sqn = ((HELLO_SQN_MASK) & rand_num(HELLO_SQN_MAX)); + } + + int i; + for (i = 0; i < FRAME_TYPE_ARRSZ; i++) { + LIST_INIT_HEAD(dev->tx_task_lists[i], struct tx_task_node, list); + } + + AVL_INIT_TREE(dev->tx_task_tree, struct tx_task_node, content); + + if (dev_ip_tree.items == 1) + register_task(rand_num(bmx_time ? 0 : DEF_TX_DELAY), tx_packets, NULL); + + + + + dev->soft_conf_changed = YES; + + //activate selector for active interfaces + change_selects(); + + //trigger plugins interested in changed interface configuration + cb_plugin_hooks(PLUGIN_CB_DEV_EVENT, dev); + cb_plugin_hooks(PLUGIN_CB_CONF, NULL); + + return; + +error: + dbgf(DBGL_SYS, DBGT_ERR, "error intitializing %s=%s", dev->arg_cfg, dev->label_cfg.str); + + ip2Str(af_cfg, &ZERO_IP, dev->ip_llocal_str); + ip2Str(af_cfg, &ZERO_IP, dev->ip_brc_str); + + dev_deactivate(dev); +} + + +STATIC_FUNC +void ip_flush_routes( void ) +{ + TRACE_FUNCTION_CALL; + uint16_t table; + + if (primary_dev_cfg) { + + for (table = Rt_table; table <= Rt_table + RT_TABLE_MAX_OFFS; table++) { + + ip(af_cfg, IP_ROUTE_FLUSH_ALL, DEL, YES/*quiet*/, &ZERO_IP, 0, table, + 0, NULL, 0, NULL, NULL); + } + } +} + +STATIC_FUNC +void ip_flush_rules(void) +{ + TRACE_FUNCTION_CALL; + uint16_t table; + + if (!af_cfg) + return; + + + for (table = Rt_table; table <= Rt_table + RT_TABLE_MAX_OFFS; table++) { + + while (ip(af_cfg, IP_RULE_FLUSH, DEL, YES, &ZERO_IP, 0, table, 0, NULL, 0, NULL, NULL) == SUCCESS) { + + dbgf(DBGL_SYS, DBGT_ERR, "removed orphan %s rule to table %d", family2Str(af_cfg), table); + + } + } +} + + + +STATIC_FUNC +void ip_flush_tracked( uint8_t cmd ) +{ + TRACE_FUNCTION_CALL; + struct avl_node *an; + struct track_node *tn; + + for (an = NULL; (tn = avl_iterate_item(&iptrack_tree, &an));) { + + if (!(cmd == tn->cmd || + (cmd == IP_ROUTE_FLUSH && tn->k.cmd_type == IP_ROUTES) || + (cmd == IP_RULE_FLUSH && tn->k.cmd_type == IP_RULES))) + continue; + + ip(tn->k.family, tn->cmd, DEL, NO, &tn->k.net, tn->k.mask, tn->k.table, tn->k.prio, &tn->k.iif, 0, NULL, NULL); + + an = NULL; + } +} + + + +STATIC_FUNC +int update_interface_rules(void) +{ + TRACE_FUNCTION_CALL; + + ip_flush_tracked(IP_THROW_MY_HNA); + ip_flush_tracked(IP_THROW_MY_NET); + + struct avl_node *lan = NULL; + struct if_link_node *iln; + + while (throw_rules && (iln = avl_iterate_item(&if_link_tree, &lan))) { + + if (!((iln->flags & IFF_UP))) + continue; + + struct avl_node *aan; + struct if_addr_node *ian; + + for (aan = NULL; (ian = avl_iterate_item(&iln->if_addr_tree, &aan));) { + + assertion(-500609, is_ip_set(&ian->ip_addr)); + + if (ian->ifa.ifa_family != af_cfg) + continue; + + if (!ian->ifa.ifa_prefixlen) + continue; + + if (is_ip_net_equal(&ian->ip_addr, &IP6_LINKLOCAL_UC_PREF, IP6_LINKLOCAL_UC_PLEN, AF_INET6)) + continue; + + struct avl_node *dan; + struct dev_node *dev = NULL; + + for (dan = NULL; (dev = avl_iterate_item(&dev_ip_tree, &dan));) { + + if (af_cfg != ian->ifa.ifa_family || !dev->if_global_addr) + continue; + + if (is_ip_net_equal(&ian->ip_addr, &dev->if_global_addr->ip_addr, ian->ifa.ifa_prefixlen, + af_cfg)) + break; + + } + + if (dev) + continue; + + IPX_T throw_net = ian->ip_addr; + ip_netmask_validate(&throw_net, ian->ifa.ifa_prefixlen, af_cfg, YES); + + ip(af_cfg, IP_THROW_MY_NET, ADD, NO, &throw_net, ian->ifa.ifa_prefixlen, + RT_TABLE_NETS, 0, NULL, 0, NULL, NULL); + + } + } + +#ifdef ADJ_PATCHED_NETW + struct list_node *throw_pos; + struct throw_node *throw_node; + + list_for_each(throw_pos, &throw4_list) { + + throw_node = list_entry(throw_pos, struct throw_node, list); + + IPX_T throw6; + ip42X(&throw6, throw_node->addr); + + configure_route(&throw6, AF_INET, throw_node->netmask, 0, 0, 0, 0, RT_TABLE_HOSTS, RTN_THROW, ADD, IP_THROW_MY_NET); + configure_route(&throw6, AF_INET, throw_node->netmask, 0, 0, 0, 0, RT_TABLE_NETS, RTN_THROW, ADD, IP_THROW_MY_NET); + configure_route(&throw6, AF_INET, throw_node->netmask, 0, 0, 0, 0, RT_TABLE_TUNS, RTN_THROW, ADD, IP_THROW_MY_NET); + + } +#endif + return SUCCESS; +} + + + +STATIC_INLINE_FUNC +void dev_if_fix(void) +{ + TRACE_FUNCTION_CALL; + struct if_link_node *iln = avl_first_item(&if_link_tree); + struct avl_node *lan; + struct dev_node *dev; + struct avl_node *dan; + + for (dan = NULL; (dev = avl_iterate_item(&dev_name_tree, &dan));) { + if (dev->hard_conf_changed) { + dev->if_link = NULL; + if (dev->if_llocal_addr) { + dev->if_llocal_addr->dev = NULL; + dev->if_llocal_addr = NULL; + } + if (dev->if_global_addr) { + dev->if_global_addr->dev = NULL; + dev->if_global_addr = NULL; + } + } + } + + + for (lan = NULL; (iln = avl_iterate_item(&if_link_tree, &lan));) { + + struct dev_node *dev = dev_get_by_name(iln->name.str); + + if (dev && dev->hard_conf_changed && (iln->flags & IFF_UP)) + dev->if_link = iln; + } + + + for (dan = NULL; (dev = avl_iterate_item(&dev_name_tree, &dan));) { + + if (!(dev->hard_conf_changed && dev->if_link && (dev->if_link->flags & IFF_UP))) + continue; + + assertion( -500620, (!dev->if_llocal_addr && !dev->if_global_addr )); + + struct if_addr_node *ian; + struct avl_node *aan; + + for (aan = NULL; (ian = avl_iterate_item(&dev->if_link->if_addr_tree, &aan));) { + + IDM_T discarded_llocal_addr = NO; + IDM_T discarded_global_addr = NO; + + if (af_cfg != ian->ifa.ifa_family || strcmp(dev->label_cfg.str, ian->label.str)) + continue; + + dbgf(DBGL_SYS, DBGT_INFO, "testing %s=%s %s", + dev->arg_cfg, ian->label.str, ipXAsStr(af_cfg, &ian->ip_addr)); + + if (af_cfg == AF_INET6 && is_ip_net_equal(&ian->ip_addr, &IP6_MC_PREF, IP6_MC_PLEN, AF_INET6)) { + + dbgf(DBGL_SYS, DBGT_INFO, "skipping multicast"); + continue; + } + + IDM_T ip6llocal = is_ip_net_equal(&ian->ip_addr, &IP6_LINKLOCAL_UC_PREF, IP6_LINKLOCAL_UC_PLEN, AF_INET6); + + if (af_cfg == AF_INET || ip6llocal) { + + if (cfg_llocal_bmx_prefix_len ? + is_ip_net_equal(&cfg_llocal_bmx_prefix, &ian->ip_addr, cfg_llocal_bmx_prefix_len, af_cfg) : + !dev->if_llocal_addr) { + + dev->if_llocal_addr = ian; + + } else if (af_cfg == AF_INET || ip6llocal) { + + discarded_llocal_addr = YES; + } + } + + if ((af_cfg == AF_INET || !ip6llocal) && + (dev == primary_dev_cfg || dev->announce)) { + + if (cfg_global_bmx_prefix_len ? + is_ip_net_equal(&cfg_global_bmx_prefix, &ian->ip_addr, cfg_global_bmx_prefix_len, af_cfg) : + !dev->if_global_addr ) { + + dev->if_global_addr = ian; + + } else if (af_cfg == AF_INET || !ip6llocal) { + + discarded_global_addr = YES; + } + } + + if (discarded_llocal_addr) { + dbg_mute(40, DBGL_SYS, DBGT_WARN, + "ambiguous link-local IP %s for dev %s (selected %s)! Use --%s=... to refine", + ipXAsStr(af_cfg, &ian->ip_addr), ian->label.str, + ipXAsStr(af_cfg, &dev->if_llocal_addr->ip_addr), ARG_LLOCAL_PREFIX); + } + + if (discarded_global_addr) { + dbg_mute(40, DBGL_SYS, DBGT_WARN, + "ambiguous global IP %s for dev %s (selected %s)! Use --%s=... to refine", + ipXAsStr(af_cfg, &ian->ip_addr), ian->label.str, + ipXAsStr(af_cfg, &dev->if_global_addr->ip_addr), ARG_GLOBAL_PREFIX); + } + } + + if (wordsEqual("lo", dev->name_phy_cfg.str)) { + // the loopback interface usually does not need a link-local address, BUT BMX needs one + // And it MUST have a global one. + if (!dev->if_global_addr) + dev->if_llocal_addr = NULL; + else if (!dev->if_llocal_addr) + dev->if_llocal_addr = dev->if_global_addr; + } + + if (dev->if_llocal_addr) { + dev->if_llocal_addr->dev = dev; + } else { + dbg_mute(30, DBGL_SYS, DBGT_ERR, + "No link-local IP found for %sprimary --%s=%s !", + dev == primary_dev_cfg ? "" : "non-", dev->arg_cfg, dev->label_cfg.str); + } + + if (dev->if_global_addr && dev->if_llocal_addr) { + + dev->if_global_addr->dev = dev; + + } else if (dev->if_global_addr && !dev->if_llocal_addr) { + + dev->if_global_addr = NULL; + + } else { + if (dev == primary_dev_cfg || dev->announce) { + + dbg_mute(30, DBGL_SYS, DBGT_ERR, + "No global IP found for %sprimary --%s=%s ! DEACTIVATING !!!", + dev == primary_dev_cfg ? "" : "non-", dev->arg_cfg, dev->label_cfg.str); + + if (dev->if_llocal_addr) { + dev->if_llocal_addr->dev = NULL; + dev->if_llocal_addr = NULL; + } + } + } + } +} + +void dev_check(IDM_T kernel_ip_config_changed) +{ + TRACE_FUNCTION_CALL; + + struct avl_node *an; + struct dev_node *dev; + + uint8_t cb_conf_hooks = NO; + + dbgf_all( DBGT_INFO, " " ); + + if ( !dev_name_tree.items ) { + dbg( DBGL_SYS, DBGT_ERR, "No interfaces specified"); + cleanup_all( CLEANUP_FAILURE ); + } + + // fix all dev->.._ian stuff here: + dev_if_fix(); + + for (an = NULL; (dev = avl_iterate_item(&dev_name_tree, &an));) { + + if (dev->hard_conf_changed) { + + if (dev->active) { + dbg(DBGL_SYS, DBGT_WARN, + "detected changed but used %sprimary interface: %s ! Deactivating now...", + (dev == primary_dev_cfg ? "" : "non-"), dev->label_cfg.str); + + cb_conf_hooks = YES; + dev_deactivate(dev); + } + + } + + IDM_T iff_up = dev->if_llocal_addr && (dev->if_llocal_addr->iln->flags & IFF_UP); + + assertion(-500895, (!(dev->active && !iff_up) == IMPLIES(dev->active, iff_up))); + assertion(-500896, (IMPLIES(dev->active, iff_up))); + assertion(-500897, (!(dev->active && !iff_up))); + + assertion(-500898, (!(dev->active && iff_up && dev->hard_conf_changed) == IMPLIES(dev->active, (!iff_up || !dev->hard_conf_changed)))); + assertion(-500901, (IMPLIES(dev->active, (!dev->hard_conf_changed)))); + assertion(-500899, (IMPLIES(dev->active ,(!iff_up || !dev->hard_conf_changed)))); + assertion(-500900, (!(dev->active && iff_up && dev->hard_conf_changed))); + + assertion(-500598, (!(dev->active && !iff_up) && !(dev->active && iff_up && dev->hard_conf_changed))); + + if (!dev->active && iff_up && dev->hard_conf_changed) { + + struct dev_node *tmp_dev = avl_find_item(&dev_ip_tree, &dev->if_llocal_addr->ip_addr); + + if (tmp_dev && !wordsEqual(tmp_dev->name_phy_cfg.str, dev->name_phy_cfg.str)) { + + dbg_mute(40, DBGL_SYS, DBGT_ERR, "%s=%s IP %-15s already used for IF %s", + dev->arg_cfg, dev->label_cfg.str, dev->ip_llocal_str, tmp_dev->label_cfg.str); + + } else if (dev->announce && !dev->if_global_addr) { + + dbg(DBGL_SYS, DBGT_ERR, + "%s=%s %s but no global addr", dev->arg_cfg, dev->label_cfg.str, "to-be announced"); + + } else if (dev == primary_dev_cfg && !dev->if_global_addr) { + + dbg(DBGL_SYS, DBGT_ERR, + "%s=%s %s but no global addr", dev->arg_cfg, dev->label_cfg.str, "primary dev"); + + } else if (wordsEqual("lo", dev->name_phy_cfg.str) && !dev->if_global_addr) { + + dbg(DBGL_SYS, DBGT_ERR, + "%s=%s %s but no global addr", dev->arg_cfg, dev->label_cfg.str, "loopback"); + + } else { + + if ( !initializing ) + dbg_mute( 50, DBGL_SYS, DBGT_INFO, + "detected valid but disabled dev: %s ! Activating now...", dev->label_cfg.str); + + dev_activate(dev); + } + } + + dev->hard_conf_changed = NO; + + if (dev->active && (dev->soft_conf_changed || dev_soft_conf_changed)) { + + dev_reconfigure_soft( dev ); + } + + + if ( initializing && !dev->active ) { + + if (dev == primary_dev_cfg) { + dbg( DBGL_SYS, DBGT_ERR, + "at least primary %s=%s MUST be operational at startup! " + "Use loopback (e.g. lo:bmx a.b.c.d/32 ) if nothing else is available!", + dev->arg_cfg, dev->label_cfg.str); + + cleanup_all( CLEANUP_FAILURE ); + } + + dbg( DBGL_SYS, DBGT_WARN, + "not using interface %s (retrying later): interface not ready", dev->label_cfg.str); + + } + } + + dev_soft_conf_changed = NO; + + + + if ( cb_conf_hooks) + cb_plugin_hooks(PLUGIN_CB_CONF, NULL); + + if (kernel_ip_config_changed) + update_interface_rules(); + +} + + + + +STATIC_FUNC +int32_t opt_policy_rt(uint8_t cmd, uint8_t _save, struct opt_type *opt, struct opt_parent *patch, struct ctrl_node *cn) +{ + TRACE_FUNCTION_CALL; + + if ( cmd == OPT_APPLY ) { + + check_apply_parent_option( ADD, OPT_APPLY, _save, get_option( 0, 0, ARG_PRIO_RULES ), "0", cn ); + check_apply_parent_option( ADD, OPT_APPLY, _save, get_option( 0, 0, ARG_THROW_RULES ), "0", cn ); + + } else if ( cmd == OPT_SET_POST && initializing ) { + + + } else if ( cmd == OPT_POST && initializing ) { + + dbgf(DBGL_CHANGES, DBGT_INFO, "OPT_POST start"); + + // add rule for hosts and announced interfaces and networks + if ( prio_rules && primary_dev_cfg) { + + ip_flush_routes(); + ip_flush_rules(); + +/* + ip_flush_tracked(IP_ROUTE_FLUSH); + ip_flush_tracked(IP_RULE_FLUSH); +*/ + + ip(af_cfg, IP_RULE_DEFAULT, ADD, NO, &ZERO_IP, 0, + RT_TABLE_HOSTS, RT_PRIO_HOSTS, NULL, 0, NULL, NULL); + + ip(af_cfg, IP_RULE_DEFAULT, ADD, NO, &ZERO_IP, 0, + RT_TABLE_NETS, RT_PRIO_NETS, NULL, 0, NULL, NULL); + + } + + /* + // add rules and routes for interfaces + if (update_interface_rules(IF_RULE_UPD_ALL//was IF_RULE_SET_NETWORKS + ) < 0) + cleanup_all( CLEANUP_FAILURE ); + */ + dbgf(DBGL_CHANGES, DBGT_INFO, "OPT_POST done"); + + } + + return SUCCESS; +} + + +#ifdef ADJ_PATCHED_NETW + +STATIC_FUNC +int32_t opt_throw(uint8_t cmd, uint8_t _save, struct opt_type *opt, struct opt_parent *patch, struct ctrl_node *cn) +{ + + IPX_T ipX; + uint8_t maskx; + uint8_t family; + + char tmp[IPXNET_STR_LEN]; + struct throw_node *throw_node = NULL; + struct list_node *throw_tmp, *throw_pos; + + if ( cmd == OPT_ADJUST || cmd == OPT_CHECK || cmd == OPT_APPLY ) { + + if ( strchr(patch->p_val, '/')//patch->p_val[0] >= '0' && patch->p_val[0] <= '9' + ) { + // configure an unnamed throw-rule + + if (str2netw(patch->p_val, &ipX, '/', cn, &maskx, &family) == FAILURE) + return FAILURE; + + if (ip_netmask_validate(&ipX, maskx, family) == FAILURE) { + dbg_cn(cn, DBGL_SYS, DBGT_ERR, "invalid prefix"); + return FAILURE; + } + + + sprintf(tmp, "%s/%d", ipXAsStr(family, &ipX), maskx); + set_opt_parent_val(patch, tmp); + + } else { + // configure a named throw-rule + + // just for adjust and check + if ( adj_patched_network( opt, patch, tmp, &ip, &mask, cn ) == FAILURE ) + return FAILURE; + + if ( patch->p_diff == ADD ) { + if ( adj_patched_network( opt, patch, tmp, &ip, &mask, cn ) == FAILURE ) + return FAILURE; + } else { + // re-configure network and netmask parameters of an already configured and named throw-rule + if (get_tracked_network(opt, patch, tmp, &ip, &mask, cn) == FAILURE) + return FAILURE; + } + } + + struct list_node *prev_pos = (struct list_node *) & throw4_list; + list_for_each_safe( throw_pos, throw_tmp, &throw4_list ) { + throw_node = list_entry(throw_pos, struct throw_node, list); + if ( throw_node->addr == ip && throw_node->netmask == mask ) + break; + prev_pos = &throw_node->list; + throw_node = NULL; + } + + if ( cmd == OPT_ADJUST ) + return SUCCESS; + + if ( ( patch->p_diff != ADD && !throw_node ) || ( patch->p_diff == ADD && throw_node ) ) { + dbg_cn( cn, DBGL_SYS, DBGT_ERR, "%s %s does %s exist!", + ARG_THROW, tmp, patch->p_diff == ADD ? "already" : "not" ); + return FAILURE; + } + + if ( cmd == OPT_CHECK ) + return SUCCESS; + + if ( patch->p_diff == DEL || patch->p_diff == NOP ) { + list_del_next( &throw4_list, prev_pos ); + debugFree( throw_pos, -300077 ); + } + + if ( patch->p_diff == NOP ) { + // get new network again + if ( adj_patched_network( opt, patch, tmp, &ip, &mask, cn ) == FAILURE ) + return FAILURE; + } + + if ( patch->p_diff == ADD || patch->p_diff == NOP ) { + + throw_node = debugMalloc( sizeof(struct throw_node), -300033 ); + memset( throw_node, 0, sizeof(struct throw_node) ); + list_add_tail( &throw4_list, &throw_node->list ); + + throw_node->addr = ip; + throw_node->netmask = mask; + } + + +/* + if ( on_the_fly ) { + // add rules and routes for interfaces : + if ( update_interface_rules( IF_RULE_UPD_ALL ) < 0 ) + cleanup_all( CLEANUP_FAILURE ); + } +*/ + + return SUCCESS; + + + } else if ( cmd == OPT_UNREGISTER ) { + + while ((throw_node = list_rem_head(&throw4_list))) + debugFree(throw_node, -300078); + + } + return SUCCESS; +} +#endif + + + +STATIC_FUNC +int32_t opt_interfaces(uint8_t cmd, uint8_t _save, struct opt_type *opt, struct opt_parent *patch, struct ctrl_node *cn) +{ + TRACE_FUNCTION_CALL; + + if ( cmd == OPT_APPLY ) { + +#define DBG_STATUS4_DEV_HEAD "%-10s %6s %9s %10s %2s %16s %2s %16s %16s %8s %1s\n" +#define DBG_STATUS6_DEV_HEAD "%-10s %6s %9s %10s %3s %30s %3s %30s %30s %8s %1s\n" +#define DBG_STATUS4_DEV_INFO "%-10s %6s %9s %10ju %16s/%-2d %16s/%-2d %16s %8d %1s\n" +#define DBG_STATUS6_DEV_INFO "%-10s %6s %9s %10ju %30s/%-3d %30s/%-3d %30s %8d %1s\n" + + dbg_printf(cn, (af_cfg == AF_INET ? DBG_STATUS4_DEV_HEAD : DBG_STATUS6_DEV_HEAD), + "dev", "status", "type", "maxMetric", " ", "llocal", " ", "global", "broadcast", "helloSqn", "#"); + + struct avl_node *it=NULL; + struct dev_node *dev; + while ((dev = avl_iterate_item(&dev_name_tree, &it))) { + + IDM_T iff_up = dev->if_llocal_addr && (dev->if_llocal_addr->iln->flags & IFF_UP); + + dbg_printf(cn, (af_cfg == AF_INET ? DBG_STATUS4_DEV_INFO : DBG_STATUS6_DEV_INFO), + dev->label_cfg.str, + iff_up ? "UP":"DOWN", + !dev->active ? "INACTIVE" : + ( dev->linklayer == VAL_DEV_LL_LO ? "loopback": + ( dev->linklayer == VAL_DEV_LL_LAN ? "ethernet": + ( dev->linklayer == VAL_DEV_LL_WLAN ? "wireless": "???" ) ) ), + dev->umetric_max, + dev->ip_llocal_str, + dev->if_llocal_addr ? dev->if_llocal_addr->ifa.ifa_prefixlen : -1, + dev->ip_global_str, + dev->if_global_addr ? dev->if_global_addr->ifa.ifa_prefixlen : -1, + dev->ip_brc_str, + dev->link_hello_sqn, + dev == primary_dev_cfg ? "P" : "N" + ); + } + dbg_printf(cn, "\n"); + } + return SUCCESS; +} + + +STATIC_FUNC +int32_t opt_dev(uint8_t cmd, uint8_t _save, struct opt_type *opt, struct opt_parent *patch, struct ctrl_node *cn) +{ + TRACE_FUNCTION_CALL; + + struct list_node *list_pos; + struct dev_node *dev = NULL; + + uint8_t family = 0; + + if (!strcmp(opt->long_name, ARG_DEV6)) + family = AF_INET6; + else if (!strcmp(opt->long_name, ARG_DEV)) + family = AF_INET; + + + if ( cmd == OPT_CHECK || cmd == OPT_APPLY ) { + + if (!family) + return FAILURE; + + if (af_cfg && af_cfg != family) { + + dbg_cn(cn, DBGL_SYS, DBGT_ERR, "only one ip protocol is supported at a time"); + return FAILURE; + } + + if ( strlen(patch->p_val) >= IFNAMSIZ ) { + dbg_cn( cn, DBGL_SYS, DBGT_ERR, "dev name MUST be smaller than %d chars", IFNAMSIZ ); + return FAILURE; + } + + char *colon_ptr; + char phy_name[IFNAMSIZ] = {0}; + strcpy(phy_name, patch->p_val); + + // if given interface is an alias then truncate to physical interface name: + if ((colon_ptr = strchr(phy_name, ':')) != NULL) + *colon_ptr = '\0'; + + + dev = dev_get_by_name(phy_name); + + if ( dev && strcmp(dev->label_cfg.str, patch->p_val)) { + dbg_cn(cn, DBGL_SYS, DBGT_ERR, + "%s=%s (%s) already used for %s=%s %s!", + opt->long_name, patch->p_val, phy_name, opt->long_name, dev->label_cfg.str, dev->ip_llocal_str); + + return FAILURE; + } + + if ( patch->p_diff == DEL ) { + + if (dev && dev == primary_dev_cfg) { + + dbg_cn(cn, DBGL_SYS, DBGT_ERR, + "primary interface %s %s can not be removed!", + dev->label_cfg.str, dev->ip_llocal_str); + + return FAILURE; + + } else if (dev && cmd == OPT_APPLY) { + + if (dev->active) + dev_deactivate(dev); + + + + avl_remove(&dev_name_tree, &dev->name_phy_cfg, -300205); + + uint16_t i; + for (i = 0; i < plugin_data_registries[PLUGIN_DATA_DEV]; i++) { + assertion(-500767, (!dev->plugin_data[i])); + } + + debugFree(dev, -300048); + + return SUCCESS; + + + } else if (!dev) { + + dbgf_cn(cn, DBGL_SYS, DBGT_ERR, "Interface does not exist!"); + return FAILURE; + } + } + + if ( cmd == OPT_CHECK ) + return SUCCESS; + + if ( !dev ) { + + dbgf(DBGL_CHANGES, DBGT_INFO, "cmd: %s opt: %s %s instance %s", + opt_cmd2str[cmd], opt->long_name, family2Str(family), patch ? patch->p_val : ""); + + uint32_t dev_size = sizeof (struct dev_node) + (sizeof (void*) * plugin_data_registries[PLUGIN_DATA_DEV]); + dev = debugMalloc(dev_size, -300002); + memset(dev, 0, dev_size); + + if (!primary_dev_cfg) { + primary_dev_cfg = dev; + + af_cfg = family; + //self.family = primary_dev_cfg->family_cfg; + //self.bmx_afinet = (self.family == AF_INET) ? BMX_AFINET4 : BMX_AFINET6; + } + + strcpy(dev->label_cfg.str, patch->p_val); + strcpy(dev->name_phy_cfg.str, phy_name); + + avl_insert(&dev_name_tree, dev, -300144); + + dev->hard_conf_changed = YES; + + dev->arg_cfg = (char*)opt->long_name; + + + if (dev == primary_dev_cfg) + dev->announce = YES; + else + dev->announce = DEF_DEV_ANNOUNCE; + + dev->umetric_max = DEF_DEV_BANDWIDTH; + + /* + * specifying the outgoing src address for IPv6 seems not working + * http://www.ureader.de/msg/12621915.aspx + * http://www.davidc.net/networking/ipv6-source-address-selection-linux + * http://etherealmind.com/ipv6-which-address-multiple-ipv6-address-default-add... + * http://marc.info/?l=linux-net&m=127811438206347&w=2 + */ + + + dbgf_all(DBGT_INFO, "assigned dev %s physical name %s", + dev->label_cfg.str, dev->name_phy_cfg.str); + + // some configurable interface values - initialized to unspecified: + + dev->linklayer_conf = OPT_CHILD_UNDEFINED; + dev->umetric_max_conf = OPT_CHILD_UNDEFINED; + + } + + + list_for_each( list_pos, &patch->childs_instance_list ) { + + struct opt_child *c = list_entry( list_pos, struct opt_child, list ); + + int32_t val = c->c_val ? strtol(c->c_val, NULL, 10) : OPT_CHILD_UNDEFINED; + + if (!strcmp(c->c_opt->long_name, ARG_DEV_IP)) { + + dev->hard_conf_changed = YES; + + } else if ( !strcmp( c->c_opt->long_name, ARG_DEV_LL ) ) { + + dev->linklayer_conf = val; + dev->hard_conf_changed = YES; + + } else if ( !strcmp( c->c_opt->long_name, ARG_DEV_BANDWIDTH ) ) { + + if (c->c_val) { + unsigned long long ull = strtoul(c->c_val, NULL, 10); + + if (ull > (umetric_max(DEF_FMETRIC_EXP_OFFSET)) || + ull < (umetric(0, 0, DEF_FMETRIC_EXP_OFFSET))) { + + dbgf(DBGL_SYS, DBGT_ERR, "%s %c%s given with illegal value", + dev->label_cfg.str, LONG_OPT_ARG_DELIMITER_CHAR, c->c_opt->long_name); + + return FAILURE; + } + + dev->umetric_max_configured = ull; + dev->umetric_max_conf = 0; + + } else { + dev->umetric_max_configured = 0; + dev->umetric_max_conf = OPT_CHILD_UNDEFINED; + } + +// dev->hard_conf_changed = YES; + + } else if ( !strcmp( c->c_opt->long_name, ARG_DEV_ANNOUNCE ) ) { + + dev->announce = val; + dev->hard_conf_changed = YES; + } + + dev->soft_conf_changed = YES; + + } + + + } else if ( cmd == OPT_POST && opt && !opt->parent_name ) { + + + dev_check(initializing ? kernel_if_config() : NO); //will always be called whenever a parameter is changed (due to OPT_POST) + + } + + return SUCCESS; +} + + + +static struct opt_type ip_options[]= +{ +// ord parent long_name shrt Attributes *ival min max default *func,*syntax,*help + {ODI,0,0, 0, 0,0,0,0,0,0, 0, 0, 0, 0, 0, + 0, "\nip options:"} + , + {ODI,0,ARG_DEV, 'i', 5,A_PMN,A_ADM,A_DYI,A_CFA,A_ANY, 0, 0, 0, 0, opt_dev, + "<interface-name>", "add or change IPv4 device or its configuration"} + , + {ODI,ARG_DEV,ARG_DEV_TTL, 't',5,A_CS1,A_ADM,A_DYI,A_CFA,A_ANY, 0, MIN_TTL, MAX_TTL, DEF_TTL, opt_dev, + ARG_VALUE_FORM, "set TTL of generated OGMs"} + , + {ODI,ARG_DEV,ARG_DEV_ANNOUNCE, 'a',5,A_CS1,A_ADM,A_DYI,A_CFA,A_ANY, 0, 0, 1, DEF_DEV_ANNOUNCE,opt_dev, + ARG_VALUE_FORM, "disable/enable announcement of interface IP"} + , + {ODI,ARG_DEV,ARG_DEV_LL, 'l',5,A_CS1,A_ADM,A_DYI,A_CFA,A_ANY, 0, VAL_DEV_LL_LAN, VAL_DEV_LL_WLAN,0, opt_dev, + ARG_VALUE_FORM, "manually set device type for linklayer specific optimization (1=lan, 2=wlan)"} + , + {ODI,ARG_DEV,ARG_DEV_BANDWIDTH, 'b',5,A_CS1,A_ADM,A_DYI,A_CFA,A_ANY, 0, 0, 0, 0, opt_dev, + ARG_VALUE_FORM, "set maximum bandwitdh as bits/sec of dev"} + + , + {ODI,0,ARG_DEV6, 0, 5,A_PMN,A_ADM,A_DYI,A_CFA,A_ANY, 0, 0, 0, 0, opt_dev, + "<interface-name>", "add or change IPv6 device or its configuration"} + , + {ODI,ARG_DEV6,ARG_DEV_ANNOUNCE, 'a',5,A_CS1,A_ADM,A_DYI,A_CFA,A_ANY, 0, 0, 1, DEF_DEV_ANNOUNCE,opt_dev, + ARG_VALUE_FORM, "disable/enable announcement of interface IP"} + , + {ODI,ARG_DEV6,ARG_DEV_LL, 'l',5,A_CS1,A_ADM,A_DYI,A_CFA,A_ANY, 0, VAL_DEV_LL_LAN, VAL_DEV_LL_WLAN,0, opt_dev, + ARG_VALUE_FORM, "manually set device type for linklayer specific optimization (1=lan, 2=wlan)"} + , + {ODI,ARG_DEV6,ARG_DEV_BANDWIDTH, 'b',5,A_CS1,A_ADM,A_DYI,A_CFA,A_ANY, 0, 0, 0, 0, opt_dev, + ARG_VALUE_FORM, "set maximum bandwitdh as bits/sec of dev"} + + + , + {ODI,0,ARG_INTERFACES, 0, 5,A_PS0,A_USR,A_DYI,A_ARG,A_ANY, 0, 0, 1, 0, opt_interfaces, + 0, "show configured interfaces"} + , +#ifndef LESS_OPTIONS + {ODI,0,ARG_PEDANTIC_CLEANUP, 0, 5,A_PS1,A_ADM,A_DYI,A_CFA,A_ANY, &Pedantic_cleanup,0, 1, DEF_PEDANT_CLNUP,0, + ARG_VALUE_FORM, "disable/enable pedantic cleanup of system configuration (like ip_forward,..) \n" + " at program termination. Its generally safer to keep this disabled to not mess up \n" + " with other routing protocols"} + , + {ODI,0,ARG_THROW_RULES, 0, 4,A_PS1,A_ADM,A_INI,A_CFA,A_ANY, &throw_rules, 0, 1, DEF_THROW_RULES,0, + ARG_VALUE_FORM, "disable/enable default throw rules"}, + + {ODI,0,ARG_PRIO_RULES, 0, 4,A_PS1,A_ADM,A_INI,A_CFA,A_ANY, &prio_rules, 0, 1, DEF_PRIO_RULES, 0, + ARG_VALUE_FORM, "disable/enable default priority rules"} + , +#endif + {ODI,0,ARG_NO_POLICY_RT, 'n',4,A_PS0,A_ADM,A_INI,A_ARG,A_ANY, 0, 0, 0, 0, opt_policy_rt, + 0, "disable policy routing (throw and priority rules)"}, + +#ifndef WITH_UNUSED + + {ODI,0,"lo_rule", 0, 4,A_PS1,A_ADM,A_INI,A_CFA,A_ANY, &Lo_rule, 0, 1, DEF_LO_RULE, 0, + ARG_VALUE_FORM, "disable/enable autoconfiguration of lo rule"} +#endif +#ifdef ADJ_PATCHED_NETW + , + {ODI,0,ARG_THROW, 0, 5,A_PMN,A_ADM,A_DYI,A_CFA,A_ANY, 0, 0, 0, 0, opt_throw, + ARG_PREFIX_FORM, "do NOT route packets matching src or dst IP range(s) into gateway tunnel or announced networks"}, + + {ODI,ARG_THROW,ARG_UHNA_NETWORK, 'n',5,A_CS1,A_ADM,A_DYI,A_CFA,A_ANY, 0, 0, 0, 0, opt_throw, + ARG_NETW_FORM, "specify network of throw rule"}, + + {ODI,ARG_THROW,ARG_UHNA_PREFIXLEN, 'm',5,A_CS1,A_ADM,A_DYI,A_CFA,A_ANY, 0, 0, 0, 0, opt_throw, + ARG_MASK_FORM, "specify network of throw rule"} +#endif + +}; + + + + +void init_ip(void) +{ + assertion(-500894, (is_zero(((char*)&ZERO_IP), sizeof (ZERO_IP)))); + + if (rtnl_open(&ip_rth) != SUCCESS) { + dbgf(DBGL_SYS, DBGT_ERR, "failed opening rtnl socket"); + cleanup_all( -500561 ); + } + + errno=0; + if ( !rt_sock && (rt_sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + dbgf( DBGL_SYS, DBGT_ERR, "can't create routing socket %s:", strerror(errno) ); + cleanup_all( -500021 ); + } + + register_options_array(ip_options, sizeof ( ip_options)); + InitSha(&ip_sha); + + if( ( nlsock_default = open_netlink_socket()) <= 0 ) + cleanup_all( -500067 ); + + if ((nlsock_flush_all = open_netlink_socket()) <= 0) + cleanup_all( -500658 ); + +} + +void cleanup_ip(void) +{ + + // if ever started succesfully in daemon mode... + //if ( !initializing ) { + + ip_flush_tracked( IP_ROUTE_FLUSH ); + ip_flush_routes(); + + ip_flush_tracked( IP_RULE_FLUSH ); + ip_flush_rules(); + + //} + + kernel_if_fix(YES,0); + + sysctl_restore(NULL); + + if (ip_rth.fd >= 0) { + close(ip_rth.fd); + ip_rth.fd = -1; + } + + if ( rt_sock ) + close( rt_sock ); + + rt_sock = 0; + + + if( nlsock_default > 0 ) + close( nlsock_default ); + nlsock_default = 0; + + + if (nlsock_flush_all> 0) + close( nlsock_flush_all ); + nlsock_flush_all = 0; + + + while (dev_name_tree.items) { + + struct dev_node *dev = dev_name_tree.root->item; + + if (dev->active) + dev_deactivate(dev); + + avl_remove(&dev_name_tree, &dev->name_phy_cfg, -300204); + + debugFree(dev, -300046); + + } + +} + diff --git a/ip.h b/ip.h new file mode 100644 index 0000000..eff2622 --- /dev/null +++ b/ip.h @@ -0,0 +1,389 @@ +/* + * Copyright (c) 2010 Axel Neumann + * 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 IFA_F_DADFAILED +#define IFA_F_DADFAILED 0x08 +#endif + +#ifndef INFINITY_LIFE_TIME +#define INFINITY_LIFE_TIME 0xFFFFFFFFU +#endif + +//from linux/wireless.h +#ifndef SIOCGIWNAME +#define SIOCGIWNAME 0x8B01 /* get name == wireless protocol */ +#endif + +struct ifname { + char str[IFNAMSIZ]; +}; + +typedef struct ifname IFNAME_T; + + + +#define ARG_DEV6 "dev6" + +#define ARG_DEV "dev" + +#define ARG_DEV_IP "ip" +#define ARG_DEV_TTL "ttl" +#define ARG_DEV_CLONE "clone" +#define ARG_DEV_LL "linklayer" + +#define ARG_DEV_ANNOUNCE "announce" +#define DEF_DEV_ANNOUNCE YES + + +#define ARG_DEV_BANDWIDTH "bandwidth" +#define DEF_DEV_BANDWIDTH 50000000 +#define DEF_DEV_BANDWIDTH_LAN 500000000 +#define DEF_DEV_BANDWIDTH_WIFI 50000000 + + +#define ARG_LLOCAL_PREFIX "link_local_prefix" +#define ARG_GLOBAL_PREFIX "global_prefix" + +#define DEF_LO_RULE 1 + +#define ARG_NO_POLICY_RT "no_policy_routing" + +#define ARG_THROW_RULES "throw_rules" +#define DEF_THROW_RULES 1 + +#define ARG_PRIO_RULES "prio_rules" +#define DEF_PRIO_RULES 1 + +#define ARG_RT_PRIO "prio_rules_offset" +#define MIN_RT_PRIO 3 +#define MAX_RT_PRIO 32765 +#define DEF_RT_PRIO 6240 +#define RT_PRIO_HOSTS (Rt_prio + 0) +#define RT_PRIO_NETS (Rt_prio + 1) +#define RT_PRIO_TUNS (Rt_prio + 2) +extern int32_t Rt_prio; + + +#define ARG_RT_TABLE "rt_table_offset" +#define DEF_RT_TABLE 62 +#define MIN_RT_TABLE 0 +#define MAX_RT_TABLE 32000 +#define RT_TABLE_HOSTS_OFFS 0 +#define RT_TABLE_NETS_OFFS 1 +#define RT_TABLE_TUNS_OFFS 2 +#define RT_TABLE_MAX_OFFS 2 +extern int32_t Rt_table; + +#define RT_TABLE_DEVS -1 +#define RT_TABLE_HOSTS -2 +#define RT_TABLE_NETS -3 +#define RT_TABLE_TUNS -4 + + +extern int32_t base_port; +#define ARG_BASE_PORT "base_port" +#define DEF_BASE_PORT 6240 +#define MIN_BASE_PORT 1025 +#define MAX_BASE_PORT 60000 + +#define DEV_LO "lo" +#define DEV_UNKNOWN "unknown" + + +#define VAL_DEV_LL_LO 0 +#define VAL_DEV_LL_LAN 1 +#define VAL_DEV_LL_WLAN 2 + + + + + + +#define B64_SIZE 64 + +#define IP6NET_STR_LEN (INET6_ADDRSTRLEN+4) // eg ::1/128 +#define IPXNET_STR_LEN IP6NET_STR_LEN + +#define IP4_MAX_PREFIXLEN 32 +#define IP6_MAX_PREFIXLEN 128 + + +#define IP2S_ARRAY_LEN 10 + +#define LINK_INFO 0 +#define ADDR_INFO 1 + +// IPv4 versus IPv6 array-position identifier +#define BMX_AFINET4 0 +#define BMX_AFINET6 1 +#define ORT_MAX 1 + +//#define IPV6_MC_ALL_ROUTERS "FF02::2" + +//#define IPV6_LINK_LOCAL_UNICAST_U32 0xFE800000 +//#define IPV6_MULTICAST_U32 0xFF000000 + +extern const IPX_T ZERO_IP; +extern const MAC_T ZERO_MAC; +extern const struct link_dev_key ZERO_LINK_KEY; + +extern const IP6_T IP6_ALLROUTERS_MC_ADDR; + +extern const IP6_T IP6_LINKLOCAL_UC_PREF; +extern const uint8_t IP6_LINKLOCAL_UC_PLEN; + +extern const IP6_T IP6_MC_PREF; +extern const uint8_t IP6_MC_PLEN; + +struct ort_data { + uint8_t family; + uint8_t max_prefixlen; + +}; + +extern const struct ort_data ort_dat[ORT_MAX + 1]; + +#define AFINET2BMX( fam ) ( ((fam) == AF_INET) ? BMX_AFINET4 : BMX_AFINET6 ) + +extern struct dev_node *primary_dev_cfg; +extern uint8_t af_cfg; + +extern struct avl_tree if_link_tree; + +extern struct avl_tree dev_ip_tree; +extern struct avl_tree dev_name_tree; + + +extern int32_t prio_rules; +extern int32_t throw_rules; + +extern IDM_T dev_soft_conf_changed; // temporary enabled to trigger changed interface configuration + + + +struct ip_req { + struct nlmsghdr nlmsghdr; + struct rtgenmsg rtgenmsg; +}; + +struct rtmsg_req { + struct nlmsghdr nlh; + struct rtmsg rtm; + char buff[ 256 ]; +}; + +struct rtnl_handle { + int fd; + struct sockaddr_nl local; + struct sockaddr_nl peer; + __u32 seq; + __u32 dump; +}; + + + +struct if_link_node { + uint16_t update_sqn; + uint16_t changed; + int index; + int type; + int alen; + unsigned flags; + + ADDR_T addr; + IFNAME_T name; + + struct avl_tree if_addr_tree; + + struct nlmsghdr nlmsghdr[]; +}; + +struct if_addr_node { + struct if_link_node *iln; + struct dev_node *dev; + struct rtattr *rta_tb[IFA_MAX + 1]; + + IPX_T ip_addr; + IPX_T ip_mcast; + + uint16_t update_sqn; + uint16_t changed; + struct ifaddrmsg ifa; + IFNAME_T label; + struct nlmsghdr nlmsghdr[]; +}; + + + +struct tx_link_node { + struct list_head tx_tasks_list[FRAME_TYPE_ARRSZ]; // scheduled frames and messages +}; + +struct dev_node { + + struct if_link_node *if_link; + struct if_addr_node *if_llocal_addr; // non-zero but might be global for ipv4 or loopback interfaces + struct if_addr_node *if_global_addr; // might be zero for non-primary interfaces + + TIME_T problem_timestamp; + + int8_t hard_conf_changed; + int8_t soft_conf_changed; + uint8_t active; + uint16_t tmp; + + // the manually configurable stuff: + + char *arg_cfg; + + IFNAME_T name_phy_cfg; //key for dev_name_tree + IFNAME_T label_cfg; + + + + // the detected stuff: + + IPX_T llocal_ip_key; // copy of dev->if_llocal_addr->ip_addr; + MAC_T mac; + TIME_T link_id_timestamp; + LINK_ID_T link_id; + + char ip_llocal_str[IPX_STR_LEN]; + char ip_global_str[IPX_STR_LEN]; + char ip_brc_str[IPX_STR_LEN]; + + int32_t ip4_rp_filter_orig; + int32_t ip4_send_redirects_orig; + + struct sockaddr_storage llocal_unicast_addr; + struct sockaddr_storage tx_netwbrc_addr; + + int32_t unicast_sock; + int32_t rx_mcast_sock; + int32_t rx_fullbrc_sock; + + HELLO_FLAGS_SQN_T link_hello_sqn; + + struct list_head tx_task_lists[FRAME_TYPE_ARRSZ]; // scheduled frames and messages + struct avl_tree tx_task_tree; + + int8_t announce; + + int8_t linklayer_conf; + int8_t linklayer; + + int8_t umetric_max_conf; + UMETRIC_T umetric_max_configured; + UMETRIC_T umetric_max; + + //size of plugin data is defined during intialization and depends on registered PLUGIN_DATA_DEV hooks + void *plugin_data[]; +}; + + +struct track_key { + IPX_T net; + IFNAME_T iif; + uint32_t prio; + uint16_t table; + uint8_t family; + uint8_t mask; + uint8_t cmd_type; +}; + +struct track_node { + struct track_key k; + uint32_t items; + int8_t cmd; +}; + + +//ip() commands: +enum { + IP_NOP, + IP_RULES, + IP_RULE_FLUSH, + IP_RULE_DEFAULT, //basic rules to interfaces, host, and networks routing tables + IP_RULE_MAX, + IP_ROUTES, + IP_ROUTE_FLUSH_ALL, + IP_ROUTE_FLUSH, + IP_THROW_MY_HNA, + IP_THROW_MY_NET, + IP_ROUTE_HOST, + IP_ROUTE_HNA, + IP_ROUTE_MAX +}; + + +//usefult IP tools: + +char *family2Str(uint8_t family); + +#define ip6Str( addr_ptr ) ipXAsStr( AF_INET6, (addr_ptr)) + +char *ipXAsStr(int family, const IPX_T *addr); +char *ip4AsStr( IP4_T addr ); +void ip2Str(int family, const IPX_T *addr, char *str); + + +#define ipXto4( ipx ) ((ipx).s6_addr32[3]) +void ip42X(IPX_T *ipx, IP4_T ip4); + +char* macAsStr(const MAC_T* mac); + + +IDM_T is_mac_equal(const MAC_T *a, const MAC_T *b); + +IDM_T is_ip_equal(const IPX_T *a, const IPX_T *b); +IDM_T is_ip_set(const IPX_T *ip); + +IDM_T is_ip_forbidden( const IPX_T *ip, const uint8_t family ); + +IDM_T ip_netmask_validate(IPX_T *ipX, uint8_t mask, uint8_t family, uint8_t force); + +IDM_T is_ip_net_equal(const IPX_T *netA, const IPX_T *netB, const uint8_t plen, const uint8_t family); + + + +// core: + +IDM_T ip(uint8_t family, uint8_t cmd, int8_t del, uint8_t quiet, const IPX_T *NET, uint8_t nmask, int32_t table_macro, uint32_t prio, IFNAME_T *iifname, int oif_idx, IPX_T *via, IPX_T *src); + +IDM_T kernel_if_config(void); + +void sysctl_config(struct dev_node *dev_node); + +void dev_check(IDM_T ip_config_changed); + +#define DEV_MARK_PROBLEM(dev) (dev)->problem_timestamp = MAX(1, bmx_time) + + +int8_t track_rule_and_proceed(uint32_t network, int16_t mask, uint32_t prio, int16_t rt_table, char* iif, + int16_t rule_type, int8_t del, int8_t cmd); + + +IDM_T track_route(IPX_T *dst, int16_t mask, uint32_t metric, int16_t table, int16_t rta_t, int8_t del, int8_t track_t); + + + +void init_ip(void); + +void cleanup_ip(void); + diff --git a/lib/Makefile b/lib/Makefile index a03a257..3d32adb 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -2,7 +2,7 @@ CFLAGS += LDFLAGS +=
-PLUGINS = $(shell find -maxdepth 1 -type d | grep -e '^./bmx_' | sort) +PLUGINS = $(shell find -maxdepth 1 -type d | grep -e '^./bmx6_' | sort)
%: for d in $(PLUGINS); do $(MAKE) CORE_CFLAGS='$(CORE_CFLAGS)' -C $$d $@ || echo compiling $$d failed; echo;echo; done diff --git a/lib/bmx6_uci_config/HOWTO b/lib/bmx6_uci_config/HOWTO new file mode 100644 index 0000000..2eba397 --- /dev/null +++ b/lib/bmx6_uci_config/HOWTO @@ -0,0 +1,15 @@ +2009-08-10 - bmx6_config plugin for openWrt universial configuraton interface (UCI) + +- plugin for dynamic interaction with uci + ( http://downloads.openwrt.org/sources/uci-0.7.3.tar.gz ) + +- to compile first install uci: + wget http://downloads.openwrt.org/sources/uci-0.7.3.tar.gz + tar xzvf uci-0.7.3.tar.gz; cd uci-0.7.3; make; sudo make install + +- default configuration backend is: /etc/config/bmx6 + +- see lib/bmx6_config/etc_config for a simple (bmx) + and an advanced (bmx-advanced) example + + diff --git a/lib/bmx_uci_config/Makefile b/lib/bmx6_uci_config/Makefile similarity index 92% rename from lib/bmx_uci_config/Makefile rename to lib/bmx6_uci_config/Makefile index 29ce78f..8927735 100644 --- a/lib/bmx_uci_config/Makefile +++ b/lib/bmx6_uci_config/Makefile @@ -1,9 +1,9 @@
CFLAGS += $(CORE_CFLAGS) -fpic -I../../ LDFLAGS += -shared -luci -#-Wl,-soname,bmx_config +#-Wl,-soname,bmx6_config
-PLUGIN_NAME = bmx_uci_config +PLUGIN_NAME = bmx6_config
SRC_C = uci_config.c SRC_H = uci_config.h diff --git a/lib/bmx6_uci_config/etc_config/bmx6-advanced b/lib/bmx6_uci_config/etc_config/bmx6-advanced new file mode 100644 index 0000000..c2671f6 --- /dev/null +++ b/lib/bmx6_uci_config/etc_config/bmx6-advanced @@ -0,0 +1,77 @@ +# bmx_uci_config plugin depends on the UCI (universial configuration interface) +# from http://downloads.openwrt.org/sources/uci-0.7.3.tar.gz +# to compile first install uci: +# wget http://downloads.openwrt.org/sources/uci-0.7.3.tar.gz +# tar xzvf uci-0.7.3.tar.gz; cd uci-0.7.3; make; sudo make install +# +# +# the default location for this config file is /etc/config/bmx +# from where it would be loaded automatically during initialization of bmxd. +# Use bmxd -f /etc/config/another-bmx-config to load an alternative config file. +# and bmxd -f 0 to disable all config-file functionality. +# +# You may also start bmxd as you always did (e.g. bmxd --neta -o 1000 ath0:bmx) +# and then use bmxd -c show-config and bmxd -c show-config > /etc/config/bmx +# to generate the config file you need. Afterwards a simple $ bmxd should do it. +# +# With uci comes a bunch of new configuration possibilities: +# The bmxd can be configured on-the-fly from bmxd or uci. +# To configure from bmxd simply type: bmxd -c ogm_interval=500 or: bmxd -co500 +# To configure from uci: uci set bmx.general.ogm_interval=500 +# followed by: kill -HUP $(cat /var/run/pid) or: bmxd -c reload-config +# To permanently store the changes: uci commit bmx +# And to revert them: uci revert bmx +# For more possibilities check out openWrt, UCI, and bmxd -X + + +# the following example substitutes the now deprecated --neta option +# +config 'bmx6' 'general' +# option 'runtime_dir' '/var/run/bmx6' + option 'base_port' '6240' + + +# bmxd always tries to load bmx6_config.so from /usr/lib/ +# Therefore, there is no obligation to request this explicitly. +# An alternative library-path can be set with the environment variable BMX6_LIB_PATH +# E.g. BMX6_LIB_PATH=/usr/src/bmx6/lib will check the given directory for plugins +config 'plugin' + option 'plugin' 'bmx6_config.so' + + +# other plugin must be requested explicitly: +# config 'plugin' +# option 'plugin' 'bmx6_howto_plugin.so' + + +# it is allways a good idea to use an alias on your loopback interface +# as the primary interface because the loopback interface is probably +# the most stable you have on your system and then you are always +# reachable under your primary IP. E.g.: +# ifconfig lo:bmx 6.6.1.1 netmask 255.255.0.0 +config 'dev' + option 'dev' 'lo:bmx' + + +# Of course, a real interface is necessary +# to link up with the rest of the world. +# However, all non-primary interfaces may be added and removed on the fly. +config 'dev' + option 'dev' 'ath0:bmx' + + +# In openWrt interfaces are usually configured in /etc/config/network +# to avoid redundancy it is also possible to resolve values from there. E.g.: +# +#config 'dev' +# option 'dev' 'ref:network.lan0_bmx.ifname' + + + + + +# unicast host-network announcements (HNAs) may look like this: +# config 'unicast_hna' +# option 'unicast_hna' '106.1.2.4/32' + + diff --git a/lib/bmx6_uci_config/etc_config/bmx6-simple b/lib/bmx6_uci_config/etc_config/bmx6-simple new file mode 100644 index 0000000..6d4293f --- /dev/null +++ b/lib/bmx6_uci_config/etc_config/bmx6-simple @@ -0,0 +1,14 @@ +# this config file should be stored in /etc/config/bmx6 +# for more options check the bmx-advanced configuration example and bmx6 -X +# +# bmx_uci_config plugin depends on the UCI (universial configuration interface) +# from http://downloads.openwrt.org/sources/uci-0.7.3.tar.gz +# to compile first install uci: +# wget http://downloads.openwrt.org/sources/uci-0.7.3.tar.gz +# tar xzvf uci-0.7.3.tar.gz; cd uci-0.7.3; make; sudo make install +# + +config 'bmx6' 'general' + +config 'dev' + option 'dev' 'ath0' diff --git a/lib/bmx_uci_config/uci_config.c b/lib/bmx6_uci_config/uci_config.c similarity index 96% rename from lib/bmx_uci_config/uci_config.c rename to lib/bmx6_uci_config/uci_config.c index b7e09d4..31da67a 100644 --- a/lib/bmx_uci_config/uci_config.c +++ b/lib/bmx6_uci_config/uci_config.c @@ -30,6 +30,7 @@
#include "../../bmx.h" #include "../../plugin.h" +#include "../../tools.h" #include "uci_config.h"
static char conf_path[MAX_PATH_SIZE] = ""; @@ -62,8 +63,8 @@ static void signal_hup_handler( int32_t sig ) { close_ctrl_node( CTRL_CLOSE_STRAIGHT, cn ); respect_opt_order( OPT_APPLY, 0, 99, NULL, NO/*load_cofig*/, OPT_POST, 0/*probably closed*/ ); - - cb_plugin_hooks( NULL, PLUGIN_CB_CONF ); + + cb_plugin_hooks(PLUGIN_CB_CONF, NULL); }
@@ -416,7 +417,7 @@ int bmx_save_config ( uint8_t del, struct opt_type *opt, char *p_val, char *c_va } else if ( opt->opt_t == A_CS1 && p_val ) { - // all A_CS1-child options like /ttl=20, /hide=1 from --dev eth0 + // all A_CS1-child options like \ttl=20 from --dev eth0 if ( uci_get_sect_name( NO/*create*/, cn, bmx_ctx, bmx_conf_name, sect_name, opt->d.parent_opt->long_name, @@ -480,7 +481,7 @@ int bmx_load_config ( uint8_t cmd, struct opt_type *opt, struct ctrl_node *cn ) if ( !( uci_lookup( bmx_ctx, &optr, name ) ) ) { - if ( on_the_fly && //no need to reset a configuration during init + if ( !initializing && //no need to reset a configuration during init check_apply_parent_option( DEL, cmd, NO/*save*/, opt, 0, cn ) == FAILURE ) { dbgf_cn( cn, DBGL_SYS, DBGT_ERR, @@ -588,7 +589,7 @@ int bmx_load_config ( uint8_t cmd, struct opt_type *opt, struct ctrl_node *cn ) } else { - if ( !on_the_fly ) + if ( initializing ) continue; //no need to reset a configuration during init config_sect_opt_val[0] = 0; @@ -640,10 +641,10 @@ int bmx_load_config ( uint8_t cmd, struct opt_type *opt, struct ctrl_node *cn ) p_tmp = list_entry( pos, struct opt_parent, list ); - if ( wordsEqual( p_tmp->p_val, BMX_LIB_UCI_CONFIG ) ) { + if ( wordsEqual( p_tmp->p_val, BMX_LIB_CONFIG ) ) { dbg_mute( 40, DBGL_SYS, DBGT_WARN, "missing section %s with option %s %s in %s", - ARG_PLUGIN, ARG_PLUGIN, BMX_LIB_UCI_CONFIG, bmx_conf_name ); + ARG_PLUGIN, ARG_PLUGIN, BMX_LIB_CONFIG, bmx_conf_name ); } else if ( check_apply_parent_option( DEL, cmd, NO, opt, p_tmp->p_val, cn ) == FAILURE ) { @@ -654,8 +655,8 @@ int bmx_load_config ( uint8_t cmd, struct opt_type *opt, struct ctrl_node *cn ) } } else { - - dbgf_cn( cn, DBGL_SYS, DBGT_ERR, "opt: %s illegal implementation! %s", opt->long_name, ILLEGAL_STATE ); + + dbgf_cn(cn, DBGL_SYS, DBGT_ERR, "opt: %s illegal implementation!", opt->long_name); cleanup_all( -500137 ); @@ -690,7 +691,7 @@ int32_t opt_conf_file ( uint8_t cmd, uint8_t _save, struct opt_type *opt, struct
char tmp_path[MAX_PATH_SIZE] = ""; - if ( on_the_fly ) + if ( !initializing ) return SUCCESS; @@ -763,7 +764,7 @@ int32_t opt_conf_file ( uint8_t cmd, uint8_t _save, struct opt_type *opt, struct uci_set_confdir( bmx_ctx, conf_path ); dbg( DBGL_CHANGES, DBGT_INFO, - "loading uci bmxd backend: file://%s/%s succeeded", conf_path, bmx_conf_name ); + "loading uci bmx6 backend: file://%s/%s succeeded", conf_path, bmx_conf_name ); //initially lookup the bmx package so that we can save future changes memset(&bmx_pptr, 0, sizeof(bmx_pptr)); @@ -904,17 +905,14 @@ int32_t init_conf( void ) {
-struct plugin_v2* get_plugin_v2( void ) { - - static struct plugin_v2 conf_plugin; +struct plugin* get_plugin( void ) { - memset( &conf_plugin, 0, sizeof ( struct plugin_v2 ) ); + static struct plugin conf_plugin; + memset( &conf_plugin, 0, sizeof( conf_plugin)); - conf_plugin.plugin_version = PLUGIN_VERSION_02; - conf_plugin.plugin_name = "bmx_uci_config_plugin"; - conf_plugin.plugin_size = sizeof ( struct plugin_v2 ); - conf_plugin.plugin_bmx_revision = REVISION_VERSION; - conf_plugin.plugin_bmx_version = SOURCE_VERSION; + conf_plugin.plugin_name = "bmx6_uci_config_plugin"; + conf_plugin.plugin_size = sizeof ( struct plugin ); + conf_plugin.plugin_code_version = CODE_VERSION; conf_plugin.cb_init = init_conf; conf_plugin.cb_cleanup = cleanup_conf;
diff --git a/lib/bmx_uci_config/uci_config.h b/lib/bmx6_uci_config/uci_config.h similarity index 85% rename from lib/bmx_uci_config/uci_config.h rename to lib/bmx6_uci_config/uci_config.h index 7e10085..c30cea1 100644 --- a/lib/bmx_uci_config/uci_config.h +++ b/lib/bmx6_uci_config/uci_config.h @@ -1,6 +1,5 @@ /* - * Copyright (C) 2010 BMX contributors: - * Axel Neumann + * Copyright (c) 2010 Axel Neumann * 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. @@ -16,9 +15,9 @@ * 02110-1301, USA */
-#define DEF_CONF_NAME "bmx" +#define DEF_CONF_NAME "bmx6" #define DEF_SECT_NAME "general" -#define DEF_SECT_TYPE "bmx" +#define DEF_SECT_TYPE "bmx6"
#define ARG_CONFIG_FILE "config_file" #define ARG_SAVE_CONFIG "save_config" diff --git a/list.c b/list.c index 85e88d2..04faf76 100644 --- a/list.c +++ b/list.c @@ -1,6 +1,4 @@ /* - * Copyright (C) 2010 BMX contributors: - * Axel Neumann * 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. @@ -21,12 +19,14 @@ * double-linked list implementaton from the linux-kernel * which can be found in include/linux/list.h * - * The following has been to better fit my needs: + * The following has been changed/added to better fit my needs: * - items counter * - plist handler (list-node structure with void* item pointer * - single-linked list instead of double-linked list to save overhead * - some functions for straight item access! + * - ... */ +#include <string.h>
#include "bmx.h" #include "list.h" @@ -38,18 +38,28 @@ */ void * list_iterate(struct list_head *head, void *node) { - struct list_node * ln; + //assertion(-500869, (0)); // does not return NULL when iteration finished + if (head->prev == (node ? ((struct list_node*) (((char*) node) + head->list_node_offset)) : head->next)) + return NULL;
- if (head->prev == (ln = ((node ? + struct list_node *ln = ((node ? (struct list_node*) (((char*) node) + head->list_node_offset) : - (struct list_node*) head))->next) - ) - return NULL; + (struct list_node*) head))->next;
return (((char*) ln) - head->list_node_offset); }
+void *list_find(struct list_head *head, void* key) +{ + char *node = NULL; + + while ((node = list_iterate(head, node))) {
+ if ( memcmp( node+head->key_node_offset, key, head->key_length ) == 0) + return node; + } + return NULL; +}
/** * list_add_head - add a new entry at the beginning of a list @@ -136,22 +146,6 @@ void * plist_iterate(struct list_head *head, struct plist_node **pln)
return (*pln)->item;
-/* - if (LIST_EMPTY(head)) - return NULL; - - if (*pln) { - - if (head->prev == (struct list_node*) (*pln = (struct plist_node*) ((*pln)->list->next))) - return NULL; - - } else { - *pln = (struct plist_node*) head->next; - } - - return (*pln)->item; -*/ - }
diff --git a/list.h b/list.h index bc8c680..66655cb 100644 --- a/list.h +++ b/list.h @@ -1,6 +1,4 @@ /* - * Copyright (C) 2010 BMX contributors: - * Axel Neumann * 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. @@ -42,6 +40,8 @@ struct list_head { struct list_node *next, *prev; uint16_t items; uint16_t list_node_offset; + uint16_t key_node_offset; + uint16_t key_length; };
struct plist_node { @@ -50,15 +50,21 @@ struct plist_node { };
-#define LIST_SIMPEL(lst, element_type, list_node_field) struct list_head lst = { \ - (struct list_node *)&lst, (struct list_node *)&lst, \ - 0, \ - ((unsigned long)(&((element_type *)0)->list_node_field)) }
-#define LIST_INIT_HEAD(ptr, element_type, list_node_field) do { \ +#define LIST_SIMPEL(lst, element_type, list_field, key_field ) struct list_head lst = { \ + .next = (struct list_node *)&lst, \ + .prev = (struct list_node *) & lst, \ + .items = 0, \ + .list_node_offset = ((unsigned long)(&((element_type *)0)->list_field)), \ + .key_node_offset = ((unsigned long)(&((element_type *)0)->key_field)), \ + .key_length = sizeof(((element_type *)0)->key_field) } + +#define LIST_INIT_HEAD(ptr, element_type, list_field) do { \ ptr.next = ptr.prev =(struct list_node *)&ptr; \ ptr.items = 0; \ - ptr.list_node_offset = ((unsigned long)(&((element_type *)0)->list_node_field)); \ + ptr.list_node_offset = ((unsigned long)(&((element_type *)0)->list_field)); \ + ptr.key_node_offset = 0; \ + ptr.key_length = 0; \ } while (0)
#define LIST_EMPTY(lst) ((lst)->next == (struct list_node *)(lst)) @@ -67,7 +73,8 @@ struct plist_node { #define list_get_first(head) ((void*)((LIST_EMPTY(head)) ? NULL : (((char*) (head)->next) - (head)->list_node_offset) )) #define list_get_last(head) ((void*)((LIST_EMPTY(head)) ? NULL : (((char*) (head)->prev) - (head)->list_node_offset) ))
-void * list_iterate( struct list_head *head, void *node ); +void *list_iterate( struct list_head *head, void *node ); +void *list_find(struct list_head *head, void* key);
void list_add_head(struct list_head *head, struct list_node *new); void list_add_tail(struct list_head *head, struct list_node *new ); diff --git a/metrics.c b/metrics.c new file mode 100644 index 0000000..f997cab --- /dev/null +++ b/metrics.c @@ -0,0 +1,1552 @@ +/* + * Copyright (c) 2010 Axel Neumann + * 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 <stdio.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <arpa/inet.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> + + +#include "bmx.h" +#include "msg.h" +#include "ip.h" +#include "plugin.h" +#include "schedule.h" +#include "tools.h" +#include "metrics.h" + + + +static int32_t my_path_metricalgo = DEF_METRIC_ALGO; +static int32_t my_path_metric_flags = DEF_PATH_METRIC_FLAGS; +static int32_t my_fmetric_exp_min = DEF_FMETRIC_EXPONENT_MIN; +static int32_t my_path_window = DEF_PATH_WINDOW; +static int32_t my_path_lounge = DEF_PATH_LOUNGE; +static int32_t my_path_regression_slow = DEF_PATH_REGRESSION_SLOW; +static int32_t my_path_regression_fast = DEF_PATH_REGRESSION_FAST; +static int32_t my_path_regression_diff = DEF_PATH_REGRESSION_DIFF; +static int32_t my_path_hystere = DEF_PATH_HYST; +static int32_t my_hop_penalty = DEF_HOP_PENALTY; +static int32_t my_late_penalty = DEF_LATE_PENAL; + + +static int32_t my_link_window = DEF_LINK_WINDOW; +static int32_t my_link_metric_flags = DEF_LINK_METRIC_FLAGS; +static int32_t my_link_regression_slow = DEF_LINK_REGRESSION_SLOW; +static int32_t my_link_regression_fast = DEF_LINK_REGRESSION_FAST; +static int32_t my_link_regression_diff = DEF_LINK_REGRESSION_DIFF; + +static int32_t my_link_rtq_lounge = DEF_LINK_RTQ_LOUNGE; + +int32_t link_ignore_min = DEF_LINK_IGNORE_MIN; + +int32_t link_ignore_max = DEF_LINK_IGNORE_MAX; + + +struct host_metricalgo link_metric_algo[SQR_RANGE]; + +//TODO: evaluate my_fmetric_exp_offset based on max configured dev_metric_max: +//static int32_t my_fmetric_exp_offset = DEF_FMETRIC_EXP_OFFSET; +//TODO: reevaluate my_dev_metric_max based on deduced my_fmetric_exp_offset (see above) +//UMETRIC_T my_dev_metric_max = umetric_max(DEF_FMETRIC_EXP_OFFSET); + +static +void (*path_metric_algos[BIT_METRIC_ALGO_ARRSZ]) +(UMETRIC_T *path_out, struct link_dev_node *link, struct host_metricalgo *algo) = {NULL}; + + + +//TODO: remove: +UMETRIC_T UMETRIC_RQ_NBDISC_MIN = 2048; +UMETRIC_T UMETRIC_RQ_OGM_ACK_MIN = 1024; + + + +FMETRIC_T fmetric(uint8_t mantissa, uint8_t exp_reduced, uint8_t exp_offset) +{ + + FMETRIC_T fm = {.val.f = + {.mantissa = mantissa, .exp_total = exp_offset + exp_reduced}, + .exp_offset = exp_offset, + .reserved = FMETRIC_UNDEFINED}; + + return fm; +} + +FMETRIC_T fmetric_max(uint8_t exp_offset) +{ + FMETRIC_T fm = {.val.f = {.exp_total = exp_offset + OGM_EXPONENT_MAX, .mantissa = OGM_MANTISSA_MAX}, .exp_offset = exp_offset, .reserved = FMETRIC_UNDEFINED}; + return fm; +} + + +UMETRIC_T umetric(uint8_t mantissa, uint8_t exp_reduced, uint8_t exp_offset) +{ + return fmetric_to_umetric(fmetric(mantissa, exp_reduced, exp_offset)); +} + + + +UMETRIC_T umetric_max(uint8_t exp_offset) +{ + + UMETRIC_T max = fmetric_to_umetric(fmetric_max(exp_offset)); + + ASSERTION(-500703, (max == (((((UMETRIC_T) 1) << (OGM_MANTISSA_BIT_SIZE + 1)) - 1) * + (((UMETRIC_T) 1) << (exp_offset + ((1 << (OGM_EXPONENT_BIT_SIZE)) - 1) - OGM_MANTISSA_BIT_SIZE))))); + + return max; +} + + + +IDM_T is_umetric_valid(uint8_t exp_offset, UMETRIC_T *um) +{ + assertion(-500704, (um)); + return ( *um <= umetric_max(exp_offset)); +} + + +IDM_T is_fmetric_valid(FMETRIC_T fm) +{ + return ( + fm.exp_offset <= MAX_FMETRIC_EXP_OFFSET && + fm.val.f.exp_total >= fm.exp_offset && + fm.val.f.exp_total <= OGM_EXPONENT_MAX + fm.exp_offset && + fm.val.f.mantissa <= OGM_MANTISSA_MAX + ); +} + + + +IDM_T fmetric_cmp(FMETRIC_T a, unsigned char cmp, FMETRIC_T b) +{ + + + assertion(-500706, (is_fmetric_valid(a) && is_fmetric_valid(b))); + + switch (cmp) { + + case '!': + return (a.val.u != b.val.u); + case '<': + return (a.val.u < b.val.u); + case '[': + return (a.val.u <= b.val.u); + case '=': + return (a.val.u == b.val.u); + case ']': + return (a.val.u >= b.val.u); + case '>': + return (a.val.u > b.val.u); + } + + assertion(-500707, (0)); + return FAILURE; +} + + +UMETRIC_T fmetric_to_umetric(FMETRIC_T fm) +{ + TRACE_FUNCTION_CALL; + + uint8_t exp_sum = (fm.val.f.exp_total + OGM_MANTISSA_BIT_SIZE); + + UMETRIC_T val = + (((UMETRIC_T) 1) << exp_sum) + + (((UMETRIC_T) fm.val.f.mantissa) << (exp_sum - OGM_MANTISSA_BIT_SIZE)); + + + if (!is_fmetric_valid(fm)) { + + dbgf(DBGL_SYS, DBGT_ERR, "mantissa=%d exp_total=%d exp_offset=%d mant_bit_size=%d -> U64x2eM=%ju ( %ju )", + fm.val.f.mantissa, fm.val.f.exp_total, fm.exp_offset, OGM_MANTISSA_BIT_SIZE, val, val >> TMP_MANTISSA_BIT_SHIFT); + + assertion(-500680, (0)); + } + + + return (val >> TMP_MANTISSA_BIT_SHIFT); +} + + + +FMETRIC_T umetric_to_fmetric(uint8_t exp_offset, UMETRIC_T val) +{ + TRACE_FUNCTION_CALL; + + FMETRIC_T fm = {.val.f={.mantissa = 0, .exp_total = exp_offset}, .exp_offset = exp_offset, .reserved = FMETRIC_UNDEFINED}; + uint8_t exp_sum; + + // these fixes are used to improove (average) rounding errors +#define INPUT_FIXA (OGM_MANTISSA_BIT_SIZE+1) +#define INPUT_FIXB (OGM_MANTISSA_BIT_SIZE+5) + + UMETRIC_T tmp = (val = (val + (val>>INPUT_FIXA) - (val>>INPUT_FIXB) )<< TMP_MANTISSA_BIT_SHIFT); // 4-bit-mantissa + + + LOG2(exp_sum, tmp, UMETRIC_T); + + + //assertion(-500678, ((exp_sum - (exp_offset + MANTISSA_BIT_SIZE)) < (1 << EXPONENT_BIT_SIZE))); + + if (exp_sum > (exp_offset + OGM_MANTISSA_BIT_SIZE + (1 << OGM_EXPONENT_BIT_SIZE) - 1)) { + + fm.val.f.exp_total += (1 << OGM_EXPONENT_BIT_SIZE) - 1; + fm.val.f.mantissa = (1 << OGM_MANTISSA_BIT_SIZE) - 1; + + } else if (exp_sum >= (exp_offset + OGM_MANTISSA_BIT_SIZE)) { + + fm.val.f.exp_total = (exp_sum - OGM_MANTISSA_BIT_SIZE); + + fm.val.f.mantissa = ((val - (((uint64_t) 1) << exp_sum)) >> (exp_sum - OGM_MANTISSA_BIT_SIZE)); + + //check for overflow, so dont exchange this expression with fm.val.f.mantissa: + assertion(-500677, (((val - (((uint64_t) 1) << exp_sum)) >> (exp_sum - OGM_MANTISSA_BIT_SIZE)) < (1 << OGM_MANTISSA_BIT_SIZE))); + } + + if (!is_fmetric_valid(fm)) { + + dbgf(DBGL_SYS, DBGT_ERR, "mantissa=%d exp_total=%d exp_offset=%d mant_bit_size=%d -> U64x2eM=%ju ( %ju )", + fm.val.f.mantissa, fm.val.f.exp_total, fm.exp_offset, OGM_MANTISSA_BIT_SIZE, val, val >> TMP_MANTISSA_BIT_SHIFT); + + assertion(-500681, (0)); + } + + return fm; +} + +STATIC_INLINE_FUNC +FMETRIC_T fmetric_substract_min(FMETRIC_T f) +{ + + if (f.val.f.mantissa) { + + f.val.f.mantissa--; + + } else if (f.val.f.exp_total > f.exp_offset) { + + f.val.f.mantissa = OGM_MANTISSA_MAX; + f.val.f.exp_total--; + } + + return f; +} + +STATIC_INLINE_FUNC +UMETRIC_T umetric_substract_min(uint8_t exp_offset, UMETRIC_T *val) +{ + return fmetric_to_umetric(fmetric_substract_min(umetric_to_fmetric(exp_offset, *val))); +} + + + + +STATIC_FUNC +void path_metricalgo_RQv0(UMETRIC_T *path_out, struct link_dev_node *link, struct host_metricalgo *algo) +{ + // make sure this product does not exceed U64 range: + assertion(-500833, ((*path_out * link->mr[SQR_RQ].umetric_final) >= link->mr[SQR_RQ].umetric_final)); + + *path_out = (*path_out * link->mr[SQR_RQ].umetric_final) / link->key.dev->umetric_max; +} + +STATIC_FUNC +void path_metricalgo_TQv0(UMETRIC_T *path_out, struct link_dev_node *link, struct host_metricalgo *algo) +{ + // make sure this product does not exceed U64 range: + // TQ = RTQ / RQ + assertion(-500834, ((*path_out * link->mr[SQR_RTQ].umetric_final) >= link->mr[SQR_RTQ].umetric_final)); + + *path_out = (*path_out * link->mr[SQR_RTQ].umetric_final) / link->mr[SQR_RQ].umetric_final; +} + +STATIC_FUNC +void path_metricalgo_RTQv0(UMETRIC_T *path_out, struct link_dev_node *link, struct host_metricalgo *algo) +{ + // make sure this product does not exceed U64 range: + assertion(-500835, ((*path_out * link->mr[SQR_RTQ].umetric_final) >= link->mr[SQR_RTQ].umetric_final)); + + *path_out = (*path_out * link->mr[SQR_RTQ].umetric_final) / link->key.dev->umetric_max; +} + +STATIC_FUNC +void path_metricalgo_ETXv0(UMETRIC_T *path_out, struct link_dev_node *link, struct host_metricalgo *algo) +{ + // make sure this product does not exceed U64 range: + assertion(-500836, ((umetric_max(algo->exp_offset) * link->mr[SQR_RTQ].umetric_final) >= link->mr[SQR_RTQ].umetric_final)); + + UMETRIC_T rtq_link = (umetric_max(algo->exp_offset) * link->mr[SQR_RTQ].umetric_final) / link->key.dev->umetric_max; + + if (*path_out < 2 || rtq_link < 2) + *path_out = umetric(FMETRIC_MANTISSA_ZERO, 0, algo->exp_offset); + else + *path_out = (U64_MAX / ((U64_MAX / *path_out) + (U64_MAX / rtq_link))); +} + +STATIC_FUNC +void path_metricalgo_ETTv0(UMETRIC_T *path_out, struct link_dev_node *link, struct host_metricalgo *algo) +{ + // make sure this product does not exceed U64 range: + assertion(-500827, ((umetric_max(algo->exp_offset) * link->mr[SQR_RTQ].umetric_final) >= link->mr[SQR_RTQ].umetric_final)); + + UMETRIC_T bw_link = link->mr[SQR_RTQ].umetric_final; + + if (*path_out < 2 || bw_link < 2) + *path_out = umetric(FMETRIC_MANTISSA_ZERO, 0, algo->exp_offset); + else + *path_out = (U64_MAX / ((U64_MAX / *path_out) + (U64_MAX / bw_link))); +} + +STATIC_FUNC +void path_metricalgo_MINBANDWIDTH(UMETRIC_T *path_out, struct link_dev_node *link, struct host_metricalgo *algo) +{ + *path_out = MIN(*path_out, link->mr[SQR_RTQ].umetric_final); +} + + +STATIC_FUNC +void register_path_metricalgo(uint8_t algo_type_bit, void (*algo) (UMETRIC_T *path_out, struct link_dev_node *link, struct host_metricalgo *algo)) +{ + assertion(-500838, (!path_metric_algos[algo_type_bit])); + assertion(-500839, (algo_type_bit < BIT_METRIC_ALGO_ARRSZ)); + path_metric_algos[algo_type_bit] = algo; +} + + +void apply_metric_algo(UMETRIC_T *out, struct link_dev_node *link, UMETRIC_T *path, struct host_metricalgo *algo) +{ + TRACE_FUNCTION_CALL; + assertion(-500823, (link->key.dev->umetric_max)); + + ALGO_T unsupported_algos = 0; + ALGO_T algo_type = algo->algo_type; + UMETRIC_T max_out, path_out; + + if (algo_type) { + max_out = umetric_substract_min(algo->exp_offset, path); + path_out = *path; + + while (algo_type) { + + uint8_t algo_type_bit; + ALGO_T algo_type_tmp = algo_type; + LOG2(algo_type_bit, algo_type_tmp, ALGO_T); + + algo_type -= (0x01 << algo_type_bit); + + if (path_metric_algos[algo_type_bit]) { + (*(path_metric_algos[algo_type_bit])) (&path_out, link, algo); + dbgf_all(DBGT_INFO, "pathalgo_type=%d returned path_out=%ju", algo_type_bit, path_out); + } else { + unsupported_algos |= (0x01 << algo_type_bit); + } + } + + } else { + max_out = path_out = umetric(FMETRIC_MANTISSA_ZERO, 0, algo->exp_offset); + } + + + if (unsupported_algos) { + uint8_t i = bits_count(unsupported_algos); + + dbgf(DBGL_SYS, DBGT_WARN, + "unsupported %s=%d (0x%X) - Need an update?! - applying pessimistic ETTv0 %d times", + ARG_PATH_METRIC_ALGO, unsupported_algos, unsupported_algos, i); + + while (i--) + (*(path_metric_algos[BIT_METRIC_ALGO_ETTv0])) (&path_out, link, algo); + } + + if (algo->hop_penalty) + path_out = (path_out * ((UMETRIC_T) (MAX_HOP_PENALTY - algo->hop_penalty))) >> MAX_HOP_PENALTY_PRECISION_EXP; + + + if (path_out > max_out) { + dbgf_all(DBGT_WARN, + "out=%ju > out_max=%ju, %s=%d, path=%ju, dev=%s, link_MAX=%ju, link_RTQ=%ju, link_RQ=%ju", + path_out, max_out, ARG_PATH_METRIC_ALGO, algo->algo_type, *path, + link->key.dev->label_cfg.str, link->key.dev->umetric_max, + link->mr[SQR_RTQ].umetric_final, link->mr[SQR_RQ].umetric_final); + } + + *out = MIN(path_out, max_out); // ensure out always decreases +} + +STATIC_FUNC +void _reconfigure_metric_record_position(const char *f, struct metric_record *rec, struct host_metricalgo *alg, + SQN_T min, SQN_T in, uint8_t sqn_bit_size, uint8_t reset) +{ + TRACE_FUNCTION_CALL; + assertion(-500737, (XOR(sqn_bit_size, rec->sqn_bit_mask))); + + if (sqn_bit_size) + rec->sqn_bit_mask = (~(SQN_MAX << sqn_bit_size)); + + assertion(-500738, (rec->sqn_bit_mask == U16_MAX || rec->sqn_bit_mask == U8_MAX || + rec->sqn_bit_mask == HELLO_SQN_MAX)); + + + if (rec->clr && /*alg->window_size > 1 &&*/ ((rec->sqn_bit_mask)&(in - rec->clr)) > (alg->lounge_size + 1)) { + dbgf(DBGL_CHANGES, DBGT_WARN, "reset_metric=%d sqn_bit_size=%d sqn_bit_mask=0x%X umetric=%ju clr=%d to ((in=%d) - (lounge=%d))=%d", + reset, sqn_bit_size, rec->sqn_bit_mask, rec->umetric_final, rec->clr, in, alg->lounge_size, ((rec->sqn_bit_mask)& (in - alg->lounge_size))); + } + + rec->clr = MAX_UXX(rec->sqn_bit_mask, min, ((rec->sqn_bit_mask)&(in - alg->lounge_size))); + + rec->set = ((rec->sqn_bit_mask)&(rec->clr - 1)); + + if (reset) { + rec->umetric_slow = 0; + rec->umetric_fast = 0; + rec->umetric_final = 0; + } + + dbgf_all(DBGT_WARN, "%s reset_metric=%d sqn_bit_size=%d sqn_bit_mask=0x%X min=%d in=%d lounge_size=%d umetric=%ju clr=%d", + f, reset, sqn_bit_size, rec->sqn_bit_mask, min, in, alg->lounge_size, rec->umetric_final, rec->clr); + +} + +#define reconfigure_metric_record_position(rec, alg, min, in, sqn_bit_size, reset) \ + _reconfigure_metric_record_position(__FUNCTION__, rec, alg, min, in, sqn_bit_size, reset) + +IDM_T update_metric_record(struct orig_node *on, struct metric_record *rec, struct host_metricalgo *alg, SQN_T range, SQN_T min, SQN_T in, UMETRIC_T *probe) +{ + TRACE_FUNCTION_CALL; + char *scenario = NULL; + SQN_T dbg_clr = rec->clr; + SQN_T dbg_set = rec->set; + SQN_T i, purge = 0; + + ASSERTION(-500739, (!((~(rec->sqn_bit_mask))&(min)))); + ASSERTION(-500740, (!((~(rec->sqn_bit_mask))&(in)))); + ASSERTION(-500741, (!((~(rec->sqn_bit_mask))&(rec->clr)))); + ASSERTION(-500742, (!((~(rec->sqn_bit_mask))&(rec->set)))); + + assertion(-500743, (range <= MAX_SQN_RANGE)); + assertion(-500744, (is_umetric_valid(alg->exp_offset, &rec->umetric_slow))); + assertion(-500907, (is_umetric_valid(alg->exp_offset, &rec->umetric_fast))); + assertion(-500908, (is_umetric_valid(alg->exp_offset, &rec->umetric_final))); + + if (((rec->sqn_bit_mask)&(rec->clr - min)) >= range) { + + if (rec->clr) { + dbgf(DBGL_CHANGES, DBGT_ERR, "sqn_bit_mask=0x%X clr=%d out of range, in=%d valid_min=%d defined_range=%d", + rec->sqn_bit_mask, rec->clr, in, min, range); + } + + reconfigure_metric_record_position(rec, alg, min, in, 0, YES/*reset_metric*/); + } + + if (probe && !is_umetric_valid(alg->exp_offset, probe)) { + + scenario = "probe contains illegal value"; + goto update_metric_error; + + } else if (((rec->sqn_bit_mask)&(in - min)) >= range) { + + scenario = "in out of defined_range (sector J)"; + goto update_metric_error; + + } else if (((rec->sqn_bit_mask)&(rec->clr - min)) >= range) { + + scenario = "clr out of defined_range (sector J)"; + goto update_metric_error; + + } else if (((rec->sqn_bit_mask)&(rec->clr - rec->set)) > 1) { + + scenario = "set invalid (compared to clr)"; + goto update_metric_error; + } + + + if (UXX_LE(rec->sqn_bit_mask, in, (rec->clr - alg->window_size))) { + + scenario = "in within valid past (sector I|H)"; + goto update_metric_success; + + } else if (in == rec->set) { + + //scenario = "in within (closed) window, in == set (sector E)"; + goto update_metric_success; + + } else if (UXX_LE(rec->sqn_bit_mask, in, rec->set)) { + + scenario = "in within (closed) window, in < set (sector F|G)"; + goto update_metric_success; + + } else if (probe) { + + dbgf_all(DBGT_INFO,"in=%d min=%d range=%d clr=%d", in, min, range, rec->clr); + assertion(-500708, (UXX_LE(rec->sqn_bit_mask, in, min + range))); + assertion(-500721, (UXX_GE(rec->sqn_bit_mask, in, rec->clr))); + + purge = ((rec->sqn_bit_mask)&(in - rec->clr)); + + if (purge > 2) + scenario = "resetting and updating: probe!=NULL, in within lounge or valid future (sector E|D|C|B|A)"; + + if (alg->wavg_slow == 1 /*|| alg->flags & TYP_METRIC_FLAG_STRAIGHT*/) { + + rec->umetric_slow = rec->umetric_fast = rec->umetric_final = *probe; + + } else { + + if (purge < alg->window_size) { + + for (i = 0; i < purge; i++) + rec->umetric_slow -= (rec->umetric_slow / alg->wavg_slow); + } else { + reconfigure_metric_record_position(rec, alg, min, in, 0, YES/*reset_metric*/); + } + + if ((rec->umetric_slow += (*probe / alg->wavg_slow)) > *probe) { + dbgf(DBGL_CHANGES, DBGT_WARN, "resulting path metric_slow=%ju > probe=%ju", + rec->umetric_slow, *probe); + rec->umetric_slow = *probe; + } + + if (alg->wavg_slow > alg->wavg_fast) { + + if (purge < alg->window_size) { + + for (i = 0; i < purge; i++) + rec->umetric_fast -= (rec->umetric_fast / alg->wavg_fast); + } + + if ((rec->umetric_fast += (*probe / alg->wavg_fast)) > *probe) { + dbgf(DBGL_CHANGES, DBGT_WARN, "resulting path metric_fast=%ju > probe=%ju", + rec->umetric_fast, *probe); + rec->umetric_fast = *probe; + } + + if (rec->umetric_slow * (alg->wavg_correction + 1) > rec->umetric_fast) { + + rec->umetric_final = + (rec->umetric_slow + (rec->umetric_slow / alg->wavg_correction)) - + (rec->umetric_fast / alg->wavg_correction); + } else { + rec->umetric_final = 0; + } + + if (rec->umetric_final > *probe) { + dbgf(DBGL_CHANGES, DBGT_WARN, "resulting path metric_final=%ju > probe=%ju", + rec->umetric_final, *probe); + rec->umetric_final = *probe; + } + + } else { + rec->umetric_final = rec->umetric_fast = rec->umetric_slow; + } + } + + rec->clr = rec->set = in; + + + } else if (UXX_LE(rec->sqn_bit_mask, in, rec->clr + alg->lounge_size)) { + + //scenario = "ignoring: probe==NULL, in within lounge (sector E,D,C)"; + + } else { + + assertion(-500709, (UXX_LE(rec->sqn_bit_mask, in, min + range))); +//[20609 1347921] ERROR metric_record_init: reset_metric=0 sqn_bit_size=0 sqn_bit_mask=0xFF clr=186 to ((in=188) - (lounge=1))=187 + + purge = ((rec->sqn_bit_mask)&((in - alg->lounge_size) - rec->clr)); + + if (purge > 2) + scenario = "purging: probe==NULL, in within valid future (sector B|A)"; + + assertion(-500710, (purge > 0)); + + if (purge >= alg->window_size) { + + reconfigure_metric_record_position(rec, alg, min, in, 0, YES/*reset_metric*/); + + } else { + + for (i = 0; i < purge; i++) + rec->umetric_slow -= (rec->umetric_slow / alg->wavg_slow); + + if (alg->wavg_slow > alg->wavg_fast) { + + for (i = 0; i < purge; i++) + rec->umetric_fast -= (rec->umetric_fast / alg->wavg_fast); + + if (rec->umetric_slow * (alg->wavg_correction + 1) > rec->umetric_fast) { + rec->umetric_final = + (rec->umetric_slow + (rec->umetric_slow / alg->wavg_correction)) - + (rec->umetric_fast / alg->wavg_correction); + } else { + rec->umetric_final = 0; + } + + } else { + rec->umetric_final = rec->umetric_fast = rec->umetric_slow; + } + + + reconfigure_metric_record_position(rec, alg, min, in, 0, NO/*reset_metric*/); + } + } + + assertion(-500711, (is_umetric_valid(alg->exp_offset, &rec->umetric_slow))); + assertion(-500909, (is_umetric_valid(alg->exp_offset, &rec->umetric_fast))); + assertion(-500910, (is_umetric_valid(alg->exp_offset, &rec->umetric_final))); + + goto update_metric_success; + + + + IDM_T ret = FAILURE; + +update_metric_success: + ret = SUCCESS; + +update_metric_error: + + if (scenario) { + dbgf(DBGL_CHANGES, ret == FAILURE ? DBGT_ERR : DBGT_WARN, + "[%s] sqn_bit_mask=0x%X in=%d clr=%d>%d set=%d>%d valid_min=%d range=%d lounge=%d window=%d purge=%d probe=%ju ", + scenario, rec->sqn_bit_mask, in, dbg_clr, rec->clr, dbg_set, rec->set, min, range, alg->lounge_size, alg->window_size, purge, probe ? *probe : 0); + } + + + EXITERROR(-500712, (ret != FAILURE)); + + if (on && &on->curr_rn->mr == rec && rec->umetric_final < on->path_metricalgo->umetric_min) + set_ogmSqn_toBeSend_and_aggregated(on, on->ogmSqn_aggregated, on->ogmSqn_aggregated); + + return ret; +} + +STATIC_FUNC +void purge_rq_metrics(void *link_node_pointer) +{ + TRACE_FUNCTION_CALL; + struct link_node *ln = link_node_pointer; + assertion(-500731, (link_node_pointer == avl_find_item(&link_tree, &ln->link_id))); + struct link_dev_node *lndev = list_get_first(&ln->lndev_list); + + //assertion(-500843, (ln->neigh && ln->neigh->dhn)); this can disappear ?????????? + if (lndev && ln && lndev->key.link == ln && ln->neigh && ln->neigh->dhn ) { + + if (ln->rq_purge_interval) { + + HELLO_FLAGS_SQN_T sqn = (HELLO_SQN_MASK & (lndev->mr[SQR_RQ].clr + 1)); + update_link_metrics(lndev, 0, sqn, sqn, SQR_RQ, NULL); + + if ((--ln->rq_purge_iterations) && lndev->mr[SQR_RQ].umetric_final) { + register_task(ln->rq_purge_interval, purge_rq_metrics, ln); + + } else { + lndev->mr[SQR_RQ].umetric_slow = 0; + lndev->mr[SQR_RQ].umetric_fast = 0; + lndev->mr[SQR_RQ].umetric_final = 0; + lndev->umetric_link = 0; + ln->rq_purge_interval = 0; + } + + + } else { + + HELLO_FLAGS_SQN_T sqn_diff = (HELLO_SQN_MASK& (ln->rq_hello_sqn_max - ln->rq_hello_sqn_max_prev)); + TIME_T interval = ((TIME_T) (ln->rq_time_max - ln->rq_time_max_prev)); + + if (ln->rq_hello_sqn_max && ln->rq_hello_sqn_max_prev && + sqn_diff && sqn_diff < my_link_window && + interval && interval < ((uint32_t)(my_link_window * MAX_TX_INTERVAL)) + ) { + + ln->rq_purge_iterations = my_link_window; + + ln->rq_purge_interval = (((interval / sqn_diff) * 5) / 4); + + register_task(ln->rq_purge_interval, purge_rq_metrics, ln); + } + } + + } else { + dbgf(DBGL_SYS, DBGT_ERR, "ln=%s disappeared! lndev=%p, ln->neigh=%p", + ipXAsStr(af_cfg, ln ? &ln->link_ip : &ZERO_IP), (void*)(lndev), (void*)(ln ? ln->neigh : NULL)); + } +} + + +STATIC_FUNC +void linkdev_create(struct link_dev_node *lndev) +{ + reconfigure_metric_record_position(&(lndev->mr[SQR_RTQ]), &(link_metric_algo[SQR_RTQ]), + ((HELLO_SQN_MASK)& (lndev->key.dev->link_hello_sqn - link_metric_algo[SQR_RTQ].lounge_size)), + lndev->key.dev->link_hello_sqn, HELLO_SQN_BIT_SIZE, YES/*reset_metric*/); + + reconfigure_metric_record_position(&(lndev->mr[SQR_RQ]), &(link_metric_algo[SQR_RQ]), 0, + 0, HELLO_SQN_BIT_SIZE, YES/*reset_metric*/); + + lndev->umetric_link = 0; +} + + +STATIC_FUNC +void remove_task_purge_rq_metrics( struct link_node *ln ) +{ + remove_task(purge_rq_metrics, ln); +} + + + + + +void update_link_metrics(struct link_dev_node *lndev, IID_T transmittersIID, + HELLO_FLAGS_SQN_T sqn, HELLO_FLAGS_SQN_T valid_max, uint8_t sqr, UMETRIC_T *probe) +{ + TRACE_FUNCTION_CALL; + struct link_node *ln = lndev->key.link; + struct dev_node *dev = lndev->key.dev; + struct list_node *lndev_pos; + struct link_dev_node *this_lndev = NULL; + HELLO_FLAGS_SQN_T valid_min = ((HELLO_SQN_MASK)&(valid_max + 1 - DEF_HELLO_SQN_RANGE)); + + + list_for_each(lndev_pos, &ln->lndev_list) + { + struct link_dev_node *lnd = list_entry(lndev_pos, struct link_dev_node, list); + + update_metric_record(NULL, &lndev->mr[sqr], &link_metric_algo[sqr], DEF_HELLO_SQN_RANGE, valid_min, sqn, + lnd == lndev ? probe : NULL); + + if (sqr == SQR_RTQ) { + + // this hits if node is blocked + //assertion(-500921, (IMPLIES(ln->neigh, ln->neigh->dhn && ln->neigh->dhn->on && ln->neigh->dhn->on->path_metricalgo))); + + if (ln->neigh && ln->neigh->dhn && ln->neigh->dhn->on && !ln->neigh->dhn->on->blocked) { + + assertion(-500921, (ln->neigh->dhn->on->path_metricalgo)); + + UMETRIC_T max = umetric_max(ln->neigh->dhn->on->path_metricalgo->exp_offset); + apply_metric_algo(&lnd->umetric_link, lnd, &max ,ln->neigh->dhn->on->path_metricalgo); + } else { + lnd->umetric_link = 0; + } + + } + + + if (lnd->key.dev == dev) { + assertion(-500912,(lnd == lndev)); + this_lndev = lnd; + continue; + } + assertion(-500913, (lnd != lndev)); + + //update_metric_record(NULL, &lnd->mr[sqr], &link_metric_algo[sqr], DEF_HELLO_SQN_RANGE, valid_min, sqn, NULL); + } + + assertion(-500732, (lndev == this_lndev)); + + //update_metric_record(NULL, &lndev->mr[sqr], &link_metric_algo[sqr], DEF_HELLO_SQN_RANGE, valid_min, sqn, probe); + + + if (probe) { + + if (sqr == SQR_RTQ) { + + lndev->rtq_time_max = bmx_time; + + if ( + ln->neigh && + (!ln->neigh->best_rtq || + ln->neigh->best_rtq->mr[SQR_RTQ].umetric_final <= lndev->mr[SQR_RTQ].umetric_final)) { + + ln->neigh->best_rtq = lndev; + } + + } else { + assertion(-500733, (sqr == SQR_RQ)); + + ln->rq_time_max_prev = ln->rq_time_max; + ln->rq_time_max = bmx_time; + + ln->rq_hello_sqn_max_prev = ln->rq_hello_sqn_max; + ln->rq_hello_sqn_max = sqn; + + ln->rq_purge_interval = 0; + + remove_task(purge_rq_metrics, ln); + + if (ln->neigh && ln->neigh->dhn && + ln->neigh->dhn == iid_get_node_by_neighIID4x(ln->neigh, transmittersIID)) { + + purge_rq_metrics(ln); + } + } + } + + dbgf_all(DBGT_INFO, "%s dev %s metric %ju", ipXAsStr(af_cfg, &ln->link_ip), dev->label_cfg.str, lndev->mr[sqr].umetric_final); +} + + +IDM_T update_path_metrics(struct packet_buff *pb, struct orig_node *on, OGM_SQN_T in_sqn, UMETRIC_T *in_umetric) +{ + TRACE_FUNCTION_CALL; + assertion(-500876, (!on->blocked)); + assertion(-500734, (on->path_metricalgo)); + ASSERTION(-500735, (!((~(OGM_SQN_MASK))&(in_sqn)))); + ASSERTION(-500736, (!((~(OGM_SQN_MASK))&(on->ogmSqn_maxRcvd)))); + + + struct host_metricalgo *algo = on->path_metricalgo; + struct router_node *in_rn = NULL; + OGM_SQN_T ogm_sqn_max_rcvd = UXX_GET_MAX(OGM_SQN_MASK, on->ogmSqn_maxRcvd, in_sqn); + + + dbgf_all(DBGT_INFO, "%s orig_sqn %d via neigh %s", on->id.name, in_sqn, pb->i.llip_str); + + if (!is_ip_set(&on->primary_ip)) + return FAILURE; + + if ((((OGM_SQN_MASK)&(in_sqn - on->ogmSqn_rangeMin)) >= on->ogmSqn_rangeSize)) + return FAILURE; + + if (UXX_LT(OGM_SQN_MASK, in_sqn, (OGM_SQN_MASK & (ogm_sqn_max_rcvd - algo->lounge_size)))) { + + dbgf(DBGL_SYS, DBGT_WARN, "dropping late ogm_sqn=%d (max_rcvd=%d lounge_size=%d) from orig=%s via neigh=%s", + in_sqn, ogm_sqn_max_rcvd, algo->lounge_size, on->id.name, pb->i.llip_str); + + return SUCCESS; + } + + UMETRIC_T upd_metric; + apply_metric_algo(&upd_metric, pb->i.lndev, in_umetric, algo); + + + if (UXX_LE(OGM_SQN_MASK, in_sqn, on->ogmSqn_toBeSend) && + upd_metric <= on->metricSqnMaxArr[in_sqn % (algo->lounge_size + 1)]) { + + if ((in_rn = avl_find_item(&on->rt_tree, &pb->i.lndev->key))) { + + upd_metric = 0; + update_metric_record(on, &in_rn->mr, algo, on->ogmSqn_rangeSize, on->ogmSqn_rangeMin, in_sqn, &upd_metric); + + if (in_rn == on->best_rn) + on->best_rn = NULL; + + } + + return SUCCESS; + + } else { + + OGM_SQN_T i = in_sqn; + while (UXX_GE(OGM_SQN_MASK, i, (ogm_sqn_max_rcvd - algo->lounge_size))) { + + if ((UXX_GT(OGM_SQN_MASK, i, on->ogmSqn_maxRcvd)) || + (on->metricSqnMaxArr[i % (algo->lounge_size + 1)] < upd_metric)) { + + on->metricSqnMaxArr[i % (algo->lounge_size + 1)] = upd_metric; + i = (OGM_SQN_MASK & (i - 1)); + + } else { + + break; + } + } + } + + + if (!on->best_rn || UXX_LT(OGM_SQN_MASK, on->ogmSqn_maxRcvd, in_sqn)) { + + struct router_node *rn; + struct avl_node *an; + on->best_rn = NULL; + + for (an = NULL; (rn = avl_iterate_item(&on->rt_tree, &an));) { + + ASSERTION(-500580, (avl_find(&link_dev_tree, &rn->key))); + + if (!in_rn && equal_link_key(&rn->key, &pb->i.lndev->key)) { + + in_rn = rn; + + } else { + + update_metric_record(on, &rn->mr, algo, on->ogmSqn_rangeSize, on->ogmSqn_rangeMin, ogm_sqn_max_rcvd, NULL); + + if (!on->best_rn || on->best_rn->mr.umetric_final < rn->mr.umetric_final) + on->best_rn = rn; + } + } + + + } else { + // already cleaned up, simple keep last best_router_node: + in_rn = avl_find_item(&on->rt_tree, &pb->i.lndev->key); + } + + if (!in_rn) { + + in_rn = debugMalloc(sizeof (struct router_node), -300222); + memset( in_rn, 0, sizeof(struct router_node)); + + in_rn->key = pb->i.lndev->key; + + reconfigure_metric_record_position(&in_rn->mr, algo, on->ogmSqn_rangeMin, ogm_sqn_max_rcvd, OGM_SQN_BIT_SIZE, YES/*reset_metric*/); + + avl_insert(&on->rt_tree, in_rn, -300223); + + dbgf(DBGL_CHANGES, DBGT_INFO, "new router_node %s to %s (total %d)", + ipXAsStr(af_cfg, &in_rn->key.link->link_ip), on->id.name, on->rt_tree.items); + } + +#ifndef NO_DEBUG_ALL + struct router_node *old_rn = on->curr_rn; + OGM_SQN_T old_set = in_rn->mr.set; + UMETRIC_T old_metric = in_rn->mr.umetric_final; + OGM_SQN_T old_ogm_sqn_to_be_send = on->ogmSqn_toBeSend; + UMETRIC_T old_curr_metric = old_rn ? old_rn->mr.umetric_final : 0; +#endif + + update_metric_record(on, &in_rn->mr, algo, on->ogmSqn_rangeSize, on->ogmSqn_rangeMin, in_sqn, &upd_metric); + + + if (UXX_GT(OGM_SQN_MASK, ogm_sqn_max_rcvd, in_sqn)) + update_metric_record(on, &in_rn->mr, algo, on->ogmSqn_rangeSize, on->ogmSqn_rangeMin, ogm_sqn_max_rcvd, NULL); + + // the best RN has a better metric and betterOrEqual sqn than all other RNs + + if (!on->best_rn || on->best_rn->mr.umetric_final <= in_rn->mr.umetric_final) + on->best_rn = in_rn; + + if (on->curr_rn && on->best_rn->mr.umetric_final <= on->curr_rn->mr.umetric_final) + on->best_rn = on->curr_rn; + + if (UXX_GT(OGM_SQN_MASK, on->best_rn->mr.set, on->ogmSqn_toBeSend) ) { + + if (on->best_rn->mr.umetric_final >= algo->umetric_min) { + + set_ogmSqn_toBeSend_and_aggregated(on, on->best_rn->mr.set, on->ogmSqn_aggregated); + + if (on->best_rn != on->curr_rn ) { + + ASSERTION(-500695, (!(on->curr_rn && !avl_find_item(&link_dev_tree, &on->curr_rn->key)))); + + dbgf(DBGL_CHANGES, DBGT_INFO, + "changing router to %s %s via %s %s metric=%ju (prev %s %s metric=%ju sqn_max=%d sqn_in=%d)", + on->id.name, on->primary_ip_str, ipXAsStr(af_cfg, &on->best_rn->key.link->link_ip), + on->best_rn->key.dev->label_cfg.str, on->best_rn->mr.umetric_final, + ipXAsStr(af_cfg, on->curr_rn ? &on->curr_rn->key.link->link_ip : &ZERO_IP), + on->curr_rn ? on->curr_rn->key.dev->label_cfg.str : "---", + on->curr_rn ? on->curr_rn->mr.umetric_final : 0, + ogm_sqn_max_rcvd, in_sqn); + + if (on->curr_rn) + cb_route_change_hooks(DEL, on); + + on->curr_rn = on->best_rn; + + cb_route_change_hooks(ADD, on); + } + + } else { + + if (on->curr_rn) + cb_route_change_hooks(DEL, on); + + on->curr_rn = NULL; + + } + } + +#ifndef NO_DEBUG_ALL + dbgf(DBGL_ALL, ((in_sqn != ((in_rn->mr.sqn_bit_mask)&(old_set + 1))) ? DBGT_ERR : DBGT_INFO), + "orig=%s self=%s dev=%s oldInSet=%-5d oldInMax=%-5d old_to_send=%-5d oldInMetric=%-10ju " + " inSqn=%-5d newInMax=%-5d new_to_send=%-5d metricAlgo( inMetric=%-10ju )=%-10ju" + "inVia=%s newInSet=%-5d newInMetric=%-10ju " + "oldRt=%s oldRtSet=%-5d oldRtMetric=%-10ju newRT=%s newRtSet=%-5d newRtMetric=%-10ju bestRt=%s bestRtSet=%-5d bestRtMetric=%-10ju %s", + on->id.name, self.id.name, pb->i.iif->label_cfg.str, old_set, on->ogmSqn_maxRcvd, old_ogm_sqn_to_be_send, old_metric, + in_sqn, ogm_sqn_max_rcvd, on->ogmSqn_toBeSend, *in_umetric, upd_metric, + pb->i.llip_str, in_rn->mr.set, in_rn->mr.umetric_final, + ipXAsStr(af_cfg, old_rn ? &old_rn->key.link->link_ip : &ZERO_IP), + old_rn ? old_rn->mr.set : 0, old_curr_metric, + ipXAsStr(af_cfg, on->curr_rn ? &on->curr_rn->key.link->link_ip : &ZERO_IP), + on->curr_rn ? on->curr_rn->mr.set : 0, on->curr_rn ? on->curr_rn->mr.umetric_final : 0, + ipXAsStr(af_cfg, &on->best_rn->key.link->link_ip), on->best_rn ? on->best_rn->mr.set : 0, + on->best_rn->mr.umetric_final, + UXX_GT(OGM_SQN_MASK, on->ogmSqn_toBeSend, old_ogm_sqn_to_be_send) ? "TO_BE_SEND" : " "); +#endif + on->ogmSqn_maxRcvd = ogm_sqn_max_rcvd; + + return SUCCESS; +} + + + + +STATIC_FUNC +IDM_T validate_metricalgo(struct host_metricalgo *ma, struct ctrl_node *cn) +{ + TRACE_FUNCTION_CALL; + + if ( + validate_param((ma->exp_offset), MIN_FMETRIC_EXP_OFFSET, MAX_FMETRIC_EXP_OFFSET,ARG_FMETRIC_EXP_OFFSET) || + validate_param((ma->fmetric_mantissa_min), MIN_FMETRIC_MANTISSA_MIN, MAX_FMETRIC_MANTISSA_MIN, ARG_FMETRIC_MANTISSA_MIN) || + validate_param((ma->fmetric_exp_reduced_min), MIN_FMETRIC_EXPONENT_MIN, MAX_FMETRIC_EXPONENT_MIN, ARG_FMETRIC_EXPONENT_MIN) || + validate_param((ma->algo_type), MIN_METRIC_ALGO, MAX_METRIC_ALGO, ARG_PATH_METRIC_ALGO) || + validate_param((ma->flags), MIN_METRIC_FLAGS, MAX_METRIC_FLAGS, ARG_PATH_METRIC_FLAGS) || + validate_param((ma->window_size), MIN_PATH_WINDOW, MAX_PATH_WINDOW, ARG_PATH_WINDOW) || + validate_param((ma->lounge_size), MIN_PATH_LOUNGE, MAX_PATH_LOUNGE, ARG_PATH_LOUNGE) || + validate_param((ma->wavg_slow), MIN_PATH_REGRESSION_SLOW, MAX_PATH_REGRESSION_SLOW, ARG_PATH_REGRESSION_SLOW) || + validate_param((ma->wavg_fast), MIN_PATH_REGRESSION_FAST, MAX_PATH_REGRESSION_FAST, ARG_PATH_REGRESSION_FAST) || + validate_param((ma->wavg_correction), MIN_PATH_REGRESSION_DIFF, MAX_PATH_REGRESSION_DIFF, ARG_PATH_REGRESSION_DIFF) || + validate_param((ma->hystere), MIN_PATH_HYST, MAX_PATH_HYST, ARG_PATH_HYST) || + validate_param((ma->hop_penalty), MIN_HOP_PENALTY, MAX_HOP_PENALTY, ARG_HOP_PENALTY) || + validate_param((ma->late_penalty), MIN_LATE_PENAL, MAX_LATE_PENAL, ARG_LATE_PENAL) || + 0) { + + EXITERROR(-500755, (0)); + + return FAILURE; + } + + + return SUCCESS; +} + + +STATIC_FUNC +IDM_T metricalgo_tlv_to_host(struct description_tlv_metricalgo *tlv_algo, struct host_metricalgo *host_algo, uint16_t size) +{ + TRACE_FUNCTION_CALL; + memset(host_algo, 0, sizeof (struct host_metricalgo)); + + if (size < sizeof (struct mandatory_tlv_metricalgo)) + return FAILURE; + + host_algo->exp_offset = tlv_algo->m.exp_offset; + host_algo->fmetric_mantissa_min = tlv_algo->m.fmetric_mantissa_min; + host_algo->fmetric_exp_reduced_min = tlv_algo->m.fmetric_exp_reduced_min; + host_algo->algo_type = ntohs(tlv_algo->m.algo_type); + host_algo->flags = ntohs(tlv_algo->m.flags); + host_algo->window_size = tlv_algo->m.path_window_size; + host_algo->lounge_size = tlv_algo->m.path_lounge_size; + host_algo->wavg_slow = tlv_algo->m.wavg_slow; + host_algo->wavg_fast = tlv_algo->m.wavg_fast; + host_algo->wavg_correction = tlv_algo->m.wavg_correction; + host_algo->hystere = tlv_algo->m.hystere; + host_algo->hop_penalty = tlv_algo->m.hop_penalty; + host_algo->late_penalty = tlv_algo->m.late_penalty; + + if (validate_metricalgo(host_algo, NULL) == FAILURE) + return FAILURE; + + + host_algo->umetric_min = MAX( + umetric(host_algo->fmetric_mantissa_min, host_algo->fmetric_exp_reduced_min, host_algo->exp_offset), + umetric(FMETRIC_MANTISSA_ROUTABLE, 0, host_algo->exp_offset)); + + return SUCCESS; +} + + +STATIC_FUNC +int create_description_tlv_metricalgo(struct tx_frame_iterator *it) +{ + TRACE_FUNCTION_CALL; + struct description_tlv_metricalgo tlv_algo; + + dbgf(DBGL_CHANGES, DBGT_INFO, " size %zu", sizeof (struct description_tlv_metricalgo)); + + memset(&tlv_algo, 0, sizeof (struct description_tlv_metricalgo)); + + tlv_algo.m.exp_offset = DEF_FMETRIC_EXP_OFFSET; + tlv_algo.m.fmetric_mantissa_min = DEF_FMETRIC_MANTISSA_MIN; + tlv_algo.m.fmetric_exp_reduced_min = my_fmetric_exp_min; + tlv_algo.m.algo_type = htons(my_path_metricalgo); //METRIC_ALGO + tlv_algo.m.flags = htons(my_path_metric_flags); + tlv_algo.m.path_window_size = my_path_window; + tlv_algo.m.path_lounge_size = my_path_lounge; + tlv_algo.m.wavg_slow = my_path_regression_slow; + tlv_algo.m.wavg_fast = my_path_regression_fast; + tlv_algo.m.wavg_correction = my_path_regression_diff; + tlv_algo.m.hystere = my_path_hystere; + tlv_algo.m.hop_penalty = my_hop_penalty; + tlv_algo.m.late_penalty = my_late_penalty; + + if (self.path_metricalgo) + debugFree(self.path_metricalgo, -300282); + + self.path_metricalgo = debugMalloc(sizeof ( struct host_metricalgo), -300283); + + + if (metricalgo_tlv_to_host(&tlv_algo, self.path_metricalgo, sizeof (struct description_tlv_metricalgo)) == FAILURE) + cleanup_all(-500844); + + if (tx_iterator_cache_data_space(it) < ((int) sizeof (struct description_tlv_metricalgo))) { + + dbgf(DBGL_SYS, DBGT_ERR, "unable to announce metric due to limiting --%s", ARG_UDPD_SIZE); + return TLV_DATA_FAILURE; + } + + memcpy(((struct description_tlv_metricalgo *) tx_iterator_cache_msg_ptr(it)), &tlv_algo, + sizeof (struct description_tlv_metricalgo)); + + return sizeof (struct description_tlv_metricalgo); +} + + +STATIC_FUNC +void dbg_metrics_status(struct ctrl_node *cn) +{ + TRACE_FUNCTION_CALL; + + dbg_printf(cn, "%s=%d %s=%d %s=%d %s=%d %s=%d\n", + ARG_LINK_REGRESSION_SLOW, link_metric_algo[SQR_RTQ].wavg_slow, + ARG_LINK_REGRESSION_FAST, link_metric_algo[SQR_RTQ].wavg_fast, + ARG_LINK_REGRESSION_DIFF, link_metric_algo[SQR_RTQ].wavg_correction, + ARG_LINK_RTQ_LOUNGE, link_metric_algo[SQR_RTQ].lounge_size, + ARG_LINK_WINDOW, link_metric_algo[SQR_RTQ].window_size); + + process_description_tlvs(NULL, &self, self.desc, TLV_OP_DEBUG, BMX_DSC_TLV_METRIC, cn); + +} + +STATIC_FUNC +void dbg_metricalgo(struct ctrl_node *cn, struct host_metricalgo *host_algo) +{ + TRACE_FUNCTION_CALL; + + dbg_printf(cn, "%s=%d %s=%d %s=%d %s=%ju %s=%d %s=0x%X %s=%d %s=%d %s=%d %s=%d %s=%d %s=%d %s=%d %s=%d\n", + ARG_FMETRIC_EXP_OFFSET, host_algo->exp_offset, + ARG_FMETRIC_MANTISSA_MIN, host_algo->fmetric_mantissa_min, + ARG_FMETRIC_EXPONENT_MIN, host_algo->fmetric_exp_reduced_min, + "umetric_min", host_algo->umetric_min, + ARG_PATH_METRIC_ALGO, host_algo->algo_type, + ARG_PATH_METRIC_FLAGS, host_algo->flags, + + ARG_PATH_REGRESSION_SLOW, host_algo->wavg_slow, + ARG_PATH_REGRESSION_FAST, host_algo->wavg_fast, + ARG_PATH_REGRESSION_DIFF, host_algo->wavg_correction, + ARG_PATH_LOUNGE, host_algo->lounge_size, + ARG_PATH_WINDOW, host_algo->window_size, + ARG_PATH_HYST, host_algo->hystere, + ARG_HOP_PENALTY, host_algo->hop_penalty, + ARG_LATE_PENAL, host_algo->late_penalty); +} + +STATIC_FUNC +int process_description_tlv_metricalgo(struct rx_frame_iterator *it ) +{ + TRACE_FUNCTION_CALL; + assertion(-500683, (it->frame_type == BMX_DSC_TLV_METRIC)); + assertion(-500684, (it->on)); + + struct orig_node *on = it->on; + IDM_T op = it->op; + + struct description_tlv_metricalgo *tlv_algo = (struct description_tlv_metricalgo *) (it->frame_data); + struct host_metricalgo host_algo; + + dbgf_all( DBGT_INFO, "%s ", tlv_op_str[op]); + + if (op == TLV_OP_DEL) { + + if (on->path_metricalgo) { + debugFree(on->path_metricalgo, -300285); + on->path_metricalgo = NULL; + } + + if (on->metricSqnMaxArr) { + debugFree(on->metricSqnMaxArr, -300307); + on->metricSqnMaxArr = NULL; + } + + + } else if (!(op == TLV_OP_TEST || op == TLV_OP_ADD || op == TLV_OP_DEBUG)) { + + return it->frame_data_length; + } + + if (metricalgo_tlv_to_host(tlv_algo, &host_algo, it->frame_data_length) == FAILURE) + return FAILURE; + + + if (op == TLV_OP_ADD) { + + assertion(-500684, (!on->path_metricalgo)); + + on->path_metricalgo = debugMalloc(sizeof (struct host_metricalgo), -300286); + + memcpy(on->path_metricalgo, &host_algo, sizeof (struct host_metricalgo)); + + on->metricSqnMaxArr = debugMalloc(((on->path_metricalgo->lounge_size + 1) * sizeof (UMETRIC_T)), -300308); + memset(on->metricSqnMaxArr, 0, ((on->path_metricalgo->lounge_size + 1) * sizeof (UMETRIC_T))); + + // migrate current router_nodes->mr.clr position to new sqn_range: + struct router_node *rn; + struct avl_node *an; + + for (an = NULL; (rn = avl_iterate_item(&on->rt_tree, &an));) { + + reconfigure_metric_record_position(&rn->mr, on->path_metricalgo, on->ogmSqn_rangeMin, on->ogmSqn_rangeMin, 0, NO); + +/* + OGM_SQN_T in = ((OGM_SQN_MASK)&(on->ogmSqn_rangeMin + on->path_metricalgo->lounge_size)); + reconfigure_metric_record(&rn->mr, on->path_metricalgo, on->ogmSqn_rangeMin, in, 0, NO); +*/ + + } + + + } else if (op == TLV_OP_DEBUG) { + + dbg_metricalgo(it->cn, &host_algo); + + } + + return it->frame_data_length; +} + + + + + + + +STATIC_FUNC +int32_t opt_link_metricalgo(uint8_t cmd, uint8_t _save, struct opt_type *opt, struct opt_parent *patch, struct ctrl_node *cn) +{ + TRACE_FUNCTION_CALL; + + if (cmd == OPT_CHECK || cmd == OPT_APPLY || cmd == OPT_REGISTER) { + + struct host_metricalgo test_algo[SQR_RANGE]; + + memset(test_algo, 0, sizeof (test_algo)); + + uint8_t r; + for (r = 0; r < SQR_RANGE; r++) { + //test_algo[r].exp_offset = 0; + //test_algo[r].fmetric_to_live = 0; + //test_algo[r].algo_type = 0; + + test_algo[r].flags = (cmd != OPT_REGISTER && !strcmp(opt->long_name, ARG_LINK_METRIC_FLAGS)) ? + strtol(patch->p_val, NULL, 10) :my_link_metric_flags; + + test_algo[r].window_size = (cmd != OPT_REGISTER && !strcmp(opt->long_name, ARG_LINK_WINDOW)) ? + strtol(patch->p_val, NULL, 10) : my_link_window; + + if ( r == SQR_RTQ) + test_algo[SQR_RTQ].lounge_size = (cmd != OPT_REGISTER && !strcmp(opt->long_name, ARG_LINK_RTQ_LOUNGE)) ? + strtol(patch->p_val, NULL, 10) : my_link_rtq_lounge; + else + test_algo[SQR_RQ].lounge_size = RQ_LINK_LOUNGE; + + test_algo[r].wavg_slow = (cmd != OPT_REGISTER && !strcmp(opt->long_name, ARG_LINK_REGRESSION_SLOW)) + ? strtol(patch->p_val, NULL, 10) : my_link_regression_slow; + + test_algo[r].wavg_fast = (cmd != OPT_REGISTER && !strcmp(opt->long_name, ARG_LINK_REGRESSION_FAST)) + ? strtol(patch->p_val, NULL, 10) : my_link_regression_fast; + + test_algo[r].wavg_correction = (cmd != OPT_REGISTER && !strcmp(opt->long_name, ARG_LINK_REGRESSION_DIFF)) + ? strtol(patch->p_val, NULL, 10) : my_link_regression_diff; + + //test_algo[r].hystere = 0; + //test_algo[r].hop_penalty = 0; + //test_algo[r].late_penalty = 0; + + if (validate_metricalgo(&(test_algo[r]), cn) == FAILURE) + return FAILURE; + } + + + if (cmd == OPT_APPLY || cmd == OPT_REGISTER) { + + memcpy( &link_metric_algo, &test_algo, sizeof(test_algo)); + +// my_description_changed = YES; + } + + } + + return SUCCESS; +} + + + +STATIC_FUNC +int32_t opt_path_metricalgo(uint8_t cmd, uint8_t _save, struct opt_type *opt, struct opt_parent *patch, struct ctrl_node *cn) +{ + TRACE_FUNCTION_CALL; + + if (cmd == OPT_REGISTER || cmd == OPT_CHECK || cmd == OPT_APPLY) { + + struct host_metricalgo test_algo; + memset(&test_algo, 0, sizeof (struct host_metricalgo)); + + // only options with a non-zero MIN value and those with illegal compinations must be tested + // other illegal option configurations will be cached by their MIN_... MAX_.. control.c architecture + + //test_algo.algo_type = (cmd != OPT_REGISTER && !strcmp(opt->long_name, ARG_PATH_METRIC_ALGO)) ? + // strtol(patch->p_val, NULL, 10) : my_path_metricalgo; + + //test_algo.flags = (cmd != OPT_REGISTER && !strcmp(opt->long_name, ARG_PATH_METRIC_FLAGS)) ? + // strtol(patch->p_val, NULL, 10) : my_path_metric_flags; + + test_algo.window_size = (cmd != OPT_REGISTER && !strcmp(opt->long_name, ARG_PATH_WINDOW)) ? + strtol(patch->p_val, NULL, 10) : my_path_window; + + test_algo.wavg_slow = (cmd != OPT_REGISTER && !strcmp(opt->long_name, ARG_PATH_REGRESSION_SLOW)) + ? strtol(patch->p_val, NULL, 10) : my_path_regression_slow; + + test_algo.wavg_fast = (cmd != OPT_REGISTER && !strcmp(opt->long_name, ARG_PATH_REGRESSION_FAST)) + ? strtol(patch->p_val, NULL, 10) : my_path_regression_fast; + + test_algo.wavg_correction = (cmd != OPT_REGISTER && !strcmp(opt->long_name, ARG_PATH_REGRESSION_DIFF)) + ? strtol(patch->p_val, NULL, 10) : my_path_regression_diff; + + + if (validate_metricalgo(&test_algo, cn) == FAILURE) + return FAILURE; + + } + + if (cmd == OPT_APPLY) { + + opt_link_metricalgo(cmd, _save, opt, patch, cn); + + my_description_changed = YES; + } + + return SUCCESS; +} + + +#ifdef WITH_UNUSED +int32_t test_value = 0; + +STATIC_FUNC +int32_t opt_test(uint8_t cmd, uint8_t _save, struct opt_type *opt, struct opt_parent *patch, struct ctrl_node *cn) +{ + + if (cmd != OPT_APPLY) + return SUCCESS; + + // test the bit-shift-uint-casting functions: + + + int i; + uint32_t sqn_u32=50, in_u32=50, dad_u32=100; + uint16_t sqn_u16=50, in_u16=50, dad_u16=100; + uint8_t is_u32, is_u16; + + for (i = -2 * U16_MAX; i <= 2 * U16_MAX; i++) { + //in_u32 = in_u16 = i; + //sqn_u32 = sqn_u16 = i; + dad_u32 = dad_u16 = i; + if ((is_u16 = (((uint16_t) (sqn_u16 - in_u16)) < dad_u16)) != + (is_u32 = (((U32_MAX >> 16)&(sqn_u32 - in_u32)) < dad_u32))) { + + dbgf_cn(cn, DBGL_SYS, DBGT_ERR, "testing bit-shift-uint-casting i=%d failed", i); + + } + } + + // test the fmetric_to_umetric() and umetric_to_fmetric() converter functions: + + float error_max = 0; + + UMETRIC_T in_max = umetric_max(DEF_FMETRIC_EXP_OFFSET); // (in_max_a * in_max_b);//((uint64_t) - 1); //(in_max_a * in_max_b); + + UMETRIC_T in_min = 0;//1 << DEF_EXPONENT_OFFSET; //0; // 1 << DEF_EXPONENT_OFFSET; + + UMETRIC_T in = in_min; + + + while(1) { + + + FMETRIC_T fm = umetric_to_fmetric(DEF_FMETRIC_EXP_OFFSET, in); + + UMETRIC_T out = fmetric_to_umetric(fm); + float error = (((float) in) - ((float) out)) / ((float) MAX(in,1)); + + dbgf_cn(cn, DBGL_SYS, DBGT_INFO, + "in: %20ju (mant=%-2u exp_total=%-2u) out: %20ju %4ju %.2e error: %8.3f %c", + in, fm.val.f.mantissa, fm.val.f.exp_total, out, + ((out << 10) / umetric_max(DEF_FMETRIC_EXP_OFFSET)), ((float) out), error * 100, '%'); + + error = error < 0 ? -error : error; + error_max = MAX(error, error_max); + + + UMETRIC_T add = ((in * (UMETRIC_T)test_value) / 1024); + + add = (add ? add : 1); + + if (in >= in_max) + break; + + if ((in_max - add) > in) + in += add; + + else + in = in_max; + + + } + + + dbgf_cn(cn, DBGL_SYS, DBGT_INFO, "in_min=%ju in_max=%ju %ju/1000 %.3e steps=%d error_max=%.3f %c", + in_min, in_max, + ((in_max << 10) / umetric_max(DEF_FMETRIC_EXP_OFFSET)), + ((float) in_max), test_value, 100 * error_max, '%'); + + cleanup_all(CLEANUP_SUCCESS); + + return SUCCESS; +} +#endif + +STATIC_FUNC +struct opt_type metrics_options[]= +{ +// ord parent long_name shrt Attributes *ival min max default *func,*syntax,*help + + {ODI, 0,0, 0, 0,0,0,0,0,0, 0, 0, 0, 0, 0, + 0, "\nMetric options:"} +, +#ifdef WITH_UNUSED + {ODI, 0, "test_metric", 0, 0, A_PS1, A_USR, A_INI, A_ARG, A_ANY, &test_value, 1, (((uint32_t)-1)>>1), 0, opt_test, + ARG_VALUE_FORM, "test metric stuff like floating-point function"} +, + {ODI, 0, ARG_PATH_HYST, 0, 5,A_PS1,A_ADM,A_DYI,A_CFA,A_ANY, &my_path_hystere,MIN_PATH_HYST, MAX_PATH_HYST, DEF_PATH_HYST, opt_path_metricalgo, + ARG_VALUE_FORM, "use hysteresis to delay route switching to alternative next-hop neighbors with better path metric"} + , + // there SHOULD! be a minimal lateness_penalty >= 1 ! Otherwise a shorter path with equal path-cost than a longer path will never dominate + {ODI, 0, ARG_LATE_PENAL, 0, 5,A_PS1,A_ADM,A_DYI,A_CFA,A_ANY, &my_late_penalty,MIN_LATE_PENAL,MAX_LATE_PENAL, DEF_LATE_PENAL, opt_path_metricalgo, + ARG_VALUE_FORM, "penalize non-first rcvd OGMs "} + , + +#endif +#ifndef LESS_OPTIONS + {ODI, 0, ARG_PATH_METRIC_ALGO, 0, 5, A_PS1, A_ADM, A_DYI, A_CFA, A_ANY, &my_path_metricalgo,MIN_METRIC_ALGO, MAX_METRIC_ALGO, DEF_METRIC_ALGO, opt_path_metricalgo, + ARG_VALUE_FORM, HELP_PATH_METRIC_ALGO} + , + {ODI, 0, ARG_FMETRIC_EXPONENT_MIN, 0, 5, A_PS1, A_ADM, A_DYI, A_CFA, A_ANY, &my_fmetric_exp_min,MIN_FMETRIC_EXPONENT_MIN,MAX_FMETRIC_EXPONENT_MIN,DEF_FMETRIC_EXPONENT_MIN, opt_path_metricalgo, + ARG_VALUE_FORM, " "} + , + {ODI, 0, ARG_PATH_WINDOW, 0, 5, A_PS1, A_ADM, A_DYI, A_CFA, A_ANY, &my_path_window, MIN_PATH_WINDOW, MAX_PATH_WINDOW, DEF_PATH_WINDOW, opt_path_metricalgo, + ARG_VALUE_FORM, "set path window size (PWS) for end2end path-quality calculation (path metric)"} + , +#endif + {ODI, 0, ARG_PATH_LOUNGE, 0, 5,A_PS1,A_ADM,A_DYI,A_CFA,A_ANY, &my_path_lounge, MIN_PATH_LOUNGE,MAX_PATH_LOUNGE,DEF_PATH_LOUNGE, opt_path_metricalgo, + ARG_VALUE_FORM, "set default PLS buffer size to artificially delay my OGM processing for ordered path-quality calulation"} + , + {ODI, 0, ARG_PATH_REGRESSION_SLOW, 0, 5,A_PS1,A_ADM,A_DYI,A_CFA,A_ANY, &my_path_regression_slow,MIN_PATH_REGRESSION_SLOW,MAX_PATH_REGRESSION_SLOW,DEF_PATH_REGRESSION_SLOW,opt_path_metricalgo, + ARG_VALUE_FORM, "set (slow) path regression "} + , +#ifndef LESS_OPTIONS + {ODI, 0, ARG_HOP_PENALTY, 0, 5,A_PS1,A_ADM,A_DYI,A_CFA,A_ANY, &my_hop_penalty, MIN_HOP_PENALTY, MAX_HOP_PENALTY, DEF_HOP_PENALTY, opt_path_metricalgo, + ARG_VALUE_FORM, "penalize non-first rcvd OGMs in 1/255 (each hop will substract metric*(VALUE/255) from current path-metric)"} + , + {ODI,0,ARG_LINK_WINDOW, 0, 5,A_PS1,A_ADM,A_DYI,A_CFA,A_ANY, &my_link_window, MIN_LINK_WINDOW, MAX_LINK_WINDOW,DEF_LINK_WINDOW, opt_link_metricalgo, + ARG_VALUE_FORM, "set link window size (LWS) for link-quality calculation (link metric)"} + , +#endif + {ODI,0,ARG_LINK_REGRESSION_SLOW, 0, 5,A_PS1,A_ADM,A_DYI,A_CFA,A_ANY, &my_link_regression_slow, MIN_LINK_REGRESSION_SLOW,MAX_LINK_REGRESSION_SLOW,DEF_LINK_REGRESSION_SLOW,opt_link_metricalgo, + ARG_VALUE_FORM, "set (slow) link regression"} + , +#ifndef LESS_OPTIONS + {ODI,0,ARG_LINK_REGRESSION_FAST, 0, 5,A_PS1,A_ADM,A_DYI,A_CFA,A_ANY, &my_link_regression_fast, MIN_LINK_REGRESSION_FAST,MAX_LINK_REGRESSION_FAST,DEF_LINK_REGRESSION_FAST,opt_link_metricalgo, + ARG_VALUE_FORM, "set (fast) link regression"} + , + {ODI,0,ARG_LINK_REGRESSION_DIFF, 0, 5,A_PS1,A_ADM,A_DYI,A_CFA,A_ANY, &my_link_regression_diff, MIN_LINK_REGRESSION_DIFF,MAX_LINK_REGRESSION_DIFF,DEF_LINK_REGRESSION_DIFF,opt_link_metricalgo, + ARG_VALUE_FORM, "set (diff) link regression"} + , + {ODI,0,ARG_LINK_RTQ_LOUNGE, 0, 5,A_PS1,A_ADM,A_DYI,A_CFA,A_ANY, &my_link_rtq_lounge,MIN_LINK_RTQ_LOUNGE,MAX_LINK_RTQ_LOUNGE,DEF_LINK_RTQ_LOUNGE, opt_link_metricalgo, + ARG_VALUE_FORM, "set local LLS buffer size to artificially delay OGM processing for ordered link-quality calulation"} +#endif + +}; + + +STATIC_FUNC +int32_t init_metrics( void ) +{ + + struct frame_handl metric_handl; + memset( &metric_handl, 0, sizeof(metric_handl)); + metric_handl.fixed_msg_size = 0; + metric_handl.is_relevant = 1; + metric_handl.min_msg_size = sizeof (struct mandatory_tlv_metricalgo); + metric_handl.name = "desc_tlv_metric0"; + metric_handl.tx_frame_handler = create_description_tlv_metricalgo; + metric_handl.rx_frame_handler = process_description_tlv_metricalgo; + register_frame_handler(description_tlv_handl, BMX_DSC_TLV_METRIC, &metric_handl); + + + register_path_metricalgo(BIT_METRIC_ALGO_RQv0, path_metricalgo_RQv0); + register_path_metricalgo(BIT_METRIC_ALGO_TQv0, path_metricalgo_TQv0); + register_path_metricalgo(BIT_METRIC_ALGO_RTQv0, path_metricalgo_RTQv0); + register_path_metricalgo(BIT_METRIC_ALGO_ETXv0, path_metricalgo_ETXv0); + register_path_metricalgo(BIT_METRIC_ALGO_ETTv0, path_metricalgo_ETTv0); + register_path_metricalgo(BIT_METRIC_ALGO_MINBANDWIDTH, path_metricalgo_MINBANDWIDTH); + + + register_options_array(metrics_options, sizeof (metrics_options)); + + return SUCCESS; +} + +STATIC_FUNC +void cleanup_metrics( void ) +{ + if (self.path_metricalgo) { + debugFree(self.path_metricalgo, -300281); + self.path_metricalgo = NULL; + } +} + + + + + +struct plugin *metrics_get_plugin( void ) { + + static struct plugin metrics_plugin; + memset( &metrics_plugin, 0, sizeof ( struct plugin ) ); + + metrics_plugin.plugin_name = "bmx6_metric_plugin"; + metrics_plugin.plugin_size = sizeof ( struct plugin ); + metrics_plugin.plugin_code_version = CODE_VERSION; + metrics_plugin.cb_init = init_metrics; + metrics_plugin.cb_cleanup = cleanup_metrics; + metrics_plugin.cb_plugin_handler[PLUGIN_CB_LINKDEV_CREATE] = (void (*) (void*)) linkdev_create; + metrics_plugin.cb_plugin_handler[PLUGIN_CB_LINK_DESTROY] = (void (*) (void*)) remove_task_purge_rq_metrics; + metrics_plugin.cb_plugin_handler[PLUGIN_CB_STATUS] = (void (*) (void*)) dbg_metrics_status; + + return &metrics_plugin; +} diff --git a/metrics.h b/metrics.h new file mode 100644 index 0000000..9e4a439 --- /dev/null +++ b/metrics.h @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2010 Axel Neumann + * 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 BIT_METRIC_ALGO_MIN 0x00 +#define BIT_METRIC_ALGO_RQv0 0x00 +#define BIT_METRIC_ALGO_TQv0 0x01 +#define BIT_METRIC_ALGO_RTQv0 0x02 +#define BIT_METRIC_ALGO_MINBANDWIDTH 0x03 +#define BIT_METRIC_ALGO_ETXv0 0x04 +#define BIT_METRIC_ALGO_ETTv0 0x05 +#define BIT_METRIC_ALGO_MAX 0x05 +#define BIT_METRIC_ALGO_ARRSZ ((8*sizeof(ALGO_T))) + +#define MIN_METRIC_ALGO 0x00 +#define TYP_METRIC_ALGO_RQv0 (0x01 << BIT_METRIC_ALGO_RQv0) // 1 +#define TYP_METRIC_ALGO_TQv0 (0x01 << BIT_METRIC_ALGO_TQv0) // 2 +#define TYP_METRIC_ALGO_RTQv0 (0x01 << BIT_METRIC_ALGO_RTQv0) // 4 +#define TYP_METRIC_ALGO_MINBANDWIDTH (0x01 << BIT_METRIC_ALGO_MINBANDWIDTH) // 8 +#define TYP_METRIC_ALGO_ETXv0 (0x01 << BIT_METRIC_ALGO_ETXv0) // 16 +#define TYP_METRIC_ALGO_ETTv0 (0x01 << BIT_METRIC_ALGO_ETTv0) // 32 +#define MAX_METRIC_ALGO (0x01 << BIT_METRIC_ALGO_MAX) // 128 +#define MAX_METRIC_ALGO_RESERVED ((ALGO_T)-1); +#define DEF_METRIC_ALGO TYP_METRIC_ALGO_ETTv0 + +#define ARG_PATH_METRIC_ALGO "path_metricalgo" +#define HELP_PATH_METRIC_ALGO "set metric algo for routing towards myself: 1=RQ 2=TQ 4=RTQ 8=HopPenalty 16=MinBW 32=ETX 64=ETTv0" + + +#define MAX_PATH_WINDOW 250 /* 250 TBD: should not be larger until ogm->ws and neigh_node.packet_count (and related variables) is only 8 bit */ +#define MIN_PATH_WINDOW 1 +#define DEF_PATH_WINDOW 5 /* NBRF: NeighBor Ranking sequence Frame) sliding packet range of received orginator messages in squence numbers (should be a multiple of our word size) */ +#define ARG_PATH_WINDOW "path_window" +//extern int32_t my_path_window; // my path window size used to quantify the end to end path quality between me and other nodes + +#define MIN_PATH_LOUNGE 0 +#define MAX_PATH_LOUNGE 4 +#define DEF_PATH_LOUNGE 2 +#define ARG_PATH_LOUNGE "path_lounge" +//extern int32_t my_path_lounge; + + +#define DEF_PATH_REGRESSION_SLOW 1 +#define MIN_PATH_REGRESSION_SLOW 1 +#define MAX_PATH_REGRESSION_SLOW 255 +#define ARG_PATH_REGRESSION_SLOW "path_regression_slow" + +#define DEF_PATH_REGRESSION_FAST 1 +#define MIN_PATH_REGRESSION_FAST 1 +#define MAX_PATH_REGRESSION_FAST 32 +#define ARG_PATH_REGRESSION_FAST "path_regression_fast" + +#define DEF_PATH_REGRESSION_DIFF 8 +#define MIN_PATH_REGRESSION_DIFF 2 +#define MAX_PATH_REGRESSION_DIFF 255 +#define ARG_PATH_REGRESSION_DIFF "path_regression_correction" + +#define MAX_LINK_WINDOW 100 +#define MIN_LINK_WINDOW 1 +#define DEF_LINK_WINDOW 40 +#define ARG_LINK_WINDOW "link_window" +//extern int32_t my_link_window; // my link window size used to quantify the link qualities to direct neighbors +#define RQ_PURGE_ITERATIONS MAX_LINK_WINDOW + + +#define DEF_LINK_REGRESSION_SLOW 16 // = ~ lg2( DEF_LINK_WINDOW ) +#define MIN_LINK_REGRESSION_SLOW 1 +#define MAX_LINK_REGRESSION_SLOW 255 +#define ARG_LINK_REGRESSION_SLOW "link_regression_slow" + +#define DEF_LINK_REGRESSION_FAST 2 // = ~ lg2( DEF_LINK_WINDOW ) +#define MIN_LINK_REGRESSION_FAST 1 +#define MAX_LINK_REGRESSION_FAST 32 +#define ARG_LINK_REGRESSION_FAST "link_regression_fast" + +#define DEF_LINK_REGRESSION_DIFF 8 // = ~ lg2( DEF_LINK_WINDOW ) +#define MIN_LINK_REGRESSION_DIFF 1 +#define MAX_LINK_REGRESSION_DIFF 255 +#define ARG_LINK_REGRESSION_DIFF "link_regression_correction" + +// the default link_lounge_size of 1o2 is good to compensate for ogi ~ but <= aggreg_interval +#define MIN_LINK_RTQ_LOUNGE 0 +#define MAX_LINK_RTQ_LOUNGE 10 +#define DEF_LINK_RTQ_LOUNGE 1 //2 +#define ARG_LINK_RTQ_LOUNGE "link_lounge" +//extern int32_t my_link_rtq_lounge; + +#define RQ_LINK_LOUNGE 0 /* may also be rtq_link_lounge */ + +// this deactivates OGM-Acks on the link: +#define MIN_LINK_IGNORE_MIN 0 +#define MAX_LINK_IGNORE_MIN 100 +#define DEF_LINK_IGNORE_MIN 50 +#define ARG_LINK_IGNORE_MIN "link_ignore_min" +//extern int32_t link_ignore_min; + +// this activates OGM-Acks on the link: +#define MIN_LINK_IGNORE_MAX 0 +#define MAX_LINK_IGNORE_MAX 255 +#define DEF_LINK_IGNORE_MAX 100 +#define ARG_LINK_IGNORE_MAX "link_ignore_max" +//extern int32_t link_ignore_max; + + + +#define MIN_PATH_HYST 0 +#define MAX_PATH_HYST 255 +#define DEF_PATH_HYST 0 +#define ARG_PATH_HYST "path_hysteresis" +//extern int32_t my_path_hystere; + + +#define MIN_LATE_PENAL 0 +#define MAX_LATE_PENAL 100 +#define DEF_LATE_PENAL 1 +#define ARG_LATE_PENAL "lateness_penalty" +//extern int32_t my_late_penalty; + + +#define DEF_HOP_PENALTY 0 //(U8_MAX/20) <=> 5% penalty on metric per hop +#define MIN_HOP_PENALTY 0 // smaller values than 4 do not show effect +#define MAX_HOP_PENALTY U8_MAX +#define ARG_HOP_PENALTY "hop_penalty" +#define MAX_HOP_PENALTY_PRECISION_EXP 8 +//extern int32_t my_hop_penalty; + + + + + +#define FMETRIC_UNDEFINED 0 +#define FMETRIC_MANTISSA_BLOCKED 0 +#define FMETRIC_MANTISSA_ZERO 1 +#define FMETRIC_MANTISSA_ROUTABLE 2 + + +#define TMP_MANTISSA_BIT_SHIFT OGM_MANTISSA_BIT_SIZE +#define OGM_EXPONENT_MAX ((1<<OGM_EXPONENT_BIT_SIZE)-1) +#define OGM_MANTISSA_MAX ((1<<OGM_MANTISSA_BIT_SIZE)-1) + + +#define DEF_FMETRIC_EXP_OFFSET 0 +#define MIN_FMETRIC_EXP_OFFSET 0 +#define MAX_FMETRIC_EXP_OFFSET ( (8*sizeof(UMETRIC_T)) - OGM_MANTISSA_BIT_SIZE - (1<<OGM_EXPONENT_BIT_SIZE) ) // konservative? +#define ARG_FMETRIC_EXP_OFFSET "metric_exponent_offset" +//extern int32_t my_fmetric_exp_offset; + +#define MIN_FMETRIC_MANTISSA_MIN (0) +#define MAX_FMETRIC_MANTISSA_MIN ((1<<(8-OGM_EXPONENT_BIT_SIZE))-1) +#define ARG_FMETRIC_MANTISSA_MIN "min_metric_mantissa" +#define DEF_FMETRIC_MANTISSA_MIN FMETRIC_MANTISSA_ROUTABLE + +#define MIN_FMETRIC_EXPONENT_MIN (0) +#define MAX_FMETRIC_EXPONENT_MIN ((1<<OGM_EXPONENT_BIT_SIZE)-1) +#define ARG_FMETRIC_EXPONENT_MIN "min_metric_exponent" +#define DEF_FMETRIC_EXPONENT_MIN MIN_FMETRIC_EXPONENT_MIN + + + +//#define TYP_METRIC_FLAG_STRAIGHT (0x1<<0) + +#define MIN_METRIC_FLAGS (0x0) +#define MAX_METRIC_FLAGS (0x1) + +#define DEF_PATH_METRIC_FLAGS (0x0) +#define ARG_PATH_METRIC_FLAGS "path_metric_flags" + +#define DEF_LINK_METRIC_FLAGS (0x0) +#define ARG_LINK_METRIC_FLAGS "link_metric_flags" + + + + +struct mandatory_tlv_metricalgo { + uint8_t exp_offset; + +#if __BYTE_ORDER == __LITTLE_ENDIAN + unsigned int fmetric_mantissa_min : (8 - OGM_EXPONENT_BIT_SIZE); + unsigned int fmetric_exp_reduced_min : OGM_EXPONENT_BIT_SIZE; +#elif __BYTE_ORDER == __BIG_ENDIAN + unsigned int fmetric_exp_reduced_min : OGM_EXPONENT_BIT_SIZE; + unsigned int fmetric_mantissa_min : (8 - OGM_EXPONENT_BIT_SIZE); +#else +# error "Please fix <bits/endian.h>" +#endif + + uint8_t reserved_for_fmetric_mantissa_size; //???? does this make sense?? + uint8_t reserved; + + ALGO_T algo_type; + uint16_t flags; + + uint8_t path_window_size; + uint8_t path_lounge_size; + uint8_t wavg_slow; + uint8_t wavg_fast; + uint8_t wavg_correction; + uint8_t hystere; + uint8_t hop_penalty; + uint8_t late_penalty; + +} __attribute__((packed)); + + +struct description_tlv_metricalgo { + struct mandatory_tlv_metricalgo m; + uint8_t optional[]; +} __attribute__((packed)); + + + +extern struct host_metricalgo link_metric_algo[SQR_RANGE]; + + +extern UMETRIC_T UMETRIC_RQ_NBDISC_MIN; +extern UMETRIC_T UMETRIC_RQ_OGM_ACK_MIN; + + +// some tools: + + +FMETRIC_T fmetric(uint8_t mantissa, uint8_t exp_reduced, uint8_t exp_offset); + +UMETRIC_T umetric_max(uint8_t exp_offset); + +UMETRIC_T umetric(uint8_t mantissa, uint8_t exp_reduced, uint8_t exp_offset); + +UMETRIC_T fmetric_to_umetric(FMETRIC_T fm); +FMETRIC_T umetric_to_fmetric(uint8_t exp_offset, UMETRIC_T val); + +IDM_T is_fmetric_valid(FMETRIC_T fm); + +IDM_T fmetric_cmp(FMETRIC_T a, unsigned char cmp, FMETRIC_T b); + + +// some core hooks: +void apply_metric_algo(UMETRIC_T *out, struct link_dev_node *link, UMETRIC_T *path, struct host_metricalgo *algo); + +IDM_T update_metric_record(struct orig_node *on, struct metric_record *rec, struct host_metricalgo *alg, SQN_T range, SQN_T min, SQN_T in, UMETRIC_T *probe); + +void update_link_metrics(struct link_dev_node *lndev, IID_T transmittersIID, HELLO_FLAGS_SQN_T sqn, HELLO_FLAGS_SQN_T valid_max, uint8_t sqr, UMETRIC_T *probe); + +IDM_T update_path_metrics(struct packet_buff *pb, struct orig_node *on, OGM_SQN_T in_sqn, UMETRIC_T *in_umetric); + + + +// plugin hooks: + +struct plugin *metrics_get_plugin( void ); diff --git a/msg.c b/msg.c index fbb6322..e565dcf 100644 --- a/msg.c +++ b/msg.c @@ -1,6 +1,5 @@ /* - * Copyright (C) 2010 BMX contributors: - * Axel Neumann + * Copyright (c) 2010 Axel Neumann * 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. @@ -19,18 +18,25 @@ #include <string.h> #include <stdio.h> #include <stdlib.h> +#include <stdarg.h>
#include <unistd.h> #include <errno.h>
- -//#include <sha.h> - #include "bmx.h" #include "msg.h" -#include "hna.h" +#include "ip.h" +#include "metrics.h" #include "schedule.h" - +#include "tools.h" +#include "plugin.h" + +union schedule_hello_info { +#define SCHEDULE_HELLO_SQN 0 +#define SCHEDULE_DEV_ID 1 + uint8_t u8[2]; + uint16_t u16; +};
static Sha bmx_sha;
@@ -38,145 +44,60 @@ AVL_TREE( description_cache_tree, struct description_cache_node, dhash );
-static int32_t max_udpd_size = DEF_UDPD_SIZE; +static int32_t pref_udpd_size = DEF_UDPD_SIZE;
-static int32_t aggreg_interval = DEF_AGGREG_INTERVAL;
-int32_t my_ogm_interval = DEF_OGM_INTERVAL; /* orginator message interval in miliseconds */ +static int32_t ogm_tx_iters = DEF_OGM_TX_ITERS; +static int32_t my_ogm_ack_tx_iters = DEF_OGM_ACK_TX_ITERS;
-int32_t my_hello_interval = DEF_HELLO_INTERVAL; +int32_t desc_req_tx_iters = DEF_DSC0_REQS_TX_ITERS; +int32_t dhash_req_tx_iters = DEF_DHS0_REQS_TX_ITERS;
-int32_t ogm_resend_attempts = DEF_OGM_RESEND_ATTEMPTS; +int32_t desc_tx_iters = DEF_DSC0_ADVS_TX_ITERS; +int32_t dhash_tx_iters = DEF_DHS0_ADVS_TX_ITERS; +int32_t tx_unsolicited_desc = DEF_UNSOLICITED_DESC_ADVS;
int my_desc0_tlv_len = 0;
IID_T myIID4me = IID_RSVD_UNUSED; +TIME_T myIID4me_timestamp = 0;
-LIST_SIMPEL( ogm_aggreg_list, struct ogm_aggreg_node, list ); +LIST_SIMPEL( ogm_aggreg_list, struct ogm_aggreg_node, list, sqn ); uint32_t ogm_aggreg_pending = 0; -static SQN_T ogm_aggreg_sqn_max; +static AGGREG_SQN_T ogm_aggreg_sqn_max;
char *tlv_op_str[] = {"TLV_DEL","TLV_TEST","TLV_ADD","TLV_DONE","TLV_DEBUG"}; +static struct dhash_node* DHASH_NODE_FAILURE = (struct dhash_node*) & DHASH_NODE_FAILURE;
- - -STATIC_FUNC int tx_msg_hello40_reply (struct tx_task_node *ttn, uint8_t *flags, uint8_t *tx_buff, uint16_t buff_size); -STATIC_FUNC int tx_msg_helloX0_adv (struct tx_task_node *ttn, uint8_t *flags, uint8_t *tx_buff, uint16_t buff_size); -STATIC_FUNC int tx_msg_description0_adv (struct tx_task_node *ttn, uint8_t *flags, uint8_t *tx_buff, uint16_t buff_size); - -STATIC_FUNC int tx_msg_dhash0_adv (struct tx_task_node *ttn, uint8_t *flags, uint8_t *tx_buff, uint16_t buff_size); - -STATIC_FUNC int tx_msg_dhash0_or_description0_request (struct tx_task_node *ttn, uint8_t *flags, uint8_t *tx_buff, uint16_t buff_size); -STATIC_FUNC int tx_msg_ogm_ack (struct tx_task_node *ttn, uint8_t *flags, uint8_t *tx_buff, uint16_t buff_size); - -STATIC_FUNC int tx_frame_ogm0_advs (struct tx_task_node *ttn, uint8_t *flags, uint8_t *tx_buff, uint16_t buff_size); - - -STATIC_FUNC int rx_frame_hello40_replies (struct packet_buff *pb, struct frame_header *frame); -STATIC_FUNC int rx_frame_helloX0_advs (struct packet_buff *pb, struct frame_header *frame); -STATIC_FUNC int rx_frame_description0_advs (struct packet_buff *pb, struct frame_header *frame); - -STATIC_FUNC int rx_frame_dhash0_advs (struct packet_buff *pb, struct frame_header *frame); - -STATIC_FUNC int rx_frame_dhash0_or_description0_requests (struct packet_buff *pb, struct frame_header *frame); - -STATIC_FUNC int rx_frame_ogm0_advs (struct packet_buff *pb, struct frame_header *frame); -STATIC_FUNC int rx_frame_ogm40_acks (struct packet_buff *pb, struct frame_header *frame); - /*********************************************************** The core frame/message structures and handlers ************************************************************/
+struct frame_handl packet_frame_handler[FRAME_TYPE_ARRSZ];
-struct description_tlv_handler { - uint16_t reserved1; - uint16_t reserved2; - uint16_t min_msg_size; - uint16_t variable_msg_size; - char *name; - int (*create_tlv) (uint8_t *data, uint16_t max_size); - int (*process_tlv) (struct orig_node *on, struct frame_header *tlv, IDM_T op, struct ctrl_node *cn); -}; - -struct description_tlv_handler description0_tlv_handler[BMX_DSC_TLV_MAX] = { - {0, 0, sizeof (struct description0_msg_ip4), 0, - "desc0tlv_glip4", create_description_tlv_ip4, process_description_tlv_hna4} - , - {0, 0, sizeof (struct description0_msg_hna4), 0, - "desc0tlv_uhna4", create_description_tlv_hna4, process_description_tlv_hna4} -}; - - - -struct pkt_frame_handler { - uint16_t reserved; - uint16_t tx_iterations; - uint16_t min_rtq; - uint16_t data_header_size; - uint16_t min_msg_size; - uint16_t fixed_msg_size; - uint32_t min_tx_interval; - char *name; - int (*tx_frm_creator) (struct tx_task_node * ttn, uint8_t *flags, uint8_t *tx_buff, uint16_t buff_size); -/* - * tx_msg_creator() - * expects sufficient buff_size for non-variable_msg_size messages !!! - * returns x=sizeof(send msg), thus (x<=buff_size), if msg was successfully created - * returns (x > buff_size) if variable_msg_size could not be created due to lack of buff_size - * returns 0 if message MUST be send later - * returns FAILRUE if porblem occured and msg-meta data (tx_task_node) MUST be destroyed - */ - int (*tx_msg_creator) (struct tx_task_node * ttn, uint8_t *flags, uint8_t *tx_buff, uint16_t buff_size); - int (*rx_frm_receptor) (struct packet_buff *, struct frame_header *); -}; - - -static struct pkt_frame_handler frame_handler[FRAME_TYPE_ARRSZ] = { - {0, 0, 0, 0, 0, 1, 0, NULL, NULL, NULL, NULL}, - {0, 0, 0, 0, 0, 1, 0, NULL, NULL, NULL, NULL}, - - {0, 1, 0, 0, sizeof (struct msg_hello_adv), 1, 0, - "hey0_adv", NULL, tx_msg_helloX0_adv, rx_frame_helloX0_advs}, - - {0, 1, 0, 0, sizeof (struct msg_hello_reply), 1, 0, - "hey0_rep", NULL, tx_msg_hello40_reply, rx_frame_hello40_replies}, - {0, 0, 0, 0, 0, 1, 0, NULL, NULL, NULL, NULL}, - - {0, 0, 1, 0, 0, 1, 0, NULL, NULL, NULL, NULL}, - {0, 0, 1, 0, 0, 1, 0, NULL, NULL, NULL, NULL}, - - {0, 1, MIN_NBDISC_RTQ, 0, sizeof (struct msg_description_request), 1, DEF_TX_DESC0_REQ_TO, // receiverIID, receiverIP4 - "desc0_req", NULL, tx_msg_dhash0_or_description0_request, rx_frame_dhash0_or_description0_requests}, - - {0, 1, MIN_NBDISC_RTQ, 0, sizeof (struct msg_description_adv), 0, DEF_TX_DESC0_ADV_TO, // myIID4x - "desc0_adv", NULL, tx_msg_description0_adv, rx_frame_description0_advs}, - - {0, 1, MIN_NBDISC_RTQ, 0, sizeof (struct msg_dhash_request), 1, DEF_TX_DHASH0_REQ_TO, // receiverIID, receiverIP4 - "dhash0_req", NULL, tx_msg_dhash0_or_description0_request, rx_frame_dhash0_or_description0_requests}, - - {0, 1, MIN_NBDISC_RTQ, 0, sizeof (struct msg_dhash_adv), 1, DEF_TX_DHASH0_ADV_TO, // myIID4x - "dhash_adv", NULL, tx_msg_dhash0_adv, rx_frame_dhash0_advs}, - - {0, 1, 0, sizeof (struct hdr_ogm_adv), sizeof (struct msg_ogm_adv), 1, 0, - "ogm_adv", tx_frame_ogm0_advs, NULL, rx_frame_ogm0_advs}, - - {0, 2, 0, 0, sizeof (struct msg_ogm_ack), 1, 0, - "ogm_ack", NULL, tx_msg_ogm_ack, rx_frame_ogm40_acks}, - - {0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL} - -}; - +struct frame_handl description_tlv_handl[BMX_DSC_TLV_ARRSZ];
+void register_frame_handler(struct frame_handl *array, int pos, struct frame_handl *handl) +{ + assertion(-500659, (pos < BMX_DSC_TLV_ARRSZ)); + assertion(-500660, (!array[pos].min_msg_size)); // the pos MUST NOT be used yet + assertion(-500661, (handl && handl->min_msg_size && handl->name)); + assertion(-500806, (XOR(handl->rx_frame_handler, handl->rx_msg_handler) && XOR(handl->tx_frame_handler, handl->tx_msg_handler))); + assertion(-500879, (!(handl->min_msg_size % TLV_DATA_STEPS))); + assertion(-500880, (!(handl->data_header_size % TLV_DATA_STEPS))); + + array[pos] = *handl; +}
STATIC_FUNC -struct description * rem_cached_description(struct description_hash *dhash) +struct description * remove_cached_description(struct description_hash *dhash) { + TRACE_FUNCTION_CALL; struct description_cache_node *dcn;
if (!(dcn = avl_find_item(&description_cache_tree, dhash))) @@ -189,10 +110,10 @@ struct description * rem_cached_description(struct description_hash *dhash)
return desc0; } - STATIC_FUNC -struct description_cache_node *purge_cached_descriptions( IDM_T purge_all ) { - +struct description_cache_node *purge_cached_descriptions(IDM_T purge_all) +{ + TRACE_FUNCTION_CALL; struct description_cache_node *dcn; struct description_cache_node *dcn_min = NULL; struct description_hash tmp_dhash; @@ -200,13 +121,11 @@ struct description_cache_node *purge_cached_descriptions( IDM_T purge_all ) {
dbgf_all( DBGT_INFO, "%s", purge_all ? "purge_all" : "only_expired");
- paranoia( -500349, (!is_zero((char*)&tmp_dhash, BMX_HASH0_LEN))); - while ((dcn = avl_next_item(&description_cache_tree, &tmp_dhash))) {
- memcpy(&tmp_dhash, &dcn->dhash, BMX_HASH0_LEN); + memcpy(&tmp_dhash, &dcn->dhash, HASH0_SHA1_LEN);
- if (purge_all || ((uint32_t) (bmx_time - dcn->timestamp)) > DEF_DESC0_CACHE_TO) { + if (purge_all || ((TIME_T) (bmx_time - dcn->timestamp)) > DEF_DESC0_CACHE_TO) {
avl_remove(&description_cache_tree, &dcn->dhash, -300208); debugFree(dcn->description, -300100); @@ -214,7 +133,7 @@ struct description_cache_node *purge_cached_descriptions( IDM_T purge_all ) {
} else {
- if (!dcn_min || LESS_U32(dcn->timestamp, dcn_min->timestamp)) + if (!dcn_min || U32_LT(dcn->timestamp, dcn_min->timestamp)) dcn_min = dcn; } } @@ -225,6 +144,7 @@ struct description_cache_node *purge_cached_descriptions( IDM_T purge_all ) { STATIC_FUNC void cache_description(struct description *desc, struct description_hash *dhash) { + TRACE_FUNCTION_CALL; struct description_cache_node *dcn;
uint16_t desc_len = sizeof (struct description) + ntohs(desc->dsc_tlvs_len); @@ -259,649 +179,451 @@ void cache_description(struct description *desc, struct description_hash *dhash) dcn = debugMalloc(sizeof ( struct description_cache_node), -300104); dcn->description = debugMalloc(desc_len, -300105); memcpy(dcn->description, desc, desc_len); - memcpy( &dcn->dhash, dhash, BMX_HASH0_LEN ); + memcpy( &dcn->dhash, dhash, HASH0_SHA1_LEN ); dcn->timestamp = bmx_time; avl_insert(&description_cache_tree, dcn, -300145);
}
-void purge_tx_timestamp_tree(struct dev_node *dev, IDM_T purge_all) -{ - struct avl_node *an; - struct tx_timestamp_node *ttn = NULL; - struct tx_timestamp_key key; - - memset(&key, 0, sizeof (struct tx_timestamp_key)); - - dbgf_all( DBGT_INFO, "%s %s", dev->name, purge_all ? "purge_all" : "only_expired"); - - while ((an = avl_next(&dev->tx_timestamp_tree, (ttn ? &ttn->key : &key)))) { - - ttn = an->item; - - if (purge_all || ((uint32_t) (bmx_time - ttn->timestamp)) > - (DEF_TX_TS_TREE_PURGE_FK * frame_handler[ttn->key.type].min_tx_interval)) {
- memcpy( &key, &ttn->key, sizeof( struct tx_timestamp_key ) );
- avl_remove( &dev->tx_timestamp_tree, &ttn->key, -300210 ); - debugFree( ttn, -300127 ); - ttn = NULL; - } - } -} - - -STATIC_FUNC -struct tx_timestamp_node * tx_timestamp_add( struct dev_node *dev, struct tx_timestamp_key *key) -{ - ASSERTION( -500263, ( dev && !avl_find( &dev->tx_timestamp_tree, key ) ) ); - - if (dev->tx_timestamp_tree.items > DEF_TX_TS_TREE_SIZE) { - - purge_tx_timestamp_tree(dev, NO); - - if (dev->tx_timestamp_tree.items > DEF_TX_TS_TREE_SIZE) { - dbg_mute(20, DBGL_SYS, DBGT_WARN, "%s tx_ts_tree reached %d %s neighIID4x %u %s %u", - dev->name, dev->tx_timestamp_tree.items, frame_handler[key->type].name, - key->neighIID4x, ipStr(key->myIID4x_or_dest_ip4), key->myIID4x_or_dest_ip4); - } - } - - struct tx_timestamp_node *ttn = debugMalloc(sizeof ( struct tx_timestamp_node), -300126); - memset(ttn, 0, sizeof ( struct tx_timestamp_node)); - memcpy( &ttn->key, key, sizeof(struct tx_timestamp_key ) ); - ttn->timestamp = bmx_time; - avl_insert(&dev->tx_timestamp_tree, ttn, -300146); - - return ttn; -} - -STATIC_FUNC -IDM_T tx_task_obsolete( struct dev_node *dev, uint8_t frame_type, struct tx_task_node *tx_task ) +IDM_T process_description_tlvs(struct packet_buff *pb, struct orig_node *on, struct description *desc, IDM_T op, uint8_t filter, struct ctrl_node *cn) { - struct tx_timestamp_node *ttn = NULL; - struct tx_timestamp_key key; - struct dhash_node *dhn = NULL; + TRACE_FUNCTION_CALL; + assertion(-500370, (op == TLV_OP_DEL || op == TLV_OP_TEST || op == TLV_OP_ADD || op == TLV_OP_DEBUG)); + assertion(-500590, (IMPLIES(on == &self, op == TLV_OP_DEBUG))); + assertion(-500807, (desc)); + assertion(-500829, (IMPLIES(op == TLV_OP_DEL, !on->blocked)));
- if (tx_task->myIID4x >= IID_MIN_USED && !((dhn = iid_get_node_by_myIID4x(tx_task->myIID4x)) && dhn->on)) { - goto tx_timestamped_deny; - } + uint16_t dsc_tlvs_len = ntohs(desc->dsc_tlvs_len);
- if (!frame_handler[frame_type].min_tx_interval) - return NO; - - memset(&key, 0, sizeof (struct tx_timestamp_key)); - - key.myIID4x_or_dest_ip4 = tx_task->myIID4x ? tx_task->myIID4x : tx_task->dst_ip4; - key.neighIID4x = tx_task->neighIID4x; - key.type = frame_type; + IDM_T tlv_result; + struct rx_frame_iterator it = { + .caller = __FUNCTION__, .on = on, .cn = cn, .op = op, .pb = pb, + .handls = description_tlv_handl, .handl_max = (BMX_DSC_TLV_MAX), .process_filter = filter, + .frames_in = (((uint8_t*) desc) + sizeof (struct description)), .frames_pos = 0, + .frames_length = dsc_tlvs_len + };
- if (frame_handler[frame_type].min_tx_interval && (ttn = avl_find_item(&dev->tx_timestamp_tree, &key))) { + dbgf_all(DBGT_INFO, "%s %s dsc_sqn %d size %d ", + tlv_op_str[op], desc->id.name, ntohs(desc->dsc_sqn), dsc_tlvs_len);
- if (((uint32_t) (bmx_time - ttn->timestamp) < frame_handler[frame_type].min_tx_interval)) {
- goto tx_timestamped_deny; - } + while ((tlv_result = rx_frame_iterate(&it)) > TLV_RX_DATA_DONE);
- ttn->timestamp = bmx_time; - } + if (tlv_result == TLV_DATA_BLOCKED) {
- if (!ttn) - ttn = tx_timestamp_add(dev, &key); + assertion(-500356, (op == TLV_OP_TEST));
- return NO; + dbgf(DBGL_SYS, DBGT_ERR, "%s data_length=%d BLOCKED", + description_tlv_handl[it.frame_type].name, it.frame_data_length);
+ on->blocked = YES;
-tx_timestamped_deny: - dbgf(DBGL_CHANGES, DBGT_WARN, - "skipping %s %s myIId4x %d neighIID4x %d %s %s send just %d ms ago", - frame_handler[frame_type].name, dev->name, - tx_task->myIID4x, tx_task->neighIID4x, ipStr(tx_task->dst_ip4), - dhn ? dhn->on->id.name : "???", - ttn ? (int)(bmx_time - ttn->timestamp) : -1); + if (!avl_find(&blocked_tree, &on->id)) + avl_insert(&blocked_tree, on, -300165);
- return YES; -} + return TLV_DATA_BLOCKED;
+ } else if (tlv_result == TLV_DATA_FAILURE) {
+ dbgf(DBGL_SYS, DBGT_WARN, + "rcvd problematic description_ltv from %s near: type=%s data_length=%d pos=%d ", + pb ? pb->i.llip_str : "---", + description_tlv_handl[it.frame_type].name, it.frame_data_length, it.frames_pos);
-STATIC_FUNC -IDM_T validate_param(int32_t probe, int32_t min, int32_t max, char *name, struct opt_type *opt) -{ - if (opt) { - min = opt->imin; - max = opt->imax; - name = opt->long_name; + return TLV_DATA_FAILURE; }
- if ( probe < min || probe > max ) { - - dbgf( DBGL_SYS, DBGT_ERR, "Illegal %s parameter value %d ( min %d max %d )", - name, probe, min, max); - - return FAILURE; + if ( op == TLV_OP_ADD ) { + on->blocked = NO; + avl_remove(&blocked_tree, &on->id, -300211); }
- return SUCCESS; + return TLV_RX_DATA_DONE; }
- - -IDM_T process_description_tlvs(struct orig_node *on, struct description *desc_new, IDM_T op, struct ctrl_node *cn) +void purge_tx_task_list(struct list_head *tx_task_lists, struct link_node *only_link, struct dev_node *only_dev) { - struct description *desc; - IDM_T tlv_result; - uint16_t pos = 0, t = 0, pt = 0, size = 0, tlv_size = 0; - struct frame_header * tlv = NULL; - - assertion(-500370, (op == TLV_DEL_TEST_ADD || op == TLV_DEBUG)); - - desc = on->desc0; //start with removing the old desc0_tlvs - - do { - if (op == TLV_TEST || op == TLV_ADD) - desc = desc_new; - - if (!desc || (op == TLV_DEL_TEST_ADD && on->blocked)) - continue; + TRACE_FUNCTION_CALL; + int i; + assertion(-500845, (tx_task_lists));
+ for (i = 0; i < FRAME_TYPE_ARRSZ; i++) {
- dbgf_all( DBGT_INFO, "%s %s dsc_sqn %d size %d ", - tlv_op_str[op], desc->id.name, ntohs(desc->dsc_sqn), ntohs(desc->dsc_tlvs_len)); + struct list_node *lpos, *tpos, *lprev = (struct list_node*) & tx_task_lists[i];
+ list_for_each_safe(lpos, tpos, &tx_task_lists[i]) + { + struct tx_task_node * tx_task = list_entry(lpos, struct tx_task_node, list);
- size = ntohs(desc->dsc_tlvs_len); - tlv = NULL; - pos = t = pt = 0; + if ((!only_link || only_link == tx_task->content.link) && + (!only_dev || only_dev == tx_task->content.dev)) {
- assertion(-500274, (size <= MAX_DESC0_TLV_SIZE)); // checked in rx_frm_desc0_advs() + if (packet_frame_handler[tx_task->content.type].min_tx_interval) { + avl_remove(&tx_task->content.dev->tx_task_tree, &tx_task->content, -300313); + }
- while (pos + sizeof ( struct frame_header) < size) { + list_del_next(&tx_task_lists[i], lprev);
- tlv = (struct frame_header*) (((char*) desc) + sizeof (struct description) + pos); - tlv_size = ntohs(tlv->length); + dbgf_all(DBGT_INFO, "removed frame_type=%d ln=%s dev=%s tx_tasks_list.items=%d", + tx_task->content.type, + ipXAsStr(af_cfg, tx_task->content.link ? &tx_task->content.link->link_ip : &ZERO_IP), + tx_task->content.dev->label_cfg.str, tx_task_lists[tx_task->content.type].items);
- if ((t = tlv->type) < pt || - tlv_size < sizeof ( struct frame_header) || - tlv_size + pos > size) { + debugFree(tx_task, -300066);
- dbgf(DBGL_SYS, DBGT_ERR, - "illegal sizes %d for type %s", tlv_size, description0_tlv_handler[t].name); - goto process_desc0_tlv_error; + continue; }
- dbgf(DBGL_ALL, DBGT_INFO, - "type %s size %d flags 0x%X", description0_tlv_handler[t].name, tlv_size, tlv->flags); - - - if (t >= BMX_DSC_TLV_ARRSZ || !(description0_tlv_handler[t].process_tlv)) { - - dbgf(DBGL_SYS, DBGT_WARN, - "unsupported type %d ! maybe you need an update?", t); - - if (t >= BMX_DSC_TLV_ARRSZ) - goto process_desc0_tlv_error; + lprev = lpos; + } + } +}
- } else if (tlv_size - sizeof (struct frame_header) < description0_tlv_handler[t].min_msg_size) {
- dbgf(DBGL_SYS, DBGT_ERR, - "too small size %d for type %s", tlv_size, description0_tlv_handler[t].name); - goto process_desc0_tlv_error; +STATIC_FUNC +IDM_T freed_tx_task_node(struct tx_task_node *tx_task, struct list_head *tx_task_list, struct list_node *lprev) +{ + TRACE_FUNCTION_CALL; + assertion(-500372, (tx_task && tx_task->content.dev)); + assertion(-500539, lprev);
- } else if (!(description0_tlv_handler[t].variable_msg_size) && - (tlv_size - sizeof (struct frame_header)) % description0_tlv_handler[t].min_msg_size) { + if (tx_task->tx_iterations <= 0) {
- dbgf(DBGL_SYS, DBGT_ERR, - "nonmaching size %d for type %s", tlv_size, description0_tlv_handler[t].name); - goto process_desc0_tlv_error; + if (packet_frame_handler[tx_task->content.type].min_tx_interval) { + avl_remove(&tx_task->content.dev->tx_task_tree, &tx_task->content, -300314); + }
- } else if ((tlv_result = (*(description0_tlv_handler[t].process_tlv)) (on, tlv, op, cn)) != TLVS_SUCCESS) { + list_del_next(tx_task_list, lprev);
- assertion(-500356, (op == TLV_TEST)); + debugFree(tx_task, -300169);
- dbgf(DBGL_SYS, DBGT_ERR, - "%s size %d %s", description0_tlv_handler[t].name, tlv_size, - tlv_result == TLVS_BLOCKED ? "BLOCKED" : "FAILURE"); + return YES; + }
- if (tlv_result == TLVS_BLOCKED) { + return NO; +}
- on->blocked = YES;
- if (!avl_find(&blocked_tree, &on->id)) - avl_insert(&blocked_tree, on, -300165); +STATIC_FUNC +IDM_T tx_task_obsolete(struct tx_task_node *tx_task) +{ + TRACE_FUNCTION_CALL; + struct dhash_node *dhn = NULL;
- return TLVS_BLOCKED; - } + if (tx_task->content.myIID4x > IID_RSVD_MAX && + (!(dhn = iid_get_node_by_myIID4x(tx_task->content.myIID4x)) || !dhn->on)) { + goto return_obsolete; + }
- goto process_desc0_tlv_msg_error; - } + if (!packet_frame_handler[tx_task->content.type].min_tx_interval) + return NO;
- pt = t; - pos += tlv_size; - } + if (((TIME_T) (bmx_time - tx_task->send_ts) < packet_frame_handler[tx_task->content.type].min_tx_interval)) {
- if (pos != size) { - dbgf(DBGL_SYS, DBGT_ERR, "nonmaching tlvs pos %d != size %d", pos, size ); + goto return_obsolete; + }
- goto process_desc0_tlv_error; - } + tx_task->send_ts = bmx_time;
- } while (++op < TLV_DONE); + return NO;
- if ( op == TLV_DONE ) { - on->blocked = NO; - avl_remove(&blocked_tree, &on->id, -300211); - } - - return SUCCESS;
+return_obsolete: + dbgf(DBGL_CHANGES, DBGT_INFO, + "%s type=%s dev=%s myIId4x=%d neighIID4x=%d link_id=0x%X name=%s or send just %d ms ago", + (dhn && dhn->on) ? "OMITTING" : (!dhn ? "UNKNOWN" : "INVALIDATED"), + packet_frame_handler[tx_task->content.type].name, tx_task->content.dev->name_phy_cfg.str, + tx_task->content.myIID4x, tx_task->content.neighIID4x, tx_task->content.link ? tx_task->content.link->link_id : 0, + (dhn && dhn->on) ? dhn->on->id.name : "???", (bmx_time - tx_task->send_ts));
-process_desc0_tlv_msg_error: - dbgf(DBGL_SYS, DBGT_WARN, - "rcvd problematic message"); + return YES; +}
-process_desc0_tlv_error: - dbgf(DBGL_SYS, DBGT_WARN, - "rcvd problematic frame type %s last %s frm_size %d pos %d ", - description0_tlv_handler[t].name, description0_tlv_handler[pt].name, tlv_size, pos);
- return TLVS_FAILURE; -}
-//BMX3 (done) -struct dhash_node * process_description(struct packet_buff *pb, struct description *desc, struct description_hash *dhash) +STATIC_FUNC +struct tx_task_node *tx_task_new(struct link_dev_node *dest_lndev, struct tx_task_node *test) { - assertion(-500262, (pb && pb->ln && desc)); - assertion(-500381, (!avl_find( &dhash_tree, dhash ))); - + assertion(-500909, (dest_lndev)); + struct frame_handl *handl = &packet_frame_handler[test->content.type]; + struct tx_task_node * tx_task = NULL; struct dhash_node *dhn; - struct orig_node *on = NULL; - int id_name_len; - - - dbgf_all( DBGT_INFO, "via dev: %s NB %s:dhash %8X.. id.rand %jX", - pb->iif->name, pb->neigh_str, dhash->h.u32[0], desc->id.rand.u64[0]); - - if ( - (id_name_len = strlen(desc->id.name)) >= DESCRIPTION0_ID_NAME_LEN || - !is_zero(&desc->id.name[id_name_len], DESCRIPTION0_ID_NAME_LEN - id_name_len) || - validate_name(desc->id.name) == FAILURE) { - - dbg(DBGL_SYS, DBGT_ERR, "illegal hostname .. %jX", desc->id.rand.u64[0]); - goto process_desc0_error; - } - - if ( - validate_param(ntohs(desc->ogm_sqn_range), MIN_OGM0_SQN_RANGE, MAX_OGM0_SQN_RANGE, ARG_OGM0_SQN_RANGE, NULL) || - validate_param(desc->ogm_sqn_pq_bits, MIN_OGM0_PQ_BITS, MAX_OGM0_PQ_BITS, ARG_OGM0_PQ_BITS, NULL) || - validate_param(ntohs(desc->path_ogi), 0, 0, NULL, get_option(0, 0, ARG_OGM_INTERVAL)) || - validate_param(desc->ttl_max, 0, 0, NULL, get_option(0, 0, ARG_TTL)) || - validate_param(ntohs(desc->path_window_size), 0, 0, NULL, get_option(0, 0, ARG_PWS)) || - validate_param(ntohs(desc->path_lounge_size), 0, 0, NULL, get_option(0, 0, ARG_PATH_LOUNGE)) || - validate_param(desc->path_hystere, 0, 0, NULL, get_option(0, 0, ARG_PATH_HYST)) || -// validate_param(dsc->hop_penalty, 0, 0, NULL, get_option(0, 0, ARG_HOP_PENALTY)) || - validate_param(desc->late_penalty, 0, 0, NULL, get_option(0, 0, ARG_LATE_PENAL)) || - validate_param(desc->asym_weight, 0, 0, NULL, get_option(0, 0, ARG_ASYM_WEIGHT)) || -// validate_param(dsc->sym_weight, 0, 0, NULL, get_option(0, 0, ARG_SYM_WEIGHT)) || - 0 - ) {
- goto process_desc0_error; + if (test->content.myIID4x > IID_RSVD_MAX && (!(dhn = iid_get_node_by_myIID4x(test->content.myIID4x)) || !dhn->on)) { + return NULL; }
+ if (handl->min_tx_interval) {
- if ((on = avl_find_item(&orig_tree, &desc->id))) { - - assertion(-500383, (on->dhn)); + if ((tx_task = avl_find_item(&test->content.dev->tx_task_tree, &test->content))) {
- if (((uint32_t) (bmx_time - on->dhn->referred_timestamp)) < (uint32_t) dad_to) { + ASSERTION(-500905, (tx_task->frame_msgs_length == test->frame_msgs_length)); + ASSERTION(-500906, (IMPLIES((!handl->is_advertisement), (tx_task->content.link == test->content.link)))); + //ASSERTION(-500907, (tx_task->u16 == test->u16));
- if ( ((SQN_T)(ntohs(desc->dsc_sqn) - (on->desc0_sqn + 1))) > SQN_DAD_RANGE ) { + tx_task->tx_iterations = MAX(tx_task->tx_iterations, test->tx_iterations);
- dbgf(DBGL_SYS, DBGT_ERR, "DAD-Alert: new dsc_sqn %d not > old %d + 1", - ntohs(desc->dsc_sqn), on->desc0_sqn); + // then it is already scheduled + return tx_task; + }
- goto process_desc0_ignore; - } + tx_task = debugMalloc(sizeof ( struct tx_task_node), -300026); + memcpy(tx_task, test, sizeof ( struct tx_task_node));
- if (LESS_SQN(ntohs(desc->ogm_sqn_min), (on->ogm_sqn_min + MAX_OGM0_SQN_RANGE))) { + tx_task->send_ts = ((TIME_T) (bmx_time - handl->min_tx_interval));
- dbgf(DBGL_SYS, DBGT_ERR, "DAD-Alert: new ogm_sqn_min %d not > old %d + %d", - ntohs(desc->ogm_sqn_min), on->ogm_sqn_min, MAX_OGM0_SQN_RANGE); + avl_insert(&test->content.dev->tx_task_tree, tx_task, -300315);
- goto process_desc0_ignore; - } + if (test->content.dev->tx_task_tree.items > DEF_TX_TS_TREE_SIZE) { + dbg_mute(20, DBGL_SYS, DBGT_WARN, + "%s tx_ts_tree reached %d %s neighIID4x=%d u16=%d u32=%d myIID4x=%d", + test->content.dev->name_phy_cfg.str, test->content.dev->tx_task_tree.items, + handl->name, test->content.neighIID4x, test->content.u16, test->content.u32, test->content.myIID4x); }
} else { - // create new orig: - on = debugMalloc( sizeof( struct orig_node ), -300128 ); - memset( on, 0, sizeof( struct orig_node ) ); - memcpy(&on->id, &desc->id, sizeof ( struct description_id)); -/* - on->id.rand.u32[0] = ntohl( desc->id.rand.u32[0] ); - on->id.rand.u32[1] = ntohl( desc->id.rand.u32[1] ); -*/ - AVL_INIT_TREE(on->router_tree, struct router_node, key ); - avl_insert(&orig_tree, on, -300148); - } - - dbgf_all( DBGT_INFO, "rcvd new desc SQN %d (old %d) from %s via %s NB %s", - ntohs(desc->dsc_sqn), on->desc0_sqn, desc->id.name, pb->iif->name, pb->neigh_str); - - if (process_description_tlvs(on, desc, TLV_DEL_TEST_ADD, NULL) == TLVS_FAILURE) - goto process_desc0_error;
- // might result in TLVS_BLOCKED !! + tx_task = debugMalloc(sizeof ( struct tx_task_node), -300026); + memcpy(tx_task, test, sizeof ( struct tx_task_node)); + }
- on->updated_timestamp = bmx_time; - on->desc0_sqn = ntohs(desc->dsc_sqn); + if (handl->is_destination_specific_frame) {
- on->ogm_sqn_min = ntohs(desc->ogm_sqn_min); - on->ogm_sqn_range = ntohs(desc->ogm_sqn_range); - on->ogm_sqn_pq_bits = desc->ogm_sqn_pq_bits; + // ensure, this is NOT a dummy dest_lndev!!!: + ASSERTION(-500850, (dest_lndev && dest_lndev == avl_find_item(&link_dev_tree, &dest_lndev->key)));
-// on->ogm_sqn_mask = (MAX_SQN << on->ogm_sqn_pq_bits); -// on->ogm_sqn_steps = (0x01 << on->ogm_sqn_pq_bits); + list_add_tail(&(dest_lndev->tx_task_lists[test->content.type]), &tx_task->list);
+ dbgf(DBGL_CHANGES, DBGT_INFO, "added %s to lndev link_id=%X link_ip=%s dev=%s tx_tasks_list.items=%d", + handl->name, dest_lndev->key.link->link_id, + ipXAsStr(af_cfg, &dest_lndev->key.link->link_ip), + dest_lndev->key.dev->label_cfg.str, dest_lndev->tx_task_lists[test->content.type].items);
- struct metric_algo test_algo; - memset(&test_algo, 0, sizeof (struct metric_algo)); + } else {
- test_algo.sqn_mask = (MAX_SQN << on->ogm_sqn_pq_bits); - test_algo.sqn_steps = (0x01 << on->ogm_sqn_pq_bits); - test_algo.regression = ntohs(desc->path_window_size) / test_algo.sqn_steps / 2; - test_algo.sqn_lounge = ntohs(desc->path_lounge_size); - test_algo.sqn_window = ntohs(desc->path_window_size); - test_algo.metric_max = PROBE_RANGE; + list_add_tail(&(test->content.dev->tx_task_lists[test->content.type]), &tx_task->list); + }
+ return tx_task; +}
- if ( validate_metric_algo( &test_algo, NULL ) == FAILURE ) - goto process_desc0_error; +void schedule_tx_task(struct link_dev_node *dest_lndev, + uint16_t frame_type, uint16_t frame_msgs_len, uint16_t u16, uint32_t u32, IID_T myIID4x, IID_T neighIID4x) +{ + TRACE_FUNCTION_CALL;
- memcpy(&on->path_metric_algo, &test_algo, sizeof (struct metric_algo)); + if (!dest_lndev) + return;
- on->ogm_sqn_max_rcvd = on->ogm_sqn_aggregated = on->ogm_sqn_to_be_send = (on->ogm_sqn_min & on->path_metric_algo.sqn_mask); + assertion(-500756, (dest_lndev && dest_lndev->key.dev)); + ASSERTION(-500713, (iid_get_node_by_myIID4x(myIID4me))); + ASSERTION(-500714, (!myIID4x || iid_get_node_by_myIID4x(myIID4x)));
+ struct frame_handl *handl = &packet_frame_handler[frame_type]; + struct dev_node *dev_out = dest_lndev->key.dev;
- // migrate current router_nodes->mr.clr position to new sqn_range: - struct router_node *rn; - struct avl_node *an; - for (an = NULL; (rn = avl_iterate_item(&on->router_tree, &an));) - rn->mr.clr = on->ogm_sqn_max_rcvd /*- on->path_metric_algo.sqn_steps*/; + if (handl->tx_iterations && !(*handl->tx_iterations)) + return;
+ self.dhn->referred_by_me_timestamp = bmx_time;
- if (on->desc0) - debugFree(on->desc0, -300111); + if (myIID4x) + iid_get_node_by_myIID4x(myIID4x)->referred_by_me_timestamp = bmx_time;
- on->desc0 = desc; - desc = NULL; + dbgf_all(DBGT_INFO, "%s %s sqn=%d myIID4x=%d neighIID4x=%d", + handl->name, dev_out->label_cfg.str, u16, myIID4x, neighIID4x);
- struct neigh_node *dhn_neigh = NULL; + if (handl->umetric_rq_min && *(handl->umetric_rq_min) > dest_lndev->mr[SQR_RQ].umetric_final) {
- if (on->dhn) { - dhn_neigh = on->dhn->neigh; - on->dhn->neigh = NULL; - on->dhn->on = NULL; - invalidate_dhash_node(on->dhn); + dbgf(DBGL_SYS, DBGT_INFO, "NOT sending %s (via %s sqn %d myIID4x %d neighIID4x %d) %ju < %ju", + handl->name, dev_out->label_cfg.str, u16, myIID4x, neighIID4x, + dest_lndev->mr[SQR_RQ].umetric_final, *(handl->umetric_rq_min)); + return; } - - on->dhn = dhn = create_dhash_node(dhash, on);
- if ( dhn_neigh ) { - dhn_neigh->dhn = dhn; - dhn->neigh = dhn_neigh; + struct tx_task_node test_task; + memset(&test_task, 0, sizeof (test_task)); + test_task.content.u16 = u16; + test_task.content.u32 = u32; + test_task.content.dev = dev_out; + test_task.content.myIID4x = myIID4x; + test_task.content.neighIID4x = neighIID4x; + test_task.content.type = frame_type; + test_task.tx_iterations = handl->tx_iterations ? *handl->tx_iterations : 1; + test_task.considered_ts = bmx_time - 1; + + // advertisements are send to all and are not bound to a specific destinations, + // therfore tx_task_obsolete should not filter due to the destination_link_id + if (!handl->is_advertisement && dest_lndev->key.link) { + ASSERTION(-500915, (dest_lndev == avl_find_item(&link_dev_tree, &dest_lndev->key))); + test_task.content.link = dest_lndev->key.link; + test_task.content.lndev = dest_lndev; }
- assertion(-500309, (dhn == avl_find_item(&dhash_tree, &dhn->dhash) && dhn->on == on)); - - assertion(-500310, (on == avl_find_item(&orig_tree, &on->desc0->id) && on->dhn == dhn)); - - return dhn; - -process_desc0_error: + if (frame_msgs_len) { + assertion(-500371, IMPLIES(handl->fixed_msg_size, !(frame_msgs_len % handl->min_msg_size))); + test_task.frame_msgs_length = frame_msgs_len; + } else { + assertion(-500769, (handl->fixed_msg_size && handl->min_msg_size)); + test_task.frame_msgs_length = handl->min_msg_size; + }
- if (on) - free_orig_node(on); + tx_task_new(dest_lndev, &test_task); +}
- blacklist_neighbor(pb);
-process_desc0_ignore:
- dbgf(DBGL_SYS, DBGT_WARN, "%jX rcvd via %s NB %s", desc ? desc->id.rand.u64[0] : 0, pb->iif->name, pb->neigh_str);
- if (desc) - debugFree(desc, -300109); - - return NULL; -}
-IDM_T freed_tx_task_node(struct tx_task_node *ttn, int tx_creator_result, struct list_node *lprev) +OGM_SQN_T set_ogmSqn_toBeSend_and_aggregated(struct orig_node *on, OGM_SQN_T to_be_send, OGM_SQN_T aggregated) { + TRACE_FUNCTION_CALL;
- assertion( -500372, (ttn && (ttn)->dev )); + to_be_send &= OGM_SQN_MASK; + aggregated &= OGM_SQN_MASK;
- if (tx_creator_result != ((int) ((ttn)->frame_data_length_target))) { - - dbgf_all( DBGT_WARN, "msg %s to %s via %s mid4o %d send_data %d != target_data %d ", - frame_handler[(ttn)->frame_type].name, - ipStr((ttn)->dst_ip4), - (ttn)->dev->name, - (ttn)->myIID4x, - tx_creator_result, - (ttn)->frame_data_length_target); - } + if (UXX_GT(OGM_SQN_MASK, to_be_send, aggregated)) {
- if ((--((ttn)->tx_iterations)) == 0) { + if (UXX_LE(OGM_SQN_MASK, on->ogmSqn_toBeSend, on->ogmSqn_aggregated)) + ogm_aggreg_pending++;
- (ttn)->dev->tx_frames_data_len_target -= (ttn)->frame_data_length_target; - - if (lprev) - list_del_next(&((ttn)->dev->tx_tasks_list[(ttn)->frame_type]), lprev); - else - (ttn)->dev->my_tx_tasks[(ttn)->frame_type] = NULL; + } else {
- debugFree((ttn), -300169); + assertion(-500830, (UXX_LE(OGM_SQN_MASK, to_be_send, aggregated)));
- return YES; + if (UXX_GT(OGM_SQN_MASK, on->ogmSqn_toBeSend, on->ogmSqn_aggregated)) + ogm_aggreg_pending--; }
- (ttn)->tx_timestamp = bmx_time; + on->ogmSqn_toBeSend = to_be_send; + on->ogmSqn_aggregated = aggregated;
- return NO; + return on->ogmSqn_toBeSend; }
-void schedule_tx_task(struct dev_node *dev_out, struct link_dev_node *lndev_out, - uint16_t frame_type, uint16_t frame_data_len, SQN_T sqn, IID_T myIID4x, IID_T neighIID4x) +STATIC_FUNC +IID_T create_ogm(struct orig_node *on, IID_T prev_ogm_iid, struct msg_ogm_adv *ogm) { - struct tx_task_node *ttn; - IP4_T dest_ip4 = lndev_out && lndev_out->link ? lndev_out->link->llip4 : 0; - -// struct link_node *ln_out = lndev_out ? lndev_out->link : NULL; - - dbgf_all( DBGT_INFO, "%s %s %s sqn %d myIID4x %d neighIID4x %d", - frame_handler[frame_type].name, ipStr(dest_ip4), dev_out->name, sqn, myIID4x, neighIID4x); - - if (frame_handler[ frame_type ].min_rtq > (lndev_out ? lndev_out->mr[SQR_RTQ].val : 0)) { - return; - } - - assertion(-500380, (myIID4x != myIID4me)); // should have been translated to IID_RSVD_4YOU by calling function - - assertion(-500433, (frame_handler[frame_type].tx_iterations)); - - if (myIID4x == IID_RSVD_4YOU) { - - if ((ttn = dev_out->my_tx_tasks[frame_type])) { - - dbgf(DBGL_CHANGES, DBGT_WARN, "my_tx_task for %s %s myIID4x %d neighIID4x %d dst %s NOT NULL", - frame_handler[frame_type].name, dev_out->name, myIID4x, neighIID4x, ipStr(dest_ip4)); - - assertion(-500442, (ttn->myIID4x == IID_RSVD_4YOU)); - - dev_out->tx_frames_data_len_target -= ttn->frame_data_length_target; - - } else { - ttn = dev_out->my_tx_tasks[frame_type] = debugMalloc(sizeof ( struct tx_task_node), -300026); - } - - } else { + TRACE_FUNCTION_CALL; + uint8_t exp_offset = on->path_metricalgo->exp_offset; + FMETRIC_T fm = umetric_to_fmetric(exp_offset, + (on == &self ? umetric_max(DEF_FMETRIC_EXP_OFFSET) : on->curr_rn->mr.umetric_final));
- ttn = debugMalloc(sizeof ( struct tx_task_node), -300026); - list_add_tail(&(dev_out->tx_tasks_list[frame_type]), &ttn->list); - } - - ttn->sqn = sqn; - ttn->dst_ip4 = dest_ip4; - ttn->myIID4x = myIID4x; - ttn->neighIID4x = neighIID4x; - ttn->frame_type = frame_type; - ttn->tx_iterations = frame_handler[frame_type].tx_iterations; - ttn->tx_timestamp = bmx_time - 1; - ttn->dev = dev_out; - - if (!frame_data_len && frame_handler[frame_type].fixed_msg_size && !frame_handler[frame_type].data_header_size) { - - ttn->frame_data_length_target = frame_handler[ frame_type ].min_msg_size; + if (UXX_GT(OGM_SQN_MASK, on->ogmSqn_toBeSend, on->ogmSqn_aggregated + OGM_SQN_STEP)) {
+ dbgf(DBGL_CHANGES, DBGT_WARN, "%s delayed %d < %d", + on->id.name, on->ogmSqn_aggregated, on->ogmSqn_toBeSend); } else {
- assertion( -500371, (frame_data_len)); - - ttn->frame_data_length_target = frame_data_len; + dbgf_all(DBGT_INFO, "%s in-time %d < %d", on->id.name, on->ogmSqn_aggregated, on->ogmSqn_toBeSend); }
- dev_out->tx_frames_data_len_target += ttn->frame_data_length_target; - - - uint16_t estimated_packet_len = - (sizeof (struct packet_header)) + - (sizeof (struct frame_header) * FRAME_TYPE_ARRSZ) + - (dev_out->tx_frames_data_len_target) + - (sizeof (struct msg_ogm_adv) * ogm_aggreg_pending); - - - if (estimated_packet_len > max_udpd_size) { - remove_task(tx_packet, dev_out); - register_task(1, tx_packet, dev_out); - } - - -} - - + set_ogmSqn_toBeSend_and_aggregated(on, on->ogmSqn_toBeSend, on->ogmSqn_toBeSend);
+ on->dhn->referred_by_me_timestamp = bmx_time;
-void purge_dev_tx_list( struct dev_node *dev ) { - int i; + assertion( -500890, ((on->dhn->myIID4orig - prev_ogm_iid) <= OGM_IIDOFFST_MASK)); + assertion( -500891, ((fm.val.f.exp_total - exp_offset) <= OGM_EXPONENT_MASK)); + assertion( -500892, ((fm.val.f.mantissa) <= OGM_MANTISSA_MASK));
- paranoia( -500203, !dev ); + OGM_MIX_T mix = + ((on->dhn->myIID4orig - prev_ogm_iid) << OGM_IIDOFFST_BIT_POS) + + ((fm.val.f.exp_total - exp_offset) << OGM_EXPONENT_BIT_POS) + + ((fm.val.f.mantissa) << OGM_MANTISSA_BIT_POS);
- for (i = 0; i < FRAME_TYPE_ARRSZ; i++) { + ogm->mix = htons(mix); + ogm->u.ogm_sqn = htons(on->ogmSqn_toBeSend);
- struct tx_task_node * dtn; - - while ((dtn=list_rem_head( &(dev->tx_tasks_list[i]) ) )) - debugFree(dtn, -300066); - - if ((dtn = dev->my_tx_tasks[i])) { - debugFree(dtn, -300066); - dev->my_tx_tasks[i]=NULL; - } - - } + return on->dhn->myIID4orig; }
STATIC_FUNC void create_ogm_aggregation(void) { + TRACE_FUNCTION_CALL; + uint32_t target_ogms = MIN(OGMS_PER_AGGREG_MAX, + ((ogm_aggreg_pending < ((OGMS_PER_AGGREG_PREF / 3)*4)) ? ogm_aggreg_pending : OGMS_PER_AGGREG_PREF));
- dbgf_all( DBGT_INFO, " "); - - uint32_t n = 0; + struct msg_ogm_adv* msgs = + debugMalloc((target_ogms + OGM_JUMPS_PER_AGGREGATION) * sizeof (struct msg_ogm_adv), -300177);
- uint32_t target_aggregations = MIN(MAX_OGMS_PER_AGGREG, - ((ogm_aggreg_pending < ((DEF_OGMS_PER_AGGREG / 3)*4)) ? ogm_aggreg_pending : DEF_OGMS_PER_AGGREG)); + IID_T curr_iid; + IID_T ogm_iid = 0; + IID_T ogm_iid_jumps = 0; + uint16_t ogm_msg = 0;
- struct msg_ogm_adv* ogm = debugMalloc(target_aggregations * sizeof (struct msg_ogm_adv), -300177); + dbgf_all(DBGT_INFO, "pending %d target %d", ogm_aggreg_pending, target_ogms);
- static IID_T curr_iid = IID_MIN_USED; + for (curr_iid = IID_MIN_USED; curr_iid < my_iid_repos.max_free; curr_iid++) {
- if (curr_iid >= my_iid_repos.max_free) - curr_iid = IID_MIN_USED; - - IID_T start_iid = curr_iid; + IID_NODE_T *dhn = my_iid_repos.arr.node[curr_iid]; + struct orig_node *on = dhn ? dhn->on : NULL;
- dbgf_all( DBGT_INFO, "pending %d target %d start %d", - ogm_aggreg_pending, target_aggregations, start_iid); + if (on && UXX_GT(OGM_SQN_MASK, on->ogmSqn_toBeSend, on->ogmSqn_aggregated)) {
- do { - IID_NODE_T *dhn = my_iid_repos.arr.node[curr_iid]; - struct orig_node *on; - int warn = 0; + if (on != &self && (!on->curr_rn || on->curr_rn->mr.umetric_final < on->path_metricalgo->umetric_min)) {
- while (dhn && (on = dhn->on) && - GREAT_SQN(on->ogm_sqn_to_be_send & on->path_metric_algo.sqn_mask, on->ogm_sqn_aggregated)) { + dbgf(DBGL_SYS, DBGT_WARN, + "%s with %s curr_rn and PENDING ogm_sqn=%d but path_metric=%jd < USABLE=%jd", + on->id.name, on->curr_rn ? " " : "NO", on->ogmSqn_toBeSend, + on->curr_rn ? on->curr_rn->mr.umetric_final : 0, + on->path_metricalgo->umetric_min);
- if (GREAT_SQN(on->ogm_sqn_to_be_send & on->path_metric_algo.sqn_mask, - on->ogm_sqn_aggregated + on->path_metric_algo.sqn_steps)) - warn++; + assertion(-500816, (0));
- if ( warn ) { - dbgf(DBGL_CHANGES, DBGT_WARN, "%s delayed %d < %d", - on->id.name, on->ogm_sqn_aggregated, on->ogm_sqn_to_be_send); - } else { - dbgf_all(DBGT_INFO, "%s in-time %d < %d", - on->id.name, on->ogm_sqn_aggregated, on->ogm_sqn_to_be_send); + continue; }
+ if (((IID_T) (dhn->myIID4orig - ogm_iid) >= OGM_IID_RSVD_JUMP)) {
- on->ogm_sqn_aggregated = on->ogm_sqn_to_be_send & on->path_metric_algo.sqn_mask; + if (ogm_iid_jumps == OGM_JUMPS_PER_AGGREGATION) + break;
- ogm[n].orig_sqn = htons(on->ogm_sqn_to_be_send); - ogm[n].transmitterIID4x = htons(dhn->myIID4orig); + dbgf((ogm_iid_jumps > 1) ? DBGL_SYS : DBGL_ALL, DBGT_INFO, + "IID jump %d from %d to %d", ogm_iid_jumps, ogm_iid, dhn->myIID4orig);
- if ((++n) == target_aggregations) - goto create_ogm_aggregation_done; - } + ogm_iid = dhn->myIID4orig;
- if ((++curr_iid) >= my_iid_repos.max_free) - curr_iid = IID_MIN_USED; + msgs[ogm_msg + ogm_iid_jumps].mix = htons((OGM_IID_RSVD_JUMP) << OGM_IIDOFFST_BIT_POS); + msgs[ogm_msg + ogm_iid_jumps].u.transmitterIIDabsolute = htons(ogm_iid);
- } while (curr_iid != start_iid); + ogm_iid_jumps++; + }
-create_ogm_aggregation_done: + ogm_iid = create_ogm(on, ogm_iid, &msgs[ogm_msg + ogm_iid_jumps]);
- if (curr_iid == start_iid) - ogm_aggreg_pending = 0; - else - ogm_aggreg_pending -= n; + if ((++ogm_msg) == target_ogms) + break; + } + } + + assertion(-500817, (IMPLIES(curr_iid == my_iid_repos.max_free, !ogm_aggreg_pending)));
if (ogm_aggreg_pending) { dbgf(DBGL_SYS, DBGT_WARN, "%d ogms left for immediate next aggregation", ogm_aggreg_pending); }
- if (!n) { - debugFree( ogm, -300219); + if (!ogm_msg) { + debugFree( msgs, -300219); return; }
struct ogm_aggreg_node *oan = debugMalloc(sizeof (struct ogm_aggreg_node), -300179); - oan->aggregated_ogms = n; - oan->ogm_advs = ogm; - oan->tx_attempts = 0; - oan->tx_timestamp = (bmx_time - DEF_OGM_RESEND_INTERVAL); + oan->aggregated_msgs = ogm_msg + ogm_iid_jumps; + oan->ogm_advs = msgs; + oan->tx_attempt = 0; oan->sqn = ++ogm_aggreg_sqn_max;
- dbgf_all( DBGT_INFO, "aggregation_sqn %d aggregated_ogms %d", oan->sqn, n); + dbgf_all( DBGT_INFO, "aggregation_sqn %d aggregated_ogms %d", oan->sqn, ogm_msg);
list_add_tail(&ogm_aggreg_list, &oan->list);
@@ -910,16 +632,20 @@ create_ogm_aggregation_done:
while ((nn = avl_iterate_item(&neigh_tree, &an))) {
- bit_set(nn->ogm_aggregations_acked, OGM_AGGREG_SQN_CACHE_RANGE, ogm_aggreg_sqn_max, 0); - + bit_set(nn->ogm_aggregations_acked, AGGREG_SQN_CACHE_RANGE, ogm_aggreg_sqn_max, 0); }
return; }
+ + + + STATIC_FUNC struct link_dev_node **get_best_lndevs_by_criteria(struct ogm_aggreg_node *oan_criteria, struct dhash_node *dhn_criteria) { + TRACE_FUNCTION_CALL;
static struct link_dev_node **lndev_arr = NULL; static uint16_t lndev_arr_items = 0; @@ -928,12 +654,12 @@ struct link_dev_node **get_best_lndevs_by_criteria(struct ogm_aggreg_node *oan_c struct dev_node *dev; uint16_t d = 0;
- if (lndev_arr_items < dev_ip4_tree.items + 1) { + if (lndev_arr_items < dev_ip_tree.items + 1) {
if (lndev_arr) debugFree(lndev_arr, -300180);
- lndev_arr_items = dev_ip4_tree.items + 1; + lndev_arr_items = dev_ip_tree.items + 1; lndev_arr = debugMalloc((lndev_arr_items * sizeof (struct link_dev_node*)), -300182); }
@@ -945,36 +671,38 @@ struct link_dev_node **get_best_lndevs_by_criteria(struct ogm_aggreg_node *oan_c dbgf_all(DBGT_INFO, "NOT %s ", dhn_criteria->on->id.name); }
- for (an = NULL; (dev = avl_iterate_item(&dev_ip4_tree, &an));) - dev->misc_flag = NO; + for (an = NULL; (dev = avl_iterate_item(&dev_ip_tree, &an));) + dev->tmp = NO;
for (an = NULL; (nn = avl_iterate_item(&neigh_tree, &an));) {
if (oan_criteria && - (bit_get(nn->ogm_aggregations_acked, OGM_AGGREG_SQN_CACHE_RANGE, oan_criteria->sqn) || - nn->best_rtq->mr[SQR_RTQ].val <= MIN_OGM_ACK_RTQ) ) + (bit_get(nn->ogm_aggregations_acked, AGGREG_SQN_CACHE_RANGE, oan_criteria->sqn) || + nn->best_rtq->mr[SQR_RQ].umetric_final <= UMETRIC_RQ_OGM_ACK_MIN)) continue;
if (dhn_criteria && dhn_criteria->neigh == nn) continue;
- assertion(-500445, (nn->best_rtq)); - assertion(-500446, (nn->best_rtq->key.dev)); - assertion(-500447, (nn->best_rtq->key.dev->active)); + assertion(-500445, (nn->best_rtq && nn->best_rtq->key.dev)); + + struct dev_node *dev_best = nn->best_rtq->key.dev;
- dbgf_all( DBGT_INFO, " via %s to %s (redundant %d)", - nn->best_rtq->key.dev->name, nn->best_rtq->link->llip4_str, - nn->best_rtq->key.dev->misc_flag); + assertion(-500446, (dev_best)); + assertion(-500447, (dev_best->active));
- if (nn->best_rtq->key.dev->misc_flag == NO) { + dbgf_all( DBGT_INFO, " via dev=%s to link_id=0x%X (redundant %d)", + dev_best->label_cfg.str, nn->best_rtq->key.link->link_id, dev_best->tmp); + + if (dev_best->tmp == NO) {
lndev_arr[d++] = nn->best_rtq;
- nn->best_rtq->key.dev->misc_flag = YES; + dev_best->tmp = YES; }
- assertion(-500444, (d <= dev_ip4_tree.items)); + assertion(-500444, (d <= dev_ip_tree.items));
} } @@ -985,21 +713,25 @@ struct link_dev_node **get_best_lndevs_by_criteria(struct ogm_aggreg_node *oan_c }
STATIC_FUNC -void schedule_and_purge_ogm_aggregations(struct dev_node *dev) +void schedule_or_purge_ogm_aggregations(IDM_T purge_all) { - static uint32_t timestamp = 0; + TRACE_FUNCTION_CALL; + + static TIME_T timestamp = 0; + + dbgf_all(DBGT_INFO, "max %d active aggregations %d pending ogms %d expiery in %d ms", + ogm_aggreg_sqn_max, ogm_aggreg_list.items, ogm_aggreg_pending, + (my_tx_interval - ((TIME_T) (bmx_time - timestamp))));
- if (dev) { + if (!purge_all && timestamp != bmx_time) {
- dbgf_all( DBGT_INFO, "%s max %d active aggregations %d pending ogms %d expiery in %d ms", - dev->name, ogm_aggreg_sqn_max, ogm_aggreg_list.items, ogm_aggreg_pending, - (DEF_OGM_AGGREG_INTERVAL - ((uint32_t) (bmx_time - timestamp)))); + timestamp = bmx_time;
- while (ogm_aggreg_pending && ((((uint32_t) bmx_time - timestamp)) >= DEF_OGM_AGGREG_INTERVAL)) { + while (ogm_aggreg_pending) {
struct ogm_aggreg_node *oan = list_get_first(&ogm_aggreg_list);
- if (oan && ((SQN_T) ((ogm_aggreg_sqn_max + 1) - oan->sqn)) >= OGM_AGGREG_SQN_CACHE_RANGE) { + if (oan && ((AGGREG_SQN_MASK)& ((ogm_aggreg_sqn_max + 1) - oan->sqn)) >= AGGREG_SQN_CACHE_RANGE) {
dbgf(DBGL_SYS, DBGT_WARN, "ogm_aggreg_list full min %d max %d items %d unaggregated %d", @@ -1012,22 +744,33 @@ void schedule_and_purge_ogm_aggregations(struct dev_node *dev)
create_ogm_aggregation();
- if (!ogm_aggreg_pending) - timestamp = bmx_time; - } - } + if (!ogm_aggreg_pending) {
-#ifndef NO_PARANOIA - if (!ogm_aggreg_pending) { - IID_T i; - struct dhash_node *dhn; - for (i = IID_MIN_USED; i < my_iid_repos.max_free && (dhn = my_iid_repos.arr.node[i]); i++) { - struct orig_node * on = dhn->on; - assertion(-500473, - (!(on && GREAT_SQN(on->ogm_sqn_to_be_send & on->path_metric_algo.sqn_mask, on->ogm_sqn_aggregated)))); + +#ifdef EXTREME_PARANOIA + IID_T curr_iid; + for (curr_iid = IID_MIN_USED; curr_iid < my_iid_repos.max_free; curr_iid++) { + + IID_NODE_T *dhn = my_iid_repos.arr.node[curr_iid]; + struct orig_node *on = dhn ? dhn->on : NULL; + + if (on && on->curr_rn && + UXX_GT(OGM_SQN_MASK, on->ogmSqn_toBeSend, on->ogmSqn_aggregated) && + on->curr_rn->mr.umetric_final >= on->path_metricalgo->umetric_min) { + + dbgf(DBGL_SYS, DBGT_ERR, + "%s with %s curr_rn and PENDING ogm_sqn=%d but path_metric=%jd < USABLE=%jd", + on->id.name, on->curr_rn ? " " : "NO", on->ogmSqn_toBeSend, + on->curr_rn ? on->curr_rn->mr.umetric_final : 0, on->path_metricalgo->umetric_min); + + ASSERTION( -500473, (0)); + + } + } +#endif + } } } -#endif
struct list_node *lpos, *tpos, *lprev = (struct list_node*) & ogm_aggreg_list;
@@ -1035,9 +778,7 @@ void schedule_and_purge_ogm_aggregations(struct dev_node *dev) { struct ogm_aggreg_node *oan = list_entry(lpos, struct ogm_aggreg_node, list);
- if (dev == NULL/*purge_all*/ || - ((((uint32_t) (bmx_time - oan->tx_timestamp)) > DEF_OGM_RESEND_INTERVAL) && - oan->tx_attempts > ogm_resend_attempts)) { + if (purge_all || oan->tx_attempt >= ogm_tx_iters) {
list_del_next(&ogm_aggreg_list, lprev); debugFree(oan->ogm_advs, -300183); @@ -1045,23 +786,30 @@ void schedule_and_purge_ogm_aggregations(struct dev_node *dev)
continue;
- } else if ((((uint32_t) (bmx_time - oan->tx_timestamp)) >= DEF_OGM_RESEND_INTERVAL) && - oan->tx_attempts <= ogm_resend_attempts) { + } else if (oan->tx_attempt < ogm_tx_iters) {
struct link_dev_node **lndev_arr = get_best_lndevs_by_criteria(oan, NULL); int d;
+ if (!lndev_arr[0]) + oan->tx_attempt = ogm_tx_iters; + else + oan->tx_attempt++; + for (d = 0; (lndev_arr[d]); d++) { - schedule_tx_task((lndev_arr[d])->key.dev, NULL, FRAME_TYPE_OGM0_ADVS, - (sizeof (struct hdr_ogm_adv) + (oan->aggregated_ogms * sizeof (struct msg_ogm_adv))), - oan->sqn, 0, 0); + + schedule_tx_task((lndev_arr[d]), FRAME_TYPE_OGM_ADVS, + (oan->aggregated_msgs * sizeof (struct msg_ogm_adv)), oan->sqn, 0, 0, 0); + + if (oan->tx_attempt >= ogm_tx_iters) { + dbgf(DBGL_CHANGES, DBGT_INFO, + "ogm_aggregation_sqn=%d msgs=%d tx_attempt=%d/%d via dev=%s last send!", + oan->sqn, oan->aggregated_msgs, oan->tx_attempt, ogm_tx_iters, + lndev_arr[d]->key.dev->label_cfg.str); + } }
- if (!lndev_arr[0]) - oan->tx_attempts = ogm_resend_attempts;
- oan->tx_timestamp = bmx_time; - oan->tx_attempts++; }
lprev = lpos; @@ -1070,15 +818,23 @@ void schedule_and_purge_ogm_aggregations(struct dev_node *dev)
STATIC_FUNC -int tx_msg_hello40_reply(struct tx_task_node *ttn, uint8_t *flags, uint8_t *tx_buff, uint16_t buff_size) +int32_t tx_msg_hello_reply(struct tx_frame_iterator *it) { - struct msg_hello_reply *hey0_rep = (struct msg_hello_reply *) (tx_buff); + TRACE_FUNCTION_CALL; + assertion(-500916, (it->ttn->content.lndev)); + assertion(-500585, (it->ttn->content.link && it->ttn->content.link->link_id >= LINK_ID_MIN)); + assertion(-500770, (tx_iterator_cache_data_space(it) >= ((int) sizeof (struct msg_hello_reply))));
- hey0_rep->receiver_ip4 = ttn->dst_ip4; - hey0_rep->hello_dev_sqn = htons(ttn->sqn); + struct tx_task_node *ttn = it->ttn; + struct msg_hello_reply *msg = (struct msg_hello_reply *) (tx_iterator_cache_msg_ptr(it)); + HELLO_FLAGS_SQN_T flags = ttn->content.lndev->tx_hello_reply_flags;
- dbgf_all( DBGT_INFO, "dev %s %s to %s SQN %d",// dest_sid: %d", - ttn->dev->name, ttn->dev->ip4_str, ipStr(ttn->dst_ip4), ttn->sqn/*, dtn->my_id_for_neigh*/); + msg->hello_flags_sqn = htons((ttn->content.u16 << HELLO_SQN_BIT_POS) + (flags << HELLO_FLAGS_BIT_POS)); + + msg->transmitterIID4x = htons(ttn->content.myIID4x); + + dbgf_all(DBGT_INFO, "dev=%s to link_id=0x%X SQN=%d", + ttn->content.dev->label_cfg.str, ttn->content.link->link_id, ttn->content.u16);
return sizeof (struct msg_hello_reply); } @@ -1086,115 +842,186 @@ int tx_msg_hello40_reply(struct tx_task_node *ttn, uint8_t *flags, uint8_t *tx_b
STATIC_FUNC -int tx_msg_helloX0_adv(struct tx_task_node *ttn, uint8_t *flags, uint8_t *tx_buff, uint16_t buff_size) +int32_t tx_msg_hello_adv(struct tx_frame_iterator *it) {
- struct msg_hello_adv *hey0_adv = (struct msg_hello_adv *) (tx_buff); + TRACE_FUNCTION_CALL; + assertion(-500771, (tx_iterator_cache_data_space(it) >= ((int) sizeof (struct msg_hello_adv)))); + assertion(-500906, (it->ttn->content.dev->link_hello_sqn <= HELLO_SQN_MASK));
- hey0_adv->hello_dev_sqn = htons(++(ttn->dev->ogm_sqn)); - - struct avl_node *it; + struct tx_task_node *ttn = it->ttn; + struct msg_hello_adv *adv = (struct msg_hello_adv *) (tx_iterator_cache_msg_ptr(it)); + struct avl_node *an; struct link_dev_node *lndev;
- for (it = NULL; (lndev = avl_iterate_item(&link_dev_tree, &it));) { - // we dont want to clean the sqr of other devs - // update_link_node(ln, ttn->dev, ttn->dev->ogm_sqn, ttn->dev->ogm_sqn, SQR_RTQ, 0); - if (lndev->key.dev != ttn->dev) + HELLO_FLAGS_SQN_T sqn_in = ttn->content.dev->link_hello_sqn = ((HELLO_SQN_MASK)&(ttn->content.dev->link_hello_sqn + 1)); + HELLO_FLAGS_SQN_T sqn_min = ((HELLO_SQN_MASK)&(sqn_in + 1 - DEF_HELLO_SQN_RANGE)); + HELLO_FLAGS_SQN_T flags = 0; + HELLO_FLAGS_SQN_T flags_sqn = (sqn_in << HELLO_SQN_BIT_POS) + (flags << HELLO_FLAGS_BIT_POS); + + adv->hello_flags_sqn = htons(flags_sqn); + + for (an = NULL; (lndev = avl_iterate_item(&link_dev_tree, &an));) { + + if (lndev->key.dev != ttn->content.dev) continue;
-// update_lounged_metric(0, local_rtq_lounge, ttn->dev->ogm_sqn, ttn->dev->ogm_sqn, &lndev->sqr[SQR_RTQ], local_lws); + //TODO: maybe this should go to update_link_metric() + + update_metric_record(NULL, &lndev->mr[SQR_RTQ], &link_metric_algo[SQR_RTQ], DEF_HELLO_SQN_RANGE, sqn_min, sqn_in, NULL); + + if (lndev->key.link->neigh && lndev->key.link->neigh->dhn && lndev->key.link->neigh->dhn->on && !lndev->key.link->neigh->dhn->on->blocked) { + + assertion(-500922, (lndev->key.link->neigh->dhn->on->path_metricalgo)); + + UMETRIC_T max = umetric_max(lndev->key.link->neigh->dhn->on->path_metricalgo->exp_offset); + + apply_metric_algo(&lndev->umetric_link, lndev, &max, lndev->key.link->neigh->dhn->on->path_metricalgo); + + } else { + lndev->umetric_link = 0; + }
- update_metric(NULL, NULL, &lndev->mr[SQR_RTQ], &link_metric_algo[SQR_RTQ], ttn->dev->ogm_sqn, ttn->dev->ogm_sqn, 0); }
- dbgf_all( DBGT_INFO, "%s %s SQN %d", ttn->dev->name, ttn->dev->ip4_str, ttn->dev->ogm_sqn); + dbgf_all(DBGT_INFO, "%s %s SQN %d", ttn->content.dev->label_cfg.str, ttn->content.dev->ip_llocal_str, sqn_in);
return sizeof (struct msg_hello_adv); }
+ STATIC_FUNC -int tx_msg_dhash0_or_description0_request(struct tx_task_node *ttn, uint8_t *flags, uint8_t *tx_buff, uint16_t buff_size) +int32_t tx_msg_dhash_or_description_request(struct tx_frame_iterator *it) { - assertion( -500366 , (sizeof ( struct msg_description_request) == sizeof( struct msg_dhash_request))); + TRACE_FUNCTION_CALL; + struct tx_task_node *ttn = it->ttn; + struct hdr_dhash_request *hdr = ((struct hdr_dhash_request*) tx_iterator_cache_hdr_ptr(it)); + struct msg_dhash_request *msg = ((struct msg_dhash_request*) tx_iterator_cache_msg_ptr(it)); + struct dhash_node *dhn; + + dbgf(DBGL_CHANGES, DBGT_INFO, "%s dev=%s to link_id=0x%X iterations=%d time=%d requesting neighIID4x=%d", + it->handls[ttn->content.type].name, ttn->content.dev->label_cfg.str, ttn->content.link->link_id, + ttn->tx_iterations, ttn->considered_ts, ttn->content.neighIID4x); + + assertion(-500853, (sizeof ( struct msg_description_request) == sizeof ( struct msg_dhash_request))); + assertion(-500855, (tx_iterator_cache_data_space(it) >= ((int) (sizeof (struct msg_dhash_request))))); + assertion(-500856, (ttn->content.link && ttn->content.link->link_id >= LINK_ID_MIN)); + assertion(-500857, (ttn->frame_msgs_length == sizeof ( struct msg_dhash_request))); + assertion(-500870, (ttn->tx_iterations > 0 && ttn->considered_ts != bmx_time)); + + + if (ttn->content.link->neigh && (dhn = iid_get_node_by_neighIID4x(ttn->content.link->neigh, ttn->content.neighIID4x))) { + + assertion(-500858, (IMPLIES((dhn && dhn->on), dhn->on->desc))); + + ttn->tx_iterations = 0; + + return TLV_TX_DATA_DONE; + } + + if (hdr->msg == msg) {
- struct msg_dhash_request *req = (struct msg_dhash_request *) (tx_buff); + assertion(-500854, (is_zero(hdr, sizeof (*hdr)))); + hdr->destination_link_id = htonl(ttn->content.link->link_id);
- req->receiver_ip4 = ttn->dst_ip4; - req->receiverIID4x = htons(ttn->neighIID4x); + } else { + + assertion(-500871, (hdr->destination_link_id == htonl(ttn->content.link->link_id))); + } + + dbgf(DBGL_CHANGES, DBGT_INFO, "creating msg=%d", + ((int) ((((char*) msg) - ((char*) hdr) - sizeof ( *hdr)) / sizeof (*msg))));
- dbgf_all( DBGT_INFO, "%s oif %s to %s requesting orig_did %d", - frame_handler[ttn->frame_type].name, ttn->dev->name, ipStr(ttn->dst_ip4), ttn->neighIID4x); + msg->receiverIID4x = htons(ttn->content.neighIID4x);
- return sizeof ( struct msg_description_request); + return sizeof (struct msg_dhash_request); }
+ STATIC_FUNC -int tx_msg_description0_adv(struct tx_task_node *ttn, uint8_t *flags, uint8_t *tx_buff, uint16_t buff_size) +int32_t tx_msg_description_adv(struct tx_frame_iterator *it) { - struct dhash_node *dhn = NULL; - struct msg_description_adv *desc0_adv = (struct msg_description_adv *) tx_buff; + TRACE_FUNCTION_CALL; + struct tx_task_node * ttn = it->ttn; + struct dhash_node *dhn; struct description *desc0;
- dbgf_all(DBGT_INFO, "ttn->myIID4x %d", ttn->myIID4x); + struct msg_description_adv *adv = (struct msg_description_adv *) tx_iterator_cache_msg_ptr(it);
- if (ttn->myIID4x == IID_RSVD_4YOU) { + dbgf_all(DBGT_INFO, "ttn->myIID4x %d", ttn->content.myIID4x);
- desc0_adv->transmitterIID4x = htons(myIID4me); - desc0 = my_orig_node.desc0; - *flags |= FRAME_FLAG_firstIsSender; + assertion( -500555, (ttn->content.myIID4x >= IID_MIN_USED));
- } else if ((dhn = iid_get_node_by_myIID4x(ttn->myIID4x)) && dhn->on) { + if (ttn->content.myIID4x == myIID4me) { //IID_RSVD_4YOU
- assertion(-500437, (dhn->on && dhn->on->desc0)); + dhn = self.dhn;
- desc0_adv->transmitterIID4x = htons(ttn->myIID4x); - desc0 = dhn->on->desc0; + } else if ((dhn = iid_get_node_by_myIID4x(ttn->content.myIID4x))) { + + assertion(-500437, (dhn->on && dhn->on->desc));
} else {
- dbgf(DBGL_SYS, DBGT_WARN, "unknown myIID4x %d !", ttn->myIID4x); - return FAILURE; + dbgf(DBGL_SYS, DBGT_WARN, "INVALID, UNCONFIRMED, or UNKNOWN myIID4x %d !", ttn->content.myIID4x); + return TLV_DATA_FAILURE; }
+ adv->transmitterIID4x = htons(ttn->content.myIID4x); + desc0 = dhn->on->desc; + uint16_t tlvs_len = ntohs(desc0->dsc_tlvs_len);
- if (sizeof (struct msg_description_adv) + tlvs_len > buff_size) - return (buff_size + 1); + if (tlvs_len + ((int) sizeof (struct msg_description_adv)) > tx_iterator_cache_data_space(it)) { + + dbgf(DBGL_SYS, DBGT_ERR, "tlvs_len=%d min description_len=%zu, cache_data_space=%d", + tlvs_len, sizeof (struct msg_description_adv), tx_iterator_cache_data_space(it)); + + return TLV_DATA_FULL; + } + + memcpy((char*) & adv->desc, (char*) desc0, sizeof (struct description) + tlvs_len);
- memcpy((char*) & desc0_adv->desc, (char*) desc0, sizeof (struct description) + tlvs_len); + dbgf(DBGL_CHANGES, DBGT_INFO, "%s descr_size=%zu", + dhn->on->id.name, (tlvs_len + sizeof (struct msg_description_adv)));
- return sizeof (struct msg_description_adv) + tlvs_len; + return (tlvs_len + sizeof (struct msg_description_adv)); }
STATIC_FUNC -int tx_msg_dhash0_adv(struct tx_task_node *ttn, uint8_t *flags, uint8_t *tx_buff, uint16_t buff_size) +int32_t tx_msg_dhash_adv(struct tx_frame_iterator *it) { - struct msg_dhash_adv *dhash0_adv = (struct msg_dhash_adv *) tx_buff; - struct dhash_node *dhn;
- if (ttn->myIID4x == IID_RSVD_4YOU) { + TRACE_FUNCTION_CALL; + assertion(-500774, (tx_iterator_cache_data_space(it) >= ((int) sizeof (struct msg_dhash_adv)))); + assertion(-500556, (it && it->ttn->content.myIID4x >= IID_MIN_USED));
- dhash0_adv->transmitterIID4x = htons(myIID4me); - dhn = my_orig_node.dhn; - *flags |= FRAME_FLAG_firstIsSender; + struct tx_task_node *ttn = it->ttn; + struct msg_dhash_adv *adv = (struct msg_dhash_adv *) tx_iterator_cache_msg_ptr(it); + struct dhash_node *dhn;
- } else if ((dhn = iid_get_node_by_myIID4x(ttn->myIID4x)) && dhn->on) { + if (ttn->content.myIID4x == myIID4me) { //IID_RSVD_4YOU
- assertion(-500259, (dhn->on && dhn->on->desc0)); + adv->transmitterIID4x = htons(myIID4me); + dhn = self.dhn;
- dhash0_adv->transmitterIID4x = htons(ttn->myIID4x); + } else if ((dhn = iid_get_node_by_myIID4x(ttn->content.myIID4x))) {
- } else { + assertion(-500259, (dhn->on && dhn->on->desc)); + adv->transmitterIID4x = htons(ttn->content.myIID4x);
- dbgf(DBGL_SYS, DBGT_WARN, "unknown myIID4x %d !", ttn->myIID4x); + } else { + dbgf(DBGL_SYS, DBGT_WARN, "INVALID, UNCONFIRMED, or UNKNOWN myIID4x %d !", ttn->content.myIID4x); return FAILURE; }
- memcpy((char*) & dhash0_adv->dhash, (char*) & dhn->dhash, sizeof ( struct description_hash)); + + memcpy((char*) & adv->dhash, (char*) & dhn->dhash, sizeof ( struct description_hash)); + + dbgf(DBGL_CHANGES, DBGT_INFO, "%s", dhn->on->id.name);
return sizeof (struct msg_dhash_adv); } @@ -1203,298 +1030,444 @@ int tx_msg_dhash0_adv(struct tx_task_node *ttn, uint8_t *flags, uint8_t *tx_buff
STATIC_FUNC -int tx_frame_ogm0_advs(struct tx_task_node *ttn, uint8_t *flags, uint8_t *tx_buff, uint16_t buff_size) +int32_t tx_frame_ogm_advs(struct tx_frame_iterator *it) { + TRACE_FUNCTION_CALL; + struct tx_task_node *ttn = it->ttn; struct list_node *list_pos;
- assertion(-500428, (ttn->frame_data_length_target <= buff_size)); - - dbgf_all( DBGT_INFO, " aggregation_sqn %d", ttn->sqn ); + dbgf_all(DBGT_INFO, " aggregation_sqn %d", ttn->content.u16);
list_for_each( list_pos, &ogm_aggreg_list ) { struct ogm_aggreg_node *oan = list_entry(list_pos, struct ogm_aggreg_node, list);
- if ( oan->sqn == ttn->sqn ) { + if ( oan->sqn == ttn->content.u16 ) {
- ((struct hdr_ogm_adv*) tx_buff)->aggregation_sqn = htons(ttn->sqn); + uint16_t msgs_length = ((oan->aggregated_msgs * sizeof (struct msg_ogm_adv))); + struct hdr_ogm_adv* hdr = ((struct hdr_ogm_adv*) tx_iterator_cache_hdr_ptr(it));
- memcpy(tx_buff + sizeof (struct hdr_ogm_adv), - oan->ogm_advs, oan->aggregated_ogms * sizeof (struct msg_ogm_adv)); + assertion(-500859, (hdr->msg == ((struct msg_ogm_adv*) tx_iterator_cache_msg_ptr(it)))); + assertion(-500429, (ttn->frame_msgs_length == msgs_length)); + assertion(-500428, (((int) (msgs_length)) <= tx_iterator_cache_data_space(it)));
- assertion(-500429, (ttn->frame_data_length_target == - (sizeof (struct hdr_ogm_adv) + oan->aggregated_ogms * sizeof (struct msg_ogm_adv)))); + hdr->aggregation_sqn = htons(ttn->content.u16);
- return ttn->frame_data_length_target; + memcpy(hdr->msg, oan->ogm_advs, msgs_length);
+ return (msgs_length); } }
- return FAILURE; + // this happens when the to-be-send ogm aggregation has already been purged... + dbgf(DBGL_SYS, DBGT_WARN, "aggregation_sqn %d does not exist anymore in ogm_aggreg_list", ttn->content.u16); + ttn->tx_iterations = 0; + return TLV_TX_DATA_DONE; }
STATIC_FUNC -int tx_msg_ogm_ack(struct tx_task_node *ttn, uint8_t *flags, uint8_t *tx_buff, uint16_t buff_size) +int32_t tx_msg_ogm_ack(struct tx_frame_iterator *it) { - struct msg_ogm_ack *ack = (struct msg_ogm_ack *) tx_buff; + TRACE_FUNCTION_CALL; + struct tx_task_node *ttn = it->ttn; + assertion(-500587, (ttn->content.link && ttn->content.link->link_id >= LINK_ID_MIN)); + + struct msg_ogm_ack *ack = (struct msg_ogm_ack *) (tx_iterator_cache_msg_ptr(it));
- ack->receiver_ip4 = ttn->dst_ip4; - ack->aggregation_sqn = htons(ttn->sqn); + ack->transmitterIID4x = htons(ttn->content.myIID4x); + ack->aggregation_sqn = htons(ttn->content.u16);
- dbgf_all( DBGT_INFO, " aggreg_sqn %d to %s", ttn->sqn, ipStr(ttn->dst_ip4)); + dbgf_all(DBGT_INFO, " aggreg_sqn=%d to link_id=0x%X", ttn->content.u16, ttn->content.link->link_id);
return sizeof (struct msg_ogm_ack); }
+ + + + STATIC_FUNC -int rx_frame_ogm0_advs(struct packet_buff *pb, struct frame_header *frame) +int32_t tx_frame_problem_adv(struct tx_frame_iterator *it) { - struct hdr_ogm_adv *hdr = (struct hdr_ogm_adv *) frame->data; - struct msg_ogm_adv *ogm = hdr->msg; - struct neigh_node *nn = pb->ln->neigh; - - SQN_T aggregation_sqn = ntohs(hdr->aggregation_sqn); + TRACE_FUNCTION_CALL; + struct tx_task_node *ttn = it->ttn; + struct msg_problem_adv *adv = ((struct msg_problem_adv*) tx_iterator_cache_msg_ptr(it));
- uint16_t msgs = (frame->length - (sizeof (struct frame_header) + sizeof (struct hdr_ogm_adv))) / - sizeof (struct msg_ogm_adv); + assertion(-500860, (ttn && ttn->content.u32 >= LINK_ID_MIN));
- dbgf_all( DBGT_INFO, " "); + dbgf_all(DBGT_INFO, "FRAME_TYPE_PROBLEM_CODE=%d link_id=0x%X", ttn->content.u16, ttn->content.u32); + + if (ttn->content.u16 == FRAME_TYPE_PROBLEM_CODE_DUP_LINK_ID) { + + adv->reserved = 0; + adv->code = ttn->content.u16; + adv->link_id = htonl(ttn->content.u32); + + return sizeof (struct msg_problem_adv); + + } else {
- if (!nn) { - dbgf_all( DBGT_INFO, "via unknown neigh %s", pb->neigh_str ); - schedule_tx_task(pb->iif, pb->lndev, FRAME_TYPE_DHS0_REQS, 0, 0, 0, IID_RSVD_4YOU); - return frame->length; + assertion(-500846, (0)); }
- schedule_tx_task(nn->best_rtq->key.dev, nn->best_rtq, FRAME_TYPE_OGM0_ACKS, 0, aggregation_sqn, 0, 0); + return TLV_DATA_FAILURE; +} + +
- if ((SQN_T) (nn->ogm_aggregation_rcvd_max - aggregation_sqn) < OGM_AGGREG_SQN_CACHE_RANGE) {
- if (bit_get(nn->ogm_aggregations_rcvd, OGM_AGGREG_SQN_CACHE_RANGE, aggregation_sqn)) { +STATIC_FUNC +int32_t rx_frame_problem_adv(struct rx_frame_iterator *it) +{ + TRACE_FUNCTION_CALL; + struct msg_problem_adv *adv = (struct msg_problem_adv *) it->frame_data; + + if (adv->code == FRAME_TYPE_PROBLEM_CODE_DUP_LINK_ID) {
- dbgf_all( DBGT_INFO, "already known ogm_aggregation_sqn %d from neigh %s", - aggregation_sqn, nn->dhn->on->id.name); + if (it->frame_data_length != sizeof (struct msg_problem_adv)) {
- return frame->length; + dbgf(DBGL_SYS, DBGT_ERR,"frame_data_length=%d !!", it->frame_data_length); + return TLV_DATA_FAILURE; }
- if (((uint16_t) (nn->ogm_aggregation_rcvd_max - aggregation_sqn)) > OGM_AGGREG_SQN_CACHE_WARN) { + struct packet_buff *pb = it->pb; + LINK_ID_T link_id =ntohl(adv->link_id); + + struct avl_node *an; + struct dev_node *dev;
- dbgf(DBGL_CHANGES, DBGT_WARN, "neigh %s with unknown %s aggregation_sqn %d max %d ogms %d", - pb->neigh_str, "OLD", aggregation_sqn, nn->ogm_aggregation_rcvd_max, msgs); + for (an = NULL; (dev = avl_iterate_item(&dev_ip_tree, &an));) { + + if ( dev->link_id != link_id ) + continue; + + if (new_link_id(dev) == LINK_ID_INVALID) { + DEV_MARK_PROBLEM(dev); + return TLV_DATA_FAILURE; + } + + + dbgf(DBGL_SYS, DBGT_ERR, "reselect dev=%s link_id=0x%X (old link_id=0x%X) as signalled by NB=%s", + dev->label_cfg.str, dev->link_id, link_id, pb->i.llip_str); + }
- bit_set(nn->ogm_aggregations_rcvd, OGM_AGGREG_SQN_CACHE_RANGE, aggregation_sqn, 1);
} else { + return TLV_RX_DATA_IGNORED; + } + + return it->frame_data_length; +} + + +STATIC_FUNC +int32_t rx_frame_ogm_advs(struct rx_frame_iterator *it) +{ + TRACE_FUNCTION_CALL; + struct hdr_ogm_adv *hdr = (struct hdr_ogm_adv *) it->frame_data; + struct msg_ogm_adv *ogm = hdr->msg; + struct packet_buff *pb = it->pb; + struct neigh_node *nn = pb->i.ln->neigh; + + AGGREG_SQN_T aggregation_sqn = ntohs(hdr->aggregation_sqn); + + uint16_t msgs = (it->frame_data_length - sizeof (struct hdr_ogm_adv)) / sizeof (struct msg_ogm_adv); + + dbgf_all(DBGT_INFO, " "); +
- if (((uint16_t) (aggregation_sqn - nn->ogm_aggregation_rcvd_max)) > OGM_AGGREG_SQN_CACHE_WARN) { + if (((AGGREG_SQN_MASK)& (nn->ogm_aggregation_cleard_max - aggregation_sqn)) >= AGGREG_SQN_CACHE_RANGE) {
- dbgf( DBGL_SYS, DBGT_WARN, "neigh %s with unknown %s aggregation_sqn %d max %d ogms %d", - pb->neigh_str, "LOST", aggregation_sqn, nn->ogm_aggregation_rcvd_max, msgs ); + if (nn->ogm_aggregation_cleard_max && + ((AGGREG_SQN_MASK)& (aggregation_sqn - nn->ogm_aggregation_cleard_max)) > AGGREG_SQN_CACHE_WARN) { + + dbgf(DBGL_CHANGES, DBGT_WARN, "neigh %s with unknown %s aggregation_sqn %d max %d ogms %d", + pb->i.llip_str, "LOST", aggregation_sqn, nn->ogm_aggregation_cleard_max, msgs); }
- bit_clear(nn->ogm_aggregations_rcvd, OGM_AGGREG_SQN_CACHE_RANGE, nn->ogm_aggregation_rcvd_max + 1, aggregation_sqn); + bit_clear(nn->ogm_aggregations_rcvd, AGGREG_SQN_CACHE_RANGE, nn->ogm_aggregation_cleard_max + 1, aggregation_sqn); + nn->ogm_aggregation_cleard_max = aggregation_sqn; + + } else { + + if (bit_get(nn->ogm_aggregations_rcvd, AGGREG_SQN_CACHE_RANGE, aggregation_sqn)) { + + dbgf_all(DBGT_INFO, "already known ogm_aggregation_sqn %d from neigh %s via dev=%s", + aggregation_sqn, nn->dhn->on->id.name, pb->i.iif->label_cfg.str);
- bit_set(nn->ogm_aggregations_rcvd, OGM_AGGREG_SQN_CACHE_RANGE, aggregation_sqn, 1); - nn->ogm_aggregation_rcvd_max = aggregation_sqn; + schedule_tx_task(nn->best_rtq, FRAME_TYPE_OGM_ACKS, 0, aggregation_sqn, 0, nn->dhn->myIID4orig, 0);
+ return it->frame_data_length; + + } else if (((uint16_t) (nn->ogm_aggregation_cleard_max - aggregation_sqn)) > AGGREG_SQN_CACHE_WARN) { + + dbgf(DBGL_CHANGES, DBGT_WARN, "neigh %s with unknown %s aggregation_sqn %d max %d ogms %d", + pb->i.llip_str, "OLD", aggregation_sqn, nn->ogm_aggregation_cleard_max, msgs); + } }
- dbgf_all(DBGT_INFO, "neigh %s with unknown %s aggregation_sqn %d max %d ogms %d", - pb->neigh_str, "NEW", aggregation_sqn, nn->ogm_aggregation_rcvd_max, msgs); + + dbgf_all(DBGT_INFO, "neigh %s with unknown %s aggregation_sqn %d max %d msgs %d", + pb->i.llip_str, "NEW", aggregation_sqn, nn->ogm_aggregation_cleard_max, msgs);
uint16_t m; + IID_T neighIID4x = 0; + for (m = 0; m < msgs; m++) {
- IID_T neighIID4x = ntohs(ogm[m].transmitterIID4x); - SQN_T orig_sqn = ntohs(ogm[m].orig_sqn); + uint16_t offset = ((ntohs(ogm[m].mix) >> OGM_IIDOFFST_BIT_POS) & OGM_IIDOFFST_MASK);
- IID_NODE_T *dhn = iid_get_node_by_neighIID4x(nn, neighIID4x ); - struct orig_node *on = NULL; + if (offset == OGM_IID_RSVD_JUMP) { + + uint16_t absolute = ntohs(ogm[m].u.transmitterIIDabsolute); + + dbgf_all(DBGT_INFO, " IID jump from %d to %d", neighIID4x, absolute); + neighIID4x = absolute; + + if ((m + 1) >= msgs) + return FAILURE;
- if ( dhn == my_orig_node.dhn ) continue;
+ } else { + + dbgf_all(DBGT_INFO, " IID offset from %d to %d", neighIID4x, neighIID4x + offset); + neighIID4x += offset; + } + + OGM_SQN_T ogm_sqn = ntohs(ogm[m].u.ogm_sqn); + + IID_NODE_T *dhn = iid_get_node_by_neighIID4x(nn, neighIID4x ); + struct orig_node *on = dhn ? dhn->on : NULL; + + + if (on) { + + if (((OGM_SQN_MASK) & (ogm_sqn - on->ogmSqn_rangeMin)) >= on->ogmSqn_rangeSize) { + + dbgf(DBGL_SYS, DBGT_ERR, + "EXCEEDED ogm_sqn=%d neighIID4x=%d orig=%s via link=%s sqn_min=%d sqn_range=%d", + ogm_sqn, neighIID4x, on->id.name, pb->i.llip_str, + on->ogmSqn_rangeMin, on->ogmSqn_rangeSize); + + return FAILURE; + } + + if (dhn == self.dhn || on->blocked) {
- if (dhn && (on = dhn->on) && ((SQN_T) (orig_sqn - on->ogm_sqn_min)) < on->ogm_sqn_range) { + dbgf_all(DBGT_WARN, "%s orig_sqn=%d/%d orig=%s via link=%s neighIID4x=%d", + dhn == self.dhn ? "MYSELF" : "BLOCKED", + ogm_sqn, on->ogmSqn_toBeSend, on->id.name, pb->i.llip_str, neighIID4x); + + continue; + }
- dbgf_all(DBGT_INFO, " new orig_sqn %d / %d from %s neighIID4x %d via %s ", - orig_sqn, on->ogm_sqn_to_be_send, on->id.name, neighIID4x, pb->neigh_str);
- update_orig_metrics(pb, on, orig_sqn); + OGM_MIX_T mix = ntohs(ogm[m].mix); + uint8_t exp = ((mix >> OGM_EXPONENT_BIT_POS) & OGM_EXPONENT_MASK); + uint8_t mant = ((mix >> OGM_MANTISSA_BIT_POS) & OGM_MANTISSA_MASK);
+ FMETRIC_T fm = fmetric(mant, exp, on->path_metricalgo->exp_offset); + IDM_T valid_metric = is_fmetric_valid(fm); + + if (!valid_metric) { + + dbgf_mute(50, DBGL_SYS, DBGT_ERR, + "INVALID metric! orig_sqn=%d/%d orig=%s via link=%s neighIID4x=%d", + ogm_sqn, on->ogmSqn_toBeSend, on->id.name, pb->i.llip_str, neighIID4x); + + return FAILURE; + } + + UMETRIC_T um = fmetric_to_umetric(fm); + + if (um < on->path_metricalgo->umetric_min) { + + dbgf_mute(50, DBGL_SYS, DBGT_ERR, + "UNUSABLE metric=%ju usable=%ju orig_sqn=%d/%d orig=%s via link=%s neighIID4x=%d", + um, on->path_metricalgo->umetric_min, + ogm_sqn, on->ogmSqn_toBeSend, on->id.name, pb->i.llip_str, neighIID4x); + + continue; + } + + if (update_path_metrics(pb, on, ogm_sqn, &um) == FAILURE) { + + dbgf(DBGL_SYS, DBGT_ERR, + "NEW orig_sqn=%d to_be_send=%d sqn_max=%d orig=%s via link=%s neighIID4x=%d", + ogm_sqn, on->ogmSqn_toBeSend, on->ogmSqn_maxRcvd, on->id.name, pb->i.llip_str, neighIID4x); + + return FAILURE; + }
} else { - dbgf((dhn && on) ? DBGL_SYS : DBGL_CHANGES, DBGT_WARN, - " %s orig_sqn %d or neighIID4x %d via %s orig %s sqn_min %d sqn_range %d", - !dhn ? "UNKNOWN" : on ? "EXCEEDED OGM_SQN RANGE" : "INVALIDATED", - orig_sqn, neighIID4x, pb->neigh_str, on ? on->id.name:"---", - on ? on->ogm_sqn_min : 0, on ? on->ogm_sqn_range : 0);
- if (dhn && dhn->on) - invalidate_dhash_node(dhn); + dbgf(DBGL_CHANGES, DBGT_WARN, + "%s orig_sqn=%d or neighIID4x=%d orig=%s via link=%s sqn_min=%d sqn_range=%d", + !dhn ? "UNKNOWN DHN" : "INVALIDATED", + ogm_sqn, neighIID4x, + on ? on->id.name : "---", + pb->i.llip_str, + on ? on->ogmSqn_rangeMin : 0, + on ? on->ogmSqn_rangeSize : 0); + + if (!dhn && nn->best_rtq && nn->best_rtq->mr[SQR_RTQ].umetric_final > UMETRIC_RQ_NBDISC_MIN) + schedule_tx_task(nn->best_rtq, FRAME_TYPE_DHS0_REQS, 0, 0, 0, 0, neighIID4x);
- schedule_tx_task(nn->best_rtq->key.dev, nn->best_rtq, FRAME_TYPE_DHS0_REQS, 0, 0, 0, neighIID4x); } }
- return frame->length; + bit_set(nn->ogm_aggregations_rcvd, AGGREG_SQN_CACHE_RANGE, aggregation_sqn, 1); + schedule_tx_task(nn->best_rtq, FRAME_TYPE_OGM_ACKS, 0, aggregation_sqn, 0, nn->dhn->myIID4orig, 0); + + return (sizeof (struct hdr_ogm_adv) + (msgs * sizeof (struct msg_ogm_adv))); }
+ + + + + STATIC_FUNC -int rx_frame_ogm40_acks(struct packet_buff *pb, struct frame_header *frame) +int32_t rx_frame_ogm_acks(struct rx_frame_iterator *it) { - struct msg_ogm_ack *ack = (struct msg_ogm_ack *) frame->data; - struct neigh_node *nn = pb->ln->neigh; + TRACE_FUNCTION_CALL; + struct packet_buff *pb = it->pb; + struct neigh_node *nn = pb->i.ln->neigh;
- uint16_t msgs = (frame->length - (sizeof (struct frame_header))) / sizeof (struct msg_ogm_ack); + uint16_t pos;
- if (!nn) { - dbgf(DBGL_CHANGES, DBGT_WARN, "%s neigh %s", "unknown", pb->neigh_str); - schedule_tx_task(pb->iif, pb->lndev, FRAME_TYPE_DHS0_REQS, 0, 0, 0, IID_RSVD_4YOU); - return frame->length; - } + for (pos = 0; pos < it->frame_data_length; pos += sizeof (struct msg_ogm_ack)) {
- uint16_t m; - for (m = 0; m < msgs; m++) { + struct msg_ogm_ack *ack = (struct msg_ogm_ack *) (it->frame_data + pos);
- if ( ack[m].receiver_ip4 != pb->iif->ip4_addr ) + if (self.dhn != iid_get_node_by_neighIID4x(nn, ntohs(ack->transmitterIID4x))) continue;
- SQN_T aggregation_sqn = ntohs(ack[m].aggregation_sqn); + AGGREG_SQN_T aggregation_sqn = ntohs(ack->aggregation_sqn);
- if (((uint32_t) (ogm_aggreg_sqn_max - aggregation_sqn) < OGM_AGGREG_SQN_CACHE_RANGE)) { + if (((AGGREG_SQN_MASK)& (ogm_aggreg_sqn_max - aggregation_sqn)) < AGGREG_SQN_CACHE_RANGE) {
- bit_set(pb->ln->neigh->ogm_aggregations_acked, OGM_AGGREG_SQN_CACHE_RANGE, aggregation_sqn, 1); + bit_set(pb->i.ln->neigh->ogm_aggregations_acked, AGGREG_SQN_CACHE_RANGE, aggregation_sqn, 1);
dbgf_all(DBGT_INFO, "neigh %s sqn %d <= sqn_max %d", - pb->neigh_str, aggregation_sqn, ogm_aggreg_sqn_max); - + pb->i.llip_str, aggregation_sqn, ogm_aggreg_sqn_max);
} else {
dbgf(DBGL_SYS, DBGT_ERR, "neigh %s sqn %d <= sqn_max %d", - pb->neigh_str, aggregation_sqn, ogm_aggreg_sqn_max); + pb->i.llip_str, aggregation_sqn, ogm_aggreg_sqn_max);
} } - return frame->length; + + return pos; }
+ + + STATIC_FUNC -struct dhash_node * -process_dhash_description_neighIID4x -(struct packet_buff *pb, struct description_hash *dhash, struct description *dsc, IID_T neighIID4x, IDM_T is_sender) +struct dhash_node *process_dhash_description_neighIID4x +(struct packet_buff *pb, struct description_hash *dhash, struct description *dsc, IID_T neighIID4x) { + TRACE_FUNCTION_CALL; struct dhash_node *orig_dhn = NULL; - struct link_node *ln = pb->ln; + struct link_node *ln = pb->i.ln; IDM_T invalid = NO; struct description *cache = NULL; + IDM_T is_transmitter_adv = (neighIID4x == pb->i.transmittersIID);
- assertion(-500511, (!ln || !ln->neigh || (ln->neigh->dhn != my_orig_node.dhn))); + assertion(-500688, (dhash)); + assertion(-500689, (!(is_transmitter_adv && !memcmp(dhash, &(self.dhn->dhash), sizeof(*dhash))))); // cant be sender and myself + assertion(-500511, (!ln || !ln->neigh || (ln->neigh->dhn != self.dhn))); // cant be neighbor and myself
if (avl_find(&dhash_invalid_tree, dhash)) {
invalid = YES;
} else if ((orig_dhn = avl_find_item(&dhash_tree, dhash))) { + // is about a known dhash: + + if (is_transmitter_adv) { + // is about the transmitter:
- if (ln->neigh) { - - // this was just for testing eh??? assertion(-500375, (ln->neigh->dhn == orig_dhn)); - - if (orig_dhn == my_orig_node.dhn) { - - dbgf_all( DBGT_INFO, - "msg refers myself via %s neighIID4neigh %d neighIID4me %d", - pb->neigh_str, ln->neigh->neighIID4neigh, neighIID4x); - - if (is_sender) - return FAILURE_POINTER; - - - } else if (orig_dhn == ln->neigh->dhn) { + if (update_neigh_node(ln, orig_dhn, neighIID4x, dsc) == FAILURE) + return DHASH_NODE_FAILURE;
- if (!is_sender) { + if (iid_set_neighIID4x(&ln->neigh->neighIID4x_repos, neighIID4x, orig_dhn->myIID4orig) == FAILURE) + return DHASH_NODE_FAILURE;
- dbgf(DBGL_SYS, DBGT_ERR, "%s via %s IS NOT sender (%d != %d)", - orig_dhn->on->id.name, pb->neigh_str, - ln->neigh->neighIID4neigh, neighIID4x); + pb->i.described_dhn = is_described_neigh_dhn(pb);
- return FAILURE_POINTER; + } else if (ln->neigh) { + // received via a known neighbor, and is NOT about the transmitter:
- } else if((ln->neigh->neighIID4neigh != neighIID4x)) { + if (orig_dhn == self.dhn) { + // is about myself:
- dbgf(DBGL_CHANGES, DBGT_WARN, "%s via %s first contact NOT VIA SENDER ??? %d != %d", - orig_dhn->on->id.name, pb->neigh_str, - ln->neigh->neighIID4neigh, neighIID4x);
- } - } + dbgf_all(DBGT_INFO, "msg refers myself via %s neighIID4me %d", pb->i.llip_str, neighIID4x);
- if (is_sender) { + ln->neigh->neighIID4me = neighIID4x;
- if (update_neigh_node(ln, orig_dhn, neighIID4x) == FAILURE ) - return FAILURE_POINTER; + } else if (orig_dhn == ln->neigh->dhn && !is_transmitter_adv) { + // is about a neighbors' dhash itself which is NOT the transmitter ???!!!
- assertion(-500512, (!ln->neigh || (ln->neigh->dhn != my_orig_node.dhn))); + dbgf(DBGL_SYS, DBGT_ERR, "%s via %s neighIID4x=%d IS NOT transmitter=%d", + orig_dhn->on->id.name, pb->i.llip_str, neighIID4x, pb->i.transmittersIID);
- } else if (update_neighIID4x_repository(ln->neigh, neighIID4x, orig_dhn) == FAILURE) { + return DHASH_NODE_FAILURE;
- return FAILURE_POINTER; + } else { + // is about.a another dhash known by me and a (neighboring) transmitter..: }
+ if (iid_set_neighIID4x(&ln->neigh->neighIID4x_repos, neighIID4x, orig_dhn->myIID4orig) == FAILURE) + return DHASH_NODE_FAILURE;
- } else { - - if (is_sender) { - if (update_neigh_node(ln, orig_dhn, neighIID4x) == FAILURE) - return FAILURE_POINTER; - - assertion(-500513, (!ln->neigh || (ln->neigh->dhn != my_orig_node.dhn))); - - } else { - //update_neigh_node(ln, dhn, IID_RSVD_UNUSED); - //update_neigh_iid_repos(ln->neigh, neighIID4x, dhn); - } }
} else { + // is about an unconfirmed or unkown dhash:
// its just the easiest to cache and remove because cache description is doing all the checks for us if (dsc) cache_description(dsc, dhash);
- if (is_sender && (cache = rem_cached_description(dhash))) { + if (is_transmitter_adv && (cache = remove_cached_description(dhash))) { + //is about the transmitter and a description + dhash is known
if ((orig_dhn = process_description(pb, cache, dhash))) {
- if (update_neigh_node(ln, orig_dhn, neighIID4x) == FAILURE) - return FAILURE_POINTER; + if (update_neigh_node(ln, orig_dhn, neighIID4x, dsc) == FAILURE) + return DHASH_NODE_FAILURE;
- assertion(-500514, (!ln->neigh || (ln->neigh->dhn != my_orig_node.dhn))); + if (iid_set_neighIID4x(&ln->neigh->neighIID4x_repos, neighIID4x, orig_dhn->myIID4orig) == FAILURE) + return DHASH_NODE_FAILURE;
+ pb->i.described_dhn = is_described_neigh_dhn(pb); }
- } else if (ln->neigh && (cache = rem_cached_description(dhash))) { - - orig_dhn = process_description(pb, cache, dhash); + } else if (ln->neigh && (cache = remove_cached_description(dhash))) {
- if (orig_dhn && update_neighIID4x_repository(ln->neigh, neighIID4x, orig_dhn) == FAILURE) - return FAILURE_POINTER; + if ((orig_dhn = process_description(pb, cache, dhash))) {
+ if (iid_set_neighIID4x(&ln->neigh->neighIID4x_repos, neighIID4x, orig_dhn->myIID4orig) == FAILURE) + return DHASH_NODE_FAILURE; + } } }
- dbgf_all( DBGT_INFO, "via dev: %s NB %s:dhash %8X.. %s neighIID4x %d is_sender %d %s", - pb->iif->name, pb->neigh_str, dhash->h.u32[0], + dbgf(DBGL_CHANGES, DBGT_INFO, "via dev=%s NB=%s dhash=%8X.. %s neighIID4x=%d is_sender=%d %s", + pb->i.iif->label_cfg.str, pb->i.llip_str, dhash->h.u32[0], (dsc ? "DESCRIPTION" : (cache ? "CACHED_DESCRIPTION" : (orig_dhn?"KNOWN":"UNDESCRIBED"))), - neighIID4x, is_sender, + neighIID4x, is_transmitter_adv, invalid ? "INVALIDATED" : (orig_dhn && orig_dhn->on ? orig_dhn->on->id.name : "---"));
@@ -1503,390 +1476,464 @@ process_dhash_description_neighIID4x
STATIC_FUNC -int rx_frame_dhash0_advs(struct packet_buff *pb, struct frame_header *frame) +int32_t rx_msg_dhash_adv( struct rx_frame_iterator *it) { + TRACE_FUNCTION_CALL; + struct packet_buff *pb = it->pb; + struct msg_dhash_adv *adv = (struct msg_dhash_adv*) (it->msg); + IID_T neighIID4x = ntohs(adv->transmitterIID4x); + IDM_T is_transmitter_adv = (neighIID4x == pb->i.transmittersIID); + struct dhash_node *dhn;
- assertion(-500373, (pb->ln && pb->lndev && pb->lndev->mr[SQR_RTQ].val >= MIN_NBDISC_RTQ)); - - int m, n = (frame->length - sizeof (struct frame_header)) / sizeof ( struct msg_dhash_adv); - - for (m = 0; m < n; m++) { - - struct msg_dhash_adv *msg = &(((struct msg_dhash_adv*) (frame->data))[m]); - IDM_T is_sender = (m == 0 && (frame->flags & FRAME_FLAG_firstIsSender)); - IID_T neighIID4x = ntohs(msg->transmitterIID4x); - struct dhash_node *dhn; - - if ( neighIID4x <= IID_RSVD_MAX ) - return FAILURE; - - dhn = process_dhash_description_neighIID4x(pb, &msg->dhash, NULL, neighIID4x, is_sender); - - if (dhn == FAILURE_POINTER) { + dbgf(DBGL_CHANGES, DBGT_INFO, "via NB: %s", pb->i.llip_str);
- return FAILURE; + ASSERTION(-500373, (pb->i.ln && pb->i.lndev && pb->i.lndev->mr[SQR_RQ].umetric_final >= + ((packet_frame_handler[FRAME_TYPE_DHS0_ADVS].umetric_rq_min) ? *(packet_frame_handler[FRAME_TYPE_DHS0_ADVS].umetric_rq_min) : 0)));
- } else if (!dhn) { - - schedule_tx_task(pb->iif, pb->lndev, FRAME_TYPE_DSC0_REQS, 0, 0, 0, neighIID4x); + if (neighIID4x <= IID_RSVD_MAX) + return FAILURE;
- }/* else if (dhn && is_sender && !pb->ln->neigh) { + if (!(is_transmitter_adv || pb->i.described_dhn)) { + dbgf(DBGL_CHANGES, DBGT_INFO, "via unconfirmed NB: %s", pb->i.llip_str); + return sizeof (struct msg_dhash_adv); + }
- schedule_tx_task(pb->iif, pb->lndev, FRAME_TYPE_DHS0_REQS, 0, 0, 0, IID_RSVD_4YOU); - }*/ + if ((dhn = process_dhash_description_neighIID4x(pb, &adv->dhash, NULL, neighIID4x)) == DHASH_NODE_FAILURE) + return FAILURE;
- paranoia(-500488, (dhn && is_sender && !pb->ln->neigh)); + assertion(-500690, (!dhn || dhn->on)); + assertion(-500488, (!(dhn && is_transmitter_adv) || (dhn->on && pb->i.ln->neigh)));
+ if (!dhn) + schedule_tx_task(pb->i.lndev, FRAME_TYPE_DSC0_REQS, 0, 0, 0, 0, neighIID4x);
- } - return frame->length; + return sizeof (struct msg_dhash_adv); }
STATIC_FUNC -int rx_frame_description0_advs(struct packet_buff *pb, struct frame_header *frame) +int32_t rx_frame_description_advs(struct rx_frame_iterator *it) { + TRACE_FUNCTION_CALL; + int32_t pos = 0; + uint16_t tlvs_len = 0; + IID_T neighIID4x = 0; + struct packet_buff *pb = it->pb;
- uint16_t pos = sizeof ( struct frame_header); + assertion(-500550, (it->frame_data_length >= ((int)sizeof (struct msg_description_adv))));
- struct description_hash dhash0; + while (pos < it->frame_data_length && pos + ((int) sizeof (struct msg_description_adv)) <= it->frame_data_length) {
- while (pos + sizeof ( struct msg_description_adv) <= frame->length) { - - IDM_T is_sender = (pos == sizeof ( struct frame_header) && (frame->flags & FRAME_FLAG_firstIsSender)); - struct msg_description_adv *adv = ((struct msg_description_adv*) (((char*)frame)+pos)); + struct msg_description_adv *adv = ((struct msg_description_adv*) (it->frame_data + pos)); struct description *desc0 = &adv->desc; - uint16_t tlvs_len = ntohs(desc0->dsc_tlvs_len); - IID_T neighIID4x = ntohs(adv->transmitterIID4x); + struct description_hash dhash0; struct dhash_node *dhn; - - if ( neighIID4x <= IID_RSVD_MAX ) - return FAILURE;
- if (tlvs_len > MAX_DESC0_TLV_SIZE || - pos + sizeof ( struct msg_description_adv) + tlvs_len > frame->length) { + tlvs_len = ntohs(desc0->dsc_tlvs_len); + neighIID4x = ntohs(adv->transmitterIID4x); + pos += (sizeof ( struct msg_description_adv) + tlvs_len);
- dbgf( DBGL_SYS, DBGT_ERR, "illegal pos %d + %lu tlvs_len %d > frm_size %d", - pos, sizeof ( struct msg_description_adv), tlvs_len, frame->length ); - - return FAILURE; - } + if (neighIID4x <= IID_RSVD_MAX || tlvs_len > MAX_DESC0_TLV_SIZE || pos > it->frame_data_length) + break;
ShaUpdate(&bmx_sha, (byte*) desc0, (sizeof (struct description) + tlvs_len)); ShaFinal(&bmx_sha, (byte*)&dhash0);
- dhn = process_dhash_description_neighIID4x(pb, &dhash0, desc0, neighIID4x, is_sender); + dhn = process_dhash_description_neighIID4x(pb, &dhash0, desc0, neighIID4x);
dbgf_all( DBGT_INFO, "rcvd %s desc0: %jX via %s NB %s", - (dhn && dhn != FAILURE_POINTER) ? "accepted" : "denied", - desc0->id.rand.u64[0], pb->iif->name, pb->neigh_str); - - - if (dhn == FAILURE_POINTER) { + (dhn && dhn != DHASH_NODE_FAILURE) ? "accepted" : "denied", + desc0->id.rand.u64[0], pb->i.iif->label_cfg.str, pb->i.llip_str);
+ if (dhn == DHASH_NODE_FAILURE) return FAILURE;
- } else if (dhn && dhn->on->updated_timestamp == bmx_time && pb->ln->neigh && DEF_UNSOLICITED_DESCRIPTIONS) { + assertion(-500691, (!dhn || (dhn->on))); + assertion(-500692, (neighIID4x != pb->i.transmittersIID || pb->i.ln->neigh)); + + if (tx_unsolicited_desc && dhn && dhn->on->updated_timestamp == bmx_time && pb->i.ln->neigh) {
- struct link_dev_node **lndev_arr = get_best_lndevs_by_criteria(NULL, pb->ln->neigh->dhn); + struct link_dev_node **lndev_arr = get_best_lndevs_by_criteria(NULL, pb->i.ln->neigh->dhn); int d;
- uint16_t desc_len = sizeof ( struct msg_description_adv) + ntohs(dhn->on->desc0->dsc_tlvs_len); + uint16_t desc_len = sizeof ( struct msg_description_adv) + ntohs(dhn->on->desc->dsc_tlvs_len);
for (d = 0; (lndev_arr[d]); d++) - schedule_tx_task(lndev_arr[d]->key.dev, lndev_arr[d], FRAME_TYPE_DSC0_ADVS, desc_len, 0, dhn->myIID4orig, 0); - + schedule_tx_task(lndev_arr[d], FRAME_TYPE_DSC0_ADVS, desc_len, 0, 0, dhn->myIID4orig, 0);
} + }
+ + if (pos != it->frame_data_length) {
- paranoia(-500379, (dhn && is_sender && !pb->ln->neigh)); - - pos += sizeof ( struct msg_description_adv) + tlvs_len; - } + dbgf(DBGL_SYS, DBGT_ERR, "(pos=%d) + (desc_size=%zu) + (tlvs_len=%d) frame_data_length=%d neighIID4x=%d", + pos, sizeof ( struct msg_description_adv), tlvs_len, it->frame_data_length, neighIID4x);
- if (frame->length != pos) return FAILURE; + }
- - return frame->length; + return pos; }
STATIC_FUNC -int rx_frame_dhash0_or_description0_requests(struct packet_buff *pb, struct frame_header *frame) +int32_t rx_msg_dhash_or_description_request(struct rx_frame_iterator *it) { + TRACE_FUNCTION_CALL; assertion( -500365 , (sizeof( struct msg_description_request ) == sizeof( struct msg_dhash_request)));
- int m, n = (frame->length - sizeof (struct frame_header)) / sizeof ( struct msg_description_request); + struct packet_buff *pb = it->pb; + struct hdr_dhash_request *hdr = (struct hdr_dhash_request*) (it->frame_data); + struct msg_dhash_request *req = (struct msg_dhash_request*) (it->msg); + IID_T myIID4x = ntohs(req->receiverIID4x); + // remember that the received link_id might be a duplicate: + LINK_ID_T link_id = ntohl(hdr->destination_link_id);
- uint8_t frame_type = frame->type; + dbgf(DBGL_CHANGES, DBGT_INFO, "%s NB %s link_id=0x%X myIID4x %d", + it->handls[it->frame_type].name, pb->i.llip_str, link_id, myIID4x);
- for (m = 0; m < n; m++) { + if (link_id != pb->i.iif->link_id) + return sizeof ( struct msg_dhash_request);
- struct msg_description_request *req = &(((struct msg_description_request*) (frame->data))[m]); - IID_T myIID4x = ntohs(req->receiverIID4x); - uint16_t desc0_len = 0; + if (myIID4x <= IID_RSVD_MAX) + return sizeof ( struct msg_dhash_request);
- dbgf_all( DBGT_INFO, "%s dest_llip4 %s myIID4x %d", - frame_handler[frame_type].name, ipStr(req->receiver_ip4), myIID4x); + struct dhash_node *dhn = iid_get_node_by_myIID4x(myIID4x);
- if ( req->receiver_ip4 != pb->iif->ip4_addr ) // if I am not asked - continue; + assertion(-500270, (IMPLIES(dhn, (dhn->on && dhn->on->desc))));
+ if (!dhn || ((TIME_T) (bmx_time - dhn->referred_by_me_timestamp)) > DEF_DESC0_REFERRED_TO) {
- if (myIID4x == IID_RSVD_4YOU || myIID4x == myIID4me) { + dbgf(DBGL_SYS, DBGT_WARN, "%s from %s requesting %s %s", + it->handls[it->frame_type].name, pb->i.llip_str, + dhn ? "REFERRED TIMEOUT" : "INVALID or UNKNOWN", dhn ? dhn->on->id.name : "?");
- myIID4x = IID_RSVD_4YOU; + return sizeof ( struct msg_dhash_request); + }
- desc0_len = sizeof ( struct msg_description_adv) + my_desc0_tlv_len; + assertion(-500251, (dhn && dhn->myIID4orig == myIID4x));
- } else { // if I am asked for somebody else description + uint16_t desc_len = ntohs(dhn->on->desc->dsc_tlvs_len) + sizeof ( struct msg_description_adv);
- struct dhash_node *dhn = iid_get_node_by_myIID4x(myIID4x); - - assertion(-500270, (!(dhn && dhn->on && !dhn->on->desc0))); + if (it->frame_type == FRAME_TYPE_DSC0_REQS) {
- if (myIID4x <= IID_RSVD_MAX || !dhn || !dhn->on || - ((uint32_t) (bmx_time - dhn->referred_timestamp)) > DEF_DESC0_REFERRED_TO) { + schedule_tx_task(pb->i.lndev, FRAME_TYPE_DSC0_ADVS, desc_len, 0, 0, myIID4x, 0); + + } else { + + schedule_tx_task(pb->i.lndev, FRAME_TYPE_DHS0_ADVS, 0, 0, 0, myIID4x, 0); + } + + return sizeof ( struct msg_dhash_request); +} + +STATIC_FUNC +int32_t rx_frame_hello_replies(struct rx_frame_iterator *it) +{ + TRACE_FUNCTION_CALL; + struct packet_buff *pb = it->pb; + struct dev_node *iif = pb->i.iif; + HELLO_FLAGS_SQN_T sqn = 0; + int pos, found = 0; + + for (pos = 0; pos < it->frame_data_length; pos += sizeof ( struct msg_hello_reply)) { + + struct msg_hello_reply *msg = (struct msg_hello_reply*) (it->frame_data + pos); + IID_T neighIID4x = ntohs(msg->transmitterIID4x); + + IID_NODE_T *dhn = iid_get_node_by_neighIID4x(pb->i.ln->neigh, neighIID4x); + + if (dhn == self.dhn) { + + HELLO_FLAGS_SQN_T flags_sqn = ntohs(msg->hello_flags_sqn); + + sqn = ((HELLO_SQN_MASK)&(flags_sqn >> HELLO_SQN_BIT_POS)); + + if (((HELLO_SQN_MASK)& (iif->link_hello_sqn - sqn)) > DEF_HELLO_DAD_RANGE) {
dbgf(DBGL_SYS, DBGT_WARN, - "%s from %s via %s myIID4x %d requesting %s", - frame_handler[frame_type].name, pb->ln->llip4_str, pb->iif->name, myIID4x, - !dhn ? "UNKNOWN" : (dhn->on ? "OUTDATED" : "INVALID")); + "DAD-Alert (duplicate link_id, can happen) my hello_sqn=%d != %d via dev=%s NBs' NB=%s !", + iif->link_hello_sqn, sqn, iif->label_cfg.str, pb->i.llip_str);
continue; }
- assertion(-500251, (dhn && dhn->on && dhn->myIID4orig == myIID4x)); - desc0_len = sizeof ( struct msg_description_adv) + ntohs(dhn->on->desc0->dsc_tlvs_len); - } + found++;
+ update_link_metrics(pb->i.lndev, 0, sqn, pb->i.iif->link_hello_sqn, SQR_RTQ, &pb->i.iif->umetric_max);
- if ( frame_type == FRAME_TYPE_DSC0_REQS) { + pb->i.lndev->rx_hello_reply_flags = ((HELLO_FLAGS_MASK)&(flags_sqn >> HELLO_FLAGS_BIT_POS));
- schedule_tx_task(pb->iif, pb->lndev, FRAME_TYPE_DSC0_ADVS, desc0_len, 0, myIID4x, 0);
- } else { + } else if (!dhn && pb->i.lndev->mr[SQR_RQ].umetric_final > UMETRIC_RQ_NBDISC_MIN) {
- schedule_tx_task(pb->iif, pb->lndev, FRAME_TYPE_DHS0_ADVS, 0, 0, myIID4x, 0); + schedule_tx_task(pb->i.lndev, FRAME_TYPE_DHS0_REQS, 0, 0, 0, 0, neighIID4x); } + }
- return frame->length; + if (found > 2) { + dbgf(DBGL_SYS, DBGT_WARN, + "rcvd %d %s messages in %d-bytes frame_data, last_rcvd_sqn=%d iif->link_hello_sqn=%d umetric=%ju", + found, packet_frame_handler[FRAME_TYPE_HELLO_REPS].name, it->frame_data_length, + sqn, pb->i.iif->link_hello_sqn, pb->i.lndev->mr[SQR_RTQ].umetric_final); + } + + return pos; }
+ + STATIC_FUNC -int rx_frame_hello40_replies(struct packet_buff *pb, struct frame_header *frame) +int32_t rx_msg_hello_adv(struct rx_frame_iterator *it) { + TRACE_FUNCTION_CALL; + struct packet_buff *pb = it->pb; + struct link_node *ln = pb->i.ln; + struct msg_hello_adv *msg = (struct msg_hello_adv*) (it->msg); + HELLO_FLAGS_SQN_T hello_flags_sqn = ntohs(msg->hello_flags_sqn); + HELLO_FLAGS_SQN_T hello_sqn = ((HELLO_SQN_MASK)&((hello_flags_sqn)>>HELLO_SQN_BIT_POS)); + + HELLO_FLAGS_SQN_T hello_flags = ((HELLO_FLAGS_MASK)&((hello_flags_sqn)>>HELLO_FLAGS_BIT_POS)); + + dbgf_all(DBGT_INFO, "NB=%s via dev=%s SQN=%d flags=%X", + pb->i.llip_str, pb->i.iif->label_cfg.str, hello_sqn, hello_flags); + + if (it->msg != it->frame_data) { + dbgf(DBGL_SYS, DBGT_WARN, "rcvd %d %s messages in %d-bytes frame_data", + (it->frame_data_length / ((uint32_t)sizeof (struct msg_hello_adv))), + packet_frame_handler[FRAME_TYPE_HELLO_ADVS].name, it->frame_data_length); + }
- int found = 0, m, n = (frame->length - sizeof (struct frame_header)) / sizeof ( struct msg_hello_reply); + // skip updateing link_node if this SQN is known but not new + if ((ln->rq_hello_sqn_max || ln->rq_time_max) && + ((HELLO_SQN_MASK) &(hello_sqn - ln->rq_hello_sqn_max)) > DEF_HELLO_DAD_RANGE && + ((TIME_T) (bmx_time - ln->rq_time_max) < (TIME_T) DEF_HELLO_DAD_RANGE * my_tx_interval)) {
- for (m = 0; m < n; m++) { + dbgf(DBGL_SYS, DBGT_INFO, "DAD-Alert NB=%s dev=%s SQN=%d rq_sqn_max=%d dad_range=%d dad_to=%d", + pb->i.llip_str, pb->i.iif->label_cfg.str, hello_sqn, ln->rq_hello_sqn_max, + DEF_HELLO_DAD_RANGE, DEF_HELLO_DAD_RANGE * my_tx_interval);
- struct msg_hello_reply *msg = &(((struct msg_hello_reply*) (frame->data))[m]); + return FAILURE; + }
- SQN_T sqn = ntohs(msg->hello_dev_sqn); + if (pb->i.described_dhn) + schedule_tx_task(pb->i.lndev, FRAME_TYPE_HELLO_REPS, 0, hello_sqn, 0, pb->i.described_dhn->myIID4orig, 0);
- dbgf_all( DBGT_INFO, "via NB %s dev %s %s to %s SQN %d", - pb->neigh_str, pb->iif->name, pb->iif->ip4_str, ipStr(msg->receiver_ip4), sqn); + update_link_metrics(pb->i.lndev, pb->i.transmittersIID, hello_sqn, hello_sqn, SQR_RQ, &pb->i.iif->umetric_max);
- if ( msg->receiver_ip4 != pb->iif->ip4_addr ) - continue; + return sizeof (struct msg_hello_adv); +}
- if ((SQN_T) (pb->iif->ogm_sqn - sqn) > (SQN_T) local_rtq_lounge) { +int32_t rx_frame_iterate(struct rx_frame_iterator *it) +{ + TRACE_FUNCTION_CALL; + int t, fl, dl, receptor_result; + struct frame_handl *fhdl; + struct packet_buff *pb;
- dbgf(DBGL_SYS, DBGT_ERR, "DAD-Alert invalid Link-Local SQN %d!=%d from %s via %s", - sqn, pb->iif->ogm_sqn, pb->neigh_str, pb->iif->name); + if (it->frames_pos + ((int)sizeof (struct frame_header_long)) <= it->frames_length) {
- return FAILURE; - } + struct frame_header_short *fhs = (struct frame_header_short *) (it->frames_in + it->frames_pos); + it->frame_type = t = fhs->type;
- found++; + assertion(-500775, (fhs->type == ((struct frame_header_long*) fhs)->type));
- if( !pb->ln->neigh) - schedule_tx_task(pb->iif, pb->lndev, FRAME_TYPE_DHS0_REQS, 0, 0, 0, IID_RSVD_4YOU); + if ((it->is_short_header = fhs->is_short)) {
- update_link_node(pb->ln, pb->iif, sqn, pb->iif->ogm_sqn, SQR_RTQ, PROBE_RANGE); + fl = fhs->length_2B << 1; + it->frame_data_length = dl = fl - sizeof (struct frame_header_short); + it->frame_data = it->frames_in + it->frames_pos + sizeof (struct frame_header_short);
- } + } else {
- if (found > 1) { - dbgf(DBGL_CHANGES, DBGT_WARN, - "rcvd %d %s messages in %d-bytes frame", - found, frame_handler[FRAME_TYPE_HI40_REPS].name, frame->length); - } + fl = ntohs(((struct frame_header_long*) fhs)->length_1B); + it->frame_data_length = dl = fl - sizeof (struct frame_header_long); + it->frame_data = it->frames_in + it->frames_pos + sizeof (struct frame_header_long); + }
- return frame->length; + it->frames_pos += fl;
-} + if (t > it->handl_max || !(it->handls[t].rx_frame_handler || it->handls[t].rx_msg_handler)) {
+ dbgf(DBGL_SYS, DBGT_WARN, "%s - unknown type=%d ! check for updates", it->caller, t);
+ if (t > it->handl_max || fhs->is_relevant) + return TLV_DATA_FAILURE;
-STATIC_FUNC -int rx_frame_helloX0_advs( struct packet_buff *pb, struct frame_header *frame ) -{ + return TLV_RX_DATA_IGNORED; + }
- struct link_node *ln = pb->ln; + fhdl = &it->handls[t]; + pb = it->pb;
- int m, n = (frame->length - sizeof (struct frame_header)) / sizeof ( struct msg_hello_adv); + dbgf_all(DBGT_INFO, "%s - type=%s frame_length=%d frame_data_length=%d", it->caller, fhdl->name, fl, dl);
- if (frame->length != sizeof ( struct frame_header) + sizeof ( struct msg_hello_adv)) { - dbgf(DBGL_SYS, DBGT_WARN, - "rcvd %d %s messages in %d-bytes frame", - n, frame_handler[FRAME_TYPE_HI40_ADVS].name, frame->length); - } + if (fhdl->is_relevant != fhs->is_relevant) { + dbgf(DBGL_SYS, DBGT_ERR, "%s - type=%s frame_length=%d from %s, signals %s but known as %s", + it->caller, fhdl->name, fl, pb ? pb->i.llip_str : "---", + fhs->is_relevant ? "RELEVANT" : "IRRELEVANT", + fhdl->is_relevant ? "RELEVANT" : "IRRELEVANT"); + return TLV_DATA_FAILURE; + }
- for (m = 0; m < n; m++) {
- struct msg_hello_adv *msg = &(((struct msg_hello_adv*) (frame->data))[m]); + if (!(it->process_filter == FRAME_TYPE_PROCESS_ALL || it->process_filter == t)) + return TLV_RX_DATA_IGNORED;
- SQN_T sqn = ntohs(msg->hello_dev_sqn); + } else if (it->frames_pos == it->frames_length) {
- dbgf_all( DBGT_INFO, "NB %s via %s SQN %d ", pb->neigh_str, pb->iif->name, sqn); + return TLV_RX_DATA_DONE;
- // skip updateing link_node if this SQN is known but not new - if ((ln->rq_sqn_max || ln->rq_time_max) && - ((SQN_T) (sqn - ln->rq_sqn_max) > SQN_DAD_RANGE) && - ((uint32_t) (bmx_time - ln->rq_time_max) < (uint32_t) dad_to)) { + } else { + + return TLV_DATA_FAILURE; + }
- dbgf(DBGL_SYS, DBGT_INFO, "DAD-Alert NB %s via %s SQN %d rq_sqn_max %d", - pb->neigh_str, pb->iif->name, sqn, ln->rq_sqn_max);
- return FAILURE; - }
- schedule_tx_task(pb->iif, pb->lndev, FRAME_TYPE_HI40_REPS, 0, sqn, 0, 0); + if (it->frames_pos > it->frames_length || dl < TLV_DATA_PROCESSED || dl % TLV_DATA_PROCESSED) { + // not yet processed anything, so return failure: + return TLV_DATA_FAILURE;
- update_link_node(ln, pb->iif, sqn, sqn, SQR_RQ, PROBE_RANGE); + } else if (dl < fhdl->data_header_size + fhdl->min_msg_size) {
- } + dbgf(DBGL_SYS, DBGT_WARN, "%s - too small length=%d for type=%s", it->caller, fl, fhdl->name); + return TLV_DATA_FAILURE;
- return frame->length; -} + } else if (fhdl->fixed_msg_size && (dl - (fhdl->data_header_size)) % fhdl->min_msg_size) {
+ dbgf(DBGL_SYS, DBGT_WARN, "%s - nonmaching length=%d for type=%s", it->caller, fl, fhdl->name); + return TLV_DATA_FAILURE;
+ } else if (pb && fhdl->umetric_rq_min && + (!pb->i.lndev || pb->i.lndev->mr[SQR_RQ].umetric_final < *(fhdl->umetric_rq_min))) {
-int rx_frames(struct packet_buff *pb, uint8_t* fdata, uint16_t fsize) -{ + dbg_mute(60, DBGL_CHANGES, DBGT_WARN, "%s - non-sufficient link %s - %s (rq=%ju), skipping type=%s", + it->caller, pb->i.iif->ip_llocal_str, pb->i.llip_str, + pb->i.lndev ? (pb->i.lndev->mr[SQR_RQ].umetric_final) : 0, fhdl->name);
- uint16_t frm_pos = 0; - int t = 0, pt = 0; + return TLV_RX_DATA_IGNORED;
- struct frame_header *fhdr = NULL; - uint16_t flength = 0; + } else if (pb && fhdl->rx_requires_described_neigh_dhn && !pb->i.described_dhn) {
- while (frm_pos + sizeof ( struct frame_header) < fsize) { + dbgf(DBGL_CHANGES, DBGT_INFO, "%s via %s IID=%d of neigh=%s - skipping frame type=%s", it->caller, + pb->i.ln->neigh ? "CHANGED" : "UNKNOWN", pb->i.transmittersIID, pb->i.llip_str, fhdl->name);
- fhdr = (struct frame_header*) & (fdata[frm_pos]); - flength = fhdr->length = ntohs(fhdr->length); - int receptor_result; + return TLV_RX_DATA_IGNORED;
- if ((t = fhdr->type) < pt || flength < sizeof ( struct frame_header) || flength + frm_pos > fsize) { + } else if (pb && fhdl->rx_requires_known_neighIID4me && (!pb->i.ln->neigh || !pb->i.ln->neigh->neighIID4me)) {
- goto rx_frames_frm_error; - } + dbgf(DBGL_CHANGES, DBGT_INFO, "%s via %s neighIID4me neigh=%s - skipping frame type=%s", it->caller, + pb->i.ln->neigh ? "CHANGED" : "UNKNOWN", pb->i.llip_str, fhdl->name);
- struct pkt_frame_handler *fhdl = &frame_handler[t]; + return TLV_RX_DATA_IGNORED;
- dbgf_all( DBGT_INFO, "type %s size %d flags 0x%X", - fhdl->name, flength, fhdr->flags); + } else if (fhdl->rx_msg_handler && fhdl->fixed_msg_size) { + + it->msg = it->frame_data + fhdl->data_header_size;
+ while (it->msg < it->frame_data + it->frame_data_length && + ((*(fhdl->rx_msg_handler)) (it)) == fhdl->min_msg_size) {
- if (t > FRAME_TYPE_NOP || !(fhdl->rx_frm_receptor)) { + it->msg += fhdl->min_msg_size; + }
- dbgf(DBGL_SYS, DBGT_WARN, "unsupported type %d ! maybe you need an update?", t); + if (it->msg != it->frame_data + it->frame_data_length) + return TLV_DATA_FAILURE;
- if (t > FRAME_TYPE_NOP) - goto rx_frames_frm_error; + return it->frame_data_length;
- } else if (flength - sizeof (struct frame_header) < fhdl->data_header_size + fhdl->min_msg_size) { + } else if (fhdl->rx_frame_handler) {
- dbgf(DBGL_SYS, DBGT_WARN, - "too small size %d for type %s", flength, fhdl->name); - goto rx_frames_frm_error; + receptor_result = (*(fhdl->rx_frame_handler)) (it);
- } else if (fhdl->fixed_msg_size && - (flength - (sizeof (struct frame_header) + fhdl->data_header_size)) % fhdl->min_msg_size) { + if (receptor_result == TLV_DATA_BLOCKED) + return TLV_DATA_BLOCKED;
- dbgf(DBGL_SYS, DBGT_WARN, - "nonmaching size %d for type %s", flength, fhdl->name); - goto rx_frames_frm_error; + if (dl != receptor_result) + return TLV_DATA_FAILURE;
- } else if (fhdl->min_rtq && (!pb->lndev || pb->lndev->mr[SQR_RTQ].val < fhdl->min_rtq)) { + return receptor_result; + }
- dbg_mute(60, DBGL_CHANGES, DBGT_WARN, - "non-sufficient bidirectional link %s - %s (rtq %d), skipping frame type %s", - pb->iif->ip4_str, pb->neigh_str, - pb->lndev ? pb->lndev->mr[SQR_RTQ].val : 0, fhdl->name); + return TLV_DATA_FAILURE; +}
- } else if (flength != (receptor_result = (*(fhdl->rx_frm_receptor)) (pb, fhdr))) { +IDM_T rx_frames(struct packet_buff *pb) +{ + TRACE_FUNCTION_CALL; + int32_t it_result;
- if (receptor_result == FAILURE) - blacklist_neighbor(pb); + struct rx_frame_iterator it = { + .caller = __FUNCTION__, .pb = pb, + .handls = packet_frame_handler, .handl_max = FRAME_TYPE_MAX, .process_filter = FRAME_TYPE_PROCESS_ALL, + .frames_in = (((uint8_t*) & pb->packet.header) + sizeof (struct packet_header)), + .frames_length = (ntohs(pb->packet.header.pkt_length) - sizeof (struct packet_header)), .frames_pos = 0 + };
- goto rx_frames_msg_error; + while ((it_result = rx_frame_iterate(&it)) > TLV_RX_DATA_DONE || it_result == TLV_DATA_BLOCKED);
- } + if (it_result <= TLV_DATA_FAILURE) { + dbgf(DBGL_SYS, DBGT_WARN, "problematic frame_type=%s data_length=%d iterator_result=%d pos=%d ", + packet_frame_handler[it.frame_type].name, it.frame_data_length, it_result, it.frames_pos); + return FAILURE; + }
- pt = t; - frm_pos += flength; - } + if (!pb->i.described_dhn) { + // this also updates referred_by_neigh_timestamp_sec + dbgf(DBGL_CHANGES, DBGT_INFO, "%s neighIID4neigh=%d %s", + pb->i.ln->neigh ? "CHANGED " : "UNKNOWN", pb->i.transmittersIID, pb->i.llip_str);
- if ( frm_pos != fsize ) - goto rx_frames_frm_error; + schedule_tx_task(pb->i.lndev, FRAME_TYPE_DHS0_REQS, 0, 0, 0, 0, pb->i.transmittersIID); + }
return SUCCESS; +}
-rx_frames_msg_error: - dbgf(DBGL_SYS, DBGT_WARN, "rcvd problematic message");
-rx_frames_frm_error: - dbgf(DBGL_SYS, DBGT_WARN, - "rcvd problematic frame type %s last %s frm_size %d pos %d ", - frame_handler[t].name, frame_handler[pt].name, flength, frm_pos); - - return FAILURE; -}
STATIC_FUNC -int8_t send_udp_packet( unsigned char *upd_data, int32_t udp_len, struct sockaddr_in *dst, int32_t send_sock ) { - +int8_t send_udp_packet(struct packet_buff *pb, struct sockaddr_storage *dst, int32_t send_sock) +{ + TRACE_FUNCTION_CALL; int status;
- dbgf_all( DBGT_INFO, "len %d", udp_len ); + dbgf_all(DBGT_INFO, "len=%d via dev=%s", pb->i.total_length, pb->i.oif->label_cfg.str);
if ( send_sock == 0 ) return 0;
/* - static struct iovec iov; - iov.iov_base = udp_data; - iov.iov_len = udp_data_len; + static struct iovec iov; + iov.iov_base = udp_data; + iov.iov_len = udp_data_len;
- static struct msghdr m = { 0, sizeof( struct sockaddr_in ), &iov, 1, NULL, 0, 0 }; - m.msg_name = dst; + static struct msghdr m = { 0, sizeof( *dst ), &iov, 1, NULL, 0, 0 }; + m.msg_name = dst;
- status = sendmsg( send_sock, &m, 0 ); - */ + status = sendmsg( send_sock, &m, 0 ); + */
- status = sendto( send_sock, upd_data, udp_len, 0, (struct sockaddr *)dst, sizeof(struct sockaddr_in) ); + status = sendto(send_sock, pb->packet.data, pb->i.total_length, 0, (struct sockaddr *) dst, sizeof (struct sockaddr_storage));
if ( status < 0 ) {
if ( errno == 1 ) {
- dbg_mute( 60, DBGL_SYS, DBGT_ERR, - "can't send udp packet: %s. Does your firewall allow outgoing packets on port %i ?", - strerror(errno), ntohs(dst->sin_port)); + dbg_mute(60, DBGL_SYS, DBGT_ERR, "can't send: %s. Does firewall accept %s dev=%s port=%i ?", + strerror(errno), family2Str(((struct sockaddr_in*) dst)->sin_family), + pb->i.oif->label_cfg.str ,ntohs(((struct sockaddr_in*) dst)->sin_port));
} else {
- dbg_mute( 60, DBGL_SYS, DBGT_ERR, "can't send udp packet via fd %d: %s", send_sock, strerror(errno)); + dbg_mute(60, DBGL_SYS, DBGT_ERR, "can't send via fd=%d dev=%s : %s", + send_sock, pb->i.oif->label_cfg.str, strerror(errno));
}
@@ -1898,416 +1945,899 @@ int8_t send_udp_packet( unsigned char *upd_data, int32_t udp_len, struct sockadd
-void tx_packet( void *dev_node ) + +/* + * iterates over to be created frames and stores them (including frame_header) in it->frames_out */ +STATIC_FUNC +int tx_frame_iterate(IDM_T iterate_msg, struct tx_frame_iterator *it) { - static unsigned char tx_buff[MAX_UDPD_SIZE+1]; - struct dev_node *dev = dev_node; - struct packet_header *packet_hdr = (struct packet_header *) tx_buff; - memset( packet_hdr, 0, sizeof( tx_buff )); - uint16_t packet_size = sizeof( struct packet_header ); - IDM_T packet_full = NO; + TRACE_FUNCTION_CALL; + uint8_t t = it->frame_type; + struct frame_handl *handl = &(it->handls[t]); + int32_t tlv_result;// = TLV_DATA_DONE; + assertion(-500977, (handl->min_msg_size)); + assertion(-500776, (it->cache_data_array)); + ASSERTION(-500777, (is_zero((tx_iterator_cache_msg_ptr(it)), tx_iterator_cache_data_space(it)))); + assertion(-500779, (it->frames_out_pos <= it->frames_out_max)); + assertion(-500780, (it->frames_out)); + assertion(-500781, (it->frame_type <= it->handl_max)); + assertion(-500784, (IMPLIES(it->cache_msgs_size, it->cache_msgs_size >= TLV_DATA_PROCESSED))); + + dbgf_all(DBGT_INFO, "from %s iterate_msg=%d frame_type=%d cache_msgs_size=%d cache_data_space=%d", + it->caller, iterate_msg, it->frame_type, it->cache_msgs_size, tx_iterator_cache_data_space(it)); + + if (iterate_msg || handl->tx_frame_handler) { + + if (handl->min_msg_size > tx_iterator_cache_data_space(it)) + return TLV_DATA_FULL; + + if (it->ttn && it->ttn->frame_msgs_length > tx_iterator_cache_data_space(it)) + return TLV_DATA_FULL; + }
- assertion( -500204, dev ); - assertion( -500205, dev->active ); + if (handl->tx_msg_handler && iterate_msg) {
- //remove_task( tx_packet, dev ); - register_task(aggreg_interval - (1 + rand_num(aggreg_interval / 10)), tx_packet, dev); + assertion(-500814, (tx_iterator_cache_data_space(it) >= 0));
- schedule_and_purge_ogm_aggregations(dev); + if ((tlv_result = (*(handl->tx_msg_handler)) (it)) >= TLV_DATA_PROCESSED) { + it->cache_msgs_size += tlv_result;
- uint16_t type = 0; // the currently processed frame_type + } else { + assertion(-500810, (tlv_result != TLV_DATA_FAILURE)); + assertion(-500874, (IMPLIES(!it->cache_msgs_size, + is_zero(tx_iterator_cache_hdr_ptr(it), handl->data_header_size)))); + }
- while (type <= FRAME_TYPE_NOP) { + return tlv_result; + }
- uint16_t length = sizeof (struct frame_header); - uint8_t flags = 0; + assertion(-500862, (!iterate_msg));
- int creator_result; - struct pkt_frame_handler *fhdl = &frame_handler[type]; - struct tx_task_node *ttn; - IDM_T frame_full = NO; + if (handl->tx_msg_handler && !iterate_msg) {
- assertion(-500351, (!(fhdl->tx_frm_creator && fhdl->tx_msg_creator))); + tlv_result = it->cache_msgs_size;
- if ((ttn = dev->my_tx_tasks[type])) { + assertion(-500863, (tlv_result >= TLV_DATA_PROCESSED));
- assertion(-500422, (!fhdl->data_header_size)); - assertion(-500424, (fhdl->tx_msg_creator)); - assertion(-500441, (ttn->myIID4x == IID_RSVD_4YOU)); + } else { + assertion(-500803, (handl->tx_frame_handler)); + assertion(-500864, (it->cache_msgs_size == 0));
- dbgf_all( DBGT_INFO, "%s type %d=%s %s", - dev->name, type, fhdl->name, "from dev->my_tx_tasks"); + tlv_result = (*(handl->tx_frame_handler)) (it);
- if (tx_task_obsolete(dev, type, ttn)) { + if (tlv_result >= TLV_DATA_PROCESSED) { + it->cache_msgs_size = tlv_result; + } else { + assertion(-500811, (tlv_result != TLV_DATA_FAILURE)); + return tlv_result; + } + }
- creator_result = FAILURE;
- } else if (packet_full || - (fhdl->fixed_msg_size && - packet_size + length + ttn->frame_data_length_target > (uint16_t) max_udpd_size) - ) { + assertion(-500865, (it->cache_msgs_size == tlv_result)); + assertion(-500881, (tlv_result >= TLV_DATA_PROCESSED)); + assertion(-500786, (tx_iterator_cache_data_space(it) >= 0)); + assertion(-500787, (!(tlv_result % TLV_DATA_STEPS))); + assertion(-500355, (IMPLIES(handl->fixed_msg_size, !(tlv_result % handl->min_msg_size))));
- creator_result = max_udpd_size + 1; + int32_t cache_pos = tlv_result + handl->data_header_size; + IDM_T is_short_header = (cache_pos <= SHORT_FRAME_DATA_MAX); + struct frame_header_short *fhs = (struct frame_header_short *) (it->frames_out + it->frames_out_pos);
- } else { + if (is_short_header) { + fhs->length_2B = ((cache_pos + sizeof ( struct frame_header_short)) >> 1); + it->frames_out_pos += sizeof ( struct frame_header_short); + } else { + struct frame_header_long *fhl = (struct frame_header_long *) fhs; + memset(fhl, 0, sizeof (struct frame_header_long)); + fhl->length_1B = htons(cache_pos + sizeof ( struct frame_header_long)); + it->frames_out_pos += sizeof ( struct frame_header_long); + }
- creator_result = (*(fhdl->tx_msg_creator)) - (ttn, &flags, (tx_buff + packet_size + length), - (max_udpd_size - (packet_size + length))); + fhs->is_short = is_short_header; + fhs->is_relevant = handl->is_relevant; + fhs->type = t;
- } + memcpy(it->frames_out + it->frames_out_pos, it->cache_data_array, cache_pos); + it->frames_out_pos += cache_pos; + + dbgf_all(DBGT_INFO, "added %s frame_header type=%s frame_data_length=%d frame_msgs_length=%d", + is_short_header ? "SHORT" : "LONG", handl->name, cache_pos, tlv_result);
- if (creator_result > (max_udpd_size - (packet_size + length))) { + memset(it->cache_data_array, 0, tlv_result + handl->data_header_size); + it->cache_msgs_size = 0;
- assertion(-500431, - (packet_size > sizeof ( struct packet_header) || - length > sizeof (struct frame_header))); + return tlv_result; +} + +STATIC_FUNC +void next_tx_task_list(struct dev_node *dev, struct tx_frame_iterator *it, struct avl_node **link_tree_iterator) +{ + TRACE_FUNCTION_CALL; + + struct link_node *ln = NULL; + + if (it->tx_task_list && it->tx_task_list->items && + ((struct tx_task_node*) (list_get_last(it->tx_task_list)))->considered_ts != bmx_time + ) { + return; + } + + if (it->tx_task_list == &(dev->tx_task_lists[it->frame_type])) + it->frame_type++; + + while ((ln = avl_iterate_item(&link_tree, link_tree_iterator))) { + struct list_node *lndev_pos; + struct link_dev_node *lndev = NULL; + + list_for_each(lndev_pos, &ln->lndev_list) + { + lndev = list_entry(lndev_pos, struct link_dev_node, list);
- packet_full = YES; + if (lndev->key.dev == dev && lndev->tx_task_lists[it->frame_type].items) {
- } else if (creator_result) { + assertion(-500866, (lndev->key.link == ln));
- if (creator_result > 0) - length += creator_result; + it->tx_task_list = &(lndev->tx_task_lists[it->frame_type]);
- freed_tx_task_node(ttn, creator_result, NULL); + dbgf(DBGL_CHANGES, DBGT_INFO, + "found %s lndev ln=%s dev=%s tx_tasks_list.items=%d", + it->handls[it->frame_type].name, + ipXAsStr(af_cfg, &lndev->key.link->link_ip), + dev->label_cfg.str, it->tx_task_list->items);
+ return; } } + } + + *link_tree_iterator = NULL; + it->tx_task_list = &(dev->tx_task_lists[it->frame_type]); + return; +} + +STATIC_FUNC +void tx_packet(void *devp) +{ + TRACE_FUNCTION_CALL; + + static uint8_t cache_data_array[MAX_UDPD_SIZE] = {0}; + static struct packet_buff pb; + struct dev_node *dev = devp; + + dbgf_all(DBGT_INFO, "dev=%s", dev->label_cfg.str); + + assertion(-500204, (dev)); + assertion(-500205, (dev->active)); + ASSERTION(-500788, ((pb.packet.data) == ((uint8_t*) (&pb.packet.header)))); + ASSERTION(-500789, ((pb.packet.data + sizeof (struct packet_header)) == ((uint8_t*) &((&pb.packet.header)[1])))); + + struct link_dev_node dummy_lndev = {.key = {.dev = dev, .link = NULL}, .mr = {ZERO_METRIC_RECORD,ZERO_METRIC_RECORD}}; + + schedule_tx_task(&dummy_lndev, FRAME_TYPE_HELLO_ADVS, 0, 0, 0, 0, 0); + + memset(&pb.i, 0, sizeof (pb.i));
- struct list_node *lprev = (struct list_node*) &(dev->tx_tasks_list[type]); - struct list_node *lpos, *ltmp; + struct tx_frame_iterator it = { + .caller = __FUNCTION__, .handls = packet_frame_handler, .handl_max = FRAME_TYPE_MAX, + .frames_out = (pb.packet.data + sizeof (struct packet_header)), .frames_out_pos = 0, + .frames_out_max = (pref_udpd_size - sizeof (struct packet_header)), + .cache_data_array = cache_data_array, .cache_msgs_size = 0, + .frame_type = 0, .tx_task_list = NULL + };
- list_for_each_safe(lpos, ltmp, &(dev->tx_tasks_list[type])) + struct avl_node *link_tree_iterator = NULL; + + while (it.frame_type < FRAME_TYPE_NOP) { + + next_tx_task_list(dev, &it, &link_tree_iterator); + + struct list_node *lpos, *ltmp, *lprev = (struct list_node*) it.tx_task_list; + int32_t tlv_result = TLV_TX_DATA_DONE; + struct frame_handl *handl = &packet_frame_handler[it.frame_type]; + uint16_t old_frames_out_pos = it.frames_out_pos; + uint32_t item =0; + + list_for_each_safe(lpos, ltmp, it.tx_task_list) { - ttn = list_entry(lpos, struct tx_task_node, list); + it.ttn = list_entry(lpos, struct tx_task_node, list); + item++;
- assertion(-500440, (ttn->frame_type == type)); + assertion(-500440, (it.ttn->content.type == it.frame_type)); + ASSERTION(-500917, (IMPLIES(!handl->is_advertisement, it.ttn->content.lndev && + it.ttn->content.lndev == avl_find_item(&link_dev_tree, &it.ttn->content.lndev->key)))); + ASSERTION(-500918, (IMPLIES(!handl->is_advertisement, it.ttn->content.link && + it.ttn->content.lndev->key.link == it.ttn->content.link && + it.ttn->content.link == avl_find_item(&link_tree, &it.ttn->content.link->link_id)))); + ASSERTION(-500920, (IMPLIES(!handl->is_advertisement, it.ttn->content.dev && + it.ttn->content.lndev->key.dev == it.ttn->content.dev && + it.ttn->content.dev == avl_find_item(&dev_ip_tree, &it.ttn->content.dev->llocal_ip_key))));
- dbgf_all( DBGT_INFO, "%s type %d=%s %s", - dev->name, type, fhdl->name, "from dev->tx_tasks_list");
- if (ttn->tx_timestamp == bmx_time) { + dbgf_all(DBGT_INFO, "%s type=%d =%s", dev->label_cfg.str, it.frame_type, handl->name);
- // just send! send again later; - creator_result = 0; + if (it.ttn->tx_iterations <= 0) {
- } else if (tx_task_obsolete(dev, type, ttn)) { + tlv_result = TLV_TX_DATA_DONE;
- creator_result = FAILURE; + } else if (it.ttn->considered_ts == bmx_time) { + // already considered during this tx iteration + tlv_result = TLV_TX_DATA_IGNORED;
- } else if (packet_full || - (fhdl->fixed_msg_size && - packet_size + length + ttn->frame_data_length_target > (uint16_t) max_udpd_size) - ) { + } else if (tx_task_obsolete(it.ttn)) { + // too recently send! send later; + tlv_result = TLV_TX_DATA_IGNORED;
- creator_result = max_udpd_size + 1; + } else if (handl->tx_frame_handler) {
- } else if (fhdl->tx_frm_creator) { + tlv_result = tx_frame_iterate(NO/*iterate_msg*/, &it);
- creator_result = ((*(fhdl->tx_frm_creator)) - (ttn, &flags, (tx_buff + packet_size + length), - (max_udpd_size - (packet_size + length)))); + } else if (handl->tx_msg_handler) {
- frame_full = YES; + tlv_result = tx_frame_iterate(YES/*iterate_msg*/, &it);
} else { + assertion(-500818, (0)); + }
- assertion(-500425, (fhdl->tx_msg_creator)); - assertion(-500426, (!fhdl->data_header_size)); // to be implemented... + if (handl->tx_msg_handler && it.cache_msgs_size && + (tlv_result == TLV_DATA_FULL || lpos == it.tx_task_list->prev)) {// last element in list: + + int32_t it_result = tx_frame_iterate(NO/*iterate_msg*/, &it);
- creator_result = (*(fhdl->tx_msg_creator)) - (ttn, &flags, (tx_buff + packet_size + length), - (max_udpd_size - (packet_size + length))); + if (it_result < TLV_DATA_PROCESSED) { + dbgf(DBGL_SYS, DBGT_ERR, "unexpected it_result=%d (tlv_result=%d) type=%d", + it_result, tlv_result, it.frame_type);
+ cleanup_all(-500790); + } }
- if (creator_result > (max_udpd_size - (packet_size + length))) { + dbgf_all(DBGT_INFO, "%s type=%d =%s considered=%d iterations=%d tlv_result=%d item=%d/%d", + dev->label_cfg.str, it.frame_type, handl->name, it.ttn->considered_ts, + it.ttn->tx_iterations, tlv_result, item, it.tx_task_list->items);
- assertion(-500430, - (packet_size > sizeof ( struct packet_header) || - length > sizeof (struct frame_header))); + if (tlv_result == TLV_TX_DATA_DONE) {
- packet_full = YES; - break; + it.ttn->considered_ts = bmx_time; + it.ttn->tx_iterations--; + + if (freed_tx_task_node(it.ttn, it.tx_task_list, lprev) == NO) + lprev = lpos; + + continue; + + } else if (tlv_result == TLV_TX_DATA_IGNORED) { + + it.ttn->considered_ts = bmx_time;
- } else if (creator_result) { + lprev = lpos; + continue;
- if (creator_result > 0) - length += creator_result; + } else if (tlv_result >= TLV_DATA_PROCESSED) {
- if (freed_tx_task_node(ttn, creator_result, lprev) == NO) + it.ttn->considered_ts = bmx_time; + it.ttn->tx_iterations--; + + if (freed_tx_task_node(it.ttn, it.tx_task_list, lprev) == NO) lprev = lpos;
- if (frame_full) + if (handl->tx_frame_handler || lpos == it.tx_task_list->prev) break;
continue;
+ } else if (tlv_result == TLV_DATA_FULL) { + // means not created because would not fit! + assertion(-500430, (it.cache_msgs_size || it.frames_out_pos)); // single message larger than max_udpd_size + break; + } else { - lprev = lpos; + + dbgf(DBGL_SYS, DBGT_ERR, "frame_type=%d tlv_result=%d", + it.frame_type, tlv_result); + assertion(-500791, (0)); } }
+ if (it.frames_out_pos > old_frames_out_pos) { + dbgf_all(DBGT_INFO, "prepared frame_type=%s frame_size=%d frames_out_pos=%d", + handl->name, (it.frames_out_pos - old_frames_out_pos), it.frames_out_pos); + }
- if (length > sizeof (struct frame_header)) { - - struct frame_header *frame_hdr = (struct frame_header *) (tx_buff + packet_size); - packet_size += length; - - frame_hdr->type = type; - frame_hdr->length = htons(length); - frame_hdr->flags |= flags; + assertion(-500796, (!it.cache_msgs_size)); + assertion(-500800, (it.frames_out_pos >= old_frames_out_pos));
- dbgf_all( DBGT_INFO, "send frame type %s size %d", fhdl->name, length); - } + if (tlv_result == TLV_DATA_FULL || (it.frame_type == FRAME_TYPE_NOP && it.frames_out_pos)) {
+ struct packet_header *packet_hdr = &pb.packet.header;
- if (packet_full || (type == FRAME_TYPE_NOP && packet_size > sizeof ( struct packet_header))) { + assertion(-500208, (it.frames_out_pos && it.frames_out_pos <= it.frames_out_max));
- assertion(-500208, (packet_size <= max_udpd_size)); - assertion(-500412, (packet_size >= sizeof ( struct packet_header))); + pb.i.oif = dev; + pb.i.total_length = (it.frames_out_pos + sizeof ( struct packet_header));
- packet_hdr->bmx_version = COMPAT_VERSION; - packet_hdr->bmx_capabilities = 0; - packet_hdr->pkt_length = htons(packet_size); - packet_hdr->pkt_dev_sqn = htons(++(dev->packet_sqn)); + memset(packet_hdr, 0, sizeof (struct packet_header));
- send_udp_packet(tx_buff, packet_size, &dev->ip4_netwbrc_addr, dev->unicast_sock); + packet_hdr->bmx_version = COMPATIBILITY_VERSION; + packet_hdr->reserved = 0; + packet_hdr->pkt_length = htons(pb.i.total_length); + packet_hdr->link_id = htonl(dev->link_id); + packet_hdr->transmitterIID = htons(myIID4me);
- dbgf_all( DBGT_INFO, "send packet size %d via dev %s", packet_size, dev->name); + cb_packet_hooks(&pb);
- packet_size = sizeof ( struct packet_header); - packet_full = NO; - } + send_udp_packet(&pb, &dev->tx_netwbrc_addr, dev->unicast_sock);
- if (type == FRAME_TYPE_NOP || - !dev->tx_tasks_list[type].items || - ((struct tx_task_node*) (list_get_last(&(dev->tx_tasks_list[type]))))->tx_timestamp == bmx_time) { + dbgf_all(DBGT_INFO, "send packet size=%d via dev=%s", + pb.i.total_length, dev->label_cfg.str);
- CHECK_INTEGRITY(); + memset(&pb.i, 0, sizeof (pb.i));
- type++; + it.frames_out_pos = 0; } + } + + assertion(-500797, (!it.frames_out_pos)); }
+void tx_packets( void *unused ) {
+ TRACE_FUNCTION_CALL;
-void schedule_my_hello_message( void* dev_node ) { + struct avl_node *an; + struct dev_node *dev;
- struct dev_node * dev = dev_node; + TIME_T dev_interval = (my_tx_interval / 10) / dev_ip_tree.items; + TIME_T dev_next = 0;
- paranoia( -500206, !dev ); - paranoia( -500207, !dev->active ); + dbgf_all(DBGT_INFO, " ");
- register_task( my_hello_interval, schedule_my_hello_message, dev ); + schedule_or_purge_ogm_aggregations(NO); + // this might schedule a new tx_packet because schedule_tx_packet() believes + // the stuff we are about to send now is still waiting to be send.
- dbgf_all( DBGT_INFO, "%s", dev->name); + //remove_task(tx_packet, NULL); + register_task((my_tx_interval + rand_num(my_tx_interval / 10) - (my_tx_interval / 20)), tx_packets, NULL);
- if (!LIST_EMPTY(&(dev->tx_tasks_list[FRAME_TYPE_HI40_ADVS]))) { - dbgf( DBGL_SYS, DBGT_ERR, " "); - } + for (an = NULL; (dev = avl_iterate_item(&dev_ip_tree, &an));) { + + if (dev->linklayer == VAL_DEV_LL_LO) + continue; + + register_task(dev_next, tx_packet, dev);
- schedule_tx_task( dev, NULL, FRAME_TYPE_HI40_ADVS, 0, 0, 0, 0 ); + dev_next += dev_interval; + + } }
void schedule_my_originator_message( void* unused ) { - my_orig_node.ogm_sqn_to_be_send += my_orig_node.path_metric_algo.sqn_steps; //ogm_sqn_steps; - my_orig_node.dhn->referred_timestamp = bmx_time; + TRACE_FUNCTION_CALL; + + if (((OGM_SQN_MASK) & (self.ogmSqn_toBeSend + 1 - self.ogmSqn_rangeMin)) >= self.ogmSqn_rangeSize) + update_my_description_adv(); + + self.ogmSqn_maxRcvd = set_ogmSqn_toBeSend_and_aggregated(&self, (self.ogmSqn_toBeSend + OGM_SQN_STEP), self.ogmSqn_aggregated); + + dbgf_all(DBGT_INFO, "ogm_sqn %d", self.ogmSqn_toBeSend);
register_task(my_ogm_interval, schedule_my_originator_message, NULL); +}
- if (((uint32_t) (my_orig_node.ogm_sqn_to_be_send + 1 - my_orig_node.ogm_sqn_min)) < my_orig_node.ogm_sqn_range) {
- ogm_aggreg_pending++; - dbgf_all(DBGT_INFO, "ogm_sqn %d", my_orig_node.ogm_sqn_to_be_send); +STATIC_FUNC +IDM_T validate_description(struct description *desc) +{ + TRACE_FUNCTION_CALL; + int id_name_len;
- } else { + if ( + (id_name_len = strlen(desc->id.name)) >= DESCRIPTION0_ID_NAME_LEN || + !is_zero(&desc->id.name[id_name_len], DESCRIPTION0_ID_NAME_LEN - id_name_len) || + validate_name(desc->id.name) == FAILURE) {
- update_my_description_adv(); + dbg(DBGL_SYS, DBGT_ERR, "illegal hostname .. %jX", desc->id.rand.u64[0]); + return FAILURE; + }
+ if ( + validate_param(desc->ttl_max, MIN_TTL, MAX_TTL, ARG_TTL) || + validate_param(ntohs(desc->ogm_sqn_range), MIN_OGM_SQN_RANGE, MAX_OGM_SQN_RANGE, ARG_OGM_SQN_RANGE) || + validate_param(ntohs(desc->tx_interval), MIN_TX_INTERVAL, MAX_TX_INTERVAL, ARG_TX_INTERVAL) || + 0 + ) { + + return FAILURE; } + + return SUCCESS; }
+struct dhash_node * process_description(struct packet_buff *pb, struct description *desc, struct description_hash *dhash) +{ + TRACE_FUNCTION_CALL; + assertion(-500262, (pb && pb->i.ln && desc)); + assertion(-500381, (!avl_find( &dhash_tree, dhash )));
+ struct dhash_node *dhn; + struct orig_node *on = NULL;
-void update_my_description_adv(void) -{ - struct description_hash dhash; - struct description *dsc = my_orig_node.desc0;
- if ( terminating() ) - return; + if ( validate_description( desc ) != SUCCESS ) + goto process_desc0_error; + + + if ((on = avl_find_item(&orig_tree, &desc->id))) { + + dbgf(DBGL_CHANGES, DBGT_INFO, "%s desc SQN=%d (old_sqn=%d) from orig=%s via dev=%s neigh=%s", + pb ? "RECEIVED NEW" : "CHECKING OLD (BLOCKED)", ntohs(desc->dsc_sqn), on->descSqn, desc->id.name, + pb ? pb->i.iif->label_cfg.str : "---", pb ? pb->i.llip_str : "---"); + + assertion(-500383, (on->dhn)); + + if (pb && ((TIME_T) (bmx_time - on->dhn->referred_by_me_timestamp)) < (TIME_T) dad_to) { + + if (((DESC_SQN_MASK)&(ntohs(desc->dsc_sqn) - (on->descSqn + 1))) > DEF_DESCRIPTION_DAD_RANGE) { + + dbgf(DBGL_SYS, DBGT_ERR, "DAD-Alert: new dsc_sqn %d not > old %d + 1", + ntohs(desc->dsc_sqn), on->descSqn); + + goto process_desc0_ignore; + } + + if (UXX_LT(OGM_SQN_MASK, ntohs(desc->ogm_sqn_min), (on->ogmSqn_rangeMin + MAX_OGM_SQN_RANGE))) { + + dbgf(DBGL_SYS, DBGT_ERR, "DAD-Alert: new ogm_sqn_min %d not > old %d + %d", + ntohs(desc->ogm_sqn_min), on->ogmSqn_rangeMin, MAX_OGM_SQN_RANGE); + + goto process_desc0_ignore; + } + } + + } else { + // create new orig: + on = debugMalloc( sizeof( struct orig_node ), -300128 ); + init_orig_node(on, &desc->id); + } + + + + + int32_t tlv_result; + + if (pb) { + + if (on->desc && !on->blocked) { + tlv_result = process_description_tlvs(pb, on, on->desc, TLV_OP_DEL, FRAME_TYPE_PROCESS_ALL, NULL); + assertion(-500808, (tlv_result == TLV_RX_DATA_DONE)); + } + + on->updated_timestamp = bmx_time; + on->descSqn = ntohs(desc->dsc_sqn); + + on->ogmSqn_rangeMin = ntohs(desc->ogm_sqn_min); + on->ogmSqn_rangeSize = ntohs(desc->ogm_sqn_range);
- // put obligatory stuff: - memset(dsc, 0, MAX_PKT_MSG_SIZE);
- memcpy(&dsc->id, &my_orig_node.id, sizeof(struct description_id)); + on->ogmSqn_maxRcvd = (OGM_SQN_MASK & (on->ogmSqn_rangeMin - OGM_SQN_STEP)); + set_ogmSqn_toBeSend_and_aggregated(on, on->ogmSqn_maxRcvd, on->ogmSqn_maxRcvd); + + } + + if ((tlv_result = process_description_tlvs(pb, on, desc, TLV_OP_TEST, FRAME_TYPE_PROCESS_ALL, NULL)) == TLV_RX_DATA_DONE) { + tlv_result = process_description_tlvs(pb, on, desc, TLV_OP_ADD, FRAME_TYPE_PROCESS_ALL, NULL); + assertion(-500831, (tlv_result == TLV_RX_DATA_DONE)); // checked, so MUST SUCCEED!! + } + + if (tlv_result == TLV_DATA_FAILURE) + goto process_desc0_error; + /* - dsc->id.rand.u32[0] = htonl(my_orig_node.id.rand.u32[0]); - dsc->id.rand.u32[1] = htonl(my_orig_node.id.rand.u32[1]); + // actually I want to accept descriptions without any primary IP: + if (!on->blocked && !ip_set(&on->ort.primary_ip)) + goto process_desc0_error; */
- my_orig_node.ogm_sqn_pq_bits = DEF_OGM0_PQ_BITS; -// my_orig_node.ogm_sqn_mask = (MAX_SQN << my_orig_node.ogm_sqn_pq_bits); -// my_orig_node.ogm_sqn_steps = (0x01 << my_orig_node.ogm_sqn_pq_bits); + if (on->desc) + debugFree(on->desc, -300111);
- // add some randomness to the ogm_sqn_range, that not all nodes invalidate at the same time: - uint16_t random_range = ((DEF_OGM0_SQN_RANGE - (DEF_OGM0_SQN_RANGE/5)) > MIN_OGM0_SQN_RANGE) ? - DEF_OGM0_SQN_RANGE - rand_num(DEF_OGM0_SQN_RANGE/5) : DEF_OGM0_SQN_RANGE + rand_num(DEF_OGM0_SQN_RANGE/5); + on->desc = desc; + desc = NULL;
- my_orig_node.ogm_sqn_range = ((random_range + my_orig_node.path_metric_algo.sqn_steps - 1) & my_orig_node.path_metric_algo.sqn_mask); + struct neigh_node *dhn_neigh = NULL;
- my_orig_node.ogm_sqn_min = ((my_orig_node.ogm_sqn_min + MAX_OGM0_SQN_RANGE + (0x01 << MAX_OGM0_PQ_BITS)) & my_orig_node.path_metric_algo.sqn_mask); + if (on->dhn) { + dhn_neigh = on->dhn->neigh; + on->dhn->neigh = NULL; + on->dhn->on = NULL; + invalidate_dhash_node(on->dhn); + }
- my_orig_node.ogm_sqn_aggregated = my_orig_node.ogm_sqn_min; - my_orig_node.ogm_sqn_to_be_send = my_orig_node.ogm_sqn_min + my_orig_node.path_metric_algo.sqn_steps - 1; + on->dhn = dhn = create_dhash_node(dhash, on);
+ if ( dhn_neigh ) { + dhn_neigh->dhn = dhn; + dhn->neigh = dhn_neigh; + }
- dsc->path_window_size = htons(my_orig_node.path_metric_algo.sqn_window); - dsc->path_lounge_size = htons(my_orig_node.path_metric_algo.sqn_lounge); + assertion(-500309, (dhn == avl_find_item(&dhash_tree, &dhn->dhash) && dhn->on == on)); + assertion(-500310, (on == avl_find_item(&orig_tree, &on->desc->id) && on->dhn == dhn));
+ return dhn;
- dsc->ttl_max = my_ttl; - dsc->path_hystere = my_path_hystere; +process_desc0_error:
- dsc->hop_penalty = my_hop_penalty; - dsc->late_penalty = my_late_penalty; - dsc->asym_weight = asym_weight; - dsc->sym_weight = sym_weight; + if (on) + free_orig_node(on);
+ blacklist_neighbor(pb);
- dsc->ogm_sqn_pq_bits = my_orig_node.ogm_sqn_pq_bits; - dsc->ogm_sqn_min = htons(my_orig_node.ogm_sqn_min); - dsc->ogm_sqn_range = htons(my_orig_node.ogm_sqn_range); +process_desc0_ignore:
- dsc->dsc_sqn = htons(++(my_orig_node.desc0_sqn)); + dbgf(DBGL_SYS, DBGT_WARN, + "%jX rcvd via %s NB %s", desc ? desc->id.rand.u64[0] : 0, pb->i.iif->label_cfg.str, pb->i.llip_str);
+ if (desc) + debugFree(desc, -300109);
- dsc->path_ogi = htons(my_ogm_interval); + return NULL; +}
- // add all tlv options: - my_desc0_tlv_len = 0; - uint8_t tlvt; - for ( tlvt=0; tlvt < BMX_DSC_TLV_ARRSZ; tlvt++) { +void update_my_description_adv(void) +{ + TRACE_FUNCTION_CALL; + static uint8_t cache_data_array[MAX_UDPD_SIZE] = {0}; + struct description_hash dhash; + struct description *dsc = self.desc;
- struct frame_header *tlv = (struct frame_header*) (((char*) dsc) + sizeof (struct description) + my_desc0_tlv_len); + if (terminating) + return;
- uint16_t rsvd = my_desc0_tlv_len + sizeof (struct frame_header); + // put obligatory stuff: + memset(dsc, 0, sizeof (struct description));
- if (rsvd <= MAX_DESC0_TLV_SIZE && (description0_tlv_handler[tlvt].create_tlv)) { + memcpy(&dsc->id, &self.id, sizeof(struct description_id));
- uint16_t msgs_size = (*(description0_tlv_handler[tlvt].create_tlv)) - (tlv->data, MAX_DESC0_TLV_SIZE - rsvd);
- if ( msgs_size ) { + // add some randomness to the ogm_sqn_range, that not all nodes invalidate at the same time: + uint16_t random_range = ((DEF_OGM_SQN_RANGE - (DEF_OGM_SQN_RANGE/5)) > MIN_OGM_SQN_RANGE) ? + DEF_OGM_SQN_RANGE - rand_num(DEF_OGM_SQN_RANGE/5) : DEF_OGM_SQN_RANGE + rand_num(DEF_OGM_SQN_RANGE/5);
- assertion(-500355, (description0_tlv_handler[tlvt].variable_msg_size || - msgs_size % description0_tlv_handler[tlvt].min_msg_size == 0)); + self.ogmSqn_rangeSize = ((OGM_SQN_MASK)&(random_range + OGM_SQN_STEP - 1));
- tlv->type = tlvt; - tlv->length = htons(sizeof (struct frame_header) + msgs_size); + self.ogmSqn_rangeMin = ((OGM_SQN_MASK)&(self.ogmSqn_rangeMin + MAX_OGM_SQN_RANGE));
- my_desc0_tlv_len += sizeof (struct frame_header) + msgs_size; + self.ogmSqn_maxRcvd = (OGM_SQN_MASK)&(self.ogmSqn_rangeMin - OGM_SQN_STEP); + set_ogmSqn_toBeSend_and_aggregated(&self, self.ogmSqn_maxRcvd, self.ogmSqn_maxRcvd);
- dbgf_all(DBGT_INFO, "added %s size %d", - description0_tlv_handler[tlvt].name, msgs_size); + dsc->ogm_sqn_min = htons(self.ogmSqn_rangeMin); + dsc->ogm_sqn_range = htons(self.ogmSqn_rangeSize); + dsc->tx_interval = htons(my_tx_interval);
- } + dsc->code_version = htons(CODE_VERSION); + dsc->dsc_sqn = htons(++(self.descSqn)); + dsc->ttl_max = my_ttl;
- } else { - cleanup_all( -500352 ); - } + // add all tlv options: + + struct tx_frame_iterator it = { + .caller = __FUNCTION__, .frames_out = (((uint8_t*) dsc) + sizeof (struct description)), + .handls = description_tlv_handl, .handl_max = FRAME_TYPE_MAX, .frames_out_pos = 0, + .frames_out_max = MAX_UDPD_SIZE - + (sizeof (struct packet_header) + sizeof (struct frame_header_long) + sizeof (struct msg_description_adv)), + .cache_data_array = cache_data_array + }; + + int iterator_result; + for (it.frame_type = 0; it.frame_type < BMX_DSC_TLV_ARRSZ; it.frame_type++) { + + if (!it.handls[it.frame_type].min_msg_size) + continue; + + iterator_result = tx_frame_iterate(NO/*iterate_msg*/, &it); + + assertion(-500792, (iterator_result >= TLV_TX_DATA_DONE)); }
- dsc->dsc_tlvs_len = htons(my_desc0_tlv_len); + dsc->dsc_tlvs_len = htons(it.frames_out_pos); +
- dbgf_all(DBGT_INFO, "added tlv total of %d ", my_desc0_tlv_len); + dbgf_all(DBGT_INFO, "added description_tlv_size=%d ", it.frames_out_pos);
// calculate hash: like shown in CTaoCrypt Usage Reference: - ShaUpdate(&bmx_sha, (byte*)dsc, (sizeof (struct description) + my_desc0_tlv_len)); - ShaFinal(&bmx_sha, (byte*) &dhash); + ShaUpdate(&bmx_sha, (byte*) dsc, (it.frames_out_pos + sizeof (struct description))); + ShaFinal(&bmx_sha, (byte*) & dhash);
- if ( my_orig_node.dhn ) { - my_orig_node.dhn->on = NULL; - invalidate_dhash_node( my_orig_node.dhn ); + if (self.dhn) { + self.dhn->on = NULL; + invalidate_dhash_node( self.dhn ); }
- my_orig_node.dhn = create_dhash_node(&dhash, &my_orig_node); + self.dhn = create_dhash_node(&dhash, &self);
- myIID4me = my_orig_node.dhn->myIID4orig; + myIID4me = self.dhn->myIID4orig; + myIID4me_timestamp = bmx_time;
- if (DEF_UNSOLICITED_DESCRIPTIONS) { - uint16_t desc_len = sizeof ( struct msg_description_adv) + my_desc0_tlv_len; - struct link_dev_node **lndev_arr = get_best_lndevs_by_criteria(NULL, my_orig_node.dhn); + if (tx_unsolicited_desc) { + uint16_t desc_len = it.frames_out_pos + sizeof (struct msg_description_adv); + struct link_dev_node **lndev_arr = get_best_lndevs_by_criteria(NULL, self.dhn); int d;
for (d = 0; (lndev_arr[d]); d++) - schedule_tx_task(lndev_arr[d]->key.dev, lndev_arr[d], FRAME_TYPE_DSC0_ADVS, desc_len, 0, IID_RSVD_4YOU, 0); + schedule_tx_task(lndev_arr[d], FRAME_TYPE_DSC0_ADVS, desc_len, 0, 0, myIID4me, 0); }
-/* - remove_task(schedule_my_originator_message, NULL); - register_task(1, schedule_my_originator_message, NULL); -*/ + my_description_changed = NO;
+}
+STATIC_FUNC +void dbg_msg_status ( struct ctrl_node *cn ) +{ + TRACE_FUNCTION_CALL; + + dbg_printf(cn, "%s=%d %s=%d %s=%d %s=%d %s=%d %s=%d %s=%d %s=%d\n", + ARG_UDPD_SIZE, pref_udpd_size, + ARG_TX_INTERVAL, my_tx_interval, + ARG_UNSOLICITED_DESC_ADVS, tx_unsolicited_desc, + ARG_DHS0_ADVS_TX_ITERS, dhash_tx_iters, + ARG_DSC0_ADVS_TX_ITERS, desc_tx_iters, + ARG_OGM_INTERVAL, my_ogm_interval, + ARG_OGM_TX_ITERS, ogm_tx_iters, + ARG_OGM_ACK_TX_ITERS, my_ogm_ack_tx_iters); }
+STATIC_FUNC +int32_t opt_show_descriptions(uint8_t cmd, uint8_t _save, struct opt_type *opt, struct opt_parent *patch, struct ctrl_node *cn) +{ + TRACE_FUNCTION_CALL; + + if ( cmd == OPT_APPLY ) { + + struct avl_node *an = NULL; + uint16_t count = 0; + struct orig_node *on; + struct list_node *list_pos; + char *name = NULL; + + int32_t filter = strtol(patch->p_val, NULL, 10); + + list_for_each( list_pos, &patch->childs_instance_list ) { + + struct opt_child *c = list_entry( list_pos, struct opt_child, list ); + + if (!strcmp(c->c_opt->long_name, ARG_DESCRIPTION_NAME)) { + + name = c->c_val; + + } else if ( !strcmp( c->c_opt->long_name, ARG_DESCRIPTION_IP ) ) { + + } + } + + + while ((on = avl_iterate_item(&orig_tree, &an))) { + + assertion(-500361, (!on || on->desc)); + + if (name && strcmp(name, on->desc->id.name)) + continue; + + dbg_printf(cn, "\nID.name=%-10s ID.rand=%s.. dhash=%s.. code=%-3d last_upd=%-4d last_ref=%-3d path_metric=%ju %s\n", + on->id.name, + memAsStr(((char*) &(on->id.rand)), 4), + memAsStr(((char*) &(on->dhn->dhash)), 4), + ntohs(on->desc->code_version), + (bmx_time - on->updated_timestamp) / 1000, + (bmx_time - on->dhn->referred_by_me_timestamp) / 1000, + on->curr_rn ? on->curr_rn->mr.umetric_final : 0, on->blocked ? "BLOCKED" : " "); + + process_description_tlvs(NULL, on, on->desc, TLV_OP_DEBUG, filter, cn); + count++; + } + + dbg_printf( cn, "\n" ); + } + return SUCCESS; +} +
-static struct opt_type msg_options[]= +STATIC_FUNC +struct opt_type msg_options[]= { // ord parent long_name shrt Attributes *ival min max default *func,*syntax,*help
{ODI, 0,0, 0, 5,0,0,0,0,0, 0, 0, 0, 0, 0, 0, "\nMessage options:"} -, - {ODI, 0, ARG_UDPD_SIZE, 0, 5, A_PS1, A_ADM, A_DYI, A_CFA, A_ANY, &max_udpd_size, MIN_UDPD_SIZE, MAX_UDPD_SIZE, DEF_UDPD_SIZE, 0, +#ifndef LESS_OPTIONS + , + {ODI, 0, ARG_UDPD_SIZE, 0, 5, A_PS1, A_ADM, A_DYI, A_CFA, A_ANY, &pref_udpd_size, MIN_UDPD_SIZE, MAX_UDPD_SIZE, DEF_UDPD_SIZE, 0, ARG_VALUE_FORM, "set preferred udp-data size for send packets"} -, - {ODI, 0, ARG_AGGREG_INTERVAL, 0, 5, A_PS1, A_ADM, A_DYI, A_CFA, A_ANY, &aggreg_interval, MIN_AGGREG_INTERVAL,MAX_AGGREG_INTERVAL,DEF_AGGREG_INTERVAL,0, - ARG_VALUE_FORM, "set aggregation interval (SHOULD be smaller than the half of your and others OGM interval)"} -, - {ODI, 0, ARG_OGM_RESEND_ATTEMPTS, 0, 5, A_PS1, A_ADM, A_DYI, A_CFA, A_ANY, &ogm_resend_attempts,MIN_OGM_RESEND_ATTEMPTS,MAX_OGM_RESEND_ATTEMPTS,DEF_OGM_RESEND_ATTEMPTS,0, + , + {ODI, 0, ARG_OGM_TX_ITERS, 0, 5, A_PS1, A_ADM, A_DYI, A_CFA, A_ANY, &ogm_tx_iters,MIN_OGM_TX_ITERS,MAX_OGM_TX_ITERS,DEF_OGM_TX_ITERS,0, ARG_VALUE_FORM, "set maximum resend attempts for ogm aggregations"} -, - {ODI, 0, ARG_HELLO_INTERVAL, 'O',5, A_PS1, A_ADM, A_DYI, A_CFA, A_ANY, &my_hello_interval,MIN_HELLO_INTERVAL, MAX_HELLO_INTERVAL, DEF_HELLO_INTERVAL, 0, - ARG_VALUE_FORM, "set interval in ms with which new originator message (OGM) are send"} -, - {ODI, 0, ARG_OGM_INTERVAL, 'o',5, A_PS1, A_ADM, A_DYI, A_CFA, A_ANY, &my_ogm_interval, MIN_OGM_INTERVAL, MAX_OGM_INTERVAL, DEF_OGM_INTERVAL, opt_update_description, - ARG_VALUE_FORM, "set interval in ms with which new originator message (OGM) are send"} + , + {ODI, 0, ARG_UNSOLICITED_DESC_ADVS,0, 5, A_PS1, A_ADM, A_DYI, A_CFA, A_ANY, &tx_unsolicited_desc,MIN_UNSOLICITED_DESC_ADVS,MAX_UNSOLICITED_DESC_ADVS,DEF_UNSOLICITED_DESC_ADVS,0, + ARG_VALUE_FORM, "send unsolicited description advertisements after receiving a new one"} + , + {ODI, 0, ARG_DSC0_REQS_TX_ITERS, 0, 5, A_PS1, A_ADM, A_DYI, A_CFA, A_ANY, &desc_req_tx_iters,MIN_DSC0_REQS_TX_ITERS,MAX_DSC0_REQS_TX_ITERS,DEF_DSC0_REQS_TX_ITERS,0, + ARG_VALUE_FORM, "set tx iterations for description requests"} + , + {ODI, 0, ARG_DHS0_REQS_TX_ITERS, 0, 5, A_PS1, A_ADM, A_DYI, A_CFA, A_ANY, &dhash_req_tx_iters,MIN_DHS0_REQS_TX_ITERS,MAX_DHS0_REQS_TX_ITERS,DEF_DHS0_REQS_TX_ITERS,0, + ARG_VALUE_FORM, "set tx iterations for description-hash requests"} + , + {ODI, 0, ARG_DSC0_ADVS_TX_ITERS, 0, 5, A_PS1, A_ADM, A_DYI, A_CFA, A_ANY, &desc_tx_iters,MIN_DSC0_ADVS_TX_ITERS,MAX_DSC0_ADVS_TX_ITERS,DEF_DSC0_ADVS_TX_ITERS,0, + ARG_VALUE_FORM, "set tx iterations for descriptions"} + , + {ODI, 0, ARG_DHS0_ADVS_TX_ITERS, 0, 5, A_PS1, A_ADM, A_DYI, A_CFA, A_ANY, &dhash_tx_iters,MIN_DHS0_ADVS_TX_ITERS,MAX_DHS0_ADVS_TX_ITERS,DEF_DHS0_ADVS_TX_ITERS,0, + ARG_VALUE_FORM, "set tx iterations for description hashes"} + , + {ODI, 0, ARG_OGM_ACK_TX_ITERS, 0, 5, A_PS1, A_ADM, A_DYI, A_CFA, A_ANY, &my_ogm_ack_tx_iters,MIN_OGM_ACK_TX_ITERS,MAX_OGM_ACK_TX_ITERS,DEF_OGM_ACK_TX_ITERS,0, + ARG_VALUE_FORM, "set tx iterations for ogm acknowledgements"} + , +#endif + {ODI, 0, ARG_DESCRIPTION_GREP, 0, 5, A_PMN, A_USR, A_DYN, A_ARG, A_ANY, 0, MIN_DESCRIPTION_GREP,MAX_DESCRIPTION_GREP,DEF_DESCRIPTION_GREP, opt_show_descriptions, + ARG_VALUE_FORM, "show descriptions of nodes\n"} + , + {ODI,ARG_DESCRIPTION_GREP,ARG_DESCRIPTION_NAME,'n',5,A_CS1,A_USR,A_DYN,A_ARG,A_ANY, 0, 0, 0,0, opt_show_descriptions, + "<NAME>", "only show description of nodes with given name"}
};
-void init_msg( void ) +STATIC_FUNC +int32_t init_msg( void ) { + paranoia( -500347, ( sizeof(struct description_hash) != HASH0_SHA1_LEN));
- paranoia( -500347, ( sizeof(struct description_hash) != BMX_HASH0_LEN)); + memset(description_tlv_handl, 0, sizeof(description_tlv_handl));
- ogm_aggreg_sqn_max = rand_num(MAX_SQN); + ogm_aggreg_sqn_max = ((AGGREG_SQN_MASK)&rand_num(AGGREG_SQN_MAX));
register_options_array( msg_options, sizeof( msg_options ) );
InitSha(&bmx_sha);
- register_task(rand_num(RAND_INIT_DELAY), schedule_my_originator_message, NULL); + register_task(my_ogm_interval, schedule_my_originator_message, NULL);
+ struct frame_handl handl; + + memset(&handl, 0, sizeof ( handl)); + handl.is_advertisement = 1; + handl.is_relevant = 1; + handl.min_msg_size = sizeof (struct msg_problem_adv); + handl.fixed_msg_size = 0; + handl.name = "PROBLEM_ADV"; + handl.tx_frame_handler = tx_frame_problem_adv; + handl.rx_frame_handler = rx_frame_problem_adv; + register_frame_handler(packet_frame_handler, FRAME_TYPE_PROBLEM_ADV, &handl); + + memset(&handl, 0, sizeof ( handl)); + handl.is_destination_specific_frame = 1; + handl.tx_iterations = &desc_req_tx_iters; + handl.umetric_rq_min = &UMETRIC_RQ_NBDISC_MIN; + handl.data_header_size = sizeof( struct hdr_description_request); + handl.min_msg_size = sizeof (struct msg_description_request); + handl.fixed_msg_size = 1; + handl.min_tx_interval = DEF_TX_DESC0_REQ_TO; + handl.name = "DESC_REQ"; + handl.tx_msg_handler = tx_msg_dhash_or_description_request; + handl.rx_msg_handler = rx_msg_dhash_or_description_request; + register_frame_handler(packet_frame_handler, FRAME_TYPE_DSC0_REQS, &handl); + + memset(&handl, 0, sizeof ( handl)); + handl.is_advertisement = 1; + handl.tx_iterations = &desc_tx_iters; + handl.umetric_rq_min = &UMETRIC_RQ_NBDISC_MIN; + handl.min_msg_size = sizeof (struct msg_description_adv); + handl.min_tx_interval = DEF_TX_DESC0_ADV_TO; + handl.name = "DESC_ADV"; + handl.tx_msg_handler = tx_msg_description_adv; + handl.rx_frame_handler = rx_frame_description_advs; + register_frame_handler(packet_frame_handler, FRAME_TYPE_DSC0_ADVS, &handl); + + memset(&handl, 0, sizeof ( handl)); + handl.is_destination_specific_frame = 1; + handl.tx_iterations = &dhash_req_tx_iters; + handl.umetric_rq_min = &UMETRIC_RQ_NBDISC_MIN; + handl.data_header_size = sizeof( struct hdr_dhash_request); + handl.min_msg_size = sizeof (struct msg_dhash_request); + handl.fixed_msg_size = 1; + handl.min_tx_interval = DEF_TX_DHASH0_REQ_TO; + handl.name = "DHASH_REQ"; + handl.tx_msg_handler = tx_msg_dhash_or_description_request; + handl.rx_msg_handler = rx_msg_dhash_or_description_request; + register_frame_handler(packet_frame_handler, FRAME_TYPE_DHS0_REQS, &handl); + + memset(&handl, 0, sizeof ( handl)); + handl.is_advertisement = 1; + handl.tx_iterations = &dhash_tx_iters; + handl.umetric_rq_min = &UMETRIC_RQ_NBDISC_MIN; + handl.min_msg_size = sizeof (struct msg_dhash_adv); + handl.fixed_msg_size = 1; + handl.min_tx_interval = DEF_TX_DHASH0_ADV_TO; + handl.name = "DHASH_ADV"; + handl.tx_msg_handler = tx_msg_dhash_adv; + handl.rx_msg_handler = rx_msg_dhash_adv; + register_frame_handler(packet_frame_handler, FRAME_TYPE_DHS0_ADVS, &handl); + + memset(&handl, 0, sizeof ( handl)); + handl.is_advertisement = 1; + handl.rx_requires_described_neigh_dhn = 0; + handl.min_msg_size = sizeof (struct msg_hello_adv); + handl.fixed_msg_size = 1; + handl.name = "HELLO_ADV"; + handl.tx_msg_handler = tx_msg_hello_adv; + handl.rx_msg_handler = rx_msg_hello_adv; + register_frame_handler(packet_frame_handler, FRAME_TYPE_HELLO_ADVS, &handl); + + memset(&handl, 0, sizeof ( handl)); + handl.rx_requires_described_neigh_dhn = 1; + handl.rx_requires_known_neighIID4me = NO; //otherwise I'll never ask for my neighIID4me + handl.min_msg_size = sizeof (struct msg_hello_reply); + handl.fixed_msg_size = 1; + handl.name = "HELLO_REPLY"; + handl.tx_msg_handler = tx_msg_hello_reply; + handl.rx_frame_handler = rx_frame_hello_replies; + register_frame_handler(packet_frame_handler, FRAME_TYPE_HELLO_REPS, &handl); + + memset(&handl, 0, sizeof ( handl)); + handl.is_advertisement = 1; + handl.rx_requires_described_neigh_dhn = 1; + handl.rx_requires_known_neighIID4me = 1; + handl.data_header_size = sizeof ( struct hdr_ogm_adv); + handl.min_msg_size = sizeof (struct msg_ogm_adv); + handl.fixed_msg_size = 1; + handl.name = "OGM_ADV"; + handl.tx_frame_handler = tx_frame_ogm_advs; + handl.rx_frame_handler = rx_frame_ogm_advs; + register_frame_handler(packet_frame_handler, FRAME_TYPE_OGM_ADVS, &handl); + + memset(&handl, 0, sizeof ( handl)); + handl.rx_requires_described_neigh_dhn = 1; + handl.rx_requires_known_neighIID4me = 1; + handl.tx_iterations = &my_ogm_ack_tx_iters; + handl.min_msg_size = sizeof (struct msg_ogm_ack); + handl.fixed_msg_size = 1; + handl.name = "OGM_ACK"; + handl.tx_msg_handler = tx_msg_ogm_ack; + handl.rx_frame_handler = rx_frame_ogm_acks; + register_frame_handler(packet_frame_handler, FRAME_TYPE_OGM_ACKS, &handl); + + return SUCCESS; }
+STATIC_FUNC void cleanup_msg( void ) { - schedule_and_purge_ogm_aggregations(NULL /*purge_all*/); + schedule_or_purge_ogm_aggregations(YES /*purge_all*/);
debugFree(get_best_lndevs_by_criteria(NULL, NULL), -300218);
purge_cached_descriptions(YES);
} + + +struct plugin *msg_get_plugin( void ) { + + static struct plugin msg_plugin; + memset( &msg_plugin, 0, sizeof ( struct plugin ) ); + + msg_plugin.plugin_name = "bmx6_msg_plugin"; + msg_plugin.plugin_size = sizeof ( struct plugin ); + msg_plugin.plugin_code_version = CODE_VERSION; + msg_plugin.cb_init = init_msg; + msg_plugin.cb_cleanup = cleanup_msg; + msg_plugin.cb_plugin_handler[PLUGIN_CB_STATUS] = (void (*) (void*)) dbg_msg_status; + + return &msg_plugin; +} diff --git a/msg.h b/msg.h index 3380263..cea6f63 100644 --- a/msg.h +++ b/msg.h @@ -1,6 +1,5 @@ /* - * Copyright (C) 2010 BMX contributors: - * Axel Neumann + * Copyright (c) 2010 Axel Neumann * 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. @@ -22,243 +21,408 @@ #include <linux/if.h>
-#define MIN_UDPD_SIZE 256 //(6+4+(22+8)+32)+184=72+56=128 -#define DEF_UDPD_SIZE 512 -#define MAX_UDPD_SIZE 1400 -#define ARG_UDPD_SIZE "udp_data_size"
-#define MIN_AGGREG_INTERVAL 35 -#define MAX_AGGREG_INTERVAL 4000 -#define DEF_AGGREG_INTERVAL 500 -#define ARG_AGGREG_INTERVAL "aggregation_interval" +#define MIN_UDPD_SIZE 128 //(6+4+(22+8)+32)+184=72+56=128 +#define DEF_UDPD_SIZE 512 +#define MAX_UDPD_SIZE (MIN( 1400, MAX_PACKET_SIZE)) +#define ARG_UDPD_SIZE "udp_data_size"
-#define ARG_HELLO_INTERVAL "hello_interval" -#define DEF_HELLO_INTERVAL DEF_AGGREG_INTERVAL -#define MIN_HELLO_INTERVAL 50 -#define MAX_HELLO_INTERVAL 10000 -extern int32_t my_hello_interval;
-#define ARG_OGM_INTERVAL "ogm_interval" -#define DEF_OGM_INTERVAL 2500 -#define MIN_OGM_INTERVAL 200 -#define MAX_OGM_INTERVAL 60000 -extern int32_t my_ogm_interval; +#define DEF_TX_TS_TREE_SIZE 150 +#define DEF_TX_TS_TREE_PURGE_FK 3
+#define DEF_DESC0_CACHE_SIZE 100 +#define DEF_DESC0_CACHE_TO 100000
-#define DEF_TX_TS_TREE_SIZE 100 -#define DEF_TX_TS_TREE_PURGE_FK 5
+#define MIN_UNSOLICITED_DESC_ADVS 0 +#define MAX_UNSOLICITED_DESC_ADVS 1 +#define DEF_UNSOLICITED_DESC_ADVS 1 +#define ARG_UNSOLICITED_DESC_ADVS "unsolicited_descriptions"
+#define MIN_DHS0_REQS_TX_ITERS 1 +#define MAX_DHS0_REQS_TX_ITERS 100 +#define DEF_DHS0_REQS_TX_ITERS 40 +#define ARG_DHS0_REQS_TX_ITERS "hash_req_sends"
-#define MIN_OGM_AGGREG_INTERVAL ( (MIN_AGGREG_INTERVAL / 3) * 2 ) -#define MAX_OGM_AGGREG_INTERVAL ( (MAX_AGGREG_INTERVAL / 3) * 2 ) -#define DEF_OGM_AGGREG_INTERVAL ( (DEF_AGGREG_INTERVAL / 3) * 2 ) +#define MIN_DSC0_REQS_TX_ITERS 1 +#define MAX_DSC0_REQS_TX_ITERS 100 +#define DEF_DSC0_REQS_TX_ITERS 40 +#define ARG_DSC0_REQS_TX_ITERS "desc_req_sends"
-#define MAX_OGM_RESEND_INTERVAL (MAX_AGGREG_INTERVAL * 2) -#define DEF_OGM_RESEND_INTERVAL ((DEF_AGGREG_INTERVAL * 2) / 3) +#define MIN_DHS0_ADVS_TX_ITERS 1 +#define MAX_DHS0_ADVS_TX_ITERS 100 +#define DEF_DHS0_ADVS_TX_ITERS 1 +#define ARG_DHS0_ADVS_TX_ITERS "hash_sends"
-#define MIN_OGM_RESEND_ATTEMPTS 0 -#define MAX_OGM_RESEND_ATTEMPTS 5 -#define DEF_OGM_RESEND_ATTEMPTS 2 -#define ARG_OGM_RESEND_ATTEMPTS "ogm_resend_attempts" +#define MIN_DSC0_ADVS_TX_ITERS 1 +#define MAX_DSC0_ADVS_TX_ITERS 20 +#define DEF_DSC0_ADVS_TX_ITERS 1 +#define ARG_DSC0_ADVS_TX_ITERS "desc_sends"
-#define MIN_NBDISC_RTQ (PROBE_RANGE / 8) -#define MIN_OGM_ACK_RTQ (PROBE_RANGE / 4) +#define MIN_OGM_TX_ITERS 0 +#define MAX_OGM_TX_ITERS 20 +#define DEF_OGM_TX_ITERS 4 +#define ARG_OGM_TX_ITERS "ogm_sends"
+#define DEF_OGM_ACK_TX_ITERS 1 +#define MIN_OGM_ACK_TX_ITERS 0 +#define MAX_OGM_ACK_TX_ITERS 4 +#define ARG_OGM_ACK_TX_ITERS "ogm_ack_sends"
//TODO: set REQ_TO to 1 (in a non-packet-loss testenvironment this may be set to 1000 for testing) -#define DEF_TX_DESC0_REQ_TO 1000 -#define DEF_TX_DESC0_ADV_TO 500 -#define DEF_TX_DHASH0_REQ_TO 1000 -#define DEF_TX_DHASH0_ADV_TO 500 +#define DEF_TX_DESC0_REQ_TO ((DEF_TX_INTERVAL*3)/2) +#define DEF_TX_DESC0_ADV_TO 200 +#define DEF_TX_DHASH0_REQ_TO ((DEF_TX_INTERVAL*3)/2) +#define DEF_TX_DHASH0_ADV_TO 200
#define MIN_DESC0_REFERRED_TO 10000 #define MAX_DESC0_REFERRED_TO 100000 #define DEF_DESC0_REFERRED_TO 10000
-#define MAX_PKT_MSG_SIZE (MAX_UDPD_SIZE - sizeof(struct packet_header) - sizeof(struct frame_header)) +#define DEF_DESC0_REQ_STONE_OLD_TO 40000 + +#define MAX_PKT_MSG_SIZE (MAX_UDPD_SIZE - sizeof(struct packet_header) - sizeof(struct frame_header_long))
#define MAX_DESC0_TLV_SIZE (MAX_PKT_MSG_SIZE - sizeof(struct msg_description_adv) )
-struct packet_header -{ - uint8_t bmx_version; - uint8_t bmx_capabilities; - uint16_t pkt_length; // the relevant data size in bytes (including the bmx_header) - uint16_t pkt_dev_sqn; - uint8_t pkt_data[]; // encapulating packet data tlvs +#define FRAME_TYPE_RSVD0 0 +#define FRAME_TYPE_RSVD1 1 +#define FRAME_TYPE_PROBLEM_ADV 2 // yet only used to indicate link_id collisions +#define FRAME_TYPE_DSC0_REQS 3 +#define FRAME_TYPE_DSC0_ADVS 4 // descriptions are send as individual advertisement frames ??? +#define FRAME_TYPE_RSVD5 5 +#define FRAME_TYPE_RSVD6 6 +#define FRAME_TYPE_DHS0_REQS 7 // Hash-for-description-of-OG-ID requests +#define FRAME_TYPE_DHS0_ADVS 8 // Hash-for-description-of-OG-ID advertisements +#define FRAME_TYPE_RSVD9 9 +#define FRAME_TYPE_RSVD10 10 +#define FRAME_TYPE_HELLO_ADVS 11 // most-simple BMX-NG hello (nb-discovery) advertisements +#define FRAME_TYPE_HELLO_REPS 12 // most-simple BMX-NG hello (nb-discovery) replies +#define FRAME_TYPE_RSVD13 13 +#define FRAME_TYPE_RSVD14 14 +#define FRAME_TYPE_OGM_ADVS 15 // most simple BMX-NG (type 0) OGM advertisements +#define FRAME_TYPE_OGM_ACKS 16 // most simple BMX-NG (type 0) OGM advertisements +#define FRAME_TYPE_NOP 17 +#define FRAME_TYPE_MAX (FRAME_TYPE_ARRSZ-1) + + +struct frame_header_short { // 2 bytes + +#if __BYTE_ORDER == __LITTLE_ENDIAN + unsigned int type : FRAME_TYPE_BIT_SIZE; + unsigned int is_relevant : FRAME_RELEVANCE_BIT_SIZE; + unsigned int is_short : FRAME_ISSHORT_BIT_SIZE; + +#elif __BYTE_ORDER == __BIG_ENDIAN + unsigned int is_short : FRAME_ISSHORT_BIT_SIZE; + unsigned int is_relevant : FRAME_RELEVANCE_BIT_SIZE; + unsigned int type : FRAME_TYPE_BIT_SIZE; +#else +# error "Please fix <bits/endian.h>" +#endif + uint8_t length_2B; // lenght of frame in 2-Byte steps, including frame_header and variable data field +// uint8_t data[]; // frame-type specific data consisting of 0-1 data headers and 1-n data messages } __attribute__((packed));
-#define FRAME_TYPE_RESERVED0 0 -#define FRAME_TYPE_RESERVED1 1 -#define FRAME_TYPE_HI40_ADVS 2 // most-simple BMX-NG hello (nb-discovery) advertisements -#define FRAME_TYPE_HI40_REPS 3 // most-simple BMX-NG hello (nb-discovery) replies -#define FRAME_TYPE_HI60_REPS 4 // -#define FRAME_TYPE_RESERVED4 5 // BMX_FRM_CRT0_REQS -#define FRAME_TYPE_RESERVED5 6 // BMX_FRM_CRT0_ADV -#define FRAME_TYPE_DSC0_REQS 7 // ... -#define FRAME_TYPE_DSC0_ADVS 8 // descriptions are send as individual advertisement frames -#define FRAME_TYPE_DHS0_REQS 9 // Hash-for-description-of-OG-ID requests -#define FRAME_TYPE_DHS0_ADVS 10 // Hash-for-description-of-OG-ID advertisements -#define FRAME_TYPE_OGM0_ADVS 11 // most simple BMX-NG (type 0) OGM advertisements -#define FRAME_TYPE_OGM0_ACKS 12 // most simple BMX-NG (type 0) OGM advertisements -#define FRAME_TYPE_NOP 13 -#define FRAME_TYPE_ARRSZ 14 -#define FRAME_TYPE_MAX 0xFF +struct frame_header_long { // 4 bytes +#if __BYTE_ORDER == __LITTLE_ENDIAN + unsigned int type : FRAME_TYPE_BIT_SIZE; + unsigned int is_relevant : FRAME_RELEVANCE_BIT_SIZE; + unsigned int is_short : FRAME_ISSHORT_BIT_SIZE; + +#elif __BYTE_ORDER == __BIG_ENDIAN + unsigned int is_short : FRAME_ISSHORT_BIT_SIZE; + unsigned int is_relevant : FRAME_RELEVANCE_BIT_SIZE; + unsigned int type : FRAME_TYPE_BIT_SIZE; +#else +# error "Please fix <bits/endian.h>" +#endif + uint8_t reserved; + uint16_t length_1B; // lenght of frame in 1-Byte steps, including frame_header and variable data field +// uint8_t data[]; // frame-type specific data consisting of 0-1 data headers and 1-n data messages +} __attribute__((packed)); + + + + + +#define SHORT_FRAME_DATA_MAX (MIN( 500, ((int)((((sizeof( ((struct frame_header_short*)NULL)->length_2B ))<<8)-1)*2)))) +
+// iterator return codes: +#define TLV_DATA_BLOCKED (-3) // blocked due to DAD, only returns from rx-iterations +#define TLV_DATA_FULL (-2) // nothing done! Frame finished or not enough remining data area to write + // only returns from tx-iterations, rx- will return FAILURE +#define TLV_DATA_FAILURE (-1) // syntax error: exit or blacklist + // only returns from rx-iterations, tx- will fail assertion() +#define TLV_TX_DATA_DONE (0) // done, nothing more to do +#define TLV_RX_DATA_DONE (0) // done, nothing more to do +#define TLV_TX_DATA_IGNORED (1) // unknown, filtered, nothing to send, or ignored due to bad link... +#define TLV_RX_DATA_IGNORED (1) // unknown, filtered, nothing to send, or ignored due to bad link... +#define TLV_DATA_PROCESSED (2) // >= means succesfully processed returned amount of data +#define TLV_DATA_STEPS (2) // legal data-size steps, never returns + // the smalles legal frame must be: + // - a multiple of two + // - have lenght of frame_header_short plus 2 bytes frame_data
+// rx_frame_iterator operation codes: +enum { + TLV_OP_DEL = 0, + TLV_OP_TEST = 1, + TLV_OP_ADD = 2, +// TLV_OP_DONE = 3, + TLV_OP_DEBUG = 4 +}; /* - * dhash0_adv or description0_adv specific frame flag - * firstIsSender flag is usefull to accelerate neighbor (and neighIID) discovery process - */ + * this iterator is given the beginning of a frame area (e.g. the end of the packet_header) + * then it iterates over the frames in that area */ +struct rx_frame_iterator { + // MUST be initialized: + // remains unchanged: + const char *caller; + struct packet_buff *pb; + struct orig_node *on; + struct ctrl_node *cn; + uint8_t *frames_in; + struct frame_handl *handls; + IDM_T op; + uint8_t process_filter; + uint8_t handl_max; + int32_t frames_length; + + // updated by rx..iterate(): + int32_t frames_pos; + + // set by rx..iterate(), and consumed by handl[].rx_tlv_handler + uint8_t is_short_header; + uint8_t frame_type; + int32_t frame_data_length; + uint8_t *frame_data; + uint8_t *msg; +}; + + +/* + * this iterator is given a fr_type and a set of handlers, + * then the handlers are supposed to figure out what needs to be done. + * finally the iterator writes ready-to-send frame_header and frame data to *fs_data */ +struct tx_frame_iterator { + // MUST be initialized: + // remains unchanged: + const char *caller; + struct list_head *tx_task_list; + struct tx_task_node *ttn; + + uint8_t *cache_data_array; + uint8_t *frames_out; + struct frame_handl *handls; + uint8_t handl_max; + int32_t frames_out_max; + + // updated by fs_caller(): + uint8_t frame_type; + + // updated by tx..iterate(): + int32_t frames_out_pos; + int32_t cache_msgs_size; + +//#define tx_iterator_cache_data_space( it ) (((it)->frames_out_max) - ((it)->frames_out_pos + (it)->cache_msg_pos + ((int)(sizeof (struct frame_header_long))))) +//#define tx_iterator_cache_hdr_ptr( it ) ((it)->cache_data_array) +//#define tx_iterator_cache_msg_ptr( it ) ((it)->cache_data_array + (it)->cache_msg_pos) +}; + + + +struct frame_handl { + uint8_t is_advertisement; // NO link information required for tx_frame_...(), dev is enough + uint8_t is_destination_specific_frame; // particularly: is NO advertisement + uint8_t is_relevant; // if set to ONE specifies: frame MUST BE processed or in case of unknown frame type, the + // whole super_frame MUST be dropped. If set to ZERO the frame can be ignored. + // if frame->is_relevant==1 and unknown and super_frame->is_relevant==1, then + // the whole super_frame MUST BE dropped as well. + // If irrelevant and unknown frames are rebroadcasted depends on the super_frame logic. + // i.e.: * unknown packet_frames MUST BE dropped. + // * unknown and irrelevant description_tlv_frames MUST BE propagated + uint8_t rx_requires_described_neigh_dhn; + uint8_t rx_requires_known_neighIID4me; + uint16_t data_header_size; + uint16_t min_msg_size; + uint16_t fixed_msg_size; + uint16_t min_tx_interval; + int32_t *tx_iterations; + UMETRIC_T *umetric_rq_min; + char *name; + + int32_t (*rx_frame_handler) (struct rx_frame_iterator *); + int32_t (*rx_msg_handler) (struct rx_frame_iterator *); + int32_t (*tx_frame_handler) (struct tx_frame_iterator *); + int32_t (*tx_msg_handler) (struct tx_frame_iterator *); +}; + + +static inline uint8_t * tx_iterator_cache_hdr_ptr(struct tx_frame_iterator *it) +{ + return it->cache_data_array; +} + +static inline uint8_t * tx_iterator_cache_msg_ptr(struct tx_frame_iterator *it) +{ + return it->cache_data_array + it->handls[it->frame_type].data_header_size + it->cache_msgs_size; +} + +static inline int32_t tx_iterator_cache_data_space(struct tx_frame_iterator *it) +{ + return it->frames_out_max - ( + it->frames_out_pos + + it->handls[it->frame_type].data_header_size + + it->cache_msgs_size + + (int) sizeof(struct frame_header_long)); +} +
-#define FRAME_FLAG_firstIsSender 0x01 // first message references transmitter of packet containing this message -#define FRAME_FLAGS_MAX 255
-struct frame_header { - uint8_t type; // frame type - uint8_t flags; // frame-type specific (8-bit) value containing flags or other data (e.g. sqn, mark,..) - uint16_t length; // lenght of frame including frame_header and variable data field - uint8_t data[]; // frame-type specific data consisting of 0-1 data headers and 0-n data messages +#define FRAME_TYPE_PROBLEM_CODE_MIN 0x01 +#define FRAME_TYPE_PROBLEM_CODE_DUP_LINK_ID 0x01 +#define FRAME_TYPE_PROBLEM_CODE_MAX 0x01 + + +struct msg_problem_adv { // 4 bytes + uint8_t code; + uint8_t reserved; + LINK_ID_T link_id; } __attribute__((packed));
-struct msg_hello_adv { - SQN_T hello_dev_sqn; + + + + +struct msg_hello_adv { // 2 bytes + HELLO_FLAGS_SQN_T hello_flags_sqn; } __attribute__((packed)); -/* - * reception trigger: - * - update_link_nodes() - * - msg_hellp40_reply[] - * - */
-struct msg_hello_reply { - IP4_T receiver_ip4; - SQN_T hello_dev_sqn; +struct msg_hello_reply { // 6 bytes + HELLO_FLAGS_SQN_T hello_flags_sqn; + IID_T transmitterIID4x; } __attribute__((packed)); -/* - * reception triggers: - * - update_link_nodes() - * - (if NOT link->neigh->dhash->orig) msg_dhash0_request[ ... orig_did = IID_RSVD_4YOU ] - * - */
-/* -struct hdr_dhash_request { - IP4_T receiver_ip4; + +struct msg_dhash_request { // 4 bytes + IID_T receiverIID4x; // IID_RSVD_4YOU to ask for neighbours' dhash0 } __attribute__((packed)); -*/ -struct msg_dhash_request { - IP4_T receiver_ip4; // dest_llip4; - IID_T receiverIID4x; //(orig_did) IID_RSVD_4YOU to ask for neighbours' dhash0 + +struct hdr_dhash_request { + LINK_ID_T destination_link_id; + struct msg_dhash_request msg[]; } __attribute__((packed)); -/* - * reception triggers: - * - msg_dhash0_adv[ ] - * - */
-struct msg_dhash_adv { - IID_T transmitterIID4x; //orig_sid +struct msg_dhash_adv { // 2 + X bytes + IID_T transmitterIID4x; struct description_hash dhash; } __attribute__((packed)); -/* - * reception triggers: - * - (if description is known AND is neighbor) creation of link <-> neigh <-> dhash <-> orig <-> description - * - (else if description is known ) creation of dhash <-> orig <-> description - * - (else) msg_description0_request[] - */
-struct msg_description_request { - IP4_T receiver_ip4; - IID_T receiverIID4x; //(orig_did) IID_RSVD_4YOU to ask for neighbours' description0 -} __attribute__((packed)); -/* - * reception triggers: - * - msg_description0_adv[] - * - */ +#define msg_description_request msg_dhash_request +#define hdr_description_request hdr_dhash_request
struct description { struct description_id id;
+ uint16_t code_version; uint16_t dsc_tlvs_len; - SQN_T dsc_sqn;
- SQN_T ogm_sqn_min; - SQN_T ogm_sqn_range; - uint8_t ogm_sqn_pq_bits; - uint8_t dsc_rsvd; + DESC_SQN_T dsc_sqn; + uint16_t capabilies;
- uint16_t path_ogi; + OGM_SQN_T ogm_sqn_min; + OGM_SQN_T ogm_sqn_range;
- uint16_t path_window_size; - uint16_t path_lounge_size; + uint16_t tx_interval;
- uint8_t path_hystere; uint8_t ttl_max; + uint8_t reserved1;
- uint8_t hop_penalty; - uint8_t late_penalty; - uint8_t asym_weight; - uint8_t sym_weight; - - uint16_t rsvd_u16; - uint32_t reserved[2]; //ensure traditional message size + uint32_t reserved[4]; //ensure traditional message size
// uint8_t tlv_frames[]; } __attribute__((packed));
-#define MSG_DESCRIPTION0_ADV_UNHASHED_SIZE 6 -#define MSG_DESCRIPTION0_ADV_HASHED_SIZE (sizeof( struct description_id) + (8 * 4)) +#define MSG_DESCRIPTION0_ADV_UNHASHED_SIZE 2 +#define MSG_DESCRIPTION0_ADV_HASHED_SIZE (sizeof( struct description_id) + (8 * sizeof(uint32_t))) #define MSG_DESCRIPTION0_ADV_SIZE (MSG_DESCRIPTION0_ADV_UNHASHED_SIZE + MSG_DESCRIPTION0_ADV_HASHED_SIZE)
struct msg_description_adv { // the unhashed part: IID_T transmitterIID4x; // orig_sid - uint8_t ttl; - uint8_t reserved0; - uint16_t reserved1;
// the hashed pard: struct description desc;
} __attribute__((packed)); -/* - * reception triggers: - * - creation of dhash_node <-> description_node - * - */
-#define MAX_OGMS_PER_AGGREG ( MIN((FRAME_FLAGS_MAX-1),((MIN_UDPD_SIZE - (sizeof(struct packet_header) + sizeof(struct frame_header))) / sizeof(struct msg_ogm_adv))) ) -#define MIN_OGMS_PER_AGGREG ( MAX_OGMS_PER_AGGREG / 8 ) -#define DEF_OGMS_PER_AGGREG ( MAX_OGMS_PER_AGGREG / 2 )
-//struct msg_ogm0_adv;
-struct msg_ogm_adv { - IID_T transmitterIID4x; //orig_sid - SQN_T orig_sqn; + + +#define OGM_JUMPS_PER_AGGREGATION 10 + +#define OGMS_PER_AGGREG_MAX \ + ( (pref_udpd_size - \ + (sizeof(struct packet_header) + sizeof(struct frame_header_long) + sizeof(struct hdr_ogm_adv) + \ + (OGM_JUMPS_PER_AGGREGATION * sizeof(struct msg_ogm_adv)) ) ) / \ + (sizeof(struct msg_ogm_adv)) ) + +#define OGMS_PER_AGGREG_PREF ( OGMS_PER_AGGREG_MAX / 2 ) + + + + +#define OGM_IID_RSVD_JUMP (OGM_IIDOFFST_MASK) // 63 //255 // resulting from ((2^transmitterIIDoffset_bit_range)-1) + + + +struct msg_ogm_adv // 4 bytes +{ + OGM_MIX_T mix; //uint16_t mix of transmitterIIDoffset, metric_exp, and metric_mant + +//#if __BYTE_ORDER == __LITTLE_ENDIAN +// unsigned int metric_mant : OGM_MANTISSA_BIT_SIZE; +// unsigned int metric_exp : OGM_EXPONENT_BIT_SIZE; +// unsigned int transmitterIIDoffset : IIDOFFSET_SIZE; +// +//#elif __BYTE_ORDER == __BIG_ENDIAN +// unsigned int transmitterIIDoffset : IIDOFFSET_SIZE; +// unsigned int metric_exp : OGM_EXPONENT_BIT_SIZE; +// unsigned int metric_mant : OGM_MANTISSA_BIT_SIZE; +//#else +//# error "Please fix <bits/endian.h>" +//#endif + + union { + OGM_SQN_T ogm_sqn; + IID_T transmitterIIDabsolute; + } u; + } __attribute__((packed));
-struct hdr_ogm_adv { - SQN_T aggregation_sqn; + +struct hdr_ogm_adv { // 2 bytes + AGGREG_SQN_T aggregation_sqn; struct msg_ogm_adv msg[]; } __attribute__((packed));
@@ -269,9 +433,8 @@ struct hdr_ogm_adv { */
struct msg_ogm_ack { -// IID_T transmitterIID4receiver; - IP4_T receiver_ip4; - SQN_T aggregation_sqn; + IID_T transmitterIID4x; + AGGREG_SQN_T aggregation_sqn; } __attribute__((packed)); /* * reception triggers: @@ -280,78 +443,58 @@ struct msg_ogm_ack { */
+#define BMX_DSC_TLV_METRIC 0x00 +#define BMX_DSC_TLV_UHNA4 0x01 +#define BMX_DSC_TLV_UHNA6 0x02 +#define BMX_DSC_TLV_MAX (FRAME_TYPE_ARRSZ-1) +#define BMX_DSC_TLV_ARRSZ FRAME_TYPE_ARRSZ
+#define DEF_DESCRIPTION_GREP 0 +#define MIN_DESCRIPTION_GREP 0 +#define MAX_DESCRIPTION_GREP FRAME_TYPE_PROCESS_ALL +#define ARG_DESCRIPTION_GREP "description"
-#define BMX_DSC_TLV_GLIP4 0x00 -#define BMX_DSC_TLV_UHNA4 0x01 -#define BMX_DSC_TLV_ARRSZ 0x02 -#define BMX_DSC_TLV_MAX 0xFF - -#define TLVS_SUCCESS SUCCESS -#define TLVS_FAILURE FAILURE -#define TLVS_BLOCKED 1 - -enum { - TLV_DEL_TEST_ADD = 0, - TLV_TEST = 1, - TLV_ADD = 2, - TLV_DONE = 3, - TLV_DEBUG = 4 -}; - - -struct description0_msg_ip4 { - IP4_T ip4; -} __attribute__((packed)); - -struct description0_msg_hna4 { - uint8_t prefix_len; - uint8_t reserved; - IP4_T ip4; - uint32_t metric; -} __attribute__((packed)); - - - +#define ARG_DESCRIPTION_NAME "name" +#define ARG_DESCRIPTION_IP "ip"
struct description_cache_node { struct description_hash dhash; - uint32_t timestamp; + TIME_T timestamp; struct description *description; };
-#define DEF_DESC0_CACHE_SIZE 3 -#define DEF_DESC0_CACHE_TO 100000 - -#define DEF_UNSOLICITED_DESCRIPTIONS YES +extern uint32_t ogm_aggreg_pending; +extern IID_T myIID4me; +extern TIME_T myIID4me_timestamp;
+extern struct frame_handl packet_frame_handler[FRAME_TYPE_ARRSZ]; +extern struct frame_handl description_tlv_handl[BMX_DSC_TLV_ARRSZ];
extern char *tlv_op_str[];
-extern uint32_t ogm_aggreg_pending;
/*********************************************************** The core frame/message structures and handlers ************************************************************/
-void update_my_description_adv( void );
+OGM_SQN_T set_ogmSqn_toBeSend_and_aggregated(struct orig_node *on, OGM_SQN_T to_be_send, OGM_SQN_T aggregated); +void update_my_description_adv( void ); +struct dhash_node * process_description(struct packet_buff *pb, struct description *desc, struct description_hash *dhash); +IDM_T process_description_tlvs(struct packet_buff *pb, struct orig_node *on, struct description *desc, IDM_T op, uint8_t filter, struct ctrl_node *cn); void purge_tx_timestamp_tree(struct dev_node *dev, IDM_T purge_all); -void purge_dev_tx_list( struct dev_node *dev ); - -void tx_packet( void* dev_node ); - -int rx_frames(struct packet_buff *pb, uint8_t* fdata, uint16_t fsize); - -void schedule_my_hello_message( void* dev_node ); - -IDM_T process_description_tlvs(struct orig_node *on, struct description *dsc_new, IDM_T op, struct ctrl_node *cn); +void purge_tx_task_list(struct list_head *tx_tasks_list, struct link_node *only_link, struct dev_node *only_dev);
-void init_msg( void ); +void tx_packets( void *unused ); +IDM_T rx_frames(struct packet_buff *pb); +int32_t rx_frame_iterate(struct rx_frame_iterator* it);
-void cleanup_msg( void ); +void schedule_tx_task(struct link_dev_node *lndev_out, + uint16_t type, uint16_t msgs_len, uint16_t u16, uint32_t u32, IID_T myIID4x, IID_T neighIID4x);
+void register_frame_handler(struct frame_handl *array, int pos, struct frame_handl *handl);
+struct plugin *msg_get_plugin( void ); diff --git a/plugin.c b/plugin.c index b071331..42a96fa 100644 --- a/plugin.c +++ b/plugin.c @@ -1,6 +1,5 @@ /* - * Copyright (C) 2010 BMX contributors: - * Axel Neumann + * Copyright (c) 2010 Axel Neumann * 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. @@ -23,21 +22,26 @@
#include "bmx.h" #include "msg.h" +#include "ip.h" #include "plugin.h" #include "schedule.h" -#include "hna.h" +#include "tools.h"
-LIST_SIMPEL(cb_fd_list, struct cb_fd_node, list); -static LIST_SIMPEL(cb_packet_list, struct cb_packet_node, list); -static LIST_SIMPEL(cb_ogm_list, struct cb_ogm_node, list); -static LIST_SIMPEL(plugin_list, struct plugin_node, list);
+static LIST_SIMPEL(plugin_list, struct plugin_node, list, list);
-int32_t plugin_data_registries[PLUGIN_DATA_SIZE];
+static LIST_SIMPEL(cb_route_change_list, struct cb_route_change_node, list, list); +static LIST_SIMPEL(cb_packet_list, struct cb_packet_node, list, list); +LIST_SIMPEL(cb_fd_list, struct cb_fd_node, list, list);
-void cb_plugin_hooks( void* data, int32_t cb_id ) { - + + +int32_t plugin_data_registries[PLUGIN_DATA_SIZE]; + +void cb_plugin_hooks(int32_t cb_id, void* data) +{ + TRACE_FUNCTION_CALL; struct list_node *list_pos; struct plugin_node *pn, *prev_pn = NULL; @@ -45,22 +49,21 @@ void cb_plugin_hooks( void* data, int32_t cb_id ) { pn = list_entry( list_pos, struct plugin_node, list ); - if ( prev_pn && prev_pn->plugin_v2 && prev_pn->plugin_v2->cb_plugin_handler[cb_id] ) - (*(prev_pn->plugin_v2->cb_plugin_handler[cb_id])) ( data ); + if ( prev_pn && prev_pn->plugin && prev_pn->plugin->cb_plugin_handler[cb_id] ) + (*(prev_pn->plugin->cb_plugin_handler[cb_id])) ( data ); prev_pn = pn; } - if ( prev_pn && prev_pn->plugin_v2 && prev_pn->plugin_v2->cb_plugin_handler[cb_id] ) - (*(prev_pn->plugin_v2->cb_plugin_handler[cb_id])) (data); + if ( prev_pn && prev_pn->plugin && prev_pn->plugin->cb_plugin_handler[cb_id] ) + ((*(prev_pn->plugin->cb_plugin_handler[cb_id])) (data)); }
- STATIC_FUNC -int32_t configure_thread_hook( int32_t cb_type, void (*cb_handler) (void), int8_t del, struct list_node *cb_list ) { - +void _set_thread_hook(int32_t cb_type, void (*cb_handler) (void), int8_t del, struct list_node *cb_list) +{ struct list_node *list_pos, *tmp_pos, *prev_pos = cb_list; struct cb_node *cbn; @@ -68,7 +71,7 @@ int32_t configure_thread_hook( int32_t cb_type, void (*cb_handler) (void), int8_ cleanup_all( -500143 ); } - list_for_each_safe( list_pos, tmp_pos, cb_list ) { + list_for_each_safe( list_pos, tmp_pos, (struct list_head*) cb_list ) { cbn = list_entry( list_pos, struct cb_node, list ); @@ -78,193 +81,123 @@ int32_t configure_thread_hook( int32_t cb_type, void (*cb_handler) (void), int8_
list_del_next(((struct list_head*) cb_list), prev_pos); debugFree( cbn, -300069 ); - return SUCCESS; + return; } else { cleanup_all( -500144 ); //dbgf( DBGL_SYS, DBGT_ERR, "cb_hook for cb_type %d and cb_handler already registered", cb_type ); - //return FAILURE; } } else { prev_pos = &cbn->list; - } - - } - - if ( del ) { - - cleanup_all( -500145 ); - return FAILURE; - - } else { - - cbn = debugMalloc( sizeof( struct cb_node), -300027 ); - memset( cbn, 0, sizeof( struct cb_node) ); - - cbn->cb_type = cb_type; - cbn->cb_handler = cb_handler; - list_add_tail(((struct list_head*) cb_list), &cbn->list); - - return SUCCESS; } -}
+ assertion(-500145, (!del));
+ cbn = debugMalloc(sizeof ( struct cb_node), -300027); + memset(cbn, 0, sizeof ( struct cb_node));
-int32_t set_fd_hook( int32_t fd, void (*cb_fd_handler) (int32_t fd), int8_t del ) { - - int32_t ret = configure_thread_hook( fd, (void (*) (void)) cb_fd_handler, del, (struct list_node*)&cb_fd_list ); - - change_selects(); - return ret; -} - + cbn->cb_type = cb_type; + cbn->cb_handler = cb_handler; + list_add_tail(((struct list_head*) cb_list), &cbn->list);
+}
-int32_t set_packet_hook( int32_t packet_type, void (*cb_packet_handler) (struct packet_buff *), int8_t del ) { - - return configure_thread_hook( packet_type, (void (*) (void)) cb_packet_handler, del, (struct list_node*)&cb_packet_list ); +void set_route_change_hooks(void (*cb_route_change_handler) (uint8_t del, struct orig_node *dest), uint8_t del) +{ + _set_thread_hook(1, (void (*) (void)) cb_route_change_handler, del, (struct list_node*) & cb_route_change_list); }
-//notify interested plugins of rcvd packet... +// notify interested plugins of a changed route... // THIS MAY CRASH when one plugin unregisteres two packet_hooks while being called with cb_packet_handler() -// TODO: find solution to prevent this ??? -uint32_t cb_packet_hooks( int32_t packet_type, struct packet_buff *pb ) { - +void cb_route_change_hooks(uint8_t del, struct orig_node *dest) +{ + TRACE_FUNCTION_CALL; struct list_node *list_pos; - struct cb_packet_node *cpn, *prev_cpn = NULL; - int calls = 0; - - list_for_each( list_pos, &cb_packet_list ) { - - cpn = list_entry( list_pos, struct cb_packet_node, list ); - - if ( prev_cpn && prev_cpn->packet_type == packet_type ) { - - (*(prev_cpn->cb_packet_handler)) (pb); - - calls++; - } - - prev_cpn = cpn; - - } - - if ( prev_cpn && prev_cpn->packet_type == packet_type ) - (*(prev_cpn->cb_packet_handler)) (pb); + struct cb_route_change_node *con, *prev_con = NULL;
- return calls; -} + assertion(-500674, (dest && dest->desc));
+ list_for_each( list_pos, &cb_route_change_list ) { + + con = list_entry( list_pos, struct cb_route_change_node, list ); + + if ( prev_con ) + (*(prev_con->cb_route_change_handler)) (del, dest); + + prev_con = con; + + } + + if (prev_con) + (*(prev_con->cb_route_change_handler)) (del, dest);
-int32_t set_ogm_hook( int32_t (*cb_ogm_handler) ( struct packet_buff *, uint16_t oCtx, struct router_node *old_router ), int8_t del ) { - - return configure_thread_hook( 1, (void (*) (void)) cb_ogm_handler, del, (struct list_node*)&cb_ogm_list ); }
+void set_packet_hook(void (*cb_packet_handler) (struct packet_buff *), int8_t del) +{ + _set_thread_hook(1, (void (*) (void)) cb_packet_handler, del, (struct list_node*) &cb_packet_list); +} + +void cb_packet_hooks(struct packet_buff *pb) +{ + TRACE_FUNCTION_CALL;
-int32_t cb_ogm_hooks( struct packet_buff *pb, uint16_t oCtx, struct router_node *old_router ) { - - struct list_node *list_pos; - struct cb_ogm_node *con, *prev_con = NULL; - - list_for_each( list_pos, &cb_ogm_list ) { - - con = list_entry( list_pos, struct cb_ogm_node, list ); - - if ( prev_con ) { - - if ( ((*(prev_con->cb_ogm_handler)) (pb, oCtx, old_router)) == CB_OGM_REJECT ) { - - return CB_OGM_REJECT; - } - - } - - prev_con = con; - - } - - if ( prev_con ) { - - if ( ((*(prev_con->cb_ogm_handler)) (pb, oCtx, old_router)) == FAILURE ) { - - return CB_OGM_REJECT; - } - - } + struct cb_packet_node *cpn, *prev_cpn = NULL;
- return CB_OGM_ACCEPT; -} + list_for_each( list_pos, &cb_packet_list ) {
+ cpn = list_entry( list_pos, struct cb_packet_node, list );
-#ifdef BMX2_TODO -int32_t set_snd_ext_hook( uint16_t ext_type, int32_t (*cb_snd_ext_handler) ( unsigned char* ext_buff ), int8_t del ) { - - static uint8_t initialized = NO; - - if ( !initialized ) { - memset( &snd_ext_hooks[0], 0, sizeof( snd_ext_hooks ) ); - initialized = YES; - } + if (prev_cpn) {
- if ( ext_type > EXT_TYPE_MAX ) - return FAILURE; - - if ( del && snd_ext_hooks[ext_type].cb_snd_ext_handler == cb_snd_ext_handler ) { - - snd_ext_hooks[ext_type].cb_snd_ext_handler = NULL; - return SUCCESS; - - } else if ( !del && snd_ext_hooks[ext_type].cb_snd_ext_handler == NULL ) { - - snd_ext_hooks[ext_type].cb_snd_ext_handler = cb_snd_ext_handler; - return SUCCESS; - } - - return FAILURE; -} + (*(prev_cpn->cb_packet_handler)) (pb);
-int32_t cb_snd_ext_hook( uint16_t ext_type, unsigned char* ext_buff ) { - - if ( snd_ext_hooks[ext_type].cb_snd_ext_handler ) - return ((*(snd_ext_hooks[ext_type].cb_snd_ext_handler))( ext_buff )); - - else - return SUCCESS; + } + + prev_cpn = cpn; + + } + + if (prev_cpn) + (*(prev_cpn->cb_packet_handler)) (pb);
}
-#endif +void set_fd_hook( int32_t fd, void (*cb_fd_handler) (int32_t fd), int8_t del ) {
+ _set_thread_hook(fd, (void (*) (void)) cb_fd_handler, del, (struct list_node*) & cb_fd_list); + + change_selects(); +}
-int32_t reg_plugin_data( uint8_t data_type ) { +int32_t get_plugin_data_registry(uint8_t data_type) +{ + TRACE_FUNCTION_CALL; - static int initialized = NO; + static int is_plugin_data_initialized = NO; - if ( !initialized ) { + if ( !is_plugin_data_initialized ) { memset( plugin_data_registries, 0, sizeof( plugin_data_registries ) ); - initialized=YES; + is_plugin_data_initialized=YES; } - if ( on_the_fly || data_type >= PLUGIN_DATA_SIZE ) + if ( !initializing || data_type >= PLUGIN_DATA_SIZE ) return FAILURE; // do NOT return the incremented value! - plugin_data_registries[data_type]++; - - return (plugin_data_registries[data_type] - 1); + return (((plugin_data_registries[data_type])++)); }
-#ifdef WITHUNUSED -void **get_plugin_data( void *data, uint8_t data_type, int32_t registry ) { +void **get_plugin_data(void *data, uint8_t data_type, int32_t registry) +{ + TRACE_FUNCTION_CALL; if ( data_type >= PLUGIN_DATA_SIZE || registry > plugin_data_registries[data_type] ) { cleanup_all( -500145 ); @@ -274,10 +207,17 @@ void **get_plugin_data( void *data, uint8_t data_type, int32_t registry ) { if ( data_type == PLUGIN_DATA_ORIG ) return &(((struct orig_node*)data)->plugin_data[registry]); + + if ( data_type == PLUGIN_DATA_DEV ) + return &(((struct dev_node*)data)->plugin_data[registry]); return NULL; } -#endif + + + + +
STATIC_FUNC int is_plugin_active( void *plugin ) { @@ -294,64 +234,49 @@ int is_plugin_active( void *plugin ) { return NO; }
-STATIC_FUNC -int activate_plugin( void *p, int32_t version, void *dlhandle, const char *dl_name ) { - - if ( p == NULL || version != PLUGIN_VERSION_02 ) - return FAILURE; + +int activate_plugin(struct plugin *p, void *dlhandle, const char *dl_name) +{ + + if (p == NULL) + return SUCCESS; if ( is_plugin_active( p ) ) return FAILURE; - - if ( version == PLUGIN_VERSION_02 ) { - - struct plugin_v2 *pv1 = (struct plugin_v2*)p;
- if (pv1->plugin_size != sizeof ( struct plugin_v2) || - strcmp(pv1->plugin_bmx_version, SOURCE_VERSION) || - (pv1->plugin_bmx_revision != REVISION_VERSION)) { + if (p->plugin_size != sizeof ( struct plugin) || (p->plugin_code_version != CODE_VERSION)) {
- dbgf( DBGL_SYS, DBGT_ERR, - "plugin with unexpected size %d != %lu, version %s != %s, revision %d != %d", - pv1->plugin_size, sizeof ( struct plugin_v2), - pv1->plugin_bmx_version, SOURCE_VERSION, - pv1->plugin_bmx_revision, REVISION_VERSION - ); + dbgf(DBGL_SYS, DBGT_ERR, + "plugin with unexpected size %d != %zu, revision %d != %d", + p->plugin_size, sizeof ( struct plugin), p->plugin_code_version, CODE_VERSION);
- return FAILURE; - } - - - if ( pv1->cb_init == NULL || ((*( pv1->cb_init )) ()) == FAILURE ) { - - dbg( DBGL_SYS, DBGT_ERR, "could not init plugin"); - return FAILURE; - } - - struct plugin_node *pn = debugMalloc( sizeof( struct plugin_node), -300028); - memset( pn, 0, sizeof( struct plugin_node) ); - - pn->version = PLUGIN_VERSION_02; - pn->plugin_v2 = pv1; - pn->plugin = p; - pn->dlhandle = dlhandle; + return FAILURE; + }
- list_add_tail(&plugin_list, &pn->list); - - dbgf_all( DBGT_INFO, "%s SUCCESS", pn->plugin_v2->plugin_name );
- if ( dl_name ) { - pn->dlname = debugMalloc( strlen(dl_name)+1, -300029 ); - strcpy( pn->dlname, dl_name ); - } - - return SUCCESS; - - } - - return FAILURE; - + if ( p->cb_init == NULL || ((*( p->cb_init )) ()) == FAILURE ) { + + dbg( DBGL_SYS, DBGT_ERR, "could not init plugin"); + return FAILURE; + } + + struct plugin_node *pn = debugMalloc( sizeof( struct plugin_node), -300028); + memset( pn, 0, sizeof( struct plugin_node) ); + + pn->plugin = p; + pn->dlhandle = dlhandle; + + list_add_tail(&plugin_list, &pn->list); + + dbgf_all( DBGT_INFO, "%s SUCCESS", pn->plugin->plugin_name ); + + if ( dl_name ) { + pn->dlname = debugMalloc( strlen(dl_name)+1, -300029 ); + strcpy( pn->dlname, dl_name ); + } + + return SUCCESS; }
STATIC_FUNC @@ -371,13 +296,10 @@ void deactivate_plugin( void *p ) {
list_del_next(&plugin_list, prev_pos); - if ( pn->version != PLUGIN_VERSION_02 ) - cleanup_all( -500098 ); + dbg( DBGL_CHANGES, DBGT_INFO, "deactivating plugin %s", pn->plugin->plugin_name ); - dbg( DBGL_CHANGES, DBGT_INFO, "deactivating plugin %s", pn->plugin_v2->plugin_name ); - - if ( pn->plugin_v2->cb_cleanup ) - (*( pn->plugin_v2->cb_cleanup )) (); + if ( pn->plugin->cb_cleanup ) + (*( pn->plugin->cb_cleanup )) (); if ( pn->dlname) @@ -395,13 +317,14 @@ void deactivate_plugin( void *p ) {
}
+#ifndef NO_DYN_PLUGIN STATIC_FUNC int8_t activate_dyn_plugin( const char* name ) { - struct plugin_v2* (*get_plugin_v2) ( void ) = NULL; + struct plugin* (*get_plugin) ( void ) = NULL; void *dlhandle; - struct plugin_v2 *pv1; + struct plugin *pv1; char dl_path[1000]; char *My_libs = getenv(BMX_ENV_LIB_PATH); @@ -443,24 +366,24 @@ int8_t activate_dyn_plugin( const char* name ) { dbgf_all( DBGT_INFO, "survived dlopen()!" );
- typedef struct plugin_v2* (*sdl_init_function_type) ( void ); + typedef struct plugin* (*sdl_init_function_type) ( void );
union { sdl_init_function_type func; void * obj; } alias;
- alias.obj = dlsym( dlhandle, "get_plugin_v2"); + alias.obj = dlsym( dlhandle, "get_plugin");
- if ( !( get_plugin_v2 = alias.func ) ) { + if ( !( get_plugin = alias.func ) ) { dbgf( DBGL_SYS, DBGT_ERR, "dlsym( %s ) failed: %s", name, dlerror() ); return FAILURE; }
- if ( !(pv1 = get_plugin_v2()) ) { + if ( !(pv1 = get_plugin()) ) {
- dbgf( DBGL_SYS, DBGT_ERR, "get_plugin_v2( %s ) failed", name ); + dbgf( DBGL_SYS, DBGT_ERR, "get_plugin( %s ) failed", name ); return FAILURE; } @@ -468,11 +391,11 @@ int8_t activate_dyn_plugin( const char* name ) { if ( is_plugin_active( pv1 ) ) return SUCCESS; - - if ( activate_plugin( pv1, PLUGIN_VERSION_02, dlhandle, name ) == FAILURE ) { - - dbgf( DBGL_SYS, DBGT_ERR, "activate_plugin( %s ) failed", dl_path ); - return FAILURE; + + if (activate_plugin(pv1, dlhandle, name) == FAILURE) { + + dbgf(DBGL_SYS, DBGT_ERR, "activate_plugin( %s ) failed", dl_path); + return FAILURE; } @@ -483,6 +406,7 @@ int8_t activate_dyn_plugin( const char* name ) { return SUCCESS; }
+ STATIC_FUNC int32_t opt_plugin ( uint8_t cmd, uint8_t _save, struct opt_type *opt, struct opt_parent *patch, struct ctrl_node *cn ) { @@ -518,49 +442,32 @@ static struct opt_type plugin_options[]= //order> config-file order to be loaded by config file, order < ARG_CONNECT oder to appera first in help text {ODI,0,ARG_PLUGIN, 0, 2,A_PMN,A_ADM,A_INI,A_CFA,A_ANY, 0, 0, 0, 0, opt_plugin, ARG_FILE_FORM, "load plugin. "ARG_FILE_FORM" must be in LD_LIBRARY_PATH or " BMX_ENV_LIB_PATH - "\n path (e.g. --plugin bmx_howto_plugin.so )\n"} + "\n path (e.g. --plugin bmx6_howto_plugin.so )\n"} }; +#endif
- -void init_plugin( void ) { +IDM_T init_plugin(void) +{
// set_snd_ext_hook( 0, NULL, YES ); //ensure correct initialization of extension hooks - reg_plugin_data( PLUGIN_DATA_SIZE );// ensure correct initialization of plugin_data - - struct plugin_v2 *pv1; +// reg_plugin_data( PLUGIN_DATA_SIZE );// ensure correct initialization of plugin_data - pv1=NULL; + struct plugin *p; + p=NULL + ; +#ifndef NO_DYN_PLUGIN // first try loading config plugin, if succesfull, continue loading optinal plugins depending on config - activate_dyn_plugin( BMX_LIB_UCI_CONFIG ); - - register_options_array( plugin_options, sizeof( plugin_options ) ); + activate_dyn_plugin( BMX_LIB_CONFIG );
- - if ( (pv1 = hna_get_plugin_v2()) != NULL ) - activate_plugin( pv1, PLUGIN_VERSION_02, NULL, NULL ); - - -#ifdef BMX2_TODO -#ifndef NOVIS - if ( (pv1 = vis_get_plugin_v1()) != NULL ) - activate_plugin( pv1, PLUGIN_VERSION_02, NULL, NULL ); -#endif - -#ifndef NOTUNNEL - if ( (pv1 = tun_get_plugin_v1()) != NULL ) - activate_plugin( pv1, PLUGIN_VERSION_02, NULL, NULL ); -#endif - -#ifndef NOSRV - if ( (pv1 = srv_get_plugin_v1()) != NULL ) - activate_plugin( pv1, PLUGIN_VERSION_02, NULL, NULL ); + register_options_array( plugin_options, sizeof( plugin_options ) ); #endif
-#endif + return SUCCESS; }
+ void cleanup_plugin( void ) {
while ( !LIST_EMPTY( &plugin_list ) ) diff --git a/plugin.h b/plugin.h index 9c24b9e..743bd62 100644 --- a/plugin.h +++ b/plugin.h @@ -1,6 +1,5 @@ /* - * Copyright (C) 2010 BMX contributors: - * Axel Neumann + * Copyright (c) 2010 Axel Neumann * 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. @@ -16,147 +15,122 @@ * 02110-1301, USA */
-#define PLUGIN_VERSION_02 0x02 -#define BMX_LIB_UCI_CONFIG "bmx_uci_config.so" +#define BMX_LIB_CONFIG "bmx6_config.so"
#define ARG_PLUGIN "plugin"
-extern struct list_head cb_fd_list; -
+//for config and rareley used hooks:
enum { - PLUGIN_CB_CONF, - PLUGIN_CB_ORIG_CREATE, - PLUGIN_CB_ORIG_FLUSH, - PLUGIN_CB_ORIG_DESTROY, - PLUGIN_CB_TERM, - PLUGIN_CB_SIZE + PLUGIN_CB_STATUS, + PLUGIN_CB_CONF, + PLUGIN_CB_DEV_EVENT, + PLUGIN_CB_ORIG_CREATE, + PLUGIN_CB_ORIG_FLUSH, + PLUGIN_CB_ORIG_DESTROY, + PLUGIN_CB_LINK_CREATE, + PLUGIN_CB_LINK_DESTROY, + PLUGIN_CB_LINKDEV_CREATE, + PLUGIN_CB_LINKDEV_DESTROY, + PLUGIN_CB_TERM, + PLUGIN_CB_SIZE };
-struct plugin_v2 { - uint32_t plugin_version; - uint32_t plugin_size; - uint32_t plugin_bmx_revision; - char *plugin_bmx_version; - char *plugin_name; - int32_t (*cb_init) ( void ); - void (*cb_cleanup) ( void ); +void cb_plugin_hooks(int32_t cb_id, void* data);
- //some more advanced (rarely called) callbacks hooks - void (*cb_plugin_handler[PLUGIN_CB_SIZE]) (void*); - - //some other attributes - uint8_t link_flags;
-};
+//for registering data hooks (attaching plugin data to bmx data structures)
-struct plugin_node { - struct list_node list; - int32_t version; - void *plugin; - struct plugin_v2 *plugin_v2; - void *dlhandle; - char *dlname; +enum { + PLUGIN_DATA_ORIG, + PLUGIN_DATA_DEV, + PLUGIN_DATA_SIZE };
-struct cb_ogm_node { - struct list_node list; - int32_t cb_type; - int32_t (*cb_ogm_handler) ( struct packet_buff *, uint16_t oCtx, struct router_node *old_router ); -}; +extern int32_t plugin_data_registries[PLUGIN_DATA_SIZE];
-struct cb_fd_node { - struct list_node list; - int32_t fd; - void (*cb_fd_handler) (int32_t fd); -}; +int32_t get_plugin_data_registry( uint8_t data_type ); + +void **get_plugin_data( void *data, uint8_t data_type, int32_t registry ); +
-struct cb_packet_node { - struct list_node list; - int32_t packet_type; - void (*cb_packet_handler) (struct packet_buff *); -};
+ +// for registering thread hooks (often and fast-to-be-done hooks) struct cb_node { struct list_node list; int32_t cb_type; void (*cb_handler) ( void ); };
- - -struct cb_snd_ext { - int32_t (*cb_snd_ext_handler) ( unsigned char* ext_buff ); +struct cb_fd_node { + struct list_node list; + int32_t fd; + void (*cb_fd_handler) (int32_t fd); };
- +extern struct list_head cb_fd_list; // cb_fd_handler is called when fd received data // called function may remove itself -int32_t set_fd_hook( int32_t fd, void (*cb_fd_handler) (int32_t fd), int8_t del ); +void set_fd_hook( int32_t fd, void (*cb_fd_handler) (int32_t fd), int8_t del );
-int32_t set_packet_hook( int32_t packet_type, void (*cb_packet_handler) (struct packet_buff *), int8_t del );
-#define CB_OGM_ACCEPT 0 -#define CB_OGM_REJECT -1 - -/* -enum cb_ogm_t { - CB_OGM_ACCEPT, - CB_OGM_REJECT +struct cb_route_change_node { + struct list_node list; + int32_t cb_type; + void (*cb_route_change_handler) (uint8_t del, struct orig_node * dest); }; -*/
-// only one cb_ogm_hook per plugin -int32_t set_ogm_hook( int32_t (*cb_ogm_handler) ( struct packet_buff *, uint16_t oCtx, struct router_node *old_router ), int8_t del ); +void set_route_change_hooks(void (*cb_route_change_handler) (uint8_t del, struct orig_node *dest), uint8_t del); +void cb_route_change_hooks(uint8_t del, struct orig_node *dest);
-//int32_t set_snd_ext_hook( uint16_t ext_type, int32_t (*cb_snd_ext_handler) ( unsigned char* ext_buff ), int8_t del );
- -//for registering data hooks: - -enum { - PLUGIN_DATA_ORIG, - PLUGIN_DATA_SIZE +struct cb_packet_node { + struct list_node list; + int32_t packet_type; + void (*cb_packet_handler) (struct packet_buff *); };
-extern int32_t plugin_data_registries[PLUGIN_DATA_SIZE]; -
-int32_t reg_plugin_data( uint8_t data_type ); +void set_packet_hook(void (*cb_packet_handler) (struct packet_buff *), int8_t del); +void cb_packet_hooks(struct packet_buff *pb);
-#ifdef WITHUNUSED -void **get_plugin_data( void *data, uint8_t data_type, int32_t registry ); -#endif
-/************************************** - *to be used by bmx sceleton... - */ -void init_plugin( void ); -void cleanup_plugin( void ); +// for initializing:
+struct plugin { + uint32_t plugin_code_version; + uint32_t plugin_size; + char *plugin_name; + int32_t (*cb_init) ( void ); + void (*cb_cleanup) ( void ); + //some more advanced (rarely called) callbacks hooks + void (*cb_plugin_handler[PLUGIN_CB_SIZE]) (void*);
-//void cb_config_hooks( void ); -void cb_plugin_hooks( void* data, int32_t cb_id ); +};
-//returns number of called packet hooks for this packet_type -uint32_t cb_packet_hooks( int32_t packet_type, struct packet_buff *pb );
-//return value FAILURE means that ogm or extension header is inacceptible and must be dropped ! -int32_t cb_ogm_hooks( struct packet_buff *pb, uint16_t oCtx, struct router_node *old_router ); +struct plugin_node { + struct list_node list; + struct plugin *plugin; + void *dlhandle; + char *dlname; +};
-int32_t cb_snd_ext_hook( uint16_t ext_type, unsigned char* ext_buff );
-// use void change_selects( void ) to trigger cb_fd_handler() +int activate_plugin(struct plugin *p, void *dlhandle, const char *dl_name);
+IDM_T init_plugin(void); +void cleanup_plugin( void );
diff --git a/route.c b/route.c deleted file mode 100644 index c94d4c7..0000000 --- a/route.c +++ /dev/null @@ -1,2218 +0,0 @@ -/* - * Copyright (C) 2006 BATMAN/BMX contributors: - * Marek Lindner, Thomas Lopatic, Axel Neumann - * 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 <stdio.h> -#include <string.h> -#include <fcntl.h> -#include <sys/ioctl.h> -#include <stdlib.h> -#include <arpa/inet.h> /* inet_ntop() */ -#include <errno.h> -#include <unistd.h> /* close() */ -#include <linux/if.h> /* ifr_if, ifr_tun */ -#include <linux/netlink.h> -#include <linux/rtnetlink.h> -#include <sys/ioctl.h> -#include <sys/socket.h> - -//from linux/wireless.h -#define SIOCGIWNAME 0x8B01 /* get name == wireless protocol */ - -#include "bmx.h" -#include "msg.h" -#include "plugin.h" -#include "schedule.h" -#include "route.h" - - - - -int32_t base_port = DEF_BASE_PORT; - - -#define ARG_RT_TABLE "rt_table_offset" -#define DEF_RT_TABLE 64 -#define MIN_RT_TABLE 0 -#define MAX_RT_TABLE 254 -#define RT_TABLE_HOSTS_OFFS 0 -#define RT_TABLE_NETS_OFFS 1 -#define RT_TABLE_TUNS_OFFS 2 -#define RT_TABLE_MAX_OFFS 2 -static int32_t Rt_table = DEF_RT_TABLE; - - -#define ARG_RT_PRIO "prio_rules_offset" -#define MIN_RT_PRIO 3 -#define MAX_RT_PRIO 32765 -#define DEF_RT_PRIO 6400 -#define RT_PRIO_HOSTS (Rt_prio + 0) -#define RT_PRIO_NETWORKS (Rt_prio + 1) -#define RT_PRIO_TUNNEL (Rt_prio + 2) -static int32_t Rt_prio = DEF_RT_PRIO; - - - -#define ARG_PRIO_RULES "prio_rules" -#define ARG_THROW_RULES "throw_rules" -#define ARG_NO_POLICY_RT "no_policy_routing" -#define ARG_PEDANTIC_CLEANUP "pedantic_cleanup" - -#define DEF_PRIO_RULES 1 -static int32_t prio_rules = DEF_PRIO_RULES; - -#define DEF_THROW_RULES 1 -static int32_t throw_rules = DEF_THROW_RULES; - -#define DEF_PEDANT_CLNUP NO -static int32_t Pedantic_cleanup = DEF_PEDANT_CLNUP; - -#define DEF_LO_RULE 1 -static int32_t Lo_rule = DEF_LO_RULE; - -static uint8_t touched_systen_config = NO; - -static int nl_sk = -1; -static int flush_sk = -1; - -static int rt_sock = 0; - - -static int32_t forward_orig=-1, if_rp_filter_all_orig=-1, if_rp_filter_default_orig=-1, if_send_redirects_all_orig=-1, if_send_redirects_default_orig=-1; - -static LIST_SIMPEL( rules_list, struct rules_node, list ); -static LIST_SIMPEL( routes_list, struct routes_node, list ); -static LIST_SIMPEL( throw_list, struct throw_node, list ); - -uint8_t if_conf_soft_changed = NO; // temporary enabled to trigger changed interface configuration -uint8_t if_conf_hard_changed = NO; // temporary enabled to trigger changed interface configuration - - -int Mtu_min = MAX_MTU; - - - -static struct { - struct nlmsghdr nlh; - struct rtmsg rtm; - char buff[ 256 ]; -} req; - -STATIC_FUNC -void add_rtattr(int rta_type, char *data, int data_len) -{ - - struct rtattr *rta = (struct rtattr *)(((char *) &req) + NLMSG_ALIGN(req.nlh.nlmsg_len)); - - req.nlh.nlmsg_len = NLMSG_ALIGN( req.nlh.nlmsg_len ) + RTA_LENGTH(data_len); - - paranoia( -50173, (NLMSG_ALIGN( req.nlh.nlmsg_len ) > sizeof( req )) ); - // if this fails then double req buff size !! - - rta->rta_type = rta_type; - rta->rta_len = RTA_LENGTH(data_len); - memcpy( RTA_DATA(rta), data, data_len ); -} - -STATIC_FUNC -char *rt2str( uint8_t t ) { - if ( t == RTN_UNICAST ) - return "RTN_UNICAST"; - else if ( t == RTN_THROW ) - return "RTN_THROW "; - - return "RTN_ILLEGAL"; -} - - -STATIC_FUNC -char *trackt2str( uint8_t t ) { - if ( t == TRACK_NO ) - return "TRACK_NO"; - else if ( t == TRACK_STANDARD ) - return "TRACK_STANDARD"; - else if ( t == TRACK_MY_HNA ) - return "TRACK_MY_HNA"; - else if ( t == TRACK_MY_HNA ) - return "TRACK_MY_NET"; - else if ( t == TRACK_MY_NET ) - return "TRACK_MY_HNA"; - else if ( t == TRACK_OTHER_HOST ) - return "TRACK_OTHER_HOST"; - else if ( t == TRACK_OTHER_HNA ) - return "TRACK_OTHER_HNA"; - else if ( t == TRACK_TUNNEL ) - - return "TRACK_TUNNEL"; - - return "TRACK_ILLEGAL"; -} - - - -STATIC_FUNC -int open_netlink_socket( void ) { - - int sock = 0; - if ( ( sock = socket( AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE ) ) < 0 ) { - - dbg( DBGL_SYS, DBGT_ERR, "can't create netlink socket for routing table manipulation: %s", - strerror(errno) ); - - return -1; - - } - - - if ( fcntl( sock, F_SETFL, O_NONBLOCK) < 0 ) { - - dbg( DBGL_SYS, DBGT_ERR, "can't set netlink socket nonblocking : (%s)", strerror(errno)); - close(sock); - return -1; - } - - return sock; - -} - - -STATIC_FUNC -int rt_macro_to_table( int rt_macro ) { - - dbgf_all( DBGT_INFO, "rt_macro %d", rt_macro ); - - if ( rt_macro == RT_TABLE_HOSTS ) - return Rt_table + RT_TABLE_HOSTS_OFFS; - - else if ( rt_macro == RT_TABLE_NETWORKS ) - return Rt_table + RT_TABLE_NETS_OFFS; - - else if ( rt_macro == RT_TABLE_TUNNEL ) - return Rt_table + RT_TABLE_TUNS_OFFS; - - else if ( rt_macro > MAX_RT_TABLE ) - cleanup_all( -500170 ); - - else if ( rt_macro >= 0 ) - return rt_macro; - - cleanup_all( -500171 ); - - return 0; - -} - -STATIC_FUNC -int8_t track_rule_and_proceed(uint32_t network, int16_t mask, uint32_t prio, int16_t rt_table, char* iif, - int16_t rule_type, int8_t del, int8_t track_t) -{ - - struct list_node *list_pos, *tmp_pos, *first_found_pos=NULL, *first_found_prev=NULL; - struct list_node *prev_pos = (struct list_node*)&rules_list; - struct rules_node *first_found_rn=NULL; - uint32_t found_rns=0; - - paranoia( -500176, ( !del && track_t == TRACK_NO ) ); - - - list_for_each_safe( list_pos, tmp_pos, &rules_list ) { - - struct rules_node *tmp_rn = list_entry( list_pos, struct rules_node, list ); - - if ( tmp_rn->network == network && - tmp_rn->netmask == mask && - tmp_rn->rt_table == rt_table && - tmp_rn->prio == prio && - tmp_rn->iif == iif && - tmp_rn->rta_type == rule_type ) - { - - // the kernel-ip-stack does not care about my track_t when adding the same rule twice - // but found_rns is evaluated for this - if ( !first_found_rn && (tmp_rn->track_t == track_t || track_t == TRACK_NO) ) { - first_found_rn = tmp_rn; - first_found_pos = list_pos; - first_found_prev = prev_pos; - } - - found_rns++; - - } - - prev_pos = &tmp_rn->list; - - } - - if ( (track_t == TRACK_NO) || - ( del && !first_found_rn ) || - ( del && found_rns != 1 ) || - ( !del && found_rns > 0 ) ) - { - - dbg( (track_t == TRACK_NO || (del && !first_found_rn)) ? DBGL_SYS : DBGL_CHANGES, - (track_t == TRACK_NO || (del && !first_found_rn)) ? DBGT_ERR : DBGT_INFO, - " %s rule from %s/%d table %d prio %d iif %s type %d " - "%s exists %d tims with at least %d exact match", - del?"del":"add", ipStr(network), mask, rt_table, prio, iif, rule_type, - trackt2str(track_t), found_rns, (first_found_rn?1:0) ); - } - - if ( track_t == TRACK_NO ) - return YES; - - if ( del ) { - - if ( first_found_rn ) { - - list_del_next(&rules_list, first_found_prev); - debugFree(first_found_rn, -300072); - - if (found_rns > 1) - return NO; - - } else { - return NO; - } - - } else { - - struct rules_node *tmp_rn = debugMalloc( sizeof( struct rules_node ), -300030 ); - memset( tmp_rn, 0, sizeof( struct rules_node ) ); - - tmp_rn->network = network; - tmp_rn->netmask = mask; - tmp_rn->rt_table = rt_table; - tmp_rn->prio = prio; - tmp_rn->iif = iif; - tmp_rn->rta_type = rule_type; - tmp_rn->track_t = track_t; - - list_add_tail(&rules_list, &tmp_rn->list); - - if ( found_rns > 0 ) - return NO; - - } - - return YES; -} - - -STATIC_FUNC -void configure_rule( uint32_t network, int16_t mask, int16_t rt_table_macro, uint32_t prio, char* iif, - int16_t rta_type, int8_t del, int8_t track_t) -{ - - char buf[4096], str1[16]; - struct sockaddr_nl nladdr; - struct msghdr msg; - struct nlmsghdr *nh; - struct iovec iov; - memset(&iov, 0, sizeof (struct iovec)); - iov.iov_base = buf; - iov.iov_len = sizeof (buf); - - uint16_t rt_table = rt_macro_to_table(rt_table_macro); - - inet_ntop( AF_INET, &network, str1, sizeof (str1) ); - - if (track_rule_and_proceed(network, mask, prio, rt_table, iif, rta_type, del, track_t) == NO) - return; - - - dbg( DBGL_CHANGES, DBGT_INFO, "%s rule from %s/%d table %d prio %d iif %s type %d", - del?"del":"add", str1, mask, rt_table, prio, iif, rta_type ); - - - memset( &nladdr, 0, sizeof(struct sockaddr_nl) ); - memset( &req, 0, sizeof(req) ); - memset( &msg, 0, sizeof(struct msghdr) ); - - nladdr.nl_family = AF_NETLINK; - - req.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); - req.nlh.nlmsg_pid = My_pid; - - req.rtm.rtm_family = AF_INET; - req.rtm.rtm_table = rt_table; - - dbgf_all( DBGT_INFO, "%s ip rule pref %d iif %s %d %s/%d lookup table %d", - (del?"del":"add"), prio, iif, rta_type, str1, mask, rt_table ); - - - if ( del ) { - - req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; - req.nlh.nlmsg_type = RTM_DELRULE; - - req.rtm.rtm_scope = RT_SCOPE_NOWHERE; - - } else { - - req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE | NLM_F_EXCL; - req.nlh.nlmsg_type = RTM_NEWRULE; - - req.rtm.rtm_scope = RT_SCOPE_UNIVERSE; - req.rtm.rtm_protocol = RTPROT_STATIC; - req.rtm.rtm_type = RTN_UNICAST; - - } - - - if (rta_type == RTA_DST) { - - req.rtm.rtm_dst_len = mask; - add_rtattr( rta_type, (char*)&network, sizeof(network) ); - - } else if ( rta_type == RTA_SRC ) { - - req.rtm.rtm_src_len = mask; - add_rtattr( rta_type, (char*)&network, sizeof(network) ); - } - - - if ( iif ) - add_rtattr( RTA_IIF, iif, strlen(iif)+1 ); - - - if ( prio ) - add_rtattr( RTA_PRIORITY, (char*)&prio, sizeof(prio) ); - - - if ( sendto( nl_sk, &req, req.nlh.nlmsg_len, 0, (struct sockaddr *)&nladdr, sizeof(struct sockaddr_nl) ) < 0 ) { - - dbg( DBGL_SYS, DBGT_ERR, - "can't send message to kernel via netlink socket for routing rule manipulation: %s", - strerror(errno) ); - return; - - } - - - while ( 1 ) { - - msg.msg_name = (void *)&nladdr; - msg.msg_namelen = sizeof(nladdr); - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - msg.msg_control = NULL; - msg.msg_controllen = 0; - msg.msg_flags = 0; - - int32_t len = recvmsg( nl_sk, &msg, 0 ); - - - if ( len < 0 ) { - - if ( errno == EINTR ) { - dbgf( DBGL_SYS, DBGT_WARN, "(EINTR) %s", strerror(errno) ); - continue; - } - - if ( errno == EWOULDBLOCK || errno == EAGAIN ) { - //dbgf( DBGL_SYS, DBGT_WARN, "(EWOULDBLOCK || EAGAIN) %s", strerror(errno) ); - break; - } - - dbgf( DBGL_SYS, DBGT_ERR, "%s", strerror(errno) ); - - continue; - - } - - if ( len == 0 ) { - dbgf( DBGL_SYS, DBGT_ERR, "netlink EOF" ); - } - - nh = (struct nlmsghdr *)buf; - - while ( NLMSG_OK(nh, (uint32_t)len) ) { - - if ( nh->nlmsg_type == NLMSG_DONE ) - return; - - if ( ( nh->nlmsg_type == NLMSG_ERROR ) && ( ((struct nlmsgerr*)NLMSG_DATA(nh))->error != 0 ) ) { - - dbg( DBGL_SYS, DBGT_WARN, "can't %s rule %s %s/%i iif %s table %d, prio %d: %s " - "(if busy: Help me! Howto avoid this ERROR message?)", - del ? "delete" : "add", - ( rta_type == RTA_DST ? "to" : - ( rta_type == RTA_SRC ? "from" : - ( rta_type == RTA_IIF ? "iif" : "???") ) ), - str1, mask, iif, rt_table, prio, - strerror(-((struct nlmsgerr*)NLMSG_DATA(nh))->error) ); - } - - nh = NLMSG_NEXT( nh, len ); - - } - } -} - -STATIC_FUNC -void flush_tracked_rules( int8_t track_type ) { - - dbgf_all( DBGT_INFO, "%s", trackt2str(track_type) ); - - struct list_node *list_pos; - struct rules_node *rn, *p_rn=NULL; - - - list_for_each( list_pos, &rules_list ) { - - rn = list_entry( list_pos, struct rules_node, list ); - - if ( p_rn ) - configure_rule( p_rn->network, p_rn->netmask, - p_rn->rt_table, p_rn->prio, p_rn->iif, p_rn->rta_type, DEL, p_rn->track_t ); - - if ( track_type == rn->track_t || track_type == TRACK_NO ) - p_rn = rn; - else - p_rn = NULL; - - } - - if ( p_rn ) - configure_rule( p_rn->network, p_rn->netmask, - p_rn->rt_table, p_rn->prio, p_rn->iif, p_rn->rta_type, DEL, p_rn->track_t ); - -} - -static void flush_tracked_routes( int8_t track_type ) { - - dbgf_all( DBGT_INFO, "%s", trackt2str(track_type) ); - - struct list_node *list_pos; - struct routes_node *rn, *p_rn=NULL; - - - list_for_each( list_pos, &routes_list ) { - - rn = list_entry( list_pos, struct routes_node, list ); - - if ( p_rn ) - configure_route( p_rn->dest, p_rn->netmask, p_rn->metric, 0, 0, 0, 0, - p_rn->rt_table, p_rn->rta_type, DEL, p_rn->track_t ); - - if ( track_type == rn->track_t || track_type == TRACK_NO ) - p_rn = rn; - else - p_rn = NULL; - - } - - if ( p_rn ) - configure_route( p_rn->dest, p_rn->netmask, p_rn->metric, 0, 0, 0, 0, - p_rn->rt_table, p_rn->rta_type, DEL, p_rn->track_t ); - -} - -static void flush_routes_rules( int8_t is_rule ) { - - dbgf_all( DBGT_INFO, "is_rule %d", is_rule); - - size_t len; - int rtl; - char buf[8192]; - struct sockaddr_nl nladdr; - struct msghdr msg; - struct nlmsghdr *nh; - struct rtmsg *rtm; - struct { - struct nlmsghdr nlh; - struct rtmsg rtm; - } req; - struct rtattr *rtap; - - struct iovec iov; - - memset(&iov, 0, sizeof (struct iovec)); - iov.iov_base = buf; - iov.iov_len = sizeof (buf); - - memset( &nladdr, 0, sizeof(struct sockaddr_nl) ); - memset( &req, 0, sizeof(req) ); - - nladdr.nl_family = AF_NETLINK; - - req.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); - req.nlh.nlmsg_pid = My_pid; - req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; - req.nlh.nlmsg_type = ( is_rule ? RTM_GETRULE : RTM_GETROUTE ); - - req.rtm.rtm_family = AF_INET; - req.rtm.rtm_scope = RTN_UNICAST; - - if ( sendto( flush_sk, &req, req.nlh.nlmsg_len, 0, - (struct sockaddr *)&nladdr, sizeof(struct sockaddr_nl) ) < 0 ) - { - - dbg( DBGL_SYS, DBGT_ERR, - "can't send message to kernel via netlink socket for flushing the routing table: %s", - strerror(errno) ); - - cleanup_all( CLEANUP_FAILURE ); - } - - uint8_t nlm_f_multi = NO; - - do { - memset(&msg, 0, sizeof(struct msghdr)); - memset(&nladdr, 0, sizeof(struct sockaddr_nl)); - - nladdr.nl_family = AF_NETLINK; - - msg.msg_name = (void *) & nladdr; - msg.msg_namelen = sizeof(nladdr); - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - msg.msg_control = NULL; - - len = recvmsg(flush_sk, &msg, 0); - nh = (struct nlmsghdr *) buf; - - dbgf_all(DBGT_INFO, "searching: %s NLMSG_OK: %d len: %zd", - is_rule ? "rules" : "routes", NLMSG_OK(nh, len), len); - - - while (NLMSG_OK(nh, len)) { - - if ( nh->nlmsg_flags & NLM_F_MULTI ) - nlm_f_multi = YES; - - if (nh->nlmsg_type == NLMSG_DONE) { - dbgf_all( DBGT_INFO, "found NLMSG_DONE"); - break; - } - - if ((nh->nlmsg_type == NLMSG_ERROR) && (((struct nlmsgerr*) NLMSG_DATA(nh))->error != 0)) { - - dbg(DBGL_SYS, DBGT_ERR, "can't flush %s: %s", - (is_rule ? "routing rules" : "routing table"), - strerror(-((struct nlmsgerr*) NLMSG_DATA(nh))->error)); - - cleanup_all( CLEANUP_FAILURE ); - } - - 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 == 0 || */ - rtm->rtm_table == Rt_table + RT_TABLE_NETS_OFFS || - rtm->rtm_table == Rt_table + RT_TABLE_HOSTS_OFFS || - rtm->rtm_table == Rt_table + RT_TABLE_TUNS_OFFS ) { - - int8_t rule_type = RTA_UNSPEC; - uint32_t dest = 0; - uint32_t router = 0; - uint16_t mask = 0; - int32_t oif = 0; - uint32_t prio = 0; - char *iif = NULL; - - while (RTA_OK(rtap, rtl)) { - - dbgf_all( DBGT_INFO, "found rtm_table %d, rta_type %d rta_len %d", - rtm->rtm_table, rtap->rta_type, rtap->rta_len); - - - switch (rtap->rta_type) { - - case RTA_DST: - dest = *((int32_t *) RTA_DATA(rtap)); - mask = rtm->rtm_dst_len; - rule_type = RTA_DST; - break; - - case RTA_SRC: - dest = *((int32_t *) RTA_DATA(rtap)); - mask = rtm->rtm_src_len; - rule_type = RTA_SRC; - break; - - case RTA_GATEWAY: - router = *((int32_t *) RTA_DATA(rtap)); - break; - - case RTA_OIF: - oif = *((int32_t *) RTA_DATA(rtap)); - break; - - case RTA_PRIORITY: - prio = *((uint32_t *) RTA_DATA(rtap)); - break; - - case RTA_IIF: - iif = ((char *) RTA_DATA(rtap)); - 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: - dbg(DBGL_SYS, DBGT_ERR, "unknown rta type: %i", rtap->rta_type); - break; - - } - - rtap = RTA_NEXT(rtap, rtl); - - } - - - if (is_rule) { - - configure_rule( dest, mask, rtm->rtm_table, prio, iif, rule_type, DEL, TRACK_NO); - - - dbg(DBGL_SYS, DBGT_WARN, "flushing orphan rule type %d dest? %s/%d table %d prio %d", - rule_type, ipStr(dest), mask , rtm->rtm_table, prio); - - } else { - - configure_route(dest, mask, prio, router, 0, oif, "unknown", rtm->rtm_table, rtm->rtm_type, DEL, TRACK_NO); - - dbg(DBGL_SYS, DBGT_WARN, "flushing orphan route to %s via %s type %d table %d", - ipStr(dest), ipStr(router), rtm->rtm_type, rtm->rtm_table); - } - } - } - - } while ( !( nlm_f_multi == NO || ( ( NLMSG_OK(nh, len) && (nh->nlmsg_type == NLMSG_DONE) ) ) ) ); - -} - -static void check_proc_sys( char *file, int32_t desired, int32_t *backup ) { - - FILE *f; - int32_t state = 0; - char filename[MAX_PATH_SIZE]; - int trash; - - - sprintf( filename, "/proc/sys/%s", file ); - - if((f = fopen(filename, "r" )) == NULL) { - - dbgf( DBGL_SYS, DBGT_ERR, "can't open %s for reading! retry later..", filename ); - - if ( backup ) - cleanup_all( CLEANUP_FAILURE ); - - return; - } - - trash=fscanf(f, "%d", &state); - fclose(f); - - if ( backup ) - *backup = state; - - // other routing protocols are probably not able to handle this therefore - // it is probably better to leave the routing configuration operational as it is! - if ( !backup && !Pedantic_cleanup && state != desired ) { - - dbg_mute( 50, DBGL_SYS, DBGT_INFO, - "NOT restoring %s to NOT mess up other routing protocols. " - "Use --%s=1 to enforce proper cleanup", - file, ARG_PEDANTIC_CLEANUP ); - - return; - } - - - if ( state != desired ) { - - touched_systen_config = YES; - - dbg( DBGL_SYS, DBGT_INFO, "changing %s from %d to %d", filename, state, desired ); - - if((f = fopen(filename, "w" )) == NULL) { - - dbgf( DBGL_SYS, DBGT_ERR, - "can't open %s for writing! retry later...", filename ); - return; - } - - fprintf(f, "%d", desired?1:0 ); - fclose(f); - - } -} - - -static void restore_kernel_config ( struct dev_node *dev_node ) { - - if ( !touched_systen_config ) - return; - - - if ( dev_node ) { - - char filename[100]; - - if (dev_node->rp_filter_orig > -1) { - sprintf( filename, "net/ipv4/conf/%s/rp_filter", dev_node->name_phy); - check_proc_sys( filename, dev_node->rp_filter_orig, NULL ); - } - - dev_node->rp_filter_orig = -1; - - - if (dev_node->send_redirects_orig > -1) { - sprintf( filename, "net/ipv4/conf/%s/send_redirects", dev_node->name_phy); - check_proc_sys( filename, dev_node->send_redirects_orig, NULL ); - } - - dev_node->send_redirects_orig = -1; - - } else { - - if( if_rp_filter_all_orig != -1 ) - check_proc_sys( "net/ipv4/conf/all/rp_filter", if_rp_filter_all_orig, NULL ); - - if_rp_filter_all_orig = -1; - - if( if_rp_filter_default_orig != -1 ) - check_proc_sys( "net/ipv4/conf/default/rp_filter", if_rp_filter_default_orig, NULL ); - - if_rp_filter_default_orig = -1; - - if( if_send_redirects_all_orig != -1 ) - check_proc_sys( "net/ipv4/conf/all/send_redirects", if_send_redirects_all_orig, NULL ); - - if_send_redirects_all_orig = -1; - - if( if_send_redirects_default_orig != -1 ) - check_proc_sys( "net/ipv4/conf/default/send_redirects", if_send_redirects_default_orig, NULL ); - - if_send_redirects_default_orig = -1; - - if( forward_orig != -1 ) - check_proc_sys( "net/ipv4/ip_forward", forward_orig, NULL ); - - forward_orig = -1; - - } - -} - - -static int8_t get_if_req( char* dev_name, struct ifreq *int_req, int siocgi_req ) { - - memset( int_req, 0, sizeof (struct ifreq) ); - strncpy( int_req->ifr_name, dev_name, IFNAMSIZ - 1 ); - - if ( ioctl( rt_sock, siocgi_req, int_req ) < 0 ) { - - dbg( DBGL_SYS, DBGT_ERR, "can't get SIOCGI %d of interface %s: %s", siocgi_req, dev_name, strerror(errno) ); - return FAILURE; - } - - return SUCCESS; - -} - -static int8_t dev_validate( uint8_t set, struct dev_node *bif, char* dev_name, uint8_t reduced ) { - - struct ifreq int_req; - - - if ( get_if_req( dev_name, &int_req, SIOCGIFADDR ) == FAILURE ) - goto if_validate_failure; - - if ( set ) { - - bif->ip4_addr = ((struct sockaddr_in *)&int_req.ifr_addr)->sin_addr.s_addr; - addr_to_str( bif->ip4_addr, bif->ip4_str ); - - } else if ( bif->ip4_addr != ((struct sockaddr_in *)&int_req.ifr_addr)->sin_addr.s_addr ) { - - dbg( DBGL_SYS, DBGT_WARN, "IP address of %s: changed from %s to %s !", - dev_name, ipStr(bif->ip4_addr), - ipStr(((struct sockaddr_in *)&int_req.ifr_addr)->sin_addr.s_addr) ); - goto if_validate_failure; - } - - if ( !bif->ip4_addr ) { - - dbg( DBGL_SYS, DBGT_ERR, "invalid IP address: %s %s", dev_name, ipStr(0)); - goto if_validate_failure; - } - - - if ( get_if_req( dev_name, &int_req, SIOCGIFNETMASK ) == FAILURE ) - goto if_validate_failure; - - if ( set ) { - - bif->ip4_netaddr = ( ((struct sockaddr_in *)&int_req.ifr_addr)->sin_addr.s_addr & bif->ip4_addr ); - - } else if ( bif->ip4_netaddr != ( ((struct sockaddr_in *)&int_req.ifr_addr)->sin_addr.s_addr & bif->ip4_addr ) ) { - - dbg( DBGL_SYS, DBGT_WARN, "Net address of interface %s changed", dev_name ); - goto if_validate_failure; - } - - if ( set ) { - - bif->ip4_netmask = ((struct sockaddr_in *)&int_req.ifr_addr)->sin_addr.s_addr; - bif->ip4_prefix_length = bits_count( bif->ip4_netmask ); - - } else if ( bif->ip4_netmask != ((struct sockaddr_in *)&int_req.ifr_addr)->sin_addr.s_addr ) { - - dbg( DBGL_SYS, DBGT_WARN, "Prefix length of interface %s changed from %d to %d", - dev_name, bif->ip4_prefix_length, - bits_count( ((struct sockaddr_in *)&int_req.ifr_addr)->sin_addr.s_addr ) ); - goto if_validate_failure; - } - - if ( !bif->ip4_prefix_length ) { - - dbg( DBGL_SYS, DBGT_WARN, "Prefix length of IF %s must be > 0", dev_name ); - goto if_validate_failure; - } - - - if ( reduced ) - return SUCCESS; - - - if ( get_if_req( dev_name, &int_req, SIOCGIFINDEX ) == FAILURE ) - goto if_validate_failure; - - if ( set ) { - - bif->index = int_req.ifr_ifindex; - - } else if ( bif->index != int_req.ifr_ifindex ) { - - dbg( DBGL_SYS, DBGT_WARN, "Interface index of %s %s: changed from %d to %d !", - dev_name, ipStr(bif->ip4_addr), - bif->index, int_req.ifr_ifindex ); - - } - - - - if ( get_if_req( dev_name, &int_req, SIOCGIFBRDADDR ) == FAILURE ) - goto if_validate_failure; - - if ( set ) { - - bif->ip4_broad = ((struct sockaddr_in *)&int_req.ifr_broadaddr)->sin_addr.s_addr; - - } else if ( bif->ip4_broad != ((struct sockaddr_in *)&int_req.ifr_broadaddr)->sin_addr.s_addr ) { - - dbg( DBGL_SYS, DBGT_WARN, "Broadcast address of %s changed", dev_name ); - goto if_validate_failure; - } - - if ( !bif->ip4_broad && bif->linklayer != VAL_DEV_LL_LO) { - - dbg( DBGL_SYS, DBGT_ERR, "invalid broadcast address: %s %s", dev_name, ipStr(0) ); - goto if_validate_failure; - } - - - - - if ( get_if_req( dev_name, &int_req, SIOCGIFMTU ) == FAILURE ) - goto if_validate_failure; - - if ( set ) { - - bif->ip4_mtu = int_req.ifr_mtu; - - } else if ( bif->ip4_mtu != int_req.ifr_mtu ) { - - dbg( DBGL_SYS, DBGT_WARN, "MTU of interface %s changed from %d to %d", - dev_name, bif->ip4_mtu, int_req.ifr_mtu ); - goto if_validate_failure; - } - - - return SUCCESS; - -if_validate_failure: - - bif->ip4_addr = 0; - addr_to_str( 0, bif->ip4_str ); - return FAILURE; -} - - - -static char *get_ip4conf_buffer ( struct ifconf *ifc ) { - - /* use netlink, netdevice and rtnetlink (7) - * to resolve ipv6 addresses. SIOCGIFCONF will only resolv ipv4 addresses !!! - */ - - char *buf; - - int32_t len = 10 * sizeof(struct ifreq); /* initial buffer size guess (10 interfaces) */ - - while ( 1 ) { - - buf = debugMalloc( len, -300031 ); - memset( buf, 0, len); - memset( ifc, 0, sizeof( struct ifconf )); - - ifc->ifc_len = len; - ifc->ifc_buf = buf; - - if ( ioctl( rt_sock, SIOCGIFCONF, ifc ) < 0 ) { - - dbg( DBGL_SYS, DBGT_ERR, "can't add interface rules (SIOCGIFCONF): %s", strerror(errno) ); - //close( tmp_fd ); - debugFree( buf, -300073); - return NULL; - - } else { - - if ( ifc->ifc_len < len ) - break; - - } - - len += 10 * sizeof(struct ifreq); - debugFree( buf, -300074 ); - - } - - return buf; -} - - -static int dev_up(char *name) -{ - struct ifreq int_req; - - memset(&int_req, 0, sizeof (struct ifreq)); - strncpy(int_req.ifr_name, name, IFNAMSIZ-1); - - if (ioctl(rt_sock, SIOCGIFFLAGS, &int_req) < 0) - return 0; - - if (!(int_req.ifr_flags & IFF_UP)) - return 0; - - if (ioctl(rt_sock, SIOCGIFADDR, &int_req) < 0) - return 0; - - return 1; - -} - - - - -static void dev_reconfigure_soft( struct dev_node *bif) { - - if ( !bif->active ) { - - dbg( DBGL_SYS, DBGT_INFO, - "skipping invalid IF %s ", bif->name ); - - } else if ( bif->linklayer == VAL_DEV_LL_LO ) { - - dbg( DBGL_SYS, DBGT_INFO, - "enabled loopback %s %s %s/%d brc %s", - ARG_DEV, bif->name, ipStr(bif->ip4_addr), bif->ip4_prefix_length, ipStr(bif->ip4_broad) ); - - } else if ( bif->linklayer == VAL_DEV_LL_WLAN ) { - - dbg( DBGL_SYS, DBGT_INFO, - "enabled wireless %s %s %s/%d brc %s (use %s /l=%d to optimize for ethernet)", - ARG_DEV, bif->name, ipStr(bif->ip4_addr), bif->ip4_prefix_length, ipStr(bif->ip4_broad), bif->name, VAL_DEV_LL_LAN ); - - bif->send_clones = wl_clones; - - } else { - - dbg( DBGL_SYS, DBGT_INFO, - "enabled ethernet %s %s %s/%d brc %s (use %s /l=%d to optimize for wireless)", - ARG_DEV, bif->name, ipStr(bif->ip4_addr), bif->ip4_prefix_length, ipStr(bif->ip4_broad), bif->name, VAL_DEV_LL_WLAN ); - - bif->send_clones = DEF_LAN_CLONES; - - } - - - if ( bif == primary_if ) - bif->announce = YES; - else - bif->announce = DEF_DEV_ANNOUNCE; - - - bif->antenna_diversity = 1; - - if ( bif->send_clones_conf != -1 ) - bif->send_clones = bif->send_clones_conf; - - if ( bif->antenna_diversity_conf != -1 ) - bif->antenna_diversity = bif->antenna_diversity_conf; - - if ( bif->announce_conf != -1 ) - bif->announce = bif->announce_conf; - - bif->link_activity_timestamp = bmx_time; - bif->next_powersave_hardbeat = bmx_time; - - bif->soft_conf_changed = NO; - - update_my_description_adv(); - -} - -static int8_t bind_to_iface( int32_t sock, char *dev ) { - - errno=0; - - if ( setsockopt( sock, SOL_SOCKET, SO_BINDTODEVICE, dev, strlen( dev ) + 1 ) < 0 ) { - dbg( DBGL_SYS, DBGT_ERR, "Cannot bind socket to device %s : %s", dev, strerror(errno)); - return -1; - } - - return 1; -} - - - -static void dev_activate( struct dev_node *bif ) { - - if ( dev_validate( YES/*set*/, bif, bif->name, NO/*reduced check*/ ) == FAILURE ) - goto error; - - if ( wordsEqual( "lo", bif->name_phy ) ) { - - bif->linklayer = VAL_DEV_LL_LO; - - } else if ( bif->linklayer_conf != -1 ) { - - //FIXME: when this parameter is changed only if_reconfigure_soft is called - bif->linklayer = bif->linklayer_conf; - - } else /* check if interface is a wireless interface */ { - - struct ifreq int_req; - memset( &int_req, 0, sizeof (struct ifreq) ); - strncpy( int_req.ifr_name, bif->name_phy, IFNAMSIZ - 1 ); - - bif->linklayer = - (ioctl( rt_sock, SIOCGIWNAME, &int_req ) < 0 ? VAL_DEV_LL_LAN : VAL_DEV_LL_WLAN); - - } - - - if ( bif->linklayer != VAL_DEV_LL_LO && (bif->unicast_sock = socket( PF_INET, SOCK_DGRAM, 0 )) < 0 ) { - - dbg( DBGL_SYS, DBGT_ERR, "can't create send socket: %s", strerror(errno) ); - goto error; - } - - // the src address and port used for sending: - bif->ip4_unicast_addr.sin_addr.s_addr = bif->ip4_addr; - bif->ip4_unicast_addr.sin_family = AF_INET; - bif->ip4_unicast_addr.sin_port = htons(base_port); - - // the dst address and port used for sending: - bif->ip4_netwbrc_addr.sin_addr.s_addr = bif->ip4_broad; - bif->ip4_netwbrc_addr.sin_family = AF_INET; - bif->ip4_netwbrc_addr.sin_port = htons(base_port); - - Mtu_min = MIN ( Mtu_min, bif->ip4_mtu ); - - dbgf_all( DBGT_INFO, "searching minimum MTU, so fare: %d, current dev %s, mtu: %d", - Mtu_min, bif->name, bif->ip4_mtu ); - - - if ( bif->linklayer == VAL_DEV_LL_LO ) { - - if ( bif->ip4_prefix_length != 32 /*|| bif->if_addr != bif->if_broad*/ ) - dbg_mute( 30, DBGL_SYS, DBGT_WARN, "netmask of loopback interface is %d but SHOULD BE 32", - bif->ip4_prefix_length ); - - } else { - - int set_on = 1, sock_opts; - - if ( setsockopt( bif->unicast_sock, SOL_SOCKET, SO_BROADCAST, &set_on, sizeof(set_on) ) < 0 ) { - - dbg( DBGL_SYS, DBGT_ERR, "can't enable broadcasts on unicast socket: %s", strerror(errno) ); - goto error; - } - - // bind send socket to interface name - if ( bind_to_iface( bif->unicast_sock, bif->name_phy ) < 0 ) - goto error; - - // bind send socket to address - if ( bind( bif->unicast_sock, (struct sockaddr *)&bif->ip4_unicast_addr, sizeof(struct sockaddr_in) ) < 0 ) { - - dbg( DBGL_SYS, DBGT_ERR, "can't bind unicast socket: %s", strerror(errno) ); - goto error; - } - - // make udp send socket non blocking - sock_opts = fcntl(bif->unicast_sock, F_GETFL, 0); - fcntl(bif->unicast_sock, F_SETFL, sock_opts | O_NONBLOCK); - -#ifdef SO_TIMESTAMP - if (setsockopt(bif->unicast_sock, SOL_SOCKET, SO_TIMESTAMP, &set_on, sizeof(set_on))) - dbg( DBGL_SYS, DBGT_WARN, - "No SO_TIMESTAMP support, despite being defined, falling back to SIOCGSTAMP"); -#else - dbg( DBGL_SYS, DBGT_WARN, "No SO_TIMESTAMP support, falling back to SIOCGSTAMP"); -#endif - - - - - // if the dst address used for sending is the full-broadcast address - // we'll also listen on the network-broadcast address - - struct sockaddr_in if_netwbrc_addr; - memset( &if_netwbrc_addr, 0, sizeof( struct sockaddr_in ) ); - if_netwbrc_addr.sin_family = AF_INET; - if_netwbrc_addr.sin_port = htons(base_port); - if ( bif->ip4_broad == 0xFFFFFFFF ) - if_netwbrc_addr.sin_addr.s_addr = bif->ip4_netaddr | ~(bif->ip4_netmask); - else - if_netwbrc_addr.sin_addr.s_addr = bif->ip4_broad; - - - // get netwbrc recv socket - if ( ( bif->netwbrc_sock = socket( PF_INET, SOCK_DGRAM, 0 ) ) < 0 ) { - - dbg( DBGL_CHANGES, DBGT_ERR, "can't create network-broadcast socket: %s", strerror(errno) ); - goto error; - } - - // bind recv socket to interface name - if ( bind_to_iface( bif->netwbrc_sock, bif->name_phy ) < 0 ) - goto error; - - // bind recv socket to address - if ( bind( bif->netwbrc_sock, (struct sockaddr *)&if_netwbrc_addr, sizeof(struct sockaddr_in) ) < 0 ) { - - dbg( DBGL_CHANGES, DBGT_ERR, "can't bind network-broadcast socket: %s", strerror(errno)); - goto error; - } - - - - // we'll always listen on the full-broadcast address - - struct sockaddr_in if_fullbrc_addr; - memset( &if_netwbrc_addr, 0, sizeof( struct sockaddr_in ) ); - if_fullbrc_addr.sin_addr.s_addr = 0xFFFFFFFF; - if_fullbrc_addr.sin_family = AF_INET; - if_fullbrc_addr.sin_port = htons(base_port); - - // get fullbrc recv socket - if ( ( bif->fullbrc_sock = socket( PF_INET, SOCK_DGRAM, 0 ) ) < 0 ) { - - dbg( DBGL_CHANGES, DBGT_ERR, "can't create full-broadcast socket: %s", strerror(errno) ); - goto error; - } - - // bind recv socket to interface name - if ( bind_to_iface( bif->fullbrc_sock, bif->name_phy ) < 0 ) - goto error; - - // bind recv socket to address - if ( bind( bif->fullbrc_sock, (struct sockaddr *)&if_fullbrc_addr, sizeof(struct sockaddr_in) ) < 0 ) { - - dbg( DBGL_CHANGES, DBGT_ERR, "can't bind full-broadcast socket: %s", strerror(errno)); - goto error; - } - - register_task( rand_num(RAND_INIT_DELAY), schedule_my_hello_message, bif ); - register_task( rand_num(RAND_INIT_DELAY), tx_packet, bif ); - - } - - check_kernel_config( bif ); - - - if ( bif == primary_if ) { - my_orig_node.primary_ip4 = bif->ip4_addr; - addr_to_str(bif->ip4_addr, my_orig_node.primary_ip4_str); - } - - bif->hard_conf_changed = NO; - - bif->soft_conf_changed = YES; - - bif->active = YES; - - if (avl_find(&dev_ip4_tree, &bif->ip4_addr)) { - dbgf(DBGL_SYS, DBGT_ERR, "%s already in dev_tree_ip4!", bif->ip4_str); - } else { - avl_insert(&dev_ip4_tree, bif, -300151); - bif->ip4_tree_addr = bif->ip4_addr; - } - - //reschedule if_reconfigure_soft( bif ) also called from check_interfaces() - // but should also be called here - // - before schedule_if_hello() - // - after if_active=YES - dev_reconfigure_soft( bif ); - - - //activate selector for active interfaces - change_selects(); - - //trigger plugins interested in changed interface configuration - cb_plugin_hooks( NULL, PLUGIN_CB_CONF ); - - return; - -error: - - dev_deactivate( bif ); - -} - -static int8_t track_route_and_proceed( uint32_t dest, int16_t mask, uint32_t metric, uint32_t gw, uint32_t src, char *dev, - int16_t rt_table, int16_t rta_type, int8_t del, int8_t track_t ) -{ - - struct list_node *list_pos, *tmp_pos, *prev_pos = (struct list_node*)&routes_list; - struct list_node *first_found_pos=NULL, *first_found_prev=NULL; - struct routes_node *first_found_rn=NULL; - uint32_t found_rns=0; - - paranoia(-500177, (!del && track_t == TRACK_NO)); - - list_for_each_safe( list_pos, tmp_pos, &routes_list ) { - - struct routes_node *tmp_rn = list_entry( list_pos, struct routes_node, list ); - - if ( tmp_rn->dest == dest && - tmp_rn->netmask == mask && - tmp_rn->metric == metric && - tmp_rn->rt_table == rt_table && - tmp_rn->rta_type == rta_type) - { - - // the kernel-ip-stack does not care about my track_t when adding the same route twice - // but found_rns is evaluated for this - if ( !first_found_rn && (tmp_rn->track_t == track_t || track_t == TRACK_NO ) ) { - - first_found_rn = tmp_rn; - first_found_pos = list_pos; - first_found_prev = prev_pos; - } - - found_rns++; - - } - - prev_pos = &tmp_rn->list; - - } - - if ( track_t == TRACK_NO || - ( del && !first_found_rn ) || - ( del && found_rns != 1 ) || - ( !del && found_rns > 0 ) ) - { - dbg( (track_t == TRACK_NO || (del && !first_found_rn)) ? DBGL_SYS : DBGL_ALL, - (track_t == TRACK_NO || (del && !first_found_rn)) ? DBGT_ERR : DBGT_INFO, - " %s route to %-15s via %-15s src %s dev %s table %d %s " - "%s has %d (%d exact) matches", - del?"del":"add", ipStr(dest), ipStr(gw), ipStr(src), dev, rt_table, - rt2str(rta_type), trackt2str(track_t), found_rns, (first_found_rn?1:0) ); - } - - if ( track_t == TRACK_NO ) - return YES; - - - if ( del && !first_found_rn) { - - dbgf_all( DBGT_WARN, "removing orphan route"); - return NO; - - } else if ( del && first_found_rn ) { - - list_del_next(&routes_list, first_found_prev); - debugFree( first_found_rn, -300075 ); - - if ( found_rns > 1 ) - return NO; - - - } else if ( !del ) { - - struct routes_node *tmp_rn = debugMalloc( sizeof( struct routes_node ), -300032 ); - memset( tmp_rn, 0, sizeof( struct routes_node ) ); - - tmp_rn->dest = dest; - tmp_rn->netmask = mask; - tmp_rn->metric = metric; - tmp_rn->rt_table = rt_table; - tmp_rn->rta_type = rta_type; - tmp_rn->track_t = track_t; - - list_add_tail(&routes_list, &tmp_rn->list); - - if ( found_rns > 0 ) - return NO; - - } - - return YES; -} - - - -void configure_route( uint32_t dest, int16_t mask, uint32_t metric, uint32_t gw, uint32_t src, int32_t ifi, char *dev, - int16_t rt_table_macro, int16_t rta_type, int8_t del, int8_t track_t ) -{ - - uint32_t my_router; - char buf[4096]; - struct sockaddr_nl nladdr; - - struct msghdr msg; - struct nlmsghdr *nh; - - struct iovec iov; - - memset(&iov, 0, sizeof (struct iovec)); - iov.iov_base = buf; - iov.iov_len = sizeof (buf); - - uint16_t rt_table = rt_macro_to_table(rt_table_macro); - - dest = dest & htonl( 0xFFFFFFFF<<(32 - mask ) ); - - if ( ( !throw_rules ) && ( rta_type == RTN_THROW ) ) - return; - - - - if ( track_route_and_proceed(dest, mask, metric, gw, src, dev, rt_table, rta_type, del, track_t) == NO ) - return; - - if ( track_t != TRACK_OTHER_HOST ) - dbg( DBGL_CHANGES, DBGT_INFO, - " %s route to %15s/%-2d table %d via %-15s dev %-10s ifi %2d %s %s", - del?"del":"add", - ipStr(dest), mask, rt_table, ipStr(gw), dev, ifi, rt2str(rta_type), trackt2str(track_t)); - - - if ( gw == dest ) - my_router = 0; - - else - my_router = gw; - - - dbgf_all( DBGT_INFO, "%s %s to %s/%i via %s (table %i - %s src %s )", - del ? "del" : "add", - rt2str(rta_type), ipStr(dest), mask, ipStr(gw), rt_table, dev, ipStr(src)); - - - memset( &nladdr, 0, sizeof(struct sockaddr_nl) ); - memset( &req, 0, sizeof(req) ); - memset( &msg, 0, sizeof(struct msghdr) ); - - nladdr.nl_family = AF_NETLINK; - - req.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); - req.nlh.nlmsg_pid = My_pid; - - req.rtm.rtm_family = AF_INET; - req.rtm.rtm_table = rt_table; - req.rtm.rtm_dst_len = mask; - - if ( del ) { - - req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; - req.nlh.nlmsg_type = RTM_DELROUTE; - req.rtm.rtm_scope = RT_SCOPE_NOWHERE; - - } else { - - req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE | NLM_F_EXCL/* | NLM_F_REPLACE*/; - req.nlh.nlmsg_type = RTM_NEWROUTE; - - if ( /* source != 0 && */ rta_type == RTN_UNICAST && my_router == 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 bmx specific value - see <linux/rtnetlink.h> - req.rtm.rtm_type = ( rta_type == RTN_THROW ? RTN_THROW : RTN_UNICAST ); - - } - - add_rtattr( RTA_DST, (char*)&dest, sizeof(dest) ); - - if ( rta_type == RTN_UNICAST ) { - - if ( my_router ) - add_rtattr( RTA_GATEWAY, (char*)&my_router, sizeof(my_router) ); - - if ( ifi ) - add_rtattr ( RTA_OIF, (char*)&ifi, sizeof(ifi) ); - - if ( src /* && my_router == 0 */) - add_rtattr( RTA_PREFSRC, (char*)&src, sizeof(src) ); - - if ( metric ) - add_rtattr( RTA_PRIORITY, (char*)&metric, sizeof(metric) ); - - } - - errno=0; - - if ( sendto( nl_sk, &req, req.nlh.nlmsg_len, 0, (struct sockaddr *)&nladdr, sizeof(struct sockaddr_nl) ) < 0 ) { - - dbg( DBGL_SYS, DBGT_ERR, - "can't send message to kernel via netlink socket for routing table manipulation: %s", - strerror(errno) ); - - return; - - } - - - while ( 1 ) { - - msg.msg_name = (void *)&nladdr; - msg.msg_namelen = sizeof(nladdr); - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - msg.msg_control = NULL; - msg.msg_controllen = 0; - msg.msg_flags = 0; - - errno=0; - int32_t len = recvmsg( nl_sk, &msg, 0 ); - - - if ( len < 0 ) { - - if ( errno == EINTR ) { - - dbgf( DBGL_SYS, DBGT_WARN, "(EINTR) %s", strerror(errno) ); - - continue; - } - - if ( errno == EWOULDBLOCK || errno == EAGAIN ) { - //dbgf( DBGL_CHANGES, DBGT_WARN, "(EWOULDBLOCK || EAGAIN) %s", strerror(errno) ); - break; - } - - dbgf( DBGL_SYS, DBGT_ERR, "%s", strerror(errno) ); - - continue; - - } - - if ( !len ) { - dbgf( DBGL_SYS, DBGT_ERR, "netlink EOF" ); - } - - nh = (struct nlmsghdr *)buf; - - while ( NLMSG_OK(nh, (uint32_t)len) ) { - - if ( nh->nlmsg_type == NLMSG_DONE ) - return; - - if ( ( nh->nlmsg_type == NLMSG_ERROR ) && ( ((struct nlmsgerr*)NLMSG_DATA(nh))->error != 0 ) ) - { - dbg( DBGL_CHANGES, DBGT_WARN, "can't %s %s to %s/%i via %s (table %i): %s", - del ? "delete" : "add", rt2str(rta_type), ipStr(dest), mask, ipStr(gw), rt_table, - strerror(-((struct nlmsgerr*)NLMSG_DATA(nh))->error) ); - } - - nh = NLMSG_NEXT( nh, len ); - - } - } -} - - - - - - -int update_interface_rules( uint8_t cmd ) { - - - static uint8_t setup_tunnel = NO; - static uint8_t setup_networks = NO; - - static uint64_t checksum = 0; - - uint64_t old_checksum = checksum; - checksum = 0; - - uint8_t if_count = 1; - char *buf, *buf_ptr; - - struct ifreq *ifr; - struct ifconf ifc; - - - struct dev_node *dev_node; - - struct list_node *throw_pos; - struct throw_node *throw_node; - uint32_t no_netmask; - - if ( cmd != IF_RULE_CHK_IPS ) { - - flush_tracked_routes( TRACK_MY_NET ); - flush_tracked_rules( TRACK_MY_NET ); - - } - - if ( cmd == IF_RULE_SET_TUNNEL ) { - - setup_tunnel = YES; - return SUCCESS; //will be called again when bat0s' IP is set - - } else if ( cmd == IF_RULE_CLR_TUNNEL ) { - - setup_tunnel = NO; - return SUCCESS; //will be called again when bat0s' IP gets removed - - } else if ( cmd == IF_RULE_SET_NETWORKS ) { - - setup_networks = YES; - - } else if ( cmd == IF_RULE_CLR_NETWORKS ) { - - setup_networks = NO; - - } - - if ( !(buf = get_ip4conf_buffer( &ifc )) ) - return FAILURE; - - for ( buf_ptr = buf; buf_ptr < buf + ifc.ifc_len; ) { - - struct dev_node bif; -// memset( &bif, 0, sizeof(struct dev_node)); - - ifr = (struct ifreq *)buf_ptr; - - buf_ptr += sizeof(struct ifreq); - - /* ignore if not IPv4 interface */ - if ( ifr->ifr_addr.sa_family != AF_INET ) - continue; - - if ( !dev_up( ifr->ifr_name ) ) - continue; - - if ( dev_validate( YES/*set*/, &bif, ifr->ifr_name, YES/*reduced check only*/ ) == FAILURE ) - continue; - - size_t i; - struct config_key { - uint32_t if_prefix_length; - uint32_t if_netaddr; - uint32_t if_addr; - } config_key; - - memset( &config_key, 0, sizeof(struct config_key)); - config_key.if_prefix_length = bif.ip4_prefix_length; - config_key.if_netaddr = bif.ip4_netaddr; - config_key.if_addr = bif.ip4_addr; - - for (i = 0; i < sizeof( struct config_key); i++) { - checksum += ((unsigned char*)(&config_key))[i]; - checksum += (checksum << 10); - checksum ^= (checksum >> 6); - } - - dbgf_ext(DBGT_INFO, "%32ju %32ju %10s %15s %15s %2d ", - old_checksum, checksum, - ifr->ifr_name, ipStr(bif.ip4_addr), ipStr(bif.ip4_netaddr), bif.ip4_prefix_length); - - - if ( cmd == IF_RULE_CHK_IPS ) - continue; - - - uint8_t add_this_rule = YES; - - list_for_each(throw_pos, &throw_list) { - - throw_node = list_entry(throw_pos, struct throw_node, list); - - no_netmask = htonl( 0xFFFFFFFF<<(32 - throw_node->netmask ) ); - - if ( ((throw_node->addr & no_netmask) == (bif.ip4_netaddr & no_netmask)) ) - add_this_rule = NO; - - } - - - if( prio_rules && setup_tunnel == YES ) { - - if ( !Lo_rule && - (bif.ip4_netaddr & htonl( 0xFF000000 ) ) == ( htonl( 0x7F000000 /*127.0.0.0*/ ) ) ) - add_this_rule = NO; - - - if ( add_this_rule ) { - configure_rule( bif.ip4_netaddr, bif.ip4_prefix_length, - RT_TABLE_TUNNEL, RT_PRIO_TUNNEL, 0, RTA_SRC, ADD, TRACK_MY_NET ); - if_count++; - } - - if ( Lo_rule && strncmp( ifr->ifr_name, "lo", strlen("lo") ) == 0 ) { - - configure_rule( 0, 0, RT_TABLE_TUNNEL, RT_PRIO_TUNNEL, "lo", RTA_IIF, ADD, TRACK_MY_NET ); - } - - } - - if( throw_rules && setup_tunnel == YES ) - configure_route( bif.ip4_netaddr, bif.ip4_prefix_length, 0, - 0, 0, 0, ifr->ifr_name, RT_TABLE_TUNNEL, RTN_THROW, ADD, TRACK_MY_NET ); - - - if ( !(dev_node = get_bif( ifr->ifr_name ) ) ) - continue; - - - if( throw_rules && setup_networks == YES ) - configure_route( bif.ip4_netaddr, bif.ip4_prefix_length, 0, - 0, 0, 0, ifr->ifr_name, RT_TABLE_NETWORKS, RTN_THROW, ADD, TRACK_MY_NET ); - - - } - - - debugFree( buf, -300076 ); - - - if ( cmd != IF_RULE_CHK_IPS ) { - - list_for_each(throw_pos, &throw_list) { - - throw_node = list_entry(throw_pos, struct throw_node, list); - - configure_route( throw_node->addr, throw_node->netmask, 0, - 0, 0, 0, "unknown", RT_TABLE_HOSTS, RTN_THROW, ADD, TRACK_MY_NET ); - configure_route( throw_node->addr, throw_node->netmask, 0, - 0, 0, 0, "unknown", RT_TABLE_NETWORKS, RTN_THROW, ADD, TRACK_MY_NET ); - configure_route( throw_node->addr, throw_node->netmask, 0, - 0, 0, 0, "unknown", RT_TABLE_TUNNEL, RTN_THROW, ADD, TRACK_MY_NET ); - - } - - } - - - if ( cmd == IF_RULE_CHK_IPS && (checksum != old_checksum) ) { - dbg( DBGL_CHANGES, DBGT_INFO, - "systems' IP configuration changed! Going to re-init interface rules..."); - update_interface_rules( IF_RULE_UPD_ALL ); - } - - - return SUCCESS; - -} - - - - -// check for further traps: http://lwn.net/Articles/45386/ -void check_kernel_config( struct dev_node *dev_node ) { - - if ( dev_node ) { - - char filename[100]; - - sprintf( filename, "net/ipv4/conf/%s/rp_filter", dev_node->name_phy); - check_proc_sys( filename, 0, &dev_node->rp_filter_orig ); - - sprintf( filename, "net/ipv4/conf/%s/send_redirects", dev_node->name_phy); - check_proc_sys( filename, 0, &dev_node->send_redirects_orig ); - - } else { - - check_proc_sys( "net/ipv4/conf/all/rp_filter", 0, &if_rp_filter_all_orig ); - check_proc_sys( "net/ipv4/conf/default/rp_filter", 0, &if_rp_filter_default_orig ); - check_proc_sys( "net/ipv4/conf/all/send_redirects", 0, &if_send_redirects_all_orig ); - check_proc_sys( "net/ipv4/conf/default/send_redirects", 0, &if_send_redirects_default_orig ); - check_proc_sys( "net/ipv4/ip_forward", 1, &forward_orig ); - - } -} - - - -void dev_deactivate( struct dev_node *bif ) { - - dbg_mute( 30, DBGL_SYS, DBGT_WARN, "deactivating IF %-10s %-15s", bif->name, ipStr(bif->ip4_addr) ); - - - if ( bif->linklayer != VAL_DEV_LL_LO ) { - - remove_task( tx_packet, bif ); - remove_task( schedule_my_hello_message, bif ); - - purge_tx_timestamp_tree( bif, YES); - purge_dev_tx_list ( bif ); - - if (bif->unicast_sock != 0) - close(bif->unicast_sock); - - bif->unicast_sock = 0; - - if (bif->netwbrc_sock != 0) - close(bif->netwbrc_sock); - - bif->netwbrc_sock = 0; - - if (bif->fullbrc_sock != 0) - close(bif->fullbrc_sock); - - bif->fullbrc_sock = 0; - - - } - - if (!bif->ip4_tree_addr) { - dbgf(DBGL_SYS, DBGT_ERR, "no address given to remove in dev_tree_ip4!"); - } else if (!avl_find(&dev_ip4_tree, &bif->ip4_tree_addr)) { - dbgf(DBGL_SYS, DBGT_ERR, "%s not in dev_tree_ip4!", ipStr(bif->ip4_tree_addr)); - } else { - avl_remove(&dev_ip4_tree, &bif->ip4_tree_addr, -300192); - bif->ip4_tree_addr = 0; - } - bif->active = NO; - - - restore_kernel_config ( bif ); - - change_selects(); - - dbgf_all( DBGT_WARN, "Interface %s deactivated", bif->name ); - - if ( bif == primary_if && !terminating() ) { - - purge_orig( NULL, NO); - - dbg_mute( 30, DBGL_SYS, DBGT_WARN, - "You SHOULD always configure a loopback-alias interface for %s/32 to remain reachable under your primary IP!", - ipStr(bif->ip4_addr) ); - - } else { - - purge_orig( bif, NO ); - } - - update_my_description_adv(); -} - - - -void dev_check() { - - uint8_t cb_conf_hooks = NO; - - dbgf_all( DBGT_INFO, " " ); - - remove_task( dev_check, NULL ); - - //Do we need this? There was an interface attribute which change is not catched by ifevent_sk ?? - register_task( 5000, dev_check, NULL ); - - if ( !dev_name_tree.items ) { - dbg( DBGL_SYS, DBGT_ERR, "No interfaces specified"); - cleanup_all( CLEANUP_FAILURE ); - } - - - Mtu_min = MAX_MTU; - - struct avl_node *it=NULL; - struct dev_node *bif; - while ((bif = avl_iterate_item(&dev_name_tree, &it))) { - - if ((bif->active) && (!dev_up(bif->name))) { - - dbg( DBGL_SYS, DBGT_WARN, - "detected inactive but used %sprimary interface: %s ! Deactivating now...", - (bif == primary_if ? "" : "non-" ), bif->name ); - - cb_conf_hooks = YES; - dev_deactivate( bif ); - - - } else if ( bif->active && dev_up(bif->name) ) { - - /* Interface properties might have changed */ - - if ( if_conf_hard_changed || bif->hard_conf_changed || - dev_validate( NO/*set*/, bif, bif->name, NO/*reduced check*/ ) == FAILURE ) { - - cb_conf_hooks = YES; - dev_deactivate( bif ); - - } else { - - Mtu_min = MIN( Mtu_min, bif->ip4_mtu ); - - dbgf_all( DBGT_INFO, - "researching minimum MTU, so fare: %d, current dev %s, mtu: %d", - Mtu_min, bif->name, bif->ip4_mtu); - } - - } - - if (if_conf_soft_changed ) - bif->soft_conf_changed = YES; // to be considered in if_activate()->if_reconfigure_soft() - - if ( (!bif->active) && (dev_up(bif->name)) ) { - - struct dev_node *tmp_bif = avl_find_item(&dev_ip4_tree, &bif->ip4_addr); - - if (tmp_bif && !wordsEqual(tmp_bif->name, bif->name)) { - - dbg_mute(40, DBGL_SYS, DBGT_ERR, "IF %-10s IP %-15s already used for IF %s", - bif->name, bif->ip4_str, tmp_bif->name); - break; - - } else { - - if ( on_the_fly ) - dbg_mute( 50, DBGL_SYS, DBGT_INFO, - "detected valid but disabled dev: %s ! Activating now...", bif->name ); - - dev_activate( bif ); - } - } - - if ( /*bif->if_active &&*/ ( /*if_conf_soft_changed ||*/ bif->soft_conf_changed) ) { - - if ( on_the_fly ) - dbg( DBGL_CHANGES, DBGT_INFO, "%s soft interface configuration changed", bif->name ); - - dev_reconfigure_soft( bif ); - } - - - if ( !on_the_fly && !bif->active ) { - - if ( bif == primary_if ) { - dbg( DBGL_SYS, DBGT_ERR, - "at least primary interface %s MUST be operational at startup! " - "Use loopback (e.g. lo:bmx a.b.c.d/32 ) if nothing else is available!", - bif->name); - - cleanup_all( CLEANUP_FAILURE ); - } - - dbg( DBGL_SYS, DBGT_WARN, - "not using interface %s (retrying later): interface not ready", bif->name); - } - } - - if_conf_soft_changed = NO; - if_conf_hard_changed = NO; - - - if ( cb_conf_hooks ) - cb_plugin_hooks( NULL, PLUGIN_CB_CONF ); - - - if ( on_the_fly ) // opt_policy_rt() is responsible for this during init - update_interface_rules( IF_RULE_CHK_IPS ); - -} - - - - - -static int32_t opt_policy_rt ( uint8_t cmd, uint8_t _save, struct opt_type *opt, struct opt_parent *patch, struct ctrl_node *cn ) { - - if ( cmd == OPT_APPLY ) { - - check_apply_parent_option( ADD, OPT_APPLY, _save, get_option( 0, 0, ARG_PRIO_RULES ), "0", cn ); - check_apply_parent_option( ADD, OPT_APPLY, _save, get_option( 0, 0, ARG_THROW_RULES ), "0", cn ); - - } else if ( cmd == OPT_SET_POST && !on_the_fly ) { - - // flush orphan routes must be before flushing rules, otherwise orphan routes are not found ! - flush_routes_rules( 0 /* flush routes */); - - /* add rule for hosts and announced interfaces and networks */ - if ( prio_rules ) - flush_routes_rules( 1 /* flush rules */); - - - } else if ( cmd == OPT_POST && !on_the_fly ) { - - // add rule for hosts and announced interfaces and networks - if ( prio_rules ) { - configure_rule( 0, 0, RT_TABLE_HOSTS, RT_PRIO_HOSTS, 0, RTA_DST, ADD, TRACK_STANDARD ); - configure_rule( 0, 0, RT_TABLE_NETWORKS, RT_PRIO_NETWORKS, 0, RTA_DST, ADD, TRACK_STANDARD ); - } - - // add rules and routes for interfaces - if ( update_interface_rules( IF_RULE_SET_NETWORKS ) < 0 ) - cleanup_all( CLEANUP_FAILURE ); - - } - - return SUCCESS; -} - - -static int32_t opt_throw ( uint8_t cmd, uint8_t _save, struct opt_type *opt, struct opt_parent *patch, struct ctrl_node *cn ) { - - uint32_t ip; - int32_t mask; - char tmp[30]; - struct throw_node *throw_node=NULL; - struct list_node *throw_tmp, *throw_pos; - - if ( cmd == OPT_ADJUST || cmd == OPT_CHECK || cmd == OPT_APPLY ) { - - if ( patch->p_val[0] >= '0' && patch->p_val[0] <= '9' ) { - // configure an unnamed throw-rule - - if ( str2netw( patch->p_val, &ip, '/', cn, &mask, 32 ) == FAILURE ) - return FAILURE; - - sprintf( tmp, "%s/%d", ipStr( validate_net_mask( ip, mask, 0 ) ), mask ); - set_opt_parent_val( patch, tmp ); - - } else { - // configure a named throw-rule - - // just for adjust and check - if ( adj_patched_network( opt, patch, tmp, &ip, &mask, cn ) == FAILURE ) - return FAILURE; - - if ( patch->p_diff == ADD ) { - if ( adj_patched_network( opt, patch, tmp, &ip, &mask, cn ) == FAILURE ) - return FAILURE; - } else { - // re-configure network and netmask parameters of an already configured and named throw-rule - if ( get_tracked_network( opt, patch, tmp, &ip, &mask, cn ) == FAILURE ) - return FAILURE; - } - } - - struct list_node *prev_pos = (struct list_node *)&throw_list; - list_for_each_safe( throw_pos, throw_tmp, &throw_list ) { - throw_node = list_entry(throw_pos, struct throw_node, list); - if ( throw_node->addr == ip && throw_node->netmask == mask ) - break; - prev_pos = &throw_node->list; - throw_node = NULL; - } - - if ( cmd == OPT_ADJUST ) - return SUCCESS; - - if ( ( patch->p_diff != ADD && !throw_node ) || ( patch->p_diff == ADD && throw_node ) ) { - dbg_cn( cn, DBGL_SYS, DBGT_ERR, "%s %s does %s exist!", - ARG_THROW, tmp, patch->p_diff == ADD ? "already" : "not" ); - return FAILURE; - } - - if ( cmd == OPT_CHECK ) - return SUCCESS; - - if ( patch->p_diff == DEL || patch->p_diff == NOP ) { - list_del_next( &throw_list, prev_pos ); - debugFree( throw_pos, -300077 ); - } - - if ( patch->p_diff == NOP ) { - // get new network again - if ( adj_patched_network( opt, patch, tmp, &ip, &mask, cn ) == FAILURE ) - return FAILURE; - } - - if ( patch->p_diff == ADD || patch->p_diff == NOP ) { - - throw_node = debugMalloc( sizeof(struct throw_node), -300033 ); - memset( throw_node, 0, sizeof(struct throw_node) ); - list_add_tail( &throw_list, &throw_node->list ); - - throw_node->addr = ip; - throw_node->netmask = mask; - } - - - if ( on_the_fly ) { - /* add rules and routes for interfaces */ - if ( update_interface_rules( IF_RULE_UPD_ALL ) < 0 ) - cleanup_all( CLEANUP_FAILURE ); - } - - return SUCCESS; - - - } else if ( cmd == OPT_UNREGISTER ) { - - while ((throw_node = list_rem_head(&throw_list))) - debugFree(throw_node, -300078); - -/* - list_for_each_safe( throw_pos, throw_tmp, &throw_list ) { - - list_del_next( &throw_list, (struct list_node *)&throw_list ); - - debugFree( throw_pos, -300078 ); - } -*/ - } - - return SUCCESS; -} - - - - -static struct opt_type route_options[]= -{ -// ord parent long_name shrt Attributes *ival min max default *func,*syntax,*help - - - {ODI,0,0, 0, 4,0,0,0,0,0, 0, 0, 0, 0, 0, - 0, "\nSystem and policy-routing options:"}, - - {ODI,0,ARG_BASE_PORT, 0, 4,A_PS1,A_ADM,A_INI,A_CFA,A_ANY, &base_port, MIN_BASE_PORT, MAX_BASE_PORT, DEF_BASE_PORT, 0, - ARG_VALUE_FORM, "set udp ports"}, - - {ODI,0,ARG_RT_PRIO, 0, 4,A_PS1,A_ADM,A_INI,A_CFA,A_ANY, &Rt_prio, MIN_RT_PRIO, MAX_RT_PRIO, DEF_RT_PRIO, 0, - ARG_VALUE_FORM, "set preferences for iproute2-style rules to rt_table (see: man ip)"}, - - {ODI,0,ARG_RT_TABLE, 0, 4,A_PS1,A_ADM,A_INI,A_CFA,A_ANY, &Rt_table, MIN_RT_TABLE, MAX_RT_TABLE-RT_TABLE_MAX_OFFS, DEF_RT_TABLE, 0, - ARG_VALUE_FORM, "set bmx routing-table offset (iproute2 style, see: man ip)"}, - -#ifndef LESS_OPTIONS - {ODI,0,ARG_THROW_RULES, 0, 4,A_PS1,A_ADM,A_INI,A_CFA,A_ANY, &throw_rules, 0, 1, DEF_THROW_RULES,0, - ARG_VALUE_FORM, "disable/enable default throw rules"}, - - {ODI,0,ARG_PRIO_RULES, 0, 4,A_PS1,A_ADM,A_INI,A_CFA,A_ANY, &prio_rules, 0, 1, DEF_PRIO_RULES, 0, - ARG_VALUE_FORM, "disable/enable default priority rules"}, -#endif - {ODI,0,ARG_NO_POLICY_RT, 'n',4,A_PS0,A_ADM,A_INI,A_ARG,A_ANY, 0, 0, 0, 0, opt_policy_rt, - 0, "disable policy routing (throw and priority rules)"}, - -#ifndef LESS_OPTIONS - - {ODI,0,"lo_rule", 0, 4,A_PS1,A_ADM,A_INI,A_CFA,A_ANY, &Lo_rule, 0, 1, DEF_LO_RULE, 0, - ARG_VALUE_FORM, "disable/enable autoconfiguration of lo rule"}, -#endif - {ODI,0,ARG_THROW, 0, 5,A_PMN,A_ADM,A_DYI,A_CFA,A_ANY, 0, 0, 0, 0, opt_throw, - ARG_PREFIX_FORM, "do NOT route packets matching src or dst IP range(s) into gateway tunnel or announced networks"}, - - {ODI,ARG_THROW,ARG_NETW, 'n',5,A_CS1,A_ADM,A_DYI,A_CFA,A_ANY, 0, 0, 0, 0, opt_throw, - ARG_NETW_FORM, "specify network of throw rule"}, - - {ODI,ARG_THROW,ARG_MASK, 'm',5,A_CS1,A_ADM,A_DYI,A_CFA,A_ANY, 0, 0, 0, 0, opt_throw, - ARG_MASK_FORM, "specify network of throw rule"} - -#ifndef LESS_OPTIONS - , - {ODI,0,ARG_PEDANTIC_CLEANUP, 0, 5,A_PS1,A_ADM,A_DYI,A_CFA,A_ANY, &Pedantic_cleanup,0, 1, DEF_PEDANT_CLNUP,0, - ARG_VALUE_FORM, "disable/enable pedantic cleanup of system configuration (like ip_forward,..) \n" - " at program termination. Its generally safer to keep this disabled to not mess up \n" - " with other routing protocols"} -#endif - - -}; - - - -void init_route( void ) { - - if( ( nl_sk = open_netlink_socket()) <= 0 ) - cleanup_all( -500067 ); - - if( ( flush_sk = open_netlink_socket()) <= 0 ) - cleanup_all( -500067 ); - - errno=0; - if ( !rt_sock && (rt_sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { - dbgf( DBGL_SYS, DBGT_ERR, "can't create routing socket %s:", strerror(errno) ); - cleanup_all( -500021 ); - } - - register_options_array( route_options, sizeof( route_options ) ); - -} - - -void cleanup_route( void ) { - - flush_tracked_routes( TRACK_NO ); - flush_tracked_rules( TRACK_NO ); - - // if ever started succesfully in daemon mode... - if ( on_the_fly ) { - - // flush orphan routes (and do warning in case) - // must be before flushing rules, otherwise orphan routes are not found ! - flush_routes_rules(0 /* flush route */ ); - - // flush orphan rules (and do warning in case) - if ( prio_rules ) - flush_routes_rules(1 /* flush rule */); - - } - - restore_kernel_config( NULL ); - - if( nl_sk > 0 ) - close( nl_sk ); - - if( flush_sk > 0 ) - close( flush_sk ); - - if ( rt_sock ) - close( rt_sock ); - - rt_sock = 0; -} - - diff --git a/route.h b/route.h deleted file mode 100644 index 508fb03..0000000 --- a/route.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (C) 2006 BATMAN/BMX contributors: - * Thomas Lopatic, Marek Lindner, Axel Neumann - * 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 DEV_LO "lo" -#define DEV_UNKNOWN "unknown" -#define MAX_MTU 1500 - - -extern int32_t base_port; -#define ARG_BASE_PORT "base_port" -#define DEF_BASE_PORT 4305 -#define MIN_BASE_PORT 1025 -#define MAX_BASE_PORT 60000 - - - - -/*** - * - * Things you should leave as is unless your know what you are doing ! - * - * RT_TABLE_INTERFACES routing table for announced (non-primary) interfaces IPs and other unique IP addresses - * RT_TABLE_HOSTS routing table for routes towards originators - * RT_TABLE_NETWORKS routing table for announced networks - * RT_TABLE_TUNNEL routing table for the tunnel towards the internet gateway - * RT_PRIO_DEFAULT standard priority for routing rules - * RT_PRIO_UNREACH standard priority for unreachable rules - * RT_PRIO_TUNNEL standard priority for tunnel routing rules - * - ***/ - -#define RT_TABLE_INTERFACES -1 -#define RT_TABLE_HOSTS -2 -#define RT_TABLE_NETWORKS -3 -#define RT_TABLE_TUNNEL -4 - - - -extern uint8_t if_conf_soft_changed; // temporary enabled to trigger changed interface configuration -extern uint8_t if_conf_hard_changed; // temporary enabled to trigger changed interface configuration - -extern int Mtu_min; - - -struct routes_node { - struct list_node list; - uint32_t dest; - uint16_t netmask; - uint16_t rt_table; - uint32_t metric; - int16_t rta_type; - int8_t track_t; -}; - - -struct rules_node { - struct list_node list; - uint32_t prio; - char *iif; - uint32_t network; - int16_t netmask; - int16_t rt_table; - int16_t rta_type; - int8_t track_t; -}; - - - -//track types: -enum { - TRACK_NO, - TRACK_STANDARD, //basic rules to interfaces, host, and networks routing tables - TRACK_MY_HNA, - TRACK_MY_NET, - TRACK_OTHER_HOST, - TRACK_OTHER_HNA, - TRACK_TUNNEL -}; - -void configure_route( uint32_t dest, int16_t mask, uint32_t metric, uint32_t gw, uint32_t src, int32_t ifi, char *dev, - int16_t rt_table_macro, int16_t rta_type, int8_t del, int8_t track_t ); - -/*** - * - * rule types: 0 = RTA_SRC, 1 = RTA_DST, 2 = RTA_IIF -#define RTA_SRC 0 -#define RTA_DST 1 -#define RTA_IIF 2 - * - ***/ - -// void add_del_rule( uint32_t network, uint8_t netmask, int16_t rt_macro, uint32_t prio, char *iif, int8_t rule_type, int8_t del, int8_t track_t ); - -enum { - IF_RULE_SET_TUNNEL, - IF_RULE_CLR_TUNNEL, - IF_RULE_SET_NETWORKS, - IF_RULE_CLR_NETWORKS, - IF_RULE_UPD_ALL, - IF_RULE_CHK_IPS -}; - -int update_interface_rules( uint8_t cmd ); - - -void check_kernel_config( struct dev_node *dev_node ); - -//int8_t bind_to_iface( int32_t sock, char *dev ); - -//int is_interface_up(char *dev); -void dev_deactivate ( struct dev_node *dev_node ); -void dev_check (); - -void init_route( void ); -void cleanup_route( void ); - diff --git a/schedule.c b/schedule.c index 5a98291..a2f6fd2 100644 --- a/schedule.c +++ b/schedule.c @@ -1,6 +1,5 @@ /* - * Copyright (C) 2010 BMX contributors: - * Axel Neumann + * Copyright (c) 2010 Axel Neumann * 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. @@ -23,27 +22,20 @@ #include <fcntl.h> #include <sys/ioctl.h> #include <sys/socket.h> -#include <linux/if.h> /* ifr_if, ifr_tun */ +#include <linux/if.h> // ifr_if, ifr_tun #include <linux/rtnetlink.h>
#include "bmx.h" #include "msg.h" +#include "ip.h" #include "plugin.h" -#include "route.h" #include "schedule.h"
-#define OUT_SEQNO_OFFSET 1
-#ifndef NO_PARANOIA -#define DEF_SIM_PARA NO -static int32_t sim_paranoia = DEF_SIM_PARA; -#endif - - -static LIST_SIMPEL( task_list, struct task_node, list ); +static LIST_SIMPEL( task_list, struct task_node, list, list );
static int32_t receive_max_sock = 0; static fd_set receive_wait_set; @@ -52,17 +44,15 @@ static uint16_t changed_readfds = 1;
static int ifevent_sk = -1;
-#ifdef BMX2_TODO -static struct ext_packet my_pip_extension_packet; -#endif - -void change_selects( void ) { +void change_selects(void) +{ changed_readfds++; }
+static void check_selects(void) +{ + TRACE_FUNCTION_CALL;
-static void check_selects( void ) { - if( changed_readfds == 0 ) return; @@ -96,24 +86,24 @@ static void check_selects( void ) { } struct avl_node *it=NULL; - struct dev_node *bif; - while ((bif = avl_iterate_item(&dev_ip4_tree, &it))) { + struct dev_node *dev; + while ((dev = avl_iterate_item(&dev_ip_tree, &it))) {
- if ( bif->active && bif->linklayer != VAL_DEV_LL_LO ) { + if ( dev->active && dev->linklayer != VAL_DEV_LL_LO ) { - receive_max_sock = MAX( receive_max_sock, bif->unicast_sock ); + receive_max_sock = MAX( receive_max_sock, dev->unicast_sock ); - FD_SET(bif->unicast_sock, &receive_wait_set); + FD_SET(dev->unicast_sock, &receive_wait_set); - receive_max_sock = MAX( receive_max_sock, bif->netwbrc_sock ); + receive_max_sock = MAX( receive_max_sock, dev->rx_mcast_sock ); - FD_SET(bif->netwbrc_sock, &receive_wait_set); + FD_SET(dev->rx_mcast_sock, &receive_wait_set); - if (bif->fullbrc_sock > 0) { + if (dev->rx_fullbrc_sock > 0) { - receive_max_sock = MAX( receive_max_sock, bif->fullbrc_sock ); + receive_max_sock = MAX( receive_max_sock, dev->rx_fullbrc_sock ); - FD_SET(bif->fullbrc_sock, &receive_wait_set); + FD_SET(dev->rx_fullbrc_sock, &receive_wait_set); } } @@ -135,9 +125,9 @@ static void check_selects( void ) {
-void register_task( uint32_t timeout, void (* task) (void *), void *data ) +void register_task( TIME_T timeout, void (* task) (void *), void *data ) { - + TRACE_FUNCTION_CALL; assertion(-500475, (remove_task(task, data) == FAILURE));
struct list_node *list_pos, *prev_pos = (struct list_node *)&task_list; @@ -157,7 +147,7 @@ void register_task( uint32_t timeout, void (* task) (void *), void *data )
tmp_tn = list_entry( list_pos, struct task_node, list );
- if ( GREAT_U32(tmp_tn->expire, tn->expire) ) { + if ( U32_GT(tmp_tn->expire, tn->expire) ) {
list_add_after(&task_list, prev_pos, &tn->list); break; @@ -168,13 +158,15 @@ void register_task( uint32_t timeout, void (* task) (void *), void *data )
}
- if ( ( tmp_tn == NULL ) || ( LSEQ_U32(tmp_tn->expire, tn->expire) )) + if ( ( tmp_tn == NULL ) || ( U32_LE(tmp_tn->expire, tn->expire) )) list_add_tail(&task_list, &tn->list); }
-IDM_T remove_task( void (* task) (void *), void *data ) { - +IDM_T remove_task(void (* task) (void *), void *data) +{ + TRACE_FUNCTION_CALL; + struct list_node *list_pos, *tmp_pos, *prev_pos = (struct list_node*)&task_list; IDM_T ret = FAILURE; @@ -187,7 +179,7 @@ IDM_T remove_task( void (* task) (void *), void *data ) { list_del_next(&task_list, prev_pos); debugFree( tn, -300080 ); -#ifdef NO_PARANOIA +#ifdef NO_ASSERTIONS return SUCCESS; #else assertion(-500474, (ret == FAILURE)); @@ -204,17 +196,17 @@ IDM_T remove_task( void (* task) (void *), void *data ) { }
-uint32_t whats_next( void ) { - - struct list_node *list_pos, *tmp_pos, *prev_pos = (struct list_node*)&task_list; +TIME_T whats_next( void ) +{ + TRACE_FUNCTION_CALL;
- paranoia( -500175, sim_paranoia ); + struct list_node *list_pos, *tmp_pos, *prev_pos = (struct list_node*)&task_list;
list_for_each_safe( list_pos, tmp_pos, &task_list ) { struct task_node *tn = list_entry( list_pos, struct task_node, list ); - if ( LSEQ_U32( tn->expire, bmx_time ) ) { + if ( U32_LE( tn->expire, bmx_time ) ) {
list_del_next( &task_list, prev_pos ); @@ -236,16 +228,17 @@ uint32_t whats_next( void ) { return MAX_SELECT_TIMEOUT_MS; }
- -static int open_ifevent_netlink_sk( void ) { - +static int open_ifevent_netlink_sk(void) +{ struct sockaddr_nl sa; int32_t unix_opts; memset (&sa, 0, sizeof(sa)); sa.nl_family = AF_NETLINK; - sa.nl_groups |= RTMGRP_IPV4_IFADDR; + sa.nl_groups |= RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_MROUTE | RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_RULE; + sa.nl_groups |= RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_MROUTE | RTMGRP_IPV6_ROUTE | RTMGRP_IPV6_IFINFO | RTMGRP_IPV6_PREFIX; sa.nl_groups |= RTMGRP_LINK; // (this can result in select storms with buggy wlan devices - + + if ( ( ifevent_sk = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE) ) < 0 ) { dbg( DBGL_SYS, DBGT_ERR, "can't create af_netlink socket for reacting on if up/down events: %s", strerror(errno) ); @@ -269,7 +262,8 @@ static int open_ifevent_netlink_sk( void ) { return ifevent_sk; }
-static void close_ifevent_netlink_sk( void ) { +static void close_ifevent_netlink_sk(void) +{ if ( ifevent_sk > 0 ) close( ifevent_sk ); @@ -277,7 +271,9 @@ static void close_ifevent_netlink_sk( void ) { ifevent_sk = 0; }
-static void recv_ifevent_netlink_sk( void ) { +static void recv_ifevent_netlink_sk(void) +{ + TRACE_FUNCTION_CALL; char buf[4096]; //test this with a very small value !!
struct sockaddr_nl sa; @@ -302,22 +298,16 @@ static void recv_ifevent_netlink_sk( void ) { }
- - - - - - - -void wait4Event( uint32_t timeout ) { - +void wait4Event(TIME_T timeout) +{ + TRACE_FUNCTION_CALL; static struct packet_buff pb; - uint32_t last_get_time_result = 0; - - static uint32_t addr_len = sizeof(struct sockaddr_in); + TIME_T last_get_time_result = 0; + + static uint32_t addr_len = sizeof (pb.i.addr);
- uint32_t return_time = bmx_time + timeout; + TIME_T return_time = bmx_time + timeout; struct timeval tv; struct list_node *list_pos; int selected; @@ -326,7 +316,7 @@ void wait4Event( uint32_t timeout ) { loop4Event: - while ( GREAT_U32(return_time, bmx_time) ) { + while ( U32_GT(return_time, bmx_time) ) { check_selects(); @@ -337,7 +327,7 @@ loop4Event: selected = select( receive_max_sock + 1, &tmp_wait_set, NULL, NULL, &tv ); - upd_time( &(pb.tv_stamp) ); + upd_time( &(pb.i.tv_stamp) ); //omit debugging here since event could be a closed -d4 ctrl socket //which should be removed before debugging @@ -354,10 +344,15 @@ loop4Event: last_get_time_result = bmx_time; if ( selected < 0 ) { - - dbg( DBGL_SYS, DBGT_WARN, //happens when receiving SIGHUP - "can't select! Waiting a moment! errno: %s", strerror(errno) ); - + static TIME_T last_interrupted_syscall = 0; + + if (((TIME_T) (bmx_time - last_interrupted_syscall) < 1000)) { + dbg(DBGL_SYS, DBGT_WARN, //happens when receiving SIGHUP + "can't select! Waiting a moment! errno: %s", strerror(errno)); + } + + last_interrupted_syscall = bmx_time; + wait_sec_msec( 0, 1 ); upd_time( NULL ); @@ -368,7 +363,7 @@ loop4Event: if ( selected == 0 ) { //Often select returns just a few milliseconds before being scheduled - if ( LESS_U32( return_time, (bmx_time + 10) ) ) { + if ( U32_LT( return_time, (bmx_time + 10) ) ) { //cheating time :-) bmx_time = return_time; @@ -393,7 +388,8 @@ loop4Event: recv_ifevent_netlink_sk( ); //do NOT delay checking of interfaces to not miss ifdown/up of interfaces !! - dev_check(); + if (kernel_if_config() /*changed*/) + dev_check(YES); goto wait4Event_end; } @@ -401,30 +397,30 @@ loop4Event: // check for received packets... struct avl_node *it = NULL; - while ((pb.iif = avl_iterate_item(&dev_ip4_tree, &it))) { + while ((pb.i.iif = avl_iterate_item(&dev_ip_tree, &it))) {
- if ( pb.iif->linklayer == VAL_DEV_LL_LO ) + if ( pb.i.iif->linklayer == VAL_DEV_LL_LO ) continue; - if ( FD_ISSET( pb.iif->netwbrc_sock, &tmp_wait_set ) ) { + if ( FD_ISSET( pb.i.iif->rx_mcast_sock, &tmp_wait_set ) ) { - pb.unicast = NO; + pb.i.unicast = NO; errno=0; - pb.total_length = recvfrom( pb.iif->netwbrc_sock, pb.packet_in, - sizeof(pb.packet_in) - 1, 0, - (struct sockaddr *)&pb.addr, &addr_len ); + pb.i.total_length = recvfrom( pb.i.iif->rx_mcast_sock, pb.packet.data, + sizeof(pb.packet.data) - 1, 0, + (struct sockaddr *)&pb.i.addr, &addr_len ); - if ( pb.total_length < 0 && ( errno == EWOULDBLOCK || errno == EAGAIN ) ) { + if ( pb.i.total_length < 0 && ( errno == EWOULDBLOCK || errno == EAGAIN ) ) { dbgf(DBGL_SYS, DBGT_WARN, "sock returned %d errno %d: %s", - pb.total_length, errno, strerror(errno) ); + pb.i.total_length, errno, strerror(errno) ); continue; }
- ioctl(pb.iif->netwbrc_sock, SIOCGSTAMP, &(pb.tv_stamp)) ; + ioctl(pb.i.iif->rx_mcast_sock, SIOCGSTAMP, &(pb.i.tv_stamp)) ; rx_packet( &pb ); @@ -433,25 +429,25 @@ loop4Event:
} - if ( FD_ISSET( pb.iif->fullbrc_sock, &tmp_wait_set ) ) { + if ( FD_ISSET( pb.i.iif->rx_fullbrc_sock, &tmp_wait_set ) ) { - pb.unicast = NO; + pb.i.unicast = NO; errno=0; - pb.total_length = recvfrom( pb.iif->fullbrc_sock, pb.packet_in, - sizeof(pb.packet_in) - 1, 0, - (struct sockaddr *)&pb.addr, &addr_len ); + pb.i.total_length = recvfrom( pb.i.iif->rx_fullbrc_sock, pb.packet.data, + sizeof(pb.packet.data) - 1, 0, + (struct sockaddr *)&pb.i.addr, &addr_len ); - if ( pb.total_length < 0 && ( errno == EWOULDBLOCK || errno == EAGAIN ) ) { + if ( pb.i.total_length < 0 && ( errno == EWOULDBLOCK || errno == EAGAIN ) ) { dbgf(DBGL_SYS, DBGT_WARN, "sock returned %d errno %d: %s", - pb.total_length, errno, strerror(errno) ); + pb.i.total_length, errno, strerror(errno) ); continue; } - ioctl(pb.iif->fullbrc_sock, SIOCGSTAMP, &(pb.tv_stamp)) ; + ioctl(pb.i.iif->rx_fullbrc_sock, SIOCGSTAMP, &(pb.i.tv_stamp)) ; rx_packet( &pb ); @@ -461,9 +457,9 @@ loop4Event: } - if ( FD_ISSET( pb.iif->unicast_sock, &tmp_wait_set ) ) { + if ( FD_ISSET( pb.i.iif->unicast_sock, &tmp_wait_set ) ) { - pb.unicast = YES; + pb.i.unicast = YES; struct msghdr msghdr; struct iovec iovec; @@ -471,10 +467,10 @@ loop4Event: struct cmsghdr *cp; struct timeval *tv_stamp = NULL; - iovec.iov_base = pb.packet_in; - iovec.iov_len = sizeof(pb.packet_in) - 1; + iovec.iov_base = pb.packet.data; + iovec.iov_len = sizeof(pb.packet.data) - 1; - msghdr.msg_name = (struct sockaddr *)&pb.addr; + msghdr.msg_name = (struct sockaddr *)&pb.i.addr; msghdr.msg_namelen = addr_len; msghdr.msg_iov = &iovec; msghdr.msg_iovlen = 1; @@ -484,12 +480,12 @@ loop4Event: errno=0; - pb.total_length = recvmsg( pb.iif->unicast_sock, &msghdr, MSG_DONTWAIT ); + pb.i.total_length = recvmsg( pb.i.iif->unicast_sock, &msghdr, MSG_DONTWAIT ); - if ( pb.total_length < 0 && ( errno == EWOULDBLOCK || errno == EAGAIN ) ) { + if ( pb.i.total_length < 0 && ( errno == EWOULDBLOCK || errno == EAGAIN ) ) { dbgf(DBGL_SYS, DBGT_WARN, "sock returned %d errno %d: %s", - pb.total_length, errno, strerror(errno) ); + pb.i.total_length, errno, strerror(errno) ); continue; } @@ -506,9 +502,9 @@ loop4Event: } #endif if ( tv_stamp == NULL ) - ioctl( pb.iif->unicast_sock, SIOCGSTAMP, &(pb.tv_stamp) ); + ioctl( pb.i.iif->unicast_sock, SIOCGSTAMP, &(pb.i.tv_stamp) ); else - timercpy( tv_stamp, &(pb.tv_stamp) ); + timercpy( tv_stamp, &(pb.i.tv_stamp) ); rx_packet( &pb ); @@ -534,10 +530,9 @@ loop4ActivePlugins: (*(cdn->cb_fd_handler)) (cdn->fd); // list might have changed, due to unregistered handlers, reiterate NOW - //TBD: check if fd was really consumed ! + //TODO: check if fd was really consumed ! if ( --selected == 0 ) goto loop4Event; - //goto wait4Event_end; goto loop4ActivePlugins; } @@ -555,7 +550,6 @@ loop4ActivePlugins: if ( --selected == 0 ) goto loop4Event; - //goto wait4Event_end; } @@ -600,39 +594,12 @@ wait4Event_end: return; }
- - - - -static struct opt_type schedule_options[]= +void init_schedule(void) { -// ord parent long_name shrt Attributes *ival min max default *func,*syntax,*help - - {ODI,0,0, 0, 5,0,0,0,0,0, 0, 0, 0, 0, 0, - 0, "\nScheduling options:"}
-#ifndef LESS_OPTIONS -#ifndef NO_PARANOIA - ,{ODI,0,"simulate_cleanup", 0, 5,A_PS1,A_ADM,A_DYI,A_ARG,A_ANY, &sim_paranoia, NO, YES, DEF_SIM_PARA, 0, - ARG_VALUE_FORM, "simulate paranoia and cleanup_all for testing"} -#endif -#endif - -}; - - - -void init_schedule( void ) { - -#ifdef BMX2_TODO - memset( &my_pip_extension_packet, 0, sizeof(struct ext_packet) ); - my_pip_extension_packet.EXT_FIELD_MSG = YES; - my_pip_extension_packet.EXT_FIELD_TYPE = EXT_TYPE_64B_PIP; -#endif if ( open_ifevent_netlink_sk() < 0 ) cleanup_all( -500150 ); - register_options_array( schedule_options, sizeof( schedule_options ) ); }
@@ -644,18 +611,6 @@ void cleanup_schedule( void ) {
while ( (tn = list_rem_head( &task_list ))) debugFree(tn, -300082); - -/* - struct list_node *list_pos_tmp, *list_pos; - list_for_each_safe( list_pos, list_pos_tmp, &task_list ) { - - struct task_node *tn = list_entry( list_pos, struct task_node, list ); - - list_del_next( &task_list, (struct list_node *)&task_list ); - - debugFree(tn, -300082); - } -*/
close_ifevent_netlink_sk(); } diff --git a/schedule.h b/schedule.h index 8087691..573db2a 100644 --- a/schedule.h +++ b/schedule.h @@ -1,6 +1,5 @@ /* - * Copyright (C) 2010 BMX contributors: - * Axel Neumann + * Copyright (c) 2010 Axel Neumann * 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. @@ -22,8 +21,8 @@ void init_schedule( void ); void change_selects( void ); void cleanup_schedule( void ); -void register_task( uint32_t timeout, void (* task) (void *), void *data ); +void register_task( TIME_T timeout, void (* task) (void *), void *data ); IDM_T remove_task(void (* task) (void *), void *data); -uint32_t whats_next( void ); -void wait4Event( uint32_t timeout ); +TIME_T whats_next( void ); +void wait4Event( TIME_T timeout );
diff --git a/tools.c b/tools.c new file mode 100644 index 0000000..e47e1dd --- /dev/null +++ b/tools.c @@ -0,0 +1,430 @@ +/* + * Copyright (c) 2010 Axel Neumann + * 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 <stdio.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <arpa/inet.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> + + +#include "bmx.h" +#include "ip.h" +#include "tools.h" + +char* memAsStr( const void* mem, const uint32_t len) +{ + static uint8_t c=0; + static char out[4][256]; + uint32_t i; + + if (!mem) + return NULL; + + c = (c+1) % 4; + + for (i = 0; i < len && i < (((sizeof (out)) / 2) - 1); i++) { + + sprintf(&(out[c][i * 2]), "%.2X", ((uint8_t*) mem)[i]); + } + + if (len > i) + snprintf(&(out[c][(i - 1) * 2]), 2, ".."); + + out[c][i*2] = 0; + + return out[c]; +} + +//TODO: check all callers: currently limit parameter defines the first out-of-range element and not the max legal one! +uint32_t rand_num(const uint32_t limit) +{ + + return ( limit == 0 ? 0 : rand() % limit ); +} + +/* counting bits based on http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetTable */ + +static unsigned char BitsSetTable256[256]; + +static +void init_set_bits_table256(void) +{ + BitsSetTable256[0] = 0; + int i; + for (i = 0; i < 256; i++) + { + BitsSetTable256[i] = (i & 1) + BitsSetTable256[i / 2]; + } +} + +// count the number of true bits in v + +uint8_t bits_count(uint32_t v) +{ + uint8_t c=0; + + for (; v; v = v>>8 ) + c += BitsSetTable256[v & 0xff]; + + return c; +} + + +uint8_t bit_get(const uint8_t *array, const uint16_t array_bit_size, uint16_t bit) +{ + bit = bit % array_bit_size; + + uint16_t byte_pos = bit / 8; + uint8_t bit_pos = bit % 8; + + return (array[byte_pos] & (0x01 << bit_pos)) ? 1 : 0; +} + +void bit_set(uint8_t *array, uint16_t array_bit_size, uint16_t bit, IDM_T value) +{ + bit = bit % array_bit_size; + + uint16_t byte_pos = bit / 8; + uint8_t bit_pos = bit % 8; + + if (value) + array[byte_pos] |= (0x01 << bit_pos); + else + array[byte_pos] &= ~(0x01 << bit_pos); + + assertion(-500415, (!value == !bit_get(array, array_bit_size, bit))); +} + +/* + * clears bit range between and including begin and end + */ +void bit_clear(uint8_t *array, uint16_t array_bit_size, uint16_t begin_bit, uint16_t end_bit) +{ + assertion(-500435, (array_bit_size % 8 == 0)); + + if (((uint16_t) (end_bit - begin_bit)) >= (array_bit_size - 1)) { + + memset(array, 0, array_bit_size / 8); + return; + } + + begin_bit = begin_bit % array_bit_size; + end_bit = end_bit % array_bit_size; + + uint16_t begin_byte = begin_bit/8; + uint16_t end_byte = end_bit/8; + uint16_t array_byte_size = array_bit_size/8; + + + if (begin_byte != end_byte && ((begin_byte + 1) % array_byte_size) != end_byte) + byte_clear(array, array_byte_size, begin_byte + 1, end_byte - 1); + + + uint8_t begin_mask = ~(0xFF << (begin_bit%8)); + uint8_t end_mask = (0xFF >> ((end_bit%8)+1)); + + if (begin_byte == end_byte) { + + array[begin_byte] &= (begin_mask | end_mask); + + } else { + + array[begin_byte] &= begin_mask; + array[end_byte] &= end_mask; + } +} + +/* + * clears byte range between and including begin and end + */ +void byte_clear(uint8_t *array, uint16_t array_size, uint16_t begin, uint16_t end) +{ + + assertion(-500436, (array_size % 2 == 0)); + + begin = begin % array_size; + end = end % array_size; + + memset(array + begin, 0, end >= begin ? end + 1 - begin : array_size - begin); + + if ( begin > end) + memset(array, 0, end + 1); + + +} + + + +uint8_t is_zero(void *data, int len) +{ + int i; + char *d = data; + for (i = 0; i < len && !d[i]; i++); + + if ( i < len ) + return NO; + + return YES; +} + + + + + + +IDM_T str2netw(char* args, IPX_T *ipX, char delimiter, struct ctrl_node *cn, uint8_t *maskp, uint8_t *familyp) +{ + + char *slashptr = NULL; + + char switch_arg[IP6NET_STR_LEN] = {0}; + + if ( wordlen( args ) < 1 || wordlen( args ) >= IP6NET_STR_LEN ) + return FAILURE; + + wordCopy( switch_arg, args ); + switch_arg[wordlen( args )] = '\0'; + + if ( maskp ) { + + if ((slashptr = strchr(switch_arg, delimiter))) { + char *end = NULL; + + *slashptr = '\0'; + + errno = 0; + int mask = strtol(slashptr + 1, &end, 10); + + if ( ( errno == ERANGE ) || mask > 128 || mask < 0 ) { + + dbgf_cn( cn, DBGL_SYS, DBGT_ERR, "invalid argument %s %s", + args, strerror( errno ) ); + + return FAILURE; + + } else if ( end==slashptr+1 || wordlen(end) ) { + + dbgf_cn( cn, DBGL_SYS, DBGT_ERR, "invalid argument trailer %s", end ); + return FAILURE; + } + + *maskp = mask; + + } else { + + dbgf_cn( cn, DBGL_SYS, DBGT_ERR, "invalid argument %s! Fix you parameters!", switch_arg ); + return FAILURE; + } + } + + errno = 0; + + struct in_addr in4; + struct in6_addr in6; + + if ((inet_pton(AF_INET, switch_arg, &in4) == 1) && (!maskp || *maskp <= 32)) { + + ip42X(ipX, in4.s_addr); + + if (familyp) + *familyp = AF_INET; + + return SUCCESS; + + } else + + if ((inet_pton(AF_INET6, switch_arg, &in6) == 1) && (!maskp || *maskp <= 128)) { + + *ipX = in6; + + if (familyp) + *familyp = AF_INET6; + + return SUCCESS; + } + + dbgf_all(DBGT_WARN, "invalid argument: %s: %s", args, strerror(errno)); + return FAILURE; +} + + + + +int32_t check_file( char *path, uint8_t write, uint8_t exec ) { + + struct stat fstat; + + errno = 0; + int stat_ret = stat( path, &fstat ); + + if ( stat_ret < 0 ) { + + dbgf( DBGL_CHANGES, DBGT_WARN, "%s does not exist! (%s)", + path, strerror(errno)); + + } else { + + if ( S_ISREG( fstat.st_mode ) && + (S_IRUSR & fstat.st_mode) && + ((S_IWUSR & fstat.st_mode) || !write) && + ((S_IXUSR & fstat.st_mode) || !exec) ) + return SUCCESS; + + dbgf( DBGL_SYS, DBGT_ERR, + "%s exists but has inapropriate permissions (%s)", + path, strerror(errno)); + + } + + return FAILURE; +} + +int32_t check_dir( char *path, uint8_t create, uint8_t write ) { + + struct stat fstat; + + errno = 0; + int stat_ret = stat( path, &fstat ); + + if ( stat_ret < 0 ) { + + if ( create && mkdir( path, S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH ) >= 0 ) + return SUCCESS; + + dbgf( DBGL_SYS, DBGT_ERR, + "directory %s does not exist and can not be created (%s)", path, strerror(errno)); + + } else { + + if ( S_ISDIR( fstat.st_mode ) && + ( S_IRUSR & fstat.st_mode) && + ( S_IXUSR & fstat.st_mode) && + ((S_IWUSR & fstat.st_mode) || !write) ) + return SUCCESS; + + dbgf( DBGL_SYS, DBGT_ERR, + "directory %s exists but has inapropriate permissions (%s)", path, strerror(errno)); + + } + + return FAILURE; +} + + + + +uint32_t wordlen ( char *s ) { + + uint32_t i = 0; + + if ( !s ) + return 0; + + for( i=0; i<strlen(s); i++ ) { + + if ( s[i] == '\0' || s[i] == '\n' || s[i]==' ' || s[i]=='\t' ) + return i; + } + + return i; +} + + +int8_t wordsEqual ( char *a, char *b ) { + + if ( wordlen( a ) == wordlen ( b ) && !strncmp( a, b, wordlen(a) ) ) + return YES; + + return NO; +} + + +void wordCopy( char *out, char *in ) { + + if ( out && in && wordlen(in) < MAX_ARG_SIZE ) { + + snprintf( out, wordlen(in)+1, "%s", in ); + + } else if ( out && !in ) { + + out[0]=0; + + } else { + + dbgf( DBGL_SYS, DBGT_ERR, "called with out: %s and in: %s", out, in ); + cleanup_all( -500017 ); + + } +} + + +#ifdef WITH_UNUSED + +struct ring_buffer { + uint16_t field_size; + uint16_t elements; + uint16_t pos; + void *buffer; +}; + +struct ring_buffer *create_ring_buffer(uint16_t field_size, uint16_t elements) +{ + struct ring_buffer *ring = debugMalloc(sizeof (struct ring_buffer), -300316); + ring->field_size = field_size; + ring->elements = elements; + ring->pos = 0; + ring->buffer = debugMalloc(field_size*elements, -300317); + memset(ring->buffer, 0, field_size * elements); + +} + +static const char LogTable256[256] = +{ +#define LT(n) n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n + -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, + LT(4), LT(5), LT(5), LT(6), LT(6), LT(6), LT(6), + LT(7), LT(7), LT(7), LT(7), LT(7), LT(7), LT(7), LT(7) +}; + +uint32_t log_bin(uint32_t v) +{ + + //unsigned int v; // 32-bit word to find the log of + uint32_t r; // r will be lg(v) + uint32_t t, tt; // temporaries + + if ((tt = v >> 16)) { + r = ((t = tt >> 8)) ? 24 + LogTable256[t] : 16 + LogTable256[tt]; + } else { + r = ((t = v >> 8)) ? 8 + LogTable256[t] : LogTable256[v]; + } + + return r; +} +#endif + + + +void init_tools( void ) +{ + init_set_bits_table256(); +} \ No newline at end of file diff --git a/tools.h b/tools.h new file mode 100644 index 0000000..83e170a --- /dev/null +++ b/tools.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2010 Axel Neumann + * 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 XOR( a, b ) ( !(a) != !(b) ) +#define IMPLIES( a, b ) ( !(a) || (b) ) + +#define LOG2(result, val_tmp, VAL_TYPE) \ + do { \ + uint8_t j = ((8 * sizeof (VAL_TYPE) ) >> 1 ); \ + result = 0; \ + for (; val_tmp > 0x01; j >>= 1) { \ + if (val_tmp >> j) { \ + result += j; \ + val_tmp >>= j; \ + } \ + } \ + } while(0) + + +/* + for (i = ((8 * sizeof (UMETRIC_T)) / 2); i; i >>= 1) { + + if (tmp >> i) { + exp_sum += i; + tmp >>= i; + } + } +*/ + + + + + + + + + + + + + + +char* memAsStr( const void* mem, const uint32_t len); + +uint32_t rand_num(const uint32_t limit); + +uint8_t bits_count(uint32_t v); + +uint8_t bit_get(const uint8_t *array, const uint16_t array_bit_size, uint16_t bit); + +void bit_set(uint8_t *array, uint16_t array_bit_size, uint16_t bit, IDM_T value); + +void bit_clear(uint8_t *array, uint16_t array_bit_size, uint16_t begin, uint16_t end); + +void byte_clear(uint8_t *array, uint16_t array_size, uint16_t begin, uint16_t range); + +uint8_t is_zero(void *data, int len); + + +IDM_T str2netw(char* args, IPX_T *ipX, char delimiter, struct ctrl_node *cn, uint8_t *maskp, uint8_t *familyp); + +int8_t wordsEqual ( char *a, char *b ); +void wordCopy( char *out, char *in ); +uint32_t wordlen ( char *s ); +int32_t check_file( char *path, uint8_t write, uint8_t exec ); +int32_t check_dir( char *path, uint8_t create, uint8_t write ); + + + +void init_tools(void); \ No newline at end of file